diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..fae6a6e
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+*.o
+pigmap
diff --git a/COPYING b/COPYING
old mode 100755
new mode 100644
diff --git a/Makefile b/Makefile
index 946daf5..2c3d824 100644
--- a/Makefile
+++ b/Makefile
@@ -1,29 +1,38 @@
-objects = pigmap.o blockimages.o chunk.o map.o render.o region.o rgba.o tables.o utils.o world.o
-
-pigmap : $(objects)
- g++ $(objects) -o pigmap -l z -l png -l pthread -O3
-
-pigmap.o : pigmap.cpp blockimages.h chunk.h map.h render.h rgba.h tables.h utils.h world.h
- g++ -c pigmap.cpp -O3
-blockimages.o : blockimages.cpp blockimages.h rgba.h utils.h
- g++ -c blockimages.cpp -O3
-chunk.o : chunk.cpp chunk.h map.h region.h tables.h utils.h
- g++ -c chunk.cpp -O3
-map.o : map.cpp map.h utils.h
- g++ -c map.cpp -O3
-render.o : render.cpp blockimages.h chunk.h map.h render.h rgba.h tables.h utils.h
- g++ -c render.cpp -O3
-region.o : region.cpp map.h region.h tables.h utils.h
- g++ -c region.cpp -O3
-rgba.o : rgba.cpp rgba.h utils.h
- g++ -c rgba.cpp -O3
-tables.o : tables.cpp map.h tables.h utils.h
- g++ -c tables.cpp -O3
-utils.o : utils.cpp utils.h
- g++ -c utils.cpp -O3
-world.o : world.cpp map.h region.h tables.h world.h
- g++ -c world.cpp -O3
-
-clean :
- rm -f *.o pigmap
-
\ No newline at end of file
+objects = pigmap.o blockimages.o chunk.o map.o render.o region.o rgba.o tables.o utils.o world.o
+
+ifeq ($(mode),debug)
+ CFLAGS = -g -Wall -D_DEBUG
+else ifeq ($(mode),profile)
+ CFLAGS = -Wall -O3 -DNDEBUG -pg
+else ifeq ($(mode),coverage)
+ CFLAGS = -Wall -O3 -DNDEBUG -fprofile-arcs -ftest-coverage
+else
+ CFLAGS = -Wall -O3 -DNDEBUG
+endif
+
+pigmap : $(objects)
+ g++ $(objects) -o pigmap -l z -l png -l jpeg -l pthread $(CFLAGS)
+
+pigmap.o : pigmap.cpp blockimages.h chunk.h map.h render.h rgba.h tables.h utils.h world.h
+ g++ -c pigmap.cpp $(CFLAGS)
+blockimages.o : blockimages.cpp blockimages.h rgba.h utils.h
+ g++ -c blockimages.cpp $(CFLAGS) -std=c++0x
+chunk.o : chunk.cpp chunk.h map.h region.h tables.h utils.h
+ g++ -c chunk.cpp $(CFLAGS)
+map.o : map.cpp map.h utils.h
+ g++ -c map.cpp $(CFLAGS)
+render.o : render.cpp blockimages.h chunk.h map.h render.h rgba.h tables.h utils.h
+ g++ -c render.cpp $(CFLAGS)
+region.o : region.cpp map.h region.h tables.h utils.h
+ g++ -c region.cpp $(CFLAGS)
+rgba.o : rgba.cpp rgba.h utils.h
+ g++ -c rgba.cpp $(CFLAGS)
+tables.o : tables.cpp map.h tables.h utils.h
+ g++ -c tables.cpp $(CFLAGS)
+utils.o : utils.cpp utils.h
+ g++ -c utils.cpp $(CFLAGS)
+world.o : world.cpp map.h region.h tables.h world.h
+ g++ -c world.cpp $(CFLAGS)
+
+clean :
+ rm -f *.o pigmap
diff --git a/README b/README
index 713de4f..87f7656 100644
--- a/README
+++ b/README
@@ -4,8 +4,8 @@ essentially the same thing, just faster and with fewer fancy options. Features
-isometric projection; level of detail on max zoom is user-settable
-Google Maps tile output
--custom tilesets (supply your own terrain.png)
--ability to manually edit the isometric block images generated from terrain.png,
+-custom tilesets (supply your own texture pack)
+-ability to manually edit the isometric block images generated from texture pack,
for further beautification
-incremental map updates, but you must supply your own list of modified chunks (most
likely via rsync or something similar)
@@ -25,12 +25,15 @@ Andrew Brown and contributors).
The official pigmap repository is at:
https://github.com/equalpants/pigmap
+Latest textures to build tile set is at (if you don't want to manually extract textures):
+https://www.dropbox.com/s/qkckuwbu1an77sm/pigmap_mc_textures.7z
+
---------------------------------------------------------------------------------------------------
Supported platforms are Linux and cygwin. OS X should also be fine, but I haven't tried it
myself. (I've heard reports of it working, though.)
-Dependencies are zlib, libpng, pthreads, and some very basic system stuff: getopt, mkdir,
+Dependencies are zlib, libpng, libjpeg, pthreads, and some very basic system stuff: getopt, mkdir,
dirent.h. If your platform has a separate development package for libpng (called libpng-dev,
libpng-devel, or something like that), you'll need that one, too.
@@ -39,6 +42,32 @@ Use supplied makefile to build with g++.
---------------------------------------------------------------------------------------------------
Change log (important stuff only):
+1.8
+-new blocks up to Minecraft 1.8 (andesite, diorite, granite, coarse dirt
+ prismarine blocks, sea lantern, sponge, iron trapdoor, inverted daylight sensor)
+-new fence & fence gate variants
+-new door variants
+-added different bottom texture for stairs (sandstone, quartz, red sandstone)
+-fixed farmland block not showing if it is wet
+
+1.7
+-added support for RGB PNG images (with no alpha channel)
+-endportal.png is no longer included in root directory
+-texture names are aligned with 1.6+/1.7 textures
+-new blocks up to Minecraft 1.7 (packed ice, tall flowers, new flowers, stained glass, stained glass pane)
+-new block type (used for tall flowers)
+-new texture directive (to combine multiple textures in one, to be used for generating tiles)
+
+1.6
+-new blocks up to Minecraft 1.6
+
+1.5
+-fire.png, terrain.png, chest.png (and similar) are no longer required
+-pigmap now works with upcoming Minecraft 1.5 textures
+-folders /item, /textures/blocks from minecraft.jar or your texture pack are
+ required (in image path), including their contents
+-new blocks up to 13w03a Minecraft snapshot (upcoming Minecraft 1.5)
+-possibility to render custom blocks
1.2
-new blocks up to Minecraft 1.3
@@ -116,7 +145,7 @@ Usage examples:
full render:
-pigmap -B 6 -T 1 -Z 10 -i input/World1 -o output/World1 -g images -h 3
+pigmap -B 6 -T 1 -Z 10 -i input/World1 -o output/World1 -g images -t 3
...builds a map with parameters B = 6, T = 1, baseZoom = 10, reading world data from the path
"input/World1", writing tiles out to the path "output/World1", reading terrain images from the path
@@ -124,7 +153,7 @@ pigmap -B 6 -T 1 -Z 10 -i input/World1 -o output/World1 -g images -h 3
incremental update:
-pigmap -i input/World1 -o output/World1 -r regionlist -h 3 -x
+pigmap -i input/World1 -o output/World1 -r regionlist -t 3 -x
...updates an existing map by redrawing any tiles touched by regions listed in the file "regionlist",
with the input and output dirs as before. Terrain images are read from the path ".", and 3 threads
@@ -168,7 +197,7 @@ incremental update; make a copy if you need to add fancier abilities to it.
c. [optional (kind of)] image path (-g)
-This is where pigmap expects to find either a copy of your tileset (terrain.png, etc.), or a copy of
+This is where pigmap expects to find either a copy of your textures (textures/ folder of your minecraft.jar etc.), or a copy of
blocks-B.png (substituting the actual numeric value of B; see below for definition of B), a
pigmap-generated file that contains the isometric renderings of each block. These files are not
optional, but the -g parameter itself may be omitted, in which case "." is used as the image path.
@@ -179,30 +208,42 @@ are stored in blocks-B.png. (As more blocks are added to the game, the version
The selection of block images works thusly:
-If blocks-B.png does not exist, then the tileset you provide will be used to create it.
--If blocks-B.png exists but has an old version, your tileset will be used to fill in any missing
- (i.e. new) blocks, but the existing portions of blocks-B.png will be preserved.
+-If blocks-B.png exists but has an old version, your tileset will be used to create new replacement. Old blocks-B.png data will be lost.
-If blocks-B.png exists and is up-to-date, its block images will be used.
This means that pigmap will need your tileset the first time it runs, so it can generate blocks-B.png;
subsequent runs will use the existing blocks-B.png, which can be manually edited if insufficiently
pretty, or for special effects, etc.
-The following images are required to generate blocks-B.png:
--terrain.png, chest.png, largechest.png, enderchest.png: these files come from your tileset
- or minecraft.jar
--fire.png, endportal.png: these files are included with pigmap
-All of these must be RGBA png files (not just RGB).
+To generate blocks-B.png, extract the entity/ and blocks/ folders from your minecraft.jar into textures/ folder inside the folder
+you have specified, so folder structure looks like this:
+/%specified_image_path%
+ /textures
+ /blocks
+ /entity
-High-res tilesets are supported. The textures in terrain.png, fire.png, and endportal.png can be
-any size, as long as they remain square. The textures in the chest pngs can be scaled up, but their
-size must be an integer multiple of the original size.
+All of these must be RGBA/RGB (32BPP/24BPP) png files.
-d. [optional] number of threads (-h)
+d. [optional] number of threads (-t)
Defaults to 1. Each thread requires around 250-300 MB of RAM (they work in different areas of the
map and keep separate caches of chunk data). Returns from extra threads may diminish quickly as the
disk becomes a bottleneck.
+e. [optional] output image file format (-f)
+
+Defaults to png. The output is either done as png files, jpeg files or both. Jpeg can be compressed to
+smaller file sizes than png and may be preferrable for web use, but incremental rendering only reads
+png files, since jpeg is a lossy format. The "both" option is supplied to deal with this situation -
+both file formats will be written, jpeg used in the html map and png files can be kept for future
+incremental renders.
+
+f. [optional] Jpeg quality (-j)
+
+Defaults to 75. A number between 1 and 100 that determines what quality level jpeg files are written.
+Higher means better quality but larger file sizes. Has no effect (obviously) if the output file format
+is not set to jpeg or both.
+
2. Params for full renders only:
@@ -283,33 +324,26 @@ are redrawn.
---------------------------------------------------------------------------------------------------
+Custom blocks:
+
+1. Textures
+blocktextures.list file is used to declare and pre-process textures, before generating blocks-B.png
+tiles. For more info read blocktextures.list;
+
+2. Blocks
+blockdescriptor.list file is used to declare and describe new blocks by their respective IDs.
+It also describes how blocks look and what textures do they use. Textures must be declared in
+blocktextures.list file. For more info read blockdescriptor.list;
+
+Note: Block IDs >= 256 will be not used by renderer.
+
+---------------------------------------------------------------------------------------------------
+
Special note for those who choose to manually edit blocks-B.png:
-When new block types are introduced, their block images are added on to the end of blocks-B.png,
-and the existing contents are preserved, so you don't need to worry about previous modifications
-getting destroyed. However, sometimes it may be necessary to remove existing block images and
-replace them with new versions; when this happens, the old block image offset will no longer be
-used, and a new block image will be added to the end of the file.
-
-Example: prior to pigmap 0.6, the furnace block images were located at offsets 68, 69, and 149-152.
-Starting with 0.6, they are instead located at 183-188. (This is because the furnace graphics
-were changed in Minecraft Beta 1.2.) So if you modified the furnace block images while using a
-pre-0.6 version of pigmap, your modified images can still be found at their old locations in your
-blocks-B.png, but they must be copied to the new locations.
-
-Complete list of block image moves:
-
---- pigmap 1.2 ---
-gravel: 21->483
-chests: 54->484, 177->485, 297->486, [173-176]->[487,490], [298-301]->[491-494]
-
---- pigmap 1.0 ---
-beds: 232->281, 233->282, 234->283, 235->284, 236->285, 237->286, 238->287, 239->288
-cake: 228->289
-
---- pigmap 0.6 ---
-furnaces: 68->183, 69->186, 149->184, 150->185, 151->187, 152->188
-fire: 48->189
-buttons: 123->190, 124->191, 125->192, 126->193
-levers: 104->194, 105->195, 106->196, 107->197, 108->198, 109->199
-ascending tracks: 88->200, 89->201, 90->202, 91->203
\ No newline at end of file
+Block positions in blocks-B.png are dynamic. When new blocks are declared in blockdescriptor.list,
+old blocks-B.png is overwritten by newly generated. Don't forget to make backups.
+
+Block images are generated in order of appearance in blockdescriptor.list. You can use that to your advantage
+by declaring new blocks at the end of the list. Then you can easily combine old and new ones with image editor,
+as new blocks-B.png will look similar to the old one with new tiles added at the end.
diff --git a/blockdescriptor.list b/blockdescriptor.list
new file mode 100644
index 0000000..e186d0c
--- /dev/null
+++ b/blockdescriptor.list
@@ -0,0 +1,307 @@
+# blockdescriptor.list
+#
+# block types:
+# 0 SOLID (specify texture for all faces, all textures for west face, south face, top face; like any solid block)
+# 1 SOLIDORIENTED (solid blocks, that can be oriented N,S,W,E but not U or D; specify list of bits for N,S,W,E, then textures for face, side, top; like dispensers, furnaces, pumpkins, jack 'o' lanterns)
+# 2 SOLIDROTATED (solid blocks, that can be oriented in any direction; specify degrees of freedom(4/6), specify top(face), side, bottom(opposite to face) textures ;like pistons)
+# 3 SOLIDDATA (list all textures in order of data bits; like wooden planks, wool, wooden double slabs)
+# 4 SOLIDDATAFILL (like SOLIDDATA, but "tiles" existing data over remaining bits(if any); like leaves)
+# 5 SOLIDDATATRUNK (specify pairs of textures for top and sides for each data bit; like sandstone, double slabs)
+# 6 SOLIDDATATRUNKROTATED (specify bit spacing method (S - each orientation is spaced 4 bits, O - each orientation is stored in order of group appearance), then list of groups (up to 4 for "S" method) with flag (if this data group should be oriented), top texture, side texture; like logs)
+# 7 SOLIDOBSTRUCTED (solid block with missing faces due to obstruction; like ice blocks)
+# 8 SOLIDPARTIAL (list top cutoff, bottom cutoff, then Wface, Sface, Uface; cutoff is specified by number 0 - 16(which is ridiculous; like cake, enchanting table(getto version))
+# 8a SOLIDDATAPARTIAL (list top cutoff, bottom cutoff, then list textures for each data bit; like carpet)
+# 9 SOLIDDATAPARTIALFILL (list Wface, Sface, Uface, then specify cutoffs for data bits in a sequence; like snow)
+# 10 SOLIDTRANSPARENT (draws all faces, in combination with empty tile, interesting results can be achieved; specify texture for each block face - D, N, E, W, S, U; like fire)
+# 11 SLABDATA (specify texture for all faces of slab for each data bit; like wooden slabs)
+# 12 SLABDATATRUNK (specify pairs of textures for top and sides for each data bit; like slabs)
+# 13 ITEMDATA (list textures for each data bit; like saplings, wheat, carrots, potatoes, tall grass, dead brush, reeds)
+# 14 ITEMDATAORIENTED (list N,S,W,E orientation bit indexes, then list of textures per data orientation group; like cocoa pods)
+# 15 ITEMDATAFILL (used for such items as sapling; behaves like ITEMDATA, but tiles provided list over bits, that remain after filling group; group size should be specified before texture list)
+# 16 ITEMDATATALLORIENTED (list pairs of top and bottom textures for each data bit [0-7]; [8-15] are used for orientation; like sunflowers, double tall grass, large fern, etc.)
+# 17 MULTIITEMDATA (list textures for each data bit; like nether wart)
+# 18 STAIR (list textures for: side, top OR side (if all faces has the same texture); stairs in all it's glory)
+# 19 FENCE (specify base texture; like fence, nether brick fence)
+# 20 WALLDATA (specify base texture for each data bit; like cobblestone wall, mossy cobblestone wall)
+# 21 FENCEGATE (specify base texture for fence gate; like fence gate)
+# 22 MUSHROOM (specify pore, stem, cap textures; like huge brown / red mushrooms)
+# 23 CHEST (specify chest texture, large chest texture(don't specify it, if chest is not double chest); like chest, ender chest, trapped chest)
+# 24 RAIL (specify rail texture, corner texture(for cornered tracks); like rails, detector rails)
+# 25 RAILPOWERED (specify rail texture(off), rail texture(on); like powered rails, activator rails)
+# 26 PANEDATA (specify base texture for each data bit; like iron bars, glass pane)
+# 27 DOOR (specify textures for lower and bottom part of the classic 2x1 door; like wooden door, iron door)
+# 28 TRAPDOOR (specify texture for trap door
+# 29 TORCH (specify base texture of the torch; like torches, redstone torches)
+# 30 ONWALLPARTIAL (specify list of bits indexes for N,S,W,E attachments, base texture, cuttoffs for N,S,W,E (tile orientation, not world orientation!); like ladders)
+# 31 ONWALLPARTIALFILL (specify list of bits indexes for N,S,W,E attachments, base texture, cuttoffs for N,S,W,E (tile orientation, not world orientation!); like buttons, tripwire hooks)
+# 32 WIRE (specify wire texture, wire crossing texture (if any); like redstone wire, tripwire)
+# 33 BITANCHOR (specify face texture; draws faces anchored to different block side for each data bit combination; like vines)
+# 34 STEM (specify straight stem texture, bent stem texture; like pumpkin stem, melon stem)
+# 35 LEVER (specify lever base texture, lever handle texture; like lever)
+# 36 SIGNPOST (specify sign base texture, sign pole texture; like sign post)
+# 37 SPECIAL (handled by id, like brewing stand, dragon egg, beacon, stonewall, flowerpot, anvil, etc)
+#
+# You can use / as a texture name to use empty tile
+#
+# blockid blocktype *
+1 SOLIDDATA stone stone_granite stone_granite_smooth stone_diorite stone_diorite_smooth stone_andesite stone_andesite_smooth
+2 SOLID grass_side grass_side grass_top
+3 SOLIDDATATRUNK dirt dirt coarse_dirt coarse_dirt dirt_podzol_top dirt_podzol_side #dirt / coarse dirt / podzol
+4 SOLID cobblestone #cobblestone
+5 SOLIDDATA planks_oak planks_spruce planks_birch planks_jungle planks_acacia planks_big_oak # oak / spruce / birch / jungle / acacia / dark oak planks
+6 ITEMDATAFILL 8 sapling_oak sapling_spruce sapling_birch sapling_jungle sapling_acacia sapling_roofed_oak #sapling
+7 SOLID bedrock
+8 SPECIAL water_still
+##9 - skip, it's water too
+10 SPECIAL lava_still
+##11 - skip, it's lava too
+12 SOLIDDATA sand red_sand
+13 SOLID gravel
+14 SOLID gold_ore
+15 SOLID iron_ore
+16 SOLID coal_ore
+17 SOLIDDATATRUNKROTATED S 1 log_oak_top log_oak 1 log_spruce_top log_spruce 1 log_birch_top log_birch 1 log_jungle_top log_jungle # oak / spruce / birch / jungle wood
+18 SOLIDDATAFILL leaves_oak leaves_spruce leaves_birch leaves_jungle # oak / spruce / birch / jungle leaves
+19 SOLIDDATA sponge sponge_wet
+20 SOLID glass
+21 SOLID lapis_ore
+22 SOLID lapis_block
+23 SOLIDORIENTED 2 3 4 5 dispenser_front_horizontal furnace_side furnace_top #dispenser
+24 SOLIDDATATRUNK sandstone_top sandstone_normal sandstone_top sandstone_carved sandstone_top sandstone_smooth #sandstone
+25 SOLID noteblock #note block
+26 SPECIAL bed_feet_end bed_feet_side bed_feet_top bed_head_end bed_head_side bed_head_top #bed
+27 RAILPOWERED rail_golden rail_golden_powered #powered rail
+28 RAIL rail_detector #detector rail
+29 SOLIDROTATED 6 piston_top_sticky piston_side piston_bottom #sticky piston
+30 ITEMDATA web #cobweb
+31 ITEMDATA deadbush tallgrass fern #tall grass
+32 ITEMDATA deadbush #dead bush
+33 SOLIDROTATED 6 piston_top_normal piston_side piston_bottom #piston
+##34 technical block
+35 SOLIDDATA wool_colored_white wool_colored_orange wool_colored_magenta wool_colored_light_blue wool_colored_yellow wool_colored_lime wool_colored_pink wool_colored_gray wool_colored_silver wool_colored_cyan wool_colored_purple wool_colored_blue wool_colored_brown wool_colored_green wool_colored_red wool_colored_black #wool
+##36 technical block
+37 ITEMDATA flower_dandelion #dandelion
+38 ITEMDATA flower_rose flower_blue_orchid flower_allium flower_houstonia flower_tulip_red flower_tulip_orange flower_tulip_white flower_tulip_pink flower_oxeye_daisy #poppy / blue orchid / allium / azure bluet / red tulip / orange tulip / white tulip / pink tulip / daisy
+39 ITEMDATA mushroom_brown
+40 ITEMDATA mushroom_red
+41 SOLID gold_block
+42 SOLID iron_block
+43 SOLIDDATATRUNK stone_slab_top stone_slab_side sandstone_top sandstone_normal planks_oak planks_oak cobblestone cobblestone brick brick stonebrick stonebrick nether_brick nether_brick quartz_block_top quartz_block_side #double slabs
+44 SLABDATATRUNK stone_slab_top stone_slab_side sandstone_top sandstone_normal planks_oak planks_oak cobblestone cobblestone brick brick stonebrick stonebrick nether_brick nether_brick quartz_block_top quartz_block_side #slabs
+45 SOLID brick
+46 SOLID tnt_side tnt_side tnt_top #tnt
+47 SOLID bookshelf bookshelf planks_oak #bookshelf
+48 SOLID cobblestone_mossy
+49 SOLID obsidian
+50 TORCH torch_on
+51 SOLIDTRANSPARENT / fire_layer_0 fire_layer_0 fire_layer_0 fire_layer_0 / #fire
+52 SOLID mob_spawner
+53 STAIR planks_oak #oak wood stairs
+54 CHEST /normal /normal_double #chest
+55 WIRE redstone_dust_line redstone_dust_cross #redstone wire
+56 SOLID diamond_ore
+57 SOLID diamond_block
+58 SOLID crafting_table_front crafting_table_side crafting_table_top #workbench
+59 ITEMDATA wheat_stage_0 wheat_stage_1 wheat_stage_2 wheat_stage_3 wheat_stage_4 wheat_stage_5 wheat_stage_6 wheat_stage_7 #wheat
+60 SOLIDDATATRUNK farmland_dry dirt farmland_dry dirt farmland_dry dirt farmland_dry dirt farmland_wet dirt farmland_wet dirt farmland_wet dirt farmland_wet dirt #farmland
+61 SOLIDORIENTED 2 3 4 5 furnace_front_off furnace_side furnace_top #furnace
+62 SOLIDORIENTED 2 3 4 5 furnace_front_on furnace_side furnace_top #burning furnace
+63 SIGNPOST planks_oak planks_oak #sign post
+64 DOOR door_wood_lower door_wood_upper #wooden door
+65 ONWALLPARTIALFILL 3 2 5 4 ladder 0 0 0 0 #ladder
+66 RAIL rail_normal rail_normal_turned #rails
+67 STAIR cobblestone #cobblestone stairs
+68 ONWALLPARTIALFILL 3 2 5 4 planks_oak 4 4 0 0 #wall sign
+69 LEVER cobblestone lever
+70 SOLIDPARTIAL 14 0 stone stone stone #stone pressure plate
+71 DOOR door_iron_lower door_iron_upper #iron door
+72 SOLIDPARTIAL 14 0 planks_oak planks_oak planks_oak #wooden pressure plate
+73 SOLID redstone_ore
+74 SOLID redstone_ore #glowing
+75 TORCH redstone_torch_off
+76 TORCH redstone_torch_on
+77 ONWALLPARTIALFILL 3 4 1 2 stone 6 6 5 5 #stone button
+78 SOLIDDATAPARTIALFILL snow snow snow 14 0 12 0 10 0 8 0 6 0 4 0 2 0 0 0 #snow
+79 SOLIDOBSTRUCTED ice
+80 SOLID snow
+81 SOLID cactus_side cactus_side cactus_top #cactus
+82 SOLID clay
+83 ITEMDATA reeds #d'uh!
+84 SOLID jukebox_side jukebox_side jukebox_top #jukebox
+85 FENCE planks_oak #fence
+86 SOLIDORIENTED 2 0 1 3 pumpkin_face_off pumpkin_side pumpkin_top #pumpkin
+87 SOLID netherrack #netherrack
+88 SOLID soul_sand #soul sand
+89 SOLID glowstone #glowstone block
+90 SOLID portal #nether portal
+91 SOLIDORIENTED 2 0 1 3 pumpkin_face_on pumpkin_side pumpkin_top #jack 'o' lantern
+92 SOLIDPARTIAL 8 0 cake_side cake_side cake_top #cake
+93 REPEATER repeater_off redstone_torch_off #repeater inactive
+94 REPEATER repeater_on redstone_torch_on #repeater active
+95 SOLIDDATA glass_white glass_orange glass_magenta glass_light_blue glass_yellow glass_lime glass_pink glass_gray glass_silver glass_cyan glass_purple glass_blue glass_brown glass_green glass_red glass_black #stained glass
+96 TRAPDOOR trapdoor
+97 SOLIDDATA stone cobblestone stonebrick # smooth / cobblestone / stone brick monster egg
+98 SOLIDDATA stonebrick stonebrick_mossy stonebrick_cracked stonebrick_carved # normal / mossy / cracked / chiseled stone bricks
+99 MUSHROOM mushroom_block_inside mushroom_block_skin_stem mushroom_block_skin_brown #huge brown mushroom
+100 MUSHROOM mushroom_block_inside mushroom_block_skin_stem mushroom_block_skin_red #huge red mushroom
+101 PANEDATA iron_bars #iron bars
+102 PANEDATA glass #glass pane
+103 SOLID melon_side melon_side melon_top #melon
+104 STEM /pumpkin_stem_disconnected /pumpkin_stem_connected #pumpkin stem
+105 STEM /melon_stem_disconnected /melon_stem_connected #melon stem
+106 BITANCHOR vine #vines
+107 FENCEGATE planks_oak #fence gate
+108 STAIR brick #brick stairs
+109 STAIR stonebrick #stone brick stairs
+110 SOLID mycelium_side mycelium_side mycelium_top #mycelium
+111 SOLIDPARTIAL 16 0 / / waterlily #lily pad
+112 SOLID nether_brick
+113 FENCE nether_brick #nether brick fence
+114 STAIR nether_brick #nether brick stairs
+115 MULTIITEMDATA nether_wart_stage_0 nether_wart_stage_1 nether_wart_stage_1 nether_wart_stage_2 #nether wart
+116 SOLIDPARTIAL 4 0 enchanting_table_side enchanting_table_side enchanting_table_top #enchantment table
+117 SPECIAL brewing_stand_base brewing_stand #brewing stand
+118 SPECIAL cauldron_side water_still #cauldron
+119 SOLIDPARTIAL 4 0 / / end_portal #end portal
+120 SOLIDPARTIAL 3 0 endframe_side endframe_side endframe_top #end portal frame
+121 SOLID end_stone #endstone
+122 SPECIAL dragon_egg #dragon egg
+# 1.2
+123 SOLID redstone_lamp_off
+124 SOLID redstone_lamp_on
+# 1.3
+125 SOLIDDATA planks_oak planks_spruce planks_birch planks_jungle planks_acacia planks_big_oak #wooden double slabs
+126 SLABDATA planks_oak planks_spruce planks_birch planks_jungle planks_acacia planks_big_oak #wooden slabs
+127 ITEMDATAORIENTED 0 2 3 1 cocoa_stage_0 cocoa_stage_1 cocoa_stage_2 #cocoa pods
+128 STAIR sandstone_normal sandstone_top sandstone_bottom #sandstone stairs
+129 SOLID emerald_ore
+130 CHEST /ender #enderchest
+131 ONWALLPARTIALFILL 0 2 3 1 trip_wire_source 0 0 0 0 #tripwire hook
+132 WIRE trip_wire #tripwire
+133 SOLID emerald_block
+134 STAIR planks_spruce #spruce wood stairs
+135 STAIR planks_birch #birch wood stairs
+136 STAIR planks_jungle #jungle wood stairs
+# 1.4
+137 SOLIDROTATED 6 command_block_front command_block_side command_block_back #command block
+138 SPECIAL beacon obsidian 20 #beacon
+139 WALLDATA cobblestone cobblestone_mossy #cobblestone / mossy cobblestone wall
+140 SPECIAL flower_pot dirt flower_rose flower_dandelion sapling_oak sapling_spruce sapling_birch sapling_jungle mushroom_red mushroom_brown cactus_side deadbush fern wool_colored_white wool_colored_white wool_colored_white wool_colored_white wool_colored_white #flower pot
+141 MULTIITEMDATA carrots_stage_0 carrots_stage_0 carrots_stage_1 carrots_stage_1 carrots_stage_2 carrots_stage_2 carrots_stage_2 carrots_stage_3 #carrots
+142 MULTIITEMDATA potatoes_stage_0 potatoes_stage_0 potatoes_stage_1 potatoes_stage_1 potatoes_stage_2 potatoes_stage_2 potatoes_stage_2 potatoes_stage_3 #potatoes
+143 ONWALLPARTIALFILL 3 4 1 2 planks_oak 6 6 5 5 #wooden button
+##144 mob heads
+145 SPECIAL anvil_base anvil_top_damaged_0 anvil_top_damaged_1 anvil_top_damaged_2 #anvil
+# 1.5
+146 CHEST /trapped /trapped_double #trapped chest
+147 SOLIDPARTIAL 14 0 gold_block gold_block gold_block #weighted pressure plate (light)
+148 SOLIDPARTIAL 14 0 iron_block iron_block iron_block #weighted pressure plate (heavy)
+149 REPEATER comparator_off redstone_torch_off comparator_on redstone_torch_on #comparator
+##150 id is not used after 1.6
+151 SOLIDPARTIAL 10 0 daylight_detector_side daylight_detector_side daylight_detector_top #daylight sensor
+152 SOLID redstone_block
+153 SOLID quartz_ore
+154 SPECIAL hopper_outside hopper_inside hopper_top #hopper
+155 SOLIDDATATRUNKROTATED O 0 quartz_block_top quartz_block_side 0 quartz_block_chiseled_top quartz_block_chiseled 1 quartz_block_lines_top quartz_block_lines #block of quartz
+156 STAIR quartz_block_side quartz_block_top quartz_block_bottom #quartz stairs
+157 RAILPOWERED rail_activator rail_activator_powered #activator rail
+158 SOLIDORIENTED 2 3 4 5 dropper_front_horizontal furnace_side furnace_top #dropper
+# 1.6
+159 SOLIDDATA hardened_clay_stained_white hardened_clay_stained_orange hardened_clay_stained_magenta hardened_clay_stained_light_blue hardened_clay_stained_yellow hardened_clay_stained_lime hardened_clay_stained_pink hardened_clay_stained_gray hardened_clay_stained_silver hardened_clay_stained_cyan hardened_clay_stained_purple hardened_clay_stained_blue hardened_clay_stained_brown hardened_clay_stained_green hardened_clay_stained_red hardened_clay_stained_black #stained hardened clay
+160 PANEDATA glass_white glass_orange glass_magenta glass_light_blue glass_yellow glass_lime glass_pink glass_gray glass_silver glass_cyan glass_purple glass_blue glass_brown glass_green glass_red glass_black #stained glass pane
+161 SOLIDDATAFILL leaves_acacia leaves_big_oak # acacia / dark oak leaves
+162 SOLIDDATATRUNKROTATED S 1 log_acacia_top log_acacia 1 log_big_oak_top log_big_oak # acacia / dark oak wood
+163 STAIR planks_acacia planks_acacia #acacia wood stairs
+164 STAIR planks_big_oak planks_big_oak #dark oak wood stairs
+165 SOLID slime
+##166 barrier block
+167 TRAPDOOR iron_trapdoor
+168 SOLIDDATA prismarine_rough prismarine_bricks prismarine_dark # prismarine rough / bricks / dark
+169 SOLID sea_lantern # sea lantern
+170 SOLIDDATATRUNKROTATED S 1 hay_block_top hay_block_side #hay block
+171 SOLIDDATAPARTIAL 15 0 wool_colored_white wool_colored_orange wool_colored_magenta wool_colored_light_blue wool_colored_yellow wool_colored_lime wool_colored_pink wool_colored_gray wool_colored_silver wool_colored_cyan wool_colored_purple wool_colored_blue wool_colored_brown wool_colored_green wool_colored_red wool_colored_black #carpet
+172 SOLID hardened_clay
+173 SOLID coal_block
+# 1.7
+174 SOLID ice_packed #packed ice
+175 ITEMDATATALLORIENTED double_plant_sunflower_top double_plant_sunflower_bottom double_plant_syringa_top double_plant_syringa_bottom double_plant_grass_top double_plant_grass_bottom double_plant_fern_top double_plant_fern_bottom double_plant_rose_top double_plant_rose_bottom double_plant_paeonia_top double_plant_paeonia_bottom #double flowers (sunflower / lilac / d. tall grass / large fern / rose bush / peony)
+#176 #standing banner
+#177 #wall banner
+178 SOLIDPARTIAL 10 0 daylight_detector_side daylight_detector_side daylight_detector_inverted_top #inverted daylight detector
+179 SOLIDDATATRUNK red_sandstone_top red_sandstone_normal red_sandstone_top red_sandstone_carved red_sandstone_top red_sandstone_smooth #red sandstone
+180 STAIR red_sandstone_normal red_sandstone_top red_sandstone_bottom #red sandstone stair
+181 SOLIDDATATRUNK red_sandstone_top red_sandstone_normal #red sandstone double slab
+182 SLABDATATRUNK red_sandstone_top red_sandstone_normal #red sandstone slab
+183 FENCEGATE planks_spruce
+184 FENCEGATE planks_birch
+185 FENCEGATE planks_jungle
+186 FENCEGATE planks_big_oak
+187 FENCEGATE planks_acacia
+188 FENCE planks_spruce
+189 FENCE planks_birch
+190 FENCE planks_jungle
+191 FENCE planks_big_oak
+192 FENCE planks_acacia
+193 DOOR door_spruce_lower door_spruce_upper #spruce door
+194 DOOR door_birch_lower door_birch_upper #birch door
+195 DOOR door_jungle_lower door_jungle_upper #jungle door
+196 DOOR door_acacia_lower door_acacia_upper #acacia door
+197 DOOR door_dark_oak_lower door_dark_oak_upper #dark oak door
+# 1.9
+198 SPECIAL /end_rod_lamp /end_rod_base # end rod
+199 WALLDATA chorus_plant # chorus plant
+200 SOLIDDATA chorus_flower chorus_flower chorus_flower chorus_flower chorus_flower chorus_flower_dead # chorus flower
+201 SOLID purpur_block # purpur block
+202 SOLIDDATATRUNKROTATED S 1 purpur_pillar_top purpur_pillar # purpur pillar
+203 STAIR purpur_block # purpur stairs
+204 SOLID purpur_block # purpur double slab
+205 SLABDATA purpur_block # purpur slab
+206 SOLID end_bricks # end stone bricks
+207 MULTIITEMDATA beetroots_stage_0 beetroots_stage_1 beetroots_stage_2 beetroots_stage_3 #beetroot
+208 SOLIDPARTIAL 1 0 grass_path_side grass_path_side grass_path_top #grass path
+209 SOLID end_portal #end gateway
+210 SOLIDROTATED 6 repeating_command_block_front repeating_command_block_side repeating_command_block_back #repeating command block
+211 SOLIDROTATED 6 chain_command_block_front chain_command_block_side chain_command_block_back #chained command block
+212 SOLIDDATA frosted_ice_0 frosted_ice_1 frosted_ice_2 frosted_ice_3 #frosted ice
+# 1.10
+213 SOLID magma #magma block
+214 SOLID nether_wart_block #nether wart block
+215 SOLID red_nether_brick #red nether brick
+216 SOLIDDATATRUNKROTATED S 1 bone_block_top bone_block_side #bone block
+# 1.11
+218 SOLIDORIENTED 2 3 4 5 observer_front observer_side observer_top # observer
+219 SOLID shulker_top_white
+220 SOLID shulker_top_orange
+221 SOLID shulker_top_magenta
+222 SOLID shulker_top_light_blue
+223 SOLID shulker_top_yellow
+224 SOLID shulker_top_lime
+225 SOLID shulker_top_pink
+226 SOLID shulker_top_gray
+227 SOLID shulker_top_silver
+228 SOLID shulker_top_cyan
+229 SOLID shulker_top_purple
+230 SOLID shulker_top_blue
+231 SOLID shulker_top_brown
+232 SOLID shulker_top_green
+233 SOLID shulker_top_red
+234 SOLID shulker_top_black
+# 1.12
+251 SOLIDDATA concrete_white concrete_orange concrete_magenta concrete_light_blue concrete_yellow concrete_lime concrete_pink concrete_gray concrete_silver concrete_cyan concrete_purple concrete_blue concrete_brown concrete_green concrete_red concrete_black # concrete 0-16
+252 SOLIDDATA concrete_powder_white concrete_powder_orange concrete_powder_magenta concrete_powder_light_blue concrete_powder_yellow concrete_powder_lime concrete_powder_pink concrete_powder_gray concrete_powder_silver concrete_powder_cyan concrete_powder_purple concrete_powder_blue concrete_powder_brown concrete_powder_green concrete_powder_red concrete_powder_black # concrete powder 0-16
+235 SOLIDROTATED 4 glazed_terracotta_white
+236 SOLIDROTATED 4 glazed_terracotta_orange
+237 SOLIDROTATED 4 glazed_terracotta_magenta
+238 SOLIDROTATED 4 glazed_terracotta_light_blue
+239 SOLIDROTATED 4 glazed_terracotta_yellow
+240 SOLIDROTATED 4 glazed_terracotta_lime
+241 SOLIDROTATED 4 glazed_terracotta_pink
+242 SOLIDROTATED 4 glazed_terracotta_gray
+243 SOLIDROTATED 4 glazed_terracotta_silver
+244 SOLIDROTATED 4 glazed_terracotta_cyan
+245 SOLIDROTATED 4 glazed_terracotta_purple
+246 SOLIDROTATED 4 glazed_terracotta_blue
+247 SOLIDROTATED 4 glazed_terracotta_brown
+248 SOLIDROTATED 4 glazed_terracotta_green
+249 SOLIDROTATED 4 glazed_terracotta_red
+250 SOLIDROTATED 4 glazed_terracotta_black
diff --git a/blockimages.cpp b/blockimages.cpp
old mode 100755
new mode 100644
index d9697c1..4277907
--- a/blockimages.cpp
+++ b/blockimages.cpp
@@ -1,2785 +1,3449 @@
-// Copyright 2010-2012 Michael J. Nelson
-//
-// This file is part of pigmap.
-//
-// pigmap is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// pigmap is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with pigmap. If not, see .
-
-#include
-#include
-
-#include "blockimages.h"
-#include "utils.h"
-
-using namespace std;
-
-
-// in this file, confusingly, "tile" refers to the tiles of terrain.png, not to the map tiles
-//
-// also, this is a nasty mess in here; apologies to anyone reading this
-
-
-void writeBlockImagesVersion(int B, const string& imgpath, int32_t version)
-{
- string versionfile = imgpath + "/blocks-" + tostring(B) + ".version";
- ofstream outfile(versionfile.c_str());
- outfile << version;
-}
-
-// get the version number associated with blocks-B.png; this is stored
-// in blocks-B.version, which is just a single string with the version number
-int getBlockImagesVersion(int B, const string& imgpath)
-{
- string versionfile = imgpath + "/blocks-" + tostring(B) + ".version";
- ifstream infile(versionfile.c_str());
- // if there's no version file, assume the version is 157, which is how many
- // blocks there were at the first "release" (before the version file was in use)
- if (infile.fail())
- {
- infile.close();
- writeBlockImagesVersion(B, imgpath, 157);
- return 157;
- }
- // otherwise, read the version
- int32_t v;
- infile >> v;
- // if the version is clearly insane, ignore it
- if (v < 0 || v > 10000)
- v = 0;
- return v;
-}
-
-
-
-bool BlockImages::create(int B, const string& imgpath)
-{
- rectsize = 4*B;
- setOffsets();
-
- // first, see if blocks-B.png exists, and what its version is
- int biversion = getBlockImagesVersion(B, imgpath);
- string blocksfile = imgpath + "/blocks-" + tostring(B) + ".png";
- RGBAImage oldimg;
- bool preserveold = false;
- if (img.readPNG(blocksfile))
- {
- // if it's the correct size and version, we're okay
- int w = rectsize*16, h = (NUMBLOCKIMAGES/16 + 1) * rectsize;
- if (img.w == w && img.h == h && biversion == NUMBLOCKIMAGES)
- {
- retouchAlphas(B);
- checkOpacityAndTransparency(B);
- return true;
- }
- // if it's a previous version (and the correct size for that version), we'll
- // use terrain.png to build the new blocks, but preserve the existing ones
- if (biversion < NUMBLOCKIMAGES && img.w == w && img.h == (biversion/16 + 1) * rectsize)
- {
- oldimg = img;
- preserveold = true;
- cerr << blocksfile << " is missing some blocks; will try to fill them in from terrain.png" << endl;
- }
- // otherwise, the file's been trashed somehow; rebuild it
- else
- {
- cerr << blocksfile << " has incorrect size (expected " << w << "x" << h << endl;
- cerr << "...will try to create from terrain.png, but without overwriting " << blocksfile << endl;
- }
- }
- else
- cerr << blocksfile << " not found (or failed to read as PNG); will try to build from terrain.png" << endl;
-
- // build blocks-B.png from terrain.png and fire.png
- string terrainfile = imgpath + "/terrain.png";
- string firefile = imgpath + "/fire.png";
- string endportalfile = imgpath + "/endportal.png";
- string chestfile = imgpath + "/chest.png";
- string largechestfile = imgpath + "/largechest.png";
- string enderchestfile = imgpath + "/enderchest.png";
- if (!construct(B, terrainfile, firefile, endportalfile, chestfile, largechestfile, enderchestfile))
- {
- cerr << "image path is missing at least one of these required files:" << endl;
- cerr << "terrain.png, chest.png, largechest.png, enderchest.png -- from minecraft.jar or your tile pack" << endl;
- cerr << "fire.png, endportal.png -- included with pigmap" << endl;
- return false;
- }
-
- // if we need to preserve the old version's blocks, copy them over
- if (preserveold)
- {
- for (int i = 0; i < biversion; i++)
- {
- ImageRect rect = getRect(i);
- blit(oldimg, rect, img, rect.x, rect.y);
- }
- }
-
- // write blocks-B.png and blocks-B.version
- img.writePNG(blocksfile);
- writeBlockImagesVersion(B, imgpath, NUMBLOCKIMAGES);
-
- retouchAlphas(B);
- checkOpacityAndTransparency(B);
- return true;
-}
-
-
-
-
-// given terrain.png, resize it so every texture becomes 2Bx2B instead of 16x16 (or whatever the actual
-// texture size is)
-// ...so the resulting image will be a 16x16 array of 2Bx2B images
-RGBAImage getResizedTerrain(const RGBAImage& terrain, int terrainSize, int B)
-{
- int newsize = 2*B;
- RGBAImage img;
- img.create(16*newsize, 16*newsize);
- for (int y = 0; y < 16; y++)
- for (int x = 0; x < 16; x++)
- resize(terrain, ImageRect(x*terrainSize, y*terrainSize, terrainSize, terrainSize),
- img, ImageRect(x*newsize, y*newsize, newsize, newsize));
- return img;
-}
-
-// take the various textures from chest.png and use them to construct "flat" 14x14 tiles (or whatever
-// the multiplied size is, if the textures are larger), then resize those flat images to 2Bx2B
-// ...the resulting image will be a 3x1 array of 2Bx2B images: first the top, then the front, then
-// the side
-RGBAImage getResizedChest(const RGBAImage& chest, int scale, int B)
-{
- int chestSize = 14 * scale;
- RGBAImage chesttiles;
- chesttiles.create(chestSize*3, chestSize);
-
- // top texture just gets copied straight over
- blit(chest, ImageRect(14*scale, 0, 14*scale, 14*scale), chesttiles, 0, 0);
-
- // front tile gets the front lid texture plus the front bottom texture, then the latch on
- // top of that
- blit(chest, ImageRect(14*scale, 14*scale, 14*scale, 4*scale), chesttiles, chestSize, 0);
- blit(chest, ImageRect(14*scale, 33*scale, 14*scale, 10*scale), chesttiles, chestSize, 4*scale);
- blit(chest, ImageRect(scale, scale, 2*scale, 4*scale), chesttiles, chestSize + 6*scale, 2*scale);
-
- // side tile gets the side lid texture plus the side bottom texture
- blit(chest, ImageRect(28*scale, 14*scale, 14*scale, 4*scale), chesttiles, chestSize*2, 0);
- blit(chest, ImageRect(28*scale, 33*scale, 14*scale, 10*scale), chesttiles, chestSize*2, 4*scale);
-
- int newsize = 2*B;
- RGBAImage img;
- img.create(3*newsize, newsize);
- for (int x = 0; x < 3; x++)
- resize(chesttiles, ImageRect(x*chestSize, 0, chestSize, chestSize),
- img, ImageRect(x*newsize, 0, newsize, newsize));
- return img;
-}
-
-// same thing for largechest.png--construct flat tiles, then resize
-// ...resulting image is a 7x1 array of 2Bx2B images:
-// -left half of top
-// -right half of top
-// -left half of front
-// -right half of front
-// -left half of back
-// -right half of back
-// -side
-RGBAImage getResizedLargeChest(const RGBAImage& chest, int scale, int B)
-{
- int newsize = 2*B;
- RGBAImage img;
- img.create(7*newsize, newsize);
-
- // top texture gets copied straight over--note that the original texture is 30x14, but
- // we're putting it into two squares
- resize(chest, ImageRect(14*scale, 0, 30*scale, 14*scale), img, ImageRect(0, 0, newsize*2, newsize));
-
- // front tile gets the front lid texture plus the front bottom texture, then the latch
- // on top of that
- RGBAImage fronttiles;
- fronttiles.create(30*scale, 14*scale);
- blit(chest, ImageRect(14*scale, 14*scale, 30*scale, 4*scale), fronttiles, 0, 0);
- blit(chest, ImageRect(14*scale, 33*scale, 30*scale, 10*scale), fronttiles, 0, 4*scale);
- blit(chest, ImageRect(scale, scale, 2*scale, 4*scale), fronttiles, 14*scale, 2*scale);
- // do two resizes, to make sure the special end processing picks up the latch
- resize(fronttiles, ImageRect(0, 0, 15*scale, 14*scale), img, ImageRect(2*newsize, 0, newsize, newsize));
- resize(fronttiles, ImageRect(15*scale, 0, 15*scale, 14*scale), img, ImageRect(3*newsize, 0, newsize, newsize));
-
- // back tile gets the back lid texture plus the back bottom texture
- RGBAImage backtiles;
- backtiles.create(30*scale, 14*scale);
- blit(chest, ImageRect(58*scale, 14*scale, 30*scale, 4*scale), backtiles, 0, 0);
- blit(chest, ImageRect(58*scale, 33*scale, 30*scale, 10*scale), backtiles, 0, 4*scale);
- resize(backtiles, ImageRect(0, 0, 30*scale, 14*scale), img, ImageRect(4*newsize, 0, 2*newsize, newsize));
-
- // side tile gets the side lid texture plus the side bottom texture
- RGBAImage sidetile;
- sidetile.create(14*scale, 14*scale);
- blit(chest, ImageRect(44*scale, 14*scale, 14*scale, 4*scale), sidetile, 0, 0);
- blit(chest, ImageRect(44*scale, 33*scale, 14*scale, 10*scale), sidetile, 0, 4*scale);
- resize(sidetile, ImageRect(0, 0, 14*scale, 14*scale), img, ImageRect(6*newsize, 0, newsize, newsize));
-
- return img;
-}
-
-
-
-// iterate over the pixels of a 2B-sized terrain tile; used for both source rectangles and
-// destination parallelograms
-struct FaceIterator
-{
- bool end; // true if we're done
- int x, y; // current pixel
- int pos;
-
- int size; // number of columns to draw, as well as number of pixels in each
- int deltaY; // amount to skew y-coord every 2 columns: -1 or 1 for E/W or N/S facing destinations, 0 for source
-
- FaceIterator(int xstart, int ystart, int dY, int sz)
- {
- size = sz;
- deltaY = dY;
- end = false;
- x = xstart;
- y = ystart;
- pos = 0;
- }
-
- void advance()
- {
- pos++;
- if (pos >= size*size)
- {
- end = true;
- return;
- }
- y++;
- if (pos % size == 0)
- {
- x++;
- y -= size;
- if (pos % (2*size) == size)
- y += deltaY;
- }
- }
-};
-
-// like FaceIterator with no deltaY (for source rectangles), but with the source rotated and/or flipped
-struct RotatedFaceIterator
-{
- bool end;
- int x, y;
- int pos;
-
- int size;
- int rot; // 0 = down, then right; 1 = left, then down; 2 = up, then left; 3 = right, then up
- bool flipX;
- int dx1, dy1, dx2, dy2;
-
- RotatedFaceIterator(int xstart, int ystart, int r, int sz, bool fX)
- {
- size = sz;
- rot = r;
- flipX = fX;
- end = false;
- pos = 0;
- if (rot == 0)
- {
- x = flipX ? (xstart + size - 1) : xstart;
- y = ystart;
- dx1 = 0;
- dy1 = 1;
- dx2 = flipX ? -1 : 1;
- dy2 = 0;
- }
- else if (rot == 1)
- {
- x = flipX ? xstart : (xstart + size - 1);
- y = ystart;
- dx1 = flipX ? 1 : -1;
- dy1 = 0;
- dx2 = 0;
- dy2 = 1;
- }
- else if (rot == 2)
- {
- x = flipX ? xstart : (xstart + size - 1);
- y = ystart + size - 1;
- dx1 = 0;
- dy1 = -1;
- dx2 = flipX ? 1 : -1;
- dy2 = 0;
- }
- else
- {
- x = flipX ? (xstart + size - 1) : xstart;
- y = ystart + size - 1;
- dx1 = flipX ? -1 : 1;
- dy1 = 0;
- dx2 = 0;
- dy2 = -1;
- }
- }
-
- void advance()
- {
- pos++;
- if (pos >= size*size)
- {
- end = true;
- return;
- }
- x += dx1;
- y += dy1;
- if (pos % size == 0)
- {
- x += dx2;
- y += dy2;
- x -= dx1 * size;
- y -= dy1 * size;
- }
- }
-};
-
-// iterate over the pixels of the top face of a block
-struct TopFaceIterator
-{
- bool end; // true if we're done
- int x, y; // current pixel
- int pos;
-
- int size; // number of "columns", and number of pixels in each
-
- TopFaceIterator(int xstart, int ystart, int sz)
- {
- size = sz;
- end = false;
- x = xstart;
- y = ystart;
- pos = 0;
- }
-
- void advance()
- {
- if ((pos/size) % 2 == 0)
- {
- int m = pos % size;
- if (m == size - 1)
- {
- x += size - 1;
- y -= size/2;
- }
- else if (m == size - 2)
- y++;
- else if (m % 2 == 0)
- {
- x--;
- y++;
- }
- else
- x--;
- }
- else
- {
- int m = pos % size;
- if (m == 0)
- y++;
- else if (m == size - 1)
- {
- x += size - 1;
- y -= size/2 - 1;
- }
- else if (m % 2 == 0)
- {
- x--;
- y++;
- }
- else
- x--;
- }
- pos++;
- if (pos >= size*size)
- end = true;
- }
-};
-
-
-struct SourceTile
-{
- const RGBAImage *image; // or NULL for no tile
- int xpos, ypos; // tile offset within the image
- int rot;
- bool flipX;
-
- SourceTile(const RGBAImage *img, int x, int y, int r, bool f) : image(img), xpos(x), ypos(y), rot(r), flipX(f) {}
- SourceTile() : image(NULL), xpos(0), ypos(0), rot(0), flipX(false) {}
- bool valid() const {return image != NULL;}
-};
-
-// iterate over a square source tile, with possible rotation and flip
-struct SourceIterator
-{
- SourceIterator(const SourceTile& tile, int tilesize)
- : image(*(tile.image)), faceit(tile.xpos*tilesize, tile.ypos*tilesize, tile.rot, tilesize, tile.flipX) {}
-
- void advance() {faceit.advance();}
- bool end() {return faceit.end;}
- RGBAPixel pixel() {return image(faceit.x, faceit.y);}
-
- const RGBAImage& image;
- RotatedFaceIterator faceit;
-};
-
-// construct a source iterator for a given terrain.png tile with rotation and/or flip
-SourceTile terrainTile(const RGBAImage& tiles, int tile, int rot, bool flipX)
-{
- if (tile < 0)
- return SourceTile();
- return SourceTile(&tiles, tile%16, tile/16, rot, flipX);
-}
-
-// construct a source iterator for a terrain.png tile with no rotation/flip
-SourceTile terrainTile(const RGBAImage& tiles, int tile)
-{
- return terrainTile(tiles, tile, 0, false);
-}
-
-
-
-// draw a normal block image, using three terrain tiles (which may be flipped/rotated/missing), and adding a bit of shadow
-// to the N and W faces
-void drawRotatedBlockImage(RGBAImage& dest, const ImageRect& drect, const SourceTile& Nface, const SourceTile& Wface, const SourceTile& Uface, int B)
-{
- int tilesize = 2*B;
- // N face starts at [0,B]
- if (Nface.valid())
- {
- FaceIterator dstit(drect.x, drect.y + B, 1, tilesize);
- for (SourceIterator srcit(Nface, tilesize); !srcit.end(); srcit.advance(), dstit.advance())
- {
- dest(dstit.x, dstit.y) = srcit.pixel();
- darken(dest(dstit.x, dstit.y), 0.9, 0.9, 0.9);
- }
- }
- // W face starts at [2B,2B]
- if (Wface.valid())
- {
- FaceIterator dstit(drect.x + 2*B, drect.y + 2*B, -1, tilesize);
- for (SourceIterator srcit(Wface, tilesize); !srcit.end(); srcit.advance(), dstit.advance())
- {
- dest(dstit.x, dstit.y) = srcit.pixel();
- darken(dest(dstit.x, dstit.y), 0.8, 0.8, 0.8);
- }
- }
- // U face starts at [2B-1,0]
- if (Uface.valid())
- {
- TopFaceIterator dstit(drect.x + 2*B-1, drect.y, tilesize);
- for (SourceIterator srcit(Uface, tilesize); !srcit.end(); srcit.advance(), dstit.advance())
- {
- dest(dstit.x, dstit.y) = srcit.pixel();
- }
- }
-}
-
-// overload of drawRotatedBlockImage taking three terrain.png tiles
-void drawRotatedBlockImage(RGBAImage& dest, const ImageRect& drect, const RGBAImage& tiles, int Nface, int Wface, int Uface, int rotN, bool flipN, int rotW, bool flipW, int rotU, bool flipU, int B)
-{
- drawRotatedBlockImage(dest, drect, terrainTile(tiles, Nface, rotN, flipN), terrainTile(tiles, Wface, rotW, flipW), terrainTile(tiles, Uface, rotU, flipU), B);
-}
-
-void drawBlockImage(RGBAImage& dest, const ImageRect& drect, const RGBAImage& tiles, int Nface, int Wface, int Uface, int B)
-{
- drawRotatedBlockImage(dest, drect, terrainTile(tiles, Nface), terrainTile(tiles, Wface), terrainTile(tiles, Uface), B);
-}
-
-// draw a block image where the block isn't full height (half-steps, snow, etc.)
-// topcutoff is the number of pixels (out of 2B) to chop off the top of the N and W faces
-// bottomcutoff is the number of pixels (out of 2B) to chop off the bottom
-// if shift is true, we start copying pixels from the very top of the source tile, even if there's a topcutoff
-// U face can also be rotated, and N/W faces can be X-flipped (set 0x1 for N, 0x2 for W)
-void drawPartialBlockImage(RGBAImage& dest, const ImageRect& drect, const RGBAImage& tiles, int Nface, int Wface, int Uface, int B, int topcutoff, int bottomcutoff, int rot, int flip, bool shift)
-{
- int tilesize = 2*B;
- if (topcutoff + bottomcutoff >= tilesize)
- return;
- int end = tilesize - bottomcutoff;
- // N face starts at [0,B]
- if (Nface != -1)
- {
- FaceIterator dstit(drect.x, drect.y + B, 1, tilesize);
- for (RotatedFaceIterator srcit((Nface%16)*tilesize, (Nface/16)*tilesize, 0, tilesize, flip & 0x1); !srcit.end; srcit.advance(), dstit.advance())
- {
- if (dstit.pos % tilesize >= topcutoff && dstit.pos % tilesize < end)
- {
- dest(dstit.x, dstit.y) = tiles(srcit.x, srcit.y - (shift ? topcutoff : 0));
- darken(dest(dstit.x, dstit.y), 0.9, 0.9, 0.9);
- }
- }
- }
- // W face starts at [2B,2B]
- if (Wface != -1)
- {
- FaceIterator dstit(drect.x + 2*B, drect.y + 2*B, -1, tilesize);
- for (RotatedFaceIterator srcit((Wface%16)*tilesize, (Wface/16)*tilesize, 0, tilesize, flip & 0x2); !srcit.end; srcit.advance(), dstit.advance())
- {
- if (dstit.pos % tilesize >= topcutoff && dstit.pos % tilesize < end)
- {
- dest(dstit.x, dstit.y) = tiles(srcit.x, srcit.y - (shift ? topcutoff : 0));
- darken(dest(dstit.x, dstit.y), 0.8, 0.8, 0.8);
- }
- }
- }
- // U face starts at [2B-1,topcutoff]
- if (Uface != -1)
- {
- TopFaceIterator dstit(drect.x + 2*B-1, drect.y + topcutoff, tilesize);
- for (RotatedFaceIterator srcit((Uface%16)*tilesize, (Uface/16)*tilesize, rot, tilesize, false); !srcit.end; srcit.advance(), dstit.advance())
- {
- dest(dstit.x, dstit.y) = tiles(srcit.x, srcit.y);
- }
- }
-}
-
-// draw two flat copies of a tile intersecting at the block center (saplings, etc.)
-void drawItemBlockImage(RGBAImage& dest, const ImageRect& drect, const SourceTile& tile, int B, bool N, bool S, bool E, bool W)
-{
- if (!tile.valid())
- return;
- int tilesize = 2*B;
- int cutoff = tilesize/2;
- // E/W face starting at [B,1.5B] -- southern half only
- if (S)
- {
- FaceIterator dstit(drect.x + B, drect.y + B*3/2, -1, tilesize);
- for (SourceIterator srcit(tile, tilesize); !srcit.end(); srcit.advance(), dstit.advance())
- {
- if (dstit.pos / tilesize >= cutoff)
- blend(dest(dstit.x, dstit.y), srcit.pixel());
- }
- }
- // N/S face starting at [B,0.5B]
- if (E || W)
- {
- FaceIterator dstit(drect.x + B, drect.y + B/2, 1, tilesize);
- for (SourceIterator srcit(tile, tilesize); !srcit.end(); srcit.advance(), dstit.advance())
- {
- if ((W && dstit.pos / tilesize >= cutoff) || (E && dstit.pos / tilesize < cutoff))
- blend(dest(dstit.x, dstit.y), srcit.pixel());
- }
- }
- // E/W face starting at [B,1.5B] -- northern half only
- if (N)
- {
- FaceIterator dstit(drect.x + B, drect.y + B*3/2, -1, tilesize);
- for (SourceIterator srcit(tile, tilesize); !srcit.end(); srcit.advance(), dstit.advance())
- {
- if (dstit.pos / tilesize < cutoff)
- blend(dest(dstit.x, dstit.y), srcit.pixel());
- }
- }
-}
-
-void drawItemBlockImage(RGBAImage& dest, const ImageRect& drect, const RGBAImage& tiles, int tile, int B)
-{
- drawItemBlockImage(dest, drect, terrainTile(tiles, tile), B, true, true, true, true);
-}
-
-
-// draw an item block image possibly missing some edges (iron bars, etc.)
-void drawPartialItemBlockImage(RGBAImage& dest, const ImageRect& drect, const RGBAImage& tiles, int tile, int rot, bool flipX, int B, bool N, bool S, bool E, bool W)
-{
- drawItemBlockImage(dest, drect, terrainTile(tiles, tile, rot, flipX), B, N, S, E, W);
-}
-
-// draw four flat copies of a tile intersecting in a square (netherwart, etc.)
-void drawMultiItemBlockImage(RGBAImage& dest, const ImageRect& drect, const SourceTile& tile, int B)
-{
- if (!tile.valid())
- return;
- int tilesize = 2*B;
- // E/W face starting at [0.5B,1.25B]
- {
- FaceIterator dstit(drect.x + B/2, drect.y + B*5/4, -1, tilesize);
- for (SourceIterator srcit(tile, tilesize); !srcit.end(); srcit.advance(), dstit.advance())
- {
- blend(dest(dstit.x, dstit.y), srcit.pixel());
- }
- }
- // E/W face starting at [1.5B,1.75B]
- {
- FaceIterator dstit(drect.x + 3*B/2, drect.y + B*7/4, -1, tilesize);
- for (SourceIterator srcit(tile, tilesize); !srcit.end(); srcit.advance(), dstit.advance())
- {
- blend(dest(dstit.x, dstit.y), srcit.pixel());
- }
- }
- // N/S face starting at [0.5B,0.75B]
- {
- FaceIterator dstit(drect.x + B/2, drect.y + B*3/4, 1, tilesize);
- for (SourceIterator srcit(tile, tilesize); !srcit.end(); srcit.advance(), dstit.advance())
- {
- blend(dest(dstit.x, dstit.y), srcit.pixel());
- }
- }
- // N/S face starting at [1.5B,0.25B]
- {
- FaceIterator dstit(drect.x + 3*B/2, drect.y + B/4, 1, tilesize);
- for (SourceIterator srcit(tile, tilesize); !srcit.end(); srcit.advance(), dstit.advance())
- {
- blend(dest(dstit.x, dstit.y), srcit.pixel());
- }
- }
-}
-
-void drawMultiItemBlockImage(RGBAImage& dest, const ImageRect& drect, const RGBAImage& tiles, int tile, int B)
-{
- drawMultiItemBlockImage(dest, drect, terrainTile(tiles, tile), B);
-}
-
-// draw a tile on a single upright face
-// 0 = S, 1 = N, 2 = W, 3 = E
-// ...handles transparency
-void drawSingleFaceBlockImage(RGBAImage& dest, const ImageRect& drect, const SourceTile& tile, int face, int B)
-{
- if (!tile.valid())
- return;
- int tilesize = 2*B;
- int xoff, yoff, deltaY;
- if (face == 0)
- {
- xoff = 2*B;
- yoff = 0;
- deltaY = 1;
- }
- else if (face == 1)
- {
- xoff = 0;
- yoff = B;
- deltaY = 1;
- }
- else if (face == 2)
- {
- xoff = 2*B;
- yoff = 2*B;
- deltaY = -1;
- }
- else
- {
- xoff = 0;
- yoff = B;
- deltaY = -1;
- }
- FaceIterator dstit(drect.x + xoff, drect.y + yoff, deltaY, tilesize);
- for (SourceIterator srcit(tile, tilesize); !srcit.end(); srcit.advance(), dstit.advance())
- {
- blend(dest(dstit.x, dstit.y), srcit.pixel());
- }
-}
-
-void drawSingleFaceBlockImage(RGBAImage& dest, const ImageRect& drect, const RGBAImage& tiles, int tile, int face, int B)
-{
- drawSingleFaceBlockImage(dest, drect, terrainTile(tiles, tile), face, B);
-}
-
-// draw part of a tile on a single upright face
-// 0 = S, 1 = N, 2 = W, 3 = E
-// ...handles transparency
-void drawPartialSingleFaceBlockImage(RGBAImage& dest, const ImageRect& drect, const SourceTile& tile, int face, int B, double fstartv, double fendv, double fstarth, double fendh)
-{
- int tilesize = 2*B;
- int vstartcutoff = max(0, min(tilesize, (int)(fstartv * tilesize)));
- int vendcutoff = max(0, min(tilesize, (int)(fendv * tilesize)));
- int hstartcutoff = max(0, min(tilesize, (int)(fstarth * tilesize)));
- int hendcutoff = max(0, min(tilesize, (int)(fendh * tilesize)));
- int xoff, yoff, deltaY;
- if (face == 0)
- {
- xoff = 2*B;
- yoff = 0;
- deltaY = 1;
- }
- else if (face == 1)
- {
- xoff = 0;
- yoff = B;
- deltaY = 1;
- }
- else if (face == 2)
- {
- xoff = 2*B;
- yoff = 2*B;
- deltaY = -1;
- }
- else
- {
- xoff = 0;
- yoff = B;
- deltaY = -1;
- }
- FaceIterator dstit(drect.x + xoff, drect.y + yoff, deltaY, tilesize);
- for (SourceIterator srcit(tile, tilesize); !srcit.end(); srcit.advance(), dstit.advance())
- {
- if (dstit.pos % tilesize >= vstartcutoff && dstit.pos % tilesize < vendcutoff &&
- dstit.pos / tilesize >= hstartcutoff && dstit.pos / tilesize < hendcutoff)
- blend(dest(dstit.x, dstit.y), srcit.pixel());
- }
-}
-
-void drawPartialSingleFaceBlockImage(RGBAImage& dest, const ImageRect& drect, const RGBAImage& tiles, int tile, int face, int B, double fstartv, double fendv, double fstarth, double fendh)
-{
- drawPartialSingleFaceBlockImage(dest, drect, terrainTile(tiles, tile), face, B, fstartv, fendv, fstarth, fendh);
-}
-
-// draw a single tile on the floor, possibly with rotation
-// 0 = top of tile is on S side; 1 = W, 2 = N, 3 = E
-void drawFloorBlockImage(RGBAImage& dest, const ImageRect& drect, const SourceTile& tile, int B)
-{
- int tilesize = 2*B;
- TopFaceIterator dstit(drect.x + 2*B-1, drect.y + 2*B, tilesize);
- for (SourceIterator srcit(tile, tilesize); !srcit.end(); srcit.advance(), dstit.advance())
- {
- dest(dstit.x, dstit.y) = srcit.pixel();
- }
-}
-
-void drawFloorBlockImage(RGBAImage& dest, const ImageRect& drect, const RGBAImage& tiles, int tile, int rot, int B)
-{
- drawFloorBlockImage(dest, drect, terrainTile(tiles, tile, rot, false), B);
-}
-
-// draw part of a single tile on the floor
-void drawPartialFloorBlockImage(RGBAImage& dest, const ImageRect& drect, const SourceTile& tile, int B, double fstartv, double fendv, double fstarth, double fendh)
-{
- int tilesize = 2*B;
- int vstartcutoff = max(0, min(tilesize, (int)(fstartv * tilesize)));
- int vendcutoff = max(0, min(tilesize, (int)(fendv * tilesize)));
- int hstartcutoff = max(0, min(tilesize, (int)(fstarth * tilesize)));
- int hendcutoff = max(0, min(tilesize, (int)(fendh * tilesize)));
- TopFaceIterator dstit(drect.x + 2*B-1, drect.y + 2*B, tilesize);
- for (SourceIterator srcit(tile, tilesize); !srcit.end(); srcit.advance(), dstit.advance())
- {
- if (dstit.pos % tilesize >= vstartcutoff && dstit.pos % tilesize < vendcutoff &&
- dstit.pos / tilesize >= hstartcutoff && dstit.pos / tilesize < hendcutoff)
- dest(dstit.x, dstit.y) = srcit.pixel();
- }
-}
-
-void drawPartialFloorBlockImage(RGBAImage& dest, const ImageRect& drect, const RGBAImage& tiles, int tile, int B, double fstartv, double fendv, double fstarth, double fendh)
-{
- drawPartialFloorBlockImage(dest, drect, terrainTile(tiles, tile), B, fstartv, fendv, fstarth, fendh);
-}
-
-// draw a single tile on the floor, possibly with rotation, angled upwards
-// rot: 0 = top of tile is on S side; 1 = W, 2 = N, 3 = E
-// up: 0 = S side of tile is highest; 1 = W, 2 = N, 3 = E
-void drawAngledFloorBlockImage(RGBAImage& dest, const ImageRect& drect, const SourceTile& tile, int up, int B)
-{
- int tilesize = 2*B;
- TopFaceIterator dstit(drect.x + 2*B-1, drect.y + 2*B, tilesize);
- for (SourceIterator srcit(tile, tilesize); !srcit.end(); srcit.advance(), dstit.advance())
- {
- int yoff = 0;
- int row = dstit.pos % tilesize, col = dstit.pos / tilesize;
- if (up == 0)
- yoff = tilesize - 1 - row;
- else if (up == 1)
- yoff = col;
- else if (up == 2)
- yoff = row;
- else if (up == 3)
- yoff = tilesize - 1 - col;
- blend(dest(dstit.x, dstit.y - yoff), srcit.pixel());
- blend(dest(dstit.x, dstit.y - yoff + 1), srcit.pixel());
- }
-}
-
-void drawAngledFloorBlockImage(RGBAImage& dest, const ImageRect& drect, const RGBAImage& tiles, int tile, int rot, int up, int B)
-{
- drawAngledFloorBlockImage(dest, drect, terrainTile(tiles, tile, rot, false), up, B);
-}
-
-// draw a single tile on the ceiling, possibly with rotation
-// 0 = top of tile is on S side; 1 = W, 2 = N, 3 = E
-void drawCeilBlockImage(RGBAImage& dest, const ImageRect& drect, const RGBAImage& tiles, int tile, int rot, int B)
-{
- int tilesize = 2*B;
- TopFaceIterator dstit(drect.x + 2*B-1, drect.y, tilesize);
- for (RotatedFaceIterator srcit((tile%16)*tilesize, (tile/16)*tilesize, rot, tilesize, false); !srcit.end; srcit.advance(), dstit.advance())
- {
- dest(dstit.x, dstit.y) = tiles(srcit.x, srcit.y);
- }
-}
-
-// draw a block image that's just a single color (plus shadows)
-void drawSolidColorBlockImage(RGBAImage& dest, const ImageRect& drect, RGBAPixel p, int B)
-{
- int tilesize = 2*B;
- // N face starts at [0,B]
- for (FaceIterator dstit(drect.x, drect.y + B, 1, tilesize); !dstit.end; dstit.advance())
- {
- dest(dstit.x, dstit.y) = p;
- darken(dest(dstit.x, dstit.y), 0.9, 0.9, 0.9);
- }
- // W face starts at [2B,2B]
- for (FaceIterator dstit(drect.x + 2*B, drect.y + 2*B, -1, tilesize); !dstit.end; dstit.advance())
- {
- dest(dstit.x, dstit.y) = p;
- darken(dest(dstit.x, dstit.y), 0.8, 0.8, 0.8);
- }
- // U face starts at [2B-1,0]
- for (TopFaceIterator dstit(drect.x + 2*B-1, drect.y, tilesize); !dstit.end; dstit.advance())
- {
- dest(dstit.x, dstit.y) = p;
- }
-}
-
-// draw S-ascending stairs
-void drawStairsS(RGBAImage& dest, const ImageRect& drect, const RGBAImage& tiles, int tileNW, int tileU, int B)
-{
- int tilesize = 2*B;
- // normal N face starts at [0,B]; draw the bottom half of it
- for (FaceIterator srcit((tileNW%16)*tilesize, (tileNW/16)*tilesize, 0, tilesize),
- dstit(drect.x, drect.y + B, 1, tilesize); !srcit.end; srcit.advance(), dstit.advance())
- {
- if (dstit.pos % tilesize >= B)
- {
- dest(dstit.x, dstit.y) = tiles(srcit.x, srcit.y);
- darken(dest(dstit.x, dstit.y), 0.9, 0.9, 0.9);
- }
- }
- // normal W face starts at [2B,2B]; draw all but the upper-left quarter of it
- for (FaceIterator srcit((tileNW%16)*tilesize, (tileNW/16)*tilesize, 0, tilesize),
- dstit(drect.x + 2*B, drect.y + 2*B, -1, tilesize); !srcit.end; srcit.advance(), dstit.advance())
- {
- if (dstit.pos % tilesize >= B || dstit.pos / tilesize >= B)
- {
- dest(dstit.x, dstit.y) = tiles(srcit.x, srcit.y);
- darken(dest(dstit.x, dstit.y), 0.8, 0.8, 0.8);
- }
- }
- // normal U face starts at [2B-1,0]; draw the top half of it
- TopFaceIterator tdstit(drect.x + 2*B-1, drect.y, tilesize);
- for (FaceIterator srcit((tileU%16)*tilesize, (tileU/16)*tilesize, 0, tilesize); !srcit.end; srcit.advance(), tdstit.advance())
- {
- // if B is odd, we need B pixels from each column, but if it's even, we need to alternate between
- // B-1 and B+1
- int cutoff = B;
- if (B % 2 == 0)
- cutoff += ((tdstit.pos / tilesize) % 2 == 0) ? -1 : 1;
- if (tdstit.pos % tilesize < cutoff)
- {
- dest(tdstit.x, tdstit.y) = tiles(srcit.x, srcit.y);
- }
- }
- // draw the top half of another N face at [B,B/2]
- for (FaceIterator srcit((tileNW%16)*tilesize, (tileNW/16)*tilesize, 0, tilesize),
- dstit(drect.x + B, drect.y + B/2, 1, tilesize); !srcit.end; srcit.advance(), dstit.advance())
- {
- // ...but if B is odd, we need to add an extra [0,1] to the even-numbered columns
- int adjust = 0;
- if (B % 2 == 1 && (dstit.pos / tilesize) % 2 == 0)
- adjust = 1;
- if (dstit.pos % tilesize < B)
- {
- dest(dstit.x, dstit.y + adjust) = tiles(srcit.x, srcit.y);
- darken(dest(dstit.x, dstit.y + adjust), 0.9, 0.9, 0.9);
- }
- }
- // draw the bottom half of another U face at [2B-1,B]
- tdstit = TopFaceIterator(drect.x + 2*B-1, drect.y + B, tilesize);
- for (FaceIterator srcit((tileU%16)*tilesize, (tileU/16)*tilesize, 0, tilesize); !srcit.end; srcit.advance(), tdstit.advance())
- {
- // again, if B is odd, take B pixels from each column; if even, take B-1 or B+1
- int cutoff = B;
- if (B % 2 == 0)
- cutoff += ((tdstit.pos / tilesize) % 2 == 0) ? -1 : 1;
- if (tdstit.pos % tilesize >= cutoff)
- {
- dest(tdstit.x, tdstit.y) = tiles(srcit.x, srcit.y);
- }
- }
-}
-
-// draw S-ascending stairs inverted
-void drawInvStairsS(RGBAImage& dest, const ImageRect& drect, const RGBAImage& tiles, int tileNW, int tileU, int B)
-{
- int tilesize = 2*B;
- // draw the bottom half of a N face at [B,B/2]; do this first because the others will partially cover it
- for (FaceIterator srcit((tileNW%16)*tilesize, (tileNW/16)*tilesize, 0, tilesize),
- dstit(drect.x + B, drect.y + B/2, 1, tilesize); !srcit.end; srcit.advance(), dstit.advance())
- {
- // ...but if B is odd, we need to add an extra [0,1] to the even-numbered columns
- int adjust = 0;
- if (B % 2 == 1 && (dstit.pos / tilesize) % 2 == 0)
- adjust = 1;
- if (dstit.pos % tilesize >= B)
- {
- dest(dstit.x, dstit.y + adjust) = tiles(srcit.x, srcit.y);
- darken(dest(dstit.x, dstit.y + adjust), 0.9, 0.9, 0.9);
- }
- }
- // normal N face starts at [0,B]; draw the top half of it
- for (FaceIterator srcit((tileNW%16)*tilesize, (tileNW/16)*tilesize, 0, tilesize),
- dstit(drect.x, drect.y + B, 1, tilesize); !srcit.end; srcit.advance(), dstit.advance())
- {
- if (dstit.pos % tilesize < B)
- {
- dest(dstit.x, dstit.y) = tiles(srcit.x, srcit.y);
- darken(dest(dstit.x, dstit.y), 0.9, 0.9, 0.9);
- }
- }
- // normal W face starts at [2B,2B]; draw all but the lower-left quarter of it
- for (FaceIterator srcit((tileNW%16)*tilesize, (tileNW/16)*tilesize, 0, tilesize),
- dstit(drect.x + 2*B, drect.y + 2*B, -1, tilesize); !srcit.end; srcit.advance(), dstit.advance())
- {
- if (dstit.pos % tilesize < B || dstit.pos / tilesize >= B)
- {
- dest(dstit.x, dstit.y) = tiles(srcit.x, srcit.y);
- darken(dest(dstit.x, dstit.y), 0.8, 0.8, 0.8);
- }
- }
- // normal U face starts at [2B-1,0]; draw the whole thing
- TopFaceIterator tdstit(drect.x + 2*B-1, drect.y, tilesize);
- for (FaceIterator srcit((tileU%16)*tilesize, (tileU/16)*tilesize, 0, tilesize); !srcit.end; srcit.advance(), tdstit.advance())
- {
- dest(tdstit.x, tdstit.y) = tiles(srcit.x, srcit.y);
- }
-}
-
-// draw N-ascending stairs
-void drawStairsN(RGBAImage& dest, const ImageRect& drect, const RGBAImage& tiles, int tileNW, int tileU, int B)
-{
- int tilesize = 2*B;
- // draw the top half of an an U face at [2B-1,B]
- TopFaceIterator tdstit(drect.x + 2*B-1, drect.y + B, tilesize);
- for (FaceIterator srcit((tileU%16)*tilesize, (tileU/16)*tilesize, 0, tilesize); !srcit.end; srcit.advance(), tdstit.advance())
- {
- // if B is odd, we need B pixels from each column, but if it's even, we need to alternate between
- // B-1 and B+1
- int cutoff = B;
- if (B % 2 == 0)
- cutoff += ((tdstit.pos / tilesize) % 2 == 0) ? -1 : 1;
- if (tdstit.pos % tilesize < cutoff)
- {
- dest(tdstit.x, tdstit.y) = tiles(srcit.x, srcit.y);
- }
- }
- // draw the bottom half of the normal U face at [2B-1,0]
- tdstit = TopFaceIterator(drect.x + 2*B-1, drect.y, tilesize);
- for (FaceIterator srcit((tileU%16)*tilesize, (tileU/16)*tilesize, 0, tilesize); !srcit.end; srcit.advance(), tdstit.advance())
- {
- // again, if B is odd, take B pixels from each column; if even, take B-1 or B+1
- int cutoff = B;
- if (B % 2 == 0)
- cutoff += ((tdstit.pos / tilesize) % 2 == 0) ? -1 : 1;
- if (tdstit.pos % tilesize >= cutoff)
- {
- dest(tdstit.x, tdstit.y) = tiles(srcit.x, srcit.y);
- }
- }
- // normal N face starts at [0,B]; draw it all
- for (FaceIterator srcit((tileNW%16)*tilesize, (tileNW/16)*tilesize, 0, tilesize),
- dstit(drect.x, drect.y + B, 1, tilesize); !srcit.end; srcit.advance(), dstit.advance())
- {
- dest(dstit.x, dstit.y) = tiles(srcit.x, srcit.y);
- darken(dest(dstit.x, dstit.y), 0.9, 0.9, 0.9);
- }
- // normal W face starts at [2B,2B]; draw all but the upper-right quarter of it
- for (FaceIterator srcit((tileNW%16)*tilesize, (tileNW/16)*tilesize, 0, tilesize),
- dstit(drect.x + 2*B, drect.y + 2*B, -1, tilesize); !srcit.end; srcit.advance(), dstit.advance())
- {
- if (dstit.pos % tilesize >= B || dstit.pos / tilesize < B)
- {
- dest(dstit.x, dstit.y) = tiles(srcit.x, srcit.y);
- darken(dest(dstit.x, dstit.y), 0.8, 0.8, 0.8);
- }
- }
-}
-
-// draw N-ascending stairs inverted
-void drawInvStairsN(RGBAImage& dest, const ImageRect& drect, const RGBAImage& tiles, int tileNW, int tileU, int B)
-{
- int tilesize = 2*B;
- // normal U face starts at [2B-1,0]; draw the whole thing
- TopFaceIterator tdstit(drect.x + 2*B-1, drect.y, tilesize);
- for (FaceIterator srcit((tileU%16)*tilesize, (tileU/16)*tilesize, 0, tilesize); !srcit.end; srcit.advance(), tdstit.advance())
- {
- dest(tdstit.x, tdstit.y) = tiles(srcit.x, srcit.y);
- }
- // normal N face starts at [0,B]; draw it all
- for (FaceIterator srcit((tileNW%16)*tilesize, (tileNW/16)*tilesize, 0, tilesize),
- dstit(drect.x, drect.y + B, 1, tilesize); !srcit.end; srcit.advance(), dstit.advance())
- {
- dest(dstit.x, dstit.y) = tiles(srcit.x, srcit.y);
- darken(dest(dstit.x, dstit.y), 0.9, 0.9, 0.9);
- }
- // normal W face starts at [2B,2B]; draw all but the lower-right quarter of it
- for (FaceIterator srcit((tileNW%16)*tilesize, (tileNW/16)*tilesize, 0, tilesize),
- dstit(drect.x + 2*B, drect.y + 2*B, -1, tilesize); !srcit.end; srcit.advance(), dstit.advance())
- {
- if (dstit.pos % tilesize < B || dstit.pos / tilesize < B)
- {
- dest(dstit.x, dstit.y) = tiles(srcit.x, srcit.y);
- darken(dest(dstit.x, dstit.y), 0.8, 0.8, 0.8);
- }
- }
-}
-
-// draw E-ascending stairs
-void drawStairsE(RGBAImage& dest, const ImageRect& drect, const RGBAImage& tiles, int tileNW, int tileU, int B)
-{
- int tilesize = 2*B;
- // normal N face starts at [0,B]; draw all but the upper-right quarter of it
- for (FaceIterator srcit((tileNW%16)*tilesize, (tileNW/16)*tilesize, 0, tilesize),
- dstit(drect.x, drect.y + B, 1, tilesize); !srcit.end; srcit.advance(), dstit.advance())
- {
- if (dstit.pos % tilesize >= B || dstit.pos / tilesize < B)
- {
- dest(dstit.x, dstit.y) = tiles(srcit.x, srcit.y);
- darken(dest(dstit.x, dstit.y), 0.9, 0.9, 0.9);
- }
- }
- // normal W face starts at [2B,2B]; draw the bottom half of it
- for (FaceIterator srcit((tileNW%16)*tilesize, (tileNW/16)*tilesize, 0, tilesize),
- dstit(drect.x + 2*B, drect.y + 2*B, -1, tilesize); !srcit.end; srcit.advance(), dstit.advance())
- {
- if (dstit.pos % tilesize >= B)
- {
- dest(dstit.x, dstit.y) = tiles(srcit.x, srcit.y);
- darken(dest(dstit.x, dstit.y), 0.8, 0.8, 0.8);
- }
- }
- // normal U face starts at [2B-1,0]; draw the left half of it
- TopFaceIterator tdstit(drect.x + 2*B-1, drect.y, tilesize);
- int tcutoff = tilesize * B;
- bool textra = false;
- // if B is odd, we need to skip the last pixel of the last left-half column, and add the very first
- // pixel of the first right-half column
- if (B % 2 == 1)
- {
- tcutoff--;
- textra = true;
- }
- for (FaceIterator srcit((tileU%16)*tilesize, (tileU/16)*tilesize, 0, tilesize); !srcit.end; srcit.advance(), tdstit.advance())
- {
- if (tdstit.pos < tcutoff || (textra && tdstit.pos == tcutoff + 1))
- {
- dest(tdstit.x, tdstit.y) = tiles(srcit.x, srcit.y);
- }
- }
- // draw the top half of another W face at [B,1.5B]
- for (FaceIterator srcit((tileNW%16)*tilesize, (tileNW/16)*tilesize, 0, tilesize),
- dstit(drect.x + B, drect.y + 3*B/2, -1, tilesize); !srcit.end; srcit.advance(), dstit.advance())
- {
- // ...but if B is odd, we need to add an extra [0,1] to the odd-numbered columns
- int adjust = 0;
- if (B % 2 == 1 && (dstit.pos / tilesize) % 2 == 1)
- adjust = 1;
- if (dstit.pos % tilesize < B)
- {
- dest(dstit.x, dstit.y + adjust) = tiles(srcit.x, srcit.y);
- darken(dest(dstit.x, dstit.y + adjust), 0.8, 0.8, 0.8);
- }
- }
- // draw the right half of another U face at [2B-1,B]
- tdstit = TopFaceIterator(drect.x + 2*B-1, drect.y + B, tilesize);
- tcutoff = tilesize * B;
- textra = false;
- // if B is odd, do the reverse of what we did with the top half
- if (B % 2 == 1)
- {
- tcutoff++;
- textra = true;
- }
- for (FaceIterator srcit((tileU%16)*tilesize, (tileU/16)*tilesize, 0, tilesize); !srcit.end; srcit.advance(), tdstit.advance())
- {
- if (tdstit.pos >= tcutoff || (textra && tdstit.pos == tcutoff - 2))
- {
- dest(tdstit.x, tdstit.y) = tiles(srcit.x, srcit.y);
- }
- }
-}
-
-// draw E-ascending stairs inverted
-void drawInvStairsE(RGBAImage& dest, const ImageRect& drect, const RGBAImage& tiles, int tileNW, int tileU, int B)
-{
- int tilesize = 2*B;
- // draw the bottom half of a W face at [B,1.5B]; do this first because the others will partially cover it
- for (FaceIterator srcit((tileNW%16)*tilesize, (tileNW/16)*tilesize, 0, tilesize),
- dstit(drect.x + B, drect.y + 3*B/2, -1, tilesize); !srcit.end; srcit.advance(), dstit.advance())
- {
- // ...but if B is odd, we need to add an extra [0,1] to the odd-numbered columns
- int adjust = 0;
- if (B % 2 == 1 && (dstit.pos / tilesize) % 2 == 1)
- adjust = 1;
- if (dstit.pos % tilesize >= B)
- {
- dest(dstit.x, dstit.y + adjust) = tiles(srcit.x, srcit.y);
- darken(dest(dstit.x, dstit.y + adjust), 0.8, 0.8, 0.8);
- }
- }
- // normal W face starts at [2B,2B]; draw the top half of it
- for (FaceIterator srcit((tileNW%16)*tilesize, (tileNW/16)*tilesize, 0, tilesize),
- dstit(drect.x + 2*B, drect.y + 2*B, -1, tilesize); !srcit.end; srcit.advance(), dstit.advance())
- {
- if (dstit.pos % tilesize < B)
- {
- dest(dstit.x, dstit.y) = tiles(srcit.x, srcit.y);
- darken(dest(dstit.x, dstit.y), 0.8, 0.8, 0.8);
- }
- }
- // normal N face starts at [0,B]; draw all but the lower-right quarter of it
- for (FaceIterator srcit((tileNW%16)*tilesize, (tileNW/16)*tilesize, 0, tilesize),
- dstit(drect.x, drect.y + B, 1, tilesize); !srcit.end; srcit.advance(), dstit.advance())
- {
- if (dstit.pos % tilesize < B || dstit.pos / tilesize < B)
- {
- dest(dstit.x, dstit.y) = tiles(srcit.x, srcit.y);
- darken(dest(dstit.x, dstit.y), 0.9, 0.9, 0.9);
- }
- }
- // normal U face starts at [2B-1,0]; draw the whole thing
- TopFaceIterator tdstit(drect.x + 2*B-1, drect.y, tilesize);
- for (FaceIterator srcit((tileU%16)*tilesize, (tileU/16)*tilesize, 0, tilesize); !srcit.end; srcit.advance(), tdstit.advance())
- {
- dest(tdstit.x, tdstit.y) = tiles(srcit.x, srcit.y);
- }
-}
-
-// draw W-ascending stairs
-void drawStairsW(RGBAImage& dest, const ImageRect& drect, const RGBAImage& tiles, int tileNW, int tileU, int B)
-{
- int tilesize = 2*B;
- // draw the left half of an U face at [2B-1,B]
- TopFaceIterator tdstit(drect.x + 2*B-1, drect.y + B, tilesize);
- int tcutoff = tilesize * B;
- bool textra = false;
- // if B is odd, we need to skip the last pixel of the last left-half column, and add the very first
- // pixel of the first right-half column
- if (B % 2 == 1)
- {
- tcutoff--;
- textra = true;
- }
- for (FaceIterator srcit((tileU%16)*tilesize, (tileU/16)*tilesize, 0, tilesize); !srcit.end; srcit.advance(), tdstit.advance())
- {
- if (tdstit.pos < tcutoff || (textra && tdstit.pos == tcutoff + 1))
- {
- dest(tdstit.x, tdstit.y) = tiles(srcit.x, srcit.y);
- }
- }
- // draw the right half of the normal U face at [2B-1,0]
- tdstit = TopFaceIterator(drect.x + 2*B-1, drect.y, tilesize);
- tcutoff = tilesize * B;
- textra = false;
- // if B is odd, do the reverse of what we did with the top half
- if (B % 2 == 1)
- {
- tcutoff++;
- textra = true;
- }
- for (FaceIterator srcit((tileU%16)*tilesize, (tileU/16)*tilesize, 0, tilesize); !srcit.end; srcit.advance(), tdstit.advance())
- {
- if (tdstit.pos >= tcutoff || (textra && tdstit.pos == tcutoff - 2))
- {
- dest(tdstit.x, tdstit.y) = tiles(srcit.x, srcit.y);
- }
- }
- // normal N face starts at [0,B]; draw all but the upper-left quarter of it
- for (FaceIterator srcit((tileNW%16)*tilesize, (tileNW/16)*tilesize, 0, tilesize),
- dstit(drect.x, drect.y + B, 1, tilesize); !srcit.end; srcit.advance(), dstit.advance())
- {
- if (dstit.pos % tilesize >= B || dstit.pos / tilesize >= B)
- {
- dest(dstit.x, dstit.y) = tiles(srcit.x, srcit.y);
- darken(dest(dstit.x, dstit.y), 0.9, 0.9, 0.9);
- }
- }
- // normal W face starts at [2B,2B]; draw the whole thing
- for (FaceIterator srcit((tileNW%16)*tilesize, (tileNW/16)*tilesize, 0, tilesize),
- dstit(drect.x + 2*B, drect.y + 2*B, -1, tilesize); !srcit.end; srcit.advance(), dstit.advance())
- {
- dest(dstit.x, dstit.y) = tiles(srcit.x, srcit.y);
- darken(dest(dstit.x, dstit.y), 0.8, 0.8, 0.8);
- }
-}
-
-// draw W-ascending stairs inverted
-void drawInvStairsW(RGBAImage& dest, const ImageRect& drect, const RGBAImage& tiles, int tileNW, int tileU, int B)
-{
- int tilesize = 2*B;
- // normal U face starts at [2B-1,0]; draw the whole thing
- TopFaceIterator tdstit(drect.x + 2*B-1, drect.y, tilesize);
- for (FaceIterator srcit((tileU%16)*tilesize, (tileU/16)*tilesize, 0, tilesize); !srcit.end; srcit.advance(), tdstit.advance())
- {
- dest(tdstit.x, tdstit.y) = tiles(srcit.x, srcit.y);
- }
- // normal W face starts at [2B,2B]; draw the whole thing
- for (FaceIterator srcit((tileNW%16)*tilesize, (tileNW/16)*tilesize, 0, tilesize),
- dstit(drect.x + 2*B, drect.y + 2*B, -1, tilesize); !srcit.end; srcit.advance(), dstit.advance())
- {
- dest(dstit.x, dstit.y) = tiles(srcit.x, srcit.y);
- darken(dest(dstit.x, dstit.y), 0.8, 0.8, 0.8);
- }
- // normal N face starts at [0,B]; draw all but the lower-left quarter of it
- for (FaceIterator srcit((tileNW%16)*tilesize, (tileNW/16)*tilesize, 0, tilesize),
- dstit(drect.x, drect.y + B, 1, tilesize); !srcit.end; srcit.advance(), dstit.advance())
- {
- if (dstit.pos % tilesize < B || dstit.pos / tilesize >= B)
- {
- dest(dstit.x, dstit.y) = tiles(srcit.x, srcit.y);
- darken(dest(dstit.x, dstit.y), 0.9, 0.9, 0.9);
- }
- }
-}
-
-// draw crappy fence post
-void drawFencePost(RGBAImage& dest, const ImageRect& drect, const RGBAImage& tiles, int tile, int B)
-{
- int tilesize = 2*B;
- int tilex = (tile%16)*tilesize, tiley = (tile/16)*tilesize;
-
- // draw a 2x2 top at [2B-1,B-1]
- for (int y = 0; y < 2; y++)
- for (int x = 0; x < 2; x++)
- dest(drect.x + 2*B - 1 + x, drect.y + B - 1 + y) = tiles(tilex + x, tiley + y);
-
- // draw a 1x2B side at [2B-1,B+1]
- for (int y = 0; y < 2*B; y++)
- dest(drect.x + 2*B - 1, drect.y + B + 1 + y) = tiles(tilex, tiley + y);
-
- // draw a 1x2B side at [2B,B+1]
- for (int y = 0; y < 2*B; y++)
- dest(drect.x + 2*B, drect.y + B + 1 + y) = tiles(tilex, tiley + y);
-}
-
-// draw fence: post and four rails, each optional
-void drawFence(RGBAImage& dest, const ImageRect& drect, const RGBAImage& tiles, int tile, bool N, bool S, bool E, bool W, bool post, int B)
-{
- // first, E and S rails, since the post should be in front of them
- int tilesize = 2*B;
- if (E)
- {
- // N/S face starting at [B,0.5B]; left half, one strip
- for (FaceIterator srcit((tile%16)*tilesize, (tile/16)*tilesize, 0, tilesize),
- dstit(drect.x + B, drect.y + B/2, 1, tilesize); !srcit.end; srcit.advance(), dstit.advance())
- {
- if (dstit.pos / tilesize < B && (((dstit.pos % tilesize) * 2 / B) % 4) == 1)
- dest(dstit.x, dstit.y) = tiles(srcit.x, srcit.y);
- }
- }
- if (S)
- {
- // E/W face starting at [B,1.5B]; right half, one strip
- for (FaceIterator srcit((tile%16)*tilesize, (tile/16)*tilesize, 0, tilesize),
- dstit(drect.x + B, drect.y + B*3/2, -1, tilesize); !srcit.end; srcit.advance(), dstit.advance())
- {
- if (dstit.pos / tilesize >= B && (((dstit.pos % tilesize) * 2 / B) % 4) == 1)
- dest(dstit.x, dstit.y) = tiles(srcit.x, srcit.y);
- }
- }
-
- // now the post
- if (post)
- drawFencePost(dest, drect, tiles, tile, B);
-
- // now the N and W rails
- if (W)
- {
- // N/S face starting at [B,0.5B]; right half, one strip
- for (FaceIterator srcit((tile%16)*tilesize, (tile/16)*tilesize, 0, tilesize),
- dstit(drect.x + B, drect.y + B/2, 1, tilesize); !srcit.end; srcit.advance(), dstit.advance())
- {
- if (dstit.pos / tilesize >= B && (((dstit.pos % tilesize) * 2 / B) % 4) == 1)
- dest(dstit.x, dstit.y) = tiles(srcit.x, srcit.y);
- }
- }
- if (N)
- {
- // E/W face starting at [B,1.5B]; left half, one strip
- for (FaceIterator srcit((tile%16)*tilesize, (tile/16)*tilesize, 0, tilesize),
- dstit(drect.x + B, drect.y + B*3/2, -1, tilesize); !srcit.end; srcit.advance(), dstit.advance())
- {
- if (dstit.pos / tilesize < B && (((dstit.pos % tilesize) * 2 / B) % 4) == 1)
- dest(dstit.x, dstit.y) = tiles(srcit.x, srcit.y);
- }
- }
-}
-
-// draw crappy sign facing out towards the viewer
-void drawSign(RGBAImage& dest, const ImageRect& drect, const RGBAImage& tiles, int tile, int B)
-{
- // start with fence post
- drawFencePost(dest, drect, tiles, tile, B);
-
- int tilesize = 2*B;
- // draw the top half of a tile at [B,B]
- for (FaceIterator srcit((tile%16)*tilesize, (tile/16)*tilesize, 0, tilesize),
- dstit(drect.x + B, drect.y + B, 0, tilesize); !srcit.end; srcit.advance(), dstit.advance())
- {
- if (dstit.pos % tilesize < B)
- dest(dstit.x, dstit.y) = tiles(srcit.x, srcit.y);
- }
-}
-
-// draw crappy wall lever
-void drawWallLever(RGBAImage& dest, const ImageRect& drect, const RGBAImage& tiles, int face, int B)
-{
- drawPartialSingleFaceBlockImage(dest, drect, tiles, 16, face, B, 0.5, 1, 0.35, 0.65);
- drawSingleFaceBlockImage(dest, drect, tiles, 96, face, B);
-}
-
-void drawFloorLeverNS(RGBAImage& dest, const ImageRect& drect, const RGBAImage& tiles, int B)
-{
- drawPartialFloorBlockImage(dest, drect, tiles, 16, B, 0.25, 0.75, 0.35, 0.65);
- drawItemBlockImage(dest, drect, tiles, 96, B);
-}
-
-void drawFloorLeverEW(RGBAImage& dest, const ImageRect& drect, const RGBAImage& tiles, int B)
-{
- drawPartialFloorBlockImage(dest, drect, tiles, 16, B, 0.35, 0.65, 0.25, 0.75);
- drawItemBlockImage(dest, drect, tiles, 96, B);
-}
-
-void drawRepeater(RGBAImage& dest, const ImageRect& drect, const RGBAImage& tiles, int tile, int rot, int B)
-{
- drawFloorBlockImage(dest, drect, tiles, tile, rot, B);
- drawItemBlockImage(dest, drect, tiles, 99, B);
-}
-
-void drawFire(RGBAImage& dest, const ImageRect& drect, const RGBAImage& firetile, int B)
-{
- drawSingleFaceBlockImage(dest, drect, firetile, 0, 0, B);
- drawSingleFaceBlockImage(dest, drect, firetile, 0, 3, B);
- drawSingleFaceBlockImage(dest, drect, firetile, 0, 1, B);
- drawSingleFaceBlockImage(dest, drect, firetile, 0, 2, B);
-}
-
-// draw crappy brewing stand: full base tile plus item-shaped stand
-void drawBrewingStand(RGBAImage& dest, const ImageRect& drect, const RGBAImage& tiles, int base, int stand, int B)
-{
- drawFloorBlockImage(dest, drect, tiles, base, 0, B);
- drawItemBlockImage(dest, drect, tiles, stand, B);
-}
-
-void drawCauldron(RGBAImage& dest, const ImageRect& drect, const RGBAImage& tiles, int side, int liquid, int cutoff, int B)
-{
- // start with E/S sides, since liquid goes in front of them
- drawSingleFaceBlockImage(dest, drect, tiles, side, 0, B);
- drawSingleFaceBlockImage(dest, drect, tiles, side, 3, B);
-
- // draw the liquid
- if (liquid != -1)
- drawPartialBlockImage(dest, drect, tiles, -1, -1, liquid, B, cutoff, 0, 0, 0, true);
-
- // now the N/W sides
- drawSingleFaceBlockImage(dest, drect, tiles, side, 1, B);
- drawSingleFaceBlockImage(dest, drect, tiles, side, 2, B);
-}
-
-void drawVines(RGBAImage& dest, const ImageRect& drect, const RGBAImage& tiles, int tile, int B, bool N, bool S, bool E, bool W, bool top)
-{
- if (S)
- drawSingleFaceBlockImage(dest, drect, tiles, tile, 0, B);
- if (E)
- drawSingleFaceBlockImage(dest, drect, tiles, tile, 3, B);
- if (N)
- drawSingleFaceBlockImage(dest, drect, tiles, tile, 1, B);
- if (W)
- drawSingleFaceBlockImage(dest, drect, tiles, tile, 2, B);
- if (top)
- drawCeilBlockImage(dest, drect, tiles, tile, 0, B);
-}
-
-// draw crappy dragon egg--just a half-size block
-void drawDragonEgg(RGBAImage& dest, const ImageRect& drect, const RGBAImage& tiles, int tile, int B)
-{
- int tilesize = 2*B;
- // N face at [0,0.5B]; draw the bottom-right quarter of it
- for (FaceIterator srcit((tile%16)*tilesize, (tile/16)*tilesize, 0, tilesize),
- dstit(drect.x, drect.y + B/2, 1, tilesize); !srcit.end; srcit.advance(), dstit.advance())
- {
- if (dstit.pos % tilesize >= B && dstit.pos / tilesize >= B)
- {
- dest(dstit.x, dstit.y) = tiles(srcit.x, srcit.y);
- darken(dest(dstit.x, dstit.y), 0.9, 0.9, 0.9);
- }
- }
- // W face at [2B,1.5B]; draw the bottom-left quarter of it
- for (FaceIterator srcit((tile%16)*tilesize, (tile/16)*tilesize, 0, tilesize),
- dstit(drect.x + 2*B, drect.y + 3*B/2, -1, tilesize); !srcit.end; srcit.advance(), dstit.advance())
- {
- if (dstit.pos % tilesize >= B && dstit.pos / tilesize < B)
- {
- dest(dstit.x, dstit.y) = tiles(srcit.x, srcit.y);
- darken(dest(dstit.x, dstit.y), 0.8, 0.8, 0.8);
- }
- }
- // draw the bottom-right quarter of a U face at [2B-1,0.5B]
- TopFaceIterator tdstit(drect.x + 2*B-1, drect.y + B/2, tilesize);
- for (FaceIterator srcit((tile%16)*tilesize, (tile/16)*tilesize, 0, tilesize); !srcit.end; srcit.advance(), tdstit.advance())
- {
- // again, if B is odd, take B pixels from each column; if even, take B-1 or B+1
- int cutoff = B;
- if (B % 2 == 0)
- cutoff += ((tdstit.pos / tilesize) % 2 == 0) ? -1 : 1;
- if (tdstit.pos % tilesize >= cutoff && tdstit.pos / tilesize >= cutoff)
- {
- dest(tdstit.x, tdstit.y) = tiles(srcit.x, srcit.y);
- }
- }
-}
-
-
-
-
-int offsetIdx(uint16_t blockID, uint8_t blockData)
-{
- return blockID * 16 + blockData;
-}
-
-void setOffsetsForID(uint16_t blockID, int offset, BlockImages& bi)
-{
- int start = blockID * 16;
- int end = start + 16;
- fill(bi.blockOffsets + start, bi.blockOffsets + end, offset);
-}
-
-void BlockImages::setOffsets()
-{
- // default is the dummy image
- fill(blockOffsets, blockOffsets + 4096*16, 0);
-
- //!!!!!! might want to use darker redstone wire for lower strength, just for some visual variety?
-
- setOffsetsForID(1, 1, *this);
- setOffsetsForID(2, 2, *this);
- setOffsetsForID(3, 3, *this);
- setOffsetsForID(4, 4, *this);
- setOffsetsForID(5, 5, *this);
- blockOffsets[offsetIdx(5, 1)] = 435;
- blockOffsets[offsetIdx(5, 2)] = 436;
- blockOffsets[offsetIdx(5, 3)] = 437;
- setOffsetsForID(6, 6, *this);
- blockOffsets[offsetIdx(6, 1)] = 250;
- blockOffsets[offsetIdx(6, 5)] = 250;
- blockOffsets[offsetIdx(6, 9)] = 250;
- blockOffsets[offsetIdx(6, 13)] = 250;
- blockOffsets[offsetIdx(6, 2)] = 251;
- blockOffsets[offsetIdx(6, 6)] = 251;
- blockOffsets[offsetIdx(6, 10)] = 251;
- blockOffsets[offsetIdx(6, 14)] = 251;
- blockOffsets[offsetIdx(6, 3)] = 429;
- blockOffsets[offsetIdx(6, 7)] = 429;
- blockOffsets[offsetIdx(6, 11)] = 429;
- blockOffsets[offsetIdx(6, 15)] = 429;
- setOffsetsForID(7, 7, *this);
- setOffsetsForID(8, 8, *this);
- blockOffsets[offsetIdx(8, 1)] = 9;
- blockOffsets[offsetIdx(8, 2)] = 10;
- blockOffsets[offsetIdx(8, 3)] = 11;
- blockOffsets[offsetIdx(8, 4)] = 12;
- blockOffsets[offsetIdx(8, 5)] = 13;
- blockOffsets[offsetIdx(8, 6)] = 14;
- blockOffsets[offsetIdx(8, 7)] = 15;
- setOffsetsForID(9, 8, *this);
- blockOffsets[offsetIdx(9, 1)] = 9;
- blockOffsets[offsetIdx(9, 2)] = 10;
- blockOffsets[offsetIdx(9, 3)] = 11;
- blockOffsets[offsetIdx(9, 4)] = 12;
- blockOffsets[offsetIdx(9, 5)] = 13;
- blockOffsets[offsetIdx(9, 6)] = 14;
- blockOffsets[offsetIdx(9, 7)] = 15;
- setOffsetsForID(10, 16, *this);
- blockOffsets[offsetIdx(10, 6)] = 19;
- blockOffsets[offsetIdx(10, 4)] = 18;
- blockOffsets[offsetIdx(10, 2)] = 17;
- setOffsetsForID(11, 16, *this);
- blockOffsets[offsetIdx(11, 6)] = 19;
- blockOffsets[offsetIdx(11, 4)] = 18;
- blockOffsets[offsetIdx(11, 2)] = 17;
- setOffsetsForID(12, 20, *this);
- setOffsetsForID(13, 483, *this);
- setOffsetsForID(14, 22, *this);
- setOffsetsForID(15, 23, *this);
- setOffsetsForID(16, 24, *this);
- setOffsetsForID(17, 25, *this);
- blockOffsets[offsetIdx(17, 1)] = 219;
- blockOffsets[offsetIdx(17, 2)] = 220;
- blockOffsets[offsetIdx(17, 3)] = 427;
- blockOffsets[offsetIdx(17, 4)] = 532;
- blockOffsets[offsetIdx(17, 5)] = 534;
- blockOffsets[offsetIdx(17, 6)] = 536;
- blockOffsets[offsetIdx(17, 7)] = 538;
- blockOffsets[offsetIdx(17, 8)] = 531;
- blockOffsets[offsetIdx(17, 9)] = 533;
- blockOffsets[offsetIdx(17, 10)] = 535;
- blockOffsets[offsetIdx(17, 11)] = 537;
- setOffsetsForID(18, 26, *this);
- blockOffsets[offsetIdx(18, 1)] = 248;
- blockOffsets[offsetIdx(18, 5)] = 248;
- blockOffsets[offsetIdx(18, 9)] = 248;
- blockOffsets[offsetIdx(18, 13)] = 248;
- blockOffsets[offsetIdx(18, 2)] = 249;
- blockOffsets[offsetIdx(18, 6)] = 249;
- blockOffsets[offsetIdx(18, 10)] = 249;
- blockOffsets[offsetIdx(18, 14)] = 249;
- blockOffsets[offsetIdx(18, 3)] = 428;
- blockOffsets[offsetIdx(18, 7)] = 428;
- blockOffsets[offsetIdx(18, 11)] = 428;
- blockOffsets[offsetIdx(18, 15)] = 428;
- setOffsetsForID(19, 27, *this);
- setOffsetsForID(20, 28, *this);
- setOffsetsForID(21, 221, *this);
- setOffsetsForID(22, 222, *this);
- setOffsetsForID(23, 223, *this);
- blockOffsets[offsetIdx(23, 2)] = 225;
- blockOffsets[offsetIdx(23, 4)] = 224;
- blockOffsets[offsetIdx(23, 5)] = 225;
- setOffsetsForID(24, 226, *this);
- blockOffsets[offsetIdx(24, 1)] = 431;
- blockOffsets[offsetIdx(24, 2)] = 432;
- setOffsetsForID(25, 227, *this);
- setOffsetsForID(26, 285, *this);
- blockOffsets[offsetIdx(26, 1)] = 286;
- blockOffsets[offsetIdx(26, 5)] = 286;
- blockOffsets[offsetIdx(26, 2)] = 287;
- blockOffsets[offsetIdx(26, 6)] = 287;
- blockOffsets[offsetIdx(26, 3)] = 288;
- blockOffsets[offsetIdx(26, 7)] = 288;
- blockOffsets[offsetIdx(26, 8)] = 281;
- blockOffsets[offsetIdx(26, 12)] = 281;
- blockOffsets[offsetIdx(26, 9)] = 282;
- blockOffsets[offsetIdx(26, 13)] = 282;
- blockOffsets[offsetIdx(26, 10)] = 283;
- blockOffsets[offsetIdx(26, 14)] = 283;
- blockOffsets[offsetIdx(26, 11)] = 284;
- blockOffsets[offsetIdx(26, 15)] = 284;
- setOffsetsForID(27, 258, *this);
- blockOffsets[offsetIdx(27, 1)] = 259;
- blockOffsets[offsetIdx(27, 2)] = 260;
- blockOffsets[offsetIdx(27, 3)] = 261;
- blockOffsets[offsetIdx(27, 4)] = 262;
- blockOffsets[offsetIdx(27, 5)] = 263;
- blockOffsets[offsetIdx(27, 8)] = 252;
- blockOffsets[offsetIdx(27, 9)] = 253;
- blockOffsets[offsetIdx(27, 10)] = 254;
- blockOffsets[offsetIdx(27, 11)] = 255;
- blockOffsets[offsetIdx(27, 12)] = 256;
- blockOffsets[offsetIdx(27, 13)] = 257;
- setOffsetsForID(28, 264, *this);
- blockOffsets[offsetIdx(28, 1)] = 265;
- blockOffsets[offsetIdx(28, 2)] = 266;
- blockOffsets[offsetIdx(28, 3)] = 267;
- blockOffsets[offsetIdx(28, 4)] = 268;
- blockOffsets[offsetIdx(28, 5)] = 269;
- setOffsetsForID(29, 413, *this);
- blockOffsets[offsetIdx(29, 1)] = 414;
- blockOffsets[offsetIdx(29, 9)] = 414;
- blockOffsets[offsetIdx(29, 4)] = 415;
- blockOffsets[offsetIdx(29, 12)] = 415;
- blockOffsets[offsetIdx(29, 5)] = 416;
- blockOffsets[offsetIdx(29, 13)] = 416;
- blockOffsets[offsetIdx(29, 3)] = 417;
- blockOffsets[offsetIdx(29, 11)] = 417;
- blockOffsets[offsetIdx(29, 2)] = 418;
- blockOffsets[offsetIdx(29, 10)] = 418;
- setOffsetsForID(30, 272, *this);
- setOffsetsForID(31, 273, *this);
- blockOffsets[offsetIdx(31, 0)] = 275;
- blockOffsets[offsetIdx(31, 2)] = 274;
- setOffsetsForID(32, 275, *this);
- setOffsetsForID(33, 407, *this);
- blockOffsets[offsetIdx(33, 1)] = 408;
- blockOffsets[offsetIdx(33, 9)] = 408;
- blockOffsets[offsetIdx(33, 4)] = 409;
- blockOffsets[offsetIdx(33, 12)] = 409;
- blockOffsets[offsetIdx(33, 5)] = 410;
- blockOffsets[offsetIdx(33, 13)] = 410;
- blockOffsets[offsetIdx(33, 3)] = 411;
- blockOffsets[offsetIdx(33, 11)] = 411;
- blockOffsets[offsetIdx(33, 2)] = 412;
- blockOffsets[offsetIdx(33, 10)] = 412;
- blockOffsets[offsetIdx(35, 0)] = 29;
- blockOffsets[offsetIdx(35, 1)] = 204;
- blockOffsets[offsetIdx(35, 2)] = 205;
- blockOffsets[offsetIdx(35, 3)] = 206;
- blockOffsets[offsetIdx(35, 4)] = 207;
- blockOffsets[offsetIdx(35, 5)] = 208;
- blockOffsets[offsetIdx(35, 6)] = 209;
- blockOffsets[offsetIdx(35, 7)] = 210;
- blockOffsets[offsetIdx(35, 8)] = 211;
- blockOffsets[offsetIdx(35, 9)] = 212;
- blockOffsets[offsetIdx(35, 10)] = 213;
- blockOffsets[offsetIdx(35, 11)] = 214;
- blockOffsets[offsetIdx(35, 12)] = 215;
- blockOffsets[offsetIdx(35, 13)] = 216;
- blockOffsets[offsetIdx(35, 14)] = 217;
- blockOffsets[offsetIdx(35, 15)] = 218;
- setOffsetsForID(37, 30, *this);
- setOffsetsForID(38, 31, *this);
- setOffsetsForID(39, 32, *this);
- setOffsetsForID(40, 33, *this);
- setOffsetsForID(41, 34, *this);
- setOffsetsForID(42, 35, *this);
- setOffsetsForID(43, 36, *this);
- blockOffsets[offsetIdx(43, 1)] = 226;
- blockOffsets[offsetIdx(43, 2)] = 5;
- blockOffsets[offsetIdx(43, 3)] = 4;
- blockOffsets[offsetIdx(43, 4)] = 38;
- blockOffsets[offsetIdx(43, 5)] = 294;
- setOffsetsForID(44, 37, *this);
- blockOffsets[offsetIdx(44, 1)] = 229;
- blockOffsets[offsetIdx(44, 2)] = 230;
- blockOffsets[offsetIdx(44, 3)] = 231;
- blockOffsets[offsetIdx(44, 4)] = 302;
- blockOffsets[offsetIdx(44, 5)] = 303;
- blockOffsets[offsetIdx(44, 8)] = 458;
- blockOffsets[offsetIdx(44, 9)] = 459;
- blockOffsets[offsetIdx(44, 10)] = 460;
- blockOffsets[offsetIdx(44, 11)] = 461;
- blockOffsets[offsetIdx(44, 12)] = 462;
- blockOffsets[offsetIdx(44, 13)] = 463;
- setOffsetsForID(45, 38, *this);
- setOffsetsForID(46, 39, *this);
- setOffsetsForID(47, 40, *this);
- setOffsetsForID(48, 41, *this);
- setOffsetsForID(49, 42, *this);
- setOffsetsForID(50, 43, *this);
- blockOffsets[offsetIdx(50, 1)] = 44;
- blockOffsets[offsetIdx(50, 2)] = 45;
- blockOffsets[offsetIdx(50, 3)] = 46;
- blockOffsets[offsetIdx(50, 4)] = 47;
- setOffsetsForID(51, 189, *this);
- setOffsetsForID(52, 49, *this);
- setOffsetsForID(53, 50, *this);
- blockOffsets[offsetIdx(53, 1)] = 51;
- blockOffsets[offsetIdx(53, 2)] = 52;
- blockOffsets[offsetIdx(53, 3)] = 53;
- blockOffsets[offsetIdx(53, 4)] = 438;
- blockOffsets[offsetIdx(53, 5)] = 439;
- blockOffsets[offsetIdx(53, 6)] = 440;
- blockOffsets[offsetIdx(53, 7)] = 441;
- setOffsetsForID(54, 484, *this);
- blockOffsets[offsetIdx(54, 4)] = 485;
- blockOffsets[offsetIdx(54, 2)] = 486;
- blockOffsets[offsetIdx(54, 5)] = 486;
- setOffsetsForID(55, 55, *this);
- setOffsetsForID(56, 56, *this);
- setOffsetsForID(57, 57, *this);
- setOffsetsForID(58, 58, *this);
- setOffsetsForID(59, 59, *this);
- blockOffsets[offsetIdx(59, 6)] = 60;
- blockOffsets[offsetIdx(59, 5)] = 61;
- blockOffsets[offsetIdx(59, 4)] = 62;
- blockOffsets[offsetIdx(59, 3)] = 63;
- blockOffsets[offsetIdx(59, 2)] = 64;
- blockOffsets[offsetIdx(59, 1)] = 65;
- blockOffsets[offsetIdx(59, 0)] = 66;
- setOffsetsForID(60, 67, *this);
- setOffsetsForID(61, 183, *this);
- blockOffsets[offsetIdx(61, 2)] = 185;
- blockOffsets[offsetIdx(61, 4)] = 184;
- blockOffsets[offsetIdx(61, 5)] = 185;
- setOffsetsForID(62, 186, *this);
- blockOffsets[offsetIdx(62, 2)] = 188;
- blockOffsets[offsetIdx(62, 4)] = 187;
- blockOffsets[offsetIdx(62, 5)] = 188;
- setOffsetsForID(63, 73, *this);
- blockOffsets[offsetIdx(63, 0)] = 72;
- blockOffsets[offsetIdx(63, 1)] = 72;
- blockOffsets[offsetIdx(63, 4)] = 70;
- blockOffsets[offsetIdx(63, 5)] = 70;
- blockOffsets[offsetIdx(63, 6)] = 71;
- blockOffsets[offsetIdx(63, 7)] = 71;
- blockOffsets[offsetIdx(63, 8)] = 72;
- blockOffsets[offsetIdx(63, 9)] = 72;
- blockOffsets[offsetIdx(63, 12)] = 70;
- blockOffsets[offsetIdx(63, 13)] = 70;
- blockOffsets[offsetIdx(63, 14)] = 71;
- blockOffsets[offsetIdx(63, 15)] = 71;
- setOffsetsForID(64, 74, *this);
- setOffsetsForID(65, 82, *this);
- blockOffsets[offsetIdx(65, 3)] = 83;
- blockOffsets[offsetIdx(65, 4)] = 84;
- blockOffsets[offsetIdx(65, 5)] = 85;
- setOffsetsForID(66, 86, *this);
- blockOffsets[offsetIdx(66, 1)] = 87;
- blockOffsets[offsetIdx(66, 2)] = 200;
- blockOffsets[offsetIdx(66, 3)] = 201;
- blockOffsets[offsetIdx(66, 4)] = 202;
- blockOffsets[offsetIdx(66, 5)] = 203;
- blockOffsets[offsetIdx(66, 6)] = 92;
- blockOffsets[offsetIdx(66, 7)] = 93;
- blockOffsets[offsetIdx(66, 8)] = 94;
- blockOffsets[offsetIdx(66, 9)] = 95;
- setOffsetsForID(67, 96, *this);
- blockOffsets[offsetIdx(67, 1)] = 97;
- blockOffsets[offsetIdx(67, 2)] = 98;
- blockOffsets[offsetIdx(67, 3)] = 99;
- blockOffsets[offsetIdx(67, 4)] = 442;
- blockOffsets[offsetIdx(67, 5)] = 443;
- blockOffsets[offsetIdx(67, 6)] = 444;
- blockOffsets[offsetIdx(67, 7)] = 445;
- setOffsetsForID(68, 100, *this);
- blockOffsets[offsetIdx(68, 3)] = 101;
- blockOffsets[offsetIdx(68, 4)] = 102;
- blockOffsets[offsetIdx(68, 5)] = 103;
- setOffsetsForID(69, 194, *this);
- blockOffsets[offsetIdx(69, 2)] = 195;
- blockOffsets[offsetIdx(69, 3)] = 196;
- blockOffsets[offsetIdx(69, 4)] = 197;
- blockOffsets[offsetIdx(69, 5)] = 198;
- blockOffsets[offsetIdx(69, 6)] = 199;
- blockOffsets[offsetIdx(69, 10)] = 195;
- blockOffsets[offsetIdx(69, 11)] = 196;
- blockOffsets[offsetIdx(69, 12)] = 197;
- blockOffsets[offsetIdx(69, 13)] = 198;
- blockOffsets[offsetIdx(69, 14)] = 199;
- setOffsetsForID(70, 110, *this);
- setOffsetsForID(71, 111, *this);
- setOffsetsForID(72, 119, *this);
- setOffsetsForID(73, 120, *this);
- setOffsetsForID(74, 120, *this);
- setOffsetsForID(75, 121, *this);
- blockOffsets[offsetIdx(75, 1)] = 145;
- blockOffsets[offsetIdx(75, 2)] = 146;
- blockOffsets[offsetIdx(75, 3)] = 147;
- blockOffsets[offsetIdx(75, 4)] = 148;
- setOffsetsForID(76, 122, *this);
- blockOffsets[offsetIdx(76, 1)] = 141;
- blockOffsets[offsetIdx(76, 2)] = 142;
- blockOffsets[offsetIdx(76, 3)] = 143;
- blockOffsets[offsetIdx(76, 4)] = 144;
- setOffsetsForID(77, 190, *this);
- blockOffsets[offsetIdx(77, 2)] = 191;
- blockOffsets[offsetIdx(77, 3)] = 192;
- blockOffsets[offsetIdx(77, 4)] = 193;
- blockOffsets[offsetIdx(77, 10)] = 191;
- blockOffsets[offsetIdx(77, 11)] = 192;
- blockOffsets[offsetIdx(77, 12)] = 193;
- setOffsetsForID(78, 127, *this);
- setOffsetsForID(79, 128, *this);
- setOffsetsForID(80, 129, *this);
- setOffsetsForID(81, 130, *this);
- setOffsetsForID(82, 131, *this);
- setOffsetsForID(83, 132, *this);
- setOffsetsForID(84, 133, *this);
- setOffsetsForID(85, 134, *this);
- setOffsetsForID(86, 153, *this);
- blockOffsets[offsetIdx(86, 0)] = 135;
- blockOffsets[offsetIdx(86, 1)] = 154;
- blockOffsets[offsetIdx(86, 3)] = 153;
- setOffsetsForID(87, 136, *this);
- setOffsetsForID(88, 137, *this);
- setOffsetsForID(89, 138, *this);
- setOffsetsForID(90, 139, *this);
- setOffsetsForID(91, 155, *this);
- blockOffsets[offsetIdx(91, 0)] = 140;
- blockOffsets[offsetIdx(91, 1)] = 156;
- blockOffsets[offsetIdx(91, 3)] = 155;
- setOffsetsForID(92, 289, *this);
- setOffsetsForID(93, 247, *this);
- blockOffsets[offsetIdx(93, 1)] = 244;
- blockOffsets[offsetIdx(93, 5)] = 244;
- blockOffsets[offsetIdx(93, 9)] = 244;
- blockOffsets[offsetIdx(93, 13)] = 244;
- blockOffsets[offsetIdx(93, 2)] = 246;
- blockOffsets[offsetIdx(93, 6)] = 246;
- blockOffsets[offsetIdx(93, 10)] = 246;
- blockOffsets[offsetIdx(93, 14)] = 246;
- blockOffsets[offsetIdx(93, 3)] = 245;
- blockOffsets[offsetIdx(93, 7)] = 245;
- blockOffsets[offsetIdx(93, 11)] = 245;
- blockOffsets[offsetIdx(93, 15)] = 245;
- setOffsetsForID(94, 243, *this);
- blockOffsets[offsetIdx(94, 1)] = 240;
- blockOffsets[offsetIdx(94, 5)] = 240;
- blockOffsets[offsetIdx(94, 9)] = 240;
- blockOffsets[offsetIdx(94, 13)] = 240;
- blockOffsets[offsetIdx(94, 2)] = 242;
- blockOffsets[offsetIdx(94, 6)] = 242;
- blockOffsets[offsetIdx(94, 10)] = 242;
- blockOffsets[offsetIdx(94, 14)] = 242;
- blockOffsets[offsetIdx(94, 3)] = 241;
- blockOffsets[offsetIdx(94, 7)] = 241;
- blockOffsets[offsetIdx(94, 11)] = 241;
- blockOffsets[offsetIdx(94, 15)] = 241;
- setOffsetsForID(95, 270, *this);
- setOffsetsForID(96, 276, *this);
- blockOffsets[offsetIdx(96, 4)] = 277;
- blockOffsets[offsetIdx(96, 5)] = 278;
- blockOffsets[offsetIdx(96, 6)] = 279;
- blockOffsets[offsetIdx(96, 7)] = 280;
- setOffsetsForID(97, 1, *this);
- blockOffsets[offsetIdx(96, 1)] = 4;
- blockOffsets[offsetIdx(96, 2)] = 294;
- setOffsetsForID(98, 294, *this);
- blockOffsets[offsetIdx(98, 1)] = 295;
- blockOffsets[offsetIdx(98, 2)] = 296;
- blockOffsets[offsetIdx(98, 3)] = 430;
- setOffsetsForID(99, 336, *this);
- blockOffsets[offsetIdx(99, 1)] = 342;
- blockOffsets[offsetIdx(99, 2)] = 341;
- blockOffsets[offsetIdx(99, 3)] = 341;
- blockOffsets[offsetIdx(99, 4)] = 342;
- blockOffsets[offsetIdx(99, 5)] = 341;
- blockOffsets[offsetIdx(99, 6)] = 341;
- blockOffsets[offsetIdx(99, 7)] = 344;
- blockOffsets[offsetIdx(99, 8)] = 343;
- blockOffsets[offsetIdx(99, 9)] = 343;
- blockOffsets[offsetIdx(99, 10)] = 345;
- setOffsetsForID(100, 336, *this);
- blockOffsets[offsetIdx(100, 1)] = 338;
- blockOffsets[offsetIdx(100, 2)] = 337;
- blockOffsets[offsetIdx(100, 3)] = 337;
- blockOffsets[offsetIdx(100, 4)] = 338;
- blockOffsets[offsetIdx(100, 5)] = 337;
- blockOffsets[offsetIdx(100, 6)] = 337;
- blockOffsets[offsetIdx(100, 7)] = 340;
- blockOffsets[offsetIdx(100, 8)] = 339;
- blockOffsets[offsetIdx(100, 9)] = 339;
- blockOffsets[offsetIdx(100, 10)] = 345;
- setOffsetsForID(101, 355, *this);
- setOffsetsForID(102, 366, *this);
- setOffsetsForID(103, 290, *this);
- setOffsetsForID(104, 395, *this);
- blockOffsets[offsetIdx(104, 1)] = 396;
- blockOffsets[offsetIdx(104, 2)] = 397;
- blockOffsets[offsetIdx(104, 3)] = 398;
- blockOffsets[offsetIdx(104, 4)] = 399;
- blockOffsets[offsetIdx(104, 5)] = 400;
- blockOffsets[offsetIdx(104, 6)] = 401;
- blockOffsets[offsetIdx(104, 7)] = 402;
- setOffsetsForID(105, 395, *this);
- blockOffsets[offsetIdx(105, 1)] = 396;
- blockOffsets[offsetIdx(105, 2)] = 397;
- blockOffsets[offsetIdx(105, 3)] = 398;
- blockOffsets[offsetIdx(105, 4)] = 399;
- blockOffsets[offsetIdx(105, 5)] = 400;
- blockOffsets[offsetIdx(105, 6)] = 401;
- blockOffsets[offsetIdx(105, 7)] = 402;
- setOffsetsForID(106, 379, *this);
- blockOffsets[offsetIdx(106, 2)] = 380;
- blockOffsets[offsetIdx(106, 8)] = 381;
- blockOffsets[offsetIdx(106, 10)] = 382;
- blockOffsets[offsetIdx(106, 4)] = 383;
- blockOffsets[offsetIdx(106, 6)] = 384;
- blockOffsets[offsetIdx(106, 12)] = 385;
- blockOffsets[offsetIdx(106, 14)] = 386;
- blockOffsets[offsetIdx(106, 1)] = 387;
- blockOffsets[offsetIdx(106, 3)] = 388;
- blockOffsets[offsetIdx(106, 9)] = 389;
- blockOffsets[offsetIdx(106, 11)] = 390;
- blockOffsets[offsetIdx(106, 5)] = 391;
- blockOffsets[offsetIdx(106, 7)] = 392;
- blockOffsets[offsetIdx(106, 13)] = 393;
- blockOffsets[offsetIdx(106, 15)] = 394;
- setOffsetsForID(107, 347, *this);
- blockOffsets[offsetIdx(107, 1)] = 346;
- blockOffsets[offsetIdx(107, 3)] = 346;
- blockOffsets[offsetIdx(107, 5)] = 346;
- blockOffsets[offsetIdx(107, 7)] = 346;
- setOffsetsForID(108, 304, *this);
- blockOffsets[offsetIdx(108, 1)] = 305;
- blockOffsets[offsetIdx(108, 2)] = 306;
- blockOffsets[offsetIdx(108, 3)] = 307;
- blockOffsets[offsetIdx(108, 4)] = 446;
- blockOffsets[offsetIdx(108, 5)] = 447;
- blockOffsets[offsetIdx(108, 6)] = 448;
- blockOffsets[offsetIdx(108, 7)] = 449;
- setOffsetsForID(109, 308, *this);
- blockOffsets[offsetIdx(109, 1)] = 309;
- blockOffsets[offsetIdx(109, 2)] = 310;
- blockOffsets[offsetIdx(109, 3)] = 311;
- blockOffsets[offsetIdx(109, 4)] = 450;
- blockOffsets[offsetIdx(109, 5)] = 451;
- blockOffsets[offsetIdx(109, 6)] = 452;
- blockOffsets[offsetIdx(109, 7)] = 453;
- setOffsetsForID(110, 291, *this);
- setOffsetsForID(111, 316, *this);
- setOffsetsForID(112, 292, *this);
- setOffsetsForID(113, 332, *this);
- setOffsetsForID(114, 312, *this);
- blockOffsets[offsetIdx(114, 1)] = 313;
- blockOffsets[offsetIdx(114, 2)] = 314;
- blockOffsets[offsetIdx(114, 3)] = 315;
- blockOffsets[offsetIdx(114, 4)] = 454;
- blockOffsets[offsetIdx(114, 5)] = 455;
- blockOffsets[offsetIdx(114, 6)] = 456;
- blockOffsets[offsetIdx(114, 7)] = 457;
- setOffsetsForID(115, 333, *this);
- blockOffsets[offsetIdx(115, 1)] = 334;
- blockOffsets[offsetIdx(115, 2)] = 334;
- blockOffsets[offsetIdx(115, 3)] = 335;
- setOffsetsForID(116, 348, *this);
- setOffsetsForID(117, 350, *this);
- setOffsetsForID(118, 351, *this);
- blockOffsets[offsetIdx(118, 1)] = 352;
- blockOffsets[offsetIdx(118, 2)] = 353;
- blockOffsets[offsetIdx(118, 3)] = 354;
- setOffsetsForID(119, 377, *this);
- setOffsetsForID(120, 349, *this);
- setOffsetsForID(121, 293, *this);
- setOffsetsForID(122, 378, *this);
- setOffsetsForID(123, 434, *this);
- setOffsetsForID(124, 433, *this);
- setOffsetsForID(125, 5, *this);
- blockOffsets[offsetIdx(125, 1)] = 435;
- blockOffsets[offsetIdx(125, 2)] = 436;
- blockOffsets[offsetIdx(125, 3)] = 437;
- setOffsetsForID(126, 230, *this);
- blockOffsets[offsetIdx(126, 1)] = 464;
- blockOffsets[offsetIdx(126, 2)] = 466;
- blockOffsets[offsetIdx(126, 3)] = 468;
- blockOffsets[offsetIdx(126, 8)] = 460;
- blockOffsets[offsetIdx(126, 9)] = 465;
- blockOffsets[offsetIdx(126, 10)] = 467;
- blockOffsets[offsetIdx(126, 11)] = 469;
- setOffsetsForID(127, 522, *this);
- blockOffsets[offsetIdx(127, 1)] = 519;
- blockOffsets[offsetIdx(127, 2)] = 521;
- blockOffsets[offsetIdx(127, 3)] = 520;
- blockOffsets[offsetIdx(127, 4)] = 526;
- blockOffsets[offsetIdx(127, 5)] = 523;
- blockOffsets[offsetIdx(127, 6)] = 525;
- blockOffsets[offsetIdx(127, 7)] = 524;
- blockOffsets[offsetIdx(127, 8)] = 530;
- blockOffsets[offsetIdx(127, 9)] = 527;
- blockOffsets[offsetIdx(127, 10)] = 529;
- blockOffsets[offsetIdx(127, 11)] = 528;
- setOffsetsForID(128, 470, *this);
- blockOffsets[offsetIdx(128, 1)] = 471;
- blockOffsets[offsetIdx(128, 2)] = 472;
- blockOffsets[offsetIdx(128, 3)] = 473;
- blockOffsets[offsetIdx(128, 4)] = 474;
- blockOffsets[offsetIdx(128, 5)] = 475;
- blockOffsets[offsetIdx(128, 6)] = 476;
- blockOffsets[offsetIdx(128, 7)] = 477;
- setOffsetsForID(129, 478, *this);
- setOffsetsForID(130, 479, *this);
- blockOffsets[offsetIdx(130, 4)] = 480;
- blockOffsets[offsetIdx(130, 2)] = 481;
- blockOffsets[offsetIdx(130, 5)] = 481;
- blockOffsets[offsetIdx(131, 0)] = 542;
- blockOffsets[offsetIdx(131, 4)] = 542;
- blockOffsets[offsetIdx(131, 8)] = 542;
- blockOffsets[offsetIdx(131, 12)] = 542;
- blockOffsets[offsetIdx(131, 1)] = 539;
- blockOffsets[offsetIdx(131, 5)] = 539;
- blockOffsets[offsetIdx(131, 9)] = 539;
- blockOffsets[offsetIdx(131, 13)] = 539;
- blockOffsets[offsetIdx(131, 2)] = 541;
- blockOffsets[offsetIdx(131, 6)] = 541;
- blockOffsets[offsetIdx(131, 10)] = 541;
- blockOffsets[offsetIdx(131, 14)] = 541;
- blockOffsets[offsetIdx(131, 3)] = 540;
- blockOffsets[offsetIdx(131, 7)] = 540;
- blockOffsets[offsetIdx(131, 11)] = 540;
- blockOffsets[offsetIdx(131, 15)] = 540;
- setOffsetsForID(132, 543, *this);
- setOffsetsForID(133, 482, *this);
- setOffsetsForID(134, 495, *this);
- blockOffsets[offsetIdx(134, 1)] = 496;
- blockOffsets[offsetIdx(134, 2)] = 497;
- blockOffsets[offsetIdx(134, 3)] = 498;
- blockOffsets[offsetIdx(134, 4)] = 499;
- blockOffsets[offsetIdx(134, 5)] = 500;
- blockOffsets[offsetIdx(134, 6)] = 501;
- blockOffsets[offsetIdx(134, 7)] = 502;
- setOffsetsForID(135, 503, *this);
- blockOffsets[offsetIdx(135, 1)] = 504;
- blockOffsets[offsetIdx(135, 2)] = 505;
- blockOffsets[offsetIdx(135, 3)] = 506;
- blockOffsets[offsetIdx(135, 4)] = 507;
- blockOffsets[offsetIdx(135, 5)] = 508;
- blockOffsets[offsetIdx(135, 6)] = 509;
- blockOffsets[offsetIdx(135, 7)] = 510;
- setOffsetsForID(136, 511, *this);
- blockOffsets[offsetIdx(136, 1)] = 512;
- blockOffsets[offsetIdx(136, 2)] = 513;
- blockOffsets[offsetIdx(136, 3)] = 514;
- blockOffsets[offsetIdx(136, 4)] = 515;
- blockOffsets[offsetIdx(136, 5)] = 516;
- blockOffsets[offsetIdx(136, 6)] = 517;
- blockOffsets[offsetIdx(136, 7)] = 518;
-}
-
-void BlockImages::checkOpacityAndTransparency(int B)
-{
- opacity.clear();
- opacity.resize(NUMBLOCKIMAGES, true);
- transparency.clear();
- transparency.resize(NUMBLOCKIMAGES, true);
-
- for (int i = 0; i < NUMBLOCKIMAGES; i++)
- {
- ImageRect rect = getRect(i);
- // use the face iterators to examine the N, W, and U faces; any non-100% alpha makes
- // the block non-opaque, and any non-0% alpha makes the block non-transparent
- int tilesize = 2*B;
- // N face starts at [0,B]
- for (FaceIterator it(rect.x, rect.y + B, 1, tilesize); !it.end; it.advance())
- {
- int a = ALPHA(img(it.x, it.y));
- if (a < 255)
- opacity[i] = false;
- if (a > 0)
- transparency[i] = false;
- if (!opacity[i] && !transparency[i])
- break;
- }
- if (!opacity[i] && !transparency[i])
- continue;
- // W face starts at [2B,2B]
- for (FaceIterator it(rect.x + 2*B, rect.y + 2*B, -1, tilesize); !it.end; it.advance())
- {
- int a = ALPHA(img(it.x, it.y));
- if (a < 255)
- opacity[i] = false;
- if (a > 0)
- transparency[i] = false;
- if (!opacity[i] && !transparency[i])
- break;
- }
- if (!opacity[i] && !transparency[i])
- continue;
- // U face starts at [2B-1,0]
- for (TopFaceIterator it(rect.x + 2*B-1, rect.y, tilesize); !it.end; it.advance())
- {
- int a = ALPHA(img(it.x, it.y));
- if (a < 255)
- opacity[i] = false;
- if (a > 0)
- transparency[i] = false;
- if (!opacity[i] && !transparency[i])
- break;
- }
- }
-}
-
-void BlockImages::retouchAlphas(int B)
-{
- for (int i = 0; i < NUMBLOCKIMAGES; i++)
- {
- ImageRect rect = getRect(i);
- // use the face iterators to examine the N, W, and U faces; any alpha under 10 is changed
- // to 0, and any alpha above 245 is changed to 255
- int tilesize = 2*B;
- // N face starts at [0,B]
- for (FaceIterator it(rect.x, rect.y + B, 1, tilesize); !it.end; it.advance())
- {
- int a = ALPHA(img(it.x, it.y));
- if (a < 10)
- setAlpha(img(it.x, it.y), 0);
- else if (a > 245)
- setAlpha(img(it.x, it.y), 255);
- }
- // W face starts at [2B,2B]
- for (FaceIterator it(rect.x + 2*B, rect.y + 2*B, -1, tilesize); !it.end; it.advance())
- {
- int a = ALPHA(img(it.x, it.y));
- if (a < 10)
- setAlpha(img(it.x, it.y), 0);
- else if (a > 245)
- setAlpha(img(it.x, it.y), 255);
- }
- // U face starts at [2B-1,0]
- for (TopFaceIterator it(rect.x + 2*B-1, rect.y, tilesize); !it.end; it.advance())
- {
- int a = ALPHA(img(it.x, it.y));
- if (a < 10)
- setAlpha(img(it.x, it.y), 0);
- else if (a > 245)
- setAlpha(img(it.x, it.y), 255);
- }
- }
-}
-
-int deinterpolate(int targetj, int srcrange, int destrange)
-{
- for (int i = 0; i < destrange; i++)
- {
- int j = interpolate(i, destrange, srcrange);
- if (j >= targetj)
- return i;
- }
- return destrange - 1;
-}
-
-bool BlockImages::construct(int B, const string& terrainfile, const string& firefile, const string& endportalfile, const string& chestfile, const string& largechestfile, const string& enderchestfile)
-{
- if (B < 2)
- return false;
-
- // read the terrain file, check that it's okay, and get a resized copy for use
- RGBAImage terrain;
- if (!terrain.readPNG(terrainfile))
- return false;
- if (terrain.w % 16 != 0 || terrain.h != terrain.w)
- return false;
- int terrainSize = terrain.w / 16;
- RGBAImage tiles = getResizedTerrain(terrain, terrainSize, B);
-
- // read fire.png, make sure it's okay, and get a resized copy
- RGBAImage fire;
- if (!fire.readPNG(firefile))
- return false;
- if (fire.w != fire.h)
- return false;
- RGBAImage firetile;
- firetile.create(2*B, 2*B);
- resize(fire, ImageRect(0, 0, fire.w, fire.h), firetile, ImageRect(0, 0, 2*B, 2*B));
-
- // read endportal.png, make sure it's okay, and get a resized copy
- RGBAImage endportal;
- if (!endportal.readPNG(endportalfile))
- return false;
- if (endportal.w != endportal.h)
- return false;
- RGBAImage endportaltile;
- endportaltile.create(2*B, 2*B);
- resize(endportal, ImageRect(0, 0, endportal.w, endportal.h), endportaltile, ImageRect(0, 0, 2*B, 2*B));
-
- // read chest.png, make sure it's okay, and build resized tiles
- RGBAImage chest;
- if (!chest.readPNG(chestfile))
- return false;
- if (chest.w % 64 != 0 || chest.h != chest.w)
- return false;
- int chestScale = chest.w / 64;
- RGBAImage chesttiles = getResizedChest(chest, chestScale, B);
-
- // read enderchest.png, make sure it's okay, and build resized tiles
- RGBAImage enderchest;
- if (!enderchest.readPNG(enderchestfile))
- return false;
- if (enderchest.w % 64 != 0 || enderchest.h != enderchest.w)
- return false;
- int enderchestScale = enderchest.w / 64;
- RGBAImage enderchesttiles = getResizedChest(enderchest, enderchestScale, B);
-
- // read largechest.png, make sure it's okay, and build resized tiles
- RGBAImage largechest;
- if (!largechest.readPNG(largechestfile))
- return false;
- if (largechest.w % 128 != 0 || largechest.h != largechest.w / 2)
- return false;
- int largechestScale = largechest.w / 128;
- RGBAImage largechesttiles = getResizedLargeChest(largechest, largechestScale, B);
-
- // colorize various tiles
- darken(tiles, ImageRect(0, 0, 2*B, 2*B), 0.6, 0.95, 0.3); // tile 0 = grass top
- darken(tiles, ImageRect(14*B, 4*B, 2*B, 2*B), 0.6, 0.95, 0.3); // tile 39 = tall grass
- darken(tiles, ImageRect(16*B, 6*B, 2*B, 2*B), 0.6, 0.95, 0.3); // tile 56 = fern
- darken(tiles, ImageRect(8*B, 20*B, 2*B, 2*B), 0.9, 0.1, 0.1); // tile 164 = redstone dust
- darken(tiles, ImageRect(24*B, 8*B, 2*B, 2*B), 0.3, 0.95, 0.3); // tile 76 = lily pad
- darken(tiles, ImageRect(30*B, 16*B, 2*B, 2*B), 0.35, 1.0, 0.15); // tile 143 = vines
-
- // create colorized copies of leaf tiles (can't colorize in place because normal and
- // birch leaves use the same texture)
- RGBAImage leaftiles;
- leaftiles.create(8*B, 2*B);
- // normal
- blit(tiles, ImageRect(8*B, 6*B, 2*B, 2*B), leaftiles, 0, 0);
- darken(leaftiles, ImageRect(0, 0, 2*B, 2*B), 0.3, 1.0, 0.1);
- // pine
- blit(tiles, ImageRect(8*B, 16*B, 2*B, 2*B), leaftiles, 2*B, 0);
- darken(leaftiles, ImageRect(2*B, 0, 2*B, 2*B), 0.3, 1.0, 0.45);
- // birch
- blit(tiles, ImageRect(8*B, 6*B, 2*B, 2*B), leaftiles, 4*B, 0);
- darken(leaftiles, ImageRect(4*B, 0, 2*B, 2*B), 0.55, 0.9, 0.1);
- // jungle
- blit(tiles, ImageRect(8*B, 24*B, 2*B, 2*B), leaftiles, 6*B, 0);
- darken(leaftiles, ImageRect(6*B, 0, 2*B, 2*B), 0.35, 1.0, 0.05);
-
- // create colorized/shortened copies of stem tiles
- RGBAImage stemtiles;
- stemtiles.create(20*B, 2*B);
- // levels 0-7
- for (int i = 1; i <= 8; i++)
- blit(tiles, ImageRect(30*B, 12*B, 2*B, i*B/4), stemtiles, (i-1)*2*B, 2*B - i*B/4);
- // stem connecting to melon/pumpkin, and flipped version
- blit(tiles, ImageRect(30*B, 14*B, 2*B, 2*B), stemtiles, 16*B, 0);
- blit(tiles, ImageRect(30*B, 14*B, 2*B, 2*B), stemtiles, 18*B, 0);
- flipX(stemtiles, ImageRect(18*B, 0, 2*B, 2*B));
- // green for levels 0-6, brown for level 7 and the connectors
- darken(stemtiles, ImageRect(0, 0, 14*B, 2*B), 0.45, 0.95, 0.4);
- darken(stemtiles, ImageRect(14*B, 0, 6*B, 2*B), 0.75, 0.6, 0.3);
-
- // calculate the pixel offset used for cactus/cake; represents one pixel of the default
- // 16x16 texture size
- int smallOffset = (terrainSize + 15) / 16; // ceil(terrainSize/16)
-
- // resize the cactus tiles again, this time taking a smaller portion of the terrain
- // image (to drop the transparent border)
- resize(terrain, ImageRect(5*terrainSize + smallOffset, 4*terrainSize + smallOffset, terrainSize - 2*smallOffset, terrainSize - 2*smallOffset),
- tiles, ImageRect(5*2*B, 4*2*B, 2*B, 2*B));
- resize(terrain, ImageRect(6*terrainSize + smallOffset, 4*terrainSize, terrainSize - 2*smallOffset, terrainSize),
- tiles, ImageRect(6*2*B, 4*2*B, 2*B, 2*B));
-
- // ...and the same thing for the cake tiles
- resize(terrain, ImageRect(9*terrainSize + smallOffset, 7*terrainSize + smallOffset, terrainSize - 2*smallOffset, terrainSize - 2*smallOffset),
- tiles, ImageRect(9*2*B, 7*2*B, 2*B, 2*B));
- resize(terrain, ImageRect(10*terrainSize + smallOffset, 7*terrainSize, terrainSize - 2*smallOffset, terrainSize),
- tiles, ImageRect(10*2*B, 7*2*B, 2*B, 2*B));
-
- // determine some cutoff values for partial block images: given a particular pixel offset in terrain.png--for
- // example, the end portal frame texture is missing its top 3 (out of 16) pixels--we need to know which pixel
- // in the resized tile is the first one past that offset
- // ...if the terrain tile size isn't a multiple of 16 for some reason, this may break down and be ugly
- int CUTOFF_2_16 = deinterpolate(2 * terrainSize/16, terrainSize, 2*B);
- int CUTOFF_3_16 = deinterpolate(3 * terrainSize/16, terrainSize, 2*B);
- int CUTOFF_4_16 = deinterpolate(4 * terrainSize/16, terrainSize, 2*B);
- int CUTOFF_6_16 = deinterpolate(6 * terrainSize/16, terrainSize, 2*B);
- int CUTOFF_8_16 = deinterpolate(8 * terrainSize/16, terrainSize, 2*B);
- int CUTOFF_10_16 = deinterpolate(10 * terrainSize/16, terrainSize, 2*B);
- int CUTOFF_12_16 = deinterpolate(12 * terrainSize/16, terrainSize, 2*B);
- int CUTOFF_14_16 = deinterpolate(14 * terrainSize/16, terrainSize, 2*B);
-
- // initialize image
- img.create(rectsize * 16, (NUMBLOCKIMAGES/16 + 1) * rectsize);
-
- // build all block images
-
- drawBlockImage(img, getRect(1), tiles, 1, 1, 1, B); // stone
- drawBlockImage(img, getRect(2), tiles, 3, 3, 0, B); // grass
- drawBlockImage(img, getRect(3), tiles, 2, 2, 2, B); // dirt
- drawBlockImage(img, getRect(4), tiles, 16, 16, 16, B); // cobblestone
- drawBlockImage(img, getRect(5), tiles, 4, 4, 4, B); // planks
- drawBlockImage(img, getRect(435), tiles, 198, 198, 198, B); // pine planks
- drawBlockImage(img, getRect(436), tiles, 214, 214, 214, B); // birch planks
- drawBlockImage(img, getRect(437), tiles, 199, 199, 199, B); // jungle planks
- drawBlockImage(img, getRect(7), tiles, 17, 17, 17, B); // bedrock
- drawBlockImage(img, getRect(8), tiles, 205, 205, 205, B); // full water
- drawBlockImage(img, getRect(157), tiles, -1, -1, 205, B); // water surface
- drawBlockImage(img, getRect(178), tiles, 205, -1, 205, B); // water missing W
- drawBlockImage(img, getRect(179), tiles, -1, 205, 205, B); // water missing N
- drawBlockImage(img, getRect(16), tiles, 237, 237, 237, B); // full lava
- drawBlockImage(img, getRect(20), tiles, 18, 18, 18, B); // sand
- drawBlockImage(img, getRect(483), tiles, 19, 19, 19, B); // gravel
- drawBlockImage(img, getRect(22), tiles, 32, 32, 32, B); // gold ore
- drawBlockImage(img, getRect(23), tiles, 33, 33, 33, B); // iron ore
- drawBlockImage(img, getRect(24), tiles, 34, 34, 34, B); // coal ore
- drawBlockImage(img, getRect(25), tiles, 20, 20, 21, B); // log
- drawBlockImage(img, getRect(219), tiles, 116, 116, 21, B); // pine log
- drawBlockImage(img, getRect(220), tiles, 117, 117, 21, B); // birch log
- drawBlockImage(img, getRect(427), tiles, 153, 153, 21, B); // jungle log
- drawBlockImage(img, getRect(26), leaftiles, 0, 0, 0, B); // leaves
- drawBlockImage(img, getRect(248), leaftiles, 1, 1, 1, B); // pine leaves
- drawBlockImage(img, getRect(249), leaftiles, 2, 2, 2, B); // birch leaves
- drawBlockImage(img, getRect(428), leaftiles, 3, 3, 3, B); // jungle leaves
- drawBlockImage(img, getRect(27), tiles, 48, 48, 48, B); // sponge
- drawBlockImage(img, getRect(28), tiles, 49, 49, 49, B); // glass
- drawBlockImage(img, getRect(29), tiles, 64, 64, 64, B); // white wool
- drawBlockImage(img, getRect(204), tiles, 210, 210, 210, B); // orange wool
- drawBlockImage(img, getRect(205), tiles, 194, 194, 194, B); // magenta wool
- drawBlockImage(img, getRect(206), tiles, 178, 178, 178, B); // light blue wool
- drawBlockImage(img, getRect(207), tiles, 162, 162, 162, B); // yellow wool
- drawBlockImage(img, getRect(208), tiles, 146, 146, 146, B); // lime wool
- drawBlockImage(img, getRect(209), tiles, 130, 130, 130, B); // pink wool
- drawBlockImage(img, getRect(210), tiles, 114, 114, 114, B); // gray wool
- drawBlockImage(img, getRect(211), tiles, 225, 225, 225, B); // light gray wool
- drawBlockImage(img, getRect(212), tiles, 209, 209, 209, B); // cyan wool
- drawBlockImage(img, getRect(213), tiles, 193, 193, 193, B); // purple wool
- drawBlockImage(img, getRect(214), tiles, 177, 177, 177, B); // blue wool
- drawBlockImage(img, getRect(215), tiles, 161, 161, 161, B); // brown wool
- drawBlockImage(img, getRect(216), tiles, 145, 145, 145, B); // green wool
- drawBlockImage(img, getRect(217), tiles, 129, 129, 129, B); // red wool
- drawBlockImage(img, getRect(218), tiles, 113, 113, 113, B); // black wool
- drawBlockImage(img, getRect(34), tiles, 23, 23, 23, B); // gold block
- drawBlockImage(img, getRect(35), tiles, 22, 22, 22, B); // iron block
- drawBlockImage(img, getRect(36), tiles, 5, 5, 6, B); // double stone slab
- drawBlockImage(img, getRect(38), tiles, 7, 7, 7, B); // brick
- drawBlockImage(img, getRect(39), tiles, 8, 8, 9, B); // TNT
- drawBlockImage(img, getRect(40), tiles, 35, 35, 4, B); // bookshelf
- drawBlockImage(img, getRect(41), tiles, 36, 36, 36, B); // mossy cobblestone
- drawBlockImage(img, getRect(42), tiles, 37, 37, 37, B); // obsidian
- drawBlockImage(img, getRect(49), tiles, 65, 65, 65, B); // spawner
- drawBlockImage(img, getRect(484), chesttiles, 2, 1, 0, B); // chest facing W
- drawBlockImage(img, getRect(485), chesttiles, 1, 2, 0, B); // chest facing N
- drawBlockImage(img, getRect(486), chesttiles, 2, 2, 0, B); // chest facing E/S
- drawBlockImage(img, getRect(479), enderchesttiles, 2, 1, 0, B); // ender chest facing W
- drawBlockImage(img, getRect(480), enderchesttiles, 1, 2, 0, B); // ender chest facing N
- drawBlockImage(img, getRect(481), enderchesttiles, 2, 2, 0, B); // ender chest facing E/S
- drawBlockImage(img, getRect(489), largechesttiles, 2, 6, 0, B); // double chest E facing N
- drawBlockImage(img, getRect(490), largechesttiles, 3, 6, 1, B); // double chest W facing N
- drawBlockImage(img, getRect(493), largechesttiles, 4, 6, 0, B); // double chest E facing S
- drawBlockImage(img, getRect(494), largechesttiles, 5, 6, 1, B); // double chest W facing S
- drawBlockImage(img, getRect(270), chesttiles, 2, 1, 0, B); // locked chest facing W
- drawBlockImage(img, getRect(271), chesttiles, 1, 2, 0, B); // locked chest facing N
- drawBlockImage(img, getRect(56), tiles, 50, 50, 50, B); // diamond ore
- drawBlockImage(img, getRect(57), tiles, 24, 24, 24, B); // diamond block
- drawBlockImage(img, getRect(58), tiles, 59, 60, 43, B); // workbench
- drawBlockImage(img, getRect(67), tiles, 2, 2, 87, B); // farmland
- drawBlockImage(img, getRect(183), tiles, 45, 44, 62, B); // furnace W
- drawBlockImage(img, getRect(184), tiles, 44, 45, 62, B); // furnace N
- drawBlockImage(img, getRect(185), tiles, 45, 45, 62, B); // furnace E/S
- drawBlockImage(img, getRect(186), tiles, 45, 61, 62, B); // lit furnace W
- drawBlockImage(img, getRect(187), tiles, 61, 45, 62, B); // lit furnace N
- drawBlockImage(img, getRect(188), tiles, 45, 45, 62, B); // lit furnace E/S
- drawBlockImage(img, getRect(120), tiles, 51, 51, 51, B); // redstone ore
- drawBlockImage(img, getRect(128), tiles, 67, 67, 67, B); // ice
- drawBlockImage(img, getRect(180), tiles, -1, -1, 67, B); // ice surface
- drawBlockImage(img, getRect(181), tiles, 67, -1, 67, B); // ice missing W
- drawBlockImage(img, getRect(182), tiles, -1, 67, 67, B); // ice missing N
- drawBlockImage(img, getRect(129), tiles, 66, 66, 66, B); // snow block
- drawBlockImage(img, getRect(130), tiles, 70, 70, 69, B); // cactus
- drawBlockImage(img, getRect(131), tiles, 72, 72, 72, B); // clay
- drawBlockImage(img, getRect(133), tiles, 74, 74, 75, B); // jukebox
- drawBlockImage(img, getRect(135), tiles, 118, 119, 102, B); // pumpkin facing W
- drawBlockImage(img, getRect(153), tiles, 118, 118, 102, B); // pumpkin facing E/S
- drawBlockImage(img, getRect(154), tiles, 119, 118, 102, B); // pumpkin facing N
- drawBlockImage(img, getRect(136), tiles, 103, 103, 103, B); // netherrack
- drawBlockImage(img, getRect(137), tiles, 104, 104, 104, B); // soul sand
- drawBlockImage(img, getRect(138), tiles, 105, 105, 105, B); // glowstone
- drawBlockImage(img, getRect(140), tiles, 118, 120, 102, B); // jack-o-lantern W
- drawBlockImage(img, getRect(155), tiles, 118, 118, 102, B); // jack-o-lantern E/S
- drawBlockImage(img, getRect(156), tiles, 120, 118, 102, B); // jack-o-lantern N
- drawBlockImage(img, getRect(221), tiles, 160, 160, 160, B); // lapis ore
- drawBlockImage(img, getRect(222), tiles, 144, 144, 144, B); // lapis block
- drawBlockImage(img, getRect(223), tiles, 45, 46, 62, B); // dispenser W
- drawBlockImage(img, getRect(224), tiles, 46, 45, 62, B); // dispenser N
- drawBlockImage(img, getRect(225), tiles, 45, 45, 62, B); // dispenser E/S
- drawBlockImage(img, getRect(226), tiles, 192, 192, 176, B); // sandstone
- drawBlockImage(img, getRect(431), tiles, 229, 229, 176, B); // hieroglyphic sandstone
- drawBlockImage(img, getRect(432), tiles, 230, 230, 176, B); // smooth sandstone
- drawBlockImage(img, getRect(227), tiles, 74, 74, 74, B); // note block
- drawBlockImage(img, getRect(290), tiles, 136, 136, 137, B); // melon
- drawBlockImage(img, getRect(291), tiles, 77, 77, 78, B); // mycelium
- drawBlockImage(img, getRect(292), tiles, 224, 224, 224, B); // nether brick
- drawBlockImage(img, getRect(293), tiles, 175, 175, 175, B); // end stone
- drawBlockImage(img, getRect(294), tiles, 54, 54, 54, B); // stone brick
- drawBlockImage(img, getRect(295), tiles, 100, 100, 100, B); // mossy stone brick
- drawBlockImage(img, getRect(296), tiles, 101, 101, 101, B); // cracked stone brick
- drawBlockImage(img, getRect(430), tiles, 213, 213, 213, B); // circle stone brick
- drawBlockImage(img, getRect(336), tiles, 142, 142, 142, B); // mushroom flesh
- drawBlockImage(img, getRect(337), tiles, 142, 142, 125, B); // red cap top only
- drawBlockImage(img, getRect(338), tiles, 125, 142, 125, B); // red cap N
- drawBlockImage(img, getRect(339), tiles, 142, 125, 125, B); // red cap W
- drawBlockImage(img, getRect(340), tiles, 125, 125, 125, B); // red cap NW
- drawBlockImage(img, getRect(341), tiles, 142, 142, 126, B); // brown cap top only
- drawBlockImage(img, getRect(342), tiles, 126, 142, 126, B); // brown cap N
- drawBlockImage(img, getRect(343), tiles, 142, 126, 126, B); // brown cap W
- drawBlockImage(img, getRect(344), tiles, 126, 126, 126, B); // brown cap NW
- drawBlockImage(img, getRect(345), tiles, 141, 141, 142, B); // mushroom stem
- drawBlockImage(img, getRect(433), tiles, 212, 212, 212, B); // redstone lamp on
- drawBlockImage(img, getRect(434), tiles, 211, 211, 211, B); // redstone lamp off
- drawBlockImage(img, getRect(478), tiles, 171, 171, 171, B); // emerald ore
- drawBlockImage(img, getRect(482), tiles, 25, 25, 25, B); // emerald block
- drawRotatedBlockImage(img, getRect(407), tiles, 108, 108, 109, 2, false, 2, false, 0, false, B); // closed piston D
- drawRotatedBlockImage(img, getRect(408), tiles, 108, 108, 107, 0, false, 0, false, 0, false, B); // closed piston U
- drawRotatedBlockImage(img, getRect(409), tiles, 107, 108, 108, 0, false, 1, false, 2, false, B); // closed piston N
- drawRotatedBlockImage(img, getRect(410), tiles, 109, 108, 108, 0, false, 3, false, 0, false, B); // closed piston S
- drawRotatedBlockImage(img, getRect(411), tiles, 108, 107, 108, 3, false, 0, false, 3, false, B); // closed piston W
- drawRotatedBlockImage(img, getRect(412), tiles, 108, 109, 108, 1, false, 0, false, 1, false, B); // closed piston E
- drawRotatedBlockImage(img, getRect(413), tiles, 108, 108, 109, 2, false, 2, false, 0, false, B); // closed sticky piston D
- drawRotatedBlockImage(img, getRect(414), tiles, 108, 108, 106, 0, false, 0, false, 0, false, B); // closed sticky piston U
- drawRotatedBlockImage(img, getRect(415), tiles, 106, 108, 108, 0, false, 1, false, 2, false, B); // closed sticky piston N
- drawRotatedBlockImage(img, getRect(416), tiles, 109, 108, 108, 0, false, 3, false, 0, false, B); // closed sticky piston S
- drawRotatedBlockImage(img, getRect(417), tiles, 108, 106, 108, 3, false, 0, false, 3, false, B); // closed sticky piston W
- drawRotatedBlockImage(img, getRect(418), tiles, 108, 109, 108, 1, false, 0, false, 1, false, B); // closed sticky piston E
- drawRotatedBlockImage(img, getRect(487), largechesttiles, 6, 2, 0, 0, false, 0, false, 1, false, B); // double chest N facing W
- drawRotatedBlockImage(img, getRect(488), largechesttiles, 6, 3, 1, 0, false, 0, false, 1, false, B); // double chest S facing W
- drawRotatedBlockImage(img, getRect(491), largechesttiles, 6, 4, 0, 0, false, 0, false, 1, false, B); // double chest N facing E
- drawRotatedBlockImage(img, getRect(492), largechesttiles, 6, 5, 1, 0, false, 0, false, 1, false, B); // double chest S facing E
- drawRotatedBlockImage(img, getRect(531), tiles, 20, 21, 20, 1, false, 0, false, 1, false, B); // log EW
- drawRotatedBlockImage(img, getRect(532), tiles, 21, 20, 20, 0, false, 3, false, 0, false, B); // log NS
- drawRotatedBlockImage(img, getRect(533), tiles, 116, 21, 116, 1, false, 0, false, 1, false, B); // pine log EW
- drawRotatedBlockImage(img, getRect(534), tiles, 21, 116, 116, 0, false, 3, false, 0, false, B); // pine log NS
- drawRotatedBlockImage(img, getRect(535), tiles, 117, 21, 117, 1, false, 0, false, 1, false, B); // birch log EW
- drawRotatedBlockImage(img, getRect(536), tiles, 21, 117, 117, 0, false, 3, false, 0, false, B); // birch log NS
- drawRotatedBlockImage(img, getRect(537), tiles, 153, 21, 153, 1, false, 0, false, 1, false, B); // jungle log EW
- drawRotatedBlockImage(img, getRect(538), tiles, 21, 153, 153, 0, false, 3, false, 0, false, B); // jungle log NS
-
- drawPartialBlockImage(img, getRect(9), tiles, 205, 205, 205, B, CUTOFF_2_16, 0, 0, 0, true); // water level 7
- drawPartialBlockImage(img, getRect(10), tiles, 205, 205, 205, B, CUTOFF_4_16, 0, 0, 0, true); // water level 6
- drawPartialBlockImage(img, getRect(11), tiles, 205, 205, 205, B, CUTOFF_6_16, 0, 0, 0, true); // water level 5
- drawPartialBlockImage(img, getRect(12), tiles, 205, 205, 205, B, CUTOFF_8_16, 0, 0, 0, true); // water level 4
- drawPartialBlockImage(img, getRect(13), tiles, 205, 205, 205, B, CUTOFF_10_16, 0, 0, 0, true); // water level 3
- drawPartialBlockImage(img, getRect(14), tiles, 205, 205, 205, B, CUTOFF_12_16, 0, 0, 0, true); // water level 2
- drawPartialBlockImage(img, getRect(15), tiles, 205, 205, 205, B, CUTOFF_14_16, 0, 0, 0, true); // water level 1
- drawPartialBlockImage(img, getRect(17), tiles, 237, 237, 237, B, CUTOFF_4_16, 0, 0, 0, true); // lava level 3
- drawPartialBlockImage(img, getRect(18), tiles, 237, 237, 237, B, CUTOFF_8_16, 0, 0, 0, true); // lava level 2
- drawPartialBlockImage(img, getRect(19), tiles, 237, 237, 237, B, CUTOFF_12_16, 0, 0, 0, true); // lava level 1
- drawPartialBlockImage(img, getRect(37), tiles, 5, 5, 6, B, CUTOFF_8_16, 0, 0, 0, true); // stone slab
- drawPartialBlockImage(img, getRect(229), tiles, 192, 192, 176, B, CUTOFF_8_16, 0, 0, 0, true); // sandstone slab
- drawPartialBlockImage(img, getRect(230), tiles, 4, 4, 4, B, CUTOFF_8_16, 0, 0, 0, true); // wooden slab
- drawPartialBlockImage(img, getRect(231), tiles, 16, 16, 16, B, CUTOFF_8_16, 0, 0, 0, true); // cobble slab
- drawPartialBlockImage(img, getRect(302), tiles, 7, 7, 7, B, CUTOFF_8_16, 0, 0, 0, true); // brick slab
- drawPartialBlockImage(img, getRect(303), tiles, 54, 54, 54, B, CUTOFF_8_16, 0, 0, 0, true); // stone brick slab
- drawPartialBlockImage(img, getRect(464), tiles, 198, 198, 198, B, CUTOFF_8_16, 0, 0, 0, true); // pine slab
- drawPartialBlockImage(img, getRect(466), tiles, 214, 214, 214, B, CUTOFF_8_16, 0, 0, 0, true); // birch slab
- drawPartialBlockImage(img, getRect(468), tiles, 199, 199, 199, B, CUTOFF_8_16, 0, 0, 0, true); // jungle slab
- drawPartialBlockImage(img, getRect(458), tiles, 5, 5, 6, B, 0, CUTOFF_8_16, 0, 0, false); // stone slab inv
- drawPartialBlockImage(img, getRect(459), tiles, 192, 192, 176, B, 0, CUTOFF_8_16, 0, 0, false); // sandstone slab inv
- drawPartialBlockImage(img, getRect(460), tiles, 4, 4, 4, B, 0, CUTOFF_8_16, 0, 0, false); // wooden slab inv
- drawPartialBlockImage(img, getRect(461), tiles, 16, 16, 16, B, 0, CUTOFF_8_16, 0, 0, false); // cobble slab inv
- drawPartialBlockImage(img, getRect(462), tiles, 7, 7, 7, B, 0, CUTOFF_8_16, 0, 0, false); // brick slab inv
- drawPartialBlockImage(img, getRect(463), tiles, 54, 54, 54, B, 0, CUTOFF_8_16, 0, 0, false); // stone brick slab inv
- drawPartialBlockImage(img, getRect(465), tiles, 198, 198, 198, B, 0, CUTOFF_8_16, 0, 0, false); // pine slab inv
- drawPartialBlockImage(img, getRect(467), tiles, 214, 214, 214, B, 0, CUTOFF_8_16, 0, 0, false); // birch slab inv
- drawPartialBlockImage(img, getRect(469), tiles, 199, 199, 199, B, 0, CUTOFF_8_16, 0, 0, false); // jungle slab inv
- drawPartialBlockImage(img, getRect(110), tiles, 1, 1, 1, B, CUTOFF_14_16, 0, 0, 0, true); // stone pressure plate
- drawPartialBlockImage(img, getRect(119), tiles, 4, 4, 4, B, CUTOFF_14_16, 0, 0, 0, true); // wood pressure plate
- drawPartialBlockImage(img, getRect(127), tiles, 66, 66, 66, B, CUTOFF_12_16, 0, 0, 0, true); // snow
- drawPartialBlockImage(img, getRect(289), tiles, 122, 122, 121, B, CUTOFF_8_16, 0, 0, 0, false); // cake
- drawPartialBlockImage(img, getRect(281), tiles, 151, 152, 135, B, CUTOFF_8_16, 0, 0, 0, false); // bed head W
- drawPartialBlockImage(img, getRect(282), tiles, 152, 151, 135, B, CUTOFF_8_16, 0, 3, 2, false); // bed head N
- drawPartialBlockImage(img, getRect(283), tiles, 151, -1, 135, B, CUTOFF_8_16, 0, 2, 1, false); // bed head E
- drawPartialBlockImage(img, getRect(284), tiles, -1, 151, 135, B, CUTOFF_8_16, 0, 1, 0, false); // bed head S
- drawPartialBlockImage(img, getRect(285), tiles, 150, -1, 134, B, CUTOFF_8_16, 0, 0, 0, false); // bed foot W
- drawPartialBlockImage(img, getRect(286), tiles, -1, 150, 134, B, CUTOFF_8_16, 0, 3, 2, false); // bed foot N
- drawPartialBlockImage(img, getRect(287), tiles, 150, 149, 134, B, CUTOFF_8_16, 0, 2, 1, false); // bed foot E
- drawPartialBlockImage(img, getRect(288), tiles, 149, 150, 134, B, CUTOFF_8_16, 0, 1, 0, false); // bed foot S
- drawPartialBlockImage(img, getRect(348), tiles, 182, 182, 166, B, CUTOFF_4_16, 0, 0, 0, false); // enchantment table
- drawPartialBlockImage(img, getRect(349), tiles, 159, 159, 158, B, CUTOFF_3_16, 0, 0, 0, false); // end portal frame
- drawPartialBlockImage(img, getRect(377), endportaltile, 0, 0, 0, B, CUTOFF_4_16, 0, 0, 0, true); // end portal
-
- drawItemBlockImage(img, getRect(6), tiles, 15, B); // sapling
- drawItemBlockImage(img, getRect(30), tiles, 13, B); // yellow flower
- drawItemBlockImage(img, getRect(31), tiles, 12, B); // red rose
- drawItemBlockImage(img, getRect(32), tiles, 29, B); // brown mushroom
- drawItemBlockImage(img, getRect(33), tiles, 28, B); // red mushroom
- drawItemBlockImage(img, getRect(43), tiles, 80, B); // torch floor
- drawItemBlockImage(img, getRect(59), tiles, 95, B); // wheat level 7
- drawItemBlockImage(img, getRect(60), tiles, 94, B); // wheat level 6
- drawItemBlockImage(img, getRect(61), tiles, 93, B); // wheat level 5
- drawItemBlockImage(img, getRect(62), tiles, 92, B); // wheat level 4
- drawItemBlockImage(img, getRect(63), tiles, 91, B); // wheat level 3
- drawItemBlockImage(img, getRect(64), tiles, 90, B); // wheat level 2
- drawItemBlockImage(img, getRect(65), tiles, 89, B); // wheat level 1
- drawItemBlockImage(img, getRect(66), tiles, 88, B); // wheat level 0
- drawItemBlockImage(img, getRect(121), tiles, 115, B); // red torch floor off
- drawItemBlockImage(img, getRect(122), tiles, 99, B); // red torch floor on
- drawItemBlockImage(img, getRect(132), tiles, 73, B); // reeds
- drawItemBlockImage(img, getRect(250), tiles, 63, B); // pine sapling
- drawItemBlockImage(img, getRect(251), tiles, 79, B); // birch sapling
- drawItemBlockImage(img, getRect(429), tiles, 30, B); // birch sapling
- drawItemBlockImage(img, getRect(272), tiles, 11, B); // web
- drawItemBlockImage(img, getRect(273), tiles, 39, B); // tall grass
- drawItemBlockImage(img, getRect(274), tiles, 56, B); // fern
- drawItemBlockImage(img, getRect(275), tiles, 55, B); // dead shrub
- drawMultiItemBlockImage(img, getRect(333), tiles, 226, B); // netherwart small
- drawMultiItemBlockImage(img, getRect(334), tiles, 227, B); // netherwart medium
- drawMultiItemBlockImage(img, getRect(335), tiles, 228, B); // netherwart large
- drawItemBlockImage(img, getRect(355), tiles, 85, B); // iron bars NSEW
- drawPartialItemBlockImage(img, getRect(356), tiles, 85, 0, false, B, true, true, false, false); // iron bars NS
- drawPartialItemBlockImage(img, getRect(357), tiles, 85, 0, false, B, true, false, true, false); // iron bars NE
- drawPartialItemBlockImage(img, getRect(358), tiles, 85, 0, false, B, true, false, false, true); // iron bars NW
- drawPartialItemBlockImage(img, getRect(359), tiles, 85, 0, false, B, false, true, true, false); // iron bars SE
- drawPartialItemBlockImage(img, getRect(360), tiles, 85, 0, false, B, false, true, false, true); // iron bars SW
- drawPartialItemBlockImage(img, getRect(361), tiles, 85, 0, false, B, false, false, true, true); // iron bars EW
- drawPartialItemBlockImage(img, getRect(362), tiles, 85, 0, false, B, false, true, true, true); // iron bars SEW
- drawPartialItemBlockImage(img, getRect(363), tiles, 85, 0, false, B, true, false, true, true); // iron bars NEW
- drawPartialItemBlockImage(img, getRect(364), tiles, 85, 0, false, B, true, true, false, true); // iron bars NSW
- drawPartialItemBlockImage(img, getRect(365), tiles, 85, 0, false, B, true, true, true, false); // iron bars NSE
- drawPartialItemBlockImage(img, getRect(419), tiles, 85, 0, false, B, true, false, false, false); // iron bars N
- drawPartialItemBlockImage(img, getRect(420), tiles, 85, 0, false, B, false, true, false, false); // iron bars S
- drawPartialItemBlockImage(img, getRect(421), tiles, 85, 0, false, B, false, false, true, false); // iron bars E
- drawPartialItemBlockImage(img, getRect(422), tiles, 85, 0, false, B, false, false, false, true); // iron bars W
- drawItemBlockImage(img, getRect(366), tiles, 49, B); // glass pane NSEW
- drawPartialItemBlockImage(img, getRect(367), tiles, 49, 0, false, B, true, true, false, false); // glass pane NS
- drawPartialItemBlockImage(img, getRect(368), tiles, 49, 0, false, B, true, false, true, false); // glass pane NE
- drawPartialItemBlockImage(img, getRect(369), tiles, 49, 0, false, B, true, false, false, true); // glass pane NW
- drawPartialItemBlockImage(img, getRect(370), tiles, 49, 0, false, B, false, true, true, false); // glass pane SE
- drawPartialItemBlockImage(img, getRect(371), tiles, 49, 0, false, B, false, true, false, true); // glass pane SW
- drawPartialItemBlockImage(img, getRect(372), tiles, 49, 0, false, B, false, false, true, true); // glass pane EW
- drawPartialItemBlockImage(img, getRect(373), tiles, 49, 0, false, B, false, true, true, true); // glass pane SEW
- drawPartialItemBlockImage(img, getRect(374), tiles, 49, 0, false, B, true, false, true, true); // glass pane NEW
- drawPartialItemBlockImage(img, getRect(375), tiles, 49, 0, false, B, true, true, false, true); // glass pane NSW
- drawPartialItemBlockImage(img, getRect(376), tiles, 49, 0, false, B, true, true, true, false); // glass pane NSE
- drawPartialItemBlockImage(img, getRect(423), tiles, 49, 0, false, B, true, false, false, false); // glass pane N
- drawPartialItemBlockImage(img, getRect(424), tiles, 49, 0, false, B, false, true, false, false); // glass pane S
- drawPartialItemBlockImage(img, getRect(425), tiles, 49, 0, false, B, false, false, true, false); // glass pane E
- drawPartialItemBlockImage(img, getRect(426), tiles, 49, 0, false, B, false, false, false, true); // glass pane W
- drawItemBlockImage(img, getRect(395), stemtiles, 0, B); // stem level 0
- drawItemBlockImage(img, getRect(396), stemtiles, 1, B); // stem level 1
- drawItemBlockImage(img, getRect(397), stemtiles, 2, B); // stem level 2
- drawItemBlockImage(img, getRect(398), stemtiles, 3, B); // stem level 3
- drawItemBlockImage(img, getRect(399), stemtiles, 4, B); // stem level 4
- drawItemBlockImage(img, getRect(400), stemtiles, 5, B); // stem level 5
- drawItemBlockImage(img, getRect(401), stemtiles, 6, B); // stem level 6
- drawItemBlockImage(img, getRect(402), stemtiles, 7, B); // stem level 7
- drawPartialItemBlockImage(img, getRect(403), stemtiles, 8, 0, false, B, true, true, false, false); // stem pointing N
- drawPartialItemBlockImage(img, getRect(404), stemtiles, 9, 0, false, B, true, true, false, false); // stem pointing S
- drawPartialItemBlockImage(img, getRect(405), stemtiles, 8, 0, false, B, false, false, true, true); // stem pointing E
- drawPartialItemBlockImage(img, getRect(406), stemtiles, 9, 0, false, B, false, false, true, true); // stem pointing W
- drawPartialItemBlockImage(img, getRect(519), tiles, 170, 0, true, B, true, false, false, false); // cocoa level 0 stem N
- drawPartialItemBlockImage(img, getRect(520), tiles, 170, 0, false, B, false, true, false, false); // cocoa level 0 stem S
- drawPartialItemBlockImage(img, getRect(521), tiles, 170, 0, true, B, false, false, true, false); // cocoa level 0 stem E
- drawPartialItemBlockImage(img, getRect(522), tiles, 170, 0, false, B, false, false, false, true); // cocoa level 0 stem W
- drawPartialItemBlockImage(img, getRect(523), tiles, 169, 0, true, B, true, false, false, false); // cocoa level 1 stem N
- drawPartialItemBlockImage(img, getRect(524), tiles, 169, 0, false, B, false, true, false, false); // cocoa level 1 stem S
- drawPartialItemBlockImage(img, getRect(525), tiles, 169, 0, true, B, false, false, true, false); // cocoa level 1 stem E
- drawPartialItemBlockImage(img, getRect(526), tiles, 169, 0, false, B, false, false, false, true); // cocoa level 1 stem W
- drawPartialItemBlockImage(img, getRect(527), tiles, 168, 0, true, B, true, false, false, false); // cocoa level 2 stem N
- drawPartialItemBlockImage(img, getRect(528), tiles, 168, 0, false, B, false, true, false, false); // cocoa level 2 stem S
- drawPartialItemBlockImage(img, getRect(529), tiles, 168, 0, true, B, false, false, true, false); // cocoa level 2 stem E
- drawPartialItemBlockImage(img, getRect(530), tiles, 168, 0, false, B, false, false, false, true); // cocoa level 2 stem W
- drawPartialItemBlockImage(img, getRect(543), tiles, 173, 2, false, B, true, true, true, true); // tripwire NSEW
- drawPartialItemBlockImage(img, getRect(544), tiles, 173, 2, false, B, true, true, false, false); // tripwire NS
- drawPartialItemBlockImage(img, getRect(545), tiles, 173, 2, false, B, true, false, true, false); // tripwire NE
- drawPartialItemBlockImage(img, getRect(546), tiles, 173, 2, false, B, true, false, false, true); // tripwire NW
- drawPartialItemBlockImage(img, getRect(547), tiles, 173, 2, false, B, false, true, true, false); // tripwire SE
- drawPartialItemBlockImage(img, getRect(548), tiles, 173, 2, false, B, false, true, false, true); // tripwire SW
- drawPartialItemBlockImage(img, getRect(549), tiles, 173, 2, false, B, false, false, true, true); // tripwire EW
- drawPartialItemBlockImage(img, getRect(550), tiles, 173, 2, false, B, false, true, true, true); // tripwire SEW
- drawPartialItemBlockImage(img, getRect(551), tiles, 173, 2, false, B, true, false, true, true); // tripwire NEW
- drawPartialItemBlockImage(img, getRect(552), tiles, 173, 2, false, B, true, true, false, true); // tripwire NSW
- drawPartialItemBlockImage(img, getRect(553), tiles, 173, 2, false, B, true, true, true, false); // tripwire NSE
-
- drawSingleFaceBlockImage(img, getRect(44), tiles, 80, 1, B); // torch pointing S
- drawSingleFaceBlockImage(img, getRect(45), tiles, 80, 0, B); // torch pointing N
- drawSingleFaceBlockImage(img, getRect(46), tiles, 80, 3, B); // torch pointing W
- drawSingleFaceBlockImage(img, getRect(47), tiles, 80, 2, B); // torch pointing E
- drawSingleFaceBlockImage(img, getRect(74), tiles, 97, 3, B); // wood door S side
- drawSingleFaceBlockImage(img, getRect(75), tiles, 97, 2, B); // wood door N side
- drawSingleFaceBlockImage(img, getRect(76), tiles, 97, 0, B); // wood door W side
- drawSingleFaceBlockImage(img, getRect(77), tiles, 97, 1, B); // wood door E side
- drawSingleFaceBlockImage(img, getRect(78), tiles, 81, 3, B); // wood door top S
- drawSingleFaceBlockImage(img, getRect(79), tiles, 81, 2, B); // wood door top N
- drawSingleFaceBlockImage(img, getRect(80), tiles, 81, 0, B); // wood door top W
- drawSingleFaceBlockImage(img, getRect(81), tiles, 81, 1, B); // wood door top E
- drawSingleFaceBlockImage(img, getRect(82), tiles, 83, 2, B); // ladder E side
- drawSingleFaceBlockImage(img, getRect(83), tiles, 83, 3, B); // ladder W side
- drawSingleFaceBlockImage(img, getRect(84), tiles, 83, 0, B); // ladder N side
- drawSingleFaceBlockImage(img, getRect(85), tiles, 83, 1, B); // ladder S side
- drawSingleFaceBlockImage(img, getRect(111), tiles, 98, 3, B); // iron door S side
- drawSingleFaceBlockImage(img, getRect(112), tiles, 98, 2, B); // iron door N side
- drawSingleFaceBlockImage(img, getRect(113), tiles, 98, 0, B); // iron door W side
- drawSingleFaceBlockImage(img, getRect(114), tiles, 98, 1, B); // iron door E side
- drawSingleFaceBlockImage(img, getRect(115), tiles, 82, 3, B); // iron door top S
- drawSingleFaceBlockImage(img, getRect(116), tiles, 82, 2, B); // iron door top N
- drawSingleFaceBlockImage(img, getRect(117), tiles, 82, 0, B); // iron door top W
- drawSingleFaceBlockImage(img, getRect(118), tiles, 82, 1, B); // iron door top E
- drawSingleFaceBlockImage(img, getRect(141), tiles, 99, 1, B); // red torch S on
- drawSingleFaceBlockImage(img, getRect(142), tiles, 99, 0, B); // red torch N on
- drawSingleFaceBlockImage(img, getRect(143), tiles, 99, 3, B); // red torch W on
- drawSingleFaceBlockImage(img, getRect(144), tiles, 99, 2, B); // red torch E on
- drawSingleFaceBlockImage(img, getRect(145), tiles, 115, 1, B); // red torch S off
- drawSingleFaceBlockImage(img, getRect(146), tiles, 115, 0, B); // red torch N off
- drawSingleFaceBlockImage(img, getRect(147), tiles, 115, 3, B); // red torch W off
- drawSingleFaceBlockImage(img, getRect(148), tiles, 115, 2, B); // red torch E off
- drawSingleFaceBlockImage(img, getRect(277), tiles, 84, 2, B); // trapdoor open W
- drawSingleFaceBlockImage(img, getRect(278), tiles, 84, 3, B); // trapdoor open E
- drawSingleFaceBlockImage(img, getRect(279), tiles, 84, 0, B); // trapdoor open S
- drawSingleFaceBlockImage(img, getRect(280), tiles, 84, 1, B); // trapdoor open N
- drawSingleFaceBlockImage(img, getRect(539), tiles, 172, 0, B); // tripwire hook S
- drawSingleFaceBlockImage(img, getRect(540), tiles, 172, 1, B); // tripwire hook N
- drawSingleFaceBlockImage(img, getRect(541), tiles, 172, 2, B); // tripwire hook W
- drawSingleFaceBlockImage(img, getRect(542), tiles, 172, 3, B); // tripwire hook E
-
- drawPartialSingleFaceBlockImage(img, getRect(100), tiles, 4, 2, B, 0.25, 0.75, 0, 1); // wall sign facing E
- drawPartialSingleFaceBlockImage(img, getRect(101), tiles, 4, 3, B, 0.25, 0.75, 0, 1); // wall sign facing W
- drawPartialSingleFaceBlockImage(img, getRect(102), tiles, 4, 0, B, 0.25, 0.75, 0, 1); // wall sign facing N
- drawPartialSingleFaceBlockImage(img, getRect(103), tiles, 4, 1, B, 0.25, 0.75, 0, 1); // wall sign facing S
- drawPartialSingleFaceBlockImage(img, getRect(190), tiles, 1, 1, B, 0.35, 0.65, 0.35, 0.65); // stone button facing S
- drawPartialSingleFaceBlockImage(img, getRect(191), tiles, 1, 0, B, 0.35, 0.65, 0.35, 0.65); // stone button facing N
- drawPartialSingleFaceBlockImage(img, getRect(192), tiles, 1, 3, B, 0.35, 0.65, 0.35, 0.65); // stone button facing W
- drawPartialSingleFaceBlockImage(img, getRect(193), tiles, 1, 2, B, 0.35, 0.65, 0.35, 0.65); // stone button facing E
-
- drawSolidColorBlockImage(img, getRect(139), 0xd07b2748, B); // portal
-
- drawStairsS(img, getRect(50), tiles, 4, 4, B); // wood stairs asc S
- drawStairsN(img, getRect(51), tiles, 4, 4, B); // wood stairs asc N
- drawStairsW(img, getRect(52), tiles, 4, 4, B); // wood stairs asc W
- drawStairsE(img, getRect(53), tiles, 4, 4, B); // wood stairs asc E
- drawStairsS(img, getRect(96), tiles, 16, 16, B); // cobble stairs asc S
- drawStairsN(img, getRect(97), tiles, 16, 16, B); // cobble stairs asc N
- drawStairsW(img, getRect(98), tiles, 16, 16, B); // cobble stairs asc W
- drawStairsE(img, getRect(99), tiles, 16, 16, B); // cobble stairs asc E
- drawStairsS(img, getRect(304), tiles, 7, 7, B); // brick stairs asc S
- drawStairsN(img, getRect(305), tiles, 7, 7, B); // brick stairs asc N
- drawStairsW(img, getRect(306), tiles, 7, 7, B); // brick stairs asc W
- drawStairsE(img, getRect(307), tiles, 7, 7, B); // brick stairs asc E
- drawStairsS(img, getRect(308), tiles, 54, 54, B); // stone brick stairs asc S
- drawStairsN(img, getRect(309), tiles, 54, 54, B); // stone brick stairs asc N
- drawStairsW(img, getRect(310), tiles, 54, 54, B); // stone brick stairs asc W
- drawStairsE(img, getRect(311), tiles, 54, 54, B); // stone brick stairs asc E
- drawStairsS(img, getRect(312), tiles, 224, 224, B); // nether brick stairs asc S
- drawStairsN(img, getRect(313), tiles, 224, 224, B); // nether brick stairs asc N
- drawStairsW(img, getRect(314), tiles, 224, 224, B); // nether brick stairs asc W
- drawStairsE(img, getRect(315), tiles, 224, 224, B); // nether brick stairs asc E
- drawStairsS(img, getRect(470), tiles, 192, 176, B); // sandstone stairs asc S
- drawStairsN(img, getRect(471), tiles, 192, 176, B); // sandstone stairs asc N
- drawStairsW(img, getRect(472), tiles, 192, 176, B); // sandstone stairs asc W
- drawStairsE(img, getRect(473), tiles, 192, 176, B); // sandstone stairs asc E
- drawStairsS(img, getRect(495), tiles, 198, 198, B); // pine stairs asc S
- drawStairsN(img, getRect(496), tiles, 198, 198, B); // pine stairs asc N
- drawStairsW(img, getRect(497), tiles, 198, 198, B); // pine stairs asc W
- drawStairsE(img, getRect(498), tiles, 198, 198, B); // pine stairs asc E
- drawStairsS(img, getRect(503), tiles, 214, 214, B); // birch stairs asc S
- drawStairsN(img, getRect(504), tiles, 214, 214, B); // birch stairs asc N
- drawStairsW(img, getRect(505), tiles, 214, 214, B); // birch stairs asc W
- drawStairsE(img, getRect(506), tiles, 214, 214, B); // birch stairs asc E
- drawStairsS(img, getRect(511), tiles, 199, 199, B); // jungle stairs asc S
- drawStairsN(img, getRect(512), tiles, 199, 199, B); // jungle stairs asc N
- drawStairsW(img, getRect(513), tiles, 199, 199, B); // jungle stairs asc W
- drawStairsE(img, getRect(514), tiles, 199, 199, B); // jungle stairs asc E
- drawInvStairsS(img, getRect(438), tiles, 4, 4, B); // wood stairs asc S inverted
- drawInvStairsN(img, getRect(439), tiles, 4, 4, B); // wood stairs asc N inverted
- drawInvStairsW(img, getRect(440), tiles, 4, 4, B); // wood stairs asc W inverted
- drawInvStairsE(img, getRect(441), tiles, 4, 4, B); // wood stairs asc E inverted
- drawInvStairsS(img, getRect(442), tiles, 16, 16, B); // cobble stairs asc S inverted
- drawInvStairsN(img, getRect(443), tiles, 16, 16, B); // cobble stairs asc N inverted
- drawInvStairsW(img, getRect(444), tiles, 16, 16, B); // cobble stairs asc W inverted
- drawInvStairsE(img, getRect(445), tiles, 16, 16, B); // cobble stairs asc E inverted
- drawInvStairsS(img, getRect(446), tiles, 7, 7, B); // brick stairs asc S inverted
- drawInvStairsN(img, getRect(447), tiles, 7, 7, B); // brick stairs asc N inverted
- drawInvStairsW(img, getRect(448), tiles, 7, 7, B); // brick stairs asc W inverted
- drawInvStairsE(img, getRect(449), tiles, 7, 7, B); // brick stairs asc E inverted
- drawInvStairsS(img, getRect(450), tiles, 54, 54, B); // stone brick stairs asc S inverted
- drawInvStairsN(img, getRect(451), tiles, 54, 54, B); // stone brick stairs asc N inverted
- drawInvStairsW(img, getRect(452), tiles, 54, 54, B); // stone brick stairs asc W inverted
- drawInvStairsE(img, getRect(453), tiles, 54, 54, B); // stone brick stairs asc E inverted
- drawInvStairsS(img, getRect(454), tiles, 224, 224, B); // nether brick stairs asc S inverted
- drawInvStairsN(img, getRect(455), tiles, 224, 224, B); // nether brick stairs asc N inverted
- drawInvStairsW(img, getRect(456), tiles, 224, 224, B); // nether brick stairs asc W inverted
- drawInvStairsE(img, getRect(457), tiles, 224, 224, B); // nether brick stairs asc E inverted
- drawInvStairsS(img, getRect(474), tiles, 192, 176, B); // sandstone stairs asc S inverted
- drawInvStairsN(img, getRect(475), tiles, 192, 176, B); // sandstone stairs asc N inverted
- drawInvStairsW(img, getRect(476), tiles, 192, 176, B); // sandstone stairs asc W inverted
- drawInvStairsE(img, getRect(477), tiles, 192, 176, B); // sandstone stairs asc E inverted
- drawInvStairsS(img, getRect(499), tiles, 198, 198, B); // pine stairs asc S inverted
- drawInvStairsN(img, getRect(500), tiles, 198, 198, B); // pine stairs asc N inverted
- drawInvStairsW(img, getRect(501), tiles, 198, 198, B); // pine stairs asc W inverted
- drawInvStairsE(img, getRect(502), tiles, 198, 198, B); // pine stairs asc E inverted
- drawInvStairsS(img, getRect(507), tiles, 214, 214, B); // birch stairs asc S inverted
- drawInvStairsN(img, getRect(508), tiles, 214, 214, B); // birch stairs asc N inverted
- drawInvStairsW(img, getRect(509), tiles, 214, 214, B); // birch stairs asc W inverted
- drawInvStairsE(img, getRect(510), tiles, 214, 214, B); // birch stairs asc E inverted
- drawInvStairsS(img, getRect(515), tiles, 199, 199, B); // jungle stairs asc S inverted
- drawInvStairsN(img, getRect(516), tiles, 199, 199, B); // jungle stairs asc N inverted
- drawInvStairsW(img, getRect(517), tiles, 199, 199, B); // jungle stairs asc W inverted
- drawInvStairsE(img, getRect(518), tiles, 199, 199, B); // jungle stairs asc E inverted
-
- drawFloorBlockImage(img, getRect(55), tiles, 164, 0, B); // redstone wire NSEW
- drawFloorBlockImage(img, getRect(86), tiles, 128, 1, B); // track EW
- drawFloorBlockImage(img, getRect(87), tiles, 128, 0, B); // track NS
- drawFloorBlockImage(img, getRect(92), tiles, 112, 1, B); // track NE corner
- drawFloorBlockImage(img, getRect(93), tiles, 112, 0, B); // track SE corner
- drawFloorBlockImage(img, getRect(94), tiles, 112, 3, B); // track SW corner
- drawFloorBlockImage(img, getRect(95), tiles, 112, 2, B); // track NW corner
- drawFloorBlockImage(img, getRect(252), tiles, 179, 1, B); // booster on EW
- drawFloorBlockImage(img, getRect(253), tiles, 179, 0, B); // booster on NS
- drawFloorBlockImage(img, getRect(258), tiles, 163, 1, B); // booster off EW
- drawFloorBlockImage(img, getRect(259), tiles, 163, 0, B); // booster off NS
- drawFloorBlockImage(img, getRect(264), tiles, 195, 1, B); // detector EW
- drawFloorBlockImage(img, getRect(265), tiles, 195, 0, B); // detector NS
- drawFloorBlockImage(img, getRect(276), tiles, 84, 0, B); // trapdoor closed
- drawFloorBlockImage(img, getRect(316), tiles, 76, 0, B); // lily pad
-
- drawAngledFloorBlockImage(img, getRect(200), tiles, 128, 0, 0, B); // track asc S
- drawAngledFloorBlockImage(img, getRect(201), tiles, 128, 0, 2, B); // track asc N
- drawAngledFloorBlockImage(img, getRect(202), tiles, 128, 1, 3, B); // track asc E
- drawAngledFloorBlockImage(img, getRect(203), tiles, 128, 1, 1, B); // track asc W
- drawAngledFloorBlockImage(img, getRect(254), tiles, 179, 0, 0, B); // booster on asc S
- drawAngledFloorBlockImage(img, getRect(255), tiles, 179, 0, 2, B); // booster on asc N
- drawAngledFloorBlockImage(img, getRect(256), tiles, 179, 1, 3, B); // booster on asc E
- drawAngledFloorBlockImage(img, getRect(257), tiles, 179, 1, 1, B); // booster on asc W
- drawAngledFloorBlockImage(img, getRect(260), tiles, 163, 0, 0, B); // booster off asc S
- drawAngledFloorBlockImage(img, getRect(261), tiles, 163, 0, 2, B); // booster off asc N
- drawAngledFloorBlockImage(img, getRect(262), tiles, 163, 1, 3, B); // booster off asc E
- drawAngledFloorBlockImage(img, getRect(263), tiles, 163, 1, 1, B); // booster off asc W
- drawAngledFloorBlockImage(img, getRect(266), tiles, 195, 0, 0, B); // detector asc S
- drawAngledFloorBlockImage(img, getRect(267), tiles, 195, 0, 2, B); // detector asc N
- drawAngledFloorBlockImage(img, getRect(268), tiles, 195, 1, 3, B); // detector asc E
- drawAngledFloorBlockImage(img, getRect(269), tiles, 195, 1, 1, B); // detector asc W
-
- drawFencePost(img, getRect(134), tiles, 4, B); // fence post
- drawFence(img, getRect(158), tiles, 4, true, false, false, false, true, B); // fence N
- drawFence(img, getRect(159), tiles, 4, false, true, false, false, true, B); // fence S
- drawFence(img, getRect(160), tiles, 4, true, true, false, false, true, B); // fence NS
- drawFence(img, getRect(161), tiles, 4, false, false, true, false, true, B); // fence E
- drawFence(img, getRect(162), tiles, 4, true, false, true, false, true, B); // fence NE
- drawFence(img, getRect(163), tiles, 4, false, true, true, false, true, B); // fence SE
- drawFence(img, getRect(164), tiles, 4, true, true, true, false, true, B); // fence NSE
- drawFence(img, getRect(165), tiles, 4, false, false, false, true, true, B); // fence W
- drawFence(img, getRect(166), tiles, 4, true, false, false, true, true, B); // fence NW
- drawFence(img, getRect(167), tiles, 4, false, true, false, true, true, B); // fence SW
- drawFence(img, getRect(168), tiles, 4, true, true, false, true, true, B); // fence NSW
- drawFence(img, getRect(169), tiles, 4, false, false, true, true, true, B); // fence EW
- drawFence(img, getRect(170), tiles, 4, true, false, true, true, true, B); // fence NEW
- drawFence(img, getRect(171), tiles, 4, false, true, true, true, true, B); // fence SEW
- drawFence(img, getRect(172), tiles, 4, true, true, true, true, true, B); // fence NSEW
- drawFencePost(img, getRect(332), tiles, 224, B); // nether fence post
- drawFence(img, getRect(317), tiles, 224, true, false, false, false, true, B); // nether fence N
- drawFence(img, getRect(318), tiles, 224, false, true, false, false, true, B); // nether fence S
- drawFence(img, getRect(319), tiles, 224, true, true, false, false, true, B); // nether fence NS
- drawFence(img, getRect(320), tiles, 224, false, false, true, false, true, B); // nether fence E
- drawFence(img, getRect(321), tiles, 224, true, false, true, false, true, B); // nether fence NE
- drawFence(img, getRect(322), tiles, 224, false, true, true, false, true, B); // nether fence SE
- drawFence(img, getRect(323), tiles, 224, true, true, true, false, true, B); // nether fence NSE
- drawFence(img, getRect(324), tiles, 224, false, false, false, true, true, B); // nether fence W
- drawFence(img, getRect(325), tiles, 224, true, false, false, true, true, B); // nether fence NW
- drawFence(img, getRect(326), tiles, 224, false, true, false, true, true, B); // nether fence SW
- drawFence(img, getRect(327), tiles, 224, true, true, false, true, true, B); // nether fence NSW
- drawFence(img, getRect(328), tiles, 224, false, false, true, true, true, B); // nether fence EW
- drawFence(img, getRect(329), tiles, 224, true, false, true, true, true, B); // nether fence NEW
- drawFence(img, getRect(330), tiles, 224, false, true, true, true, true, B); // nether fence SEW
- drawFence(img, getRect(331), tiles, 224, true, true, true, true, true, B); // nether fence NSEW
- drawFence(img, getRect(346), tiles, 4, false, false, true, true, false, B); // fence gate EW
- drawFence(img, getRect(347), tiles, 4, true, true, false, false, false, B); // fence gate NS
-
- drawSign(img, getRect(70), tiles, 4, B); // sign facing N/S
- drawSign(img, getRect(71), tiles, 4, B); // sign facing NE/SW
- drawSign(img, getRect(72), tiles, 4, B); // sign facing E/W
- drawSign(img, getRect(73), tiles, 4, B); // sign facing SE/NW
-
- drawWallLever(img, getRect(194), tiles, 1, B); // wall lever facing S
- drawWallLever(img, getRect(195), tiles, 0, B); // wall lever facing N
- drawWallLever(img, getRect(196), tiles, 3, B); // wall lever facing W
- drawWallLever(img, getRect(197), tiles, 2, B); // wall lever facing E
- drawFloorLeverEW(img, getRect(198), tiles, B); // ground lever EW
- drawFloorLeverNS(img, getRect(199), tiles, B); // ground lever NS
-
- drawRepeater(img, getRect(240), tiles, 147, 0, B); // repeater on N
- drawRepeater(img, getRect(241), tiles, 147, 2, B); // repeater on S
- drawRepeater(img, getRect(242), tiles, 147, 3, B); // repeater on E
- drawRepeater(img, getRect(243), tiles, 147, 1, B); // repeater on W
- drawRepeater(img, getRect(244), tiles, 131, 0, B); // repeater on N
- drawRepeater(img, getRect(245), tiles, 131, 2, B); // repeater on S
- drawRepeater(img, getRect(246), tiles, 131, 3, B); // repeater on E
- drawRepeater(img, getRect(247), tiles, 131, 1, B); // repeater on W
-
- drawFire(img, getRect(189), firetile, B); // fire
-
- drawBrewingStand(img, getRect(350), tiles, 156, 157, B); // brewing stand
-
- drawCauldron(img, getRect(351), tiles, 154, -1, 0, B); // cauldron empty
- drawCauldron(img, getRect(352), tiles, 154, 205, CUTOFF_10_16, B); // cauldron 1/3 full
- drawCauldron(img, getRect(353), tiles, 154, 205, CUTOFF_6_16, B); // cauldron 2/3 full
- drawCauldron(img, getRect(354), tiles, 154, 205, CUTOFF_2_16, B); // cauldron full
-
- drawDragonEgg(img, getRect(378), tiles, 167, B); // dragon egg
-
- drawVines(img, getRect(379), tiles, 143, B, false, false, false, false, true); // vines top only
- drawVines(img, getRect(380), tiles, 143, B, true, false, false, false, false); // vines N
- drawVines(img, getRect(381), tiles, 143, B, false, true, false, false, false); // vines S
- drawVines(img, getRect(382), tiles, 143, B, true, true, false, false, false); // vines NS
- drawVines(img, getRect(383), tiles, 143, B, false, false, true, false, false); // vines E
- drawVines(img, getRect(384), tiles, 143, B, true, false, true, false, false); // vines NE
- drawVines(img, getRect(385), tiles, 143, B, false, true, true, false, false); // vines SE
- drawVines(img, getRect(386), tiles, 143, B, true, true, true, false, false); // vines NSE
- drawVines(img, getRect(387), tiles, 143, B, false, false, false, true, false); // vines W
- drawVines(img, getRect(388), tiles, 143, B, true, false, false, true, false); // vines NW
- drawVines(img, getRect(389), tiles, 143, B, false, true, false, true, false); // vines SW
- drawVines(img, getRect(390), tiles, 143, B, true, true, false, true, false); // vines NSW
- drawVines(img, getRect(391), tiles, 143, B, false, false, true, true, false); // vines EW
- drawVines(img, getRect(392), tiles, 143, B, true, false, true, true, false); // vines NEW
- drawVines(img, getRect(393), tiles, 143, B, false, true, true, true, false); // vines SEW
- drawVines(img, getRect(394), tiles, 143, B, true, true, true, true, false); // vines NSEW
-
- return true;
-}
-
+// Copyright 2010-2012 Michael J. Nelson
+//
+// This file is part of pigmap.
+//
+// pigmap is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// pigmap is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with pigmap. If not, see .
+
+#include
+#include
+#include
+#include
+#include
+
+#include "blockimages.h"
+#include "utils.h"
+
+using namespace std;
+
+
+// in this file, confusingly, "tile" refers to the texture/image tile, not to the map tiles
+// also, this is a nasty mess in here; apologies to anyone reading this
+
+
+void writeBlockImagesVersion(int B, const string& imgpath, int32_t version)
+{
+ string versionfile = imgpath + "/blocks-" + tostring(B) + ".version";
+ ofstream outfile(versionfile.c_str());
+ outfile << version;
+}
+
+// get the version number associated with blocks-B.png; this is stored
+// in blocks-B.version, which is just a single string with the version number
+int getBlockImagesVersion(int B, const string& imgpath)
+{
+ string versionfile = imgpath + "/blocks-" + tostring(B) + ".version";
+ ifstream infile(versionfile.c_str());
+ // if there's no version file, assume the version is 0, so new version file
+ // will be generated according to the descriptor file version
+ if (infile.fail())
+ {
+ infile.close();
+ writeBlockImagesVersion(B, imgpath, 0);
+ return 0;
+ }
+ // otherwise, read the version
+ int32_t v;
+ infile >> v;
+ // if the version is clearly insane, ignore it
+ if (v < 0 || v > 10000)
+ v = 0;
+ return v;
+}
+
+bool BlockImages::create(int B, const string& imgpath)
+{
+ rectsize = 4*B;
+
+ // 1.5
+ // Block mapping is specified in a separate list, pointing to textures listed in another file
+ string blocktexturesfile = imgpath + "/blocktextures.list";
+ string blockdescriptorfile = imgpath + "/blockdescriptor.list";
+
+ ifstream texturelist(blocktexturesfile.c_str());
+ ifstream descriptorlist(blockdescriptorfile.c_str());
+ if(descriptorlist.fail())
+ {
+ descriptorlist.close();
+ cerr << blockdescriptorfile << " is missing" << endl;
+ return false;
+ }
+ setBlockDescriptors(descriptorlist);
+ blockversion = setOffsets();
+
+ // first, see if blocks-B.png exists, and what its version is
+ int biversion = getBlockImagesVersion(B, imgpath);
+ string blocksfile = imgpath + "/blocks-" + tostring(B) + ".png";
+ if (img.readPNG(blocksfile))
+ {
+ // if it's the correct size and version, we're okay
+ int w = rectsize*16, h = (blockversion/16 + 1) * rectsize;
+ if (img.w == w && img.h == h && biversion == blockversion)
+ {
+ retouchAlphas(B);
+ checkOpacityAndTransparency(B);
+ return true;
+ }
+ // if it's a previous version, we will need to build a new one, in case descriptor order
+ // has been changed
+ if (biversion < blockversion && img.w == w && img.h == (biversion/16 + 1) * rectsize)
+ {
+ cerr << blocksfile << " is of and older version (" << biversion << ")" << endl;
+ cerr << "...new block file will be built (" << blockversion << ")" << endl;
+ }
+ // otherwise, the file's been trashed somehow; rebuild it
+ else
+ {
+ cerr << blocksfile << " has incorrect size (expected " << w << "x" << h << ")" << endl;
+ cerr << "...will try to create new block file" << blocksfile << endl;
+ }
+ }
+ else
+ cerr << blocksfile << " not found (or failed to read as PNG); will try to build from provided textures" << endl;
+
+ // build blocks-B.png from list of textures in texture list file
+ if(texturelist.fail())
+ {
+ texturelist.close();
+ cerr << blocktexturesfile << " is missing" << endl;
+ return false;
+ }
+ else if (!construct(B, texturelist, descriptorlist, imgpath))
+ {
+ cerr << "image path is missing at least one of the required files" << endl;
+ cerr << "from minecraft.jar or your tile pack." << endl;
+ cerr << "endportal.png -- included with pigmap" << endl;
+ return false;
+ }
+
+ // write blocks-B.png and blocks-B.version
+ img.writePNG(blocksfile);
+ writeBlockImagesVersion(B, imgpath, blockversion);
+
+ retouchAlphas(B);
+ checkOpacityAndTransparency(B);
+ return true;
+}
+
+
+
+// take the various textures from chest.png and use them to construct "flat" 14x14 tiles (or whatever
+// the multiplied size is, if the textures are larger), then resize those flat images to 2Bx2B
+// ...the resulting image will be a 3x1 array of 2Bx2B images: first the top, then the front, then
+// the side
+int generateChestTiles(unordered_map& blockTextures, const RGBAImage& texture, const string& name, int B)
+{
+ int scale = texture.w / 64;
+
+ int chestSize = 14 * scale;
+ RGBAImage chesttiles;
+ chesttiles.create(chestSize*3, chestSize);
+
+ // top texture just gets copied straight over
+ blit(texture, ImageRect(14*scale, 0, 14*scale, 14*scale), chesttiles, 0, 0);
+
+ // front tile gets the front lid texture plus the front bottom texture, then the latch on
+ // top of that
+ blit(texture, ImageRect(14*scale, 14*scale, 14*scale, 4*scale), chesttiles, chestSize, 0);
+ blit(texture, ImageRect(14*scale, 33*scale, 14*scale, 10*scale), chesttiles, chestSize, 4*scale);
+ blit(texture, ImageRect(scale, scale, 2*scale, 4*scale), chesttiles, chestSize + 6*scale, 2*scale);
+
+ // side tile gets the side lid texture plus the side bottom texture
+ blit(texture, ImageRect(28*scale, 14*scale, 14*scale, 4*scale), chesttiles, chestSize*2, 0);
+ blit(texture, ImageRect(28*scale, 33*scale, 14*scale, 10*scale), chesttiles, chestSize*2, 4*scale);
+
+ int tilesize = 2*B;
+ for (int x = 0; x < 3; x++)
+ {
+ RGBAImage img;
+ img.create(tilesize, tilesize);
+ resize(chesttiles, ImageRect(x*chestSize, 0, chestSize, chestSize),
+ img, ImageRect(0, 0, tilesize, tilesize));
+ blockTextures["/" + name + "_" + tostring(x)] = img;
+ }
+ return 3;
+}
+
+// same thing for largechest.png--construct flat tiles, then resize
+// ...resulting image is a 7x1 array of 2Bx2B images:
+// -left half of top
+// -right half of top
+// -left half of front
+// -right half of front
+// -left half of back
+// -right half of back
+// -side
+int generateLargeChestTiles(unordered_map& blockTextures, const RGBAImage& texture, const string& name, int B)
+{
+ int scale = texture.w / 128;
+
+ int tilesize = 2*B;
+ RGBAImage chesttiles;
+ chesttiles.create(7*tilesize, tilesize);
+
+ // top texture gets copied straight over--note that the original texture is 30x14, but
+ // we're putting it into two squares
+ resize(texture, ImageRect(14*scale, 0, 30*scale, 14*scale), chesttiles, ImageRect(0, 0, tilesize*2, tilesize));
+ // front tile gets the front lid texture plus the front bottom texture, then the latch
+ // on top of that
+ RGBAImage fronttiles;
+ fronttiles.create(30*scale, 14*scale);
+ blit(texture, ImageRect(14*scale, 14*scale, 30*scale, 4*scale), fronttiles, 0, 0);
+ blit(texture, ImageRect(14*scale, 33*scale, 30*scale, 10*scale), fronttiles, 0, 4*scale);
+ blit(texture, ImageRect(scale, scale, 2*scale, 4*scale), fronttiles, 14*scale, 2*scale);
+ // do two resizes, to make sure the special end processing picks up the latch
+ resize(fronttiles, ImageRect(0, 0, 15*scale, 14*scale), chesttiles, ImageRect(2*tilesize, 0, tilesize, tilesize));
+ resize(fronttiles, ImageRect(15*scale, 0, 15*scale, 14*scale), chesttiles, ImageRect(3*tilesize, 0, tilesize, tilesize));
+
+ // back tile gets the back lid texture plus the back bottom texture
+ RGBAImage backtiles;
+ backtiles.create(30*scale, 14*scale);
+ blit(texture, ImageRect(58*scale, 14*scale, 30*scale, 4*scale), backtiles, 0, 0);
+ blit(texture, ImageRect(58*scale, 33*scale, 30*scale, 10*scale), backtiles, 0, 4*scale);
+ resize(backtiles, ImageRect(0, 0, 30*scale, 14*scale), chesttiles, ImageRect(4*tilesize, 0, 2*tilesize, tilesize));
+
+ // side tile gets the side lid texture plus the side bottom texture
+ RGBAImage sidetile;
+ sidetile.create(14*scale, 14*scale);
+ blit(texture, ImageRect(44*scale, 14*scale, 14*scale, 4*scale), sidetile, 0, 0);
+ blit(texture, ImageRect(44*scale, 33*scale, 14*scale, 10*scale), sidetile, 0, 4*scale);
+ resize(sidetile, ImageRect(0, 0, 14*scale, 14*scale), chesttiles, ImageRect(6*tilesize, 0, tilesize, tilesize));
+
+ for (int x = 0; x < 7; x++)
+ {
+ RGBAImage img;
+ img.create(tilesize, tilesize);
+ blit(chesttiles, ImageRect(x*tilesize, 0, tilesize, tilesize), img, 0, 0);
+ blockTextures["/" + name + "_" + tostring(x)] = img;
+ }
+
+ return 3;
+}
+
+
+
+// iterate over the pixels of a 2B-sized texture tile; used for both source rectangles and
+// destination parallelograms
+struct FaceIterator
+{
+ bool end; // true if we're done
+ int x, y; // current pixel
+ int pos;
+
+ int size; // number of columns to draw, as well as number of pixels in each
+ int deltaY; // amount to skew y-coord every 2 columns: -1 or 1 for N/S or W/E facing destinations, 0 for source
+
+ FaceIterator(int xstart, int ystart, int dY, int sz)
+ {
+ size = sz;
+ deltaY = dY;
+ end = false;
+ x = xstart;
+ y = ystart;
+ pos = 0;
+ }
+
+ void advance()
+ {
+ pos++;
+ if (pos >= size*size)
+ {
+ end = true;
+ return;
+ }
+ y++;
+ if (pos % size == 0)
+ {
+ x++;
+ y -= size;
+ if (pos % (2*size) == size)
+ y += deltaY;
+ }
+ }
+};
+
+// like FaceIterator with no deltaY (for source rectangles), but with the source rotated and/or flipped
+struct RotatedFaceIterator
+{
+ bool end;
+ int x, y;
+ int pos;
+
+ int size;
+ int rot; // 0 = down, then right; 1 = left, then down; 2 = up, then left; 3 = right, then up
+ bool flipX;
+ int dx1, dy1, dx2, dy2;
+
+ RotatedFaceIterator(int xstart, int ystart, int r, int sz, bool fX)
+ {
+ size = sz;
+ rot = r;
+ flipX = fX;
+ end = false;
+ pos = 0;
+ if (rot == 0)
+ {
+ x = flipX ? (xstart + size - 1) : xstart;
+ y = ystart;
+ dx1 = 0;
+ dy1 = 1;
+ dx2 = flipX ? -1 : 1;
+ dy2 = 0;
+ }
+ else if (rot == 1)
+ {
+ x = flipX ? xstart : (xstart + size - 1);
+ y = ystart;
+ dx1 = flipX ? 1 : -1;
+ dy1 = 0;
+ dx2 = 0;
+ dy2 = 1;
+ }
+ else if (rot == 2)
+ {
+ x = flipX ? xstart : (xstart + size - 1);
+ y = ystart + size - 1;
+ dx1 = 0;
+ dy1 = -1;
+ dx2 = flipX ? 1 : -1;
+ dy2 = 0;
+ }
+ else
+ {
+ x = flipX ? (xstart + size - 1) : xstart;
+ y = ystart + size - 1;
+ dx1 = flipX ? -1 : 1;
+ dy1 = 0;
+ dx2 = 0;
+ dy2 = -1;
+ }
+ }
+
+ void advance()
+ {
+ pos++;
+ if (pos >= size*size)
+ {
+ end = true;
+ return;
+ }
+ x += dx1;
+ y += dy1;
+ if (pos % size == 0)
+ {
+ x += dx2;
+ y += dy2;
+ x -= dx1 * size;
+ y -= dy1 * size;
+ }
+ }
+};
+
+// iterate over the pixels of the top face of a block
+struct TopFaceIterator
+{
+ bool end; // true if we're done
+ int x, y; // current pixel
+ int pos;
+
+ int size; // number of "columns", and number of pixels in each
+
+ TopFaceIterator(int xstart, int ystart, int sz)
+ {
+ size = sz;
+ end = false;
+ x = xstart;
+ y = ystart;
+ pos = 0;
+ }
+
+ void advance()
+ {
+ if ((pos/size) % 2 == 0)
+ {
+ int m = pos % size;
+ if (m == size - 1)
+ {
+ x += size - 1;
+ y -= size/2;
+ }
+ else if (m == size - 2)
+ y++;
+ else if (m % 2 == 0)
+ {
+ x--;
+ y++;
+ }
+ else
+ x--;
+ }
+ else
+ {
+ int m = pos % size;
+ if (m == 0)
+ y++;
+ else if (m == size - 1)
+ {
+ x += size - 1;
+ y -= size/2 - 1;
+ }
+ else if (m % 2 == 0)
+ {
+ x--;
+ y++;
+ }
+ else
+ x--;
+ }
+ pos++;
+ if (pos >= size*size)
+ end = true;
+ }
+};
+
+
+struct SourceTile
+{
+ const RGBAImage *image; // or NULL for no tile
+ int xpos, ypos; // tile offset within the image
+ int rot;
+ bool flipX;
+
+ SourceTile(const RGBAImage *img, int r, bool f) : image(img), xpos(0), ypos(0), rot(r), flipX(f) {}
+ SourceTile() : image(NULL), xpos(0), ypos(0), rot(0), flipX(false) {}
+ bool valid() const {return image != NULL;}
+};
+
+// iterate over a square source tile, with possible rotation and flip
+struct SourceIterator
+{
+ SourceIterator(const SourceTile& tile, int tilesize)
+ : image(*(tile.image)), faceit(tile.xpos*tilesize, tile.ypos*tilesize, tile.rot, tilesize, tile.flipX) {}
+
+ void advance() {faceit.advance();}
+ bool end() {return faceit.end;}
+ RGBAPixel pixel() {return image(faceit.x, faceit.y);}
+
+ const RGBAImage& image;
+ RotatedFaceIterator faceit;
+};
+
+// construct a source iterator for a given texture tile with rotation and/or flip
+SourceTile blockTile(const RGBAImage& tile, int rot, bool flipX)
+{
+ return SourceTile(&tile, rot, flipX);
+}
+SourceTile blockTile(const RGBAImage& tile)
+{
+ return blockTile(tile, 0, false);
+}
+
+
+int deinterpolate(int targetj, int srcrange, int destrange)
+{
+ for (int i = 0; i < destrange; i++)
+ {
+ int j = interpolate(i, destrange, srcrange);
+ if (j >= targetj)
+ return i;
+ }
+ return destrange - 1;
+}
+
+// draw a normal block image, using three texture tiles (which may be flipped/rotated/missing), and adding a bit of shadow
+// to the N and W faces
+void drawRotatedBlockImage(RGBAImage& dest, const ImageRect& drect, const SourceTile& Wface, const SourceTile& Sface, const SourceTile& Uface, int B) // re-oriented
+{
+ int tilesize = 2*B;
+ // N face starts at [0,B]
+ if (Wface.valid())
+ {
+ FaceIterator dstit(drect.x, drect.y + B, 1, tilesize);
+ for (SourceIterator srcit(Wface, tilesize); !srcit.end(); srcit.advance(), dstit.advance())
+ {
+ dest(dstit.x, dstit.y) = srcit.pixel();
+ darken(dest(dstit.x, dstit.y), 0.9, 0.9, 0.9);
+ }
+ }
+ // W face starts at [2B,2B]
+ if (Sface.valid())
+ {
+ FaceIterator dstit(drect.x + 2*B, drect.y + 2*B, -1, tilesize);
+ for (SourceIterator srcit(Sface, tilesize); !srcit.end(); srcit.advance(), dstit.advance())
+ {
+ dest(dstit.x, dstit.y) = srcit.pixel();
+ darken(dest(dstit.x, dstit.y), 0.8, 0.8, 0.8);
+ }
+ }
+ // U face starts at [2B-1,0]
+ if (Uface.valid())
+ {
+ TopFaceIterator dstit(drect.x + 2*B-1, drect.y, tilesize);
+ for (SourceIterator srcit(Uface, tilesize); !srcit.end(); srcit.advance(), dstit.advance())
+ {
+ dest(dstit.x, dstit.y) = srcit.pixel();
+ }
+ }
+}
+
+// overload of drawRotatedBlockImage taking three .png tiles
+void drawBlockImage(RGBAImage& dest, const ImageRect& drect, RGBAImage& Wface, RGBAImage& Sface, RGBAImage& Uface, int B) // re-oriented
+{
+ drawRotatedBlockImage(dest, drect, blockTile(Wface), blockTile(Sface), blockTile(Uface), B);
+}
+
+// draw a block image where the block isn't full height (half-steps, snow, etc.)
+// topcutoff is the number of pixels (out of 2B) to chop off the top of the N and W faces
+// bottomcutoff is the number of pixels (out of 2B) to chop off the bottom
+// if shift is true, we start copying pixels from the very top of the source tile, even if there's a topcutoff
+// U face can also be rotated, and N/W faces can be X-flipped (set 0x1 for N, 0x2 for W)
+void drawPartialBlockImage(RGBAImage& dest, const ImageRect& drect, RGBAImage& Wface, RGBAImage& Sface, RGBAImage& Uface, int B, bool W, bool S, bool U, int topcutoff, int bottomcutoff, int rot, int flip, bool shift) // re-oriented
+{
+ int tilesize = 2*B;
+ if (topcutoff + bottomcutoff >= tilesize)
+ return;
+ int end = tilesize - bottomcutoff;
+ // W face starts at [0,B]
+ if (W)
+ {
+ FaceIterator dstit(drect.x, drect.y + B, 1, tilesize);
+ for (RotatedFaceIterator srcit(0, 0, 0, tilesize, flip & 0x1); !srcit.end; srcit.advance(), dstit.advance())
+ {
+ if (dstit.pos % tilesize >= topcutoff && dstit.pos % tilesize < end)
+ {
+ dest(dstit.x, dstit.y) = Wface(srcit.x, srcit.y - (shift ? topcutoff : 0));
+ darken(dest(dstit.x, dstit.y), 0.9, 0.9, 0.9);
+ }
+ }
+ }
+ // S face starts at [2B,2B]
+ if (S)
+ {
+ FaceIterator dstit(drect.x + 2*B, drect.y + 2*B, -1, tilesize);
+ for (RotatedFaceIterator srcit(0, 0, 0, tilesize, flip & 0x2); !srcit.end; srcit.advance(), dstit.advance())
+ {
+ if (dstit.pos % tilesize >= topcutoff && dstit.pos % tilesize < end)
+ {
+ dest(dstit.x, dstit.y) = Sface(srcit.x, srcit.y - (shift ? topcutoff : 0));
+ darken(dest(dstit.x, dstit.y), 0.8, 0.8, 0.8);
+ }
+ }
+ }
+ // U face starts at [2B-1,topcutoff]
+ if (U)
+ {
+ TopFaceIterator dstit(drect.x + 2*B-1, drect.y + topcutoff, tilesize);
+ for (RotatedFaceIterator srcit(0, 0, rot, tilesize, false); !srcit.end; srcit.advance(), dstit.advance())
+ {
+ dest(dstit.x, dstit.y) = Uface(srcit.x, srcit.y);
+ }
+ }
+}
+// override drawPartialBlockImage without arguments for optional face drawing (draw all faces by default)
+void drawPartialBlockImage(RGBAImage& dest, const ImageRect& drect, RGBAImage& Wface, RGBAImage& Sface, RGBAImage& Uface, int B, int topcutoff, int bottomcutoff, int rot, int flip, bool shift)
+{
+ drawPartialBlockImage(dest, drect, Wface, Sface, Uface, B, true, true, true, topcutoff, bottomcutoff, rot, flip, shift);
+}
+
+// draw two flat copies of a tile intersecting at the block center (saplings, etc.)
+void drawItemBlockImage(RGBAImage& dest, const ImageRect& drect, const SourceTile& tile, bool N, bool S, bool W, bool E, int B) // re-oriented
+{
+ if (!tile.valid())
+ return;
+ int tilesize = 2*B;
+ int cutoff = tilesize/2;
+ // S face starting at [B,1.5B] -- eastern half only
+ if (E)
+ {
+ FaceIterator dstit(drect.x + B, drect.y + B*3/2, -1, tilesize);
+ for (SourceIterator srcit(tile, tilesize); !srcit.end(); srcit.advance(), dstit.advance())
+ {
+ if (dstit.pos / tilesize >= cutoff)
+ blend(dest(dstit.x, dstit.y), srcit.pixel());
+ }
+ }
+ // W face starting at [B,0.5B]
+ if (N || S)
+ {
+ FaceIterator dstit(drect.x + B, drect.y + B/2, 1, tilesize);
+ for (SourceIterator srcit(tile, tilesize); !srcit.end(); srcit.advance(), dstit.advance())
+ {
+ if ((S && dstit.pos / tilesize >= cutoff) || (N && dstit.pos / tilesize < cutoff))
+ blend(dest(dstit.x, dstit.y), srcit.pixel());
+ }
+ }
+ // S face starting at [B,1.5B] -- western half only
+ if (W)
+ {
+ FaceIterator dstit(drect.x + B, drect.y + B*3/2, -1, tilesize);
+ for (SourceIterator srcit(tile, tilesize); !srcit.end(); srcit.advance(), dstit.advance())
+ {
+ if (dstit.pos / tilesize < cutoff)
+ blend(dest(dstit.x, dstit.y), srcit.pixel());
+ }
+ }
+}
+
+void drawItemBlockImage(RGBAImage& dest, const ImageRect& drect, const RGBAImage& tile, int B)
+{
+ drawItemBlockImage(dest, drect, blockTile(tile), true, true, true, true, B);
+}
+
+
+// draw an item block image possibly missing some edges (iron bars, etc.)
+void drawPartialItemBlockImage(RGBAImage& dest, const ImageRect& drect, const RGBAImage& tile, int rot, bool flipX, bool N, bool S, bool W, bool E, int B)
+{
+ drawItemBlockImage(dest, drect, blockTile(tile, rot, flipX), N, S, W, E, B);
+}
+
+// draw four flat copies of a tile intersecting in a square (netherwart, etc.)
+void drawMultiItemBlockImage(RGBAImage& dest, const ImageRect& drect, const SourceTile& tile, int B)
+{
+ if (!tile.valid())
+ return;
+ int tilesize = 2*B;
+ // E/W face starting at [0.5B,1.25B]
+ {
+ FaceIterator dstit(drect.x + B/2, drect.y + B*5/4, -1, tilesize);
+ for (SourceIterator srcit(tile, tilesize); !srcit.end(); srcit.advance(), dstit.advance())
+ {
+ blend(dest(dstit.x, dstit.y), srcit.pixel());
+ }
+ }
+ // E/W face starting at [1.5B,1.75B]
+ {
+ FaceIterator dstit(drect.x + 3*B/2, drect.y + B*7/4, -1, tilesize);
+ for (SourceIterator srcit(tile, tilesize); !srcit.end(); srcit.advance(), dstit.advance())
+ {
+ blend(dest(dstit.x, dstit.y), srcit.pixel());
+ }
+ }
+ // N/S face starting at [0.5B,0.75B]
+ {
+ FaceIterator dstit(drect.x + B/2, drect.y + B*3/4, 1, tilesize);
+ for (SourceIterator srcit(tile, tilesize); !srcit.end(); srcit.advance(), dstit.advance())
+ {
+ blend(dest(dstit.x, dstit.y), srcit.pixel());
+ }
+ }
+ // N/S face starting at [1.5B,0.25B]
+ {
+ FaceIterator dstit(drect.x + 3*B/2, drect.y + B/4, 1, tilesize);
+ for (SourceIterator srcit(tile, tilesize); !srcit.end(); srcit.advance(), dstit.advance())
+ {
+ blend(dest(dstit.x, dstit.y), srcit.pixel());
+ }
+ }
+}
+
+void drawMultiItemBlockImage(RGBAImage& dest, const ImageRect& drect, const RGBAImage& tile, int B)
+{
+ drawMultiItemBlockImage(dest, drect, blockTile(tile), B);
+}
+
+// draw a tile on a single upright face
+// 0 = E, 1 = W, 2 = S, 3 = N
+// ...handles transparency
+void drawSingleFaceBlockImage(RGBAImage& dest, const ImageRect& drect, const SourceTile& tile, int face, int B) // re-oriented maybe?
+{
+ if (!tile.valid())
+ return;
+ int tilesize = 2*B;
+ int xoff, yoff, deltaY;
+ if (face == 0)
+ {
+ xoff = 2*B;
+ yoff = 0;
+ deltaY = 1;
+ }
+ else if (face == 1)
+ {
+ xoff = 0;
+ yoff = B;
+ deltaY = 1;
+ }
+ else if (face == 2)
+ {
+ xoff = 2*B;
+ yoff = 2*B;
+ deltaY = -1;
+ }
+ else
+ {
+ xoff = 0;
+ yoff = B;
+ deltaY = -1;
+ }
+ FaceIterator dstit(drect.x + xoff, drect.y + yoff, deltaY, tilesize);
+ for (SourceIterator srcit(tile, tilesize); !srcit.end(); srcit.advance(), dstit.advance())
+ {
+ blend(dest(dstit.x, dstit.y), srcit.pixel());
+ }
+}
+
+void drawSingleFaceBlockImage(RGBAImage& dest, const ImageRect& drect, const RGBAImage& tile, int face, int B)
+{
+ drawSingleFaceBlockImage(dest, drect, blockTile(tile), face, B);
+}
+
+// draw part of a tile on a single upright face
+// 0 = S, 1 = N, 2 = W, 3 = E
+// ...handles transparency
+void drawPartialSingleFaceBlockImage(RGBAImage& dest, const ImageRect& drect, const SourceTile& tile, int face, int B, double croptop, double cropbottom, double cropleft, double cropright)
+{
+ int tilesize = 2*B;
+ int xoff, yoff, deltaY;
+ if (face == 0)
+ {
+ xoff = 2*B;
+ yoff = 0;
+ deltaY = 1;
+ }
+ else if (face == 1)
+ {
+ xoff = 0;
+ yoff = B;
+ deltaY = 1;
+ }
+ else if (face == 2)
+ {
+ xoff = 2*B;
+ yoff = 2*B;
+ deltaY = -1;
+ }
+ else
+ {
+ xoff = 0;
+ yoff = B;
+ deltaY = -1;
+ }
+ FaceIterator dstit(drect.x + xoff, drect.y + yoff, deltaY, tilesize);
+ for (SourceIterator srcit(tile, tilesize); !srcit.end(); srcit.advance(), dstit.advance())
+ {
+ if (dstit.pos % tilesize >= croptop && dstit.pos % tilesize < tilesize - cropbottom &&
+ dstit.pos / tilesize >= cropleft && dstit.pos / tilesize < tilesize - cropright)
+ blend(dest(dstit.x, dstit.y), srcit.pixel());
+ }
+}
+
+void drawPartialSingleFaceBlockImage(RGBAImage& dest, const ImageRect& drect, const RGBAImage& tile, int face, int B, int croptop, int cropbottom, int cropleft, int cropright)
+{
+ drawPartialSingleFaceBlockImage(dest, drect, blockTile(tile), face, B, croptop, cropbottom, cropleft, cropright);
+}
+
+// draw a single tile on the floor, possibly with rotation
+// 0 = top of tile is on E side; 1 = N, 2 = E, 3 = S
+void drawFloorBlockImage(RGBAImage& dest, const ImageRect& drect, const SourceTile& tile, int B)
+{
+ int tilesize = 2*B;
+ TopFaceIterator dstit(drect.x + 2*B-1, drect.y + 2*B, tilesize);
+ for (SourceIterator srcit(tile, tilesize); !srcit.end(); srcit.advance(), dstit.advance())
+ {
+ dest(dstit.x, dstit.y) = srcit.pixel();
+ }
+}
+
+void drawFloorBlockImage(RGBAImage& dest, const ImageRect& drect, const RGBAImage& tile, int rot, int B)
+{
+ drawFloorBlockImage(dest, drect, blockTile(tile, rot, false), B);
+}
+
+// draw a single tile on the floor, possibly with rotation, angled upwards
+// rot: 0 = top of tile is on S side; 1 = W, 2 = N, 3 = E
+// up: 0 = S side of tile is highest; 1 = W, 2 = N, 3 = E
+void drawAngledFloorBlockImage(RGBAImage& dest, const ImageRect& drect, const SourceTile& tile, int up, int B)
+{
+ int tilesize = 2*B;
+ TopFaceIterator dstit(drect.x + 2*B-1, drect.y + 2*B, tilesize);
+ for (SourceIterator srcit(tile, tilesize); !srcit.end(); srcit.advance(), dstit.advance())
+ {
+ int yoff = 0;
+ int row = dstit.pos % tilesize, col = dstit.pos / tilesize;
+ if (up == 0)
+ yoff = tilesize - 1 - row;
+ else if (up == 1)
+ yoff = col;
+ else if (up == 2)
+ yoff = row;
+ else if (up == 3)
+ yoff = tilesize - 1 - col;
+ blend(dest(dstit.x, dstit.y - yoff), srcit.pixel());
+ blend(dest(dstit.x, dstit.y - yoff + 1), srcit.pixel());
+ }
+}
+
+void drawAngledFloorBlockImage(RGBAImage& dest, const ImageRect& drect, const RGBAImage& tile, int rot, int up, int B)
+{
+ drawAngledFloorBlockImage(dest, drect, blockTile(tile, rot, false), up, B);
+}
+
+// draw a single tile on the ceiling, possibly with rotation
+// 0 = top of tile is on S side; 1 = W, 2 = N, 3 = E
+void drawCeilBlockImage(RGBAImage& dest, const ImageRect& drect, const RGBAImage& tile, int rot, int B)
+{
+ int tilesize = 2*B;
+ TopFaceIterator dstit(drect.x + 2*B-1, drect.y, tilesize);
+ for (RotatedFaceIterator srcit(0, 0, rot, tilesize, false); !srcit.end; srcit.advance(), dstit.advance())
+ {
+ dest(dstit.x, dstit.y) = tile(srcit.x, srcit.y);
+ }
+}
+
+// draw a block image that's just a single color (plus shadows)
+void drawSolidColorBlockImage(RGBAImage& dest, const ImageRect& drect, RGBAPixel p, int B)
+{
+ int tilesize = 2*B;
+ // N face starts at [0,B]
+ for (FaceIterator dstit(drect.x, drect.y + B, 1, tilesize); !dstit.end; dstit.advance())
+ {
+ dest(dstit.x, dstit.y) = p;
+ darken(dest(dstit.x, dstit.y), 0.9, 0.9, 0.9);
+ }
+ // W face starts at [2B,2B]
+ for (FaceIterator dstit(drect.x + 2*B, drect.y + 2*B, -1, tilesize); !dstit.end; dstit.advance())
+ {
+ dest(dstit.x, dstit.y) = p;
+ darken(dest(dstit.x, dstit.y), 0.8, 0.8, 0.8);
+ }
+ // U face starts at [2B-1,0]
+ for (TopFaceIterator dstit(drect.x + 2*B-1, drect.y, tilesize); !dstit.end; dstit.advance())
+ {
+ dest(dstit.x, dstit.y) = p;
+ }
+}
+
+// draw E-ascending stairs
+void drawStairsE(RGBAImage& dest, const ImageRect& drect, RGBAImage& tileWS, RGBAImage& tileU, int B)
+{
+ int tilesize = 2*B;
+ // normal W face starts at [0,B]; draw the bottom half of it
+ for (FaceIterator srcit(0, 0, 0, tilesize),
+ dstit(drect.x, drect.y + B, 1, tilesize); !srcit.end; srcit.advance(), dstit.advance())
+ {
+ if (dstit.pos % tilesize >= B)
+ {
+ dest(dstit.x, dstit.y) = tileWS(srcit.x, srcit.y);
+ darken(dest(dstit.x, dstit.y), 0.9, 0.9, 0.9);
+ }
+ }
+ // normal S face starts at [2B,2B]; draw all but the upper-left quarter of it
+ for (FaceIterator srcit(0, 0, 0, tilesize),
+ dstit(drect.x + 2*B, drect.y + 2*B, -1, tilesize); !srcit.end; srcit.advance(), dstit.advance())
+ {
+ if (dstit.pos % tilesize >= B || dstit.pos / tilesize >= B)
+ {
+ dest(dstit.x, dstit.y) = tileWS(srcit.x, srcit.y);
+ darken(dest(dstit.x, dstit.y), 0.8, 0.8, 0.8);
+ }
+ }
+ // normal U face starts at [2B-1,0]; draw the top half of it
+ TopFaceIterator tdstit(drect.x + 2*B-1, drect.y, tilesize);
+ for (FaceIterator srcit(0, 0, 0, tilesize); !srcit.end; srcit.advance(), tdstit.advance())
+ {
+ // if B is odd, we need B pixels from each column, but if it's even, we need to alternate between
+ // B-1 and B+1
+ int cutoff = B;
+ if (B % 2 == 0)
+ cutoff += ((tdstit.pos / tilesize) % 2 == 0) ? -1 : 1;
+ if (tdstit.pos % tilesize < cutoff)
+ {
+ dest(tdstit.x, tdstit.y) = tileU(srcit.x, srcit.y);
+ }
+ }
+ // draw the top half of another W face at [B,B/2]
+ for (FaceIterator srcit(0, 0, 0, tilesize),
+ dstit(drect.x + B, drect.y + B/2, 1, tilesize); !srcit.end; srcit.advance(), dstit.advance())
+ {
+ // ...but if B is odd, we need to add an extra [0,1] to the even-numbered columns
+ int adjust = 0;
+ if (B % 2 == 1 && (dstit.pos / tilesize) % 2 == 0)
+ adjust = 1;
+ if (dstit.pos % tilesize < B)
+ {
+ dest(dstit.x, dstit.y + adjust) = tileWS(srcit.x, srcit.y);
+ darken(dest(dstit.x, dstit.y + adjust), 0.9, 0.9, 0.9);
+ }
+ }
+ // draw the bottom half of another U face at [2B-1,B]
+ tdstit = TopFaceIterator(drect.x + 2*B-1, drect.y + B, tilesize);
+ for (FaceIterator srcit(0, 0, 0, tilesize); !srcit.end; srcit.advance(), tdstit.advance())
+ {
+ // again, if B is odd, take B pixels from each column; if even, take B-1 or B+1
+ int cutoff = B;
+ if (B % 2 == 0)
+ cutoff += ((tdstit.pos / tilesize) % 2 == 0) ? -1 : 1;
+ if (tdstit.pos % tilesize >= cutoff)
+ {
+ dest(tdstit.x, tdstit.y) = tileU(srcit.x, srcit.y);
+ }
+ }
+}
+
+// draw E-ascending stairs inverted
+void drawInvStairsE(RGBAImage& dest, const ImageRect& drect, RGBAImage& tileWS, RGBAImage& tileU, int B)
+{
+ int tilesize = 2*B;
+ // draw the bottom half of a W face at [B,B/2]; do this first because the others will partially cover it
+ for (FaceIterator srcit(0, 0, 0, tilesize),
+ dstit(drect.x + B, drect.y + B/2, 1, tilesize); !srcit.end; srcit.advance(), dstit.advance())
+ {
+ // ...but if B is odd, we need to add an extra [0,1] to the even-numbered columns
+ int adjust = 0;
+ if (B % 2 == 1 && (dstit.pos / tilesize) % 2 == 0)
+ adjust = 1;
+ if (dstit.pos % tilesize >= B)
+ {
+ dest(dstit.x, dstit.y + adjust) = tileWS(srcit.x, srcit.y);
+ darken(dest(dstit.x, dstit.y + adjust), 0.9, 0.9, 0.9);
+ }
+ }
+ // normal W face starts at [0,B]; draw the top half of it
+ for (FaceIterator srcit(0, 0, 0, tilesize),
+ dstit(drect.x, drect.y + B, 1, tilesize); !srcit.end; srcit.advance(), dstit.advance())
+ {
+ if (dstit.pos % tilesize < B)
+ {
+ dest(dstit.x, dstit.y) = tileWS(srcit.x, srcit.y);
+ darken(dest(dstit.x, dstit.y), 0.9, 0.9, 0.9);
+ }
+ }
+ // normal S face starts at [2B,2B]; draw all but the lower-left quarter of it
+ for (FaceIterator srcit(0, 0, 0, tilesize),
+ dstit(drect.x + 2*B, drect.y + 2*B, -1, tilesize); !srcit.end; srcit.advance(), dstit.advance())
+ {
+ if (dstit.pos % tilesize < B || dstit.pos / tilesize >= B)
+ {
+ dest(dstit.x, dstit.y) = tileWS(srcit.x, srcit.y);
+ darken(dest(dstit.x, dstit.y), 0.8, 0.8, 0.8);
+ }
+ }
+ // normal U face starts at [2B-1,0]; draw the whole thing
+ TopFaceIterator tdstit(drect.x + 2*B-1, drect.y, tilesize);
+ for (FaceIterator srcit(0, 0, 0, tilesize); !srcit.end; srcit.advance(), tdstit.advance())
+ {
+ dest(tdstit.x, tdstit.y) = tileU(srcit.x, srcit.y);
+ }
+}
+
+// draw W-ascending stairs
+void drawStairsW(RGBAImage& dest, const ImageRect& drect, RGBAImage& tileWS, RGBAImage& tileU, int B)
+{
+ int tilesize = 2*B;
+ // draw the top half of an an U face at [2B-1,B]
+ TopFaceIterator tdstit(drect.x + 2*B-1, drect.y + B, tilesize);
+ for (FaceIterator srcit(0, 0, 0, tilesize); !srcit.end; srcit.advance(), tdstit.advance())
+ {
+ // if B is odd, we need B pixels from each column, but if it's even, we need to alternate between
+ // B-1 and B+1
+ int cutoff = B;
+ if (B % 2 == 0)
+ cutoff += ((tdstit.pos / tilesize) % 2 == 0) ? -1 : 1;
+ if (tdstit.pos % tilesize < cutoff)
+ {
+ dest(tdstit.x, tdstit.y) = tileU(srcit.x, srcit.y);
+ }
+ }
+ // draw the bottom half of the normal U face at [2B-1,0]
+ tdstit = TopFaceIterator(drect.x + 2*B-1, drect.y, tilesize);
+ for (FaceIterator srcit(0, 0, 0, tilesize); !srcit.end; srcit.advance(), tdstit.advance())
+ {
+ // again, if B is odd, take B pixels from each column; if even, take B-1 or B+1
+ int cutoff = B;
+ if (B % 2 == 0)
+ cutoff += ((tdstit.pos / tilesize) % 2 == 0) ? -1 : 1;
+ if (tdstit.pos % tilesize >= cutoff)
+ {
+ dest(tdstit.x, tdstit.y) = tileU(srcit.x, srcit.y);
+ }
+ }
+ // normal W face starts at [0,B]; draw it all
+ for (FaceIterator srcit(0, 0, 0, tilesize),
+ dstit(drect.x, drect.y + B, 1, tilesize); !srcit.end; srcit.advance(), dstit.advance())
+ {
+ dest(dstit.x, dstit.y) = tileWS(srcit.x, srcit.y);
+ darken(dest(dstit.x, dstit.y), 0.9, 0.9, 0.9);
+ }
+ // normal S face starts at [2B,2B]; draw all but the upper-right quarter of it
+ for (FaceIterator srcit(0, 0, 0, tilesize),
+ dstit(drect.x + 2*B, drect.y + 2*B, -1, tilesize); !srcit.end; srcit.advance(), dstit.advance())
+ {
+ if (dstit.pos % tilesize >= B || dstit.pos / tilesize < B)
+ {
+ dest(dstit.x, dstit.y) = tileWS(srcit.x, srcit.y);
+ darken(dest(dstit.x, dstit.y), 0.8, 0.8, 0.8);
+ }
+ }
+}
+
+// draw W-ascending stairs inverted
+void drawInvStairsW(RGBAImage& dest, const ImageRect& drect, RGBAImage& tileWS, RGBAImage& tileU, int B)
+{
+ int tilesize = 2*B;
+ // normal U face starts at [2B-1,0]; draw the whole thing
+ TopFaceIterator tdstit(drect.x + 2*B-1, drect.y, tilesize);
+ for (FaceIterator srcit(0, 0, 0, tilesize); !srcit.end; srcit.advance(), tdstit.advance())
+ {
+ dest(tdstit.x, tdstit.y) = tileU(srcit.x, srcit.y);
+ }
+ // normal W face starts at [0,B]; draw it all
+ for (FaceIterator srcit(0, 0, 0, tilesize),
+ dstit(drect.x, drect.y + B, 1, tilesize); !srcit.end; srcit.advance(), dstit.advance())
+ {
+ dest(dstit.x, dstit.y) = tileWS(srcit.x, srcit.y);
+ darken(dest(dstit.x, dstit.y), 0.9, 0.9, 0.9);
+ }
+ // normal S face starts at [2B,2B]; draw all but the lower-right quarter of it
+ for (FaceIterator srcit(0, 0, 0, tilesize),
+ dstit(drect.x + 2*B, drect.y + 2*B, -1, tilesize); !srcit.end; srcit.advance(), dstit.advance())
+ {
+ if (dstit.pos % tilesize < B || dstit.pos / tilesize < B)
+ {
+ dest(dstit.x, dstit.y) = tileWS(srcit.x, srcit.y);
+ darken(dest(dstit.x, dstit.y), 0.8, 0.8, 0.8);
+ }
+ }
+}
+
+// draw N-ascending stairs
+void drawStairsN(RGBAImage& dest, const ImageRect& drect, RGBAImage& tileWS, RGBAImage& tileU, int B)
+{
+ int tilesize = 2*B;
+ // normal W face starts at [0,B]; draw all but the upper-right quarter of it
+ for (FaceIterator srcit(0, 0, 0, tilesize),
+ dstit(drect.x, drect.y + B, 1, tilesize); !srcit.end; srcit.advance(), dstit.advance())
+ {
+ if (dstit.pos % tilesize >= B || dstit.pos / tilesize < B)
+ {
+ dest(dstit.x, dstit.y) = tileWS(srcit.x, srcit.y);
+ darken(dest(dstit.x, dstit.y), 0.9, 0.9, 0.9);
+ }
+ }
+ // normal S face starts at [2B,2B]; draw the bottom half of it
+ for (FaceIterator srcit(0, 0, 0, tilesize),
+ dstit(drect.x + 2*B, drect.y + 2*B, -1, tilesize); !srcit.end; srcit.advance(), dstit.advance())
+ {
+ if (dstit.pos % tilesize >= B)
+ {
+ dest(dstit.x, dstit.y) = tileWS(srcit.x, srcit.y);
+ darken(dest(dstit.x, dstit.y), 0.8, 0.8, 0.8);
+ }
+ }
+ // normal U face starts at [2B-1,0]; draw the left half of it
+ TopFaceIterator tdstit(drect.x + 2*B-1, drect.y, tilesize);
+ int tcutoff = tilesize * B;
+ bool textra = false;
+ // if B is odd, we need to skip the last pixel of the last left-half column, and add the very first
+ // pixel of the first right-half column
+ if (B % 2 == 1)
+ {
+ tcutoff--;
+ textra = true;
+ }
+ for (FaceIterator srcit(0, 0, 0, tilesize); !srcit.end; srcit.advance(), tdstit.advance())
+ {
+ if (tdstit.pos < tcutoff || (textra && tdstit.pos == tcutoff + 1))
+ {
+ dest(tdstit.x, tdstit.y) = tileU(srcit.x, srcit.y);
+ }
+ }
+ // draw the top half of another S face at [B,1.5B]
+ for (FaceIterator srcit(0, 0, 0, tilesize),
+ dstit(drect.x + B, drect.y + 3*B/2, -1, tilesize); !srcit.end; srcit.advance(), dstit.advance())
+ {
+ // ...but if B is odd, we need to add an extra [0,1] to the odd-numbered columns
+ int adjust = 0;
+ if (B % 2 == 1 && (dstit.pos / tilesize) % 2 == 1)
+ adjust = 1;
+ if (dstit.pos % tilesize < B)
+ {
+ dest(dstit.x, dstit.y + adjust) = tileWS(srcit.x, srcit.y);
+ darken(dest(dstit.x, dstit.y + adjust), 0.8, 0.8, 0.8);
+ }
+ }
+ // draw the right half of another U face at [2B-1,B]
+ tdstit = TopFaceIterator(drect.x + 2*B-1, drect.y + B, tilesize);
+ tcutoff = tilesize * B;
+ textra = false;
+ // if B is odd, do the reverse of what we did with the top half
+ if (B % 2 == 1)
+ {
+ tcutoff++;
+ textra = true;
+ }
+ for (FaceIterator srcit(0, 0, 0, tilesize); !srcit.end; srcit.advance(), tdstit.advance())
+ {
+ if (tdstit.pos >= tcutoff || (textra && tdstit.pos == tcutoff - 2))
+ {
+ dest(tdstit.x, tdstit.y) = tileU(srcit.x, srcit.y);
+ }
+ }
+}
+
+// draw N-ascending stairs inverted
+void drawInvStairsN(RGBAImage& dest, const ImageRect& drect, RGBAImage& tileWS, RGBAImage& tileU, int B)
+{
+ int tilesize = 2*B;
+ // draw the bottom half of a S face at [B,1.5B]; do this first because the others will partially cover it
+ for (FaceIterator srcit(0, 0, 0, tilesize),
+ dstit(drect.x + B, drect.y + 3*B/2, -1, tilesize); !srcit.end; srcit.advance(), dstit.advance())
+ {
+ // ...but if B is odd, we need to add an extra [0,1] to the odd-numbered columns
+ int adjust = 0;
+ if (B % 2 == 1 && (dstit.pos / tilesize) % 2 == 1)
+ adjust = 1;
+ if (dstit.pos % tilesize >= B)
+ {
+ dest(dstit.x, dstit.y + adjust) = tileWS(srcit.x, srcit.y);
+ darken(dest(dstit.x, dstit.y + adjust), 0.8, 0.8, 0.8);
+ }
+ }
+ // normal S face starts at [2B,2B]; draw the top half of it
+ for (FaceIterator srcit(0, 0, 0, tilesize),
+ dstit(drect.x + 2*B, drect.y + 2*B, -1, tilesize); !srcit.end; srcit.advance(), dstit.advance())
+ {
+ if (dstit.pos % tilesize < B)
+ {
+ dest(dstit.x, dstit.y) = tileWS(srcit.x, srcit.y);
+ darken(dest(dstit.x, dstit.y), 0.8, 0.8, 0.8);
+ }
+ }
+ // normal W face starts at [0,B]; draw all but the lower-right quarter of it
+ for (FaceIterator srcit(0, 0, 0, tilesize),
+ dstit(drect.x, drect.y + B, 1, tilesize); !srcit.end; srcit.advance(), dstit.advance())
+ {
+ if (dstit.pos % tilesize < B || dstit.pos / tilesize < B)
+ {
+ dest(dstit.x, dstit.y) = tileWS(srcit.x, srcit.y);
+ darken(dest(dstit.x, dstit.y), 0.9, 0.9, 0.9);
+ }
+ }
+ // normal U face starts at [2B-1,0]; draw the whole thing
+ TopFaceIterator tdstit(drect.x + 2*B-1, drect.y, tilesize);
+ for (FaceIterator srcit(0, 0, 0, tilesize); !srcit.end; srcit.advance(), tdstit.advance())
+ {
+ dest(tdstit.x, tdstit.y) = tileU(srcit.x, srcit.y);
+ }
+}
+
+// draw S-ascending stairs
+void drawStairsS(RGBAImage& dest, const ImageRect& drect, RGBAImage& tileWS, RGBAImage& tileU, int B)
+{
+ int tilesize = 2*B;
+ // draw the left half of an U face at [2B-1,B]
+ TopFaceIterator tdstit(drect.x + 2*B-1, drect.y + B, tilesize);
+ int tcutoff = tilesize * B;
+ bool textra = false;
+ // if B is odd, we need to skip the last pixel of the last left-half column, and add the very first
+ // pixel of the first right-half column
+ if (B % 2 == 1)
+ {
+ tcutoff--;
+ textra = true;
+ }
+ for (FaceIterator srcit(0, 0, 0, tilesize); !srcit.end; srcit.advance(), tdstit.advance())
+ {
+ if (tdstit.pos < tcutoff || (textra && tdstit.pos == tcutoff + 1))
+ {
+ dest(tdstit.x, tdstit.y) = tileU(srcit.x, srcit.y);
+ }
+ }
+ // draw the right half of the normal U face at [2B-1,0]
+ tdstit = TopFaceIterator(drect.x + 2*B-1, drect.y, tilesize);
+ tcutoff = tilesize * B;
+ textra = false;
+ // if B is odd, do the reverse of what we did with the top half
+ if (B % 2 == 1)
+ {
+ tcutoff++;
+ textra = true;
+ }
+ for (FaceIterator srcit(0, 0, 0, tilesize); !srcit.end; srcit.advance(), tdstit.advance())
+ {
+ if (tdstit.pos >= tcutoff || (textra && tdstit.pos == tcutoff - 2))
+ {
+ dest(tdstit.x, tdstit.y) = tileU(srcit.x, srcit.y);
+ }
+ }
+ // normal W face starts at [0,B]; draw all but the upper-left quarter of it
+ for (FaceIterator srcit(0, 0, 0, tilesize),
+ dstit(drect.x, drect.y + B, 1, tilesize); !srcit.end; srcit.advance(), dstit.advance())
+ {
+ if (dstit.pos % tilesize >= B || dstit.pos / tilesize >= B)
+ {
+ dest(dstit.x, dstit.y) = tileWS(srcit.x, srcit.y);
+ darken(dest(dstit.x, dstit.y), 0.9, 0.9, 0.9);
+ }
+ }
+ // normal S face starts at [2B,2B]; draw the whole thing
+ for (FaceIterator srcit(0, 0, 0, tilesize),
+ dstit(drect.x + 2*B, drect.y + 2*B, -1, tilesize); !srcit.end; srcit.advance(), dstit.advance())
+ {
+ dest(dstit.x, dstit.y) = tileWS(srcit.x, srcit.y);
+ darken(dest(dstit.x, dstit.y), 0.8, 0.8, 0.8);
+ }
+}
+
+// draw S-ascending stairs inverted
+void drawInvStairsS(RGBAImage& dest, const ImageRect& drect, RGBAImage& tileWS, RGBAImage& tileU, int B)
+{
+ int tilesize = 2*B;
+ // normal U face starts at [2B-1,0]; draw the whole thing
+ TopFaceIterator tdstit(drect.x + 2*B-1, drect.y, tilesize);
+ for (FaceIterator srcit(0, 0, 0, tilesize); !srcit.end; srcit.advance(), tdstit.advance())
+ {
+ dest(tdstit.x, tdstit.y) = tileU(srcit.x, srcit.y);
+ }
+ // normal S face starts at [2B,2B]; draw the whole thing
+ for (FaceIterator srcit(0, 0, 0, tilesize),
+ dstit(drect.x + 2*B, drect.y + 2*B, -1, tilesize); !srcit.end; srcit.advance(), dstit.advance())
+ {
+ dest(dstit.x, dstit.y) = tileWS(srcit.x, srcit.y);
+ darken(dest(dstit.x, dstit.y), 0.8, 0.8, 0.8);
+ }
+ // normal W face starts at [0,B]; draw all but the lower-left quarter of it
+ for (FaceIterator srcit(0, 0, 0, tilesize),
+ dstit(drect.x, drect.y + B, 1, tilesize); !srcit.end; srcit.advance(), dstit.advance())
+ {
+ if (dstit.pos % tilesize < B || dstit.pos / tilesize >= B)
+ {
+ dest(dstit.x, dstit.y) = tileWS(srcit.x, srcit.y);
+ darken(dest(dstit.x, dstit.y), 0.9, 0.9, 0.9);
+ }
+ }
+}
+
+// generic functions for drawing separate faces with offsets and cutoffs
+// - tint: controls how much face is darkened
+// - offset: controls how far face is offset from original cube position inwards
+// - croptop: controls how much of the face is cropped from the top
+// - cropbottom: controls how much of the face is cropped from the bottom
+// - cropleft: controls how much of the face is cropped from the left
+// - cropright: controls how much of the face is cropped from the right
+void drawOffsetPaddedWFace(RGBAImage& dest, const ImageRect& drect, const RGBAImage& tile, int B, double tint, int offset, int croptop, int cropbottom, int cropleft, int cropright)
+{
+ int tilesize = 2 * B;
+ // draw N face
+ for (FaceIterator srcit(0, 0, 0, tilesize),
+ dstit(drect.x + offset, drect.y + B - deinterpolate(offset, 2*tilesize, tilesize), 1, tilesize); !srcit.end; srcit.advance(), dstit.advance())
+ {
+ if (dstit.pos % tilesize >= croptop && dstit.pos % tilesize < tilesize - cropbottom && dstit.pos / tilesize >= cropleft && dstit.pos / tilesize < tilesize - cropright)
+ {
+ dest(dstit.x, dstit.y) = tile(srcit.x, srcit.y);
+ darken(dest(dstit.x, dstit.y), tint, tint, tint);
+ }
+ }
+}
+void drawOffsetPaddedSFace(RGBAImage& dest, const ImageRect& drect, const RGBAImage& tile, int B, double tint, int offset, int croptop, int cropbottom, int cropleft, int cropright)
+{
+ int tilesize = 2 * B;
+ // draw W face
+ for (FaceIterator srcit(0, 0, 0, tilesize),
+ dstit(drect.x + 2*B - offset, drect.y + 2*B - deinterpolate(offset, 2*tilesize, tilesize), -1, tilesize); !srcit.end; srcit.advance(), dstit.advance())
+ {
+ if(dstit.pos % tilesize >= croptop && dstit.pos % tilesize < tilesize - cropbottom && dstit.pos / tilesize >= cropleft && dstit.pos / tilesize < tilesize - cropright) {
+ dest(dstit.x, dstit.y) = tile(srcit.x, srcit.y);
+ darken(dest(dstit.x, dstit.y), tint, tint, tint);
+ }
+ }
+}
+void drawOffsetPaddedUFace(RGBAImage& dest, const ImageRect& drect, const RGBAImage& tile, int B, int offset, int croptop, int cropbottom, int cropleft, int cropright)
+{
+ int tilesize = 2 * B;
+ // draw U face
+ TopFaceIterator tdstit(drect.x + 2*B-1, drect.y + offset, tilesize);
+ for (FaceIterator srcit(0, 0, 0, tilesize); !srcit.end; srcit.advance(), tdstit.advance())
+ {
+ int adjust = 0;
+ if (croptop % 2 == 0)
+ adjust += ((tdstit.pos / tilesize) % 2 == 0) ? -1 : 1; // adjust for missing pixels
+ if(tdstit.pos % tilesize >= croptop + adjust && tdstit.pos % tilesize < tilesize - cropbottom + adjust && tdstit.pos / tilesize >= cropleft && tdstit.pos / tilesize < tilesize - cropright)
+ blend(dest(tdstit.x, tdstit.y),tile(srcit.x, srcit.y));
+ }
+}
+// draw simple fence post (that actually works for different zoom levels)
+void drawFencePost(RGBAImage& dest, const ImageRect& drect, const RGBAImage& tile, int B)
+{
+ // draw a 2x2 top at [2B-1,B-1]
+ for (int y = 0; y < 2; y++)
+ for (int x = 0; x < 2; x++)
+ dest(drect.x + 2*B - 1 + x, drect.y + B - 1 + y) = tile(x, y);
+
+ // draw a 1x2B side at [2B-1,B+1]
+ for (int y = 0; y < 2*B; y++)
+ dest(drect.x + 2*B - 1, drect.y + B + 1 + y) = tile(0, y);
+
+ // draw a 1x2B side at [2B,B+1]
+ for (int y = 0; y < 2*B; y++)
+ dest(drect.x + 2*B, drect.y + B + 1 + y) = tile(0, y);
+}
+
+// draw simple fence: post and four rails, each optional
+void drawFence(RGBAImage& dest, const ImageRect& drect, const RGBAImage& tile, bool N, bool S, bool W, bool E, bool post, int B) // re-oriented
+{
+ // first, E and S rails, since the post should be in front of them
+ int tilesize = 2*B;
+ if (N)
+ {
+ // N/S face starting at [B,0.5B]; left half, one strip
+ for (FaceIterator srcit(0, 0, 0, tilesize),
+ dstit(drect.x + B, drect.y + B/2, 1, tilesize); !srcit.end; srcit.advance(), dstit.advance())
+ {
+ if (dstit.pos / tilesize < B && (((dstit.pos % tilesize) * 2 / B) % 4) == 1)
+ dest(dstit.x, dstit.y) = tile(srcit.x, srcit.y);
+ }
+ }
+ if (E)
+ {
+ // E/W face starting at [B,1.5B]; right half, one strip
+ for (FaceIterator srcit(0, 0, 0, tilesize),
+ dstit(drect.x + B, drect.y + B*3/2, -1, tilesize); !srcit.end; srcit.advance(), dstit.advance())
+ {
+ if (dstit.pos / tilesize >= B && (((dstit.pos % tilesize) * 2 / B) % 4) == 1)
+ dest(dstit.x, dstit.y) = tile(srcit.x, srcit.y);
+ }
+ }
+
+ // now the post
+ if (post)
+ drawFencePost(dest, drect, tile, B);
+
+ // now the N and W rails
+ if (S)
+ {
+ // N/S face starting at [B,0.5B]; right half, one strip
+ for (FaceIterator srcit(0, 0, 0, tilesize),
+ dstit(drect.x + B, drect.y + B/2, 1, tilesize); !srcit.end; srcit.advance(), dstit.advance())
+ {
+ if (dstit.pos / tilesize >= B && (((dstit.pos % tilesize) * 2 / B) % 4) == 1)
+ dest(dstit.x, dstit.y) = tile(srcit.x, srcit.y);
+ }
+ }
+ if (W)
+ {
+ // E/W face starting at [B,1.5B]; left half, one strip
+ for (FaceIterator srcit(0, 0, 0, tilesize),
+ dstit(drect.x + B, drect.y + B*3/2, -1, tilesize); !srcit.end; srcit.advance(), dstit.advance())
+ {
+ if (dstit.pos / tilesize < B && (((dstit.pos % tilesize) * 2 / B) % 4) == 1)
+ dest(dstit.x, dstit.y) = tile(srcit.x, srcit.y);
+ }
+ }
+}
+// draw cobblestone/moss wall post
+void drawStoneWallPost(RGBAImage& dest, const ImageRect& drect, const RGBAImage& tile, int B)
+{
+ int tilesize = 2*B;
+
+ int CUTOFF_4_16 = deinterpolate(4, 16, tilesize); // quarter
+
+ drawOffsetPaddedWFace(dest, drect, tile, B, 0.8, CUTOFF_4_16, 0, 0, CUTOFF_4_16, CUTOFF_4_16); // offset W face
+ drawOffsetPaddedSFace(dest, drect, tile, B, 0.6, CUTOFF_4_16, 0, 0, CUTOFF_4_16, CUTOFF_4_16); // offset S face
+ drawOffsetPaddedUFace(dest, drect, tile, B, 0, CUTOFF_4_16, CUTOFF_4_16, CUTOFF_4_16, CUTOFF_4_16); // offset U face
+}
+
+// draw solid moss/cobblestone wall
+void drawStoneWall(RGBAImage& dest, const ImageRect& drect, const RGBAImage& tile, bool N, int B)
+{
+ int tilesize = 2*B;
+
+ int CUTOFF_3_16 = deinterpolate(3, 16, tilesize); // wall cutoff
+ int CUTOFF_5_16 = deinterpolate(5, 16, tilesize); // wall offset
+
+ if(N) // cobblestone wall going NS
+ {
+ drawOffsetPaddedWFace(dest, drect, tile, B, 0.8, CUTOFF_5_16, CUTOFF_3_16, 0, 0, 0); // offset W face
+ drawOffsetPaddedSFace(dest, drect, tile, B, 0.6, 0, CUTOFF_3_16, 0, CUTOFF_5_16, CUTOFF_5_16); // offset S face
+ drawOffsetPaddedUFace(dest, drect, tile, B, CUTOFF_3_16, CUTOFF_5_16, CUTOFF_5_16, 0, 0); // offset U face
+ }
+ else // cobblestone wall going EW
+ {
+ drawOffsetPaddedWFace(dest, drect, tile, B, 0.8, 0, CUTOFF_3_16, 0, CUTOFF_5_16, CUTOFF_5_16); // offset W face
+ drawOffsetPaddedSFace(dest, drect, tile, B, 0.6, CUTOFF_5_16, CUTOFF_3_16, 0, 0, 0); // offset S face
+ drawOffsetPaddedUFace(dest, drect, tile, B, CUTOFF_3_16, 0, -1, CUTOFF_5_16, CUTOFF_5_16); // offset U face
+ }
+}
+// draw cobblestone/moss stone post(optional) and any combination of wall rails (N/S/E/W)
+void drawStoneWallConnected(RGBAImage& dest, const ImageRect& drect, const RGBAImage& tile, bool N, bool S, bool E, bool W, int B)
+{
+ int tilesize = 2*B;
+
+ int CUTOFF_3_16 = deinterpolate(3, 16, tilesize); // wall cutoff
+ int CUTOFF_4_16 = deinterpolate(4, 16, tilesize); // quarter
+ int CUTOFF_5_16 = deinterpolate(5, 16, tilesize); // wall offset
+
+ // first, N and E rails, since the post should be in front of them
+ if (N) // draw N rail of the wall
+ {
+ drawOffsetPaddedWFace(dest, drect, tile, B, 0.8, CUTOFF_5_16, CUTOFF_3_16, 0, 0, tilesize - CUTOFF_4_16); // offset W face
+ drawOffsetPaddedUFace(dest, drect, tile, B, CUTOFF_3_16, CUTOFF_5_16, CUTOFF_5_16, 0, tilesize - CUTOFF_4_16); // offset U face
+ }
+ if (E) // draw E rail of the wall
+ {
+ drawOffsetPaddedSFace(dest, drect, tile, B, 0.6, CUTOFF_5_16, CUTOFF_3_16, 0, tilesize - CUTOFF_4_16, 0); // offset S face
+ drawOffsetPaddedUFace(dest, drect, tile, B, CUTOFF_3_16, 0, tilesize - CUTOFF_4_16, CUTOFF_5_16, CUTOFF_5_16); // offset U face
+ }
+
+ // now the post
+ drawStoneWallPost(dest, drect, tile, B);
+
+ // now the S and W rails
+ if (S) // draw S rail of the wall
+ {
+ drawOffsetPaddedWFace(dest, drect, tile, B, 0.8, CUTOFF_5_16, CUTOFF_3_16, 0, tilesize - CUTOFF_4_16, 0); // offset W face
+ drawOffsetPaddedSFace(dest, drect, tile, B, 0.6, 0, CUTOFF_3_16, 0, CUTOFF_5_16, CUTOFF_5_16); // offset S face
+ drawOffsetPaddedUFace(dest, drect, tile, B, CUTOFF_3_16, CUTOFF_5_16, CUTOFF_5_16, tilesize - CUTOFF_4_16, 0); // offset U face
+ }
+ if (W) // draw W rail of the wall
+ {
+ drawOffsetPaddedWFace(dest, drect, tile, B, 0.8, 0, CUTOFF_3_16, 0, CUTOFF_5_16, CUTOFF_5_16); // offset W face
+ drawOffsetPaddedSFace(dest, drect, tile, B, 0.6, CUTOFF_5_16, CUTOFF_3_16, 0, 0, tilesize - CUTOFF_4_16); // offset S face
+ drawOffsetPaddedUFace(dest, drect, tile, B, CUTOFF_3_16, tilesize - CUTOFF_4_16, -1, CUTOFF_5_16, CUTOFF_5_16); // offset U face
+ }
+}
+
+// draw heart of the beacon
+void drawBeacon(RGBAImage& dest, const ImageRect& drect, const RGBAImage& pedestalTile, const RGBAImage& heartTile, const ImageRect& glassrect, int B)
+{
+ int tilesize = 2*B;
+
+ int CUTOFF_2_16 = deinterpolate(2, 16, tilesize); // eighth
+ int CUTOFF_3_16 = deinterpolate(3, 16, tilesize); // pedestal height, heart offset
+
+ // draw obsidion pedestal
+ drawOffsetPaddedWFace(dest, drect, pedestalTile, B, 0.9, CUTOFF_2_16, tilesize - CUTOFF_3_16, 0, CUTOFF_2_16, CUTOFF_2_16); // offset N face
+ drawOffsetPaddedSFace(dest, drect, pedestalTile, B, 0.8, CUTOFF_2_16, tilesize - CUTOFF_3_16, 0, CUTOFF_2_16, CUTOFF_2_16); // offset W face
+ drawOffsetPaddedUFace(dest, drect, pedestalTile, B, 2*B - CUTOFF_3_16, CUTOFF_2_16, CUTOFF_2_16, CUTOFF_2_16, CUTOFF_2_16); // offset U face
+
+ // draw nether star heart
+ drawOffsetPaddedWFace(dest, drect, heartTile, B, 0.9, CUTOFF_3_16, CUTOFF_3_16, CUTOFF_3_16, CUTOFF_3_16, CUTOFF_3_16); // offset N face
+ drawOffsetPaddedSFace(dest, drect, heartTile, B, 0.8, CUTOFF_3_16, CUTOFF_3_16, CUTOFF_3_16, CUTOFF_3_16, CUTOFF_3_16); // offset W face
+ drawOffsetPaddedUFace(dest, drect, heartTile, B, CUTOFF_3_16, CUTOFF_3_16, CUTOFF_3_16, CUTOFF_3_16, CUTOFF_3_16); // offset U face
+
+ // blit glass over the drawn beacon heart
+ alphablit(dest, glassrect, dest, drect.x, drect.y);
+}
+
+// draw oriented anvil; orientation = 0 for NS, 1 - EW orientation
+// function does ignore the fact, that anvil facing N is different from one facing S; though difference is so insignificant, that it is deliberately omitted
+void drawAnvil(RGBAImage& dest, const ImageRect& drect, const RGBAImage& tile, const RGBAImage& faceTile, int orientation, int B)
+{
+ int tilesize = 2*B;
+
+ int CUTOFF_2_16 = deinterpolate(2, 16, tilesize); // base crop
+ int CUTOFF_3_16 = deinterpolate(3, 16, tilesize); // second base crop, face crop
+ int CUTOFF_4_16 = deinterpolate(4, 16, tilesize); // quarter
+ int CUTOFF_5_16 = deinterpolate(5, 16, tilesize); // second base crop on another side, pillar crop
+ int CUTOFF_6_16 = deinterpolate(6, 16, tilesize); // pillar height crops
+ int CUTOFF_10_16 = deinterpolate(10, 16, tilesize); // face crop (from bottom)
+
+ // draw anvil base (orientation independent)
+ drawOffsetPaddedUFace(dest, drect, tile, B, 2*B - CUTOFF_4_16, CUTOFF_2_16, CUTOFF_2_16, CUTOFF_2_16, CUTOFF_2_16); // offset U face
+ drawOffsetPaddedWFace(dest, drect, tile, B, 0.85, CUTOFF_2_16, tilesize - CUTOFF_4_16, 0, CUTOFF_2_16, CUTOFF_2_16); // offset W face
+ drawOffsetPaddedSFace(dest, drect, tile, B, 0.7, CUTOFF_2_16, tilesize - CUTOFF_4_16, 0, CUTOFF_2_16, CUTOFF_2_16); // offset S face
+
+ // draw anvil second base (oriented)
+ int noffset = 0;
+ int woffset = 0;
+ if(orientation == 0)
+ {
+ noffset = CUTOFF_3_16;
+ woffset = CUTOFF_5_16;
+ }
+ else
+ {
+ noffset = CUTOFF_5_16;
+ woffset = CUTOFF_3_16;
+ }
+ drawOffsetPaddedUFace(dest, drect, tile, B, 2*B - CUTOFF_5_16, woffset, woffset, noffset, noffset); // offset U face
+ drawOffsetPaddedWFace(dest, drect, tile, B, 0.85, woffset, tilesize - CUTOFF_5_16, CUTOFF_4_16, noffset, noffset); // offset W face
+ drawOffsetPaddedSFace(dest, drect, tile, B, 0.7, noffset, tilesize - CUTOFF_5_16, CUTOFF_4_16, woffset, woffset); // offset S face
+
+ // draw anvil pillar (oriented)
+ if(orientation == 0)
+ {
+ noffset = 0;
+ woffset = CUTOFF_2_16;
+ }
+ else
+ {
+ noffset = CUTOFF_2_16;
+ woffset = 0;
+ }
+ drawOffsetPaddedWFace(dest, drect, tile, B, 0.85, CUTOFF_4_16 + woffset, CUTOFF_6_16, CUTOFF_5_16, CUTOFF_4_16 + noffset, CUTOFF_4_16 + noffset); // offset W face
+ drawOffsetPaddedSFace(dest, drect, tile, B, 0.7, CUTOFF_4_16 + noffset, CUTOFF_6_16, CUTOFF_5_16, CUTOFF_4_16 + woffset, CUTOFF_4_16 + woffset); // offset S face
+
+ // draw anvil face (oriented)
+ if(orientation == 0)
+ {
+ noffset = 0;
+ woffset = CUTOFF_3_16;
+ }
+ else
+ {
+ noffset = CUTOFF_3_16;
+ woffset = 0;
+ }
+ int rot = 0;
+ if(orientation == 0)
+ rot = 1;
+ else
+ rot = 0;
+ // draw U bottom layer (cropped-texture-fix)
+ drawOffsetPaddedUFace(dest, drect, tile, B, 0, woffset, woffset, noffset, noffset); // cropped U face
+
+ // draw U face
+ TopFaceIterator tdstit = TopFaceIterator(drect.x + 2*B-1, drect.y, tilesize);
+ for (RotatedFaceIterator srcit(0, 0, rot, tilesize, 0); !srcit.end; srcit.advance(), tdstit.advance())
+ {
+ if(ALPHA(faceTile(srcit.x, srcit.y)) != 0)
+ dest(tdstit.x, tdstit.y) = faceTile(srcit.x, srcit.y);
+ }
+ drawOffsetPaddedWFace(dest, drect, tile, B, 0.85, woffset, 0, CUTOFF_10_16, noffset, noffset); // offset W face
+ drawOffsetPaddedSFace(dest, drect, tile, B, 0.7, noffset, 0, CUTOFF_10_16, woffset, woffset); // offset S face
+}
+
+// draw hopper
+void drawHopper(RGBAImage& dest, const ImageRect& drect, const RGBAImage& baseTile, const RGBAImage& insideTile, int B)
+{
+ int tilesize = 2*B;
+
+ int CUTOFF_4_16 = deinterpolate(4, 16, tilesize); // middle offset, bottom height
+ int CUTOFF_6_16 = deinterpolate(6, 16, tilesize); // top and middle height
+ int CUTOFF_10_16 = deinterpolate(10, 16, tilesize); // top height from bottom fix
+
+ // draw funnel
+ drawOffsetPaddedWFace(dest, drect, baseTile, B, 0.85, CUTOFF_6_16, 2*CUTOFF_6_16, 0, CUTOFF_6_16, CUTOFF_6_16); // offset W face
+ drawOffsetPaddedSFace(dest, drect, baseTile, B, 0.7, CUTOFF_6_16, 2*CUTOFF_6_16, 0, CUTOFF_6_16, CUTOFF_6_16); // offset S face
+
+ // draw middle part
+ drawOffsetPaddedWFace(dest, drect, baseTile, B, 0.85, CUTOFF_4_16, CUTOFF_6_16, CUTOFF_4_16, CUTOFF_4_16, CUTOFF_4_16); // offset W face
+ drawOffsetPaddedSFace(dest, drect, baseTile, B, 0.7, CUTOFF_4_16, CUTOFF_6_16, CUTOFF_4_16, CUTOFF_4_16, CUTOFF_4_16); // offset S face
+
+ // draw hopper top back part
+ drawPartialSingleFaceBlockImage(dest, drect, baseTile, 3, B, 0, CUTOFF_10_16, 0, 0); // facing S (N wall)
+ drawPartialSingleFaceBlockImage(dest, drect, baseTile, 0, B, 0, CUTOFF_10_16, 0, 0); // facing W (E wall)
+ // draw hopper inside
+ drawOffsetPaddedUFace(dest, drect, insideTile, B, CUTOFF_4_16, 0, 0, 0, 0); // inside offset U face
+ // draw hopper top front part
+ drawOffsetPaddedWFace(dest, drect, baseTile, B, 0.85, 0, 0, CUTOFF_10_16, 0, 0); // offset W face
+ drawOffsetPaddedSFace(dest, drect, baseTile, B, 0.7, 0, 0, CUTOFF_10_16, 0, 0); // offset S face
+
+}
+
+// draw end rod
+void drawEndRod(RGBAImage& dest, const ImageRect& drect, const RGBAImage& lampTile, const RGBAImage& baseTile, int orientation, int B)
+{
+ int tilesize = 2*B;
+
+ int CUTOFF_1_16 = deinterpolate(1, 16, tilesize);
+ int CUTOFF_6_16 = deinterpolate(6, 16, tilesize);
+ int CUTOFF_7_16 = deinterpolate(7, 16, tilesize);
+ int CUTOFF_15_16 = deinterpolate(15, 16, tilesize);
+
+ if(orientation == 0) // D
+ {
+ drawOffsetPaddedUFace(dest, drect, lampTile, B, CUTOFF_1_16, CUTOFF_7_16, CUTOFF_7_16, CUTOFF_7_16, CUTOFF_7_16); // U face
+ drawOffsetPaddedWFace(dest, drect, lampTile, B, 0.85, CUTOFF_7_16, CUTOFF_1_16, 0, CUTOFF_7_16, CUTOFF_7_16); // W face
+ drawOffsetPaddedSFace(dest, drect, lampTile, B, 0.7, CUTOFF_7_16, CUTOFF_1_16, 0, CUTOFF_7_16, CUTOFF_7_16); // S face // S face
+ /* ----- */
+ drawOffsetPaddedUFace(dest, drect, baseTile, B, 0, CUTOFF_6_16, CUTOFF_6_16, CUTOFF_6_16, CUTOFF_6_16); // U face
+ drawOffsetPaddedWFace(dest, drect, baseTile, B, 0.85, CUTOFF_6_16, 0, CUTOFF_15_16, CUTOFF_6_16, CUTOFF_6_16); // W face
+ drawOffsetPaddedSFace(dest, drect, baseTile, B, 0.7, CUTOFF_6_16, 0, CUTOFF_15_16, CUTOFF_6_16, CUTOFF_6_16); // S face
+ }
+ else if(orientation == 1) // U - base first
+ {
+ drawOffsetPaddedUFace(dest, drect, baseTile, B, CUTOFF_15_16, CUTOFF_6_16, CUTOFF_6_16, CUTOFF_6_16, CUTOFF_6_16); // U face
+ drawOffsetPaddedWFace(dest, drect, baseTile, B, 0.85, CUTOFF_6_16, CUTOFF_15_16, 0, CUTOFF_6_16, CUTOFF_6_16); // W face
+ drawOffsetPaddedSFace(dest, drect, baseTile, B, 0.7, CUTOFF_6_16, CUTOFF_15_16, 0, CUTOFF_6_16, CUTOFF_6_16); // S face
+ /* ----- */
+ drawOffsetPaddedUFace(dest, drect, lampTile, B, 0, CUTOFF_7_16, CUTOFF_7_16, CUTOFF_7_16, CUTOFF_7_16); // U face
+ drawOffsetPaddedWFace(dest, drect, lampTile, B, 0.85, CUTOFF_7_16, 0, CUTOFF_1_16, CUTOFF_7_16, CUTOFF_7_16); // W face
+ drawOffsetPaddedSFace(dest, drect, lampTile, B, 0.7, CUTOFF_7_16, 0, CUTOFF_1_16, CUTOFF_7_16, CUTOFF_7_16); // S face
+
+
+ }
+ else if(orientation == 2)
+ {
+ drawOffsetPaddedUFace(dest, drect, lampTile, B, CUTOFF_7_16, CUTOFF_7_16, CUTOFF_7_16, 0, CUTOFF_1_16); // U face
+ drawOffsetPaddedWFace(dest, drect, lampTile, B, 0.85, CUTOFF_7_16, CUTOFF_7_16, CUTOFF_7_16, 0, CUTOFF_1_16); // W face
+ drawOffsetPaddedSFace(dest, drect, lampTile, B, 0.7, CUTOFF_1_16, CUTOFF_7_16, CUTOFF_7_16, CUTOFF_7_16, CUTOFF_7_16); // S face
+ /* ----- */
+ drawOffsetPaddedUFace(dest, drect, baseTile, B, CUTOFF_6_16, CUTOFF_6_16, CUTOFF_6_16, CUTOFF_15_16, 0); // U face
+ drawOffsetPaddedWFace(dest, drect, baseTile, B, 0.85, CUTOFF_6_16, CUTOFF_6_16, CUTOFF_6_16, CUTOFF_15_16, 0); // W face
+ drawOffsetPaddedSFace(dest, drect, baseTile, B, 0.7, 0, CUTOFF_6_16, CUTOFF_6_16, CUTOFF_6_16, CUTOFF_6_16); // S face
+ }
+ else if(orientation == 3) // base first
+ {
+ drawOffsetPaddedUFace(dest, drect, baseTile, B, CUTOFF_6_16, CUTOFF_6_16, CUTOFF_6_16, 0, CUTOFF_15_16); // U face
+ drawOffsetPaddedWFace(dest, drect, baseTile, B, 0.85, CUTOFF_6_16, CUTOFF_6_16, CUTOFF_6_16, 0, CUTOFF_15_16); // W face
+ drawOffsetPaddedSFace(dest, drect, baseTile, B, 0.7, CUTOFF_15_16, CUTOFF_6_16, CUTOFF_6_16, CUTOFF_6_16, CUTOFF_6_16); // S face
+ /* ----- */
+ drawOffsetPaddedUFace(dest, drect, lampTile, B, CUTOFF_7_16, CUTOFF_7_16, CUTOFF_7_16, CUTOFF_1_16, 0); // U face
+ drawOffsetPaddedWFace(dest, drect, lampTile, B, 0.85, CUTOFF_7_16, CUTOFF_7_16, CUTOFF_7_16, CUTOFF_1_16, 0); // W face
+ drawOffsetPaddedSFace(dest, drect, lampTile, B, 0.7, 0, CUTOFF_7_16, CUTOFF_7_16, CUTOFF_7_16, CUTOFF_7_16); // S face
+
+
+ }
+ else if(orientation == 4) // base first
+ {
+ drawOffsetPaddedUFace(dest, drect, baseTile, B, CUTOFF_6_16, 0, CUTOFF_15_16, CUTOFF_6_16, CUTOFF_6_16); // U face
+ drawOffsetPaddedWFace(dest, drect, baseTile, B, 0.85, CUTOFF_15_16, CUTOFF_6_16, CUTOFF_6_16, CUTOFF_6_16, CUTOFF_6_16); // W face
+ drawOffsetPaddedSFace(dest, drect, baseTile, B, 0.7, CUTOFF_6_16, CUTOFF_6_16, CUTOFF_6_16, CUTOFF_15_16, 0); // S face
+ /* ----- */
+ drawOffsetPaddedUFace(dest, drect, lampTile, B, CUTOFF_7_16, CUTOFF_1_16, -1, CUTOFF_7_16, CUTOFF_7_16); // U face
+ drawOffsetPaddedWFace(dest, drect, lampTile, B, 0.85, 0, CUTOFF_7_16, CUTOFF_7_16, CUTOFF_7_16, CUTOFF_7_16); // W face
+ drawOffsetPaddedSFace(dest, drect, lampTile, B, 0.7, CUTOFF_7_16, CUTOFF_7_16, CUTOFF_7_16, 0, CUTOFF_1_16); // S face
+
+ }
+ else if(orientation == 5)
+ {
+ drawOffsetPaddedUFace(dest, drect, lampTile, B, CUTOFF_7_16, 0, CUTOFF_1_16, CUTOFF_7_16, CUTOFF_7_16); // U face
+ drawOffsetPaddedWFace(dest, drect, lampTile, B, 0.85, CUTOFF_1_16, CUTOFF_7_16, CUTOFF_7_16, CUTOFF_7_16, CUTOFF_7_16); // W face
+ drawOffsetPaddedSFace(dest, drect, lampTile, B, 0.7, CUTOFF_7_16, CUTOFF_7_16, CUTOFF_7_16, CUTOFF_1_16, 0); // S face
+ /* ----- */
+ drawOffsetPaddedUFace(dest, drect, baseTile, B, CUTOFF_6_16, CUTOFF_15_16, -1, CUTOFF_6_16, CUTOFF_6_16); // U face
+ drawOffsetPaddedWFace(dest, drect, baseTile, B, 0.85, 0, CUTOFF_6_16, CUTOFF_6_16, CUTOFF_6_16, CUTOFF_6_16); // W face
+ drawOffsetPaddedSFace(dest, drect, baseTile, B, 0.7, CUTOFF_6_16, CUTOFF_6_16, CUTOFF_6_16, 0, CUTOFF_15_16); // S face
+ }
+ return;
+
+}
+
+// draw empty flower pot
+void drawFlowerPot(RGBAImage& dest, const ImageRect& drect, const RGBAImage& tile, const RGBAImage& fillerTile, bool drawContent, const RGBAImage& contentTile, int contentType, int B)
+{
+ int tilesize = 2*B;
+
+ int CUTOFF_4_16 = deinterpolate(4, 16, tilesize); // offset, side crop
+ int CUTOFF_5_16 = deinterpolate(5, 16, tilesize); // offset, side crop
+ int CUTOFF_6_16 = deinterpolate(6, 16, tilesize); // dirt crop
+ int CUTOFF_10_16 = deinterpolate(10, 16, tilesize); // top crop
+ int CUTOFF_11_16 = deinterpolate(11, 16, tilesize); // inner side offset
+ int CUTOFF_12_16 = deinterpolate(12, 16, tilesize); // dirt offset
+
+ // draw background pot faces
+ drawOffsetPaddedWFace(dest, drect, tile, B, 0.9, CUTOFF_11_16, CUTOFF_10_16, 0, CUTOFF_5_16, CUTOFF_5_16); // offset W face
+ drawOffsetPaddedSFace(dest, drect, tile, B, 0.8, CUTOFF_11_16, CUTOFF_10_16, 0, CUTOFF_5_16, CUTOFF_5_16); // offset S face
+ drawOffsetPaddedUFace(dest, drect, fillerTile, B, CUTOFF_12_16, CUTOFF_6_16, CUTOFF_6_16, CUTOFF_6_16, CUTOFF_6_16); // cropped U face
+ // draw cactus, if possible
+ if(drawContent && contentType == 1) {
+ drawOffsetPaddedWFace(dest, drect, contentTile, B, 0.9, CUTOFF_6_16, 0, CUTOFF_4_16, CUTOFF_6_16, CUTOFF_6_16); // offset W face
+ drawOffsetPaddedSFace(dest, drect, contentTile, B, 0.8, CUTOFF_6_16, 0, CUTOFF_4_16, CUTOFF_6_16, CUTOFF_6_16); // offset S face
+ drawOffsetPaddedUFace(dest, drect, contentTile, B, 0, CUTOFF_6_16, CUTOFF_6_16, CUTOFF_6_16, CUTOFF_6_16); // cropped U face
+ }
+ // draw front pot faces
+ drawOffsetPaddedWFace(dest, drect, tile, B, 0.9, CUTOFF_5_16, CUTOFF_10_16, 0, CUTOFF_5_16, CUTOFF_5_16); // offset W face
+ drawOffsetPaddedSFace(dest, drect, tile, B, 0.8, CUTOFF_5_16, CUTOFF_10_16, 0, CUTOFF_5_16, CUTOFF_5_16); // offset S face
+
+ // draw multipart/sprite contents of the pot
+ if(drawContent && contentType == 0)
+ drawItemBlockImage(dest, ImageRect(drect.x, drect.y - CUTOFF_4_16, drect.w, drect.h), contentTile, B);
+}
+
+// draw crappy sign facing out towards the viewer
+void drawSign(RGBAImage& dest, const ImageRect& drect, const RGBAImage& faceTile, const RGBAImage& poleTile, int B)
+{
+ // start with fence post
+ drawFencePost(dest, drect, poleTile, B); // fence post
+
+ int tilesize = 2*B;
+ // draw the top half of a tile at [B,B]
+ for (FaceIterator srcit(0, 0, 0, tilesize),
+ dstit(drect.x + B, drect.y + B, 0, tilesize); !srcit.end; srcit.advance(), dstit.advance())
+ {
+ if (dstit.pos % tilesize < B)
+ dest(dstit.x, dstit.y) = faceTile(srcit.x, srcit.y);
+ }
+}
+
+// draw crappy wall lever
+void drawWallLever(RGBAImage& dest, const ImageRect& drect, const RGBAImage& baseTile, const RGBAImage& leverTile, int face, int B)
+{
+ int CUTOFF_8_16 = deinterpolate(8, 16, 2*B);
+ int CUTOFF_5_16 = deinterpolate(5, 16, 2*B);
+ drawPartialSingleFaceBlockImage(dest, drect, baseTile, face, B, CUTOFF_8_16, 0, CUTOFF_5_16, CUTOFF_5_16);
+ drawSingleFaceBlockImage(dest, drect, leverTile, face, B);
+}
+
+void drawFloorLeverNS(RGBAImage& dest, const ImageRect& drect, const RGBAImage& baseTile, const RGBAImage& leverTile, int B)
+{
+ int CUTOFF_5_16 = deinterpolate(5, 16, 2*B);
+ int CUTOFF_4_16 = deinterpolate(4, 16, 2*B);
+ int CUTOFF_16_16 = deinterpolate(16, 16, 2*B);
+ drawOffsetPaddedUFace(dest, drect, baseTile, B, CUTOFF_16_16, CUTOFF_5_16, CUTOFF_5_16, CUTOFF_4_16, CUTOFF_4_16);
+ drawItemBlockImage(dest, drect, leverTile, B);
+}
+
+void drawFloorLeverEW(RGBAImage& dest, const ImageRect& drect, const RGBAImage& baseTile, const RGBAImage& leverTile, int B)
+{
+ int CUTOFF_5_16 = deinterpolate(5, 16, 2*B);
+ int CUTOFF_4_16 = deinterpolate(4, 16, 2*B);
+ int CUTOFF_16_16 = deinterpolate(16, 16, 2*B);
+ drawOffsetPaddedUFace(dest, drect, baseTile, B, CUTOFF_16_16, CUTOFF_4_16, CUTOFF_4_16, CUTOFF_5_16, CUTOFF_5_16);
+ drawItemBlockImage(dest, drect, leverTile, B);
+}
+
+void drawCeilLever(RGBAImage& dest, const ImageRect& drect, const RGBAImage& leverTile, int B)
+{
+ drawItemBlockImage(dest, drect, blockTile(leverTile, 2, false), true, true, true, true, B);
+}
+
+void drawRepeater(RGBAImage& dest, const ImageRect& drect, const RGBAImage& baseTile, const RGBAImage& torchTile, int rot, int B)
+{
+ drawFloorBlockImage(dest, drect, baseTile, rot, B);
+ drawItemBlockImage(dest, drect, torchTile, B);
+}
+
+// draw crappy brewing stand: full base tile plus item-shaped stand
+void drawBrewingStand(RGBAImage& dest, const ImageRect& drect, RGBAImage& base, RGBAImage& stand, int B)
+{
+ drawFloorBlockImage(dest, drect, blockTile(base), B);
+ drawItemBlockImage(dest, drect, stand, B);
+}
+
+void drawCauldron(RGBAImage& dest, const ImageRect& drect, RGBAImage& side, RGBAImage& liquid, int cutoff, int B)
+{
+ SourceTile sideTile = blockTile(side);
+ // start with E/S sides, since liquid goes in front of them
+ drawSingleFaceBlockImage(dest, drect, sideTile, 0, B);
+ drawSingleFaceBlockImage(dest, drect, sideTile, 3, B);
+
+ // draw the liquid
+ if (cutoff > 0)
+ drawPartialBlockImage(dest, drect, liquid, liquid, liquid, B, false, false, true, cutoff, 0, 0, 0, true);
+
+ // now the N/W sides
+ drawSingleFaceBlockImage(dest, drect, sideTile, 1, B);
+ drawSingleFaceBlockImage(dest, drect, sideTile, 2, B);
+}
+
+void drawAnchoredFace(RGBAImage& dest, const ImageRect& drect, const RGBAImage& tile, int B, bool N, bool S, bool W, bool E, bool U)
+{
+ if (N)
+ drawSingleFaceBlockImage(dest, drect, tile, 3, B);
+ if (S)
+ drawSingleFaceBlockImage(dest, drect, tile, 2, B);
+ if (W)
+ drawSingleFaceBlockImage(dest, drect, tile, 1, B);
+ if (E)
+ drawSingleFaceBlockImage(dest, drect, tile, 0, B);
+ if (U)
+ drawCeilBlockImage(dest, drect, tile, 0, B);
+}
+
+// draw crappy dragon egg--just a half-size block
+void drawDragonEgg(RGBAImage& dest, const ImageRect& drect, RGBAImage& tile, int B)
+{
+ int tilesize = 2*B;
+ // N face at [0,0.5B]; draw the bottom-right quarter of it
+ for (FaceIterator srcit(0, 0, 0, tilesize),
+ dstit(drect.x, drect.y + B/2, 1, tilesize); !srcit.end; srcit.advance(), dstit.advance())
+ {
+ if (dstit.pos % tilesize >= B && dstit.pos / tilesize >= B)
+ {
+ dest(dstit.x, dstit.y) = tile(srcit.x, srcit.y);
+ darken(dest(dstit.x, dstit.y), 0.9, 0.9, 0.9);
+ }
+ }
+ // W face at [2B,1.5B]; draw the bottom-left quarter of it
+ for (FaceIterator srcit(0, 0, 0, tilesize),
+ dstit(drect.x + 2*B, drect.y + 3*B/2, -1, tilesize); !srcit.end; srcit.advance(), dstit.advance())
+ {
+ if (dstit.pos % tilesize >= B && dstit.pos / tilesize < B)
+ {
+ dest(dstit.x, dstit.y) = tile(srcit.x, srcit.y);
+ darken(dest(dstit.x, dstit.y), 0.8, 0.8, 0.8);
+ }
+ }
+ // draw the bottom-right quarter of a U face at [2B-1,0.5B]
+ TopFaceIterator tdstit(drect.x + 2*B-1, drect.y + B/2, tilesize);
+ for (FaceIterator srcit(0, 0, 0, tilesize); !srcit.end; srcit.advance(), tdstit.advance())
+ {
+ // again, if B is odd, take B pixels from each column; if even, take B-1 or B+1
+ int cutoff = B;
+ if (B % 2 == 0)
+ cutoff += ((tdstit.pos / tilesize) % 2 == 0) ? -1 : 1;
+ if (tdstit.pos % tilesize >= cutoff && tdstit.pos / tilesize >= cutoff)
+ {
+ dest(tdstit.x, tdstit.y) = tile(srcit.x, srcit.y);
+ }
+ }
+}
+
+
+
+
+int offsetIdx(uint16_t blockID, uint8_t blockData)
+{
+ return blockID * 16 + blockData;
+}
+
+void setOffsetsForID(uint16_t blockID, int offset, BlockImages& bi)
+{
+ int start = blockID * 16;
+ int end = start + 16;
+ fill(bi.blockOffsets + start, bi.blockOffsets + end, offset);
+}
+
+void BlockImages::setBlockDescriptors(ifstream& descriptorlist)
+{
+ // parse block descriptor list
+ int desversion = 0;
+ descriptorlist.clear();
+ descriptorlist.seekg(0, ios_base::beg);
+ string descriptorline;
+
+ while(getline(descriptorlist, descriptorline))
+ {
+ vector blockDescriptor;
+ if(descriptorline.size() > 0 && descriptorline[0] != '#')
+ {
+ istringstream descriptorlinestream(descriptorline);
+ while (!descriptorlinestream.eof())
+ {
+ string descriptorfield;
+ getline( descriptorlinestream, descriptorfield, ' ' );
+ if(descriptorfield[0] == '#')
+ break;
+ blockDescriptor.push_back(descriptorfield);
+ desversion++;
+ }
+ blockDescriptors.push_back(blockDescriptor);
+ }
+ }
+}
+
+int BlockImages::setOffsets()
+{
+ // default is the dummy image
+ fill(blockOffsets, blockOffsets + 4096*16, 0);
+
+ // Fill in offset depending on block type
+ int offsetIterator = 1;
+ int64_t blockid;
+ for(vector< vector >::iterator it = blockDescriptors.begin(); it != blockDescriptors.end(); ++it)
+ {
+ vector descriptor = (*it);
+ if(fromstring(descriptor[0], blockid))
+ {
+ int descriptorsize = descriptor.size();
+ if(descriptor[1] == "SOLID")
+ {
+ if(descriptorsize == 3 || descriptorsize == 5)
+ setOffsetsForID(blockid, offsetIterator, *this);
+ }
+ else if(descriptor[1] == "SOLIDORIENTED")
+ {
+ if(descriptorsize == 9)
+ {
+ // orientation bits order: N S W E - descriptor[2 3 4 5]
+ int orientationoffset;
+ setOffsetsForID(blockid, offsetIterator, *this); // default orientation assumed N, so skip checking N offset descriptor
+ if(!fromstring(descriptor[5], orientationoffset))
+ orientationoffset = 5;
+ blockOffsets[offsetIdx(blockid, orientationoffset)] = offsetIterator; // oriented E, since front is facing from viewer, it is same as N facing block
+ if(!fromstring(descriptor[3], orientationoffset))
+ orientationoffset = 3;
+ blockOffsets[offsetIdx(blockid, orientationoffset)] = ++offsetIterator; // oriented S
+ if(!fromstring(descriptor[4], orientationoffset))
+ orientationoffset = 4;
+ blockOffsets[offsetIdx(blockid, orientationoffset)] = ++offsetIterator; // oriented W
+ }
+ }
+ else if(descriptor[1] == "SOLIDROTATED")
+ {
+ if(descriptorsize == 6 || descriptorsize == 4)
+ {
+ int rotDegrees;
+ if(!fromstring(descriptor[2], rotDegrees)) rotDegrees = 6;
+
+ setOffsetsForID(blockid, offsetIterator, *this);
+
+ if(rotDegrees == 6)
+ {
+ // piston value order: down / top / N / S / W / E
+ // piston extension bit: 0x8 (top bit)
+ blockOffsets[offsetIdx(blockid, 0)] = blockOffsets[offsetIdx(blockid, 8)] = offsetIterator; // facing Down
+ blockOffsets[offsetIdx(blockid, 1)] = blockOffsets[offsetIdx(blockid, 9)] = ++offsetIterator; // facing Top
+ blockOffsets[offsetIdx(blockid, 2)] = blockOffsets[offsetIdx(blockid, 10)] = ++offsetIterator; // facing N
+ blockOffsets[offsetIdx(blockid, 3)] = blockOffsets[offsetIdx(blockid, 11)] = ++offsetIterator; // facing S
+ blockOffsets[offsetIdx(blockid, 4)] = blockOffsets[offsetIdx(blockid, 12)] = ++offsetIterator; // facing W
+ blockOffsets[offsetIdx(blockid, 5)] = blockOffsets[offsetIdx(blockid, 13)] = ++offsetIterator; // facing E
+ }
+ else if(rotDegrees == 4)
+ {
+ blockOffsets[offsetIdx(blockid, 0)] = offsetIterator; // facing N
+ blockOffsets[offsetIdx(blockid, 1)] = ++offsetIterator; // facing S
+ blockOffsets[offsetIdx(blockid, 2)] = ++offsetIterator; // facing W
+ blockOffsets[offsetIdx(blockid, 3)] = ++offsetIterator; // facing E
+ }
+ }
+ }
+ else if(descriptor[1] == "SOLIDDATA")
+ {
+ if(descriptorsize > 2)
+ {
+ setOffsetsForID(blockid, offsetIterator, *this);
+ for(int i = 0; i < descriptorsize - 2; i++, offsetIterator++)
+ {
+ blockOffsets[offsetIdx(blockid, i)] = offsetIterator;
+ }
+ continue;
+ }
+ }
+ else if(descriptor[1] == "SOLIDDATAFILL")
+ {
+ if(descriptorsize > 2)
+ {
+ int datasize = descriptorsize - 2;
+ for(int i = 0; i < descriptorsize - 2; i++, offsetIterator++)
+ {
+ for(int di = i; di < 16; di += datasize)
+ blockOffsets[offsetIdx(blockid, di)] = offsetIterator;
+ }
+ continue;
+ }
+ }
+ else if(descriptor[1] == "SOLIDDATATRUNK")
+ {
+ if(descriptorsize % 2 == 0 && descriptorsize > 3)
+ {
+ setOffsetsForID(blockid, offsetIterator, *this);
+ for(int i = 0; i < descriptorsize - 2; i += 2, offsetIterator++)
+ blockOffsets[offsetIdx(blockid, i/2)] = offsetIterator;
+ continue;
+ }
+ }
+ else if(descriptor[1] == "SOLIDDATATRUNKROTATED")
+ {
+ if((descriptorsize - 3) % 3 == 0 && descriptorsize > 3)
+ {
+ int orientationFlag;
+ bool dataOrdered = (descriptor[2] == "O") ? true : false;
+
+ setOffsetsForID(blockid, offsetIterator, *this);
+ for(int i = 0, j = 0; i < descriptorsize - 3 && j < 16; i += 3, j++, offsetIterator++)
+ {
+ blockOffsets[offsetIdx(blockid, j)] = offsetIterator;
+
+ if(!fromstring(descriptor[i + 3], orientationFlag))
+ orientationFlag = 0;
+ if(dataOrdered && orientationFlag == 1)
+ {
+ blockOffsets[offsetIdx(blockid, ++j)] = ++offsetIterator; // trunk EW
+ blockOffsets[offsetIdx(blockid, ++j)] = ++offsetIterator; // trunk NS
+ }
+ else if(orientationFlag == 1)
+ {
+ blockOffsets[offsetIdx(blockid, j + 4)] = ++offsetIterator; // trunk EW
+ blockOffsets[offsetIdx(blockid, j + 8)] = ++offsetIterator; // trunk NS
+ blockOffsets[offsetIdx(blockid, j + 12)] = ++offsetIterator; // trunk not oriented
+ }
+ }
+ continue;
+ }
+ }
+ else if(descriptor[1] == "SOLIDOBSTRUCTED")
+ {
+ if(descriptorsize == 3 || descriptorsize == 5)
+ {
+ setOffsetsForID(blockid, offsetIterator, *this);
+ offsetIterator += 3;// reserve space for special cases of missing faces facing viewer (W, S, W+S)
+ }
+ }
+ else if(descriptor[1] == "SOLIDPARTIAL")
+ {
+ if(descriptorsize == 7)
+ {
+ setOffsetsForID(blockid, offsetIterator, *this);
+ }
+ }
+ else if(descriptor[1] == "SOLIDDATAPARTIAL")
+ {
+ int datasize = descriptorsize - 4;
+ if(datasize > 0)
+ {
+ setOffsetsForID(blockid, offsetIterator, *this);
+ for(int i = 0; i < datasize && i < 16; i++, offsetIterator++)
+ {
+ blockOffsets[offsetIdx(blockid, i)] = offsetIterator;
+ }
+ continue;
+ }
+ }
+ else if(descriptor[1] == "SOLIDDATAPARTIALFILL")
+ {
+ int datasize = descriptorsize - 5;
+ if(datasize % 2 == 0)
+ {
+ for(int i = 0; i < datasize/2; i++, offsetIterator++)
+ for(int di = i; di < 16; di += datasize)
+ {
+ blockOffsets[offsetIdx(blockid, di)] = offsetIterator;
+ }
+ continue;
+ }
+ }
+ else if(descriptor[1] == "SOLIDTRANSPARENT")
+ {
+ if(descriptorsize == 8)
+ {
+ setOffsetsForID(blockid, offsetIterator, *this);
+ }
+ }
+ else if(descriptor[1] == "SLABDATA")
+ {
+ if(descriptorsize > 2)
+ {
+ for(int i = 0; i < descriptorsize - 2; i++, offsetIterator++)
+ {
+ // bottom slab
+ blockOffsets[offsetIdx(blockid, i)] = offsetIterator;
+ // inverted slab
+ blockOffsets[offsetIdx(blockid, i + 8)] = ++offsetIterator;
+ }
+ continue;
+ }
+ }
+ else if(descriptor[1] == "SLABDATATRUNK")
+ {
+ if(descriptorsize % 2 == 0 && descriptorsize > 3)
+ {
+ setOffsetsForID(blockid, offsetIterator, *this);
+ for(int i = 0; i < descriptorsize - 2; i += 2, offsetIterator++)
+ {
+ // bottom slab
+ blockOffsets[offsetIdx(blockid, i/2)] = offsetIterator;
+ // inverted slab
+ blockOffsets[offsetIdx(blockid, i/2 + 8)] = ++offsetIterator;
+ }
+ continue;
+ }
+ }
+ else if(descriptor[1] == "ITEMDATA" || descriptor[1] == "MULTIITEMDATA")
+ {
+ if(descriptorsize > 2)
+ {
+ setOffsetsForID(blockid, offsetIterator, *this);
+ for(int i = 0; i < descriptorsize - 2; i++, offsetIterator++)
+ {
+ blockOffsets[offsetIdx(blockid, i)] = offsetIterator;
+ }
+ continue;
+ }
+ }
+ else if(descriptor[1] == "ITEMDATAORIENTED")
+ {
+ if(descriptorsize > 6)
+ {
+ int datasize = descriptorsize - 6;
+ // orientation bits order: N S W E - descriptor[2 3 4 5]
+ int orientationoffset;
+ setOffsetsForID(blockid, offsetIterator, *this);
+ for(int i = 0; i < datasize && i < 4; i++, offsetIterator++)
+ {
+ if(!fromstring(descriptor[2], orientationoffset))
+ orientationoffset = 0;
+ blockOffsets[offsetIdx(blockid, orientationoffset + 4*i)] = offsetIterator; // N
+ if(!fromstring(descriptor[3], orientationoffset))
+ orientationoffset = 2;
+ blockOffsets[offsetIdx(blockid, orientationoffset + 4*i)] = ++offsetIterator; // S
+ if(!fromstring(descriptor[4], orientationoffset))
+ orientationoffset = 3;
+ blockOffsets[offsetIdx(blockid, orientationoffset + 4*i)] = ++offsetIterator; // W
+ if(!fromstring(descriptor[5], orientationoffset))
+ orientationoffset = 1;
+ blockOffsets[offsetIdx(blockid, orientationoffset + 4*i)] = ++offsetIterator; // E
+ }
+ continue;
+ }
+ }
+ else if(descriptor[1] == "ITEMDATAFILL")
+ {
+ if(descriptorsize > 3)
+ {
+ int datasize = descriptorsize - 3;
+ int groupsize;
+ if(!fromstring(descriptor[2], groupsize))
+ groupsize = 4;
+ for(int i = 0; i < datasize; i++, offsetIterator++)
+ {
+ for(int di = i; di < 16; di += groupsize)
+ blockOffsets[offsetIdx(blockid, di)] = offsetIterator;
+ }
+ continue;
+ }
+
+ }
+ else if(descriptor[1] == "ITEMDATATALLORIENTED")
+ {
+ if(descriptorsize % 2 == 0 && descriptorsize > 2)
+ {
+ int datasize = descriptorsize - 2;
+ setOffsetsForID(blockid, offsetIterator, *this); // dummy
+ for(int i = 0; i < datasize/2 && i < 8; i++, offsetIterator++)
+ {
+ blockOffsets[offsetIdx(blockid, i)] = offsetIterator++; // bottom-base block
+ }
+ continue;
+ }
+
+ }
+ else if(descriptor[1] == "STAIR")
+ {
+ if(descriptorsize > 2)
+ {
+ setOffsetsForID(blockid, offsetIterator, *this); // asc E
+ blockOffsets[offsetIdx(blockid, 1)] = ++offsetIterator; // asc W
+ blockOffsets[offsetIdx(blockid, 2)] = ++offsetIterator; // asc S
+ blockOffsets[offsetIdx(blockid, 3)] = ++offsetIterator; // asc N
+ blockOffsets[offsetIdx(blockid, 4)] = ++offsetIterator; // asc E inverted
+ blockOffsets[offsetIdx(blockid, 5)] = ++offsetIterator; // asc W inverted
+ blockOffsets[offsetIdx(blockid, 6)] = ++offsetIterator; // asc S inverted
+ blockOffsets[offsetIdx(blockid, 7)] = ++offsetIterator; // asc N inverted
+ }
+ }
+ else if(descriptor[1] == "FENCE")
+ {
+ setOffsetsForID(blockid, offsetIterator, *this); // fence post
+ offsetIterator += 15; // reserve space for fence connections
+ }
+ else if(descriptor[1] == "WALLDATA")
+ {
+ setOffsetsForID(blockid, offsetIterator, *this);
+ for(int i = 0; i < descriptorsize - 2; i++, offsetIterator++)
+ {
+ blockOffsets[offsetIdx(blockid, i)] = offsetIterator; // wall post
+ offsetIterator += 17; // reserve space for wall connections for each wall type (per data bit) + plain walls
+ }
+ continue;
+
+ }
+ else if(descriptor[1] == "FENCEGATE")
+ {
+ setOffsetsForID(blockid, offsetIterator, *this); // fence gate EW
+ // fence gate NS
+ blockOffsets[offsetIdx(blockid, 1)] = blockOffsets[offsetIdx(blockid, 3)] = blockOffsets[offsetIdx(blockid, 5)] = blockOffsets[offsetIdx(blockid, 7)] = ++offsetIterator;
+ }
+ else if(descriptor[1] == "MUSHROOM")
+ {
+ setOffsetsForID(blockid, offsetIterator, *this); // pores on all sides
+ blockOffsets[offsetIdx(blockid, 15)] = ++offsetIterator; // all stem
+ blockOffsets[offsetIdx(blockid, 7)] = blockOffsets[offsetIdx(blockid, 14)] = ++offsetIterator; // all cap
+ blockOffsets[offsetIdx(blockid, 1)] = blockOffsets[offsetIdx(blockid, 4)] = ++offsetIterator; // cap @ UWN + UW
+ blockOffsets[offsetIdx(blockid, 2)] = blockOffsets[offsetIdx(blockid, 3)] = blockOffsets[offsetIdx(blockid, 5)] = blockOffsets[offsetIdx(blockid, 6)] = ++offsetIterator; // only top visible - cap @ U + UN + UE + UNE
+ blockOffsets[offsetIdx(blockid, 8)] = blockOffsets[offsetIdx(blockid, 9)] = ++offsetIterator; // cap @ US + USE
+ blockOffsets[offsetIdx(blockid, 10)] = ++offsetIterator; // stem
+ }
+ else if(descriptor[1] == "CHEST")
+ {
+ // single chest
+ setOffsetsForID(blockid, offsetIterator, *this);
+ blockOffsets[offsetIdx(blockid, 2)] = blockOffsets[offsetIdx(blockid, 5)] = offsetIterator; // facing N,E
+ blockOffsets[offsetIdx(blockid, 3)] = ++offsetIterator; // facing S
+ blockOffsets[offsetIdx(blockid, 4)] = ++offsetIterator; // facing W
+ if(descriptorsize == 4) // double chests
+ {
+ offsetIterator += 8; // reserve space for connected chests variations
+ }
+ }
+ else if(descriptor[1] == "RAIL")
+ {
+ setOffsetsForID(blockid, offsetIterator, *this); // flat NS
+ blockOffsets[offsetIdx(blockid, 1)] = ++offsetIterator; // flat WE
+ blockOffsets[offsetIdx(blockid, 2)] = ++offsetIterator; // asc E
+ blockOffsets[offsetIdx(blockid, 3)] = ++offsetIterator; // asc W
+ blockOffsets[offsetIdx(blockid, 4)] = ++offsetIterator; // asc N
+ blockOffsets[offsetIdx(blockid, 5)] = ++offsetIterator; // asc S
+ if(descriptorsize == 4) // rail turns
+ {
+ blockOffsets[offsetIdx(blockid, 6)] = ++offsetIterator; // NW corner (->SE)
+ blockOffsets[offsetIdx(blockid, 7)] = ++offsetIterator; // NE corner (->SW)
+ blockOffsets[offsetIdx(blockid, 8)] = ++offsetIterator; // SE corner (->NW)
+ blockOffsets[offsetIdx(blockid, 9)] = ++offsetIterator; // SW corner (->NE)
+ }
+ }
+ else if(descriptor[1] == "RAILPOWERED")
+ {
+ setOffsetsForID(blockid, offsetIterator, *this); // flat NS
+ blockOffsets[offsetIdx(blockid, 1)] = ++offsetIterator; // flat WE
+ blockOffsets[offsetIdx(blockid, 2)] = ++offsetIterator; // asc E
+ blockOffsets[offsetIdx(blockid, 3)] = ++offsetIterator; // asc W
+ blockOffsets[offsetIdx(blockid, 4)] = ++offsetIterator; // asc N
+ blockOffsets[offsetIdx(blockid, 5)] = ++offsetIterator; // asc S
+ blockOffsets[offsetIdx(blockid, 8)] = ++offsetIterator; // flat NS powered
+ blockOffsets[offsetIdx(blockid, 9)] = ++offsetIterator; // flat WE powered
+ blockOffsets[offsetIdx(blockid, 10)] = ++offsetIterator; // asc E powered
+ blockOffsets[offsetIdx(blockid, 11)] = ++offsetIterator; // asc W powered
+ blockOffsets[offsetIdx(blockid, 12)] = ++offsetIterator; // asc N powered
+ blockOffsets[offsetIdx(blockid, 13)] = ++offsetIterator; // asc S powered
+ }
+ else if(descriptor[1] == "PANEDATA")
+ {
+ setOffsetsForID(blockid, offsetIterator, *this); // basic pane
+ for(int i = 0; i < descriptorsize - 2; i++, offsetIterator++)
+ {
+ blockOffsets[offsetIdx(blockid, i)] = offsetIterator; // basic pane
+ offsetIterator += 14; // reserve space for pane connections for each pane type (per data bit)
+ }
+ continue;
+ }
+ else if(descriptor[1] == "DOOR")
+ {
+ setOffsetsForID(blockid, offsetIterator, *this); // door
+ offsetIterator += 7; // reserve space for different orientations of top and down door parts
+ }
+ else if(descriptor[1] == "TRAPDOOR")
+ {
+ // closed on the bottom half of block
+ blockOffsets[offsetIdx(blockid, 0)] = blockOffsets[offsetIdx(blockid, 1)] = blockOffsets[offsetIdx(blockid, 2)] = blockOffsets[offsetIdx(blockid, 3)] = offsetIterator;
+ // closed on the top half of block
+ blockOffsets[offsetIdx(blockid, 8)] = blockOffsets[offsetIdx(blockid, 9)] = blockOffsets[offsetIdx(blockid, 10)] = blockOffsets[offsetIdx(blockid, 11)] = ++offsetIterator;
+ blockOffsets[offsetIdx(blockid, 4)] = blockOffsets[offsetIdx(blockid, 12)] = ++offsetIterator; // attached to S
+ blockOffsets[offsetIdx(blockid, 5)] = blockOffsets[offsetIdx(blockid, 13)] = ++offsetIterator; // attached to N
+ blockOffsets[offsetIdx(blockid, 6)] = blockOffsets[offsetIdx(blockid, 14)] = ++offsetIterator; // attached to E
+ blockOffsets[offsetIdx(blockid, 7)] = blockOffsets[offsetIdx(blockid, 15)] = ++offsetIterator; // attached to W
+ }
+ else if(descriptor[1] == "TORCH")
+ {
+ setOffsetsForID(blockid, offsetIterator, *this);
+ blockOffsets[offsetIdx(blockid, 1)] = ++offsetIterator; // pointing E
+ blockOffsets[offsetIdx(blockid, 2)] = ++offsetIterator; // pointing W
+ blockOffsets[offsetIdx(blockid, 3)] = ++offsetIterator; // pointing S
+ blockOffsets[offsetIdx(blockid, 4)] = ++offsetIterator; // pointing N
+ }
+ else if(descriptor[1] == "ONWALLPARTIALFILL")
+ {
+ if(descriptorsize == 11)
+ {
+ int64_t dataoffset;
+ for(int i = 0; i < 4; i++, offsetIterator++) // for each wall side
+ {
+ if(!fromstring(descriptor[2 + i], dataoffset))
+ dataoffset = i;
+ for(int di = dataoffset; di < 16; di += 4) // fill until end of blockdata
+ blockOffsets[offsetIdx(blockid, di)] = offsetIterator;
+ }
+ continue;
+ }
+ }
+ else if(descriptor[1] == "WIRE")
+ {
+ setOffsetsForID(blockid, offsetIterator, *this);
+ offsetIterator += 11; // reserve space for different wire connections
+ }
+ else if(descriptor[1] == "BITANCHOR")
+ {
+ for(int i = 0; i < 16; i++, offsetIterator++)
+ blockOffsets[offsetIdx(blockid, i)] = offsetIterator;
+ continue;
+ }
+ else if(descriptor[1] == "STEM")
+ {
+ setOffsetsForID(blockid, offsetIterator, *this);
+ for(int i = 0; i < 8; i++, offsetIterator++)
+ blockOffsets[offsetIdx(blockid, i)] = offsetIterator;
+ offsetIterator += 3; // reserve space for different stem connections (N S W E)
+ }
+ else if(descriptor[1] == "REPEATER")
+ {
+ if(descriptorsize == 6) // combined state (comparator)
+ {
+ blockOffsets[offsetIdx(blockid, 0)] = blockOffsets[offsetIdx(blockid, 4)] = offsetIterator;
+ blockOffsets[offsetIdx(blockid, 1)] = blockOffsets[offsetIdx(blockid, 5)] = ++offsetIterator;
+ blockOffsets[offsetIdx(blockid, 2)] = blockOffsets[offsetIdx(blockid, 6)] = ++offsetIterator;
+ blockOffsets[offsetIdx(blockid, 3)] = blockOffsets[offsetIdx(blockid, 7)] = ++offsetIterator;
+
+ blockOffsets[offsetIdx(blockid, 8)] = blockOffsets[offsetIdx(blockid, 12)] = ++offsetIterator;
+ blockOffsets[offsetIdx(blockid, 9)] = blockOffsets[offsetIdx(blockid, 13)] = ++offsetIterator;
+ blockOffsets[offsetIdx(blockid, 10)] = blockOffsets[offsetIdx(blockid, 14)] = ++offsetIterator;
+ blockOffsets[offsetIdx(blockid, 11)] = blockOffsets[offsetIdx(blockid, 15)] = ++offsetIterator;
+ }
+ else // separate states (repeater)
+ {
+ blockOffsets[offsetIdx(blockid, 0)] = blockOffsets[offsetIdx(blockid, 4)] = blockOffsets[offsetIdx(blockid, 8)] = blockOffsets[offsetIdx(blockid, 12)] = offsetIterator;
+ blockOffsets[offsetIdx(blockid, 1)] = blockOffsets[offsetIdx(blockid, 5)] = blockOffsets[offsetIdx(blockid, 9)] = blockOffsets[offsetIdx(blockid, 13)] = ++offsetIterator;
+ blockOffsets[offsetIdx(blockid, 2)] = blockOffsets[offsetIdx(blockid, 6)] = blockOffsets[offsetIdx(blockid, 10)] = blockOffsets[offsetIdx(blockid, 14)] = ++offsetIterator;
+ blockOffsets[offsetIdx(blockid, 3)] = blockOffsets[offsetIdx(blockid, 7)] = blockOffsets[offsetIdx(blockid, 11)] = blockOffsets[offsetIdx(blockid, 15)] = ++offsetIterator;
+ }
+ }
+ else if(descriptor[1] == "LEVER")
+ {
+ blockOffsets[offsetIdx(blockid, 1)] = blockOffsets[offsetIdx(blockid, 9)] = offsetIterator; // facing E
+ blockOffsets[offsetIdx(blockid, 2)] = blockOffsets[offsetIdx(blockid, 10)] = ++offsetIterator; // facing W
+ blockOffsets[offsetIdx(blockid, 3)] = blockOffsets[offsetIdx(blockid, 11)] = ++offsetIterator; // facing S
+ blockOffsets[offsetIdx(blockid, 4)] = blockOffsets[offsetIdx(blockid, 12)] = ++offsetIterator; // facing N
+ blockOffsets[offsetIdx(blockid, 5)] = blockOffsets[offsetIdx(blockid, 13)] = ++offsetIterator; // ground NS
+ blockOffsets[offsetIdx(blockid, 6)] = blockOffsets[offsetIdx(blockid, 14)] = ++offsetIterator; // ground WE
+ blockOffsets[offsetIdx(blockid, 0)] = blockOffsets[offsetIdx(blockid, 7)] = ++offsetIterator; // ceil NS
+ blockOffsets[offsetIdx(blockid, 8)] = blockOffsets[offsetIdx(blockid, 15)] = offsetIterator; // ceil WE
+ }
+ else if(blockid == 8) // water
+ {
+ setOffsetsForID(8, offsetIterator, *this);
+ setOffsetsForID(9, offsetIterator, *this);
+ offsetIterator += 3; // reserve space for water special cases (surface, missing W face, missing S face)
+ blockOffsets[offsetIdx(8, 1)] = blockOffsets[offsetIdx(9, 1)] = ++offsetIterator; // draw water levels
+ blockOffsets[offsetIdx(8, 2)] = blockOffsets[offsetIdx(9, 2)] = ++offsetIterator;
+ blockOffsets[offsetIdx(8, 3)] = blockOffsets[offsetIdx(9, 3)] = ++offsetIterator;
+ blockOffsets[offsetIdx(8, 4)] = blockOffsets[offsetIdx(9, 4)] = ++offsetIterator;
+ blockOffsets[offsetIdx(8, 5)] = blockOffsets[offsetIdx(9, 5)] = ++offsetIterator;
+ blockOffsets[offsetIdx(8, 6)] = blockOffsets[offsetIdx(9, 6)] = ++offsetIterator;
+ blockOffsets[offsetIdx(8, 7)] = blockOffsets[offsetIdx(9, 7)] = ++offsetIterator;
+ }
+ else if(blockid == 10) // lava
+ {
+ setOffsetsForID(10, offsetIterator, *this);
+ setOffsetsForID(11, offsetIterator, *this);
+ blockOffsets[offsetIdx(10, 2)] = blockOffsets[offsetIdx(11, 2)] = ++offsetIterator;
+ blockOffsets[offsetIdx(10, 4)] = blockOffsets[offsetIdx(11, 4)] = ++offsetIterator;
+ blockOffsets[offsetIdx(10, 6)] = blockOffsets[offsetIdx(11, 6)] = ++offsetIterator;
+ }
+ else if(blockid == 26) // bed
+ {
+ blockOffsets[offsetIdx(blockid, 0)] = blockOffsets[offsetIdx(blockid, 4)] = offsetIterator; // bed foot pointing S
+ blockOffsets[offsetIdx(blockid, 1)] = blockOffsets[offsetIdx(blockid, 5)] = ++offsetIterator; // bed foot pointing W
+ blockOffsets[offsetIdx(blockid, 2)] = blockOffsets[offsetIdx(blockid, 6)] = ++offsetIterator; // bed foot pointing N
+ blockOffsets[offsetIdx(blockid, 3)] = blockOffsets[offsetIdx(blockid, 7)] = ++offsetIterator; // bed foot pointing E
+ blockOffsets[offsetIdx(blockid, 8)] = blockOffsets[offsetIdx(blockid, 12)] = ++offsetIterator; // bed head pointing S
+ blockOffsets[offsetIdx(blockid, 9)] = blockOffsets[offsetIdx(blockid, 13)] = ++offsetIterator; // bed head pointing W
+ blockOffsets[offsetIdx(blockid, 10)] = blockOffsets[offsetIdx(blockid, 14)] = ++offsetIterator; // bed head pointing N
+ blockOffsets[offsetIdx(blockid, 11)] = blockOffsets[offsetIdx(blockid, 15)] = ++offsetIterator; // bed head pointing E
+ }
+ else if(blockid == 117 || blockid == 122 || blockid == 138 || blockid == 154 || descriptor[1] == "SIGNPOST") // single special blocks: brewing stand, dragon egg, beacon, hopper
+ {
+ setOffsetsForID(blockid, offsetIterator, *this);
+ }
+ else if(blockid == 118) // cauldron
+ {
+ setOffsetsForID(blockid, offsetIterator, *this);
+ blockOffsets[offsetIdx(blockid, 1)] = ++offsetIterator; // cauldron 1/3 full
+ blockOffsets[offsetIdx(blockid, 2)] = ++offsetIterator; // cauldron 2/3 full
+ blockOffsets[offsetIdx(blockid, 3)] = ++offsetIterator; // cauldron full
+ }
+ else if(blockid == 140) // flower pot
+ {
+ setOffsetsForID(blockid, offsetIterator, *this); // flower pot
+ /* flower pot item data is contained in tile entity since 1.7(unavailable in rendering process)
+ for(int i = 4; i < descriptorsize; i++)
+ blockOffsets[offsetIdx(blockid, i - 3)] = ++offsetIterator;
+ */
+ }
+ else if(blockid == 145) // anvil
+ {
+ setOffsetsForID(blockid, offsetIterator, *this); // anvil NS
+ blockOffsets[offsetIdx(blockid, 1)] = blockOffsets[offsetIdx(blockid, 3)] = ++offsetIterator; // anvil EW
+ blockOffsets[offsetIdx(blockid, 4)] = blockOffsets[offsetIdx(blockid, 6)] = ++offsetIterator; // slightly damaged anvil NS
+ blockOffsets[offsetIdx(blockid, 5)] = blockOffsets[offsetIdx(blockid, 7)] = ++offsetIterator; // slightly damaged anvil EW
+ blockOffsets[offsetIdx(blockid, 8)] = blockOffsets[offsetIdx(blockid, 10)] = ++offsetIterator; // very damaged anvil NS
+ blockOffsets[offsetIdx(blockid, 9)] = blockOffsets[offsetIdx(blockid, 11)] = ++offsetIterator; // very damaged anvil EW
+ }
+ else if(blockid == 198) // end rod
+ {
+ setOffsetsForID(blockid, offsetIterator, *this); // end rod D
+ blockOffsets[offsetIdx(blockid, 1)] = ++offsetIterator; // U
+ blockOffsets[offsetIdx(blockid, 2)] = ++offsetIterator; // N
+ blockOffsets[offsetIdx(blockid, 3)] = ++offsetIterator; // S
+ blockOffsets[offsetIdx(blockid, 4)] = ++offsetIterator; // W
+ blockOffsets[offsetIdx(blockid, 5)] = ++offsetIterator; // E
+ }
+ offsetIterator++;
+ }
+ }
+
+ return offsetIterator;
+}
+
+void BlockImages::checkOpacityAndTransparency(int B)
+{
+ opacity.clear();
+ opacity.resize(blockversion, true);
+ transparency.clear();
+ transparency.resize(blockversion, true);
+
+ for (int i = 0; i < blockversion; i++)
+ {
+ ImageRect rect = getRect(i);
+ // use the face iterators to examine the N, W, and U faces; any non-100% alpha makes
+ // the block non-opaque, and any non-0% alpha makes the block non-transparent
+ int tilesize = 2*B;
+ // N face starts at [0,B]
+ for (FaceIterator it(rect.x, rect.y + B, 1, tilesize); !it.end; it.advance())
+ {
+ int a = ALPHA(img(it.x, it.y));
+ if (a < 255)
+ opacity[i] = false;
+ if (a > 0)
+ transparency[i] = false;
+ if (!opacity[i] && !transparency[i])
+ break;
+ }
+ if (!opacity[i] && !transparency[i])
+ continue;
+ // W face starts at [2B,2B]
+ for (FaceIterator it(rect.x + 2*B, rect.y + 2*B, -1, tilesize); !it.end; it.advance())
+ {
+ int a = ALPHA(img(it.x, it.y));
+ if (a < 255)
+ opacity[i] = false;
+ if (a > 0)
+ transparency[i] = false;
+ if (!opacity[i] && !transparency[i])
+ break;
+ }
+ if (!opacity[i] && !transparency[i])
+ continue;
+ // U face starts at [2B-1,0]
+ for (TopFaceIterator it(rect.x + 2*B-1, rect.y, tilesize); !it.end; it.advance())
+ {
+ int a = ALPHA(img(it.x, it.y));
+ if (a < 255)
+ opacity[i] = false;
+ if (a > 0)
+ transparency[i] = false;
+ if (!opacity[i] && !transparency[i])
+ break;
+ }
+ }
+}
+
+void BlockImages::retouchAlphas(int B)
+{
+ for (int i = 0; i < blockversion; i++)
+ {
+ ImageRect rect = getRect(i);
+ // use the face iterators to examine the N, W, and U faces; any alpha under 10 is changed
+ // to 0, and any alpha above 245 is changed to 255
+ int tilesize = 2*B;
+ // N face starts at [0,B]
+ for (FaceIterator it(rect.x, rect.y + B, 1, tilesize); !it.end; it.advance())
+ {
+ int a = ALPHA(img(it.x, it.y));
+ if (a < 10)
+ setAlpha(img(it.x, it.y), 0);
+ else if (a > 245)
+ setAlpha(img(it.x, it.y), 255);
+ }
+ // W face starts at [2B,2B]
+ for (FaceIterator it(rect.x + 2*B, rect.y + 2*B, -1, tilesize); !it.end; it.advance())
+ {
+ int a = ALPHA(img(it.x, it.y));
+ if (a < 10)
+ setAlpha(img(it.x, it.y), 0);
+ else if (a > 245)
+ setAlpha(img(it.x, it.y), 255);
+ }
+ // U face starts at [2B-1,0]
+ for (TopFaceIterator it(rect.x + 2*B-1, rect.y, tilesize); !it.end; it.advance())
+ {
+ int a = ALPHA(img(it.x, it.y));
+ if (a < 10)
+ setAlpha(img(it.x, it.y), 0);
+ else if (a > 245)
+ setAlpha(img(it.x, it.y), 255);
+ }
+ }
+}
+
+bool BlockImages::construct(int B, ifstream& texturelist, ifstream& descriptorlist, const string& imgpath)
+{
+ if (B < 2)
+ return false;
+
+ int32_t tileSize = 2*B;
+
+ // determine some cutoff values for partial block images: given a particular pixel offset in texture tile--for
+ // example, the end portal frame texture is missing its top 3 (out of 16) pixels--we need to know which pixel
+ // in the resized tile is the first one past that offset
+ // ...if the texture tile size isn't a multiple of 16 for some reason, this may break down and be ugly
+ int CUTOFFS_16[17];
+ for(int i = 0; i < 17; i++)
+ {
+ CUTOFFS_16[i] = deinterpolate(i, 16, tileSize);
+ }
+
+ // Load block textures into hashmap based on their name
+ unordered_map blockTextures; // vector holding source textures
+ string blocktexturespath = imgpath + "/textures/blocks"; // default path
+ string textureline;
+ string texturename;
+ int32_t textureSize;
+ unsigned textureiterator = 0;
+ bool missingtextures = false;
+ RGBAImage iblockimage;
+
+ // Reset file stream
+ texturelist.clear();
+ texturelist.seekg(0, ios_base::beg);
+ // Read list of textures (each texture file on new line)
+ while(getline(texturelist, textureline))
+ {
+ vector textureDirectives;
+ // read texture list
+ if(textureline.size() > 0 && textureline[0] != '#')
+ {
+ istringstream texturelinestream(textureline);
+ while (!texturelinestream.eof())
+ {
+ string texturedirective;
+ getline( texturelinestream, texturedirective, ' ' );
+ if(texturedirective[0] == '#')
+ break;
+ if(texturedirective.size() == 0) // skip empty directive
+ continue;
+ textureDirectives.push_back(texturedirective);
+ }
+ }
+ // process directives
+ if(textureDirectives.size() == 2 && textureDirectives[0] == "$") // switch texture directory
+ {
+ blocktexturespath = imgpath + textureDirectives[1];
+ }
+ else if(textureDirectives.size() > 2 && textureDirectives[0] == "/") // process texture with directives
+ {
+ if(!iblockimage.readPNG(blocktexturespath + "/" + textureDirectives[1])) // texture read error
+ {
+ cerr << "[blocktextures.list] @" << textureiterator + 1 << " - " << blocktexturespath << "/" << textureDirectives[1] << " is missing or invalid (not 24BPP/32BPP PNG image)" << endl;
+ missingtextures = true;
+ }
+ else // process texture
+ {
+ // make a tile
+ RGBAImage iblocktile;
+ iblocktile.create(tileSize, tileSize);
+ textureSize = min(iblockimage.w, iblockimage.h); // assume block textures are square, and choose smallest of the sides if they aren't
+ resize(iblockimage, ImageRect(0, 0, textureSize, textureSize), iblocktile, ImageRect(0, 0, tileSize, tileSize));
+
+ // directive: RENAME DARKEN OFFSET OFFSETTILE EXPAND CROP FLIPX CHEST LCHEST
+ texturename = textureDirectives[1];
+ for(unsigned i = 2; i < textureDirectives.size(); i++)
+ {
+ if(textureDirectives[i] == "RENAME") // assign different name to texture
+ {
+ texturename = textureDirectives[++i];
+ }
+ else if(textureDirectives[i] == "DARKEN") // make texture darker; can be used for colorizing monochrome textures aswell
+ {
+ double darkenR = strtod(textureDirectives[++i].c_str(), NULL);
+ double darkenG = strtod(textureDirectives[++i].c_str(), NULL);
+ double darkenB = strtod(textureDirectives[++i].c_str(), NULL);
+ darken(iblocktile, ImageRect(0, 0, tileSize, tileSize), darkenR, darkenG, darkenB);
+ }
+ else if(textureDirectives[i] == "OFFSET")
+ {
+ int xOffset = (fromstring(textureDirectives[++i], xOffset)) ? xOffset : 0;
+ int yOffset = (fromstring(textureDirectives[++i], yOffset)) ? yOffset : 0;
+ int xSign = (xOffset > 0) - (xOffset < 0);
+ int ySign = (yOffset > 0) - (yOffset < 0);
+ imgoffset(iblocktile, xSign * CUTOFFS_16[xSign * xOffset%17], ySign * CUTOFFS_16[ySign * yOffset%17]);
+ }
+ else if(textureDirectives[i] == "OFFSETTILE")
+ {
+ int xOffset = (fromstring(textureDirectives[++i], xOffset)) ? xOffset : 0;
+ int yOffset = (fromstring(textureDirectives[++i], yOffset)) ? yOffset : 0;
+ int xSign = (xOffset > 0) - (xOffset < 0);
+ int ySign = (yOffset > 0) - (yOffset < 0);
+ imgtileoffset(iblocktile, xSign * CUTOFFS_16[xSign * xOffset%17], ySign * CUTOFFS_16[ySign * yOffset%17]);
+ }
+ else if(textureDirectives[i] == "EXPAND")
+ {
+ int x = (fromstring(textureDirectives[++i], x)) ? x % (iblockimage.w + 1) : 0;
+ int y = (fromstring(textureDirectives[++i], y)) ? y % (iblockimage.h + 1) : 0;
+ int width = (fromstring(textureDirectives[++i], width)) ? width % (iblockimage.w - x + 1) : 0;
+ int height = (fromstring(textureDirectives[++i], height)) ? height % (iblockimage.h - y + 1) : 0;
+ resize(iblockimage, ImageRect(x, y, width, height), iblocktile, ImageRect(0, 0, tileSize, tileSize));
+ }
+ else if(textureDirectives[i] == "CROP")
+ {
+ int tCrop = (fromstring(textureDirectives[++i], tCrop)) ? tCrop % 17 : 0;
+ int rCrop = (fromstring(textureDirectives[++i], rCrop)) ? rCrop % 17 : 0;
+ int bCrop = (fromstring(textureDirectives[++i], bCrop)) ? bCrop % 17 : 0;
+ int lCrop = (fromstring(textureDirectives[++i], lCrop)) ? lCrop % 17 : 0;
+ imgcrop(iblocktile, ImageRect(CUTOFFS_16[lCrop], CUTOFFS_16[tCrop], tileSize - (CUTOFFS_16[lCrop] + CUTOFFS_16[rCrop]), tileSize - (CUTOFFS_16[tCrop] + CUTOFFS_16[bCrop])));
+ }
+ else if(textureDirectives[i] == "FLIPX")
+ {
+ flipX(iblocktile, ImageRect(0, 0, tileSize, tileSize));
+ }
+ else if(textureDirectives[i] == "OVERLAY") // alpha blit source image onto destination image
+ {
+ // load overlaying texture
+ if(!iblockimage.readPNG(blocktexturespath + "/" + textureDirectives[++i])) // texture read error
+ {
+ cerr << "[blocktextures.list] @" << textureiterator + 1 << " - " << blocktexturespath << "/" << textureDirectives[i] << " is missing or invalid (not 24BPP/32BPP PNG image)" << endl;
+ missingtextures = true;
+ }
+ else
+ {
+ RGBAImage overlaytile;
+ overlaytile.create(tileSize, tileSize);
+ textureSize = min(iblockimage.w, iblockimage.h); // assume block textures are square, and choose smallest of the sides if they aren't
+ resize(iblockimage, ImageRect(0, 0, textureSize, textureSize), overlaytile, ImageRect(0, 0, tileSize, tileSize));
+
+ alphablit(overlaytile, ImageRect(0, 0, tileSize, tileSize), iblocktile, 0, 0);
+ }
+ }
+ else if(textureDirectives[i] == "CHEST")
+ {
+ textureiterator += generateChestTiles(blockTextures, iblockimage, texturename, B);
+ }
+ else if(textureDirectives[i] == "LCHEST")
+ {
+ textureiterator += generateLargeChestTiles(blockTextures, iblockimage, texturename, B);
+ }
+ }
+ blockTextures[texturename] = iblocktile;
+ }
+ }
+ else if(textureDirectives.size() == 1) // just load the texture
+ {
+ if(!iblockimage.readPNG(blocktexturespath + "/" + textureDirectives[0])) // texture read error
+ {
+ cerr << "[blocktextures.list] @" << textureiterator + 1 << " - " << blocktexturespath << "/" << textureDirectives[0] << " is missing or invalid (not 24BPP/32BPP PNG image)" << endl;
+ missingtextures = true;
+ }
+ else
+ {
+ texturename = textureDirectives[0];
+ RGBAImage iblocktile;
+ iblocktile.create(tileSize, tileSize);
+ textureSize = min(iblockimage.w, iblockimage.h); // assume block textures are square, and choose smallest of the sides if they aren't
+ resize(iblockimage, ImageRect(0, 0, textureSize, textureSize), iblocktile, ImageRect(0, 0, tileSize, tileSize));
+ blockTextures[texturename] = iblocktile;
+ }
+ }
+ textureiterator++;
+ }
+ texturelist.close();
+ if(missingtextures)
+ return false;
+
+ RGBAImage emptyTile;
+ emptyTile.create(tileSize, tileSize); // create empty/dummy texture
+ blockTextures["/.png"] = emptyTile;
+
+ // initialize image
+ img.create(rectsize * 16, (blockversion/16 + 1) * rectsize);
+
+ // build all block images based on block descriptors
+ // Fill in offset depending on block type
+ unsigned offsetIterator = 1;
+ int64_t blockid;
+ for(vector< vector >::iterator it = blockDescriptors.begin(); it != blockDescriptors.end(); ++it)
+ {
+ vector descriptor = (*it);
+ if(fromstring(descriptor[0], blockid))
+ {
+ int descriptorsize = descriptor.size();
+ if(descriptor[1] == "SOLID")
+ {
+ if(descriptorsize == 3)
+ {
+ // all faces have the same texture
+ RGBAImage& facetexture = blockTextures.at((descriptor[2] + ".png"));
+ drawBlockImage(img, getRect(offsetIterator), facetexture, facetexture, facetexture, B);
+ }
+ else if(descriptorsize == 5)
+ {
+ // separate textures for separate faces
+ drawBlockImage(img, getRect(offsetIterator), blockTextures.at((descriptor[2] + ".png")), blockTextures.at((descriptor[3] + ".png")), blockTextures.at((descriptor[4] + ".png")), B);
+ }
+ }
+ else if(descriptor[1] == "SOLIDORIENTED")
+ {
+ if(descriptorsize == 9)
+ {
+ // texture order: face side top - descriptor[6 7 8]
+ drawBlockImage(img, getRect(offsetIterator), blockTextures.at((descriptor[7] + ".png")), blockTextures.at((descriptor[7] + ".png")), blockTextures.at((descriptor[8] + ".png")), B); // this will server for both N and E orientations
+ drawBlockImage(img, getRect(++offsetIterator), blockTextures.at((descriptor[7] + ".png")), blockTextures.at((descriptor[6] + ".png")), blockTextures.at((descriptor[8] + ".png")), B);
+ drawBlockImage(img, getRect(++offsetIterator), blockTextures.at((descriptor[6] + ".png")), blockTextures.at((descriptor[7] + ".png")), blockTextures.at((descriptor[8] + ".png")), B);
+ }
+ }
+ else if(descriptor[1] == "SOLIDROTATED")
+ {
+ if(descriptorsize == 6 || descriptorsize == 4)
+ {
+ int rotDegrees;
+ if(!fromstring(descriptor[2], rotDegrees)) rotDegrees = 6;
+ // piston value order: down / top / N / S / W / E
+ // piston extension bit: 0x8 (top bit)
+ // texture order: top side bottom - descriptor[2 3 4]
+ int topIndex;
+ int sideIndex;
+ int bottomIndex;
+ if(descriptorsize == 6)
+ {
+ topIndex = 3;
+ sideIndex = 4;
+ bottomIndex = 5;
+ }
+ else
+ {
+ topIndex = sideIndex = bottomIndex = 3;
+ }
+
+ RGBAImage& topface = blockTextures.at((descriptor[topIndex] + ".png"));
+ RGBAImage& sideface = blockTextures.at((descriptor[sideIndex] + ".png"));
+ RGBAImage& bottomface = blockTextures.at((descriptor[bottomIndex] + ".png"));
+ if(rotDegrees == 6)
+ {
+ drawRotatedBlockImage(img, getRect(offsetIterator), blockTile(sideface, 2, false), blockTile(sideface, 2, false), blockTile(bottomface), B); // facing Down
+ drawRotatedBlockImage(img, getRect(++offsetIterator), blockTile(sideface), blockTile(sideface), blockTile(topface), B); // facing Up
+ drawRotatedBlockImage(img, getRect(++offsetIterator), blockTile(sideface, 1, false), blockTile(bottomface), blockTile(sideface, 1, false), B); // facing N
+ drawRotatedBlockImage(img, getRect(++offsetIterator), blockTile(sideface, 3, false), blockTile(topface), blockTile(sideface, 3, false), B); // facing S
+ drawRotatedBlockImage(img, getRect(++offsetIterator), blockTile(topface), blockTile(sideface, 1, false), blockTile(sideface, 2, false), B); // facing W
+ drawRotatedBlockImage(img, getRect(++offsetIterator), blockTile(bottomface), blockTile(sideface, 3, false), blockTile(sideface), B); // facing E
+ }
+ else if(rotDegrees == 4) // tailored for glazed terracotta blocks
+ {
+ drawRotatedBlockImage(img, getRect(offsetIterator), blockTile(sideface, 0, false), blockTile(bottomface, 1, false), blockTile(topface, 1, false), B); // facing N (S)
+ drawRotatedBlockImage(img, getRect(++offsetIterator), blockTile(sideface, 1, false), blockTile(bottomface, 2, false), blockTile(topface, 0, false), B); // facing S (W)
+ drawRotatedBlockImage(img, getRect(++offsetIterator), blockTile(sideface, 2, false), blockTile(bottomface, 3, false), blockTile(topface, 3, false), B); // facing W (N)
+ drawRotatedBlockImage(img, getRect(++offsetIterator), blockTile(sideface, 3, false), blockTile(bottomface, 0, false), blockTile(topface, 2 , false), B); // facing E (E)
+ }
+ }
+ }
+ else if(descriptor[1] == "SOLIDDATA" || descriptor[1] == "SOLIDDATAFILL")
+ {
+ if(descriptorsize > 2)
+ {
+ for(int i = 2; i < descriptorsize; i++, offsetIterator++)
+ drawBlockImage(img, getRect(offsetIterator), blockTextures.at((descriptor[i] + ".png")), blockTextures.at((descriptor[i] + ".png")), blockTextures.at((descriptor[i] + ".png")), B);
+ continue;
+ }
+ }
+ else if(descriptor[1] == "SOLIDDATATRUNK")
+ {
+ if(descriptorsize % 2 == 0 && descriptorsize > 3)
+ {
+ for(int i = 2; i < descriptorsize; i += 2, offsetIterator++)
+ drawBlockImage(img, getRect(offsetIterator), blockTextures.at((descriptor[i+1] + ".png")), blockTextures.at((descriptor[i+1] + ".png")), blockTextures.at((descriptor[i] + ".png")), B);
+ continue;
+ }
+ }
+ else if(descriptor[1] == "SOLIDDATATRUNKROTATED")
+ {
+ if((descriptorsize - 3) % 3 == 0 && descriptorsize > 3)
+ {
+ int orientationFlag;
+ bool dataOrdered = (descriptor[2] == "O") ? true : false;
+
+ RGBAImage trunkTop;
+ RGBAImage trunkSide;
+ for(int i = 0; i < descriptorsize - 3; i += 3, offsetIterator++)
+ {
+ trunkTop = blockTextures.at((descriptor[i+4] + ".png"));
+ trunkSide = blockTextures.at((descriptor[i+5] + ".png"));
+ drawBlockImage(img, getRect(offsetIterator), trunkSide, trunkSide, trunkTop, B); // trunk UD
+
+ if(!fromstring(descriptor[i + 3], orientationFlag))
+ orientationFlag = 0;
+ if(orientationFlag == 1)
+ {
+ drawRotatedBlockImage(img, getRect(++offsetIterator), blockTile(trunkTop, 0, false), blockTile(trunkSide, 3, false), blockTile(trunkSide, 0, false), B); // trunk EW
+ drawRotatedBlockImage(img, getRect(++offsetIterator), blockTile(trunkSide, 1, false), blockTile(trunkTop, 0, false), blockTile(trunkSide, 1, false), B); // trunk NS
+ if(!dataOrdered)
+ drawBlockImage(img, getRect(++offsetIterator), trunkSide, trunkSide, trunkSide, B); // trunk not oriented
+ }
+ }
+ continue;
+ }
+ }
+ else if(descriptor[1] == "SOLIDOBSTRUCTED")
+ {
+ if(descriptorsize == 3)
+ {
+ // all faces have the same texture
+ RGBAImage& facetexture = blockTextures.at((descriptor[2] + ".png"));
+ drawBlockImage(img, getRect(offsetIterator), facetexture, facetexture, facetexture, B);
+ drawRotatedBlockImage(img, getRect(++offsetIterator), SourceTile(), SourceTile(), blockTile(facetexture), B); // only top surface
+ drawRotatedBlockImage(img, getRect(++offsetIterator), SourceTile(), blockTile(facetexture), blockTile(facetexture), B); // missing W
+ drawRotatedBlockImage(img, getRect(++offsetIterator), blockTile(facetexture), SourceTile(), blockTile(facetexture), B); // missing S
+ }
+ else if(descriptorsize == 5)
+ {
+ // separate textures for separate faces
+ RGBAImage& wtexture = blockTextures.at((descriptor[2] + ".png"));
+ RGBAImage& stexture = blockTextures.at((descriptor[3] + ".png"));
+ RGBAImage& toptexture = blockTextures.at((descriptor[4] + ".png"));
+ drawBlockImage(img, getRect(offsetIterator), wtexture, stexture, toptexture, B);
+ drawRotatedBlockImage(img, getRect(++offsetIterator), SourceTile(), blockTile(stexture), blockTile(toptexture), B); // missing W
+ drawRotatedBlockImage(img, getRect(++offsetIterator), blockTile(wtexture), SourceTile(), blockTile(toptexture), B); // missing S
+ drawRotatedBlockImage(img, getRect(++offsetIterator), SourceTile(), SourceTile(), blockTile(toptexture), B); // only top surface
+ }
+ }
+ else if(descriptor[1] == "SOLIDPARTIAL")
+ {
+ int topCutoff;
+ int bottomCutoff;
+ if(fromstring(descriptor[2], topCutoff) && fromstring(descriptor[3], bottomCutoff) && descriptorsize == 7) {
+ topCutoff = min(max(topCutoff, 0), 16);
+ bottomCutoff = min(max(bottomCutoff, 0), 16);
+ drawPartialBlockImage(img, getRect(offsetIterator), blockTextures.at((descriptor[4] + ".png")), blockTextures.at((descriptor[5] + ".png")), blockTextures.at((descriptor[6] + ".png")), B, CUTOFFS_16[topCutoff], CUTOFFS_16[bottomCutoff], 0, 0, false);
+ }
+ }
+ else if(descriptor[1] == "SOLIDDATAPARTIAL")
+ {
+ int topCutoff;
+ int bottomCutoff;
+ int datasize = descriptorsize - 4;
+ if(fromstring(descriptor[2], topCutoff) && fromstring(descriptor[3], bottomCutoff) && datasize > 0)
+ {
+ topCutoff = min(max(topCutoff, 0), 16);
+ bottomCutoff = min(max(bottomCutoff, 0), 16);
+
+ RGBAImage facetexture;
+ for(int i = 0; i < datasize; i++, offsetIterator++)
+ {
+ facetexture = blockTextures.at((descriptor[i+4] + ".png"));
+ drawPartialBlockImage(img, getRect(offsetIterator), facetexture, facetexture, facetexture, B, CUTOFFS_16[topCutoff], CUTOFFS_16[bottomCutoff], 0, 0, false);
+ }
+ continue;
+ }
+ }
+ else if(descriptor[1] == "SOLIDDATAPARTIALFILL")
+ {
+ int datasize = descriptorsize - 5;
+ if(datasize % 2 == 0)
+ {
+ int topCutoff;
+ int bottomCutoff;
+ RGBAImage& Wface = blockTextures.at((descriptor[2] + ".png"));
+ RGBAImage& Sface = blockTextures.at((descriptor[3] + ".png"));
+ RGBAImage& Uface = blockTextures.at((descriptor[4] + ".png"));
+ for(int i = 0; i < datasize; i += 2, offsetIterator++)
+ {
+ if(!fromstring(descriptor[i+5], topCutoff)) topCutoff = 0;
+ if(!fromstring(descriptor[i+6], bottomCutoff)) bottomCutoff = 0;
+ drawPartialBlockImage(img, getRect(offsetIterator), Wface, Sface, Uface, B, CUTOFFS_16[topCutoff], CUTOFFS_16[bottomCutoff], 0, 0, false);
+ }
+ continue;
+ }
+ }
+ else if(descriptor[1] == "SOLIDTRANSPARENT")
+ {
+ if(descriptorsize == 8)
+ {
+ RGBAImage& Dface = blockTextures.at((descriptor[2] + ".png"));
+ RGBAImage& Nface = blockTextures.at((descriptor[3] + ".png"));
+ RGBAImage& Eface = blockTextures.at((descriptor[4] + ".png"));
+ RGBAImage& Wface = blockTextures.at((descriptor[5] + ".png"));
+ RGBAImage& Sface = blockTextures.at((descriptor[6] + ".png"));
+ RGBAImage& Uface = blockTextures.at((descriptor[7] + ".png"));
+
+ drawFloorBlockImage(img, getRect(offsetIterator), Dface, 0, B);
+ drawSingleFaceBlockImage(img, getRect(offsetIterator), Nface, 3, B);
+ drawSingleFaceBlockImage(img, getRect(offsetIterator), Eface, 0, B);
+ drawSingleFaceBlockImage(img, getRect(offsetIterator), Wface, 1, B);
+ drawSingleFaceBlockImage(img, getRect(offsetIterator), Sface, 2, B);
+ drawOffsetPaddedUFace(img, getRect(offsetIterator), Uface, B, 0, 0, 0, 0, 0);
+ //drawRotatedBlockImage(img, getRect(offsetIterator), SourceTile(), SourceTile(), blockTile(Uface), B); // closed on the top half of block
+ }
+ }
+ else if(descriptor[1] == "SLABDATA")
+ {
+ if(descriptorsize > 2)
+ {
+ for(int i = 2; i < descriptorsize; i++, offsetIterator++)
+ {
+ // bottom slab
+ drawPartialBlockImage(img, getRect(offsetIterator), blockTextures.at((descriptor[i] + ".png")), blockTextures.at((descriptor[i] + ".png")), blockTextures.at((descriptor[i] + ".png")), B, CUTOFFS_16[8], 0, 0, 0, true);
+ // inverted slab
+ drawPartialBlockImage(img, getRect(++offsetIterator), blockTextures.at((descriptor[i] + ".png")), blockTextures.at((descriptor[i] + ".png")), blockTextures.at((descriptor[i] + ".png")), B, 0, CUTOFFS_16[8], 0, 0, false);
+ }
+ continue;
+ }
+ }
+ else if(descriptor[1] == "SLABDATATRUNK")
+ {
+ if(descriptorsize % 2 == 0 && descriptorsize > 3)
+ {
+ for(int i = 2; i < descriptorsize; i += 2, offsetIterator++)
+ {
+ // bottom slab
+ drawPartialBlockImage(img, getRect(offsetIterator), blockTextures.at((descriptor[i+1] + ".png")), blockTextures.at((descriptor[i+1] + ".png")), blockTextures.at((descriptor[i] + ".png")), B, CUTOFFS_16[8], 0, 0, 0, true);
+ // inverted slab
+ drawPartialBlockImage(img, getRect(++offsetIterator), blockTextures.at((descriptor[i+1] + ".png")), blockTextures.at((descriptor[i+1] + ".png")), blockTextures.at((descriptor[i] + ".png")), B, 0, CUTOFFS_16[8], 0, 0, false);
+ }
+ continue;
+ }
+ }
+ else if(descriptor[1] == "ITEMDATA")
+ {
+ if(descriptorsize > 2)
+ {
+ for(int i = 2; i < descriptorsize; i++, offsetIterator++)
+ {
+ drawItemBlockImage(img, getRect(offsetIterator), blockTextures.at((descriptor[i] + ".png")), B);
+ }
+ continue;
+ }
+ }
+ else if(descriptor[1] == "ITEMDATAFILL")
+ {
+ if(descriptorsize > 3)
+ {
+ for(int i = 3; i < descriptorsize; i++, offsetIterator++)
+ {
+ drawItemBlockImage(img, getRect(offsetIterator), blockTextures.at((descriptor[i] + ".png")), B);
+ }
+ continue;
+ }
+ }
+ else if(descriptor[1] == "ITEMDATAORIENTED")
+ {
+ if(descriptorsize > 6)
+ {
+ int datasize = descriptorsize - 6;
+ // orientation bits order: N S W E - descriptor[2 3 4 5]
+ RGBAImage baseTile;
+ for(int i = 0; i < datasize; i++, offsetIterator++)
+ {
+ baseTile = blockTextures.at(descriptor[i + 6] + ".png");
+ drawPartialItemBlockImage(img, getRect(offsetIterator), baseTile, 0, false, false, true, false, false, B); // attached to N (S side)
+ drawPartialItemBlockImage(img, getRect(++offsetIterator), baseTile, 0, true, true, false, false, false, B); // attached S (N side)
+ drawPartialItemBlockImage(img, getRect(++offsetIterator), baseTile, 0, false, false, false, false, true, B); // attached W (E side)
+ drawPartialItemBlockImage(img, getRect(++offsetIterator), baseTile, 0, true, false, false, true, false, B); // attached E (W side)
+ }
+ continue;
+ }
+ }
+ else if(descriptor[1] == "ITEMDATATALLORIENTED")
+ {
+ if(descriptorsize % 2 == 0 && descriptorsize > 2)
+ {
+ int datasize = descriptorsize - 2;
+ RGBAImage topTile;
+ RGBAImage bottomTile;
+ for(int i = 0; i < datasize/2 && i < 8; i++, offsetIterator++)
+ {
+ topTile = blockTextures.at(descriptor[i * 2 + 2] + ".png");
+ bottomTile = blockTextures.at(descriptor[i * 2 + 3] + ".png");
+
+ drawItemBlockImage(img, getRect(offsetIterator++), bottomTile, B); // bottom tile
+ drawItemBlockImage(img, getRect(offsetIterator), topTile, B); // top tile
+ }
+ continue;
+ }
+
+ }
+ else if(descriptor[1] == "MULTIITEMDATA")
+ {
+ if(descriptorsize > 2)
+ {
+ for(int i = 2; i < descriptorsize; i++, offsetIterator++)
+ {
+ drawMultiItemBlockImage(img, getRect(offsetIterator), blockTextures.at((descriptor[i] + ".png")), B);
+ }
+ continue;
+ }
+ }
+ else if(descriptor[1] == "STAIR")
+ {
+ if(descriptorsize > 2)
+ {
+ RGBAImage sideface;
+ RGBAImage topface;
+ RGBAImage bottomface;
+ if(descriptorsize == 3)
+ {
+ sideface = topface = bottomface = blockTextures.at((descriptor[2] + ".png"));
+ }
+ else if(descriptorsize == 4)
+ {
+ sideface = blockTextures.at((descriptor[2] + ".png"));
+ topface = bottomface = blockTextures.at((descriptor[3] + ".png"));
+ }
+ else if(descriptorsize == 5)
+ {
+ sideface = blockTextures.at((descriptor[2] + ".png"));
+ topface = blockTextures.at((descriptor[3] + ".png"));
+ bottomface = blockTextures.at((descriptor[4] + ".png"));
+ }
+ drawStairsE(img, getRect(offsetIterator), sideface, topface, B); // stairs asc E
+ drawStairsW(img, getRect(++offsetIterator), sideface, topface, B); // stairs asc W
+ drawStairsS(img, getRect(++offsetIterator), sideface, topface, B); // stairs asc S
+ drawStairsN(img, getRect(++offsetIterator), sideface, topface, B); // stairs asc N
+ drawInvStairsE(img, getRect(++offsetIterator), sideface, bottomface, B); // stairs asc E inverted
+ drawInvStairsW(img, getRect(++offsetIterator), sideface, bottomface, B); // stairs asc W inverted
+ drawInvStairsS(img, getRect(++offsetIterator), sideface, bottomface, B); // stairs asc S inverted
+ drawInvStairsN(img, getRect(++offsetIterator), sideface, bottomface, B); // stairs asc N inverted
+ }
+ }
+ else if(descriptor[1] == "FENCE")
+ {
+ RGBAImage& baseTexture = blockTextures.at((descriptor[2] + ".png"));
+ drawFencePost(img, getRect(offsetIterator), baseTexture, B); // fence post
+ drawFence(img, getRect(++offsetIterator), baseTexture, true, false, false, false, true, B); // fence N
+ drawFence(img, getRect(++offsetIterator), baseTexture, false, true, false, false, true, B); // fence S
+ drawFence(img, getRect(++offsetIterator), baseTexture, true, true, false, false, true, B); // fence NS
+ drawFence(img, getRect(++offsetIterator), baseTexture, false, false, false, true, true, B); // fence E
+ drawFence(img, getRect(++offsetIterator), baseTexture, true, false, false, true, true, B); // fence NE
+ drawFence(img, getRect(++offsetIterator), baseTexture, false, true, false, true, true, B); // fence SE
+ drawFence(img, getRect(++offsetIterator), baseTexture, true, true, false, true, true, B); // fence NSE
+ drawFence(img, getRect(++offsetIterator), baseTexture, false, false, true, false, true, B); // fence W
+ drawFence(img, getRect(++offsetIterator), baseTexture, true, false, true, false, true, B); // fence NW
+ drawFence(img, getRect(++offsetIterator), baseTexture, false, true, true, false, true, B); // fence SW
+ drawFence(img, getRect(++offsetIterator), baseTexture, true, true, true, false, true, B); // fence NSW
+ drawFence(img, getRect(++offsetIterator), baseTexture, false, false, true, true, true, B); // fence EW
+ drawFence(img, getRect(++offsetIterator), baseTexture, true, false, true, true, true, B); // fence NEW
+ drawFence(img, getRect(++offsetIterator), baseTexture, false, true, true, true, true, B); // fence SEW
+ drawFence(img, getRect(++offsetIterator), baseTexture, true, true, true, true, true, B); // fence NSEW
+ }
+ else if(descriptor[1] == "WALLDATA")
+ {
+ RGBAImage baseTexture;
+ for(int i = 0; i < descriptorsize - 2; i++, offsetIterator++)
+ {
+ baseTexture = blockTextures.at((descriptor[2 + i] + ".png"));
+ drawStoneWallPost(img, getRect(offsetIterator), baseTexture, B); // cobblestone wall post
+ drawStoneWallConnected(img, getRect(++offsetIterator), baseTexture, true, false, false, false, B); // cobblestone wall post N
+ drawStoneWallConnected(img, getRect(++offsetIterator), baseTexture, false, true, false, false, B); // cobblestone wall post S
+ drawStoneWallConnected(img, getRect(++offsetIterator), baseTexture, true, true, false, false, B); // cobblestone wall post NS
+ drawStoneWallConnected(img, getRect(++offsetIterator), baseTexture, false, false, true, false, B); // cobblestone wall post E
+ drawStoneWallConnected(img, getRect(++offsetIterator), baseTexture, true, false, true, false, B); // cobblestone wall post NE
+ drawStoneWallConnected(img, getRect(++offsetIterator), baseTexture, false, true, true, false, B); // cobblestone wall post SE
+ drawStoneWallConnected(img, getRect(++offsetIterator), baseTexture, true, true, true, false, B); // cobblestone wall post NSE
+ drawStoneWallConnected(img, getRect(++offsetIterator), baseTexture, false, false, false, true, B); // cobblestone wall post W
+ drawStoneWallConnected(img, getRect(++offsetIterator), baseTexture, true, false, false, true, B); // cobblestone wall post NW
+ drawStoneWallConnected(img, getRect(++offsetIterator), baseTexture, false, true, false, true, B); // cobblestone wall post SW
+ drawStoneWallConnected(img, getRect(++offsetIterator), baseTexture, true, true, false, true, B); // cobblestone wall post NSW
+ drawStoneWallConnected(img, getRect(++offsetIterator), baseTexture, false, false, true, true, B); // cobblestone wall post EW
+ drawStoneWallConnected(img, getRect(++offsetIterator), baseTexture, true, false, true, true, B); // cobblestone wall post NEW
+ drawStoneWallConnected(img, getRect(++offsetIterator), baseTexture, false, true, true, true, B); // cobblestone wall post SEW
+ drawStoneWallConnected(img, getRect(++offsetIterator), baseTexture, true, true, true, true, B); // cobblestone wall post NSEW
+ drawStoneWall(img, getRect(++offsetIterator), baseTexture, true, B); // cobblestone wall NS
+ drawStoneWall(img, getRect(++offsetIterator), baseTexture, false, B); // cobblestone wall EW
+ }
+ continue;
+ }
+ else if(descriptor[1] == "FENCEGATE")
+ {
+ RGBAImage& baseTile = blockTextures.at((descriptor[2] + ".png"));
+ drawOffsetPaddedSFace(img, getRect(offsetIterator), baseTile, B, 0.8, CUTOFFS_16[8], CUTOFFS_16[4], CUTOFFS_16[4], 0, 0); // fence gate EW
+ drawOffsetPaddedWFace(img, getRect(++offsetIterator), baseTile, B, 0.9, CUTOFFS_16[8], CUTOFFS_16[4], CUTOFFS_16[4], 0, 0); // fence gate NS
+ }
+ else if(descriptor[1] == "MUSHROOM")
+ {
+ RGBAImage& poreTile = blockTextures.at((descriptor[2] + ".png"));
+ RGBAImage& stemTile = blockTextures.at((descriptor[3] + ".png"));
+ RGBAImage& capTile = blockTextures.at((descriptor[4] + ".png"));
+ drawBlockImage(img, getRect(offsetIterator), poreTile, poreTile, poreTile, B); // pores on all sides
+ drawBlockImage(img, getRect(++offsetIterator), stemTile, stemTile, stemTile, B); // all stem
+ drawBlockImage(img, getRect(++offsetIterator), capTile, capTile, capTile, B); // all cap
+ drawBlockImage(img, getRect(++offsetIterator), capTile, poreTile, capTile, B); // cap @ UWN + UW
+ drawBlockImage(img, getRect(++offsetIterator), poreTile, poreTile, capTile, B); // only top - cap @ U + UN + UE + UNE
+ drawBlockImage(img, getRect(++offsetIterator), poreTile, capTile, capTile, B); // cap @ US + USE
+ drawBlockImage(img, getRect(++offsetIterator), stemTile, stemTile, poreTile, B); // stem
+ }
+ else if(descriptor[1] == "CHEST")
+ {
+ // single chest
+ RGBAImage& chestTop = blockTextures.at((descriptor[2] + ".png_0"));
+ RGBAImage& chestFront = blockTextures.at((descriptor[2] + ".png_1"));
+ RGBAImage& chestSide = blockTextures.at((descriptor[2] + ".png_2"));
+ drawBlockImage(img, getRect(offsetIterator), chestSide, chestSide, chestTop, B); // facing N,E
+ drawBlockImage(img, getRect(++offsetIterator), chestSide, chestFront, chestTop, B); // facing S
+ drawBlockImage(img, getRect(++offsetIterator), chestFront, chestSide, chestTop, B); // facing W
+ if(descriptorsize == 4) // double chests
+ {
+ RGBAImage largeTile0 = blockTextures.at((descriptor[3] + ".png_0"));
+ RGBAImage largeTile1 = blockTextures.at((descriptor[3] + ".png_1"));
+ RGBAImage largeTile2 = blockTextures.at((descriptor[3] + ".png_2"));
+ RGBAImage largeTile3 = blockTextures.at((descriptor[3] + ".png_3"));
+ RGBAImage largeTile4 = blockTextures.at((descriptor[3] + ".png_4"));
+ RGBAImage largeTile5 = blockTextures.at((descriptor[3] + ".png_5"));
+ RGBAImage largeTile6 = blockTextures.at((descriptor[3] + ".png_6"));
+ drawRotatedBlockImage(img, getRect(++offsetIterator), blockTile(largeTile6, 0, false), blockTile(largeTile4, 0, false), blockTile(largeTile0, 1, false), B); // double chest W facing N
+ drawRotatedBlockImage(img, getRect(++offsetIterator), blockTile(largeTile6, 0, false), blockTile(largeTile5, 0, false), blockTile(largeTile1, 1, false), B); // double chest E facing N
+ drawRotatedBlockImage(img, getRect(++offsetIterator), blockTile(largeTile6, 0, false), blockTile(largeTile2, 0, false), blockTile(largeTile0, 1, false), B); // double chest W facing S
+ drawRotatedBlockImage(img, getRect(++offsetIterator), blockTile(largeTile6, 0, false), blockTile(largeTile3, 0, false), blockTile(largeTile1, 1, false), B); // double chest E facing S
+ drawBlockImage(img, getRect(++offsetIterator), largeTile2, largeTile6, largeTile0, B); // double chest S facing W
+ drawBlockImage(img, getRect(++offsetIterator), largeTile3, largeTile6, largeTile1, B); // double chest N facing W
+ drawBlockImage(img, getRect(++offsetIterator), largeTile4, largeTile6, largeTile0, B); // double chest S facing E
+ drawBlockImage(img, getRect(++offsetIterator), largeTile5, largeTile6, largeTile1, B); // double chest N facing E
+ }
+ }
+ else if(descriptor[1] == "RAIL")
+ {
+ RGBAImage& rail = blockTextures.at(descriptor[2] + ".png");
+ drawFloorBlockImage(img, getRect(offsetIterator), rail, 1, B); // flat NS
+ drawFloorBlockImage(img, getRect(++offsetIterator), rail, 0, B); // flat EW
+ drawAngledFloorBlockImage(img, getRect(++offsetIterator), rail, 0, 0, B); // asc E
+ drawAngledFloorBlockImage(img, getRect(++offsetIterator), rail, 0, 2, B); // asc W
+ drawAngledFloorBlockImage(img, getRect(++offsetIterator), rail, 1, 3, B); // asc N
+ drawAngledFloorBlockImage(img, getRect(++offsetIterator), rail, 1, 1, B); // asc S
+ if(descriptorsize == 4)
+ {
+ RGBAImage& railcorner = blockTextures.at(descriptor[3] + ".png");
+ drawFloorBlockImage(img, getRect(++offsetIterator), railcorner, 1, B); // track NW corner
+ drawFloorBlockImage(img, getRect(++offsetIterator), railcorner, 0, B); // track NE corner
+ drawFloorBlockImage(img, getRect(++offsetIterator), railcorner, 3, B); // track SE corner
+ drawFloorBlockImage(img, getRect(++offsetIterator), railcorner, 2, B); // track SW corner
+ }
+ }
+ else if(descriptor[1] == "RAILPOWERED")
+ {
+ RGBAImage& rail = blockTextures.at(descriptor[2] + ".png");
+ RGBAImage& railpowered = blockTextures.at(descriptor[3] + ".png");
+ drawFloorBlockImage(img, getRect(offsetIterator), rail, 1, B); // flat NS
+ drawFloorBlockImage(img, getRect(++offsetIterator), rail, 0, B); // flat EW
+ drawAngledFloorBlockImage(img, getRect(++offsetIterator), rail, 0, 0, B); // asc E
+ drawAngledFloorBlockImage(img, getRect(++offsetIterator), rail, 0, 2, B); // asc W
+ drawAngledFloorBlockImage(img, getRect(++offsetIterator), rail, 1, 3, B); // asc N
+ drawAngledFloorBlockImage(img, getRect(++offsetIterator), rail, 1, 1, B); // asc S
+
+ drawFloorBlockImage(img, getRect(++offsetIterator), railpowered, 1, B); // flat NS powered
+ drawFloorBlockImage(img, getRect(++offsetIterator), railpowered, 0, B); // flat EW powered
+ drawAngledFloorBlockImage(img, getRect(++offsetIterator), railpowered, 0, 0, B); // asc E powered
+ drawAngledFloorBlockImage(img, getRect(++offsetIterator), railpowered, 0, 2, B); // asc W powered
+ drawAngledFloorBlockImage(img, getRect(++offsetIterator), railpowered, 1, 3, B); // asc N powered
+ drawAngledFloorBlockImage(img, getRect(++offsetIterator), railpowered, 1, 1, B); // asc S powered
+ }
+ else if(descriptor[1] == "PANEDATA")
+ {
+ RGBAImage baseTexture;
+ for(int i = 0; i < descriptorsize - 2; i++, offsetIterator++)
+ {
+ baseTexture = blockTextures.at((descriptor[2 + i] + ".png"));
+ drawItemBlockImage(img, getRect(offsetIterator), baseTexture, B); // base pane unconnected / NSWE
+ drawPartialItemBlockImage(img, getRect(++offsetIterator), baseTexture, 0, false, true, false, false, false, B); // pane N
+ drawPartialItemBlockImage(img, getRect(++offsetIterator), baseTexture, 0, false, false, true, false, false, B); // pane S
+ drawPartialItemBlockImage(img, getRect(++offsetIterator), baseTexture, 0, false, true, true, false, false, B); // pane NS
+ drawPartialItemBlockImage(img, getRect(++offsetIterator), baseTexture, 0, false, false, false, false, true, B); // pane E
+ drawPartialItemBlockImage(img, getRect(++offsetIterator), baseTexture, 0, false, true, false, false, true, B); // pane NE
+ drawPartialItemBlockImage(img, getRect(++offsetIterator), baseTexture, 0, false, false, true, false, true, B); // pane SE
+ drawPartialItemBlockImage(img, getRect(++offsetIterator), baseTexture, 0, false, true, true, false, true, B); // pane NSE
+ drawPartialItemBlockImage(img, getRect(++offsetIterator), baseTexture, 0, false, false, false, true, false, B); // pane W
+ drawPartialItemBlockImage(img, getRect(++offsetIterator), baseTexture, 0, false, true, false, true, false, B); // pane NW
+ drawPartialItemBlockImage(img, getRect(++offsetIterator), baseTexture, 0, false, false, true, true, false, B); // pane SW
+ drawPartialItemBlockImage(img, getRect(++offsetIterator), baseTexture, 0, false, true, true, true, false, B); // pane NSW
+ drawPartialItemBlockImage(img, getRect(++offsetIterator), baseTexture, 0, false, false, false, true, true, B); // pane EW
+ drawPartialItemBlockImage(img, getRect(++offsetIterator), baseTexture, 0, false, true, false, true, true, B); // pane NEW
+ drawPartialItemBlockImage(img, getRect(++offsetIterator), baseTexture, 0, false, false, true, true, true, B); // pane SEW
+ }
+ continue;
+ }
+ else if(descriptor[1] == "DOOR")
+ {
+ RGBAImage& bottomTile = blockTextures.at((descriptor[2] + ".png"));
+ RGBAImage& topTile = blockTextures.at((descriptor[3] + ".png"));
+ drawSingleFaceBlockImage(img, getRect(offsetIterator), bottomTile, 1, B); // door W side
+ drawSingleFaceBlockImage(img, getRect(++offsetIterator), bottomTile, 3, B); // door N side
+ drawSingleFaceBlockImage(img, getRect(++offsetIterator), bottomTile, 0, B); // door E side
+ drawSingleFaceBlockImage(img, getRect(++offsetIterator), bottomTile, 2, B); // door S side
+ drawSingleFaceBlockImage(img, getRect(++offsetIterator), topTile, 1, B); // door W top side
+ drawSingleFaceBlockImage(img, getRect(++offsetIterator), topTile, 3, B); // door N top side
+ drawSingleFaceBlockImage(img, getRect(++offsetIterator), topTile, 0, B); // door E top side
+ drawSingleFaceBlockImage(img, getRect(++offsetIterator), topTile, 2, B); // door S top side
+ }
+ else if(descriptor[1] == "TRAPDOOR")
+ {
+ RGBAImage& baseTile = blockTextures.at((descriptor[2] + ".png"));
+
+ drawFloorBlockImage(img, getRect(offsetIterator), blockTile(baseTile), B); // closed on the bottom half of block
+ drawRotatedBlockImage(img, getRect(++offsetIterator), SourceTile(), SourceTile(), blockTile(baseTile), B); // closed on the top half of block
+ drawSingleFaceBlockImage(img, getRect(++offsetIterator), baseTile, 2, B); // trapdoor open S
+ drawSingleFaceBlockImage(img, getRect(++offsetIterator), baseTile, 3, B); // trapdoor open N
+ drawSingleFaceBlockImage(img, getRect(++offsetIterator), baseTile, 0, B); // trapdoor open E
+ drawSingleFaceBlockImage(img, getRect(++offsetIterator), baseTile, 1, B); // trapdoor open W
+ }
+ else if(descriptor[1] == "TORCH")
+ {
+ RGBAImage& torchTile = blockTextures.at((descriptor[2] + ".png"));
+ drawItemBlockImage(img, getRect(offsetIterator), torchTile, B); // torch floor
+ drawSingleFaceBlockImage(img, getRect(++offsetIterator), torchTile, 1, B); // torch pointing E
+ drawSingleFaceBlockImage(img, getRect(++offsetIterator), torchTile, 0, B); // torch pointing W
+ drawSingleFaceBlockImage(img, getRect(++offsetIterator), torchTile, 3, B); // torch pointing S
+ drawSingleFaceBlockImage(img, getRect(++offsetIterator), torchTile, 2, B); // torch pointing N
+ }
+ else if(descriptor[1] == "ONWALLPARTIALFILL")
+ {
+ if(descriptorsize == 11)
+ {
+ RGBAImage faceTile = blockTextures.at(descriptor[6] + ".png");
+ int croptop;
+ int cropbottom;
+ int cropleft;
+ int cropright;
+ if(!fromstring(descriptor[7], croptop)) croptop = 0;
+ else croptop = CUTOFFS_16[croptop];
+ if(!fromstring(descriptor[8], cropbottom)) cropbottom = 0;
+ else cropbottom = CUTOFFS_16[cropbottom];
+ if(!fromstring(descriptor[9], cropleft)) cropleft = 0;
+ else cropleft = CUTOFFS_16[cropleft];
+ if(!fromstring(descriptor[10], cropright)) cropright = 0;
+ else cropright = CUTOFFS_16[cropright];
+ if((croptop + cropbottom + cropleft + cropright) == 0)
+ {
+ drawSingleFaceBlockImage(img, getRect(offsetIterator), faceTile, 3, B); // facing S (N wall)
+ drawSingleFaceBlockImage(img, getRect(++offsetIterator), faceTile, 2, B); // facing N (S wall)
+ drawSingleFaceBlockImage(img, getRect(++offsetIterator), faceTile, 1, B); // facing E (W wall)
+ drawSingleFaceBlockImage(img, getRect(++offsetIterator), faceTile, 0, B); // facing W (E wall)
+ }
+ else
+ {
+ drawPartialSingleFaceBlockImage(img, getRect(offsetIterator), faceTile, 3, B, croptop, cropbottom, cropleft, cropright); // facing S (N wall)
+ drawPartialSingleFaceBlockImage(img, getRect(++offsetIterator), faceTile, 2, B, croptop, cropbottom, cropleft, cropright); // facing N (S wall)
+ drawPartialSingleFaceBlockImage(img, getRect(++offsetIterator), faceTile, 1, B, croptop, cropbottom, cropleft, cropright); // facing E (W wall)
+ drawPartialSingleFaceBlockImage(img, getRect(++offsetIterator), faceTile, 0, B, croptop, cropbottom, cropleft, cropright); // facing W (E wall)
+ }
+ }
+ }
+ else if(descriptor[1] == "WIRE")
+ {
+ //setOffsetsForID(blockid, offsetIterator, *this);
+ RGBAImage wireCross;
+ RGBAImage& wireTile = blockTextures.at(descriptor[2] + ".png");
+ if(descriptorsize == 4)
+ {
+ wireCross = blockTextures.at(descriptor[3] + ".png");
+ drawOffsetPaddedUFace(img, getRect(offsetIterator), wireCross, B, CUTOFFS_16[16], CUTOFFS_16[5], CUTOFFS_16[5], CUTOFFS_16[5], CUTOFFS_16[5]); // unconnected
+ }
+ else
+ {
+ // we will need to create crossed wire
+ RGBAImage rotatedTile;
+ rotatedTile.create(tileSize, tileSize);
+ RotatedFaceIterator dstit(0, 0, 1, tileSize, false);
+ for (FaceIterator srcit(0, 0, 0, tileSize); !srcit.end; srcit.advance(), dstit.advance())
+ rotatedTile(dstit.x, dstit.y) = wireTile(srcit.x, srcit.y);
+
+ wireCross.create(tileSize, tileSize);
+ alphablit(wireTile, ImageRect(0, 0, tileSize, tileSize), wireCross, 0, 0);
+ alphablit(rotatedTile, ImageRect(0, 0, tileSize, tileSize), wireCross, 0, 0);
+
+ drawFloorBlockImage(img, getRect(offsetIterator), wireTile, 0, B); // unconnected
+ }
+ drawFloorBlockImage(img, getRect(++offsetIterator), wireTile, 0, B); // flat NS
+ drawFloorBlockImage(img, getRect(++offsetIterator), wireTile, 1, B); // flat WE
+ drawOffsetPaddedUFace(img, getRect(++offsetIterator), wireCross, B, CUTOFFS_16[16], 0, CUTOFFS_16[5], 0, CUTOFFS_16[5]); // NE
+ drawOffsetPaddedUFace(img, getRect(++offsetIterator), wireCross, B, CUTOFFS_16[16], 0, CUTOFFS_16[5], CUTOFFS_16[5], 0); // SE
+ drawOffsetPaddedUFace(img, getRect(++offsetIterator), wireCross, B, CUTOFFS_16[16], 0, CUTOFFS_16[5], 0, 0); // NSE
+ drawOffsetPaddedUFace(img, getRect(++offsetIterator), wireCross, B, CUTOFFS_16[16], CUTOFFS_16[5], 0, 0, CUTOFFS_16[5]); // NW
+ drawOffsetPaddedUFace(img, getRect(++offsetIterator), wireCross, B, CUTOFFS_16[16], CUTOFFS_16[5], 0, CUTOFFS_16[5], 0); // SW
+ drawOffsetPaddedUFace(img, getRect(++offsetIterator), wireCross, B, CUTOFFS_16[16], CUTOFFS_16[5], 0, 0, 0); // NSW
+ drawOffsetPaddedUFace(img, getRect(++offsetIterator), wireCross, B, CUTOFFS_16[16], 0, 0, 0, CUTOFFS_16[5]); // NEW
+ drawOffsetPaddedUFace(img, getRect(++offsetIterator), wireCross, B, CUTOFFS_16[16], 0, 0, CUTOFFS_16[5], 0); // SEW
+ drawOffsetPaddedUFace(img, getRect(++offsetIterator), wireCross, B, CUTOFFS_16[16], 0, 0, 0, 0); // NSEW
+ }
+ else if(descriptor[1] == "BITANCHOR")
+ {
+ RGBAImage& baseTile = blockTextures.at(descriptor[2] + ".png");
+ drawAnchoredFace(img, getRect(offsetIterator), baseTile, B, false, false, false, false, true); // U face
+ drawAnchoredFace(img, getRect(++offsetIterator), baseTile, B, false, true, false, false, false); // S face
+ drawAnchoredFace(img, getRect(++offsetIterator), baseTile, B, false, false, true, false, false); // W face
+ drawAnchoredFace(img, getRect(++offsetIterator), baseTile, B, false, true, true, false, false); // SW face
+ drawAnchoredFace(img, getRect(++offsetIterator), baseTile, B, true, false, false, false, false); // N face
+ drawAnchoredFace(img, getRect(++offsetIterator), baseTile, B, true, true, false, false, false); // NS face
+ drawAnchoredFace(img, getRect(++offsetIterator), baseTile, B, true, false, true, false, false); // NW face
+ drawAnchoredFace(img, getRect(++offsetIterator), baseTile, B, true, true, true, false, false); // NSW face
+ drawAnchoredFace(img, getRect(++offsetIterator), baseTile, B, false, false, false, true, false); // E face
+ drawAnchoredFace(img, getRect(++offsetIterator), baseTile, B, false, true, false, true, false); // SE face
+ drawAnchoredFace(img, getRect(++offsetIterator), baseTile, B, false, false, true, true, false); // WE face
+ drawAnchoredFace(img, getRect(++offsetIterator), baseTile, B, false, true, true, true, false); // SWE face
+ drawAnchoredFace(img, getRect(++offsetIterator), baseTile, B, true, false, false, true, false); // NE face
+ drawAnchoredFace(img, getRect(++offsetIterator), baseTile, B, true, true, false, true, false); // NSE face
+ drawAnchoredFace(img, getRect(++offsetIterator), baseTile, B, true, false, true, true, false); // NWE face
+ drawAnchoredFace(img, getRect(++offsetIterator), baseTile, B, true, true, true, true, false); // NSWE face
+ }
+ else if(descriptor[1] == "STEM")
+ {
+ RGBAImage stemTile;
+ for(int i = 0; i < 8; i++, offsetIterator++)
+ {
+ stemTile = blockTextures.at(descriptor[2] + ".png_" + tostring(i));
+ drawItemBlockImage(img, getRect(offsetIterator), stemTile, B); // draw stem level 0-7
+ }
+ stemTile = blockTextures.at(descriptor[3] + ".png_0");
+ RGBAImage& stemBent = blockTextures.at(descriptor[3] + ".png_1");
+ drawPartialItemBlockImage(img, getRect(offsetIterator), stemTile, 0, false, true, true, false, false, B); // N
+ drawPartialItemBlockImage(img, getRect(++offsetIterator), stemBent, 0, false, true, true, false, false, B); // S
+ drawPartialItemBlockImage(img, getRect(++offsetIterator), stemTile, 0, false, false, false, true, true, B); // W
+ drawPartialItemBlockImage(img, getRect(++offsetIterator), stemBent, 0, false, false, false, true, true, B); // E
+ }
+ else if(descriptor[1] == "REPEATER")
+ {
+ RGBAImage& baseTile = blockTextures.at(descriptor[2] + ".png");
+ RGBAImage& torchTile = blockTextures.at(descriptor[3] + ".png");
+ drawRepeater(img, getRect(offsetIterator), baseTile, torchTile, 1, B); // repeater on N
+ drawRepeater(img, getRect(++offsetIterator), baseTile, torchTile, 0, B); // repeater on E
+ drawRepeater(img, getRect(++offsetIterator), baseTile, torchTile, 3, B); // repeater on S
+ drawRepeater(img, getRect(++offsetIterator), baseTile, torchTile, 2, B); // repeater on W
+
+ if(descriptorsize == 6) // combined state (comparator) - draw extra tiles
+ {
+ baseTile = blockTextures.at(descriptor[4] + ".png");
+ torchTile = blockTextures.at(descriptor[5] + ".png");
+ drawRepeater(img, getRect(++offsetIterator), baseTile, torchTile, 1, B); // repeater on N
+ drawRepeater(img, getRect(++offsetIterator), baseTile, torchTile, 0, B); // repeater on E
+ drawRepeater(img, getRect(++offsetIterator), baseTile, torchTile, 3, B); // repeater on S
+ drawRepeater(img, getRect(++offsetIterator), baseTile, torchTile, 2, B); // repeater on W
+ }
+ }
+ else if(descriptor[1] == "LEVER")
+ {
+ RGBAImage& baseTile = blockTextures.at(descriptor[2] + ".png");
+ RGBAImage& leverTile = blockTextures.at(descriptor[3] + ".png");
+ drawWallLever(img, getRect(offsetIterator), baseTile, leverTile, 1, B); // wall lever facing E
+ drawWallLever(img, getRect(++offsetIterator), baseTile, leverTile, 0, B); // wall lever facing W
+ drawWallLever(img, getRect(++offsetIterator), baseTile, leverTile, 3, B); // wall lever facing S
+ drawWallLever(img, getRect(++offsetIterator), baseTile, leverTile, 2, B); // wall lever facing N
+ drawFloorLeverNS(img, getRect(++offsetIterator), baseTile, leverTile, B); // ground lever NS
+ drawFloorLeverEW(img, getRect(++offsetIterator), baseTile, leverTile, B); // ground lever WE
+ drawCeilLever(img, getRect(++offsetIterator), leverTile, B); // ground lever NS / WE
+//# 34 LEVER (specify lever base texture, lever handle texture; like lever)
+/*
+ blockOffsets[offsetIdx(blockid, 1)] = blockOffsets[offsetIdx(blockid, 9)] = offsetIterator; // facing E
+ blockOffsets[offsetIdx(blockid, 2)] = blockOffsets[offsetIdx(blockid, 10)] = ++offsetIterator; // facing W
+ blockOffsets[offsetIdx(blockid, 3)] = blockOffsets[offsetIdx(blockid, 11)] = ++offsetIterator; // facing S
+ blockOffsets[offsetIdx(blockid, 4)] = blockOffsets[offsetIdx(blockid, 12)] = ++offsetIterator; // facing N
+ blockOffsets[offsetIdx(blockid, 5)] = blockOffsets[offsetIdx(blockid, 13)] = ++offsetIterator; // ground NS
+ blockOffsets[offsetIdx(blockid, 6)] = blockOffsets[offsetIdx(blockid, 14)] = ++offsetIterator; // ground WE
+ blockOffsets[offsetIdx(blockid, 0)] = blockOffsets[offsetIdx(blockid, 7)] = ++offsetIterator; // ceil NS
+ blockOffsets[offsetIdx(blockid, 8)] = blockOffsets[offsetIdx(blockid, 15)] = offsetIterator; // ceil WE
+ */
+ }
+ else if(descriptor[1] == "SIGNPOST")
+ {
+ drawSign(img, getRect(offsetIterator), blockTextures.at((descriptor[2] + ".png")), blockTextures.at((descriptor[3] + ".png")), B); // generic sign post
+ }
+ else if(blockid == 8) // water
+ {
+ if(blockTextures.count((descriptor[2] + ".png")) == 0)
+ {
+ offsetIterator += 11;
+ continue;
+ }
+
+ RGBAImage& waterTile = blockTextures.at((descriptor[2] + ".png"));
+ drawBlockImage(img, getRect(offsetIterator), waterTile, waterTile, waterTile, B); // full water
+ drawRotatedBlockImage(img, getRect(++offsetIterator), SourceTile(), SourceTile(), blockTile(waterTile), B); // water surface
+ drawRotatedBlockImage(img, getRect(++offsetIterator), SourceTile(), blockTile(waterTile), blockTile(waterTile), B); // water missing W
+ drawRotatedBlockImage(img, getRect(++offsetIterator), blockTile(waterTile), SourceTile(), blockTile(waterTile), B); // water missing S
+
+ drawPartialBlockImage(img, getRect(++offsetIterator), waterTile, waterTile, waterTile, B, CUTOFFS_16[2], 0, 0, 0, true); // water level 7
+ drawPartialBlockImage(img, getRect(++offsetIterator), waterTile, waterTile, waterTile, B, CUTOFFS_16[4], 0, 0, 0, true); // water level 6
+ drawPartialBlockImage(img, getRect(++offsetIterator), waterTile, waterTile, waterTile, B, CUTOFFS_16[6], 0, 0, 0, true); // water level 5
+ drawPartialBlockImage(img, getRect(++offsetIterator), waterTile, waterTile, waterTile, B, CUTOFFS_16[8], 0, 0, 0, true); // water level 4
+ drawPartialBlockImage(img, getRect(++offsetIterator), waterTile, waterTile, waterTile, B, CUTOFFS_16[10], 0, 0, 0, true); // water level 3
+ drawPartialBlockImage(img, getRect(++offsetIterator), waterTile, waterTile, waterTile, B, CUTOFFS_16[12], 0, 0, 0, true); // water level 2
+ drawPartialBlockImage(img, getRect(++offsetIterator), waterTile, waterTile, waterTile, B, CUTOFFS_16[14], 0, 0, 0, true); // water level 1
+
+ }
+ else if(blockid == 10) // lava
+ {
+ if(blockTextures.count((descriptor[2] + ".png")) == 0)
+ {
+ offsetIterator += 4;
+ continue;
+ }
+
+ RGBAImage& lavaTile = blockTextures.at((descriptor[2] + ".png"));
+ drawBlockImage(img, getRect(offsetIterator), lavaTile, lavaTile, lavaTile, B); // full lava
+ drawPartialBlockImage(img, getRect(++offsetIterator), lavaTile, lavaTile, lavaTile, B, CUTOFFS_16[4], 0, 0, 0, true); // lava level 3
+ drawPartialBlockImage(img, getRect(++offsetIterator), lavaTile, lavaTile, lavaTile, B, CUTOFFS_16[8], 0, 0, 0, true); // lava level 2
+ drawPartialBlockImage(img, getRect(++offsetIterator), lavaTile, lavaTile, lavaTile, B, CUTOFFS_16[12], 0, 0, 0, true); // lava level 1
+ }
+ else if(blockid == 26) // bed
+ {
+ RGBAImage& footFront = blockTextures.at((descriptor[2] + ".png"));
+ RGBAImage& footSide = blockTextures.at((descriptor[3] + ".png"));
+ RGBAImage& footTop = blockTextures.at((descriptor[4] + ".png"));
+ RGBAImage& headFront = blockTextures.at((descriptor[5] + ".png"));
+ RGBAImage& headSide = blockTextures.at((descriptor[6] + ".png"));
+ RGBAImage& headTop = blockTextures.at((descriptor[7] + ".png"));
+ drawPartialBlockImage(img, getRect(offsetIterator), footSide, footFront, footTop, B, true, false, true, CUTOFFS_16[8], 0, 0, 0, false); // bed foot pointing S
+ drawPartialBlockImage(img, getRect(++offsetIterator), footFront, footSide, footTop, B, false, true, true, CUTOFFS_16[8], 0, 3, 2, false); // bed foot pointing W
+ drawPartialBlockImage(img, getRect(++offsetIterator), footSide, footFront, footTop, B, true, true, true, CUTOFFS_16[8], 0, 2, 1, false); // bed foot pointing N
+ drawPartialBlockImage(img, getRect(++offsetIterator), footFront, footSide, footTop, B, true, true, true, CUTOFFS_16[8], 0, 1, 0, false); // bed foot pointing E
+ drawPartialBlockImage(img, getRect(++offsetIterator), headSide, headFront, headTop, B, true, true, true, CUTOFFS_16[8], 0, 0, 0, false); // bed head pointing S
+ drawPartialBlockImage(img, getRect(++offsetIterator), headFront, headSide, headTop, B, true, true, true, CUTOFFS_16[8], 0, 3, 2, false); // bed head pointing W
+ drawPartialBlockImage(img, getRect(++offsetIterator), headSide, headFront, headTop, B, true, false, true, CUTOFFS_16[8], 0, 2, 1, false); // bed head pointing N
+ drawPartialBlockImage(img, getRect(++offsetIterator), headFront, headSide, headTop, B, false, true, true, CUTOFFS_16[8], 0, 1, 0, false); // bed head pointing E
+ }
+ else if(blockid == 117) // brewing stand
+ {
+ drawBrewingStand(img, getRect(offsetIterator), blockTextures.at((descriptor[2] + ".png")), blockTextures.at((descriptor[3] + ".png")), B); // brewing stand
+ }
+ else if(blockid == 118) // cauldron
+ {
+ RGBAImage& cauldronSide = blockTextures.at((descriptor[2] + ".png"));
+ RGBAImage& waterTile = blockTextures.at((descriptor[3] + ".png"));
+ drawCauldron(img, getRect(offsetIterator), cauldronSide, waterTile, 0, B); // cauldron empty
+ drawCauldron(img, getRect(++offsetIterator), cauldronSide, waterTile, CUTOFFS_16[10], B); // cauldron 1/3 full
+ drawCauldron(img, getRect(++offsetIterator), cauldronSide, waterTile, CUTOFFS_16[6], B); // cauldron 2/3 full
+ drawCauldron(img, getRect(++offsetIterator), cauldronSide, waterTile, CUTOFFS_16[2], B); // cauldron full
+ }
+ else if(blockid == 122) // dragon egg
+ {
+ drawDragonEgg(img, getRect(offsetIterator), blockTextures.at((descriptor[2] + ".png")), B); // dragon egg
+ }
+ else if(blockid == 138) // beacon
+ {
+ int coverid;
+ if(!fromstring(descriptor[3], coverid))
+ coverid = 20; // glass
+ drawBeacon(img, getRect(offsetIterator), blockTextures.at((descriptor[3] + ".png")), blockTextures.at((descriptor[2] + ".png")), getRect(blockOffsets[offsetIdx(coverid, 0)]), B);
+ }
+ else if(blockid == 140) // flower pot
+ {
+ RGBAImage& flowerpotTile = blockTextures.at((descriptor[2] + ".png"));
+ RGBAImage& fillerTile = blockTextures.at((descriptor[3] + ".png"));
+ int contenttype = 0;
+ drawFlowerPot(img, getRect(offsetIterator), flowerpotTile, fillerTile, false, fillerTile, contenttype, B); // flower pot [empty]
+ /*
+ for(int i = 4; i < descriptorsize; i++)
+ {
+ if(i == 12)
+ contenttype = 1;
+ else
+ contenttype = 0;
+ drawFlowerPot(img, getRect(++offsetIterator), flowerpotTile, fillerTile, true, blockTextures.at((descriptor[i] + ".png")), contenttype, B);
+ }
+ */
+ }
+ else if(blockid == 145) // anvil
+ {
+ RGBAImage& basetexture = blockTextures.at((descriptor[2] + ".png"));
+ RGBAImage& anvildamage0 = blockTextures.at((descriptor[3] + ".png"));
+ RGBAImage& anvildamage1 = blockTextures.at((descriptor[4] + ".png"));
+ RGBAImage& anvildamage2 = blockTextures.at((descriptor[5] + ".png"));
+ drawAnvil(img, getRect(offsetIterator), basetexture, anvildamage0, 0, B);
+ drawAnvil(img, getRect(++offsetIterator), basetexture, anvildamage0, 1, B);
+ drawAnvil(img, getRect(++offsetIterator), basetexture, anvildamage1, 0, B);
+ drawAnvil(img, getRect(++offsetIterator), basetexture, anvildamage1, 1, B);
+ drawAnvil(img, getRect(++offsetIterator), basetexture, anvildamage2, 0, B);
+ drawAnvil(img, getRect(++offsetIterator), basetexture, anvildamage2, 1, B);
+ }
+ else if(blockid == 154) // hopper
+ {
+ drawHopper(img, getRect(offsetIterator), blockTextures.at((descriptor[2] + ".png")), blockTextures.at((descriptor[3] + ".png")), B); // hopper
+ }
+ else if(blockid == 198) // end rod
+ {
+ RGBAImage& lamptexture = blockTextures.at((descriptor[2] + ".png"));
+ RGBAImage& basetexture = blockTextures.at((descriptor[3] + ".png"));
+ drawEndRod(img, getRect(offsetIterator), lamptexture, basetexture, 0, B); // D
+ drawEndRod(img, getRect(++offsetIterator), lamptexture, basetexture, 1, B); // U
+ drawEndRod(img, getRect(++offsetIterator), lamptexture, basetexture, 2, B); // N
+ drawEndRod(img, getRect(++offsetIterator), lamptexture, basetexture, 3, B); // S
+ drawEndRod(img, getRect(++offsetIterator), lamptexture, basetexture, 4, B); // W
+ drawEndRod(img, getRect(++offsetIterator), lamptexture, basetexture, 5, B); // E
+ }
+ offsetIterator++;
+ }
+ }
+
+ return true;
+}
diff --git a/blockimages.h b/blockimages.h
old mode 100755
new mode 100644
index 7266fcc..2e35872
--- a/blockimages.h
+++ b/blockimages.h
@@ -1,294 +1,132 @@
-// Copyright 2010-2012 Michael J. Nelson
-//
-// This file is part of pigmap.
-//
-// pigmap is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// pigmap is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with pigmap. If not, see .
-
-#ifndef BLOCKIMAGES_H
-#define BLOCKIMAGES_H
-
-#include
-
-#include "rgba.h"
-
-// IMPORTANT NOTE:
-// This program was written before the location of the sun moved in Minecraft Beta 1.9 or so,
-// therefore all of the N/S/E/W directions here are now wrong--rotated 90 degrees from what they
-// should be. For example, the positive X direction used to be South, and is called South here,
-// but is now East in the game (as of Minecraft 1.0, anyway).
-// I decided to leave the old direction names here, because it would be pretty easy to mess
-// something up trying to go through and change everything. Apologies for the confusion!
-
-// this structure holds the block images used to build the map; each block image is a hexagonal shape within
-// a 4Bx4B rectangle, with the unused area around it set to fully transparent
-//
-// example of hexagon shape for B = 3, where U represents pixels belonging to the U-facing side of the block, etc.:
-//
-// UU
-// UUUUUU
-// UUUUUUUUUU
-// NUUUUUUUUUUW
-// NNNUUUUUUWWW
-// NNNNNUUWWWWW
-// NNNNNNWWWWWW
-// NNNNNNWWWWWW
-// NNNNNNWWWWWW
-// NNNNNWWWWW
-// NNNWWW
-// NW
-//
-// when supplying your own block images, there's nothing to stop you from going "out of bounds" and having
-// non-transparent pixels outside the hexagon, but you'll just get a messed-up image, since the renderer
-// uses only the hexagon to determine visibility, etc.
-//
-// note that translucent blocks require the most work to render, simply because you can see what's behind them;
-// if every block in the world was translucent, for example, then every block would be considered visible
-// ...so if you're editing the block images for special purposes like X-ray vision, the fastest results are
-// obtained by making unwanted blocks fully transparent, not just translucent
-// ...also, any pixels in the block images with alphas < 10 will have their alphas set to 0, and similarly
-// any alphas > 245 will be set to 255; this is to prevent massive slowdown from accidental image-editing
-// cock-ups, like somehow setting the transparency of the whole image to 99% instead of 100%, etc.
-//
-// most block images are created by resizing the relevant terrain.png images from 16x16 to 2Bx2B, then painting
-// their columns onto the faces of the block image thusly (example is for B = 3 again):
-//
-// a f
-// abcdef ab abc def
-// abcdef aabbcd abcde bcdef
-// abcdef ---> aabbccddef or abcdef or abcdef
-// abcdef abccddeeff abcdef abcdef
-// abcdef cdeeff abcdef abcdef
-// abcdef ef bcdef abcde
-// def abc
-// f a
-
-struct BlockImages
-{
- // this image holds all the block images, in rows of 16 (so its width is 4B*16; height depends on number of rows)
- // ...the very first block image is a dummy one, fully transparent, for use with unrecognized blocks
- RGBAImage img;
- int rectsize; // size of block image bounding boxes
-
- // for every possible 12-bit block id/4-bit block data combination, this holds the offset into the image
- // (unrecognized id/data values are pointed at the dummy block image)
- // this doesn't handle some things like fences and double chests where the rendering doesn't depend solely
- // on the blockID/blockData; for those, the renderer just has to know the proper offsets on its own
- int blockOffsets[4096 * 16];
- int getOffset(uint16_t blockID, uint8_t blockData) const {return blockOffsets[blockID * 16 + blockData];}
-
- // check whether a block image is opaque (this is a function of the block images computed from the terrain,
- // not of the actual block data; if a block image has 100% alpha everywhere, it's considered opaque)
- std::vector opacity; // size is NUMBLOCKIMAGES; indexed by offset
- bool isOpaque(int offset) const {return opacity[offset];}
- bool isOpaque(uint16_t blockID, uint8_t blockData) const {return opacity[getOffset(blockID, blockData)];}
-
- // ...and the same thing for complete transparency (0% alpha everywhere)
- std::vector transparency; // size is NUMBLOCKIMAGES; indexed by offset
- bool isTransparent(int offset) const {return transparency[offset];}
- bool isTransparent(uint16_t blockID, uint8_t blockData) const {return transparency[getOffset(blockID, blockData)];}
-
- // get the rectangle in img corresponding to an offset
- ImageRect getRect(int offset) const {return ImageRect((offset%16)*rectsize, (offset/16)*rectsize, rectsize, rectsize);}
- ImageRect getRect(uint16_t blockID, uint8_t blockData) const {return getRect(getOffset(blockID, blockData));}
-
- // attempt to create a BlockImages structure: look for blocks-B.png in the imgpath, where B is the block size
- // parameter; failing that, look for terrain.png and construct a new blocks-B.png from it; failing that, uh, fail
- bool create(int B, const std::string& imgpath);
-
- // set the offsets
- void setOffsets();
-
- // fill in the opacity and transparency members
- void checkOpacityAndTransparency(int B);
-
- // scan the block images looking for not-quite-transparent or not-quite-opaque pixels; if they're close enough,
- // push them all the way
- void retouchAlphas(int B);
-
- // build block images from terrain.png, etc.
- bool construct(int B, const std::string& terrainfile, const std::string& firefile, const std::string& endportalfile, const std::string& chestfile, const std::string& largechestfile, const std::string& enderchestfile);
-};
-
-// block image offsets:
-//
-// 0 dummy/air (transparent) 32 brown mushroom 64 wheat level 2 96 cobble stairs asc S
-// 1 stone 33 red mushroom 65 wheat level 1 97 cobble stairs asc N
-// 2 grass 34 gold block 66 wheat level 0 98 cobble stairs asc W
-// 3 dirt 35 iron block 67 farmland 99 cobble stairs asc E
-// 4 cobblestone 36 double stone slab 68 UNUSED 100 wall sign facing E
-// 5 planks 37 stone slab 69 UNUSED 101 wall sign facing W
-// 6 sapling 38 brick 70 sign facing N/S 102 wall sign facing N
-// 7 bedrock 39 TNT 71 sign facing NE/SW 103 wall sign facing S
-// 8 water full/falling 40 bookshelf 72 sign facing E/W 104 UNUSED
-// 9 water level 7 41 mossy cobblestone 73 sign facing SE/NW 105 UNUSED
-// 10 water level 6 42 obsidian 74 wood door S side 106 UNUSED
-// 11 water level 5 43 torch floor 75 wood door N side 107 UNUSED
-// 12 water level 4 44 torch pointing S 76 wood door W side 108 UNUSED
-// 13 water level 3 45 torch pointing N 77 wood door E side 109 UNUSED
-// 14 water level 2 46 torch pointing W 78 wood door top S 110 stone pressure plate
-// 15 water level 1 47 torch pointing E 79 wood door top N 111 iron door S side
-// 16 lava full/falling 48 UNUSED 80 wood door top W 112 iron door N side
-// 17 lava level 3 49 spawner 81 wood door top E 113 iron door W side
-// 18 lava level 2 50 wood stairs asc S 82 ladder E side 114 iron door E side
-// 19 lava level 1 51 wood stairs asc N 83 ladder W side 115 iron door top S
-// 20 sand 52 wood stairs asc W 84 ladder N side 116 iron door top N
-// 21 UNUSED 53 wood stairs asc E 85 ladder S side 117 iron door top W
-// 22 gold ore 54 UNUSED 86 track EW 118 iron door top E
-// 23 iron ore 55 redstone wire NSEW 87 track NS 119 wood pressure plate
-// 24 coal ore 56 diamond ore 88 UNUSED 120 redstone ore
-// 25 log 57 diamond block 89 UNUSED 121 red torch floor off
-// 26 leaves 58 workbench 90 UNUSED 122 red torch floor on
-// 27 sponge 59 wheat level 7 91 UNUSED 123 UNUSED
-// 28 glass 60 wheat level 6 92 track NE corner 124 UNUSED
-// 29 white wool 61 wheat level 5 93 track SE corner 125 UNUSED
-// 30 yellow flower 62 wheat level 4 94 track SW corner 126 UNUSED
-// 31 red rose 63 wheat level 3 95 track NW corner 127 snow
-//
-// 128 ice 160 fence NS 192 stone button facing W 224 dispenser N
-// 129 snow block 161 fence E 193 stone button facing E 225 dispenser E/S
-// 130 cactus 162 fence NE 194 wall lever facing S 226 sandstone
-// 131 clay 163 fence SE 195 wall lever facing N 227 note block
-// 132 reeds 164 fence NSE 196 wall lever facing W 228 UNUSED
-// 133 jukebox 165 fence W 197 wall lever facing E 229 sandstone slab
-// 134 fence post 166 fence NW 198 ground lever EW 230 wooden slab
-// 135 pumpkin facing W 167 fence SW 199 ground lever NS 231 cobble slab
-// 136 netherrack 168 fence NSW 200 track asc S 232 UNUSED
-// 137 soul sand 169 fence EW 201 track asc N 233 UNUSED
-// 138 glowstone 170 fence NEW 202 track asc E 234 UNUSED
-// 139 portal 171 fence SEW 203 track asc W 235 UNUSED
-// 140 jack-o-lantern W 172 fence NSEW 204 orange wool 236 UNUSED
-// 141 red torch S on 173 UNUSED 205 magenta wool 237 UNUSED
-// 142 red torch N on 174 UNUSED 206 light blue wool 238 UNUSED
-// 143 red torch E on 175 UNUSED 207 yellow wool 239 UNUSED
-// 144 red torch W on 176 UNUSED 208 lime wool 240 repeater on N
-// 145 red torch S off 177 UNUSED 209 pink wool 241 repeater on S
-// 146 red torch N off 178 water missing W 210 gray wool 242 repeater on E
-// 147 red torch E off 179 water missing N 211 light gray wool 243 repeater on W
-// 148 red torch W off 180 ice surface 212 cyan wool 244 repeater off N
-// 149 UNUSED 181 ice missing W 213 purple wool 245 repeater off S
-// 150 UNUSED 182 ice missing N 214 blue wool 246 repeater off E
-// 151 UNUSED 183 furnace W 215 brown wool 247 repeater off W
-// 152 UNUSED 184 furnace N 216 green wool 248 pine leaves
-// 153 pumpkin facing E/S 185 furnace E/S 217 red wool 249 birch leaves
-// 154 pumpkin facing N 186 lit furnace W 218 black wool 250 pine sapling
-// 155 jack-o-lantern E/S 187 lit furnace N 219 pine log 251 birch sapling
-// 156 jack-o-lantern N 188 lit furnace E/S 220 birch log 252 booster on EW
-// 157 water surface 189 fire 221 lapis ore 253 booster on NS
-// 158 fence N 190 stone button facing S 222 lapis block 254 booster on asc S
-// 159 fence S 191 stone button facing N 223 dispenser W 255 booster on asc N
-//
-// 256 booster on asc E 288 bed foot S 320 nether fence E 352 cauldron 1/3 full
-// 257 booster on asc W 289 cake 321 nether fence NE 353 cauldron 2/3 full
-// 258 booster off EW 290 melon 322 nether fence SE 354 cauldron full
-// 259 booster off NS 291 mycelium 323 nether fence NSE 355 iron bars NSEW
-// 260 booster off asc S 292 nether brick 324 nether fence W 356 iron bars NS
-// 261 booster off asc N 293 end stone 325 nether fence NW 357 iron bars NE
-// 262 booster off asc E 294 stone brick 326 nether fence SW 358 iron bars NW
-// 263 booster off asc W 295 mossy stone brick 327 nether fence NSW 359 iron bars SE
-// 264 detector EW 296 cracked stone brick 328 nether fence EW 360 iron bars SW
-// 265 detector NS 297 UNUSED 329 nether fence NEW 361 iron bars EW
-// 266 detector asc S 298 UNUSED 330 nether fence SEW 362 iron bars SEW
-// 267 detector asc N 299 UNUSED 331 nether fence NSEW 363 iron bars NEW
-// 268 detector asc E 300 UNUSED 332 nether fence post 364 iron bars NSW
-// 269 detector asc W 301 UNUSED 333 netherwart small 365 iron bars NSE
-// 270 locked chest facing W 302 brick slab 334 netherwart medium 366 glass pane NSEW
-// 271 locked chest facing N 303 stone brick slab 335 netherwart large 367 glass pane NS
-// 272 web 304 brick stairs asc S 336 mushroom flesh 368 glass pane NE
-// 273 tall grass 305 brick stairs asc N 337 red cap top only 369 glass pane NW
-// 274 fern 306 brick stairs asc W 338 red cap N 370 glass pane SE
-// 275 dead shrub 307 brick stairs asc E 339 red cap W 371 glass pane SW
-// 276 trapdoor closed 308 stone brick stairs S 340 red cap NW 372 glass pane EW
-// 277 trapdoor open W 309 stone brick stairs N 341 brown cap top only 373 glass pane SEW
-// 278 trapdoor open E 310 stone brick stairs W 342 brown cap N 374 glass pane NEW
-// 279 trapdoor open S 311 stone brick stairs E 343 brown cap W 375 glass pane NSW
-// 280 trapdoor open N 312 nether stairs asc S 344 brown cap NW 376 glass pane NSE
-// 281 bed head W 313 nether stairs asc N 345 mushroom stem 377 end portal
-// 282 bed head N 314 nether stairs asc W 346 fence gate EW 378 dragon egg
-// 283 bed head E 315 nether stairs asc E 347 fence gate NS 379 vines top only
-// 284 bed head S 316 lily pad 348 enchantment table 380 vines N
-// 285 bed foot W 317 nether fence N 349 end portal frame 381 vines S
-// 286 bed foot N 318 nether fence S 350 brewing stand 382 vines NS
-// 287 bed foot E 319 nether fence NS 351 cauldron empty 383 vines E
-//
-// 384 vines NE 416 closed sticky piston S 448 brick stairs inv W 480 ender chest facing N
-// 385 vines SE 417 closed sticky piston W 449 brick stairs inv E 481 ender chest facing E/S
-// 386 vines NSE 418 closed sticky piston E 450 stone brick stairs inv S 482 emerald block
-// 387 vines W 419 iron bars N 451 stone brick stairs inv N 483 gravel
-// 388 vines NW 420 iron bars S 452 stone brick stairs inv W 484 chest facing W
-// 389 vines SW 421 iron bars E 453 stone brick stairs inv E 485 chest facing N
-// 390 vines NSW 422 iron bars W 454 nether stairs inv S 486 chest facing E/S
-// 391 vines EW 423 glass pane N 455 nether stairs inv N 487 double chest N facing W
-// 392 vines NEW 424 glass pane S 456 nether stairs inv W 488 double chest S facing W
-// 393 vines SEW 425 glass pane E 457 nether stairs inv E 489 double chest E facing N
-// 394 vines NSEW 426 glass pane W 458 stone slab inv 490 double chest W facing N
-// 395 stem level 0 427 jungle log 459 sandstone slab inv 491 double chest N facing E
-// 396 stem level 1 428 jungle leaves 460 wooden slab inv 492 double chest S facing E
-// 397 stem level 2 429 jungle sapling 461 cobblestone slab inv 493 double chest E facing S
-// 398 stem level 3 430 circle stone brick 462 brick slab inv 494 double chest W facing S
-// 399 stem level 4 431 hieroglyphic sandstone 463 stone brick slab inv 495 pine stairs asc S
-// 400 stem level 5 432 smooth sandstone 464 pine slab 496 pine stairs asc N
-// 401 stem level 6 433 redstone lamp on 465 pine slab inv 497 pine stairs asc W
-// 402 stem level 7 434 redstone lamp off 466 birch slab 498 pine stairs asc E
-// 403 stem pointing N 435 pine planks 467 birch slab inv 499 pine stairs inv S
-// 404 stem pointing S 436 birch planks 468 jungle slab 500 pine stairs inv N
-// 405 stem pointing E 437 jungle planks 469 jungle slab inv 501 pine stairs inv W
-// 406 stem pointing W 438 wood stairs inv S 470 sandstone stairs asc S 502 pine stairs inv E
-// 407 closed piston D 439 wood stairs inv N 471 sandstone stairs asc N 503 birch stairs asc S
-// 408 closed piston U 440 wood stairs inv W 472 sandstone stairs asc W 504 birch stairs asc N
-// 409 closed piston N 441 wood stairs inv E 473 sandstone stairs asc E 505 birch stairs asc W
-// 410 closed piston S 442 cobble stairs inv S 474 sandstone stairs inv S 506 birch stairs asc E
-// 411 closed piston W 443 cobble stairs inv N 475 sandstone stairs inv N 507 birch stairs inv S
-// 412 closed piston E 444 cobble stairs inv W 476 sandstone stairs inv W 508 birch stairs inv N
-// 413 closed sticky piston D 445 cobble stairs inv E 477 sandstone stairs inv E 509 birch stairs inv W
-// 414 closed sticky piston U 446 brick stairs inv S 478 emerald ore 510 birch stairs inv E
-// 415 closed sticky piston N 447 brick stairs inv N 479 ender chest facing W 511 jungle stairs asc S
-//
-// 512 jungle stairs asc N 544 tripwire NS
-// 513 jungle stairs asc W 545 tripwire NE
-// 514 jungle stairs asc E 546 tripwire NW
-// 515 jungle stairs inv S 547 tripwire SE
-// 516 jungle stairs inv N 548 tripwire SW
-// 517 jungle stairs inv W 549 tripwire EW
-// 518 jungle stairs inv E 550 tripwire SEW
-// 519 cocoa level 0 stem N 551 tripwire NEW
-// 520 cocoa level 0 stem S 552 tripwire NSW
-// 521 cocoa level 0 stem E 553 tripwire NSE
-// 522 cocoa level 0 stem W
-// 523 cocoa level 1 stem N
-// 524 cocoa level 1 stem S
-// 525 cocoa level 1 stem E
-// 526 cocoa level 1 stem W
-// 527 cocoa level 2 stem N
-// 528 cocoa level 2 stem S
-// 529 cocoa level 2 stem E
-// 530 cocoa level 2 stem W
-// 531 log EW
-// 532 log NS
-// 533 pine log EW
-// 534 pine log NS
-// 535 birch log EW
-// 536 birch log NS
-// 537 jungle log EW
-// 538 jungle log NS
-// 539 tripwire hook S
-// 540 tripwire hook N
-// 541 tripwire hook W
-// 542 tripwire hook E
-// 543 tripwire NSEW
-
-#define NUMBLOCKIMAGES 554
-
-
-
-#endif // BLOCKIMAGES_H
\ No newline at end of file
+// Copyright 2010-2012 Michael J. Nelson
+//
+// This file is part of pigmap.
+//
+// pigmap is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// pigmap is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with pigmap. If not, see .
+
+#ifndef BLOCKIMAGES_H
+#define BLOCKIMAGES_H
+
+#include
+
+#include "rgba.h"
+
+// IMPORTANT NOTE:
+// This program was written before the location of the sun moved in Minecraft Beta 1.9 or so,
+// therefore all of the N/S/E/W directions here are now wrong--rotated 90 degrees from what they
+// should be. For example, the positive X direction used to be South, and is called South here,
+// but is now East in the game (as of Minecraft 1.0, anyway).
+// I decided to leave the old direction names here, because it would be pretty easy to mess
+// something up trying to go through and change everything. Apologies for the confusion!
+// EDIT: (Akudeu Kie)
+// Since in 1.5 terrain.png will be deprecated and new texture format will be introduced,
+// programm requires some rewriting anyway, so orientation is changed accordingly (N -> W, W -> S, S -> E, E -> N)
+
+// this structure holds the block images used to build the map; each block image is a hexagonal shape within
+// a 4Bx4B rectangle, with the unused area around it set to fully transparent
+//
+// example of hexagon shape for B = 3, where U represents pixels belonging to the U-facing side of the block, etc.:
+//
+// UU
+// UUUUUU
+// UUUUUUUUUU
+// WUUUUUUUUUUS
+// WWWUUUUUUSSS
+// WWWWWUUSSSSS
+// WWWWWWSSSSSS
+// WWWWWWSSSSSS
+// WWWWWWSSSSSS
+// WWWWWSSSSS
+// WWWSSS
+// WS
+//
+// when supplying your own block images, there's nothing to stop you from going "out of bounds" and having
+// non-transparent pixels outside the hexagon, but you'll just get a messed-up image, since the renderer
+// uses only the hexagon to determine visibility, etc.
+//
+// note that translucent blocks require the most work to render, simply because you can see what's behind them;
+// if every block in the world was translucent, for example, then every block would be considered visible
+// ...so if you're editing the block images for special purposes like X-ray vision, the fastest results are
+// obtained by making unwanted blocks fully transparent, not just translucent
+// ...also, any pixels in the block images with alphas < 10 will have their alphas set to 0, and similarly
+// any alphas > 245 will be set to 255; this is to prevent massive slowdown from accidental image-editing
+// cock-ups, like somehow setting the transparency of the whole image to 99% instead of 100%, etc.
+//
+// most block images are created by resizing the relevant terrain.png images from 16x16 to 2Bx2B, then painting
+// their columns onto the faces of the block image thusly (example is for B = 3 again):
+//
+// a f
+// abcdef ab abc def
+// abcdef aabbcd abcde bcdef
+// abcdef ---> aabbccddef or abcdef or abcdef
+// abcdef abccddeeff abcdef abcdef
+// abcdef cdeeff abcdef abcdef
+// abcdef ef bcdef abcde
+// def abc
+// f a
+
+struct BlockImages
+{
+ // this image holds all the block images, in rows of 16 (so its width is 4B*16; height depends on number of rows)
+ // ...the very first block image is a dummy one, fully transparent, for use with unrecognized blocks
+ RGBAImage img;
+ int rectsize; // size of block image bounding boxes
+ int blockversion; // version of the blocks-B.png
+
+ std::vector< std::vector< std::string > > blockDescriptors; // vector holding block type and block texture descriptions
+
+ // for every possible 12-bit block id/4-bit block data combination, this holds the offset into the image
+ // (unrecognized id/data values are pointed at the dummy block image)
+ // this doesn't handle some things like fences and double chests where the rendering doesn't depend solely
+ // on the blockID/blockData; for those, the renderer just has to know the proper offsets on its own
+ int blockOffsets[4096 * 16];
+ int getOffset(uint16_t blockID, uint8_t blockData) const {return blockOffsets[blockID * 16 + blockData];}
+
+ // check whether a block image is opaque (this is a function of the block images computed from the terrain,
+ // not of the actual block data; if a block image has 100% alpha everywhere, it's considered opaque)
+ std::vector opacity; // size is blockversion; indexed by offset
+ bool isOpaque(int offset) const {return opacity[offset];}
+ bool isOpaque(uint16_t blockID, uint8_t blockData) const {return opacity[getOffset(blockID, blockData)];}
+
+ // ...and the same thing for complete transparency (0% alpha everywhere)
+ std::vector transparency; // size is blockversion; indexed by offset
+ bool isTransparent(int offset) const {return transparency[offset];}
+ bool isTransparent(uint16_t blockID, uint8_t blockData) const {return transparency[getOffset(blockID, blockData)];}
+
+ // get the rectangle in img corresponding to an offset
+ ImageRect getRect(int offset) const {return ImageRect((offset%16)*rectsize, (offset/16)*rectsize, rectsize, rectsize);}
+ ImageRect getRect(uint16_t blockID, uint8_t blockData) const {return getRect(getOffset(blockID, blockData));}
+
+ // attempt to create a BlockImages structure: look for blocks-B.png in the imgpath, where B is the block size
+ // parameter; failing that, look for terrain.png and construct a new blocks-B.png from it; failing that, uh, fail
+ bool create(int B, const std::string& imgpath);
+
+ // create vector with block descriptors, used for offset assignment and block images construction
+ void setBlockDescriptors(std::ifstream& descriptorlist);
+
+ // set the offsets
+ int setOffsets();
+
+ // fill in the opacity and transparency members
+ void checkOpacityAndTransparency(int B);
+
+ // scan the block images looking for not-quite-transparent or not-quite-opaque pixels; if they're close enough,
+ // push them all the way
+ void retouchAlphas(int B);
+
+ // build block images from terrain.png, etc.
+ bool construct(int B, std::ifstream& texturelist, std::ifstream& descriptorlist, const std::string& imgpath);
+};
+
+#endif // BLOCKIMAGES_H
diff --git a/blocktextures.list b/blocktextures.list
new file mode 100644
index 0000000..367d997
--- /dev/null
+++ b/blocktextures.list
@@ -0,0 +1,557 @@
+# blocktextures.list
+#
+# List of textures to include for processing
+# Enter full name of the texture (should be PNG images) on separate line
+# You can specify from which directory to read texture (switch current directory, as to say). To do that use the following syntax:
+# $ /new/path
+# $ /
+# Directories should be relative to the image path, or path where renderer is being executed from.
+#
+# You can prefix texture with a / (slash), to apply different filters to the texture.
+# !!!NOTE!!! Filters will be applied only to the copies of textures stored in memory. Original textures will not be modified.
+# If you do so, you can use a couple of directives after a texture name.
+# !!!NOTE!!! Directives are executed in order of appearance. EXPAND, CHEST and LCHEST create new textures. If you want to apply other filters,
+# they (filters) should go -AFTER- EXPAND directive, and -BEFORE- CHEST and LCHEST directives.
+# !!!NOTE!!! CHEST and LCHEST are similar, but should not be used together.
+# Here is a list of available directives and their syntax:
+# - RENAME newtexturename
+# Assigns different name to a texture. You can, for example, read the same texture twice, but second one a different name and apply
+# few more other filters. Renamed texture then can be used in block descriptor list.
+# =Example=
+# / leaves.png RENAME leaves_birch.png
+# - DARKEN darkenRed darkenGreen darkenBlue
+# Darkens each separate color channel of the texture based on given amount. Amount is specified as a decimal number[0-1].
+# =Example=
+# / leaves.png DARKEN 0.3 1.0 0.1
+# - OFFSET offsetX offsetY
+# Offset texture by specified offset. Offset is specified in pixels (x out 16).
+# If offset exceeds the width or height of the texture, modulus of an offset will be taken.
+# Offset texture is not tiled. If you want to offset texture, so it leaves it's size area, just use blank texture (/).
+# =Example=
+# / stem_straight.png OFFSET 0 14
+# - OFFSETTILE offsetX offsetY
+# Same as OFFSET, but texture is tiled - it repeats it's pattern from opposite side where it is being offset.
+# - EXPAND expandX expandY
+# Expands specified region of the texture to full tile size by resizing it. Using this directive results in new texture. Use this directive before other directives.
+# / %texturename% EXPAND x y width height
+# =Example=
+# / cake_top.png EXPAND 1 1 14 14
+# - CROP top right bottom left
+# Crops texture from each side by a specified amount. Amount is specified in pixels (x out 16).
+# =Example=
+# / stem_straight.png CROP 14 0 0 0
+# - FLIPX
+# Flips the texture along the x axis. The result is mirrored texture.
+# =Example=
+# / stem_straight.png FLIPX
+# - OVERLAY
+# Overlays texture with different texture to make single composite texture
+# =Example=
+# / doublePlant_sunflower_top.png OVERLAY doublePlant_sunflower_front.png
+# - CHEST
+# - LCHEST
+# CHEST and LCHEST are directives for generating special tile, in this case - specific tiles for small and large chests.
+# Since original textures are chest model textures, they don't fit in tile size (e.g. 16x16). Renderer will create required tiles for chest blocks,
+# and then will use them to build block tiles.
+# To use textures with this directive, just prefix the original name with / (slash) in block descriptor list.
+#
+$ /textures/blocks
+anvil_base.png
+anvil_top_damaged_0.png
+anvil_top_damaged_1.png
+anvil_top_damaged_2.png
+beacon.png
+bed_feet_end.png
+bed_feet_side.png
+bed_feet_top.png
+bed_head_end.png
+bed_head_side.png
+bed_head_top.png
+bedrock.png
+beetroots_stage_0.png
+beetroots_stage_1.png
+beetroots_stage_2.png
+beetroots_stage_3.png
+bone_block_side.png
+bone_block_top.png
+bookshelf.png
+brewing_stand.png
+brewing_stand_base.png
+brick.png
+/ cactus_bottom.png EXPAND 1 1 14 14
+/ cactus_side.png EXPAND 1 1 14 14
+/ cactus_top.png EXPAND 1 1 14 14
+/ cake_bottom.png EXPAND 1 1 14 14
+/ cake_inner.png EXPAND 1 1 14 14
+/ cake_side.png EXPAND 1 1 14 14
+/ cake_top.png EXPAND 1 1 14 14
+carrots_stage_0.png
+carrots_stage_1.png
+carrots_stage_2.png
+carrots_stage_3.png
+cauldron_bottom.png
+cauldron_inner.png
+cauldron_side.png
+cauldron_top.png
+chain_command_block_back.png
+chain_command_block_conditional.png
+chain_command_block_front.png
+chain_command_block_side.png
+chorus_flower.png
+chorus_flower_dead.png
+chorus_plant.png
+clay.png
+coal_block.png
+coal_ore.png
+coarse_dirt.png
+cobblestone.png
+cobblestone_mossy.png
+cocoa_stage_0.png
+cocoa_stage_1.png
+cocoa_stage_2.png
+command_block_back.png
+command_block_conditional.png
+command_block_front.png
+command_block_side.png
+comparator_off.png
+comparator_on.png
+concrete_black.png
+concrete_blue.png
+concrete_brown.png
+concrete_cyan.png
+concrete_gray.png
+concrete_green.png
+concrete_light_blue.png
+concrete_lime.png
+concrete_magenta.png
+concrete_orange.png
+concrete_pink.png
+concrete_powder_black.png
+concrete_powder_blue.png
+concrete_powder_brown.png
+concrete_powder_cyan.png
+concrete_powder_gray.png
+concrete_powder_green.png
+concrete_powder_light_blue.png
+concrete_powder_lime.png
+concrete_powder_magenta.png
+concrete_powder_orange.png
+concrete_powder_pink.png
+concrete_powder_purple.png
+concrete_powder_red.png
+concrete_powder_silver.png
+concrete_powder_white.png
+concrete_powder_yellow.png
+concrete_purple.png
+concrete_red.png
+concrete_silver.png
+concrete_white.png
+concrete_yellow.png
+crafting_table_front.png
+crafting_table_side.png
+crafting_table_top.png
+daylight_detector_inverted_top.png
+daylight_detector_side.png
+daylight_detector_top.png
+deadbush.png
+destroy_stage_0.png
+destroy_stage_1.png
+destroy_stage_2.png
+destroy_stage_3.png
+destroy_stage_4.png
+destroy_stage_5.png
+destroy_stage_6.png
+destroy_stage_7.png
+destroy_stage_8.png
+destroy_stage_9.png
+diamond_block.png
+diamond_ore.png
+dirt.png
+dirt_podzol_side.png
+dirt_podzol_top.png
+dispenser_front_horizontal.png
+dispenser_front_vertical.png
+door_acacia_lower.png
+door_acacia_upper.png
+door_birch_lower.png
+door_birch_upper.png
+door_dark_oak_lower.png
+door_dark_oak_upper.png
+door_iron_lower.png
+door_iron_upper.png
+door_jungle_lower.png
+door_jungle_upper.png
+door_spruce_lower.png
+door_spruce_upper.png
+door_wood_lower.png
+door_wood_upper.png
+/ double_plant_fern_bottom.png DARKEN 0.6 0.95 0.3
+/ double_plant_fern_top.png DARKEN 0.6 0.95 0.3
+/ double_plant_grass_bottom.png DARKEN 0.6 0.95 0.3
+/ double_plant_grass_top.png DARKEN 0.6 0.95 0.3
+double_plant_paeonia_bottom.png
+double_plant_paeonia_top.png
+double_plant_rose_bottom.png
+double_plant_rose_top.png
+#double_plant_sunflower_back.png
+double_plant_sunflower_bottom.png
+#double_plant_sunflower_front.png
+/ double_plant_sunflower_top.png OVERLAY double_plant_sunflower_front.png
+double_plant_syringa_bottom.png
+double_plant_syringa_top.png
+dragon_egg.png
+dropper_front_horizontal.png
+dropper_front_vertical.png
+emerald_block.png
+emerald_ore.png
+enchanting_table_bottom.png
+enchanting_table_side.png
+enchanting_table_top.png
+end_bricks.png
+end_rod.png
+/ end_rod.png RENAME /end_rod_lamp.png EXPAND 0 0 2 15
+/ end_rod.png RENAME /end_rod_base.png EXPAND 2 2 4 5
+end_stone.png
+endframe_eye.png
+endframe_side.png
+endframe_top.png
+farmland_dry.png
+farmland_wet.png
+/ fern.png DARKEN 0.6 0.95 0.3
+fire_layer_0.png
+fire_layer_1.png
+flower_allium.png
+flower_blue_orchid.png
+flower_dandelion.png
+flower_houstonia.png
+flower_oxeye_daisy.png
+flower_paeonia.png
+flower_pot.png
+flower_rose.png
+flower_tulip_orange.png
+flower_tulip_pink.png
+flower_tulip_red.png
+flower_tulip_white.png
+frosted_ice_0.png
+frosted_ice_1.png
+frosted_ice_2.png
+frosted_ice_3.png
+furnace_front_off.png
+furnace_front_on.png
+furnace_side.png
+furnace_top.png
+glass.png
+glass_black.png
+glass_blue.png
+glass_brown.png
+glass_cyan.png
+glass_gray.png
+glass_green.png
+glass_light_blue.png
+glass_lime.png
+glass_magenta.png
+glass_orange.png
+glass_pane_top.png
+glass_pane_top_black.png
+glass_pane_top_blue.png
+glass_pane_top_brown.png
+glass_pane_top_cyan.png
+glass_pane_top_gray.png
+glass_pane_top_green.png
+glass_pane_top_light_blue.png
+glass_pane_top_lime.png
+glass_pane_top_magenta.png
+glass_pane_top_orange.png
+glass_pane_top_pink.png
+glass_pane_top_purple.png
+glass_pane_top_red.png
+glass_pane_top_silver.png
+glass_pane_top_white.png
+glass_pane_top_yellow.png
+glass_pink.png
+glass_purple.png
+glass_red.png
+glass_silver.png
+glass_white.png
+glass_yellow.png
+glazed_terracotta_black.png
+glazed_terracotta_blue.png
+glazed_terracotta_brown.png
+glazed_terracotta_cyan.png
+glazed_terracotta_gray.png
+glazed_terracotta_green.png
+glazed_terracotta_light_blue.png
+glazed_terracotta_lime.png
+glazed_terracotta_magenta.png
+glazed_terracotta_orange.png
+glazed_terracotta_pink.png
+glazed_terracotta_purple.png
+glazed_terracotta_red.png
+glazed_terracotta_silver.png
+glazed_terracotta_white.png
+glazed_terracotta_yellow.png
+glowstone.png
+gold_block.png
+gold_ore.png
+grass_path_side.png
+grass_path_top.png
+grass_side.png
+grass_side_overlay.png
+grass_side_snowed.png
+/ grass_top.png DARKEN 0.6 0.95 0.3
+gravel.png
+hardened_clay.png
+hardened_clay_stained_black.png
+hardened_clay_stained_blue.png
+hardened_clay_stained_brown.png
+hardened_clay_stained_cyan.png
+hardened_clay_stained_gray.png
+hardened_clay_stained_green.png
+hardened_clay_stained_light_blue.png
+hardened_clay_stained_lime.png
+hardened_clay_stained_magenta.png
+hardened_clay_stained_orange.png
+hardened_clay_stained_pink.png
+hardened_clay_stained_purple.png
+hardened_clay_stained_red.png
+hardened_clay_stained_silver.png
+hardened_clay_stained_white.png
+hardened_clay_stained_yellow.png
+hay_block_side.png
+hay_block_top.png
+hopper_inside.png
+hopper_outside.png
+hopper_top.png
+ice.png
+ice_packed.png
+iron_bars.png
+iron_block.png
+iron_ore.png
+iron_trapdoor.png
+itemframe_background.png
+jukebox_side.png
+jukebox_top.png
+ladder.png
+lapis_block.png
+lapis_ore.png
+lava_still.png
+/ leaves_acacia.png DARKEN 0.55 0.9 0.1
+/ leaves_big_oak.png DARKEN 0.3 1.0 0.1
+/ leaves_birch.png DARKEN 0.55 0.9 0.1
+/ leaves_jungle.png DARKEN 0.35, 1.0, 0.05
+/ leaves_oak.png DARKEN 0.3 1.0 0.1
+/ leaves_spruce.png DARKEN 0.3 1.0 0.45
+lever.png
+log_acacia.png
+log_acacia_top.png
+log_big_oak.png
+log_big_oak_top.png
+log_birch.png
+log_birch_top.png
+log_jungle.png
+log_jungle_top.png
+log_oak.png
+log_oak_top.png
+log_spruce.png
+log_spruce_top.png
+magma.png
+melon_side.png
+/ melon_stem_connected.png RENAME /melon_stem_connected.png_0 DARKEN 0.75 0.6 0.3
+/ melon_stem_connected.png RENAME /melon_stem_connected.png_1 DARKEN 0.75 0.6 0.3 FLIPX
+/ melon_stem_disconnected.png RENAME /melon_stem_disconnected.png_0 DARKEN 0.45 0.95 0.4 OFFSET 0 14
+/ melon_stem_disconnected.png RENAME /melon_stem_disconnected.png_1 DARKEN 0.45 0.95 0.4 OFFSET 0 12
+/ melon_stem_disconnected.png RENAME /melon_stem_disconnected.png_2 DARKEN 0.45 0.95 0.4 OFFSET 0 10
+/ melon_stem_disconnected.png RENAME /melon_stem_disconnected.png_3 DARKEN 0.45 0.95 0.4 OFFSET 0 8
+/ melon_stem_disconnected.png RENAME /melon_stem_disconnected.png_4 DARKEN 0.45 0.95 0.4 OFFSET 0 6
+/ melon_stem_disconnected.png RENAME /melon_stem_disconnected.png_5 DARKEN 0.45 0.95 0.4 OFFSET 0 4
+/ melon_stem_disconnected.png RENAME /melon_stem_disconnected.png_6 DARKEN 0.45 0.95 0.4 OFFSET 0 2
+/ melon_stem_disconnected.png RENAME /melon_stem_disconnected.png_7 DARKEN 0.75 0.6 0.3
+melon_top.png
+mob_spawner.png
+mushroom_block_inside.png
+mushroom_block_skin_brown.png
+mushroom_block_skin_red.png
+mushroom_block_skin_stem.png
+mushroom_brown.png
+mushroom_red.png
+mycelium_side.png
+mycelium_top.png
+nether_brick.png
+nether_wart_block.png
+nether_wart_stage_0.png
+nether_wart_stage_1.png
+nether_wart_stage_2.png
+netherrack.png
+noteblock.png
+observer_back.png
+observer_back_lit.png
+observer_front.png
+observer_side.png
+observer_top.png
+obsidian.png
+piston_bottom.png
+piston_inner.png
+piston_side.png
+piston_top_normal.png
+piston_top_sticky.png
+planks_acacia.png
+planks_big_oak.png
+planks_birch.png
+planks_jungle.png
+planks_oak.png
+planks_spruce.png
+portal.png
+potatoes_stage_0.png
+potatoes_stage_1.png
+potatoes_stage_2.png
+potatoes_stage_3.png
+prismarine_bricks.png
+prismarine_dark.png
+prismarine_rough.png
+pumpkin_face_off.png
+pumpkin_face_on.png
+pumpkin_side.png
+/ pumpkin_stem_connected.png RENAME /pumpkin_stem_connected.png_0 DARKEN 0.75 0.6 0.3
+/ pumpkin_stem_connected.png RENAME /pumpkin_stem_connected.png_1 DARKEN 0.75 0.6 0.3 FLIPX
+/ pumpkin_stem_disconnected.png RENAME /pumpkin_stem_disconnected.png_0 DARKEN 0.45 0.95 0.4 OFFSET 0 14
+/ pumpkin_stem_disconnected.png RENAME /pumpkin_stem_disconnected.png_1 DARKEN 0.45 0.95 0.4 OFFSET 0 12
+/ pumpkin_stem_disconnected.png RENAME /pumpkin_stem_disconnected.png_2 DARKEN 0.45 0.95 0.4 OFFSET 0 10
+/ pumpkin_stem_disconnected.png RENAME /pumpkin_stem_disconnected.png_3 DARKEN 0.45 0.95 0.4 OFFSET 0 8
+/ pumpkin_stem_disconnected.png RENAME /pumpkin_stem_disconnected.png_4 DARKEN 0.45 0.95 0.4 OFFSET 0 6
+/ pumpkin_stem_disconnected.png RENAME /pumpkin_stem_disconnected.png_5 DARKEN 0.45 0.95 0.4 OFFSET 0 4
+/ pumpkin_stem_disconnected.png RENAME /pumpkin_stem_disconnected.png_6 DARKEN 0.45 0.95 0.4 OFFSET 0 2
+/ pumpkin_stem_disconnected.png RENAME /pumpkin_stem_disconnected.png_7 DARKEN 0.75 0.6 0.3
+pumpkin_top.png
+purpur_block.png
+purpur_pillar.png
+purpur_pillar_top.png
+quartz_block_bottom.png
+quartz_block_chiseled.png
+quartz_block_chiseled_top.png
+quartz_block_lines.png
+quartz_block_lines_top.png
+quartz_block_side.png
+quartz_block_top.png
+quartz_ore.png
+rail_activator.png
+rail_activator_powered.png
+rail_detector.png
+rail_detector_powered.png
+rail_golden.png
+rail_golden_powered.png
+rail_normal.png
+rail_normal_turned.png
+red_nether_brick.png
+red_sand.png
+red_sandstone_bottom.png
+red_sandstone_carved.png
+red_sandstone_normal.png
+red_sandstone_smooth.png
+red_sandstone_top.png
+redstone_block.png
+/ redstone_dust_cross.png DARKEN 0.9 0.1 0.1
+/ redstone_dust_line.png DARKEN 0.9 0.1 0.1
+redstone_lamp_off.png
+redstone_lamp_on.png
+redstone_ore.png
+redstone_torch_off.png
+redstone_torch_on.png
+reeds.png
+repeater_off.png
+repeater_on.png
+repeating_command_block_back.png
+repeating_command_block_conditional.png
+repeating_command_block_front.png
+repeating_command_block_side.png
+sand.png
+sandstone_bottom.png
+sandstone_carved.png
+sandstone_normal.png
+sandstone_smooth.png
+sandstone_top.png
+sapling_acacia.png
+sapling_birch.png
+sapling_jungle.png
+sapling_oak.png
+sapling_roofed_oak.png
+sapling_spruce.png
+sea_lantern.png
+shulker_top_black.png
+shulker_top_blue.png
+shulker_top_brown.png
+shulker_top_cyan.png
+shulker_top_gray.png
+shulker_top_green.png
+shulker_top_light_blue.png
+shulker_top_lime.png
+shulker_top_magenta.png
+shulker_top_orange.png
+shulker_top_pink.png
+shulker_top_purple.png
+shulker_top_red.png
+shulker_top_silver.png
+shulker_top_white.png
+shulker_top_yellow.png
+slime.png
+snow.png
+soul_sand.png
+sponge.png
+sponge_wet.png
+stone.png
+stone_andesite.png
+stone_andesite_smooth.png
+stone_diorite.png
+stone_diorite_smooth.png
+stone_granite.png
+stone_granite_smooth.png
+stone_slab_side.png
+stone_slab_top.png
+stonebrick.png
+stonebrick_carved.png
+stonebrick_cracked.png
+stonebrick_mossy.png
+/ tallgrass.png DARKEN 0.6 0.95 0.3
+tnt_bottom.png
+tnt_side.png
+tnt_top.png
+torch_on.png
+trapdoor.png
+/ trip_wire.png OFFSET 0 6
+trip_wire_source.png
+/ vine.png DARKEN 0.35 1.0 0.15
+water_flow.png
+water_still.png
+/ waterlily.png DARKEN 0.3 0.95 0.3
+web.png
+wheat_stage_0.png
+wheat_stage_1.png
+wheat_stage_2.png
+wheat_stage_3.png
+wheat_stage_4.png
+wheat_stage_5.png
+wheat_stage_6.png
+wheat_stage_7.png
+wool_colored_black.png
+wool_colored_blue.png
+wool_colored_brown.png
+wool_colored_cyan.png
+wool_colored_gray.png
+wool_colored_green.png
+wool_colored_light_blue.png
+wool_colored_lime.png
+wool_colored_magenta.png
+wool_colored_orange.png
+wool_colored_pink.png
+wool_colored_purple.png
+wool_colored_red.png
+wool_colored_silver.png
+wool_colored_white.png
+wool_colored_yellow.png
+$ /textures/entity/chest
+/ normal.png CHEST
+/ normal_double.png LCHEST
+/ ender.png CHEST
+/ trapped.png CHEST
+/ trapped_double.png LCHEST
+$ /textures/entity
+end_portal.png
diff --git a/chunk.cpp b/chunk.cpp
old mode 100755
new mode 100644
index a9288c2..549b786
--- a/chunk.cpp
+++ b/chunk.cpp
@@ -1,411 +1,457 @@
-// Copyright 2010-2012 Michael J. Nelson
-//
-// This file is part of pigmap.
-//
-// pigmap is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// pigmap is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with pigmap. If not, see .
-
-#include
-#include
-#include
-#include
-#include
-
-#include "chunk.h"
-#include "utils.h"
-
-using namespace std;
-
-
-
-//---------------------------------------------------------------------------------------------------
-
-
-bool ChunkData::loadFromOldFile(const vector& filebuf)
-{
- anvil = false;
- // the hell with parsing this whole godforsaken NBT format; just look for the arrays we need
- uint8_t idsTag[13] = {7, 0, 6, 'B', 'l', 'o', 'c', 'k', 's', 0, 0, 128, 0};
- uint8_t dataTag[11] = {7, 0, 4, 'D', 'a', 't', 'a', 0, 0, 64, 0};
- bool foundIDs = false, foundData = false;
- for (vector::const_iterator it = filebuf.begin(); it != filebuf.end(); it++)
- {
- if (*it != 7)
- continue;
- if (!foundIDs && it + 13 + 32768 <= filebuf.end() && equal(it, it + 13, idsTag))
- {
- copy(it + 13, it + 13 + 32768, blockIDs);
- it += 13 + 32768 - 1; // one less because of the loop we're in
- foundIDs = true;
- }
- else if (!foundData && it + 11 + 16384 <= filebuf.end() && equal(it, it + 11, dataTag))
- {
- copy(it + 11, it + 11 + 16384, blockData);
- it += 11 + 16384 - 1; // one less because of the loop we're in
- foundData = true;
- }
- if (foundIDs && foundData)
- return true;
- }
- return false;
-}
-
-
-//---------------------------------------------------------------------------------------------------
-
-
-// quasi-NBT-parsing stuff for Anvil format: doesn't actually bother trying to read the whole thing,
-// just skips through the data looking for what we're interested in
-#define TAG_END 0
-#define TAG_BYTE 1
-#define TAG_SHORT 2
-#define TAG_INT 3
-#define TAG_LONG 4
-#define TAG_FLOAT 5
-#define TAG_DOUBLE 6
-#define TAG_BYTE_ARRAY 7
-#define TAG_STRING 8
-#define TAG_LIST 9
-#define TAG_COMPOUND 10
-#define TAG_INT_ARRAY 11
-
-// although tag names are UTF8, we'll just pretend they're ASCII--we don't really care about how the
-// actual string data breaks down into characters, as long as we know where the end of the string is
-void parseTypeAndName(const uint8_t*& ptr, uint8_t& type, string& name)
-{
- type = *ptr;
- ptr++;
- if (type != TAG_END)
- {
- uint16_t len = fromBigEndian(*((uint16_t*)ptr));
- name.resize(len);
- copy(ptr + 2, ptr + 2 + len, name.begin());
- ptr += 2 + len;
- }
-}
-
-// structure for locating the block data for a 16x16x16 section--the compound tags on the "Sections" list will pass
-// this down to their immediate children, so they can fill in pointers to their payloads if appropriate
-// ...after the whole structure is parsed, the block data will be copied into the ChunkData
-// (note that we can't read the block data immediately upon finding it, because we have to know the Y value
-// for the section first, and the tags may appear in any order)
-struct chunkSection
-{
- int y; // or -1 for "not found yet"
- const uint8_t *blockIDs; // pointer into the file buffer, or NULL for "not found yet"
- const uint8_t *blockData; // pointer into the file buffer, or NULL for "not found yet"
- const uint8_t *blockAdd; // pointer into the file buffer, or NULL for "not found" (this one may not be present at all)
-
- chunkSection() : y(-1), blockIDs(NULL), blockData(NULL), blockAdd(NULL) {}
- bool complete() const {return y >= 0 && y < 16 && blockIDs != NULL && blockData != NULL;}
-
- void extract(ChunkData& chunkdata) const
- {
- copy(blockIDs, blockIDs + 4096, chunkdata.blockIDs + (y * 4096));
- copy(blockData, blockData + 2048, chunkdata.blockData + (y * 2048));
- if (blockAdd != NULL)
- copy(blockAdd, blockAdd + 2048, chunkdata.blockAdd + (y * 2048));
- }
-};
-
-bool isSection(const vector& names)
-{
- return names.size() == 4 &&
- names[3] == "" &&
- names[2] == "Sections" &&
- names[1] == "Level" &&
- names[0] == "";
-}
-
-// if section != NULL, then the immediate parent of this tag is one of the compound tags in the "Sections"
-// list, so the block data tags will fill in their locations
-bool parsePayload(const uint8_t*& ptr, uint8_t type, vector& names, chunkSection *section, vector& completedSections)
-{
- switch (type)
- {
- case TAG_END:
- {
- return true;
- }
- case TAG_BYTE:
- {
- if (section != NULL && names.back() == "Y")
- section->y = *ptr;
- ptr++;
- return true;
- }
- case TAG_SHORT:
- {
- ptr += 2;
- return true;
- }
- case TAG_INT:
- case TAG_FLOAT:
- {
- ptr += 4;
- return true;
- }
- case TAG_LONG:
- case TAG_DOUBLE:
- {
- ptr += 8;
- return true;
- }
- case TAG_BYTE_ARRAY:
- {
- uint32_t len = fromBigEndian(*((uint32_t*)ptr));
- ptr += 4;
- if (section != NULL)
- {
- if (names.back() == "Blocks" && len == 4096)
- section->blockIDs = ptr;
- else if (names.back() == "Data" && len == 2048)
- section->blockData = ptr;
- else if (names.back() == "Add" && len == 2048)
- section->blockAdd = ptr;
- }
- ptr += len;
- return true;
- }
- case TAG_INT_ARRAY:
- {
- uint32_t len = fromBigEndian(*((uint32_t*)ptr));
- ptr += 4 + len*4;
- return true;
- }
- case TAG_STRING:
- {
- uint16_t len = fromBigEndian(*((uint16_t*)ptr));
- ptr += 2 + len;
- return true;
- }
- case TAG_LIST:
- {
- uint8_t listtype = *ptr;
- ptr++;
- uint32_t len = fromBigEndian(*((uint32_t*)ptr));
- ptr += 4;
- stackPusher sp(names, "");
- for (uint32_t i = 0; i < len; i++)
- if (!parsePayload(ptr, listtype, names, NULL, completedSections))
- return false;
- return true;
- }
- case TAG_COMPOUND:
- {
- chunkSection section;
- chunkSection *sectionPtr = isSection(names) ? §ion : NULL;
-
- uint8_t nexttype;
- string nextname;
- parseTypeAndName(ptr, nexttype, nextname);
- while (nexttype != TAG_END)
- {
- stackPusher sp(names, nextname);
- if (!parsePayload(ptr, nexttype, names, sectionPtr, completedSections))
- return false;
- parseTypeAndName(ptr, nexttype, nextname);
- }
-
- if (sectionPtr != NULL)
- {
- if (section.complete())
- completedSections.push_back(section);
- else
- {
- cerr << "incomplete chunk section!" << endl;
- return false;
- }
- }
-
- return true;
- }
- default:
- {
- // unknown tag--since we have no idea how large it is, we must abort
- cerr << "unknown NBT tag: type " << type << endl;
- return false;
- }
- }
- return false; // shouldn't be able to reach here
-}
-
-bool ChunkData::loadFromAnvilFile(const vector& filebuf)
-{
- anvil = true;
- fill(blockIDs, blockIDs + 65536, 0);
- fill(blockAdd, blockAdd + 32768, 0);
- fill(blockData, blockData + 32768, 0);
-
- const uint8_t *ptr = &(filebuf[0]);
- uint8_t type;
- string name;
- parseTypeAndName(ptr, type, name);
- if (type != TAG_COMPOUND || !name.empty())
- {
- cerr << "unrecognized NBT chunk file: top tag has type " << (int)type << " and name " << name << endl;
- return false;
- }
-
- vector names(1, name);
- vector completedSections;
- if (!parsePayload(ptr, type, names, NULL, completedSections))
- return false;
-
- for (vector::const_iterator it = completedSections.begin(); it != completedSections.end(); it++)
- it->extract(*this);
-
- return true;
-}
-
-
-//---------------------------------------------------------------------------------------------------
-
-
-ChunkCacheStats& ChunkCacheStats::operator+=(const ChunkCacheStats& ccs)
-{
- hits += ccs.hits;
- misses += ccs.misses;
- read += ccs.read;
- skipped += ccs.skipped;
- missing += ccs.missing;
- reqmissing += ccs.reqmissing;
- corrupt += ccs.corrupt;
- return *this;
-}
-
-ChunkData* ChunkCache::getData(const PosChunkIdx& ci)
-{
- int e = getEntryNum(ci);
- int state = chunktable.getDiskState(ci);
-
- if (state == ChunkSet::CHUNK_UNKNOWN)
- stats.misses++;
- else
- stats.hits++;
-
- // if we've already tried and failed to read the chunk, don't try again
- if (state == ChunkSet::CHUNK_CORRUPTED || state == ChunkSet::CHUNK_MISSING)
- return &blankdata;
-
- // if the chunk is in the cache, return it
- if (state == ChunkSet::CHUNK_CACHED)
- {
- if (entries[e].ci != ci)
- {
- cerr << "grievous chunk cache failure!" << endl;
- cerr << "[" << ci.x << "," << ci.z << "] [" << entries[e].ci.x << "," << entries[e].ci.z << "]" << endl;
- exit(-1);
- }
- return &entries[e].data;
- }
-
- // if this is a full render and the chunk is not required, we already know it doesn't exist
- bool req = chunktable.isRequired(ci);
- if (fullrender && !req)
- {
- stats.skipped++;
- chunktable.setDiskState(ci, ChunkSet::CHUNK_MISSING);
- return &blankdata;
- }
-
- // okay, we actually have to read the chunk from disk
- if (regionformat)
- readFromRegionCache(ci);
- else
- readChunkFile(ci);
-
- // check whether the read succeeded; return the data if so
- state = chunktable.getDiskState(ci);
- if (state == ChunkSet::CHUNK_CORRUPTED)
- {
- stats.corrupt++;
- return &blankdata;
- }
- if (state == ChunkSet::CHUNK_MISSING)
- {
- if (req)
- stats.reqmissing++;
- else
- stats.missing++;
- return &blankdata;
- }
- if (state != ChunkSet::CHUNK_CACHED || entries[e].ci != ci)
- {
- cerr << "grievous chunk cache failure!" << endl;
- cerr << "[" << ci.x << "," << ci.z << "] [" << entries[e].ci.x << "," << entries[e].ci.z << "]" << endl;
- exit(-1);
- }
- stats.read++;
- return &entries[e].data;
-}
-
-void ChunkCache::readChunkFile(const PosChunkIdx& ci)
-{
- // read the gzip file from disk, if it's there
- string filename = inputpath + "/" + ci.toChunkIdx().toFilePath();
- int result = readGzFile(filename, readbuf);
- if (result == -1)
- {
- chunktable.setDiskState(ci, ChunkSet::CHUNK_MISSING);
- return;
- }
- if (result == -2)
- {
- chunktable.setDiskState(ci, ChunkSet::CHUNK_CORRUPTED);
- return;
- }
-
- // gzip read was successful; extract the data we need from the chunk
- // and put it in the cache
- parseReadBuf(ci, false);
-}
-
-void ChunkCache::readFromRegionCache(const PosChunkIdx& ci)
-{
- // try to decompress the chunk data
- bool anvil;
- int result = regioncache.getDecompressedChunk(ci, readbuf, anvil);
- if (result == -1)
- {
- chunktable.setDiskState(ci, ChunkSet::CHUNK_MISSING);
- return;
- }
- if (result == -2)
- {
- chunktable.setDiskState(ci, ChunkSet::CHUNK_CORRUPTED);
- return;
- }
-
- // decompression was successful; extract the data we need from the chunk
- // and put it in the cache
- parseReadBuf(ci, anvil);
-}
-
-void ChunkCache::parseReadBuf(const PosChunkIdx& ci, bool anvil)
-{
- // evict current tenant of chunk's cache slot
- int e = getEntryNum(ci);
- if (entries[e].ci.valid())
- chunktable.setDiskState(entries[e].ci, ChunkSet::CHUNK_UNKNOWN);
- entries[e].ci = PosChunkIdx(-1,-1);
- // ...and put this chunk's data into the slot, assuming the data can actually be parsed
- bool result = anvil ? entries[e].data.loadFromAnvilFile(readbuf) : entries[e].data.loadFromOldFile(readbuf);
- if (result)
- {
- entries[e].ci = ci;
- chunktable.setDiskState(ci, ChunkSet::CHUNK_CACHED);
- }
- else
- chunktable.setDiskState(ci, ChunkSet::CHUNK_CORRUPTED);
-}
+// Copyright 2010-2012 Michael J. Nelson
+//
+// This file is part of pigmap.
+//
+// pigmap is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// pigmap is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with pigmap. If not, see .
+
+#include
+#include
+#include
+#include
+#include
+
+#include "chunk.h"
+#include "utils.h"
+
+using namespace std;
+
+
+
+//---------------------------------------------------------------------------------------------------
+
+
+bool ChunkData::loadFromOldFile(const vector& filebuf)
+{
+ anvil = false;
+ // the hell with parsing this whole godforsaken NBT format; just look for the arrays we need
+ uint8_t idsTag[13] = {7, 0, 6, 'B', 'l', 'o', 'c', 'k', 's', 0, 0, 128, 0};
+ uint8_t dataTag[11] = {7, 0, 4, 'D', 'a', 't', 'a', 0, 0, 64, 0};
+ bool foundIDs = false, foundData = false;
+
+ fill(blockIDs, blockIDs + 65536, 0);
+ fill(blockData, blockData + 32768, 0);
+
+ for (vector::const_iterator it = filebuf.begin(); it != filebuf.end(); it++)
+ {
+ if (*it != 7)
+ continue;
+ if (!foundIDs && it + 13 + 32768 <= filebuf.end() && equal(it, it + 13, idsTag))
+ {
+ for (unsigned x = 0; x < 16; ++x)
+ {
+ for (unsigned z = 0; z < 16; ++z)
+ {
+ for (unsigned y = 0; y < 128; ++y)
+ {
+ unsigned oldloc = (x * 16 + z) * 128 + y;
+ unsigned newloc = (y * 16 + z) * 16 + x;
+ blockIDs[newloc] = *(it + 13 + oldloc);
+ }
+ }
+ }
+ it += 13 + 32768 - 1; // one less because of the loop we're in
+ foundIDs = true;
+ }
+ else if (!foundData && it + 11 + 16384 <= filebuf.end() && equal(it, it + 11, dataTag))
+ {
+ for (unsigned x = 0; x < 16; ++x)
+ {
+ for (unsigned z = 0; z < 16; ++z)
+ {
+ for (unsigned y = 0; y < 128; ++y)
+ {
+ unsigned oldloc = (x * 16 + z) * 128 + y;
+ uint8_t data = *(it + 11 + oldloc / 2);
+ if (oldloc % 2 == 0)
+ data &= 0xf;
+ else
+ data = (data & 0xf0) >> 4;
+
+ unsigned newloc = (y * 16 + z) * 16 + x;
+ uint8_t& writeloc = blockData[newloc / 2];
+ if (newloc % 2 == 0)
+ writeloc = (writeloc & 0xf0) | data;
+ else
+ writeloc = (writeloc & 0xf) | (data << 4);
+ }
+ }
+ }
+ it += 11 + 16384 - 1; // one less because of the loop we're in
+ foundData = true;
+ }
+ if (foundIDs && foundData)
+ return true;
+ }
+ return false;
+}
+
+
+//---------------------------------------------------------------------------------------------------
+
+
+// quasi-NBT-parsing stuff for Anvil format: doesn't actually bother trying to read the whole thing,
+// just skips through the data looking for what we're interested in
+#define TAG_END 0
+#define TAG_BYTE 1
+#define TAG_SHORT 2
+#define TAG_INT 3
+#define TAG_LONG 4
+#define TAG_FLOAT 5
+#define TAG_DOUBLE 6
+#define TAG_BYTE_ARRAY 7
+#define TAG_STRING 8
+#define TAG_LIST 9
+#define TAG_COMPOUND 10
+#define TAG_INT_ARRAY 11
+
+// although tag names are UTF8, we'll just pretend they're ASCII--we don't really care about how the
+// actual string data breaks down into characters, as long as we know where the end of the string is
+void parseTypeAndName(const uint8_t*& ptr, uint8_t& type, string& name)
+{
+ type = *ptr;
+ ptr++;
+ if (type != TAG_END)
+ {
+ uint16_t len = fromBigEndian(*((uint16_t*)ptr));
+ name.resize(len);
+ copy(ptr + 2, ptr + 2 + len, name.begin());
+ ptr += 2 + len;
+ }
+}
+
+// structure for locating the block data for a 16x16x16 section--the compound tags on the "Sections" list will pass
+// this down to their immediate children, so they can fill in pointers to their payloads if appropriate
+// ...after the whole structure is parsed, the block data will be copied into the ChunkData
+// (note that we can't read the block data immediately upon finding it, because we have to know the Y value
+// for the section first, and the tags may appear in any order)
+struct chunkSection
+{
+ int y; // or -1 for "not found yet"
+ const uint8_t *blockIDs; // pointer into the file buffer, or NULL for "not found yet"
+ const uint8_t *blockData; // pointer into the file buffer, or NULL for "not found yet"
+ const uint8_t *blockAdd; // pointer into the file buffer, or NULL for "not found" (this one may not be present at all)
+
+ chunkSection() : y(-1), blockIDs(NULL), blockData(NULL), blockAdd(NULL) {}
+ bool complete() const {return y >= 0 && y < 16 && blockIDs != NULL && blockData != NULL;}
+
+ void extract(ChunkData& chunkdata) const
+ {
+ uint16_t* destination = chunkdata.blockIDs + (y * 4096);
+ for (unsigned i = 0; i < 4096; ++i)
+ {
+ uint16_t val = blockIDs[i];
+ if (blockAdd)
+ {
+ if (i % 2 == 0)
+ val |= (blockAdd[i / 2] & 0xf) << 8;
+ else
+ val |= (blockAdd[i / 2] & 0xf0) << 4;
+ }
+ destination[i] = val;
+ }
+ copy(blockData, blockData + 2048, chunkdata.blockData + (y * 2048));
+ }
+};
+
+bool isSection(const vector& names)
+{
+ return names.size() == 4 &&
+ names[3] == "" &&
+ names[2] == "Sections" &&
+ names[1] == "Level" &&
+ names[0] == "";
+}
+
+// if section != NULL, then the immediate parent of this tag is one of the compound tags in the "Sections"
+// list, so the block data tags will fill in their locations
+bool parsePayload(const uint8_t*& ptr, uint8_t type, vector& names, chunkSection *section, vector& completedSections)
+{
+ switch (type)
+ {
+ case TAG_END:
+ {
+ return true;
+ }
+ case TAG_BYTE:
+ {
+ if (section != NULL && names.back() == "Y")
+ section->y = *ptr;
+ ptr++;
+ return true;
+ }
+ case TAG_SHORT:
+ {
+ ptr += 2;
+ return true;
+ }
+ case TAG_INT:
+ case TAG_FLOAT:
+ {
+ ptr += 4;
+ return true;
+ }
+ case TAG_LONG:
+ case TAG_DOUBLE:
+ {
+ ptr += 8;
+ return true;
+ }
+ case TAG_BYTE_ARRAY:
+ {
+ uint32_t len = fromBigEndian(*((uint32_t*)ptr));
+ ptr += 4;
+ if (section != NULL)
+ {
+ if (names.back() == "Blocks" && len == 4096)
+ section->blockIDs = ptr;
+ else if (names.back() == "Data" && len == 2048)
+ section->blockData = ptr;
+ else if (names.back() == "Add" && len == 2048)
+ section->blockAdd = ptr;
+ }
+ ptr += len;
+ return true;
+ }
+ case TAG_INT_ARRAY:
+ {
+ uint32_t len = fromBigEndian(*((uint32_t*)ptr));
+ ptr += 4 + len*4;
+ return true;
+ }
+ case TAG_STRING:
+ {
+ uint16_t len = fromBigEndian(*((uint16_t*)ptr));
+ ptr += 2 + len;
+ return true;
+ }
+ case TAG_LIST:
+ {
+ uint8_t listtype = *ptr;
+ ptr++;
+ uint32_t len = fromBigEndian(*((uint32_t*)ptr));
+ ptr += 4;
+ stackPusher sp(names, "");
+ for (uint32_t i = 0; i < len; i++)
+ if (!parsePayload(ptr, listtype, names, NULL, completedSections))
+ return false;
+ return true;
+ }
+ case TAG_COMPOUND:
+ {
+ chunkSection section;
+ chunkSection *sectionPtr = isSection(names) ? §ion : NULL;
+
+ uint8_t nexttype;
+ string nextname;
+ parseTypeAndName(ptr, nexttype, nextname);
+ while (nexttype != TAG_END)
+ {
+ stackPusher sp(names, nextname);
+ if (!parsePayload(ptr, nexttype, names, sectionPtr, completedSections))
+ return false;
+ parseTypeAndName(ptr, nexttype, nextname);
+ }
+
+ if (sectionPtr != NULL)
+ {
+ if (section.complete())
+ completedSections.push_back(section);
+ else
+ {
+ cerr << "incomplete chunk section!" << endl;
+ return false;
+ }
+ }
+
+ return true;
+ }
+ default:
+ {
+ // unknown tag--since we have no idea how large it is, we must abort
+ cerr << "unknown NBT tag: type " << type << endl;
+ return false;
+ }
+ }
+ return false; // shouldn't be able to reach here
+}
+
+bool ChunkData::loadFromAnvilFile(const vector& filebuf)
+{
+ anvil = true;
+ fill(blockIDs, blockIDs + 65536, 0);
+ fill(blockData, blockData + 32768, 0);
+
+ const uint8_t *ptr = &(filebuf[0]);
+ uint8_t type;
+ string name;
+ parseTypeAndName(ptr, type, name);
+ if (type != TAG_COMPOUND || !name.empty())
+ {
+ cerr << "unrecognized NBT chunk file: top tag has type " << (int)type << " and name " << name << endl;
+ return false;
+ }
+
+ vector names(1, name);
+ vector completedSections;
+ if (!parsePayload(ptr, type, names, NULL, completedSections))
+ return false;
+
+ for (vector::const_iterator it = completedSections.begin(); it != completedSections.end(); it++)
+ it->extract(*this);
+
+ return true;
+}
+
+
+//---------------------------------------------------------------------------------------------------
+
+
+ChunkCacheStats& ChunkCacheStats::operator+=(const ChunkCacheStats& ccs)
+{
+ hits += ccs.hits;
+ misses += ccs.misses;
+ read += ccs.read;
+ skipped += ccs.skipped;
+ missing += ccs.missing;
+ reqmissing += ccs.reqmissing;
+ corrupt += ccs.corrupt;
+ return *this;
+}
+
+ChunkData* ChunkCache::getData(const PosChunkIdx& ci)
+{
+ int state = chunktable.getDiskState(ci);
+ if (state == ChunkSet::CHUNK_UNKNOWN)
+ stats.misses++;
+ else
+ stats.hits++;
+
+ // if the chunk is in the cache, return it
+ if (state == ChunkSet::CHUNK_CACHED)
+ {
+ int e = getEntryNum(ci);
+ ChunkCacheEntry& entry = entries[e];
+ if (entry.ci != ci)
+ {
+ cerr << "grievous chunk cache failure!" << endl;
+ cerr << "[" << ci.x << "," << ci.z << "] [" << entries[e].ci.x << "," << entries[e].ci.z << "]" << endl;
+ exit(-1);
+ }
+ return &entry.data;
+ }
+
+ // if we've already tried and failed to read the chunk, don't try again
+ if (state == ChunkSet::CHUNK_MISSING || state == ChunkSet::CHUNK_CORRUPTED)
+ return &blankdata;
+
+ // if this is a full render and the chunk is not required, we already know it doesn't exist
+ bool req = chunktable.isRequired(ci);
+ if (fullrender && !req)
+ {
+ stats.skipped++;
+ chunktable.setDiskState(ci, ChunkSet::CHUNK_MISSING);
+ return &blankdata;
+ }
+
+ // okay, we actually have to read the chunk from disk
+ if (regionformat)
+ readFromRegionCache(ci);
+ else
+ readChunkFile(ci);
+
+ // check whether the read succeeded; return the data if so
+ state = chunktable.getDiskState(ci);
+ if (state == ChunkSet::CHUNK_CORRUPTED)
+ {
+ stats.corrupt++;
+ return &blankdata;
+ }
+ if (state == ChunkSet::CHUNK_MISSING)
+ {
+ if (req)
+ stats.reqmissing++;
+ else
+ stats.missing++;
+ return &blankdata;
+ }
+ int e = getEntryNum(ci);
+ if (state != ChunkSet::CHUNK_CACHED || entries[e].ci != ci)
+ {
+ cerr << "grievous chunk cache failure!" << endl;
+ cerr << "[" << ci.x << "," << ci.z << "] [" << entries[e].ci.x << "," << entries[e].ci.z << "]" << endl;
+ exit(-1);
+ }
+ stats.read++;
+ return &entries[e].data;
+}
+
+void ChunkCache::readChunkFile(const PosChunkIdx& ci)
+{
+ // read the gzip file from disk, if it's there
+ string filename = inputpath + "/" + ci.toChunkIdx().toFilePath();
+ int result = readGzFile(filename, readbuf);
+ if (result == -1)
+ {
+ chunktable.setDiskState(ci, ChunkSet::CHUNK_MISSING);
+ return;
+ }
+ if (result == -2)
+ {
+ chunktable.setDiskState(ci, ChunkSet::CHUNK_CORRUPTED);
+ return;
+ }
+
+ // gzip read was successful; extract the data we need from the chunk
+ // and put it in the cache
+ parseReadBuf(ci, false);
+}
+
+void ChunkCache::readFromRegionCache(const PosChunkIdx& ci)
+{
+ // try to decompress the chunk data
+ bool anvil;
+ int result = regioncache.getDecompressedChunk(ci, readbuf, anvil);
+ if (result == -1)
+ {
+ chunktable.setDiskState(ci, ChunkSet::CHUNK_MISSING);
+ return;
+ }
+ if (result == -2)
+ {
+ chunktable.setDiskState(ci, ChunkSet::CHUNK_CORRUPTED);
+ return;
+ }
+
+ // decompression was successful; extract the data we need from the chunk
+ // and put it in the cache
+ parseReadBuf(ci, anvil);
+}
+
+void ChunkCache::parseReadBuf(const PosChunkIdx& ci, bool anvil)
+{
+ // evict current tenant of chunk's cache slot
+ int e = getEntryNum(ci);
+ if (entries[e].ci.valid())
+ chunktable.setDiskState(entries[e].ci, ChunkSet::CHUNK_UNKNOWN);
+ entries[e].ci = PosChunkIdx(-1,-1);
+ // ...and put this chunk's data into the slot, assuming the data can actually be parsed
+ bool result = anvil ? entries[e].data.loadFromAnvilFile(readbuf) : entries[e].data.loadFromOldFile(readbuf);
+ if (result)
+ {
+ entries[e].ci = ci;
+ chunktable.setDiskState(ci, ChunkSet::CHUNK_CACHED);
+ }
+ else
+ chunktable.setDiskState(ci, ChunkSet::CHUNK_CORRUPTED);
+}
diff --git a/chunk.h b/chunk.h
old mode 100755
new mode 100644
index 4c4764c..32668e2
--- a/chunk.h
+++ b/chunk.h
@@ -1,159 +1,149 @@
-// Copyright 2010-2012 Michael J. Nelson
-//
-// This file is part of pigmap.
-//
-// pigmap is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// pigmap is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with pigmap. If not, see .
-
-#ifndef CHUNK_H
-#define CHUNK_H
-
-#include
-#include
-#include
-#include
-
-#include "map.h"
-#include "tables.h"
-#include "region.h"
-
-
-
-// offset into a chunk of a block
-struct BlockOffset
-{
- int64_t x, z, y;
- BlockOffset(const BlockIdx& bi)
- {
- ChunkIdx ci = bi.getChunkIdx();
- x = bi.x - ci.x*16;
- z = bi.z - ci.z*16;
- y = bi.y;
- }
-};
-
-struct ChunkData
-{
- uint8_t blockIDs[65536]; // one byte per block (only half of this space used for old-style chunks)
- uint8_t blockAdd[32768]; // only in Anvil--extra bits for block ID (4 bits per block)
- uint8_t blockData[32768]; // 4 bits per block (only half of this space used for old-style chunks)
- bool anvil; // whether this data came from an Anvil chunk or an old-style one
-
- // these guys assume that the BlockIdx actually points to this chunk
- // (so they only look at the lower bits)
- uint16_t id(const BlockOffset& bo) const
- {
- if (!anvil)
- return (bo.y > 127) ? 0 : blockIDs[(bo.x * 16 + bo.z) * 128 + bo.y];
- int i = (bo.y * 16 + bo.z) * 16 + bo.x;
- if ((i % 2) == 0)
- return ((blockAdd[i/2] & 0xf) << 8) | blockIDs[i];
- return ((blockAdd[i/2] & 0xf0) << 4) | blockIDs[i];
- }
- uint8_t data(const BlockOffset& bo) const
- {
- int i;
- if (!anvil)
- {
- if (bo.y > 127)
- return 0;
- i = (bo.x * 16 + bo.z) * 128 + bo.y;
- }
- else
- i = (bo.y * 16 + bo.z) * 16 + bo.x;
- if ((i % 2) == 0)
- return blockData[i/2] & 0xf;
- return (blockData[i/2] & 0xf0) >> 4;
- }
-
- bool loadFromOldFile(const std::vector& filebuf);
- bool loadFromAnvilFile(const std::vector& filebuf);
-};
-
-
-
-struct ChunkCacheStats
-{
- int64_t hits, misses;
- // types of misses:
- int64_t read; // successfully read from disk
- int64_t skipped; // assumed not to exist because not required in a full render
- int64_t missing; // non-required chunk not present on disk
- int64_t reqmissing; // required chunk not present on disk
- int64_t corrupt; // found on disk, but failed to read
-
- // when in region mode, the miss stats have slightly different meanings:
- // read: chunk was successfully read from region cache (which may or may not have triggered an
- // actual read of the region file from disk)
- // missing: not present in the region file, or region file missing/corrupt
- // corrupt: region file itself is okay, but chunk data within it is corrupt
- // skipped/reqmissing: unused
-
- ChunkCacheStats() : hits(0), misses(0), read(0), skipped(0), missing(0), reqmissing(0), corrupt(0) {}
-
- ChunkCacheStats& operator+=(const ChunkCacheStats& ccs);
-};
-
-struct ChunkCacheEntry
-{
- PosChunkIdx ci; // or [-1,-1] if this entry is empty
- ChunkData data;
-
- ChunkCacheEntry() : ci(-1,-1) {}
-};
-
-#define CACHEBITSX 5
-#define CACHEBITSZ 5
-#define CACHEXSIZE (1 << CACHEBITSX)
-#define CACHEZSIZE (1 << CACHEBITSZ)
-#define CACHESIZE (CACHEXSIZE * CACHEZSIZE)
-#define CACHEXMASK (CACHEXSIZE - 1)
-#define CACHEZMASK (CACHEZSIZE - 1)
-
-struct ChunkCache : private nocopy
-{
- ChunkCacheEntry entries[CACHESIZE];
- ChunkData blankdata; // for use with missing chunks
-
- ChunkTable& chunktable;
- RegionTable& regiontable;
- ChunkCacheStats& stats;
- RegionCache& regioncache;
- std::string inputpath;
- bool fullrender;
- bool regionformat;
- std::vector readbuf; // buffer for decompressing into when reading
- ChunkCache(ChunkTable& ctable, RegionTable& rtable, RegionCache& rcache, const std::string& inpath, bool fullr, bool regform, ChunkCacheStats& st)
- : chunktable(ctable), regiontable(rtable), regioncache(rcache), inputpath(inpath), fullrender(fullr), regionformat(regform), stats(st)
- {
- memset(blankdata.blockIDs, 0, 65536);
- memset(blankdata.blockData, 0, 32768);
- memset(blankdata.blockAdd, 0, 32768);
- blankdata.anvil = true;
- readbuf.reserve(262144);
- }
-
- // look up a chunk and return a pointer to its data
- // ...for missing/corrupt chunks, return a pointer to some blank data
- ChunkData* getData(const PosChunkIdx& ci);
-
- static int getEntryNum(const PosChunkIdx& ci) {return (ci.x & CACHEXMASK) * CACHEZSIZE + (ci.z & CACHEZMASK);}
-
- void readChunkFile(const PosChunkIdx& ci);
- void readFromRegionCache(const PosChunkIdx& ci);
- void parseReadBuf(const PosChunkIdx& ci, bool anvil);
-};
-
-
-
+// Copyright 2010-2012 Michael J. Nelson
+//
+// This file is part of pigmap.
+//
+// pigmap is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// pigmap is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with pigmap. If not, see .
+
+#ifndef CHUNK_H
+#define CHUNK_H
+
+#include
+#include
+#include
+#include
+#include
+
+#include "map.h"
+#include "tables.h"
+#include "region.h"
+
+
+
+// offset into a chunk of a block
+struct BlockOffset
+{
+ int64_t x, z, y;
+ BlockOffset(const BlockIdx& bi)
+ {
+ ChunkIdx ci = bi.getChunkIdx();
+ x = bi.x - ci.x*16;
+ z = bi.z - ci.z*16;
+ y = bi.y;
+
+ assert(x >= 0 && x < 16);
+ assert(y >= 0 && y < 256);
+ assert(z >= 0 && z < 16);
+ }
+};
+
+struct ChunkData
+{
+ uint16_t blockIDs[65536]; // 8 bits in mcr format, 12 in anvil - use 16 for fast access, transform on load.
+ uint8_t blockData[32768]; // 4 bits per block (only half of this space used for old-style chunks)
+ bool anvil; // whether this data came from an Anvil chunk or an old-style one
+
+ // these guys assume that the BlockIdx actually points to this chunk
+ // (so they only look at the lower bits)
+ uint16_t id(const BlockOffset& bo) const
+ {
+ return blockIDs[(bo.y * 16 + bo.z) * 16 + bo.x];
+ }
+ uint8_t data(const BlockOffset& bo) const
+ {
+ int i = (bo.y * 16 + bo.z) * 16 + bo.x;
+ if ((i % 2) == 0)
+ return blockData[i/2] & 0xf;
+ return (blockData[i/2] & 0xf0) >> 4;
+ }
+
+ bool loadFromOldFile(const std::vector& filebuf);
+ bool loadFromAnvilFile(const std::vector& filebuf);
+};
+
+
+
+struct ChunkCacheStats
+{
+ int64_t hits, misses;
+ // types of misses:
+ int64_t read; // successfully read from disk
+ int64_t skipped; // assumed not to exist because not required in a full render
+ int64_t missing; // non-required chunk not present on disk
+ int64_t reqmissing; // required chunk not present on disk
+ int64_t corrupt; // found on disk, but failed to read
+
+ // when in region mode, the miss stats have slightly different meanings:
+ // read: chunk was successfully read from region cache (which may or may not have triggered an
+ // actual read of the region file from disk)
+ // missing: not present in the region file, or region file missing/corrupt
+ // corrupt: region file itself is okay, but chunk data within it is corrupt
+ // skipped/reqmissing: unused
+
+ ChunkCacheStats() : hits(0), misses(0), read(0), skipped(0), missing(0), reqmissing(0), corrupt(0) {}
+
+ ChunkCacheStats& operator+=(const ChunkCacheStats& ccs);
+};
+
+struct ChunkCacheEntry
+{
+ PosChunkIdx ci; // or [-1,-1] if this entry is empty
+ ChunkData data;
+
+ ChunkCacheEntry() : ci(-1,-1) {}
+};
+
+#define CACHEBITSX 5
+#define CACHEBITSZ 5
+#define CACHEXSIZE (1 << CACHEBITSX)
+#define CACHEZSIZE (1 << CACHEBITSZ)
+#define CACHESIZE (CACHEXSIZE * CACHEZSIZE)
+#define CACHEXMASK (CACHEXSIZE - 1)
+#define CACHEZMASK (CACHEZSIZE - 1)
+
+struct ChunkCache : private nocopy
+{
+ ChunkCacheEntry entries[CACHESIZE];
+ ChunkData blankdata; // for use with missing chunks
+
+ ChunkTable& chunktable;
+ RegionTable& regiontable;
+ ChunkCacheStats& stats;
+ RegionCache& regioncache;
+ std::string inputpath;
+ bool fullrender;
+ bool regionformat;
+ std::vector readbuf; // buffer for decompressing into when reading
+ ChunkCache(ChunkTable& ctable, RegionTable& rtable, RegionCache& rcache, const std::string& inpath, bool fullr, bool regform, ChunkCacheStats& st)
+ : chunktable(ctable), regiontable(rtable), stats(st), regioncache(rcache), inputpath(inpath), fullrender(fullr), regionformat(regform)
+ {
+ memset(blankdata.blockIDs, 0, 65536 * 2);
+ memset(blankdata.blockData, 0, 32768);
+ blankdata.anvil = true;
+ readbuf.reserve(262144);
+ }
+
+ // look up a chunk and return a pointer to its data
+ // ...for missing/corrupt chunks, return a pointer to some blank data
+ ChunkData* getData(const PosChunkIdx& ci);
+
+ static int getEntryNum(const PosChunkIdx& ci) {return (ci.x & CACHEXMASK) * CACHEZSIZE + (ci.z & CACHEZMASK);}
+
+ void readChunkFile(const PosChunkIdx& ci);
+ void readFromRegionCache(const PosChunkIdx& ci);
+ void parseReadBuf(const PosChunkIdx& ci, bool anvil);
+};
+
+
+
#endif // CHUNK_H
\ No newline at end of file
diff --git a/endportal.png b/endportal.png
deleted file mode 100644
index 5d1cd4a..0000000
Binary files a/endportal.png and /dev/null differ
diff --git a/fire.png b/fire.png
deleted file mode 100755
index f230f96..0000000
Binary files a/fire.png and /dev/null differ
diff --git a/map.cpp b/map.cpp
old mode 100755
new mode 100644
index efd857a..076f213
--- a/map.cpp
+++ b/map.cpp
@@ -1,348 +1,341 @@
-// Copyright 2010-2012 Michael J. Nelson
-//
-// This file is part of pigmap.
-//
-// pigmap is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// pigmap is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with pigmap. If not, see .
-
-#include
-#include