diff --git a/stb_voxel_render.h b/stb_voxel_render.h index b647854..45f9618 100644 --- a/stb_voxel_render.h +++ b/stb_voxel_render.h @@ -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, // 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 // in the output, and each voxel can have 6 faces and 8 vertices, it -// would require an impossibly large data structure to describe all -// of the possibilities. Instead, the API provides multiple ways -// to express each property; each such way has some limitations on -// what it can express. +// would require an very large data structure to describe all +// of the possibilities, and this would cause the mesh-creation +// process to be slow. Instead, the API provides multiple ways +// 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 // have been tested. Just report bugs and I'll fix 'em. @@ -159,28 +160,30 @@ // 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 // // Features Porting Bugfixes & Warnings // Sean Barrett github:r-leyh Jesus Fernandez // Miguel Lechon github:Arbeiterunfallversicherungsgesetz +// Thomas Frase // // VERSION HISTORY // -// 0.79 fix the missing types from 0.78; fix string constants being const -// 0.78 bad "#else", compile as C++ -// 0.77 documentation tweaks, rename config var to STB_VOXEL_RENDER_STATIC -// 0.76 typos, signed/unsigned shader issue, more documentation -// 0.75 initial release +// 0.80 (2015-04-11) fix broken STBVOX_CONFIG_ROTATION_IN_LIGHTING refactoring; +// add STBVOX_CONFIG_VHEIGHT_IN_LIGHTING and other vheight fixes; +// added documentation for vheight ("weird slopes") +// 0.79 (2015-04-01) fix the missing types from 0.78; fix string constants being const +// 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 #define INCLUDE_STB_VOXEL_RENDER_H @@ -279,6 +282,11 @@ extern "C" { // Changes the meaning of the 'lighting' mesher input variable to also // 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 // Adjusts the shader calculations on the assumption that tex1.rgba, // tex2.rgba, and color.rgba all use premultiplied values, and that @@ -293,7 +301,6 @@ extern "C" { // when alpha testing). // - ////////////////////////////////////////////////////////////////////////////// // // MESHING @@ -671,6 +678,11 @@ typedef struct // 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. +// +// 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 { unsigned char lighting_at_vertices; @@ -697,19 +709,20 @@ struct stbvox_input_description // The raw lighting values are defined at the center of blocks // (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 // in this field as well. // // Encode with STBVOX_MAKE_LIGHTING(lighting,rot)--here // '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 - // be independent of blocktype, but is only 2 bits so - // doesn't want to be its own array. Lighting is the one - // thing that was likely to already be in use and that - // I could easily steal 2 bits from.) + // (Rationale: rotation needs to be independent of blocktype, + // but is only 2 bits so doesn't want to be its own array. + // Lighting is the one thing that was likely to already be + // in use and that I could easily steal 2 bits from.) stbvox_block_type *blocktype; // Indexed by 3D coordinate. This is a core "block type" value, which is used @@ -950,12 +963,92 @@ struct stbvox_input_description // cache efficiency +////////////////////////////////////////////////////////////////////////////// +// +// VHEIGHT DOCUMENTATION +// + enum { STBVOX_VERTEX_HEIGHT_0, STBVOX_VERTEX_HEIGHT_half, 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 { @@ -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_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)) #else #define STBVOX_MAKE_LIGHTING(lighting) (lighting) @@ -1064,6 +1157,7 @@ struct stbvox_mesh_maker #include #include // memset +// have to use our own names to avoid the _MSC_VER path having conflicting type names #ifndef _MSC_VER #include typedef uint16_t stbvox_uint16; @@ -1085,6 +1179,11 @@ struct stbvox_mesh_maker #error "Must defined STBVOX_CONFIG_MODE to select the mode" #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 // currently implemented. Reducing the storage-per-quad further // 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 }; -#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 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 { unsigned char *amb = &mm->input.lighting[v_off]; 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_LIGHTING_ROUNDOFF 8 #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 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; } - #ifdef STBVOX_ROTATION_IN_LIGHTING + #ifdef STBVOX_CONFIG_ROTATION_IN_LIGHTING simple_rot = mm->input.lighting[v_off] & 3; #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[5] = mm->input.geometry[v_off - 1]; - #ifndef STBVOX_ROTATION_IN_LIGHTING + #ifndef STBVOX_CONFIG_ROTATION_IN_LIGHTING rot = (geo >> 4) & 3; geo &= 15; 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) ngeo[i] = mm->input.block_geometry[nbt[i]]; if (mm->input.selector) { - #ifndef STBVOX_ROTATION_IN_LIGHTING + #ifndef STBVOX_CONFIG_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; @@ -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; #endif } else { - #ifndef STBVOX_ROTATION_IN_LIGHTING + #ifndef STBVOX_CONFIG_ROTATION_IN_LIGHTING rot = (geo>>4)&3; geo &= 15; 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; nrot[0] = (mm->input.lighting[v_off + ew_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; // 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) { unsigned char v = mm->input.vheight[v_off]; 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) 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 { assert(0); } + #endif // flag whether any sides go off the top of the block, which means // 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 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 + #ifndef STBVOX_CONFIG_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 @@ -3092,7 +3203,7 @@ static void stbvox_make_mesh_for_block_with_geo(stbvox_mesh_maker *mm, stbvox_po // 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 + #ifndef STBVOX_CONFIG_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 diff --git a/tests/caveview/cave_mesher.c b/tests/caveview/cave_mesher.c index a22215b..c9d0710 100644 --- a/tests/caveview/cave_mesher.c +++ b/tests/caveview/cave_mesher.c @@ -26,7 +26,7 @@ //#define STBVOX_CONFIG_TEX1_EDGE_CLAMP #define STBVOX_CONFIG_DISABLE_TEX2 -#define STBVOX_ROTATION_IN_LIGHTING +#define STBVOX_CONFIG_ROTATION_IN_LIGHTING #define STB_VOXEL_RENDER_IMPLEMENTATION #include "stb_voxel_render.h" diff --git a/tests/caveview/caveview.h b/tests/caveview/caveview.h index 37f37ec..96288e0 100644 --- a/tests/caveview/caveview.h +++ b/tests/caveview/caveview.h @@ -3,7 +3,7 @@ #include "stb.h" -#define STBVOX_ROTATION_IN_LIGHTING +#define STBVOX_CONFIG_ROTATION_IN_LIGHTING #include "stb_voxel_render.h" typedef struct