|
@@ -1,4 +1,4 @@
|
|
-// stb_voxel_render.h - v0.77 - Sean Barrett, 2015 - public domain
|
|
|
|
|
|
+// stb_voxel_render.h - v0.78 - Sean Barrett, 2015 - public domain
|
|
//
|
|
//
|
|
// This library helps render large-scale "voxel" worlds for games,
|
|
// This library helps render large-scale "voxel" worlds for games,
|
|
// in this case, one with blocks that can have textures and that
|
|
// in this case, one with blocks that can have textures and that
|
|
@@ -72,7 +72,9 @@
|
|
// - indexed-by-texture-#2-id blend mode (alpha composite or modulate/multiply);
|
|
// - indexed-by-texture-#2-id blend mode (alpha composite or modulate/multiply);
|
|
// the first is good for decals, the second for detail textures, "light maps",
|
|
// the first is good for decals, the second for detail textures, "light maps",
|
|
// etc; both modes are controlled by texture #2's alpha, scaled by the
|
|
// etc; both modes are controlled by texture #2's alpha, scaled by the
|
|
-// per-vertex texture crossfade and the per-face color (if enabled on texture #2)
|
|
|
|
|
|
+// per-vertex texture crossfade and the per-face color (if enabled on texture #2);
|
|
|
|
+// modulate/multiply multiplies by an extra factor of 2.0 so that if you
|
|
|
|
+// make detail maps whose average brightness is 0.5 everything works nicely.
|
|
//
|
|
//
|
|
// - ambient lighting: half-lambert directional plus constant, all scaled by vertex ao
|
|
// - ambient lighting: half-lambert directional plus constant, all scaled by vertex ao
|
|
// - face can be fullbright (emissive), controlled by per-face color
|
|
// - face can be fullbright (emissive), controlled by per-face color
|
|
@@ -168,10 +170,11 @@
|
|
//
|
|
//
|
|
// Features Porting Bugfixes & Warnings
|
|
// Features Porting Bugfixes & Warnings
|
|
// Sean Barrett github:r-leyh Jesus Fernandez
|
|
// Sean Barrett github:r-leyh Jesus Fernandez
|
|
-// Miguel Lechon
|
|
|
|
|
|
+// Miguel Lechon github:Arbeiterunfallversicherungsgesetz
|
|
//
|
|
//
|
|
// VERSION HISTORY
|
|
// VERSION HISTORY
|
|
//
|
|
//
|
|
|
|
+// 0.78 bad "#else", compile as C++
|
|
// 0.77 documentation tweaks, rename config var to STB_VOXEL_RENDER_STATIC
|
|
// 0.77 documentation tweaks, rename config var to STB_VOXEL_RENDER_STATIC
|
|
// 0.76 typos, signed/unsigned shader issue, more documentation
|
|
// 0.76 typos, signed/unsigned shader issue, more documentation
|
|
// 0.75 initial release
|
|
// 0.75 initial release
|
|
@@ -1164,7 +1167,7 @@ struct stbvox_mesh_maker
|
|
typedef stbvox_uint16 stbvox_mesh_vertex;
|
|
typedef stbvox_uint16 stbvox_mesh_vertex;
|
|
#define stbvox_vertex_encode(x,y,z,ao,texlerp) \
|
|
#define stbvox_vertex_encode(x,y,z,ao,texlerp) \
|
|
((stbvox_uint16) ((x)+((z)<<6))+((ao)<<10))
|
|
((stbvox_uint16) ((x)+((z)<<6))+((ao)<<10))
|
|
-#else defined(STBVOX_ICONFIG_VERTEX_8)
|
|
|
|
|
|
+#elif defined(STBVOX_ICONFIG_VERTEX_8)
|
|
typedef stbvox_uint8 stbvox_mesh_vertex;
|
|
typedef stbvox_uint8 stbvox_mesh_vertex;
|
|
#define stbvox_vertex_encode(x,y,z,ao,texlerp) \
|
|
#define stbvox_vertex_encode(x,y,z,ao,texlerp) \
|
|
((stbvox_uint8) ((z)+((ao)<<6))
|
|
((stbvox_uint8) ((z)+((ao)<<6))
|
|
@@ -1255,11 +1258,117 @@ enum
|
|
STBVF_count,
|
|
STBVF_count,
|
|
};
|
|
};
|
|
|
|
|
|
-// get opposite-facing normal & texgen for opposite face, used to map up-facing vheight data to down-facing data
|
|
|
|
-static unsigned char stbvox_reverse_face[STBVF_count];
|
|
|
|
-static float stbvox_default_texgen[2][32][3];
|
|
|
|
-static float stbvox_default_normals[32][3];
|
|
|
|
-static float stbvox_default_texscale[128][4];
|
|
|
|
|
|
+/////////////////////////////////////////////////////////////////////////////
|
|
|
|
+//
|
|
|
|
+// tables -- i'd prefer if these were at the end of the file, but: C++
|
|
|
|
+//
|
|
|
|
+
|
|
|
|
+static float stbvox_default_texgen[2][32][3] =
|
|
|
|
+{
|
|
|
|
+ { { 0, 1,0 }, { 0, 0, 1 }, { 0,-1,0 }, { 0, 0,-1 },
|
|
|
|
+ { -1, 0,0 }, { 0, 0, 1 }, { 1, 0,0 }, { 0, 0,-1 },
|
|
|
|
+ { 0,-1,0 }, { 0, 0, 1 }, { 0, 1,0 }, { 0, 0,-1 },
|
|
|
|
+ { 1, 0,0 }, { 0, 0, 1 }, { -1, 0,0 }, { 0, 0,-1 },
|
|
|
|
+
|
|
|
|
+ { 1, 0,0 }, { 0, 1, 0 }, { -1, 0,0 }, { 0,-1, 0 },
|
|
|
|
+ { -1, 0,0 }, { 0,-1, 0 }, { 1, 0,0 }, { 0, 1, 0 },
|
|
|
|
+ { 1, 0,0 }, { 0, 1, 0 }, { -1, 0,0 }, { 0,-1, 0 },
|
|
|
|
+ { -1, 0,0 }, { 0,-1, 0 }, { 1, 0,0 }, { 0, 1, 0 },
|
|
|
|
+ },
|
|
|
|
+ { { 0, 0,-1 }, { 0, 1,0 }, { 0, 0, 1 }, { 0,-1,0 },
|
|
|
|
+ { 0, 0,-1 }, { -1, 0,0 }, { 0, 0, 1 }, { 1, 0,0 },
|
|
|
|
+ { 0, 0,-1 }, { 0,-1,0 }, { 0, 0, 1 }, { 0, 1,0 },
|
|
|
|
+ { 0, 0,-1 }, { 1, 0,0 }, { 0, 0, 1 }, { -1, 0,0 },
|
|
|
|
+
|
|
|
|
+ { 0,-1, 0 }, { 1, 0,0 }, { 0, 1, 0 }, { -1, 0,0 },
|
|
|
|
+ { 0, 1, 0 }, { -1, 0,0 }, { 0,-1, 0 }, { 1, 0,0 },
|
|
|
|
+ { 0,-1, 0 }, { 1, 0,0 }, { 0, 1, 0 }, { -1, 0,0 },
|
|
|
|
+ { 0, 1, 0 }, { -1, 0,0 }, { 0,-1, 0 }, { 1, 0,0 },
|
|
|
|
+ },
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+#define STBVOX_RSQRT2 0.7071067811865f
|
|
|
|
+#define STBVOX_RSQRT3 0.5773502691896f
|
|
|
|
+
|
|
|
|
+static float stbvox_default_normals[32][3] =
|
|
|
|
+{
|
|
|
|
+ { 1,0,0 }, // east
|
|
|
|
+ { 0,1,0 }, // north
|
|
|
|
+ { -1,0,0 }, // west
|
|
|
|
+ { 0,-1,0 }, // south
|
|
|
|
+ { 0,0,1 }, // up
|
|
|
|
+ { 0,0,-1 }, // down
|
|
|
|
+ { STBVOX_RSQRT2,0, STBVOX_RSQRT2 }, // east & up
|
|
|
|
+ { STBVOX_RSQRT2,0, -STBVOX_RSQRT2 }, // east & down
|
|
|
|
+
|
|
|
|
+ { STBVOX_RSQRT2,0, STBVOX_RSQRT2 }, // east & up
|
|
|
|
+ { 0, STBVOX_RSQRT2, STBVOX_RSQRT2 }, // north & up
|
|
|
|
+ { -STBVOX_RSQRT2,0, STBVOX_RSQRT2 }, // west & up
|
|
|
|
+ { 0,-STBVOX_RSQRT2, STBVOX_RSQRT2 }, // south & up
|
|
|
|
+ { STBVOX_RSQRT3, STBVOX_RSQRT3, STBVOX_RSQRT3 }, // ne & up
|
|
|
|
+ { STBVOX_RSQRT3, STBVOX_RSQRT3,-STBVOX_RSQRT3 }, // ne & down
|
|
|
|
+ { 0, STBVOX_RSQRT2, STBVOX_RSQRT2 }, // north & up
|
|
|
|
+ { 0, STBVOX_RSQRT2, -STBVOX_RSQRT2 }, // north & down
|
|
|
|
+
|
|
|
|
+ { STBVOX_RSQRT2,0, -STBVOX_RSQRT2 }, // east & down
|
|
|
|
+ { 0, STBVOX_RSQRT2, -STBVOX_RSQRT2 }, // north & down
|
|
|
|
+ { -STBVOX_RSQRT2,0, -STBVOX_RSQRT2 }, // west & down
|
|
|
|
+ { 0,-STBVOX_RSQRT2, -STBVOX_RSQRT2 }, // south & down
|
|
|
|
+ { -STBVOX_RSQRT3, STBVOX_RSQRT3, STBVOX_RSQRT3 }, // NW & up
|
|
|
|
+ { -STBVOX_RSQRT3, STBVOX_RSQRT3,-STBVOX_RSQRT3 }, // NW & down
|
|
|
|
+ { -STBVOX_RSQRT2,0, STBVOX_RSQRT2 }, // west & up
|
|
|
|
+ { -STBVOX_RSQRT2,0, -STBVOX_RSQRT2 }, // west & down
|
|
|
|
+
|
|
|
|
+ { STBVOX_RSQRT3, STBVOX_RSQRT3,STBVOX_RSQRT3 }, // NE & up crossed
|
|
|
|
+ { -STBVOX_RSQRT3, STBVOX_RSQRT3,STBVOX_RSQRT3 }, // NW & up crossed
|
|
|
|
+ { -STBVOX_RSQRT3,-STBVOX_RSQRT3,STBVOX_RSQRT3 }, // SW & up crossed
|
|
|
|
+ { STBVOX_RSQRT3,-STBVOX_RSQRT3,STBVOX_RSQRT3 }, // SE & up crossed
|
|
|
|
+ { -STBVOX_RSQRT3,-STBVOX_RSQRT3, STBVOX_RSQRT3 }, // SW & up
|
|
|
|
+ { -STBVOX_RSQRT3,-STBVOX_RSQRT3,-STBVOX_RSQRT3 }, // SW & up
|
|
|
|
+ { 0,-STBVOX_RSQRT2, STBVOX_RSQRT2 }, // south & up
|
|
|
|
+ { 0,-STBVOX_RSQRT2, -STBVOX_RSQRT2 }, // south & down
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static float stbvox_default_texscale[128][4] =
|
|
|
|
+{
|
|
|
|
+ {1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},
|
|
|
|
+ {1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},
|
|
|
|
+ {1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},
|
|
|
|
+ {1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},
|
|
|
|
+ {1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},
|
|
|
|
+ {1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},
|
|
|
|
+ {1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},
|
|
|
|
+ {1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},
|
|
|
|
+ {1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},
|
|
|
|
+ {1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},
|
|
|
|
+ {1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},
|
|
|
|
+ {1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},
|
|
|
|
+ {1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},
|
|
|
|
+ {1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},
|
|
|
|
+ {1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},
|
|
|
|
+ {1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static unsigned char stbvox_default_palette_compact[64][3] =
|
|
|
|
+{
|
|
|
|
+ { 255,255,255 }, { 238,238,238 }, { 221,221,221 }, { 204,204,204 },
|
|
|
|
+ { 187,187,187 }, { 170,170,170 }, { 153,153,153 }, { 136,136,136 },
|
|
|
|
+ { 119,119,119 }, { 102,102,102 }, { 85, 85, 85 }, { 68, 68, 68 },
|
|
|
|
+ { 51, 51, 51 }, { 34, 34, 34 }, { 17, 17, 17 }, { 0, 0, 0 },
|
|
|
|
+ { 255,240,240 }, { 255,220,220 }, { 255,160,160 }, { 255, 32, 32 },
|
|
|
|
+ { 200,120,160 }, { 200, 60,150 }, { 220,100,130 }, { 255, 0,128 },
|
|
|
|
+ { 240,240,255 }, { 220,220,255 }, { 160,160,255 }, { 32, 32,255 },
|
|
|
|
+ { 120,160,200 }, { 60,150,200 }, { 100,130,220 }, { 0,128,255 },
|
|
|
|
+ { 240,255,240 }, { 220,255,220 }, { 160,255,160 }, { 32,255, 32 },
|
|
|
|
+ { 160,200,120 }, { 150,200, 60 }, { 130,220,100 }, { 128,255, 0 },
|
|
|
|
+ { 255,255,240 }, { 255,255,220 }, { 220,220,180 }, { 255,255, 32 },
|
|
|
|
+ { 200,160,120 }, { 200,150, 60 }, { 220,130,100 }, { 255,128, 0 },
|
|
|
|
+ { 255,240,255 }, { 255,220,255 }, { 220,180,220 }, { 255, 32,255 },
|
|
|
|
+ { 160,120,200 }, { 150, 60,200 }, { 130,100,220 }, { 128, 0,255 },
|
|
|
|
+ { 240,255,255 }, { 220,255,255 }, { 180,220,220 }, { 32,255,255 },
|
|
|
|
+ { 120,200,160 }, { 60,200,150 }, { 100,220,130 }, { 0,255,128 },
|
|
|
|
+};
|
|
|
|
+
|
|
static float stbvox_default_ambient[4][4] =
|
|
static float stbvox_default_ambient[4][4] =
|
|
{
|
|
{
|
|
{ 0,0,1 ,0 }, // reversed lighting direction
|
|
{ 0,0,1 ,0 }, // reversed lighting direction
|
|
@@ -1268,7 +1377,6 @@ static float stbvox_default_ambient[4][4] =
|
|
{ 0.5,0.5,0.5,1.0f/1000.0f/1000.0f }, // fog data for simple_fog
|
|
{ 0.5,0.5,0.5,1.0f/1000.0f/1000.0f }, // fog data for simple_fog
|
|
};
|
|
};
|
|
|
|
|
|
-static unsigned char stbvox_default_palette_compact[64][3];
|
|
|
|
static float stbvox_default_palette[64][4];
|
|
static float stbvox_default_palette[64][4];
|
|
|
|
|
|
static void stbvox_build_default_palette(void)
|
|
static void stbvox_build_default_palette(void)
|
|
@@ -1381,7 +1489,7 @@ static char *stbvox_fragment_program =
|
|
#if defined(STBVOX_ICONFIG_GLSL)
|
|
#if defined(STBVOX_ICONFIG_GLSL)
|
|
"#define rlerp(t,x,y) mix(x,y,t)\n"
|
|
"#define rlerp(t,x,y) mix(x,y,t)\n"
|
|
#elif defined(STBVOX_CONFIG_HLSL)
|
|
#elif defined(STBVOX_CONFIG_HLSL)
|
|
- "#define rlerp(t,x,y) lerp(x,t,y)\n"
|
|
|
|
|
|
+ "#define rlerp(t,x,y) lerp(x,y,t)\n"
|
|
#else
|
|
#else
|
|
#error "need definition of rlerp()"
|
|
#error "need definition of rlerp()"
|
|
#endif
|
|
#endif
|
|
@@ -1872,1593 +1980,1442 @@ stbvox_mesh_face stbvox_compute_mesh_face_value(stbvox_mesh_maker *mm, stbvox_ro
|
|
return face_data;
|
|
return face_data;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+// these are the types of faces each block can have
|
|
|
|
+enum
|
|
|
|
+{
|
|
|
|
+ STBVOX_FT_none ,
|
|
|
|
+ STBVOX_FT_upper ,
|
|
|
|
+ STBVOX_FT_lower ,
|
|
|
|
+ STBVOX_FT_solid ,
|
|
|
|
+ STBVOX_FT_diag_012,
|
|
|
|
+ STBVOX_FT_diag_023,
|
|
|
|
+ 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
|
|
|
|
+
|
|
|
|
+ STBVOX_FT_count
|
|
|
|
+};
|
|
|
|
+
|
|
static unsigned char stbvox_face_lerp[6] = { 0,2,0,2,4,4 };
|
|
static unsigned char stbvox_face_lerp[6] = { 0,2,0,2,4,4 };
|
|
static unsigned char stbvox_vert3_lerp[5] = { 0,3,6,9,12 };
|
|
static unsigned char stbvox_vert3_lerp[5] = { 0,3,6,9,12 };
|
|
static unsigned char stbvox_vert_lerp_for_face_lerp[4] = { 0, 4, 7, 7 };
|
|
static unsigned char stbvox_vert_lerp_for_face_lerp[4] = { 0, 4, 7, 7 };
|
|
static unsigned char stbvox_face3_lerp[6] = { 0,3,6,9,12,14 };
|
|
static unsigned char stbvox_face3_lerp[6] = { 0,3,6,9,12,14 };
|
|
static unsigned char stbvox_vert_lerp_for_simple[4] = { 0,2,5,7 };
|
|
static unsigned char stbvox_vert_lerp_for_simple[4] = { 0,2,5,7 };
|
|
static unsigned char stbvox_face3_updown[8] = { 0,2,5,7,0,2,5,7 }; // ignore top bit
|
|
static unsigned char stbvox_face3_updown[8] = { 0,2,5,7,0,2,5,7 }; // ignore top bit
|
|
|
|
+
|
|
// vertex offsets for face vertices
|
|
// vertex offsets for face vertices
|
|
-static unsigned char stbvox_vertex_vector[6][4][3];
|
|
|
|
-static stbvox_mesh_vertex stbvox_vmesh_delta_normal[6][4];
|
|
|
|
-static stbvox_mesh_vertex stbvox_vmesh_pre_vheight[6][4];
|
|
|
|
-static stbvox_mesh_vertex stbvox_vmesh_delta_half_z[6][4];
|
|
|
|
-static stbvox_mesh_vertex stbvox_vmesh_crossed_pair[6][4];
|
|
|
|
|
|
+static unsigned char stbvox_vertex_vector[6][4][3] =
|
|
|
|
+{
|
|
|
|
+ { { 1,0,1 }, { 1,1,1 }, { 1,1,0 }, { 1,0,0 } }, // east
|
|
|
|
+ { { 1,1,1 }, { 0,1,1 }, { 0,1,0 }, { 1,1,0 } }, // north
|
|
|
|
+ { { 0,1,1 }, { 0,0,1 }, { 0,0,0 }, { 0,1,0 } }, // west
|
|
|
|
+ { { 0,0,1 }, { 1,0,1 }, { 1,0,0 }, { 0,0,0 } }, // south
|
|
|
|
+ { { 0,1,1 }, { 1,1,1 }, { 1,0,1 }, { 0,0,1 } }, // up
|
|
|
|
+ { { 0,0,0 }, { 1,0,0 }, { 1,1,0 }, { 0,1,0 } }, // down
|
|
|
|
+};
|
|
|
|
|
|
// stbvox_vertex_vector, but read coordinates as binary numbers, zyx
|
|
// stbvox_vertex_vector, but read coordinates as binary numbers, zyx
|
|
-static unsigned char stbvox_vertex_selector[6][4];
|
|
|
|
-
|
|
|
|
-void stbvox_get_quad_vertex_pointer(stbvox_mesh_maker *mm, int mesh, stbvox_mesh_vertex **vertices, stbvox_mesh_face face)
|
|
|
|
|
|
+static unsigned char stbvox_vertex_selector[6][4] =
|
|
{
|
|
{
|
|
- char *p = mm->output_cur[mesh][0];
|
|
|
|
- int step = mm->output_step[mesh][0];
|
|
|
|
-
|
|
|
|
- // allocate a new quad from the mesh
|
|
|
|
- vertices[0] = (stbvox_mesh_vertex *) p; p += step;
|
|
|
|
- vertices[1] = (stbvox_mesh_vertex *) p; p += step;
|
|
|
|
- vertices[2] = (stbvox_mesh_vertex *) p; p += step;
|
|
|
|
- vertices[3] = (stbvox_mesh_vertex *) p; p += step;
|
|
|
|
- mm->output_cur[mesh][0] = p;
|
|
|
|
-
|
|
|
|
- // output the face
|
|
|
|
- #ifdef STBVOX_ICONFIG_FACE_ATTRIBUTE
|
|
|
|
- // write face as interleaved vertex data
|
|
|
|
- *(stbvox_mesh_face *) (vertices[0]+1) = face;
|
|
|
|
- *(stbvox_mesh_face *) (vertices[1]+1) = face;
|
|
|
|
- *(stbvox_mesh_face *) (vertices[2]+1) = face;
|
|
|
|
- *(stbvox_mesh_face *) (vertices[3]+1) = face;
|
|
|
|
- #else
|
|
|
|
- *(stbvox_mesh_face *) mm->output_cur[mesh][1] = face;
|
|
|
|
- mm->output_cur[mesh][1] += 4;
|
|
|
|
- #endif
|
|
|
|
-}
|
|
|
|
|
|
+ { 5,7,3,1 },
|
|
|
|
+ { 7,6,2,3 },
|
|
|
|
+ { 6,4,0,2 },
|
|
|
|
+ { 4,5,1,0 },
|
|
|
|
+ { 6,7,5,4 },
|
|
|
|
+ { 0,1,3,2 },
|
|
|
|
+};
|
|
|
|
|
|
-void stbvox_make_mesh_for_face(stbvox_mesh_maker *mm, stbvox_rotate rot, int face, int v_off, stbvox_pos pos, stbvox_mesh_vertex vertbase, stbvox_mesh_vertex *face_coord, unsigned char mesh, int normal)
|
|
|
|
|
|
+static stbvox_mesh_vertex stbvox_vmesh_delta_normal[6][4] =
|
|
{
|
|
{
|
|
- stbvox_mesh_face face_data = stbvox_compute_mesh_face_value(mm,rot,face,v_off, normal);
|
|
|
|
|
|
+ { stbvox_vertex_encode(1,0,1,0,0) ,
|
|
|
|
+ stbvox_vertex_encode(1,1,1,0,0) ,
|
|
|
|
+ stbvox_vertex_encode(1,1,0,0,0) ,
|
|
|
|
+ stbvox_vertex_encode(1,0,0,0,0) },
|
|
|
|
+ { stbvox_vertex_encode(1,1,1,0,0) ,
|
|
|
|
+ stbvox_vertex_encode(0,1,1,0,0) ,
|
|
|
|
+ stbvox_vertex_encode(0,1,0,0,0) ,
|
|
|
|
+ stbvox_vertex_encode(1,1,0,0,0) },
|
|
|
|
+ { stbvox_vertex_encode(0,1,1,0,0) ,
|
|
|
|
+ stbvox_vertex_encode(0,0,1,0,0) ,
|
|
|
|
+ stbvox_vertex_encode(0,0,0,0,0) ,
|
|
|
|
+ stbvox_vertex_encode(0,1,0,0,0) },
|
|
|
|
+ { stbvox_vertex_encode(0,0,1,0,0) ,
|
|
|
|
+ stbvox_vertex_encode(1,0,1,0,0) ,
|
|
|
|
+ stbvox_vertex_encode(1,0,0,0,0) ,
|
|
|
|
+ stbvox_vertex_encode(0,0,0,0,0) },
|
|
|
|
+ { stbvox_vertex_encode(0,1,1,0,0) ,
|
|
|
|
+ stbvox_vertex_encode(1,1,1,0,0) ,
|
|
|
|
+ stbvox_vertex_encode(1,0,1,0,0) ,
|
|
|
|
+ stbvox_vertex_encode(0,0,1,0,0) },
|
|
|
|
+ { stbvox_vertex_encode(0,0,0,0,0) ,
|
|
|
|
+ stbvox_vertex_encode(1,0,0,0,0) ,
|
|
|
|
+ stbvox_vertex_encode(1,1,0,0,0) ,
|
|
|
|
+ stbvox_vertex_encode(0,1,0,0,0) }
|
|
|
|
+};
|
|
|
|
|
|
- // still need to compute ao & texlerp for each vertex
|
|
|
|
|
|
+static stbvox_mesh_vertex stbvox_vmesh_pre_vheight[6][4] =
|
|
|
|
+{
|
|
|
|
+ { stbvox_vertex_encode(1,0,0,0,0) ,
|
|
|
|
+ stbvox_vertex_encode(1,1,0,0,0) ,
|
|
|
|
+ stbvox_vertex_encode(1,1,0,0,0) ,
|
|
|
|
+ stbvox_vertex_encode(1,0,0,0,0) },
|
|
|
|
+ { stbvox_vertex_encode(1,1,0,0,0) ,
|
|
|
|
+ stbvox_vertex_encode(0,1,0,0,0) ,
|
|
|
|
+ stbvox_vertex_encode(0,1,0,0,0) ,
|
|
|
|
+ stbvox_vertex_encode(1,1,0,0,0) },
|
|
|
|
+ { stbvox_vertex_encode(0,1,0,0,0) ,
|
|
|
|
+ stbvox_vertex_encode(0,0,0,0,0) ,
|
|
|
|
+ stbvox_vertex_encode(0,0,0,0,0) ,
|
|
|
|
+ stbvox_vertex_encode(0,1,0,0,0) },
|
|
|
|
+ { stbvox_vertex_encode(0,0,0,0,0) ,
|
|
|
|
+ stbvox_vertex_encode(1,0,0,0,0) ,
|
|
|
|
+ stbvox_vertex_encode(1,0,0,0,0) ,
|
|
|
|
+ stbvox_vertex_encode(0,0,0,0,0) },
|
|
|
|
+ { stbvox_vertex_encode(0,1,0,0,0) ,
|
|
|
|
+ stbvox_vertex_encode(1,1,0,0,0) ,
|
|
|
|
+ stbvox_vertex_encode(1,0,0,0,0) ,
|
|
|
|
+ stbvox_vertex_encode(0,0,0,0,0) },
|
|
|
|
+ { stbvox_vertex_encode(0,0,0,0,0) ,
|
|
|
|
+ stbvox_vertex_encode(1,0,0,0,0) ,
|
|
|
|
+ stbvox_vertex_encode(1,1,0,0,0) ,
|
|
|
|
+ stbvox_vertex_encode(0,1,0,0,0) }
|
|
|
|
+};
|
|
|
|
|
|
- // first compute texlerp into p1
|
|
|
|
- stbvox_mesh_vertex p1[4] = { 0 };
|
|
|
|
|
|
+static stbvox_mesh_vertex stbvox_vmesh_delta_half_z[6][4] =
|
|
|
|
+{
|
|
|
|
+ { stbvox_vertex_encode(1,0,2,0,0) ,
|
|
|
|
+ stbvox_vertex_encode(1,1,2,0,0) ,
|
|
|
|
+ stbvox_vertex_encode(1,1,0,0,0) ,
|
|
|
|
+ stbvox_vertex_encode(1,0,0,0,0) },
|
|
|
|
+ { stbvox_vertex_encode(1,1,2,0,0) ,
|
|
|
|
+ stbvox_vertex_encode(0,1,2,0,0) ,
|
|
|
|
+ stbvox_vertex_encode(0,1,0,0,0) ,
|
|
|
|
+ stbvox_vertex_encode(1,1,0,0,0) },
|
|
|
|
+ { stbvox_vertex_encode(0,1,2,0,0) ,
|
|
|
|
+ stbvox_vertex_encode(0,0,2,0,0) ,
|
|
|
|
+ stbvox_vertex_encode(0,0,0,0,0) ,
|
|
|
|
+ stbvox_vertex_encode(0,1,0,0,0) },
|
|
|
|
+ { stbvox_vertex_encode(0,0,2,0,0) ,
|
|
|
|
+ stbvox_vertex_encode(1,0,2,0,0) ,
|
|
|
|
+ stbvox_vertex_encode(1,0,0,0,0) ,
|
|
|
|
+ stbvox_vertex_encode(0,0,0,0,0) },
|
|
|
|
+ { stbvox_vertex_encode(0,1,2,0,0) ,
|
|
|
|
+ stbvox_vertex_encode(1,1,2,0,0) ,
|
|
|
|
+ stbvox_vertex_encode(1,0,2,0,0) ,
|
|
|
|
+ stbvox_vertex_encode(0,0,2,0,0) },
|
|
|
|
+ { stbvox_vertex_encode(0,0,0,0,0) ,
|
|
|
|
+ stbvox_vertex_encode(1,0,0,0,0) ,
|
|
|
|
+ stbvox_vertex_encode(1,1,0,0,0) ,
|
|
|
|
+ stbvox_vertex_encode(0,1,0,0,0) }
|
|
|
|
+};
|
|
|
|
|
|
- if (mm->input.block_texlerp) {
|
|
|
|
- stbvox_block_type bt = mm->input.blocktype[v_off];
|
|
|
|
- unsigned char val = mm->input.block_texlerp[bt];
|
|
|
|
- p1[0] = p1[1] = p1[2] = p1[3] = stbvox_vertex_encode(0,0,0,0,val);
|
|
|
|
- } else if (mm->input.block_texlerp_face) {
|
|
|
|
- stbvox_block_type bt = mm->input.blocktype[v_off];
|
|
|
|
- unsigned char bt_face = STBVOX_ROTATE(face, rot.block);
|
|
|
|
- unsigned char val = mm->input.block_texlerp_face[bt][bt_face];
|
|
|
|
- p1[0] = p1[1] = p1[2] = p1[3] = stbvox_vertex_encode(0,0,0,0,val);
|
|
|
|
- } else if (mm->input.texlerp_face3) {
|
|
|
|
- unsigned char val = (mm->input.texlerp_face3[v_off] >> stbvox_face3_lerp[face]) & 7;
|
|
|
|
- if (face >= STBVOX_FACE_up)
|
|
|
|
- val = stbvox_face3_updown[val];
|
|
|
|
- p1[0] = p1[1] = p1[2] = p1[3] = stbvox_vertex_encode(0,0,0,0,val);
|
|
|
|
- } else if (mm->input.texlerp_simple) {
|
|
|
|
- unsigned char val = mm->input.texlerp_simple[v_off];
|
|
|
|
- unsigned char lerp_face = (val >> 2) & 7;
|
|
|
|
- if (lerp_face == face) {
|
|
|
|
- p1[0] = (mm->input.texlerp_simple[v_off + mm->cube_vertex_offset[face][0]] >> 5) & 7;
|
|
|
|
- p1[1] = (mm->input.texlerp_simple[v_off + mm->cube_vertex_offset[face][1]] >> 5) & 7;
|
|
|
|
- p1[2] = (mm->input.texlerp_simple[v_off + mm->cube_vertex_offset[face][2]] >> 5) & 7;
|
|
|
|
- p1[3] = (mm->input.texlerp_simple[v_off + mm->cube_vertex_offset[face][3]] >> 5) & 7;
|
|
|
|
- p1[0] = stbvox_vertex_encode(0,0,0,0,p1[0]);
|
|
|
|
- p1[1] = stbvox_vertex_encode(0,0,0,0,p1[1]);
|
|
|
|
- p1[2] = stbvox_vertex_encode(0,0,0,0,p1[2]);
|
|
|
|
- p1[3] = stbvox_vertex_encode(0,0,0,0,p1[3]);
|
|
|
|
- } else {
|
|
|
|
- unsigned char base = stbvox_vert_lerp_for_simple[val&3];
|
|
|
|
- p1[0] = p1[1] = p1[2] = p1[3] = stbvox_vertex_encode(0,0,0,0,base);
|
|
|
|
- }
|
|
|
|
- } else if (mm->input.texlerp) {
|
|
|
|
- unsigned char facelerp = (mm->input.texlerp[v_off] >> stbvox_face_lerp[face]) & 3;
|
|
|
|
- if (facelerp == STBVOX_TEXLERP_FACE_use_vert) {
|
|
|
|
- if (mm->input.texlerp_vert3 && face != STBVOX_FACE_down) {
|
|
|
|
- unsigned char shift = stbvox_vert3_lerp[face];
|
|
|
|
- p1[0] = (mm->input.texlerp_vert3[mm->cube_vertex_offset[face][0]] >> shift) & 7;
|
|
|
|
- p1[1] = (mm->input.texlerp_vert3[mm->cube_vertex_offset[face][1]] >> shift) & 7;
|
|
|
|
- p1[2] = (mm->input.texlerp_vert3[mm->cube_vertex_offset[face][2]] >> shift) & 7;
|
|
|
|
- p1[3] = (mm->input.texlerp_vert3[mm->cube_vertex_offset[face][3]] >> shift) & 7;
|
|
|
|
- } else {
|
|
|
|
- p1[0] = stbvox_vert_lerp_for_simple[mm->input.texlerp[mm->cube_vertex_offset[face][0]]>>6];
|
|
|
|
- p1[1] = stbvox_vert_lerp_for_simple[mm->input.texlerp[mm->cube_vertex_offset[face][1]]>>6];
|
|
|
|
- p1[2] = stbvox_vert_lerp_for_simple[mm->input.texlerp[mm->cube_vertex_offset[face][2]]>>6];
|
|
|
|
- p1[3] = stbvox_vert_lerp_for_simple[mm->input.texlerp[mm->cube_vertex_offset[face][3]]>>6];
|
|
|
|
- }
|
|
|
|
- p1[0] = stbvox_vertex_encode(0,0,0,0,p1[0]);
|
|
|
|
- p1[1] = stbvox_vertex_encode(0,0,0,0,p1[1]);
|
|
|
|
- p1[2] = stbvox_vertex_encode(0,0,0,0,p1[2]);
|
|
|
|
- p1[3] = stbvox_vertex_encode(0,0,0,0,p1[3]);
|
|
|
|
- } else {
|
|
|
|
- p1[0] = p1[1] = p1[2] = p1[3] = stbvox_vertex_encode(0,0,0,0,stbvox_vert_lerp_for_face_lerp[facelerp]);
|
|
|
|
- }
|
|
|
|
- } else {
|
|
|
|
- p1[0] = p1[1] = p1[2] = p1[3] = stbvox_vertex_encode(0,0,0,0,7);
|
|
|
|
- }
|
|
|
|
|
|
+static stbvox_mesh_vertex stbvox_vmesh_crossed_pair[6][4] =
|
|
|
|
+{
|
|
|
|
+ { stbvox_vertex_encode(1,0,2,0,0) ,
|
|
|
|
+ stbvox_vertex_encode(0,1,2,0,0) ,
|
|
|
|
+ stbvox_vertex_encode(0,1,0,0,0) ,
|
|
|
|
+ stbvox_vertex_encode(1,0,0,0,0) },
|
|
|
|
+ { stbvox_vertex_encode(1,1,2,0,0) ,
|
|
|
|
+ stbvox_vertex_encode(0,0,2,0,0) ,
|
|
|
|
+ stbvox_vertex_encode(0,0,0,0,0) ,
|
|
|
|
+ stbvox_vertex_encode(1,1,0,0,0) },
|
|
|
|
+ { stbvox_vertex_encode(0,1,2,0,0) ,
|
|
|
|
+ stbvox_vertex_encode(1,0,2,0,0) ,
|
|
|
|
+ stbvox_vertex_encode(1,0,0,0,0) ,
|
|
|
|
+ stbvox_vertex_encode(0,1,0,0,0) },
|
|
|
|
+ { stbvox_vertex_encode(0,0,2,0,0) ,
|
|
|
|
+ stbvox_vertex_encode(1,1,2,0,0) ,
|
|
|
|
+ stbvox_vertex_encode(1,1,0,0,0) ,
|
|
|
|
+ stbvox_vertex_encode(0,0,0,0,0) },
|
|
|
|
+ // not used, so we leave it non-degenerate to make sure it doesn't get gen'd accidentally
|
|
|
|
+ { stbvox_vertex_encode(0,1,2,0,0) ,
|
|
|
|
+ stbvox_vertex_encode(1,1,2,0,0) ,
|
|
|
|
+ stbvox_vertex_encode(1,0,2,0,0) ,
|
|
|
|
+ stbvox_vertex_encode(0,0,2,0,0) },
|
|
|
|
+ { stbvox_vertex_encode(0,0,0,0,0) ,
|
|
|
|
+ stbvox_vertex_encode(1,0,0,0,0) ,
|
|
|
|
+ stbvox_vertex_encode(1,1,0,0,0) ,
|
|
|
|
+ stbvox_vertex_encode(0,1,0,0,0) }
|
|
|
|
+};
|
|
|
|
|
|
- {
|
|
|
|
- stbvox_mesh_vertex *mv[4];
|
|
|
|
- stbvox_get_quad_vertex_pointer(mm, mesh, mv, face_data);
|
|
|
|
|
|
+#define STBVOX_MAX_GEOM 16
|
|
|
|
+#define STBVOX_NUM_ROTATION 4
|
|
|
|
|
|
- if (mm->input.lighting) {
|
|
|
|
- // @TODO: lighting at block centers, but not gathered, instead constant-per-face
|
|
|
|
- if (mm->input.lighting_at_vertices) {
|
|
|
|
- int i;
|
|
|
|
- for (i=0; i < 4; ++i) {
|
|
|
|
- *mv[i] = vertbase + face_coord[i]
|
|
|
|
- + stbvox_vertex_encode(0,0,0,mm->input.lighting[v_off + mm->cube_vertex_offset[face][i]] & 63,0)
|
|
|
|
- + p1[i];
|
|
|
|
- }
|
|
|
|
- } else {
|
|
|
|
- unsigned char *amb = &mm->input.lighting[v_off];
|
|
|
|
- int i,j;
|
|
|
|
- #ifdef STBVOX_ROTATION_IN_LIGHTING
|
|
|
|
- #define STBVOX_GET_LIGHTING(light) ((light) & ~3)
|
|
|
|
- #define STBVOX_LIGHTING_ROUNDOFF 8
|
|
|
|
- #else
|
|
|
|
- #define STBVOX_GET_LIGHTING(light) (light)
|
|
|
|
- #define STBVOX_LIGHTING_ROUNDOFF 2
|
|
|
|
- #endif
|
|
|
|
|
|
+// this is used to determine if a face is ever generated at all
|
|
|
|
+static unsigned char stbvox_hasface[STBVOX_MAX_GEOM][STBVOX_NUM_ROTATION] =
|
|
|
|
+{
|
|
|
|
+ { 0,0,0,0 }, // empty
|
|
|
|
+ { 0,0,0,0 }, // knockout
|
|
|
|
+ { 63,63,63,63 }, // solid
|
|
|
|
+ { 63,63,63,63 }, // transp
|
|
|
|
+ { 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 }, // force
|
|
|
|
+ { 63,63,63,63 },
|
|
|
|
+ { 63,63,63,63 },
|
|
|
|
+ { 63,63,63,63 },
|
|
|
|
+ { 63,63,63,63 },
|
|
|
|
+};
|
|
|
|
|
|
- for (i=0; i < 4; ++i) {
|
|
|
|
- // for each vertex, gather from the four neighbor blocks it's facing
|
|
|
|
- unsigned char *vamb = &amb[mm->cube_vertex_offset[face][i]];
|
|
|
|
- int total=0;
|
|
|
|
- for (j=0; j < 4; ++j)
|
|
|
|
- total += STBVOX_GET_LIGHTING(vamb[mm->vertex_gather_offset[face][j]]);
|
|
|
|
- *mv[i] = vertbase + face_coord[i]
|
|
|
|
- + stbvox_vertex_encode(0,0,0,(total+STBVOX_LIGHTING_ROUNDOFF)>>4,0)
|
|
|
|
- + p1[i];
|
|
|
|
- // >> 4 is because:
|
|
|
|
- // >> 2 to divide by 4 to get average over 4 samples
|
|
|
|
- // >> 2 because input is 8 bits, output is 6 bits
|
|
|
|
- }
|
|
|
|
|
|
+// this determines which face type above is visible on each side of the geometry
|
|
|
|
+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
|
|
|
|
+ { STBVOX_FT_solid, STBVOX_FT_solid, STBVOX_FT_solid, STBVOX_FT_solid, STBVOX_FT_solid, STBVOX_FT_solid }, // solid
|
|
|
|
+ { STBVOX_FT_force, STBVOX_FT_force, STBVOX_FT_force, STBVOX_FT_force, STBVOX_FT_force, STBVOX_FT_force }, // transp
|
|
|
|
|
|
- // @TODO: note that gathering baked *lighting*
|
|
|
|
- // is different from gathering baked ao; baked ao can count
|
|
|
|
- // solid blocks as 0 ao, but baked lighting wants average
|
|
|
|
- // of non-blocked--not take average & treat blocked as 0. And
|
|
|
|
- // we can't bake the right value into the solid blocks
|
|
|
|
- // because they can have different lighting values on
|
|
|
|
- // different sides. So we need to actually gather and
|
|
|
|
- // then divide by 0..4 (which we can do with a table-driven
|
|
|
|
- // multiply, or have an 'if' for the 3 case)
|
|
|
|
|
|
+ { STBVOX_FT_upper, STBVOX_FT_upper, STBVOX_FT_upper, STBVOX_FT_upper, STBVOX_FT_solid, STBVOX_FT_force },
|
|
|
|
+ { STBVOX_FT_lower, STBVOX_FT_lower, STBVOX_FT_lower, STBVOX_FT_lower, STBVOX_FT_force, STBVOX_FT_solid },
|
|
|
|
+ { STBVOX_FT_diag_123, STBVOX_FT_solid, STBVOX_FT_diag_023, STBVOX_FT_none, STBVOX_FT_force, STBVOX_FT_solid },
|
|
|
|
+ { STBVOX_FT_diag_012, STBVOX_FT_solid, STBVOX_FT_diag_013, STBVOX_FT_none, STBVOX_FT_solid, STBVOX_FT_force },
|
|
|
|
|
|
- }
|
|
|
|
- } else {
|
|
|
|
- vertbase += stbvox_vertex_encode(0,0,0,63,0);
|
|
|
|
- *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];
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
|
|
+ { 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 }, // GEOM_force
|
|
|
|
|
|
-#ifndef STBVOX_OPTIMIZED_VHEIGHT
|
|
|
|
-static stbvox_face_up_normal_012[4][4][4];
|
|
|
|
-static stbvox_face_up_normal_013[4][4][4];
|
|
|
|
-static stbvox_face_up_normal_023[4][4][4];
|
|
|
|
-static stbvox_face_up_normal_123[4][4][4];
|
|
|
|
|
|
+ { 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
|
|
|
|
+};
|
|
|
|
|
|
-// render non-planar quads by splitting into two triangles, rendering each as a degenerate quad
|
|
|
|
-static void stbvox_make_12_split_mesh_for_face(stbvox_mesh_maker *mm, stbvox_rotate rot, int face, int v_off, stbvox_pos pos, stbvox_mesh_vertex vertbase, stbvox_mesh_vertex *face_coord, unsigned char mesh, unsigned char *ht)
|
|
|
|
|
|
+// This table indicates what normal to use for the "up" face of a sloped geom
|
|
|
|
+// @TODO this could be done with math given the current arrangement of the enum, but let's not require it
|
|
|
|
+static unsigned char stbvox_floor_slope_for_rot[4] =
|
|
{
|
|
{
|
|
- stbvox_mesh_vertex v[4];
|
|
|
|
-
|
|
|
|
- unsigned char normal1 = stbvox_face_up_normal_012[ht[2]][ht[1]][ht[0]];
|
|
|
|
- unsigned char normal2 = stbvox_face_up_normal_123[ht[3]][ht[2]][ht[1]];
|
|
|
|
|
|
+ STBVF_su,
|
|
|
|
+ STBVF_wu, // @TODO: why is this reversed from what it should be? this is a north-is-up face, so slope should be south&up
|
|
|
|
+ STBVF_nu,
|
|
|
|
+ STBVF_eu,
|
|
|
|
+};
|
|
|
|
|
|
- if (face == STBVOX_FACE_down) {
|
|
|
|
- normal1 = stbvox_reverse_face[normal1];
|
|
|
|
- normal2 = stbvox_reverse_face[normal2];
|
|
|
|
- }
|
|
|
|
|
|
+static unsigned char stbvox_ceil_slope_for_rot[4] =
|
|
|
|
+{
|
|
|
|
+ STBVF_sd,
|
|
|
|
+ STBVF_ed,
|
|
|
|
+ STBVF_nd,
|
|
|
|
+ STBVF_wd,
|
|
|
|
+};
|
|
|
|
|
|
- // the floor side face_coord is stored in order NW,NE,SE,SW, but ht[] is stored SW,SE,NW,NE
|
|
|
|
- v[0] = face_coord[2];
|
|
|
|
- v[1] = face_coord[3];
|
|
|
|
- v[2] = face_coord[0];
|
|
|
|
- v[3] = face_coord[2];
|
|
|
|
- stbvox_make_mesh_for_face(mm, rot, face, v_off, pos, vertbase, v, mesh, normal1);
|
|
|
|
- v[1] = face_coord[0];
|
|
|
|
- v[2] = face_coord[1];
|
|
|
|
- stbvox_make_mesh_for_face(mm, rot, face, v_off, pos, vertbase, v, mesh, normal2);
|
|
|
|
-}
|
|
|
|
|
|
+// 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[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
|
|
|
|
+ (unsigned short) ((~0x07ff )<<5), // none is completely obscured by everything
|
|
|
|
+ (unsigned short) ((~((1<<STBVOX_FT_solid) | (1<<STBVOX_FT_upper) ))<<5), // upper
|
|
|
|
+ (unsigned short) ((~((1<<STBVOX_FT_solid) | (1<<STBVOX_FT_lower) ))<<5), // lower
|
|
|
|
+ (unsigned short) ((~((1<<STBVOX_FT_solid) ))<<5), // solid is only completely obscured only by solid
|
|
|
|
+ (unsigned short) ((~((1<<STBVOX_FT_solid) | (1<<STBVOX_FT_diag_013)))<<5), // diag012 matches diag013
|
|
|
|
+ (unsigned short) ((~((1<<STBVOX_FT_solid) | (1<<STBVOX_FT_diag_123)))<<5), // diag023 matches diag123
|
|
|
|
+ (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
|
|
|
|
+};
|
|
|
|
|
|
-static void stbvox_make_03_split_mesh_for_face(stbvox_mesh_maker *mm, stbvox_rotate rot, int face, int v_off, stbvox_pos pos, stbvox_mesh_vertex vertbase, stbvox_mesh_vertex *face_coord, unsigned char mesh, unsigned char *ht)
|
|
|
|
|
|
+// the vertex heights of the block types, in binary vertex order (zyx):
|
|
|
|
+// lower: SW, SE, NW, NE; upper: SW, SE, NW, NE
|
|
|
|
+static stbvox_mesh_vertex stbvox_geometry_vheight[8][8] =
|
|
{
|
|
{
|
|
- stbvox_mesh_vertex v[4];
|
|
|
|
|
|
+ #define STBVOX_HEIGHTS(a,b,c,d,e,f,g,h) \
|
|
|
|
+ { stbvox_vertex_encode(0,0,a,0,0), \
|
|
|
|
+ stbvox_vertex_encode(0,0,b,0,0), \
|
|
|
|
+ stbvox_vertex_encode(0,0,c,0,0), \
|
|
|
|
+ stbvox_vertex_encode(0,0,d,0,0), \
|
|
|
|
+ stbvox_vertex_encode(0,0,e,0,0), \
|
|
|
|
+ stbvox_vertex_encode(0,0,f,0,0), \
|
|
|
|
+ stbvox_vertex_encode(0,0,g,0,0), \
|
|
|
|
+ stbvox_vertex_encode(0,0,h,0,0) }
|
|
|
|
|
|
- unsigned char normal1 = stbvox_face_up_normal_013[ht[3]][ht[1]][ht[0]];
|
|
|
|
- unsigned char normal2 = stbvox_face_up_normal_023[ht[3]][ht[2]][ht[0]];
|
|
|
|
|
|
+ STBVOX_HEIGHTS(0,0,0,0, 2,2,2,2),
|
|
|
|
+ STBVOX_HEIGHTS(0,0,0,0, 2,2,2,2),
|
|
|
|
+ STBVOX_HEIGHTS(0,0,0,0, 2,2,2,2),
|
|
|
|
+ STBVOX_HEIGHTS(0,0,0,0, 2,2,2,2),
|
|
|
|
+ STBVOX_HEIGHTS(1,1,1,1, 2,2,2,2),
|
|
|
|
+ STBVOX_HEIGHTS(0,0,0,0, 1,1,1,1),
|
|
|
|
+ STBVOX_HEIGHTS(0,0,0,0, 0,0,2,2),
|
|
|
|
+ STBVOX_HEIGHTS(2,2,0,0, 2,2,2,2),
|
|
|
|
+};
|
|
|
|
|
|
- if (face == STBVOX_FACE_down) {
|
|
|
|
- normal1 = stbvox_reverse_face[normal1];
|
|
|
|
- normal2 = stbvox_reverse_face[normal2];
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- 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, face, v_off, pos, vertbase, v, mesh, normal1);
|
|
|
|
- v[1] = face_coord[3];
|
|
|
|
- v[2] = face_coord[0];
|
|
|
|
- stbvox_make_mesh_for_face(mm, rot, face, v_off, pos, vertbase, v, mesh, normal2); // this one is correct!
|
|
|
|
-}
|
|
|
|
-#endif
|
|
|
|
-
|
|
|
|
-#ifndef STBVOX_CONFIG_PRECISION_Z
|
|
|
|
-#define STBVOX_CONFIG_PRECISION_Z 1
|
|
|
|
-#endif
|
|
|
|
-
|
|
|
|
-// simple case for mesh generation: we have only solid and empty blocks
|
|
|
|
-static void stbvox_make_mesh_for_block(stbvox_mesh_maker *mm, stbvox_pos pos, int v_off, stbvox_mesh_vertex *vmesh)
|
|
|
|
|
|
+// rotate vertices defined as [z][y][x] coords
|
|
|
|
+static unsigned char stbvox_rotate_vertex[8][4] =
|
|
{
|
|
{
|
|
- int ns_off = mm->y_stride_in_bytes;
|
|
|
|
- int ew_off = mm->x_stride_in_bytes;
|
|
|
|
-
|
|
|
|
- unsigned char *blockptr = &mm->input.blocktype[v_off];
|
|
|
|
- stbvox_mesh_vertex basevert = stbvox_vertex_encode(pos.x, pos.y, pos.z << STBVOX_CONFIG_PRECISION_Z , 0,0);
|
|
|
|
-
|
|
|
|
- stbvox_rotate rot = { 0,0,0,0 };
|
|
|
|
- unsigned char simple_rot = 0;
|
|
|
|
-
|
|
|
|
- unsigned char mesh = mm->default_mesh;
|
|
|
|
-
|
|
|
|
- if (mm->input.selector)
|
|
|
|
- mesh = mm->input.selector[v_off];
|
|
|
|
|
|
+ { 0,1,3,2 }, // zyx=000
|
|
|
|
+ { 1,3,2,0 }, // zyx=001
|
|
|
|
+ { 2,0,1,3 }, // zyx=010
|
|
|
|
+ { 3,2,0,1 }, // zyx=011
|
|
|
|
+ { 4,5,7,6 }, // zyx=100
|
|
|
|
+ { 5,7,6,4 }, // zyx=101
|
|
|
|
+ { 6,4,5,7 }, // zyx=110
|
|
|
|
+ { 7,6,4,5 }, // zyx=111
|
|
|
|
+};
|
|
|
|
|
|
- // 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]) {
|
|
|
|
- mm->full = 1;
|
|
|
|
- return;
|
|
|
|
|
|
+#ifdef STBVOX_OPTIMIZED_VHEIGHT
|
|
|
|
+// optimized vheight generates a single normal over the entire face, even if it's not planar
|
|
|
|
+static stbvox_optimized_face_up_normal[4][4][4][4] =
|
|
|
|
+{
|
|
|
|
+ {
|
|
|
|
+ {
|
|
|
|
+ { STBVF_u , STBVF_ne_u, STBVF_ne_u, STBVF_ne_u, },
|
|
|
|
+ { STBVF_nw_u, STBVF_nu , STBVF_nu , STBVF_ne_u, },
|
|
|
|
+ { STBVF_nw_u, STBVF_nu , STBVF_nu , STBVF_nu , },
|
|
|
|
+ { STBVF_nw_u, STBVF_nw_u, STBVF_nu , STBVF_nu , },
|
|
|
|
+ },{
|
|
|
|
+ { STBVF_su , STBVF_eu , STBVF_eu , STBVF_ne_u, },
|
|
|
|
+ { STBVF_u , STBVF_ne_u, STBVF_ne_u, STBVF_ne_u, },
|
|
|
|
+ { STBVF_nw_u, STBVF_nu , STBVF_nu , STBVF_ne_u, },
|
|
|
|
+ { STBVF_nw_u, STBVF_nu , STBVF_nu , STBVF_nu , },
|
|
|
|
+ },{
|
|
|
|
+ { STBVF_eu , STBVF_eu , STBVF_eu , STBVF_eu , },
|
|
|
|
+ { STBVF_su , STBVF_eu , STBVF_eu , STBVF_ne_u, },
|
|
|
|
+ { STBVF_u , STBVF_ne_u, STBVF_ne_u, STBVF_ne_u, },
|
|
|
|
+ { STBVF_nw_u, STBVF_nu , STBVF_nu , STBVF_ne_u, },
|
|
|
|
+ },{
|
|
|
|
+ { STBVF_eu , STBVF_eu , STBVF_eu , STBVF_eu , },
|
|
|
|
+ { STBVF_eu , STBVF_eu , STBVF_eu , STBVF_eu , },
|
|
|
|
+ { STBVF_su , STBVF_eu , STBVF_eu , STBVF_ne_u, },
|
|
|
|
+ { STBVF_u , STBVF_ne_u, STBVF_ne_u, STBVF_ne_u, },
|
|
|
|
+ },
|
|
|
|
+ },{
|
|
|
|
+ {
|
|
|
|
+ { STBVF_sw_u, STBVF_u , STBVF_ne_u, STBVF_ne_u, },
|
|
|
|
+ { STBVF_wu , STBVF_nw_u, STBVF_nu , STBVF_nu , },
|
|
|
|
+ { STBVF_wu , STBVF_nw_u, STBVF_nu , STBVF_nu , },
|
|
|
|
+ { STBVF_nw_u, STBVF_nw_u, STBVF_nw_u, STBVF_nu , },
|
|
|
|
+ },{
|
|
|
|
+ { STBVF_su , STBVF_su , STBVF_eu , STBVF_eu , },
|
|
|
|
+ { STBVF_sw_u, STBVF_u , STBVF_ne_u, STBVF_ne_u, },
|
|
|
|
+ { STBVF_wu , STBVF_nw_u, STBVF_nu , STBVF_nu , },
|
|
|
|
+ { STBVF_wu , STBVF_nw_u, STBVF_nu , STBVF_nu , },
|
|
|
|
+ },{
|
|
|
|
+ { STBVF_su , STBVF_eu , STBVF_eu , STBVF_eu , },
|
|
|
|
+ { STBVF_su , STBVF_su , STBVF_eu , STBVF_eu , },
|
|
|
|
+ { STBVF_sw_u, STBVF_u , STBVF_ne_u, STBVF_ne_u, },
|
|
|
|
+ { STBVF_wu , STBVF_nw_u, STBVF_nu , STBVF_nu , },
|
|
|
|
+ },{
|
|
|
|
+ { STBVF_su , STBVF_eu , STBVF_eu , STBVF_eu , },
|
|
|
|
+ { STBVF_su , STBVF_eu , STBVF_eu , STBVF_eu , },
|
|
|
|
+ { STBVF_su , STBVF_su , STBVF_eu , STBVF_eu , },
|
|
|
|
+ { STBVF_sw_u, STBVF_u , STBVF_ne_u, STBVF_ne_u, },
|
|
|
|
+ },
|
|
|
|
+ },{
|
|
|
|
+ {
|
|
|
|
+ { STBVF_sw_u, STBVF_sw_u, STBVF_u , STBVF_ne_u, },
|
|
|
|
+ { STBVF_wu , STBVF_wu , STBVF_nw_u, STBVF_nu , },
|
|
|
|
+ { STBVF_wu , STBVF_wu , STBVF_nw_u, STBVF_nu , },
|
|
|
|
+ { STBVF_wu , STBVF_nw_u, STBVF_nw_u, STBVF_nw_u, },
|
|
|
|
+ },{
|
|
|
|
+ { STBVF_su , STBVF_su , STBVF_su , STBVF_eu , },
|
|
|
|
+ { STBVF_sw_u, STBVF_sw_u, STBVF_u , STBVF_ne_u, },
|
|
|
|
+ { STBVF_wu , STBVF_wu , STBVF_nw_u, STBVF_nu , },
|
|
|
|
+ { STBVF_wu , STBVF_wu , STBVF_nw_u, STBVF_nu , },
|
|
|
|
+ },{
|
|
|
|
+ { STBVF_su , STBVF_su , STBVF_eu , STBVF_eu , },
|
|
|
|
+ { STBVF_su , STBVF_su , STBVF_su , STBVF_eu , },
|
|
|
|
+ { STBVF_sw_u, STBVF_sw_u, STBVF_u , STBVF_ne_u, },
|
|
|
|
+ { STBVF_wu , STBVF_wu , STBVF_nw_u, STBVF_nu , },
|
|
|
|
+ },{
|
|
|
|
+ { STBVF_su , STBVF_su , STBVF_eu , STBVF_eu , },
|
|
|
|
+ { STBVF_su , STBVF_su , STBVF_eu , STBVF_eu , },
|
|
|
|
+ { STBVF_su , STBVF_su , STBVF_su , STBVF_eu , },
|
|
|
|
+ { STBVF_sw_u, STBVF_sw_u, STBVF_u , STBVF_ne_u, },
|
|
|
|
+ },
|
|
|
|
+ },{
|
|
|
|
+ {
|
|
|
|
+ { STBVF_sw_u, STBVF_sw_u, STBVF_sw_u, STBVF_u , },
|
|
|
|
+ { STBVF_sw_u, STBVF_wu , STBVF_wu , STBVF_nw_u, },
|
|
|
|
+ { STBVF_wu , STBVF_wu , STBVF_wu , STBVF_nw_u, },
|
|
|
|
+ { STBVF_wu , STBVF_wu , STBVF_nw_u, STBVF_nw_u, },
|
|
|
|
+ },{
|
|
|
|
+ { STBVF_sw_u, STBVF_su , STBVF_su , STBVF_su , },
|
|
|
|
+ { STBVF_sw_u, STBVF_sw_u, STBVF_sw_u, STBVF_u , },
|
|
|
|
+ { STBVF_sw_u, STBVF_wu , STBVF_wu , STBVF_nw_u, },
|
|
|
|
+ { STBVF_wu , STBVF_wu , STBVF_wu , STBVF_nw_u, },
|
|
|
|
+ },{
|
|
|
|
+ { STBVF_su , STBVF_su , STBVF_su , STBVF_eu , },
|
|
|
|
+ { STBVF_sw_u, STBVF_su , STBVF_su , STBVF_su , },
|
|
|
|
+ { STBVF_sw_u, STBVF_sw_u, STBVF_sw_u, STBVF_u , },
|
|
|
|
+ { STBVF_sw_u, STBVF_wu , STBVF_wu , STBVF_nw_u, },
|
|
|
|
+ },{
|
|
|
|
+ { STBVF_su , STBVF_su , STBVF_su , STBVF_eu , },
|
|
|
|
+ { STBVF_su , STBVF_su , STBVF_su , STBVF_eu , },
|
|
|
|
+ { STBVF_sw_u, STBVF_su , STBVF_su , STBVF_su , },
|
|
|
|
+ { STBVF_sw_u, STBVF_sw_u, STBVF_sw_u, STBVF_u , },
|
|
|
|
+ },
|
|
|
|
+ },
|
|
|
|
+};
|
|
|
|
+#else
|
|
|
|
+// which normal to use for a given vheight that's planar
|
|
|
|
+// @TODO: this table was constructed by hand and may have bugs
|
|
|
|
+// nw se sw
|
|
|
|
+static stbvox_planar_face_up_normal[4][4][4] =
|
|
|
|
+{
|
|
|
|
+ { // sw,se,nw,ne; ne = se+nw-sw
|
|
|
|
+ { STBVF_u , 0 , 0 , 0 }, // 0,0,0,0; 1,0,0,-1; 2,0,0,-2; 3,0,0,-3;
|
|
|
|
+ { STBVF_u , STBVF_u , 0 , 0 }, // 0,1,0,1; 1,1,0, 0; 2,1,0,-1; 3,1,0,-2;
|
|
|
|
+ { STBVF_wu , STBVF_nw_u, STBVF_nu , 0 }, // 0,2,0,2; 1,2,0, 1; 2,2,0, 0; 3,2,0,-1;
|
|
|
|
+ { STBVF_wu , STBVF_nw_u, STBVF_nw_u, STBVF_nu }, // 0,3,0,3; 1,3,0, 2; 2,3,0, 1; 3,3,0, 0;
|
|
|
|
+ },{
|
|
|
|
+ { STBVF_u , STBVF_u , 0 , 0 }, // 0,0,1,1; 1,0,1, 0; 2,0,1,-1; 3,0,1,-2;
|
|
|
|
+ { STBVF_sw_u, STBVF_u , STBVF_ne_u, 0 }, // 0,1,1,2; 1,1,1, 1; 2,1,1, 0; 3,1,1,-1;
|
|
|
|
+ { STBVF_sw_u, STBVF_u , STBVF_u , STBVF_ne_u }, // 0,2,1,3; 1,2,1, 2; 2,2,1, 1; 3,2,1, 0;
|
|
|
|
+ { 0 , STBVF_wu , STBVF_nw_u, STBVF_nu }, // 0,3,1,4; 1,3,1, 3; 2,3,1, 2; 3,3,1, 1;
|
|
|
|
+ },{
|
|
|
|
+ { STBVF_su , STBVF_se_u, STBVF_eu , 0 }, // 0,0,2,2; 1,0,2, 1; 2,0,2, 0; 3,0,2,-1;
|
|
|
|
+ { STBVF_sw_u, STBVF_u , STBVF_u , STBVF_ne_u }, // 0,1,2,3; 1,1,2, 2; 2,1,2, 1; 3,1,2, 0;
|
|
|
|
+ { 0 , STBVF_sw_u, STBVF_u , STBVF_ne_u }, // 0,2,2,4; 1,2,2, 3; 2,2,2, 2; 3,2,2, 1;
|
|
|
|
+ { 0 , 0 , STBVF_u , STBVF_u }, // 0,3,2,5; 1,3,2, 4; 2,3,2, 3; 3,3,2, 2;
|
|
|
|
+ },{
|
|
|
|
+ { STBVF_su , STBVF_se_u, STBVF_se_u, STBVF_eu }, // 0,0,3,3; 1,0,3, 2; 2,0,3, 1; 3,0,3, 0;
|
|
|
|
+ { 0 , STBVF_su , STBVF_se_u, STBVF_eu }, // 0,1,3,4; 1,1,3, 3; 2,1,3, 2; 3,1,3, 1;
|
|
|
|
+ { 0 , 0 , STBVF_u , STBVF_u }, // 0,2,3,5; 1,2,3, 4; 2,2,3, 3; 3,2,3, 2;
|
|
|
|
+ { 0 , 0 , 0 , STBVF_u }, // 0,3,3,6; 1,3,3, 5; 2,3,3, 4; 3,3,3, 3;
|
|
}
|
|
}
|
|
|
|
+};
|
|
|
|
|
|
- #ifdef STBVOX_ROTATION_IN_LIGHTING
|
|
|
|
- simple_rot = mm->input.lighting[v_off] & 3;
|
|
|
|
- #endif
|
|
|
|
-
|
|
|
|
- if (blockptr[ 1]==0) {
|
|
|
|
- rot.facerot = simple_rot;
|
|
|
|
- stbvox_make_mesh_for_face(mm, rot, STBVOX_FACE_up , v_off, pos, basevert, vmesh+4*STBVOX_FACE_up, mesh, STBVOX_FACE_up);
|
|
|
|
- }
|
|
|
|
- if (blockptr[-1]==0) {
|
|
|
|
- rot.facerot = (-simple_rot) & 3;
|
|
|
|
- stbvox_make_mesh_for_face(mm, rot, STBVOX_FACE_down, v_off, pos, basevert, vmesh+4*STBVOX_FACE_down, mesh, STBVOX_FACE_down);
|
|
|
|
|
|
+// these tables were constructed automatically using a variant of the code
|
|
|
|
+// below; however, they seem wrong, so who knows
|
|
|
|
+static stbvox_face_up_normal_012[4][4][4] =
|
|
|
|
+{
|
|
|
|
+ {
|
|
|
|
+ { STBVF_u , STBVF_ne_u, STBVF_ne_u, STBVF_ne_u, },
|
|
|
|
+ { STBVF_wu , STBVF_nu , STBVF_ne_u, STBVF_ne_u, },
|
|
|
|
+ { STBVF_wu , STBVF_nw_u, STBVF_nu , STBVF_ne_u, },
|
|
|
|
+ { STBVF_wu , STBVF_nw_u, STBVF_nw_u, STBVF_nu , },
|
|
|
|
+ },{
|
|
|
|
+ { STBVF_su , STBVF_eu , STBVF_ne_u, STBVF_ne_u, },
|
|
|
|
+ { STBVF_sw_u, STBVF_u , STBVF_ne_u, STBVF_ne_u, },
|
|
|
|
+ { STBVF_sw_u, STBVF_wu , STBVF_nu , STBVF_ne_u, },
|
|
|
|
+ { STBVF_sw_u, STBVF_wu , STBVF_nw_u, STBVF_nu , },
|
|
|
|
+ },{
|
|
|
|
+ { STBVF_su , STBVF_eu , STBVF_eu , STBVF_ne_u, },
|
|
|
|
+ { STBVF_sw_u, STBVF_su , STBVF_eu , STBVF_ne_u, },
|
|
|
|
+ { STBVF_sw_u, STBVF_sw_u, STBVF_u , STBVF_ne_u, },
|
|
|
|
+ { STBVF_sw_u, STBVF_sw_u, STBVF_wu , STBVF_nu , },
|
|
|
|
+ },{
|
|
|
|
+ { STBVF_su , STBVF_su , STBVF_eu , STBVF_eu , },
|
|
|
|
+ { STBVF_sw_u, STBVF_su , STBVF_eu , STBVF_eu , },
|
|
|
|
+ { STBVF_sw_u, STBVF_sw_u, STBVF_su , STBVF_eu , },
|
|
|
|
+ { STBVF_sw_u, STBVF_sw_u, STBVF_sw_u, STBVF_u , },
|
|
}
|
|
}
|
|
|
|
+};
|
|
|
|
|
|
- if (mm->input.rotate) {
|
|
|
|
- unsigned char val = mm->input.rotate[v_off];
|
|
|
|
- rot.block = (val >> 0) & 3;
|
|
|
|
- rot.overlay = (val >> 2) & 3;
|
|
|
|
- //rot.tex2 = (val >> 4) & 3;
|
|
|
|
- rot.ecolor = (val >> 6) & 3;
|
|
|
|
- } else {
|
|
|
|
- rot.block = rot.overlay = rot.ecolor = simple_rot;
|
|
|
|
|
|
+static stbvox_face_up_normal_013[4][4][4] =
|
|
|
|
+{
|
|
|
|
+ {
|
|
|
|
+ { STBVF_u , STBVF_eu , STBVF_eu , STBVF_eu , },
|
|
|
|
+ { STBVF_nw_u, STBVF_nu , STBVF_ne_u, STBVF_ne_u, },
|
|
|
|
+ { STBVF_nw_u, STBVF_nw_u, STBVF_nu , STBVF_ne_u, },
|
|
|
|
+ { STBVF_nw_u, STBVF_nw_u, STBVF_nw_u, STBVF_nu , },
|
|
|
|
+ },{
|
|
|
|
+ { STBVF_su , STBVF_eu , STBVF_eu , STBVF_eu , },
|
|
|
|
+ { STBVF_wu , STBVF_u , STBVF_eu , STBVF_eu , },
|
|
|
|
+ { STBVF_nw_u, STBVF_nw_u, STBVF_nu , STBVF_ne_u, },
|
|
|
|
+ { STBVF_nw_u, STBVF_nw_u, STBVF_nw_u, STBVF_nu , },
|
|
|
|
+ },{
|
|
|
|
+ { STBVF_su , STBVF_su , STBVF_su , STBVF_eu , },
|
|
|
|
+ { STBVF_sw_u, STBVF_su , STBVF_eu , STBVF_eu , },
|
|
|
|
+ { STBVF_wu , STBVF_wu , STBVF_u , STBVF_eu , },
|
|
|
|
+ { STBVF_nw_u, STBVF_nw_u, STBVF_nw_u, STBVF_nu , },
|
|
|
|
+ },{
|
|
|
|
+ { STBVF_su , STBVF_su , STBVF_su , STBVF_eu , },
|
|
|
|
+ { STBVF_sw_u, STBVF_su , STBVF_su , STBVF_su , },
|
|
|
|
+ { STBVF_sw_u, STBVF_sw_u, STBVF_su , STBVF_eu , },
|
|
|
|
+ { STBVF_wu , STBVF_wu , STBVF_wu , STBVF_u , },
|
|
}
|
|
}
|
|
- rot.facerot = 0;
|
|
|
|
-
|
|
|
|
- if (blockptr[ ns_off]==0)
|
|
|
|
- stbvox_make_mesh_for_face(mm, rot, STBVOX_FACE_north, v_off, pos, basevert, vmesh+4*STBVOX_FACE_north, mesh, STBVOX_FACE_north);
|
|
|
|
- if (blockptr[-ns_off]==0)
|
|
|
|
- stbvox_make_mesh_for_face(mm, rot, STBVOX_FACE_south, v_off, pos, basevert, vmesh+4*STBVOX_FACE_south, mesh, STBVOX_FACE_south);
|
|
|
|
- if (blockptr[ ew_off]==0)
|
|
|
|
- stbvox_make_mesh_for_face(mm, rot, STBVOX_FACE_east , v_off, pos, basevert, vmesh+4*STBVOX_FACE_east, mesh, STBVOX_FACE_east);
|
|
|
|
- if (blockptr[-ew_off]==0)
|
|
|
|
- stbvox_make_mesh_for_face(mm, rot, STBVOX_FACE_west , v_off, pos, basevert, vmesh+4*STBVOX_FACE_west, mesh, STBVOX_FACE_west);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
|
|
+};
|
|
|
|
|
|
-// void stbvox_make_mesh_for_block_with_geo(stbvox_mesh_maker *mm, stbvox_pos pos, int v_off)
|
|
|
|
-//
|
|
|
|
-// complex case for mesh generation: we have lots of different
|
|
|
|
-// block types, and we don't want to generate faces of blocks
|
|
|
|
-// if they're hidden by neighbors.
|
|
|
|
-//
|
|
|
|
-// we use lots of tables to determine this: we have a table
|
|
|
|
-// which tells us what face type is generated for each type of
|
|
|
|
-// geometry, and then a table that tells us whether that type
|
|
|
|
-// is hidden by a neighbor.
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-#define STBVOX_MAX_GEOM 16
|
|
|
|
-#define STBVOX_NUM_ROTATION 4
|
|
|
|
-
|
|
|
|
-// this is used to determine if a face is ever generated at all
|
|
|
|
-static unsigned char stbvox_hasface[STBVOX_MAX_GEOM][STBVOX_NUM_ROTATION];
|
|
|
|
-
|
|
|
|
-// this determines which face type above is visible on each side of the geometry
|
|
|
|
-static unsigned char stbvox_facetype[STBVOX_GEOM_count][6];
|
|
|
|
-
|
|
|
|
-// This table indicates what normal to use for the "up" face of a sloped geom
|
|
|
|
-static unsigned char stbvox_floor_slope_for_rot[4];
|
|
|
|
-static unsigned char stbvox_ceil_slope_for_rot[4];
|
|
|
|
-
|
|
|
|
-// these are the types of faces each block can have
|
|
|
|
-enum
|
|
|
|
|
|
+static stbvox_face_up_normal_023[4][4][4] =
|
|
{
|
|
{
|
|
- STBVOX_FT_none ,
|
|
|
|
- STBVOX_FT_upper ,
|
|
|
|
- STBVOX_FT_lower ,
|
|
|
|
- STBVOX_FT_solid ,
|
|
|
|
- STBVOX_FT_diag_012,
|
|
|
|
- STBVOX_FT_diag_023,
|
|
|
|
- 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
|
|
|
|
-
|
|
|
|
- STBVOX_FT_count
|
|
|
|
|
|
+ {
|
|
|
|
+ { STBVF_u , STBVF_nu , STBVF_nu , STBVF_nu , },
|
|
|
|
+ { STBVF_eu , STBVF_eu , STBVF_ne_u, STBVF_ne_u, },
|
|
|
|
+ { STBVF_su , STBVF_eu , STBVF_eu , STBVF_ne_u, },
|
|
|
|
+ { STBVF_eu , STBVF_eu , STBVF_eu , STBVF_eu , },
|
|
|
|
+ },{
|
|
|
|
+ { STBVF_wu , STBVF_nw_u, STBVF_nw_u, STBVF_nw_u, },
|
|
|
|
+ { STBVF_su , STBVF_u , STBVF_nu , STBVF_nu , },
|
|
|
|
+ { STBVF_su , STBVF_eu , STBVF_eu , STBVF_ne_u, },
|
|
|
|
+ { STBVF_su , STBVF_su , STBVF_eu , STBVF_eu , },
|
|
|
|
+ },{
|
|
|
|
+ { STBVF_wu , STBVF_nw_u, STBVF_nw_u, STBVF_nw_u, },
|
|
|
|
+ { STBVF_sw_u, STBVF_wu , STBVF_nw_u, STBVF_nw_u, },
|
|
|
|
+ { STBVF_su , STBVF_su , STBVF_u , STBVF_nu , },
|
|
|
|
+ { STBVF_su , STBVF_su , STBVF_eu , STBVF_eu , },
|
|
|
|
+ },{
|
|
|
|
+ { STBVF_wu , STBVF_nw_u, STBVF_nw_u, STBVF_nw_u, },
|
|
|
|
+ { STBVF_sw_u, STBVF_wu , STBVF_nw_u, STBVF_nw_u, },
|
|
|
|
+ { STBVF_sw_u, STBVF_sw_u, STBVF_wu , STBVF_nw_u, },
|
|
|
|
+ { STBVF_su , STBVF_su , STBVF_su , STBVF_u , },
|
|
|
|
+ }
|
|
};
|
|
};
|
|
|
|
|
|
-// this table indicates whether, for each pair of types above, a face is visible.
|
|
|
|
-// each value indicates whether a given type is visible for each neighbor type
|
|
|
|
-static unsigned short stbvox_face_visible[STBVOX_FT_count];
|
|
|
|
|
|
+static stbvox_face_up_normal_123[4][4][4] =
|
|
|
|
+{
|
|
|
|
+ {
|
|
|
|
+ { STBVF_u , STBVF_nu , STBVF_nu , STBVF_nu , },
|
|
|
|
+ { STBVF_eu , STBVF_ne_u, STBVF_ne_u, STBVF_ne_u, },
|
|
|
|
+ { STBVF_eu , STBVF_ne_u, STBVF_ne_u, STBVF_ne_u, },
|
|
|
|
+ { STBVF_eu , STBVF_ne_u, STBVF_ne_u, STBVF_ne_u, },
|
|
|
|
+ },{
|
|
|
|
+ { STBVF_sw_u, STBVF_wu , STBVF_nw_u, STBVF_nw_u, },
|
|
|
|
+ { STBVF_su , STBVF_u , STBVF_nu , STBVF_nu , },
|
|
|
|
+ { STBVF_eu , STBVF_eu , STBVF_ne_u, STBVF_ne_u, },
|
|
|
|
+ { STBVF_eu , STBVF_eu , STBVF_ne_u, STBVF_ne_u, },
|
|
|
|
+ },{
|
|
|
|
+ { STBVF_sw_u, STBVF_sw_u, STBVF_wu , STBVF_nw_u, },
|
|
|
|
+ { STBVF_sw_u, STBVF_sw_u, STBVF_wu , STBVF_nw_u, },
|
|
|
|
+ { STBVF_su , STBVF_su , STBVF_u , STBVF_nu , },
|
|
|
|
+ { STBVF_su , STBVF_eu , STBVF_eu , STBVF_ne_u, },
|
|
|
|
+ },{
|
|
|
|
+ { STBVF_sw_u, STBVF_sw_u, STBVF_sw_u, STBVF_wu , },
|
|
|
|
+ { STBVF_sw_u, STBVF_sw_u, STBVF_sw_u, STBVF_wu , },
|
|
|
|
+ { STBVF_sw_u, STBVF_sw_u, STBVF_sw_u, STBVF_wu , },
|
|
|
|
+ { STBVF_su , STBVF_su , STBVF_su , STBVF_u , },
|
|
|
|
+ }
|
|
|
|
+};
|
|
|
|
+#endif
|
|
|
|
|
|
-// the vertex heights of the block types, in binary vertex order (zyx):
|
|
|
|
-// lower: SW, SE, NW, NE; upper: SW, SE, NW, NE
|
|
|
|
-static stbvox_mesh_vertex stbvox_geometry_vheight[8][8];
|
|
|
|
|
|
+void stbvox_get_quad_vertex_pointer(stbvox_mesh_maker *mm, int mesh, stbvox_mesh_vertex **vertices, stbvox_mesh_face face)
|
|
|
|
+{
|
|
|
|
+ char *p = mm->output_cur[mesh][0];
|
|
|
|
+ int step = mm->output_step[mesh][0];
|
|
|
|
|
|
-// rotate vertices defined as [z][y][x] coords
|
|
|
|
-static unsigned char stbvox_rotate_vertex[8][4];
|
|
|
|
|
|
+ // allocate a new quad from the mesh
|
|
|
|
+ vertices[0] = (stbvox_mesh_vertex *) p; p += step;
|
|
|
|
+ vertices[1] = (stbvox_mesh_vertex *) p; p += step;
|
|
|
|
+ vertices[2] = (stbvox_mesh_vertex *) p; p += step;
|
|
|
|
+ vertices[3] = (stbvox_mesh_vertex *) p; p += step;
|
|
|
|
+ mm->output_cur[mesh][0] = p;
|
|
|
|
|
|
-#ifdef STBVOX_OPTIMIZED_VHEIGHT
|
|
|
|
-static stbvox_optimized_face_up_normal[4][4][4][4];
|
|
|
|
-#else
|
|
|
|
-static stbvox_planar_face_up_normal[4][4][4];
|
|
|
|
-#endif
|
|
|
|
|
|
+ // output the face
|
|
|
|
+ #ifdef STBVOX_ICONFIG_FACE_ATTRIBUTE
|
|
|
|
+ // write face as interleaved vertex data
|
|
|
|
+ *(stbvox_mesh_face *) (vertices[0]+1) = face;
|
|
|
|
+ *(stbvox_mesh_face *) (vertices[1]+1) = face;
|
|
|
|
+ *(stbvox_mesh_face *) (vertices[2]+1) = face;
|
|
|
|
+ *(stbvox_mesh_face *) (vertices[3]+1) = face;
|
|
|
|
+ #else
|
|
|
|
+ *(stbvox_mesh_face *) mm->output_cur[mesh][1] = face;
|
|
|
|
+ mm->output_cur[mesh][1] += 4;
|
|
|
|
+ #endif
|
|
|
|
+}
|
|
|
|
|
|
-static void stbvox_make_mesh_for_block_with_geo(stbvox_mesh_maker *mm, stbvox_pos pos, int v_off)
|
|
|
|
|
|
+void stbvox_make_mesh_for_face(stbvox_mesh_maker *mm, stbvox_rotate rot, int face, int v_off, stbvox_pos pos, stbvox_mesh_vertex vertbase, stbvox_mesh_vertex *face_coord, unsigned char mesh, int normal)
|
|
{
|
|
{
|
|
- int ns_off = mm->y_stride_in_bytes;
|
|
|
|
- int ew_off = mm->x_stride_in_bytes;
|
|
|
|
- int visible_faces, visible_base;
|
|
|
|
- unsigned char mesh;
|
|
|
|
-
|
|
|
|
- // first gather the geometry info for this block and all neighbors
|
|
|
|
|
|
+ stbvox_mesh_face face_data = stbvox_compute_mesh_face_value(mm,rot,face,v_off, normal);
|
|
|
|
|
|
- unsigned char bt, nbt[6];
|
|
|
|
- unsigned char geo, ngeo[6];
|
|
|
|
- unsigned char rot, nrot[6];
|
|
|
|
|
|
+ // still need to compute ao & texlerp for each vertex
|
|
|
|
|
|
- bt = mm->input.blocktype[v_off];
|
|
|
|
- nbt[0] = mm->input.blocktype[v_off + ew_off];
|
|
|
|
- nbt[1] = mm->input.blocktype[v_off + ns_off];
|
|
|
|
- nbt[2] = mm->input.blocktype[v_off - ew_off];
|
|
|
|
- nbt[3] = mm->input.blocktype[v_off - ns_off];
|
|
|
|
- nbt[4] = mm->input.blocktype[v_off + 1];
|
|
|
|
- nbt[5] = mm->input.blocktype[v_off - 1];
|
|
|
|
- if (mm->input.geometry) {
|
|
|
|
- int i;
|
|
|
|
- geo = mm->input.geometry[v_off];
|
|
|
|
- ngeo[0] = mm->input.geometry[v_off + ew_off];
|
|
|
|
- ngeo[1] = mm->input.geometry[v_off + ns_off];
|
|
|
|
- ngeo[2] = mm->input.geometry[v_off - ew_off];
|
|
|
|
- ngeo[3] = mm->input.geometry[v_off - ns_off];
|
|
|
|
- ngeo[4] = mm->input.geometry[v_off + 1];
|
|
|
|
- ngeo[5] = mm->input.geometry[v_off - 1];
|
|
|
|
|
|
+ // first compute texlerp into p1
|
|
|
|
+ stbvox_mesh_vertex p1[4] = { 0 };
|
|
|
|
|
|
- #ifndef STBVOX_ROTATION_IN_LIGHTING
|
|
|
|
- rot = (geo >> 4) & 3;
|
|
|
|
- geo &= 15;
|
|
|
|
- for (i=0; i < 6; ++i) {
|
|
|
|
- nrot[i] = (ngeo[i] >> 4) & 3;
|
|
|
|
- ngeo[i] &= 15;
|
|
|
|
- }
|
|
|
|
- #endif
|
|
|
|
- STBVOX_NOTUSED(i);
|
|
|
|
- } else {
|
|
|
|
- int i;
|
|
|
|
- assert(mm->input.block_geometry);
|
|
|
|
- geo = mm->input.block_geometry[bt];
|
|
|
|
- for (i=0; i < 6; ++i)
|
|
|
|
- ngeo[i] = mm->input.block_geometry[nbt[i]];
|
|
|
|
- if (mm->input.selector) {
|
|
|
|
- #ifndef STBVOX_ROTATION_IN_LIGHTING
|
|
|
|
- rot = (mm->input.selector[v_off ] >> 4) & 3;
|
|
|
|
- nrot[0] = (mm->input.selector[v_off + ew_off] >> 4) & 3;
|
|
|
|
- nrot[1] = (mm->input.selector[v_off + ns_off] >> 4) & 3;
|
|
|
|
- nrot[2] = (mm->input.selector[v_off - ew_off] >> 4) & 3;
|
|
|
|
- nrot[3] = (mm->input.selector[v_off - ns_off] >> 4) & 3;
|
|
|
|
- nrot[4] = (mm->input.selector[v_off + 1] >> 4) & 3;
|
|
|
|
- nrot[5] = (mm->input.selector[v_off - 1] >> 4) & 3;
|
|
|
|
- #endif
|
|
|
|
|
|
+ if (mm->input.block_texlerp) {
|
|
|
|
+ stbvox_block_type bt = mm->input.blocktype[v_off];
|
|
|
|
+ unsigned char val = mm->input.block_texlerp[bt];
|
|
|
|
+ p1[0] = p1[1] = p1[2] = p1[3] = stbvox_vertex_encode(0,0,0,0,val);
|
|
|
|
+ } else if (mm->input.block_texlerp_face) {
|
|
|
|
+ stbvox_block_type bt = mm->input.blocktype[v_off];
|
|
|
|
+ unsigned char bt_face = STBVOX_ROTATE(face, rot.block);
|
|
|
|
+ unsigned char val = mm->input.block_texlerp_face[bt][bt_face];
|
|
|
|
+ p1[0] = p1[1] = p1[2] = p1[3] = stbvox_vertex_encode(0,0,0,0,val);
|
|
|
|
+ } else if (mm->input.texlerp_face3) {
|
|
|
|
+ unsigned char val = (mm->input.texlerp_face3[v_off] >> stbvox_face3_lerp[face]) & 7;
|
|
|
|
+ if (face >= STBVOX_FACE_up)
|
|
|
|
+ val = stbvox_face3_updown[val];
|
|
|
|
+ p1[0] = p1[1] = p1[2] = p1[3] = stbvox_vertex_encode(0,0,0,0,val);
|
|
|
|
+ } else if (mm->input.texlerp_simple) {
|
|
|
|
+ unsigned char val = mm->input.texlerp_simple[v_off];
|
|
|
|
+ unsigned char lerp_face = (val >> 2) & 7;
|
|
|
|
+ if (lerp_face == face) {
|
|
|
|
+ p1[0] = (mm->input.texlerp_simple[v_off + mm->cube_vertex_offset[face][0]] >> 5) & 7;
|
|
|
|
+ p1[1] = (mm->input.texlerp_simple[v_off + mm->cube_vertex_offset[face][1]] >> 5) & 7;
|
|
|
|
+ p1[2] = (mm->input.texlerp_simple[v_off + mm->cube_vertex_offset[face][2]] >> 5) & 7;
|
|
|
|
+ p1[3] = (mm->input.texlerp_simple[v_off + mm->cube_vertex_offset[face][3]] >> 5) & 7;
|
|
|
|
+ p1[0] = stbvox_vertex_encode(0,0,0,0,p1[0]);
|
|
|
|
+ p1[1] = stbvox_vertex_encode(0,0,0,0,p1[1]);
|
|
|
|
+ p1[2] = stbvox_vertex_encode(0,0,0,0,p1[2]);
|
|
|
|
+ p1[3] = stbvox_vertex_encode(0,0,0,0,p1[3]);
|
|
} else {
|
|
} else {
|
|
- #ifndef STBVOX_ROTATION_IN_LIGHTING
|
|
|
|
- rot = (geo>>4)&3;
|
|
|
|
- geo &= 15;
|
|
|
|
- for (i=0; i < 6; ++i) {
|
|
|
|
- nrot[i] = (ngeo[i]>>4)&3;
|
|
|
|
- ngeo[i] &= 15;
|
|
|
|
|
|
+ unsigned char base = stbvox_vert_lerp_for_simple[val&3];
|
|
|
|
+ p1[0] = p1[1] = p1[2] = p1[3] = stbvox_vertex_encode(0,0,0,0,base);
|
|
|
|
+ }
|
|
|
|
+ } else if (mm->input.texlerp) {
|
|
|
|
+ unsigned char facelerp = (mm->input.texlerp[v_off] >> stbvox_face_lerp[face]) & 3;
|
|
|
|
+ if (facelerp == STBVOX_TEXLERP_FACE_use_vert) {
|
|
|
|
+ if (mm->input.texlerp_vert3 && face != STBVOX_FACE_down) {
|
|
|
|
+ unsigned char shift = stbvox_vert3_lerp[face];
|
|
|
|
+ p1[0] = (mm->input.texlerp_vert3[mm->cube_vertex_offset[face][0]] >> shift) & 7;
|
|
|
|
+ p1[1] = (mm->input.texlerp_vert3[mm->cube_vertex_offset[face][1]] >> shift) & 7;
|
|
|
|
+ p1[2] = (mm->input.texlerp_vert3[mm->cube_vertex_offset[face][2]] >> shift) & 7;
|
|
|
|
+ p1[3] = (mm->input.texlerp_vert3[mm->cube_vertex_offset[face][3]] >> shift) & 7;
|
|
|
|
+ } else {
|
|
|
|
+ p1[0] = stbvox_vert_lerp_for_simple[mm->input.texlerp[mm->cube_vertex_offset[face][0]]>>6];
|
|
|
|
+ p1[1] = stbvox_vert_lerp_for_simple[mm->input.texlerp[mm->cube_vertex_offset[face][1]]>>6];
|
|
|
|
+ p1[2] = stbvox_vert_lerp_for_simple[mm->input.texlerp[mm->cube_vertex_offset[face][2]]>>6];
|
|
|
|
+ p1[3] = stbvox_vert_lerp_for_simple[mm->input.texlerp[mm->cube_vertex_offset[face][3]]>>6];
|
|
}
|
|
}
|
|
- #endif
|
|
|
|
|
|
+ p1[0] = stbvox_vertex_encode(0,0,0,0,p1[0]);
|
|
|
|
+ p1[1] = stbvox_vertex_encode(0,0,0,0,p1[1]);
|
|
|
|
+ p1[2] = stbvox_vertex_encode(0,0,0,0,p1[2]);
|
|
|
|
+ p1[3] = stbvox_vertex_encode(0,0,0,0,p1[3]);
|
|
|
|
+ } else {
|
|
|
|
+ p1[0] = p1[1] = p1[2] = p1[3] = stbvox_vertex_encode(0,0,0,0,stbvox_vert_lerp_for_face_lerp[facelerp]);
|
|
}
|
|
}
|
|
|
|
+ } else {
|
|
|
|
+ p1[0] = p1[1] = p1[2] = p1[3] = stbvox_vertex_encode(0,0,0,0,7);
|
|
}
|
|
}
|
|
|
|
|
|
- #ifdef STBVOX_ROTATION_IN_LIGHTING
|
|
|
|
- rot = mm->input.lighting[v_off] & 3;
|
|
|
|
- nrot[0] = (mm->input.lighting[v_off + ew_off]) & 3;
|
|
|
|
- nrot[1] = (mm->input.lighting[v_off + ns_off]) & 3;
|
|
|
|
- nrot[2] = (mm->input.lighting[v_off - ew_off]) & 3;
|
|
|
|
- nrot[3] = (mm->input.lighting[v_off - ns_off]) & 3;
|
|
|
|
- nrot[4] = (mm->input.lighting[v_off + 1]) & 3;
|
|
|
|
- nrot[5] = (mm->input.lighting[v_off - 1]) & 3;
|
|
|
|
- #endif
|
|
|
|
-
|
|
|
|
- if (geo == STBVOX_GEOM_transp) {
|
|
|
|
- // transparency has a special rule: if the blocktype is the same,
|
|
|
|
- // and the faces are compatible, then can hide them; otherwise,
|
|
|
|
- // force them on
|
|
|
|
- // Note that this means we don't support any transparentshapes other
|
|
|
|
- // than solid blocks, since detecting them is too complicated. If
|
|
|
|
- // you wanted to do something like minecraft water, you probably
|
|
|
|
- // should just do that with a separate renderer anyway. (We don't
|
|
|
|
- // support transparency sorting so you need to use alpha test
|
|
|
|
- // anyway)
|
|
|
|
- int i;
|
|
|
|
- for (i=0; i < 6; ++i)
|
|
|
|
- if (nbt[i] != bt) {
|
|
|
|
- nbt[i] = 0;
|
|
|
|
- ngeo[i] = STBVOX_GEOM_empty;
|
|
|
|
- } else
|
|
|
|
- ngeo[i] = STBVOX_GEOM_solid;
|
|
|
|
- geo = STBVOX_GEOM_solid;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // now compute the face visibility
|
|
|
|
- visible_base = stbvox_hasface[geo][rot];
|
|
|
|
- // @TODO: assert(visible_base != 0); // we should have early-outted earlier in this case
|
|
|
|
- visible_faces = 0;
|
|
|
|
|
|
+ {
|
|
|
|
+ stbvox_mesh_vertex *mv[4];
|
|
|
|
+ stbvox_get_quad_vertex_pointer(mm, mesh, mv, face_data);
|
|
|
|
|
|
- // now, for every face that might be visible, check if neighbor hides it
|
|
|
|
- if (visible_base & (1 << STBVOX_FACE_east)) {
|
|
|
|
- int type = stbvox_facetype[ geo ][(STBVOX_FACE_east+ rot )&3];
|
|
|
|
- int ntype = stbvox_facetype[ngeo[0]][(STBVOX_FACE_west+nrot[0])&3];
|
|
|
|
- visible_faces |= ((stbvox_face_visible[type]) >> (ntype + 5 - STBVOX_FACE_east)) & (1 << STBVOX_FACE_east);
|
|
|
|
- }
|
|
|
|
- if (visible_base & (1 << STBVOX_FACE_north)) {
|
|
|
|
- int type = stbvox_facetype[ geo ][(STBVOX_FACE_north+ rot )&3];
|
|
|
|
- int ntype = stbvox_facetype[ngeo[1]][(STBVOX_FACE_south+nrot[1])&3];
|
|
|
|
- visible_faces |= ((stbvox_face_visible[type]) >> (ntype + 5 - STBVOX_FACE_north)) & (1 << STBVOX_FACE_north);
|
|
|
|
- }
|
|
|
|
- if (visible_base & (1 << STBVOX_FACE_west)) {
|
|
|
|
- int type = stbvox_facetype[ geo ][(STBVOX_FACE_west+ rot )&3];
|
|
|
|
- int ntype = stbvox_facetype[ngeo[2]][(STBVOX_FACE_east+nrot[2])&3];
|
|
|
|
- visible_faces |= ((stbvox_face_visible[type]) >> (ntype + 5 - STBVOX_FACE_west)) & (1 << STBVOX_FACE_west);
|
|
|
|
- }
|
|
|
|
- if (visible_base & (1 << STBVOX_FACE_south)) {
|
|
|
|
- int type = stbvox_facetype[ geo ][(STBVOX_FACE_south+ rot )&3];
|
|
|
|
- int ntype = stbvox_facetype[ngeo[3]][(STBVOX_FACE_north+nrot[3])&3];
|
|
|
|
- visible_faces |= ((stbvox_face_visible[type]) >> (ntype + 5 - STBVOX_FACE_south)) & (1 << STBVOX_FACE_south);
|
|
|
|
- }
|
|
|
|
- if (visible_base & (1 << STBVOX_FACE_up)) {
|
|
|
|
- int type = stbvox_facetype[ geo ][STBVOX_FACE_up];
|
|
|
|
- int ntype = stbvox_facetype[ngeo[4]][STBVOX_FACE_down];
|
|
|
|
- visible_faces |= ((stbvox_face_visible[type]) >> (ntype + 5 - STBVOX_FACE_up)) & (1 << STBVOX_FACE_up);
|
|
|
|
- }
|
|
|
|
- if (visible_base & (1 << STBVOX_FACE_down)) {
|
|
|
|
- int type = stbvox_facetype[ geo ][STBVOX_FACE_down];
|
|
|
|
- int ntype = stbvox_facetype[ngeo[5]][STBVOX_FACE_up];
|
|
|
|
- visible_faces |= ((stbvox_face_visible[type]) >> (ntype + 5 - STBVOX_FACE_down)) & (1 << STBVOX_FACE_down);
|
|
|
|
- }
|
|
|
|
|
|
+ if (mm->input.lighting) {
|
|
|
|
+ // @TODO: lighting at block centers, but not gathered, instead constant-per-face
|
|
|
|
+ if (mm->input.lighting_at_vertices) {
|
|
|
|
+ int i;
|
|
|
|
+ for (i=0; i < 4; ++i) {
|
|
|
|
+ *mv[i] = vertbase + face_coord[i]
|
|
|
|
+ + stbvox_vertex_encode(0,0,0,mm->input.lighting[v_off + mm->cube_vertex_offset[face][i]] & 63,0)
|
|
|
|
+ + p1[i];
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ unsigned char *amb = &mm->input.lighting[v_off];
|
|
|
|
+ int i,j;
|
|
|
|
+ #ifdef STBVOX_ROTATION_IN_LIGHTING
|
|
|
|
+ #define STBVOX_GET_LIGHTING(light) ((light) & ~3)
|
|
|
|
+ #define STBVOX_LIGHTING_ROUNDOFF 8
|
|
|
|
+ #else
|
|
|
|
+ #define STBVOX_GET_LIGHTING(light) (light)
|
|
|
|
+ #define STBVOX_LIGHTING_ROUNDOFF 2
|
|
|
|
+ #endif
|
|
|
|
|
|
- if (geo == STBVOX_GEOM_force)
|
|
|
|
- geo = STBVOX_GEOM_solid;
|
|
|
|
|
|
+ for (i=0; i < 4; ++i) {
|
|
|
|
+ // for each vertex, gather from the four neighbor blocks it's facing
|
|
|
|
+ unsigned char *vamb = &amb[mm->cube_vertex_offset[face][i]];
|
|
|
|
+ int total=0;
|
|
|
|
+ for (j=0; j < 4; ++j)
|
|
|
|
+ total += STBVOX_GET_LIGHTING(vamb[mm->vertex_gather_offset[face][j]]);
|
|
|
|
+ *mv[i] = vertbase + face_coord[i]
|
|
|
|
+ + stbvox_vertex_encode(0,0,0,(total+STBVOX_LIGHTING_ROUNDOFF)>>4,0)
|
|
|
|
+ + p1[i];
|
|
|
|
+ // >> 4 is because:
|
|
|
|
+ // >> 2 to divide by 4 to get average over 4 samples
|
|
|
|
+ // >> 2 because input is 8 bits, output is 6 bits
|
|
|
|
+ }
|
|
|
|
|
|
- assert((geo == STBVOX_GEOM_crossed_pair) ? (visible_faces == 15) : 1);
|
|
|
|
|
|
+ // @TODO: note that gathering baked *lighting*
|
|
|
|
+ // is different from gathering baked ao; baked ao can count
|
|
|
|
+ // solid blocks as 0 ao, but baked lighting wants average
|
|
|
|
+ // of non-blocked--not take average & treat blocked as 0. And
|
|
|
|
+ // we can't bake the right value into the solid blocks
|
|
|
|
+ // because they can have different lighting values on
|
|
|
|
+ // different sides. So we need to actually gather and
|
|
|
|
+ // then divide by 0..4 (which we can do with a table-driven
|
|
|
|
+ // multiply, or have an 'if' for the 3 case)
|
|
|
|
|
|
- // now we finally know for sure which faces are getting generated
|
|
|
|
- if (visible_faces == 0)
|
|
|
|
- return;
|
|
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ vertbase += stbvox_vertex_encode(0,0,0,63,0);
|
|
|
|
+ *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];
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
|
|
- mesh = mm->default_mesh;
|
|
|
|
- if (mm->input.selector)
|
|
|
|
- mesh = mm->input.selector[v_off];
|
|
|
|
|
|
+#ifndef STBVOX_OPTIMIZED_VHEIGHT
|
|
|
|
+// get opposite-facing normal & texgen for opposite face, used to map up-facing vheight data to down-facing data
|
|
|
|
+static unsigned char stbvox_reverse_face[STBVF_count] =
|
|
|
|
+{
|
|
|
|
+ STBVF_w, STBVF_s, STBVF_e, STBVF_n, STBVF_d , STBVF_u , STBVF_wd, STBVF_wu,
|
|
|
|
+ 0, 0, 0, 0, STBVF_sw_d, STBVF_sw_u, STBVF_sd, STBVF_su,
|
|
|
|
+ 0, 0, 0, 0, STBVF_se_d, STBVF_se_u, STBVF_ed, STBVF_eu,
|
|
|
|
+ 0, 0, 0, 0, STBVF_ne_d, STBVF_ne_d, STBVF_nd, STBVF_nu
|
|
|
|
+};
|
|
|
|
|
|
- if (geo <= STBVOX_GEOM_ceil_slope_north_is_bottom) {
|
|
|
|
- // this is the simple case, we can just use regular block gen with special vmesh calculated with vheight
|
|
|
|
- stbvox_mesh_vertex basevert;
|
|
|
|
- stbvox_mesh_vertex vmesh[6][4];
|
|
|
|
- stbvox_rotate rotate = { 0,0,0,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
|
|
|
|
- // for visible faces only
|
|
|
|
- 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]
|
|
|
|
- + stbvox_geometry_vheight[geo][vert];
|
|
|
|
- }
|
|
|
|
|
|
|
|
- basevert = stbvox_vertex_encode(pos.x, pos.y, pos.z << STBVOX_CONFIG_PRECISION_Z, 0,0);
|
|
|
|
- if (mm->input.selector) {
|
|
|
|
- mesh = mm->input.selector[v_off];
|
|
|
|
- }
|
|
|
|
|
|
+// render non-planar quads by splitting into two triangles, rendering each as a degenerate quad
|
|
|
|
+static void stbvox_make_12_split_mesh_for_face(stbvox_mesh_maker *mm, stbvox_rotate rot, int face, int v_off, stbvox_pos pos, stbvox_mesh_vertex vertbase, stbvox_mesh_vertex *face_coord, unsigned char mesh, unsigned char *ht)
|
|
|
|
+{
|
|
|
|
+ stbvox_mesh_vertex v[4];
|
|
|
|
|
|
- // 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]) {
|
|
|
|
- mm->full = 1;
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
|
|
+ unsigned char normal1 = stbvox_face_up_normal_012[ht[2]][ht[1]][ht[0]];
|
|
|
|
+ unsigned char normal2 = stbvox_face_up_normal_123[ht[3]][ht[2]][ht[1]];
|
|
|
|
|
|
- if (geo >= STBVOX_GEOM_floor_slope_north_is_top) {
|
|
|
|
- if (visible_faces & (1 << STBVOX_FACE_up)) {
|
|
|
|
- int normal = geo == STBVOX_GEOM_floor_slope_north_is_top ? stbvox_floor_slope_for_rot[simple_rot] : STBVOX_FACE_up;
|
|
|
|
- rotate.facerot = simple_rot;
|
|
|
|
- stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_up , v_off, pos, basevert, vmesh[STBVOX_FACE_up], mesh, normal);
|
|
|
|
- }
|
|
|
|
- if (visible_faces & (1 << STBVOX_FACE_down)) {
|
|
|
|
- int normal = geo == STBVOX_GEOM_ceil_slope_north_is_bottom ? stbvox_ceil_slope_for_rot[simple_rot] : STBVOX_FACE_down;
|
|
|
|
- rotate.facerot = (-rotate.facerot) & 3;
|
|
|
|
- stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_down, v_off, pos, basevert, vmesh[STBVOX_FACE_down], mesh, normal);
|
|
|
|
- }
|
|
|
|
- } else {
|
|
|
|
- if (visible_faces & (1 << STBVOX_FACE_up)) {
|
|
|
|
- rotate.facerot = simple_rot;
|
|
|
|
- stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_up , v_off, pos, basevert, vmesh[STBVOX_FACE_up], mesh, STBVOX_FACE_up);
|
|
|
|
- }
|
|
|
|
- if (visible_faces & (1 << STBVOX_FACE_down)) {
|
|
|
|
- rotate.facerot = (-rotate.facerot) & 3;
|
|
|
|
- stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_down, v_off, pos, basevert, vmesh[STBVOX_FACE_down], mesh, STBVOX_FACE_down);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ if (face == STBVOX_FACE_down) {
|
|
|
|
+ normal1 = stbvox_reverse_face[normal1];
|
|
|
|
+ normal2 = stbvox_reverse_face[normal2];
|
|
|
|
+ }
|
|
|
|
|
|
- if (mm->input.rotate) {
|
|
|
|
- unsigned char val = mm->input.rotate[v_off];
|
|
|
|
- rotate.block = (val >> 0) & 3;
|
|
|
|
- rotate.overlay = (val >> 2) & 3;
|
|
|
|
- //rotate.tex2 = (val >> 4) & 3;
|
|
|
|
- rotate.ecolor = (val >> 6) & 3;
|
|
|
|
- } else {
|
|
|
|
- rotate.block = rotate.overlay = rotate.ecolor = simple_rot;
|
|
|
|
- }
|
|
|
|
|
|
+ // the floor side face_coord is stored in order NW,NE,SE,SW, but ht[] is stored SW,SE,NW,NE
|
|
|
|
+ v[0] = face_coord[2];
|
|
|
|
+ v[1] = face_coord[3];
|
|
|
|
+ v[2] = face_coord[0];
|
|
|
|
+ v[3] = face_coord[2];
|
|
|
|
+ stbvox_make_mesh_for_face(mm, rot, face, v_off, pos, vertbase, v, mesh, normal1);
|
|
|
|
+ v[1] = face_coord[0];
|
|
|
|
+ v[2] = face_coord[1];
|
|
|
|
+ stbvox_make_mesh_for_face(mm, rot, face, v_off, pos, vertbase, v, mesh, normal2);
|
|
|
|
+}
|
|
|
|
|
|
- rotate.facerot = 0;
|
|
|
|
|
|
+static void stbvox_make_03_split_mesh_for_face(stbvox_mesh_maker *mm, stbvox_rotate rot, int face, int v_off, stbvox_pos pos, stbvox_mesh_vertex vertbase, stbvox_mesh_vertex *face_coord, unsigned char mesh, unsigned char *ht)
|
|
|
|
+{
|
|
|
|
+ stbvox_mesh_vertex v[4];
|
|
|
|
|
|
- if (visible_faces & (1 << STBVOX_FACE_north))
|
|
|
|
- stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_north, v_off, pos, basevert, vmesh[STBVOX_FACE_north], mesh, STBVOX_FACE_north);
|
|
|
|
- if (visible_faces & (1 << STBVOX_FACE_south))
|
|
|
|
- stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_south, v_off, pos, basevert, vmesh[STBVOX_FACE_south], mesh, STBVOX_FACE_south);
|
|
|
|
- if (visible_faces & (1 << STBVOX_FACE_east))
|
|
|
|
- stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_east , v_off, pos, basevert, vmesh[STBVOX_FACE_east ], mesh, STBVOX_FACE_east);
|
|
|
|
- if (visible_faces & (1 << STBVOX_FACE_west))
|
|
|
|
- stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_west , v_off, pos, basevert, vmesh[STBVOX_FACE_west ], mesh, STBVOX_FACE_west);
|
|
|
|
|
|
+ unsigned char normal1 = stbvox_face_up_normal_013[ht[3]][ht[1]][ht[0]];
|
|
|
|
+ unsigned char normal2 = stbvox_face_up_normal_023[ht[3]][ht[2]][ht[0]];
|
|
|
|
+
|
|
|
|
+ if (face == STBVOX_FACE_down) {
|
|
|
|
+ normal1 = stbvox_reverse_face[normal1];
|
|
|
|
+ normal2 = stbvox_reverse_face[normal2];
|
|
}
|
|
}
|
|
- if (geo >= STBVOX_GEOM_floor_vheight_03) {
|
|
|
|
- // this case can also be generated with regular block gen with special vmesh,
|
|
|
|
- // except:
|
|
|
|
- // if we want to generate middle diagonal for 'weird' blocks
|
|
|
|
- // it's more complicated to detect neighbor matchups
|
|
|
|
- stbvox_mesh_vertex vmesh[6][4];
|
|
|
|
- stbvox_mesh_vertex cube[8];
|
|
|
|
- stbvox_mesh_vertex basevert;
|
|
|
|
- stbvox_rotate rotate = { 0,0,0,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];
|
|
|
|
- ht[0] = (v >> 0) & 3;
|
|
|
|
- ht[1] = (v >> 2) & 3;
|
|
|
|
- ht[2] = (v >> 4) & 3;
|
|
|
|
- ht[3] = (v >> 6) & 3;
|
|
|
|
- } else if (mm->input.block_vheight) {
|
|
|
|
- unsigned char v = mm->input.block_vheight[bt];
|
|
|
|
- unsigned char raw[4];
|
|
|
|
- int i;
|
|
|
|
|
|
+ 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, face, v_off, pos, vertbase, v, mesh, normal1);
|
|
|
|
+ v[1] = face_coord[3];
|
|
|
|
+ v[2] = face_coord[0];
|
|
|
|
+ stbvox_make_mesh_for_face(mm, rot, face, v_off, pos, vertbase, v, mesh, normal2); // this one is correct!
|
|
|
|
+}
|
|
|
|
+#endif
|
|
|
|
|
|
- raw[0] = (v >> 0) & 3;
|
|
|
|
- raw[1] = (v >> 2) & 3;
|
|
|
|
- raw[2] = (v >> 4) & 3;
|
|
|
|
- raw[3] = (v >> 6) & 3;
|
|
|
|
|
|
+#ifndef STBVOX_CONFIG_PRECISION_Z
|
|
|
|
+#define STBVOX_CONFIG_PRECISION_Z 1
|
|
|
|
+#endif
|
|
|
|
|
|
- for (i=0; i < 4; ++i)
|
|
|
|
- ht[i] = raw[stbvox_rotate_vertex[i][rot]];
|
|
|
|
- } else {
|
|
|
|
- assert(0);
|
|
|
|
- }
|
|
|
|
|
|
+// simple case for mesh generation: we have only solid and empty blocks
|
|
|
|
+static void stbvox_make_mesh_for_block(stbvox_mesh_maker *mm, stbvox_pos pos, int v_off, stbvox_mesh_vertex *vmesh)
|
|
|
|
+{
|
|
|
|
+ int ns_off = mm->y_stride_in_bytes;
|
|
|
|
+ int ew_off = mm->x_stride_in_bytes;
|
|
|
|
|
|
- // 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);
|
|
|
|
|
|
+ unsigned char *blockptr = &mm->input.blocktype[v_off];
|
|
|
|
+ stbvox_mesh_vertex basevert = stbvox_vertex_encode(pos.x, pos.y, pos.z << STBVOX_CONFIG_PRECISION_Z , 0,0);
|
|
|
|
|
|
- if (geo >= STBVOX_GEOM_ceil_vheight_03) {
|
|
|
|
- cube[0] = stbvox_vertex_encode(0,0,ht[0],0,0);
|
|
|
|
- cube[1] = stbvox_vertex_encode(0,0,ht[1],0,0);
|
|
|
|
- cube[2] = stbvox_vertex_encode(0,0,ht[2],0,0);
|
|
|
|
- cube[3] = stbvox_vertex_encode(0,0,ht[3],0,0);
|
|
|
|
- cube[4] = stbvox_vertex_encode(0,0,2,0,0);
|
|
|
|
- cube[5] = stbvox_vertex_encode(0,0,2,0,0);
|
|
|
|
- cube[6] = stbvox_vertex_encode(0,0,2,0,0);
|
|
|
|
- cube[7] = stbvox_vertex_encode(0,0,2,0,0);
|
|
|
|
- } else {
|
|
|
|
- cube[0] = stbvox_vertex_encode(0,0,0,0,0);
|
|
|
|
- cube[1] = stbvox_vertex_encode(0,0,0,0,0);
|
|
|
|
- cube[2] = stbvox_vertex_encode(0,0,0,0,0);
|
|
|
|
- cube[3] = stbvox_vertex_encode(0,0,0,0,0);
|
|
|
|
- cube[4] = stbvox_vertex_encode(0,0,ht[0],0,0);
|
|
|
|
- cube[5] = stbvox_vertex_encode(0,0,ht[1],0,0);
|
|
|
|
- cube[6] = stbvox_vertex_encode(0,0,ht[2],0,0);
|
|
|
|
- cube[7] = stbvox_vertex_encode(0,0,ht[3],0,0);
|
|
|
|
- }
|
|
|
|
- if (!mm->input.vheight && mm->input.block_vheight) {
|
|
|
|
- // @TODO: support block vheight here, I've forgotten what needs to be done specially
|
|
|
|
- }
|
|
|
|
|
|
+ stbvox_rotate rot = { 0,0,0,0 };
|
|
|
|
+ unsigned char simple_rot = 0;
|
|
|
|
|
|
- // build vertex mesh
|
|
|
|
- {
|
|
|
|
- int i;
|
|
|
|
- for (i=0; i < 6*4; ++i) {
|
|
|
|
- int vert = stbvox_vertex_selector[0][i];
|
|
|
|
- vmesh[0][i] = stbvox_vmesh_pre_vheight[0][i]
|
|
|
|
- + cube[vert];
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ unsigned char mesh = mm->default_mesh;
|
|
|
|
|
|
- basevert = stbvox_vertex_encode(pos.x, pos.y, pos.z << STBVOX_CONFIG_PRECISION_Z, 0,0);
|
|
|
|
- // 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]) {
|
|
|
|
- mm->full = 1;
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
|
|
+ if (mm->input.selector)
|
|
|
|
+ mesh = mm->input.selector[v_off];
|
|
|
|
|
|
- // @TODO generate split faces
|
|
|
|
- if (visible_faces & (1 << STBVOX_FACE_up)) {
|
|
|
|
- if (geo >= STBVOX_GEOM_ceil_vheight_03)
|
|
|
|
- // flat
|
|
|
|
- stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_up , v_off, pos, basevert, vmesh[STBVOX_FACE_up], mesh, STBVOX_FACE_up);
|
|
|
|
- else {
|
|
|
|
- #ifndef STBVOX_OPTIMIZED_VHEIGHT
|
|
|
|
- // check if it's non-planar
|
|
|
|
- if (cube[5] + cube[6] != cube[4] + cube[7]) {
|
|
|
|
- // not planar, split along diagonal and make degenerate quads
|
|
|
|
- if (geo == STBVOX_GEOM_floor_vheight_03)
|
|
|
|
- stbvox_make_03_split_mesh_for_face(mm, rotate, STBVOX_FACE_up, v_off, pos, basevert, vmesh[STBVOX_FACE_up], mesh, ht);
|
|
|
|
- else
|
|
|
|
- stbvox_make_12_split_mesh_for_face(mm, rotate, STBVOX_FACE_up, v_off, pos, basevert, vmesh[STBVOX_FACE_up], mesh, ht);
|
|
|
|
- } else
|
|
|
|
- stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_up , v_off, pos, basevert, vmesh[STBVOX_FACE_up], mesh, stbvox_planar_face_up_normal[ht[2]][ht[1]][ht[0]]);
|
|
|
|
- #else
|
|
|
|
- stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_up , v_off, pos, basevert, vmesh[STBVOX_FACE_up], mesh, stbvox_optimized_face_up_normal[ht[3]][ht[2]][ht[1]][ht[0]]);
|
|
|
|
- #endif
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- if (visible_faces & (1 << STBVOX_FACE_down)) {
|
|
|
|
- if (geo < STBVOX_GEOM_ceil_vheight_03)
|
|
|
|
- // flat
|
|
|
|
- stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_down, v_off, pos, basevert, vmesh[STBVOX_FACE_down], mesh, STBVOX_FACE_down);
|
|
|
|
- else {
|
|
|
|
- #ifndef STBVOX_OPTIMIZED_VHEIGHT
|
|
|
|
- // check if it's non-planar
|
|
|
|
- if (cube[1] + cube[2] != cube[0] + cube[3]) {
|
|
|
|
- // not planar, split along diagonal and make degenerate quads
|
|
|
|
- if (geo == STBVOX_GEOM_ceil_vheight_03)
|
|
|
|
- stbvox_make_03_split_mesh_for_face(mm, rotate, STBVOX_FACE_down, v_off, pos, basevert, vmesh[STBVOX_FACE_down], mesh, ht);
|
|
|
|
- else
|
|
|
|
- stbvox_make_12_split_mesh_for_face(mm, rotate, STBVOX_FACE_down, v_off, pos, basevert, vmesh[STBVOX_FACE_down], mesh, ht);
|
|
|
|
- } else
|
|
|
|
- stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_down, v_off, pos, basevert, vmesh[STBVOX_FACE_down], mesh, stbvox_reverse_face[stbvox_planar_face_up_normal[ht[2]][ht[1]][ht[0]]]);
|
|
|
|
- #else
|
|
|
|
- stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_down, v_off, pos, basevert, vmesh[STBVOX_FACE_down], mesh, stbvox_reverse_face[stbvox_optimized_face_up_normal[ht[3]][ht[2]][ht[1]][ht[0]]]);
|
|
|
|
- #endif
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ // 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]) {
|
|
|
|
+ mm->full = 1;
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
|
|
- if (mm->input.rotate) {
|
|
|
|
- unsigned char val = mm->input.rotate[v_off];
|
|
|
|
- rotate.block = (val >> 0) & 3;
|
|
|
|
- rotate.overlay = (val >> 2) & 3;
|
|
|
|
- //rotate.tex2 = (val >> 4) & 3;
|
|
|
|
- rotate.ecolor = (val >> 6) & 3;
|
|
|
|
- } else if (mm->input.selector) {
|
|
|
|
- rotate.block = rotate.overlay = rotate.ecolor = simple_rot;
|
|
|
|
- }
|
|
|
|
|
|
+ #ifdef STBVOX_ROTATION_IN_LIGHTING
|
|
|
|
+ simple_rot = mm->input.lighting[v_off] & 3;
|
|
|
|
+ #endif
|
|
|
|
|
|
- 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, STBVOX_FACE_north);
|
|
|
|
- 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, STBVOX_FACE_south);
|
|
|
|
- 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, STBVOX_FACE_east);
|
|
|
|
- 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, STBVOX_FACE_west);
|
|
|
|
|
|
+ if (blockptr[ 1]==0) {
|
|
|
|
+ rot.facerot = simple_rot;
|
|
|
|
+ stbvox_make_mesh_for_face(mm, rot, STBVOX_FACE_up , v_off, pos, basevert, vmesh+4*STBVOX_FACE_up, mesh, STBVOX_FACE_up);
|
|
|
|
+ }
|
|
|
|
+ if (blockptr[-1]==0) {
|
|
|
|
+ rot.facerot = (-simple_rot) & 3;
|
|
|
|
+ stbvox_make_mesh_for_face(mm, rot, STBVOX_FACE_down, v_off, pos, basevert, vmesh+4*STBVOX_FACE_down, mesh, STBVOX_FACE_down);
|
|
}
|
|
}
|
|
|
|
|
|
- if (geo == STBVOX_GEOM_crossed_pair) {
|
|
|
|
- // this can be generated with a special vmesh
|
|
|
|
- stbvox_mesh_vertex basevert = stbvox_vertex_encode(pos.x, pos.y, pos.z << STBVOX_CONFIG_PRECISION_Z , 0,0);
|
|
|
|
- unsigned char simple_rot=0;
|
|
|
|
- stbvox_rotate rot = { 0,0,0,0 };
|
|
|
|
- unsigned char mesh = mm->default_mesh;
|
|
|
|
- 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]*4 > mm->output_end[mesh][0]) {
|
|
|
|
- mm->full = 1;
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
|
|
+ if (mm->input.rotate) {
|
|
|
|
+ unsigned char val = mm->input.rotate[v_off];
|
|
|
|
+ rot.block = (val >> 0) & 3;
|
|
|
|
+ rot.overlay = (val >> 2) & 3;
|
|
|
|
+ //rot.tex2 = (val >> 4) & 3;
|
|
|
|
+ rot.ecolor = (val >> 6) & 3;
|
|
|
|
+ } else {
|
|
|
|
+ rot.block = rot.overlay = rot.ecolor = simple_rot;
|
|
|
|
+ }
|
|
|
|
+ rot.facerot = 0;
|
|
|
|
|
|
- if (mm->input.rotate) {
|
|
|
|
- unsigned char val = mm->input.rotate[v_off];
|
|
|
|
- rot.block = (val >> 0) & 3;
|
|
|
|
- rot.overlay = (val >> 2) & 3;
|
|
|
|
- //rot.tex2 = (val >> 4) & 3;
|
|
|
|
- rot.ecolor = (val >> 6) & 3;
|
|
|
|
- } else if (mm->input.selector) {
|
|
|
|
- rot.block = rot.overlay = rot.ecolor = simple_rot;
|
|
|
|
- }
|
|
|
|
- rot.facerot = 0;
|
|
|
|
|
|
+ if (blockptr[ ns_off]==0)
|
|
|
|
+ stbvox_make_mesh_for_face(mm, rot, STBVOX_FACE_north, v_off, pos, basevert, vmesh+4*STBVOX_FACE_north, mesh, STBVOX_FACE_north);
|
|
|
|
+ if (blockptr[-ns_off]==0)
|
|
|
|
+ stbvox_make_mesh_for_face(mm, rot, STBVOX_FACE_south, v_off, pos, basevert, vmesh+4*STBVOX_FACE_south, mesh, STBVOX_FACE_south);
|
|
|
|
+ if (blockptr[ ew_off]==0)
|
|
|
|
+ stbvox_make_mesh_for_face(mm, rot, STBVOX_FACE_east , v_off, pos, basevert, vmesh+4*STBVOX_FACE_east, mesh, STBVOX_FACE_east);
|
|
|
|
+ if (blockptr[-ew_off]==0)
|
|
|
|
+ stbvox_make_mesh_for_face(mm, rot, STBVOX_FACE_west , v_off, pos, basevert, vmesh+4*STBVOX_FACE_west, mesh, STBVOX_FACE_west);
|
|
|
|
+}
|
|
|
|
|
|
- stbvox_make_mesh_for_face(mm, rot, STBVOX_FACE_north, v_off, pos, basevert, stbvox_vmesh_crossed_pair[STBVOX_FACE_north], mesh, STBVF_ne_u_cross);
|
|
|
|
- stbvox_make_mesh_for_face(mm, rot, STBVOX_FACE_south, v_off, pos, basevert, stbvox_vmesh_crossed_pair[STBVOX_FACE_south], mesh, STBVF_sw_u_cross);
|
|
|
|
- stbvox_make_mesh_for_face(mm, rot, STBVOX_FACE_east , v_off, pos, basevert, stbvox_vmesh_crossed_pair[STBVOX_FACE_east ], mesh, STBVF_se_u_cross);
|
|
|
|
- stbvox_make_mesh_for_face(mm, rot, STBVOX_FACE_west , v_off, pos, basevert, stbvox_vmesh_crossed_pair[STBVOX_FACE_west ], mesh, STBVF_nw_u_cross);
|
|
|
|
- }
|
|
|
|
|
|
|
|
|
|
+// void stbvox_make_mesh_for_block_with_geo(stbvox_mesh_maker *mm, stbvox_pos pos, int v_off)
|
|
|
|
+//
|
|
|
|
+// complex case for mesh generation: we have lots of different
|
|
|
|
+// block types, and we don't want to generate faces of blocks
|
|
|
|
+// if they're hidden by neighbors.
|
|
|
|
+//
|
|
|
|
+// we use lots of tables to determine this: we have a table
|
|
|
|
+// which tells us what face type is generated for each type of
|
|
|
|
+// geometry, and then a table that tells us whether that type
|
|
|
|
+// is hidden by a neighbor.
|
|
|
|
|
|
- // @TODO
|
|
|
|
- // STBVOX_GEOM_floor_slope_north_is_top_as_wall,
|
|
|
|
- // STBVOX_GEOM_ceil_slope_north_is_bottom_as_wall,
|
|
|
|
-}
|
|
|
|
|
|
|
|
-static void stbvox_make_mesh_for_column(stbvox_mesh_maker *mm, int x, int y, int z0)
|
|
|
|
|
|
+static void stbvox_make_mesh_for_block_with_geo(stbvox_mesh_maker *mm, stbvox_pos pos, int v_off)
|
|
{
|
|
{
|
|
- stbvox_pos pos = { x,y,0 };
|
|
|
|
- int v_off = x * mm->x_stride_in_bytes + y * mm->y_stride_in_bytes;
|
|
|
|
int ns_off = mm->y_stride_in_bytes;
|
|
int ns_off = mm->y_stride_in_bytes;
|
|
int ew_off = mm->x_stride_in_bytes;
|
|
int ew_off = mm->x_stride_in_bytes;
|
|
|
|
+ int visible_faces, visible_base;
|
|
|
|
+ unsigned char mesh;
|
|
|
|
+
|
|
|
|
+ // first gather the geometry info for this block and all neighbors
|
|
|
|
+
|
|
|
|
+ unsigned char bt, nbt[6];
|
|
|
|
+ unsigned char geo, ngeo[6];
|
|
|
|
+ unsigned char rot, nrot[6];
|
|
|
|
+
|
|
|
|
+ bt = mm->input.blocktype[v_off];
|
|
|
|
+ nbt[0] = mm->input.blocktype[v_off + ew_off];
|
|
|
|
+ nbt[1] = mm->input.blocktype[v_off + ns_off];
|
|
|
|
+ nbt[2] = mm->input.blocktype[v_off - ew_off];
|
|
|
|
+ nbt[3] = mm->input.blocktype[v_off - ns_off];
|
|
|
|
+ nbt[4] = mm->input.blocktype[v_off + 1];
|
|
|
|
+ nbt[5] = mm->input.blocktype[v_off - 1];
|
|
if (mm->input.geometry) {
|
|
if (mm->input.geometry) {
|
|
- unsigned char *bt = mm->input.blocktype + v_off;
|
|
|
|
- unsigned char *geo = mm->input.geometry + v_off;
|
|
|
|
- int z;
|
|
|
|
- for (z=z0; z < mm->z1; ++z) {
|
|
|
|
- if (bt[z] && ( !bt[z+ns_off] || !STBVOX_GET_GEO(geo[z+ns_off]) || !bt[z-ns_off] || !STBVOX_GET_GEO(geo[z-ns_off])
|
|
|
|
- || !bt[z+ew_off] || !STBVOX_GET_GEO(geo[z+ew_off]) || !bt[z-ew_off] || !STBVOX_GET_GEO(geo[z-ew_off])))
|
|
|
|
- { // TODO check up and down
|
|
|
|
- pos.z = z;
|
|
|
|
- stbvox_make_mesh_for_block_with_geo(mm, pos, v_off+z);
|
|
|
|
- if (mm->full) {
|
|
|
|
- mm->cur_z = z;
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- } else if (mm->input.block_geometry) {
|
|
|
|
- int z;
|
|
|
|
- unsigned char *bt = mm->input.blocktype + v_off;
|
|
|
|
- unsigned char *geo = mm->input.block_geometry;
|
|
|
|
- for (z=z0; z < mm->z1; ++z) {
|
|
|
|
- if (bt[z] && ( geo[bt[z+ns_off]] != STBVOX_GEOM_solid
|
|
|
|
- || geo[bt[z-ns_off]] != STBVOX_GEOM_solid
|
|
|
|
- || geo[bt[z+ew_off]] != STBVOX_GEOM_solid
|
|
|
|
- || geo[bt[z-ew_off]] != STBVOX_GEOM_solid
|
|
|
|
- || geo[bt[z-1]] != STBVOX_GEOM_solid
|
|
|
|
- || geo[bt[z+1]] != STBVOX_GEOM_solid))
|
|
|
|
- {
|
|
|
|
- pos.z = z;
|
|
|
|
- stbvox_make_mesh_for_block_with_geo(mm, pos, v_off+z);
|
|
|
|
- if (mm->full) {
|
|
|
|
- mm->cur_z = z;
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ int i;
|
|
|
|
+ geo = mm->input.geometry[v_off];
|
|
|
|
+ ngeo[0] = mm->input.geometry[v_off + ew_off];
|
|
|
|
+ ngeo[1] = mm->input.geometry[v_off + ns_off];
|
|
|
|
+ ngeo[2] = mm->input.geometry[v_off - ew_off];
|
|
|
|
+ ngeo[3] = mm->input.geometry[v_off - ns_off];
|
|
|
|
+ ngeo[4] = mm->input.geometry[v_off + 1];
|
|
|
|
+ ngeo[5] = mm->input.geometry[v_off - 1];
|
|
|
|
+
|
|
|
|
+ #ifndef STBVOX_ROTATION_IN_LIGHTING
|
|
|
|
+ rot = (geo >> 4) & 3;
|
|
|
|
+ geo &= 15;
|
|
|
|
+ for (i=0; i < 6; ++i) {
|
|
|
|
+ nrot[i] = (ngeo[i] >> 4) & 3;
|
|
|
|
+ ngeo[i] &= 15;
|
|
}
|
|
}
|
|
- } else {
|
|
|
|
- unsigned char *bt = mm->input.blocktype + v_off;
|
|
|
|
- int z;
|
|
|
|
- #if STBVOX_CONFIG_PRECISION_Z == 1
|
|
|
|
- stbvox_mesh_vertex *vmesh = stbvox_vmesh_delta_half_z[0];
|
|
|
|
- #else
|
|
|
|
- stbvox_mesh_vertex *vmesh = stbvox_vmesh_delta_normal[0];
|
|
|
|
#endif
|
|
#endif
|
|
- for (z=z0; z < mm->z1; ++z) {
|
|
|
|
- // if it's solid and at least one neighbor isn't solid
|
|
|
|
- if (bt[z] && (!bt[z+ns_off] || !bt[z-ns_off] || !bt[z+ew_off] || !bt[z-ew_off] || !bt[z-1] || !bt[z+1])) {
|
|
|
|
- pos.z = z;
|
|
|
|
- stbvox_make_mesh_for_block(mm, pos, v_off+z, vmesh);
|
|
|
|
- if (mm->full) {
|
|
|
|
- mm->cur_z = z;
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
|
|
+ STBVOX_NOTUSED(i);
|
|
|
|
+ } else {
|
|
|
|
+ int i;
|
|
|
|
+ assert(mm->input.block_geometry);
|
|
|
|
+ geo = mm->input.block_geometry[bt];
|
|
|
|
+ for (i=0; i < 6; ++i)
|
|
|
|
+ ngeo[i] = mm->input.block_geometry[nbt[i]];
|
|
|
|
+ if (mm->input.selector) {
|
|
|
|
+ #ifndef STBVOX_ROTATION_IN_LIGHTING
|
|
|
|
+ rot = (mm->input.selector[v_off ] >> 4) & 3;
|
|
|
|
+ nrot[0] = (mm->input.selector[v_off + ew_off] >> 4) & 3;
|
|
|
|
+ nrot[1] = (mm->input.selector[v_off + ns_off] >> 4) & 3;
|
|
|
|
+ nrot[2] = (mm->input.selector[v_off - ew_off] >> 4) & 3;
|
|
|
|
+ nrot[3] = (mm->input.selector[v_off - ns_off] >> 4) & 3;
|
|
|
|
+ nrot[4] = (mm->input.selector[v_off + 1] >> 4) & 3;
|
|
|
|
+ nrot[5] = (mm->input.selector[v_off - 1] >> 4) & 3;
|
|
|
|
+ #endif
|
|
|
|
+ } else {
|
|
|
|
+ #ifndef STBVOX_ROTATION_IN_LIGHTING
|
|
|
|
+ rot = (geo>>4)&3;
|
|
|
|
+ geo &= 15;
|
|
|
|
+ for (i=0; i < 6; ++i) {
|
|
|
|
+ nrot[i] = (ngeo[i]>>4)&3;
|
|
|
|
+ ngeo[i] &= 15;
|
|
}
|
|
}
|
|
|
|
+ #endif
|
|
}
|
|
}
|
|
}
|
|
}
|
|
-}
|
|
|
|
|
|
|
|
-static void stbvox_bring_up_to_date(stbvox_mesh_maker *mm)
|
|
|
|
-{
|
|
|
|
- if (mm->config_dirty) {
|
|
|
|
- int i;
|
|
|
|
- #ifdef STBVOX_ICONFIG_FACE_ATTRIBUTE
|
|
|
|
- mm->num_mesh_slots = 1;
|
|
|
|
- for (i=0; i < STBVOX_MAX_MESHES; ++i) {
|
|
|
|
- mm->output_size[i][0] = 32;
|
|
|
|
- mm->output_step[i][0] = 8;
|
|
|
|
- }
|
|
|
|
- #else
|
|
|
|
- mm->num_mesh_slots = 2;
|
|
|
|
- for (i=0; i < STBVOX_MAX_MESHES; ++i) {
|
|
|
|
- mm->output_size[i][0] = 16;
|
|
|
|
- mm->output_step[i][0] = 4;
|
|
|
|
- mm->output_size[i][1] = 4;
|
|
|
|
- mm->output_step[i][1] = 4;
|
|
|
|
- }
|
|
|
|
- #endif
|
|
|
|
|
|
+ #ifdef STBVOX_ROTATION_IN_LIGHTING
|
|
|
|
+ rot = mm->input.lighting[v_off] & 3;
|
|
|
|
+ nrot[0] = (mm->input.lighting[v_off + ew_off]) & 3;
|
|
|
|
+ nrot[1] = (mm->input.lighting[v_off + ns_off]) & 3;
|
|
|
|
+ nrot[2] = (mm->input.lighting[v_off - ew_off]) & 3;
|
|
|
|
+ nrot[3] = (mm->input.lighting[v_off - ns_off]) & 3;
|
|
|
|
+ nrot[4] = (mm->input.lighting[v_off + 1]) & 3;
|
|
|
|
+ nrot[5] = (mm->input.lighting[v_off - 1]) & 3;
|
|
|
|
+ #endif
|
|
|
|
|
|
- mm->config_dirty = 0;
|
|
|
|
|
|
+ if (geo == STBVOX_GEOM_transp) {
|
|
|
|
+ // transparency has a special rule: if the blocktype is the same,
|
|
|
|
+ // and the faces are compatible, then can hide them; otherwise,
|
|
|
|
+ // force them on
|
|
|
|
+ // Note that this means we don't support any transparentshapes other
|
|
|
|
+ // than solid blocks, since detecting them is too complicated. If
|
|
|
|
+ // you wanted to do something like minecraft water, you probably
|
|
|
|
+ // should just do that with a separate renderer anyway. (We don't
|
|
|
|
+ // support transparency sorting so you need to use alpha test
|
|
|
|
+ // anyway)
|
|
|
|
+ int i;
|
|
|
|
+ for (i=0; i < 6; ++i)
|
|
|
|
+ if (nbt[i] != bt) {
|
|
|
|
+ nbt[i] = 0;
|
|
|
|
+ ngeo[i] = STBVOX_GEOM_empty;
|
|
|
|
+ } else
|
|
|
|
+ ngeo[i] = STBVOX_GEOM_solid;
|
|
|
|
+ geo = STBVOX_GEOM_solid;
|
|
}
|
|
}
|
|
-}
|
|
|
|
|
|
|
|
-int stbvox_make_mesh(stbvox_mesh_maker *mm)
|
|
|
|
-{
|
|
|
|
- int x,y;
|
|
|
|
- stbvox_bring_up_to_date(mm);
|
|
|
|
- mm->full = 0;
|
|
|
|
- if (mm->cur_x > mm->x0 || mm->cur_y > mm->y0 || mm->cur_z > mm->z0) {
|
|
|
|
- stbvox_make_mesh_for_column(mm, mm->cur_x, mm->cur_y, mm->cur_z);
|
|
|
|
- if (mm->full)
|
|
|
|
- return 0;
|
|
|
|
- ++mm->cur_y;
|
|
|
|
- while (mm->cur_y < mm->y1 && !mm->full) {
|
|
|
|
- stbvox_make_mesh_for_column(mm, mm->cur_x, mm->cur_y, mm->z0);
|
|
|
|
- if (mm->full)
|
|
|
|
- return 0;
|
|
|
|
- ++mm->cur_y;
|
|
|
|
- }
|
|
|
|
- ++mm->cur_x;
|
|
|
|
|
|
+ // now compute the face visibility
|
|
|
|
+ visible_base = stbvox_hasface[geo][rot];
|
|
|
|
+ // @TODO: assert(visible_base != 0); // we should have early-outted earlier in this case
|
|
|
|
+ visible_faces = 0;
|
|
|
|
+
|
|
|
|
+ // now, for every face that might be visible, check if neighbor hides it
|
|
|
|
+ if (visible_base & (1 << STBVOX_FACE_east)) {
|
|
|
|
+ int type = stbvox_facetype[ geo ][(STBVOX_FACE_east+ rot )&3];
|
|
|
|
+ int ntype = stbvox_facetype[ngeo[0]][(STBVOX_FACE_west+nrot[0])&3];
|
|
|
|
+ visible_faces |= ((stbvox_face_visible[type]) >> (ntype + 5 - STBVOX_FACE_east)) & (1 << STBVOX_FACE_east);
|
|
}
|
|
}
|
|
- for (x=mm->cur_x; x < mm->x1; ++x) {
|
|
|
|
- for (y=mm->y0; y < mm->y1; ++y) {
|
|
|
|
- stbvox_make_mesh_for_column(mm, x, y, mm->z0);
|
|
|
|
- if (mm->full) {
|
|
|
|
- mm->cur_x = x;
|
|
|
|
- mm->cur_y = y;
|
|
|
|
- return 0;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ if (visible_base & (1 << STBVOX_FACE_north)) {
|
|
|
|
+ int type = stbvox_facetype[ geo ][(STBVOX_FACE_north+ rot )&3];
|
|
|
|
+ int ntype = stbvox_facetype[ngeo[1]][(STBVOX_FACE_south+nrot[1])&3];
|
|
|
|
+ visible_faces |= ((stbvox_face_visible[type]) >> (ntype + 5 - STBVOX_FACE_north)) & (1 << STBVOX_FACE_north);
|
|
|
|
+ }
|
|
|
|
+ if (visible_base & (1 << STBVOX_FACE_west)) {
|
|
|
|
+ int type = stbvox_facetype[ geo ][(STBVOX_FACE_west+ rot )&3];
|
|
|
|
+ int ntype = stbvox_facetype[ngeo[2]][(STBVOX_FACE_east+nrot[2])&3];
|
|
|
|
+ visible_faces |= ((stbvox_face_visible[type]) >> (ntype + 5 - STBVOX_FACE_west)) & (1 << STBVOX_FACE_west);
|
|
|
|
+ }
|
|
|
|
+ if (visible_base & (1 << STBVOX_FACE_south)) {
|
|
|
|
+ int type = stbvox_facetype[ geo ][(STBVOX_FACE_south+ rot )&3];
|
|
|
|
+ int ntype = stbvox_facetype[ngeo[3]][(STBVOX_FACE_north+nrot[3])&3];
|
|
|
|
+ visible_faces |= ((stbvox_face_visible[type]) >> (ntype + 5 - STBVOX_FACE_south)) & (1 << STBVOX_FACE_south);
|
|
|
|
+ }
|
|
|
|
+ if (visible_base & (1 << STBVOX_FACE_up)) {
|
|
|
|
+ int type = stbvox_facetype[ geo ][STBVOX_FACE_up];
|
|
|
|
+ int ntype = stbvox_facetype[ngeo[4]][STBVOX_FACE_down];
|
|
|
|
+ visible_faces |= ((stbvox_face_visible[type]) >> (ntype + 5 - STBVOX_FACE_up)) & (1 << STBVOX_FACE_up);
|
|
|
|
+ }
|
|
|
|
+ if (visible_base & (1 << STBVOX_FACE_down)) {
|
|
|
|
+ int type = stbvox_facetype[ geo ][STBVOX_FACE_down];
|
|
|
|
+ int ntype = stbvox_facetype[ngeo[5]][STBVOX_FACE_up];
|
|
|
|
+ visible_faces |= ((stbvox_face_visible[type]) >> (ntype + 5 - STBVOX_FACE_down)) & (1 << STBVOX_FACE_down);
|
|
}
|
|
}
|
|
- return 1;
|
|
|
|
-}
|
|
|
|
|
|
|
|
-void stbvox_init_mesh_maker(stbvox_mesh_maker *mm)
|
|
|
|
-{
|
|
|
|
- memset(mm, 0, sizeof(*mm));
|
|
|
|
- stbvox_build_default_palette();
|
|
|
|
|
|
+ if (geo == STBVOX_GEOM_force)
|
|
|
|
+ geo = STBVOX_GEOM_solid;
|
|
|
|
|
|
- mm->config_dirty = 1;
|
|
|
|
- mm->default_mesh = 0;
|
|
|
|
-}
|
|
|
|
|
|
+ assert((geo == STBVOX_GEOM_crossed_pair) ? (visible_faces == 15) : 1);
|
|
|
|
|
|
-int stbvox_get_buffer_count(stbvox_mesh_maker *mm)
|
|
|
|
-{
|
|
|
|
- stbvox_bring_up_to_date(mm);
|
|
|
|
- return mm->num_mesh_slots;
|
|
|
|
-}
|
|
|
|
|
|
+ // now we finally know for sure which faces are getting generated
|
|
|
|
+ if (visible_faces == 0)
|
|
|
|
+ return;
|
|
|
|
|
|
-int stbvox_get_buffer_size_per_quad(stbvox_mesh_maker *mm, int n)
|
|
|
|
-{
|
|
|
|
- return mm->output_size[0][n];
|
|
|
|
-}
|
|
|
|
|
|
+ mesh = mm->default_mesh;
|
|
|
|
+ if (mm->input.selector)
|
|
|
|
+ mesh = mm->input.selector[v_off];
|
|
|
|
|
|
-void stbvox_reset_buffers(stbvox_mesh_maker *mm)
|
|
|
|
-{
|
|
|
|
- int i;
|
|
|
|
- for (i=0; i < STBVOX_MAX_MESHES*STBVOX_MAX_MESH_SLOTS; ++i) {
|
|
|
|
- mm->output_cur[0][i] = 0;
|
|
|
|
- mm->output_buffer[0][i] = 0;
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
|
|
+ if (geo <= STBVOX_GEOM_ceil_slope_north_is_bottom) {
|
|
|
|
+ // this is the simple case, we can just use regular block gen with special vmesh calculated with vheight
|
|
|
|
+ stbvox_mesh_vertex basevert;
|
|
|
|
+ stbvox_mesh_vertex vmesh[6][4];
|
|
|
|
+ stbvox_rotate rotate = { 0,0,0,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
|
|
|
|
+ // for visible faces only
|
|
|
|
+ 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]
|
|
|
|
+ + stbvox_geometry_vheight[geo][vert];
|
|
|
|
+ }
|
|
|
|
|
|
-void stbvox_set_buffer(stbvox_mesh_maker *mm, int mesh, int slot, void *buffer, size_t len)
|
|
|
|
-{
|
|
|
|
- int i;
|
|
|
|
- stbvox_bring_up_to_date(mm);
|
|
|
|
- mm->output_buffer[mesh][slot] = (char *) buffer;
|
|
|
|
- mm->output_cur [mesh][slot] = (char *) buffer;
|
|
|
|
- mm->output_len [mesh][slot] = len;
|
|
|
|
- mm->output_end [mesh][slot] = (char *) buffer + len;
|
|
|
|
- for (i=0; i < STBVOX_MAX_MESH_SLOTS; ++i) {
|
|
|
|
- if (mm->output_buffer[mesh][i]) {
|
|
|
|
- assert(mm->output_len[mesh][i] / mm->output_size[mesh][i] == mm->output_len[mesh][slot] / mm->output_size[mesh][slot]);
|
|
|
|
|
|
+ basevert = stbvox_vertex_encode(pos.x, pos.y, pos.z << STBVOX_CONFIG_PRECISION_Z, 0,0);
|
|
|
|
+ if (mm->input.selector) {
|
|
|
|
+ mesh = mm->input.selector[v_off];
|
|
}
|
|
}
|
|
- }
|
|
|
|
-}
|
|
|
|
|
|
|
|
-void stbvox_set_default_mesh(stbvox_mesh_maker *mm, int mesh)
|
|
|
|
-{
|
|
|
|
- mm->default_mesh = mesh;
|
|
|
|
-}
|
|
|
|
|
|
+ // 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]) {
|
|
|
|
+ mm->full = 1;
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
|
|
-int stbvox_get_quad_count(stbvox_mesh_maker *mm, int mesh)
|
|
|
|
-{
|
|
|
|
- return (mm->output_cur[mesh][0] - mm->output_buffer[mesh][0]) / mm->output_size[mesh][0];
|
|
|
|
-}
|
|
|
|
|
|
+ if (geo >= STBVOX_GEOM_floor_slope_north_is_top) {
|
|
|
|
+ if (visible_faces & (1 << STBVOX_FACE_up)) {
|
|
|
|
+ int normal = geo == STBVOX_GEOM_floor_slope_north_is_top ? stbvox_floor_slope_for_rot[simple_rot] : STBVOX_FACE_up;
|
|
|
|
+ rotate.facerot = simple_rot;
|
|
|
|
+ stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_up , v_off, pos, basevert, vmesh[STBVOX_FACE_up], mesh, normal);
|
|
|
|
+ }
|
|
|
|
+ if (visible_faces & (1 << STBVOX_FACE_down)) {
|
|
|
|
+ int normal = geo == STBVOX_GEOM_ceil_slope_north_is_bottom ? stbvox_ceil_slope_for_rot[simple_rot] : STBVOX_FACE_down;
|
|
|
|
+ rotate.facerot = (-rotate.facerot) & 3;
|
|
|
|
+ stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_down, v_off, pos, basevert, vmesh[STBVOX_FACE_down], mesh, normal);
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ if (visible_faces & (1 << STBVOX_FACE_up)) {
|
|
|
|
+ rotate.facerot = simple_rot;
|
|
|
|
+ stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_up , v_off, pos, basevert, vmesh[STBVOX_FACE_up], mesh, STBVOX_FACE_up);
|
|
|
|
+ }
|
|
|
|
+ if (visible_faces & (1 << STBVOX_FACE_down)) {
|
|
|
|
+ rotate.facerot = (-rotate.facerot) & 3;
|
|
|
|
+ stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_down, v_off, pos, basevert, vmesh[STBVOX_FACE_down], mesh, STBVOX_FACE_down);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
|
|
-stbvox_input_description *stbvox_get_input_description(stbvox_mesh_maker *mm)
|
|
|
|
-{
|
|
|
|
- return &mm->input;
|
|
|
|
-}
|
|
|
|
|
|
+ if (mm->input.rotate) {
|
|
|
|
+ unsigned char val = mm->input.rotate[v_off];
|
|
|
|
+ rotate.block = (val >> 0) & 3;
|
|
|
|
+ rotate.overlay = (val >> 2) & 3;
|
|
|
|
+ //rotate.tex2 = (val >> 4) & 3;
|
|
|
|
+ rotate.ecolor = (val >> 6) & 3;
|
|
|
|
+ } else {
|
|
|
|
+ rotate.block = rotate.overlay = rotate.ecolor = simple_rot;
|
|
|
|
+ }
|
|
|
|
|
|
-void stbvox_set_input_range(stbvox_mesh_maker *mm, int x0, int y0, int z0, int x1, int y1, int z1)
|
|
|
|
-{
|
|
|
|
- mm->x0 = x0;
|
|
|
|
- mm->y0 = y0;
|
|
|
|
- mm->z0 = z0;
|
|
|
|
|
|
+ rotate.facerot = 0;
|
|
|
|
|
|
- mm->x1 = x1;
|
|
|
|
- mm->y1 = y1;
|
|
|
|
- mm->z1 = z1;
|
|
|
|
-
|
|
|
|
- mm->cur_x = x0;
|
|
|
|
- mm->cur_y = y0;
|
|
|
|
- mm->cur_z = z0;
|
|
|
|
|
|
+ if (visible_faces & (1 << STBVOX_FACE_north))
|
|
|
|
+ stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_north, v_off, pos, basevert, vmesh[STBVOX_FACE_north], mesh, STBVOX_FACE_north);
|
|
|
|
+ if (visible_faces & (1 << STBVOX_FACE_south))
|
|
|
|
+ stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_south, v_off, pos, basevert, vmesh[STBVOX_FACE_south], mesh, STBVOX_FACE_south);
|
|
|
|
+ if (visible_faces & (1 << STBVOX_FACE_east))
|
|
|
|
+ stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_east , v_off, pos, basevert, vmesh[STBVOX_FACE_east ], mesh, STBVOX_FACE_east);
|
|
|
|
+ if (visible_faces & (1 << STBVOX_FACE_west))
|
|
|
|
+ stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_west , v_off, pos, basevert, vmesh[STBVOX_FACE_west ], mesh, STBVOX_FACE_west);
|
|
|
|
+ }
|
|
|
|
+ if (geo >= STBVOX_GEOM_floor_vheight_03) {
|
|
|
|
+ // this case can also be generated with regular block gen with special vmesh,
|
|
|
|
+ // except:
|
|
|
|
+ // if we want to generate middle diagonal for 'weird' blocks
|
|
|
|
+ // it's more complicated to detect neighbor matchups
|
|
|
|
+ stbvox_mesh_vertex vmesh[6][4];
|
|
|
|
+ stbvox_mesh_vertex cube[8];
|
|
|
|
+ stbvox_mesh_vertex basevert;
|
|
|
|
+ stbvox_rotate rotate = { 0,0,0,0 };
|
|
|
|
+ unsigned char simple_rot = rot;
|
|
|
|
+ unsigned char ht[4];
|
|
|
|
+ int extreme;
|
|
|
|
|
|
- // @TODO validate that this range is representable in this mode
|
|
|
|
-}
|
|
|
|
|
|
+ // extract the heights
|
|
|
|
+ if (mm->input.vheight) {
|
|
|
|
+ unsigned char v = mm->input.vheight[v_off];
|
|
|
|
+ ht[0] = (v >> 0) & 3;
|
|
|
|
+ ht[1] = (v >> 2) & 3;
|
|
|
|
+ ht[2] = (v >> 4) & 3;
|
|
|
|
+ ht[3] = (v >> 6) & 3;
|
|
|
|
+ } else if (mm->input.block_vheight) {
|
|
|
|
+ unsigned char v = mm->input.block_vheight[bt];
|
|
|
|
+ unsigned char raw[4];
|
|
|
|
+ int i;
|
|
|
|
|
|
-void stbvox_get_transform(stbvox_mesh_maker *mm, float transform[3][3])
|
|
|
|
-{
|
|
|
|
- // scale
|
|
|
|
- transform[0][0] = 1.0;
|
|
|
|
- transform[0][1] = 1.0;
|
|
|
|
- #if STBVOX_CONFIG_PRECISION_Z==1
|
|
|
|
- transform[0][2] = 0.5f;
|
|
|
|
- #else
|
|
|
|
- transform[0][2] = 1.0f;
|
|
|
|
- #endif
|
|
|
|
- // translation
|
|
|
|
- transform[1][0] = (float) (mm->pos_x);
|
|
|
|
- transform[1][1] = (float) (mm->pos_y);
|
|
|
|
- transform[1][2] = (float) (mm->pos_z);
|
|
|
|
- // texture coordinate projection translation
|
|
|
|
- transform[2][0] = (float) (mm->pos_x & 255); // @TODO depends on max texture scale
|
|
|
|
- transform[2][1] = (float) (mm->pos_y & 255);
|
|
|
|
- transform[2][2] = (float) (mm->pos_z & 255);
|
|
|
|
-}
|
|
|
|
|
|
+ raw[0] = (v >> 0) & 3;
|
|
|
|
+ raw[1] = (v >> 2) & 3;
|
|
|
|
+ raw[2] = (v >> 4) & 3;
|
|
|
|
+ raw[3] = (v >> 6) & 3;
|
|
|
|
|
|
-void stbvox_get_bounds(stbvox_mesh_maker *mm, float bounds[2][3])
|
|
|
|
-{
|
|
|
|
- bounds[0][0] = (float) (mm->pos_x + mm->x0);
|
|
|
|
- bounds[0][1] = (float) (mm->pos_y + mm->y0);
|
|
|
|
- bounds[0][2] = (float) (mm->pos_z + mm->z0);
|
|
|
|
- bounds[1][0] = (float) (mm->pos_x + mm->x1);
|
|
|
|
- bounds[1][1] = (float) (mm->pos_y + mm->y1);
|
|
|
|
- bounds[1][2] = (float) (mm->pos_z + mm->z1);
|
|
|
|
-}
|
|
|
|
|
|
+ for (i=0; i < 4; ++i)
|
|
|
|
+ ht[i] = raw[stbvox_rotate_vertex[i][rot]];
|
|
|
|
+ } else {
|
|
|
|
+ assert(0);
|
|
|
|
+ }
|
|
|
|
|
|
-void stbvox_set_mesh_coordinates(stbvox_mesh_maker *mm, int x, int y, int z)
|
|
|
|
-{
|
|
|
|
- mm->pos_x = x;
|
|
|
|
- mm->pos_y = y;
|
|
|
|
- mm->pos_z = z;
|
|
|
|
-}
|
|
|
|
|
|
+ // 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);
|
|
|
|
|
|
-void stbvox_set_input_stride(stbvox_mesh_maker *mm, int x_stride_in_bytes, int y_stride_in_bytes)
|
|
|
|
-{
|
|
|
|
- int f,v;
|
|
|
|
- mm->x_stride_in_bytes = x_stride_in_bytes;
|
|
|
|
- mm->y_stride_in_bytes = y_stride_in_bytes;
|
|
|
|
- for (f=0; f < 6; ++f) {
|
|
|
|
- for (v=0; v < 4; ++v) {
|
|
|
|
- mm->cube_vertex_offset[f][v] = stbvox_vertex_vector[f][v][0] * mm->x_stride_in_bytes
|
|
|
|
- + stbvox_vertex_vector[f][v][1] * mm->y_stride_in_bytes
|
|
|
|
- + stbvox_vertex_vector[f][v][2] ;
|
|
|
|
- mm->vertex_gather_offset[f][v] = (stbvox_vertex_vector[f][v][0]-1) * mm->x_stride_in_bytes
|
|
|
|
- + (stbvox_vertex_vector[f][v][1]-1) * mm->y_stride_in_bytes
|
|
|
|
- + (stbvox_vertex_vector[f][v][2]-1) ;
|
|
|
|
|
|
+ if (geo >= STBVOX_GEOM_ceil_vheight_03) {
|
|
|
|
+ cube[0] = stbvox_vertex_encode(0,0,ht[0],0,0);
|
|
|
|
+ cube[1] = stbvox_vertex_encode(0,0,ht[1],0,0);
|
|
|
|
+ cube[2] = stbvox_vertex_encode(0,0,ht[2],0,0);
|
|
|
|
+ cube[3] = stbvox_vertex_encode(0,0,ht[3],0,0);
|
|
|
|
+ cube[4] = stbvox_vertex_encode(0,0,2,0,0);
|
|
|
|
+ cube[5] = stbvox_vertex_encode(0,0,2,0,0);
|
|
|
|
+ cube[6] = stbvox_vertex_encode(0,0,2,0,0);
|
|
|
|
+ cube[7] = stbvox_vertex_encode(0,0,2,0,0);
|
|
|
|
+ } else {
|
|
|
|
+ cube[0] = stbvox_vertex_encode(0,0,0,0,0);
|
|
|
|
+ cube[1] = stbvox_vertex_encode(0,0,0,0,0);
|
|
|
|
+ cube[2] = stbvox_vertex_encode(0,0,0,0,0);
|
|
|
|
+ cube[3] = stbvox_vertex_encode(0,0,0,0,0);
|
|
|
|
+ cube[4] = stbvox_vertex_encode(0,0,ht[0],0,0);
|
|
|
|
+ cube[5] = stbvox_vertex_encode(0,0,ht[1],0,0);
|
|
|
|
+ cube[6] = stbvox_vertex_encode(0,0,ht[2],0,0);
|
|
|
|
+ cube[7] = stbvox_vertex_encode(0,0,ht[3],0,0);
|
|
|
|
+ }
|
|
|
|
+ if (!mm->input.vheight && mm->input.block_vheight) {
|
|
|
|
+ // @TODO: support block vheight here, I've forgotten what needs to be done specially
|
|
}
|
|
}
|
|
- }
|
|
|
|
-}
|
|
|
|
|
|
|
|
-/////////////////////////////////////////////////////////////////////////////
|
|
|
|
-//
|
|
|
|
-// tables
|
|
|
|
-//
|
|
|
|
|
|
+ // build vertex mesh
|
|
|
|
+ {
|
|
|
|
+ int i;
|
|
|
|
+ for (i=0; i < 6*4; ++i) {
|
|
|
|
+ int vert = stbvox_vertex_selector[0][i];
|
|
|
|
+ vmesh[0][i] = stbvox_vmesh_pre_vheight[0][i]
|
|
|
|
+ + cube[vert];
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
|
|
-// get opposite-facing normal & texgen for opposite face, used to map up-facing vheight data to down-facing data
|
|
|
|
-static unsigned char stbvox_reverse_face[STBVF_count] =
|
|
|
|
-{
|
|
|
|
- STBVF_w, STBVF_s, STBVF_e, STBVF_n, STBVF_d , STBVF_u , STBVF_wd, STBVF_wu,
|
|
|
|
- 0, 0, 0, 0, STBVF_sw_d, STBVF_sw_u, STBVF_sd, STBVF_su,
|
|
|
|
- 0, 0, 0, 0, STBVF_se_d, STBVF_se_u, STBVF_ed, STBVF_eu,
|
|
|
|
- 0, 0, 0, 0, STBVF_ne_d, STBVF_ne_d, STBVF_nd, STBVF_nu
|
|
|
|
-};
|
|
|
|
|
|
+ basevert = stbvox_vertex_encode(pos.x, pos.y, pos.z << STBVOX_CONFIG_PRECISION_Z, 0,0);
|
|
|
|
+ // 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]) {
|
|
|
|
+ mm->full = 1;
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
|
|
-static float stbvox_default_texgen[2][32][3] =
|
|
|
|
-{
|
|
|
|
- { { 0, 1,0 }, { 0, 0, 1 }, { 0,-1,0 }, { 0, 0,-1 },
|
|
|
|
- { -1, 0,0 }, { 0, 0, 1 }, { 1, 0,0 }, { 0, 0,-1 },
|
|
|
|
- { 0,-1,0 }, { 0, 0, 1 }, { 0, 1,0 }, { 0, 0,-1 },
|
|
|
|
- { 1, 0,0 }, { 0, 0, 1 }, { -1, 0,0 }, { 0, 0,-1 },
|
|
|
|
|
|
+ // @TODO generate split faces
|
|
|
|
+ if (visible_faces & (1 << STBVOX_FACE_up)) {
|
|
|
|
+ if (geo >= STBVOX_GEOM_ceil_vheight_03)
|
|
|
|
+ // flat
|
|
|
|
+ stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_up , v_off, pos, basevert, vmesh[STBVOX_FACE_up], mesh, STBVOX_FACE_up);
|
|
|
|
+ else {
|
|
|
|
+ #ifndef STBVOX_OPTIMIZED_VHEIGHT
|
|
|
|
+ // check if it's non-planar
|
|
|
|
+ if (cube[5] + cube[6] != cube[4] + cube[7]) {
|
|
|
|
+ // not planar, split along diagonal and make degenerate quads
|
|
|
|
+ if (geo == STBVOX_GEOM_floor_vheight_03)
|
|
|
|
+ stbvox_make_03_split_mesh_for_face(mm, rotate, STBVOX_FACE_up, v_off, pos, basevert, vmesh[STBVOX_FACE_up], mesh, ht);
|
|
|
|
+ else
|
|
|
|
+ stbvox_make_12_split_mesh_for_face(mm, rotate, STBVOX_FACE_up, v_off, pos, basevert, vmesh[STBVOX_FACE_up], mesh, ht);
|
|
|
|
+ } else
|
|
|
|
+ stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_up , v_off, pos, basevert, vmesh[STBVOX_FACE_up], mesh, stbvox_planar_face_up_normal[ht[2]][ht[1]][ht[0]]);
|
|
|
|
+ #else
|
|
|
|
+ stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_up , v_off, pos, basevert, vmesh[STBVOX_FACE_up], mesh, stbvox_optimized_face_up_normal[ht[3]][ht[2]][ht[1]][ht[0]]);
|
|
|
|
+ #endif
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if (visible_faces & (1 << STBVOX_FACE_down)) {
|
|
|
|
+ if (geo < STBVOX_GEOM_ceil_vheight_03)
|
|
|
|
+ // flat
|
|
|
|
+ stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_down, v_off, pos, basevert, vmesh[STBVOX_FACE_down], mesh, STBVOX_FACE_down);
|
|
|
|
+ else {
|
|
|
|
+ #ifndef STBVOX_OPTIMIZED_VHEIGHT
|
|
|
|
+ // check if it's non-planar
|
|
|
|
+ if (cube[1] + cube[2] != cube[0] + cube[3]) {
|
|
|
|
+ // not planar, split along diagonal and make degenerate quads
|
|
|
|
+ if (geo == STBVOX_GEOM_ceil_vheight_03)
|
|
|
|
+ stbvox_make_03_split_mesh_for_face(mm, rotate, STBVOX_FACE_down, v_off, pos, basevert, vmesh[STBVOX_FACE_down], mesh, ht);
|
|
|
|
+ else
|
|
|
|
+ stbvox_make_12_split_mesh_for_face(mm, rotate, STBVOX_FACE_down, v_off, pos, basevert, vmesh[STBVOX_FACE_down], mesh, ht);
|
|
|
|
+ } else
|
|
|
|
+ stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_down, v_off, pos, basevert, vmesh[STBVOX_FACE_down], mesh, stbvox_reverse_face[stbvox_planar_face_up_normal[ht[2]][ht[1]][ht[0]]]);
|
|
|
|
+ #else
|
|
|
|
+ stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_down, v_off, pos, basevert, vmesh[STBVOX_FACE_down], mesh, stbvox_reverse_face[stbvox_optimized_face_up_normal[ht[3]][ht[2]][ht[1]][ht[0]]]);
|
|
|
|
+ #endif
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
|
|
- { 1, 0,0 }, { 0, 1, 0 }, { -1, 0,0 }, { 0,-1, 0 },
|
|
|
|
- { -1, 0,0 }, { 0,-1, 0 }, { 1, 0,0 }, { 0, 1, 0 },
|
|
|
|
- { 1, 0,0 }, { 0, 1, 0 }, { -1, 0,0 }, { 0,-1, 0 },
|
|
|
|
- { -1, 0,0 }, { 0,-1, 0 }, { 1, 0,0 }, { 0, 1, 0 },
|
|
|
|
- },
|
|
|
|
- { { 0, 0,-1 }, { 0, 1,0 }, { 0, 0, 1 }, { 0,-1,0 },
|
|
|
|
- { 0, 0,-1 }, { -1, 0,0 }, { 0, 0, 1 }, { 1, 0,0 },
|
|
|
|
- { 0, 0,-1 }, { 0,-1,0 }, { 0, 0, 1 }, { 0, 1,0 },
|
|
|
|
- { 0, 0,-1 }, { 1, 0,0 }, { 0, 0, 1 }, { -1, 0,0 },
|
|
|
|
|
|
+ if (mm->input.rotate) {
|
|
|
|
+ unsigned char val = mm->input.rotate[v_off];
|
|
|
|
+ rotate.block = (val >> 0) & 3;
|
|
|
|
+ rotate.overlay = (val >> 2) & 3;
|
|
|
|
+ //rotate.tex2 = (val >> 4) & 3;
|
|
|
|
+ rotate.ecolor = (val >> 6) & 3;
|
|
|
|
+ } else if (mm->input.selector) {
|
|
|
|
+ rotate.block = rotate.overlay = rotate.ecolor = simple_rot;
|
|
|
|
+ }
|
|
|
|
|
|
- { 0,-1, 0 }, { 1, 0,0 }, { 0, 1, 0 }, { -1, 0,0 },
|
|
|
|
- { 0, 1, 0 }, { -1, 0,0 }, { 0,-1, 0 }, { 1, 0,0 },
|
|
|
|
- { 0,-1, 0 }, { 1, 0,0 }, { 0, 1, 0 }, { -1, 0,0 },
|
|
|
|
- { 0, 1, 0 }, { -1, 0,0 }, { 0,-1, 0 }, { 1, 0,0 },
|
|
|
|
- },
|
|
|
|
-};
|
|
|
|
|
|
+ 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, STBVOX_FACE_north);
|
|
|
|
+ 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, STBVOX_FACE_south);
|
|
|
|
+ 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, STBVOX_FACE_east);
|
|
|
|
+ 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, STBVOX_FACE_west);
|
|
|
|
+ }
|
|
|
|
|
|
-#define STBVOX_RSQRT2 0.7071067811865f
|
|
|
|
-#define STBVOX_RSQRT3 0.5773502691896f
|
|
|
|
|
|
+ if (geo == STBVOX_GEOM_crossed_pair) {
|
|
|
|
+ // this can be generated with a special vmesh
|
|
|
|
+ stbvox_mesh_vertex basevert = stbvox_vertex_encode(pos.x, pos.y, pos.z << STBVOX_CONFIG_PRECISION_Z , 0,0);
|
|
|
|
+ unsigned char simple_rot=0;
|
|
|
|
+ stbvox_rotate rot = { 0,0,0,0 };
|
|
|
|
+ unsigned char mesh = mm->default_mesh;
|
|
|
|
+ if (mm->input.selector) {
|
|
|
|
+ mesh = mm->input.selector[v_off];
|
|
|
|
+ simple_rot = mesh >> 4;
|
|
|
|
+ mesh &= 15;
|
|
|
|
+ }
|
|
|
|
|
|
-static float stbvox_default_normals[32][3] =
|
|
|
|
-{
|
|
|
|
- { 1,0,0 }, // east
|
|
|
|
- { 0,1,0 }, // north
|
|
|
|
- { -1,0,0 }, // west
|
|
|
|
- { 0,-1,0 }, // south
|
|
|
|
- { 0,0,1 }, // up
|
|
|
|
- { 0,0,-1 }, // down
|
|
|
|
- { STBVOX_RSQRT2,0, STBVOX_RSQRT2 }, // east & up
|
|
|
|
- { STBVOX_RSQRT2,0, -STBVOX_RSQRT2 }, // east & down
|
|
|
|
|
|
+ // check if we're going off the end
|
|
|
|
+ if (mm->output_cur[mesh][0] + mm->output_size[mesh][0]*4 > mm->output_end[mesh][0]) {
|
|
|
|
+ mm->full = 1;
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
|
|
- { STBVOX_RSQRT2,0, STBVOX_RSQRT2 }, // east & up
|
|
|
|
- { 0, STBVOX_RSQRT2, STBVOX_RSQRT2 }, // north & up
|
|
|
|
- { -STBVOX_RSQRT2,0, STBVOX_RSQRT2 }, // west & up
|
|
|
|
- { 0,-STBVOX_RSQRT2, STBVOX_RSQRT2 }, // south & up
|
|
|
|
- { STBVOX_RSQRT3, STBVOX_RSQRT3, STBVOX_RSQRT3 }, // ne & up
|
|
|
|
- { STBVOX_RSQRT3, STBVOX_RSQRT3,-STBVOX_RSQRT3 }, // ne & down
|
|
|
|
- { 0, STBVOX_RSQRT2, STBVOX_RSQRT2 }, // north & up
|
|
|
|
- { 0, STBVOX_RSQRT2, -STBVOX_RSQRT2 }, // north & down
|
|
|
|
-
|
|
|
|
- { STBVOX_RSQRT2,0, -STBVOX_RSQRT2 }, // east & down
|
|
|
|
- { 0, STBVOX_RSQRT2, -STBVOX_RSQRT2 }, // north & down
|
|
|
|
- { -STBVOX_RSQRT2,0, -STBVOX_RSQRT2 }, // west & down
|
|
|
|
- { 0,-STBVOX_RSQRT2, -STBVOX_RSQRT2 }, // south & down
|
|
|
|
- { -STBVOX_RSQRT3, STBVOX_RSQRT3, STBVOX_RSQRT3 }, // NW & up
|
|
|
|
- { -STBVOX_RSQRT3, STBVOX_RSQRT3,-STBVOX_RSQRT3 }, // NW & down
|
|
|
|
- { -STBVOX_RSQRT2,0, STBVOX_RSQRT2 }, // west & up
|
|
|
|
- { -STBVOX_RSQRT2,0, -STBVOX_RSQRT2 }, // west & down
|
|
|
|
-
|
|
|
|
- { STBVOX_RSQRT3, STBVOX_RSQRT3,STBVOX_RSQRT3 }, // NE & up crossed
|
|
|
|
- { -STBVOX_RSQRT3, STBVOX_RSQRT3,STBVOX_RSQRT3 }, // NW & up crossed
|
|
|
|
- { -STBVOX_RSQRT3,-STBVOX_RSQRT3,STBVOX_RSQRT3 }, // SW & up crossed
|
|
|
|
- { STBVOX_RSQRT3,-STBVOX_RSQRT3,STBVOX_RSQRT3 }, // SE & up crossed
|
|
|
|
- { -STBVOX_RSQRT3,-STBVOX_RSQRT3, STBVOX_RSQRT3 }, // SW & up
|
|
|
|
- { -STBVOX_RSQRT3,-STBVOX_RSQRT3,-STBVOX_RSQRT3 }, // SW & up
|
|
|
|
- { 0,-STBVOX_RSQRT2, STBVOX_RSQRT2 }, // south & up
|
|
|
|
- { 0,-STBVOX_RSQRT2, -STBVOX_RSQRT2 }, // south & down
|
|
|
|
-};
|
|
|
|
-
|
|
|
|
-static float stbvox_default_texscale[128][4] =
|
|
|
|
-{
|
|
|
|
- {1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},
|
|
|
|
- {1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},
|
|
|
|
- {1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},
|
|
|
|
- {1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},
|
|
|
|
- {1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},
|
|
|
|
- {1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},
|
|
|
|
- {1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},
|
|
|
|
- {1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},
|
|
|
|
- {1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},
|
|
|
|
- {1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},
|
|
|
|
- {1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},
|
|
|
|
- {1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},
|
|
|
|
- {1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},
|
|
|
|
- {1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},
|
|
|
|
- {1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},
|
|
|
|
- {1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},
|
|
|
|
-};
|
|
|
|
-
|
|
|
|
-static unsigned char stbvox_default_palette_compact[64][3] =
|
|
|
|
-{
|
|
|
|
- { 255,255,255 }, { 238,238,238 }, { 221,221,221 }, { 204,204,204 },
|
|
|
|
- { 187,187,187 }, { 170,170,170 }, { 153,153,153 }, { 136,136,136 },
|
|
|
|
- { 119,119,119 }, { 102,102,102 }, { 85, 85, 85 }, { 68, 68, 68 },
|
|
|
|
- { 51, 51, 51 }, { 34, 34, 34 }, { 17, 17, 17 }, { 0, 0, 0 },
|
|
|
|
- { 255,240,240 }, { 255,220,220 }, { 255,160,160 }, { 255, 32, 32 },
|
|
|
|
- { 200,120,160 }, { 200, 60,150 }, { 220,100,130 }, { 255, 0,128 },
|
|
|
|
- { 240,240,255 }, { 220,220,255 }, { 160,160,255 }, { 32, 32,255 },
|
|
|
|
- { 120,160,200 }, { 60,150,200 }, { 100,130,220 }, { 0,128,255 },
|
|
|
|
- { 240,255,240 }, { 220,255,220 }, { 160,255,160 }, { 32,255, 32 },
|
|
|
|
- { 160,200,120 }, { 150,200, 60 }, { 130,220,100 }, { 128,255, 0 },
|
|
|
|
- { 255,255,240 }, { 255,255,220 }, { 220,220,180 }, { 255,255, 32 },
|
|
|
|
- { 200,160,120 }, { 200,150, 60 }, { 220,130,100 }, { 255,128, 0 },
|
|
|
|
- { 255,240,255 }, { 255,220,255 }, { 220,180,220 }, { 255, 32,255 },
|
|
|
|
- { 160,120,200 }, { 150, 60,200 }, { 130,100,220 }, { 128, 0,255 },
|
|
|
|
- { 240,255,255 }, { 220,255,255 }, { 180,220,220 }, { 32,255,255 },
|
|
|
|
- { 120,200,160 }, { 60,200,150 }, { 100,220,130 }, { 0,255,128 },
|
|
|
|
-};
|
|
|
|
-
|
|
|
|
-static unsigned char stbvox_vertex_vector[6][4][3] =
|
|
|
|
-{
|
|
|
|
- { { 1,0,1 }, { 1,1,1 }, { 1,1,0 }, { 1,0,0 } }, // east
|
|
|
|
- { { 1,1,1 }, { 0,1,1 }, { 0,1,0 }, { 1,1,0 } }, // north
|
|
|
|
- { { 0,1,1 }, { 0,0,1 }, { 0,0,0 }, { 0,1,0 } }, // west
|
|
|
|
- { { 0,0,1 }, { 1,0,1 }, { 1,0,0 }, { 0,0,0 } }, // south
|
|
|
|
- { { 0,1,1 }, { 1,1,1 }, { 1,0,1 }, { 0,0,1 } }, // up
|
|
|
|
- { { 0,0,0 }, { 1,0,0 }, { 1,1,0 }, { 0,1,0 } }, // down
|
|
|
|
-};
|
|
|
|
-
|
|
|
|
-// stbvox_vertex_vector, but read coordinates as binary numbers, zyx
|
|
|
|
-static unsigned char stbvox_vertex_selector[6][4] =
|
|
|
|
-{
|
|
|
|
- { 5,7,3,1 },
|
|
|
|
- { 7,6,2,3 },
|
|
|
|
- { 6,4,0,2 },
|
|
|
|
- { 4,5,1,0 },
|
|
|
|
- { 6,7,5,4 },
|
|
|
|
- { 0,1,3,2 },
|
|
|
|
-};
|
|
|
|
-
|
|
|
|
-static stbvox_mesh_vertex stbvox_vmesh_delta_normal[6][4] =
|
|
|
|
-{
|
|
|
|
- { stbvox_vertex_encode(1,0,1,0,0) ,
|
|
|
|
- stbvox_vertex_encode(1,1,1,0,0) ,
|
|
|
|
- stbvox_vertex_encode(1,1,0,0,0) ,
|
|
|
|
- stbvox_vertex_encode(1,0,0,0,0) },
|
|
|
|
- { stbvox_vertex_encode(1,1,1,0,0) ,
|
|
|
|
- stbvox_vertex_encode(0,1,1,0,0) ,
|
|
|
|
- stbvox_vertex_encode(0,1,0,0,0) ,
|
|
|
|
- stbvox_vertex_encode(1,1,0,0,0) },
|
|
|
|
- { stbvox_vertex_encode(0,1,1,0,0) ,
|
|
|
|
- stbvox_vertex_encode(0,0,1,0,0) ,
|
|
|
|
- stbvox_vertex_encode(0,0,0,0,0) ,
|
|
|
|
- stbvox_vertex_encode(0,1,0,0,0) },
|
|
|
|
- { stbvox_vertex_encode(0,0,1,0,0) ,
|
|
|
|
- stbvox_vertex_encode(1,0,1,0,0) ,
|
|
|
|
- stbvox_vertex_encode(1,0,0,0,0) ,
|
|
|
|
- stbvox_vertex_encode(0,0,0,0,0) },
|
|
|
|
- { stbvox_vertex_encode(0,1,1,0,0) ,
|
|
|
|
- stbvox_vertex_encode(1,1,1,0,0) ,
|
|
|
|
- stbvox_vertex_encode(1,0,1,0,0) ,
|
|
|
|
- stbvox_vertex_encode(0,0,1,0,0) },
|
|
|
|
- { stbvox_vertex_encode(0,0,0,0,0) ,
|
|
|
|
- stbvox_vertex_encode(1,0,0,0,0) ,
|
|
|
|
- stbvox_vertex_encode(1,1,0,0,0) ,
|
|
|
|
- stbvox_vertex_encode(0,1,0,0,0) }
|
|
|
|
-};
|
|
|
|
-
|
|
|
|
-static stbvox_mesh_vertex stbvox_vmesh_pre_vheight[6][4] =
|
|
|
|
-{
|
|
|
|
- { stbvox_vertex_encode(1,0,0,0,0) ,
|
|
|
|
- stbvox_vertex_encode(1,1,0,0,0) ,
|
|
|
|
- stbvox_vertex_encode(1,1,0,0,0) ,
|
|
|
|
- stbvox_vertex_encode(1,0,0,0,0) },
|
|
|
|
- { stbvox_vertex_encode(1,1,0,0,0) ,
|
|
|
|
- stbvox_vertex_encode(0,1,0,0,0) ,
|
|
|
|
- stbvox_vertex_encode(0,1,0,0,0) ,
|
|
|
|
- stbvox_vertex_encode(1,1,0,0,0) },
|
|
|
|
- { stbvox_vertex_encode(0,1,0,0,0) ,
|
|
|
|
- stbvox_vertex_encode(0,0,0,0,0) ,
|
|
|
|
- stbvox_vertex_encode(0,0,0,0,0) ,
|
|
|
|
- stbvox_vertex_encode(0,1,0,0,0) },
|
|
|
|
- { stbvox_vertex_encode(0,0,0,0,0) ,
|
|
|
|
- stbvox_vertex_encode(1,0,0,0,0) ,
|
|
|
|
- stbvox_vertex_encode(1,0,0,0,0) ,
|
|
|
|
- stbvox_vertex_encode(0,0,0,0,0) },
|
|
|
|
- { stbvox_vertex_encode(0,1,0,0,0) ,
|
|
|
|
- stbvox_vertex_encode(1,1,0,0,0) ,
|
|
|
|
- stbvox_vertex_encode(1,0,0,0,0) ,
|
|
|
|
- stbvox_vertex_encode(0,0,0,0,0) },
|
|
|
|
- { stbvox_vertex_encode(0,0,0,0,0) ,
|
|
|
|
- stbvox_vertex_encode(1,0,0,0,0) ,
|
|
|
|
- stbvox_vertex_encode(1,1,0,0,0) ,
|
|
|
|
- stbvox_vertex_encode(0,1,0,0,0) }
|
|
|
|
-};
|
|
|
|
-
|
|
|
|
-static stbvox_mesh_vertex stbvox_vmesh_delta_half_z[6][4] =
|
|
|
|
-{
|
|
|
|
- { stbvox_vertex_encode(1,0,2,0,0) ,
|
|
|
|
- stbvox_vertex_encode(1,1,2,0,0) ,
|
|
|
|
- stbvox_vertex_encode(1,1,0,0,0) ,
|
|
|
|
- stbvox_vertex_encode(1,0,0,0,0) },
|
|
|
|
- { stbvox_vertex_encode(1,1,2,0,0) ,
|
|
|
|
- stbvox_vertex_encode(0,1,2,0,0) ,
|
|
|
|
- stbvox_vertex_encode(0,1,0,0,0) ,
|
|
|
|
- stbvox_vertex_encode(1,1,0,0,0) },
|
|
|
|
- { stbvox_vertex_encode(0,1,2,0,0) ,
|
|
|
|
- stbvox_vertex_encode(0,0,2,0,0) ,
|
|
|
|
- stbvox_vertex_encode(0,0,0,0,0) ,
|
|
|
|
- stbvox_vertex_encode(0,1,0,0,0) },
|
|
|
|
- { stbvox_vertex_encode(0,0,2,0,0) ,
|
|
|
|
- stbvox_vertex_encode(1,0,2,0,0) ,
|
|
|
|
- stbvox_vertex_encode(1,0,0,0,0) ,
|
|
|
|
- stbvox_vertex_encode(0,0,0,0,0) },
|
|
|
|
- { stbvox_vertex_encode(0,1,2,0,0) ,
|
|
|
|
- stbvox_vertex_encode(1,1,2,0,0) ,
|
|
|
|
- stbvox_vertex_encode(1,0,2,0,0) ,
|
|
|
|
- stbvox_vertex_encode(0,0,2,0,0) },
|
|
|
|
- { stbvox_vertex_encode(0,0,0,0,0) ,
|
|
|
|
- stbvox_vertex_encode(1,0,0,0,0) ,
|
|
|
|
- stbvox_vertex_encode(1,1,0,0,0) ,
|
|
|
|
- stbvox_vertex_encode(0,1,0,0,0) }
|
|
|
|
-};
|
|
|
|
-
|
|
|
|
-static stbvox_mesh_vertex stbvox_vmesh_crossed_pair[6][4] =
|
|
|
|
-{
|
|
|
|
- { stbvox_vertex_encode(1,0,2,0,0) ,
|
|
|
|
- stbvox_vertex_encode(0,1,2,0,0) ,
|
|
|
|
- stbvox_vertex_encode(0,1,0,0,0) ,
|
|
|
|
- stbvox_vertex_encode(1,0,0,0,0) },
|
|
|
|
- { stbvox_vertex_encode(1,1,2,0,0) ,
|
|
|
|
- stbvox_vertex_encode(0,0,2,0,0) ,
|
|
|
|
- stbvox_vertex_encode(0,0,0,0,0) ,
|
|
|
|
- stbvox_vertex_encode(1,1,0,0,0) },
|
|
|
|
- { stbvox_vertex_encode(0,1,2,0,0) ,
|
|
|
|
- stbvox_vertex_encode(1,0,2,0,0) ,
|
|
|
|
- stbvox_vertex_encode(1,0,0,0,0) ,
|
|
|
|
- stbvox_vertex_encode(0,1,0,0,0) },
|
|
|
|
- { stbvox_vertex_encode(0,0,2,0,0) ,
|
|
|
|
- stbvox_vertex_encode(1,1,2,0,0) ,
|
|
|
|
- stbvox_vertex_encode(1,1,0,0,0) ,
|
|
|
|
- stbvox_vertex_encode(0,0,0,0,0) },
|
|
|
|
- // not used, so we leave it non-degenerate to make sure it doesn't get gen'd accidentally
|
|
|
|
- { stbvox_vertex_encode(0,1,2,0,0) ,
|
|
|
|
- stbvox_vertex_encode(1,1,2,0,0) ,
|
|
|
|
- stbvox_vertex_encode(1,0,2,0,0) ,
|
|
|
|
- stbvox_vertex_encode(0,0,2,0,0) },
|
|
|
|
- { stbvox_vertex_encode(0,0,0,0,0) ,
|
|
|
|
- stbvox_vertex_encode(1,0,0,0,0) ,
|
|
|
|
- stbvox_vertex_encode(1,1,0,0,0) ,
|
|
|
|
- stbvox_vertex_encode(0,1,0,0,0) }
|
|
|
|
-};
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-// this is used to determine if a face is ever generated at all
|
|
|
|
-static unsigned char stbvox_hasface[STBVOX_MAX_GEOM][STBVOX_NUM_ROTATION] =
|
|
|
|
-{
|
|
|
|
- { 0,0,0,0 }, // empty
|
|
|
|
- { 0,0,0,0 }, // knockout
|
|
|
|
- { 63,63,63,63 }, // solid
|
|
|
|
- { 63,63,63,63 }, // transp
|
|
|
|
- { 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 }, // force
|
|
|
|
- { 63,63,63,63 },
|
|
|
|
- { 63,63,63,63 },
|
|
|
|
- { 63,63,63,63 },
|
|
|
|
- { 63,63,63,63 },
|
|
|
|
-};
|
|
|
|
-
|
|
|
|
-// this determines which face type above is visible on each side of the geometry
|
|
|
|
-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
|
|
|
|
- { STBVOX_FT_solid, STBVOX_FT_solid, STBVOX_FT_solid, STBVOX_FT_solid, STBVOX_FT_solid, STBVOX_FT_solid }, // solid
|
|
|
|
- { STBVOX_FT_force, STBVOX_FT_force, STBVOX_FT_force, STBVOX_FT_force, STBVOX_FT_force, STBVOX_FT_force }, // transp
|
|
|
|
-
|
|
|
|
- { STBVOX_FT_upper, STBVOX_FT_upper, STBVOX_FT_upper, STBVOX_FT_upper, STBVOX_FT_solid, STBVOX_FT_force },
|
|
|
|
- { STBVOX_FT_lower, STBVOX_FT_lower, STBVOX_FT_lower, STBVOX_FT_lower, STBVOX_FT_force, STBVOX_FT_solid },
|
|
|
|
- { STBVOX_FT_diag_123, STBVOX_FT_solid, STBVOX_FT_diag_023, STBVOX_FT_none, STBVOX_FT_force, STBVOX_FT_solid },
|
|
|
|
- { STBVOX_FT_diag_012, STBVOX_FT_solid, STBVOX_FT_diag_013, STBVOX_FT_none, STBVOX_FT_solid, STBVOX_FT_force },
|
|
|
|
-
|
|
|
|
- { 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 }, // GEOM_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 what normal to use for the "up" face of a sloped geom
|
|
|
|
-// @TODO this could be done with math given the current arrangement of the enum, but let's not require it
|
|
|
|
-static unsigned char stbvox_floor_slope_for_rot[4] =
|
|
|
|
-{
|
|
|
|
- STBVF_su,
|
|
|
|
- STBVF_wu, // @TODO: why is this reversed from what it should be? this is a north-is-up face, so slope should be south&up
|
|
|
|
- STBVF_nu,
|
|
|
|
- STBVF_eu,
|
|
|
|
-};
|
|
|
|
-
|
|
|
|
-static unsigned char stbvox_ceil_slope_for_rot[4] =
|
|
|
|
-{
|
|
|
|
- STBVF_sd,
|
|
|
|
- STBVF_ed,
|
|
|
|
- STBVF_nd,
|
|
|
|
- STBVF_wd,
|
|
|
|
-};
|
|
|
|
|
|
+ if (mm->input.rotate) {
|
|
|
|
+ unsigned char val = mm->input.rotate[v_off];
|
|
|
|
+ rot.block = (val >> 0) & 3;
|
|
|
|
+ rot.overlay = (val >> 2) & 3;
|
|
|
|
+ //rot.tex2 = (val >> 4) & 3;
|
|
|
|
+ rot.ecolor = (val >> 6) & 3;
|
|
|
|
+ } else if (mm->input.selector) {
|
|
|
|
+ rot.block = rot.overlay = rot.ecolor = simple_rot;
|
|
|
|
+ }
|
|
|
|
+ rot.facerot = 0;
|
|
|
|
|
|
-// 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[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
|
|
|
|
- (unsigned short) ((~0x07ff )<<5), // none is completely obscured by everything
|
|
|
|
- (unsigned short) ((~((1<<STBVOX_FT_solid) | (1<<STBVOX_FT_upper) ))<<5), // upper
|
|
|
|
- (unsigned short) ((~((1<<STBVOX_FT_solid) | (1<<STBVOX_FT_lower) ))<<5), // lower
|
|
|
|
- (unsigned short) ((~((1<<STBVOX_FT_solid) ))<<5), // solid is only completely obscured only by solid
|
|
|
|
- (unsigned short) ((~((1<<STBVOX_FT_solid) | (1<<STBVOX_FT_diag_013)))<<5), // diag012 matches diag013
|
|
|
|
- (unsigned short) ((~((1<<STBVOX_FT_solid) | (1<<STBVOX_FT_diag_123)))<<5), // diag023 matches diag123
|
|
|
|
- (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
|
|
|
|
-};
|
|
|
|
|
|
+ stbvox_make_mesh_for_face(mm, rot, STBVOX_FACE_north, v_off, pos, basevert, stbvox_vmesh_crossed_pair[STBVOX_FACE_north], mesh, STBVF_ne_u_cross);
|
|
|
|
+ stbvox_make_mesh_for_face(mm, rot, STBVOX_FACE_south, v_off, pos, basevert, stbvox_vmesh_crossed_pair[STBVOX_FACE_south], mesh, STBVF_sw_u_cross);
|
|
|
|
+ stbvox_make_mesh_for_face(mm, rot, STBVOX_FACE_east , v_off, pos, basevert, stbvox_vmesh_crossed_pair[STBVOX_FACE_east ], mesh, STBVF_se_u_cross);
|
|
|
|
+ stbvox_make_mesh_for_face(mm, rot, STBVOX_FACE_west , v_off, pos, basevert, stbvox_vmesh_crossed_pair[STBVOX_FACE_west ], mesh, STBVF_nw_u_cross);
|
|
|
|
+ }
|
|
|
|
|
|
-// the vertex heights of the block types, in binary vertex order (zyx):
|
|
|
|
-// lower: SW, SE, NW, NE; upper: SW, SE, NW, NE
|
|
|
|
-static stbvox_mesh_vertex stbvox_geometry_vheight[8][8] =
|
|
|
|
-{
|
|
|
|
- #define STBVOX_HEIGHTS(a,b,c,d,e,f,g,h) \
|
|
|
|
- { stbvox_vertex_encode(0,0,a,0,0), \
|
|
|
|
- stbvox_vertex_encode(0,0,b,0,0), \
|
|
|
|
- stbvox_vertex_encode(0,0,c,0,0), \
|
|
|
|
- stbvox_vertex_encode(0,0,d,0,0), \
|
|
|
|
- stbvox_vertex_encode(0,0,e,0,0), \
|
|
|
|
- stbvox_vertex_encode(0,0,f,0,0), \
|
|
|
|
- stbvox_vertex_encode(0,0,g,0,0), \
|
|
|
|
- stbvox_vertex_encode(0,0,h,0,0) }
|
|
|
|
|
|
|
|
- STBVOX_HEIGHTS(0,0,0,0, 2,2,2,2),
|
|
|
|
- STBVOX_HEIGHTS(0,0,0,0, 2,2,2,2),
|
|
|
|
- STBVOX_HEIGHTS(0,0,0,0, 2,2,2,2),
|
|
|
|
- STBVOX_HEIGHTS(0,0,0,0, 2,2,2,2),
|
|
|
|
- STBVOX_HEIGHTS(1,1,1,1, 2,2,2,2),
|
|
|
|
- STBVOX_HEIGHTS(0,0,0,0, 1,1,1,1),
|
|
|
|
- STBVOX_HEIGHTS(0,0,0,0, 0,0,2,2),
|
|
|
|
- STBVOX_HEIGHTS(2,2,0,0, 2,2,2,2),
|
|
|
|
-};
|
|
|
|
|
|
+ // @TODO
|
|
|
|
+ // STBVOX_GEOM_floor_slope_north_is_top_as_wall,
|
|
|
|
+ // STBVOX_GEOM_ceil_slope_north_is_bottom_as_wall,
|
|
|
|
+}
|
|
|
|
|
|
-// rotate vertices defined as [z][y][x] coords
|
|
|
|
-static unsigned char stbvox_rotate_vertex[8][4] =
|
|
|
|
|
|
+static void stbvox_make_mesh_for_column(stbvox_mesh_maker *mm, int x, int y, int z0)
|
|
{
|
|
{
|
|
- { 0,1,3,2 }, // zyx=000
|
|
|
|
- { 1,3,2,0 }, // zyx=001
|
|
|
|
- { 2,0,1,3 }, // zyx=010
|
|
|
|
- { 3,2,0,1 }, // zyx=011
|
|
|
|
- { 4,5,7,6 }, // zyx=100
|
|
|
|
- { 5,7,6,4 }, // zyx=101
|
|
|
|
- { 6,4,5,7 }, // zyx=110
|
|
|
|
- { 7,6,4,5 }, // zyx=111
|
|
|
|
-};
|
|
|
|
|
|
+ stbvox_pos pos = { x,y,0 };
|
|
|
|
+ int v_off = x * mm->x_stride_in_bytes + y * mm->y_stride_in_bytes;
|
|
|
|
+ int ns_off = mm->y_stride_in_bytes;
|
|
|
|
+ int ew_off = mm->x_stride_in_bytes;
|
|
|
|
+ if (mm->input.geometry) {
|
|
|
|
+ unsigned char *bt = mm->input.blocktype + v_off;
|
|
|
|
+ unsigned char *geo = mm->input.geometry + v_off;
|
|
|
|
+ int z;
|
|
|
|
+ for (z=z0; z < mm->z1; ++z) {
|
|
|
|
+ if (bt[z] && ( !bt[z+ns_off] || !STBVOX_GET_GEO(geo[z+ns_off]) || !bt[z-ns_off] || !STBVOX_GET_GEO(geo[z-ns_off])
|
|
|
|
+ || !bt[z+ew_off] || !STBVOX_GET_GEO(geo[z+ew_off]) || !bt[z-ew_off] || !STBVOX_GET_GEO(geo[z-ew_off])))
|
|
|
|
+ { // TODO check up and down
|
|
|
|
+ pos.z = z;
|
|
|
|
+ stbvox_make_mesh_for_block_with_geo(mm, pos, v_off+z);
|
|
|
|
+ if (mm->full) {
|
|
|
|
+ mm->cur_z = z;
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ } else if (mm->input.block_geometry) {
|
|
|
|
+ int z;
|
|
|
|
+ unsigned char *bt = mm->input.blocktype + v_off;
|
|
|
|
+ unsigned char *geo = mm->input.block_geometry;
|
|
|
|
+ for (z=z0; z < mm->z1; ++z) {
|
|
|
|
+ if (bt[z] && ( geo[bt[z+ns_off]] != STBVOX_GEOM_solid
|
|
|
|
+ || geo[bt[z-ns_off]] != STBVOX_GEOM_solid
|
|
|
|
+ || geo[bt[z+ew_off]] != STBVOX_GEOM_solid
|
|
|
|
+ || geo[bt[z-ew_off]] != STBVOX_GEOM_solid
|
|
|
|
+ || geo[bt[z-1]] != STBVOX_GEOM_solid
|
|
|
|
+ || geo[bt[z+1]] != STBVOX_GEOM_solid))
|
|
|
|
+ {
|
|
|
|
+ pos.z = z;
|
|
|
|
+ stbvox_make_mesh_for_block_with_geo(mm, pos, v_off+z);
|
|
|
|
+ if (mm->full) {
|
|
|
|
+ mm->cur_z = z;
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ unsigned char *bt = mm->input.blocktype + v_off;
|
|
|
|
+ int z;
|
|
|
|
+ #if STBVOX_CONFIG_PRECISION_Z == 1
|
|
|
|
+ stbvox_mesh_vertex *vmesh = stbvox_vmesh_delta_half_z[0];
|
|
|
|
+ #else
|
|
|
|
+ stbvox_mesh_vertex *vmesh = stbvox_vmesh_delta_normal[0];
|
|
|
|
+ #endif
|
|
|
|
+ for (z=z0; z < mm->z1; ++z) {
|
|
|
|
+ // if it's solid and at least one neighbor isn't solid
|
|
|
|
+ if (bt[z] && (!bt[z+ns_off] || !bt[z-ns_off] || !bt[z+ew_off] || !bt[z-ew_off] || !bt[z-1] || !bt[z+1])) {
|
|
|
|
+ pos.z = z;
|
|
|
|
+ stbvox_make_mesh_for_block(mm, pos, v_off+z, vmesh);
|
|
|
|
+ if (mm->full) {
|
|
|
|
+ mm->cur_z = z;
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
|
|
-#ifdef STBVOX_OPTIMIZED_VHEIGHT
|
|
|
|
-// optimized vheight generates a single normal over the entire face, even if it's not planar
|
|
|
|
-static stbvox_optimized_face_up_normal[4][4][4][4] =
|
|
|
|
|
|
+static void stbvox_bring_up_to_date(stbvox_mesh_maker *mm)
|
|
{
|
|
{
|
|
- {
|
|
|
|
- {
|
|
|
|
- { STBVF_u , STBVF_ne_u, STBVF_ne_u, STBVF_ne_u, },
|
|
|
|
- { STBVF_nw_u, STBVF_nu , STBVF_nu , STBVF_ne_u, },
|
|
|
|
- { STBVF_nw_u, STBVF_nu , STBVF_nu , STBVF_nu , },
|
|
|
|
- { STBVF_nw_u, STBVF_nw_u, STBVF_nu , STBVF_nu , },
|
|
|
|
- },{
|
|
|
|
- { STBVF_su , STBVF_eu , STBVF_eu , STBVF_ne_u, },
|
|
|
|
- { STBVF_u , STBVF_ne_u, STBVF_ne_u, STBVF_ne_u, },
|
|
|
|
- { STBVF_nw_u, STBVF_nu , STBVF_nu , STBVF_ne_u, },
|
|
|
|
- { STBVF_nw_u, STBVF_nu , STBVF_nu , STBVF_nu , },
|
|
|
|
- },{
|
|
|
|
- { STBVF_eu , STBVF_eu , STBVF_eu , STBVF_eu , },
|
|
|
|
- { STBVF_su , STBVF_eu , STBVF_eu , STBVF_ne_u, },
|
|
|
|
- { STBVF_u , STBVF_ne_u, STBVF_ne_u, STBVF_ne_u, },
|
|
|
|
- { STBVF_nw_u, STBVF_nu , STBVF_nu , STBVF_ne_u, },
|
|
|
|
- },{
|
|
|
|
- { STBVF_eu , STBVF_eu , STBVF_eu , STBVF_eu , },
|
|
|
|
- { STBVF_eu , STBVF_eu , STBVF_eu , STBVF_eu , },
|
|
|
|
- { STBVF_su , STBVF_eu , STBVF_eu , STBVF_ne_u, },
|
|
|
|
- { STBVF_u , STBVF_ne_u, STBVF_ne_u, STBVF_ne_u, },
|
|
|
|
- },
|
|
|
|
- },{
|
|
|
|
- {
|
|
|
|
- { STBVF_sw_u, STBVF_u , STBVF_ne_u, STBVF_ne_u, },
|
|
|
|
- { STBVF_wu , STBVF_nw_u, STBVF_nu , STBVF_nu , },
|
|
|
|
- { STBVF_wu , STBVF_nw_u, STBVF_nu , STBVF_nu , },
|
|
|
|
- { STBVF_nw_u, STBVF_nw_u, STBVF_nw_u, STBVF_nu , },
|
|
|
|
- },{
|
|
|
|
- { STBVF_su , STBVF_su , STBVF_eu , STBVF_eu , },
|
|
|
|
- { STBVF_sw_u, STBVF_u , STBVF_ne_u, STBVF_ne_u, },
|
|
|
|
- { STBVF_wu , STBVF_nw_u, STBVF_nu , STBVF_nu , },
|
|
|
|
- { STBVF_wu , STBVF_nw_u, STBVF_nu , STBVF_nu , },
|
|
|
|
- },{
|
|
|
|
- { STBVF_su , STBVF_eu , STBVF_eu , STBVF_eu , },
|
|
|
|
- { STBVF_su , STBVF_su , STBVF_eu , STBVF_eu , },
|
|
|
|
- { STBVF_sw_u, STBVF_u , STBVF_ne_u, STBVF_ne_u, },
|
|
|
|
- { STBVF_wu , STBVF_nw_u, STBVF_nu , STBVF_nu , },
|
|
|
|
- },{
|
|
|
|
- { STBVF_su , STBVF_eu , STBVF_eu , STBVF_eu , },
|
|
|
|
- { STBVF_su , STBVF_eu , STBVF_eu , STBVF_eu , },
|
|
|
|
- { STBVF_su , STBVF_su , STBVF_eu , STBVF_eu , },
|
|
|
|
- { STBVF_sw_u, STBVF_u , STBVF_ne_u, STBVF_ne_u, },
|
|
|
|
- },
|
|
|
|
- },{
|
|
|
|
- {
|
|
|
|
- { STBVF_sw_u, STBVF_sw_u, STBVF_u , STBVF_ne_u, },
|
|
|
|
- { STBVF_wu , STBVF_wu , STBVF_nw_u, STBVF_nu , },
|
|
|
|
- { STBVF_wu , STBVF_wu , STBVF_nw_u, STBVF_nu , },
|
|
|
|
- { STBVF_wu , STBVF_nw_u, STBVF_nw_u, STBVF_nw_u, },
|
|
|
|
- },{
|
|
|
|
- { STBVF_su , STBVF_su , STBVF_su , STBVF_eu , },
|
|
|
|
- { STBVF_sw_u, STBVF_sw_u, STBVF_u , STBVF_ne_u, },
|
|
|
|
- { STBVF_wu , STBVF_wu , STBVF_nw_u, STBVF_nu , },
|
|
|
|
- { STBVF_wu , STBVF_wu , STBVF_nw_u, STBVF_nu , },
|
|
|
|
- },{
|
|
|
|
- { STBVF_su , STBVF_su , STBVF_eu , STBVF_eu , },
|
|
|
|
- { STBVF_su , STBVF_su , STBVF_su , STBVF_eu , },
|
|
|
|
- { STBVF_sw_u, STBVF_sw_u, STBVF_u , STBVF_ne_u, },
|
|
|
|
- { STBVF_wu , STBVF_wu , STBVF_nw_u, STBVF_nu , },
|
|
|
|
- },{
|
|
|
|
- { STBVF_su , STBVF_su , STBVF_eu , STBVF_eu , },
|
|
|
|
- { STBVF_su , STBVF_su , STBVF_eu , STBVF_eu , },
|
|
|
|
- { STBVF_su , STBVF_su , STBVF_su , STBVF_eu , },
|
|
|
|
- { STBVF_sw_u, STBVF_sw_u, STBVF_u , STBVF_ne_u, },
|
|
|
|
- },
|
|
|
|
- },{
|
|
|
|
- {
|
|
|
|
- { STBVF_sw_u, STBVF_sw_u, STBVF_sw_u, STBVF_u , },
|
|
|
|
- { STBVF_sw_u, STBVF_wu , STBVF_wu , STBVF_nw_u, },
|
|
|
|
- { STBVF_wu , STBVF_wu , STBVF_wu , STBVF_nw_u, },
|
|
|
|
- { STBVF_wu , STBVF_wu , STBVF_nw_u, STBVF_nw_u, },
|
|
|
|
- },{
|
|
|
|
- { STBVF_sw_u, STBVF_su , STBVF_su , STBVF_su , },
|
|
|
|
- { STBVF_sw_u, STBVF_sw_u, STBVF_sw_u, STBVF_u , },
|
|
|
|
- { STBVF_sw_u, STBVF_wu , STBVF_wu , STBVF_nw_u, },
|
|
|
|
- { STBVF_wu , STBVF_wu , STBVF_wu , STBVF_nw_u, },
|
|
|
|
- },{
|
|
|
|
- { STBVF_su , STBVF_su , STBVF_su , STBVF_eu , },
|
|
|
|
- { STBVF_sw_u, STBVF_su , STBVF_su , STBVF_su , },
|
|
|
|
- { STBVF_sw_u, STBVF_sw_u, STBVF_sw_u, STBVF_u , },
|
|
|
|
- { STBVF_sw_u, STBVF_wu , STBVF_wu , STBVF_nw_u, },
|
|
|
|
- },{
|
|
|
|
- { STBVF_su , STBVF_su , STBVF_su , STBVF_eu , },
|
|
|
|
- { STBVF_su , STBVF_su , STBVF_su , STBVF_eu , },
|
|
|
|
- { STBVF_sw_u, STBVF_su , STBVF_su , STBVF_su , },
|
|
|
|
- { STBVF_sw_u, STBVF_sw_u, STBVF_sw_u, STBVF_u , },
|
|
|
|
- },
|
|
|
|
- },
|
|
|
|
-};
|
|
|
|
-#else
|
|
|
|
-// which normal to use for a given vheight that's planar
|
|
|
|
-// @TODO: this table was constructed by hand and may have bugs
|
|
|
|
-// nw se sw
|
|
|
|
-static stbvox_planar_face_up_normal[4][4][4] =
|
|
|
|
-{
|
|
|
|
- { // sw,se,nw,ne; ne = se+nw-sw
|
|
|
|
- { STBVF_u , 0 , 0 , 0 }, // 0,0,0,0; 1,0,0,-1; 2,0,0,-2; 3,0,0,-3;
|
|
|
|
- { STBVF_u , STBVF_u , 0 , 0 }, // 0,1,0,1; 1,1,0, 0; 2,1,0,-1; 3,1,0,-2;
|
|
|
|
- { STBVF_wu , STBVF_nw_u, STBVF_nu , 0 }, // 0,2,0,2; 1,2,0, 1; 2,2,0, 0; 3,2,0,-1;
|
|
|
|
- { STBVF_wu , STBVF_nw_u, STBVF_nw_u, STBVF_nu }, // 0,3,0,3; 1,3,0, 2; 2,3,0, 1; 3,3,0, 0;
|
|
|
|
- },{
|
|
|
|
- { STBVF_u , STBVF_u , 0 , 0 }, // 0,0,1,1; 1,0,1, 0; 2,0,1,-1; 3,0,1,-2;
|
|
|
|
- { STBVF_sw_u, STBVF_u , STBVF_ne_u, 0 }, // 0,1,1,2; 1,1,1, 1; 2,1,1, 0; 3,1,1,-1;
|
|
|
|
- { STBVF_sw_u, STBVF_u , STBVF_u , STBVF_ne_u }, // 0,2,1,3; 1,2,1, 2; 2,2,1, 1; 3,2,1, 0;
|
|
|
|
- { 0 , STBVF_wu , STBVF_nw_u, STBVF_nu }, // 0,3,1,4; 1,3,1, 3; 2,3,1, 2; 3,3,1, 1;
|
|
|
|
- },{
|
|
|
|
- { STBVF_su , STBVF_se_u, STBVF_eu , 0 }, // 0,0,2,2; 1,0,2, 1; 2,0,2, 0; 3,0,2,-1;
|
|
|
|
- { STBVF_sw_u, STBVF_u , STBVF_u , STBVF_ne_u }, // 0,1,2,3; 1,1,2, 2; 2,1,2, 1; 3,1,2, 0;
|
|
|
|
- { 0 , STBVF_sw_u, STBVF_u , STBVF_ne_u }, // 0,2,2,4; 1,2,2, 3; 2,2,2, 2; 3,2,2, 1;
|
|
|
|
- { 0 , 0 , STBVF_u , STBVF_u }, // 0,3,2,5; 1,3,2, 4; 2,3,2, 3; 3,3,2, 2;
|
|
|
|
- },{
|
|
|
|
- { STBVF_su , STBVF_se_u, STBVF_se_u, STBVF_eu }, // 0,0,3,3; 1,0,3, 2; 2,0,3, 1; 3,0,3, 0;
|
|
|
|
- { 0 , STBVF_su , STBVF_se_u, STBVF_eu }, // 0,1,3,4; 1,1,3, 3; 2,1,3, 2; 3,1,3, 1;
|
|
|
|
- { 0 , 0 , STBVF_u , STBVF_u }, // 0,2,3,5; 1,2,3, 4; 2,2,3, 3; 3,2,3, 2;
|
|
|
|
- { 0 , 0 , 0 , STBVF_u }, // 0,3,3,6; 1,3,3, 5; 2,3,3, 4; 3,3,3, 3;
|
|
|
|
|
|
+ if (mm->config_dirty) {
|
|
|
|
+ int i;
|
|
|
|
+ #ifdef STBVOX_ICONFIG_FACE_ATTRIBUTE
|
|
|
|
+ mm->num_mesh_slots = 1;
|
|
|
|
+ for (i=0; i < STBVOX_MAX_MESHES; ++i) {
|
|
|
|
+ mm->output_size[i][0] = 32;
|
|
|
|
+ mm->output_step[i][0] = 8;
|
|
|
|
+ }
|
|
|
|
+ #else
|
|
|
|
+ mm->num_mesh_slots = 2;
|
|
|
|
+ for (i=0; i < STBVOX_MAX_MESHES; ++i) {
|
|
|
|
+ mm->output_size[i][0] = 16;
|
|
|
|
+ mm->output_step[i][0] = 4;
|
|
|
|
+ mm->output_size[i][1] = 4;
|
|
|
|
+ mm->output_step[i][1] = 4;
|
|
|
|
+ }
|
|
|
|
+ #endif
|
|
|
|
+
|
|
|
|
+ mm->config_dirty = 0;
|
|
}
|
|
}
|
|
-};
|
|
|
|
|
|
+}
|
|
|
|
|
|
-// these tables were constructed automatically using a variant of the code
|
|
|
|
-// below; however, they seem wrong, so who knows
|
|
|
|
-static stbvox_face_up_normal_012[4][4][4] =
|
|
|
|
|
|
+int stbvox_make_mesh(stbvox_mesh_maker *mm)
|
|
{
|
|
{
|
|
- {
|
|
|
|
- { STBVF_u , STBVF_ne_u, STBVF_ne_u, STBVF_ne_u, },
|
|
|
|
- { STBVF_wu , STBVF_nu , STBVF_ne_u, STBVF_ne_u, },
|
|
|
|
- { STBVF_wu , STBVF_nw_u, STBVF_nu , STBVF_ne_u, },
|
|
|
|
- { STBVF_wu , STBVF_nw_u, STBVF_nw_u, STBVF_nu , },
|
|
|
|
- },{
|
|
|
|
- { STBVF_su , STBVF_eu , STBVF_ne_u, STBVF_ne_u, },
|
|
|
|
- { STBVF_sw_u, STBVF_u , STBVF_ne_u, STBVF_ne_u, },
|
|
|
|
- { STBVF_sw_u, STBVF_wu , STBVF_nu , STBVF_ne_u, },
|
|
|
|
- { STBVF_sw_u, STBVF_wu , STBVF_nw_u, STBVF_nu , },
|
|
|
|
- },{
|
|
|
|
- { STBVF_su , STBVF_eu , STBVF_eu , STBVF_ne_u, },
|
|
|
|
- { STBVF_sw_u, STBVF_su , STBVF_eu , STBVF_ne_u, },
|
|
|
|
- { STBVF_sw_u, STBVF_sw_u, STBVF_u , STBVF_ne_u, },
|
|
|
|
- { STBVF_sw_u, STBVF_sw_u, STBVF_wu , STBVF_nu , },
|
|
|
|
- },{
|
|
|
|
- { STBVF_su , STBVF_su , STBVF_eu , STBVF_eu , },
|
|
|
|
- { STBVF_sw_u, STBVF_su , STBVF_eu , STBVF_eu , },
|
|
|
|
- { STBVF_sw_u, STBVF_sw_u, STBVF_su , STBVF_eu , },
|
|
|
|
- { STBVF_sw_u, STBVF_sw_u, STBVF_sw_u, STBVF_u , },
|
|
|
|
|
|
+ int x,y;
|
|
|
|
+ stbvox_bring_up_to_date(mm);
|
|
|
|
+ mm->full = 0;
|
|
|
|
+ if (mm->cur_x > mm->x0 || mm->cur_y > mm->y0 || mm->cur_z > mm->z0) {
|
|
|
|
+ stbvox_make_mesh_for_column(mm, mm->cur_x, mm->cur_y, mm->cur_z);
|
|
|
|
+ if (mm->full)
|
|
|
|
+ return 0;
|
|
|
|
+ ++mm->cur_y;
|
|
|
|
+ while (mm->cur_y < mm->y1 && !mm->full) {
|
|
|
|
+ stbvox_make_mesh_for_column(mm, mm->cur_x, mm->cur_y, mm->z0);
|
|
|
|
+ if (mm->full)
|
|
|
|
+ return 0;
|
|
|
|
+ ++mm->cur_y;
|
|
|
|
+ }
|
|
|
|
+ ++mm->cur_x;
|
|
}
|
|
}
|
|
-};
|
|
|
|
|
|
+ for (x=mm->cur_x; x < mm->x1; ++x) {
|
|
|
|
+ for (y=mm->y0; y < mm->y1; ++y) {
|
|
|
|
+ stbvox_make_mesh_for_column(mm, x, y, mm->z0);
|
|
|
|
+ if (mm->full) {
|
|
|
|
+ mm->cur_x = x;
|
|
|
|
+ mm->cur_y = y;
|
|
|
|
+ return 0;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return 1;
|
|
|
|
+}
|
|
|
|
|
|
-static stbvox_face_up_normal_013[4][4][4] =
|
|
|
|
|
|
+void stbvox_init_mesh_maker(stbvox_mesh_maker *mm)
|
|
{
|
|
{
|
|
- {
|
|
|
|
- { STBVF_u , STBVF_eu , STBVF_eu , STBVF_eu , },
|
|
|
|
- { STBVF_nw_u, STBVF_nu , STBVF_ne_u, STBVF_ne_u, },
|
|
|
|
- { STBVF_nw_u, STBVF_nw_u, STBVF_nu , STBVF_ne_u, },
|
|
|
|
- { STBVF_nw_u, STBVF_nw_u, STBVF_nw_u, STBVF_nu , },
|
|
|
|
- },{
|
|
|
|
- { STBVF_su , STBVF_eu , STBVF_eu , STBVF_eu , },
|
|
|
|
- { STBVF_wu , STBVF_u , STBVF_eu , STBVF_eu , },
|
|
|
|
- { STBVF_nw_u, STBVF_nw_u, STBVF_nu , STBVF_ne_u, },
|
|
|
|
- { STBVF_nw_u, STBVF_nw_u, STBVF_nw_u, STBVF_nu , },
|
|
|
|
- },{
|
|
|
|
- { STBVF_su , STBVF_su , STBVF_su , STBVF_eu , },
|
|
|
|
- { STBVF_sw_u, STBVF_su , STBVF_eu , STBVF_eu , },
|
|
|
|
- { STBVF_wu , STBVF_wu , STBVF_u , STBVF_eu , },
|
|
|
|
- { STBVF_nw_u, STBVF_nw_u, STBVF_nw_u, STBVF_nu , },
|
|
|
|
- },{
|
|
|
|
- { STBVF_su , STBVF_su , STBVF_su , STBVF_eu , },
|
|
|
|
- { STBVF_sw_u, STBVF_su , STBVF_su , STBVF_su , },
|
|
|
|
- { STBVF_sw_u, STBVF_sw_u, STBVF_su , STBVF_eu , },
|
|
|
|
- { STBVF_wu , STBVF_wu , STBVF_wu , STBVF_u , },
|
|
|
|
|
|
+ memset(mm, 0, sizeof(*mm));
|
|
|
|
+ stbvox_build_default_palette();
|
|
|
|
+
|
|
|
|
+ mm->config_dirty = 1;
|
|
|
|
+ mm->default_mesh = 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+int stbvox_get_buffer_count(stbvox_mesh_maker *mm)
|
|
|
|
+{
|
|
|
|
+ stbvox_bring_up_to_date(mm);
|
|
|
|
+ return mm->num_mesh_slots;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+int stbvox_get_buffer_size_per_quad(stbvox_mesh_maker *mm, int n)
|
|
|
|
+{
|
|
|
|
+ return mm->output_size[0][n];
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void stbvox_reset_buffers(stbvox_mesh_maker *mm)
|
|
|
|
+{
|
|
|
|
+ int i;
|
|
|
|
+ for (i=0; i < STBVOX_MAX_MESHES*STBVOX_MAX_MESH_SLOTS; ++i) {
|
|
|
|
+ mm->output_cur[0][i] = 0;
|
|
|
|
+ mm->output_buffer[0][i] = 0;
|
|
}
|
|
}
|
|
-};
|
|
|
|
|
|
+}
|
|
|
|
|
|
-static stbvox_face_up_normal_023[4][4][4] =
|
|
|
|
|
|
+void stbvox_set_buffer(stbvox_mesh_maker *mm, int mesh, int slot, void *buffer, size_t len)
|
|
{
|
|
{
|
|
- {
|
|
|
|
- { STBVF_u , STBVF_nu , STBVF_nu , STBVF_nu , },
|
|
|
|
- { STBVF_eu , STBVF_eu , STBVF_ne_u, STBVF_ne_u, },
|
|
|
|
- { STBVF_su , STBVF_eu , STBVF_eu , STBVF_ne_u, },
|
|
|
|
- { STBVF_eu , STBVF_eu , STBVF_eu , STBVF_eu , },
|
|
|
|
- },{
|
|
|
|
- { STBVF_wu , STBVF_nw_u, STBVF_nw_u, STBVF_nw_u, },
|
|
|
|
- { STBVF_su , STBVF_u , STBVF_nu , STBVF_nu , },
|
|
|
|
- { STBVF_su , STBVF_eu , STBVF_eu , STBVF_ne_u, },
|
|
|
|
- { STBVF_su , STBVF_su , STBVF_eu , STBVF_eu , },
|
|
|
|
- },{
|
|
|
|
- { STBVF_wu , STBVF_nw_u, STBVF_nw_u, STBVF_nw_u, },
|
|
|
|
- { STBVF_sw_u, STBVF_wu , STBVF_nw_u, STBVF_nw_u, },
|
|
|
|
- { STBVF_su , STBVF_su , STBVF_u , STBVF_nu , },
|
|
|
|
- { STBVF_su , STBVF_su , STBVF_eu , STBVF_eu , },
|
|
|
|
- },{
|
|
|
|
- { STBVF_wu , STBVF_nw_u, STBVF_nw_u, STBVF_nw_u, },
|
|
|
|
- { STBVF_sw_u, STBVF_wu , STBVF_nw_u, STBVF_nw_u, },
|
|
|
|
- { STBVF_sw_u, STBVF_sw_u, STBVF_wu , STBVF_nw_u, },
|
|
|
|
- { STBVF_su , STBVF_su , STBVF_su , STBVF_u , },
|
|
|
|
|
|
+ int i;
|
|
|
|
+ stbvox_bring_up_to_date(mm);
|
|
|
|
+ mm->output_buffer[mesh][slot] = (char *) buffer;
|
|
|
|
+ mm->output_cur [mesh][slot] = (char *) buffer;
|
|
|
|
+ mm->output_len [mesh][slot] = len;
|
|
|
|
+ mm->output_end [mesh][slot] = (char *) buffer + len;
|
|
|
|
+ for (i=0; i < STBVOX_MAX_MESH_SLOTS; ++i) {
|
|
|
|
+ if (mm->output_buffer[mesh][i]) {
|
|
|
|
+ assert(mm->output_len[mesh][i] / mm->output_size[mesh][i] == mm->output_len[mesh][slot] / mm->output_size[mesh][slot]);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
-};
|
|
|
|
|
|
+}
|
|
|
|
|
|
-static stbvox_face_up_normal_123[4][4][4] =
|
|
|
|
|
|
+void stbvox_set_default_mesh(stbvox_mesh_maker *mm, int mesh)
|
|
{
|
|
{
|
|
- {
|
|
|
|
- { STBVF_u , STBVF_nu , STBVF_nu , STBVF_nu , },
|
|
|
|
- { STBVF_eu , STBVF_ne_u, STBVF_ne_u, STBVF_ne_u, },
|
|
|
|
- { STBVF_eu , STBVF_ne_u, STBVF_ne_u, STBVF_ne_u, },
|
|
|
|
- { STBVF_eu , STBVF_ne_u, STBVF_ne_u, STBVF_ne_u, },
|
|
|
|
- },{
|
|
|
|
- { STBVF_sw_u, STBVF_wu , STBVF_nw_u, STBVF_nw_u, },
|
|
|
|
- { STBVF_su , STBVF_u , STBVF_nu , STBVF_nu , },
|
|
|
|
- { STBVF_eu , STBVF_eu , STBVF_ne_u, STBVF_ne_u, },
|
|
|
|
- { STBVF_eu , STBVF_eu , STBVF_ne_u, STBVF_ne_u, },
|
|
|
|
- },{
|
|
|
|
- { STBVF_sw_u, STBVF_sw_u, STBVF_wu , STBVF_nw_u, },
|
|
|
|
- { STBVF_sw_u, STBVF_sw_u, STBVF_wu , STBVF_nw_u, },
|
|
|
|
- { STBVF_su , STBVF_su , STBVF_u , STBVF_nu , },
|
|
|
|
- { STBVF_su , STBVF_eu , STBVF_eu , STBVF_ne_u, },
|
|
|
|
- },{
|
|
|
|
- { STBVF_sw_u, STBVF_sw_u, STBVF_sw_u, STBVF_wu , },
|
|
|
|
- { STBVF_sw_u, STBVF_sw_u, STBVF_sw_u, STBVF_wu , },
|
|
|
|
- { STBVF_sw_u, STBVF_sw_u, STBVF_sw_u, STBVF_wu , },
|
|
|
|
- { STBVF_su , STBVF_su , STBVF_su , STBVF_u , },
|
|
|
|
|
|
+ mm->default_mesh = mesh;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+int stbvox_get_quad_count(stbvox_mesh_maker *mm, int mesh)
|
|
|
|
+{
|
|
|
|
+ return (mm->output_cur[mesh][0] - mm->output_buffer[mesh][0]) / mm->output_size[mesh][0];
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+stbvox_input_description *stbvox_get_input_description(stbvox_mesh_maker *mm)
|
|
|
|
+{
|
|
|
|
+ return &mm->input;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void stbvox_set_input_range(stbvox_mesh_maker *mm, int x0, int y0, int z0, int x1, int y1, int z1)
|
|
|
|
+{
|
|
|
|
+ mm->x0 = x0;
|
|
|
|
+ mm->y0 = y0;
|
|
|
|
+ mm->z0 = z0;
|
|
|
|
+
|
|
|
|
+ mm->x1 = x1;
|
|
|
|
+ mm->y1 = y1;
|
|
|
|
+ mm->z1 = z1;
|
|
|
|
+
|
|
|
|
+ mm->cur_x = x0;
|
|
|
|
+ mm->cur_y = y0;
|
|
|
|
+ mm->cur_z = z0;
|
|
|
|
+
|
|
|
|
+ // @TODO validate that this range is representable in this mode
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void stbvox_get_transform(stbvox_mesh_maker *mm, float transform[3][3])
|
|
|
|
+{
|
|
|
|
+ // scale
|
|
|
|
+ transform[0][0] = 1.0;
|
|
|
|
+ transform[0][1] = 1.0;
|
|
|
|
+ #if STBVOX_CONFIG_PRECISION_Z==1
|
|
|
|
+ transform[0][2] = 0.5f;
|
|
|
|
+ #else
|
|
|
|
+ transform[0][2] = 1.0f;
|
|
|
|
+ #endif
|
|
|
|
+ // translation
|
|
|
|
+ transform[1][0] = (float) (mm->pos_x);
|
|
|
|
+ transform[1][1] = (float) (mm->pos_y);
|
|
|
|
+ transform[1][2] = (float) (mm->pos_z);
|
|
|
|
+ // texture coordinate projection translation
|
|
|
|
+ transform[2][0] = (float) (mm->pos_x & 255); // @TODO depends on max texture scale
|
|
|
|
+ transform[2][1] = (float) (mm->pos_y & 255);
|
|
|
|
+ transform[2][2] = (float) (mm->pos_z & 255);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void stbvox_get_bounds(stbvox_mesh_maker *mm, float bounds[2][3])
|
|
|
|
+{
|
|
|
|
+ bounds[0][0] = (float) (mm->pos_x + mm->x0);
|
|
|
|
+ bounds[0][1] = (float) (mm->pos_y + mm->y0);
|
|
|
|
+ bounds[0][2] = (float) (mm->pos_z + mm->z0);
|
|
|
|
+ bounds[1][0] = (float) (mm->pos_x + mm->x1);
|
|
|
|
+ bounds[1][1] = (float) (mm->pos_y + mm->y1);
|
|
|
|
+ bounds[1][2] = (float) (mm->pos_z + mm->z1);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void stbvox_set_mesh_coordinates(stbvox_mesh_maker *mm, int x, int y, int z)
|
|
|
|
+{
|
|
|
|
+ mm->pos_x = x;
|
|
|
|
+ mm->pos_y = y;
|
|
|
|
+ mm->pos_z = z;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void stbvox_set_input_stride(stbvox_mesh_maker *mm, int x_stride_in_bytes, int y_stride_in_bytes)
|
|
|
|
+{
|
|
|
|
+ int f,v;
|
|
|
|
+ mm->x_stride_in_bytes = x_stride_in_bytes;
|
|
|
|
+ mm->y_stride_in_bytes = y_stride_in_bytes;
|
|
|
|
+ for (f=0; f < 6; ++f) {
|
|
|
|
+ for (v=0; v < 4; ++v) {
|
|
|
|
+ mm->cube_vertex_offset[f][v] = stbvox_vertex_vector[f][v][0] * mm->x_stride_in_bytes
|
|
|
|
+ + stbvox_vertex_vector[f][v][1] * mm->y_stride_in_bytes
|
|
|
|
+ + stbvox_vertex_vector[f][v][2] ;
|
|
|
|
+ mm->vertex_gather_offset[f][v] = (stbvox_vertex_vector[f][v][0]-1) * mm->x_stride_in_bytes
|
|
|
|
+ + (stbvox_vertex_vector[f][v][1]-1) * mm->y_stride_in_bytes
|
|
|
|
+ + (stbvox_vertex_vector[f][v][2]-1) ;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
-};
|
|
|
|
-#endif
|
|
|
|
|
|
+}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|