comments updated
[henge/apc.git] / stb / stb_voxel_render.h
1 // stb_voxel_render.h - v0.84 - Sean Barrett, 2015 - public domain
2 //
3 // This library helps render large-scale "voxel" worlds for games,
4 // in this case, one with blocks that can have textures and that
5 // can also be a few shapes other than cubes.
6 //
7 // Video introduction:
8 // http://www.youtube.com/watch?v=2vnTtiLrV1w
9 //
10 // Minecraft-viewer sample app (not very simple though):
11 // http://github.com/nothings/stb/tree/master/tests/caveview
12 //
13 // It works by creating triangle meshes. The library includes
14 //
15 // - converter from dense 3D arrays of block info to vertex mesh
16 // - shader for the vertex mesh
17 // - assistance in setting up shader state
18 //
19 // For portability, none of the library code actually accesses
20 // the 3D graphics API. (At the moment, it's not actually portable
21 // since the shaders are GLSL only, but patches are welcome.)
22 //
23 // You have to do all the caching and tracking of vertex buffers
24 // yourself. However, you could also try making a game with
25 // a small enough world that it's fully loaded rather than
26 // streaming. Currently the preferred vertex format is 20 bytes
27 // per quad. There are plans to allow much more compact formats
28 // with a slight reduction in shader features.
29 //
30 //
31 // USAGE
32 //
33 // #define the symbol STB_VOXEL_RENDER_IMPLEMENTATION in *one*
34 // C/C++ file before the #include of this file; the implementation
35 // will be generated in that file.
36 //
37 // If you define the symbols STB_VOXEL_RENDER_STATIC, then the
38 // implementation will be private to that file.
39 //
40 //
41 // FEATURES
42 //
43 // - you can choose textured blocks with the features below,
44 // or colored voxels with 2^24 colors and no textures.
45 //
46 // - voxels are mostly just cubes, but there's support for
47 // half-height cubes and diagonal slopes, half-height
48 // diagonals, and even odder shapes especially for doing
49 // more-continuous "ground".
50 //
51 // - texture coordinates are projections along one of the major
52 // axes, with the per-texture scaling.
53 //
54 // - a number of aspects of the shader and the vertex format
55 // are configurable; the library generally takes care of
56 // coordinating the vertex format with the mesh for you.
57 //
58 //
59 // FEATURES (SHADER PERSPECTIVE)
60 //
61 // - vertices aligned on integer lattice, z on multiples of 0.5
62 // - per-vertex "lighting" or "ambient occlusion" value (6 bits)
63 // - per-vertex texture crossfade (3 bits)
64 //
65 // - per-face texture #1 id (8-bit index into array texture)
66 // - per-face texture #2 id (8-bit index into second array texture)
67 // - per-face color (6-bit palette index, 2 bits of per-texture boolean enable)
68 // - per-face 5-bit normal for lighting calculations & texture coord computation
69 // - per-face 2-bit texture matrix rotation to rotate faces
70 //
71 // - indexed-by-texture-id scale factor (separate for texture #1 and texture #2)
72 // - indexed-by-texture-#2-id blend mode (alpha composite or modulate/multiply);
73 // the first is good for decals, the second for detail textures, "light maps",
74 // etc; both modes are controlled by texture #2's alpha, scaled by the
75 // per-vertex texture crossfade and the per-face color (if enabled on texture #2);
76 // modulate/multiply multiplies by an extra factor of 2.0 so that if you
77 // make detail maps whose average brightness is 0.5 everything works nicely.
78 //
79 // - ambient lighting: half-lambert directional plus constant, all scaled by vertex ao
80 // - face can be fullbright (emissive), controlled by per-face color
81 // - installable lighting, with default single-point-light
82 // - installable fog, with default hacked smoothstep
83 //
84 // Note that all the variations of lighting selection and texture
85 // blending are run-time conditions in the shader, so they can be
86 // intermixed in a single mesh.
87 //
88 //
89 // INTEGRATION ARC
90 //
91 // The way to get this library to work from scratch is to do the following:
92 //
93 // Step 1. define STBVOX_CONFIG_MODE to 0
94 //
95 // This mode uses only vertex attributes and uniforms, and is easiest
96 // to get working. It requires 32 bytes per quad and limits the
97 // size of some tables to avoid hitting uniform limits.
98 //
99 // Step 2. define STBVOX_CONFIG_MODE to 1
100 //
101 // This requires using a texture buffer to store the quad data,
102 // reducing the size to 20 bytes per quad.
103 //
104 // Step 3: define STBVOX_CONFIG_PREFER_TEXBUFFER
105 //
106 // This causes some uniforms to be stored as texture buffers
107 // instead. This increases the size of some of those tables,
108 // and avoids a potential slow path (gathering non-uniform
109 // data from uniforms) on some hardware.
110 //
111 // In the future I hope to add additional modes that have significantly
112 // smaller meshes but reduce features, down as small as 6 bytes per quad.
113 // See elsewhere in this file for a table of candidate modes. Switching
114 // to a mode will require changing some of your mesh creation code, but
115 // everything else should be seamless. (And I'd like to change the API
116 // so that mesh creation is data-driven the way the uniforms are, and
117 // then you wouldn't even have to change anything but the mode number.)
118 //
119 //
120 // IMPROVEMENTS FOR SHIP-WORTHY PROGRAMS USING THIS LIBRARY
121 //
122 // I currently tolerate a certain level of "bugginess" in this library.
123 //
124 // I'm referring to things which look a little wrong (as long as they
125 // don't cause holes or cracks in the output meshes), or things which
126 // do not produce as optimal a mesh as possible. Notable examples:
127 //
128 // - incorrect lighting on slopes
129 // - inefficient meshes for vheight blocks
130 //
131 // I am willing to do the work to improve these things if someone is
132 // going to ship a substantial program that would be improved by them.
133 // (It need not be commercial, nor need it be a game.) I just didn't
134 // want to do the work up front if it might never be leveraged. So just
135 // submit a bug report as usual (github is preferred), but add a note
136 // that this is for a thing that is really going to ship. (That means
137 // you need to be far enough into the project that it's clear you're
138 // committed to it; not during early exploratory development.)
139 //
140 //
141 // VOXEL MESH API
142 //
143 // Context
144 //
145 // To understand the API, make sure you first understand the feature set
146 // listed above.
147 //
148 // Because the vertices are compact, they have very limited spatial
149 // precision. Thus a single mesh can only contain the data for a limited
150 // area. To make very large voxel maps, you'll need to build multiple
151 // vertex buffers. (But you want this anyway for frustum culling.)
152 //
153 // Each generated mesh has three components:
154 // - vertex data (vertex buffer)
155 // - face data (optional, stored in texture buffer)
156 // - mesh transform (uniforms)
157 //
158 // Once you've generated the mesh with this library, it's up to you
159 // to upload it to the GPU, to keep track of the state, and to render
160 // it.
161 //
162 // Concept
163 //
164 // The basic design is that you pass in one or more 3D arrays; each array
165 // is (typically) one-byte-per-voxel and contains information about one
166 // or more properties of some particular voxel property.
167 //
168 // Because there is so much per-vertex and per-face data possible
169 // in the output, and each voxel can have 6 faces and 8 vertices, it
170 // would require an very large data structure to describe all
171 // of the possibilities, and this would cause the mesh-creation
172 // process to be slow. Instead, the API provides multiple ways
173 // to express each property, some more compact, others less so;
174 // each such way has some limitations on what it can express.
175 //
176 // Note that there are so many paths and combinations, not all of them
177 // have been tested. Just report bugs and I'll fix 'em.
178 //
179 // Details
180 //
181 // See the API documentation in the header-file section.
182 //
183 //
184 // CONTRIBUTORS
185 //
186 // Features Porting Bugfixes & Warnings
187 // Sean Barrett github:r-leyh Jesus Fernandez
188 // Miguel Lechon github:Arbeiterunfallversicherungsgesetz
189 // Thomas Frase James Hofmann
190 // Stephen Olsen
191 //
192 // VERSION HISTORY
193 //
194 // 0.84 (2016-04-02) fix GLSL syntax error on glModelView path
195 // 0.83 (2015-09-13) remove non-constant struct initializers to support more compilers
196 // 0.82 (2015-08-01) added input.packed_compact to store rot, vheight & texlerp efficiently
197 // fix broken tex_overlay2
198 // 0.81 (2015-05-28) fix broken STBVOX_CONFIG_OPTIMIZED_VHEIGHT
199 // 0.80 (2015-04-11) fix broken STBVOX_CONFIG_ROTATION_IN_LIGHTING refactoring
200 // change STBVOX_MAKE_LIGHTING to STBVOX_MAKE_LIGHTING_EXT so
201 // that header defs don't need to see config vars
202 // add STBVOX_CONFIG_VHEIGHT_IN_LIGHTING and other vheight fixes
203 // added documentation for vheight ("weird slopes")
204 // 0.79 (2015-04-01) fix the missing types from 0.78; fix string constants being const
205 // 0.78 (2015-04-02) bad "#else", compile as C++
206 // 0.77 (2015-04-01) documentation tweaks, rename config var to STB_VOXEL_RENDER_STATIC
207 // 0.76 (2015-04-01) typos, signed/unsigned shader issue, more documentation
208 // 0.75 (2015-04-01) initial release
209 //
210 //
211 // HISTORICAL FOUNDATION
212 //
213 // stb_voxel_render 20-byte quads 2015/01
214 // zmc engine 32-byte quads 2013/12
215 // zmc engine 96-byte quads 2011/10
216 //
217 //
218 // LICENSE
219 //
220 // This software is dual-licensed to the public domain and under the following
221 // license: you are granted a perpetual, irrevocable license to copy, modify,
222 // publish, and distribute this file as you see fit.
223
224 #ifndef INCLUDE_STB_VOXEL_RENDER_H
225 #define INCLUDE_STB_VOXEL_RENDER_H
226
227 #include <stdlib.h>
228
229 typedef struct stbvox_mesh_maker stbvox_mesh_maker;
230 typedef struct stbvox_input_description stbvox_input_description;
231
232 #ifdef STB_VOXEL_RENDER_STATIC
233 #define STBVXDEC static
234 #else
235 #define STBVXDEC extern
236 #endif
237
238 #ifdef __cplusplus
239 extern "C" {
240 #endif
241
242 //////////////////////////////////////////////////////////////////////////////
243 //
244 // CONFIGURATION MACROS
245 //
246 // #define STBVOX_CONFIG_MODE <integer> // REQUIRED
247 // Configures the overall behavior of stb_voxel_render. This
248 // can affect the shaders, the uniform info, and other things.
249 // (If you need more than one mode in the same app, you can
250 // use STB_VOXEL_RENDER_STATIC to create multiple versions
251 // in separate files, and then wrap them.)
252 //
253 // Mode value Meaning
254 // 0 Textured blocks, 32-byte quads
255 // 1 Textured blocks, 20-byte quads
256 // 20 Untextured blocks, 32-byte quads
257 // 21 Untextured blocks, 20-byte quads
258 //
259 //
260 // #define STBVOX_CONFIG_PRECISION_Z <integer> // OPTIONAL
261 // Defines the number of bits of fractional position for Z.
262 // Only 0 or 1 are valid. 1 is the default. If 0, then a
263 // single mesh has twice the legal Z range; e.g. in
264 // modes 0,1,20,21, Z in the mesh can extend to 511 instead
265 // of 255. However, half-height blocks cannot be used.
266 //
267 // All of the following just #ifdef tested so need no values, and are optional.
268 //
269 // STBVOX_CONFIG_BLOCKTYPE_SHORT
270 // use unsigned 16-bit values for 'blocktype' in the input instead of 8-bit values
271 //
272 // STBVOX_CONFIG_OPENGL_MODELVIEW
273 // use the gl_ModelView matrix rather than the explicit uniform
274 //
275 // STBVOX_CONFIG_HLSL
276 // NOT IMPLEMENTED! Define HLSL shaders instead of GLSL shaders
277 //
278 // STBVOX_CONFIG_PREFER_TEXBUFFER
279 // Stores many of the uniform arrays in texture buffers intead,
280 // so they can be larger and may be more efficient on some hardware.
281 //
282 // STBVOX_CONFIG_LIGHTING_SIMPLE
283 // Creates a simple lighting engine with a single point light source
284 // in addition to the default half-lambert ambient light.
285 //
286 // STBVOX_CONFIG_LIGHTING
287 // Declares a lighting function hook; you must append a lighting function
288 // to the shader before compiling it:
289 // vec3 compute_lighting(vec3 pos, vec3 norm, vec3 albedo, vec3 ambient);
290 // 'ambient' is the half-lambert ambient light with vertex ambient-occlusion applied
291 //
292 // STBVOX_CONFIG_FOG_SMOOTHSTEP
293 // Defines a simple unrealistic fog system designed to maximize
294 // unobscured view distance while not looking too weird when things
295 // emerge from the fog. Configured using an extra array element
296 // in the STBVOX_UNIFORM_ambient uniform.
297 //
298 // STBVOX_CONFIG_FOG
299 // Defines a fog function hook; you must append a fog function to
300 // the shader before compiling it:
301 // vec3 compute_fog(vec3 color, vec3 relative_pos, float fragment_alpha);
302 // "color" is the incoming pre-fogged color, fragment_alpha is the alpha value,
303 // and relative_pos is the vector from the point to the camera in worldspace
304 //
305 // STBVOX_CONFIG_DISABLE_TEX2
306 // This disables all processing of texture 2 in the shader in case
307 // you don't use it. Eventually this will be replaced with a mode
308 // that omits the unused data entirely.
309 //
310 // STBVOX_CONFIG_TEX1_EDGE_CLAMP
311 // STBVOX_CONFIG_TEX2_EDGE_CLAMP
312 // If you want to edge clamp the textures, instead of letting them wrap,
313 // set this flag. By default stb_voxel_render relies on texture wrapping
314 // to simplify texture coordinate generation. This flag forces it to do
315 // it correctly, although there can still be minor artifacts.
316 //
317 // STBVOX_CONFIG_ROTATION_IN_LIGHTING
318 // Changes the meaning of the 'lighting' mesher input variable to also
319 // store the rotation; see later discussion.
320 //
321 // STBVOX_CONFIG_VHEIGHT_IN_LIGHTING
322 // Changes the meaning of the 'lighting' mesher input variable to also
323 // store the vheight; see later discussion. Cannot use both this and
324 // the previous variable.
325 //
326 // STBVOX_CONFIG_PREMULTIPLIED_ALPHA
327 // Adjusts the shader calculations on the assumption that tex1.rgba,
328 // tex2.rgba, and color.rgba all use premultiplied values, and that
329 // the output of the fragment shader should be premultiplied.
330 //
331 // STBVOX_CONFIG_UNPREMULTIPLY
332 // Only meaningful if STBVOX_CONFIG_PREMULTIPLIED_ALPHA is defined.
333 // Changes the behavior described above so that the inputs are
334 // still premultiplied alpha, but the output of the fragment
335 // shader is not premultiplied alpha. This is needed when allowing
336 // non-unit alpha values but not doing alpha-blending (for example
337 // when alpha testing).
338 //
339
340 //////////////////////////////////////////////////////////////////////////////
341 //
342 // MESHING
343 //
344 // A mesh represents a (typically) small chunk of a larger world.
345 // Meshes encode coordinates using small integers, so those
346 // coordinates must be relative to some base location.
347 // All of the coordinates in the functions below use
348 // these relative coordinates unless explicitly stated
349 // otherwise.
350 //
351 // Input to the meshing step is documented further down
352
353 STBVXDEC void stbvox_init_mesh_maker(stbvox_mesh_maker *mm);
354 // Call this function to initialize a mesh-maker context structure
355 // used to build meshes. You should have one context per thread
356 // that's building meshes.
357
358 STBVXDEC void stbvox_set_buffer(stbvox_mesh_maker *mm, int mesh, int slot, void *buffer, size_t len);
359 // Call this to set the buffer into which stbvox will write the mesh
360 // it creates. It can build more than one mesh in parallel (distinguished
361 // by the 'mesh' parameter), and each mesh can be made up of more than
362 // one buffer (distinguished by the 'slot' parameter).
363 //
364 // Multiple meshes are under your control; use the 'selector' input
365 // variable to choose which mesh each voxel's vertices are written to.
366 // For example, you can use this to generate separate meshes for opaque
367 // and transparent data.
368 //
369 // You can query the number of slots by calling stbvox_get_buffer_count
370 // described below. The meaning of the buffer for each slot depends
371 // on STBVOX_CONFIG_MODE.
372 //
373 // In mode 0 & mode 20, there is only one slot. The mesh data for that
374 // slot is two interleaved vertex attributes: attr_vertex, a single
375 // 32-bit uint, and attr_face, a single 32-bit uint.
376 //
377 // In mode 1 & mode 21, there are two slots. The first buffer should
378 // be four times as large as the second buffer. The first buffer
379 // contains a single vertex attribute: 'attr_vertex', a single 32-bit uint.
380 // The second buffer contains texture buffer data (an array of 32-bit uints)
381 // that will be accessed through the sampler identified by STBVOX_UNIFORM_face_data.
382
383 STBVXDEC int stbvox_get_buffer_count(stbvox_mesh_maker *mm);
384 // Returns the number of buffers needed per mesh as described above.
385
386 STBVXDEC int stbvox_get_buffer_size_per_quad(stbvox_mesh_maker *mm, int slot);
387 // Returns how much of a given buffer will get used per quad. This
388 // allows you to choose correct relative sizes for each buffer, although
389 // the values are fixed based on the configuration you've selected at
390 // compile time, and the details are described in stbvox_set_buffer.
391
392 STBVXDEC void stbvox_set_default_mesh(stbvox_mesh_maker *mm, int mesh);
393 // Selects which mesh the mesher will output to (see previous function)
394 // if the input doesn't specify a per-voxel selector. (I doubt this is
395 // useful, but it's here just in case.)
396
397 STBVXDEC stbvox_input_description *stbvox_get_input_description(stbvox_mesh_maker *mm);
398 // This function call returns a pointer to the stbvox_input_description part
399 // of stbvox_mesh_maker (which you should otherwise treat as opaque). You
400 // zero this structure, then fill out the relevant pointers to the data
401 // describing your voxel object/world.
402 //
403 // See further documentation at the description of stbvox_input_description below.
404
405 STBVXDEC void stbvox_set_input_stride(stbvox_mesh_maker *mm, int x_stride_in_elements, int y_stride_in_elements);
406 // This sets the stride between successive elements of the 3D arrays
407 // in the stbvox_input_description. Z values are always stored consecutively.
408 // (The preferred coordinate system for stbvox is X right, Y forwards, Z up.)
409
410 STBVXDEC void stbvox_set_input_range(stbvox_mesh_maker *mm, int x0, int y0, int z0, int x1, int y1, int z1);
411 // This sets the range of values in the 3D array for the voxels that
412 // the mesh generator will convert. The lower values are inclusive,
413 // the higher values are exclusive, so (0,0,0) to (16,16,16) generates
414 // mesh data associated with voxels up to (15,15,15) but no higher.
415 //
416 // The mesh generate generates faces at the boundary between open space
417 // and solid space but associates them with the solid space, so if (15,0,0)
418 // is open and (16,0,0) is solid, then the mesh will contain the boundary
419 // between them if x0 <= 16 and x1 > 16.
420 //
421 // Note that the mesh generator will access array elements 1 beyond the
422 // limits set in these parameters. For example, if you set the limits
423 // to be (0,0,0) and (16,16,16), then the generator will access all of
424 // the voxels between (-1,-1,-1) and (16,16,16), including (16,16,16).
425 // You may have to do pointer arithmetic to make it work.
426 //
427 // For example, caveview processes mesh chunks that are 32x32x16, but it
428 // does this using input buffers that are 34x34x18.
429 //
430 // The lower limits are x0 >= 0, y0 >= 0, and z0 >= 0.
431 //
432 // The upper limits are mode dependent, but all the current methods are
433 // limited to x1 < 127, y1 < 127, z1 < 255. Note that these are not
434 // powers of two; if you want to use power-of-two chunks (to make
435 // it efficient to decide which chunk a coordinate falls in), you're
436 // limited to at most x1=64, y1=64, z1=128. For classic Minecraft-style
437 // worlds with limited vertical extent, I recommend using a single
438 // chunk for the entire height, which limits the height to 255 blocks
439 // (one less than Minecraft), and only chunk the map in X & Y.
440
441 STBVXDEC int stbvox_make_mesh(stbvox_mesh_maker *mm);
442 // Call this function to create mesh data for the currently configured
443 // set of input data. This appends to the currently configured mesh output
444 // buffer. Returns 1 on success. If there is not enough room in the buffer,
445 // it outputs as much as it can, and returns 0; you need to switch output
446 // buffers (either by calling stbvox_set_buffer to set new buffers, or
447 // by copying the data out and calling stbvox_reset_buffers), and then
448 // call this function again without changing any of the input parameters.
449 //
450 // Note that this function appends; you can call it multiple times to
451 // build a single mesh. For example, caveview uses chunks that are
452 // 32x32x255, but builds the mesh for it by processing 32x32x16 at atime
453 // (this is faster as it is reuses the same 34x34x18 input buffers rather
454 // than needing 34x34x257 input buffers).
455
456 // Once you're done creating a mesh into a given buffer,
457 // consider the following functions:
458
459 STBVXDEC int stbvox_get_quad_count(stbvox_mesh_maker *mm, int mesh);
460 // Returns the number of quads in the mesh currently generated by mm.
461 // This is the sum of all consecutive stbvox_make_mesh runs appending
462 // to the same buffer. 'mesh' distinguishes between the multiple user
463 // meshes available via 'selector' or stbvox_set_default_mesh.
464 //
465 // Typically you use this function when you're done building the mesh
466 // and want to record how to draw it.
467 //
468 // Note that there are no index buffers; the data stored in the buffers
469 // should be drawn as quads (e.g. with GL_QUAD); if your API does not
470 // support quads, you can create a single index buffer large enough to
471 // draw your largest vertex buffer, and reuse it for every rendering.
472 // (Note that if you use 32-bit indices, you'll use 24 bytes of bandwidth
473 // per quad, more than the 20 bytes for the vertex/face mesh data.)
474
475 STBVXDEC void stbvox_set_mesh_coordinates(stbvox_mesh_maker *mm, int x, int y, int z);
476 // Sets the global coordinates for this chunk, such that (0,0,0) relative
477 // coordinates will be at (x,y,z) in global coordinates.
478
479 STBVXDEC void stbvox_get_bounds(stbvox_mesh_maker *mm, float bounds[2][3]);
480 // Returns the bounds for the mesh in global coordinates. Use this
481 // for e.g. frustum culling the mesh. @BUG: this just uses the
482 // values from stbvox_set_input_range(), so if you build by
483 // appending multiple values, this will be wrong, and you need to
484 // set stbvox_set_input_range() to the full size. Someday this
485 // will switch to tracking the actual bounds of the *mesh*, though.
486
487 STBVXDEC void stbvox_get_transform(stbvox_mesh_maker *mm, float transform[3][3]);
488 // Returns the 'transform' data for the shader uniforms. It is your
489 // job to set this to the shader before drawing the mesh. It is the
490 // only uniform that needs to change per-mesh. Note that it is not
491 // a 3x3 matrix, but rather a scale to decode fixed point numbers as
492 // floats, a translate from relative to global space, and a special
493 // translation for texture coordinate generation that avoids
494 // floating-point precision issues. @TODO: currently we add the
495 // global translation to the vertex, than multiply by modelview,
496 // but this means if camera location and vertex are far from the
497 // origin, we lose precision. Need to make a special modelview with
498 // the translation (or some of it) factored out to avoid this.
499
500 STBVXDEC void stbvox_reset_buffers(stbvox_mesh_maker *mm);
501 // Call this function if you're done with the current output buffer
502 // but want to reuse it (e.g. you're done appending with
503 // stbvox_make_mesh and you've copied the data out to your graphics API
504 // so can reuse the buffer).
505
506 //////////////////////////////////////////////////////////////////////////////
507 //
508 // RENDERING
509 //
510
511 STBVXDEC char *stbvox_get_vertex_shader(void);
512 // Returns the (currently GLSL-only) vertex shader.
513
514 STBVXDEC char *stbvox_get_fragment_shader(void);
515 // Returns the (currently GLSL-only) fragment shader.
516 // You can override the lighting and fogging calculations
517 // by appending data to the end of these; see the #define
518 // documentation for more information.
519
520 STBVXDEC char *stbvox_get_fragment_shader_alpha_only(void);
521 // Returns a slightly cheaper fragment shader that computes
522 // alpha but not color. This is useful for e.g. a depth-only
523 // pass when using alpha test.
524
525 typedef struct stbvox_uniform_info stbvox_uniform_info;
526
527 STBVXDEC int stbvox_get_uniform_info(stbvox_uniform_info *info, int uniform);
528 // Gets the information about a uniform necessary for you to
529 // set up each uniform with a minimal amount of explicit code.
530 // See the sample code after the structure definition for stbvox_uniform_info,
531 // further down in this header section.
532 //
533 // "uniform" is from the list immediately following. For many
534 // of these, default values are provided which you can set.
535 // Most values are shared for most draw calls; e.g. for stateful
536 // APIs you can set most of the state only once. Only
537 // STBVOX_UNIFORM_transform needs to change per draw call.
538 //
539 // STBVOX_UNIFORM_texscale
540 // 64- or 128-long vec4 array. (128 only if STBVOX_CONFIG_PREFER_TEXBUFFER)
541 // x: scale factor to apply to texture #1. must be a power of two. 1.0 means 'face-sized'
542 // y: scale factor to apply to texture #2. must be a power of two. 1.0 means 'face-sized'
543 // z: blend mode indexed by texture #2. 0.0 is alpha compositing; 1.0 is multiplication.
544 // w: unused currently. @TODO use to support texture animation?
545 //
546 // Texscale is indexed by the bottom 6 or 7 bits of the texture id; thus for
547 // example the texture at index 0 in the array and the texture in index 128 of
548 // the array must be scaled the same. This means that if you only have 64 or 128
549 // unique textures, they all get distinct values anyway; otherwise you have
550 // to group them in pairs or sets of four.
551 //
552 // STBVOX_UNIFORM_ambient
553 // 4-long vec4 array:
554 // ambient[0].xyz - negative of direction of a directional light for half-lambert
555 // ambient[1].rgb - color of light scaled by NdotL (can be negative)
556 // ambient[2].rgb - constant light added to above calculation;
557 // effectively light ranges from ambient[2]-ambient[1] to ambient[2]+ambient[1]
558 // ambient[3].rgb - fog color for STBVOX_CONFIG_FOG_SMOOTHSTEP
559 // ambient[3].a - reciprocal of squared distance of farthest fog point (viewing distance)
560
561
562 // +----- has a default value
563 // | +-- you should always use the default value
564 enum // V V
565 { // ------------------------------------------------
566 STBVOX_UNIFORM_face_data, // n the sampler with the face texture buffer
567 STBVOX_UNIFORM_transform, // n the transform data from stbvox_get_transform
568 STBVOX_UNIFORM_tex_array, // n an array of two texture samplers containing the two texture arrays
569 STBVOX_UNIFORM_texscale, // Y a table of texture properties, see above
570 STBVOX_UNIFORM_color_table, // Y 64 vec4 RGBA values; a default palette is provided; if A > 1.0, fullbright
571 STBVOX_UNIFORM_normals, // Y Y table of normals, internal-only
572 STBVOX_UNIFORM_texgen, // Y Y table of texgen vectors, internal-only
573 STBVOX_UNIFORM_ambient, // n lighting & fog info, see above
574 STBVOX_UNIFORM_camera_pos, // Y camera position in global voxel space (for lighting & fog)
575
576 STBVOX_UNIFORM_count,
577 };
578
579 enum
580 {
581 STBVOX_UNIFORM_TYPE_none,
582 STBVOX_UNIFORM_TYPE_sampler,
583 STBVOX_UNIFORM_TYPE_vec2,
584 STBVOX_UNIFORM_TYPE_vec3,
585 STBVOX_UNIFORM_TYPE_vec4,
586 };
587
588 struct stbvox_uniform_info
589 {
590 int type; // which type of uniform
591 int bytes_per_element; // the size of each uniform array element (e.g. vec3 = 12 bytes)
592 int array_length; // length of the uniform array
593 char *name; // name in the shader @TODO use numeric binding
594 float *default_value; // if not NULL, you can use this as the uniform pointer
595 int use_tex_buffer; // if true, then the uniform is a sampler but the data can come from default_value
596 };
597
598 //////////////////////////////////////////////////////////////////////////////
599 //
600 // Uniform sample code
601 //
602
603 #if 0
604 // Run this once per frame before drawing all the meshes.
605 // You still need to separately set the 'transform' uniform for every mesh.
606 void setup_uniforms(GLuint shader, float camera_pos[4], GLuint tex1, GLuint tex2)
607 {
608 int i;
609 glUseProgram(shader); // so uniform binding works
610 for (i=0; i < STBVOX_UNIFORM_count; ++i) {
611 stbvox_uniform_info sui;
612 if (stbvox_get_uniform_info(&sui, i)) {
613 GLint loc = glGetUniformLocation(shader, sui.name);
614 if (loc != 0) {
615 switch (i) {
616 case STBVOX_UNIFORM_camera_pos: // only needed for fog
617 glUniform4fv(loc, sui.array_length, camera_pos);
618 break;
619
620 case STBVOX_UNIFORM_tex_array: {
621 GLuint tex_unit[2] = { 0, 1 }; // your choice of samplers
622 glUniform1iv(loc, 2, tex_unit);
623
624 glActiveTexture(GL_TEXTURE0 + tex_unit[0]); glBindTexture(GL_TEXTURE_2D_ARRAY, tex1);
625 glActiveTexture(GL_TEXTURE0 + tex_unit[1]); glBindTexture(GL_TEXTURE_2D_ARRAY, tex2);
626 glActiveTexture(GL_TEXTURE0); // reset to default
627 break;
628 }
629
630 case STBVOX_UNIFORM_face_data:
631 glUniform1i(loc, SAMPLER_YOU_WILL_BIND_PER_MESH_FACE_DATA_TO);
632 break;
633
634 case STBVOX_UNIFORM_ambient: // you definitely want to override this
635 case STBVOX_UNIFORM_color_table: // you might want to override this
636 case STBVOX_UNIFORM_texscale: // you may want to override this
637 glUniform4fv(loc, sui.array_length, sui.default_value);
638 break;
639
640 case STBVOX_UNIFORM_normals: // you never want to override this
641 case STBVOX_UNIFORM_texgen: // you never want to override this
642 glUniform3fv(loc, sui.array_length, sui.default_value);
643 break;
644 }
645 }
646 }
647 }
648 }
649 #endif
650
651 #ifdef __cplusplus
652 }
653 #endif
654
655 //////////////////////////////////////////////////////////////////////////////
656 //
657 // INPUT TO MESHING
658 //
659
660 // Shapes of blocks that aren't always cubes
661 enum
662 {
663 STBVOX_GEOM_empty,
664 STBVOX_GEOM_knockout, // creates a hole in the mesh
665 STBVOX_GEOM_solid,
666 STBVOX_GEOM_transp, // solid geometry, but transparent contents so neighbors generate normally, unless same blocktype
667
668 // following 4 can be represented by vheight as well
669 STBVOX_GEOM_slab_upper,
670 STBVOX_GEOM_slab_lower,
671 STBVOX_GEOM_floor_slope_north_is_top,
672 STBVOX_GEOM_ceil_slope_north_is_bottom,
673
674 STBVOX_GEOM_floor_slope_north_is_top_as_wall_UNIMPLEMENTED, // same as floor_slope above, but uses wall's texture & texture projection
675 STBVOX_GEOM_ceil_slope_north_is_bottom_as_wall_UNIMPLEMENTED,
676 STBVOX_GEOM_crossed_pair, // corner-to-corner pairs, with normal vector bumped upwards
677 STBVOX_GEOM_force, // like GEOM_transp, but faces visible even if neighbor is same type, e.g. minecraft fancy leaves
678
679 // these access vheight input
680 STBVOX_GEOM_floor_vheight_03 = 12, // diagonal is SW-NE
681 STBVOX_GEOM_floor_vheight_12, // diagonal is SE-NW
682 STBVOX_GEOM_ceil_vheight_03,
683 STBVOX_GEOM_ceil_vheight_12,
684
685 STBVOX_GEOM_count, // number of geom cases
686 };
687
688 enum
689 {
690 STBVOX_FACE_east,
691 STBVOX_FACE_north,
692 STBVOX_FACE_west,
693 STBVOX_FACE_south,
694 STBVOX_FACE_up,
695 STBVOX_FACE_down,
696
697 STBVOX_FACE_count,
698 };
699
700 #ifdef STBVOX_CONFIG_BLOCKTYPE_SHORT
701 typedef unsigned short stbvox_block_type;
702 #else
703 typedef unsigned char stbvox_block_type;
704 #endif
705
706 // 24-bit color
707 typedef struct
708 {
709 unsigned char r,g,b;
710 } stbvox_rgb;
711
712 #define STBVOX_COLOR_TEX1_ENABLE 64
713 #define STBVOX_COLOR_TEX2_ENABLE 128
714
715 // This is the data structure you fill out. Most of the arrays can be
716 // NULL, except when one is required to get the value to index another.
717 //
718 // The compass system used in the following descriptions is:
719 // east means increasing x
720 // north means increasing y
721 // up means increasing z
722 struct stbvox_input_description
723 {
724 unsigned char lighting_at_vertices;
725 // The default is lighting values (i.e. ambient occlusion) are at block
726 // center, and the vertex light is gathered from those adjacent block
727 // centers that the vertex is facing. This makes smooth lighting
728 // consistent across adjacent faces with the same orientation.
729 //
730 // Setting this flag to non-zero gives you explicit control
731 // of light at each vertex, but now the lighting/ao will be
732 // shared by all vertices at the same point, even if they
733 // have different normals.
734
735 // these are mostly 3D maps you use to define your voxel world, using x_stride and y_stride
736 // note that for cache efficiency, you want to use the block_foo palettes as much as possible instead
737
738 stbvox_rgb *rgb;
739 // Indexed by 3D coordinate.
740 // 24-bit voxel color for STBVOX_CONFIG_MODE = 20 or 21 only
741
742 unsigned char *lighting;
743 // Indexed by 3D coordinate. The lighting value / ambient occlusion
744 // value that is used to define the vertex lighting values.
745 // The raw lighting values are defined at the center of blocks
746 // (or at vertex if 'lighting_at_vertices' is true).
747 //
748 // If the macro STBVOX_CONFIG_ROTATION_IN_LIGHTING is defined,
749 // then an additional 2-bit block rotation value is stored
750 // in this field as well.
751 //
752 // Encode with STBVOX_MAKE_LIGHTING_EXT(lighting,rot)--here
753 // 'lighting' should still be 8 bits, as the macro will
754 // discard the bottom bits automatically. Similarly, if
755 // using STBVOX_CONFIG_VHEIGHT_IN_LIGHTING, encode with
756 // STBVOX_MAKE_LIGHTING_EXT(lighting,vheight).
757 //
758 // (Rationale: rotation needs to be independent of blocktype,
759 // but is only 2 bits so doesn't want to be its own array.
760 // Lighting is the one thing that was likely to already be
761 // in use and that I could easily steal 2 bits from.)
762
763 stbvox_block_type *blocktype;
764 // Indexed by 3D coordinate. This is a core "block type" value, which is used
765 // to index into other arrays; essentially a "palette". This is much more
766 // memory-efficient and performance-friendly than storing the values explicitly,
767 // but only makes sense if the values are always synchronized.
768 //
769 // If a voxel's blocktype is 0, it is assumed to be empty (STBVOX_GEOM_empty),
770 // and no other blocktypes should be STBVOX_GEOM_empty. (Only if you do not
771 // have blocktypes should STBVOX_GEOM_empty ever used.)
772 //
773 // Normally it is an unsigned byte, but you can override it to be
774 // a short if you have too many blocktypes.
775
776 unsigned char *geometry;
777 // Indexed by 3D coordinate. Contains the geometry type for the block.
778 // Also contains a 2-bit rotation for how the whole block is rotated.
779 // Also includes a 2-bit vheight value when using shared vheight values.
780 // See the separate vheight documentation.
781 // Encode with STBVOX_MAKE_GEOMETRY(geom, rot, vheight)
782
783 unsigned char *block_geometry;
784 // Array indexed by blocktype containing the geometry for this block, plus
785 // a 2-bit "simple rotation". Note rotation has limited use since it's not
786 // independent of blocktype.
787 //
788 // Encode with STBVOX_MAKE_GEOMETRY(geom,simple_rot,0)
789
790 unsigned char *block_tex1;
791 // Array indexed by blocktype containing the texture id for texture #1.
792
793 unsigned char (*block_tex1_face)[6];
794 // Array indexed by blocktype and face containing the texture id for texture #1.
795 // The N/E/S/W face choices can be rotated by one of the rotation selectors;
796 // The top & bottom face textures will rotate to match.
797 // Note that it only makes sense to use one of block_tex1 or block_tex1_face;
798 // this pattern repeats throughout and this notice is not repeated.
799
800 unsigned char *tex2;
801 // Indexed by 3D coordinate. Contains the texture id for texture #2
802 // to use on all faces of the block.
803
804 unsigned char *block_tex2;
805 // Array indexed by blocktype containing the texture id for texture #2.
806
807 unsigned char (*block_tex2_face)[6];
808 // Array indexed by blocktype and face containing the texture id for texture #2.
809 // The N/E/S/W face choices can be rotated by one of the rotation selectors;
810 // The top & bottom face textures will rotate to match.
811
812 unsigned char *color;
813 // Indexed by 3D coordinate. Contains the color for all faces of the block.
814 // The core color value is 0..63.
815 // Encode with STBVOX_MAKE_COLOR(color_number, tex1_enable, tex2_enable)
816
817 unsigned char *block_color;
818 // Array indexed by blocktype containing the color value to apply to the faces.
819 // The core color value is 0..63.
820 // Encode with STBVOX_MAKE_COLOR(color_number, tex1_enable, tex2_enable)
821
822 unsigned char (*block_color_face)[6];
823 // Array indexed by blocktype and face containing the color value to apply to that face.
824 // The core color value is 0..63.
825 // Encode with STBVOX_MAKE_COLOR(color_number, tex1_enable, tex2_enable)
826
827 unsigned char *block_texlerp;
828 // Array indexed by blocktype containing 3-bit scalar for texture #2 alpha
829 // (known throughout as 'texlerp'). This is constant over every face even
830 // though the property is potentially per-vertex.
831
832 unsigned char (*block_texlerp_face)[6];
833 // Array indexed by blocktype and face containing 3-bit scalar for texture #2 alpha.
834 // This is constant over the face even though the property is potentially per-vertex.
835
836 unsigned char *block_vheight;
837 // Array indexed by blocktype containing the vheight values for the
838 // top or bottom face of this block. These will rotate properly if the
839 // block is rotated. See discussion of vheight.
840 // Encode with STBVOX_MAKE_VHEIGHT(sw_height, se_height, nw_height, ne_height)
841
842 unsigned char *selector;
843 // Array indexed by 3D coordinates indicating which output mesh to select.
844
845 unsigned char *block_selector;
846 // Array indexed by blocktype indicating which output mesh to select.
847
848 unsigned char *side_texrot;
849 // Array indexed by 3D coordinates encoding 2-bit texture rotations for the
850 // faces on the E/N/W/S sides of the block.
851 // Encode with STBVOX_MAKE_SIDE_TEXROT(rot_e, rot_n, rot_w, rot_s)
852
853 unsigned char *block_side_texrot;
854 // Array indexed by blocktype encoding 2-bit texture rotations for the faces
855 // on the E/N/W/S sides of the block.
856 // Encode with STBVOX_MAKE_SIDE_TEXROT(rot_e, rot_n, rot_w, rot_s)
857
858 unsigned char *overlay; // index into palettes listed below
859 // Indexed by 3D coordinate. If 0, there is no overlay. If non-zero,
860 // it indexes into to the below arrays and overrides the values
861 // defined by the blocktype.
862
863 unsigned char (*overlay_tex1)[6];
864 // Array indexed by overlay value and face, containing an override value
865 // for the texture id for texture #1. If 0, the value defined by blocktype
866 // is used.
867
868 unsigned char (*overlay_tex2)[6];
869 // Array indexed by overlay value and face, containing an override value
870 // for the texture id for texture #2. If 0, the value defined by blocktype
871 // is used.
872
873 unsigned char (*overlay_color)[6];
874 // Array indexed by overlay value and face, containing an override value
875 // for the face color. If 0, the value defined by blocktype is used.
876
877 unsigned char *overlay_side_texrot;
878 // Array indexed by overlay value, encoding 2-bit texture rotations for the faces
879 // on the E/N/W/S sides of the block.
880 // Encode with STBVOX_MAKE_SIDE_TEXROT(rot_e, rot_n, rot_w, rot_s)
881
882 unsigned char *rotate;
883 // Indexed by 3D coordinate. Allows independent rotation of several
884 // parts of the voxel, where by rotation I mean swapping textures
885 // and colors between E/N/S/W faces.
886 // Block: rotates anything indexed by blocktype
887 // Overlay: rotates anything indexed by overlay
888 // EColor: rotates faces defined in ecolor_facemask
889 // Encode with STBVOX_MAKE_MATROT(block,overlay,ecolor)
890
891 unsigned char *tex2_for_tex1;
892 // Array indexed by tex1 containing the texture id for texture #2.
893 // You can use this if the two are always/almost-always strictly
894 // correlated (e.g. if tex2 is a detail texture for tex1), as it
895 // will be more efficient (touching fewer cache lines) than using
896 // e.g. block_tex2_face.
897
898 unsigned char *tex2_replace;
899 // Indexed by 3D coordinate. Specifies the texture id for texture #2
900 // to use on a single face of the voxel, which must be E/N/W/S (not U/D).
901 // The texture id is limited to 6 bits unless tex2_facemask is also
902 // defined (see below).
903 // Encode with STBVOX_MAKE_TEX2_REPLACE(tex2, face)
904
905 unsigned char *tex2_facemask;
906 // Indexed by 3D coordinate. Specifies which of the six faces should
907 // have their tex2 replaced by the value of tex2_replace. In this
908 // case, all 8 bits of tex2_replace are used as the texture id.
909 // Encode with STBVOX_MAKE_FACE_MASK(east,north,west,south,up,down)
910
911 unsigned char *extended_color;
912 // Indexed by 3D coordinate. Specifies a value that indexes into
913 // the ecolor arrays below (both of which must be defined).
914
915 unsigned char *ecolor_color;
916 // Indexed by extended_color value, specifies an optional override
917 // for the color value on some faces.
918 // Encode with STBVOX_MAKE_COLOR(color_number, tex1_enable, tex2_enable)
919
920 unsigned char *ecolor_facemask;
921 // Indexed by extended_color value, this specifies which faces the
922 // color in ecolor_color should be applied to. The faces can be
923 // independently rotated by the ecolor value of 'rotate', if it exists.
924 // Encode with STBVOX_MAKE_FACE_MASK(e,n,w,s,u,d)
925
926 unsigned char *color2;
927 // Indexed by 3D coordinates, specifies an alternative color to apply
928 // to some of the faces of the block.
929 // Encode with STBVOX_MAKE_COLOR(color_number, tex1_enable, tex2_enable)
930
931 unsigned char *color2_facemask;
932 // Indexed by 3D coordinates, specifies which faces should use the
933 // color defined in color2. No rotation value is applied.
934 // Encode with STBVOX_MAKE_FACE_MASK(e,n,w,s,u,d)
935
936 unsigned char *color3;
937 // Indexed by 3D coordinates, specifies an alternative color to apply
938 // to some of the faces of the block.
939 // Encode with STBVOX_MAKE_COLOR(color_number, tex1_enable, tex2_enable)
940
941 unsigned char *color3_facemask;
942 // Indexed by 3D coordinates, specifies which faces should use the
943 // color defined in color3. No rotation value is applied.
944 // Encode with STBVOX_MAKE_FACE_MASK(e,n,w,s,u,d)
945
946 unsigned char *texlerp_simple;
947 // Indexed by 3D coordinates, this is the smallest texlerp encoding
948 // that can do useful work. It consits of three values: baselerp,
949 // vertlerp, and face_vertlerp. Baselerp defines the value
950 // to use on all of the faces but one, from the STBVOX_TEXLERP_BASE
951 // values. face_vertlerp is one of the 6 face values (or STBVOX_FACE_NONE)
952 // which specifies the face should use the vertlerp values.
953 // Vertlerp defines a lerp value at every vertex of the mesh.
954 // Thus, one face can have per-vertex texlerp values, and those
955 // values are encoded in the space so that they will be shared
956 // by adjacent faces that also use vertlerp, allowing continuity
957 // (this is used for the "texture crossfade" bit of the release video).
958 // Encode with STBVOX_MAKE_TEXLERP_SIMPLE(baselerp, vertlerp, face_vertlerp)
959
960 // The following texlerp encodings are experimental and maybe not
961 // that useful.
962
963 unsigned char *texlerp;
964 // Indexed by 3D coordinates, this defines four values:
965 // vertlerp is a lerp value at every vertex of the mesh (using STBVOX_TEXLERP_BASE values).
966 // ud is the value to use on up and down faces, from STBVOX_TEXLERP_FACE values
967 // ew is the value to use on east and west faces, from STBVOX_TEXLERP_FACE values
968 // ns is the value to use on north and south faces, from STBVOX_TEXLERP_FACE values
969 // If any of ud, ew, or ns is STBVOX_TEXLERP_FACE_use_vert, then the
970 // vertlerp values for the vertices are gathered and used for those faces.
971 // Encode with STBVOX_MAKE_TEXLERP(vertlerp,ud,ew,sw)
972
973 unsigned short *texlerp_vert3;
974 // Indexed by 3D coordinates, this works with texlerp and
975 // provides a unique texlerp value for every direction at
976 // every vertex. The same rules of whether faces share values
977 // applies. The STBVOX_TEXLERP_FACE vertlerp value defined in
978 // texlerp is only used for the down direction. The values at
979 // each vertex in other directions are defined in this array,
980 // and each uses the STBVOX_TEXLERP3 values (i.e. full precision
981 // 3-bit texlerp values).
982 // Encode with STBVOX_MAKE_VERT3(vertlerp_e,vertlerp_n,vertlerp_w,vertlerp_s,vertlerp_u)
983
984 unsigned short *texlerp_face3; // e:3,n:3,w:3,s:3,u:2,d:2
985 // Indexed by 3D coordinates, this provides a compact way to
986 // fully specify the texlerp value indepenendly for every face,
987 // but doesn't allow per-vertex variation. E/N/W/S values are
988 // encoded using STBVOX_TEXLERP3 values, whereas up and down
989 // use STBVOX_TEXLERP_SIMPLE values.
990 // Encode with STBVOX_MAKE_FACE3(face_e,face_n,face_w,face_s,face_u,face_d)
991
992 unsigned char *vheight; // STBVOX_MAKE_VHEIGHT -- sw:2, se:2, nw:2, ne:2, doesn't rotate
993 // Indexed by 3D coordinates, this defines the four
994 // vheight values to use if the geometry is STBVOX_GEOM_vheight*.
995 // See the vheight discussion.
996
997 unsigned char *packed_compact;
998 // Stores block rotation, vheight, and texlerp values:
999 // block rotation: 2 bits
1000 // vertex vheight: 2 bits
1001 // use_texlerp : 1 bit
1002 // vertex texlerp: 3 bits
1003 // If STBVOX_CONFIG_UP_TEXLERP_PACKED is defined, then 'vertex texlerp' is
1004 // used for up faces if use_texlerp is 1. If STBVOX_CONFIG_DOWN_TEXLERP_PACKED
1005 // is defined, then 'vertex texlerp' is used for down faces if use_texlerp is 1.
1006 // Note if those symbols are defined but packed_compact is NULL, the normal
1007 // texlerp default will be used.
1008 // Encode with STBVOX_MAKE_PACKED_COMPACT(rot, vheight, texlerp, use_texlerp)
1009 };
1010 // @OPTIMIZE allow specializing; build a single struct with all of the
1011 // 3D-indexed arrays combined so it's AoS instead of SoA for better
1012 // cache efficiency
1013
1014
1015 //////////////////////////////////////////////////////////////////////////////
1016 //
1017 // VHEIGHT DOCUMENTATION
1018 //
1019 // "vheight" is the internal name for the special block types
1020 // with sloped tops or bottoms. "vheight" stands for "vertex height".
1021 //
1022 // Note that these blocks are very flexible (there are 256 of them,
1023 // although at least 17 of them should never be used), but they
1024 // also have a disadvantage that they generate extra invisible
1025 // faces; the generator does not currently detect whether adjacent
1026 // vheight blocks hide each others sides, so those side faces are
1027 // always generated. For a continuous ground terrain, this means
1028 // that you may generate 5x as many quads as needed. See notes
1029 // on "improvements for shipping products" in the introduction.
1030
1031 enum
1032 {
1033 STBVOX_VERTEX_HEIGHT_0,
1034 STBVOX_VERTEX_HEIGHT_half,
1035 STBVOX_VERTEX_HEIGHT_1,
1036 STBVOX_VERTEX_HEIGHT_one_and_a_half,
1037 };
1038 // These are the "vheight" values. Vheight stands for "vertex height".
1039 // The idea is that for a "floor vheight" block, you take a cube and
1040 // reposition the top-most vertices at various heights as specified by
1041 // the vheight values. Similarly, a "ceiling vheight" block takes a
1042 // cube and repositions the bottom-most vertices.
1043 //
1044 // A floor block only adjusts the top four vertices; the bottom four vertices
1045 // remain at the bottom of the block. The height values are 2 bits,
1046 // measured in halves of a block; so you can specify heights of 0/2,
1047 // 1/2, 2/2, or 3/2. 0 is the bottom of the block, 1 is halfway
1048 // up the block, 2 is the top of the block, and 3 is halfway up the
1049 // next block (and actually outside of the block). The value 3 is
1050 // actually legal for floor vheight (but not ceiling), and allows you to:
1051 //
1052 // (A) have smoother terrain by having slopes that cross blocks,
1053 // e.g. (1,1,3,3) is a regular-seeming slope halfway between blocks
1054 // (B) make slopes steeper than 45-degrees, e.g. (0,0,3,3)
1055 //
1056 // (Because only z coordinates have half-block precision, and x&y are
1057 // limited to block corner precision, it's not possible to make these
1058 // things "properly" out of blocks, e.g. a half-slope block on its side
1059 // or a sloped block halfway between blocks that's made out of two blocks.)
1060 //
1061 // If you define STBVOX_CONFIG_OPTIMIZED_VHEIGHT, then the top face
1062 // (or bottom face for a ceiling vheight block) will be drawn as a
1063 // single quad even if the four vertex heights aren't planar, and a
1064 // single normal will be used over the entire quad. If you
1065 // don't define it, then if the top face is non-planar, it will be
1066 // split into two triangles, each with their own normal/lighting.
1067 // (Note that since all output from stb_voxel_render is quad meshes,
1068 // triangles are actually rendered as degenerate quads.) In this case,
1069 // the distinction betwen STBVOX_GEOM_floor_vheight_03 and
1070 // STBVOX_GEOM_floor_vheight_12 comes into play; the former introduces
1071 // an edge from the SW to NE corner (i.e. from <0,0,?> to <1,1,?>),
1072 // while the latter introduces an edge from the NW to SE corner
1073 // (i.e. from <0,1,?> to <1,0,?>.) For a "lazy mesh" look, use
1074 // exclusively _03 or _12. For a "classic mesh" look, alternate
1075 // _03 and _12 in a checkerboard pattern. For a "smoothest surface"
1076 // look, choose the edge based on actual vertex heights.
1077 //
1078 // The four vertex heights can come from several places. The simplest
1079 // encoding is to just use the 'vheight' parameter which stores four
1080 // explicit vertex heights for every block. This allows total independence,
1081 // but at the cost of the largest memory usage, 1 byte per 3D block.
1082 // Encode this with STBVOX_MAKE_VHEIGHT(vh_sw, vh_se, vh_nw, vh_ne).
1083 // These coordinates are absolute, not affected by block rotations.
1084 //
1085 // An alternative if you just want to encode some very specific block
1086 // types, not all the possibilities--say you just want half-height slopes,
1087 // so you want (0,0,1,1) and (1,1,2,2)--then you can use block_vheight
1088 // to specify them. The geometry rotation will cause block_vheight values
1089 // to be rotated (because it's as if you're just defining a type of
1090 // block). This value is also encoded with STBVOX_MAKE_VHEIGHT.
1091 //
1092 // If you want to save memory and you're creating a "continuous ground"
1093 // sort of effect, you can make each vertex of the lattice share the
1094 // vheight value; that is, two adjacent blocks that share a vertex will
1095 // always get the same vheight value for that vertex. Then you need to
1096 // store two bits of vheight for every block, which you do by storing it
1097 // as part another data structure. Store the south-west vertex's vheight
1098 // with the block. You can either use the "geometry" mesh variable (it's
1099 // a parameter to STBVOX_MAKE_GEOMETRY) or you can store it in the
1100 // "lighting" mesh variable if you defined STBVOX_CONFIG_VHEIGHT_IN_LIGHTING,
1101 // using STBVOX_MAKE_LIGHTING_EXT(lighting,vheight).
1102 //
1103 // Note that if you start with a 2D height map and generate vheight data from
1104 // it, you don't necessarily store only one value per (x,y) coordinate,
1105 // as the same value may need to be set up at multiple z heights. For
1106 // example, if height(8,8) = 13.5, then you want the block at (8,8,13)
1107 // to store STBVOX_VERTEX_HEIGHT_half, and this will be used by blocks
1108 // at (7,7,13), (8,7,13), (7,8,13), and (8,8,13). However, if you're
1109 // allowing steep slopes, it might be the case that you have a block
1110 // at (7,7,12) which is supposed to stick up to 13.5; that means
1111 // you also need to store STBVOX_VERTEX_HEIGHT_one_and_a_half at (8,8,12).
1112
1113 enum
1114 {
1115 STBVOX_TEXLERP_FACE_0,
1116 STBVOX_TEXLERP_FACE_half,
1117 STBVOX_TEXLERP_FACE_1,
1118 STBVOX_TEXLERP_FACE_use_vert,
1119 };
1120
1121 enum
1122 {
1123 STBVOX_TEXLERP_BASE_0, // 0.0
1124 STBVOX_TEXLERP_BASE_2_7, // 2/7
1125 STBVOX_TEXLERP_BASE_5_7, // 4/7
1126 STBVOX_TEXLERP_BASE_1 // 1.0
1127 };
1128
1129 enum
1130 {
1131 STBVOX_TEXLERP3_0_8,
1132 STBVOX_TEXLERP3_1_8,
1133 STBVOX_TEXLERP3_2_8,
1134 STBVOX_TEXLERP3_3_8,
1135 STBVOX_TEXLERP3_4_8,
1136 STBVOX_TEXLERP3_5_8,
1137 STBVOX_TEXLERP3_6_8,
1138 STBVOX_TEXLERP3_7_8,
1139 };
1140
1141 #define STBVOX_FACE_NONE 7
1142
1143 #define STBVOX_BLOCKTYPE_EMPTY 0
1144
1145 #ifdef STBVOX_BLOCKTYPE_SHORT
1146 #define STBVOX_BLOCKTYPE_HOLE 65535
1147 #else
1148 #define STBVOX_BLOCKTYPE_HOLE 255
1149 #endif
1150
1151 #define STBVOX_MAKE_GEOMETRY(geom, rotate, vheight) ((geom) + (rotate)*16 + (vheight)*64)
1152 #define STBVOX_MAKE_VHEIGHT(v_sw, v_se, v_nw, v_ne) ((v_sw) + (v_se)*4 + (v_nw)*16 + (v_ne)*64)
1153 #define STBVOX_MAKE_MATROT(block, overlay, color) ((block) + (overlay)*4 + (color)*64)
1154 #define STBVOX_MAKE_TEX2_REPLACE(tex2, tex2_replace_face) ((tex2) + ((tex2_replace_face) & 3)*64)
1155 #define STBVOX_MAKE_TEXLERP(ns2, ew2, ud2, vert) ((ew2) + (ns2)*4 + (ud2)*16 + (vert)*64)
1156 #define STBVOX_MAKE_TEXLERP_SIMPLE(baselerp,vert,face) ((vert)*32 + (face)*4 + (baselerp))
1157 #define STBVOX_MAKE_TEXLERP1(vert,e2,n2,w2,s2,u4,d2) STBVOX_MAKE_TEXLERP(s2, w2, d2, vert)
1158 #define STBVOX_MAKE_TEXLERP2(vert,e2,n2,w2,s2,u4,d2) ((u2)*16 + (n2)*4 + (s2))
1159 #define STBVOX_MAKE_FACE_MASK(e,n,w,s,u,d) ((e)+(n)*2+(w)*4+(s)*8+(u)*16+(d)*32)
1160 #define STBVOX_MAKE_SIDE_TEXROT(e,n,w,s) ((e)+(n)*4+(w)*16+(s)*64)
1161 #define STBVOX_MAKE_COLOR(color,t1,t2) ((color)+(t1)*64+(t2)*128)
1162 #define STBVOX_MAKE_TEXLERP_VERT3(e,n,w,s,u) ((e)+(n)*8+(w)*64+(s)*512+(u)*4096)
1163 #define STBVOX_MAKE_TEXLERP_FACE3(e,n,w,s,u,d) ((e)+(n)*8+(w)*64+(s)*512+(u)*4096+(d)*16384)
1164 #define STBVOX_MAKE_PACKED_COMPACT(rot, vheight, texlerp, def) ((rot)+4*(vheight)+16*(use)+32*(texlerp))
1165
1166 #define STBVOX_MAKE_LIGHTING_EXT(lighting, rot) (((lighting)&~3)+(rot))
1167 #define STBVOX_MAKE_LIGHTING(lighting) (lighting)
1168
1169 #ifndef STBVOX_MAX_MESHES
1170 #define STBVOX_MAX_MESHES 2 // opaque & transparent
1171 #endif
1172
1173 #define STBVOX_MAX_MESH_SLOTS 3 // one vertex & two faces, or two vertex and one face
1174
1175
1176 // don't mess with this directly, it's just here so you can
1177 // declare stbvox_mesh_maker on the stack or as a global
1178 struct stbvox_mesh_maker
1179 {
1180 stbvox_input_description input;
1181 int cur_x, cur_y, cur_z; // last unprocessed voxel if it splits into multiple buffers
1182 int x0,y0,z0,x1,y1,z1;
1183 int x_stride_in_bytes;
1184 int y_stride_in_bytes;
1185 int config_dirty;
1186 int default_mesh;
1187 unsigned int tags;
1188
1189 int cube_vertex_offset[6][4]; // this allows access per-vertex data stored block-centered (like texlerp, ambient)
1190 int vertex_gather_offset[6][4];
1191
1192 int pos_x,pos_y,pos_z;
1193 int full;
1194
1195 // computed from user input
1196 char *output_cur [STBVOX_MAX_MESHES][STBVOX_MAX_MESH_SLOTS];
1197 char *output_end [STBVOX_MAX_MESHES][STBVOX_MAX_MESH_SLOTS];
1198 char *output_buffer[STBVOX_MAX_MESHES][STBVOX_MAX_MESH_SLOTS];
1199 int output_len [STBVOX_MAX_MESHES][STBVOX_MAX_MESH_SLOTS];
1200
1201 // computed from config
1202 int output_size [STBVOX_MAX_MESHES][STBVOX_MAX_MESH_SLOTS]; // per quad
1203 int output_step [STBVOX_MAX_MESHES][STBVOX_MAX_MESH_SLOTS]; // per vertex or per face, depending
1204 int num_mesh_slots;
1205
1206 float default_tex_scale[128][2];
1207 };
1208
1209 #endif // INCLUDE_STB_VOXEL_RENDER_H
1210
1211
1212 #ifdef STB_VOXEL_RENDER_IMPLEMENTATION
1213
1214 #include <stdlib.h>
1215 #include <assert.h>
1216 #include <string.h> // memset
1217
1218 // have to use our own names to avoid the _MSC_VER path having conflicting type names
1219 #ifndef _MSC_VER
1220 #include <stdint.h>
1221 typedef uint16_t stbvox_uint16;
1222 typedef uint32_t stbvox_uint32;
1223 #else
1224 typedef unsigned short stbvox_uint16;
1225 typedef unsigned int stbvox_uint32;
1226 #endif
1227
1228 #ifdef _MSC_VER
1229 #define STBVOX_NOTUSED(v) (void)(v)
1230 #else
1231 #define STBVOX_NOTUSED(v) (void)sizeof(v)
1232 #endif
1233
1234
1235
1236 #ifndef STBVOX_CONFIG_MODE
1237 #error "Must defined STBVOX_CONFIG_MODE to select the mode"
1238 #endif
1239
1240 #if defined(STBVOX_CONFIG_ROTATION_IN_LIGHTING) && defined(STBVOX_CONFIG_VHEIGHT_IN_LIGHTING)
1241 #error "Can't store both rotation and vheight in lighting"
1242 #endif
1243
1244
1245 // The following are candidate voxel modes. Only modes 0, 1, and 20, and 21 are
1246 // currently implemented. Reducing the storage-per-quad further
1247 // shouldn't improve performance, although obviously it allow you
1248 // to create larger worlds without streaming.
1249 //
1250 //
1251 // ----------- Two textures ----------- -- One texture -- ---- Color only ----
1252 // Mode: 0 1 2 3 4 5 6 10 11 12 20 21 22 23 24
1253 // ============================================================================================================
1254 // uses Tex Buffer n Y Y Y Y Y Y Y Y Y n Y Y Y Y
1255 // bytes per quad 32 20 14 12 10 6 6 8 8 4 32 20 10 6 4
1256 // non-blocks all all some some some slabs stairs some some none all all slabs slabs none
1257 // tex1 256 256 256 256 256 256 256 256 256 256 n n n n n
1258 // tex2 256 256 256 256 256 256 128 n n n n n n n n
1259 // colors 64 64 64 64 64 64 64 8 n n 2^24 2^24 2^24 2^24 256
1260 // vertex ao Y Y Y Y Y n n Y Y n Y Y Y n n
1261 // vertex texlerp Y Y Y n n n n - - - - - - - -
1262 // x&y extents 127 127 128 64 64 128 64 64 128 128 127 127 128 128 128
1263 // z extents 255 255 128 64? 64? 64 64 32 64 128 255 255 128 64 128
1264
1265 // not sure why I only wrote down the above "result data" and didn't preserve
1266 // the vertex formats, but here I've tried to reconstruct the designs...
1267 // mode # 3 is wrong, one byte too large, but they may have been an error originally
1268
1269 // Mode: 0 1 2 3 4 5 6 10 11 12 20 21 22 23 24
1270 // =============================================================================================================
1271 // bytes per quad 32 20 14 12 10 6 6 8 8 4 20 10 6 4
1272 //
1273 // vertex x bits 7 7 0 6 0 0 0 0 0 0 7 0 0 0
1274 // vertex y bits 7 7 0 0 0 0 0 0 0 0 7 0 0 0
1275 // vertex z bits 9 9 7 4 2 0 0 2 2 0 9 2 0 0
1276 // vertex ao bits 6 6 6 6 6 0 0 6 6 0 6 6 0 0
1277 // vertex txl bits 3 3 3 0 0 0 0 0 0 0 (3) 0 0 0
1278 //
1279 // face tex1 bits (8) 8 8 8 8 8 8 8 8 8
1280 // face tex2 bits (8) 8 8 8 8 8 7 - - -
1281 // face color bits (8) 8 8 8 8 8 8 3 0 0 24 24 24 8
1282 // face normal bits (8) 8 8 8 6 4 7 4 4 3 8 3 4 3
1283 // face x bits 7 0 6 7 6 6 7 7 0 7 7 7
1284 // face y bits 7 6 6 7 6 6 7 7 0 7 7 7
1285 // face z bits 2 2 6 6 6 5 6 7 0 7 6 7
1286
1287
1288 #if STBVOX_CONFIG_MODE==0 || STBVOX_CONFIG_MODE==1
1289
1290 #define STBVOX_ICONFIG_VERTEX_32
1291 #define STBVOX_ICONFIG_FACE1_1
1292
1293 #elif STBVOX_CONFIG_MODE==20 || STBVOX_CONFIG_MODE==21
1294
1295 #define STBVOX_ICONFIG_VERTEX_32
1296 #define STBVOX_ICONFIG_FACE1_1
1297 #define STBVOX_ICONFIG_UNTEXTURED
1298
1299 #else
1300 #error "Selected value of STBVOX_CONFIG_MODE is not supported"
1301 #endif
1302
1303 #if STBVOX_CONFIG_MODE==0 || STBVOX_CONFIG_MODE==20
1304 #define STBVOX_ICONFIG_FACE_ATTRIBUTE
1305 #endif
1306
1307 #ifndef STBVOX_CONFIG_HLSL
1308 // the fallback if all others are exhausted is GLSL
1309 #define STBVOX_ICONFIG_GLSL
1310 #endif
1311
1312 #ifdef STBVOX_CONFIG_OPENGL_MODELVIEW
1313 #define STBVOX_ICONFIG_OPENGL_3_1_COMPATIBILITY
1314 #endif
1315
1316 #if defined(STBVOX_ICONFIG_VERTEX_32)
1317 typedef stbvox_uint32 stbvox_mesh_vertex;
1318 #define stbvox_vertex_encode(x,y,z,ao,texlerp) \
1319 ((stbvox_uint32) ((x)+((y)<<7)+((z)<<14)+((ao)<<23)+((texlerp)<<29)))
1320 #elif defined(STBVOX_ICONFIG_VERTEX_16_1) // mode=2
1321 typedef stbvox_uint16 stbvox_mesh_vertex;
1322 #define stbvox_vertex_encode(x,y,z,ao,texlerp) \
1323 ((stbvox_uint16) ((z)+((ao)<<7)+((texlerp)<<13)
1324 #elif defined(STBVOX_ICONFIG_VERTEX_16_2) // mode=3
1325 typedef stbvox_uint16 stbvox_mesh_vertex;
1326 #define stbvox_vertex_encode(x,y,z,ao,texlerp) \
1327 ((stbvox_uint16) ((x)+((z)<<6))+((ao)<<10))
1328 #elif defined(STBVOX_ICONFIG_VERTEX_8)
1329 typedef stbvox_uint8 stbvox_mesh_vertex;
1330 #define stbvox_vertex_encode(x,y,z,ao,texlerp) \
1331 ((stbvox_uint8) ((z)+((ao)<<6))
1332 #else
1333 #error "internal error, no vertex type"
1334 #endif
1335
1336 #ifdef STBVOX_ICONFIG_FACE1_1
1337 typedef struct
1338 {
1339 unsigned char tex1,tex2,color,face_info;
1340 } stbvox_mesh_face;
1341 #else
1342 #error "internal error, no face type"
1343 #endif
1344
1345
1346 // 20-byte quad format:
1347 //
1348 // per vertex:
1349 //
1350 // x:7
1351 // y:7
1352 // z:9
1353 // ao:6
1354 // tex_lerp:3
1355 //
1356 // per face:
1357 //
1358 // tex1:8
1359 // tex2:8
1360 // face:8
1361 // color:8
1362
1363
1364 // Faces:
1365 //
1366 // Faces use the bottom 3 bits to choose the texgen
1367 // mode, and all the bits to choose the normal.
1368 // Thus the bottom 3 bits have to be:
1369 // e, n, w, s, u, d, u, d
1370 //
1371 // These use compact names so tables are readable
1372
1373 enum
1374 {
1375 STBVF_e,
1376 STBVF_n,
1377 STBVF_w,
1378 STBVF_s,
1379 STBVF_u,
1380 STBVF_d,
1381 STBVF_eu,
1382 STBVF_ed,
1383
1384 STBVF_eu_wall,
1385 STBVF_nu_wall,
1386 STBVF_wu_wall,
1387 STBVF_su_wall,
1388 STBVF_ne_u,
1389 STBVF_ne_d,
1390 STBVF_nu,
1391 STBVF_nd,
1392
1393 STBVF_ed_wall,
1394 STBVF_nd_wall,
1395 STBVF_wd_wall,
1396 STBVF_sd_wall,
1397 STBVF_nw_u,
1398 STBVF_nw_d,
1399 STBVF_wu,
1400 STBVF_wd,
1401
1402 STBVF_ne_u_cross,
1403 STBVF_nw_u_cross,
1404 STBVF_sw_u_cross,
1405 STBVF_se_u_cross,
1406 STBVF_sw_u,
1407 STBVF_sw_d,
1408 STBVF_su,
1409 STBVF_sd,
1410
1411 // @TODO we need more than 5 bits to encode the normal to fit the following
1412 // so for now we use the right projection but the wrong normal
1413 STBVF_se_u = STBVF_su,
1414 STBVF_se_d = STBVF_sd,
1415
1416 STBVF_count,
1417 };
1418
1419 /////////////////////////////////////////////////////////////////////////////
1420 //
1421 // tables -- i'd prefer if these were at the end of the file, but: C++
1422 //
1423
1424 static float stbvox_default_texgen[2][32][3] =
1425 {
1426 { { 0, 1,0 }, { 0, 0, 1 }, { 0,-1,0 }, { 0, 0,-1 },
1427 { -1, 0,0 }, { 0, 0, 1 }, { 1, 0,0 }, { 0, 0,-1 },
1428 { 0,-1,0 }, { 0, 0, 1 }, { 0, 1,0 }, { 0, 0,-1 },
1429 { 1, 0,0 }, { 0, 0, 1 }, { -1, 0,0 }, { 0, 0,-1 },
1430
1431 { 1, 0,0 }, { 0, 1, 0 }, { -1, 0,0 }, { 0,-1, 0 },
1432 { -1, 0,0 }, { 0,-1, 0 }, { 1, 0,0 }, { 0, 1, 0 },
1433 { 1, 0,0 }, { 0, 1, 0 }, { -1, 0,0 }, { 0,-1, 0 },
1434 { -1, 0,0 }, { 0,-1, 0 }, { 1, 0,0 }, { 0, 1, 0 },
1435 },
1436 { { 0, 0,-1 }, { 0, 1,0 }, { 0, 0, 1 }, { 0,-1,0 },
1437 { 0, 0,-1 }, { -1, 0,0 }, { 0, 0, 1 }, { 1, 0,0 },
1438 { 0, 0,-1 }, { 0,-1,0 }, { 0, 0, 1 }, { 0, 1,0 },
1439 { 0, 0,-1 }, { 1, 0,0 }, { 0, 0, 1 }, { -1, 0,0 },
1440
1441 { 0,-1, 0 }, { 1, 0,0 }, { 0, 1, 0 }, { -1, 0,0 },
1442 { 0, 1, 0 }, { -1, 0,0 }, { 0,-1, 0 }, { 1, 0,0 },
1443 { 0,-1, 0 }, { 1, 0,0 }, { 0, 1, 0 }, { -1, 0,0 },
1444 { 0, 1, 0 }, { -1, 0,0 }, { 0,-1, 0 }, { 1, 0,0 },
1445 },
1446 };
1447
1448 #define STBVOX_RSQRT2 0.7071067811865f
1449 #define STBVOX_RSQRT3 0.5773502691896f
1450
1451 static float stbvox_default_normals[32][3] =
1452 {
1453 { 1,0,0 }, // east
1454 { 0,1,0 }, // north
1455 { -1,0,0 }, // west
1456 { 0,-1,0 }, // south
1457 { 0,0,1 }, // up
1458 { 0,0,-1 }, // down
1459 { STBVOX_RSQRT2,0, STBVOX_RSQRT2 }, // east & up
1460 { STBVOX_RSQRT2,0, -STBVOX_RSQRT2 }, // east & down
1461
1462 { STBVOX_RSQRT2,0, STBVOX_RSQRT2 }, // east & up
1463 { 0, STBVOX_RSQRT2, STBVOX_RSQRT2 }, // north & up
1464 { -STBVOX_RSQRT2,0, STBVOX_RSQRT2 }, // west & up
1465 { 0,-STBVOX_RSQRT2, STBVOX_RSQRT2 }, // south & up
1466 { STBVOX_RSQRT3, STBVOX_RSQRT3, STBVOX_RSQRT3 }, // ne & up
1467 { STBVOX_RSQRT3, STBVOX_RSQRT3,-STBVOX_RSQRT3 }, // ne & down
1468 { 0, STBVOX_RSQRT2, STBVOX_RSQRT2 }, // north & up
1469 { 0, STBVOX_RSQRT2, -STBVOX_RSQRT2 }, // north & down
1470
1471 { STBVOX_RSQRT2,0, -STBVOX_RSQRT2 }, // east & down
1472 { 0, STBVOX_RSQRT2, -STBVOX_RSQRT2 }, // north & down
1473 { -STBVOX_RSQRT2,0, -STBVOX_RSQRT2 }, // west & down
1474 { 0,-STBVOX_RSQRT2, -STBVOX_RSQRT2 }, // south & down
1475 { -STBVOX_RSQRT3, STBVOX_RSQRT3, STBVOX_RSQRT3 }, // NW & up
1476 { -STBVOX_RSQRT3, STBVOX_RSQRT3,-STBVOX_RSQRT3 }, // NW & down
1477 { -STBVOX_RSQRT2,0, STBVOX_RSQRT2 }, // west & up
1478 { -STBVOX_RSQRT2,0, -STBVOX_RSQRT2 }, // west & down
1479
1480 { STBVOX_RSQRT3, STBVOX_RSQRT3,STBVOX_RSQRT3 }, // NE & up crossed
1481 { -STBVOX_RSQRT3, STBVOX_RSQRT3,STBVOX_RSQRT3 }, // NW & up crossed
1482 { -STBVOX_RSQRT3,-STBVOX_RSQRT3,STBVOX_RSQRT3 }, // SW & up crossed
1483 { STBVOX_RSQRT3,-STBVOX_RSQRT3,STBVOX_RSQRT3 }, // SE & up crossed
1484 { -STBVOX_RSQRT3,-STBVOX_RSQRT3, STBVOX_RSQRT3 }, // SW & up
1485 { -STBVOX_RSQRT3,-STBVOX_RSQRT3,-STBVOX_RSQRT3 }, // SW & up
1486 { 0,-STBVOX_RSQRT2, STBVOX_RSQRT2 }, // south & up
1487 { 0,-STBVOX_RSQRT2, -STBVOX_RSQRT2 }, // south & down
1488 };
1489
1490 static float stbvox_default_texscale[128][4] =
1491 {
1492 {1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},
1493 {1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},
1494 {1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},
1495 {1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},
1496 {1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},
1497 {1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},
1498 {1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},
1499 {1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},
1500 {1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},
1501 {1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},
1502 {1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},
1503 {1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},
1504 {1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},
1505 {1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},
1506 {1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},
1507 {1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},{1,1,0,0},
1508 };
1509
1510 static unsigned char stbvox_default_palette_compact[64][3] =
1511 {
1512 { 255,255,255 }, { 238,238,238 }, { 221,221,221 }, { 204,204,204 },
1513 { 187,187,187 }, { 170,170,170 }, { 153,153,153 }, { 136,136,136 },
1514 { 119,119,119 }, { 102,102,102 }, { 85, 85, 85 }, { 68, 68, 68 },
1515 { 51, 51, 51 }, { 34, 34, 34 }, { 17, 17, 17 }, { 0, 0, 0 },
1516 { 255,240,240 }, { 255,220,220 }, { 255,160,160 }, { 255, 32, 32 },
1517 { 200,120,160 }, { 200, 60,150 }, { 220,100,130 }, { 255, 0,128 },
1518 { 240,240,255 }, { 220,220,255 }, { 160,160,255 }, { 32, 32,255 },
1519 { 120,160,200 }, { 60,150,200 }, { 100,130,220 }, { 0,128,255 },
1520 { 240,255,240 }, { 220,255,220 }, { 160,255,160 }, { 32,255, 32 },
1521 { 160,200,120 }, { 150,200, 60 }, { 130,220,100 }, { 128,255, 0 },
1522 { 255,255,240 }, { 255,255,220 }, { 220,220,180 }, { 255,255, 32 },
1523 { 200,160,120 }, { 200,150, 60 }, { 220,130,100 }, { 255,128, 0 },
1524 { 255,240,255 }, { 255,220,255 }, { 220,180,220 }, { 255, 32,255 },
1525 { 160,120,200 }, { 150, 60,200 }, { 130,100,220 }, { 128, 0,255 },
1526 { 240,255,255 }, { 220,255,255 }, { 180,220,220 }, { 32,255,255 },
1527 { 120,200,160 }, { 60,200,150 }, { 100,220,130 }, { 0,255,128 },
1528 };
1529
1530 static float stbvox_default_ambient[4][4] =
1531 {
1532 { 0,0,1 ,0 }, // reversed lighting direction
1533 { 0.5,0.5,0.5,0 }, // directional color
1534 { 0.5,0.5,0.5,0 }, // constant color
1535 { 0.5,0.5,0.5,1.0f/1000.0f/1000.0f }, // fog data for simple_fog
1536 };
1537
1538 static float stbvox_default_palette[64][4];
1539
1540 static void stbvox_build_default_palette(void)
1541 {
1542 int i;
1543 for (i=0; i < 64; ++i) {
1544 stbvox_default_palette[i][0] = stbvox_default_palette_compact[i][0] / 255.0f;
1545 stbvox_default_palette[i][1] = stbvox_default_palette_compact[i][1] / 255.0f;
1546 stbvox_default_palette[i][2] = stbvox_default_palette_compact[i][2] / 255.0f;
1547 stbvox_default_palette[i][3] = 1.0f;
1548 }
1549 }
1550
1551 //////////////////////////////////////////////////////////////////////////////
1552 //
1553 // Shaders
1554 //
1555
1556 #if defined(STBVOX_ICONFIG_OPENGL_3_1_COMPATIBILITY)
1557 #define STBVOX_SHADER_VERSION "#version 150 compatibility\n"
1558 #elif defined(STBVOX_ICONFIG_OPENGL_3_0)
1559 #define STBVOX_SHADER_VERSION "#version 130\n"
1560 #elif defined(STBVOX_ICONFIG_GLSL)
1561 #define STBVOX_SHADER_VERSION "#version 150\n"
1562 #else
1563 #define STBVOX_SHADER_VERSION ""
1564 #endif
1565
1566 static const char *stbvox_vertex_program =
1567 {
1568 STBVOX_SHADER_VERSION
1569
1570 #ifdef STBVOX_ICONFIG_FACE_ATTRIBUTE // NOT TAG_face_sampled
1571 "in uvec4 attr_face;\n"
1572 #else
1573 "uniform usamplerBuffer facearray;\n"
1574 #endif
1575
1576 #ifdef STBVOX_ICONFIG_FACE_ARRAY_2
1577 "uniform usamplerBuffer facearray2;\n"
1578 #endif
1579
1580 // vertex input data
1581 "in uint attr_vertex;\n"
1582
1583 // per-buffer data
1584 "uniform vec3 transform[3];\n"
1585
1586 // per-frame data
1587 "uniform vec4 camera_pos;\n" // 4th value is used for arbitrary hacking
1588
1589 // to simplify things, we avoid using more than 256 uniform vectors
1590 // in fragment shader to avoid possible 1024 component limit, so
1591 // we access this table in the fragment shader.
1592 "uniform vec3 normal_table[32];\n"
1593
1594 #ifndef STBVOX_CONFIG_OPENGL_MODELVIEW
1595 "uniform mat4x4 model_view;\n"
1596 #endif
1597
1598 // fragment output data
1599 "flat out uvec4 facedata;\n"
1600 " out vec3 voxelspace_pos;\n"
1601 " out vec3 vnormal;\n"
1602 " out float texlerp;\n"
1603 " out float amb_occ;\n"
1604
1605 // @TODO handle the HLSL way to do this
1606 "void main()\n"
1607 "{\n"
1608 #ifdef STBVOX_ICONFIG_FACE_ATTRIBUTE
1609 " facedata = attr_face;\n"
1610 #else
1611 " int faceID = gl_VertexID >> 2;\n"
1612 " facedata = texelFetch(facearray, faceID);\n"
1613 #endif
1614
1615 // extract data for vertex
1616 " vec3 offset;\n"
1617 " offset.x = float( (attr_vertex ) & 127u );\n" // a[0..6]
1618 " offset.y = float( (attr_vertex >> 7u) & 127u );\n" // a[7..13]
1619 " offset.z = float( (attr_vertex >> 14u) & 511u );\n" // a[14..22]
1620 " amb_occ = float( (attr_vertex >> 23u) & 63u ) / 63.0;\n" // a[23..28]
1621 " texlerp = float( (attr_vertex >> 29u) ) / 7.0;\n" // a[29..31]
1622
1623 " vnormal = normal_table[(facedata.w>>2u) & 31u];\n"
1624 " voxelspace_pos = offset * transform[0];\n" // mesh-to-object scale
1625 " vec3 position = voxelspace_pos + transform[1];\n" // mesh-to-object translate
1626
1627 #ifdef STBVOX_DEBUG_TEST_NORMALS
1628 " if ((facedata.w & 28u) == 16u || (facedata.w & 28u) == 24u)\n"
1629 " position += vnormal.xyz * camera_pos.w;\n"
1630 #endif
1631
1632 #ifndef STBVOX_CONFIG_OPENGL_MODELVIEW
1633 " gl_Position = model_view * vec4(position,1.0);\n"
1634 #else
1635 " gl_Position = gl_ModelViewProjectionMatrix * vec4(position,1.0);\n"
1636 #endif
1637
1638 "}\n"
1639 };
1640
1641
1642 static const char *stbvox_fragment_program =
1643 {
1644 STBVOX_SHADER_VERSION
1645
1646 // rlerp is lerp but with t on the left, like god intended
1647 #if defined(STBVOX_ICONFIG_GLSL)
1648 "#define rlerp(t,x,y) mix(x,y,t)\n"
1649 #elif defined(STBVOX_CONFIG_HLSL)
1650 "#define rlerp(t,x,y) lerp(x,y,t)\n"
1651 #else
1652 #error "need definition of rlerp()"
1653 #endif
1654
1655
1656 // vertex-shader output data
1657 "flat in uvec4 facedata;\n"
1658 " in vec3 voxelspace_pos;\n"
1659 " in vec3 vnormal;\n"
1660 " in float texlerp;\n"
1661 " in float amb_occ;\n"
1662
1663 // per-buffer data
1664 "uniform vec3 transform[3];\n"
1665
1666 // per-frame data
1667 "uniform vec4 camera_pos;\n" // 4th value is used for arbitrary hacking
1668
1669 // probably constant data
1670 "uniform vec4 ambient[4];\n"
1671
1672 #ifndef STBVOX_ICONFIG_UNTEXTURED
1673 // generally constant data
1674 "uniform sampler2DArray tex_array[2];\n"
1675
1676 #ifdef STBVOX_CONFIG_PREFER_TEXBUFFER
1677 "uniform samplerBuffer color_table;\n"
1678 "uniform samplerBuffer texscale;\n"
1679 "uniform samplerBuffer texgen;\n"
1680 #else
1681 "uniform vec4 color_table[64];\n"
1682 "uniform vec4 texscale[64];\n" // instead of 128, to avoid running out of uniforms
1683 "uniform vec3 texgen[64];\n"
1684 #endif
1685 #endif
1686
1687 "out vec4 outcolor;\n"
1688
1689 #if defined(STBVOX_CONFIG_LIGHTING) || defined(STBVOX_CONFIG_LIGHTING_SIMPLE)
1690 "vec3 compute_lighting(vec3 pos, vec3 norm, vec3 albedo, vec3 ambient);\n"
1691 #endif
1692 #if defined(STBVOX_CONFIG_FOG) || defined(STBVOX_CONFIG_FOG_SMOOTHSTEP)
1693 "vec3 compute_fog(vec3 color, vec3 relative_pos, float fragment_alpha);\n"
1694 #endif
1695
1696 "void main()\n"
1697 "{\n"
1698 " vec3 albedo;\n"
1699 " float fragment_alpha;\n"
1700
1701 #ifndef STBVOX_ICONFIG_UNTEXTURED
1702 // unpack the values
1703 " uint tex1_id = facedata.x;\n"
1704 " uint tex2_id = facedata.y;\n"
1705 " uint texprojid = facedata.w & 31u;\n"
1706 " uint color_id = facedata.z;\n"
1707
1708 #ifndef STBVOX_CONFIG_PREFER_TEXBUFFER
1709 // load from uniforms / texture buffers
1710 " vec3 texgen_s = texgen[texprojid];\n"
1711 " vec3 texgen_t = texgen[texprojid+32u];\n"
1712 " float tex1_scale = texscale[tex1_id & 63u].x;\n"
1713 " vec4 color = color_table[color_id & 63u];\n"
1714 #ifndef STBVOX_CONFIG_DISABLE_TEX2
1715 " vec4 tex2_props = texscale[tex2_id & 63u];\n"
1716 #endif
1717 #else
1718 " vec3 texgen_s = texelFetch(texgen, int(texprojid)).xyz;\n"
1719 " vec3 texgen_t = texelFetch(texgen, int(texprojid+32u)).xyz;\n"
1720 " float tex1_scale = texelFetch(texscale, int(tex1_id & 127u)).x;\n"
1721 " vec4 color = texelFetch(color_table, int(color_id & 63u));\n"
1722 #ifndef STBVOX_CONFIG_DISABLE_TEX2
1723 " vec4 tex2_props = texelFetch(texscale, int(tex1_id & 127u));\n"
1724 #endif
1725 #endif
1726
1727 #ifndef STBVOX_CONFIG_DISABLE_TEX2
1728 " float tex2_scale = tex2_props.y;\n"
1729 " bool texblend_mode = tex2_props.z != 0.0;\n"
1730 #endif
1731 " vec2 texcoord;\n"
1732 " vec3 texturespace_pos = voxelspace_pos + transform[2].xyz;\n"
1733 " texcoord.s = dot(texturespace_pos, texgen_s);\n"
1734 " texcoord.t = dot(texturespace_pos, texgen_t);\n"
1735
1736 " vec2 texcoord_1 = tex1_scale * texcoord;\n"
1737 #ifndef STBVOX_CONFIG_DISABLE_TEX2
1738 " vec2 texcoord_2 = tex2_scale * texcoord;\n"
1739 #endif
1740
1741 #ifdef STBVOX_CONFIG_TEX1_EDGE_CLAMP
1742 " texcoord_1 = texcoord_1 - floor(texcoord_1);\n"
1743 " vec4 tex1 = textureGrad(tex_array[0], vec3(texcoord_1, float(tex1_id)), dFdx(tex1_scale*texcoord), dFdy(tex1_scale*texcoord));\n"
1744 #else
1745 " vec4 tex1 = texture(tex_array[0], vec3(texcoord_1, float(tex1_id)));\n"
1746 #endif
1747
1748 #ifndef STBVOX_CONFIG_DISABLE_TEX2
1749 #ifdef STBVOX_CONFIG_TEX2_EDGE_CLAMP
1750 " texcoord_2 = texcoord_2 - floor(texcoord_2);\n"
1751 " vec4 tex2 = textureGrad(tex_array[0], vec3(texcoord_2, float(tex2_id)), dFdx(tex2_scale*texcoord), dFdy(tex2_scale*texcoord));\n"
1752 #else
1753 " vec4 tex2 = texture(tex_array[1], vec3(texcoord_2, float(tex2_id)));\n"
1754 #endif
1755 #endif
1756
1757 " bool emissive = (color.a > 1.0);\n"
1758 " color.a = min(color.a, 1.0);\n"
1759
1760 // recolor textures
1761 " if ((color_id & 64u) != 0u) tex1.rgba *= color.rgba;\n"
1762 " fragment_alpha = tex1.a;\n"
1763 #ifndef STBVOX_CONFIG_DISABLE_TEX2
1764 " if ((color_id & 128u) != 0u) tex2.rgba *= color.rgba;\n"
1765
1766 #ifdef STBVOX_CONFIG_PREMULTIPLIED_ALPHA
1767 " tex2.rgba *= texlerp;\n"
1768 #else
1769 " tex2.a *= texlerp;\n"
1770 #endif
1771
1772 " if (texblend_mode)\n"
1773 " albedo = tex1.xyz * rlerp(tex2.a, vec3(1.0,1.0,1.0), 2.0*tex2.xyz);\n"
1774 " else {\n"
1775 #ifdef STBVOX_CONFIG_PREMULTIPLIED_ALPHA
1776 " albedo = (1.0-tex2.a)*tex1.xyz + tex2.xyz;\n"
1777 #else
1778 " albedo = rlerp(tex2.a, tex1.xyz, tex2.xyz);\n"
1779 #endif
1780 " fragment_alpha = tex1.a*(1-tex2.a)+tex2.a;\n"
1781 " }\n"
1782 #else
1783 " albedo = tex1.xyz;\n"
1784 #endif
1785
1786 #else // UNTEXTURED
1787 " vec4 color;"
1788 " color.xyz = vec3(facedata.xyz) / 255.0;\n"
1789 " bool emissive = false;\n"
1790 " albedo = color.xyz;\n"
1791 " fragment_alpha = 1.0;\n"
1792 #endif
1793
1794 #ifdef STBVOX_ICONFIG_VARYING_VERTEX_NORMALS
1795 // currently, there are no modes that trigger this path; idea is that there
1796 // could be a couple of bits per vertex to perturb the normal to e.g. get curved look
1797 " vec3 normal = normalize(vnormal);\n"
1798 #else
1799 " vec3 normal = vnormal;\n"
1800 #endif
1801
1802 " vec3 ambient_color = dot(normal, ambient[0].xyz) * ambient[1].xyz + ambient[2].xyz;\n"
1803
1804 " ambient_color = clamp(ambient_color, 0.0, 1.0);"
1805 " ambient_color *= amb_occ;\n"
1806
1807 " vec3 lit_color;\n"
1808 " if (!emissive)\n"
1809 #if defined(STBVOX_ICONFIG_LIGHTING) || defined(STBVOX_CONFIG_LIGHTING_SIMPLE)
1810 " lit_color = compute_lighting(voxelspace_pos + transform[1], normal, albedo, ambient_color);\n"
1811 #else
1812 " lit_color = albedo * ambient_color ;\n"
1813 #endif
1814 " else\n"
1815 " lit_color = albedo;\n"
1816
1817 #if defined(STBVOX_ICONFIG_FOG) || defined(STBVOX_CONFIG_FOG_SMOOTHSTEP)
1818 " vec3 dist = voxelspace_pos + (transform[1] - camera_pos.xyz);\n"
1819 " lit_color = compute_fog(lit_color, dist, fragment_alpha);\n"
1820 #endif
1821
1822 #ifdef STBVOX_CONFIG_UNPREMULTIPLY
1823 " vec4 final_color = vec4(lit_color/fragment_alpha, fragment_alpha);\n"
1824 #else
1825 " vec4 final_color = vec4(lit_color, fragment_alpha);\n"
1826 #endif
1827 " outcolor = final_color;\n"
1828 "}\n"
1829
1830 #ifdef STBVOX_CONFIG_LIGHTING_SIMPLE
1831 "\n"
1832 "uniform vec3 light_source[2];\n"
1833 "vec3 compute_lighting(vec3 pos, vec3 norm, vec3 albedo, vec3 ambient)\n"
1834 "{\n"
1835 " vec3 light_dir = light_source[0] - pos;\n"
1836 " float lambert = dot(light_dir, norm) / dot(light_dir, light_dir);\n"
1837 " vec3 diffuse = clamp(light_source[1] * clamp(lambert, 0.0, 1.0), 0.0, 1.0);\n"
1838 " return (diffuse + ambient) * albedo;\n"
1839 "}\n"
1840 #endif
1841
1842 #ifdef STBVOX_CONFIG_FOG_SMOOTHSTEP
1843 "\n"
1844 "vec3 compute_fog(vec3 color, vec3 relative_pos, float fragment_alpha)\n"
1845 "{\n"
1846 " float f = dot(relative_pos,relative_pos)*ambient[3].w;\n"
1847 //" f = rlerp(f, -2,1);\n"
1848 " f = clamp(f, 0.0, 1.0);\n"
1849 " f = 3.0*f*f - 2.0*f*f*f;\n" // smoothstep
1850 //" f = f*f;\n" // fade in more smoothly
1851 #ifdef STBVOX_CONFIG_PREMULTIPLIED_ALPHA
1852 " return rlerp(f, color.xyz, ambient[3].xyz*fragment_alpha);\n"
1853 #else
1854 " return rlerp(f, color.xyz, ambient[3].xyz);\n"
1855 #endif
1856 "}\n"
1857 #endif
1858 };
1859
1860
1861 // still requires full alpha lookups, including tex2 if texblend is enabled
1862 static const char *stbvox_fragment_program_alpha_only =
1863 {
1864 STBVOX_SHADER_VERSION
1865
1866 // vertex-shader output data
1867 "flat in uvec4 facedata;\n"
1868 " in vec3 voxelspace_pos;\n"
1869 " in float texlerp;\n"
1870
1871 // per-buffer data
1872 "uniform vec3 transform[3];\n"
1873
1874 #ifndef STBVOX_ICONFIG_UNTEXTURED
1875 // generally constant data
1876 "uniform sampler2DArray tex_array[2];\n"
1877
1878 #ifdef STBVOX_CONFIG_PREFER_TEXBUFFER
1879 "uniform samplerBuffer texscale;\n"
1880 "uniform samplerBuffer texgen;\n"
1881 #else
1882 "uniform vec4 texscale[64];\n" // instead of 128, to avoid running out of uniforms
1883 "uniform vec3 texgen[64];\n"
1884 #endif
1885 #endif
1886
1887 "out vec4 outcolor;\n"
1888
1889 "void main()\n"
1890 "{\n"
1891 " vec3 albedo;\n"
1892 " float fragment_alpha;\n"
1893
1894 #ifndef STBVOX_ICONFIG_UNTEXTURED
1895 // unpack the values
1896 " uint tex1_id = facedata.x;\n"
1897 " uint tex2_id = facedata.y;\n"
1898 " uint texprojid = facedata.w & 31u;\n"
1899 " uint color_id = facedata.z;\n"
1900
1901 #ifndef STBVOX_CONFIG_PREFER_TEXBUFFER
1902 // load from uniforms / texture buffers
1903 " vec3 texgen_s = texgen[texprojid];\n"
1904 " vec3 texgen_t = texgen[texprojid+32u];\n"
1905 " float tex1_scale = texscale[tex1_id & 63u].x;\n"
1906 " vec4 color = color_table[color_id & 63u];\n"
1907 " vec4 tex2_props = texscale[tex2_id & 63u];\n"
1908 #else
1909 " vec3 texgen_s = texelFetch(texgen, int(texprojid)).xyz;\n"
1910 " vec3 texgen_t = texelFetch(texgen, int(texprojid+32u)).xyz;\n"
1911 " float tex1_scale = texelFetch(texscale, int(tex1_id & 127u)).x;\n"
1912 " vec4 color = texelFetch(color_table, int(color_id & 63u));\n"
1913 " vec4 tex2_props = texelFetch(texscale, int(tex2_id & 127u));\n"
1914 #endif
1915
1916 #ifndef STBVOX_CONFIG_DISABLE_TEX2
1917 " float tex2_scale = tex2_props.y;\n"
1918 " bool texblend_mode = tex2_props.z &((facedata.w & 128u) != 0u);\n"
1919 #endif
1920
1921 " color.a = min(color.a, 1.0);\n"
1922
1923 " vec2 texcoord;\n"
1924 " vec3 texturespace_pos = voxelspace_pos + transform[2].xyz;\n"
1925 " texcoord.s = dot(texturespace_pos, texgen_s);\n"
1926 " texcoord.t = dot(texturespace_pos, texgen_t);\n"
1927
1928 " vec2 texcoord_1 = tex1_scale * texcoord;\n"
1929 " vec2 texcoord_2 = tex2_scale * texcoord;\n"
1930
1931 #ifdef STBVOX_CONFIG_TEX1_EDGE_CLAMP
1932 " texcoord_1 = texcoord_1 - floor(texcoord_1);\n"
1933 " vec4 tex1 = textureGrad(tex_array[0], vec3(texcoord_1, float(tex1_id)), dFdx(tex1_scale*texcoord), dFdy(tex1_scale*texcoord));\n"
1934 #else
1935 " vec4 tex1 = texture(tex_array[0], vec3(texcoord_1, float(tex1_id)));\n"
1936 #endif
1937
1938 " if ((color_id & 64u) != 0u) tex1.a *= color.a;\n"
1939 " fragment_alpha = tex1.a;\n"
1940
1941 #ifndef STBVOX_CONFIG_DISABLE_TEX2
1942 " if (!texblend_mode) {\n"
1943 #ifdef STBVOX_CONFIG_TEX2_EDGE_CLAMP
1944 " texcoord_2 = texcoord_2 - floor(texcoord_2);\n"
1945 " vec4 tex2 = textureGrad(tex_array[0], vec3(texcoord_2, float(tex2_id)), dFdx(tex2_scale*texcoord), dFdy(tex2_scale*texcoord));\n"
1946 #else
1947 " vec4 tex2 = texture(tex_array[1], vec3(texcoord_2, float(tex2_id)));\n"
1948 #endif
1949
1950 " tex2.a *= texlerp;\n"
1951 " if ((color_id & 128u) != 0u) tex2.rgba *= color.a;\n"
1952 " fragment_alpha = tex1.a*(1-tex2.a)+tex2.a;\n"
1953 "}\n"
1954 "\n"
1955 #endif
1956
1957 #else // UNTEXTURED
1958 " fragment_alpha = 1.0;\n"
1959 #endif
1960
1961 " outcolor = vec4(0.0, 0.0, 0.0, fragment_alpha);\n"
1962 "}\n"
1963 };
1964
1965
1966 STBVXDEC char *stbvox_get_vertex_shader(void)
1967 {
1968 return (char *) stbvox_vertex_program;
1969 }
1970
1971 STBVXDEC char *stbvox_get_fragment_shader(void)
1972 {
1973 return (char *) stbvox_fragment_program;
1974 }
1975
1976 STBVXDEC char *stbvox_get_fragment_shader_alpha_only(void)
1977 {
1978 return (char *) stbvox_fragment_program_alpha_only;
1979 }
1980
1981 static float stbvox_dummy_transform[3][3];
1982
1983 #ifdef STBVOX_CONFIG_PREFER_TEXBUFFER
1984 #define STBVOX_TEXBUF 1
1985 #else
1986 #define STBVOX_TEXBUF 0
1987 #endif
1988
1989 static stbvox_uniform_info stbvox_uniforms[] =
1990 {
1991 { STBVOX_UNIFORM_TYPE_sampler , 4, 1, (char*) "facearray" , 0 },
1992 { STBVOX_UNIFORM_TYPE_vec3 , 12, 3, (char*) "transform" , stbvox_dummy_transform[0] },
1993 { STBVOX_UNIFORM_TYPE_sampler , 4, 2, (char*) "tex_array" , 0 },
1994 { STBVOX_UNIFORM_TYPE_vec4 , 16, 128, (char*) "texscale" , stbvox_default_texscale[0] , STBVOX_TEXBUF },
1995 { STBVOX_UNIFORM_TYPE_vec4 , 16, 64, (char*) "color_table" , stbvox_default_palette[0] , STBVOX_TEXBUF },
1996 { STBVOX_UNIFORM_TYPE_vec3 , 12, 32, (char*) "normal_table" , stbvox_default_normals[0] },
1997 { STBVOX_UNIFORM_TYPE_vec3 , 12, 64, (char*) "texgen" , stbvox_default_texgen[0][0], STBVOX_TEXBUF },
1998 { STBVOX_UNIFORM_TYPE_vec4 , 16, 4, (char*) "ambient" , stbvox_default_ambient[0] },
1999 { STBVOX_UNIFORM_TYPE_vec4 , 16, 1, (char*) "camera_pos" , stbvox_dummy_transform[0] },
2000 };
2001
2002 STBVXDEC int stbvox_get_uniform_info(stbvox_uniform_info *info, int uniform)
2003 {
2004 if (uniform < 0 || uniform >= STBVOX_UNIFORM_count)
2005 return 0;
2006
2007 *info = stbvox_uniforms[uniform];
2008 return 1;
2009 }
2010
2011 #define STBVOX_GET_GEO(geom_data) ((geom_data) & 15)
2012
2013 typedef struct
2014 {
2015 unsigned char block:2;
2016 unsigned char overlay:2;
2017 unsigned char facerot:2;
2018 unsigned char ecolor:2;
2019 } stbvox_rotate;
2020
2021 typedef struct
2022 {
2023 unsigned char x,y,z;
2024 } stbvox_pos;
2025
2026 static unsigned char stbvox_rotate_face[6][4] =
2027 {
2028 { 0,1,2,3 },
2029 { 1,2,3,0 },
2030 { 2,3,0,1 },
2031 { 3,0,1,2 },
2032 { 4,4,4,4 },
2033 { 5,5,5,5 },
2034 };
2035
2036 #define STBVOX_ROTATE(x,r) stbvox_rotate_face[x][r] // (((x)+(r))&3)
2037
2038 stbvox_mesh_face stbvox_compute_mesh_face_value(stbvox_mesh_maker *mm, stbvox_rotate rot, int face, int v_off, int normal)
2039 {
2040 stbvox_mesh_face face_data = { 0 };
2041 stbvox_block_type bt = mm->input.blocktype[v_off];
2042 unsigned char bt_face = STBVOX_ROTATE(face, rot.block);
2043 int facerot = rot.facerot;
2044
2045 #ifdef STBVOX_ICONFIG_UNTEXTURED
2046 if (mm->input.rgb) {
2047 face_data.tex1 = mm->input.rgb[v_off].r;
2048 face_data.tex2 = mm->input.rgb[v_off].g;
2049 face_data.color = mm->input.rgb[v_off].b;
2050 face_data.face_info = (normal<<2);
2051 return face_data;
2052 }
2053 #else
2054 unsigned char color_face;
2055
2056 if (mm->input.color)
2057 face_data.color = mm->input.color[v_off];
2058
2059 if (mm->input.block_tex1)
2060 face_data.tex1 = mm->input.block_tex1[bt];
2061 else if (mm->input.block_tex1_face)
2062 face_data.tex1 = mm->input.block_tex1_face[bt][bt_face];
2063 else
2064 face_data.tex1 = bt;
2065
2066 if (mm->input.block_tex2)
2067 face_data.tex2 = mm->input.block_tex2[bt];
2068 else if (mm->input.block_tex2_face)
2069 face_data.tex2 = mm->input.block_tex2_face[bt][bt_face];
2070
2071 if (mm->input.block_color) {
2072 unsigned char mcol = mm->input.block_color[bt];
2073 if (mcol)
2074 face_data.color = mcol;
2075 } else if (mm->input.block_color_face) {
2076 unsigned char mcol = mm->input.block_color_face[bt][bt_face];
2077 if (mcol)
2078 face_data.color = mcol;
2079 }
2080
2081 if (face <= STBVOX_FACE_south) {
2082 if (mm->input.side_texrot)
2083 facerot = mm->input.side_texrot[v_off] >> (2 * face);
2084 else if (mm->input.block_side_texrot)
2085 facerot = mm->input.block_side_texrot[v_off] >> (2 * bt_face);
2086 }
2087
2088 if (mm->input.overlay) {
2089 int over_face = STBVOX_ROTATE(face, rot.overlay);
2090 unsigned char over = mm->input.overlay[v_off];
2091 if (over) {
2092 if (mm->input.overlay_tex1) {
2093 unsigned char rep1 = mm->input.overlay_tex1[over][over_face];
2094 if (rep1)
2095 face_data.tex1 = rep1;
2096 }
2097 if (mm->input.overlay_tex2) {
2098 unsigned char rep2 = mm->input.overlay_tex2[over][over_face];
2099 if (rep2)
2100 face_data.tex2 = rep2;
2101 }
2102 if (mm->input.overlay_color) {
2103 unsigned char rep3 = mm->input.overlay_color[over][over_face];
2104 if (rep3)
2105 face_data.color = rep3;
2106 }
2107
2108 if (mm->input.overlay_side_texrot && face <= STBVOX_FACE_south)
2109 facerot = mm->input.overlay_side_texrot[over] >> (2*over_face);
2110 }
2111 }
2112
2113 if (mm->input.tex2_for_tex1)
2114 face_data.tex2 = mm->input.tex2_for_tex1[face_data.tex1];
2115 if (mm->input.tex2)
2116 face_data.tex2 = mm->input.tex2[v_off];
2117 if (mm->input.tex2_replace) {
2118 if (mm->input.tex2_facemask[v_off] & (1 << face))
2119 face_data.tex2 = mm->input.tex2_replace[v_off];
2120 }
2121
2122 color_face = STBVOX_ROTATE(face, rot.ecolor);
2123 if (mm->input.extended_color) {
2124 unsigned char ec = mm->input.extended_color[v_off];
2125 if (mm->input.ecolor_facemask[ec] & (1 << color_face))
2126 face_data.color = mm->input.ecolor_color[ec];
2127 }
2128
2129 if (mm->input.color2) {
2130 if (mm->input.color2_facemask[v_off] & (1 << color_face))
2131 face_data.color = mm->input.color2[v_off];
2132 if (mm->input.color3 && (mm->input.color3_facemask[v_off] & (1 << color_face)))
2133 face_data.color = mm->input.color3[v_off];
2134 }
2135 #endif
2136
2137 face_data.face_info = (normal<<2) + facerot;
2138 return face_data;
2139 }
2140
2141 // these are the types of faces each block can have
2142 enum
2143 {
2144 STBVOX_FT_none ,
2145 STBVOX_FT_upper ,
2146 STBVOX_FT_lower ,
2147 STBVOX_FT_solid ,
2148 STBVOX_FT_diag_012,
2149 STBVOX_FT_diag_023,
2150 STBVOX_FT_diag_013,
2151 STBVOX_FT_diag_123,
2152 STBVOX_FT_force , // can't be covered up, used for internal faces, also hides nothing
2153 STBVOX_FT_partial , // only covered by solid, never covers anything else
2154
2155 STBVOX_FT_count
2156 };
2157
2158 static unsigned char stbvox_face_lerp[6] = { 0,2,0,2,4,4 };
2159 static unsigned char stbvox_vert3_lerp[5] = { 0,3,6,9,12 };
2160 static unsigned char stbvox_vert_lerp_for_face_lerp[4] = { 0, 4, 7, 7 };
2161 static unsigned char stbvox_face3_lerp[6] = { 0,3,6,9,12,14 };
2162 static unsigned char stbvox_vert_lerp_for_simple[4] = { 0,2,5,7 };
2163 static unsigned char stbvox_face3_updown[8] = { 0,2,5,7,0,2,5,7 }; // ignore top bit
2164
2165 // vertex offsets for face vertices
2166 static unsigned char stbvox_vertex_vector[6][4][3] =
2167 {
2168 { { 1,0,1 }, { 1,1,1 }, { 1,1,0 }, { 1,0,0 } }, // east
2169 { { 1,1,1 }, { 0,1,1 }, { 0,1,0 }, { 1,1,0 } }, // north
2170 { { 0,1,1 }, { 0,0,1 }, { 0,0,0 }, { 0,1,0 } }, // west
2171 { { 0,0,1 }, { 1,0,1 }, { 1,0,0 }, { 0,0,0 } }, // south
2172 { { 0,1,1 }, { 1,1,1 }, { 1,0,1 }, { 0,0,1 } }, // up
2173 { { 0,0,0 }, { 1,0,0 }, { 1,1,0 }, { 0,1,0 } }, // down
2174 };
2175
2176 // stbvox_vertex_vector, but read coordinates as binary numbers, zyx
2177 static unsigned char stbvox_vertex_selector[6][4] =
2178 {
2179 { 5,7,3,1 },
2180 { 7,6,2,3 },
2181 { 6,4,0,2 },
2182 { 4,5,1,0 },
2183 { 6,7,5,4 },
2184 { 0,1,3,2 },
2185 };
2186
2187 static stbvox_mesh_vertex stbvox_vmesh_delta_normal[6][4] =
2188 {
2189 { stbvox_vertex_encode(1,0,1,0,0) ,
2190 stbvox_vertex_encode(1,1,1,0,0) ,
2191 stbvox_vertex_encode(1,1,0,0,0) ,
2192 stbvox_vertex_encode(1,0,0,0,0) },
2193 { stbvox_vertex_encode(1,1,1,0,0) ,
2194 stbvox_vertex_encode(0,1,1,0,0) ,
2195 stbvox_vertex_encode(0,1,0,0,0) ,
2196 stbvox_vertex_encode(1,1,0,0,0) },
2197 { stbvox_vertex_encode(0,1,1,0,0) ,
2198 stbvox_vertex_encode(0,0,1,0,0) ,
2199 stbvox_vertex_encode(0,0,0,0,0) ,
2200 stbvox_vertex_encode(0,1,0,0,0) },
2201 { stbvox_vertex_encode(0,0,1,0,0) ,
2202 stbvox_vertex_encode(1,0,1,0,0) ,
2203 stbvox_vertex_encode(1,0,0,0,0) ,
2204 stbvox_vertex_encode(0,0,0,0,0) },
2205 { stbvox_vertex_encode(0,1,1,0,0) ,
2206 stbvox_vertex_encode(1,1,1,0,0) ,
2207 stbvox_vertex_encode(1,0,1,0,0) ,
2208 stbvox_vertex_encode(0,0,1,0,0) },
2209 { stbvox_vertex_encode(0,0,0,0,0) ,
2210 stbvox_vertex_encode(1,0,0,0,0) ,
2211 stbvox_vertex_encode(1,1,0,0,0) ,
2212 stbvox_vertex_encode(0,1,0,0,0) }
2213 };
2214
2215 static stbvox_mesh_vertex stbvox_vmesh_pre_vheight[6][4] =
2216 {
2217 { stbvox_vertex_encode(1,0,0,0,0) ,
2218 stbvox_vertex_encode(1,1,0,0,0) ,
2219 stbvox_vertex_encode(1,1,0,0,0) ,
2220 stbvox_vertex_encode(1,0,0,0,0) },
2221 { stbvox_vertex_encode(1,1,0,0,0) ,
2222 stbvox_vertex_encode(0,1,0,0,0) ,
2223 stbvox_vertex_encode(0,1,0,0,0) ,
2224 stbvox_vertex_encode(1,1,0,0,0) },
2225 { stbvox_vertex_encode(0,1,0,0,0) ,
2226 stbvox_vertex_encode(0,0,0,0,0) ,
2227 stbvox_vertex_encode(0,0,0,0,0) ,
2228 stbvox_vertex_encode(0,1,0,0,0) },
2229 { stbvox_vertex_encode(0,0,0,0,0) ,
2230 stbvox_vertex_encode(1,0,0,0,0) ,
2231 stbvox_vertex_encode(1,0,0,0,0) ,
2232 stbvox_vertex_encode(0,0,0,0,0) },
2233 { stbvox_vertex_encode(0,1,0,0,0) ,
2234 stbvox_vertex_encode(1,1,0,0,0) ,
2235 stbvox_vertex_encode(1,0,0,0,0) ,
2236 stbvox_vertex_encode(0,0,0,0,0) },
2237 { stbvox_vertex_encode(0,0,0,0,0) ,
2238 stbvox_vertex_encode(1,0,0,0,0) ,
2239 stbvox_vertex_encode(1,1,0,0,0) ,
2240 stbvox_vertex_encode(0,1,0,0,0) }
2241 };
2242
2243 static stbvox_mesh_vertex stbvox_vmesh_delta_half_z[6][4] =
2244 {
2245 { stbvox_vertex_encode(1,0,2,0,0) ,
2246 stbvox_vertex_encode(1,1,2,0,0) ,
2247 stbvox_vertex_encode(1,1,0,0,0) ,
2248 stbvox_vertex_encode(1,0,0,0,0) },
2249 { stbvox_vertex_encode(1,1,2,0,0) ,
2250 stbvox_vertex_encode(0,1,2,0,0) ,
2251 stbvox_vertex_encode(0,1,0,0,0) ,
2252 stbvox_vertex_encode(1,1,0,0,0) },
2253 { stbvox_vertex_encode(0,1,2,0,0) ,
2254 stbvox_vertex_encode(0,0,2,0,0) ,
2255 stbvox_vertex_encode(0,0,0,0,0) ,
2256 stbvox_vertex_encode(0,1,0,0,0) },
2257 { stbvox_vertex_encode(0,0,2,0,0) ,
2258 stbvox_vertex_encode(1,0,2,0,0) ,
2259 stbvox_vertex_encode(1,0,0,0,0) ,
2260 stbvox_vertex_encode(0,0,0,0,0) },
2261 { stbvox_vertex_encode(0,1,2,0,0) ,
2262 stbvox_vertex_encode(1,1,2,0,0) ,
2263 stbvox_vertex_encode(1,0,2,0,0) ,
2264 stbvox_vertex_encode(0,0,2,0,0) },
2265 { stbvox_vertex_encode(0,0,0,0,0) ,
2266 stbvox_vertex_encode(1,0,0,0,0) ,
2267 stbvox_vertex_encode(1,1,0,0,0) ,
2268 stbvox_vertex_encode(0,1,0,0,0) }
2269 };
2270
2271 static stbvox_mesh_vertex stbvox_vmesh_crossed_pair[6][4] =
2272 {
2273 { stbvox_vertex_encode(1,0,2,0,0) ,
2274 stbvox_vertex_encode(0,1,2,0,0) ,
2275 stbvox_vertex_encode(0,1,0,0,0) ,
2276 stbvox_vertex_encode(1,0,0,0,0) },
2277 { stbvox_vertex_encode(1,1,2,0,0) ,
2278 stbvox_vertex_encode(0,0,2,0,0) ,
2279 stbvox_vertex_encode(0,0,0,0,0) ,
2280 stbvox_vertex_encode(1,1,0,0,0) },
2281 { stbvox_vertex_encode(0,1,2,0,0) ,
2282 stbvox_vertex_encode(1,0,2,0,0) ,
2283 stbvox_vertex_encode(1,0,0,0,0) ,
2284 stbvox_vertex_encode(0,1,0,0,0) },
2285 { stbvox_vertex_encode(0,0,2,0,0) ,
2286 stbvox_vertex_encode(1,1,2,0,0) ,
2287 stbvox_vertex_encode(1,1,0,0,0) ,
2288 stbvox_vertex_encode(0,0,0,0,0) },
2289 // not used, so we leave it non-degenerate to make sure it doesn't get gen'd accidentally
2290 { stbvox_vertex_encode(0,1,2,0,0) ,
2291 stbvox_vertex_encode(1,1,2,0,0) ,
2292 stbvox_vertex_encode(1,0,2,0,0) ,
2293 stbvox_vertex_encode(0,0,2,0,0) },
2294 { stbvox_vertex_encode(0,0,0,0,0) ,
2295 stbvox_vertex_encode(1,0,0,0,0) ,
2296 stbvox_vertex_encode(1,1,0,0,0) ,
2297 stbvox_vertex_encode(0,1,0,0,0) }
2298 };
2299
2300 #define STBVOX_MAX_GEOM 16
2301 #define STBVOX_NUM_ROTATION 4
2302
2303 // this is used to determine if a face is ever generated at all
2304 static unsigned char stbvox_hasface[STBVOX_MAX_GEOM][STBVOX_NUM_ROTATION] =
2305 {
2306 { 0,0,0,0 }, // empty
2307 { 0,0,0,0 }, // knockout
2308 { 63,63,63,63 }, // solid
2309 { 63,63,63,63 }, // transp
2310 { 63,63,63,63 }, // slab
2311 { 63,63,63,63 }, // slab
2312 { 1|2|4|48, 8|1|2|48, 4|8|1|48, 2|4|8|48, }, // floor slopes
2313 { 1|2|4|48, 8|1|2|48, 4|8|1|48, 2|4|8|48, }, // ceil slopes
2314 { 47,47,47,47 }, // wall-projected diagonal with down face
2315 { 31,31,31,31 }, // wall-projected diagonal with up face
2316 { 63,63,63,63 }, // crossed-pair has special handling, but avoid early-out
2317 { 63,63,63,63 }, // force
2318 { 63,63,63,63 }, // vheight
2319 { 63,63,63,63 }, // vheight
2320 { 63,63,63,63 }, // vheight
2321 { 63,63,63,63 }, // vheight
2322 };
2323
2324 // this determines which face type above is visible on each side of the geometry
2325 static unsigned char stbvox_facetype[STBVOX_GEOM_count][6] =
2326 {
2327 { 0, }, // STBVOX_GEOM_empty
2328 { STBVOX_FT_solid, STBVOX_FT_solid, STBVOX_FT_solid, STBVOX_FT_solid, STBVOX_FT_solid, STBVOX_FT_solid }, // knockout
2329 { STBVOX_FT_solid, STBVOX_FT_solid, STBVOX_FT_solid, STBVOX_FT_solid, STBVOX_FT_solid, STBVOX_FT_solid }, // solid
2330 { STBVOX_FT_force, STBVOX_FT_force, STBVOX_FT_force, STBVOX_FT_force, STBVOX_FT_force, STBVOX_FT_force }, // transp
2331
2332 { STBVOX_FT_upper, STBVOX_FT_upper, STBVOX_FT_upper, STBVOX_FT_upper, STBVOX_FT_solid, STBVOX_FT_force },
2333 { STBVOX_FT_lower, STBVOX_FT_lower, STBVOX_FT_lower, STBVOX_FT_lower, STBVOX_FT_force, STBVOX_FT_solid },
2334 { STBVOX_FT_diag_123, STBVOX_FT_solid, STBVOX_FT_diag_023, STBVOX_FT_none, STBVOX_FT_force, STBVOX_FT_solid },
2335 { STBVOX_FT_diag_012, STBVOX_FT_solid, STBVOX_FT_diag_013, STBVOX_FT_none, STBVOX_FT_solid, STBVOX_FT_force },
2336
2337 { STBVOX_FT_diag_123, STBVOX_FT_solid, STBVOX_FT_diag_023, STBVOX_FT_force, STBVOX_FT_none, STBVOX_FT_solid },
2338 { STBVOX_FT_diag_012, STBVOX_FT_solid, STBVOX_FT_diag_013, STBVOX_FT_force, STBVOX_FT_solid, STBVOX_FT_none },
2339 { STBVOX_FT_force, STBVOX_FT_force, STBVOX_FT_force, STBVOX_FT_force, 0,0 }, // crossed pair
2340 { STBVOX_FT_force, STBVOX_FT_force, STBVOX_FT_force, STBVOX_FT_force, STBVOX_FT_force, STBVOX_FT_force }, // GEOM_force
2341
2342 { STBVOX_FT_partial,STBVOX_FT_partial,STBVOX_FT_partial,STBVOX_FT_partial, STBVOX_FT_force, STBVOX_FT_solid }, // floor vheight, all neighbors forced
2343 { STBVOX_FT_partial,STBVOX_FT_partial,STBVOX_FT_partial,STBVOX_FT_partial, STBVOX_FT_force, STBVOX_FT_solid }, // floor vheight, all neighbors forced
2344 { STBVOX_FT_partial,STBVOX_FT_partial,STBVOX_FT_partial,STBVOX_FT_partial, STBVOX_FT_solid, STBVOX_FT_force }, // ceil vheight, all neighbors forced
2345 { STBVOX_FT_partial,STBVOX_FT_partial,STBVOX_FT_partial,STBVOX_FT_partial, STBVOX_FT_solid, STBVOX_FT_force }, // ceil vheight, all neighbors forced
2346 };
2347
2348 // This table indicates what normal to use for the "up" face of a sloped geom
2349 // @TODO this could be done with math given the current arrangement of the enum, but let's not require it
2350 static unsigned char stbvox_floor_slope_for_rot[4] =
2351 {
2352 STBVF_su,
2353 STBVF_wu, // @TODO: why is this reversed from what it should be? this is a north-is-up face, so slope should be south&up
2354 STBVF_nu,
2355 STBVF_eu,
2356 };
2357
2358 static unsigned char stbvox_ceil_slope_for_rot[4] =
2359 {
2360 STBVF_sd,
2361 STBVF_ed,
2362 STBVF_nd,
2363 STBVF_wd,
2364 };
2365
2366 // this table indicates whether, for each pair of types above, a face is visible.
2367 // each value indicates whether a given type is visible for all neighbor types
2368 static unsigned short stbvox_face_visible[STBVOX_FT_count] =
2369 {
2370 // we encode the table by listing which cases cause *obscuration*, and bitwise inverting that
2371 // table is pre-shifted by 5 to save a shift when it's accessed
2372 (unsigned short) ((~0x07ff )<<5), // none is completely obscured by everything
2373 (unsigned short) ((~((1<<STBVOX_FT_solid) | (1<<STBVOX_FT_upper) ))<<5), // upper
2374 (unsigned short) ((~((1<<STBVOX_FT_solid) | (1<<STBVOX_FT_lower) ))<<5), // lower
2375 (unsigned short) ((~((1<<STBVOX_FT_solid) ))<<5), // solid is only completely obscured only by solid
2376 (unsigned short) ((~((1<<STBVOX_FT_solid) | (1<<STBVOX_FT_diag_013)))<<5), // diag012 matches diag013
2377 (unsigned short) ((~((1<<STBVOX_FT_solid) | (1<<STBVOX_FT_diag_123)))<<5), // diag023 matches diag123
2378 (unsigned short) ((~((1<<STBVOX_FT_solid) | (1<<STBVOX_FT_diag_012)))<<5), // diag013 matches diag012
2379 (unsigned short) ((~((1<<STBVOX_FT_solid) | (1<<STBVOX_FT_diag_023)))<<5), // diag123 matches diag023
2380 (unsigned short) ((~0 )<<5), // force is always rendered regardless, always forces neighbor
2381 (unsigned short) ((~((1<<STBVOX_FT_solid) ))<<5), // partial is only completely obscured only by solid
2382 };
2383
2384 // the vertex heights of the block types, in binary vertex order (zyx):
2385 // lower: SW, SE, NW, NE; upper: SW, SE, NW, NE
2386 static stbvox_mesh_vertex stbvox_geometry_vheight[8][8] =
2387 {
2388 #define STBVOX_HEIGHTS(a,b,c,d,e,f,g,h) \
2389 { stbvox_vertex_encode(0,0,a,0,0), \
2390 stbvox_vertex_encode(0,0,b,0,0), \
2391 stbvox_vertex_encode(0,0,c,0,0), \
2392 stbvox_vertex_encode(0,0,d,0,0), \
2393 stbvox_vertex_encode(0,0,e,0,0), \
2394 stbvox_vertex_encode(0,0,f,0,0), \
2395 stbvox_vertex_encode(0,0,g,0,0), \
2396 stbvox_vertex_encode(0,0,h,0,0) }
2397
2398 STBVOX_HEIGHTS(0,0,0,0, 2,2,2,2),
2399 STBVOX_HEIGHTS(0,0,0,0, 2,2,2,2),
2400 STBVOX_HEIGHTS(0,0,0,0, 2,2,2,2),
2401 STBVOX_HEIGHTS(0,0,0,0, 2,2,2,2),
2402 STBVOX_HEIGHTS(1,1,1,1, 2,2,2,2),
2403 STBVOX_HEIGHTS(0,0,0,0, 1,1,1,1),
2404 STBVOX_HEIGHTS(0,0,0,0, 0,0,2,2),
2405 STBVOX_HEIGHTS(2,2,0,0, 2,2,2,2),
2406 };
2407
2408 // rotate vertices defined as [z][y][x] coords
2409 static unsigned char stbvox_rotate_vertex[8][4] =
2410 {
2411 { 0,1,3,2 }, // zyx=000
2412 { 1,3,2,0 }, // zyx=001
2413 { 2,0,1,3 }, // zyx=010
2414 { 3,2,0,1 }, // zyx=011
2415 { 4,5,7,6 }, // zyx=100
2416 { 5,7,6,4 }, // zyx=101
2417 { 6,4,5,7 }, // zyx=110
2418 { 7,6,4,5 }, // zyx=111
2419 };
2420
2421 #ifdef STBVOX_CONFIG_OPTIMIZED_VHEIGHT
2422 // optimized vheight generates a single normal over the entire face, even if it's not planar
2423 static unsigned char stbvox_optimized_face_up_normal[4][4][4][4] =
2424 {
2425 {
2426 {
2427 { STBVF_u , STBVF_ne_u, STBVF_ne_u, STBVF_ne_u, },
2428 { STBVF_nw_u, STBVF_nu , STBVF_nu , STBVF_ne_u, },
2429 { STBVF_nw_u, STBVF_nu , STBVF_nu , STBVF_nu , },
2430 { STBVF_nw_u, STBVF_nw_u, STBVF_nu , STBVF_nu , },
2431 },{
2432 { STBVF_su , STBVF_eu , STBVF_eu , STBVF_ne_u, },
2433 { STBVF_u , STBVF_ne_u, STBVF_ne_u, STBVF_ne_u, },
2434 { STBVF_nw_u, STBVF_nu , STBVF_nu , STBVF_ne_u, },
2435 { STBVF_nw_u, STBVF_nu , STBVF_nu , STBVF_nu , },
2436 },{
2437 { STBVF_eu , STBVF_eu , STBVF_eu , STBVF_eu , },
2438 { STBVF_su , STBVF_eu , STBVF_eu , STBVF_ne_u, },
2439 { STBVF_u , STBVF_ne_u, STBVF_ne_u, STBVF_ne_u, },
2440 { STBVF_nw_u, STBVF_nu , STBVF_nu , STBVF_ne_u, },
2441 },{
2442 { STBVF_eu , STBVF_eu , STBVF_eu , STBVF_eu , },
2443 { STBVF_eu , STBVF_eu , STBVF_eu , STBVF_eu , },
2444 { STBVF_su , STBVF_eu , STBVF_eu , STBVF_ne_u, },
2445 { STBVF_u , STBVF_ne_u, STBVF_ne_u, STBVF_ne_u, },
2446 },
2447 },{
2448 {
2449 { STBVF_sw_u, STBVF_u , STBVF_ne_u, STBVF_ne_u, },
2450 { STBVF_wu , STBVF_nw_u, STBVF_nu , STBVF_nu , },
2451 { STBVF_wu , STBVF_nw_u, STBVF_nu , STBVF_nu , },
2452 { STBVF_nw_u, STBVF_nw_u, STBVF_nw_u, STBVF_nu , },
2453 },{
2454 { STBVF_su , STBVF_su , STBVF_eu , STBVF_eu , },
2455 { STBVF_sw_u, STBVF_u , STBVF_ne_u, STBVF_ne_u, },
2456 { STBVF_wu , STBVF_nw_u, STBVF_nu , STBVF_nu , },
2457 { STBVF_wu , STBVF_nw_u, STBVF_nu , STBVF_nu , },
2458 },{
2459 { STBVF_su , STBVF_eu , STBVF_eu , STBVF_eu , },
2460 { STBVF_su , STBVF_su , STBVF_eu , STBVF_eu , },
2461 { STBVF_sw_u, STBVF_u , STBVF_ne_u, STBVF_ne_u, },
2462 { STBVF_wu , STBVF_nw_u, STBVF_nu , STBVF_nu , },
2463 },{
2464 { STBVF_su , STBVF_eu , STBVF_eu , STBVF_eu , },
2465 { STBVF_su , STBVF_eu , STBVF_eu , STBVF_eu , },
2466 { STBVF_su , STBVF_su , STBVF_eu , STBVF_eu , },
2467 { STBVF_sw_u, STBVF_u , STBVF_ne_u, STBVF_ne_u, },
2468 },
2469 },{
2470 {
2471 { STBVF_sw_u, STBVF_sw_u, STBVF_u , STBVF_ne_u, },
2472 { STBVF_wu , STBVF_wu , STBVF_nw_u, STBVF_nu , },
2473 { STBVF_wu , STBVF_wu , STBVF_nw_u, STBVF_nu , },
2474 { STBVF_wu , STBVF_nw_u, STBVF_nw_u, STBVF_nw_u, },
2475 },{
2476 { STBVF_su , STBVF_su , STBVF_su , STBVF_eu , },
2477 { STBVF_sw_u, STBVF_sw_u, STBVF_u , STBVF_ne_u, },
2478 { STBVF_wu , STBVF_wu , STBVF_nw_u, STBVF_nu , },
2479 { STBVF_wu , STBVF_wu , STBVF_nw_u, STBVF_nu , },
2480 },{
2481 { STBVF_su , STBVF_su , STBVF_eu , STBVF_eu , },
2482 { STBVF_su , STBVF_su , STBVF_su , STBVF_eu , },
2483 { STBVF_sw_u, STBVF_sw_u, STBVF_u , STBVF_ne_u, },
2484 { STBVF_wu , STBVF_wu , STBVF_nw_u, STBVF_nu , },
2485 },{
2486 { STBVF_su , STBVF_su , STBVF_eu , STBVF_eu , },
2487 { STBVF_su , STBVF_su , STBVF_eu , STBVF_eu , },
2488 { STBVF_su , STBVF_su , STBVF_su , STBVF_eu , },
2489 { STBVF_sw_u, STBVF_sw_u, STBVF_u , STBVF_ne_u, },
2490 },
2491 },{
2492 {
2493 { STBVF_sw_u, STBVF_sw_u, STBVF_sw_u, STBVF_u , },
2494 { STBVF_sw_u, STBVF_wu , STBVF_wu , STBVF_nw_u, },
2495 { STBVF_wu , STBVF_wu , STBVF_wu , STBVF_nw_u, },
2496 { STBVF_wu , STBVF_wu , STBVF_nw_u, STBVF_nw_u, },
2497 },{
2498 { STBVF_sw_u, STBVF_su , STBVF_su , STBVF_su , },
2499 { STBVF_sw_u, STBVF_sw_u, STBVF_sw_u, STBVF_u , },
2500 { STBVF_sw_u, STBVF_wu , STBVF_wu , STBVF_nw_u, },
2501 { STBVF_wu , STBVF_wu , STBVF_wu , STBVF_nw_u, },
2502 },{
2503 { STBVF_su , STBVF_su , STBVF_su , STBVF_eu , },
2504 { STBVF_sw_u, STBVF_su , STBVF_su , STBVF_su , },
2505 { STBVF_sw_u, STBVF_sw_u, STBVF_sw_u, STBVF_u , },
2506 { STBVF_sw_u, STBVF_wu , STBVF_wu , STBVF_nw_u, },
2507 },{
2508 { STBVF_su , STBVF_su , STBVF_su , STBVF_eu , },
2509 { STBVF_su , STBVF_su , STBVF_su , STBVF_eu , },
2510 { STBVF_sw_u, STBVF_su , STBVF_su , STBVF_su , },
2511 { STBVF_sw_u, STBVF_sw_u, STBVF_sw_u, STBVF_u , },
2512 },
2513 },
2514 };
2515 #else
2516 // which normal to use for a given vheight that's planar
2517 // @TODO: this table was constructed by hand and may have bugs
2518 // nw se sw
2519 static unsigned char stbvox_planar_face_up_normal[4][4][4] =
2520 {
2521 { // sw,se,nw,ne; ne = se+nw-sw
2522 { STBVF_u , 0 , 0 , 0 }, // 0,0,0,0; 1,0,0,-1; 2,0,0,-2; 3,0,0,-3;
2523 { STBVF_u , STBVF_u , 0 , 0 }, // 0,1,0,1; 1,1,0, 0; 2,1,0,-1; 3,1,0,-2;
2524 { STBVF_wu , STBVF_nw_u, STBVF_nu , 0 }, // 0,2,0,2; 1,2,0, 1; 2,2,0, 0; 3,2,0,-1;
2525 { STBVF_wu , STBVF_nw_u, STBVF_nw_u, STBVF_nu }, // 0,3,0,3; 1,3,0, 2; 2,3,0, 1; 3,3,0, 0;
2526 },{
2527 { STBVF_u , STBVF_u , 0 , 0 }, // 0,0,1,1; 1,0,1, 0; 2,0,1,-1; 3,0,1,-2;
2528 { STBVF_sw_u, STBVF_u , STBVF_ne_u, 0 }, // 0,1,1,2; 1,1,1, 1; 2,1,1, 0; 3,1,1,-1;
2529 { STBVF_sw_u, STBVF_u , STBVF_u , STBVF_ne_u }, // 0,2,1,3; 1,2,1, 2; 2,2,1, 1; 3,2,1, 0;
2530 { 0 , STBVF_wu , STBVF_nw_u, STBVF_nu }, // 0,3,1,4; 1,3,1, 3; 2,3,1, 2; 3,3,1, 1;
2531 },{
2532 { STBVF_su , STBVF_se_u, STBVF_eu , 0 }, // 0,0,2,2; 1,0,2, 1; 2,0,2, 0; 3,0,2,-1;
2533 { STBVF_sw_u, STBVF_u , STBVF_u , STBVF_ne_u }, // 0,1,2,3; 1,1,2, 2; 2,1,2, 1; 3,1,2, 0;
2534 { 0 , STBVF_sw_u, STBVF_u , STBVF_ne_u }, // 0,2,2,4; 1,2,2, 3; 2,2,2, 2; 3,2,2, 1;
2535 { 0 , 0 , STBVF_u , STBVF_u }, // 0,3,2,5; 1,3,2, 4; 2,3,2, 3; 3,3,2, 2;
2536 },{
2537 { STBVF_su , STBVF_se_u, STBVF_se_u, STBVF_eu }, // 0,0,3,3; 1,0,3, 2; 2,0,3, 1; 3,0,3, 0;
2538 { 0 , STBVF_su , STBVF_se_u, STBVF_eu }, // 0,1,3,4; 1,1,3, 3; 2,1,3, 2; 3,1,3, 1;
2539 { 0 , 0 , STBVF_u , STBVF_u }, // 0,2,3,5; 1,2,3, 4; 2,2,3, 3; 3,2,3, 2;
2540 { 0 , 0 , 0 , STBVF_u }, // 0,3,3,6; 1,3,3, 5; 2,3,3, 4; 3,3,3, 3;
2541 }
2542 };
2543
2544 // these tables were constructed automatically using a variant of the code
2545 // below; however, they seem wrong, so who knows
2546 static unsigned char stbvox_face_up_normal_012[4][4][4] =
2547 {
2548 {
2549 { STBVF_u , STBVF_ne_u, STBVF_ne_u, STBVF_ne_u, },
2550 { STBVF_wu , STBVF_nu , STBVF_ne_u, STBVF_ne_u, },
2551 { STBVF_wu , STBVF_nw_u, STBVF_nu , STBVF_ne_u, },
2552 { STBVF_wu , STBVF_nw_u, STBVF_nw_u, STBVF_nu , },
2553 },{
2554 { STBVF_su , STBVF_eu , STBVF_ne_u, STBVF_ne_u, },
2555 { STBVF_sw_u, STBVF_u , STBVF_ne_u, STBVF_ne_u, },
2556 { STBVF_sw_u, STBVF_wu , STBVF_nu , STBVF_ne_u, },
2557 { STBVF_sw_u, STBVF_wu , STBVF_nw_u, STBVF_nu , },
2558 },{
2559 { STBVF_su , STBVF_eu , STBVF_eu , STBVF_ne_u, },
2560 { STBVF_sw_u, STBVF_su , STBVF_eu , STBVF_ne_u, },
2561 { STBVF_sw_u, STBVF_sw_u, STBVF_u , STBVF_ne_u, },
2562 { STBVF_sw_u, STBVF_sw_u, STBVF_wu , STBVF_nu , },
2563 },{
2564 { STBVF_su , STBVF_su , STBVF_eu , STBVF_eu , },
2565 { STBVF_sw_u, STBVF_su , STBVF_eu , STBVF_eu , },
2566 { STBVF_sw_u, STBVF_sw_u, STBVF_su , STBVF_eu , },
2567 { STBVF_sw_u, STBVF_sw_u, STBVF_sw_u, STBVF_u , },
2568 }
2569 };
2570
2571 static unsigned char stbvox_face_up_normal_013[4][4][4] =
2572 {
2573 {
2574 { STBVF_u , STBVF_eu , STBVF_eu , STBVF_eu , },
2575 { STBVF_nw_u, STBVF_nu , STBVF_ne_u, STBVF_ne_u, },
2576 { STBVF_nw_u, STBVF_nw_u, STBVF_nu , STBVF_ne_u, },
2577 { STBVF_nw_u, STBVF_nw_u, STBVF_nw_u, STBVF_nu , },
2578 },{
2579 { STBVF_su , STBVF_eu , STBVF_eu , STBVF_eu , },
2580 { STBVF_wu , STBVF_u , STBVF_eu , STBVF_eu , },
2581 { STBVF_nw_u, STBVF_nw_u, STBVF_nu , STBVF_ne_u, },
2582 { STBVF_nw_u, STBVF_nw_u, STBVF_nw_u, STBVF_nu , },
2583 },{
2584 { STBVF_su , STBVF_su , STBVF_su , STBVF_eu , },
2585 { STBVF_sw_u, STBVF_su , STBVF_eu , STBVF_eu , },
2586 { STBVF_wu , STBVF_wu , STBVF_u , STBVF_eu , },
2587 { STBVF_nw_u, STBVF_nw_u, STBVF_nw_u, STBVF_nu , },
2588 },{
2589 { STBVF_su , STBVF_su , STBVF_su , STBVF_eu , },
2590 { STBVF_sw_u, STBVF_su , STBVF_su , STBVF_su , },
2591 { STBVF_sw_u, STBVF_sw_u, STBVF_su , STBVF_eu , },
2592 { STBVF_wu , STBVF_wu , STBVF_wu , STBVF_u , },
2593 }
2594 };
2595
2596 static unsigned char stbvox_face_up_normal_023[4][4][4] =
2597 {
2598 {
2599 { STBVF_u , STBVF_nu , STBVF_nu , STBVF_nu , },
2600 { STBVF_eu , STBVF_eu , STBVF_ne_u, STBVF_ne_u, },
2601 { STBVF_su , STBVF_eu , STBVF_eu , STBVF_ne_u, },
2602 { STBVF_eu , STBVF_eu , STBVF_eu , STBVF_eu , },
2603 },{
2604 { STBVF_wu , STBVF_nw_u, STBVF_nw_u, STBVF_nw_u, },
2605 { STBVF_su , STBVF_u , STBVF_nu , STBVF_nu , },
2606 { STBVF_su , STBVF_eu , STBVF_eu , STBVF_ne_u, },
2607 { STBVF_su , STBVF_su , STBVF_eu , STBVF_eu , },
2608 },{
2609 { STBVF_wu , STBVF_nw_u, STBVF_nw_u, STBVF_nw_u, },
2610 { STBVF_sw_u, STBVF_wu , STBVF_nw_u, STBVF_nw_u, },
2611 { STBVF_su , STBVF_su , STBVF_u , STBVF_nu , },
2612 { STBVF_su , STBVF_su , STBVF_eu , STBVF_eu , },
2613 },{
2614 { STBVF_wu , STBVF_nw_u, STBVF_nw_u, STBVF_nw_u, },
2615 { STBVF_sw_u, STBVF_wu , STBVF_nw_u, STBVF_nw_u, },
2616 { STBVF_sw_u, STBVF_sw_u, STBVF_wu , STBVF_nw_u, },
2617 { STBVF_su , STBVF_su , STBVF_su , STBVF_u , },
2618 }
2619 };
2620
2621 static unsigned char stbvox_face_up_normal_123[4][4][4] =
2622 {
2623 {
2624 { STBVF_u , STBVF_nu , STBVF_nu , STBVF_nu , },
2625 { STBVF_eu , STBVF_ne_u, STBVF_ne_u, STBVF_ne_u, },
2626 { STBVF_eu , STBVF_ne_u, STBVF_ne_u, STBVF_ne_u, },
2627 { STBVF_eu , STBVF_ne_u, STBVF_ne_u, STBVF_ne_u, },
2628 },{
2629 { STBVF_sw_u, STBVF_wu , STBVF_nw_u, STBVF_nw_u, },
2630 { STBVF_su , STBVF_u , STBVF_nu , STBVF_nu , },
2631 { STBVF_eu , STBVF_eu , STBVF_ne_u, STBVF_ne_u, },
2632 { STBVF_eu , STBVF_eu , STBVF_ne_u, STBVF_ne_u, },
2633 },{
2634 { STBVF_sw_u, STBVF_sw_u, STBVF_wu , STBVF_nw_u, },
2635 { STBVF_sw_u, STBVF_sw_u, STBVF_wu , STBVF_nw_u, },
2636 { STBVF_su , STBVF_su , STBVF_u , STBVF_nu , },
2637 { STBVF_su , STBVF_eu , STBVF_eu , STBVF_ne_u, },
2638 },{
2639 { STBVF_sw_u, STBVF_sw_u, STBVF_sw_u, STBVF_wu , },
2640 { STBVF_sw_u, STBVF_sw_u, STBVF_sw_u, STBVF_wu , },
2641 { STBVF_sw_u, STBVF_sw_u, STBVF_sw_u, STBVF_wu , },
2642 { STBVF_su , STBVF_su , STBVF_su , STBVF_u , },
2643 }
2644 };
2645 #endif
2646
2647 void stbvox_get_quad_vertex_pointer(stbvox_mesh_maker *mm, int mesh, stbvox_mesh_vertex **vertices, stbvox_mesh_face face)
2648 {
2649 char *p = mm->output_cur[mesh][0];
2650 int step = mm->output_step[mesh][0];
2651
2652 // allocate a new quad from the mesh
2653 vertices[0] = (stbvox_mesh_vertex *) p; p += step;
2654 vertices[1] = (stbvox_mesh_vertex *) p; p += step;
2655 vertices[2] = (stbvox_mesh_vertex *) p; p += step;
2656 vertices[3] = (stbvox_mesh_vertex *) p; p += step;
2657 mm->output_cur[mesh][0] = p;
2658
2659 // output the face
2660 #ifdef STBVOX_ICONFIG_FACE_ATTRIBUTE
2661 // write face as interleaved vertex data
2662 *(stbvox_mesh_face *) (vertices[0]+1) = face;
2663 *(stbvox_mesh_face *) (vertices[1]+1) = face;
2664 *(stbvox_mesh_face *) (vertices[2]+1) = face;
2665 *(stbvox_mesh_face *) (vertices[3]+1) = face;
2666 #else
2667 *(stbvox_mesh_face *) mm->output_cur[mesh][1] = face;
2668 mm->output_cur[mesh][1] += 4;
2669 #endif
2670 }
2671
2672 void stbvox_make_mesh_for_face(stbvox_mesh_maker *mm, stbvox_rotate rot, int face, int v_off, stbvox_pos pos, stbvox_mesh_vertex vertbase, stbvox_mesh_vertex *face_coord, unsigned char mesh, int normal)
2673 {
2674 stbvox_mesh_face face_data = stbvox_compute_mesh_face_value(mm,rot,face,v_off, normal);
2675
2676 // still need to compute ao & texlerp for each vertex
2677
2678 // first compute texlerp into p1
2679 stbvox_mesh_vertex p1[4] = { 0 };
2680
2681 #if defined(STBVOX_CONFIG_DOWN_TEXLERP_PACKED) && defined(STBVOX_CONFIG_UP_TEXLERP_PACKED)
2682 #define STBVOX_USE_PACKED(f) ((f) == STBVOX_FACE_up || (f) == STBVOX_FACE_down)
2683 #elif defined(STBVOX_CONFIG_UP_TEXLERP_PACKED)
2684 #define STBVOX_USE_PACKED(f) ((f) == STBVOX_FACE_up )
2685 #elif defined(STBVOX_CONFIG_DOWN_TEXLERP_PACKED)
2686 #define STBVOX_USE_PACKED(f) ( (f) == STBVOX_FACE_down)
2687 #endif
2688
2689 #if defined(STBVOX_CONFIG_DOWN_TEXLERP_PACKED) || defined(STBVOX_CONFIG_UP_TEXLERP_PACKED)
2690 if (STBVOX_USE_PACKED(face)) {
2691 if (!mm->input.packed_compact || 0==(mm->input.packed_compact[v_off]&16))
2692 goto set_default;
2693 p1[0] = (mm->input.packed_compact[v_off + mm->cube_vertex_offset[face][0]] >> 5);
2694 p1[1] = (mm->input.packed_compact[v_off + mm->cube_vertex_offset[face][1]] >> 5);
2695 p1[2] = (mm->input.packed_compact[v_off + mm->cube_vertex_offset[face][2]] >> 5);
2696 p1[3] = (mm->input.packed_compact[v_off + mm->cube_vertex_offset[face][3]] >> 5);
2697 p1[0] = stbvox_vertex_encode(0,0,0,0,p1[0]);
2698 p1[1] = stbvox_vertex_encode(0,0,0,0,p1[1]);
2699 p1[2] = stbvox_vertex_encode(0,0,0,0,p1[2]);
2700 p1[3] = stbvox_vertex_encode(0,0,0,0,p1[3]);
2701 goto skip;
2702 }
2703 #endif
2704
2705 if (mm->input.block_texlerp) {
2706 stbvox_block_type bt = mm->input.blocktype[v_off];
2707 unsigned char val = mm->input.block_texlerp[bt];
2708 p1[0] = p1[1] = p1[2] = p1[3] = stbvox_vertex_encode(0,0,0,0,val);
2709 } else if (mm->input.block_texlerp_face) {
2710 stbvox_block_type bt = mm->input.blocktype[v_off];
2711 unsigned char bt_face = STBVOX_ROTATE(face, rot.block);
2712 unsigned char val = mm->input.block_texlerp_face[bt][bt_face];
2713 p1[0] = p1[1] = p1[2] = p1[3] = stbvox_vertex_encode(0,0,0,0,val);
2714 } else if (mm->input.texlerp_face3) {
2715 unsigned char val = (mm->input.texlerp_face3[v_off] >> stbvox_face3_lerp[face]) & 7;
2716 if (face >= STBVOX_FACE_up)
2717 val = stbvox_face3_updown[val];
2718 p1[0] = p1[1] = p1[2] = p1[3] = stbvox_vertex_encode(0,0,0,0,val);
2719 } else if (mm->input.texlerp_simple) {
2720 unsigned char val = mm->input.texlerp_simple[v_off];
2721 unsigned char lerp_face = (val >> 2) & 7;
2722 if (lerp_face == face) {
2723 p1[0] = (mm->input.texlerp_simple[v_off + mm->cube_vertex_offset[face][0]] >> 5) & 7;
2724 p1[1] = (mm->input.texlerp_simple[v_off + mm->cube_vertex_offset[face][1]] >> 5) & 7;
2725 p1[2] = (mm->input.texlerp_simple[v_off + mm->cube_vertex_offset[face][2]] >> 5) & 7;
2726 p1[3] = (mm->input.texlerp_simple[v_off + mm->cube_vertex_offset[face][3]] >> 5) & 7;
2727 p1[0] = stbvox_vertex_encode(0,0,0,0,p1[0]);
2728 p1[1] = stbvox_vertex_encode(0,0,0,0,p1[1]);
2729 p1[2] = stbvox_vertex_encode(0,0,0,0,p1[2]);
2730 p1[3] = stbvox_vertex_encode(0,0,0,0,p1[3]);
2731 } else {
2732 unsigned char base = stbvox_vert_lerp_for_simple[val&3];
2733 p1[0] = p1[1] = p1[2] = p1[3] = stbvox_vertex_encode(0,0,0,0,base);
2734 }
2735 } else if (mm->input.texlerp) {
2736 unsigned char facelerp = (mm->input.texlerp[v_off] >> stbvox_face_lerp[face]) & 3;
2737 if (facelerp == STBVOX_TEXLERP_FACE_use_vert) {
2738 if (mm->input.texlerp_vert3 && face != STBVOX_FACE_down) {
2739 unsigned char shift = stbvox_vert3_lerp[face];
2740 p1[0] = (mm->input.texlerp_vert3[mm->cube_vertex_offset[face][0]] >> shift) & 7;
2741 p1[1] = (mm->input.texlerp_vert3[mm->cube_vertex_offset[face][1]] >> shift) & 7;
2742 p1[2] = (mm->input.texlerp_vert3[mm->cube_vertex_offset[face][2]] >> shift) & 7;
2743 p1[3] = (mm->input.texlerp_vert3[mm->cube_vertex_offset[face][3]] >> shift) & 7;
2744 } else {
2745 p1[0] = stbvox_vert_lerp_for_simple[mm->input.texlerp[mm->cube_vertex_offset[face][0]]>>6];
2746 p1[1] = stbvox_vert_lerp_for_simple[mm->input.texlerp[mm->cube_vertex_offset[face][1]]>>6];
2747 p1[2] = stbvox_vert_lerp_for_simple[mm->input.texlerp[mm->cube_vertex_offset[face][2]]>>6];
2748 p1[3] = stbvox_vert_lerp_for_simple[mm->input.texlerp[mm->cube_vertex_offset[face][3]]>>6];
2749 }
2750 p1[0] = stbvox_vertex_encode(0,0,0,0,p1[0]);
2751 p1[1] = stbvox_vertex_encode(0,0,0,0,p1[1]);
2752 p1[2] = stbvox_vertex_encode(0,0,0,0,p1[2]);
2753 p1[3] = stbvox_vertex_encode(0,0,0,0,p1[3]);
2754 } else {
2755 p1[0] = p1[1] = p1[2] = p1[3] = stbvox_vertex_encode(0,0,0,0,stbvox_vert_lerp_for_face_lerp[facelerp]);
2756 }
2757 } else {
2758 #if defined(STBVOX_CONFIG_UP_TEXLERP_PACKED) || defined(STBVOX_CONFIG_DOWN_TEXLERP_PACKED)
2759 set_default:
2760 #endif
2761 p1[0] = p1[1] = p1[2] = p1[3] = stbvox_vertex_encode(0,0,0,0,7); // @TODO make this configurable
2762 }
2763
2764 #if defined(STBVOX_CONFIG_UP_TEXLERP_PACKED) || defined(STBVOX_CONFIG_DOWN_TEXLERP_PACKED)
2765 skip:
2766 #endif
2767
2768 // now compute lighting and store to vertices
2769 {
2770 stbvox_mesh_vertex *mv[4];
2771 stbvox_get_quad_vertex_pointer(mm, mesh, mv, face_data);
2772
2773 if (mm->input.lighting) {
2774 // @TODO: lighting at block centers, but not gathered, instead constant-per-face
2775 if (mm->input.lighting_at_vertices) {
2776 int i;
2777 for (i=0; i < 4; ++i) {
2778 *mv[i] = vertbase + face_coord[i]
2779 + stbvox_vertex_encode(0,0,0,mm->input.lighting[v_off + mm->cube_vertex_offset[face][i]] & 63,0)
2780 + p1[i];
2781 }
2782 } else {
2783 unsigned char *amb = &mm->input.lighting[v_off];
2784 int i,j;
2785 #if defined(STBVOX_CONFIG_ROTATION_IN_LIGHTING) || defined(STBVOX_CONFIG_VHEIGHT_IN_LIGHTING)
2786 #define STBVOX_GET_LIGHTING(light) ((light) & ~3)
2787 #define STBVOX_LIGHTING_ROUNDOFF 8
2788 #else
2789 #define STBVOX_GET_LIGHTING(light) (light)
2790 #define STBVOX_LIGHTING_ROUNDOFF 2
2791 #endif
2792
2793 for (i=0; i < 4; ++i) {
2794 // for each vertex, gather from the four neighbor blocks it's facing
2795 unsigned char *vamb = &amb[mm->cube_vertex_offset[face][i]];
2796 int total=0;
2797 for (j=0; j < 4; ++j)
2798 total += STBVOX_GET_LIGHTING(vamb[mm->vertex_gather_offset[face][j]]);
2799 *mv[i] = vertbase + face_coord[i]
2800 + stbvox_vertex_encode(0,0,0,(total+STBVOX_LIGHTING_ROUNDOFF)>>4,0)
2801 + p1[i];
2802 // >> 4 is because:
2803 // >> 2 to divide by 4 to get average over 4 samples
2804 // >> 2 because input is 8 bits, output is 6 bits
2805 }
2806
2807 // @TODO: note that gathering baked *lighting*
2808 // is different from gathering baked ao; baked ao can count
2809 // solid blocks as 0 ao, but baked lighting wants average
2810 // of non-blocked--not take average & treat blocked as 0. And
2811 // we can't bake the right value into the solid blocks
2812 // because they can have different lighting values on
2813 // different sides. So we need to actually gather and
2814 // then divide by 0..4 (which we can do with a table-driven
2815 // multiply, or have an 'if' for the 3 case)
2816
2817 }
2818 } else {
2819 vertbase += stbvox_vertex_encode(0,0,0,63,0);
2820 *mv[0] = vertbase + face_coord[0] + p1[0];
2821 *mv[1] = vertbase + face_coord[1] + p1[1];
2822 *mv[2] = vertbase + face_coord[2] + p1[2];
2823 *mv[3] = vertbase + face_coord[3] + p1[3];
2824 }
2825 }
2826 }
2827
2828 // get opposite-facing normal & texgen for opposite face, used to map up-facing vheight data to down-facing data
2829 static unsigned char stbvox_reverse_face[STBVF_count] =
2830 {
2831 STBVF_w, STBVF_s, STBVF_e, STBVF_n, STBVF_d , STBVF_u , STBVF_wd, STBVF_wu,
2832 0, 0, 0, 0, STBVF_sw_d, STBVF_sw_u, STBVF_sd, STBVF_su,
2833 0, 0, 0, 0, STBVF_se_d, STBVF_se_u, STBVF_ed, STBVF_eu,
2834 0, 0, 0, 0, STBVF_ne_d, STBVF_ne_d, STBVF_nd, STBVF_nu
2835 };
2836
2837 #ifndef STBVOX_CONFIG_OPTIMIZED_VHEIGHT
2838 // render non-planar quads by splitting into two triangles, rendering each as a degenerate quad
2839 static void stbvox_make_12_split_mesh_for_face(stbvox_mesh_maker *mm, stbvox_rotate rot, int face, int v_off, stbvox_pos pos, stbvox_mesh_vertex vertbase, stbvox_mesh_vertex *face_coord, unsigned char mesh, unsigned char *ht)
2840 {
2841 stbvox_mesh_vertex v[4];
2842
2843 unsigned char normal1 = stbvox_face_up_normal_012[ht[2]][ht[1]][ht[0]];
2844 unsigned char normal2 = stbvox_face_up_normal_123[ht[3]][ht[2]][ht[1]];
2845
2846 if (face == STBVOX_FACE_down) {
2847 normal1 = stbvox_reverse_face[normal1];
2848 normal2 = stbvox_reverse_face[normal2];
2849 }
2850
2851 // the floor side face_coord is stored in order NW,NE,SE,SW, but ht[] is stored SW,SE,NW,NE
2852 v[0] = face_coord[2];
2853 v[1] = face_coord[3];
2854 v[2] = face_coord[0];
2855 v[3] = face_coord[2];
2856 stbvox_make_mesh_for_face(mm, rot, face, v_off, pos, vertbase, v, mesh, normal1);
2857 v[1] = face_coord[0];
2858 v[2] = face_coord[1];
2859 stbvox_make_mesh_for_face(mm, rot, face, v_off, pos, vertbase, v, mesh, normal2);
2860 }
2861
2862 static void stbvox_make_03_split_mesh_for_face(stbvox_mesh_maker *mm, stbvox_rotate rot, int face, int v_off, stbvox_pos pos, stbvox_mesh_vertex vertbase, stbvox_mesh_vertex *face_coord, unsigned char mesh, unsigned char *ht)
2863 {
2864 stbvox_mesh_vertex v[4];
2865
2866 unsigned char normal1 = stbvox_face_up_normal_013[ht[3]][ht[1]][ht[0]];
2867 unsigned char normal2 = stbvox_face_up_normal_023[ht[3]][ht[2]][ht[0]];
2868
2869 if (face == STBVOX_FACE_down) {
2870 normal1 = stbvox_reverse_face[normal1];
2871 normal2 = stbvox_reverse_face[normal2];
2872 }
2873
2874 v[0] = face_coord[1];
2875 v[1] = face_coord[2];
2876 v[2] = face_coord[3];
2877 v[3] = face_coord[1];
2878 stbvox_make_mesh_for_face(mm, rot, face, v_off, pos, vertbase, v, mesh, normal1);
2879 v[1] = face_coord[3];
2880 v[2] = face_coord[0];
2881 stbvox_make_mesh_for_face(mm, rot, face, v_off, pos, vertbase, v, mesh, normal2); // this one is correct!
2882 }
2883 #endif
2884
2885 #ifndef STBVOX_CONFIG_PRECISION_Z
2886 #define STBVOX_CONFIG_PRECISION_Z 1
2887 #endif
2888
2889 // simple case for mesh generation: we have only solid and empty blocks
2890 static void stbvox_make_mesh_for_block(stbvox_mesh_maker *mm, stbvox_pos pos, int v_off, stbvox_mesh_vertex *vmesh)
2891 {
2892 int ns_off = mm->y_stride_in_bytes;
2893 int ew_off = mm->x_stride_in_bytes;
2894
2895 unsigned char *blockptr = &mm->input.blocktype[v_off];
2896 stbvox_mesh_vertex basevert = stbvox_vertex_encode(pos.x, pos.y, pos.z << STBVOX_CONFIG_PRECISION_Z , 0,0);
2897
2898 stbvox_rotate rot = { 0,0,0,0 };
2899 unsigned char simple_rot = 0;
2900
2901 unsigned char mesh = mm->default_mesh;
2902
2903 if (mm->input.selector)
2904 mesh = mm->input.selector[v_off];
2905
2906 // check if we're going off the end
2907 if (mm->output_cur[mesh][0] + mm->output_size[mesh][0]*6 > mm->output_end[mesh][0]) {
2908 mm->full = 1;
2909 return;
2910 }
2911
2912 #ifdef STBVOX_CONFIG_ROTATION_IN_LIGHTING
2913 simple_rot = mm->input.lighting[v_off] & 3;
2914 #endif
2915
2916 if (mm->input.packed_compact)
2917 simple_rot = mm->input.packed_compact[v_off] & 3;
2918
2919 if (blockptr[ 1]==0) {
2920 rot.facerot = simple_rot;
2921 stbvox_make_mesh_for_face(mm, rot, STBVOX_FACE_up , v_off, pos, basevert, vmesh+4*STBVOX_FACE_up, mesh, STBVOX_FACE_up);
2922 }
2923 if (blockptr[-1]==0) {
2924 rot.facerot = (-simple_rot) & 3;
2925 stbvox_make_mesh_for_face(mm, rot, STBVOX_FACE_down, v_off, pos, basevert, vmesh+4*STBVOX_FACE_down, mesh, STBVOX_FACE_down);
2926 }
2927
2928 if (mm->input.rotate) {
2929 unsigned char val = mm->input.rotate[v_off];
2930 rot.block = (val >> 0) & 3;
2931 rot.overlay = (val >> 2) & 3;
2932 //rot.tex2 = (val >> 4) & 3;
2933 rot.ecolor = (val >> 6) & 3;
2934 } else {
2935 rot.block = rot.overlay = rot.ecolor = simple_rot;
2936 }
2937 rot.facerot = 0;
2938
2939 if (blockptr[ ns_off]==0)
2940 stbvox_make_mesh_for_face(mm, rot, STBVOX_FACE_north, v_off, pos, basevert, vmesh+4*STBVOX_FACE_north, mesh, STBVOX_FACE_north);
2941 if (blockptr[-ns_off]==0)
2942 stbvox_make_mesh_for_face(mm, rot, STBVOX_FACE_south, v_off, pos, basevert, vmesh+4*STBVOX_FACE_south, mesh, STBVOX_FACE_south);
2943 if (blockptr[ ew_off]==0)
2944 stbvox_make_mesh_for_face(mm, rot, STBVOX_FACE_east , v_off, pos, basevert, vmesh+4*STBVOX_FACE_east, mesh, STBVOX_FACE_east);
2945 if (blockptr[-ew_off]==0)
2946 stbvox_make_mesh_for_face(mm, rot, STBVOX_FACE_west , v_off, pos, basevert, vmesh+4*STBVOX_FACE_west, mesh, STBVOX_FACE_west);
2947 }
2948
2949 // complex case for mesh generation: we have lots of different
2950 // block types, and we don't want to generate faces of blocks
2951 // if they're hidden by neighbors.
2952 //
2953 // we use lots of tables to determine this: we have a table
2954 // which tells us what face type is generated for each type of
2955 // geometry, and then a table that tells us whether that type
2956 // is hidden by a neighbor.
2957 static void stbvox_make_mesh_for_block_with_geo(stbvox_mesh_maker *mm, stbvox_pos pos, int v_off)
2958 {
2959 int ns_off = mm->y_stride_in_bytes;
2960 int ew_off = mm->x_stride_in_bytes;
2961 int visible_faces, visible_base;
2962 unsigned char mesh;
2963
2964 // first gather the geometry info for this block and all neighbors
2965
2966 unsigned char bt, nbt[6];
2967 unsigned char geo, ngeo[6];
2968 unsigned char rot, nrot[6];
2969
2970 bt = mm->input.blocktype[v_off];
2971 nbt[0] = mm->input.blocktype[v_off + ew_off];
2972 nbt[1] = mm->input.blocktype[v_off + ns_off];
2973 nbt[2] = mm->input.blocktype[v_off - ew_off];
2974 nbt[3] = mm->input.blocktype[v_off - ns_off];
2975 nbt[4] = mm->input.blocktype[v_off + 1];
2976 nbt[5] = mm->input.blocktype[v_off - 1];
2977 if (mm->input.geometry) {
2978 int i;
2979 geo = mm->input.geometry[v_off];
2980 ngeo[0] = mm->input.geometry[v_off + ew_off];
2981 ngeo[1] = mm->input.geometry[v_off + ns_off];
2982 ngeo[2] = mm->input.geometry[v_off - ew_off];
2983 ngeo[3] = mm->input.geometry[v_off - ns_off];
2984 ngeo[4] = mm->input.geometry[v_off + 1];
2985 ngeo[5] = mm->input.geometry[v_off - 1];
2986
2987 rot = (geo >> 4) & 3;
2988 geo &= 15;
2989 for (i=0; i < 6; ++i) {
2990 nrot[i] = (ngeo[i] >> 4) & 3;
2991 ngeo[i] &= 15;
2992 }
2993 } else {
2994 int i;
2995 assert(mm->input.block_geometry);
2996 geo = mm->input.block_geometry[bt];
2997 for (i=0; i < 6; ++i)
2998 ngeo[i] = mm->input.block_geometry[nbt[i]];
2999 if (mm->input.selector) {
3000 #ifndef STBVOX_CONFIG_ROTATION_IN_LIGHTING
3001 if (mm->input.packed_compact == NULL) {
3002 rot = (mm->input.selector[v_off ] >> 4) & 3;
3003 nrot[0] = (mm->input.selector[v_off + ew_off] >> 4) & 3;
3004 nrot[1] = (mm->input.selector[v_off + ns_off] >> 4) & 3;
3005 nrot[2] = (mm->input.selector[v_off - ew_off] >> 4) & 3;
3006 nrot[3] = (mm->input.selector[v_off - ns_off] >> 4) & 3;
3007 nrot[4] = (mm->input.selector[v_off + 1] >> 4) & 3;
3008 nrot[5] = (mm->input.selector[v_off - 1] >> 4) & 3;
3009 }
3010 #endif
3011 } else {
3012 #ifndef STBVOX_CONFIG_ROTATION_IN_LIGHTING
3013 if (mm->input.packed_compact == NULL) {
3014 rot = (geo>>4)&3;
3015 geo &= 15;
3016 for (i=0; i < 6; ++i) {
3017 nrot[i] = (ngeo[i]>>4)&3;
3018 ngeo[i] &= 15;
3019 }
3020 }
3021 #endif
3022 }
3023 }
3024
3025 #ifndef STBVOX_CONFIG_ROTATION_IN_LIGHTING
3026 if (mm->input.packed_compact) {
3027 rot = mm->input.packed_compact[rot] & 3;
3028 nrot[0] = mm->input.packed_compact[v_off + ew_off] & 3;
3029 nrot[1] = mm->input.packed_compact[v_off + ns_off] & 3;
3030 nrot[2] = mm->input.packed_compact[v_off - ew_off] & 3;
3031 nrot[3] = mm->input.packed_compact[v_off - ns_off] & 3;
3032 nrot[4] = mm->input.packed_compact[v_off + 1] & 3;
3033 nrot[5] = mm->input.packed_compact[v_off - 1] & 3;
3034 }
3035 #else
3036 rot = mm->input.lighting[v_off] & 3;
3037 nrot[0] = (mm->input.lighting[v_off + ew_off]) & 3;
3038 nrot[1] = (mm->input.lighting[v_off + ns_off]) & 3;
3039 nrot[2] = (mm->input.lighting[v_off - ew_off]) & 3;
3040 nrot[3] = (mm->input.lighting[v_off - ns_off]) & 3;
3041 nrot[4] = (mm->input.lighting[v_off + 1]) & 3;
3042 nrot[5] = (mm->input.lighting[v_off - 1]) & 3;
3043 #endif
3044
3045 if (geo == STBVOX_GEOM_transp) {
3046 // transparency has a special rule: if the blocktype is the same,
3047 // and the faces are compatible, then can hide them; otherwise,
3048 // force them on
3049 // Note that this means we don't support any transparentshapes other
3050 // than solid blocks, since detecting them is too complicated. If
3051 // you wanted to do something like minecraft water, you probably
3052 // should just do that with a separate renderer anyway. (We don't
3053 // support transparency sorting so you need to use alpha test
3054 // anyway)
3055 int i;
3056 for (i=0; i < 6; ++i)
3057 if (nbt[i] != bt) {
3058 nbt[i] = 0;
3059 ngeo[i] = STBVOX_GEOM_empty;
3060 } else
3061 ngeo[i] = STBVOX_GEOM_solid;
3062 geo = STBVOX_GEOM_solid;
3063 }
3064
3065 // now compute the face visibility
3066 visible_base = stbvox_hasface[geo][rot];
3067 // @TODO: assert(visible_base != 0); // we should have early-outted earlier in this case
3068 visible_faces = 0;
3069
3070 // now, for every face that might be visible, check if neighbor hides it
3071 if (visible_base & (1 << STBVOX_FACE_east)) {
3072 int type = stbvox_facetype[ geo ][(STBVOX_FACE_east+ rot )&3];
3073 int ntype = stbvox_facetype[ngeo[0]][(STBVOX_FACE_west+nrot[0])&3];
3074 visible_faces |= ((stbvox_face_visible[type]) >> (ntype + 5 - STBVOX_FACE_east)) & (1 << STBVOX_FACE_east);
3075 }
3076 if (visible_base & (1 << STBVOX_FACE_north)) {
3077 int type = stbvox_facetype[ geo ][(STBVOX_FACE_north+ rot )&3];
3078 int ntype = stbvox_facetype[ngeo[1]][(STBVOX_FACE_south+nrot[1])&3];
3079 visible_faces |= ((stbvox_face_visible[type]) >> (ntype + 5 - STBVOX_FACE_north)) & (1 << STBVOX_FACE_north);
3080 }
3081 if (visible_base & (1 << STBVOX_FACE_west)) {
3082 int type = stbvox_facetype[ geo ][(STBVOX_FACE_west+ rot )&3];
3083 int ntype = stbvox_facetype[ngeo[2]][(STBVOX_FACE_east+nrot[2])&3];
3084 visible_faces |= ((stbvox_face_visible[type]) >> (ntype + 5 - STBVOX_FACE_west)) & (1 << STBVOX_FACE_west);
3085 }
3086 if (visible_base & (1 << STBVOX_FACE_south)) {
3087 int type = stbvox_facetype[ geo ][(STBVOX_FACE_south+ rot )&3];
3088 int ntype = stbvox_facetype[ngeo[3]][(STBVOX_FACE_north+nrot[3])&3];
3089 visible_faces |= ((stbvox_face_visible[type]) >> (ntype + 5 - STBVOX_FACE_south)) & (1 << STBVOX_FACE_south);
3090 }
3091 if (visible_base & (1 << STBVOX_FACE_up)) {
3092 int type = stbvox_facetype[ geo ][STBVOX_FACE_up];
3093 int ntype = stbvox_facetype[ngeo[4]][STBVOX_FACE_down];
3094 visible_faces |= ((stbvox_face_visible[type]) >> (ntype + 5 - STBVOX_FACE_up)) & (1 << STBVOX_FACE_up);
3095 }
3096 if (visible_base & (1 << STBVOX_FACE_down)) {
3097 int type = stbvox_facetype[ geo ][STBVOX_FACE_down];
3098 int ntype = stbvox_facetype[ngeo[5]][STBVOX_FACE_up];
3099 visible_faces |= ((stbvox_face_visible[type]) >> (ntype + 5 - STBVOX_FACE_down)) & (1 << STBVOX_FACE_down);
3100 }
3101
3102 if (geo == STBVOX_GEOM_force)
3103 geo = STBVOX_GEOM_solid;
3104
3105 assert((geo == STBVOX_GEOM_crossed_pair) ? (visible_faces == 15) : 1);
3106
3107 // now we finally know for sure which faces are getting generated
3108 if (visible_faces == 0)
3109 return;
3110
3111 mesh = mm->default_mesh;
3112 if (mm->input.selector)
3113 mesh = mm->input.selector[v_off];
3114
3115 if (geo <= STBVOX_GEOM_ceil_slope_north_is_bottom) {
3116 // this is the simple case, we can just use regular block gen with special vmesh calculated with vheight
3117 stbvox_mesh_vertex basevert;
3118 stbvox_mesh_vertex vmesh[6][4];
3119 stbvox_rotate rotate = { 0,0,0,0 };
3120 unsigned char simple_rot = rot;
3121 int i;
3122 // we only need to do this for the displayed faces, but it's easier
3123 // to just do it up front; @OPTIMIZE check if it's faster to do it
3124 // for visible faces only
3125 for (i=0; i < 6*4; ++i) {
3126 int vert = stbvox_vertex_selector[0][i];
3127 vert = stbvox_rotate_vertex[vert][rot];
3128 vmesh[0][i] = stbvox_vmesh_pre_vheight[0][i]
3129 + stbvox_geometry_vheight[geo][vert];
3130 }
3131
3132 basevert = stbvox_vertex_encode(pos.x, pos.y, pos.z << STBVOX_CONFIG_PRECISION_Z, 0,0);
3133 if (mm->input.selector) {
3134 mesh = mm->input.selector[v_off];
3135 }
3136
3137 // check if we're going off the end
3138 if (mm->output_cur[mesh][0] + mm->output_size[mesh][0]*6 > mm->output_end[mesh][0]) {
3139 mm->full = 1;
3140 return;
3141 }
3142
3143 if (geo >= STBVOX_GEOM_floor_slope_north_is_top) {
3144 if (visible_faces & (1 << STBVOX_FACE_up)) {
3145 int normal = geo == STBVOX_GEOM_floor_slope_north_is_top ? stbvox_floor_slope_for_rot[simple_rot] : STBVOX_FACE_up;
3146 rotate.facerot = simple_rot;
3147 stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_up , v_off, pos, basevert, vmesh[STBVOX_FACE_up], mesh, normal);
3148 }
3149 if (visible_faces & (1 << STBVOX_FACE_down)) {
3150 int normal = geo == STBVOX_GEOM_ceil_slope_north_is_bottom ? stbvox_ceil_slope_for_rot[simple_rot] : STBVOX_FACE_down;
3151 rotate.facerot = (-rotate.facerot) & 3;
3152 stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_down, v_off, pos, basevert, vmesh[STBVOX_FACE_down], mesh, normal);
3153 }
3154 } else {
3155 if (visible_faces & (1 << STBVOX_FACE_up)) {
3156 rotate.facerot = simple_rot;
3157 stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_up , v_off, pos, basevert, vmesh[STBVOX_FACE_up], mesh, STBVOX_FACE_up);
3158 }
3159 if (visible_faces & (1 << STBVOX_FACE_down)) {
3160 rotate.facerot = (-rotate.facerot) & 3;
3161 stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_down, v_off, pos, basevert, vmesh[STBVOX_FACE_down], mesh, STBVOX_FACE_down);
3162 }
3163 }
3164
3165 if (mm->input.rotate) {
3166 unsigned char val = mm->input.rotate[v_off];
3167 rotate.block = (val >> 0) & 3;
3168 rotate.overlay = (val >> 2) & 3;
3169 //rotate.tex2 = (val >> 4) & 3;
3170 rotate.ecolor = (val >> 6) & 3;
3171 } else {
3172 rotate.block = rotate.overlay = rotate.ecolor = simple_rot;
3173 }
3174
3175 rotate.facerot = 0;
3176
3177 if (visible_faces & (1 << STBVOX_FACE_north))
3178 stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_north, v_off, pos, basevert, vmesh[STBVOX_FACE_north], mesh, STBVOX_FACE_north);
3179 if (visible_faces & (1 << STBVOX_FACE_south))
3180 stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_south, v_off, pos, basevert, vmesh[STBVOX_FACE_south], mesh, STBVOX_FACE_south);
3181 if (visible_faces & (1 << STBVOX_FACE_east))
3182 stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_east , v_off, pos, basevert, vmesh[STBVOX_FACE_east ], mesh, STBVOX_FACE_east);
3183 if (visible_faces & (1 << STBVOX_FACE_west))
3184 stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_west , v_off, pos, basevert, vmesh[STBVOX_FACE_west ], mesh, STBVOX_FACE_west);
3185 }
3186 if (geo >= STBVOX_GEOM_floor_vheight_03) {
3187 // this case can also be generated with regular block gen with special vmesh,
3188 // except:
3189 // if we want to generate middle diagonal for 'weird' blocks
3190 // it's more complicated to detect neighbor matchups
3191 stbvox_mesh_vertex vmesh[6][4];
3192 stbvox_mesh_vertex cube[8];
3193 stbvox_mesh_vertex basevert;
3194 stbvox_rotate rotate = { 0,0,0,0 };
3195 unsigned char simple_rot = rot;
3196 unsigned char ht[4];
3197 int extreme;
3198
3199 // extract the heights
3200 #ifdef STBVOX_CONFIG_VHEIGHT_IN_LIGHTING
3201 ht[0] = mm->input.lighting[v_off ] & 3;
3202 ht[1] = mm->input.lighting[v_off+ew_off ] & 3;
3203 ht[2] = mm->input.lighting[v_off +ns_off] & 3;
3204 ht[3] = mm->input.lighting[v_off+ew_off+ns_off] & 3;
3205 #else
3206 if (mm->input.vheight) {
3207 unsigned char v = mm->input.vheight[v_off];
3208 ht[0] = (v >> 0) & 3;
3209 ht[1] = (v >> 2) & 3;
3210 ht[2] = (v >> 4) & 3;
3211 ht[3] = (v >> 6) & 3;
3212 } else if (mm->input.block_vheight) {
3213 unsigned char v = mm->input.block_vheight[bt];
3214 unsigned char raw[4];
3215 int i;
3216
3217 raw[0] = (v >> 0) & 3;
3218 raw[1] = (v >> 2) & 3;
3219 raw[2] = (v >> 4) & 3;
3220 raw[3] = (v >> 6) & 3;
3221
3222 for (i=0; i < 4; ++i)
3223 ht[i] = raw[stbvox_rotate_vertex[i][rot]];
3224 } else if (mm->input.packed_compact) {
3225 ht[0] = (mm->input.packed_compact[v_off ] >> 2) & 3;
3226 ht[1] = (mm->input.packed_compact[v_off+ew_off ] >> 2) & 3;
3227 ht[2] = (mm->input.packed_compact[v_off +ns_off] >> 2) & 3;
3228 ht[3] = (mm->input.packed_compact[v_off+ew_off+ns_off] >> 2) & 3;
3229 } else if (mm->input.geometry) {
3230 ht[0] = mm->input.geometry[v_off ] >> 6;
3231 ht[1] = mm->input.geometry[v_off+ew_off ] >> 6;
3232 ht[2] = mm->input.geometry[v_off +ns_off] >> 6;
3233 ht[3] = mm->input.geometry[v_off+ew_off+ns_off] >> 6;
3234 } else {
3235 assert(0);
3236 }
3237 #endif
3238
3239 // flag whether any sides go off the top of the block, which means
3240 // our visible_faces test was wrong
3241 extreme = (ht[0] == 3 || ht[1] == 3 || ht[2] == 3 || ht[3] == 3);
3242
3243 if (geo >= STBVOX_GEOM_ceil_vheight_03) {
3244 cube[0] = stbvox_vertex_encode(0,0,ht[0],0,0);
3245 cube[1] = stbvox_vertex_encode(0,0,ht[1],0,0);
3246 cube[2] = stbvox_vertex_encode(0,0,ht[2],0,0);
3247 cube[3] = stbvox_vertex_encode(0,0,ht[3],0,0);
3248 cube[4] = stbvox_vertex_encode(0,0,2,0,0);
3249 cube[5] = stbvox_vertex_encode(0,0,2,0,0);
3250 cube[6] = stbvox_vertex_encode(0,0,2,0,0);
3251 cube[7] = stbvox_vertex_encode(0,0,2,0,0);
3252 } else {
3253 cube[0] = stbvox_vertex_encode(0,0,0,0,0);
3254 cube[1] = stbvox_vertex_encode(0,0,0,0,0);
3255 cube[2] = stbvox_vertex_encode(0,0,0,0,0);
3256 cube[3] = stbvox_vertex_encode(0,0,0,0,0);
3257 cube[4] = stbvox_vertex_encode(0,0,ht[0],0,0);
3258 cube[5] = stbvox_vertex_encode(0,0,ht[1],0,0);
3259 cube[6] = stbvox_vertex_encode(0,0,ht[2],0,0);
3260 cube[7] = stbvox_vertex_encode(0,0,ht[3],0,0);
3261 }
3262 if (!mm->input.vheight && mm->input.block_vheight) {
3263 // @TODO: support block vheight here, I've forgotten what needs to be done specially
3264 }
3265
3266 // build vertex mesh
3267 {
3268 int i;
3269 for (i=0; i < 6*4; ++i) {
3270 int vert = stbvox_vertex_selector[0][i];
3271 vmesh[0][i] = stbvox_vmesh_pre_vheight[0][i]
3272 + cube[vert];
3273 }
3274 }
3275
3276 basevert = stbvox_vertex_encode(pos.x, pos.y, pos.z << STBVOX_CONFIG_PRECISION_Z, 0,0);
3277 // check if we're going off the end
3278 if (mm->output_cur[mesh][0] + mm->output_size[mesh][0]*6 > mm->output_end[mesh][0]) {
3279 mm->full = 1;
3280 return;
3281 }
3282
3283 // @TODO generate split faces
3284 if (visible_faces & (1 << STBVOX_FACE_up)) {
3285 if (geo >= STBVOX_GEOM_ceil_vheight_03)
3286 // flat
3287 stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_up , v_off, pos, basevert, vmesh[STBVOX_FACE_up], mesh, STBVOX_FACE_up);
3288 else {
3289 #ifndef STBVOX_CONFIG_OPTIMIZED_VHEIGHT
3290 // check if it's non-planar
3291 if (cube[5] + cube[6] != cube[4] + cube[7]) {
3292 // not planar, split along diagonal and make degenerate quads
3293 if (geo == STBVOX_GEOM_floor_vheight_03)
3294 stbvox_make_03_split_mesh_for_face(mm, rotate, STBVOX_FACE_up, v_off, pos, basevert, vmesh[STBVOX_FACE_up], mesh, ht);
3295 else
3296 stbvox_make_12_split_mesh_for_face(mm, rotate, STBVOX_FACE_up, v_off, pos, basevert, vmesh[STBVOX_FACE_up], mesh, ht);
3297 } else
3298 stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_up , v_off, pos, basevert, vmesh[STBVOX_FACE_up], mesh, stbvox_planar_face_up_normal[ht[2]][ht[1]][ht[0]]);
3299 #else
3300 stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_up , v_off, pos, basevert, vmesh[STBVOX_FACE_up], mesh, stbvox_optimized_face_up_normal[ht[3]][ht[2]][ht[1]][ht[0]]);
3301 #endif
3302 }
3303 }
3304 if (visible_faces & (1 << STBVOX_FACE_down)) {
3305 if (geo < STBVOX_GEOM_ceil_vheight_03)
3306 // flat
3307 stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_down, v_off, pos, basevert, vmesh[STBVOX_FACE_down], mesh, STBVOX_FACE_down);
3308 else {
3309 #ifndef STBVOX_CONFIG_OPTIMIZED_VHEIGHT
3310 // check if it's non-planar
3311 if (cube[1] + cube[2] != cube[0] + cube[3]) {
3312 // not planar, split along diagonal and make degenerate quads
3313 if (geo == STBVOX_GEOM_ceil_vheight_03)
3314 stbvox_make_03_split_mesh_for_face(mm, rotate, STBVOX_FACE_down, v_off, pos, basevert, vmesh[STBVOX_FACE_down], mesh, ht);
3315 else
3316 stbvox_make_12_split_mesh_for_face(mm, rotate, STBVOX_FACE_down, v_off, pos, basevert, vmesh[STBVOX_FACE_down], mesh, ht);
3317 } else
3318 stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_down, v_off, pos, basevert, vmesh[STBVOX_FACE_down], mesh, stbvox_reverse_face[stbvox_planar_face_up_normal[ht[2]][ht[1]][ht[0]]]);
3319 #else
3320 stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_down, v_off, pos, basevert, vmesh[STBVOX_FACE_down], mesh, stbvox_reverse_face[stbvox_optimized_face_up_normal[ht[3]][ht[2]][ht[1]][ht[0]]]);
3321 #endif
3322 }
3323 }
3324
3325 if (mm->input.rotate) {
3326 unsigned char val = mm->input.rotate[v_off];
3327 rotate.block = (val >> 0) & 3;
3328 rotate.overlay = (val >> 2) & 3;
3329 //rotate.tex2 = (val >> 4) & 3;
3330 rotate.ecolor = (val >> 6) & 3;
3331 } else if (mm->input.selector) {
3332 rotate.block = rotate.overlay = rotate.ecolor = simple_rot;
3333 }
3334
3335 if ((visible_faces & (1 << STBVOX_FACE_north)) || (extreme && (ht[2] == 3 || ht[3] == 3)))
3336 stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_north, v_off, pos, basevert, vmesh[STBVOX_FACE_north], mesh, STBVOX_FACE_north);
3337 if ((visible_faces & (1 << STBVOX_FACE_south)) || (extreme && (ht[0] == 3 || ht[1] == 3)))
3338 stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_south, v_off, pos, basevert, vmesh[STBVOX_FACE_south], mesh, STBVOX_FACE_south);
3339 if ((visible_faces & (1 << STBVOX_FACE_east)) || (extreme && (ht[1] == 3 || ht[3] == 3)))
3340 stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_east , v_off, pos, basevert, vmesh[STBVOX_FACE_east ], mesh, STBVOX_FACE_east);
3341 if ((visible_faces & (1 << STBVOX_FACE_west)) || (extreme && (ht[0] == 3 || ht[2] == 3)))
3342 stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_west , v_off, pos, basevert, vmesh[STBVOX_FACE_west ], mesh, STBVOX_FACE_west);
3343 }
3344
3345 if (geo == STBVOX_GEOM_crossed_pair) {
3346 // this can be generated with a special vmesh
3347 stbvox_mesh_vertex basevert = stbvox_vertex_encode(pos.x, pos.y, pos.z << STBVOX_CONFIG_PRECISION_Z , 0,0);
3348 unsigned char simple_rot=0;
3349 stbvox_rotate rot = { 0,0,0,0 };
3350 unsigned char mesh = mm->default_mesh;
3351 if (mm->input.selector) {
3352 mesh = mm->input.selector[v_off];
3353 simple_rot = mesh >> 4;
3354 mesh &= 15;
3355 }
3356
3357 // check if we're going off the end
3358 if (mm->output_cur[mesh][0] + mm->output_size[mesh][0]*4 > mm->output_end[mesh][0]) {
3359 mm->full = 1;
3360 return;
3361 }
3362
3363 if (mm->input.rotate) {
3364 unsigned char val = mm->input.rotate[v_off];
3365 rot.block = (val >> 0) & 3;
3366 rot.overlay = (val >> 2) & 3;
3367 //rot.tex2 = (val >> 4) & 3;
3368 rot.ecolor = (val >> 6) & 3;
3369 } else if (mm->input.selector) {
3370 rot.block = rot.overlay = rot.ecolor = simple_rot;
3371 }
3372 rot.facerot = 0;
3373
3374 stbvox_make_mesh_for_face(mm, rot, STBVOX_FACE_north, v_off, pos, basevert, stbvox_vmesh_crossed_pair[STBVOX_FACE_north], mesh, STBVF_ne_u_cross);
3375 stbvox_make_mesh_for_face(mm, rot, STBVOX_FACE_south, v_off, pos, basevert, stbvox_vmesh_crossed_pair[STBVOX_FACE_south], mesh, STBVF_sw_u_cross);
3376 stbvox_make_mesh_for_face(mm, rot, STBVOX_FACE_east , v_off, pos, basevert, stbvox_vmesh_crossed_pair[STBVOX_FACE_east ], mesh, STBVF_se_u_cross);
3377 stbvox_make_mesh_for_face(mm, rot, STBVOX_FACE_west , v_off, pos, basevert, stbvox_vmesh_crossed_pair[STBVOX_FACE_west ], mesh, STBVF_nw_u_cross);
3378 }
3379
3380
3381 // @TODO
3382 // STBVOX_GEOM_floor_slope_north_is_top_as_wall,
3383 // STBVOX_GEOM_ceil_slope_north_is_bottom_as_wall,
3384 }
3385
3386 static void stbvox_make_mesh_for_column(stbvox_mesh_maker *mm, int x, int y, int z0)
3387 {
3388 stbvox_pos pos;
3389 int v_off = x * mm->x_stride_in_bytes + y * mm->y_stride_in_bytes;
3390 int ns_off = mm->y_stride_in_bytes;
3391 int ew_off = mm->x_stride_in_bytes;
3392 pos.x = x;
3393 pos.y = y;
3394 pos.z = 0;
3395 if (mm->input.geometry) {
3396 unsigned char *bt = mm->input.blocktype + v_off;
3397 unsigned char *geo = mm->input.geometry + v_off;
3398 int z;
3399 for (z=z0; z < mm->z1; ++z) {
3400 if (bt[z] && ( !bt[z+ns_off] || !STBVOX_GET_GEO(geo[z+ns_off]) || !bt[z-ns_off] || !STBVOX_GET_GEO(geo[z-ns_off])
3401 || !bt[z+ew_off] || !STBVOX_GET_GEO(geo[z+ew_off]) || !bt[z-ew_off] || !STBVOX_GET_GEO(geo[z-ew_off])
3402 || !bt[z-1] || !STBVOX_GET_GEO(geo[z-1]) || !bt[z+1] || !STBVOX_GET_GEO(geo[z+1])))
3403 { // TODO check up and down
3404 pos.z = z;
3405 stbvox_make_mesh_for_block_with_geo(mm, pos, v_off+z);
3406 if (mm->full) {
3407 mm->cur_z = z;
3408 return;
3409 }
3410 }
3411 }
3412 } else if (mm->input.block_geometry) {
3413 int z;
3414 unsigned char *bt = mm->input.blocktype + v_off;
3415 unsigned char *geo = mm->input.block_geometry;
3416 for (z=z0; z < mm->z1; ++z) {
3417 if (bt[z] && ( geo[bt[z+ns_off]] != STBVOX_GEOM_solid
3418 || geo[bt[z-ns_off]] != STBVOX_GEOM_solid
3419 || geo[bt[z+ew_off]] != STBVOX_GEOM_solid
3420 || geo[bt[z-ew_off]] != STBVOX_GEOM_solid
3421 || geo[bt[z-1]] != STBVOX_GEOM_solid
3422 || geo[bt[z+1]] != STBVOX_GEOM_solid))
3423 {
3424 pos.z = z;
3425 stbvox_make_mesh_for_block_with_geo(mm, pos, v_off+z);
3426 if (mm->full) {
3427 mm->cur_z = z;
3428 return;
3429 }
3430 }
3431 }
3432 } else {
3433 unsigned char *bt = mm->input.blocktype + v_off;
3434 int z;
3435 #if STBVOX_CONFIG_PRECISION_Z == 1
3436 stbvox_mesh_vertex *vmesh = stbvox_vmesh_delta_half_z[0];
3437 #else
3438 stbvox_mesh_vertex *vmesh = stbvox_vmesh_delta_normal[0];
3439 #endif
3440 for (z=z0; z < mm->z1; ++z) {
3441 // if it's solid and at least one neighbor isn't solid
3442 if (bt[z] && (!bt[z+ns_off] || !bt[z-ns_off] || !bt[z+ew_off] || !bt[z-ew_off] || !bt[z-1] || !bt[z+1])) {
3443 pos.z = z;
3444 stbvox_make_mesh_for_block(mm, pos, v_off+z, vmesh);
3445 if (mm->full) {
3446 mm->cur_z = z;
3447 return;
3448 }
3449 }
3450 }
3451 }
3452 }
3453
3454 static void stbvox_bring_up_to_date(stbvox_mesh_maker *mm)
3455 {
3456 if (mm->config_dirty) {
3457 int i;
3458 #ifdef STBVOX_ICONFIG_FACE_ATTRIBUTE
3459 mm->num_mesh_slots = 1;
3460 for (i=0; i < STBVOX_MAX_MESHES; ++i) {
3461 mm->output_size[i][0] = 32;
3462 mm->output_step[i][0] = 8;
3463 }
3464 #else
3465 mm->num_mesh_slots = 2;
3466 for (i=0; i < STBVOX_MAX_MESHES; ++i) {
3467 mm->output_size[i][0] = 16;
3468 mm->output_step[i][0] = 4;
3469 mm->output_size[i][1] = 4;
3470 mm->output_step[i][1] = 4;
3471 }
3472 #endif
3473
3474 mm->config_dirty = 0;
3475 }
3476 }
3477
3478 int stbvox_make_mesh(stbvox_mesh_maker *mm)
3479 {
3480 int x,y;
3481 stbvox_bring_up_to_date(mm);
3482 mm->full = 0;
3483 if (mm->cur_x > mm->x0 || mm->cur_y > mm->y0 || mm->cur_z > mm->z0) {
3484 stbvox_make_mesh_for_column(mm, mm->cur_x, mm->cur_y, mm->cur_z);
3485 if (mm->full)
3486 return 0;
3487 ++mm->cur_y;
3488 while (mm->cur_y < mm->y1 && !mm->full) {
3489 stbvox_make_mesh_for_column(mm, mm->cur_x, mm->cur_y, mm->z0);
3490 if (mm->full)
3491 return 0;
3492 ++mm->cur_y;
3493 }
3494 ++mm->cur_x;
3495 }
3496 for (x=mm->cur_x; x < mm->x1; ++x) {
3497 for (y=mm->y0; y < mm->y1; ++y) {
3498 stbvox_make_mesh_for_column(mm, x, y, mm->z0);
3499 if (mm->full) {
3500 mm->cur_x = x;
3501 mm->cur_y = y;
3502 return 0;
3503 }
3504 }
3505 }
3506 return 1;
3507 }
3508
3509 void stbvox_init_mesh_maker(stbvox_mesh_maker *mm)
3510 {
3511 memset(mm, 0, sizeof(*mm));
3512 stbvox_build_default_palette();
3513
3514 mm->config_dirty = 1;
3515 mm->default_mesh = 0;
3516 }
3517
3518 int stbvox_get_buffer_count(stbvox_mesh_maker *mm)
3519 {
3520 stbvox_bring_up_to_date(mm);
3521 return mm->num_mesh_slots;
3522 }
3523
3524 int stbvox_get_buffer_size_per_quad(stbvox_mesh_maker *mm, int n)
3525 {
3526 return mm->output_size[0][n];
3527 }
3528
3529 void stbvox_reset_buffers(stbvox_mesh_maker *mm)
3530 {
3531 int i;
3532 for (i=0; i < STBVOX_MAX_MESHES*STBVOX_MAX_MESH_SLOTS; ++i) {
3533 mm->output_cur[0][i] = 0;
3534 mm->output_buffer[0][i] = 0;
3535 }
3536 }
3537
3538 void stbvox_set_buffer(stbvox_mesh_maker *mm, int mesh, int slot, void *buffer, size_t len)
3539 {
3540 int i;
3541 stbvox_bring_up_to_date(mm);
3542 mm->output_buffer[mesh][slot] = (char *) buffer;
3543 mm->output_cur [mesh][slot] = (char *) buffer;
3544 mm->output_len [mesh][slot] = len;
3545 mm->output_end [mesh][slot] = (char *) buffer + len;
3546 for (i=0; i < STBVOX_MAX_MESH_SLOTS; ++i) {
3547 if (mm->output_buffer[mesh][i]) {
3548 assert(mm->output_len[mesh][i] / mm->output_size[mesh][i] == mm->output_len[mesh][slot] / mm->output_size[mesh][slot]);
3549 }
3550 }
3551 }
3552
3553 void stbvox_set_default_mesh(stbvox_mesh_maker *mm, int mesh)
3554 {
3555 mm->default_mesh = mesh;
3556 }
3557
3558 int stbvox_get_quad_count(stbvox_mesh_maker *mm, int mesh)
3559 {
3560 return (mm->output_cur[mesh][0] - mm->output_buffer[mesh][0]) / mm->output_size[mesh][0];
3561 }
3562
3563 stbvox_input_description *stbvox_get_input_description(stbvox_mesh_maker *mm)
3564 {
3565 return &mm->input;
3566 }
3567
3568 void stbvox_set_input_range(stbvox_mesh_maker *mm, int x0, int y0, int z0, int x1, int y1, int z1)
3569 {
3570 mm->x0 = x0;
3571 mm->y0 = y0;
3572 mm->z0 = z0;
3573
3574 mm->x1 = x1;
3575 mm->y1 = y1;
3576 mm->z1 = z1;
3577
3578 mm->cur_x = x0;
3579 mm->cur_y = y0;
3580 mm->cur_z = z0;
3581
3582 // @TODO validate that this range is representable in this mode
3583 }
3584
3585 void stbvox_get_transform(stbvox_mesh_maker *mm, float transform[3][3])
3586 {
3587 // scale
3588 transform[0][0] = 1.0;
3589 transform[0][1] = 1.0;
3590 #if STBVOX_CONFIG_PRECISION_Z==1
3591 transform[0][2] = 0.5f;
3592 #else
3593 transform[0][2] = 1.0f;
3594 #endif
3595 // translation
3596 transform[1][0] = (float) (mm->pos_x);
3597 transform[1][1] = (float) (mm->pos_y);
3598 transform[1][2] = (float) (mm->pos_z);
3599 // texture coordinate projection translation
3600 transform[2][0] = (float) (mm->pos_x & 255); // @TODO depends on max texture scale
3601 transform[2][1] = (float) (mm->pos_y & 255);
3602 transform[2][2] = (float) (mm->pos_z & 255);
3603 }
3604
3605 void stbvox_get_bounds(stbvox_mesh_maker *mm, float bounds[2][3])
3606 {
3607 bounds[0][0] = (float) (mm->pos_x + mm->x0);
3608 bounds[0][1] = (float) (mm->pos_y + mm->y0);
3609 bounds[0][2] = (float) (mm->pos_z + mm->z0);
3610 bounds[1][0] = (float) (mm->pos_x + mm->x1);
3611 bounds[1][1] = (float) (mm->pos_y + mm->y1);
3612 bounds[1][2] = (float) (mm->pos_z + mm->z1);
3613 }
3614
3615 void stbvox_set_mesh_coordinates(stbvox_mesh_maker *mm, int x, int y, int z)
3616 {
3617 mm->pos_x = x;
3618 mm->pos_y = y;
3619 mm->pos_z = z;
3620 }
3621
3622 void stbvox_set_input_stride(stbvox_mesh_maker *mm, int x_stride_in_bytes, int y_stride_in_bytes)
3623 {
3624 int f,v;
3625 mm->x_stride_in_bytes = x_stride_in_bytes;
3626 mm->y_stride_in_bytes = y_stride_in_bytes;
3627 for (f=0; f < 6; ++f) {
3628 for (v=0; v < 4; ++v) {
3629 mm->cube_vertex_offset[f][v] = stbvox_vertex_vector[f][v][0] * mm->x_stride_in_bytes
3630 + stbvox_vertex_vector[f][v][1] * mm->y_stride_in_bytes
3631 + stbvox_vertex_vector[f][v][2] ;
3632 mm->vertex_gather_offset[f][v] = (stbvox_vertex_vector[f][v][0]-1) * mm->x_stride_in_bytes
3633 + (stbvox_vertex_vector[f][v][1]-1) * mm->y_stride_in_bytes
3634 + (stbvox_vertex_vector[f][v][2]-1) ;
3635 }
3636 }
3637 }
3638
3639 /////////////////////////////////////////////////////////////////////////////
3640 //
3641 // offline computation of tables
3642 //
3643
3644 #if 0
3645 // compute optimized vheight table
3646 static char *normal_names[32] =
3647 {
3648 0,0,0,0,"u ",0, "eu ",0,
3649 0,0,0,0,"ne_u",0, "nu ",0,
3650 0,0,0,0,"nw_u",0, "wu ",0,
3651 0,0,0,0,"sw_u",0, "su ",0,
3652 };
3653
3654 static char *find_best_normal(float x, float y, float z)
3655 {
3656 int best_slot = 4;
3657 float best_dot = 0;
3658 int i;
3659 for (i=0; i < 32; ++i) {
3660 if (normal_names[i]) {
3661 float dot = x * stbvox_default_normals[i][0] + y * stbvox_default_normals[i][1] + z * stbvox_default_normals[i][2];
3662 if (dot > best_dot) {
3663 best_dot = dot;
3664 best_slot = i;
3665 }
3666 }
3667 }
3668 return normal_names[best_slot];
3669 }
3670
3671 int main(int argc, char **argv)
3672 {
3673 int sw,se,nw,ne;
3674 for (ne=0; ne < 4; ++ne) {
3675 for (nw=0; nw < 4; ++nw) {
3676 for (se=0; se < 4; ++se) {
3677 printf(" { ");
3678 for (sw=0; sw < 4; ++sw) {
3679 float x = (float) (nw + sw - ne - se);
3680 float y = (float) (sw + se - nw - ne);
3681 float z = 2;
3682 printf("STBVF_%s, ", find_best_normal(x,y,z));
3683 }
3684 printf("},\n");
3685 }
3686 }
3687 }
3688 return 0;
3689 }
3690 #endif
3691
3692 // @TODO
3693 //
3694 // - test API for texture rotation on side faces
3695 // - API for texture rotation on top & bottom
3696 // - better culling of vheight faces with vheight neighbors
3697 // - better culling of non-vheight faces with vheight neighbors
3698 // - gather vertex lighting from slopes correctly
3699 // - better support texture edge_clamp: currently if you fall
3700 // exactly on 1.0 you get wrapped incorrectly; this is rare, but
3701 // can avoid: compute texcoords in vertex shader, offset towards
3702 // center before modding, need 2 bits per vertex to know offset direction)
3703 // - other mesh modes (10,6,4-byte quads)
3704 //
3705 //
3706 // With TexBuffer for the fixed vertex data, we can actually do
3707 // minecrafty non-blocks like stairs -- we still probably only
3708 // want 256 or so, so we can't do the equivalent of all the vheight
3709 // combos, but that's ok. The 256 includes baked rotations, but only
3710 // some of them need it, and lots of block types share some faces.
3711 //
3712 // mode 5 (6 bytes): mode 6 (6 bytes)
3713 // x:7 x:6
3714 // y:7 y:6
3715 // z:6 z:6
3716 // tex1:8 tex1:8
3717 // tex2:8 tex2:7
3718 // color:8 color:8
3719 // face:4 face:7
3720 //
3721 //
3722 // side faces (all x4) top&bottom faces (2x) internal faces (1x)
3723 // 1 regular 1 regular
3724 // 2 slabs 2
3725 // 8 stairs 4 stairs 16
3726 // 4 diag side 8
3727 // 4 upper diag side 8
3728 // 4 lower diag side 8
3729 // 4 crossed pairs
3730 //
3731 // 23*4 + 5*4 + 46
3732 // == 92 + 20 + 46 = 158
3733 //
3734 // Must drop 30 of them to fit in 7 bits:
3735 // ceiling half diagonals: 16+8 = 24
3736 // Need to get rid of 6 more.
3737 // ceiling diagonals: 8+4 = 12
3738 // This brings it to 122, so can add a crossed-pair variant.
3739 // (diagonal and non-diagonal, or randomly offset)
3740 // Or carpet, which would be 5 more.
3741 //
3742 //
3743 // Mode 4 (10 bytes):
3744 // v: z:2,light:6
3745 // f: x:6,y:6,z:7, t1:8,t2:8,c:8,f:5
3746 //
3747 // Mode ? (10 bytes)
3748 // v: xyz:5 (27 values), light:3
3749 // f: x:7,y:7,z:6, t1:8,t2:8,c:8,f:4
3750 // (v: x:2,y:2,z:2,light:2)
3751
3752 #endif // STB_VOXEL_RENDER_IMPLEMENTATION