/** Trace ray, based on "Voxel Tranversal along a 3D line" */ private void raytrace( MapChunkCache cache, MapIterator mapiter, HDShaderState[] shaderstate, boolean[] shaderdone) { /* Initialize raytrace state variables */ raytrace_init(); mapiter.initialize(x, y, z); for (; n > 0; --n) { if (visit_block(mapiter, shaderstate, shaderdone)) { return; } /* If X step is next best */ if ((t_next_x <= t_next_y) && (t_next_x <= t_next_z)) { x += x_inc; t = t_next_x; t_next_x += dt_dx; laststep = stepx; mapiter.stepPosition(laststep); } /* If Y step is next best */ else if ((t_next_y <= t_next_x) && (t_next_y <= t_next_z)) { y += y_inc; t = t_next_y; t_next_y += dt_dy; laststep = stepy; mapiter.stepPosition(laststep); /* If outside 0-127 range */ if ((y & (~0x7F)) != 0) return; } /* Else, Z step is next best */ else { z += z_inc; t = t_next_z; t_next_z += dt_dz; laststep = stepz; mapiter.stepPosition(laststep); } } }
/** Process visit of ray to block */ private final boolean visit_block( MapIterator mapiter, HDShaderState[] shaderstate, boolean[] shaderdone) { lastblocktypeid = blocktypeid; blocktypeid = mapiter.getBlockTypeID(); if (skiptoair) { /* If skipping until we see air */ if (blocktypeid == 0) /* If air, we're done */ skiptoair = false; } else if (nonairhit || (blocktypeid != 0)) { switch (blocktypeid) { case FENCE_BLKTYPEID: /* Special case for fence - need to fake data so we can render properly */ blockdata = generateFenceBlockData(mapiter); break; case CHEST_BLKTYPEID: /* Special case for chest - need to fake data so we can render */ blockdata = generateChestBlockData(mapiter); break; case REDSTONE_BLKTYPEID: /* Special case for redstone - fake data for wire pattern */ blockdata = generateRedstoneWireBlockData(mapiter); break; default: blockdata = mapiter.getBlockData(); break; } /* Look up to see if block is modelled */ short[] model = scalemodels.getScaledModel(blocktypeid, blockdata); if (model != null) { return handleSubModel(model, shaderstate, shaderdone); } else { boolean done = true; skylevel = emitlevel = -1; subalpha = -1; for (int i = 0; i < shaderstate.length; i++) { if (!shaderdone[i]) shaderdone[i] = shaderstate[i].processBlock(this); done = done && shaderdone[i]; } /* If all are done, we're out */ if (done) return true; nonairhit = true; } } return false; }
/** * Generate redstone wire model data: 0 = NSEW wire 1 = NS wire 2 = EW wire 3 = NE wire 4 = NW * wire 5 = SE wire 6 = SW wire 7 = NSE wire 8 = NSW wire 9 = NEW wire 10 = SEW wire * * @param mapiter * @return */ private int generateRedstoneWireBlockData(MapIterator mapiter) { /* Check adjacent block IDs */ int ids[] = { mapiter.getBlockTypeIDAt(BlockStep.Z_PLUS), /* To west */ mapiter.getBlockTypeIDAt(BlockStep.X_PLUS), /* To south */ mapiter.getBlockTypeIDAt(BlockStep.Z_MINUS), /* To east */ mapiter.getBlockTypeIDAt(BlockStep.X_MINUS) }; /* To north */ int flags = 0; for (int i = 0; i < 4; i++) if (ids[i] == REDSTONE_BLKTYPEID) flags |= (1 << i); switch (flags) { case 0: /* Nothing nearby */ case 15: /* NSEW */ return 0; /* NSEW graphic */ case 2: /* S */ case 8: /* N */ case 10: /* NS */ return 1; /* NS graphic */ case 1: /* W */ case 4: /* E */ case 5: /* EW */ return 2; /* EW graphic */ case 12: /* NE */ return 3; case 9: /* NW */ return 4; case 6: /* SE */ return 5; case 3: /* SW */ return 6; case 14: /* NSE */ return 7; case 11: /* NSW */ return 8; case 13: /* NEW */ return 9; case 7: /* SEW */ return 10; } return 0; }
/** * Generate chest block to drive model selection: 0 = single facing west 1 = single facing south * 2 = single facing east 3 = single facing north 4 = left side facing west 5 = left side facing * south 6 = left side facing east 7 = left side facing north 8 = right side facing west 9 = * right side facing south 10 = right side facing east 11 = right side facing north * * @param mapiter * @return */ private int generateChestBlockData(MapIterator mapiter) { ChestData cd = ChestData.SINGLE_WEST; /* Default to single facing west */ /* Check adjacent block IDs */ int ids[] = { mapiter.getBlockTypeIDAt(BlockStep.Z_PLUS), /* To west */ mapiter.getBlockTypeIDAt(BlockStep.X_PLUS), /* To south */ mapiter.getBlockTypeIDAt(BlockStep.Z_MINUS), /* To east */ mapiter.getBlockTypeIDAt(BlockStep.X_MINUS) }; /* To north */ /* First, check if we're a double - see if any adjacent chests */ if (ids[0] == CHEST_BLKTYPEID) { /* Another to west - assume we face south */ cd = ChestData.RIGHT_SOUTH; /* We're right side */ } else if (ids[1] == CHEST_BLKTYPEID) { /* Another to south - assume west facing */ cd = ChestData.LEFT_WEST; /* We're left side */ } else if (ids[2] == CHEST_BLKTYPEID) { /* Another to east - assume south facing */ cd = ChestData.LEFT_SOUTH; /* We're left side */ } else if (ids[3] == CHEST_BLKTYPEID) { /* Another to north - assume west facing */ cd = ChestData.RIGHT_WEST; /* We're right side */ } else { /* Else, single - build index into lookup table */ int idx = 0; for (int i = 0; i < ids.length; i++) { if ((ids[i] != 0) && (HDTextureMap.getTransparency(ids[i]) != BlockTransparency.TRANSPARENT)) { idx |= (1 << i); } } cd = SINGLE_LOOKUP[idx]; } return cd.ordinal(); }
private int generateFenceBlockData(MapIterator mapiter) { int blockdata = 0; /* Check north */ if (mapiter.getBlockTypeIDAt(BlockStep.X_MINUS) == FENCE_BLKTYPEID) { /* Fence? */ blockdata |= 1; } /* Look east */ if (mapiter.getBlockTypeIDAt(BlockStep.Z_MINUS) == FENCE_BLKTYPEID) { /* Fence? */ blockdata |= 2; } /* Look south */ if (mapiter.getBlockTypeIDAt(BlockStep.X_PLUS) == FENCE_BLKTYPEID) { /* Fence? */ blockdata |= 4; } /* Look west */ if (mapiter.getBlockTypeIDAt(BlockStep.Z_PLUS) == FENCE_BLKTYPEID) { /* Fence? */ blockdata |= 8; } return blockdata; }
protected void scan( DynmapWorld world, int seq, boolean isnether, final Color result, final Color result_day, MapIterator mapiter) { int lightlevel = 15; int lightlevel_day = 15; BiomeMap bio = null; double rain = 0.0; double temp = 0.0; result.setTransparent(); if (result_day != null) result_day.setTransparent(); for (; ; ) { if (mapiter.getY() < 0) { return; } int id = mapiter.getBlockTypeID(); int data = 0; if (isnether) { /* Make bedrock ceiling into air in nether */ if (id != 0) { /* Remember first color we see, in case we wind up solid */ if (result.isTransparent()) { try { if (colorScheme.colors[id] != null) { result.setColor(colorScheme.colors[id][seq]); } } catch (ArrayIndexOutOfBoundsException aioobx) { colorScheme.resizeColorArray(id); } } id = 0; } else isnether = false; } if (id != 0) { /* No update needed for air */ switch (biomecolored) { case NONE: try { if (colorScheme.datacolors[id] != null) { /* If data colored */ data = mapiter.getBlockData(); } } catch (ArrayIndexOutOfBoundsException aioobx) { colorScheme.resizeColorArray(id); } break; case BIOME: bio = mapiter.getBiome(); break; case RAINFALL: rain = mapiter.getRawBiomeRainfall(); break; case TEMPERATURE: temp = mapiter.getRawBiomeTemperature(); break; } if ((shadowscale != null) && (mapiter.getY() < (mapiter.getWorldHeight() - 1))) { /* Find light level of previous chunk */ BlockStep last = mapiter.unstepPosition(); lightlevel = lightlevel_day = mapiter.getBlockSkyLight(); if (lightscale != null) lightlevel = lightscale[lightlevel]; if ((lightlevel < 15) || (lightlevel_day < 15)) { int emitted = mapiter.getBlockEmittedLight(); lightlevel = Math.max(emitted, lightlevel); lightlevel_day = Math.max(emitted, lightlevel_day); } mapiter.stepPosition(last); } } switch (seq) { case 0: mapiter.stepPosition(BlockStep.X_MINUS); break; case 1: case 3: mapiter.stepPosition(BlockStep.Y_MINUS); break; case 2: mapiter.stepPosition(BlockStep.Z_PLUS); break; } seq = (seq + 1) & 3; if (id != 0) { if (highlightBlocks.contains(id)) { result.setColor(highlightColor); return; } Color[] colors = null; switch (biomecolored) { case NONE: try { if (data != 0) colors = colorScheme.datacolors[id][data]; else colors = colorScheme.colors[id]; } catch (ArrayIndexOutOfBoundsException aioobx) { colorScheme.resizeColorArray(id); } break; case BIOME: if (bio != null) colors = colorScheme.biomecolors[bio.ordinal()]; break; case RAINFALL: colors = colorScheme.getRainColor(rain); break; case TEMPERATURE: colors = colorScheme.getTempColor(temp); break; } if (colors != null) { Color c = colors[seq]; if (c.getAlpha() > 0) { /* we found something that isn't transparent, or not doing transparency */ if ((!transparency) || (c.getAlpha() == 255)) { /* it's opaque - the ray ends here */ result.setARGB(c.getARGB() | 0xFF000000); if (lightlevel < 15) { /* Not full light? */ shadowColor(result, lightlevel); } if (result_day != null) { if (lightlevel_day == lightlevel) /* Same light = same result */ result_day.setColor(result); else { result_day.setColor(c); if (lightlevel_day < 15) shadowColor(result_day, lightlevel_day); } } return; } /* this block is transparent, so recurse */ scan(world, seq, isnether, result, result_day, mapiter); int cr = c.getRed(); int cg = c.getGreen(); int cb = c.getBlue(); int ca = c.getAlpha(); if (lightlevel < 15) { int scale = shadowscale[lightlevel]; cr = (cr * scale) >> 8; cg = (cg * scale) >> 8; cb = (cb * scale) >> 8; } cr *= ca; cg *= ca; cb *= ca; int na = 255 - ca; result.setRGBA( (result.getRed() * na + cr) >> 8, (result.getGreen() * na + cg) >> 8, (result.getBlue() * na + cb) >> 8, 255); /* Handle day also */ if (result_day != null) { cr = c.getRed(); cg = c.getGreen(); cb = c.getBlue(); if (lightlevel_day < 15) { int scale = shadowscale[lightlevel_day]; cr = (cr * scale) >> 8; cg = (cg * scale) >> 8; cb = (cb * scale) >> 8; } cr *= ca; cg *= ca; cb *= ca; result_day.setRGBA( (result_day.getRed() * na + cr) >> 8, (result_day.getGreen() * na + cg) >> 8, (result_day.getBlue() * na + cb) >> 8, 255); } return; } } } } }
public boolean render(MapChunkCache cache, KzedMapTile tile, File outputFile) { DynmapWorld world = tile.getDynmapWorld(); boolean isnether = world.isNether(); DynmapBufferedImage im = DynmapBufferedImage.allocateBufferedImage(KzedMap.tileWidth, KzedMap.tileHeight); DynmapBufferedImage zim = DynmapBufferedImage.allocateBufferedImage(KzedMap.tileWidth / 2, KzedMap.tileHeight / 2); DynmapBufferedImage im_day = null; DynmapBufferedImage zim_day = null; if (night_and_day) { im_day = DynmapBufferedImage.allocateBufferedImage(KzedMap.tileWidth, KzedMap.tileHeight); zim_day = DynmapBufferedImage.allocateBufferedImage(KzedMap.tileWidth / 2, KzedMap.tileHeight / 2); } if (cache.getWorld().worldheight > 128) { if (maximumHeight == 127) maximumHeight = cache.getWorld().worldheight - 1; } int ix = tile.px / 2 + tile.py / 2 - ((127 - maximumHeight) / 2); int iy = maximumHeight; int iz = tile.px / 2 - tile.py / 2 + ((127 - maximumHeight) / 2); /* Don't mess with existing height-clipped renders */ if (maximumHeight < 127) isnether = false; int jx, jz; int x, y; MapIterator mapiter = cache.getIterator(ix, iy, iz); Color c1 = new Color(); Color c2 = new Color(); int[] argb = im.argb_buf; int[] zargb = zim.argb_buf; Color c1_day = null; Color c2_day = null; int[] argb_day = null; int[] zargb_day = null; if (night_and_day) { c1_day = new Color(); c2_day = new Color(); argb_day = im_day.argb_buf; zargb_day = zim_day.argb_buf; } int rowoff = 0; /* draw the map */ for (y = 0; y < KzedMap.tileHeight; ) { jx = ix; jz = iz; for (x = KzedMap.tileWidth - 1; x >= 0; x -= 2) { mapiter.initialize(jx, iy, jz); scan(world, 0, isnether, c1, c1_day, mapiter); mapiter.initialize(jx, iy, jz); scan(world, 2, isnether, c2, c2_day, mapiter); argb[rowoff + x] = c1.getARGB(); argb[rowoff + x - 1] = c2.getARGB(); if (night_and_day) { argb_day[rowoff + x] = c1_day.getARGB(); argb_day[rowoff + x - 1] = c2_day.getARGB(); } jx++; jz++; } y++; rowoff += KzedMap.tileWidth; jx = ix; jz = iz - 1; for (x = KzedMap.tileWidth - 1; x >= 0; x -= 2) { mapiter.initialize(jx, iy, jz); scan(world, 2, isnether, c1, c1_day, mapiter); jx++; jz++; mapiter.initialize(jx, iy, jz); scan(world, 0, isnether, c2, c2_day, mapiter); argb[rowoff + x] = c1.getARGB(); argb[rowoff + x - 1] = c2.getARGB(); if (night_and_day) { argb_day[rowoff + x] = c1_day.getARGB(); argb_day[rowoff + x - 1] = c2_day.getARGB(); } } y++; rowoff += KzedMap.tileWidth; ix++; iz--; } /* Now, compute zoomed tile - bilinear filter 2x2 -> 1x1 */ doScaleWithBilinear(argb, zargb, KzedMap.tileWidth, KzedMap.tileHeight); if (night_and_day) { doScaleWithBilinear(argb_day, zargb_day, KzedMap.tileWidth, KzedMap.tileHeight); } /* Hand encoding and writing file off to MapManager */ KzedZoomedMapTile zmtile = new KzedZoomedMapTile(tile.getDynmapWorld(), tile); File zoomFile = MapManager.mapman.getTileFile(zmtile); return doFileWrites(outputFile, tile, im, im_day, zmtile, zoomFile, zim, zim_day); }
/** Update sky and emitted light */ private final void updateLightLevel() { /* Look up transparency for current block */ BlockTransparency bt = HDTextureMap.getTransparency(blocktypeid); if (bt == BlockTransparency.TRANSPARENT) { skylevel = mapiter.getBlockSkyLight(); emitlevel = mapiter.getBlockEmittedLight(); } else if (HDTextureMap.getTransparency(lastblocktypeid) != BlockTransparency.SEMITRANSPARENT) { mapiter.unstepPosition(laststep); /* Back up to block we entered on */ if (mapiter.getY() < 128) { emitlevel = mapiter.getBlockEmittedLight(); skylevel = mapiter.getBlockSkyLight(); } else { emitlevel = 0; skylevel = 15; } mapiter.stepPosition(laststep); } else { mapiter.unstepPosition(laststep); /* Back up to block we entered on */ if (mapiter.getY() < 128) { mapiter.stepPosition(BlockStep.Y_PLUS); /* Look above */ emitlevel = mapiter.getBlockEmittedLight(); skylevel = mapiter.getBlockSkyLight(); mapiter.stepPosition(BlockStep.Y_MINUS); } else { emitlevel = 0; skylevel = 15; } mapiter.stepPosition(laststep); } }