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..51033ff 100644
--- a/README
+++ b/README
@@ -40,6 +40,24 @@ Use supplied makefile to build with g++.
Change log (important stuff only):
+%LATEST_VERSION%
+-new block up to Minecraft 1.6 13w18c snapshot
+-new textures should be added to image folder (or updated):
+ textures/blocks/blockCoal.png
+ textures/blocks/blockLapis.png
+ textures/blocks/clayHardened.png
+ textures/blocks/clayHardenedStained_[0-15].png
+ textures/blocks/hayBlock.png
+ textures/blocks/hayBlock_top.png
+
+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
-chest.png, etc. now required
@@ -116,7 +134,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 +142,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 +186,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 (texture/ 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.
@@ -187,22 +205,29 @@ This means that pigmap will need your tileset the first time it runs, so it can
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).
-
-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.
+The generate blocks-B.pngi, extract the item/ and textures/ folder of your minecraft.jar into the folder you have specified.
+All of these must be RGBA png files (not just RGB). So check the alpha channels, if one file is not recognized. From minecraft version 1.5 it is known that the lava.png is missing an alpha channel. You can simply add one by using tools like GIMP.
-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:
@@ -312,4 +337,4 @@ 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
+ascending tracks: 88->200, 89->201, 90->202, 91->203
diff --git a/blockdescriptor.list b/blockdescriptor.list
new file mode 100644
index 0000000..3fbdce0
--- /dev/null
+++ b/blockdescriptor.list
@@ -0,0 +1,214 @@
+# 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 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 spaced based on group name, O - each orientation is stored in order of group appearance), then list of groups with flag (if this data group should be oriented), top texture, side texture; like wood 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 if list of textures is not full (up to 16), it will "tile" existing data over remaining bits)
+# 16 MULTIITEMDATA (list textures for each data bit; like nether wart)
+# 17 STAIR (list textures for: side, top OR side (if all faces has the same texture); stairs in all it's glory)
+# 18 FENCE (specify base texture; like fence, nether brick fence)
+# 19 WALLDATA (specify base texture for each data bit; like cobblestone wall, mossy cobblestone wall)
+# 20 FENCEGATE (specify base texture for fence gate; like fence gate)
+# 21 MUSHROOM (specify pore, stem, cap textures; like huge brown / red mushrooms)
+# 22 CHEST (specify chest texture, large chest texture(don't specify it, if chest is not double chest); like chest, ender chest, trapped chest)
+# 23 RAIL (specify rail texture, corner texture(for cornered tracks); like rails, detector rails)
+# 24 RAILPOWERED (specify rail texture(off), rail texture(on); like powered rails, activator rails)
+# 25 PANEDATA (specify base texture for each data bit; like iron bars, glass pane)
+# 26 DOOR (specify textures for lower and bottom part of the classic 2x1 door; like wooden door, iron door)
+# 27 TRAPDOOR (specify texture for trap door
+# 28 TORCH (specify base texture of the torch; like torches, redstone torches)
+# 29 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)
+# 30 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)
+# 31 WIRE (specify wire texture, wire crossing texture (if any); like redstone wire, tripwire)
+# 32 BITANCHOR (specify face texture; draws faces anchored to different block side for each data bit combination; like vines)
+# 33 STEM (specify straight stem texture, bent stem texture; like pumpkin stem, melon stem)
+# 34 LEVER (specify lever base texture, lever handle texture; like lever)
+# 35 SIGNPOST (specify sign base texture, sign pole texture; like sign post)
+# 36 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 SOLID stone
+2 SOLID grass_side grass_side grass_top
+3 SOLID dirt
+4 SOLID stonebrick #cobblestone
+5 SOLIDDATA wood wood_spruce wood_birch wood_jungle # oak / spruce / birch / jungle planks
+6 ITEMDATAFILL sapling sapling_spruce sapling_birch sapling_jungle #sapling
+7 SOLID bedrock
+8 SPECIAL water
+##9 - skip, it's water too
+10 SPECIAL lava
+##11 - skip, it's lava too
+12 SOLID sand
+13 SOLID gravel
+14 SOLID oreGold
+15 SOLID oreIron
+16 SOLID oreCoal
+17 SOLIDDATATRUNKROTATED S 1 tree_top tree_side 1 tree_top tree_spruce 1 tree_top tree_birch 1 tree_top tree_jungle # oak / spruce / birch / jungle wood
+18 SOLIDDATAFILL leaves leaves_spruce leaves_birch leaves_jungle # oak / spruce / birch / jungle leaves
+19 SOLID sponge
+20 SOLID glass
+21 SOLID oreLapis
+22 SOLID blockLapis
+23 SOLIDORIENTED 2 3 4 5 dispenser_front furnace_side furnace_top #dispenser
+24 SOLIDDATATRUNK sandstone_top sandstone_side sandstone_top sandstone_carved sandstone_top sandstone_smooth #sandstone
+25 SOLID musicBlock #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 goldenRail goldenRail_powered #powered rail
+28 RAIL detectorRail #detector rail
+29 SOLIDROTATED 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 piston_top piston_side piston_bottom #piston
+##34 technical block
+35 SOLIDDATA cloth_0 cloth_1 cloth_2 cloth_3 cloth_4 cloth_5 cloth_6 cloth_7 cloth_8 cloth_9 cloth_10 cloth_11 cloth_12 cloth_13 cloth_14 cloth_15 #wool
+##36 technical block
+37 ITEMDATA flower #dandelion
+38 ITEMDATA rose #rose
+39 ITEMDATA mushroom_brown
+40 ITEMDATA mushroom_red
+41 SOLID blockGold
+42 SOLID blockIron
+43 SOLIDDATATRUNK stoneslab_top stoneslab_side sandstone_top sandstone_side wood wood stonebrick stonebrick brick brick stonebricksmooth stonebricksmooth netherBrick netherBrick #double slabs
+44 SLABDATATRUNK stoneslab_top stoneslab_side sandstone_top sandstone_side wood wood stonebrick stonebrick brick brick stonebricksmooth stonebricksmooth netherBrick netherBrick #slabs
+45 SOLID brick
+46 SOLID tnt_side tnt_side tnt_top #tnt
+47 SOLID bookshelf bookshelf wood #bookshelf
+48 SOLID stoneMoss
+49 SOLID obsidian
+50 TORCH torch
+51 SOLIDTRANSPARENT / fire_0 fire_0 fire_0 fire_0 / #fire
+52 SOLID mobSpawner
+53 STAIR wood #oak wood stairs
+54 CHEST /chest /largechest #chest
+55 WIRE redstoneDust_line redstoneDust_cross #redstone wire
+56 SOLID oreDiamond
+57 SOLID blockDiamond
+58 SOLID workbench_front workbench_side workbench_top #workbench
+59 ITEMDATA crops_0 crops_1 crops_2 crops_3 crops_4 crops_5 crops_6 crops_7 #wheat
+60 SOLID dirt dirt farmland_dry #farmland
+61 SOLIDORIENTED 2 3 4 5 furnace_front furnace_side furnace_top #furnace
+62 SOLIDORIENTED 2 3 4 5 furnace_front_lit furnace_side furnace_top #burning furnace
+63 SIGNPOST wood wood #sign post
+64 DOOR doorWood_lower doorWood_upper #wooden door
+65 ONWALLPARTIALFILL 3 2 5 4 ladder 0 0 0 0 #ladder
+66 RAIL rail rail_turn #rails
+67 STAIR stonebrick #cobblestone stairs
+68 ONWALLPARTIALFILL 3 2 5 4 wood 4 4 0 0 #wall sign
+69 LEVER stonebrick lever
+70 SOLIDPARTIAL 14 0 stone stone stone #stone pressure plate
+71 DOOR doorIron_lower doorIron_upper #iron door
+72 SOLIDPARTIAL 14 0 wood wood wood #wooden pressure plate
+73 SOLID oreRedstone
+74 SOLID oreRedstone #glowing
+75 TORCH redtorch
+76 TORCH redtorch_lit
+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 musicBlock musicBlock jukebox_top #jukebox
+85 FENCE wood #fence
+86 SOLIDORIENTED 2 0 1 3 pumpkin_face pumpkin_side pumpkin_top #pumpkin
+87 SOLID hellrock #netherrack
+88 SOLID hellsand #soul sand
+89 SOLID lightgem #glowstone block
+90 SOLID portal #nether portal
+91 SOLIDORIENTED 2 0 1 3 pumpkin_jack pumpkin_side pumpkin_top #jack 'o' lantern
+92 SOLIDPARTIAL 8 0 cake_side cake_side cake_top #cake
+93 REPEATER repeater redtorch #repeater inactive
+94 REPEATER repeater_lit redtorch_lit #repeater active
+##95 locked chest isn't actually in a game
+96 TRAPDOOR trapdoor
+97 SOLIDDATA stone stonebrick stonebricksmooth # smooth / cobblestone / stone brick monster egg
+98 SOLIDDATA stonebricksmooth stonebricksmooth_mossy stonebricksmooth_cracked stonebricksmooth_carved # normal / mossy / cracked / chiseled stone bricks
+99 MUSHROOM mushroom_inside mushroom_skin_stem mushroom_skin_brown #huge brown mushroom
+100 MUSHROOM mushroom_inside mushroom_skin_stem mushroom_skin_red #huge red mushroom
+101 PANEDATA fenceIron #iron bars
+102 PANEDATA glass #glass pane
+103 SOLID melon_side melon_side melon_top #melon
+104 STEM /stem_straight /stem_bent #pumpkin stem
+105 STEM /stem_straight /stem_bent #melon stem
+106 BITANCHOR vine #vines
+107 FENCEGATE wood #fence gate
+108 STAIR brick #brick stairs
+109 STAIR stonebricksmooth #stone brick stairs
+110 SOLID mycel_side mycel_side mycel_top #mycelium
+111 SOLIDPARTIAL 16 0 / / waterlily #lily pad
+112 SOLID netherBrick
+113 FENCE netherBrick #nether brick fence
+114 STAIR netherBrick #nether brick stairs
+115 MULTIITEMDATA netherStalk_0 netherStalk_1 netherStalk_1 netherStalk_2 #nether wart
+116 SOLIDPARTIAL 4 0 enchantment_side enchantment_side enchantment_top #enchantment table
+117 SPECIAL brewingStand_base brewingStand #brewing stand
+118 SPECIAL cauldron_side water #cauldron
+119 SOLIDPARTIAL 4 0 / / endportal #end portal
+120 SOLIDPARTIAL 3 0 endframe_side endframe_side endframe_top #end portal frame
+121 SOLID whiteStone #endstone
+122 SPECIAL dragonEgg #dragon egg
+# 1.2
+123 SOLID redstoneLight
+124 SOLID redstoneLight_lit
+# 1.3
+125 SOLIDDATA wood wood_spruce wood_birch wood_jungle #wooden double slabs
+126 SLABDATA wood wood_spruce wood_birch wood_jungle #wooden slabs
+127 ITEMDATAORIENTED 0 2 3 1 cocoa_0 cocoa_1 cocoa_2 #cocoa pods
+128 STAIR sandstone_side sandstone_top #sandstone stairs
+129 SOLID oreEmerald
+130 CHEST /enderchest #enderchest
+131 ONWALLPARTIALFILL 0 2 3 1 tripWireSource 0 0 0 0 #tripwire hook
+132 WIRE tripWire #tripwire
+133 SOLID blockEmerald
+134 STAIR wood_spruce #spruce wood stairs
+135 STAIR wood_birch #birch wood stairs
+136 STAIR wood_jungle #jungle wood stairs
+# 1.4
+137 SOLID commandBlock
+138 SPECIAL beacon obsidian 20 #beacon
+139 WALLDATA stonebrick stoneMoss #cobblestone / mossy cobblestone wall
+140 SPECIAL flowerPot dirt rose flower sapling sapling_spruce sapling_birch sapling_jungle mushroom_red mushroom_brown cactus_side deadbush fern #flower pot
+141 MULTIITEMDATA carrots_0 carrots_0 carrots_1 carrots_1 carrots_2 carrots_2 carrots_2 carrots_3 #carrots
+142 MULTIITEMDATA potatoes_0 potatoes_0 potatoes_1 potatoes_1 potatoes_2 potatoes_2 potatoes_2 potatoes_3 #potatoes
+143 ONWALLPARTIALFILL 3 4 1 2 wood 6 6 5 5 #wooden button
+##144 mob heads
+145 SPECIAL anvil_base anvil_top anvil_top_damaged_1 anvil_top_damaged_2 #anvil
+# 1.5
+146 CHEST /trap_small /trap_large #trapped chest
+147 SOLIDPARTIAL 14 0 blockGold blockGold blockGold #weighted pressure plate (light)
+148 SOLIDPARTIAL 14 0 blockIron blockIron blockIron #weighted pressure plate (heavy)
+149 REPEATER comparator redtorch #repeater inactive
+150 REPEATER comparator_lit redtorch_lit #repeater active
+151 SOLIDPARTIAL 10 0 daylightDetector_side daylightDetector_side daylightDetector_top #daylight sensor
+152 SOLID blockRedstone
+153 SOLID netherquartz
+154 SPECIAL hopper hopper_inside hopper_top #hopper
+155 SOLIDDATATRUNKROTATED O 0 quartzblock_top quartzblock_side 0 quartzblock_chiseled_top quartzblock_chiseled 1 quartzblock_lines_top quartzblock_lines #block of quartz
+156 STAIR quartzblock_side quartzblock_top #quartz stairs
+157 RAILPOWERED activatorRail activatorRail_powered #activator rail
+158 SOLIDORIENTED 2 3 4 5 dropper_front furnace_side furnace_top #dropper
+# 1.6
+159 SOLIDDATA clayHardenedStained_0 clayHardenedStained_1 clayHardenedStained_2 clayHardenedStained_3 clayHardenedStained_4 clayHardenedStained_5 clayHardenedStained_6 clayHardenedStained_7 clayHardenedStained_8 clayHardenedStained_9 clayHardenedStained_10 clayHardenedStained_11 clayHardenedStained_12 clayHardenedStained_13 clayHardenedStained_14 clayHardenedStained_15 #stained hardened clay
+##169-169 unused
+170 SOLIDDATATRUNKROTATED S 1 hayBlock_top hayBlock 1 hayBlock_top hayBlock 1 hayBlock_top hayBlock 1 hayBlock_top hayBlock #hay block
+171 SOLIDDATAPARTIAL 15 0 cloth_0 cloth_1 cloth_2 cloth_3 cloth_4 cloth_5 cloth_6 cloth_7 cloth_8 cloth_9 cloth_10 cloth_11 cloth_12 cloth_13 cloth_14 cloth_15 #carpet
+172 SOLID clayHardened
+173 SOLID blockCoal
\ No newline at end of file
diff --git a/blockimages.cpp b/blockimages.cpp
old mode 100755
new mode 100644
index d9697c1..d68fa8d
--- a/blockimages.cpp
+++ b/blockimages.cpp
@@ -1,2785 +1,3205 @@
-// 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 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 == 5)
+ {
+ // piston value order: down / top / N / S / W / E
+ // piston extension bit: 0x8 (top bit)
+ setOffsetsForID(blockid, offsetIterator, *this);
+ 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(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;
+ int groupSize = (descriptorsize - 3)/3;
+ 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 + groupSize)] = ++offsetIterator; // trunk EW
+ blockOffsets[offsetIdx(blockid, j + 2*groupSize)] = ++offsetIterator; // trunk NS
+ }
+ }
+ 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 > 2)
+ {
+ int datasize = descriptorsize - 2;
+ for(int i = 0; i < datasize; i++, offsetIterator++)
+ {
+ for(int di = i; di < 16; di += datasize)
+ blockOffsets[offsetIdx(blockid, di)] = offsetIterator;
+ }
+ 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")
+ {
+ 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
+ for(int i = 0; i < descriptorsize - 4; i++)
+ blockOffsets[offsetIdx(blockid, i)] = ++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
+ }
+ 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 << "[blocktexture.list]" << textureiterator + 1 << " - " << blocktexturespath << "/" << textureDirectives[1] << " is missing or invalid (check, if it has an alpha channel!)" << 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 xExpansion = (fromstring(textureDirectives[++i], xExpansion)) ? xExpansion % 17 : 0;
+ int yExpansion = (fromstring(textureDirectives[++i], yExpansion)) ? yExpansion % 17 : 0;
+ resize(iblockimage, ImageRect(CUTOFFS_16[xExpansion], CUTOFFS_16[yExpansion], iblockimage.w - 2 * CUTOFFS_16[xExpansion], iblockimage.h - 2 * CUTOFFS_16[yExpansion]), 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] == "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 << "[texture.list]" << textureiterator + 1 << " - " << blocktexturespath << "/" << textureDirectives[0] << " is missing or invalid" << 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 == 5)
+ {
+ // piston value order: down / top / N / S / W / E
+ // piston extension bit: 0x8 (top bit)
+ // texture order: top side bottom - descriptor[2 3 4]
+ RGBAImage& topface = blockTextures.at((descriptor[2] + ".png"));
+ RGBAImage& sideface = blockTextures.at((descriptor[3] + ".png"));
+ RGBAImage& bottomface = blockTextures.at((descriptor[4] + ".png"));
+ 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(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;
+
+ 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
+ }
+ }
+ 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" || descriptor[1] == "ITEMDATAFILL")
+ {
+ 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] == "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[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] == "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;
+ if(descriptorsize == 3)
+ {
+ sideface = topface = blockTextures.at((descriptor[2] + ".png"));
+
+ }
+ else if(descriptorsize > 3)
+ {
+ sideface = blockTextures.at((descriptor[2] + ".png"));
+ topface = blockTextures.at((descriptor[3] + ".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, topface, B); // stairs asc E inverted
+ drawInvStairsW(img, getRect(++offsetIterator), sideface, topface, B); // stairs asc W inverted
+ drawInvStairsS(img, getRect(++offsetIterator), sideface, topface, B); // stairs asc S inverted
+ drawInvStairsN(img, getRect(++offsetIterator), sideface, topface, 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[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[descriptor[2] + ".png"];
+ if(descriptorsize == 4)
+ {
+ wireCross = blockTextures[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[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[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
+ }
+ 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)
+ {
+ drawHopper(img, getRect(offsetIterator), blockTextures.at((descriptor[2] + ".png")), blockTextures.at((descriptor[3] + ".png")), B); // hopper
+ }
+ 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..f783775
--- /dev/null
+++ b/blocktextures.list
@@ -0,0 +1,337 @@
+# 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 be untouched.
+# If you do so, you can use a couple of directive after a texture name.
+# !!!NOTE!!! Directive 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 texture by a specified amount by resizing it. Using this directive results in new texture. Use this directive before other directives.
+# =Example=
+# / cake_top.png EXPAND 1 1
+# - 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
+# - 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
+activatorRail.png
+activatorRail_powered.png
+anvil_base.png
+anvil_top.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
+blockCoal.png
+blockDiamond.png
+blockEmerald.png
+blockGold.png
+blockIron.png
+blockLapis.png
+blockRedstone.png
+bookshelf.png
+brewingStand.png
+brewingStand_base.png
+brick.png
+/ cactus_bottom.png EXPAND 1 1
+/ cactus_side.png EXPAND 1 1
+/ cactus_top.png EXPAND 1 1
+/ cake_bottom.png EXPAND 1 1
+/ cake_inner.png EXPAND 1 1
+/ cake_side.png EXPAND 1 1
+/ cake_top.png EXPAND 1 1
+carrots_0.png
+carrots_1.png
+carrots_2.png
+carrots_3.png
+cauldron_bottom.png
+cauldron_inner.png
+cauldron_side.png
+cauldron_top.png
+clay.png
+clayHardened.png
+clayHardenedStained_0.png
+clayHardenedStained_1.png
+clayHardenedStained_2.png
+clayHardenedStained_3.png
+clayHardenedStained_4.png
+clayHardenedStained_5.png
+clayHardenedStained_6.png
+clayHardenedStained_7.png
+clayHardenedStained_8.png
+clayHardenedStained_9.png
+clayHardenedStained_10.png
+clayHardenedStained_11.png
+clayHardenedStained_12.png
+clayHardenedStained_13.png
+clayHardenedStained_14.png
+clayHardenedStained_15.png
+cloth_0.png
+cloth_1.png
+cloth_10.png
+cloth_11.png
+cloth_12.png
+cloth_13.png
+cloth_14.png
+cloth_15.png
+cloth_2.png
+cloth_3.png
+cloth_4.png
+cloth_5.png
+cloth_6.png
+cloth_7.png
+cloth_8.png
+cloth_9.png
+cocoa_0.png
+cocoa_1.png
+cocoa_2.png
+commandBlock.png
+comparator.png
+comparator_lit.png
+crops_0.png
+crops_1.png
+crops_2.png
+crops_3.png
+crops_4.png
+crops_5.png
+crops_6.png
+crops_7.png
+daylightDetector_side.png
+daylightDetector_top.png
+deadbush.png
+destroy_0.png
+destroy_1.png
+destroy_2.png
+destroy_3.png
+destroy_4.png
+destroy_5.png
+destroy_6.png
+destroy_7.png
+destroy_8.png
+destroy_9.png
+detectorRail.png
+dirt.png
+dispenser_front.png
+doorIron_lower.png
+doorIron_upper.png
+doorWood_lower.png
+doorWood_upper.png
+dragonEgg.png
+dropper_front.png
+enchantment_bottom.png
+enchantment_side.png
+enchantment_top.png
+endframe_eye.png
+endframe_side.png
+endframe_top.png
+farmland_dry.png
+farmland_wet.png
+fenceIron.png
+/ fern.png DARKEN 0.6 0.95 0.3
+fire_0.png
+fire_1.png
+flower.png
+flowerPot.png
+furnace_front.png
+furnace_front_lit.png
+furnace_side.png
+furnace_top.png
+glass.png
+goldenRail.png
+goldenRail_powered.png
+grass_side.png
+grass_side_overlay.png
+/ grass_top.png DARKEN 0.6 0.95 0.3
+gravel.png
+hayBlock.png
+hayBlock_top.png
+hellrock.png
+hellsand.png
+hopper.png
+hopper_inside.png
+hopper_top.png
+ice.png
+itemframe_back.png
+jukebox_top.png
+ladder.png
+lava.png
+/ leaves.png DARKEN 0.3 1.0 0.1
+#/ leaves_opaque.png DARKEN 0.3 1.0 0.1
+/ leaves.png RENAME leaves_birch.png DARKEN 0.55 0.9 0.1
+/ leaves_jungle.png DARKEN 0.35, 1.0, 0.05
+#/ leaves_jungle_opaque.png DARKEN 0.35, 1.0, 0.05
+/ leaves_spruce.png DARKEN 0.3 1.0 0.45
+#/ leaves_spruce_opaque.png DARKEN 0.3 1.0 0.45
+lever.png
+lightgem.png
+melon_side.png
+melon_top.png
+mobSpawner.png
+mushroom_brown.png
+mushroom_inside.png
+mushroom_red.png
+mushroom_skin_brown.png
+mushroom_skin_red.png
+mushroom_skin_stem.png
+musicBlock.png
+mycel_side.png
+mycel_top.png
+netherBrick.png
+netherStalk_0.png
+netherStalk_1.png
+netherStalk_2.png
+netherquartz.png
+obsidian.png
+oreCoal.png
+oreDiamond.png
+oreEmerald.png
+oreGold.png
+oreIron.png
+oreLapis.png
+oreRedstone.png
+piston_bottom.png
+piston_inner_top.png
+piston_side.png
+piston_top.png
+piston_top_sticky.png
+portal.png
+potatoes_0.png
+potatoes_1.png
+potatoes_2.png
+potatoes_3.png
+pumpkin_face.png
+pumpkin_jack.png
+pumpkin_side.png
+pumpkin_top.png
+quartzblock_bottom.png
+quartzblock_chiseled.png
+quartzblock_chiseled_top.png
+quartzblock_lines.png
+quartzblock_lines_top.png
+quartzblock_side.png
+quartzblock_top.png
+rail.png
+rail_turn.png
+/ redstoneDust_cross.png DARKEN 0.9 0.1 0.1
+#redstoneDust_cross_overlay.png
+/ redstoneDust_line.png DARKEN 0.9 0.1 0.1
+#redstoneDust_line_overlay.png
+redstoneLight.png
+redstoneLight_lit.png
+redtorch.png
+redtorch_lit.png
+reeds.png
+repeater.png
+repeater_lit.png
+results.png
+rose.png
+sand.png
+sandstone_bottom.png
+sandstone_carved.png
+sandstone_side.png
+sandstone_smooth.png
+sandstone_top.png
+sapling.png
+sapling_birch.png
+sapling_jungle.png
+sapling_spruce.png
+snow.png
+snow_side.png
+sponge.png
+/ stem_bent.png RENAME /stem_bent.png_0 DARKEN 0.75 0.6 0.3
+/ stem_bent.png RENAME /stem_bent.png_1 DARKEN 0.75 0.6 0.3 FLIPX
+/ stem_straight.png RENAME /stem_straight.png_0 DARKEN 0.45 0.95 0.4 OFFSET 0 14
+/ stem_straight.png RENAME /stem_straight.png_1 DARKEN 0.45 0.95 0.4 OFFSET 0 12
+/ stem_straight.png RENAME /stem_straight.png_2 DARKEN 0.45 0.95 0.4 OFFSET 0 10
+/ stem_straight.png RENAME /stem_straight.png_3 DARKEN 0.45 0.95 0.4 OFFSET 0 8
+/ stem_straight.png RENAME /stem_straight.png_4 DARKEN 0.45 0.95 0.4 OFFSET 0 6
+/ stem_straight.png RENAME /stem_straight.png_5 DARKEN 0.45 0.95 0.4 OFFSET 0 4
+/ stem_straight.png RENAME /stem_straight.png_6 DARKEN 0.45 0.95 0.4 OFFSET 0 2
+/ stem_straight.png RENAME /stem_straight.png_7 DARKEN 0.75 0.6 0.3
+stone.png
+stoneMoss.png
+stonebrick.png
+stonebricksmooth.png
+stonebricksmooth_carved.png
+stonebricksmooth_cracked.png
+stonebricksmooth_mossy.png
+stoneslab_side.png
+stoneslab_top.png
+/ tallgrass.png DARKEN 0.6 0.95 0.3
+thinglass_top.png
+tnt_bottom.png
+tnt_side.png
+tnt_top.png
+torch.png
+trapdoor.png
+tree_birch.png
+tree_jungle.png
+tree_side.png
+tree_spruce.png
+tree_top.png
+/ tripWire.png OFFSET 0 6
+tripWireSource.png
+/ vine.png DARKEN 0.35 1.0 0.15
+water.png
+/ waterlily.png DARKEN 0.3 0.95 0.3
+web.png
+whiteStone.png
+wood.png
+wood_birch.png
+wood_jungle.png
+wood_spruce.png
+workbench_front.png
+workbench_side.png
+workbench_top.png
+$ /item
+/ chest.png CHEST
+/ largechest.png LCHEST
+/ enderchest.png CHEST
+$ /item/chests
+/ trap_small.png CHEST
+/ trap_large.png LCHEST
+$ /
+endportal.png
\ No newline at end of file
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/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