nothings-stb/stb_voxel_render.h

3804 lines
157 KiB
C

// stb_voxel_render.h - v0.85 - 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:
// http://www.youtube.com/watch?v=2vnTtiLrV1w
//
// Minecraft-viewer sample app (not very simple though):
// http://github.com/nothings/stb/tree/master/tests/caveview
//
// It works by creating triangle meshes. The library includes
//
// - converter from dense 3D arrays of block info to vertex mesh
// - vertex & fragment shaders for the vertex mesh
// - assistance in setting up shader state
//
// For portability, none of the library code actually accesses
// the 3D graphics API. (At the moment, it's not actually portable
// since the shaders are GLSL only, but patches are welcome.)
//
// 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 designs to allow much more compact formats
// with a slight reduction in shader features, but no roadmap
// for actually implementing them.
//
//
// USAGE
//
// #define the symbol STB_VOXEL_RENDER_IMPLEMENTATION in *one*
// C/C++ file before the #include of this file; the implementation
// will be generated in that file.
//
// If you define the symbols STB_VOXEL_RENDER_STATIC, then the
// implementation will be private to that file.
//
//
// FEATURES
//
// - you can choose textured blocks with the features below,
// or colored voxels with 2^24 colors and no textures.
//
// - voxels are mostly just cubes, but there's support for
// half-height cubes and diagonal slopes, half-height
// diagonals, and even odder shapes especially for doing
// more-continuous "ground".
//
// - texture coordinates are projections along one of the major
// axes, with the per-texture scaling.
//
// - a number of aspects of the shader and the vertex format
// are configurable; the library generally takes care of
// coordinating the vertex format with the mesh for you.
//
//
// FEATURES (SHADER PERSPECTIVE)
//
// - vertices aligned on integer lattice, z on multiples of 0.5
// - per-vertex "lighting" or "ambient occlusion" value (6 bits)
// - per-vertex texture crossfade (3 bits)
//
// - per-face texture #1 id (8-bit index into array texture)
// - per-face texture #2 id (8-bit index into second array texture)
// - per-face color (6-bit palette index, 2 bits of per-texture boolean enable)
// - per-face 5-bit normal for lighting calculations & texture coord computation
// - per-face 2-bit texture matrix rotation to rotate faces
//
// - indexed-by-texture-id scale factor (separate for texture #1 and texture #2)
// - 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",
// 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);
// 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
// - face can be fullbright (emissive), controlled by per-face color
// - installable lighting, with default single-point-light
// - installable fog, with default hacked smoothstep
//
// Note that all the variations of lighting selection and texture
// blending are run-time conditions in the shader, so they can be
// intermixed in a single mesh.
//
//
// INTEGRATION ARC
//
// The way to get this library to work from scratch is to do the following:
//
// Step 1. define STBVOX_CONFIG_MODE to 0
//
// This mode uses only vertex attributes and uniforms, and is easiest
// to get working. It requires 32 bytes per quad and limits the
// size of some tables to avoid hitting uniform limits.
//
// Step 2. define STBVOX_CONFIG_MODE to 1
//
// This requires using a texture buffer to store the quad data,
// reducing the size to 20 bytes per quad.
//
// Step 3: define STBVOX_CONFIG_PREFER_TEXBUFFER
//
// This causes some uniforms to be stored as texture buffers
// instead. This increases the size of some of those tables,
// and avoids a potential slow path (gathering non-uniform
// data from uniforms) on some hardware.
//
// In the future I might add additional modes that have significantly
// smaller meshes but reduce features, down as small as 6 bytes per quad.
// See elsewhere in this file for a table of candidate modes. Switching
// to a mode will require changing some of your mesh creation code, but
// everything else should be seamless. (And I'd like to change the API
// so that mesh creation is data-driven the way the uniforms are, and
// then you wouldn't even have to change anything but the mode number.)
//
//
// IMPROVEMENTS FOR SHIP-WORTHY PROGRAMS USING THIS LIBRARY
//
// I currently tolerate a certain level of "bugginess" in this library.
//
// I'm referring to things which look a little wrong (as long as they
// don't cause holes or cracks in the output meshes), or things which
// do not produce as optimal a mesh as possible. Notable examples:
//
// - incorrect lighting on slopes
// - inefficient meshes for vheight blocks
//
// I am willing to do the work to improve these things if someone is
// going to ship a substantial program that would be improved by them.
// (It need not be commercial, nor need it be a game.) I just didn't
// want to do the work up front if it might never be leveraged. So just
// submit a bug report as usual (github is preferred), but add a note
// that this is for a thing that is really going to ship. (That means
// you need to be far enough into the project that it's clear you're
// committed to it; not during early exploratory development.)
//
//
// VOXEL MESH API
//
// Context
//
// To understand the API, make sure you first understand the feature set
// listed above.
//
// Because the vertices are compact, they have very limited spatial
// precision. Thus a single mesh can only contain the data for a limited
// area. To make very large voxel maps, you'll need to build multiple
// vertex buffers. (But you want this anyway for frustum culling.)
//
// Each generated mesh has three components:
// - vertex data (vertex buffer)
// - face data (optional, stored in texture buffer)
// - mesh transform (uniforms)
//
// Once you've generated the mesh with this library, it's up to you
// to upload it to the GPU, to keep track of the state, and to render
// it.
//
// Concept
//
// The basic design is that you pass in one or more 3D arrays; each array
// is (typically) one-byte-per-voxel and contains information about one
// or more properties of some particular voxel property.
//
// 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 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.
//
// Details
//
// See the API documentation in the header-file section.
//
//
// CONTRIBUTORS
//
// Features Porting Bugfixes & Warnings
// Sean Barrett github:r-leyh Jesus Fernandez
// Miguel Lechon github:Arbeiterunfallversicherungsgesetz
// Thomas Frase James Hofmann
// Stephen Olsen github:guitarfreak
//
// VERSION HISTORY
//
// 0.85 (2017-03-03) add block_selector (by guitarfreak)
// 0.84 (2016-04-02) fix GLSL syntax error on glModelView path
// 0.83 (2015-09-13) remove non-constant struct initializers to support more compilers
// 0.82 (2015-08-01) added input.packed_compact to store rot, vheight & texlerp efficiently
// fix broken tex_overlay2
// 0.81 (2015-05-28) fix broken STBVOX_CONFIG_OPTIMIZED_VHEIGHT
// 0.80 (2015-04-11) fix broken STBVOX_CONFIG_ROTATION_IN_LIGHTING refactoring
// change STBVOX_MAKE_LIGHTING to STBVOX_MAKE_LIGHTING_EXT so
// that header defs don't need to see config vars
// 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
//
//
// LICENSE
//
// See end of file for license information.
#ifndef INCLUDE_STB_VOXEL_RENDER_H
#define INCLUDE_STB_VOXEL_RENDER_H
#include <stdlib.h>
typedef struct stbvox_mesh_maker stbvox_mesh_maker;
typedef struct stbvox_input_description stbvox_input_description;
#ifdef STB_VOXEL_RENDER_STATIC
#define STBVXDEC static
#else
#define STBVXDEC extern
#endif
#ifdef __cplusplus
extern "C" {
#endif
//////////////////////////////////////////////////////////////////////////////
//
// CONFIGURATION MACROS
//
// #define STBVOX_CONFIG_MODE <integer> // REQUIRED
// 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 STB_VOXEL_RENDER_STATIC 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> // OPTIONAL
// Defines the number of bits of fractional position for Z.
// Only 0 or 1 are valid. 1 is the default. 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 are just #ifdef tested so need no values, and are optional.
//
// 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 ambient-occlusion applied
//
// STBVOX_CONFIG_FOG_SMOOTHSTEP
// Defines a simple unrealistic fog system designed to maximize
// unobscured view distance while not looking too 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 could 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_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
// 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 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
// these relative coordinates unless explicitly stated
// otherwise.
//
// Input to the meshing step is documented further down
STBVXDEC void stbvox_init_mesh_maker(stbvox_mesh_maker *mm);
// Call this function to initialize a mesh-maker context structure
// used to build meshes. You should have one context per thread
// that's building meshes.
STBVXDEC void stbvox_set_buffer(stbvox_mesh_maker *mm, int mesh, int slot, void *buffer, size_t len);
// Call this to set the buffer into which stbvox will write the mesh
// it creates. It can build more than one mesh in parallel (distinguished
// by the 'mesh' parameter), and each mesh can be made up of more than
// one buffer (distinguished by the 'slot' parameter).
//
// Multiple meshes are under your control; use the 'selector' input
// variable to choose which mesh each voxel's vertices are written to.
// For example, you can use this to generate separate meshes for opaque
// and transparent data.
//
// You can query the number of slots by calling stbvox_get_buffer_count
// described below. The meaning of the buffer for each slot depends
// on STBVOX_CONFIG_MODE.
//
// In mode 0 & mode 20, there is only one slot. The mesh data for that
// slot is two interleaved vertex attributes: attr_vertex, a single
// 32-bit uint, and attr_face, a single 32-bit uint.
//
// In mode 1 & mode 21, there are two slots. The first buffer should
// be four times as large as the second buffer. The first buffer
// contains a single vertex attribute: 'attr_vertex', a single 32-bit uint.
// The second buffer contains texture buffer data (an array of 32-bit uints)
// that will be accessed through the sampler identified by STBVOX_UNIFORM_face_data.
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, 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)
// if the input doesn't specify a per-voxel selector. (I doubt this is
// useful, but it's here just in case.)
STBVXDEC stbvox_input_description *stbvox_get_input_description(stbvox_mesh_maker *mm);
// This function call returns a pointer to the stbvox_input_description part
// of stbvox_mesh_maker (which you should otherwise treat as opaque). You
// zero this structure, then fill out the relevant pointers to the data
// describing your voxel object/world.
//
// See further documentation at the description of stbvox_input_description below.
STBVXDEC void stbvox_set_input_stride(stbvox_mesh_maker *mm, int x_stride_in_elements, int y_stride_in_elements);
// This sets the stride between successive elements of the 3D arrays
// in the stbvox_input_description. Z values are always stored consecutively.
// (The preferred coordinate system for stbvox is X right, Y forwards, Z up.)
STBVXDEC void stbvox_set_input_range(stbvox_mesh_maker *mm, int x0, int y0, int z0, int x1, int y1, int z1);
// This sets the range of values in the 3D array for the voxels that
// the mesh generator will convert. The lower values are inclusive,
// the higher values are exclusive, so (0,0,0) to (16,16,16) generates
// mesh data associated with voxels up to (15,15,15) but no higher.
//
// The mesh generate generates faces at the boundary between open space
// and solid space but associates them with the solid space, so if (15,0,0)
// is open and (16,0,0) is solid, then the mesh will contain the boundary
// between them if x0 <= 16 and x1 > 16.
//
// Note that the mesh generator will access array elements 1 beyond the
// limits set in these parameters. For example, if you set the limits
// to be (0,0,0) and (16,16,16), then the generator will access all of
// the voxels between (-1,-1,-1) and (16,16,16), including (16,16,16).
// You may have to do pointer arithmetic to make it work.
//
// For example, caveview processes mesh chunks that are 32x32x16, but it
// does this using input buffers that are 34x34x18.
//
// The lower limits are x0 >= 0, y0 >= 0, and z0 >= 0.
//
// The upper limits are mode dependent, but all the current methods are
// limited to x1 < 127, y1 < 127, z1 < 255. Note that these are not
// powers of two; if you want to use power-of-two chunks (to make
// it efficient to decide which chunk a coordinate falls in), you're
// limited to at most x1=64, y1=64, z1=128. For classic Minecraft-style
// worlds with limited vertical extent, I recommend using a single
// chunk for the entire height, which limits the height to 255 blocks
// (one less than Minecraft), and only chunk the map in X & Y.
STBVXDEC int stbvox_make_mesh(stbvox_mesh_maker *mm);
// Call this function to create mesh data for the currently configured
// set of input data. This appends to the currently configured mesh output
// buffer. Returns 1 on success. If there is not enough room in the buffer,
// it outputs as much as it can, and returns 0; you need to switch output
// buffers (either by calling stbvox_set_buffer to set new buffers, or
// by copying the data out and calling stbvox_reset_buffers), and then
// call this function again without changing any of the input parameters.
//
// Note that this function appends; you can call it multiple times to
// build a single mesh. For example, caveview uses chunks that are
// 32x32x255, but builds the mesh for it by processing 32x32x16 at atime
// (this is faster as it is reuses the same 34x34x18 input buffers rather
// than needing 34x34x257 input buffers).
// Once you're done creating a mesh into a given buffer,
// consider the following functions:
STBVXDEC int stbvox_get_quad_count(stbvox_mesh_maker *mm, int mesh);
// Returns the number of quads in the mesh currently generated by mm.
// This is the sum of all consecutive stbvox_make_mesh runs appending
// to the same buffer. 'mesh' distinguishes between the multiple user
// meshes available via 'selector' or stbvox_set_default_mesh.
//
// Typically you use this function when you're done building the mesh
// and want to record how to draw it.
//
// Note that there are no index buffers; the data stored in the buffers
// should be drawn as quads (e.g. with GL_QUAD); if your API does not
// support quads, you can create a single index buffer large enough to
// draw your largest vertex buffer, and reuse it for every rendering.
// (Note that if you use 32-bit indices, you'll use 24 bytes of bandwidth
// per quad, more than the 20 bytes for the vertex/face mesh data.)
STBVXDEC void stbvox_set_mesh_coordinates(stbvox_mesh_maker *mm, int x, int y, int z);
// Sets the global coordinates for this chunk, such that (0,0,0) relative
// coordinates will be at (x,y,z) in global coordinates.
STBVXDEC void stbvox_get_bounds(stbvox_mesh_maker *mm, float bounds[2][3]);
// Returns the bounds for the mesh in global coordinates. Use this
// for e.g. frustum culling the mesh. @BUG: this just uses the
// values from stbvox_set_input_range(), so if you build by
// appending multiple values, this will be wrong, and you need to
// set stbvox_set_input_range() to the full size. Someday this
// will switch to tracking the actual bounds of the *mesh*, though.
STBVXDEC void stbvox_get_transform(stbvox_mesh_maker *mm, float transform[3][3]);
// Returns the 'transform' data for the shader uniforms. It is your
// job to set this to the shader before drawing the mesh. It is the
// only uniform that needs to change per-mesh. Note that it is not
// a 3x3 matrix, but rather a scale to decode fixed point numbers as
// floats, a translate from relative to global space, and a special
// translation for texture coordinate generation that avoids
// floating-point precision issues. @TODO: currently we add the
// global translation to the vertex, than multiply by modelview,
// but this means if camera location and vertex are far from the
// origin, we lose precision. Need to make a special modelview with
// the translation (or some of it) factored out to avoid this.
STBVXDEC void stbvox_reset_buffers(stbvox_mesh_maker *mm);
// Call this function if you're done with the current output buffer
// but want to reuse it (e.g. you're done appending with
// stbvox_make_mesh and you've copied the data out to your graphics API
// so can reuse the buffer).
//////////////////////////////////////////////////////////////////////////////
//
// RENDERING
//
STBVXDEC char *stbvox_get_vertex_shader(void);
// Returns the (currently GLSL-only) vertex shader.
STBVXDEC char *stbvox_get_fragment_shader(void);
// Returns the (currently GLSL-only) fragment shader.
// You can override the lighting and fogging calculations
// by appending data to the end of these; see the #define
// documentation for more information.
STBVXDEC char *stbvox_get_fragment_shader_alpha_only(void);
// Returns a slightly cheaper fragment shader that computes
// alpha but not color. This is useful for e.g. a depth-only
// pass when using alpha test.
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 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.
// Most values are shared for most draw calls; e.g. for stateful
// APIs you can set most of the state only once. Only
// STBVOX_UNIFORM_transform needs to change per draw call.
//
// 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'
// y: scale factor to apply to texture #2. must be a power of two. 1.0 means 'face-sized'
// z: blend mode indexed by texture #2. 0.0 is alpha compositing; 1.0 is multiplication.
// w: unused currently. @TODO use to support texture animation?
//
// 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. 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:
// ambient[0].xyz - negative of direction of a directional light for half-lambert
// ambient[1].rgb - color of light scaled by NdotL (can be negative)
// ambient[2].rgb - constant light added to above calculation;
// effectively light ranges from ambient[2]-ambient[1] to ambient[2]+ambient[1]
// ambient[3].rgb - fog color for STBVOX_CONFIG_FOG_SMOOTHSTEP
// ambient[3].a - reciprocal of squared distance of farthest fog point (viewing distance)
// +----- has a 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; 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
STBVOX_UNIFORM_camera_pos, // Y camera position in global voxel space (for lighting & fog)
STBVOX_UNIFORM_count,
};
enum
{
STBVOX_UNIFORM_TYPE_none,
STBVOX_UNIFORM_TYPE_sampler,
STBVOX_UNIFORM_TYPE_vec2,
STBVOX_UNIFORM_TYPE_vec3,
STBVOX_UNIFORM_TYPE_vec4,
};
struct stbvox_uniform_info
{
int type; // which type of uniform
int bytes_per_element; // the size of each uniform array element (e.g. vec3 = 12 bytes)
int array_length; // length of the uniform array
char *name; // name in the shader @TODO use numeric binding
float *default_value; // if not NULL, you can use this as the uniform pointer
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 separately set the 'transform' uniform for every mesh.
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
//////////////////////////////////////////////////////////////////////////////
//
// INPUT TO MESHING
//
// Shapes of blocks that aren't always cubes
enum
{
STBVOX_GEOM_empty,
STBVOX_GEOM_knockout, // creates a hole in the mesh
STBVOX_GEOM_solid,
STBVOX_GEOM_transp, // solid geometry, but transparent contents so neighbors generate normally, unless same blocktype
// following 4 can be represented by vheight as well
STBVOX_GEOM_slab_upper,
STBVOX_GEOM_slab_lower,
STBVOX_GEOM_floor_slope_north_is_top,
STBVOX_GEOM_ceil_slope_north_is_bottom,
STBVOX_GEOM_floor_slope_north_is_top_as_wall_UNIMPLEMENTED, // same as floor_slope above, but uses wall's texture & texture projection
STBVOX_GEOM_ceil_slope_north_is_bottom_as_wall_UNIMPLEMENTED,
STBVOX_GEOM_crossed_pair, // corner-to-corner pairs, with normal vector bumped upwards
STBVOX_GEOM_force, // like GEOM_transp, but faces visible even if neighbor is same type, e.g. minecraft fancy leaves
// these access vheight input
STBVOX_GEOM_floor_vheight_03 = 12, // diagonal is SW-NE
STBVOX_GEOM_floor_vheight_12, // diagonal is SE-NW
STBVOX_GEOM_ceil_vheight_03,
STBVOX_GEOM_ceil_vheight_12,
STBVOX_GEOM_count, // number of geom cases
};
enum
{
STBVOX_FACE_east,
STBVOX_FACE_north,
STBVOX_FACE_west,
STBVOX_FACE_south,
STBVOX_FACE_up,
STBVOX_FACE_down,
STBVOX_FACE_count,
};
#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. 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;
// The default is lighting values (i.e. ambient occlusion) are at block
// 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, but now the lighting/ao will be
// shared by all vertices at the same point, even if they
// have different normals.
// 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
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_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_EXT(lighting,rot)--here
// 'lighting' should still be 8 bits, as the macro will
// discard the bottom bits automatically. Similarly, if
// using STBVOX_CONFIG_VHEIGHT_IN_LIGHTING, encode with
// STBVOX_MAKE_LIGHTING_EXT(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.)
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
// have blocktypes should STBVOX_GEOM_empty ever used.)
//
// 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
// independent of blocktype.
//
// Encode with STBVOX_MAKE_GEOMETRY(geom,simple_rot,0)
unsigned char *block_tex1;
// Array indexed by blocktype containing the texture id for texture #1.
unsigned char (*block_tex1_face)[6];
// 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.
unsigned char (*block_tex2_face)[6];
// Array indexed by blocktype and face containing the texture id for texture #2.
// 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.
// Encode with STBVOX_MAKE_COLOR(color_number, tex1_enable, tex2_enable)
unsigned char (*block_color_face)[6];
// Array indexed by blocktype and face containing the color value to apply to that face.
// The core color value is 0..63.
// Encode with STBVOX_MAKE_COLOR(color_number, tex1_enable, tex2_enable)
unsigned char *block_texlerp;
// Array indexed by blocktype containing 3-bit scalar for texture #2 alpha
// (known throughout as 'texlerp'). This is constant over every face even
// though the property is potentially per-vertex.
unsigned char (*block_texlerp_face)[6];
// Array indexed by blocktype and face containing 3-bit scalar for texture #2 alpha.
// This is constant over the face even though the property is potentially per-vertex.
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. 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-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 *overlay; // index into palettes listed below
// 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.
unsigned char (*overlay_tex1)[6];
// 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.
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.
unsigned char *packed_compact;
// Stores block rotation, vheight, and texlerp values:
// block rotation: 2 bits
// vertex vheight: 2 bits
// use_texlerp : 1 bit
// vertex texlerp: 3 bits
// If STBVOX_CONFIG_UP_TEXLERP_PACKED is defined, then 'vertex texlerp' is
// used for up faces if use_texlerp is 1. If STBVOX_CONFIG_DOWN_TEXLERP_PACKED
// is defined, then 'vertex texlerp' is used for down faces if use_texlerp is 1.
// Note if those symbols are defined but packed_compact is NULL, the normal
// texlerp default will be used.
// Encode with STBVOX_MAKE_PACKED_COMPACT(rot, vheight, texlerp, use_texlerp)
};
// @OPTIMIZE allow specializing; build a single struct with all of the
// 3D-indexed arrays combined so it's AoS instead of SoA for better
// cache efficiency
//////////////////////////////////////////////////////////////////////////////
//
// VHEIGHT DOCUMENTATION
//
// "vheight" is the internal name for the special block types
// with sloped tops or bottoms. "vheight" stands for "vertex height".
//
// Note that these blocks are very flexible (there are 256 of them,
// although at least 17 of them should never be used), but they
// also have a disadvantage that they generate extra invisible
// faces; the generator does not currently detect whether adjacent
// vheight blocks hide each others sides, so those side faces are
// always generated. For a continuous ground terrain, this means
// that you may generate 5x as many quads as needed. See notes
// on "improvements for shipping products" in the introduction.
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 for floor vheight (but not ceiling), and allows you to:
//
// (A) have 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 independence,
// but at the cost of the largest memory usage, 1 byte per 3D block.
// 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_EXT(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
{
STBVOX_TEXLERP_FACE_0,
STBVOX_TEXLERP_FACE_half,
STBVOX_TEXLERP_FACE_1,
STBVOX_TEXLERP_FACE_use_vert,
};
enum
{
STBVOX_TEXLERP_BASE_0, // 0.0
STBVOX_TEXLERP_BASE_2_7, // 2/7
STBVOX_TEXLERP_BASE_5_7, // 4/7
STBVOX_TEXLERP_BASE_1 // 1.0
};
enum
{
STBVOX_TEXLERP3_0_8,
STBVOX_TEXLERP3_1_8,
STBVOX_TEXLERP3_2_8,
STBVOX_TEXLERP3_3_8,
STBVOX_TEXLERP3_4_8,
STBVOX_TEXLERP3_5_8,
STBVOX_TEXLERP3_6_8,
STBVOX_TEXLERP3_7_8,
};
#define STBVOX_FACE_NONE 7
#define STBVOX_BLOCKTYPE_EMPTY 0
#ifdef STBVOX_BLOCKTYPE_SHORT
#define STBVOX_BLOCKTYPE_HOLE 65535
#else
#define STBVOX_BLOCKTYPE_HOLE 255
#endif
#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, 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))
#define STBVOX_MAKE_TEXLERP1(vert,e2,n2,w2,s2,u4,d2) STBVOX_MAKE_TEXLERP(s2, w2, d2, vert)
#define STBVOX_MAKE_TEXLERP2(vert,e2,n2,w2,s2,u4,d2) ((u2)*16 + (n2)*4 + (s2))
#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)
#define STBVOX_MAKE_PACKED_COMPACT(rot, vheight, texlerp, def) ((rot)+4*(vheight)+16*(use)+32*(texlerp))
#define STBVOX_MAKE_LIGHTING_EXT(lighting, rot) (((lighting)&~3)+(rot))
#define STBVOX_MAKE_LIGHTING(lighting) (lighting)
#ifndef STBVOX_MAX_MESHES
#define STBVOX_MAX_MESHES 2 // opaque & transparent
#endif
#define STBVOX_MAX_MESH_SLOTS 3 // one vertex & two faces, or two vertex and one face
// don't mess with this directly, it's just here so you can
// declare stbvox_mesh_maker on the stack or as a global
struct stbvox_mesh_maker
{
stbvox_input_description input;
int cur_x, cur_y, cur_z; // last unprocessed voxel if it splits into multiple buffers
int x0,y0,z0,x1,y1,z1;
int x_stride_in_bytes;
int y_stride_in_bytes;
int config_dirty;
int default_mesh;
unsigned int tags;
int cube_vertex_offset[6][4]; // this allows access per-vertex data stored block-centered (like texlerp, ambient)
int vertex_gather_offset[6][4];
int pos_x,pos_y,pos_z;
int full;
// computed from user input
char *output_cur [STBVOX_MAX_MESHES][STBVOX_MAX_MESH_SLOTS];
char *output_end [STBVOX_MAX_MESHES][STBVOX_MAX_MESH_SLOTS];
char *output_buffer[STBVOX_MAX_MESHES][STBVOX_MAX_MESH_SLOTS];
int output_len [STBVOX_MAX_MESHES][STBVOX_MAX_MESH_SLOTS];
// computed from config
int output_size [STBVOX_MAX_MESHES][STBVOX_MAX_MESH_SLOTS]; // per quad
int output_step [STBVOX_MAX_MESHES][STBVOX_MAX_MESH_SLOTS]; // per vertex or per face, depending
int num_mesh_slots;
float default_tex_scale[128][2];
};
#endif // INCLUDE_STB_VOXEL_RENDER_H
#ifdef STB_VOXEL_RENDER_IMPLEMENTATION
#include <stdlib.h>
#include <assert.h>
#include <string.h> // memset
// have to use our own names to avoid the _MSC_VER path having conflicting type names
#ifndef _MSC_VER
#include <stdint.h>
typedef uint16_t stbvox_uint16;
typedef uint32_t stbvox_uint32;
#else
typedef unsigned short stbvox_uint16;
typedef unsigned int stbvox_uint32;
#endif
#ifdef _MSC_VER
#define STBVOX_NOTUSED(v) (void)(v)
#else
#define STBVOX_NOTUSED(v) (void)sizeof(v)
#endif
#ifndef STBVOX_CONFIG_MODE
#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, and 21 are
// currently implemented. Reducing the storage-per-quad further
// shouldn't improve performance, although obviously it allow you
// to create larger worlds without streaming.
//
//
// ----------- Two textures ----------- -- One texture -- ---- Color only ----
// Mode: 0 1 2 3 4 5 6 10 11 12 20 21 22 23 24
// ============================================================================================================
// uses Tex Buffer n Y Y Y Y Y Y Y Y Y n Y Y Y Y
// bytes per quad 32 20 14 12 10 6 6 8 8 4 32 20 10 6 4
// non-blocks all all some some some slabs stairs some some none all all slabs slabs none
// tex1 256 256 256 256 256 256 256 256 256 256 n n n n n
// tex2 256 256 256 256 256 256 128 n n n n n n n n
// colors 64 64 64 64 64 64 64 8 n n 2^24 2^24 2^24 2^24 256
// vertex ao Y Y Y Y Y n n Y Y n Y Y Y n n
// vertex texlerp Y Y Y n n n n - - - - - - - -
// x&y extents 127 127 128 64 64 128 64 64 128 128 127 127 128 128 128
// z extents 255 255 128 64? 64? 64 64 32 64 128 255 255 128 64 128
// not sure why I only wrote down the above "result data" and didn't preserve
// the vertex formats, but here I've tried to reconstruct the designs...
// mode # 3 is wrong, one byte too large, but they may have been an error originally
// Mode: 0 1 2 3 4 5 6 10 11 12 20 21 22 23 24
// =============================================================================================================
// bytes per quad 32 20 14 12 10 6 6 8 8 4 20 10 6 4
//
// vertex x bits 7 7 0 6 0 0 0 0 0 0 7 0 0 0
// vertex y bits 7 7 0 0 0 0 0 0 0 0 7 0 0 0
// vertex z bits 9 9 7 4 2 0 0 2 2 0 9 2 0 0
// vertex ao bits 6 6 6 6 6 0 0 6 6 0 6 6 0 0
// vertex txl bits 3 3 3 0 0 0 0 0 0 0 (3) 0 0 0
//
// face tex1 bits (8) 8 8 8 8 8 8 8 8 8
// face tex2 bits (8) 8 8 8 8 8 7 - - -
// face color bits (8) 8 8 8 8 8 8 3 0 0 24 24 24 8
// face normal bits (8) 8 8 8 6 4 7 4 4 3 8 3 4 3
// face x bits 7 0 6 7 6 6 7 7 0 7 7 7
// face y bits 7 6 6 7 6 6 7 7 0 7 7 7
// face z bits 2 2 6 6 6 5 6 7 0 7 6 7
#if STBVOX_CONFIG_MODE==0 || STBVOX_CONFIG_MODE==1
#define STBVOX_ICONFIG_VERTEX_32
#define STBVOX_ICONFIG_FACE1_1
#elif STBVOX_CONFIG_MODE==20 || STBVOX_CONFIG_MODE==21
#define STBVOX_ICONFIG_VERTEX_32
#define STBVOX_ICONFIG_FACE1_1
#define STBVOX_ICONFIG_UNTEXTURED
#else
#error "Selected value of STBVOX_CONFIG_MODE is not supported"
#endif
#if STBVOX_CONFIG_MODE==0 || STBVOX_CONFIG_MODE==20
#define STBVOX_ICONFIG_FACE_ATTRIBUTE
#endif
#ifndef STBVOX_CONFIG_HLSL
// the fallback if all others are exhausted is GLSL
#define STBVOX_ICONFIG_GLSL
#endif
#ifdef STBVOX_CONFIG_OPENGL_MODELVIEW
#define STBVOX_ICONFIG_OPENGL_3_1_COMPATIBILITY
#endif
#if defined(STBVOX_ICONFIG_VERTEX_32)
typedef stbvox_uint32 stbvox_mesh_vertex;
#define stbvox_vertex_encode(x,y,z,ao,texlerp) \
((stbvox_uint32) ((x)+((y)<<7)+((z)<<14)+((ao)<<23)+((texlerp)<<29)))
#elif defined(STBVOX_ICONFIG_VERTEX_16_1) // mode=2
typedef stbvox_uint16 stbvox_mesh_vertex;
#define stbvox_vertex_encode(x,y,z,ao,texlerp) \
((stbvox_uint16) ((z)+((ao)<<7)+((texlerp)<<13)
#elif defined(STBVOX_ICONFIG_VERTEX_16_2) // mode=3
typedef stbvox_uint16 stbvox_mesh_vertex;
#define stbvox_vertex_encode(x,y,z,ao,texlerp) \
((stbvox_uint16) ((x)+((z)<<6))+((ao)<<10))
#elif defined(STBVOX_ICONFIG_VERTEX_8)
typedef stbvox_uint8 stbvox_mesh_vertex;
#define stbvox_vertex_encode(x,y,z,ao,texlerp) \
((stbvox_uint8) ((z)+((ao)<<6))
#else
#error "internal error, no vertex type"
#endif
#ifdef STBVOX_ICONFIG_FACE1_1
typedef struct
{
unsigned char tex1,tex2,color,face_info;
} stbvox_mesh_face;
#else
#error "internal error, no face type"
#endif
// 20-byte quad format:
//
// per vertex:
//
// x:7
// y:7
// z:9
// ao:6
// tex_lerp:3
//
// per face:
//
// tex1:8
// tex2:8
// face:8
// color:8
// Faces:
//
// Faces use the bottom 3 bits to choose the texgen
// mode, and all the bits to choose the normal.
// Thus the bottom 3 bits have to be:
// e, n, w, s, u, d, u, d
//
// These use compact names so tables are readable
enum
{
STBVF_e,
STBVF_n,
STBVF_w,
STBVF_s,
STBVF_u,
STBVF_d,
STBVF_eu,
STBVF_ed,
STBVF_eu_wall,
STBVF_nu_wall,
STBVF_wu_wall,
STBVF_su_wall,
STBVF_ne_u,
STBVF_ne_d,
STBVF_nu,
STBVF_nd,
STBVF_ed_wall,
STBVF_nd_wall,
STBVF_wd_wall,
STBVF_sd_wall,
STBVF_nw_u,
STBVF_nw_d,
STBVF_wu,
STBVF_wd,
STBVF_ne_u_cross,
STBVF_nw_u_cross,
STBVF_sw_u_cross,
STBVF_se_u_cross,
STBVF_sw_u,
STBVF_sw_d,
STBVF_su,
STBVF_sd,
// @TODO we need more than 5 bits to encode the normal to fit the following
// so for now we use the right projection but the wrong normal
STBVF_se_u = STBVF_su,
STBVF_se_d = STBVF_sd,
STBVF_count,
};
/////////////////////////////////////////////////////////////////////////////
//
// 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] =
{
{ 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/1000.0f }, // fog data for simple_fog
};
static float stbvox_default_palette[64][4];
static void stbvox_build_default_palette(void)
{
int i;
for (i=0; i < 64; ++i) {
stbvox_default_palette[i][0] = stbvox_default_palette_compact[i][0] / 255.0f;
stbvox_default_palette[i][1] = stbvox_default_palette_compact[i][1] / 255.0f;
stbvox_default_palette[i][2] = stbvox_default_palette_compact[i][2] / 255.0f;
stbvox_default_palette[i][3] = 1.0f;
}
}
//////////////////////////////////////////////////////////////////////////////
//
// Shaders
//
#if defined(STBVOX_ICONFIG_OPENGL_3_1_COMPATIBILITY)
#define STBVOX_SHADER_VERSION "#version 150 compatibility\n"
#elif defined(STBVOX_ICONFIG_OPENGL_3_0)
#define STBVOX_SHADER_VERSION "#version 130\n"
#elif defined(STBVOX_ICONFIG_GLSL)
#define STBVOX_SHADER_VERSION "#version 150\n"
#else
#define STBVOX_SHADER_VERSION ""
#endif
static const char *stbvox_vertex_program =
{
STBVOX_SHADER_VERSION
#ifdef STBVOX_ICONFIG_FACE_ATTRIBUTE // NOT TAG_face_sampled
"in uvec4 attr_face;\n"
#else
"uniform usamplerBuffer facearray;\n"
#endif
#ifdef STBVOX_ICONFIG_FACE_ARRAY_2
"uniform usamplerBuffer facearray2;\n"
#endif
// vertex input data
"in uint attr_vertex;\n"
// per-buffer data
"uniform vec3 transform[3];\n"
// per-frame data
"uniform vec4 camera_pos;\n" // 4th value is used for arbitrary hacking
// to simplify things, we avoid using more than 256 uniform vectors
// in fragment shader to avoid possible 1024 component limit, so
// we access this table in the fragment shader.
"uniform vec3 normal_table[32];\n"
#ifndef STBVOX_CONFIG_OPENGL_MODELVIEW
"uniform mat4x4 model_view;\n"
#endif
// fragment output data
"flat out uvec4 facedata;\n"
" out vec3 voxelspace_pos;\n"
" out vec3 vnormal;\n"
" out float texlerp;\n"
" out float amb_occ;\n"
// @TODO handle the HLSL way to do this
"void main()\n"
"{\n"
#ifdef STBVOX_ICONFIG_FACE_ATTRIBUTE
" facedata = attr_face;\n"
#else
" int faceID = gl_VertexID >> 2;\n"
" facedata = texelFetch(facearray, faceID);\n"
#endif
// extract data for vertex
" vec3 offset;\n"
" offset.x = float( (attr_vertex ) & 127u );\n" // a[0..6]
" offset.y = float( (attr_vertex >> 7u) & 127u );\n" // a[7..13]
" offset.z = float( (attr_vertex >> 14u) & 511u );\n" // a[14..22]
" 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>>2u) & 31u];\n"
" voxelspace_pos = offset * transform[0];\n" // mesh-to-object scale
" vec3 position = voxelspace_pos + transform[1];\n" // mesh-to-object translate
#ifdef STBVOX_DEBUG_TEST_NORMALS
" if ((facedata.w & 28u) == 16u || (facedata.w & 28u) == 24u)\n"
" position += vnormal.xyz * camera_pos.w;\n"
#endif
#ifndef STBVOX_CONFIG_OPENGL_MODELVIEW
" gl_Position = model_view * vec4(position,1.0);\n"
#else
" gl_Position = gl_ModelViewProjectionMatrix * vec4(position,1.0);\n"
#endif
"}\n"
};
static const char *stbvox_fragment_program =
{
STBVOX_SHADER_VERSION
// rlerp is lerp but with t on the left, like god intended
#if defined(STBVOX_ICONFIG_GLSL)
"#define rlerp(t,x,y) mix(x,y,t)\n"
#elif defined(STBVOX_CONFIG_HLSL)
"#define rlerp(t,x,y) lerp(x,y,t)\n"
#else
#error "need definition of rlerp()"
#endif
// vertex-shader output data
"flat in uvec4 facedata;\n"
" in vec3 voxelspace_pos;\n"
" in vec3 vnormal;\n"
" in float texlerp;\n"
" in float amb_occ;\n"
// per-buffer data
"uniform vec3 transform[3];\n"
// per-frame data
"uniform vec4 camera_pos;\n" // 4th value is used for arbitrary hacking
// probably constant data
"uniform vec4 ambient[4];\n"
#ifndef STBVOX_ICONFIG_UNTEXTURED
// generally constant data
"uniform sampler2DArray tex_array[2];\n"
#ifdef STBVOX_CONFIG_PREFER_TEXBUFFER
"uniform samplerBuffer color_table;\n"
"uniform samplerBuffer texscale;\n"
"uniform samplerBuffer texgen;\n"
#else
"uniform vec4 color_table[64];\n"
"uniform vec4 texscale[64];\n" // instead of 128, to avoid running out of uniforms
"uniform vec3 texgen[64];\n"
#endif
#endif
"out vec4 outcolor;\n"
#if defined(STBVOX_CONFIG_LIGHTING) || defined(STBVOX_CONFIG_LIGHTING_SIMPLE)
"vec3 compute_lighting(vec3 pos, vec3 norm, vec3 albedo, vec3 ambient);\n"
#endif
#if defined(STBVOX_CONFIG_FOG) || defined(STBVOX_CONFIG_FOG_SMOOTHSTEP)
"vec3 compute_fog(vec3 color, vec3 relative_pos, float fragment_alpha);\n"
#endif
"void main()\n"
"{\n"
" vec3 albedo;\n"
" float fragment_alpha;\n"
#ifndef STBVOX_ICONFIG_UNTEXTURED
// unpack the values
" uint tex1_id = facedata.x;\n"
" uint tex2_id = facedata.y;\n"
" uint texprojid = facedata.w & 31u;\n"
" uint color_id = facedata.z;\n"
#ifndef STBVOX_CONFIG_PREFER_TEXBUFFER
// load from uniforms / texture buffers
" vec3 texgen_s = texgen[texprojid];\n"
" vec3 texgen_t = texgen[texprojid+32u];\n"
" float tex1_scale = texscale[tex1_id & 63u].x;\n"
" vec4 color = color_table[color_id & 63u];\n"
#ifndef STBVOX_CONFIG_DISABLE_TEX2
" vec4 tex2_props = texscale[tex2_id & 63u];\n"
#endif
#else
" vec3 texgen_s = texelFetch(texgen, int(texprojid)).xyz;\n"
" vec3 texgen_t = texelFetch(texgen, int(texprojid+32u)).xyz;\n"
" float tex1_scale = texelFetch(texscale, int(tex1_id & 127u)).x;\n"
" vec4 color = texelFetch(color_table, int(color_id & 63u));\n"
#ifndef STBVOX_CONFIG_DISABLE_TEX2
" vec4 tex2_props = texelFetch(texscale, int(tex1_id & 127u));