Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
944 lines (817 sloc) 45.8 KB
module brala.dine.builder.builder;
private {
import brala.gfx.data : Vertex;
import brala.dine.chunk : Block;
import brala.dine.builder.constants : Side, Facing;
}
public {
import std.array : array, join;
import std.algorithm : map, canFind;
import std.functional : memoize;
import std.typetuple : TypeTuple;
import std.conv : to;
import std.string : format;
import brala.gfx.terrain : ProjectionTextureCoordinates;
import brala.dine.builder.blocks : BLOCKS, BlockDescriptor;
import brala.dine.builder.biomes : BiomeData, Color3;
import brala.dine.builder.vertices;
import brala.utils.ctfe : TupleRange;
}
protected {
template WoolPair(byte xi, byte yi) {
enum x = xi;
enum y = yi;
}
}
mixin template BlockBuilder() {
void add_template_vertices(T : Vertex)(const auto ref T[] vertices,
const Block block,
float x_offset, float y_offset, float z_offset,
ubyte r=0xff, ubyte g=0xff, ubyte b=0xff)
in { assert(terrain_elements+Vertex.sizeof*vertices.length <= buffer.terrain.length,
"not enough allocated memory for tessellator: %d+%d*Vertex.sizeof <= %d"
.format(terrain_elements, vertices.length, buffer.terrain.length)); }
body {
size_t end = terrain_elements + vertices.length*Vertex.sizeof;
buffer.terrain.ptr[terrain_elements..end] = cast(void[])vertices;
for(; terrain_elements < end; terrain_elements += Vertex.sizeof) {
Vertex* vertex = cast(Vertex*)&((buffer.terrain.ptr)[terrain_elements]);
vertex.x += x_offset;
vertex.y += y_offset;
vertex.z += z_offset;
vertex.r = r;
vertex.g = g;
vertex.b = b;
vertex.sky_light = block.sky_light;
vertex.block_light = block.block_light;
}
}
void add_vertices(T : Vertex)(const auto ref T[] vertices)
in { assert(terrain_elements+vertices.length <= buffer.terrain.length,
"not enough allocated memory for tessellator"); }
body {
buffer.terrain.ptr[terrain_elements..(terrain_elements += vertices.length*Vertex.sizeof)] = cast(void[])vertices;
}
// blocks
void grass_block(Side s)(const Block block, const ref BiomeData biome_data,
float x_offset, float y_offset, float z_offset) {
Vertex[] vertices = atlas.get_vertices!(s)(block.id);
add_template_vertices(vertices, block, x_offset, y_offset, z_offset, biome_data.color.grass.field);
}
void plank_block(Side s)(const Block block, const ref BiomeData biome_data,
float x_offset, float y_offset, float z_offset) {
final switch(block.metadata & 0x3) {
case 0: mixin(add_block_vertices("planks_oak")); break; // oak
case 1: mixin(add_block_vertices("planks_spruce")); break; // spruce
case 2: mixin(add_block_vertices("planks_birch")); break; // birch
case 3: mixin(add_block_vertices("planks_jungle")); break; // jungle
}
}
void wood_block(Side s)(const Block block, const ref BiomeData biome_data,
float x_offset, float y_offset, float z_offset) {
if(block.metadata == 0) {
return tessellate_simple_block!(s)(block, biome_data, x_offset, y_offset, z_offset);
}
static string set_tex(string rot) {
return ```
final switch(block.metadata & 0x3) {
case 0: texcoords = atlas.get!("log_oak", ` ~ rot ~ `)(); break; // oak
case 1: texcoords = atlas.get!("log_spruce", ` ~ rot ~ `)(); break; // spruce
case 2: texcoords = atlas.get!("log_birch", ` ~ rot ~ `)(); break; // birch
case 3: texcoords = atlas.get!("log_jungle", ` ~ rot ~ `)(); break; // jungle
}```;
}
enum set_top_tex = ```
final switch(block.metadata & 0x3) {
case 0: texcoords = atlas.get!("log_oak_top")(); break;
case 1: texcoords = atlas.get!("log_spruce_top")(); break;
case 2: texcoords = atlas.get!("log_birch_top")(); break;
case 3: texcoords = atlas.get!("log_jungle_top")(); break;
}```;
short[2][4] texcoords;
// TODO: rewrite it/think of something better, I don't like it
static if(s == Side.NEAR || s == Side.FAR) { // south and north
if((block.metadata & 0xc) == 0) {
mixin(set_tex("0"));
} else if(block.metadata & 0x4) {
mixin(set_tex("90"));
} else { // it is 0x8
mixin(set_top_tex);
}
} else static if(s == Side.LEFT || s == Side.RIGHT) { // west and east
if((block.metadata & 0xc) == 0) {
mixin(set_tex("0"));
} else if(block.metadata & 0x8) {
mixin(set_tex("90"));
} else { // it is 0x4
mixin(set_top_tex);
}
} else static if(s == Side.TOP || s == Side.BOTTOM) {
if(block.metadata & 0x4) {
mixin(set_tex("90"));
} else if(block.metadata & 0x8) {
mixin(set_tex("0"));
} else { // it is 0x0
mixin(set_top_tex);
}
} else {
static assert(false, "use single_side string-mixin gen for wood_block.");
}
auto sb = memoize!(simple_block, 16)(s, texcoords); // memoize is faster!
add_template_vertices(sb, block, x_offset, y_offset, z_offset);
}
void leave_block(Side s)(const Block block, const ref BiomeData biome_data,
float x_offset, float y_offset, float z_offset) {
final switch(block.metadata & 0x03) {
case 0: auto vertices = simple_block(s, atlas.get!("leaves_oak")); // oak
add_template_vertices(vertices, block, x_offset, y_offset, z_offset, biome_data.color.leave.field); break;
case 1: auto vertices = simple_block(s, atlas.get!("leaves_spruce")); // spruce
add_template_vertices(vertices, block, x_offset, y_offset, z_offset, biome_data.color.leave.field); break;
case 2: auto vertices = simple_block(s, atlas.get!("leaves_oak")); // birch, uses oak texture
// birch trees have a different biome color?
add_template_vertices(vertices, block, x_offset, y_offset, z_offset, biome_data.color.leave.field); break;
case 3: auto vertices = simple_block(s, atlas.get!("leaves_jungle")); // jungle
add_template_vertices(vertices, block, x_offset, y_offset, z_offset, biome_data.color.leave.field); break;
}
}
void sandstone_block(Side s)(const Block block, const ref BiomeData biome_data,
float x_offset, float y_offset, float z_offset) {
if(block.metadata == 0) {
return tessellate_simple_block!(s)(block, biome_data, x_offset, y_offset, z_offset);
}
static if(s == Side.TOP) {
mixin(add_block_vertices("sandstone_top"));
} else static if(s == Side.BOTTOM) {
mixin(add_block_vertices("sandstone_bottom"));
} else {
if(block.metadata == 0x1) { // chiseled aka carved
mixin(add_block_vertices("sandstone_carved"));
} else { // smooth
mixin(add_block_vertices("sandstone_smooth"));
}
}
}
void wool_block(Side s)(const Block block, const ref BiomeData biome_data,
float x_offset, float y_offset, float z_offset) {
static string wool_vertices(string index) {
// no enum possible due to CTFE bug?
return `auto vertices = memoize!(simple_block, 16)(s, atlas.get!("wool_colored_` ~ index ~ `"));
add_template_vertices(vertices, block, x_offset, y_offset, z_offset);`;
}
alias WoolPair t;
final switch(block.metadata) {
foreach(i, index; TypeTuple!("white", "orange", "magenta", "light_blue", "yellow", "lime", "pink",
"gray","silver", "cyan", "purple", "blue", "brown", "green", "red", "black")) {
case i: mixin(wool_vertices(index)); break;
}
}
}
void stone_double_slab(Side s)(const Block block, const ref BiomeData biome_data,
float x_offset, float y_offset, float z_offset) {
final switch(block.metadata & 0x7) {
case 0: tessellate_simple_block!(s)(block, biome_data, x_offset, y_offset, z_offset); break;
case 1: enum sandstone = Block(24); // sandstone
tessellate_simple_block!(s)(sandstone, biome_data, x_offset, y_offset, z_offset); break;
case 2: mixin(add_block_vertices("planks_oak")); break; // wooden stone
case 3: mixin(add_block_vertices("cobblestone")); break; // cobblestone
case 4: mixin(add_block_vertices("brick")); break; // brick
case 5: mixin(add_block_vertices("stonebrick")); break; // stone brick
case 6: mixin(add_block_vertices("nether_brick")); break;
case 7: enum quartz = Block(155); // quartz
tessellate_simple_block!(s)(quartz, biome_data, x_offset, y_offset, z_offset); break;
}
}
void stone_slab(Side s)(const Block block, const ref BiomeData biome_data,
float x_offset, float y_offset, float z_offset) {
bool upside_down = (block.metadata & 0x8) != 0;
static if(s == Side.TOP) {
if((block.metadata & 0x7) == 0) { // stone
mixin(add_slab_vertices(s, "stone_slab_top"));
return;
} else if((block.metadata & 0x7) == 1) { // sandstone
mixin(add_slab_vertices(s, "sandstone_top"));
return;
} else if((block.metadata & 0x7) == 7) {
mixin(add_slab_vertices(s, "quartz_block_top"));
return;
}
} else static if(s == Side.BOTTOM) {
if((block.metadata & 0x7) == 0) { // stone
mixin(add_slab_vertices(s, "stone_slab_top"));
return;
} else if((block.metadata & 0x7) == 1) { // sandstone
mixin(add_slab_vertices(s, "sandstone_bottom"));
return;
} else if((block.metadata & 0x7) == 7) {
mixin(add_slab_vertices(s, "quartz_block_bottom"));
return;
}
}
final switch(block.metadata & 0x7) {
case 0: mixin(add_slab_vertices(s, "stone_slab_side")); break; // stone
case 1: mixin(add_slab_vertices(s, "sandstone_normal")); break; // sandstone
case 2: mixin(add_slab_vertices(s, "planks_oak")); break; // wooden stone
case 3: mixin(add_slab_vertices(s, "stonebrick")); break; // cobblestone
case 4: mixin(add_slab_vertices(s, "brick")); break; // brick
case 5: mixin(add_slab_vertices(s, "stonebrick")); break; // stone brick
case 6: mixin(add_slab_vertices(s, "nether_brick")); break; // netherbrick
case 7: mixin(add_slab_vertices(s, "quartz_block_side")); break; // quartz
}
}
void stonebrick_block(Side s)(const Block block, const ref BiomeData biome_data,
float x_offset, float y_offset, float z_offset) {
final switch(block.metadata & 0x3) {
case 0: mixin(add_block_vertices("stonebrick")); break; // normal
case 1: mixin(add_block_vertices("stonebrick_mossy")); break; // mossy
case 2: mixin(add_block_vertices("stonebrick_cracked")); break; // cracked
case 3: mixin(add_block_vertices("stonebrick_carved")); break; // chiseled aka carved
}
}
void wooden_double_slab(Side s)(const Block block, const ref BiomeData biome_data,
float x_offset, float y_offset, float z_offset) {
final switch(block.metadata & 0x3) {
case 0: mixin(add_block_vertices("planks_oak")); break; // oak
case 1: mixin(add_block_vertices("planks_spruce")); break; // spruce
case 2: mixin(add_block_vertices("planks_birch")); break; // birch
case 3: mixin(add_block_vertices("planks_jungle")); break; // jungle
}
}
void wooden_slab(Side s)(const Block block, const ref BiomeData biome_data,
float x_offset, float y_offset, float z_offset) {
bool upside_down = (block.metadata & 0x8) != 0;
final switch(block.metadata & 0x3) {
case 0: mixin(add_slab_vertices(s, "planks_oak")); break; // oak
case 1: mixin(add_slab_vertices(s, "planks_spruce")); break; // spruce
case 2: mixin(add_slab_vertices(s, "planks_birch")); break; // birch
case 3: mixin(add_slab_vertices(s, "planks_jungle")); break; // jungle
}
}
void stair(Side s)(const Block block, ProjectionTextureCoordinates tex, const ref BiomeData biome_data,
float x_offset, float y_offset, float z_offset) {
enum fs = [Facing.WEST, Facing.EAST, Facing.NORTH, Facing.SOUTH];
Facing f = fs[block.metadata & 0x3];
bool upside_down = (block.metadata & 0x4) != 0;
add_template_vertices(memoize!(simple_stair, 72)(s, f, upside_down, tex), block, x_offset, y_offset, z_offset);
}
void wheat(Side s)(const Block block, const ref BiomeData biome_data,
float x_offset, float y_offset, float z_offset) {
short[2][4] tex;
final switch(block.metadata & 0x7) {
foreach(i; TupleRange!(0, 8)) {
case i: tex = atlas.get!("wheat_stage_" ~ to!string(i))(); break;
}
}
add_template_vertices(simple_food_plant(tex), block, x_offset, y_offset, z_offset);
}
void farmland(Side s)(const Block block, const ref BiomeData biome_data,
float x_offset, float y_offset, float z_offset) {
Vertex[] fb;
static if(s == Side.TOP) {
if(block.metadata == 0) { // dry
fb = farmland_block(s, atlas.get_proj!("farmland_dry"));
} else { // wet
fb = farmland_block(s, atlas.get_proj!("farmland_wet"));
}
} else {
fb = farmland_block(s, atlas.get_proj!("dirt"));
}
add_template_vertices(fb, block, x_offset, y_offset, z_offset);
}
void furnace(Side s, string tex = `atlas.get!("furnace_front_off")`)(const Block block, const ref BiomeData biome_data,
float x_offset, float y_offset, float z_offset) {
enum fs = [Facing.WEST, Facing.EAST, Facing.NORTH, Facing.SOUTH];
Facing f = fs[block.metadata & 0x3];
if(cast(Side)f == s) { // special side
add_template_vertices(simple_block(s, mixin(tex)), block, x_offset, y_offset, z_offset);
} else {
tessellate_simple_block!(s)(block, biome_data, x_offset, y_offset, z_offset);
}
}
void burning_furnace(Side s)(const Block block, const ref BiomeData biome_data,
float x_offset, float y_offset, float z_offset) {
furnace!(s, `atlas.get!("furnace_front_on")`)(block, biome_data, x_offset, y_offset, z_offset);
}
void dispenser(Side s)(const Block block, const ref BiomeData biome_data,
float x_offset, float y_offset, float z_offset) {
furnace!(s, `atlas.get!("dispenser_front_horizontal")`)(block, biome_data, x_offset, y_offset, z_offset);
}
void pumpkin(Side s, bool is_jako = false)(const Block block, const ref BiomeData biome_data,
float x_offset, float y_offset, float z_offset) {
enum fs = [Facing.SOUTH, Facing.WEST, Facing.NORTH, Facing.EAST];
Facing f = fs[block.metadata & 0x3];
static if(s == Side.TOP) {
add_template_vertices(simple_block(s, atlas.get!("pumpkin_top"), f), block, x_offset, y_offset, z_offset);
} else {
if(cast(Side)f == s) { // side with the face
static if(is_jako) { // it's a jako lantern
add_template_vertices(simple_block(s, atlas.get!("pumpkin_face_on")), block, x_offset, y_offset, z_offset);
} else {
add_template_vertices(simple_block(s, atlas.get!("pumpkin_face_off")), block, x_offset, y_offset, z_offset);
}
} else {
tessellate_simple_block!(s)(block, biome_data, x_offset, y_offset, z_offset);
}
}
}
void jack_o_lantern(Side s)(const Block block, const ref BiomeData biome_data,
float x_offset, float y_offset, float z_offset) {
pumpkin!(s, true)(block, biome_data, x_offset, y_offset, z_offset);
}
void plant(Side s)(const Block block, short[2][4] tex, const ref BiomeData biome_data,
float x_offset, float y_offset, float z_offset) {
add_template_vertices(simple_plant(tex), block, x_offset, y_offset, z_offset);
}
void saplings(Side s)(const Block block, const ref BiomeData biome_data,
float x_offset, float y_offset, float z_offset) {
short[2][4] tex;
final switch(block.metadata & 0x3) {
case 0: tex = atlas.get!("sapling_oak"); break; // oak
case 1: tex = atlas.get!("sapling_spruce"); break; // spruce
case 2: tex = atlas.get!("sapling_birch"); break; // birch
case 3: tex = atlas.get!("sapling_jungle"); break; // jungle
}
add_template_vertices(simple_plant(tex), block, x_offset, y_offset, z_offset);
}
void tall_grass(Side s)(const Block block, const ref BiomeData biome_data,
float x_offset, float y_offset, float z_offset) {
short[2][4] tex;
Color3 color = Color3(cast(ubyte)0xff, cast(ubyte)0xff, cast(ubyte)0xff);
final switch(block.metadata & 0x3) {
case 0: tex = atlas.get!("deadbush"); break; // shrub aka deadbush
case 1: tex = atlas.get!("tallgrass"); color = biome_data.color.grass; break; // grass
case 2: tex = atlas.get!("fern"); color = biome_data.color.grass; break; // fern
case 3: tex = atlas.get!("tallgrass"); color = biome_data.color.grass; break; // grass
}
add_template_vertices(simple_plant(tex), block, x_offset, y_offset, z_offset, color.field);
}
void stem(Side s)(const Block block, const ref BiomeData biome_data,
vec3i world_coords, float x_offset, float y_offset, float z_offset) {
// TODO pumpkin/melon_stem
auto stem = atlas.get!("pumpkin_stem_disconnected")();
Color3 color = Color3(cast(ubyte)0x0, cast(ubyte)0xad, cast(ubyte)0x17);
int id = 86; // pumpkin
if(block.id == 105) {
id = 103; // melon
}
Facing face = Facing.SOUTH;
bool render_stem2 = false;
if((block.metadata & 0x7) == 0x7) { // fully grown
color = Color3(cast(ubyte)0x8a, cast(ubyte)0x77, cast(ubyte)0x11);
if(world.get_block_safe(vec3i(world_coords.x+1, world_coords.y, world_coords.z)).id == id) {
face = Facing.EAST; render_stem2 = true;
} else if(world.get_block_safe(vec3i(world_coords.x-1, world_coords.y, world_coords.z)).id == id) {
face = Facing.WEST; render_stem2 = true;
} else if(world.get_block_safe(vec3i(world_coords.x, world_coords.y, world_coords.z+1)).id == id) {
face = Facing.SOUTH; render_stem2 = true;
} else if(world.get_block_safe(vec3i(world_coords.x, world_coords.y, world_coords.z-1)).id == id) {
face = Facing.NORTH; render_stem2 = true;
}
}
if(render_stem2) {
auto stem2 = atlas.get!("pumpkin_stem_connected")();
add_template_vertices(side_stem(face, stem2), block, x_offset, y_offset, z_offset, color.field);
y_offset -= 0.4f;
}
y_offset -= 0.1f;
y_offset -= (7-block.metadata)/10.0f;
add_template_vertices(simple_plant(stem, face), block, x_offset, y_offset, z_offset, color.field);
}
void nether_wart(Side s)(const Block block, const ref BiomeData biome_data,
float x_offset, float y_offset, float z_offset) {
short[2][4] tex;
final switch(block.metadata & 0x3) {
case 0: tex = atlas.get!("nether_wart_stage_0")();
case 1: tex = atlas.get!("nether_wart_stage_1")();
case 2: tex = atlas.get!("nether_wart_stage_1")();
case 3: tex = atlas.get!("nether_wart_stage_2")();
}
return add_template_vertices(simple_food_plant(tex), block, x_offset, y_offset, z_offset);
}
void rail(Side s)(const Block block, float x_offset, float y_offset, float z_offset) {
short[2][4] tex = atlas.get!("rail_normal")();
if(block.metadata < 2) {
enum fs = [Facing.SOUTH, Facing.WEST];
add_template_vertices(simple_rail(tex, fs[block.metadata]), block, x_offset, y_offset, z_offset);
} else if(block.metadata < 6) {
enum fs = [Facing.EAST, Facing.WEST, Facing.NORTH, Facing.SOUTH];
add_template_vertices(simple_ascending_rail(tex, fs[block.metadata-2]), block, x_offset, y_offset, z_offset);
} else { // curved
enum fs = [Facing.SOUTH, Facing.WEST, Facing.NORTH, Facing.EAST];
tex = atlas.get!("rail_normal_turned");
add_template_vertices(simple_rail(tex, fs[block.metadata-6]), block, x_offset, y_offset, z_offset);
}
}
void special_rail(Side s)(const Block block, float x_offset, float y_offset, float z_offset) {
short[2][4] tex;
if(block.id == 27) { // powered rail
if(block.metadata & 0x8) { // powered
tex = atlas.get!("rail_golden_powered");
} else {
tex = atlas.get!("rail_golden");
}
} else {
if(block.metadata & 0x8) { // powered
tex = atlas.get!("rail_detector_powered");
} else {
tex = atlas.get!("rail_detector");
}
}
final switch(block.metadata & 0x07) {
case 0: add_template_vertices(simple_rail(tex, Facing.SOUTH), block, x_offset, y_offset, z_offset); break;
case 1: add_template_vertices(simple_rail(tex, Facing.WEST), block, x_offset, y_offset, z_offset); break;
case 2: add_template_vertices(simple_ascending_rail(tex, Facing.EAST), block, x_offset, y_offset, z_offset); break;
case 3: add_template_vertices(simple_ascending_rail(tex, Facing.WEST), block, x_offset, y_offset, z_offset); break;
case 4: add_template_vertices(simple_ascending_rail(tex, Facing.NORTH), block, x_offset, y_offset, z_offset); break;
case 5: add_template_vertices(simple_ascending_rail(tex, Facing.SOUTH), block, x_offset, y_offset, z_offset); break;
}
}
void ladder(Side s)(const Block block, float x_offset, float y_offset, float z_offset) {
enum fs = [Facing.WEST, Facing.EAST, Facing.NORTH, Facing.SOUTH];
add_template_vertices(simple_ladder(atlas.get!("ladder"), fs[block.metadata & 0x3]), block, x_offset, y_offset, z_offset);
}
void vines(Side s)(const Block block, const ref BiomeData biome_data, vec3i world_coords,
float x_offset, float y_offset, float z_offset) {
enum fs = [Facing.NORTH, Facing.EAST, Facing.SOUTH, Facing.WEST];
foreach(shift; 0..4) {
if(block.metadata & (1 << shift)) {
add_template_vertices(simple_vine(atlas.get!("vine"), fs[shift]), block,
x_offset, y_offset, z_offset, biome_data.color.leave.field);
}
}
if(block.metadata == 0 || BLOCKS[world.get_block_safe(vec3i(world_coords.x, world_coords.y+1, world_coords.z)).id].opaque) {
add_template_vertices(top_vine(atlas.get!("vine")), block, x_offset, y_offset, z_offset, biome_data.color.leave.field);
}
}
void piston_block_sticky(Side s)(const Block block, const ref BiomeData biome_data,
float x_offset, float y_offset, float z_offset) {
piston_block!(s, true)(block, biome_data, x_offset, y_offset, z_offset);
}
void piston_block(Side s, bool sticky = false)(const Block block, const ref BiomeData biome_data,
float x_offset, float y_offset, float z_offset) {
static assert(s != Side.ALL);
enum fs = [Side.BOTTOM, Side.TOP, Side.FAR, Side.NEAR, Side.LEFT, Side.RIGHT];
if(block.metadata & 0x8) {
short[2][4] tex;
final switch(s) {
case 0: tex = atlas.get!("piston_inner")(); break;
case 1: tex = atlas.get!("piston_side", 90, 8, 8, 4, 8)(); break;
case 2: tex = atlas.get!("piston_bottom")(); break;
case 3: tex = atlas.get!("piston_side", 270, 8, 8, 4, 8)(); break;
case 4: tex = atlas.get!("piston_side", 180, 8, 8, 4, 8)(); break;
case 5: tex = atlas.get!("piston_side", 0 , 8, 8, 4, 8)(); break;
case 6: break;
}
size_t m = (block.metadata & 0x7) > 5 ? 5 : block.metadata;
auto vertices = extended_piston(s, fs[(m & 0x7)], tex);
add_template_vertices(vertices, block, x_offset, y_offset, z_offset);
} else {
short[2][4] tex;
final switch(s) {
case 0:
static if(sticky) {
tex = atlas.get!("piston_top_sticky");
} else {
tex = atlas.get!("piston_top_normal");
}
break;
case 1: tex = atlas.get!("piston_side", 90)(); break;
case 2: tex = atlas.get!("piston_bottom")(); break;
case 3: tex = atlas.get!("piston_side", 270)(); break;
case 4: tex = atlas.get!("piston_side", 180)(); break;
case 5: tex = atlas.get!("piston_side")(); break;
case 6: break;
}
size_t m = (block.metadata & 0x7) > 5 ? 5 : block.metadata;
auto vertices = retracted_piston(s, fs[(m & 0x7)], tex);
add_template_vertices(vertices, block, x_offset, y_offset, z_offset);
}
}
void piston_arm(Side s)(const Block block, const ref BiomeData biome_data,
float x_offset, float y_offset, float z_offset) {
short[2][4] tex;
final switch(s) {
case 0:
if(block.metadata & 0x8) {
tex = atlas.get!("piston_top_sticky")();
} else {
tex = atlas.get!("piston_top_normal")();
}
break;
case 1: tex = atlas.get!("piston_side", 90, 8, 8, 8, -4)(); break;
case 2: tex = atlas.get!("piston_top_normal")(); break;
case 3: tex = atlas.get!("piston_side", 270, 8, 8, 8, -4)(); break;
case 4: tex = atlas.get!("piston_side", 180, 8, 8, 8, -4)(); break;
case 5: tex = atlas.get!("piston_side", 0, 8, 8, 8, -4)(); break;
case 6: break;
}
static if(s == Side.LEFT || s == Side.RIGHT) {
auto arm_tex = atlas.get!("piston_side", 0, 8, 8, 8, -4)();
} else {
auto arm_tex = atlas.get!("piston_side", 90, 8, 8, 8, -4)();
}
enum fs = [Side.BOTTOM, Side.TOP, Side.FAR, Side.NEAR, Side.LEFT, Side.RIGHT];
size_t m = (block.metadata & 0x7) > 5 ? 5 : block.metadata;
auto vertices = .piston_arm(s, fs[(m & 0x7)], tex, arm_tex);
add_template_vertices(vertices, block, x_offset, y_offset, z_offset);
}
void torch(Side s, string tex)(const Block block,
float x_offset, float y_offset, float z_offset) {
bool adjust_height = false;
static if(s == Side.TOP) {
enum left = 1;
enum right = 1;
enum top = 2;
enum bottom = 0;
} else static if(s == Side.BOTTOM) {
enum left = 1;
enum right = 1;
enum top = -6;
enum bottom = 8;
} else {
enum left = 2;
enum right = 2;
static if(tex == "redstone_torch_on") {
adjust_height = true;
enum top = 3;
} else {
enum top = 2;
}
enum bottom = 8;
}
enum fs = [Facing.EAST, Facing.WEST, Facing.SOUTH, Facing.NORTH];
auto vertices = simple_torch(s, fs[block.metadata > 0x4 ? 3 : block.metadata-1], block.metadata > 0x4,
atlas.get!(tex, 0, left, right, top, bottom)(), adjust_height);
add_template_vertices(vertices, block, x_offset, y_offset, z_offset);
}
void redstone_repeater_active(Side s)(const Block block, const ref BiomeData biome_data,
float x_offset, float y_offset, float z_offset) {
redstone_repeater!(s, true)(block, biome_data, x_offset, y_offset, z_offset);
}
void redstone_repeater(Side s, bool powered = false)(const Block block, const ref BiomeData biome_data,
float x_offset, float y_offset, float z_offset) {
bool adjust_height = false;
short[2][4] tex;
short[2][4] torch_tex;
static if(s == Side.TOP || s == Side.BOTTOM) {
static if(powered) {
tex = atlas.get!("repeater_on")();
torch_tex = atlas.get!("redstone_torch_on", 0, 1, 1, 2, 0)();
} else {
tex = atlas.get!("repeater_off")();
torch_tex = atlas.get!("redstone_torch_off", 0, 1, 1, 2, 0)();
}
} else {
tex = atlas.get!("stone_slab_side", 0, 8, 8, -6, 8)(); // double slab texture
static if(powered) {
torch_tex = atlas.get!("redstone_torch_on", 0, 2, 2, 3, 4)();
adjust_height = true;
} else {
torch_tex = atlas.get!("redstone_torch_off", 0, 2, 2, 2, 4)();
}
}
enum fs = [Facing.SOUTH, Facing.EAST, Facing.NORTH, Facing.WEST];
float offset = -0.0625f + ((block.metadata >> 2) & 0x3) * 0.125f;
alias memoize!(.redstone_repeater, 16) rr;
add_template_vertices(rr(s, fs[block.metadata & 0x3], offset, tex, torch_tex, adjust_height), block, x_offset, y_offset, z_offset);
}
void redstone(Side s)(const Block block, vec3i world_coords, float x_offset, float y_offset, float z_offset) {
enum rs_id = 55;
enum redstone_devices = [rs_id, 69, 70, 75, 76, 77, 131, 143];
enum special_redstone_devices = [93, 94];
static bool connects_to(string side, const Block other) {
if(redstone_devices.canFind(other.id)) {
return true;
} else if(other.id == 93 || other.id == 94) {
if(side == "FRONT" || side == "BACK") {
return (other.metadata & 0x3) % 2 == 0;
} else {
return (other.metadata & 0x3) % 2 == 1;
}
}
return false;
}
auto color = Color3(cast(ubyte)(0x5a+block.metadata*10), cast(ubyte)0x00, cast(ubyte)0x00);
enum {
FRONT = 0b00000001,
BACK = 0b00000010,
LEFT = 0b00000100,
RIGHT = 0b00001000,
FRONT_TOP = 0b00010000,
BACK_TOP = 0b00100000,
LEFT_TOP = 0b01000000,
RIGHT_TOP = 0b10000000
}
ubyte data = 0;
ubyte sides = 0;
Block b = world.get_block_safe(vec3i(world_coords.x , world_coords.y+1, world_coords.z));
BlockDescriptor orig_block_desc;
bool can_travel_up = !BLOCKS[b.id].opaque;
static string make_check(string x, string z, string flag) {
return `b = world.get_block_safe(vec3i(world_coords.x+` ~ x ~ ` , world_coords.y, world_coords.z+` ~ z ~ `));
orig_block_desc = BLOCKS[b.id];
if(connects_to("` ~ flag ~ `", b)) {
data |= ` ~ flag ~ `;
sides++;
} else if(can_travel_up && orig_block_desc.opaque) {
b = world.get_block_safe(vec3i(world_coords.x+` ~ x ~ ` , world_coords.y+1, world_coords.z+` ~ z ~ `));
if(b.id == rs_id) {
data |= ` ~ flag ~ `;
data |= ` ~ flag ~ `_TOP;
sides++;
}
}
if(!orig_block_desc.opaque) {
b = world.get_block_safe(vec3i(world_coords.x+` ~ x ~ ` , world_coords.y-1, world_coords.z+` ~ z ~ `));
if(b.id == rs_id) {
if((data & ` ~ flag ~ `) == 0) {
data |= ` ~ flag ~ `;
sides++;
}
}
}
`;
}
mixin(make_check("0", "1", "FRONT"));
mixin(make_check("0", "-1", "BACK"));
mixin(make_check("1", "0", "RIGHT"));
mixin(make_check("-1", "0", "LEFT"));
if(sides == 0) {
auto vertices = redstone_wire(Facing.SOUTH, atlas.get!("redstone_dust_cross", 0, 3, 3, 3, 3)(), 3, 3, 3, 3);
add_template_vertices(vertices, block, x_offset, y_offset, z_offset, color.field);
} else if(sides == 1 || (data & 0b1111) == 0b1100 || (data & 0b1111) == 0b0011) {
if(data & 0b1100) {
auto vertices = redstone_wire(Facing.SOUTH, atlas.get!("redstone_dust_line")());
add_template_vertices(vertices, block, x_offset, y_offset, z_offset, color.field);
} else if(data & 0b0011) {
auto vertices = redstone_wire(Facing.EAST, atlas.get!("redstone_dust_line")());
add_template_vertices(vertices, block, x_offset, y_offset, z_offset, color.field);
}
} else {
short top = (data & 1) ? 8 : 3;
short bottom = (data & 2) ? 8 : 3;
short right = (data & 4) ? 8 : 3;
short left = (data & 8) ? 8 : 3;
auto tex = atlas.get_tex!("redstone_dust_cross")();
auto coords = tex.r0(tex.unify(left, right, top, bottom).expand);
auto vertices = memoize!(redstone_wire, 8)(Facing.SOUTH, coords, left, right, top, bottom);
add_template_vertices(vertices, block, x_offset, y_offset, z_offset, color.field);
}
foreach(i; TypeTuple!(4, 5, 6, 7)) {
if(data & (1 << i)) {
enum s = [Facing.SOUTH, Facing.NORTH, Facing.WEST, Facing.EAST];
auto vertices = redstone_wire_side(s[i-4], atlas.get!("redstone_dust_line", 90)());
add_template_vertices(vertices, block, x_offset, y_offset, z_offset, color.field);
}
}
}
void dispatch(Side side)(const Block block, const ref BiomeData biome_data,
vec3i world_coords, float x_offset, float y_offset, float z_offset) {
switch(block.id) {
case 2: mixin(single_side("grass_block")); break; // grass
case 5: mixin(single_side("plank_block")); break; // planks
case 6: dispatch_once!(saplings, side)(block, biome_data, x_offset, y_offset, z_offset); break; // saplings
case 17: mixin(single_side("wood_block")); break; // wood
case 18: mixin(single_side("leave_block")); break; // leaves
case 23: mixin(single_side("dispenser")); break; // dispenser
case 24: mixin(single_side("sandstone_block")); break; // sandstone
case 27: dispatch_once!(special_rail, side)(block, x_offset, y_offset, z_offset); break; // powered rail
case 28: dispatch_once!(special_rail, side)(block, x_offset, y_offset, z_offset); break; // detector rail
case 29: mixin(single_side("piston_block_sticky")); break; // sticky-piston
case 30: dispatch_once!(plant, side)(block, atlas.get!("web")(), // cobweb
biome_data, x_offset, y_offset, z_offset); break;
case 31: dispatch_once!(tall_grass, side)(block, biome_data, x_offset, y_offset, z_offset); break; // tall grass
case 33: mixin(single_side("piston_block")); break; // normal piston
case 34: mixin(single_side("piston_arm")); break; // piston arm/extension
case 35: mixin(single_side("wool_block")); break; // wool
case 37: dispatch_once!(plant, side)(block, atlas.get!("flower_dandelion"), // dandelion
biome_data, x_offset, y_offset, z_offset); break;
case 38: dispatch_once!(plant, side)(block, atlas.get!("flower_rose"), // rose
biome_data, x_offset, y_offset, z_offset); break;
case 39: dispatch_once!(plant, side)(block, atlas.get!("mushroom_brown"), // brown mushroom
biome_data, x_offset, y_offset, z_offset); break;
case 40: dispatch_once!(plant, side)(block, atlas.get!("mushroom_red"), // red mushroom
biome_data, x_offset, y_offset, z_offset); break;
case 50: dispatch_single_side_torch!(torch, side, "torch_on")(block, x_offset, y_offset, z_offset); break; // torch
case 43: mixin(single_side("stone_double_slab")); break; // stone double slaps
case 44: mixin(single_side("stone_slab")); break; // stone slabs - stone, sandstone, wooden stone, cobblestone, brick, stone brick
case 53: dispatch_single_side!(stair, side)(block, atlas.get_proj!("planks_oak", "planks_oak"), // oak wood stair
biome_data, x_offset, y_offset, z_offset); break;
case 55: dispatch_once!(redstone, side)(block, world_coords, x_offset, y_offset, z_offset); break; // redstone wire
case 59: dispatch_once!(wheat, side)(block, biome_data, x_offset, y_offset, z_offset); break; // wheat
case 60: mixin(single_side("farmland")); break; // farmland
case 61: mixin(single_side("furnace")); break; // furnace
case 62: mixin(single_side("burning_furnace")); break; // burning furnace
case 65: dispatch_once!(ladder, side)(block, x_offset, y_offset, z_offset); break; // ladder
case 66: dispatch_once!(rail, side)(block, x_offset, y_offset, z_offset); break; // rail
case 67: dispatch_single_side!(stair, side)(block, atlas.get_proj!("stonebrick", "stonebrick"), // cobblestone stair
biome_data, x_offset, y_offset, z_offset); break;
case 75: dispatch_single_side_torch!(torch, side, "redstone_torch_off")(block, x_offset, y_offset, z_offset); break; // rs-torch inactive
case 76: dispatch_single_side_torch!(torch, side, "redstone_torch_on")(block, x_offset, y_offset, z_offset); break; // rs-torch active
case 83: dispatch_once!(plant, side)(block, atlas.get!("reeds"), // reeds
biome_data, x_offset, y_offset, z_offset); break;
case 86: mixin(single_side("pumpkin")); break;
case 91: mixin(single_side("jack_o_lantern")); break;
case 93: mixin(single_side("redstone_repeater")); break; // redstone repeater inactive
case 94: mixin(single_side("redstone_repeater_active")); break; // redstone repeater active
case 98: mixin(single_side("stonebrick_block")); break; // stone brick
case 104: dispatch_once!(stem, side)(block, biome_data, world_coords, x_offset, y_offset, z_offset); break; // pumpkin stem
case 105: dispatch_once!(stem, side)(block, biome_data, world_coords, x_offset, y_offset, z_offset); break; // melon stem
case 106: dispatch_once!(vines, side)(block, biome_data, world_coords, x_offset, y_offset, z_offset); break; // vines
case 108: dispatch_single_side!(stair, side)(block, atlas.get_proj!("brick", "brick"), // brick stair
biome_data, x_offset, y_offset, z_offset); break;
case 109: dispatch_single_side!(stair, side)(block, atlas.get_proj!("stonebrick", "stonebrick"), // stone brick stair
biome_data, x_offset, y_offset, z_offset); break;
case 114: dispatch_single_side!(stair, side)(block, atlas.get_proj!("nether_brick", "nether_brick"), // nether brick stair
biome_data, x_offset, y_offset, z_offset); break;
case 115: dispatch_once!(nether_wart, side)(block, biome_data, x_offset, y_offset, z_offset); break; // nether wart
case 125: mixin(single_side("wooden_double_slab")); break; // wooden double slab
case 126: mixin(single_side("wooden_slab")); break; // wooden slab
case 128: dispatch_single_side!(stair, side)(block, atlas.get_proj!("sandstone_normal", "sandstone_top", "sandstone_bottom"), // sandstone stair
biome_data, x_offset, y_offset, z_offset); break;
case 134: dispatch_single_side!(stair, side)(block, atlas.get_proj!("planks_spruce", "planks_spruce"), // spruce wood stair
biome_data, x_offset, y_offset, z_offset); break;
case 135: dispatch_single_side!(stair, side)(block, atlas.get_proj!("planks_birch", "planks_birch"), // birch wood stair
biome_data, x_offset, y_offset, z_offset); break;
case 136: dispatch_single_side!(stair, side)(block, atlas.get_proj!("planks_jungle", "planks_jungle"), // jungle wood stair
biome_data, x_offset, y_offset, z_offset); break;
default: tessellate_simple_block!(side)(block, biome_data, x_offset, y_offset, z_offset);
}
}
void dispatch_single_side(alias func, Side s, Args...)(Args args) {
static if(s == Side.ALL) {
func!(Side.LEFT)(args);
func!(Side.RIGHT)(args);
func!(Side.NEAR)(args);
func!(Side.FAR)(args);
func!(Side.TOP)(args);
func!(Side.BOTTOM)(args);
} else {
func!(s)(args);
}
}
void dispatch_single_side_torch(alias func, Side s, string str, Args...)(Args args) {
static if(s == Side.ALL) {
func!(Side.LEFT, str)(args);
func!(Side.RIGHT, str)(args);
func!(Side.NEAR, str)(args);
func!(Side.FAR, str)(args);
func!(Side.TOP, str)(args);
func!(Side.BOTTOM, str)(args);
} else {
func!(s, str)(args);
}
}
void dispatch_once(alias func, Side s, Args...)(Args args) {
static if(s == Side.ALL || s == Side.RIGHT) {
func!(Side.ALL)(args);
}
}
void tessellate_simple_block(Side side)(const Block block, const ref BiomeData biome_data,
float x_offset, float y_offset, float z_offset) {
static if(side == Side.ALL) {
tessellate_simple_block!(Side.LEFT)(block, biome_data, x_offset, y_offset, z_offset);
tessellate_simple_block!(Side.RIGHT)(block, biome_data, x_offset, y_offset, z_offset);
tessellate_simple_block!(Side.NEAR)(block, biome_data, x_offset, y_offset, z_offset);
tessellate_simple_block!(Side.FAR)(block, biome_data, x_offset, y_offset, z_offset);
tessellate_simple_block!(Side.TOP)(block, biome_data, x_offset, y_offset, z_offset);
tessellate_simple_block!(Side.BOTTOM)(block, biome_data, x_offset, y_offset, z_offset);
} else {
add_template_vertices(atlas.get_vertices!(side)(block.id), block, x_offset, y_offset, z_offset);
}
}
}
static string add_block_vertices(string name) {
return `auto vertices = simple_block(s, atlas.get!("` ~ name ~ `")());
add_template_vertices(vertices, block, x_offset, y_offset, z_offset);`;
}
static string add_slab_vertices(Side s, string name) {
string v;
string vusd;
if(s == Side.TOP || s == Side.BOTTOM) {
v = `auto vertices = simple_slab(s, false, atlas.get!("` ~ name ~ `")());`;
vusd = `auto vertices_usd = simple_slab(s, true, atlas.get!("` ~ name ~ `")());`;
} else {
v = `auto vertices = simple_slab(s, false, atlas.get!("` ~ name ~ `", 0, 8, 8, 0, 8)());`;
vusd = `auto vertices_usd = simple_slab(s, true, atlas.get!("` ~ name ~ `", 0, 8, 8, 8, 0)());`;
}
return `if(upside_down) {
` ~ vusd ~ `
add_template_vertices(vertices_usd, block, x_offset, y_offset, z_offset);
} else {
` ~ v ~ `
add_template_vertices(vertices, block, x_offset, y_offset, z_offset);
}`;
}
string single_side(string func) {
return
`static if(side == Side.ALL) {` ~
func ~ `!(Side.LEFT)(block, biome_data, x_offset, y_offset, z_offset);` ~
func ~ `!(Side.RIGHT)(block, biome_data, x_offset, y_offset, z_offset);` ~
func ~ `!(Side.NEAR)(block, biome_data, x_offset, y_offset, z_offset);` ~
func ~ `!(Side.FAR)(block, biome_data, x_offset, y_offset, z_offset);` ~
func ~ `!(Side.TOP)(block, biome_data, x_offset, y_offset, z_offset);` ~
func ~ `!(Side.BOTTOM)(block, biome_data, x_offset, y_offset, z_offset);` ~
`} else {` ~
func ~ `!(side)(block, biome_data, x_offset, y_offset, z_offset);` ~
`}`;
}
You can’t perform that action at this time.