|
@@ -155,6 +155,14 @@
|
|
|
// stb_voxel_render 4..14 bytes : 2015/02???
|
|
|
|
|
|
|
|
|
+
|
|
|
+
|
|
|
+//
|
|
|
+
|
|
|
+#ifndef STBVOX_MODE
|
|
|
+#define STBVOX_MODE 0
|
|
|
+#endif
|
|
|
+
|
|
|
// The following are candidate voxel modes. Only modes 0, 1, and 20 are
|
|
|
// currently implemented. Reducing the storage-per-quad further
|
|
|
// shouldn't improve performance, although obviously it allow you
|
|
@@ -252,7 +260,7 @@ enum
|
|
|
STBVOX_UNIFORM_ambient,
|
|
|
STBVOX_UNIFORM_camera_pos,
|
|
|
|
|
|
- STBVOX_UNIFORM__count,
|
|
|
+ STBVOX_UNIFORM_count,
|
|
|
};
|
|
|
|
|
|
enum
|
|
@@ -928,7 +936,7 @@ stbvox_uniform_info *stbvox_get_uniform_info(stbvox_mesh_maker *mm, int uniform)
|
|
|
if (stbvox_default_palette[0][0] == 0) // NOTE: not threadsafe, so call once to init
|
|
|
stbvox_build_default_palette();
|
|
|
|
|
|
- if (uniform < 0 || uniform >= STBVOX_UNIFORM__count)
|
|
|
+ if (uniform < 0 || uniform >= STBVOX_UNIFORM_count)
|
|
|
return NULL;
|
|
|
|
|
|
if (stbvox_check_tag(mm, stbvox_uniforms[uniform].tags))
|
|
@@ -1322,14 +1330,41 @@ void stbvox_make_mesh_for_face(stbvox_mesh_maker *mm, stbvox_rotate rot, int fac
|
|
|
|
|
|
}
|
|
|
} else {
|
|
|
- int i;
|
|
|
- for (i=0; i < 4; ++i) {
|
|
|
- *mv[i] = vertbase + face_coord[i] + p1[i];
|
|
|
- }
|
|
|
+ *mv[0] = vertbase + face_coord[0] + p1[0];
|
|
|
+ *mv[1] = vertbase + face_coord[1] + p1[1];
|
|
|
+ *mv[2] = vertbase + face_coord[2] + p1[2];
|
|
|
+ *mv[3] = vertbase + face_coord[3] + p1[3];
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+// render non-planar quads by splitting into two triangles, rendering each as a degenerate quad
|
|
|
+void stbvox_make_02_split_mesh_for_face(stbvox_mesh_maker *mm, stbvox_rotate rot, int face1, int face2, int v_off, stbvox_pos pos, stbvox_mesh_vertex vertbase, stbvox_mesh_vertex *face_coord, unsigned char mesh)
|
|
|
+{
|
|
|
+ stbvox_mesh_vertex v[4];
|
|
|
+ v[0] = face_coord[0];
|
|
|
+ v[1] = face_coord[1];
|
|
|
+ v[2] = face_coord[2];
|
|
|
+ v[3] = face_coord[0];
|
|
|
+ stbvox_make_mesh_for_face(mm, rot, face1, v_off, pos, vertbase, v, mesh);
|
|
|
+ v[1] = face_coord[2];
|
|
|
+ v[2] = face_coord[3];
|
|
|
+ stbvox_make_mesh_for_face(mm, rot, face2, v_off, pos, vertbase, v, mesh);
|
|
|
+}
|
|
|
+
|
|
|
+void stbvox_make_13_split_mesh_for_face(stbvox_mesh_maker *mm, stbvox_rotate rot, int face1, int face2, int v_off, stbvox_pos pos, stbvox_mesh_vertex vertbase, stbvox_mesh_vertex *face_coord, unsigned char mesh)
|
|
|
+{
|
|
|
+ stbvox_mesh_vertex v[4];
|
|
|
+ v[0] = face_coord[1];
|
|
|
+ v[1] = face_coord[2];
|
|
|
+ v[2] = face_coord[3];
|
|
|
+ v[3] = face_coord[1];
|
|
|
+ stbvox_make_mesh_for_face(mm, rot, face1, v_off, pos, vertbase, v, mesh);
|
|
|
+ v[1] = face_coord[3];
|
|
|
+ v[2] = face_coord[0];
|
|
|
+ stbvox_make_mesh_for_face(mm, rot, face2, v_off, pos, vertbase, v, mesh);
|
|
|
+}
|
|
|
+
|
|
|
// simple case for mesh generation: we have only solid and empty blocks
|
|
|
void stbvox_make_mesh_for_block(stbvox_mesh_maker *mm, stbvox_pos pos, int v_off, stbvox_mesh_vertex *vmesh)
|
|
|
{
|
|
@@ -1344,11 +1379,8 @@ void stbvox_make_mesh_for_block(stbvox_mesh_maker *mm, stbvox_pos pos, int v_off
|
|
|
|
|
|
unsigned char mesh = mm->default_mesh;
|
|
|
|
|
|
- if (mm->input.selector) {
|
|
|
+ if (mm->input.selector)
|
|
|
mesh = mm->input.selector[v_off];
|
|
|
- simple_rot = mesh >> 4;
|
|
|
- mesh &= 15;
|
|
|
- }
|
|
|
|
|
|
// check if we're going off the end
|
|
|
if (mm->output_cur[mesh][0] + mm->output_size[mesh][0]*6 > mm->output_end[mesh][0]) {
|
|
@@ -1356,6 +1388,10 @@ void stbvox_make_mesh_for_block(stbvox_mesh_maker *mm, stbvox_pos pos, int v_off
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
+ #ifdef STBVOX_ROTATION_IN_LIGHTING
|
|
|
+ simple_rot = mm->input.lighting[v_off] & 3;
|
|
|
+ #endif
|
|
|
+
|
|
|
if (blockptr[ 1]==0)
|
|
|
stbvox_make_mesh_for_face(mm, rot, STBVOX_FACE_up , v_off, pos, basevert, vmesh+4*STBVOX_FACE_up, mesh);
|
|
|
if (blockptr[-1]==0)
|
|
@@ -1404,14 +1440,14 @@ static unsigned char stbvox_hasface[STBVOX_MAX_GEOM][STBVOX_NUM_ROTATION] =
|
|
|
{ 0,0,0,0 }, // knockout
|
|
|
{ 63,63,63,63 }, // solid
|
|
|
{ 63,63,63,63 }, // transp
|
|
|
- { 63,63,63,63 }, // slabs
|
|
|
- { 63,63,63,63 },
|
|
|
+ { 63,63,63,63 }, // slab
|
|
|
+ { 63,63,63,63 }, // slab
|
|
|
{ 1|2|4|48, 8|1|2|48, 4|8|1|48, 2|4|8|48, }, // floor slopes
|
|
|
{ 1|2|4|48, 8|1|2|48, 4|8|1|48, 2|4|8|48, }, // ceil slopes
|
|
|
{ 47,47,47,47 }, // wall-projected diagonal with down face
|
|
|
{ 31,31,31,31 }, // wall-projected diagonal with up face
|
|
|
{ 63,63,63,63 }, // crossed-pair has special handling, but avoid early-out
|
|
|
- { 63,63,63,63 }, // reserved
|
|
|
+ { 63,63,63,63 }, // force
|
|
|
{ 63,63,63,63 },
|
|
|
{ 63,63,63,63 },
|
|
|
{ 63,63,63,63 },
|
|
@@ -1430,17 +1466,13 @@ enum
|
|
|
STBVOX_FT_diag_013,
|
|
|
STBVOX_FT_diag_123,
|
|
|
STBVOX_FT_force , // can't be covered up, used for internal faces, also hides nothing
|
|
|
-};
|
|
|
+ STBVOX_FT_partial , // only covered by solid, never covers anything else
|
|
|
|
|
|
-// these are additional geometry types used internally
|
|
|
-enum
|
|
|
-{
|
|
|
- STBVOX_GEOM_internal_force = STBVOX_GEOM_count,
|
|
|
- STBVOX_GEOM_internal_count
|
|
|
+ STBVOX_FT_count
|
|
|
};
|
|
|
|
|
|
// this determines which face type above is visible on each side of the geometry
|
|
|
-static unsigned char stbvox_facetype[STBVOX_GEOM_internal_count][6] =
|
|
|
+static unsigned char stbvox_facetype[STBVOX_GEOM_count][6] =
|
|
|
{
|
|
|
{ 0, }, // STBVOX_GEOM_empty
|
|
|
{ STBVOX_FT_solid, STBVOX_FT_solid, STBVOX_FT_solid, STBVOX_FT_solid, STBVOX_FT_solid, STBVOX_FT_solid }, // knockout
|
|
@@ -1455,20 +1487,17 @@ static unsigned char stbvox_facetype[STBVOX_GEOM_internal_count][6] =
|
|
|
{ STBVOX_FT_diag_123, STBVOX_FT_solid, STBVOX_FT_diag_023, STBVOX_FT_force, STBVOX_FT_none, STBVOX_FT_solid },
|
|
|
{ STBVOX_FT_diag_012, STBVOX_FT_solid, STBVOX_FT_diag_013, STBVOX_FT_force, STBVOX_FT_solid, STBVOX_FT_none },
|
|
|
{ STBVOX_FT_force, STBVOX_FT_force, STBVOX_FT_force, STBVOX_FT_force, 0,0 }, // crossed pair
|
|
|
- { STBVOX_FT_force, STBVOX_FT_force, STBVOX_FT_force, STBVOX_FT_force, STBVOX_FT_force, STBVOX_FT_force },
|
|
|
- //0, }, // GEOM_force, show as empty so that neighbors are always visible
|
|
|
-
|
|
|
- { 0,0,0,0,0, STBVOX_FT_solid }, // floor vheight
|
|
|
- { 0,0,0,0,0, STBVOX_FT_solid }, // floor vheight
|
|
|
- { 0,0,0,0, STBVOX_FT_solid,0 }, // ceil vheight
|
|
|
- { 0,0,0,0, STBVOX_FT_solid,0 }, // ceil vheight
|
|
|
+ { STBVOX_FT_force, STBVOX_FT_force, STBVOX_FT_force, STBVOX_FT_force, STBVOX_FT_force, STBVOX_FT_force }, // GEOM_force
|
|
|
|
|
|
- //{ STBVOX_FT_solid, STBVOX_FT_solid, STBVOX_FT_solid, STBVOX_FT_solid, STBVOX_FT_solid, STBVOX_FT_solid }, // internal force
|
|
|
+ { STBVOX_FT_partial,STBVOX_FT_partial,STBVOX_FT_partial,STBVOX_FT_partial, STBVOX_FT_force, STBVOX_FT_solid }, // floor vheight, all neighbors forced
|
|
|
+ { STBVOX_FT_partial,STBVOX_FT_partial,STBVOX_FT_partial,STBVOX_FT_partial, STBVOX_FT_force, STBVOX_FT_solid }, // floor vheight, all neighbors forced
|
|
|
+ { STBVOX_FT_partial,STBVOX_FT_partial,STBVOX_FT_partial,STBVOX_FT_partial, STBVOX_FT_solid, STBVOX_FT_force }, // ceil vheight, all neighbors forced
|
|
|
+ { STBVOX_FT_partial,STBVOX_FT_partial,STBVOX_FT_partial,STBVOX_FT_partial, STBVOX_FT_solid, STBVOX_FT_force }, // ceil vheight, all neighbors forced
|
|
|
};
|
|
|
|
|
|
// this table indicates whether, for each pair of types above, a face is visible.
|
|
|
// each value indicates whether a given type is visible for all neighbor types
|
|
|
-static unsigned short stbvox_face_visible[9] =
|
|
|
+static unsigned short stbvox_face_visible[STBVOX_FT_count] =
|
|
|
{
|
|
|
// we encode the table by listing which cases cause *obscuration*, and bitwise inverting that
|
|
|
// table is pre-shifted by 5 to save a shift when it's accessed
|
|
@@ -1481,6 +1510,7 @@ static unsigned short stbvox_face_visible[9] =
|
|
|
(unsigned short) ((~((1<<STBVOX_FT_solid) | (1<<STBVOX_FT_diag_012)))<<5), // diag013 matches diag012
|
|
|
(unsigned short) ((~((1<<STBVOX_FT_solid) | (1<<STBVOX_FT_diag_023)))<<5), // diag123 matches diag023
|
|
|
(unsigned short) ((~0 )<<5), // force is always rendered regardless, always forces neighbor
|
|
|
+ (unsigned short) ((~((1<<STBVOX_FT_solid) ))<<5), // partial is only completely obscured only by solid
|
|
|
};
|
|
|
|
|
|
// the vertex heights of the block types, in binary vertex order (zyx):
|
|
@@ -1665,7 +1695,7 @@ void stbvox_make_mesh_for_block_with_geo(stbvox_mesh_maker *mm, stbvox_pos pos,
|
|
|
stbvox_mesh_vertex basevert;
|
|
|
stbvox_mesh_vertex vmesh[6][4];
|
|
|
stbvox_rotate rotate = { 0,0,0,0 };
|
|
|
- unsigned char simple_rot = 0;
|
|
|
+ unsigned char simple_rot = rot;
|
|
|
int i;
|
|
|
// we only need to do this for the displayed faces, but it's easier
|
|
|
// to just do it up front; @OPTIMIZE check if it's faster to do it
|
|
@@ -1721,8 +1751,10 @@ void stbvox_make_mesh_for_block_with_geo(stbvox_mesh_maker *mm, stbvox_pos pos,
|
|
|
stbvox_mesh_vertex cube[8];
|
|
|
stbvox_mesh_vertex basevert;
|
|
|
stbvox_rotate rotate = { 0,0,0,0 };
|
|
|
- unsigned char simple_rot = 0;
|
|
|
+ unsigned char simple_rot = rot;
|
|
|
unsigned char ht[4];
|
|
|
+ int extreme;
|
|
|
+
|
|
|
// extract the heights
|
|
|
if (mm->input.vheight) {
|
|
|
unsigned char v = mm->input.vheight[v_off];
|
|
@@ -1732,15 +1764,34 @@ void stbvox_make_mesh_for_block_with_geo(stbvox_mesh_maker *mm, stbvox_pos pos,
|
|
|
ht[3] = (v >> 6) & 3;
|
|
|
} else if (mm->input.block_vheight) {
|
|
|
unsigned char v = mm->input.block_vheight[bt];
|
|
|
- // @TODO: these need to be rotated by 'rotate'
|
|
|
- ht[0] = (v >> 0) & 3;
|
|
|
- ht[1] = (v >> 2) & 3;
|
|
|
- ht[2] = (v >> 4) & 3;
|
|
|
- ht[3] = (v >> 6) & 3;
|
|
|
+ unsigned char raw[4];
|
|
|
+ int i;
|
|
|
+
|
|
|
+ raw[0] = (v >> 0) & 3;
|
|
|
+ raw[1] = (v >> 2) & 3;
|
|
|
+ raw[2] = (v >> 4) & 3;
|
|
|
+ raw[3] = (v >> 6) & 3;
|
|
|
+
|
|
|
+ for (i=0; i < 4; ++i)
|
|
|
+ ht[i] = raw[stbvox_rotate_vertex[i][rot]];
|
|
|
} else {
|
|
|
assert(mm->input.geometry);
|
|
|
}
|
|
|
+
|
|
|
+ // flag whether any sides go off the top of the block, which means
|
|
|
+ // our visible_faces test was wrong
|
|
|
+ extreme = (ht[0] == 3 || ht[1] == 3 || ht[2] == 3 || ht[3] == 3);
|
|
|
+
|
|
|
if (geo >= STBVOX_GEOM_ceil_vheight_02) {
|
|
|
+ cube[0] = stbvox_vertex_p(0,0,ht[0],0,0);
|
|
|
+ cube[1] = stbvox_vertex_p(0,0,ht[1],0,0);
|
|
|
+ cube[2] = stbvox_vertex_p(0,0,ht[2],0,0);
|
|
|
+ cube[3] = stbvox_vertex_p(0,0,ht[3],0,0);
|
|
|
+ cube[4] = stbvox_vertex_p(0,0,2,0,0);
|
|
|
+ cube[5] = stbvox_vertex_p(0,0,2,0,0);
|
|
|
+ cube[6] = stbvox_vertex_p(0,0,2,0,0);
|
|
|
+ cube[7] = stbvox_vertex_p(0,0,2,0,0);
|
|
|
+ } else {
|
|
|
cube[0] = stbvox_vertex_p(0,0,0,0,0);
|
|
|
cube[1] = stbvox_vertex_p(0,0,0,0,0);
|
|
|
cube[2] = stbvox_vertex_p(0,0,0,0,0);
|
|
@@ -1749,26 +1800,12 @@ void stbvox_make_mesh_for_block_with_geo(stbvox_mesh_maker *mm, stbvox_pos pos,
|
|
|
cube[5] = stbvox_vertex_p(0,0,ht[1],0,0);
|
|
|
cube[6] = stbvox_vertex_p(0,0,ht[2],0,0);
|
|
|
cube[7] = stbvox_vertex_p(0,0,ht[3],0,0);
|
|
|
- } else {
|
|
|
- cube[0] = stbvox_vertex_p(0,0,ht[0],0,0);
|
|
|
- cube[1] = stbvox_vertex_p(0,0,ht[1],0,0);
|
|
|
- cube[2] = stbvox_vertex_p(0,0,ht[2],0,0);
|
|
|
- cube[3] = stbvox_vertex_p(0,0,ht[3],0,0);
|
|
|
- cube[4] = stbvox_vertex_p(0,0,0,0,0);
|
|
|
- cube[5] = stbvox_vertex_p(0,0,0,0,0);
|
|
|
- cube[6] = stbvox_vertex_p(0,0,0,0,0);
|
|
|
- cube[7] = stbvox_vertex_p(0,0,0,0,0);
|
|
|
}
|
|
|
if (!mm->input.vheight && mm->input.block_vheight) {
|
|
|
- int i;
|
|
|
- // apply rotation
|
|
|
- for (i=0; i < 6*4; ++i) {
|
|
|
- int vert = stbvox_vertex_selector[0][i];
|
|
|
- vert = stbvox_rotate_vertex[vert][rot];
|
|
|
- vmesh[0][i] = stbvox_vmesh_pre_vheight[0][i]
|
|
|
- + cube[vert];
|
|
|
- }
|
|
|
- } else {
|
|
|
+ }
|
|
|
+
|
|
|
+ // build vertex mesh
|
|
|
+ {
|
|
|
int i;
|
|
|
for (i=0; i < 6*4; ++i) {
|
|
|
int vert = stbvox_vertex_selector[0][i];
|
|
@@ -1784,10 +1821,33 @@ void stbvox_make_mesh_for_block_with_geo(stbvox_mesh_maker *mm, stbvox_pos pos,
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- if (visible_faces & (1 << STBVOX_FACE_up))
|
|
|
- stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_up , v_off, pos, basevert, vmesh[STBVOX_FACE_up], mesh);
|
|
|
- if (visible_faces & (1 << STBVOX_FACE_down))
|
|
|
- stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_down, v_off, pos, basevert, vmesh[STBVOX_FACE_down], mesh);
|
|
|
+ // @TODO generate split faces
|
|
|
+ if (visible_faces & (1 << STBVOX_FACE_up)) {
|
|
|
+ #ifndef STBVOX_OPTIMIZED_VHEIGHT
|
|
|
+ // check if it's planar
|
|
|
+ if (geo < STBVOX_GEOM_ceil_vheight_02 && cube[5] + cube[6] != cube[4] + cube[7]) {
|
|
|
+ // not planar, split along diagonal and make degenerate
|
|
|
+ if (geo == STBVOX_GEOM_floor_vheight_02)
|
|
|
+ stbvox_make_02_split_mesh_for_face(mm, rotate, STBVOX_FACE_up, STBVOX_FACE_up, v_off, pos, basevert, vmesh[STBVOX_FACE_up], mesh);
|
|
|
+ else
|
|
|
+ stbvox_make_13_split_mesh_for_face(mm, rotate, STBVOX_FACE_up, STBVOX_FACE_up, v_off, pos, basevert, vmesh[STBVOX_FACE_up], mesh);
|
|
|
+ } else
|
|
|
+ #endif
|
|
|
+ stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_up , v_off, pos, basevert, vmesh[STBVOX_FACE_up], mesh);
|
|
|
+ }
|
|
|
+ if (visible_faces & (1 << STBVOX_FACE_down)) {
|
|
|
+ #ifndef STBVOX_OPTIMIZED_VHEIGHT
|
|
|
+ // check if it's planar
|
|
|
+ if (geo >= STBVOX_GEOM_ceil_vheight_02 && cube[1] + cube[2] != cube[0] + cube[3]) {
|
|
|
+ // not planar, split along diagonal and make degenerate
|
|
|
+ if (geo == STBVOX_GEOM_ceil_vheight_02)
|
|
|
+ stbvox_make_02_split_mesh_for_face(mm, rotate, STBVOX_FACE_down, STBVOX_FACE_down, v_off, pos, basevert, vmesh[STBVOX_FACE_down], mesh);
|
|
|
+ else
|
|
|
+ stbvox_make_13_split_mesh_for_face(mm, rotate, STBVOX_FACE_down, STBVOX_FACE_down, v_off, pos, basevert, vmesh[STBVOX_FACE_down], mesh);
|
|
|
+ } else
|
|
|
+ #endif
|
|
|
+ stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_down, v_off, pos, basevert, vmesh[STBVOX_FACE_down], mesh);
|
|
|
+ }
|
|
|
|
|
|
if (mm->input.rotate) {
|
|
|
unsigned char val = mm->input.rotate[v_off];
|
|
@@ -1799,15 +1859,16 @@ void stbvox_make_mesh_for_block_with_geo(stbvox_mesh_maker *mm, stbvox_pos pos,
|
|
|
rotate.block = rotate.overlay = rotate.tex2 = rotate.ecolor = simple_rot;
|
|
|
}
|
|
|
|
|
|
- if (visible_faces & (1 << STBVOX_FACE_north))
|
|
|
+ if ((visible_faces & (1 << STBVOX_FACE_north)) || (extreme && (ht[2] == 3 || ht[3] == 3)))
|
|
|
stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_north, v_off, pos, basevert, vmesh[STBVOX_FACE_north], mesh);
|
|
|
- if (visible_faces & (1 << STBVOX_FACE_south))
|
|
|
+ if ((visible_faces & (1 << STBVOX_FACE_south)) || (extreme && (ht[0] == 3 || ht[1] == 3)))
|
|
|
stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_south, v_off, pos, basevert, vmesh[STBVOX_FACE_south], mesh);
|
|
|
- if (visible_faces & (1 << STBVOX_FACE_east))
|
|
|
+ if ((visible_faces & (1 << STBVOX_FACE_east)) || (extreme && (ht[1] == 3 || ht[3] == 3)))
|
|
|
stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_east , v_off, pos, basevert, vmesh[STBVOX_FACE_east ], mesh);
|
|
|
- if (visible_faces & (1 << STBVOX_FACE_west))
|
|
|
+ if ((visible_faces & (1 << STBVOX_FACE_west)) || (extreme && (ht[0] == 3 || ht[2] == 3)))
|
|
|
stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_west , v_off, pos, basevert, vmesh[STBVOX_FACE_west ], mesh);
|
|
|
}
|
|
|
+
|
|
|
if (geo == STBVOX_GEOM_crossed_pair) {
|
|
|
// this can be generated with a special vmesh
|
|
|
stbvox_mesh_vertex basevert = stbvox_vertex_p(pos.x, pos.y, pos.z<<mm->precision_z , 0,0);
|