@ -1,4 +1,4 @@
// stb_voxel_render.h - v0.79 - Sean Barrett, 2015 - public domain
// stb_voxel_render.h - v0.80 - 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
@ -146,10 +146,11 @@
//
//
// Because there is so much per-vertex and per-face data possible
// Because there is so much per-vertex and per-face data possible
// in the output, and each voxel can have 6 faces and 8 vertices, it
// in the output, and each voxel can have 6 faces and 8 vertices, it
// would require an impossibly large data structure to describe all
// would require an very large data structure to describe all
// of the possibilities. Instead, the API provides multiple ways
// of the possibilities, and this would cause the mesh-creation
// to express each property; each such way has some limitations on
// process to be slow. Instead, the API provides multiple ways
// what it can express.
// to express each property, some more compact, others less so;
// each such way has some limitations on what it can express.
//
//
// Note that there are so many paths and combinations, not all of them
// Note that there are so many paths and combinations, not all of them
// have been tested. Just report bugs and I'll fix 'em.
// have been tested. Just report bugs and I'll fix 'em.
@ -159,28 +160,30 @@
// See the API documentation in the header-file section.
// See the API documentation in the header-file section.
//
//
//
//
// HISTORICAL FOUNDATION
//
// zmc engine 96-byte quads 2011/10
// zmc engine 32-byte quads 2013/12
// stb_voxel_render 20-byte quads 2015/01
//
//
// CONTRIBUTORS
// CONTRIBUTORS
//
//
// Features Porting Bugfixes & Warnings
// Features Porting Bugfixes & Warnings
// Sean Barrett github:r-leyh Jesus Fernandez
// Sean Barrett github:r-leyh Jesus Fernandez
// Miguel Lechon github:Arbeiterunfallversicherungsgesetz
// Miguel Lechon github:Arbeiterunfallversicherungsgesetz
// Thomas Frase
//
//
// VERSION HISTORY
// VERSION HISTORY
//
//
// 0.79 fix the missing types from 0.78; fix string constants being const
// 0.80 (2015-04-11) fix broken STBVOX_CONFIG_ROTATION_IN_LIGHTING refactoring;
// 0.78 bad "#else", compile as C++
// add STBVOX_CONFIG_VHEIGHT_IN_LIGHTING and other vheight fixes;
// 0.77 documentation tweaks, rename config var to STB_VOXEL_RENDER_STATIC
// added documentation for vheight ("weird slopes")
// 0.76 typos, signed/unsigned shader issue, more documentation
// 0.79 (2015-04-01) fix the missing types from 0.78; fix string constants being const
// 0.75 initial release
// 0.78 (2015-04-02) bad "#else", compile as C++
// 0.77 (2015-04-01) documentation tweaks, rename config var to STB_VOXEL_RENDER_STATIC
// 0.76 (2015-04-01) typos, signed/unsigned shader issue, more documentation
// 0.75 (2015-04-01) initial release
//
//
//
//
// HISTORICAL FOUNDATION
//
// stb_voxel_render 20-byte quads 2015/01
// zmc engine 32-byte quads 2013/12
// zmc engine 96-byte quads 2011/10
# ifndef INCLUDE_STB_VOXEL_RENDER_H
# ifndef INCLUDE_STB_VOXEL_RENDER_H
# define INCLUDE_STB_VOXEL_RENDER_H
# define INCLUDE_STB_VOXEL_RENDER_H
@ -279,6 +282,11 @@ extern "C" {
// Changes the meaning of the 'lighting' mesher input variable to also
// Changes the meaning of the 'lighting' mesher input variable to also
// store the rotation; see later discussion.
// store the rotation; see later discussion.
//
//
// STBVOX_CONFIG_VHEIGHT_IN_LIGHTING
// Changes the meaning of the 'lighting' mesher input variable to also
// store the vheight; see later discussion. Cannot use both this and
// the previous variable.
//
// STBVOX_CONFIG_PREMULTIPLIED_ALPHA
// STBVOX_CONFIG_PREMULTIPLIED_ALPHA
// Adjusts the shader calculations on the assumption that tex1.rgba,
// Adjusts the shader calculations on the assumption that tex1.rgba,
// tex2.rgba, and color.rgba all use premultiplied values, and that
// tex2.rgba, and color.rgba all use premultiplied values, and that
@ -293,7 +301,6 @@ extern "C" {
// when alpha testing).
// when alpha testing).
//
//
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//
//
// MESHING
// MESHING
@ -671,6 +678,11 @@ typedef struct
// This is the data structure you fill out. Most of the arrays can be
// This is the data structure you fill out. Most of the arrays can be
// NULL, except when one is required to get the value to index another.
// NULL, except when one is required to get the value to index another.
//
// The compass system used in the following descriptions is:
// east means increasing x
// north means increasing y
// up means increasing z
struct stbvox_input_description
struct stbvox_input_description
{
{
unsigned char lighting_at_vertices ;
unsigned char lighting_at_vertices ;
@ -697,19 +709,20 @@ struct stbvox_input_description
// The raw lighting values are defined at the center of blocks
// The raw lighting values are defined at the center of blocks
// (or at vertex if 'lighting_at_vertices' is true).
// (or at vertex if 'lighting_at_vertices' is true).
//
//
// If the macro STBVOX_ROTATION_IN_LIGHTING is defined,
// If the macro STBVOX_CONFIG_ ROTATION_IN_LIGHTING is defined,
// then an additional 2-bit block rotation value is stored
// then an additional 2-bit block rotation value is stored
// in this field as well.
// in this field as well.
//
//
// Encode with STBVOX_MAKE_LIGHTING(lighting,rot)--here
// Encode with STBVOX_MAKE_LIGHTING(lighting,rot)--here
// 'lighting' should still be 8 bits, as the macro will
// 'lighting' should still be 8 bits, as the macro will
// discard the bottom bits automatically.
// discard the bottom bits automatically. Similarly, if
// using STBVOX_CONFIG_VHEIGHT_IN_LIGHTING, encode with
// STBVOX_MAKE_LIGHTING(lighting,vheight).
//
//
// (Rationale: rotation needs to
// (Rationale: rotation needs to be independent of blocktype,
// be independent of blocktype, but is only 2 bits so
// but is only 2 bits so doesn't want to be its own array.
// doesn't want to be its own array. Lighting is the one
// Lighting is the one thing that was likely to already be
// thing that was likely to already be in use and that
// in use and that I could easily steal 2 bits from.)
// I could easily steal 2 bits from.)
stbvox_block_type * blocktype ;
stbvox_block_type * blocktype ;
// Indexed by 3D coordinate. This is a core "block type" value, which is used
// Indexed by 3D coordinate. This is a core "block type" value, which is used
@ -950,12 +963,92 @@ struct stbvox_input_description
// cache efficiency
// cache efficiency
//////////////////////////////////////////////////////////////////////////////
//
// VHEIGHT DOCUMENTATION
//
enum
enum
{
{
STBVOX_VERTEX_HEIGHT_0 ,
STBVOX_VERTEX_HEIGHT_0 ,
STBVOX_VERTEX_HEIGHT_half ,
STBVOX_VERTEX_HEIGHT_half ,
STBVOX_VERTEX_HEIGHT_1 ,
STBVOX_VERTEX_HEIGHT_1 ,
STBVOX_VERTEX_HEIGHT_one_and_a_half ,
} ;
} ;
// These are the "vheight" values. Vheight stands for "vertex height".
// The idea is that for a "floor vheight" block, you take a cube and
// reposition the top-most vertices at various heights as specified by
// the vheight values. Similarly, a "ceiling vheight" block takes a
// cube and repositions the bottom-most vertices.
//
// A floor block only adjusts the top four vertices; the bottom four vertices
// remain at the bottom of the block. The height values are 2 bits,
// measured in halves of a block; so you can specify heights of 0/2,
// 1/2, 2/2, or 3/2. 0 is the bottom of the block, 1 is halfway
// up the block, 2 is the top of the block, and 3 is halfway up the
// next block (and actually outside of the block). The value 3 is
// actually legal, and allows you to:
//
// (A) allows smoother terrain by having slopes that cross blocks,
// e.g. (1,1,3,3) is a regular-seeming slope halfway between blocks
// (B) make slopes steeper than 45-degrees, e.g. (0,0,3,3)
//
// (Because only z coordinates have half-block precision, and x&y are
// limited to block corner precision, it's not possible to make these
// things "properly" out of blocks, e.g. a half-slope block on its side
// or a sloped block halfway between blocks that's made out of two blocks.)
//
// If you define STBVOX_CONFIG_OPTIMIZED_VHEIGHT, then the top face
// (or bottom face for a ceiling vheight block) will be drawn as a
// single quad even if the four vertex heights aren't planar, and a
// single normal will be used over the entire quad. If you
// don't define it, then if the top face is non-planar, it will be
// split into two triangles, each with their own normal/lighting.
// (Note that since all output from stb_voxel_render is quad meshes,
// triangles are actually rendered as degenerate quads.) In this case,
// the distinction betwen STBVOX_GEOM_floor_vheight_03 and
// STBVOX_GEOM_floor_vheight_12 comes into play; the former introduces
// an edge from the SW to NE corner (i.e. from <0,0,?> to <1,1,?>),
// while the latter introduces an edge from the NW to SE corner
// (i.e. from <0,1,?> to <1,0,?>.) For a "lazy mesh" look, use
// exclusively _03 or _12. For a "classic mesh" look, alternate
// _03 and _12 in a checkerboard pattern. For a "smoothest surface"
// look, choose the edge based on actual vertex heights.
//
// The four vertex heights can come from several places. The simplest
// encoding is to just use the 'vheight' parameter which stores four
// explicit vertex heights for every block. This allows total indepdence,
// but at the cost of the most memory usage. Encode this with
// STBVOX_MAKE_VHEIGHT(vh_sw, vh_se, vh_nw, vh_ne). These coordinates
// are absolute, not affected by block rotations.
//
// An alternative if you just want to encode some very specific block
// types, not all the possibilities--say you just want half-height slopes,
// so you want (0,0,1,1) and (1,1,2,2)--then you can use block_vheight
// to specify them. The geometry rotation will cause block_vheight values
// to be rotated (because it's as if you're just defining a type of
// block). This value is also encoded with STBVOX_MAKE_VHEIGHT.
//
// If you want to save memory and you're creating a "continuous ground"
// sort of effect, you can make each vertex of the lattice share the
// vheight value; that is, two adjacent blocks that share a vertex will
// always get the same vheight value for that vertex. Then you need to
// store two bits of vheight for every block, which you do by storing it
// as part another data structure. Store the south-west vertex's vheight
// with the block. You can either use the "geometry" mesh variable (it's
// a parameter to STBVOX_MAKE_GEOMETRY) or you can store it in the
// "lighting" mesh variable if you defined STBVOX_CONFIG_VHEIGHT_IN_LIGHTING,
// using STBVOX_MAKE_LIGHTING(lighting,vheight).
//
// Note that if you start with a 2D height map and generate vheight data from
// it, you don't necessarily store only one value per (x,y) coordinate,
// as the same value may need to be set up at multiple z heights. For
// example, if height(8,8) = 13.5, then you want the block at (8,8,13)
// to store STBVOX_VERTEX_HEIGHT_half, and this will be used by blocks
// at (7,7,13), (8,7,13), (7,8,13), and (8,8,13). However, if you're
// allowing steep slopes, it might be the case that you have a block
// at (7,7,12) which is supposed to stick up to 13.5; that means
// you also need to store STBVOX_VERTEX_HEIGHT_one_and_a_half at (8,8,12).
enum
enum
{
{
@ -1009,7 +1102,7 @@ enum
# define STBVOX_MAKE_TEXLERP_VERT3(e,n,w,s,u) ((e)+(n)*8+(w)*64+(s)*512+(u)*4096)
# define STBVOX_MAKE_TEXLERP_VERT3(e,n,w,s,u) ((e)+(n)*8+(w)*64+(s)*512+(u)*4096)
# define STBVOX_MAKE_TEXLERP_FACE3(e,n,w,s,u,d) ((e)+(n)*8+(w)*64+(s)*512+(u)*4096+(d)*16384)
# define STBVOX_MAKE_TEXLERP_FACE3(e,n,w,s,u,d) ((e)+(n)*8+(w)*64+(s)*512+(u)*4096+(d)*16384)
# ifdef STBVOX_ROTATION_IN_LIGHTING
# if defined(STBVOX_CONFIG_ROTATION_IN_LIGHTING) || defined(STBVOX_CONFIG_VHEIGHT_IN_LIGHTING)
# define STBVOX_MAKE_LIGHTING(lighting, rot) (((lighting)&~3)+(rot))
# define STBVOX_MAKE_LIGHTING(lighting, rot) (((lighting)&~3)+(rot))
# else
# else
# define STBVOX_MAKE_LIGHTING(lighting) (lighting)
# define STBVOX_MAKE_LIGHTING(lighting) (lighting)
@ -1064,6 +1157,7 @@ struct stbvox_mesh_maker
# include <assert.h>
# include <assert.h>
# include <string.h> // memset
# include <string.h> // memset
// have to use our own names to avoid the _MSC_VER path having conflicting type names
# ifndef _MSC_VER
# ifndef _MSC_VER
# include <stdint.h>
# include <stdint.h>
typedef uint16_t stbvox_uint16 ;
typedef uint16_t stbvox_uint16 ;
@ -1085,6 +1179,11 @@ struct stbvox_mesh_maker
# error "Must defined STBVOX_CONFIG_MODE to select the mode"
# error "Must defined STBVOX_CONFIG_MODE to select the mode"
# endif
# endif
# if defined(STBVOX_CONFIG_ROTATION_IN_LIGHTING) && defined(STBVOX_CONFIG_VHEIGHT_IN_LIGHTING)
# error "Can't store both rotation and vheight in lighting"
# endif
// The following are candidate voxel modes. Only modes 0, 1, and 20 are
// The following are candidate voxel modes. Only modes 0, 1, and 20 are
// currently implemented. Reducing the storage-per-quad further
// currently implemented. Reducing the storage-per-quad further
// shouldn't improve performance, although obviously it allow you
// shouldn't improve performance, although obviously it allow you
@ -2261,7 +2360,7 @@ static unsigned char stbvox_rotate_vertex[8][4] =
{ 7 , 6 , 4 , 5 } , // zyx=111
{ 7 , 6 , 4 , 5 } , // zyx=111
} ;
} ;
# ifdef STBVOX_OPTIMIZED_VHEIGHT
# ifdef STBVOX_CONFIG_ OPTIMIZED_VHEIGHT
// optimized vheight generates a single normal over the entire face, even if it's not planar
// optimized vheight generates a single normal over the entire face, even if it's not planar
static unsigned char stbvox_optimized_face_up_normal [ 4 ] [ 4 ] [ 4 ] [ 4 ] =
static unsigned char stbvox_optimized_face_up_normal [ 4 ] [ 4 ] [ 4 ] [ 4 ] =
{
{
@ -2593,7 +2692,7 @@ void stbvox_make_mesh_for_face(stbvox_mesh_maker *mm, stbvox_rotate rot, int fac
} else {
} else {
unsigned char * amb = & mm - > input . lighting [ v_off ] ;
unsigned char * amb = & mm - > input . lighting [ v_off ] ;
int i , j ;
int i , j ;
# ifdef STBVOX_ROTATION_IN_LIGHTING
# if defined(STBVOX_CONFIG_ROTATION_IN_LIGHTING) || defined(STBVOX_CONFIG_VHEIGHT_IN_LIGHTING)
# define STBVOX_GET_LIGHTING(light) ((light) & ~3)
# define STBVOX_GET_LIGHTING(light) ((light) & ~3)
# define STBVOX_LIGHTING_ROUNDOFF 8
# define STBVOX_LIGHTING_ROUNDOFF 8
# else
# else
@ -2636,7 +2735,7 @@ void stbvox_make_mesh_for_face(stbvox_mesh_maker *mm, stbvox_rotate rot, int fac
}
}
}
}
# ifndef STBVOX_OPTIMIZED_VHEIGHT
# ifndef STBVOX_CONFIG_ OPTIMIZED_VHEIGHT
// get opposite-facing normal & texgen for opposite face, used to map up-facing vheight data to down-facing data
// 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 unsigned char stbvox_reverse_face [ STBVF_count ] =
{
{
@ -2721,7 +2820,7 @@ static void stbvox_make_mesh_for_block(stbvox_mesh_maker *mm, stbvox_pos pos, in
return ;
return ;
}
}
# ifdef STBVOX_ROTATION_IN_LIGHTING
# ifdef STBVOX_CONFIG_ ROTATION_IN_LIGHTING
simple_rot = mm - > input . lighting [ v_off ] & 3 ;
simple_rot = mm - > input . lighting [ v_off ] & 3 ;
# endif
# endif
@ -2798,7 +2897,7 @@ static void stbvox_make_mesh_for_block_with_geo(stbvox_mesh_maker *mm, stbvox_po
ngeo [ 4 ] = mm - > input . geometry [ v_off + 1 ] ;
ngeo [ 4 ] = mm - > input . geometry [ v_off + 1 ] ;
ngeo [ 5 ] = mm - > input . geometry [ v_off - 1 ] ;
ngeo [ 5 ] = mm - > input . geometry [ v_off - 1 ] ;
# ifndef STBVOX_ROTATION_IN_LIGHTING
# ifndef STBVOX_CONFIG_ ROTATION_IN_LIGHTING
rot = ( geo > > 4 ) & 3 ;
rot = ( geo > > 4 ) & 3 ;
geo & = 15 ;
geo & = 15 ;
for ( i = 0 ; i < 6 ; + + i ) {
for ( i = 0 ; i < 6 ; + + i ) {
@ -2814,7 +2913,7 @@ static void stbvox_make_mesh_for_block_with_geo(stbvox_mesh_maker *mm, stbvox_po
for ( i = 0 ; i < 6 ; + + i )
for ( i = 0 ; i < 6 ; + + i )
ngeo [ i ] = mm - > input . block_geometry [ nbt [ i ] ] ;
ngeo [ i ] = mm - > input . block_geometry [ nbt [ i ] ] ;
if ( mm - > input . selector ) {
if ( mm - > input . selector ) {
# ifndef STBVOX_ROTATION_IN_LIGHTING
# ifndef STBVOX_CONFIG_ ROTATION_IN_LIGHTING
rot = ( mm - > input . selector [ v_off ] > > 4 ) & 3 ;
rot = ( mm - > input . selector [ v_off ] > > 4 ) & 3 ;
nrot [ 0 ] = ( mm - > input . selector [ v_off + ew_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 [ 1 ] = ( mm - > input . selector [ v_off + ns_off ] > > 4 ) & 3 ;
@ -2824,7 +2923,7 @@ static void stbvox_make_mesh_for_block_with_geo(stbvox_mesh_maker *mm, stbvox_po
nrot [ 5 ] = ( mm - > input . selector [ v_off - 1 ] > > 4 ) & 3 ;
nrot [ 5 ] = ( mm - > input . selector [ v_off - 1 ] > > 4 ) & 3 ;
# endif
# endif
} else {
} else {
# ifndef STBVOX_ROTATION_IN_LIGHTING
# ifndef STBVOX_CONFIG_ ROTATION_IN_LIGHTING
rot = ( geo > > 4 ) & 3 ;
rot = ( geo > > 4 ) & 3 ;
geo & = 15 ;
geo & = 15 ;
for ( i = 0 ; i < 6 ; + + i ) {
for ( i = 0 ; i < 6 ; + + i ) {
@ -2835,7 +2934,7 @@ static void stbvox_make_mesh_for_block_with_geo(stbvox_mesh_maker *mm, stbvox_po
}
}
}
}
# ifdef STBVOX_ROTATION_IN_LIGHTING
# ifdef STBVOX_CONFIG_ ROTATION_IN_LIGHTING
rot = mm - > input . lighting [ v_off ] & 3 ;
rot = mm - > input . lighting [ v_off ] & 3 ;
nrot [ 0 ] = ( mm - > input . lighting [ v_off + ew_off ] ) & 3 ;
nrot [ 0 ] = ( mm - > input . lighting [ v_off + ew_off ] ) & 3 ;
nrot [ 1 ] = ( mm - > input . lighting [ v_off + ns_off ] ) & 3 ;
nrot [ 1 ] = ( mm - > input . lighting [ v_off + ns_off ] ) & 3 ;
@ -3000,6 +3099,12 @@ static void stbvox_make_mesh_for_block_with_geo(stbvox_mesh_maker *mm, stbvox_po
int extreme ;
int extreme ;
// extract the heights
// extract the heights
# ifdef STBVOX_CONFIG_VHEIGHT_IN_LIGHTING
ht [ 0 ] = mm - > input . lighting [ v_off ] & 3 ;
ht [ 1 ] = mm - > input . lighting [ v_off + ew_off ] & 3 ;
ht [ 2 ] = mm - > input . lighting [ v_off + ns_off ] & 3 ;
ht [ 3 ] = mm - > input . lighting [ v_off + ew_off + ns_off ] & 3 ;
# else
if ( mm - > input . vheight ) {
if ( mm - > input . vheight ) {
unsigned char v = mm - > input . vheight [ v_off ] ;
unsigned char v = mm - > input . vheight [ v_off ] ;
ht [ 0 ] = ( v > > 0 ) & 3 ;
ht [ 0 ] = ( v > > 0 ) & 3 ;
@ -3018,9 +3123,15 @@ static void stbvox_make_mesh_for_block_with_geo(stbvox_mesh_maker *mm, stbvox_po
for ( i = 0 ; i < 4 ; + + i )
for ( i = 0 ; i < 4 ; + + i )
ht [ i ] = raw [ stbvox_rotate_vertex [ i ] [ rot ] ] ;
ht [ i ] = raw [ stbvox_rotate_vertex [ i ] [ rot ] ] ;
} else if ( mm - > input . geometry ) {
ht [ 0 ] = mm - > input . geometry [ v_off ] > > 6 ;
ht [ 1 ] = mm - > input . geometry [ v_off + ew_off ] > > 6 ;
ht [ 2 ] = mm - > input . geometry [ v_off + ns_off ] > > 6 ;
ht [ 3 ] = mm - > input . geometry [ v_off + ew_off + ns_off ] > > 6 ;
} else {
} else {
assert ( 0 ) ;
assert ( 0 ) ;
}
}
# endif
// flag whether any sides go off the top of the block, which means
// flag whether any sides go off the top of the block, which means
// our visible_faces test was wrong
// our visible_faces test was wrong
@ -3072,7 +3183,7 @@ static void stbvox_make_mesh_for_block_with_geo(stbvox_mesh_maker *mm, stbvox_po
// flat
// flat
stbvox_make_mesh_for_face ( mm , rotate , STBVOX_FACE_up , v_off , pos , basevert , vmesh [ STBVOX_FACE_up ] , mesh , STBVOX_FACE_up ) ;
stbvox_make_mesh_for_face ( mm , rotate , STBVOX_FACE_up , v_off , pos , basevert , vmesh [ STBVOX_FACE_up ] , mesh , STBVOX_FACE_up ) ;
else {
else {
# ifndef STBVOX_OPTIMIZED_VHEIGHT
# ifndef STBVOX_CONFIG_ OPTIMIZED_VHEIGHT
// check if it's non-planar
// check if it's non-planar
if ( cube [ 5 ] + cube [ 6 ] ! = cube [ 4 ] + cube [ 7 ] ) {
if ( cube [ 5 ] + cube [ 6 ] ! = cube [ 4 ] + cube [ 7 ] ) {
// not planar, split along diagonal and make degenerate quads
// not planar, split along diagonal and make degenerate quads
@ -3092,7 +3203,7 @@ static void stbvox_make_mesh_for_block_with_geo(stbvox_mesh_maker *mm, stbvox_po
// flat
// flat
stbvox_make_mesh_for_face ( mm , rotate , STBVOX_FACE_down , v_off , pos , basevert , vmesh [ STBVOX_FACE_down ] , mesh , STBVOX_FACE_down ) ;
stbvox_make_mesh_for_face ( mm , rotate , STBVOX_FACE_down , v_off , pos , basevert , vmesh [ STBVOX_FACE_down ] , mesh , STBVOX_FACE_down ) ;
else {
else {
# ifndef STBVOX_OPTIMIZED_VHEIGHT
# ifndef STBVOX_CONFIG_ OPTIMIZED_VHEIGHT
// check if it's non-planar
// check if it's non-planar
if ( cube [ 1 ] + cube [ 2 ] ! = cube [ 0 ] + cube [ 3 ] ) {
if ( cube [ 1 ] + cube [ 2 ] ! = cube [ 0 ] + cube [ 3 ] ) {
// not planar, split along diagonal and make degenerate quads
// not planar, split along diagonal and make degenerate quads