-
Notifications
You must be signed in to change notification settings - Fork 0
/
stb_voxel_render.h
3807 lines (3418 loc) · 157 KB
/
stb_voxel_render.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
// stb_voxel_render.h - v0.89 - Sean Barrett, 2015 - public domain
//
// This library helps render large-scale "voxel" worlds for games,
// in this case, one with blocks that can have textures and that
// can also be a few shapes other than cubes.
//
// Video introduction:
// http://www.youtube.com/watch?v=2vnTtiLrV1w
//
// Minecraft-viewer sample app (not very simple though):
// http://github.com/nothings/stb/tree/master/tests/caveview
//
// It works by creating triangle meshes. The library includes
//
// - converter from dense 3D arrays of block info to vertex mesh
// - vertex & fragment shaders for the vertex mesh
// - assistance in setting up shader state
//
// For portability, none of the library code actually accesses
// the 3D graphics API. (At the moment, it's not actually portable
// since the shaders are GLSL only, but patches are welcome.)
//
// You have to do all the caching and tracking of vertex buffers
// yourself. However, you could also try making a game with
// a small enough world that it's fully loaded rather than
// streaming. Currently the preferred vertex format is 20 bytes
// per quad. There are designs to allow much more compact formats
// with a slight reduction in shader features, but no roadmap
// for actually implementing them.
//
//
// USAGE
//
// #define the symbol STB_VOXEL_RENDER_IMPLEMENTATION in *one*
// C/C++ file before the #include of this file; the implementation
// will be generated in that file.
//
// If you define the symbols STB_VOXEL_RENDER_STATIC, then the
// implementation will be private to that file.
//
//
// FEATURES
//
// - you can choose textured blocks with the features below,
// or colored voxels with 2^24 colors and no textures.
//
// - voxels are mostly just cubes, but there's support for
// half-height cubes and diagonal slopes, half-height
// diagonals, and even odder shapes especially for doing
// more-continuous "ground".
//
// - texture coordinates are projections along one of the major
// axes, with the per-texture scaling.
//
// - a number of aspects of the shader and the vertex format
// are configurable; the library generally takes care of
// coordinating the vertex format with the mesh for you.
//
//
// FEATURES (SHADER PERSPECTIVE)
//
// - vertices aligned on integer lattice, z on multiples of 0.5
// - per-vertex "lighting" or "ambient occlusion" value (6 bits)
// - per-vertex texture crossfade (3 bits)
//
// - per-face texture #1 id (8-bit index into array texture)
// - per-face texture #2 id (8-bit index into second array texture)
// - per-face color (6-bit palette index, 2 bits of per-texture boolean enable)
// - per-face 5-bit normal for lighting calculations & texture coord computation
// - per-face 2-bit texture matrix rotation to rotate faces
//
// - indexed-by-texture-id scale factor (separate for texture #1 and texture #2)
// - indexed-by-texture-#2-id blend mode (alpha composite or modulate/multiply);
// the first is good for decals, the second for detail textures, "light maps",
// etc; both modes are controlled by texture #2's alpha, scaled by the
// per-vertex texture crossfade and the per-face color (if enabled on texture #2);
// modulate/multiply multiplies by an extra factor of 2.0 so that if you
// make detail maps whose average brightness is 0.5 everything works nicely.
//
// - ambient lighting: half-lambert directional plus constant, all scaled by vertex ao
// - face can be fullbright (emissive), controlled by per-face color
// - installable lighting, with default single-point-light
// - installable fog, with default hacked smoothstep
//
// Note that all the variations of lighting selection and texture
// blending are run-time conditions in the shader, so they can be
// intermixed in a single mesh.
//
//
// INTEGRATION ARC
//
// The way to get this library to work from scratch is to do the following:
//
// Step 1. define STBVOX_CONFIG_MODE to 0
//
// This mode uses only vertex attributes and uniforms, and is easiest
// to get working. It requires 32 bytes per quad and limits the
// size of some tables to avoid hitting uniform limits.
//
// Step 2. define STBVOX_CONFIG_MODE to 1
//
// This requires using a texture buffer to store the quad data,
// reducing the size to 20 bytes per quad.
//
// Step 3: define STBVOX_CONFIG_PREFER_TEXBUFFER
//
// This causes some uniforms to be stored as texture buffers
// instead. This increases the size of some of those tables,
// and avoids a potential slow path (gathering non-uniform
// data from uniforms) on some hardware.
//
// In the future I might add additional modes that have significantly
// smaller meshes but reduce features, down as small as 6 bytes per quad.
// See elsewhere in this file for a table of candidate modes. Switching
// to a mode will require changing some of your mesh creation code, but
// everything else should be seamless. (And I'd like to change the API
// so that mesh creation is data-driven the way the uniforms are, and
// then you wouldn't even have to change anything but the mode number.)
//
//
// IMPROVEMENTS FOR SHIP-WORTHY PROGRAMS USING THIS LIBRARY
//
// I currently tolerate a certain level of "bugginess" in this library.
//
// I'm referring to things which look a little wrong (as long as they
// don't cause holes or cracks in the output meshes), or things which
// do not produce as optimal a mesh as possible. Notable examples:
//
// - incorrect lighting on slopes
// - inefficient meshes for vheight blocks
//
// I am willing to do the work to improve these things if someone is
// going to ship a substantial program that would be improved by them.
// (It need not be commercial, nor need it be a game.) I just didn't
// want to do the work up front if it might never be leveraged. So just
// submit a bug report as usual (github is preferred), but add a note
// that this is for a thing that is really going to ship. (That means
// you need to be far enough into the project that it's clear you're
// committed to it; not during early exploratory development.)
//
//
// VOXEL MESH API
//
// Context
//
// To understand the API, make sure you first understand the feature set
// listed above.
//
// Because the vertices are compact, they have very limited spatial
// precision. Thus a single mesh can only contain the data for a limited
// area. To make very large voxel maps, you'll need to build multiple
// vertex buffers. (But you want this anyway for frustum culling.)
//
// Each generated mesh has three components:
// - vertex data (vertex buffer)
// - face data (optional, stored in texture buffer)
// - mesh transform (uniforms)
//
// Once you've generated the mesh with this library, it's up to you
// to upload it to the GPU, to keep track of the state, and to render
// it.
//
// Concept
//
// The basic design is that you pass in one or more 3D arrays; each array
// is (typically) one-byte-per-voxel and contains information about one
// or more properties of some particular voxel property.
//
// Because there is so much per-vertex and per-face data possible
// in the output, and each voxel can have 6 faces and 8 vertices, it
// would require an very large data structure to describe all
// of the possibilities, and this would cause the mesh-creation
// process to be slow. Instead, the API provides multiple ways
// to express each property, some more compact, others less so;
// each such way has some limitations on what it can express.
//
// Note that there are so many paths and combinations, not all of them
// have been tested. Just report bugs and I'll fix 'em.
//
// Details
//
// See the API documentation in the header-file section.
//
//
// CONTRIBUTORS
//
// Features Porting Bugfixes & Warnings
// Sean Barrett github:r-leyh Jesus Fernandez
// Miguel Lechon github:Arbeiterunfallversicherungsgesetz
// Thomas Frase James Hofmann
// Stephen Olsen github:guitarfreak
//
// VERSION HISTORY
//
// 0.89 (2020-02-02) bugfix in sample code
// 0.88 (2019-03-04) fix warnings
// 0.87 (2019-02-25) fix warning
// 0.86 (2019-02-07) fix typos in comments
// 0.85 (2017-03-03) add block_selector (by guitarfreak)
// 0.84 (2016-04-02) fix GLSL syntax error on glModelView path
// 0.83 (2015-09-13) remove non-constant struct initializers to support more compilers
// 0.82 (2015-08-01) added input.packed_compact to store rot, vheight & texlerp efficiently
// fix broken tex_overlay2
// 0.81 (2015-05-28) fix broken STBVOX_CONFIG_OPTIMIZED_VHEIGHT
// 0.80 (2015-04-11) fix broken STBVOX_CONFIG_ROTATION_IN_LIGHTING refactoring
// change STBVOX_MAKE_LIGHTING to STBVOX_MAKE_LIGHTING_EXT so
// that header defs don't need to see config vars
// add STBVOX_CONFIG_VHEIGHT_IN_LIGHTING and other vheight fixes
// added documentation for vheight ("weird slopes")
// 0.79 (2015-04-01) fix the missing types from 0.78; fix string constants being const
// 0.78 (2015-04-02) bad "#else", compile as C++
// 0.77 (2015-04-01) documentation tweaks, rename config var to STB_VOXEL_RENDER_STATIC
// 0.76 (2015-04-01) typos, signed/unsigned shader issue, more documentation
// 0.75 (2015-04-01) initial release
//
//
// HISTORICAL FOUNDATION
//
// stb_voxel_render 20-byte quads 2015/01
// zmc engine 32-byte quads 2013/12
// zmc engine 96-byte quads 2011/10
//
//
// LICENSE
//
// See end of file for license information.
#ifndef INCLUDE_STB_VOXEL_RENDER_H
#define INCLUDE_STB_VOXEL_RENDER_H
#include <stdlib.h>
typedef struct stbvox_mesh_maker stbvox_mesh_maker;
typedef struct stbvox_input_description stbvox_input_description;
#ifdef STB_VOXEL_RENDER_STATIC
#define STBVXDEC static
#else
#define STBVXDEC extern
#endif
#ifdef __cplusplus
extern "C" {
#endif
//////////////////////////////////////////////////////////////////////////////
//
// CONFIGURATION MACROS
//
// #define STBVOX_CONFIG_MODE <integer> // REQUIRED
// Configures the overall behavior of stb_voxel_render. This
// can affect the shaders, the uniform info, and other things.
// (If you need more than one mode in the same app, you can
// use STB_VOXEL_RENDER_STATIC to create multiple versions
// in separate files, and then wrap them.)
//
// Mode value Meaning
// 0 Textured blocks, 32-byte quads
// 1 Textured blocks, 20-byte quads
// 20 Untextured blocks, 32-byte quads
// 21 Untextured blocks, 20-byte quads
//
//
// #define STBVOX_CONFIG_PRECISION_Z <integer> // OPTIONAL
// Defines the number of bits of fractional position for Z.
// Only 0 or 1 are valid. 1 is the default. If 0, then a
// single mesh has twice the legal Z range; e.g. in
// modes 0,1,20,21, Z in the mesh can extend to 511 instead
// of 255. However, half-height blocks cannot be used.
//
// All of the following are just #ifdef tested so need no values, and are optional.
//
// STBVOX_CONFIG_BLOCKTYPE_SHORT
// use unsigned 16-bit values for 'blocktype' in the input instead of 8-bit values
//
// STBVOX_CONFIG_OPENGL_MODELVIEW
// use the gl_ModelView matrix rather than the explicit uniform
//
// STBVOX_CONFIG_HLSL
// NOT IMPLEMENTED! Define HLSL shaders instead of GLSL shaders
//
// STBVOX_CONFIG_PREFER_TEXBUFFER
// Stores many of the uniform arrays in texture buffers instead,
// so they can be larger and may be more efficient on some hardware.
//
// STBVOX_CONFIG_LIGHTING_SIMPLE
// Creates a simple lighting engine with a single point light source
// in addition to the default half-lambert ambient light.
//
// STBVOX_CONFIG_LIGHTING
// Declares a lighting function hook; you must append a lighting function
// to the shader before compiling it:
// vec3 compute_lighting(vec3 pos, vec3 norm, vec3 albedo, vec3 ambient);
// 'ambient' is the half-lambert ambient light with vertex ambient-occlusion applied
//
// STBVOX_CONFIG_FOG_SMOOTHSTEP
// Defines a simple unrealistic fog system designed to maximize
// unobscured view distance while not looking too weird when things
// emerge from the fog. Configured using an extra array element
// in the STBVOX_UNIFORM_ambient uniform.
//
// STBVOX_CONFIG_FOG
// Defines a fog function hook; you must append a fog function to
// the shader before compiling it:
// vec3 compute_fog(vec3 color, vec3 relative_pos, float fragment_alpha);
// "color" is the incoming pre-fogged color, fragment_alpha is the alpha value,
// and relative_pos is the vector from the point to the camera in worldspace
//
// STBVOX_CONFIG_DISABLE_TEX2
// This disables all processing of texture 2 in the shader in case
// you don't use it. Eventually this could be replaced with a mode
// that omits the unused data entirely.
//
// STBVOX_CONFIG_TEX1_EDGE_CLAMP
// STBVOX_CONFIG_TEX2_EDGE_CLAMP
// If you want to edge clamp the textures, instead of letting them wrap,
// set this flag. By default stb_voxel_render relies on texture wrapping
// to simplify texture coordinate generation. This flag forces it to do
// it correctly, although there can still be minor artifacts.
//
// STBVOX_CONFIG_ROTATION_IN_LIGHTING
// Changes the meaning of the 'lighting' mesher input variable to also
// store the rotation; see later discussion.
//
// STBVOX_CONFIG_VHEIGHT_IN_LIGHTING
// Changes the meaning of the 'lighting' mesher input variable to also
// store the vheight; see later discussion. Cannot use both this and
// the previous variable.
//
// STBVOX_CONFIG_PREMULTIPLIED_ALPHA
// Adjusts the shader calculations on the assumption that tex1.rgba,
// tex2.rgba, and color.rgba all use premultiplied values, and that
// the output of the fragment shader should be premultiplied.
//
// STBVOX_CONFIG_UNPREMULTIPLY
// Only meaningful if STBVOX_CONFIG_PREMULTIPLIED_ALPHA is defined.
// Changes the behavior described above so that the inputs are
// still premultiplied alpha, but the output of the fragment
// shader is not premultiplied alpha. This is needed when allowing
// non-unit alpha values but not doing alpha-blending (for example
// when alpha testing).
//
//////////////////////////////////////////////////////////////////////////////
//
// MESHING
//
// A mesh represents a (typically) small chunk of a larger world.
// Meshes encode coordinates using small integers, so those
// coordinates must be relative to some base location.
// All of the coordinates in the functions below use
// these relative coordinates unless explicitly stated
// otherwise.
//
// Input to the meshing step is documented further down
STBVXDEC void stbvox_init_mesh_maker(stbvox_mesh_maker *mm);
// Call this function to initialize a mesh-maker context structure
// used to build meshes. You should have one context per thread
// that's building meshes.
STBVXDEC void stbvox_set_buffer(stbvox_mesh_maker *mm, int mesh, int slot, void *buffer, size_t len);
// Call this to set the buffer into which stbvox will write the mesh
// it creates. It can build more than one mesh in parallel (distinguished
// by the 'mesh' parameter), and each mesh can be made up of more than
// one buffer (distinguished by the 'slot' parameter).
//
// Multiple meshes are under your control; use the 'selector' input
// variable to choose which mesh each voxel's vertices are written to.
// For example, you can use this to generate separate meshes for opaque
// and transparent data.
//
// You can query the number of slots by calling stbvox_get_buffer_count
// described below. The meaning of the buffer for each slot depends
// on STBVOX_CONFIG_MODE.
//
// In mode 0 & mode 20, there is only one slot. The mesh data for that
// slot is two interleaved vertex attributes: attr_vertex, a single
// 32-bit uint, and attr_face, a single 32-bit uint.
//
// In mode 1 & mode 21, there are two slots. The first buffer should
// be four times as large as the second buffer. The first buffer
// contains a single vertex attribute: 'attr_vertex', a single 32-bit uint.
// The second buffer contains texture buffer data (an array of 32-bit uints)
// that will be accessed through the sampler identified by STBVOX_UNIFORM_face_data.
STBVXDEC int stbvox_get_buffer_count(stbvox_mesh_maker *mm);
// Returns the number of buffers needed per mesh as described above.
STBVXDEC int stbvox_get_buffer_size_per_quad(stbvox_mesh_maker *mm, int slot);
// Returns how much of a given buffer will get used per quad. This
// allows you to choose correct relative sizes for each buffer, although
// the values are fixed based on the configuration you've selected at
// compile time, and the details are described in stbvox_set_buffer.
STBVXDEC void stbvox_set_default_mesh(stbvox_mesh_maker *mm, int mesh);
// Selects which mesh the mesher will output to (see previous function)
// if the input doesn't specify a per-voxel selector. (I doubt this is
// useful, but it's here just in case.)
STBVXDEC stbvox_input_description *stbvox_get_input_description(stbvox_mesh_maker *mm);
// This function call returns a pointer to the stbvox_input_description part
// of stbvox_mesh_maker (which you should otherwise treat as opaque). You
// zero this structure, then fill out the relevant pointers to the data
// describing your voxel object/world.
//
// See further documentation at the description of stbvox_input_description below.
STBVXDEC void stbvox_set_input_stride(stbvox_mesh_maker *mm, int x_stride_in_elements, int y_stride_in_elements);
// This sets the stride between successive elements of the 3D arrays
// in the stbvox_input_description. Z values are always stored consecutively.
// (The preferred coordinate system for stbvox is X right, Y forwards, Z up.)
STBVXDEC void stbvox_set_input_range(stbvox_mesh_maker *mm, int x0, int y0, int z0, int x1, int y1, int z1);
// This sets the range of values in the 3D array for the voxels that
// the mesh generator will convert. The lower values are inclusive,
// the higher values are exclusive, so (0,0,0) to (16,16,16) generates
// mesh data associated with voxels up to (15,15,15) but no higher.
//
// The mesh generate generates faces at the boundary between open space
// and solid space but associates them with the solid space, so if (15,0,0)
// is open and (16,0,0) is solid, then the mesh will contain the boundary
// between them if x0 <= 16 and x1 > 16.
//
// Note that the mesh generator will access array elements 1 beyond the
// limits set in these parameters. For example, if you set the limits
// to be (0,0,0) and (16,16,16), then the generator will access all of
// the voxels between (-1,-1,-1) and (16,16,16), including (16,16,16).
// You may have to do pointer arithmetic to make it work.
//
// For example, caveview processes mesh chunks that are 32x32x16, but it
// does this using input buffers that are 34x34x18.
//
// The lower limits are x0 >= 0, y0 >= 0, and z0 >= 0.
//
// The upper limits are mode dependent, but all the current methods are
// limited to x1 < 127, y1 < 127, z1 < 255. Note that these are not
// powers of two; if you want to use power-of-two chunks (to make
// it efficient to decide which chunk a coordinate falls in), you're
// limited to at most x1=64, y1=64, z1=128. For classic Minecraft-style
// worlds with limited vertical extent, I recommend using a single
// chunk for the entire height, which limits the height to 255 blocks
// (one less than Minecraft), and only chunk the map in X & Y.
STBVXDEC int stbvox_make_mesh(stbvox_mesh_maker *mm);
// Call this function to create mesh data for the currently configured
// set of input data. This appends to the currently configured mesh output
// buffer. Returns 1 on success. If there is not enough room in the buffer,
// it outputs as much as it can, and returns 0; you need to switch output
// buffers (either by calling stbvox_set_buffer to set new buffers, or
// by copying the data out and calling stbvox_reset_buffers), and then
// call this function again without changing any of the input parameters.
//
// Note that this function appends; you can call it multiple times to
// build a single mesh. For example, caveview uses chunks that are
// 32x32x255, but builds the mesh for it by processing 32x32x16 at atime
// (this is faster as it is reuses the same 34x34x18 input buffers rather
// than needing 34x34x257 input buffers).
// Once you're done creating a mesh into a given buffer,
// consider the following functions:
STBVXDEC int stbvox_get_quad_count(stbvox_mesh_maker *mm, int mesh);
// Returns the number of quads in the mesh currently generated by mm.
// This is the sum of all consecutive stbvox_make_mesh runs appending
// to the same buffer. 'mesh' distinguishes between the multiple user
// meshes available via 'selector' or stbvox_set_default_mesh.
//
// Typically you use this function when you're done building the mesh
// and want to record how to draw it.
//
// Note that there are no index buffers; the data stored in the buffers
// should be drawn as quads (e.g. with GL_QUAD); if your API does not
// support quads, you can create a single index buffer large enough to
// draw your largest vertex buffer, and reuse it for every rendering.
// (Note that if you use 32-bit indices, you'll use 24 bytes of bandwidth
// per quad, more than the 20 bytes for the vertex/face mesh data.)
STBVXDEC void stbvox_set_mesh_coordinates(stbvox_mesh_maker *mm, int x, int y, int z);
// Sets the global coordinates for this chunk, such that (0,0,0) relative
// coordinates will be at (x,y,z) in global coordinates.
STBVXDEC void stbvox_get_bounds(stbvox_mesh_maker *mm, float bounds[2][3]);
// Returns the bounds for the mesh in global coordinates. Use this
// for e.g. frustum culling the mesh. @BUG: this just uses the
// values from stbvox_set_input_range(), so if you build by
// appending multiple values, this will be wrong, and you need to
// set stbvox_set_input_range() to the full size. Someday this
// will switch to tracking the actual bounds of the *mesh*, though.
STBVXDEC void stbvox_get_transform(stbvox_mesh_maker *mm, float transform[3][3]);
// Returns the 'transform' data for the shader uniforms. It is your
// job to set this to the shader before drawing the mesh. It is the
// only uniform that needs to change per-mesh. Note that it is not
// a 3x3 matrix, but rather a scale to decode fixed point numbers as
// floats, a translate from relative to global space, and a special
// translation for texture coordinate generation that avoids
// floating-point precision issues. @TODO: currently we add the
// global translation to the vertex, than multiply by modelview,
// but this means if camera location and vertex are far from the
// origin, we lose precision. Need to make a special modelview with
// the translation (or some of it) factored out to avoid this.
STBVXDEC void stbvox_reset_buffers(stbvox_mesh_maker *mm);
// Call this function if you're done with the current output buffer
// but want to reuse it (e.g. you're done appending with
// stbvox_make_mesh and you've copied the data out to your graphics API
// so can reuse the buffer).
//////////////////////////////////////////////////////////////////////////////
//
// RENDERING
//
STBVXDEC char *stbvox_get_vertex_shader(void);
// Returns the (currently GLSL-only) vertex shader.
STBVXDEC char *stbvox_get_fragment_shader(void);
// Returns the (currently GLSL-only) fragment shader.
// You can override the lighting and fogging calculations
// by appending data to the end of these; see the #define
// documentation for more information.
STBVXDEC char *stbvox_get_fragment_shader_alpha_only(void);
// Returns a slightly cheaper fragment shader that computes
// alpha but not color. This is useful for e.g. a depth-only
// pass when using alpha test.
typedef struct stbvox_uniform_info stbvox_uniform_info;
STBVXDEC int stbvox_get_uniform_info(stbvox_uniform_info *info, int uniform);
// Gets the information about a uniform necessary for you to
// set up each uniform with a minimal amount of explicit code.
// See the sample code after the structure definition for stbvox_uniform_info,
// further down in this header section.
//
// "uniform" is from the list immediately following. For many
// of these, default values are provided which you can set.
// Most values are shared for most draw calls; e.g. for stateful
// APIs you can set most of the state only once. Only
// STBVOX_UNIFORM_transform needs to change per draw call.
//
// STBVOX_UNIFORM_texscale
// 64- or 128-long vec4 array. (128 only if STBVOX_CONFIG_PREFER_TEXBUFFER)
// x: scale factor to apply to texture #1. must be a power of two. 1.0 means 'face-sized'
// y: scale factor to apply to texture #2. must be a power of two. 1.0 means 'face-sized'
// z: blend mode indexed by texture #2. 0.0 is alpha compositing; 1.0 is multiplication.
// w: unused currently. @TODO use to support texture animation?
//
// Texscale is indexed by the bottom 6 or 7 bits of the texture id; thus for
// example the texture at index 0 in the array and the texture in index 128 of
// the array must be scaled the same. This means that if you only have 64 or 128
// unique textures, they all get distinct values anyway; otherwise you have
// to group them in pairs or sets of four.
//
// STBVOX_UNIFORM_ambient
// 4-long vec4 array:
// ambient[0].xyz - negative of direction of a directional light for half-lambert
// ambient[1].rgb - color of light scaled by NdotL (can be negative)
// ambient[2].rgb - constant light added to above calculation;
// effectively light ranges from ambient[2]-ambient[1] to ambient[2]+ambient[1]
// ambient[3].rgb - fog color for STBVOX_CONFIG_FOG_SMOOTHSTEP
// ambient[3].a - reciprocal of squared distance of farthest fog point (viewing distance)
// +----- has a default value
// | +-- you should always use the default value
enum // V V
{ // ------------------------------------------------
STBVOX_UNIFORM_face_data, // n the sampler with the face texture buffer
STBVOX_UNIFORM_transform, // n the transform data from stbvox_get_transform
STBVOX_UNIFORM_tex_array, // n an array of two texture samplers containing the two texture arrays
STBVOX_UNIFORM_texscale, // Y a table of texture properties, see above
STBVOX_UNIFORM_color_table, // Y 64 vec4 RGBA values; a default palette is provided; if A > 1.0, fullbright
STBVOX_UNIFORM_normals, // Y Y table of normals, internal-only
STBVOX_UNIFORM_texgen, // Y Y table of texgen vectors, internal-only
STBVOX_UNIFORM_ambient, // n lighting & fog info, see above
STBVOX_UNIFORM_camera_pos, // Y camera position in global voxel space (for lighting & fog)
STBVOX_UNIFORM_count,
};
enum
{
STBVOX_UNIFORM_TYPE_none,
STBVOX_UNIFORM_TYPE_sampler,
STBVOX_UNIFORM_TYPE_vec2,
STBVOX_UNIFORM_TYPE_vec3,
STBVOX_UNIFORM_TYPE_vec4,
};
struct stbvox_uniform_info
{
int type; // which type of uniform
int bytes_per_element; // the size of each uniform array element (e.g. vec3 = 12 bytes)
int array_length; // length of the uniform array
char *name; // name in the shader @TODO use numeric binding
float *default_value; // if not NULL, you can use this as the uniform pointer
int use_tex_buffer; // if true, then the uniform is a sampler but the data can come from default_value
};
//////////////////////////////////////////////////////////////////////////////
//
// Uniform sample code
//
#if 0
// Run this once per frame before drawing all the meshes.
// You still need to separately set the 'transform' uniform for every mesh.
void setup_uniforms(GLuint shader, float camera_pos[4], GLuint tex1, GLuint tex2)
{
int i;
glUseProgram(shader); // so uniform binding works
for (i=0; i < STBVOX_UNIFORM_count; ++i) {
stbvox_uniform_info sui;
if (stbvox_get_uniform_info(&sui, i)) {
GLint loc = glGetUniformLocation(shader, sui.name);
if (loc != -1) {
switch (i) {
case STBVOX_UNIFORM_camera_pos: // only needed for fog
glUniform4fv(loc, sui.array_length, camera_pos);
break;
case STBVOX_UNIFORM_tex_array: {
GLuint tex_unit[2] = { 0, 1 }; // your choice of samplers
glUniform1iv(loc, 2, tex_unit);
glActiveTexture(GL_TEXTURE0 + tex_unit[0]); glBindTexture(GL_TEXTURE_2D_ARRAY, tex1);
glActiveTexture(GL_TEXTURE0 + tex_unit[1]); glBindTexture(GL_TEXTURE_2D_ARRAY, tex2);
glActiveTexture(GL_TEXTURE0); // reset to default
break;
}
case STBVOX_UNIFORM_face_data:
glUniform1i(loc, SAMPLER_YOU_WILL_BIND_PER_MESH_FACE_DATA_TO);
break;
case STBVOX_UNIFORM_ambient: // you definitely want to override this
case STBVOX_UNIFORM_color_table: // you might want to override this
case STBVOX_UNIFORM_texscale: // you may want to override this
glUniform4fv(loc, sui.array_length, sui.default_value);
break;
case STBVOX_UNIFORM_normals: // you never want to override this
case STBVOX_UNIFORM_texgen: // you never want to override this
glUniform3fv(loc, sui.array_length, sui.default_value);
break;
}
}
}
}
}
#endif
#ifdef __cplusplus
}
#endif
//////////////////////////////////////////////////////////////////////////////
//
// INPUT TO MESHING
//
// Shapes of blocks that aren't always cubes
enum
{
STBVOX_GEOM_empty,
STBVOX_GEOM_knockout, // creates a hole in the mesh
STBVOX_GEOM_solid,
STBVOX_GEOM_transp, // solid geometry, but transparent contents so neighbors generate normally, unless same blocktype
// following 4 can be represented by vheight as well
STBVOX_GEOM_slab_upper,
STBVOX_GEOM_slab_lower,
STBVOX_GEOM_floor_slope_north_is_top,
STBVOX_GEOM_ceil_slope_north_is_bottom,
STBVOX_GEOM_floor_slope_north_is_top_as_wall_UNIMPLEMENTED, // same as floor_slope above, but uses wall's texture & texture projection
STBVOX_GEOM_ceil_slope_north_is_bottom_as_wall_UNIMPLEMENTED,
STBVOX_GEOM_crossed_pair, // corner-to-corner pairs, with normal vector bumped upwards
STBVOX_GEOM_force, // like GEOM_transp, but faces visible even if neighbor is same type, e.g. minecraft fancy leaves
// these access vheight input
STBVOX_GEOM_floor_vheight_03 = 12, // diagonal is SW-NE
STBVOX_GEOM_floor_vheight_12, // diagonal is SE-NW
STBVOX_GEOM_ceil_vheight_03,
STBVOX_GEOM_ceil_vheight_12,
STBVOX_GEOM_count, // number of geom cases
};
enum
{
STBVOX_FACE_east,
STBVOX_FACE_north,
STBVOX_FACE_west,
STBVOX_FACE_south,
STBVOX_FACE_up,
STBVOX_FACE_down,
STBVOX_FACE_count,
};
#ifdef STBVOX_CONFIG_BLOCKTYPE_SHORT
typedef unsigned short stbvox_block_type;
#else
typedef unsigned char stbvox_block_type;
#endif
// 24-bit color
typedef struct
{
unsigned char r,g,b;
} stbvox_rgb;
#define STBVOX_COLOR_TEX1_ENABLE 64
#define STBVOX_COLOR_TEX2_ENABLE 128
// This is the data structure you fill out. Most of the arrays can be
// NULL, except when one is required to get the value to index another.
//
// The compass system used in the following descriptions is:
// east means increasing x
// north means increasing y
// up means increasing z
struct stbvox_input_description
{
unsigned char lighting_at_vertices;
// The default is lighting values (i.e. ambient occlusion) are at block
// center, and the vertex light is gathered from those adjacent block
// centers that the vertex is facing. This makes smooth lighting
// consistent across adjacent faces with the same orientation.
//
// Setting this flag to non-zero gives you explicit control
// of light at each vertex, but now the lighting/ao will be
// shared by all vertices at the same point, even if they
// have different normals.
// these are mostly 3D maps you use to define your voxel world, using x_stride and y_stride
// note that for cache efficiency, you want to use the block_foo palettes as much as possible instead
stbvox_rgb *rgb;
// Indexed by 3D coordinate.
// 24-bit voxel color for STBVOX_CONFIG_MODE = 20 or 21 only
unsigned char *lighting;
// Indexed by 3D coordinate. The lighting value / ambient occlusion
// value that is used to define the vertex lighting values.
// The raw lighting values are defined at the center of blocks
// (or at vertex if 'lighting_at_vertices' is true).
//
// If the macro STBVOX_CONFIG_ROTATION_IN_LIGHTING is defined,
// then an additional 2-bit block rotation value is stored
// in this field as well.
//
// Encode with STBVOX_MAKE_LIGHTING_EXT(lighting,rot)--here
// 'lighting' should still be 8 bits, as the macro will
// discard the bottom bits automatically. Similarly, if
// using STBVOX_CONFIG_VHEIGHT_IN_LIGHTING, encode with
// STBVOX_MAKE_LIGHTING_EXT(lighting,vheight).
//
// (Rationale: rotation needs to be independent of blocktype,
// but is only 2 bits so doesn't want to be its own array.
// Lighting is the one thing that was likely to already be
// in use and that I could easily steal 2 bits from.)
stbvox_block_type *blocktype;
// Indexed by 3D coordinate. This is a core "block type" value, which is used
// to index into other arrays; essentially a "palette". This is much more
// memory-efficient and performance-friendly than storing the values explicitly,
// but only makes sense if the values are always synchronized.
//
// If a voxel's blocktype is 0, it is assumed to be empty (STBVOX_GEOM_empty),
// and no other blocktypes should be STBVOX_GEOM_empty. (Only if you do not
// have blocktypes should STBVOX_GEOM_empty ever used.)
//
// Normally it is an unsigned byte, but you can override it to be
// a short if you have too many blocktypes.
unsigned char *geometry;
// Indexed by 3D coordinate. Contains the geometry type for the block.
// Also contains a 2-bit rotation for how the whole block is rotated.
// Also includes a 2-bit vheight value when using shared vheight values.
// See the separate vheight documentation.
// Encode with STBVOX_MAKE_GEOMETRY(geom, rot, vheight)
unsigned char *block_geometry;
// Array indexed by blocktype containing the geometry for this block, plus
// a 2-bit "simple rotation". Note rotation has limited use since it's not
// independent of blocktype.
//
// Encode with STBVOX_MAKE_GEOMETRY(geom,simple_rot,0)
unsigned char *block_tex1;
// Array indexed by blocktype containing the texture id for texture #1.
unsigned char (*block_tex1_face)[6];
// Array indexed by blocktype and face containing the texture id for texture #1.
// The N/E/S/W face choices can be rotated by one of the rotation selectors;
// The top & bottom face textures will rotate to match.
// Note that it only makes sense to use one of block_tex1 or block_tex1_face;
// this pattern repeats throughout and this notice is not repeated.
unsigned char *tex2;
// Indexed by 3D coordinate. Contains the texture id for texture #2
// to use on all faces of the block.
unsigned char *block_tex2;
// Array indexed by blocktype containing the texture id for texture #2.
unsigned char (*block_tex2_face)[6];
// Array indexed by blocktype and face containing the texture id for texture #2.
// The N/E/S/W face choices can be rotated by one of the rotation selectors;
// The top & bottom face textures will rotate to match.
unsigned char *color;
// Indexed by 3D coordinate. Contains the color for all faces of the block.
// The core color value is 0..63.
// Encode with STBVOX_MAKE_COLOR(color_number, tex1_enable, tex2_enable)
unsigned char *block_color;
// Array indexed by blocktype containing the color value to apply to the faces.
// The core color value is 0..63.
// Encode with STBVOX_MAKE_COLOR(color_number, tex1_enable, tex2_enable)
unsigned char (*block_color_face)[6];
// Array indexed by blocktype and face containing the color value to apply to that face.
// The core color value is 0..63.
// Encode with STBVOX_MAKE_COLOR(color_number, tex1_enable, tex2_enable)
unsigned char *block_texlerp;
// Array indexed by blocktype containing 3-bit scalar for texture #2 alpha
// (known throughout as 'texlerp'). This is constant over every face even
// though the property is potentially per-vertex.
unsigned char (*block_texlerp_face)[6];
// Array indexed by blocktype and face containing 3-bit scalar for texture #2 alpha.
// This is constant over the face even though the property is potentially per-vertex.
unsigned char *block_vheight;
// Array indexed by blocktype containing the vheight values for the
// top or bottom face of this block. These will rotate properly if the
// block is rotated. See discussion of vheight.
// Encode with STBVOX_MAKE_VHEIGHT(sw_height, se_height, nw_height, ne_height)
unsigned char *selector;
// Array indexed by 3D coordinates indicating which output mesh to select.
unsigned char *block_selector;
// Array indexed by blocktype indicating which output mesh to select.
unsigned char *side_texrot;
// Array indexed by 3D coordinates encoding 2-bit texture rotations for the
// faces on the E/N/W/S sides of the block.
// Encode with STBVOX_MAKE_SIDE_TEXROT(rot_e, rot_n, rot_w, rot_s)
unsigned char *block_side_texrot;
// Array indexed by blocktype encoding 2-bit texture rotations for the faces
// on the E/N/W/S sides of the block.
// Encode with STBVOX_MAKE_SIDE_TEXROT(rot_e, rot_n, rot_w, rot_s)
unsigned char *overlay; // index into palettes listed below
// Indexed by 3D coordinate. If 0, there is no overlay. If non-zero,
// it indexes into to the below arrays and overrides the values
// defined by the blocktype.
unsigned char (*overlay_tex1)[6];
// Array indexed by overlay value and face, containing an override value
// for the texture id for texture #1. If 0, the value defined by blocktype
// is used.
unsigned char (*overlay_tex2)[6];
// Array indexed by overlay value and face, containing an override value
// for the texture id for texture #2. If 0, the value defined by blocktype
// is used.
unsigned char (*overlay_color)[6];
// Array indexed by overlay value and face, containing an override value
// for the face color. If 0, the value defined by blocktype is used.
unsigned char *overlay_side_texrot;
// Array indexed by overlay value, encoding 2-bit texture rotations for the faces
// on the E/N/W/S sides of the block.
// Encode with STBVOX_MAKE_SIDE_TEXROT(rot_e, rot_n, rot_w, rot_s)
unsigned char *rotate;
// Indexed by 3D coordinate. Allows independent rotation of several
// parts of the voxel, where by rotation I mean swapping textures
// and colors between E/N/S/W faces.
// Block: rotates anything indexed by blocktype
// Overlay: rotates anything indexed by overlay
// EColor: rotates faces defined in ecolor_facemask
// Encode with STBVOX_MAKE_MATROT(block,overlay,ecolor)
unsigned char *tex2_for_tex1;
// Array indexed by tex1 containing the texture id for texture #2.
// You can use this if the two are always/almost-always strictly
// correlated (e.g. if tex2 is a detail texture for tex1), as it
// will be more efficient (touching fewer cache lines) than using
// e.g. block_tex2_face.
unsigned char *tex2_replace;
// Indexed by 3D coordinate. Specifies the texture id for texture #2
// to use on a single face of the voxel, which must be E/N/W/S (not U/D).
// The texture id is limited to 6 bits unless tex2_facemask is also
// defined (see below).
// Encode with STBVOX_MAKE_TEX2_REPLACE(tex2, face)
unsigned char *tex2_facemask;
// Indexed by 3D coordinate. Specifies which of the six faces should
// have their tex2 replaced by the value of tex2_replace. In this
// case, all 8 bits of tex2_replace are used as the texture id.
// Encode with STBVOX_MAKE_FACE_MASK(east,north,west,south,up,down)
unsigned char *extended_color;
// Indexed by 3D coordinate. Specifies a value that indexes into
// the ecolor arrays below (both of which must be defined).
unsigned char *ecolor_color;
// Indexed by extended_color value, specifies an optional override
// for the color value on some faces.
// Encode with STBVOX_MAKE_COLOR(color_number, tex1_enable, tex2_enable)
unsigned char *ecolor_facemask;
// Indexed by extended_color value, this specifies which faces the
// color in ecolor_color should be applied to. The faces can be
// independently rotated by the ecolor value of 'rotate', if it exists.
// Encode with STBVOX_MAKE_FACE_MASK(e,n,w,s,u,d)
unsigned char *color2;
// Indexed by 3D coordinates, specifies an alternative color to apply
// to some of the faces of the block.
// Encode with STBVOX_MAKE_COLOR(color_number, tex1_enable, tex2_enable)
unsigned char *color2_facemask;
// Indexed by 3D coordinates, specifies which faces should use the
// color defined in color2. No rotation value is applied.
// Encode with STBVOX_MAKE_FACE_MASK(e,n,w,s,u,d)
unsigned char *color3;
// Indexed by 3D coordinates, specifies an alternative color to apply
// to some of the faces of the block.
// Encode with STBVOX_MAKE_COLOR(color_number, tex1_enable, tex2_enable)
unsigned char *color3_facemask;
// Indexed by 3D coordinates, specifies which faces should use the
// color defined in color3. No rotation value is applied.
// Encode with STBVOX_MAKE_FACE_MASK(e,n,w,s,u,d)
unsigned char *texlerp_simple;
// Indexed by 3D coordinates, this is the smallest texlerp encoding
// that can do useful work. It consits of three values: baselerp,
// vertlerp, and face_vertlerp. Baselerp defines the value
// to use on all of the faces but one, from the STBVOX_TEXLERP_BASE
// values. face_vertlerp is one of the 6 face values (or STBVOX_FACE_NONE)
// which specifies the face should use the vertlerp values.
// Vertlerp defines a lerp value at every vertex of the mesh.
// Thus, one face can have per-vertex texlerp values, and those
// values are encoded in the space so that they will be shared
// by adjacent faces that also use vertlerp, allowing continuity
// (this is used for the "texture crossfade" bit of the release video).
// Encode with STBVOX_MAKE_TEXLERP_SIMPLE(baselerp, vertlerp, face_vertlerp)
// The following texlerp encodings are experimental and maybe not
// that useful.
unsigned char *texlerp;
// Indexed by 3D coordinates, this defines four values:
// vertlerp is a lerp value at every vertex of the mesh (using STBVOX_TEXLERP_BASE values).
// ud is the value to use on up and down faces, from STBVOX_TEXLERP_FACE values
// ew is the value to use on east and west faces, from STBVOX_TEXLERP_FACE values
// ns is the value to use on north and south faces, from STBVOX_TEXLERP_FACE values
// If any of ud, ew, or ns is STBVOX_TEXLERP_FACE_use_vert, then the
// vertlerp values for the vertices are gathered and used for those faces.
// Encode with STBVOX_MAKE_TEXLERP(vertlerp,ud,ew,sw)
unsigned short *texlerp_vert3;
// Indexed by 3D coordinates, this works with texlerp and
// provides a unique texlerp value for every direction at
// every vertex. The same rules of whether faces share values
// applies. The STBVOX_TEXLERP_FACE vertlerp value defined in
// texlerp is only used for the down direction. The values at
// each vertex in other directions are defined in this array,
// and each uses the STBVOX_TEXLERP3 values (i.e. full precision
// 3-bit texlerp values).
// Encode with STBVOX_MAKE_VERT3(vertlerp_e,vertlerp_n,vertlerp_w,vertlerp_s,vertlerp_u)
unsigned short *texlerp_face3; // e:3,n:3,w:3,s:3,u:2,d:2
// Indexed by 3D coordinates, this provides a compact way to
// fully specify the texlerp value indepenendly for every face,
// but doesn't allow per-vertex variation. E/N/W/S values are
// encoded using STBVOX_TEXLERP3 values, whereas up and down
// use STBVOX_TEXLERP_SIMPLE values.
// Encode with STBVOX_MAKE_FACE3(face_e,face_n,face_w,face_s,face_u,face_d)
unsigned char *vheight; // STBVOX_MAKE_VHEIGHT -- sw:2, se:2, nw:2, ne:2, doesn't rotate
// Indexed by 3D coordinates, this defines the four
// vheight values to use if the geometry is STBVOX_GEOM_vheight*.
// See the vheight discussion.