bump to version 0.76; documentation, minor changes to texlerp, other input tweaks

This commit is contained in:
Sean Barrett 2015-04-01 05:47:36 -07:00
parent 5690ff7c60
commit 2cbeaa3001
2 changed files with 596 additions and 141 deletions

View File

@ -0,0 +1,141 @@
# An interview with STB about stb_voxel_render.h
**Q:**
I suppose you really like Minecraft?
**A:**
Not really. I mean, I do own it and play it some, and
I do watch YouTube videos of other people playing it
once in a while, but I'm not saying it's that great.
But I do love voxels. I've been playing with voxel rendering
since the mid-late 90's when we were still doing software
rendering and thinking maybe polygons weren't the answer.
Once GPUs came along that kind of died off, at least until
Minecraft brought it back to attention.
**Q:**
Do you expect people will make a lot of Minecraft clones
with this?
**A:**
I hope not!
For one thing, it's a terrible idea for the
developer. Remember before Minecraft was on the Xbox 360,
there were a ton of "indie" clones (some maybe making
decent money even), but then the real Minecraft came out
and just crushed them (as far as I know). It's just not
something you really want to compete with.
The reason I made this library is because I'd like
to see more games with Minecraft's *art style*, not
necessary its *gameplay*.
I can understand the urge to clone the gameplay. When
you have a world made of voxels/blocks, there are a
few things that become incredibly easy to do that would
otherwise be very hard (at least for an indie) to do in 3D.
One thing is that procedural generation becomes much easier.
Another is that destructible environments are easy. Another
is that you have a world where your average user can build
stuff that they find satisfactory.
Minecraft is at a sort of local maximum, a sweet spot, where
it leverages all of those easy-to-dos. And so I'm sure it's
hard to look at the space of 'games using voxels' and move
away from that local maximum, to give up some of that.
But I think that's what people should do.
**Q:**
So what else can people do with stb_voxel_render?
**A:**
All of those benefits I mentioned above are still valid even
if you stay away from the sweet spot. You can make a 3D roguelike
without player-creation/destruction that uses procedural generation.
You could make a shooter with pre-designed maps but destructible
environments.
And I'm sure there are other possible benefits to using voxels/blocks.
Hopefully this will make it easier for people to explore the space.
Also, the library has a pretty wide range of features to allow
people to come up with some distinctive looks. For example,
the art style of Continue?9876543210. I'm terrible at art,
so this isn't really my thing, but I tried to put in flexible
technology that could be used multiple ways.
One thing I did intentionally was try to make it possible to
make nicer looking ground terrain, using the half-height
slopes and "weird slopes". There are Minecraft mods with
drivable cars and they just go up these blocky slopes and,
like, what? So I wanted you to be able to make smoother
terrain, either just for the look, or for vehicles etc.
Also, you can cross-fade between two ground textures for
that classic bad dirt/grass transition that has shipped
in plenty of professional games. Of course, you could
just use a separate non-voxel ground renderer for all of
this. But this way, you can seamlessly integrate everything
else with it. E.g. in your authoring tool (or procedural
generation) you can make smooth ground and then cut a
sharp-edged hole in it for a building's basement or whatever.
**Q:**
What one thing would you really like to see somebody do?
**A:**
Before Unity, 3D has seemed deeply problematic in the indie
space. Software like GameMaker has tried to support 3D but
it seems like little of note has been done with it.
Minecraft has shown that people can build worlds with that
toolset far more easily than we've ever seen from those
other tools. Obviously people have done great things with
Unity, but those people are much closer to professional
developers; typically they still need real 3D modelling
and all of that stuff.
So what I'd really like to see is someone build some kind
of voxel-game-construction-set. Start with stb_voxel_render,
maybe expose all the flexibility of stb_voxel_render (so
people
**Q:**
Why'd you make this library?
**A:**
Mainly as a way of releasing this technology I've been working
on since 2011 and seemed unlikely to ever ship myself. In 2011
I was playing the voxel shooter Ace of Spades. One of the maps
that we played on was a partial port of Broville (which is the
first Minecraft map in stb_voxel_render release trailer). I'd
made a bunch of procedural level generators for the game, and
I started trying to make a city generator inspired by Broville.
But I realized it would be a lot of work, and of very little
value (most of my maps didn't get much play because people
preferred to play on maps where they could charge straight
at the enemies and shoot them as fast as possible). So I
wrote my own voxel engine and started working on a procedural
city game. But I got bogged down after I finally got the road
generator working and never got anywhere with building
generation or gameplay.
stb_voxel_render is actually a complete rewrite from scratch,
but it's based a lot on what I learned from that previous work.
**Q:**
About the release video... how long did that take to edit?
**A:**
About seven or eight hours. I had the first version done in
maybe six or sevent hours, but then I realized I'd left out
one clip, and when I went back to add it I also gussied up
a couple other moments in the video.
**Q:**
Ok, that's it. Thanks, me.
**A:**
Thanks *me!*

View File

@ -1,10 +1,14 @@
// stb_voxel_render.h - v0.75 - Sean Barrett, 2015 - public domain
// stb_voxel_render.h - v0.76 - 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
// can also be a few shapes other than cubes.
//
// Video introduction: https://www.youtube.com/watch?v=2vnTtiLrV1w
// Video introduction:
// http://www.youtube.com/watch?v=2vnTtiLrV1w
//
// Minecraft-viewer sample app:
// http://github.com/nothings/stb/tree/master/tests/caveview
//
// It works by creating triangle meshes. The library includes
//
@ -16,9 +20,12 @@
// the 3D graphics API. (At the moment, it's not actually portable
// since the shaders are GLSL only, but patches are welcome.)
//
// Currently the preferred vertex format is 20 bytes per quad.
// There are plans to allow more compact formats with a slight
// reduction in features.
// You have to do all the caching and tracking of vertex buffers
// yourself. However, you could also try making a game with
// a small enough world that it's fully loaded rather than
// streaming. Currently the preferred vertex format is 20 bytes
// per quad. There are plans to allow much more compact formats
// with a slight reduction in shader features.
//
//
// USAGE
@ -152,6 +159,20 @@
// 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
//
// VERSION HISTORY
//
// 0.76 typos, signed/unsigned shader issue, more documentation
// 0.75 initial release
//
//
#ifndef INCLUDE_STB_VOXEL_RENDER_H
#define INCLUDE_STB_VOXEL_RENDER_H
@ -171,11 +192,106 @@ typedef struct stbvox_input_description stbvox_input_description;
extern "C" {
#endif
//////////////////////////////////////////////////////////////////////////////
//
// CONFIGURATION MACROS
//
// #define STBVOX_CONFIG_MODE <integer>
// Configures the overall behavior of stb_voxel_render. This
// can affect the shaders, the uniform info, and other things.
// (If you need more than one mode in the same app, you can
// use STBVOX_STATIC_IMPLEMENTATION to create multiple versions
// in separate files, and then wrap them.)
//
// Mode value Meaning
// 0 Textured blocks, 32-byte quads
// 1 Textured blocks, 20-byte quads
// 20 Untextured blocks, 32-byte quads
// 21 Untextured blocks, 20-byte quads
//
//
// #define STBVOX_CONFIG_PRECISION_Z <integer>
// Defines the number of bits of fractional position for Z.
// Only 0 or 1 are valid. If 0, then a single mesh has
// twice the legal Z range; e.g. in modes 0,1,20,21,
// Z in the mesh can extend to 511 instead of 255.
// However, half-height blocks cannot be used.
//
//
// All of the following just #ifdef tested so need no values.
//
// STBVOX_CONFIG_BLOCKTYPE_SHORT
// use unsigned 16-bit values for 'blocktype' in the input instead of 8-bit values
//
// STBVOX_CONFIG_OPENGL_MODELVIEW
// use the gl_ModelView matrix rather than the explicit uniform
//
// STBVOX_CONFIG_HLSL
// NOT IMPLEMENTED! Define HLSL shaders instead of GLSL shaders
//
// STBVOX_CONFIG_PREFER_TEXBUFFER
// Stores many of the uniform arrays in texture buffers intead,
// so they can be larger and may be more efficient on some hardware.
//
// STBVOX_CONFIG_LIGHTING_SIMPLE
// Creates a simple lighting engine with a single point light source
// in addition to the default half-lambert ambient light.
//
// STBVOX_CONFIG_LIGHTING
// Declares a lighting function hook; you must append a lighting function
// to the shader before compiling it:
// vec3 compute_lighting(vec3 pos, vec3 norm, vec3 albedo, vec3 ambient);
// 'ambient' is the half-lambert ambient light with vertex ao applied
//
// STBVOX_CONFIG_FOG_SMOOTHSTEP
// Defines a simple unrealistic fog system designed to maximize
// unobscured view distance while not looking to weird when things
// emerge from the fog. Configured using an extra array element
// in the STBVOX_UNIFORM_ambient uniform.
//
// STBVOX_CONFIG_FOG
// Defines a fog function hook; you must append a fog function to
// the shader before compiling it:
// vec3 compute_fog(vec3 color, vec3 relative_pos, float fragment_alpha);
// "color" is the incoming pre-fogged color, fragment_alpha is the alpha value,
// and relative_pos is the vector from the point to the camera in worldspace
//
// STBVOX_CONFIG_DISABLE_TEX2
// This disables all processing of texture 2 in the shader in case
// you don't use it. Eventually this will be replaced with a mode
// that omits the unused data entirely.
//
// STBVOX_CONFIG_TEX1_EDGE_CLAMP
// STBVOX_CONFIG_TEX2_EDGE_CLAMP
// If you want to edge clamp the textures, instead of letting them wrap,
// set this flag. By default stb_voxel_render relies on texture wrapping
// to simplify texture coordinate generation. This flag forces it to do
// it correctly, although there can still be minor artifacts.
//
// STBVOX_CONFIG_ROTATION_IN_LIGHTING
// Changes the meaning of the 'lighting' mesher input variable to also
// store the rotation; see later discussion.
//
// 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
// the output of the fragment shader should be premultiplied.
//
// STBVOX_CONFIG_UNPREMULTIPLY
// Only meaningful if STBVOX_CONFIG_PREMULTIPLIED_ALPHA is defined.
// Changes the behavior described above so that the inputs are
// still premultiplied alpha, but the output of the fragment
// shader is not premultiplied alpha. This is needed when allowing
// non-unit alpha values but not doing alpha-blending (for example
// when alpha testing).
//
//////////////////////////////////////////////////////////////////////////////
//
// MESHING
//
// A mesh represents a (typically) small chunk of a larger level.
// A mesh represents a (typically) small chunk of a larger world.
// Meshes encode coordinates using small integers, so those
// coordinates must be relative to some base location.
// All of the coordinates in the functions below use
@ -218,8 +334,10 @@ STBVXDEC int stbvox_get_buffer_count(stbvox_mesh_maker *mm);
// Returns the number of buffers needed per mesh as described above.
STBVXDEC int stbvox_get_buffer_size_per_quad(stbvox_mesh_maker *mm, int slot);
// Returns how much of a given buffer will get used per quad.
// This allows you to choose correct relative sizes for each buffer.
// Returns how much of a given buffer will get used per quad. This
// allows you to choose correct relative sizes for each buffer, although
// the values are fixed based on the configuration you've selected at
// compile time, and the details are described in stbvox_set_buffer.
STBVXDEC void stbvox_set_default_mesh(stbvox_mesh_maker *mm, int mesh);
// Selects which mesh the mesher will output to (see previous function)
@ -359,7 +477,8 @@ typedef struct stbvox_uniform_info stbvox_uniform_info;
STBVXDEC int stbvox_get_uniform_info(stbvox_uniform_info *info, int uniform);
// Gets the information about a uniform necessary for you to
// set up each uniform with a minimal amount of explicit code.
// See the sample code for examples.
// See the sample code after the structure definition for stbvox_uniform_info,
// further down in this header section.
//
// "uniform" is from the list immediately following. For many
// of these, default values are provided which you can set.
@ -367,8 +486,6 @@ STBVXDEC int stbvox_get_uniform_info(stbvox_uniform_info *info, int uniform);
// APIs you can set most of the state only once. Only
// STBVOX_UNIFORM_transform needs to change per draw call.
//
// The info from this function allows you to cal
//
// STBVOX_UNIFORM_texscale
// 64- or 128-long vec4 array. (128 only if STBVOX_CONFIG_PREFER_TEXBUFFER)
// x: scale factor to apply to texture #1. must be a power of two. 1.0 means 'face-sized'
@ -378,7 +495,9 @@ STBVXDEC int stbvox_get_uniform_info(stbvox_uniform_info *info, int uniform);
//
// Texscale is indexed by the bottom 6 or 7 bits of the texture id; thus for
// example the texture at index 0 in the array and the texture in index 128 of
// the array must be scaled the same.
// the array must be scaled the same. This means that if you only have 64 or 128
// unique textures, they all get distinct values anyway; otherwise you have
// to group them in pairs or sets of four.
//
// STBVOX_UNIFORM_ambient
// 4-long vec4 array:
@ -391,14 +510,14 @@ STBVXDEC int stbvox_get_uniform_info(stbvox_uniform_info *info, int uniform);
// +----- has a default value
// | +-- always use the default value
// | +-- you should always use the default value
enum // V V
{ // ------------------------------------------------
STBVOX_UNIFORM_face_data, // n the sampler with the face texture buffer
STBVOX_UNIFORM_transform, // n the transform data from stbvox_get_transform
STBVOX_UNIFORM_tex_array, // n an array of two texture samplers containing the two texture arrays
STBVOX_UNIFORM_texscale, // Y a table of texture properties, see above
STBVOX_UNIFORM_color_table, // Y 64 vec4 RGBA values; a default palette is provided
STBVOX_UNIFORM_color_table, // Y 64 vec4 RGBA values; a default palette is provided; if A > 1.0, fullbright
STBVOX_UNIFORM_normals, // Y Y table of normals, internal-only
STBVOX_UNIFORM_texgen, // Y Y table of texgen vectors, internal-only
STBVOX_UNIFORM_ambient, // n lighting & fog info, see above
@ -426,6 +545,59 @@ struct stbvox_uniform_info
int use_tex_buffer; // if true, then the uniform is a sampler but the data can come from default_value
};
//////////////////////////////////////////////////////////////////////////////
//
// Uniform sample code
//
#if 0
// Run this once per frame before drawing all the meshes.
// You still need to set the 'transform' uniform for every mesh, etc.
void setup_uniforms(GLuint shader, float camera_pos[4], GLuint tex1, GLuint tex2)
{
int i;
glUseProgram(shader); // so uniform binding works
for (i=0; i < STBVOX_UNIFORM_count; ++i) {
stbvox_uniform_info sui;
if (stbvox_get_uniform_info(&sui, i)) {
GLint loc = glGetUniformLocation(shader, sui.name);
if (loc != 0) {
switch (i) {
case STBVOX_UNIFORM_camera_pos: // only needed for fog
glUniform4fv(loc, sui.array_length, camera_pos);
break;
case STBVOX_UNIFORM_tex_array: {
GLuint tex_unit[2] = { 0, 1 }; // your choice of samplers
glUniform1iv(loc, 2, tex_unit);
glActiveTexture(GL_TEXTURE0 + tex_unit[0]); glBindTexture(GL_TEXTURE_2D_ARRAY, tex1);
glActiveTexture(GL_TEXTURE0 + tex_unit[1]); glBindTexture(GL_TEXTURE_2D_ARRAY, tex2);
glActiveTexture(GL_TEXTURE0); // reset to default
break;
}
case STBVOX_UNIFORM_face_data:
glUniform1i(loc, SAMPLER_YOU_WILL_BIND_PER_MESH_FACE_DATA_TO);
break;
case STBVOX_UNIFORM_ambient: // you definitely want to override this
case STBVOX_UNIFORM_color_table: // you might want to override this
case STBVOX_UNIFORM_texscale: // you may want to override this
glUniform4fv(loc, sui.array_length, sui.default_value);
break;
case STBVOX_UNIFORM_normals: // you never want to override this
case STBVOX_UNIFORM_texgen: // you never want to override this
glUniform3fv(loc, sui.array_length, sui.default_value);
break;
}
}
}
}
}
#endif
#ifdef __cplusplus
}
#endif
@ -475,43 +647,68 @@ enum
STBVOX_FACE_count,
};
// 24-bit color
typedef struct
{
unsigned char r,g,b;
} stbvox_rgb;
#ifdef STBVOX_CONFIG_BLOCKTYPE_SHORT
typedef unsigned short stbvox_block_type;
#else
typedef unsigned char stbvox_block_type;
#endif
// 24-bit color
typedef struct
{
unsigned char r,g,b;
} stbvox_rgb;
#define STBVOX_COLOR_TEX1_ENABLE 64
#define STBVOX_COLOR_TEX2_ENABLE 128
// This is the data structure you fill out
// 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.
struct stbvox_input_description
{
unsigned char lighting_at_vertices;
// The default is lighting values (i.e. ambient occlusion) are at block
// center, and the vertex light is gathered from the adjacent block
// centers the vertex faces. This makes smooth lighting consistent
// on adjacent faces with the same orientation.
// center, and the vertex light is gathered from those adjacent block
// centers that the vertex is facing. This makes smooth lighting
// consistent across adjacent faces with the same orientation.
//
// Setting this flag to non-zero gives you explicit control
// of light at each vertex; now the lighting/ao will be shared by
// all vertices at the same point, even if they have different normals.
// of light at each vertex, but now the lighting/ao will be
// shared by all vertices at the same point, even if they
// have different normals.
// these are 3D maps you use to define your voxel world, using x_stride and y_stride
// these are mostly 3D maps you use to define your voxel world, using x_stride and y_stride
// note that for cache efficiency, you want to use the block_foo palettes as much as possible instead
stbvox_rgb *rgb;
// Indexed by 3D coordinate.
// 24-bit voxel color for STBVOX_CONFIG_MODE = 20 or 21 only
stbvox_block_type *blocktype; // index into palettes listed below
// This is a core "block type" value, which is used to index into
// other arrays.
unsigned char *lighting;
// Indexed by 3D coordinate. The lighting value / ambient occlusion
// value that is used to define the vertex lighting values.
// 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,
// 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.
//
// (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
// to index into other arrays; essentially a "palette". This is much more
// memory-efficient and performance-friendly than storing the values explicitly,
// but only makes sense if the values are always synchronized.
//
// If a voxel's blocktype is 0, it is assumed to be empty (STBVOX_GEOM_empty),
// and no other blocktypes should be STBVOX_GEOM_empty. (Only if you do not
@ -520,6 +717,13 @@ struct stbvox_input_description
// Normally it is an unsigned byte, but you can override it to be
// a short if you have too many blocktypes.
unsigned char *geometry;
// Indexed by 3D coordinate. Contains the geometry type for the block.
// Also contains a 2-bit rotation for how the whole block is rotated.
// Also includes a 2-bit vheight value when using shared vheight values.
// See the separate vheight documentation.
// Encode with STBVOX_MAKE_GEOMETRY(geom, rot, vheight)
unsigned char *block_geometry;
// Array indexed by blocktype containing the geometry for this block, plus
// a 2-bit "simple rotation". Note rotation has limited use since it's not
@ -534,6 +738,12 @@ struct stbvox_input_description
// Array indexed by blocktype and face containing the texture id for texture #1.
// The N/E/S/W face choices can be rotated by one of the rotation selectors;
// The top & bottom face textures will rotate to match.
// Note that it only makes sense to use one of block_tex1 or block_tex1_face;
// this pattern repeats throughout and this notice is not repeated.
unsigned char *tex2;
// Indexed by 3D coordinate. Contains the texture id for texture #2
// to use on all faces of the block.
unsigned char *block_tex2;
// Array indexed by blocktype containing the texture id for texture #2.
@ -543,6 +753,11 @@ struct stbvox_input_description
// The N/E/S/W face choices can be rotated by one of the rotation selectors;
// The top & bottom face textures will rotate to match.
unsigned char *color;
// Indexed by 3D coordinate. Contains the color for all faces of the block.
// The core color value is 0..63.
// Encode with STBVOX_MAKE_COLOR(color_number, tex1_enable, tex2_enable)
unsigned char *block_color;
// Array indexed by blocktype containing the color value to apply to the faces.
// The core color value is 0..63.
@ -565,69 +780,166 @@ struct stbvox_input_description
unsigned char *block_vheight;
// Array indexed by blocktype containing the vheight values for the
// top or bottom face of this block. These will rotate properly if the
// block is rotated.
// block is rotated. See discussion of vheight.
// Encode with STBVOX_MAKE_VHEIGHT(sw_height, se_height, nw_height, ne_height)
unsigned char *selector;
// Array indexed by 3D coordinates indicating which output mesh to select.
unsigned char *block_selector;
// Array indexed by blocktype indicating which output mesh to select.
unsigned char *side_texrot;
// Array indexed by 3D coordinates encoding 2-bit texture rotations for the
// faces on the E/N/W/S sides of the block.
// Encode with STBVOX_MAKE_SIDE_TEXROT(rot_e, rot_n, rot_w, rot_s)
unsigned char *block_side_texrot;
// Array indexed by blocktype encoding 2-bin texture rotations for the faces
// Array indexed by blocktype encoding 2-bit texture rotations for the faces
// on the E/N/W/S sides of the block.
// Encode with STBVOX_MAKE_SIDE_TEXROT(rot_e, rot_n, rot_w, rot_s)
//////////////////////////////////////////////////////////////////////////////
// X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X//
//X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X //
// X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X//
//X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X //
// X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X//
//X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X //
// X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X//
//X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X //
//////////////////////////////////////////////////////////////////////////////
// Note the detailed documentation runs out here, I still have to finish this
// and document all the #define STBVOX_CONFIGs as well
unsigned char *overlay; // index into palettes listed below
unsigned char *selector; // raw selector (chooses which mesh to write to)
unsigned char *geometry; // STBVOX_MAKE_GEOMETRY -- geom:4, rot:2, vheight:2
unsigned char *rotate; // STBVOX_MAKE_MATROT -- block:2, overlay:2, tex2:2, color:2
unsigned char *tex2; // raw tex2 value to use on all sides of block
unsigned char *tex2_replace; // STBVOX_MAKE_TEX2_REPLACE -- tex2:6, face_1:2
unsigned char *tex2_facemask; // facemask:6 (use all bits of tex2_replace as texture)
unsigned char *side_texrot; // e:2,n:2,w:2,s:2 texture rotation
unsigned char *vheight; // STBVOX_MAKE_VHEIGHT -- sw:2, se:2, nw:2, ne:2, doesn't rotate
unsigned char *texlerp; // STBVOX_MAKE_TEXLERP -- vert:2, ud:2, ew:2, ns:2
unsigned char *texlerp2; // STBVOX_MAKE_TEXLERP2 (and use STBVOX_MAKE_TEXLERP1 for 'texlerp' -- e:2, n:2, u:3, unused:1
unsigned char *texlerp_simple; // STBVOX_MAKE_TEXLERP_SIMPLE -- baselerp:2, vert_lerp:3, face_to_use_vert_lerp:3
unsigned short *texlerp_vert3; // e:3,n:3,w:3,s:3,u:3 (down comes from 'texlerp')
unsigned short *texlerp_face3; // e:3,n:3,w:3,s:3,u:2,d:2
unsigned char *lighting; // lighting:8
unsigned char *color; // color for entire block
unsigned char *extended_color; // index into ecolor palettes
unsigned char *color2, *color2_facemask;// additional override colors with face bitmask
unsigned char *color3, *color3_facemask;// additional override colors with face bitmask
// Indexed by 3D coordinate. If 0, there is no overlay. If non-zero,
// it indexes into to the below arrays and overrides the values
// defined by the blocktype.
// indexed by tex1, used to determine tex2 if not otherwise specified
unsigned char *tex2_for_tex1; // 256
// @TODO: when specializing, build a single struct with all of the
// below values, so it's AoS instead of SoA for better cache efficiency
// indexed by overlay*6+side; in all cases 0 means 'nochange'
unsigned char (*overlay_tex1)[6];
unsigned char (*overlay_tex2)[6];
unsigned char (*overlay_color)[6];
unsigned char *overlay_side_texrot;
// Array indexed by overlay value and face, containing an override value
// for the texture id for texture #1. If 0, the value defined by blocktype
// is used.
// indexed by extended_color
unsigned char *ecolor_color; // 256
unsigned char *ecolor_facemask; // 256
unsigned char (*overlay_tex2)[6];
// Array indexed by overlay value and face, containing an override value
// for the texture id for texture #2. If 0, the value defined by blocktype
// is used.
unsigned char (*overlay_color)[6];
// Array indexed by overlay value and face, containing an override value
// for the face color. If 0, the value defined by blocktype is used.
unsigned char *overlay_side_texrot;
// Array indexed by overlay value, encoding 2-bit texture rotations for the faces
// on the E/N/W/S sides of the block.
// Encode with STBVOX_MAKE_SIDE_TEXROT(rot_e, rot_n, rot_w, rot_s)
unsigned char *rotate;
// Indexed by 3D coordinate. Allows independent rotation of several
// parts of the voxel, where by rotation I mean swapping textures
// and colors between E/N/S/W faces.
// Block: rotates anything indexed by blocktype
// Overlay: rotates anything indexed by overlay
// EColor: rotates faces defined in ecolor_facemask
// Encode with STBVOX_MAKE_MATROT(block,overlay,ecolor)
unsigned char *tex2_for_tex1;
// Array indexed by tex1 containing the texture id for texture #2.
// You can use this if the two are always/almost-always strictly
// correlated (e.g. if tex2 is a detail texture for tex1), as it
// will be more efficient (touching fewer cache lines) than using
// e.g. block_tex2_face.
unsigned char *tex2_replace;
// Indexed by 3D coordinate. Specifies the texture id for texture #2
// to use on a single face of the voxel, which must be E/N/W/S (not U/D).
// The texture id is limited to 6 bits unless tex2_facemask is also
// defined (see below).
// Encode with STBVOX_MAKE_TEX2_REPLACE(tex2, face)
unsigned char *tex2_facemask;
// Indexed by 3D coordinate. Specifies which of the six faces should
// have their tex2 replaced by the value of tex2_replace. In this
// case, all 8 bits of tex2_replace are used as the texture id.
// Encode with STBVOX_MAKE_FACE_MASK(east,north,west,south,up,down)
unsigned char *extended_color;
// Indexed by 3D coordinate. Specifies a value that indexes into
// the ecolor arrays below (both of which must be defined).
unsigned char *ecolor_color;
// Indexed by extended_color value, specifies an optional override
// for the color value on some faces.
// Encode with STBVOX_MAKE_COLOR(color_number, tex1_enable, tex2_enable)
unsigned char *ecolor_facemask;
// Indexed by extended_color value, this specifies which faces the
// color in ecolor_color should be applied to. The faces can be
// independently rotated by the ecolor value of 'rotate', if it exists.
// Encode with STBVOX_MAKE_FACE_MASK(e,n,w,s,u,d)
unsigned char *color2;
// Indexed by 3D coordinates, specifies an alternative color to apply
// to some of the faces of the block.
// Encode with STBVOX_MAKE_COLOR(color_number, tex1_enable, tex2_enable)
unsigned char *color2_facemask;
// Indexed by 3D coordinates, specifies which faces should use the
// color defined in color2. No rotation value is applied.
// Encode with STBVOX_MAKE_FACE_MASK(e,n,w,s,u,d)
unsigned char *color3;
// Indexed by 3D coordinates, specifies an alternative color to apply
// to some of the faces of the block.
// Encode with STBVOX_MAKE_COLOR(color_number, tex1_enable, tex2_enable)
unsigned char *color3_facemask;
// Indexed by 3D coordinates, specifies which faces should use the
// color defined in color3. No rotation value is applied.
// Encode with STBVOX_MAKE_FACE_MASK(e,n,w,s,u,d)
unsigned char *texlerp_simple;
// Indexed by 3D coordinates, this is the smallest texlerp encoding
// that can do useful work. It consits of three values: baselerp,
// vertlerp, and face_vertlerp. Baselerp defines the value
// to use on all of the faces but one, from the STBVOX_TEXLERP_BASE
// values. face_vertlerp is one of the 6 face values (or STBVOX_FACE_NONE)
// which specifies the face should use the vertlerp values.
// Vertlerp defines a lerp value at every vertex of the mesh.
// Thus, one face can have per-vertex texlerp values, and those
// values are encoded in the space so that they will be shared
// by adjacent faces that also use vertlerp, allowing continuity
// (this is used for the "texture crossfade" bit of the release video).
// Encode with STBVOX_MAKE_TEXLERP_SIMPLE(baselerp, vertlerp, face_vertlerp)
// The following texlerp encodings are experimental and maybe not
// that useful.
unsigned char *texlerp;
// Indexed by 3D coordinates, this defines four values:
// vertlerp is a lerp value at every vertex of the mesh (using STBVOX_TEXLERP_BASE values).
// ud is the value to use on up and down faces, from STBVOX_TEXLERP_FACE values
// ew is the value to use on east and west faces, from STBVOX_TEXLERP_FACE values
// ns is the value to use on north and south faces, from STBVOX_TEXLERP_FACE values
// If any of ud, ew, or ns is STBVOX_TEXLERP_FACE_use_vert, then the
// vertlerp values for the vertices are gathered and used for those faces.
// Encode with STBVOX_MAKE_TEXLERP(vertlerp,ud,ew,sw)
unsigned short *texlerp_vert3;
// Indexed by 3D coordinates, this works with texlerp and
// provides a unique texlerp value for every direction at
// every vertex. The same rules of whether faces share values
// applies. The STBVOX_TEXLERP_FACE vertlerp value defined in
// texlerp is only used for the down direction. The values at
// each vertex in other directions are defined in this array,
// and each uses the STBVOX_TEXLERP3 values (i.e. full precision
// 3-bit texlerp values).
// Encode with STBVOX_MAKE_VERT3(vertlerp_e,vertlerp_n,vertlerp_w,vertlerp_s,vertlerp_u)
unsigned short *texlerp_face3; // e:3,n:3,w:3,s:3,u:2,d:2
// Indexed by 3D coordinates, this provides a compact way to
// fully specify the texlerp value indepenendly for every face,
// but doesn't allow per-vertex variation. E/N/W/S values are
// encoded using STBVOX_TEXLERP3 values, whereas up and down
// use STBVOX_TEXLERP_SIMPLE values.
// Encode with STBVOX_MAKE_FACE3(face_e,face_n,face_w,face_s,face_u,face_d)
unsigned char *vheight; // STBVOX_MAKE_VHEIGHT -- sw:2, se:2, nw:2, ne:2, doesn't rotate
// Indexed by 3D coordinates, this defines the four
// vheight values to use if the geometry is STBVOX_GEOM_vheight*.
// See the vheight discussion.
};
// @OPTIMIZE when specializing, build a single struct with all of the
// 3D-indexed so it's AoS instead of SoA for better cache efficiency
enum
@ -639,10 +951,10 @@ enum
enum
{
STBVOX_TEXLERP_0,
STBVOX_TEXLERP_half,
STBVOX_TEXLERP_1,
STBVOX_TEXLERP_use_vert,
STBVOX_TEXLERP_FACE_0,
STBVOX_TEXLERP_FACE_half,
STBVOX_TEXLERP_FACE_1,
STBVOX_TEXLERP_FACE_use_vert,
};
enum
@ -677,7 +989,7 @@ enum
#define STBVOX_MAKE_GEOMETRY(geom, rotate, vheight) ((geom) + (rotate)*16 + (vheight)*64)
#define STBVOX_MAKE_VHEIGHT(v_sw, v_se, v_nw, v_ne) ((v_sw) + (v_se)*4 + (v_nw)*16 + (v_ne)*64)
#define STBVOX_MAKE_MATROT(block, overlay, tex2, color) ((block) + (overlay)*4 + (tex2)*16 + (color)*64)
#define STBVOX_MAKE_MATROT(block, overlay, color) ((block) + (overlay)*4 + (color)*64)
#define STBVOX_MAKE_TEX2_REPLACE(tex2, tex2_replace_face) ((tex2) + ((tex2_replace_face) & 3)*64)
#define STBVOX_MAKE_TEXLERP(ns2, ew2, ud2, vert) ((ew2) + (ns2)*4 + (ud2)*16 + (vert)*64)
#define STBVOX_MAKE_TEXLERP_SIMPLE(baselerp,vert,face) ((vert)*32 + (face)*4 + (baselerp))
@ -686,6 +998,8 @@ enum
#define STBVOX_MAKE_FACE_MASK(e,n,w,s,u,d) ((e)+(n)*2+(w)*4+(s)*8+(u)*16+(d)*32)
#define STBVOX_MAKE_SIDE_TEXROT(e,n,w,s) ((e)+(n)*4+(w)*16+(s)*64)
#define STBVOX_MAKE_COLOR(color,t1,t2) ((color)+(t1)*64+(t2)*128)
#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
#define STBVOX_MAKE_LIGHTING(lighting, rot) (((lighting)&~3)+(rot))
@ -947,7 +1261,7 @@ static float stbvox_default_ambient[4][4] =
{ 0,0,1 ,0 }, // reversed lighting direction
{ 0.5,0.5,0.5,0 }, // directional color
{ 0.5,0.5,0.5,0 }, // constant color
{ 0.5,0.5,0.5,1.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];
@ -1036,7 +1350,7 @@ static char *stbvox_vertex_program =
" amb_occ = float( (attr_vertex >> 23u) & 63u ) / 63.0;\n" // a[23..28]
" texlerp = float( (attr_vertex >> 29u) ) / 7.0;\n" // a[29..31]
" vnormal = normal_table[(facedata.w>>2) & 31u];\n"
" vnormal = normal_table[(facedata.w>>2u) & 31u];\n"
" voxelspace_pos = offset * transform[0];\n" // mesh-to-object scale
" vec3 position = voxelspace_pos + transform[1];\n" // mesh-to-object translate
@ -1428,11 +1742,10 @@ STBVXDEC int stbvox_get_uniform_info(stbvox_uniform_info *info, int uniform)
typedef struct
{
unsigned char block;
unsigned char overlay;
unsigned char facerot:4;
unsigned char ecolor:4;
unsigned char tex2;
unsigned char block:2;
unsigned char overlay:2;
unsigned char facerot:2;
unsigned char ecolor:2;
} stbvox_rotate;
typedef struct
@ -1505,6 +1818,7 @@ stbvox_mesh_face stbvox_compute_mesh_face_value(stbvox_mesh_maker *mm, stbvox_ro
if (mm->input.overlay) {
int over_face = STBVOX_ROTATE(face, rot.overlay);
unsigned char over = mm->input.overlay[v_off];
if (over) {
if (mm->input.overlay_tex1) {
unsigned char rep1 = mm->input.overlay_tex1[over][over_face];
if (rep1)
@ -1521,17 +1835,17 @@ stbvox_mesh_face stbvox_compute_mesh_face_value(stbvox_mesh_maker *mm, stbvox_ro
face_data.color = rep3;
}
if (face <= STBVOX_FACE_south)
if (mm->input.overlay_side_texrot && face <= STBVOX_FACE_south)
facerot = mm->input.overlay_side_texrot[over] >> (2*over_face);
}
}
if (mm->input.tex2_for_tex1)
face_data.tex2 = mm->input.tex2_for_tex1[face_data.tex1];
if (mm->input.tex2)
face_data.tex2 = mm->input.tex2[v_off];
if (mm->input.tex2_replace) {
int tex2_face = STBVOX_ROTATE(face, rot.tex2);
if (mm->input.tex2_facemask[v_off] & (1 << tex2_face))
if (mm->input.tex2_facemask[v_off] & (1 << face))
face_data.tex2 = mm->input.tex2_replace[v_off];
}
@ -1555,11 +1869,11 @@ stbvox_mesh_face stbvox_compute_mesh_face_value(stbvox_mesh_maker *mm, stbvox_ro
}
static unsigned char stbvox_face_lerp[6] = { 0,2,0,2,4,4 };
static unsigned char stbvox_vert3_lerp[6] = { 0,3,6,9,12,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_face3_lerp[6] = { 0,3,6,9,12,14 };
static unsigned char stbvox_face3_updown[8] = { 0,2,4,7,0,2,4,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
// vertex offsets for face vertices
static unsigned char stbvox_vertex_vector[6][4][3];
static stbvox_mesh_vertex stbvox_vmesh_delta_normal[6][4];
@ -1615,7 +1929,7 @@ void stbvox_make_mesh_for_face(stbvox_mesh_maker *mm, stbvox_rotate rot, int fac
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 >= 4)
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) {
@ -1636,7 +1950,7 @@ void stbvox_make_mesh_for_face(stbvox_mesh_maker *mm, stbvox_rotate rot, int fac
}
} else if (mm->input.texlerp) {
unsigned char facelerp = (mm->input.texlerp[v_off] >> stbvox_face_lerp[face]) & 3;
if (facelerp == STBVOX_TEXLERP_use_vert) {
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;
@ -1644,10 +1958,10 @@ void stbvox_make_mesh_for_face(stbvox_mesh_maker *mm, stbvox_rotate rot, int fac
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_face_lerp[mm->input.texlerp[mm->cube_vertex_offset[face][0]]>>6];
p1[1] = stbvox_vert_lerp_for_face_lerp[mm->input.texlerp[mm->cube_vertex_offset[face][1]]>>6];
p1[2] = stbvox_vert_lerp_for_face_lerp[mm->input.texlerp[mm->cube_vertex_offset[face][2]]>>6];
p1[3] = stbvox_vert_lerp_for_face_lerp[mm->input.texlerp[mm->cube_vertex_offset[face][3]]>>6];
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]);
@ -1785,7 +2099,7 @@ static void stbvox_make_mesh_for_block(stbvox_mesh_maker *mm, stbvox_pos pos, in
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,0 };
stbvox_rotate rot = { 0,0,0,0 };
unsigned char simple_rot = 0;
unsigned char mesh = mm->default_mesh;
@ -1816,10 +2130,10 @@ static void stbvox_make_mesh_for_block(stbvox_mesh_maker *mm, stbvox_pos pos, in
unsigned char val = mm->input.rotate[v_off];
rot.block = (val >> 0) & 3;
rot.overlay = (val >> 2) & 3;
rot.tex2 = (val >> 4) & 3;
//rot.tex2 = (val >> 4) & 3;
rot.ecolor = (val >> 6) & 3;
} else {
rot.block = rot.overlay = rot.tex2 = rot.ecolor = simple_rot;
rot.block = rot.overlay = rot.ecolor = simple_rot;
}
rot.facerot = 0;
@ -2044,7 +2358,7 @@ static void stbvox_make_mesh_for_block_with_geo(stbvox_mesh_maker *mm, stbvox_po
// 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,0 };
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
@ -2094,10 +2408,10 @@ static void stbvox_make_mesh_for_block_with_geo(stbvox_mesh_maker *mm, stbvox_po
unsigned char val = mm->input.rotate[v_off];
rotate.block = (val >> 0) & 3;
rotate.overlay = (val >> 2) & 3;
rotate.tex2 = (val >> 4) & 3;
//rotate.tex2 = (val >> 4) & 3;
rotate.ecolor = (val >> 6) & 3;
} else {
rotate.block = rotate.overlay = rotate.tex2 = rotate.ecolor = simple_rot;
rotate.block = rotate.overlay = rotate.ecolor = simple_rot;
}
rotate.facerot = 0;
@ -2119,7 +2433,7 @@ static void stbvox_make_mesh_for_block_with_geo(stbvox_mesh_maker *mm, stbvox_po
stbvox_mesh_vertex vmesh[6][4];
stbvox_mesh_vertex cube[8];
stbvox_mesh_vertex basevert;
stbvox_rotate rotate = { 0,0,0,0,0 };
stbvox_rotate rotate = { 0,0,0,0 };
unsigned char simple_rot = rot;
unsigned char ht[4];
int extreme;
@ -2237,10 +2551,10 @@ static void stbvox_make_mesh_for_block_with_geo(stbvox_mesh_maker *mm, stbvox_po
unsigned char val = mm->input.rotate[v_off];
rotate.block = (val >> 0) & 3;
rotate.overlay = (val >> 2) & 3;
rotate.tex2 = (val >> 4) & 3;
//rotate.tex2 = (val >> 4) & 3;
rotate.ecolor = (val >> 6) & 3;
} else if (mm->input.selector) {
rotate.block = rotate.overlay = rotate.tex2 = rotate.ecolor = simple_rot;
rotate.block = rotate.overlay = rotate.ecolor = simple_rot;
}
if ((visible_faces & (1 << STBVOX_FACE_north)) || (extreme && (ht[2] == 3 || ht[3] == 3)))
@ -2257,7 +2571,7 @@ static void stbvox_make_mesh_for_block_with_geo(stbvox_mesh_maker *mm, stbvox_po
// 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,0 };
stbvox_rotate rot = { 0,0,0,0 };
unsigned char mesh = mm->default_mesh;
if (mm->input.selector) {
mesh = mm->input.selector[v_off];
@ -2275,10 +2589,10 @@ static void stbvox_make_mesh_for_block_with_geo(stbvox_mesh_maker *mm, stbvox_po
unsigned char val = mm->input.rotate[v_off];
rot.block = (val >> 0) & 3;
rot.overlay = (val >> 2) & 3;
rot.tex2 = (val >> 4) & 3;
//rot.tex2 = (val >> 4) & 3;
rot.ecolor = (val >> 6) & 3;
} else if (mm->input.selector) {
rot.block = rot.overlay = rot.tex2 = rot.ecolor = simple_rot;
rot.block = rot.overlay = rot.ecolor = simple_rot;
}
rot.facerot = 0;