Plasma Engine  2.0
Loading...
Searching...
No Matches
ogt_vox.h
1/*
2 opengametools vox file reader/writer - v0.6 - MIT license - Justin Paver, Oct 2019
3
4 This is a single-header-file library that provides easy-to-use
5 support for reading MagicaVoxel .vox files into structures that
6 are easy to dereference and extract information from. It also
7 supports writing back out to .vox file from those structures.
8
9 Please see the MIT license information at the end of this file.
10
11 Also, please consider sharing any improvements you make.
12
13 For more information and more tools, visit:
14 https://github.com/jpaver/opengametools
15
16 HOW TO COMPILE THIS LIBRARY
17
18 1. To compile this library, do this in *one* C or C++ file:
19 #define OGT_VOX_IMPLEMENTATION
20 #include "ogt_vox.h"
21
22 2. From any other module, it is sufficient to just #include this as usual:
23 #include "ogt_vox.h"
24
25 HOW TO READ A VOX SCENE (See demo_vox.cpp)
26
27 1. load a .vox file off disk into a memory buffer.
28
29 2. construct a scene from the memory buffer:
30 ogt_vox_scene* scene = ogt_vox_read_scene(buffer, buffer_size);
31
32 3. use the scene members to extract the information you need. eg.
33 printf("# of layers: %u\n", scene->num_layers );
34
35 4. destroy the scene:
36 ogt_vox_destroy_scene(scene);
37
38 HOW TO MERGE MULTIPLE VOX SCENES (See merge_vox.cpp)
39
40 1. construct multiple scenes from files you want to merge.
41
42 // read buffer1/buffer_size1 from "test1.vox"
43 // read buffer2/buffer_size2 from "test2.vox"
44 // read buffer3/buffer_size3 from "test3.vox"
45 ogt_vox_scene* scene1 = ogt_vox_read_scene(buffer1, buffer_size1);
46 ogt_vox_scene* scene2 = ogt_vox_read_scene(buffer2, buffer_size2);
47 ogt_vox_scene* scene3 = ogt_vox_read_scene(buffer3, buffer_size3);
48
49 2. construct a merged scene
50
51 const ogt_vox_scene* scenes[] = {scene1, scene2, scene3};
52 ogt_vox_scene* merged_scene = ogt_vox_merge_scenes(scenes, 3, NULL, 0);
53
54 3. save out the merged scene
55
56 uint8_t* out_buffer = ogt_vox_write_scene(merged_scene, &out_buffer_size);
57 // save out_buffer to disk as a .vox file (it has length out_buffer_size)
58
59 4. destroy the merged scene:
60
61 ogt_vox_destroy_scene(merged_scene);
62
63 EXPLANATION OF SCENE ELEMENTS:
64
65 A ogt_vox_scene comprises primarily a set of instances, models, layers and a palette.
66
67 A ogt_vox_palette contains a set of 256 colors that is used for the scene.
68 Each color is represented by a 4-tuple called an ogt_vox_rgba which contains red,
69 green, blue and alpha values for the color.
70
71 A ogt_vox_model is a 3-dimensional grid of voxels, where each of those voxels
72 is represented by an 8-bit color index. Voxels are arranged in order of increasing
73 X then increasing Y then increasing Z.
74
75 Given the x,y,z values for a voxel within the model dimensions, the voxels index
76 in the grid can be obtained as follows:
77
78 voxel_index = x + (y * model->size_x) + (z * model->size_x * model->size_y)
79
80 The index is only valid if the coordinate x,y,z satisfy the following conditions:
81 0 <= x < model->size_x -AND-
82 0 <= y < model->size_y -AND-
83 0 <= z < model->size_z
84
85 A voxels color index can be obtained as follows:
86
87 uint8_t color_index = model->voxel_data[voxel_index];
88
89 If color_index == 0, the voxel is not solid and can be skipped,
90 If color_index != 0, the voxel is solid and can be used to lookup the color in the palette:
91
92 ogt_vox_rgba color = scene->palette.color[ color_index]
93
94 A ogt_vox_instance is an individual placement of a voxel model within the scene. Each
95 instance has a transform that determines its position and orientation within the scene,
96 but it also has an index that specifies which model the instance uses for its shape. It
97 is expected that there is a many-to-one mapping of instances to models.
98
99 An ogt_vox_layer is used to conceptually group instances. Each instance indexes the
100 layer that it belongs to, but the layer itself has its own name and hidden/shown state.
101
102 EXPLANATION OF MERGED SCENES:
103
104 A merged scene contains all the models and all the scene instances from
105 each of the scenes that were passed into it.
106
107 The merged scene will have a combined palette of all the source scene
108 palettes by trying to match existing colors exactly, and falling back
109 to an RGB-distance matched color when all 256 colors in the merged
110 scene palette has been allocated.
111
112 You can explicitly control up to 255 merge palette colors by providing
113 those colors to ogt_vox_merge_scenes in the required_colors parameters eg.
114
115 const ogt_vox_palette palette; // load this via .vox or procedurally or whatever
116 const ogt_vox_scene* scenes[] = {scene1, scene2, scene3};
117 // palette.color[0] is always the empty color which is why we pass 255 colors starting from index 1 only:
118 ogt_vox_scene* merged_scene = ogt_vox_merge_scenes(scenes, 3, &palette.color[1], 255);
119*/
120#ifndef OGT_VOX_H__
121# define OGT_VOX_H__
122
123# if _MSC_VER == 1400
124// VS2005 doesn't have inttypes or stdint so we just define what we need here.
125typedef unsigned char uint8_t;
126typedef signed int int32_t;
127typedef unsigned int uint32_t;
128# ifndef UINT32_MAX
129# define UINT32_MAX ((uint32_t)0xFFFFFFFF)
130# endif
131# ifndef INT32_MAX
132# define INT32_MAX ((int32_t)0x7FFFFFFF)
133# endif
134# ifndef UINT8_MAX
135# define UINT8_MAX ((uint8_t)0xFF)
136# endif
137# elif defined(_MSC_VER)
138// general VS*
139# include <inttypes.h>
140# elif __APPLE__
141// general Apple compiler
142# elif defined(__GNUC__)
143// any GCC*
144# include <inttypes.h>
145# include <stdlib.h> // for size_t
146# else
147# error some fixup needed for this platform?
148# endif
149
150// denotes an invalid group index. Usually this is only applicable to the scene's root group's parent.
151static const uint32_t k_invalid_group_index = UINT32_MAX;
152
153// color
154typedef struct ogt_vox_rgba
155{
156 uint8_t r, g, b, a; // red, green, blue and alpha components of a color.
158
159// column-major 4x4 matrix
160typedef struct ogt_vox_transform
161{
162 float m00, m01, m02, m03; // column 0 of 4x4 matrix, 1st three elements = x axis vector, last element always 0.0
163 float m10, m11, m12, m13; // column 1 of 4x4 matrix, 1st three elements = y axis vector, last element always 0.0
164 float m20, m21, m22, m23; // column 2 of 4x4 matrix, 1st three elements = z axis vector, last element always 0.0
165 float m30, m31, m32, m33; // column 3 of 4x4 matrix. 1st three elements = translation vector, last element always 1.0
167
168// a palette of colors
169typedef struct ogt_vox_palette
170{
171 ogt_vox_rgba color[256]; // palette of colors. use the voxel indices to lookup color from the palette.
173
174// a 3-dimensional model of voxels
175typedef struct ogt_vox_model
176{
177 uint32_t size_x; // number of voxels in the local x dimension
178 uint32_t size_y; // number of voxels in the local y dimension
179 uint32_t size_z; // number of voxels in the local z dimension
180 uint32_t voxel_hash; // hash of the content of the grid.
181 const uint8_t* voxel_data; // grid of voxel data comprising color indices in x -> y -> z order. a color index of 0 means empty, all other indices mean solid and can be used to index the scene's palette to obtain the color for the voxel.
183
184// an instance of a model within the scene
185typedef struct ogt_vox_instance
186{
187 const char* name; // name of the instance if there is one, will be NULL otherwise.
188 ogt_vox_transform transform; // orientation and position of this instance within the scene. This is relative to its group local transform if group_index is not 0
189 uint32_t model_index; // index of the model used by this instance. used to lookup the model in the scene's models[] array.
190 uint32_t layer_index; // index of the layer used by this instance. used to lookup the layer in the scene's layers[] array.
191 uint32_t group_index; // this will be the index of the group in the scene's groups[] array. If group is zero it will be the scene root group and the instance transform will be a world-space transform, otherwise the transform is relative to the group.
192 bool hidden; // whether this instance is individually hidden or not. Note: the instance can also be hidden when its layer is hidden, or if it belongs to a group that is hidden.
194
195// describes a layer within the scene
196typedef struct ogt_vox_layer
197{
198 const char* name; // name of this layer if there is one, will be NULL otherwise.
199 bool hidden; // whether this layer is hidden or not.
201
202// describes a group within the scene
203typedef struct ogt_vox_group
204{
205 ogt_vox_transform transform; // transform of this group relative to its parent group (if any), otherwise this will be relative to world-space.
206 uint32_t parent_group_index; // if this group is parented to another group, this will be the index of its parent in the scene's groups[] array, otherwise this group will be the scene root group and this value will be k_invalid_group_index
207 uint32_t layer_index; // which layer this group belongs to. used to lookup the layer in the scene's layers[] array.
208 bool hidden; // whether this group is hidden or not.
210
211// the scene parsed from a .vox file.
212typedef struct ogt_vox_scene
213{
214 uint32_t num_models; // number of models within the scene.
215 uint32_t num_instances; // number of instances in the scene
216 uint32_t num_layers; // number of layers in the scene
217 uint32_t num_groups; // number of groups in the scene
218 const ogt_vox_model** models; // array of models. size is num_models
219 const ogt_vox_instance* instances; // array of instances. size is num_instances
220 const ogt_vox_layer* layers; // array of layers. size is num_layers
221 const ogt_vox_group* groups; // array of groups. size is num_groups
222 ogt_vox_palette palette; // the palette for this scene
224
225// allocate memory function interface. pass in size, and get a pointer to memory with at least that size available.
226typedef void* (*ogt_vox_alloc_func)(size_t size);
227
228// free memory function interface. pass in a pointer previously allocated and it will be released back to the system managing memory.
229typedef void (*ogt_vox_free_func)(void* ptr);
230
231// override the default scene memory allocator if you need to control memory precisely.
232void ogt_vox_set_memory_allocator(ogt_vox_alloc_func alloc_func, ogt_vox_free_func free_func);
233void* ogt_vox_malloc(size_t uiSize);
234void ogt_vox_free(void* pMem);
235
236// flags for ogt_vox_read_scene_with_flags
237static const uint32_t k_read_scene_flags_groups = 1 << 0; // if not specified, all instance transforms will be flattened into world space. If specified, will read group information and keep all transforms as local transform relative to the group they are in.
238
239// creates a scene from a vox file within a memory buffer of a given size.
240// you can destroy the input buffer once you have the scene as this function will allocate separate memory for the scene objecvt.
241const ogt_vox_scene* ogt_vox_read_scene(const uint8_t* pBuffer, uint32_t buffer_size);
242
243// just like ogt_vox_read_scene, but you can additionally pass a union of k_read_scene_flags
244const ogt_vox_scene* ogt_vox_read_scene_with_flags(const uint8_t* pBuffer, uint32_t buffer_size, uint32_t read_flags);
245
246// destroys a scene object to release its memory.
247void ogt_vox_destroy_scene(const ogt_vox_scene* pScene);
248
249// writes the scene to a new buffer and returns the buffer size. free the buffer with ogt_vox_free
250uint8_t* ogt_vox_write_scene(const ogt_vox_scene* pScene, uint32_t* pBuffer_size);
251
252// merges the specified scenes together to create a bigger scene. Merged scene can be destroyed using ogt_vox_destroy_scene
253// If you require specific colors in the merged scene palette, provide up to and including 255 of them via required_colors/required_color_count.
254ogt_vox_scene* ogt_vox_merge_scenes(const ogt_vox_scene** pScenes, uint32_t scene_count, const ogt_vox_rgba* pRequired_colors, const uint32_t required_color_count);
255
256#endif // OGT_VOX_H__
257
258//-----------------------------------------------------------------------------------------------------------------
259//
260// If you're only interested in using this library, everything you need is above this point.
261// If you're interested in how this library works, everything you need is below this point.
262//
263//-----------------------------------------------------------------------------------------------------------------
264#ifdef OGT_VOX_IMPLEMENTATION
265# include <assert.h>
266# include <stdio.h>
267# include <stdlib.h>
268# include <string.h>
269
270// MAKE_VOX_CHUNK_ID: used to construct a literal to describe a chunk in a .vox file.
271# define MAKE_VOX_CHUNK_ID(c0, c1, c2, c3) ((c0 << 0) | (c1 << 8) | (c2 << 16) | (c3 << 24))
272
273static const uint32_t CHUNK_ID_VOX_ = MAKE_VOX_CHUNK_ID('V', 'O', 'X', ' ');
274static const uint32_t CHUNK_ID_MAIN = MAKE_VOX_CHUNK_ID('M', 'A', 'I', 'N');
275static const uint32_t CHUNK_ID_SIZE = MAKE_VOX_CHUNK_ID('S', 'I', 'Z', 'E');
276static const uint32_t CHUNK_ID_XYZI = MAKE_VOX_CHUNK_ID('X', 'Y', 'Z', 'I');
277static const uint32_t CHUNK_ID_RGBA = MAKE_VOX_CHUNK_ID('R', 'G', 'B', 'A');
278static const uint32_t CHUNK_ID_nTRN = MAKE_VOX_CHUNK_ID('n', 'T', 'R', 'N');
279static const uint32_t CHUNK_ID_nGRP = MAKE_VOX_CHUNK_ID('n', 'G', 'R', 'P');
280static const uint32_t CHUNK_ID_nSHP = MAKE_VOX_CHUNK_ID('n', 'S', 'H', 'P');
281static const uint32_t CHUNK_ID_IMAP = MAKE_VOX_CHUNK_ID('I', 'M', 'A', 'P');
282static const uint32_t CHUNK_ID_LAYR = MAKE_VOX_CHUNK_ID('L', 'A', 'Y', 'R');
283static const uint32_t CHUNK_ID_MATL = MAKE_VOX_CHUNK_ID('M', 'A', 'T', 'L');
284static const uint32_t CHUNK_ID_MATT = MAKE_VOX_CHUNK_ID('M', 'A', 'T', 'T');
285static const uint32_t CHUNK_ID_rOBJ = MAKE_VOX_CHUNK_ID('r', 'O', 'B', 'J');
286
287// Some older .vox files will not store a palette, in which case the following palette will be used!
288static const uint8_t k_default_vox_palette[256 * 4] = {
289 0xff,
290 0xff,
291 0xff,
292 0xff,
293 0xff,
294 0xff,
295 0xcc,
296 0xff,
297 0xff,
298 0xff,
299 0x99,
300 0xff,
301 0xff,
302 0xff,
303 0x66,
304 0xff,
305 0xff,
306 0xff,
307 0x33,
308 0xff,
309 0xff,
310 0xff,
311 0x00,
312 0xff,
313 0xff,
314 0xcc,
315 0xff,
316 0xff,
317 0xff,
318 0xcc,
319 0xcc,
320 0xff,
321 0xff,
322 0xcc,
323 0x99,
324 0xff,
325 0xff,
326 0xcc,
327 0x66,
328 0xff,
329 0xff,
330 0xcc,
331 0x33,
332 0xff,
333 0xff,
334 0xcc,
335 0x00,
336 0xff,
337 0xff,
338 0x99,
339 0xff,
340 0xff,
341 0xff,
342 0x99,
343 0xcc,
344 0xff,
345 0xff,
346 0x99,
347 0x99,
348 0xff,
349 0xff,
350 0x99,
351 0x66,
352 0xff,
353 0xff,
354 0x99,
355 0x33,
356 0xff,
357 0xff,
358 0x99,
359 0x00,
360 0xff,
361 0xff,
362 0x66,
363 0xff,
364 0xff,
365 0xff,
366 0x66,
367 0xcc,
368 0xff,
369 0xff,
370 0x66,
371 0x99,
372 0xff,
373 0xff,
374 0x66,
375 0x66,
376 0xff,
377 0xff,
378 0x66,
379 0x33,
380 0xff,
381 0xff,
382 0x66,
383 0x00,
384 0xff,
385 0xff,
386 0x33,
387 0xff,
388 0xff,
389 0xff,
390 0x33,
391 0xcc,
392 0xff,
393 0xff,
394 0x33,
395 0x99,
396 0xff,
397 0xff,
398 0x33,
399 0x66,
400 0xff,
401 0xff,
402 0x33,
403 0x33,
404 0xff,
405 0xff,
406 0x33,
407 0x00,
408 0xff,
409 0xff,
410 0x00,
411 0xff,
412 0xff,
413 0xff,
414 0x00,
415 0xcc,
416 0xff,
417 0xff,
418 0x00,
419 0x99,
420 0xff,
421 0xff,
422 0x00,
423 0x66,
424 0xff,
425 0xff,
426 0x00,
427 0x33,
428 0xff,
429 0xff,
430 0x00,
431 0x00,
432 0xff,
433 0xcc,
434 0xff,
435 0xff,
436 0xff,
437 0xcc,
438 0xff,
439 0xcc,
440 0xff,
441 0xcc,
442 0xff,
443 0x99,
444 0xff,
445 0xcc,
446 0xff,
447 0x66,
448 0xff,
449 0xcc,
450 0xff,
451 0x33,
452 0xff,
453 0xcc,
454 0xff,
455 0x00,
456 0xff,
457 0xcc,
458 0xcc,
459 0xff,
460 0xff,
461 0xcc,
462 0xcc,
463 0xcc,
464 0xff,
465 0xcc,
466 0xcc,
467 0x99,
468 0xff,
469 0xcc,
470 0xcc,
471 0x66,
472 0xff,
473 0xcc,
474 0xcc,
475 0x33,
476 0xff,
477 0xcc,
478 0xcc,
479 0x00,
480 0xff,
481 0xcc,
482 0x99,
483 0xff,
484 0xff,
485 0xcc,
486 0x99,
487 0xcc,
488 0xff,
489 0xcc,
490 0x99,
491 0x99,
492 0xff,
493 0xcc,
494 0x99,
495 0x66,
496 0xff,
497 0xcc,
498 0x99,
499 0x33,
500 0xff,
501 0xcc,
502 0x99,
503 0x00,
504 0xff,
505 0xcc,
506 0x66,
507 0xff,
508 0xff,
509 0xcc,
510 0x66,
511 0xcc,
512 0xff,
513 0xcc,
514 0x66,
515 0x99,
516 0xff,
517 0xcc,
518 0x66,
519 0x66,
520 0xff,
521 0xcc,
522 0x66,
523 0x33,
524 0xff,
525 0xcc,
526 0x66,
527 0x00,
528 0xff,
529 0xcc,
530 0x33,
531 0xff,
532 0xff,
533 0xcc,
534 0x33,
535 0xcc,
536 0xff,
537 0xcc,
538 0x33,
539 0x99,
540 0xff,
541 0xcc,
542 0x33,
543 0x66,
544 0xff,
545 0xcc,
546 0x33,
547 0x33,
548 0xff,
549 0xcc,
550 0x33,
551 0x00,
552 0xff,
553 0xcc,
554 0x00,
555 0xff,
556 0xff,
557 0xcc,
558 0x00,
559 0xcc,
560 0xff,
561 0xcc,
562 0x00,
563 0x99,
564 0xff,
565 0xcc,
566 0x00,
567 0x66,
568 0xff,
569 0xcc,
570 0x00,
571 0x33,
572 0xff,
573 0xcc,
574 0x00,
575 0x00,
576 0xff,
577 0x99,
578 0xff,
579 0xff,
580 0xff,
581 0x99,
582 0xff,
583 0xcc,
584 0xff,
585 0x99,
586 0xff,
587 0x99,
588 0xff,
589 0x99,
590 0xff,
591 0x66,
592 0xff,
593 0x99,
594 0xff,
595 0x33,
596 0xff,
597 0x99,
598 0xff,
599 0x00,
600 0xff,
601 0x99,
602 0xcc,
603 0xff,
604 0xff,
605 0x99,
606 0xcc,
607 0xcc,
608 0xff,
609 0x99,
610 0xcc,
611 0x99,
612 0xff,
613 0x99,
614 0xcc,
615 0x66,
616 0xff,
617 0x99,
618 0xcc,
619 0x33,
620 0xff,
621 0x99,
622 0xcc,
623 0x00,
624 0xff,
625 0x99,
626 0x99,
627 0xff,
628 0xff,
629 0x99,
630 0x99,
631 0xcc,
632 0xff,
633 0x99,
634 0x99,
635 0x99,
636 0xff,
637 0x99,
638 0x99,
639 0x66,
640 0xff,
641 0x99,
642 0x99,
643 0x33,
644 0xff,
645 0x99,
646 0x99,
647 0x00,
648 0xff,
649 0x99,
650 0x66,
651 0xff,
652 0xff,
653 0x99,
654 0x66,
655 0xcc,
656 0xff,
657 0x99,
658 0x66,
659 0x99,
660 0xff,
661 0x99,
662 0x66,
663 0x66,
664 0xff,
665 0x99,
666 0x66,
667 0x33,
668 0xff,
669 0x99,
670 0x66,
671 0x00,
672 0xff,
673 0x99,
674 0x33,
675 0xff,
676 0xff,
677 0x99,
678 0x33,
679 0xcc,
680 0xff,
681 0x99,
682 0x33,
683 0x99,
684 0xff,
685 0x99,
686 0x33,
687 0x66,
688 0xff,
689 0x99,
690 0x33,
691 0x33,
692 0xff,
693 0x99,
694 0x33,
695 0x00,
696 0xff,
697 0x99,
698 0x00,
699 0xff,
700 0xff,
701 0x99,
702 0x00,
703 0xcc,
704 0xff,
705 0x99,
706 0x00,
707 0x99,
708 0xff,
709 0x99,
710 0x00,
711 0x66,
712 0xff,
713 0x99,
714 0x00,
715 0x33,
716 0xff,
717 0x99,
718 0x00,
719 0x00,
720 0xff,
721 0x66,
722 0xff,
723 0xff,
724 0xff,
725 0x66,
726 0xff,
727 0xcc,
728 0xff,
729 0x66,
730 0xff,
731 0x99,
732 0xff,
733 0x66,
734 0xff,
735 0x66,
736 0xff,
737 0x66,
738 0xff,
739 0x33,
740 0xff,
741 0x66,
742 0xff,
743 0x00,
744 0xff,
745 0x66,
746 0xcc,
747 0xff,
748 0xff,
749 0x66,
750 0xcc,
751 0xcc,
752 0xff,
753 0x66,
754 0xcc,
755 0x99,
756 0xff,
757 0x66,
758 0xcc,
759 0x66,
760 0xff,
761 0x66,
762 0xcc,
763 0x33,
764 0xff,
765 0x66,
766 0xcc,
767 0x00,
768 0xff,
769 0x66,
770 0x99,
771 0xff,
772 0xff,
773 0x66,
774 0x99,
775 0xcc,
776 0xff,
777 0x66,
778 0x99,
779 0x99,
780 0xff,
781 0x66,
782 0x99,
783 0x66,
784 0xff,
785 0x66,
786 0x99,
787 0x33,
788 0xff,
789 0x66,
790 0x99,
791 0x00,
792 0xff,
793 0x66,
794 0x66,
795 0xff,
796 0xff,
797 0x66,
798 0x66,
799 0xcc,
800 0xff,
801 0x66,
802 0x66,
803 0x99,
804 0xff,
805 0x66,
806 0x66,
807 0x66,
808 0xff,
809 0x66,
810 0x66,
811 0x33,
812 0xff,
813 0x66,
814 0x66,
815 0x00,
816 0xff,
817 0x66,
818 0x33,
819 0xff,
820 0xff,
821 0x66,
822 0x33,
823 0xcc,
824 0xff,
825 0x66,
826 0x33,
827 0x99,
828 0xff,
829 0x66,
830 0x33,
831 0x66,
832 0xff,
833 0x66,
834 0x33,
835 0x33,
836 0xff,
837 0x66,
838 0x33,
839 0x00,
840 0xff,
841 0x66,
842 0x00,
843 0xff,
844 0xff,
845 0x66,
846 0x00,
847 0xcc,
848 0xff,
849 0x66,
850 0x00,
851 0x99,
852 0xff,
853 0x66,
854 0x00,
855 0x66,
856 0xff,
857 0x66,
858 0x00,
859 0x33,
860 0xff,
861 0x66,
862 0x00,
863 0x00,
864 0xff,
865 0x33,
866 0xff,
867 0xff,
868 0xff,
869 0x33,
870 0xff,
871 0xcc,
872 0xff,
873 0x33,
874 0xff,
875 0x99,
876 0xff,
877 0x33,
878 0xff,
879 0x66,
880 0xff,
881 0x33,
882 0xff,
883 0x33,
884 0xff,
885 0x33,
886 0xff,
887 0x00,
888 0xff,
889 0x33,
890 0xcc,
891 0xff,
892 0xff,
893 0x33,
894 0xcc,
895 0xcc,
896 0xff,
897 0x33,
898 0xcc,
899 0x99,
900 0xff,
901 0x33,
902 0xcc,
903 0x66,
904 0xff,
905 0x33,
906 0xcc,
907 0x33,
908 0xff,
909 0x33,
910 0xcc,
911 0x00,
912 0xff,
913 0x33,
914 0x99,
915 0xff,
916 0xff,
917 0x33,
918 0x99,
919 0xcc,
920 0xff,
921 0x33,
922 0x99,
923 0x99,
924 0xff,
925 0x33,
926 0x99,
927 0x66,
928 0xff,
929 0x33,
930 0x99,
931 0x33,
932 0xff,
933 0x33,
934 0x99,
935 0x00,
936 0xff,
937 0x33,
938 0x66,
939 0xff,
940 0xff,
941 0x33,
942 0x66,
943 0xcc,
944 0xff,
945 0x33,
946 0x66,
947 0x99,
948 0xff,
949 0x33,
950 0x66,
951 0x66,
952 0xff,
953 0x33,
954 0x66,
955 0x33,
956 0xff,
957 0x33,
958 0x66,
959 0x00,
960 0xff,
961 0x33,
962 0x33,
963 0xff,
964 0xff,
965 0x33,
966 0x33,
967 0xcc,
968 0xff,
969 0x33,
970 0x33,
971 0x99,
972 0xff,
973 0x33,
974 0x33,
975 0x66,
976 0xff,
977 0x33,
978 0x33,
979 0x33,
980 0xff,
981 0x33,
982 0x33,
983 0x00,
984 0xff,
985 0x33,
986 0x00,
987 0xff,
988 0xff,
989 0x33,
990 0x00,
991 0xcc,
992 0xff,
993 0x33,
994 0x00,
995 0x99,
996 0xff,
997 0x33,
998 0x00,
999 0x66,
1000 0xff,
1001 0x33,
1002 0x00,
1003 0x33,
1004 0xff,
1005 0x33,
1006 0x00,
1007 0x00,
1008 0xff,
1009 0x00,
1010 0xff,
1011 0xff,
1012 0xff,
1013 0x00,
1014 0xff,
1015 0xcc,
1016 0xff,
1017 0x00,
1018 0xff,
1019 0x99,
1020 0xff,
1021 0x00,
1022 0xff,
1023 0x66,
1024 0xff,
1025 0x00,
1026 0xff,
1027 0x33,
1028 0xff,
1029 0x00,
1030 0xff,
1031 0x00,
1032 0xff,
1033 0x00,
1034 0xcc,
1035 0xff,
1036 0xff,
1037 0x00,
1038 0xcc,
1039 0xcc,
1040 0xff,
1041 0x00,
1042 0xcc,
1043 0x99,
1044 0xff,
1045 0x00,
1046 0xcc,
1047 0x66,
1048 0xff,
1049 0x00,
1050 0xcc,
1051 0x33,
1052 0xff,
1053 0x00,
1054 0xcc,
1055 0x00,
1056 0xff,
1057 0x00,
1058 0x99,
1059 0xff,
1060 0xff,
1061 0x00,
1062 0x99,
1063 0xcc,
1064 0xff,
1065 0x00,
1066 0x99,
1067 0x99,
1068 0xff,
1069 0x00,
1070 0x99,
1071 0x66,
1072 0xff,
1073 0x00,
1074 0x99,
1075 0x33,
1076 0xff,
1077 0x00,
1078 0x99,
1079 0x00,
1080 0xff,
1081 0x00,
1082 0x66,
1083 0xff,
1084 0xff,
1085 0x00,
1086 0x66,
1087 0xcc,
1088 0xff,
1089 0x00,
1090 0x66,
1091 0x99,
1092 0xff,
1093 0x00,
1094 0x66,
1095 0x66,
1096 0xff,
1097 0x00,
1098 0x66,
1099 0x33,
1100 0xff,
1101 0x00,
1102 0x66,
1103 0x00,
1104 0xff,
1105 0x00,
1106 0x33,
1107 0xff,
1108 0xff,
1109 0x00,
1110 0x33,
1111 0xcc,
1112 0xff,
1113 0x00,
1114 0x33,
1115 0x99,
1116 0xff,
1117 0x00,
1118 0x33,
1119 0x66,
1120 0xff,
1121 0x00,
1122 0x33,
1123 0x33,
1124 0xff,
1125 0x00,
1126 0x33,
1127 0x00,
1128 0xff,
1129 0x00,
1130 0x00,
1131 0xff,
1132 0xff,
1133 0x00,
1134 0x00,
1135 0xcc,
1136 0xff,
1137 0x00,
1138 0x00,
1139 0x99,
1140 0xff,
1141 0x00,
1142 0x00,
1143 0x66,
1144 0xff,
1145 0x00,
1146 0x00,
1147 0x33,
1148 0xff,
1149 0xee,
1150 0x00,
1151 0x00,
1152 0xff,
1153 0xdd,
1154 0x00,
1155 0x00,
1156 0xff,
1157 0xbb,
1158 0x00,
1159 0x00,
1160 0xff,
1161 0xaa,
1162 0x00,
1163 0x00,
1164 0xff,
1165 0x88,
1166 0x00,
1167 0x00,
1168 0xff,
1169 0x77,
1170 0x00,
1171 0x00,
1172 0xff,
1173 0x55,
1174 0x00,
1175 0x00,
1176 0xff,
1177 0x44,
1178 0x00,
1179 0x00,
1180 0xff,
1181 0x22,
1182 0x00,
1183 0x00,
1184 0xff,
1185 0x11,
1186 0x00,
1187 0x00,
1188 0xff,
1189 0x00,
1190 0xee,
1191 0x00,
1192 0xff,
1193 0x00,
1194 0xdd,
1195 0x00,
1196 0xff,
1197 0x00,
1198 0xbb,
1199 0x00,
1200 0xff,
1201 0x00,
1202 0xaa,
1203 0x00,
1204 0xff,
1205 0x00,
1206 0x88,
1207 0x00,
1208 0xff,
1209 0x00,
1210 0x77,
1211 0x00,
1212 0xff,
1213 0x00,
1214 0x55,
1215 0x00,
1216 0xff,
1217 0x00,
1218 0x44,
1219 0x00,
1220 0xff,
1221 0x00,
1222 0x22,
1223 0x00,
1224 0xff,
1225 0x00,
1226 0x11,
1227 0x00,
1228 0xff,
1229 0x00,
1230 0x00,
1231 0xee,
1232 0xff,
1233 0x00,
1234 0x00,
1235 0xdd,
1236 0xff,
1237 0x00,
1238 0x00,
1239 0xbb,
1240 0xff,
1241 0x00,
1242 0x00,
1243 0xaa,
1244 0xff,
1245 0x00,
1246 0x00,
1247 0x88,
1248 0xff,
1249 0x00,
1250 0x00,
1251 0x77,
1252 0xff,
1253 0x00,
1254 0x00,
1255 0x55,
1256 0xff,
1257 0x00,
1258 0x00,
1259 0x44,
1260 0xff,
1261 0x00,
1262 0x00,
1263 0x22,
1264 0xff,
1265 0x00,
1266 0x00,
1267 0x11,
1268 0xff,
1269 0xee,
1270 0xee,
1271 0xee,
1272 0xff,
1273 0xdd,
1274 0xdd,
1275 0xdd,
1276 0xff,
1277 0xbb,
1278 0xbb,
1279 0xbb,
1280 0xff,
1281 0xaa,
1282 0xaa,
1283 0xaa,
1284 0xff,
1285 0x88,
1286 0x88,
1287 0x88,
1288 0xff,
1289 0x77,
1290 0x77,
1291 0x77,
1292 0xff,
1293 0x55,
1294 0x55,
1295 0x55,
1296 0xff,
1297 0x44,
1298 0x44,
1299 0x44,
1300 0xff,
1301 0x22,
1302 0x22,
1303 0x22,
1304 0xff,
1305 0x11,
1306 0x11,
1307 0x11,
1308 0xff,
1309 0x00,
1310 0x00,
1311 0x00,
1312 0xff,
1313};
1314
1315// internal math/helper utilities
1316static inline uint32_t _vox_max(uint32_t a, uint32_t b)
1317{
1318 return (a > b) ? a : b;
1319}
1320static inline uint32_t _vox_min(uint32_t a, uint32_t b)
1321{
1322 return (a < b) ? a : b;
1323}
1324
1325// string utilities
1326# ifdef _MSC_VER
1327# define _vox_str_scanf(str, ...) sscanf_s(str, __VA_ARGS__)
1328# define _vox_strcpy_static(dst, src) strcpy_s(dst, src)
1329# define _vox_strcasecmp(a, b) _stricmp(a, b)
1330# define _vox_strcmp(a, b) strcmp(a, b)
1331# define _vox_strlen(a) strlen(a)
1332# define _vox_sprintf(str, str_max, fmt, ...) sprintf_s(str, str_max, fmt, __VA_ARGS__)
1333# else
1334# define _vox_str_scanf(str, ...) sscanf(str, __VA_ARGS__)
1335# define _vox_strcpy_static(dst, src) strcpy(dst, src)
1336# define _vox_strcasecmp(a, b) strcasecmp(a, b)
1337# define _vox_strcmp(a, b) strcmp(a, b)
1338# define _vox_strlen(a) strlen(a)
1339# define _vox_sprintf(str, str_max, fmt, ...) snprintf(str, str_max, fmt, __VA_ARGS__)
1340# endif
1341
1342// 3d vector utilities
1343struct vec3
1344{
1345 float x, y, z;
1346};
1347static inline vec3 vec3_make(float x, float y, float z)
1348{
1349 vec3 v;
1350 v.x = x;
1351 v.y = y;
1352 v.z = z;
1353 return v;
1354}
1355static inline vec3 vec3_negate(const vec3& v)
1356{
1357 vec3 r;
1358 r.x = -v.x;
1359 r.y = -v.y;
1360 r.z = -v.z;
1361 return r;
1362}
1363
1364// API for emulating file transactions on an in-memory buffer of data.
1365struct _vox_file
1366{
1367 const uint8_t* buffer; // source buffer data
1368 const uint32_t buffer_size; // size of the data in the buffer
1369 uint32_t offset; // current offset in the buffer data.
1370};
1371
1372static bool _vox_file_read(_vox_file* pFp, void* pData, uint32_t data_size)
1373{
1374 size_t data_to_read = _vox_min(pFp->buffer_size - pFp->offset, data_size);
1375 memcpy(pData, &pFp->buffer[pFp->offset], data_to_read);
1376 pFp->offset += data_size;
1377 return data_to_read == data_size;
1378}
1379
1380static void _vox_file_seek_forwards(_vox_file* pFp, uint32_t offset)
1381{
1382 pFp->offset += offset;
1383}
1384
1385static bool _vox_file_eof(const _vox_file* pFp)
1386{
1387 return pFp->offset >= pFp->buffer_size;
1388}
1389
1390static const void* _vox_file_data_pointer(const _vox_file* pFp)
1391{
1392 return &pFp->buffer[pFp->offset];
1393}
1394
1395// hash utilities
1396static uint32_t _vox_hash(const uint8_t* pData, uint32_t data_size)
1397{
1398 uint32_t hash = 0;
1399 for (uint32_t i = 0; i < data_size; i++)
1400 hash = pData[i] + (hash * 65559);
1401 return hash;
1402}
1403
1404// memory allocation utils.
1405static void* _ogt_priv_alloc_default(size_t uiSize)
1406{
1407 return malloc(uiSize);
1408}
1409static void _ogt_priv_free_default(void* pPtr)
1410{
1411 free(pPtr);
1412}
1413static ogt_vox_alloc_func g_alloc_func = _ogt_priv_alloc_default; // default function for allocating
1414static ogt_vox_free_func g_free_func = _ogt_priv_free_default; // default function for freeing.
1415
1416// set the provided allocate/free functions if they are non-null, otherwise reset to default allocate/free functions
1417void ogt_vox_set_memory_allocator(ogt_vox_alloc_func alloc_func, ogt_vox_free_func free_func)
1418{
1419 assert((alloc_func && free_func) || // both alloc/free must be non-NULL -OR-
1420 (!alloc_func && !free_func)); // both alloc/free must be NULL. No mixing 'n matching.
1421 if (alloc_func && free_func)
1422 {
1423 g_alloc_func = alloc_func;
1424 g_free_func = free_func;
1425 }
1426 else
1427 {
1428 // reset to default allocate/free functions.
1429 g_alloc_func = _ogt_priv_alloc_default;
1430 g_free_func = _ogt_priv_free_default;
1431 }
1432}
1433
1434static void* _vox_malloc(size_t uiSize)
1435{
1436 return uiSize ? g_alloc_func(uiSize) : NULL;
1437}
1438
1439static void* _vox_calloc(size_t uiSize)
1440{
1441 void* pMem = _vox_malloc(uiSize);
1442 if (pMem)
1443 memset(pMem, 0, uiSize);
1444 return pMem;
1445}
1446
1447static void _vox_free(void* pOld_ptr)
1448{
1449 if (pOld_ptr)
1450 g_free_func(pOld_ptr);
1451}
1452
1453static void* _vox_realloc(void* pOld_ptr, size_t uiOld_size, size_t uiNew_size)
1454{
1455 // early out if new size is non-zero and no resize is required.
1456 if (uiNew_size && uiOld_size >= uiNew_size)
1457 return pOld_ptr;
1458
1459 // memcpy from the old ptr only if both sides are valid.
1460 void* new_ptr = _vox_malloc(uiNew_size);
1461 if (new_ptr)
1462 {
1463 // copy any existing elements over
1464 if (pOld_ptr && uiOld_size)
1465 memcpy(new_ptr, pOld_ptr, uiOld_size);
1466 // zero out any new tail elements
1467 assert(uiNew_size > uiOld_size); // this should be guaranteed by the _vox_realloc early out case above.
1468 uintptr_t new_tail_ptr = (uintptr_t)new_ptr + uiOld_size;
1469 memset((void*)new_tail_ptr, 0, uiNew_size - uiOld_size);
1470 }
1471 if (pOld_ptr)
1472 _vox_free(pOld_ptr);
1473 return new_ptr;
1474}
1475
1476// std::vector-style allocator, which use client-provided allocation functions.
1477template <class T>
1478struct _vox_array
1479{
1480 _vox_array()
1481 : data(NULL)
1482 , capacity(0)
1483 , count(0)
1484 {
1485 }
1486 ~_vox_array()
1487 {
1488 _vox_free(data);
1489 data = NULL;
1490 count = 0;
1491 capacity = 0;
1492 }
1493 void reserve(size_t uiNew_capacity)
1494 {
1495 data = (T*)_vox_realloc(data, capacity * sizeof(T), uiNew_capacity * sizeof(T));
1496 capacity = uiNew_capacity;
1497 }
1498 void grow_to_fit_index(size_t uiIndex)
1499 {
1500 if (uiIndex >= count)
1501 resize(uiIndex + 1);
1502 }
1503 void resize(size_t uiNew_count)
1504 {
1505 if (uiNew_count > capacity)
1506 reserve(uiNew_count);
1507 count = uiNew_count;
1508 }
1509 void push_back(const T& new_element)
1510 {
1511 if (count == capacity)
1512 {
1513 size_t new_capacity = capacity ? (capacity * 3) >> 1 : 2; // grow by 50% each time, otherwise start at 2 elements.
1514 reserve(new_capacity);
1515 assert(capacity > count);
1516 }
1517 data[count++] = new_element;
1518 }
1519 void push_back_many(const T* pNew_elements, size_t uiNum_elements)
1520 {
1521 if (count + uiNum_elements > capacity)
1522 {
1523 size_t new_capacity = capacity + uiNum_elements;
1524 new_capacity = new_capacity ? (new_capacity * 3) >> 1 : 2; // grow by 50% each time, otherwise start at 2 elements.
1525 reserve(new_capacity);
1526 assert(capacity >= (count + uiNum_elements));
1527 }
1528 for (size_t i = 0; i < uiNum_elements; i++)
1529 data[count + i] = pNew_elements[i];
1530 count += uiNum_elements;
1531 }
1532 size_t size() const
1533 {
1534 return count;
1535 }
1536 T& operator[](size_t uiIndex)
1537 {
1538 assert(uiIndex < count);
1539 return data[uiIndex];
1540 }
1541 const T& operator[](size_t uiIndex) const
1542 {
1543 assert(uiIndex < count);
1544 return data[uiIndex];
1545 }
1546 T* data; // data for the array
1547 size_t capacity; // capacity of the array
1548 size_t count; // size of the array
1549};
1550
1551// matrix utilities
1552static ogt_vox_transform _vox_transform_identity()
1553{
1555 t.m00 = 1.0f;
1556 t.m01 = 0.0f;
1557 t.m02 = 0.0f;
1558 t.m03 = 0.0f;
1559 t.m10 = 0.0f;
1560 t.m11 = 1.0f;
1561 t.m12 = 0.0f;
1562 t.m13 = 0.0f;
1563 t.m20 = 0.0f;
1564 t.m21 = 0.0f;
1565 t.m22 = 1.0f;
1566 t.m23 = 0.0f;
1567 t.m30 = 0.0f;
1568 t.m31 = 0.0f;
1569 t.m32 = 0.0f;
1570 t.m33 = 1.0f;
1571 return t;
1572}
1573
1574static ogt_vox_transform _vox_transform_multiply(const ogt_vox_transform& a, const ogt_vox_transform& b)
1575{
1577 r.m00 = (a.m00 * b.m00) + (a.m01 * b.m10) + (a.m02 * b.m20) + (a.m03 * b.m30);
1578 r.m01 = (a.m00 * b.m01) + (a.m01 * b.m11) + (a.m02 * b.m21) + (a.m03 * b.m31);
1579 r.m02 = (a.m00 * b.m02) + (a.m01 * b.m12) + (a.m02 * b.m22) + (a.m03 * b.m32);
1580 r.m03 = (a.m00 * b.m03) + (a.m01 * b.m13) + (a.m02 * b.m23) + (a.m03 * b.m33);
1581 r.m10 = (a.m10 * b.m00) + (a.m11 * b.m10) + (a.m12 * b.m20) + (a.m13 * b.m30);
1582 r.m11 = (a.m10 * b.m01) + (a.m11 * b.m11) + (a.m12 * b.m21) + (a.m13 * b.m31);
1583 r.m12 = (a.m10 * b.m02) + (a.m11 * b.m12) + (a.m12 * b.m22) + (a.m13 * b.m32);
1584 r.m13 = (a.m10 * b.m03) + (a.m11 * b.m13) + (a.m12 * b.m23) + (a.m13 * b.m33);
1585 r.m20 = (a.m20 * b.m00) + (a.m21 * b.m10) + (a.m22 * b.m20) + (a.m23 * b.m30);
1586 r.m21 = (a.m20 * b.m01) + (a.m21 * b.m11) + (a.m22 * b.m21) + (a.m23 * b.m31);
1587 r.m22 = (a.m20 * b.m02) + (a.m21 * b.m12) + (a.m22 * b.m22) + (a.m23 * b.m32);
1588 r.m23 = (a.m20 * b.m03) + (a.m21 * b.m13) + (a.m22 * b.m23) + (a.m23 * b.m33);
1589 r.m30 = (a.m30 * b.m00) + (a.m31 * b.m10) + (a.m32 * b.m20) + (a.m33 * b.m30);
1590 r.m31 = (a.m30 * b.m01) + (a.m31 * b.m11) + (a.m32 * b.m21) + (a.m33 * b.m31);
1591 r.m32 = (a.m30 * b.m02) + (a.m31 * b.m12) + (a.m32 * b.m22) + (a.m33 * b.m32);
1592 r.m33 = (a.m30 * b.m03) + (a.m31 * b.m13) + (a.m32 * b.m23) + (a.m33 * b.m33);
1593 return r;
1594}
1595
1596// dictionary utilities
1597static const uint32_t k_vox_max_dict_buffer_size = 4096;
1598static const uint32_t k_vox_max_dict_key_value_pairs = 256;
1599struct _vox_dictionary
1600{
1601 const char* keys[k_vox_max_dict_key_value_pairs];
1602 const char* values[k_vox_max_dict_key_value_pairs];
1603 uint32_t num_key_value_pairs;
1604 char buffer[k_vox_max_dict_buffer_size + 4]; // max 4096, +4 for safety
1605 uint32_t buffer_mem_used;
1606};
1607
1608static bool _vox_file_read_dict(_vox_dictionary* pDict, _vox_file* pFp)
1609{
1610 uint32_t num_pairs_to_read = 0;
1611 _vox_file_read(pFp, &num_pairs_to_read, sizeof(uint32_t));
1612 assert(num_pairs_to_read <= k_vox_max_dict_key_value_pairs);
1613
1614 pDict->buffer_mem_used = 0;
1615 pDict->num_key_value_pairs = 0;
1616 for (uint32_t i = 0; i < num_pairs_to_read; i++)
1617 {
1618 // get the size of the key string
1619 uint32_t key_string_size = 0;
1620 _vox_file_read(pFp, &key_string_size, sizeof(uint32_t));
1621 // allocate space for the key, and read it in.
1622 if (pDict->buffer_mem_used + key_string_size > k_vox_max_dict_buffer_size)
1623 return false;
1624 char* key = &pDict->buffer[pDict->buffer_mem_used];
1625 pDict->buffer_mem_used += key_string_size + 1; // + 1 for zero terminator
1626 _vox_file_read(pFp, key, key_string_size);
1627 key[key_string_size] = 0; // zero-terminate
1628 assert(_vox_strlen(key) == key_string_size); // sanity check
1629
1630 // get the size of the value string
1631 uint32_t value_string_size = 0;
1632 _vox_file_read(pFp, &value_string_size, sizeof(uint32_t));
1633 // allocate space for the value, and read it in.
1634 if (pDict->buffer_mem_used + value_string_size > k_vox_max_dict_buffer_size)
1635 return (false);
1636 char* value = &pDict->buffer[pDict->buffer_mem_used];
1637 pDict->buffer_mem_used += value_string_size + 1; // + 1 for zero terminator
1638 _vox_file_read(pFp, value, value_string_size);
1639 value[value_string_size] = 0; // zero-terminate
1640 assert(_vox_strlen(value) == value_string_size); // sanity check
1641 // now assign it in the dictionary
1642 pDict->keys[pDict->num_key_value_pairs] = key;
1643 pDict->values[pDict->num_key_value_pairs] = value;
1644 pDict->num_key_value_pairs++;
1645 }
1646
1647 return true;
1648}
1649
1650// helper for looking up in the dictionary
1651static const char* _vox_dict_get_value_as_string(const _vox_dictionary* pDict, const char* szKey_to_find, const char* szDefault_value = NULL)
1652{
1653 for (uint32_t i = 0; i < pDict->num_key_value_pairs; i++)
1654 if (_vox_strcasecmp(pDict->keys[i], szKey_to_find) == 0)
1655 return pDict->values[i];
1656 return szDefault_value;
1657}
1658
1659// lookup table for _vox_make_transform_from_dict_strings
1660static const vec3 k_vectors[4] = {
1661 vec3_make(1.0f, 0.0f, 0.0f),
1662 vec3_make(0.0f, 1.0f, 0.0f),
1663 vec3_make(0.0f, 0.0f, 1.0f),
1664 vec3_make(0.0f, 0.0f, 0.0f) // invalid!
1665};
1666
1667// lookup table for _vox_make_transform_from_dict_strings
1668static const uint32_t k_row2_index[] = {UINT32_MAX, UINT32_MAX, UINT32_MAX, 2, UINT32_MAX, 1, 0, UINT32_MAX};
1669
1670
1671static ogt_vox_transform _vox_make_transform_from_dict_strings(const char* szRotation_string, const char* szTranslation_string)
1672{
1673 ogt_vox_transform transform = _vox_transform_identity();
1674
1675 if (szRotation_string != NULL)
1676 {
1677 // compute the per-row indexes into k_vectors[] array.
1678 // unpack rotation bits.
1679 // bits : meaning
1680 // 0 - 1 : index of the non-zero entry in the first row
1681 // 2 - 3 : index of the non-zero entry in the second row
1682 uint32_t packed_rotation_bits = atoi(szRotation_string);
1683 uint32_t row0_vec_index = (packed_rotation_bits >> 0) & 3;
1684 uint32_t row1_vec_index = (packed_rotation_bits >> 2) & 3;
1685 uint32_t row2_vec_index = k_row2_index[(1 << row0_vec_index) | (1 << row1_vec_index)]; // process of elimination to determine row 2 index based on row0/row1 being one of {0,1,2} choose 2.
1686 assert(row2_vec_index != UINT32_MAX); // if you hit this, you probably have invalid indices for row0_vec_index/row1_vec_index.
1687
1688 // unpack rotation bits for vector signs
1689 // bits : meaning
1690 // 4 : the sign in the first row (0 : positive; 1 : negative)
1691 // 5 : the sign in the second row (0 : positive; 1 : negative)
1692 // 6 : the sign in the third row (0 : positive; 1 : negative)
1693 vec3 row0 = k_vectors[row0_vec_index];
1694 vec3 row1 = k_vectors[row1_vec_index];
1695 vec3 row2 = k_vectors[row2_vec_index];
1696 if (packed_rotation_bits & (1 << 4))
1697 row0 = vec3_negate(row0);
1698 if (packed_rotation_bits & (1 << 5))
1699 row1 = vec3_negate(row1);
1700 if (packed_rotation_bits & (1 << 6))
1701 row2 = vec3_negate(row2);
1702
1703 // magicavoxel stores rows, we need columns, so we do the swizzle here into columns
1704 transform.m00 = row0.x;
1705 transform.m01 = row1.x;
1706 transform.m02 = row2.x;
1707 transform.m10 = row0.y;
1708 transform.m11 = row1.y;
1709 transform.m12 = row2.y;
1710 transform.m20 = row0.z;
1711 transform.m21 = row1.z;
1712 transform.m22 = row2.z;
1713 }
1714
1715 if (szTranslation_string != NULL)
1716 {
1717 int32_t x = 0;
1718 int32_t y = 0;
1719 int32_t z = 0;
1720 _vox_str_scanf(szTranslation_string, "%i %i %i", &x, &y, &z);
1721 transform.m30 = (float)x;
1722 transform.m31 = (float)y;
1723 transform.m32 = (float)z;
1724 }
1725 return transform;
1726}
1727
1728enum _vox_scene_node_type
1729{
1730 k_nodetype_invalid = 0, // has not been parsed yet.
1731 k_nodetype_group = 1,
1732 k_nodetype_transform = 2,
1733 k_nodetype_shape = 3,
1734};
1735
1736struct _vox_scene_node_
1737{
1738 _vox_scene_node_type node_type; // only gets assigned when this has been parsed, otherwise will be k_nodetype_invalid
1739 union
1740 {
1741 // used only when node_type == k_nodetype_transform
1742 struct
1743 {
1744 char name[64]; // max name size is 64
1745 ogt_vox_transform transform;
1746 uint32_t child_node_id;
1747 uint32_t layer_id;
1748 bool hidden;
1749 } transform;
1750 // used only when node_type == k_nodetype_group
1751 struct
1752 {
1753 uint32_t first_child_node_id_index; // the index of the first child node ID within the ChildNodeID array
1754 uint32_t num_child_nodes; // number of child node IDs starting at the first index
1755 } group;
1756 // used only when node_type == k_nodetype_shape
1757 struct
1758 {
1759 uint32_t model_id; // will be UINT32_MAX if there is no model. Unlikely, there should always be a model.
1760 } shape;
1761 } u;
1762};
1763
1764static void generate_instances_for_node(
1765 const _vox_array<_vox_scene_node_>& nodes, uint32_t node_index, const _vox_array<uint32_t>& child_id_array, uint32_t layer_index,
1766 const ogt_vox_transform& transform, const _vox_array<ogt_vox_model*>& model_ptrs, const char* szTransform_last_name, bool bTransform_last_hidden,
1767 _vox_array<ogt_vox_instance>& ref_instances, _vox_array<char>& ref_string_data, _vox_array<ogt_vox_group>& ref_groups, uint32_t group_index, bool bGenerate_groups)
1768{
1769 const _vox_scene_node_* node = &nodes[node_index];
1770 assert(node);
1771 switch (node->node_type)
1772 {
1773 case k_nodetype_transform:
1774 {
1775 ogt_vox_transform new_transform = (bGenerate_groups) ? node->u.transform.transform // don't multiply by the parent transform. caller wants the group-relative transform
1776 : _vox_transform_multiply(node->u.transform.transform, transform); // flatten the transform if we're not generating groups: child transform * parent transform
1777 const char* new_transform_name = node->u.transform.name[0] ? node->u.transform.name : NULL;
1778 szTransform_last_name = new_transform_name ? new_transform_name : szTransform_last_name; // if this node has a name, use it instead of our parent name
1779 generate_instances_for_node(nodes, node->u.transform.child_node_id, child_id_array, node->u.transform.layer_id, new_transform, model_ptrs, szTransform_last_name, node->u.transform.hidden, ref_instances, ref_string_data, ref_groups, group_index, bGenerate_groups);
1780 break;
1781 }
1782 case k_nodetype_group:
1783 {
1784 // create a new group only if we're generating groups.
1785 uint32_t next_group_index = 0;
1786 if (bGenerate_groups)
1787 {
1788 next_group_index = (uint32_t)ref_groups.size();
1789 ogt_vox_group group;
1790 group.parent_group_index = group_index;
1791 group.transform = transform;
1792 group.hidden = bTransform_last_hidden;
1793 group.layer_index = layer_index;
1794 ref_groups.push_back(group);
1795 }
1796 // child nodes will only be hidden if their immediate transform is hidden.
1797 bTransform_last_hidden = false;
1798
1799 const uint32_t* child_node_ids = (const uint32_t*)&child_id_array[node->u.group.first_child_node_id_index];
1800 for (uint32_t i = 0; i < node->u.group.num_child_nodes; i++)
1801 {
1802 generate_instances_for_node(nodes, child_node_ids[i], child_id_array, layer_index, transform, model_ptrs, szTransform_last_name, bTransform_last_hidden, ref_instances, ref_string_data, ref_groups, next_group_index, bGenerate_groups);
1803 }
1804 break;
1805 }
1806 case k_nodetype_shape:
1807 {
1808 assert(node->u.shape.model_id < model_ptrs.size());
1809 if (node->u.shape.model_id < model_ptrs.size() && // model ID is valid
1810 model_ptrs[node->u.shape.model_id] != NULL) // model is non-NULL.
1811 {
1812 assert(bGenerate_groups || group_index == 0); // if we're not generating groups, group_index should be zero to map to the root group.
1813 ogt_vox_instance new_instance;
1814 new_instance.model_index = node->u.shape.model_id;
1815 new_instance.transform = transform;
1816 new_instance.layer_index = layer_index;
1817 new_instance.group_index = group_index;
1818 new_instance.hidden = bTransform_last_hidden;
1819 // if we got a transform name, allocate space in string_data for it and keep track of the index
1820 // within string data. This will be patched to a real pointer at the very end.
1821 new_instance.name = 0;
1822 if (szTransform_last_name && szTransform_last_name[0])
1823 {
1824 new_instance.name = (const char*)(ref_string_data.size());
1825 size_t name_size = _vox_strlen(szTransform_last_name) + 1; // +1 for terminator
1826 ref_string_data.push_back_many(szTransform_last_name, name_size);
1827 }
1828 // create the instance
1829 ref_instances.push_back(new_instance);
1830 }
1831 break;
1832 }
1833 default:
1834 {
1835 assert(0); // unhandled node type!
1836 }
1837 }
1838}
1839
1840// ensure instances are ordered in order of increasing model_index
1841static int _vox_ordered_compare_instance(const void* p_lhs, const void* p_rhs)
1842{
1843 const ogt_vox_instance* lhs = (const ogt_vox_instance*)p_lhs;
1844 const ogt_vox_instance* rhs = (const ogt_vox_instance*)p_rhs;
1845 return lhs->model_index < rhs->model_index ? -1 : lhs->model_index > rhs->model_index ? 1
1846 : 0;
1847}
1848
1849// returns true if the 2 models are content-wise identical.
1850static bool _vox_models_are_equal(const ogt_vox_model* lhs, const ogt_vox_model* rhs)
1851{
1852 // early out: if hashes don't match, they can't be equal
1853 // if hashes match, they might be equal OR there might be a hash collision.
1854 if (lhs->voxel_hash != rhs->voxel_hash)
1855 return false;
1856 // early out: if number of voxels in the model's grid don't match, they can't be equal.
1857 uint32_t num_voxels_lhs = lhs->size_x * lhs->size_y * lhs->size_z;
1858 uint32_t num_voxels_rhs = rhs->size_x * rhs->size_y * rhs->size_z;
1859 if (num_voxels_lhs != num_voxels_rhs)
1860 return false;
1861 // Finally, we know their hashes are the same, and their dimensions are the same
1862 // but they are only equal if they have exactly the same voxel data.
1863 return memcmp(lhs->voxel_data, rhs->voxel_data, num_voxels_lhs) == 0 ? true : false;
1864}
1865
1866const ogt_vox_scene* ogt_vox_read_scene_with_flags(const uint8_t* pBuffer, uint32_t buffer_size, uint32_t read_flags)
1867{
1868 _vox_file file = {pBuffer, buffer_size, 0};
1869 _vox_file* fp = &file;
1870
1871 // parsing state/context
1872 _vox_array<ogt_vox_model*> model_ptrs;
1873 _vox_array<_vox_scene_node_> nodes;
1874 _vox_array<ogt_vox_instance> instances;
1875 _vox_array<char> string_data;
1876 _vox_array<ogt_vox_layer> layers;
1877 _vox_array<ogt_vox_group> groups;
1878 _vox_array<uint32_t> child_ids;
1879 ogt_vox_palette palette;
1880 _vox_dictionary dict;
1881 uint32_t size_x = 0;
1882 uint32_t size_y = 0;
1883 uint32_t size_z = 0;
1884 uint8_t index_map[256];
1885 bool found_index_map_chunk = false;
1886
1887 // size some of our arrays to prevent resizing during the parsing for smallish cases.
1888 model_ptrs.reserve(64);
1889 instances.reserve(256);
1890 child_ids.reserve(256);
1891 nodes.reserve(16);
1892 layers.reserve(8);
1893 groups.reserve(0);
1894 string_data.reserve(256);
1895
1896 // push a sentinel character into these datastructures. This allows us to keep indexes
1897 // rather than pointers into data-structures that grow, and still allow an index of 0
1898 // to means invalid
1899 string_data.push_back('X');
1900 child_ids.push_back(-1);
1901
1902 // copy the default palette into the scene. It may get overwritten by a palette chunk later
1903 memcpy(&palette, k_default_vox_palette, sizeof(ogt_vox_palette));
1904
1905 // load and validate fileheader and file version.
1906 uint32_t file_header;
1907 uint32_t file_version;
1908 _vox_file_read(fp, &file_header, sizeof(uint32_t));
1909 _vox_file_read(fp, &file_version, sizeof(uint32_t));
1910 if (file_header != CHUNK_ID_VOX_ || file_version != 150)
1911 return NULL;
1912
1913 // parse chunks until we reach the end of the file/buffer
1914 while (!_vox_file_eof(fp))
1915 {
1916 // read the fields common to all chunks
1917 uint32_t chunk_id = 0;
1918 uint32_t chunk_size = 0;
1919 uint32_t chunk_child_size = 0;
1920 _vox_file_read(fp, &chunk_id, sizeof(uint32_t));
1921 _vox_file_read(fp, &chunk_size, sizeof(uint32_t));
1922 _vox_file_read(fp, &chunk_child_size, sizeof(uint32_t));
1923
1924 // process the chunk.
1925 switch (chunk_id)
1926 {
1927 case CHUNK_ID_MAIN:
1928 {
1929 assert(chunk_size == 0);
1930 break;
1931 }
1932 case CHUNK_ID_SIZE:
1933 {
1934 assert(chunk_size == 12 && chunk_child_size == 0);
1935 _vox_file_read(fp, &size_x, sizeof(uint32_t));
1936 _vox_file_read(fp, &size_y, sizeof(uint32_t));
1937 _vox_file_read(fp, &size_z, sizeof(uint32_t));
1938 break;
1939 }
1940 case CHUNK_ID_XYZI:
1941 {
1942 assert(chunk_child_size == 0 && size_x && size_y && size_z); // must have read a SIZE chunk prior to XYZI.
1943 // read the number of voxels to process for this moodel
1944 uint32_t num_voxels_in_chunk = 0;
1945 _vox_file_read(fp, &num_voxels_in_chunk, sizeof(uint32_t));
1946 if (num_voxels_in_chunk != 0)
1947 {
1948 uint32_t voxel_count = size_x * size_y * size_z;
1949 ogt_vox_model* model = (ogt_vox_model*)_vox_calloc(sizeof(ogt_vox_model) + voxel_count); // 1 byte for each voxel
1950 if (!model)
1951 return NULL;
1952 uint8_t* voxel_data = (uint8_t*)&model[1];
1953
1954 // insert the model into the model array
1955 model_ptrs.push_back(model);
1956
1957 // now setup the model
1958 model->size_x = size_x;
1959 model->size_y = size_y;
1960 model->size_z = size_z;
1961 model->voxel_data = voxel_data;
1962
1963 // setup some strides for computing voxel index based on x/y/z
1964 const uint32_t k_stride_x = 1;
1965 const uint32_t k_stride_y = size_x;
1966 const uint32_t k_stride_z = size_x * size_y;
1967
1968 // read this many voxels and store it in voxel data.
1969 const uint8_t* packed_voxel_data = (const uint8_t*)_vox_file_data_pointer(fp);
1970 for (uint32_t i = 0; i < num_voxels_in_chunk; i++)
1971 {
1972 uint8_t x = packed_voxel_data[i * 4 + 0];
1973 uint8_t y = packed_voxel_data[i * 4 + 1];
1974 uint8_t z = packed_voxel_data[i * 4 + 2];
1975 uint8_t color_index = packed_voxel_data[i * 4 + 3];
1976 assert(x < size_x && y < size_y && z < size_z);
1977 voxel_data[(x * k_stride_x) + (y * k_stride_y) + (z * k_stride_z)] = color_index;
1978 }
1979 _vox_file_seek_forwards(fp, num_voxels_in_chunk * 4);
1980 // compute the hash of the voxels in this model-- used to accelerate duplicate models checking.
1981 model->voxel_hash = _vox_hash(voxel_data, size_x * size_y * size_z);
1982 }
1983 else
1984 {
1985 model_ptrs.push_back(NULL);
1986 }
1987 break;
1988 }
1989 case CHUNK_ID_RGBA:
1990 {
1991 assert(chunk_size == sizeof(palette));
1992 _vox_file_read(fp, &palette, sizeof(palette));
1993 break;
1994 }
1995 case CHUNK_ID_nTRN:
1996 {
1997 uint32_t node_id;
1998 _vox_file_read(fp, &node_id, sizeof(node_id));
1999
2000 // Parse the node dictionary, which can contain:
2001 // _name: string
2002 // _hidden: 0/1
2003 char node_name[64];
2004 bool hidden = false;
2005 node_name[0] = 0;
2006 {
2007 _vox_file_read_dict(&dict, fp);
2008 const char* name_string = _vox_dict_get_value_as_string(&dict, "_name");
2009 if (name_string)
2010 _vox_strcpy_static(node_name, name_string);
2011 // if we got a hidden attribute - assign it now.
2012 const char* hidden_string = _vox_dict_get_value_as_string(&dict, "_hidden", "0");
2013 if (hidden_string)
2014 hidden = (hidden_string[0] == '1' ? true : false);
2015 }
2016
2017
2018 // get other properties.
2019 uint32_t child_node_id, reserved_id, layer_id, num_frames;
2020 _vox_file_read(fp, &child_node_id, sizeof(child_node_id));
2021 _vox_file_read(fp, &reserved_id, sizeof(reserved_id));
2022 _vox_file_read(fp, &layer_id, sizeof(layer_id));
2023 _vox_file_read(fp, &num_frames, sizeof(num_frames));
2024 assert(reserved_id == UINT32_MAX && num_frames == 1); // must be these values according to the spec
2025
2026 // Parse the frame dictionary that contains:
2027 // _r : int8 ROTATION (c)
2028 // _t : int32x3 translation
2029 // and extract a transform
2030 ogt_vox_transform frame_transform;
2031 {
2032 _vox_file_read_dict(&dict, fp);
2033 const char* rotation_value = _vox_dict_get_value_as_string(&dict, "_r");
2034 const char* translation_value = _vox_dict_get_value_as_string(&dict, "_t");
2035 frame_transform = _vox_make_transform_from_dict_strings(rotation_value, translation_value);
2036 }
2037 // setup the transform node.
2038 {
2039 nodes.grow_to_fit_index(node_id);
2040 _vox_scene_node_* transform_node = &nodes[node_id];
2041 assert(transform_node);
2042 transform_node->node_type = k_nodetype_transform;
2043 transform_node->u.transform.child_node_id = child_node_id;
2044 transform_node->u.transform.layer_id = layer_id;
2045 transform_node->u.transform.transform = frame_transform;
2046 transform_node->u.transform.hidden = hidden;
2047 // assign the name
2048 _vox_strcpy_static(transform_node->u.transform.name, node_name);
2049 }
2050 break;
2051 }
2052 case CHUNK_ID_nGRP:
2053 {
2054 uint32_t node_id;
2055 _vox_file_read(fp, &node_id, sizeof(node_id));
2056
2057 // parse the node dictionary - data is unused.
2058 _vox_file_read_dict(&dict, fp);
2059
2060 // setup the group node
2061 nodes.grow_to_fit_index(node_id);
2062 _vox_scene_node_* group_node = &nodes[node_id];
2063 group_node->node_type = k_nodetype_group;
2064 group_node->u.group.first_child_node_id_index = 0;
2065 group_node->u.group.num_child_nodes = 0;
2066
2067 // setup all child scene nodes to point back to this node.
2068 uint32_t num_child_nodes = 0;
2069 _vox_file_read(fp, &num_child_nodes, sizeof(num_child_nodes));
2070
2071 // allocate space for all the child node IDs
2072 if (num_child_nodes)
2073 {
2074 size_t prior_size = child_ids.size();
2075 assert(prior_size > 0); // should be guaranteed by the sentinel we reserved at the very beginning.
2076 child_ids.resize(prior_size + num_child_nodes);
2077 _vox_file_read(fp, &child_ids[prior_size], sizeof(uint32_t) * num_child_nodes);
2078 group_node->u.group.first_child_node_id_index = (uint32_t)prior_size;
2079 group_node->u.group.num_child_nodes = num_child_nodes;
2080 }
2081 break;
2082 }
2083 case CHUNK_ID_nSHP:
2084 {
2085 uint32_t node_id;
2086 _vox_file_read(fp, &node_id, sizeof(node_id));
2087
2088 // setup the shape node
2089 nodes.grow_to_fit_index(node_id);
2090 _vox_scene_node_* shape_node = &nodes[node_id];
2091 shape_node->node_type = k_nodetype_shape;
2092 shape_node->u.shape.model_id = UINT32_MAX;
2093
2094 // parse the node dictionary - data is unused.
2095 _vox_file_read_dict(&dict, fp);
2096
2097 uint32_t num_models = 0;
2098 _vox_file_read(fp, &num_models, sizeof(num_models));
2099 assert(num_models == 1); // must be 1 according to the spec.
2100
2101 // assign instances
2102 _vox_file_read(fp, &shape_node->u.shape.model_id, sizeof(uint32_t));
2103 assert(shape_node->u.shape.model_id < model_ptrs.size());
2104
2105 // parse the model dictionary - data is unsued.
2106 _vox_file_read_dict(&dict, fp);
2107 break;
2108 }
2109 case CHUNK_ID_IMAP:
2110 {
2111 assert(chunk_size == 256);
2112 _vox_file_read(fp, index_map, 256);
2113 found_index_map_chunk = true;
2114 break;
2115 }
2116 case CHUNK_ID_LAYR:
2117 {
2118 int32_t layer_id = 0;
2119 int32_t reserved_id = 0;
2120 _vox_file_read(fp, &layer_id, sizeof(layer_id));
2121 _vox_file_read_dict(&dict, fp);
2122 _vox_file_read(fp, &reserved_id, sizeof(reserved_id));
2123 assert(reserved_id == -1);
2124
2125 layers.grow_to_fit_index(layer_id);
2126 layers[layer_id].name = NULL;
2127 layers[layer_id].hidden = false;
2128
2129 // if we got a layer name from the LAYR dictionary, allocate space in string_data for it and keep track of the index
2130 // within string data. This will be patched to a real pointer at the very end.
2131 const char* name_string = _vox_dict_get_value_as_string(&dict, "_name", NULL);
2132 if (name_string)
2133 {
2134 layers[layer_id].name = (const char*)(string_data.size());
2135 size_t name_size = _vox_strlen(name_string) + 1; // +1 for terminator
2136 string_data.push_back_many(name_string, name_size);
2137 }
2138 // if we got a hidden attribute - assign it now.
2139 const char* hidden_string = _vox_dict_get_value_as_string(&dict, "_hidden", "0");
2140 if (hidden_string)
2141 layers[layer_id].hidden = (hidden_string[0] == '1' ? true : false);
2142 break;
2143 }
2144 // we don't handle MATL/MATT/rOBJ or any other chunks for now, so we just skip the chunk payload.
2145 case CHUNK_ID_MATL:
2146 case CHUNK_ID_MATT:
2147 case CHUNK_ID_rOBJ:
2148 default:
2149 {
2150 _vox_file_seek_forwards(fp, chunk_size);
2151 break;
2152 }
2153 } // end switch
2154 }
2155
2156 // ok, now that we've parsed all scene nodes - walk the scene hierarchy, and generate instances
2157 // we can't do this while parsing chunks unfortunately because some chunks reference chunks
2158 // that are later in the file than them.
2159 if (nodes.size())
2160 {
2161 bool generate_groups = read_flags & k_read_scene_flags_groups ? true : false;
2162 // if we're not reading scene-embedded groups, we generate only one and then flatten all instance transforms.
2163 if (!generate_groups)
2164 {
2165 ogt_vox_group root_group;
2166 root_group.transform = _vox_transform_identity();
2167 root_group.parent_group_index = k_invalid_group_index;
2168 root_group.layer_index = 0;
2169 root_group.hidden = false;
2170 groups.push_back(root_group);
2171 }
2172 generate_instances_for_node(nodes, 0, child_ids, 0, _vox_transform_identity(), model_ptrs, NULL, false, instances, string_data, groups, k_invalid_group_index, generate_groups);
2173 }
2174 else if (model_ptrs.size() == 1)
2175 {
2176 // add a single instance
2177 ogt_vox_instance new_instance;
2178 new_instance.model_index = 0;
2179 new_instance.group_index = 0;
2180 new_instance.transform = _vox_transform_identity();
2181 new_instance.layer_index = 0;
2182 new_instance.name = 0;
2183 new_instance.hidden = false;
2184 instances.push_back(new_instance);
2185 }
2186
2187 // if we didn't get a layer chunk -- just create a default layer.
2188 if (layers.size() == 0)
2189 {
2190 // go through all instances and ensure they are only mapped to layer 0
2191 for (uint32_t i = 0; i < instances.size(); i++)
2192 instances[i].layer_index = 0;
2193 // add a single layer
2194 ogt_vox_layer new_layer;
2195 new_layer.hidden = false;
2196 new_layer.name = NULL;
2197 layers.push_back(new_layer);
2198 }
2199
2200 // To support index-level assumptions (eg. artists using top 16 colors for color/palette cycling,
2201 // other ranges for emissive etc), we must ensure the order of colors that the artist sees in the
2202 // magicavoxel tool matches the actual index we'll end up using here. Unfortunately, magicavoxel
2203 // does an unexpected thing when remapping colors in the editor using ctrl+drag within the palette.
2204 // Instead of remapping all indices in all models, it just keeps track of a display index to actual
2205 // palette map and uses that to show reordered colors in the palette window. This is how that
2206 // map works:
2207 // displaycolor[k] = paletteColor[imap[k]]
2208 // To ensure our indices are in the same order as displayed by magicavoxel within the palette
2209 // window, we apply the mapping from the IMAP chunk both to the color palette and indices within each
2210 // voxel model.
2211 if (found_index_map_chunk)
2212 {
2213 // the imap chunk maps from display index to actual index.
2214 // generate an inverse index map (maps from actual index to display index)
2215 uint8_t index_map_inverse[256];
2216 for (uint32_t i = 0; i < 256; i++)
2217 {
2218 index_map_inverse[index_map[i]] = (uint8_t)i;
2219 }
2220
2221 // reorder colors in the palette so the palette contains colors in display order
2222 ogt_vox_palette old_palette = palette;
2223 for (uint32_t i = 0; i < 256; i++)
2224 {
2225 uint32_t remapped_index = (index_map[i] + 255) & 0xFF;
2226 palette.color[i] = old_palette.color[remapped_index];
2227 }
2228
2229 // ensure that all models are remapped so they are using display order palette indices.
2230 for (uint32_t i = 0; i < model_ptrs.size(); i++)
2231 {
2232 ogt_vox_model* model = model_ptrs[i];
2233 if (model)
2234 {
2235 uint32_t num_voxels = model->size_x * model->size_y * model->size_z;
2236 uint8_t* voxels = (uint8_t*)&model[1];
2237 for (uint32_t j = 0; j < num_voxels; j++)
2238 voxels[j] = 1 + index_map_inverse[voxels[j]];
2239 }
2240 }
2241 }
2242
2243 // rotate the scene palette now so voxel indices can just map straight into the palette
2244 {
2245 ogt_vox_rgba last_color = palette.color[255];
2246 for (uint32_t i = 255; i > 0; i--)
2247 palette.color[i] = palette.color[i - 1];
2248 palette.color[0] = last_color;
2249 palette.color[0].a = 0; // alpha is zero for the 0th color as that color index represents a transparent voxel.
2250 }
2251
2252 // check for models that are identical by doing a pair-wise compare. If we find identical
2253 // models, we'll end up with NULL gaps in the model_ptrs array, but instances will have
2254 // been remapped to keep the earlier model.
2255 for (uint32_t i = 0; i < model_ptrs.size(); i++)
2256 {
2257 if (!model_ptrs[i])
2258 continue;
2259 for (uint32_t j = i + 1; j < model_ptrs.size(); j++)
2260 {
2261 if (!model_ptrs[j] || !_vox_models_are_equal(model_ptrs[i], model_ptrs[j]))
2262 continue;
2263 // model i and model j are the same, so free model j and keep model i.
2264 _vox_free(model_ptrs[j]);
2265 model_ptrs[j] = NULL;
2266 // remap all instances that were referring to j to now refer to i.
2267 for (uint32_t k = 0; k < instances.size(); k++)
2268 if (instances[k].model_index == j)
2269 instances[k].model_index = i;
2270 }
2271 }
2272
2273 // sometimes a model can be created which has no solid voxels within just due to the
2274 // authoring flow within magicavoxel. We have already have prevented creation of
2275 // instances that refer to empty models, but here we want to compact the model_ptrs
2276 // array such that it contains no more NULL models. This also requires we remap the
2277 // indices for instances so they continue to refer to their correct models.
2278 {
2279 // first, check to see if we find any empty model. No need to do work otherwise.
2280 bool found_empty_model = false;
2281 for (uint32_t i = 0; i < model_ptrs.size() && !found_empty_model; i++)
2282 {
2283 if (model_ptrs[i] == NULL)
2284 found_empty_model = true;
2285 }
2286 if (found_empty_model)
2287 {
2288 // build a remap table for all instances and simultaneously compact the model_ptrs array.
2289 uint32_t* model_remap = (uint32_t*)_vox_malloc(model_ptrs.size() * sizeof(uint32_t));
2290 uint32_t num_output_models = 0;
2291 for (uint32_t i = 0; i < model_ptrs.size(); i++)
2292 {
2293 if (model_ptrs[i] != NULL)
2294 {
2295 model_ptrs[num_output_models] = model_ptrs[i];
2296 model_remap[i] = num_output_models;
2297 num_output_models++;
2298 }
2299 else
2300 {
2301 model_remap[i] = UINT32_MAX;
2302 }
2303 }
2304 model_ptrs.resize(num_output_models);
2305
2306 // remap all instances to point to the compacted model index
2307 for (uint32_t i = 0; i < instances.size(); i++)
2308 {
2309 uint32_t new_model_index = model_remap[instances[i].model_index];
2310 assert(new_model_index != UINT32_MAX); // we should have suppressed instances already that point to NULL models.
2311 instances[i].model_index = new_model_index;
2312 }
2313
2314 // free remap table
2315 _vox_free(model_remap);
2316 model_remap = NULL;
2317 }
2318 }
2319
2320 // finally, construct the output scene..
2321 size_t scene_size = sizeof(ogt_vox_scene) + string_data.size();
2322 ogt_vox_scene* scene = (ogt_vox_scene*)_vox_calloc(scene_size);
2323 {
2324 // copy name data into the scene
2325 char* scene_string_data = (char*)&scene[1];
2326 memcpy(scene_string_data, &string_data[0], sizeof(char) * string_data.size());
2327
2328 // copy instances over to scene, and sort them so that instances with the same model are contiguous.
2329 size_t num_scene_instances = instances.size();
2330 ogt_vox_instance* scene_instances = (ogt_vox_instance*)_vox_malloc(sizeof(ogt_vox_instance) * num_scene_instances);
2331 if (num_scene_instances)
2332 {
2333 memcpy(scene_instances, &instances[0], sizeof(ogt_vox_instance) * num_scene_instances);
2334 qsort(scene_instances, num_scene_instances, sizeof(ogt_vox_instance), _vox_ordered_compare_instance);
2335 }
2336 scene->instances = scene_instances;
2337 scene->num_instances = (uint32_t)instances.size();
2338
2339 // copy model pointers over to the scene,
2340 size_t num_scene_models = model_ptrs.size();
2341 ogt_vox_model** scene_models = (ogt_vox_model**)_vox_malloc(sizeof(ogt_vox_model*) * num_scene_models);
2342 if (num_scene_models)
2343 memcpy(scene_models, &model_ptrs[0], sizeof(ogt_vox_model*) * num_scene_models);
2344 scene->models = (const ogt_vox_model**)scene_models;
2345 scene->num_models = (uint32_t)num_scene_models;
2346
2347 // copy layer pointers over to the scene
2348 size_t num_scene_layers = layers.size();
2349 ogt_vox_layer* scene_layers = (ogt_vox_layer*)_vox_malloc(sizeof(ogt_vox_layer) * num_scene_layers);
2350 memcpy(scene_layers, &layers[0], sizeof(ogt_vox_layer) * num_scene_layers);
2351 scene->layers = scene_layers;
2352 scene->num_layers = (uint32_t)num_scene_layers;
2353
2354 // copy group pointers over to the scene
2355 size_t num_scene_groups = groups.size();
2356 ogt_vox_group* scene_groups = num_scene_groups ? (ogt_vox_group*)_vox_malloc(sizeof(ogt_vox_group) * num_scene_groups) : NULL;
2357 if (num_scene_groups)
2358 memcpy(scene_groups, &groups[0], sizeof(ogt_vox_group) * num_scene_groups);
2359 scene->groups = scene_groups;
2360 scene->num_groups = (uint32_t)num_scene_groups;
2361
2362 // now patch up instance name pointers to point into the scene string area
2363 for (uint32_t i = 0; i < num_scene_instances; i++)
2364 if (scene_instances[i].name)
2365 scene_instances[i].name = scene_string_data + (size_t)scene_instances[i].name;
2366
2367 // now patch up layer name pointers to point into the scene string area
2368 for (uint32_t i = 0; i < num_scene_layers; i++)
2369 if (scene_layers[i].name)
2370 scene_layers[i].name = scene_string_data + (size_t)scene_layers[i].name;
2371
2372 // copy the palette.
2373 scene->palette = palette;
2374 }
2375 return scene;
2376}
2377
2378const ogt_vox_scene* ogt_vox_read_scene(const uint8_t* pBuffer, uint32_t buffer_size)
2379{
2380 return ogt_vox_read_scene_with_flags(pBuffer, buffer_size, 0);
2381}
2382
2383void ogt_vox_destroy_scene(const ogt_vox_scene* p_scene)
2384{
2385 ogt_vox_scene* scene = const_cast<ogt_vox_scene*>(p_scene);
2386 // free models from model array
2387 for (uint32_t i = 0; i < scene->num_models; i++)
2388 _vox_free((void*)scene->models[i]);
2389 // free model array itself
2390 if (scene->models)
2391 {
2392 _vox_free(scene->models);
2393 scene->models = NULL;
2394 }
2395 // free instance array
2396 if (scene->instances)
2397 {
2398 _vox_free(const_cast<ogt_vox_instance*>(scene->instances));
2399 scene->instances = NULL;
2400 }
2401 // free layer array
2402 if (scene->layers)
2403 {
2404 _vox_free(const_cast<ogt_vox_layer*>(scene->layers));
2405 scene->layers = NULL;
2406 }
2407 // free groups array
2408 if (scene->groups)
2409 {
2410 _vox_free(const_cast<ogt_vox_group*>(scene->groups));
2411 scene->groups = NULL;
2412 }
2413 // finally, free the scene.
2414 _vox_free(scene);
2415}
2416
2417// the vector should be a unit vector aligned along one of the cardinal directions exactly. eg. (1,0,0) or (0, 0, -1)
2418// this function returns the non-zero column index in out_index and the returns whether that entry is negative.
2419static bool _vox_get_vec3_rotation_bits(const vec3& vec, uint32_t& out_index)
2420{
2421 const float* f = &vec.x;
2422 out_index = 3;
2423 bool is_negative = false;
2424 for (uint32_t i = 0; i < 3; i++)
2425 {
2426 if (f[i] == 1.0f || f[i] == -1.0f)
2427 {
2428 out_index = i;
2429 is_negative = f[i] < 0.0f ? true : false;
2430 }
2431 else
2432 {
2433 assert(f[i] == 0.0f); // must be zero
2434 }
2435 }
2436 assert(out_index != 3); // if you hit this, you probably have all zeroes in the vector!
2437 return is_negative;
2438}
2439
2440static uint8_t _vox_make_packed_rotation_from_transform(const ogt_vox_transform* pTransform)
2441{
2442 // magicavoxel stores rows, and we have columns, so we do the swizzle here into rows
2443 vec3 row0 = vec3_make(pTransform->m00, pTransform->m10, pTransform->m20);
2444 vec3 row1 = vec3_make(pTransform->m01, pTransform->m11, pTransform->m21);
2445 vec3 row2 = vec3_make(pTransform->m02, pTransform->m12, pTransform->m22);
2446 uint32_t row0_index = 3, row1_index = 3, row2_index = 3;
2447 bool row0_negative = _vox_get_vec3_rotation_bits(row0, row0_index);
2448 bool row1_negative = _vox_get_vec3_rotation_bits(row1, row1_index);
2449 bool row2_negative = _vox_get_vec3_rotation_bits(row2, row2_index);
2450 assert(((1 << row0_index) | (1 << row1_index) | (1 << row2_index)) == 7); // check that rows are orthogonal. There must be a non-zero entry in column 0, 1 and 2 across these 3 rows.
2451 return static_cast<uint8_t>((row0_index) | (row1_index << 2) | (row0_negative ? 1 << 4 : 0) | (row1_negative ? 1 << 5 : 0) | (row2_negative ? 1 << 6 : 0));
2452}
2453
2454struct _vox_file_writeable
2455{
2456 _vox_array<uint8_t> data;
2457};
2458
2459static void _vox_file_writeable_init(_vox_file_writeable* pFp)
2460{
2461 pFp->data.reserve(1024);
2462}
2463static void _vox_file_write(_vox_file_writeable* pFp, const void* pData, uint32_t data_size)
2464{
2465 pFp->data.push_back_many((const uint8_t*)pData, data_size);
2466}
2467static void _vox_file_write_uint32(_vox_file_writeable* pFp, uint32_t data)
2468{
2469 pFp->data.push_back_many((const uint8_t*)&data, sizeof(uint32_t));
2470}
2471static void _vox_file_write_uint8(_vox_file_writeable* pFp, uint8_t data)
2472{
2473 pFp->data.push_back_many((const uint8_t*)&data, sizeof(uint8_t));
2474}
2475static uint32_t _vox_file_get_offset(const _vox_file_writeable* pFp)
2476{
2477 return (uint32_t)pFp->data.count;
2478}
2479static uint8_t* _vox_file_get_data(_vox_file_writeable* pFp)
2480{
2481 return &pFp->data[0];
2482}
2483static void _vox_file_write_dict_key_value(_vox_file_writeable* pFp, const char* szKey, const char* value)
2484{
2485 if (szKey == NULL || value == NULL)
2486 return;
2487 uint32_t key_len = (uint32_t)_vox_strlen(szKey);
2488 uint32_t value_len = (uint32_t)_vox_strlen(value);
2489 _vox_file_write_uint32(pFp, key_len);
2490 _vox_file_write(pFp, szKey, key_len);
2491 _vox_file_write_uint32(pFp, value_len);
2492 _vox_file_write(pFp, value, value_len);
2493}
2494
2495static uint32_t _vox_dict_key_value_size(const char* szKey, const char* value)
2496{
2497 if (szKey == NULL || value == NULL)
2498 return 0;
2499 size_t size = sizeof(uint32_t) + _vox_strlen(szKey) + sizeof(uint32_t) + _vox_strlen(value);
2500 return (uint32_t)size;
2501}
2502
2503static void _vox_file_write_chunk_nTRN(_vox_file_writeable* pFp, uint32_t node_id, uint32_t child_node_id, const char* szName, bool bHidden, const ogt_vox_transform* pTransform, uint32_t layer_id)
2504{
2505 // obtain dictionary string pointers
2506 const char* hidden_string = bHidden ? "1" : NULL;
2507 const char* t_string = NULL;
2508 const char* r_string = NULL;
2509 char t_string_buf[64];
2510 char r_string_buf[64];
2511 t_string_buf[0] = 0;
2512 r_string_buf[0] = 0;
2513 if (pTransform != NULL)
2514 {
2515 uint8_t packed_rotation_bits = _vox_make_packed_rotation_from_transform(pTransform);
2516 _vox_sprintf(t_string_buf, sizeof(t_string_buf), "%i %i %i", (int32_t)pTransform->m30, (int32_t)pTransform->m31, (int32_t)pTransform->m32);
2517 _vox_sprintf(r_string_buf, sizeof(r_string_buf), "%u", packed_rotation_bits);
2518 t_string = t_string_buf;
2519 r_string = r_string_buf;
2520 }
2521
2522 uint32_t node_dict_size =
2523 sizeof(uint32_t) + // num key value pairs
2524 _vox_dict_key_value_size("_name", szName) +
2525 _vox_dict_key_value_size("_hidden", hidden_string);
2526
2527 uint32_t frame_dict_size =
2528 sizeof(uint32_t) + // num key value pairs
2529 _vox_dict_key_value_size("_t", t_string) +
2530 _vox_dict_key_value_size("_r", r_string);
2531
2532 uint32_t chunk_size_ntrn =
2533 sizeof(uint32_t) + // node_id
2534 node_dict_size + // node dictionary
2535 4 * sizeof(uint32_t) + // middle section - 4 uint32s
2536 frame_dict_size;
2537
2538 // write the nTRN header
2539 _vox_file_write_uint32(pFp, CHUNK_ID_nTRN);
2540 _vox_file_write_uint32(pFp, chunk_size_ntrn);
2541 _vox_file_write_uint32(pFp, 0);
2542
2543 // write the nTRN payload
2544 _vox_file_write_uint32(pFp, node_id);
2545
2546 // write the node dictionary
2547 uint32_t node_dict_keyvalue_count = (szName ? 1 : 0) + (hidden_string ? 1 : 0);
2548 _vox_file_write_uint32(pFp, node_dict_keyvalue_count); // num key values
2549 _vox_file_write_dict_key_value(pFp, "_name", szName);
2550 _vox_file_write_dict_key_value(pFp, "_hidden", hidden_string);
2551
2552 // get other properties.
2553 _vox_file_write_uint32(pFp, child_node_id);
2554 _vox_file_write_uint32(pFp, UINT32_MAX); // reserved_id must have all bits set.
2555 _vox_file_write_uint32(pFp, layer_id);
2556 _vox_file_write_uint32(pFp, 1); // num_frames must be 1
2557
2558 // write the frame dictionary
2559 _vox_file_write_uint32(pFp, (r_string ? 1 : 0) + (t_string ? 1 : 0)); // num key values
2560 _vox_file_write_dict_key_value(pFp, "_r", r_string);
2561 _vox_file_write_dict_key_value(pFp, "_t", t_string);
2562}
2563
2564// saves the scene out to a buffer that when saved as a .vox file can be loaded with magicavoxel.
2565uint8_t* ogt_vox_write_scene(const ogt_vox_scene* pScene, uint32_t* pBuffer_size)
2566{
2567 _vox_file_writeable file;
2568 _vox_file_writeable_init(&file);
2569 _vox_file_writeable* fp = &file;
2570
2571 // write file header and file version
2572 _vox_file_write_uint32(fp, CHUNK_ID_VOX_);
2573 _vox_file_write_uint32(fp, 150);
2574
2575 // write the main chunk
2576 _vox_file_write_uint32(fp, CHUNK_ID_MAIN);
2577 _vox_file_write_uint32(fp, 0);
2578 _vox_file_write_uint32(fp, 0); // this main_chunk_child_size will get patched up once everything is written.
2579
2580 // we need to know how to patch up the main chunk size after we've written everything
2581 const uint32_t offset_post_main_chunk = _vox_file_get_offset(fp);
2582
2583 // write out all model chunks
2584 for (uint32_t i = 0; i < pScene->num_models; i++)
2585 {
2586 const ogt_vox_model* model = pScene->models[i];
2587 assert(model->size_x <= 126 && model->size_y <= 126 && model->size_z <= 126);
2588 // count the number of solid voxels in the grid
2589 uint32_t num_voxels_in_grid = model->size_x * model->size_y * model->size_z;
2590 uint32_t num_solid_voxels = 0;
2591 for (uint32_t voxel_index = 0; voxel_index < num_voxels_in_grid; voxel_index++)
2592 if (model->voxel_data[voxel_index] != 0)
2593 num_solid_voxels++;
2594 uint32_t chunk_size_xyzi = sizeof(uint32_t) + 4 * num_solid_voxels;
2595
2596 // write the SIZE chunk header
2597 _vox_file_write_uint32(fp, CHUNK_ID_SIZE);
2598 _vox_file_write_uint32(fp, 12);
2599 _vox_file_write_uint32(fp, 0);
2600
2601 // write the SIZE chunk payload
2602 _vox_file_write_uint32(fp, model->size_x);
2603 _vox_file_write_uint32(fp, model->size_y);
2604 _vox_file_write_uint32(fp, model->size_z);
2605
2606 // write the XYZI chunk header
2607 _vox_file_write_uint32(fp, CHUNK_ID_XYZI);
2608 _vox_file_write_uint32(fp, chunk_size_xyzi);
2609 _vox_file_write_uint32(fp, 0);
2610
2611 // write out XYZI chunk payload
2612 _vox_file_write_uint32(fp, num_solid_voxels);
2613 uint32_t voxel_index = 0;
2614 for (uint32_t z = 0; z < model->size_z; z++)
2615 {
2616 for (uint32_t y = 0; y < model->size_y; y++)
2617 {
2618 for (uint32_t x = 0; x < model->size_x; x++, voxel_index++)
2619 {
2620 uint8_t color_index = model->voxel_data[voxel_index];
2621 if (color_index != 0)
2622 {
2623 _vox_file_write_uint8(fp, (uint8_t)x);
2624 _vox_file_write_uint8(fp, (uint8_t)y);
2625 _vox_file_write_uint8(fp, (uint8_t)z);
2626 _vox_file_write_uint8(fp, color_index);
2627 }
2628 }
2629 }
2630 }
2631 }
2632
2633 // define our node_id ranges.
2634 assert(pScene->num_groups);
2635 uint32_t first_group_transform_node_id = 0;
2636 uint32_t first_group_node_id = first_group_transform_node_id + pScene->num_groups;
2637 uint32_t first_shape_node_id = first_group_node_id + pScene->num_groups;
2638 uint32_t first_instance_transform_node_id = first_shape_node_id + pScene->num_models;
2639
2640 // write the nTRN nodes for each of the groups in the scene.
2641 for (uint32_t group_index = 0; group_index < pScene->num_groups; group_index++)
2642 {
2643 const ogt_vox_group* group = &pScene->groups[group_index];
2644 _vox_file_write_chunk_nTRN(fp, first_group_transform_node_id + group_index, first_group_node_id + group_index, NULL, group->hidden, &group->transform, group->layer_index);
2645 }
2646 // write the group nodes for each of the groups in the scene
2647 for (uint32_t group_index = 0; group_index < pScene->num_groups; group_index++)
2648 {
2649 // count how many childnodes there are. This is simply the sum of all
2650 // groups and instances that have this group as its parent
2651 uint32_t num_child_nodes = 0;
2652 for (uint32_t child_group_index = 0; child_group_index < pScene->num_groups; child_group_index++)
2653 if (pScene->groups[child_group_index].parent_group_index == group_index)
2654 num_child_nodes++;
2655 for (uint32_t child_instance_index = 0; child_instance_index < pScene->num_instances; child_instance_index++)
2656 if (pScene->instances[child_instance_index].group_index == group_index)
2657 num_child_nodes++;
2658
2659 // count number of dictionary items
2660 const char* hidden_string = pScene->groups[group_index].hidden ? "1" : NULL;
2661 uint32_t group_dict_keyvalue_count = (hidden_string ? 1 : 0);
2662
2663 // compute the chunk size.
2664 uint32_t chunk_size_ngrp =
2665 sizeof(uint32_t) + // node_id
2666 sizeof(uint32_t) + // num keyvalue pairs in node dictionary
2667 _vox_dict_key_value_size("_hidden", hidden_string) +
2668 sizeof(uint32_t) + // num_child_nodes field
2669 sizeof(uint32_t) * num_child_nodes; // uint32_t for each child node id.
2670
2671 // write the nGRP header
2672 _vox_file_write_uint32(fp, CHUNK_ID_nGRP);
2673 _vox_file_write_uint32(fp, chunk_size_ngrp);
2674 _vox_file_write_uint32(fp, 0);
2675 // write the nGRP payload
2676 _vox_file_write_uint32(fp, first_group_node_id + group_index); // node_id
2677 _vox_file_write_uint32(fp, group_dict_keyvalue_count); // num keyvalue pairs in node dictionary
2678 _vox_file_write_dict_key_value(fp, "_hidden", hidden_string);
2679 _vox_file_write_uint32(fp, num_child_nodes);
2680 // write the child group transform nodes
2681 for (uint32_t child_group_index = 0; child_group_index < pScene->num_groups; child_group_index++)
2682 if (pScene->groups[child_group_index].parent_group_index == group_index)
2683 _vox_file_write_uint32(fp, first_group_transform_node_id + child_group_index);
2684 // write the child instance transform nodes
2685 for (uint32_t child_instance_index = 0; child_instance_index < pScene->num_instances; child_instance_index++)
2686 if (pScene->instances[child_instance_index].group_index == group_index)
2687 _vox_file_write_uint32(fp, first_instance_transform_node_id + child_instance_index);
2688 }
2689
2690 // write out an nSHP chunk for each of the models
2691 for (uint32_t i = 0; i < pScene->num_models; i++)
2692 {
2693 // compute the size of the nSHP chunk
2694 uint32_t chunk_size_nshp =
2695 sizeof(uint32_t) + // node_id
2696 sizeof(uint32_t) + // num keyvalue pairs in node dictionary
2697 sizeof(uint32_t) + // num_models
2698 sizeof(uint32_t) + // model_id
2699 sizeof(uint32_t); // num keyvalue pairs in model dictionary
2700 // write the nSHP chunk header
2701 _vox_file_write_uint32(fp, CHUNK_ID_nSHP);
2702 _vox_file_write_uint32(fp, chunk_size_nshp);
2703 _vox_file_write_uint32(fp, 0);
2704 // write the nSHP chunk payload
2705 _vox_file_write_uint32(fp, first_shape_node_id + i); // node_id
2706 _vox_file_write_uint32(fp, 0); // num keyvalue pairs in node dictionary
2707 _vox_file_write_uint32(fp, 1); // num_models must be 1
2708 _vox_file_write_uint32(fp, i); // model_id
2709 _vox_file_write_uint32(fp, 0); // num keyvalue pairs in model dictionary
2710 }
2711 // write out an nTRN chunk for all instances - and make them point to the relevant nSHP chunk
2712 for (uint32_t i = 0; i < pScene->num_instances; i++)
2713 {
2714 const ogt_vox_instance* instance = &pScene->instances[i];
2715 uint32_t node_id = first_instance_transform_node_id + i;
2716 uint32_t child_node_id = first_shape_node_id + instance->model_index;
2717 _vox_file_write_chunk_nTRN(fp, node_id, child_node_id, instance->name, instance->hidden, &instance->transform, instance->layer_index);
2718 }
2719
2720 // write out RGBA chunk for the palette
2721 {
2722 // .vox stores palette rotated by 1 color index, so do that now.
2723 ogt_vox_palette rotated_palette;
2724 for (uint32_t i = 0; i < 256; i++)
2725 rotated_palette.color[i] = pScene->palette.color[(i + 1) & 255];
2726
2727 // write the palette chunk header
2728 _vox_file_write_uint32(fp, CHUNK_ID_RGBA);
2729 _vox_file_write_uint32(fp, sizeof(ogt_vox_palette));
2730 _vox_file_write_uint32(fp, 0);
2731 // write the palette chunk payload
2732 _vox_file_write(fp, &rotated_palette, sizeof(ogt_vox_palette));
2733 }
2734
2735 // write all layer chunks out.
2736 for (uint32_t i = 0; i < pScene->num_layers; i++)
2737 {
2738 const char* layer_name_string = pScene->layers[i].name;
2739 const char* hidden_string = pScene->layers[i].hidden ? "1" : NULL;
2740 uint32_t layer_chunk_size =
2741 sizeof(int32_t) + // layer_id
2742 sizeof(uint32_t) + // num key value pairs
2743 _vox_dict_key_value_size("_name", layer_name_string) +
2744 _vox_dict_key_value_size("_hidden", hidden_string) +
2745 sizeof(int32_t); // reserved id, must be -1
2746 uint32_t layer_dict_keyvalue_count = (layer_name_string ? 1 : 0) + (hidden_string ? 1 : 0);
2747 // write the layer chunk header
2748 _vox_file_write_uint32(fp, CHUNK_ID_LAYR);
2749 _vox_file_write_uint32(fp, layer_chunk_size);
2750 _vox_file_write_uint32(fp, 0);
2751 // write the layer chunk payload
2752 _vox_file_write_uint32(fp, i); // layer_id
2753 _vox_file_write_uint32(fp, layer_dict_keyvalue_count); // num keyvalue pairs in layer dictionary
2754 _vox_file_write_dict_key_value(fp, "_name", layer_name_string);
2755 _vox_file_write_dict_key_value(fp, "_hidden", hidden_string);
2756 _vox_file_write_uint32(fp, UINT32_MAX); // reserved id
2757 }
2758
2759 // we deliberately don't free the fp->data field, just pass the buffer pointer and size out to the caller
2760 *pBuffer_size = (uint32_t)fp->data.count;
2761 uint8_t* buffer_data = _vox_file_get_data(fp);
2762 // we deliberately clear this pointer so it doesn't get auto-freed on exiting. The caller will own the memory hereafter.
2763 fp->data.data = NULL;
2764
2765 // patch up the main chunk's child chunk size now that we've written everything we're going to write.
2766 {
2767 uint32_t* main_chunk_child_size = (uint32_t*)&buffer_data[offset_post_main_chunk - sizeof(uint32_t)];
2768 *main_chunk_child_size = *pBuffer_size - offset_post_main_chunk;
2769 }
2770
2771 return buffer_data;
2772}
2773
2774void* ogt_vox_malloc(size_t uiSize)
2775{
2776 return _vox_malloc(uiSize);
2777}
2778
2779void ogt_vox_free(void* pMem)
2780{
2781 _vox_free(pMem);
2782}
2783
2784// compute the minimum and maximum x coordinate within the scene.
2785static void compute_scene_bounding_box_x(const ogt_vox_scene* pScene, int32_t& out_min_x, int32_t& out_max_x)
2786{
2787 if (pScene->num_instances && pScene->num_models)
2788 {
2789 // We don't apply orientation to the model dimensions and compute the exact min/max.
2790 // Instead we just conservatively use the maximum dimension of the model.
2791 int32_t scene_min_x = 0x7ffffff;
2792 int32_t scene_max_x = -0x7ffffff;
2793 for (uint32_t instance_index = 0; instance_index < pScene->num_instances; instance_index++)
2794 {
2795 const ogt_vox_instance* instance = &pScene->instances[instance_index];
2796 // compute the instance transform, taking into account the group hierarchy.
2797 ogt_vox_transform instance_transform = instance->transform;
2798 uint32_t parent_group_index = instance->group_index;
2799 while (parent_group_index != k_invalid_group_index)
2800 {
2801 const ogt_vox_group* group = &pScene->groups[parent_group_index];
2802 instance_transform = _vox_transform_multiply(instance_transform, group->transform);
2803 parent_group_index = group->parent_group_index;
2804 }
2805
2806 const ogt_vox_model* model = pScene->models[instance->model_index];
2807 // the instance_transform can be rotated, so we try to figure out whether the
2808 // model's local x, y or z size is aligned along the world x axis.
2809 // One of the column vectors of the transform must have a non-zero in its
2810 // x field and the dimension associated with that column is the correct choice of rus.
2811 int32_t max_dim = instance_transform.m00 != 0.0f ? model->size_x : instance_transform.m10 != 0.0f ? model->size_y
2812 : instance_transform.m20 != 0.0f ? model->size_z
2813 : model->size_x;
2814 int32_t half_dim = max_dim / 2;
2815 int32_t min_x = (int32_t)instance_transform.m30 - half_dim;
2816 int32_t max_x = (int32_t)instance_transform.m30 + half_dim;
2817 scene_min_x = min_x < scene_min_x ? min_x : scene_min_x;
2818 scene_max_x = max_x > scene_max_x ? max_x : scene_max_x;
2819 }
2820 // pass out the dimensions.
2821 out_min_x = scene_min_x;
2822 out_max_x = scene_max_x;
2823 }
2824 else
2825 {
2826 out_min_x = 0;
2827 out_max_x = 0;
2828 }
2829}
2830
2831// returns a mask of which color indices are used by the specified scene.
2832// used_mask[0] can be false at the end of this if all models 100% fill their voxel grid with solid voxels, so callers
2833// should handle that case properly.
2834static void compute_scene_used_color_index_mask(bool* pUsed_mask, const ogt_vox_scene* pScene)
2835{
2836 memset(pUsed_mask, 0, 256);
2837 for (uint32_t model_index = 0; model_index < pScene->num_models; model_index++)
2838 {
2839 const ogt_vox_model* model = pScene->models[model_index];
2840 uint32_t voxel_count = model->size_x * model->size_y * model->size_z;
2841 for (uint32_t voxel_index = 0; voxel_index < voxel_count; voxel_index++)
2842 {
2843 uint8_t color_index = model->voxel_data[voxel_index];
2844 pUsed_mask[color_index] = true;
2845 }
2846 }
2847}
2848
2849// finds an exact color in the specified palette if it exists, and UINT32_MAX otherwise
2850static uint32_t find_exact_color_in_palette(const ogt_vox_rgba* pPalette, uint32_t palette_count, const ogt_vox_rgba color_to_find)
2851{
2852 for (uint32_t color_index = 1; color_index < palette_count; color_index++)
2853 {
2854 const ogt_vox_rgba color_to_match = pPalette[color_index];
2855 // we only try to match r,g,b components exactly.
2856 if (color_to_match.r == color_to_find.r && color_to_match.g == color_to_find.g && color_to_match.b == color_to_find.b)
2857 return color_index;
2858 }
2859 // no exact color found
2860 return UINT32_MAX;
2861}
2862
2863// finds the index within the specified palette that is closest to the color we want to find
2864static uint32_t find_closest_color_in_palette(const ogt_vox_rgba* pPalette, uint32_t palette_count, const ogt_vox_rgba color_to_find)
2865{
2866 // the lower the score the better, so initialize this to the maximum possible score
2867 int32_t best_score = INT32_MAX;
2868 uint32_t best_index = 1;
2869 // Here we compute a score based on the pythagorean distance between each color in the palette and the color to find.
2870 // The distance is in R,G,B space, and we choose the color with the lowest score.
2871 for (uint32_t color_index = 1; color_index < palette_count; color_index++)
2872 {
2873 int32_t r_diff = (int32_t)color_to_find.r - (int32_t)pPalette[color_index].r;
2874 int32_t g_diff = (int32_t)color_to_find.g - (int32_t)pPalette[color_index].g;
2875 int32_t b_diff = (int32_t)color_to_find.b - (int32_t)pPalette[color_index].b;
2876 // There are 2 aspects of our treatment of color here you may want to experiment with:
2877 // 1. differences in R, differences in G, differences in B are weighted the same rather than perceptually. Different weightings may be better for you.
2878 // 2. We treat R,G,B as if they are in a perceptually linear within each channel. eg. the differences between
2879 // a value of 5 and 8 in any channel is perceptually the same as the difference between 233 and 236 in the same channel.
2880 int32_t score = (r_diff * r_diff) + (g_diff * g_diff) + (b_diff * b_diff);
2881 if (score < best_score)
2882 {
2883 best_score = score;
2884 best_index = color_index;
2885 }
2886 }
2887 assert(best_score < UINT32_MAX); // this might indicate a completely degenerate palette.
2888 return best_index;
2889}
2890
2891static void update_master_palette_from_scene(ogt_vox_rgba* pMaster_palette, uint32_t& ref_master_palette_count, const ogt_vox_scene* pScene, uint32_t* pScene_to_master_map)
2892{
2893 // compute the mask of used colors in the scene.
2894 bool scene_used_mask[256];
2895 compute_scene_used_color_index_mask(scene_used_mask, pScene);
2896
2897 // initialize the map that converts from scene color_index to master color_index
2898 pScene_to_master_map[0] = 0; // zero/empty always maps to zero/empty in the master palette
2899 for (uint32_t i = 1; i < 256; i++)
2900 pScene_to_master_map[i] = UINT32_MAX; // UINT32_MAX means unassigned
2901
2902 // for each used color in the scene, now allocate it into the master palette.
2903 for (uint32_t color_index = 1; color_index < 256; color_index++)
2904 {
2905 if (scene_used_mask[color_index])
2906 {
2907 const ogt_vox_rgba color = pScene->palette.color[color_index];
2908 // find the exact color in the master palette. Will be UINT32_MAX if the color doesn't already exist
2909 uint32_t master_index = find_exact_color_in_palette(pMaster_palette, ref_master_palette_count, color);
2910 if (master_index == UINT32_MAX)
2911 {
2912 if (ref_master_palette_count < 256)
2913 {
2914 // master palette capacity hasn't been exceeded so far, allocate the color to it.
2915 pMaster_palette[ref_master_palette_count] = color;
2916 master_index = ref_master_palette_count++;
2917 }
2918 else
2919 {
2920 // otherwise, find the color that is perceptually closest to the original color.
2921
2922 // TODO(jpaver): It is potentially problematic if we hit this path for a many-scene merge.
2923 // Earlier scenes will reserve their colors exactly into the master palette, whereas later
2924 // scenes will end up having some of their colors remapped to different colors.
2925
2926 // A more holistic approach to color allocation may be necessary here eg.
2927 // we might allow the master palette to grow to more than 256 entries, and then use
2928 // similarity/frequency metrics to reduce the palette from that down to 256 entries. This
2929 // will mean all scenes will have be equally important if they have a high-frequency
2930 // usage of a color.
2931 master_index = find_closest_color_in_palette(pMaster_palette, ref_master_palette_count, color);
2932 }
2933 }
2934 // caller needs to know how to map its original color index into the master palette
2935 pScene_to_master_map[color_index] = master_index;
2936 }
2937 }
2938}
2939
2940ogt_vox_scene* ogt_vox_merge_scenes(const ogt_vox_scene** pScenes, uint32_t scene_count, const ogt_vox_rgba* pRequired_colors, const uint32_t required_color_count)
2941{
2942 assert(required_color_count <= 255); // can't exceed the maximum colors in the master palette plus the empty slot.
2943
2944 // initialize the master palette. If required colors are specified, map them into the master palette now.
2945 ogt_vox_rgba master_palette[256];
2946 uint32_t master_palette_count = 1; // color_index 0 is reserved for empty color!
2947 memset(&master_palette, 0, sizeof(master_palette));
2948 for (uint32_t required_index = 0; required_index < required_color_count; required_index++)
2949 master_palette[master_palette_count++] = pRequired_colors[required_index];
2950
2951 // count the number of required models, instances in the master scene
2952 uint32_t max_layers = 1; // we don't actually merge layers. Every instance will be in layer 0.
2953 uint32_t max_models = 0;
2954 uint32_t max_instances = 0;
2955 uint32_t max_groups = 1; // we add 1 root global group that everything will ultimately be parented to.
2956 for (uint32_t scene_index = 0; scene_index < scene_count; scene_index++)
2957 {
2958 if (!pScenes[scene_index])
2959 continue;
2960 max_instances += pScenes[scene_index]->num_instances;
2961 max_models += pScenes[scene_index]->num_models;
2962 max_groups += pScenes[scene_index]->num_groups;
2963 }
2964
2965 // allocate the master instances array
2966 ogt_vox_instance* instances = (ogt_vox_instance*)_vox_malloc(sizeof(ogt_vox_instance) * max_instances);
2967 ogt_vox_model** models = (ogt_vox_model**)_vox_malloc(sizeof(ogt_vox_model*) * max_models);
2968 ogt_vox_layer* layers = (ogt_vox_layer*)_vox_malloc(sizeof(ogt_vox_layer) * max_layers);
2969 ogt_vox_group* groups = (ogt_vox_group*)_vox_malloc(sizeof(ogt_vox_group) * max_groups);
2970 uint32_t num_instances = 0;
2971 uint32_t num_models = 0;
2972 uint32_t num_layers = 0;
2973 uint32_t num_groups = 0;
2974
2975 // add a single layer.
2976 layers[num_layers].hidden = false;
2977 layers[num_layers].name = "merged";
2978 num_layers++;
2979
2980 // magicavoxel expects exactly 1 root group, so if we have multiple scenes with multiple roots,
2981 // we must ensure all merged scenes are parented to the same root group. Allocate it now for the
2982 // merged scene.
2983 uint32_t global_root_group_index = num_groups;
2984 {
2985 assert(global_root_group_index == 0);
2986 ogt_vox_group root_group;
2987 root_group.hidden = false;
2988 root_group.layer_index = 0;
2989 root_group.parent_group_index = k_invalid_group_index;
2990 root_group.transform = _vox_transform_identity();
2991 groups[num_groups++] = root_group;
2992 }
2993
2994 // go ahead and do the merge now!
2995 size_t string_data_size = 0;
2996 int32_t offset_x = 0;
2997 for (uint32_t scene_index = 0; scene_index < scene_count; scene_index++)
2998 {
2999 const ogt_vox_scene* scene = pScenes[scene_index];
3000 if (!scene)
3001 continue;
3002
3003 // update the master palette, and get the map of this scene's color indices into the master palette.
3004 uint32_t scene_color_index_to_master_map[256];
3005 update_master_palette_from_scene(master_palette, master_palette_count, scene, scene_color_index_to_master_map);
3006
3007 // cache away the base model index for this scene.
3008 uint32_t base_model_index = num_models;
3009 uint32_t base_group_index = num_groups;
3010
3011 // create copies of all models that have color indices remapped.
3012 for (uint32_t model_index = 0; model_index < scene->num_models; model_index++)
3013 {
3014 const ogt_vox_model* model = scene->models[model_index];
3015 uint32_t voxel_count = model->size_x * model->size_y * model->size_z;
3016 // clone the model
3017 ogt_vox_model* override_model = (ogt_vox_model*)_vox_malloc(sizeof(ogt_vox_model) + voxel_count);
3018 uint8_t* override_voxel_data = (uint8_t*)&override_model[1];
3019
3020 // remap all color indices in the cloned model so they reference the master palette now!
3021 for (uint32_t voxel_index = 0; voxel_index < voxel_count; voxel_index++)
3022 {
3023 uint8_t old_color_index = model->voxel_data[voxel_index];
3024 uint32_t new_color_index = scene_color_index_to_master_map[old_color_index];
3025 assert(new_color_index < 256);
3026 override_voxel_data[voxel_index] = (uint8_t)new_color_index;
3027 }
3028 // assign the new model.
3029 *override_model = *model;
3030 override_model->voxel_data = override_voxel_data;
3031 override_model->voxel_hash = _vox_hash(override_voxel_data, voxel_count);
3032
3033 models[num_models++] = override_model;
3034 }
3035
3036 // compute the scene bounding box on x dimension. this is used to offset instances
3037 // and groups in the merged model along X dimension such that they do not overlap
3038 // with instances from another scene in the merged model.
3039 int32_t scene_min_x, scene_max_x;
3040 compute_scene_bounding_box_x(scene, scene_min_x, scene_max_x);
3041 float scene_offset_x = (float)(offset_x - scene_min_x);
3042
3043 // each scene has a root group, and it must the 0th group in its local groups[] array,
3044 assert(scene->groups[0].parent_group_index == k_invalid_group_index);
3045 // create copies of all groups into the merged scene (except the root group from each scene -- which is why we start group_index at 1 here)
3046 for (uint32_t group_index = 1; group_index < scene->num_groups; group_index++)
3047 {
3048 const ogt_vox_group* src_group = &scene->groups[group_index];
3049 assert(src_group->parent_group_index != k_invalid_group_index); // there can be only 1 root group per scene and it must be the 0th group.
3050 ogt_vox_group dst_group = *src_group;
3051 assert(dst_group.parent_group_index < scene->num_groups);
3052 dst_group.layer_index = 0;
3053 dst_group.parent_group_index = (dst_group.parent_group_index == 0) ? global_root_group_index : base_group_index + (dst_group.parent_group_index - 1);
3054 // if this group belongs to the global root group, it must be translated so it doesn't overlap with other scenes.
3055 if (dst_group.parent_group_index == global_root_group_index)
3056 dst_group.transform.m30 += scene_offset_x;
3057 groups[num_groups++] = dst_group;
3058 }
3059
3060 // create copies of all instances (and bias them such that minimum on x starts at zero)
3061 for (uint32_t instance_index = 0; instance_index < scene->num_instances; instance_index++)
3062 {
3063 const ogt_vox_instance* src_instance = &scene->instances[instance_index];
3064 assert(src_instance->group_index < scene->num_groups); // every instance must be mapped to a group.
3065 ogt_vox_instance* dst_instance = &instances[num_instances++];
3066 *dst_instance = *src_instance;
3067 dst_instance->layer_index = 0;
3068 dst_instance->group_index = (dst_instance->group_index == 0) ? global_root_group_index : base_group_index + (dst_instance->group_index - 1);
3069 dst_instance->model_index += base_model_index;
3070 if (dst_instance->name)
3071 string_data_size += _vox_strlen(dst_instance->name) + 1; // + 1 for zero terminator
3072 // if this instance belongs to the global rot group, it must be translated so it doesn't overlap with other scenes.
3073 if (dst_instance->group_index == global_root_group_index)
3074 dst_instance->transform.m30 += scene_offset_x;
3075 }
3076
3077 offset_x += (scene_max_x - scene_min_x); // step the width of the scene in x dimension
3078 offset_x += 4; // a margin of this many voxels between scenes
3079 }
3080
3081 // fill any unused master palette entries with purple/invalid color.
3082 const ogt_vox_rgba k_invalid_color = {255, 0, 255, 255}; // purple = invalid
3083 for (uint32_t color_index = master_palette_count; color_index < 256; color_index++)
3084 master_palette[color_index] = k_invalid_color;
3085
3086 // assign the master scene on output. string_data is part of the scene allocation.
3087 size_t scene_size = sizeof(ogt_vox_scene) + string_data_size;
3088 ogt_vox_scene* merged_scene = (ogt_vox_scene*)_vox_calloc(scene_size);
3089
3090 // copy name data into the string section and make instances point to it. This makes the merged model self-contained.
3091 char* scene_string_data = (char*)&merged_scene[1];
3092 for (uint32_t instance_index = 0; instance_index < num_instances; instance_index++)
3093 {
3094 if (instances[instance_index].name)
3095 {
3096 size_t string_len = _vox_strlen(instances[instance_index].name) + 1; // +1 for zero terminator
3097 memcpy(scene_string_data, instances[instance_index].name, string_len);
3098 instances[instance_index].name = scene_string_data;
3099 scene_string_data += string_len;
3100 }
3101 }
3102
3103 assert(num_groups <= max_groups);
3104
3105 memset(merged_scene, 0, sizeof(ogt_vox_scene));
3106 merged_scene->instances = instances;
3107 merged_scene->num_instances = max_instances;
3108 merged_scene->models = (const ogt_vox_model**)models;
3109 merged_scene->num_models = max_models;
3110 merged_scene->layers = layers;
3111 merged_scene->num_layers = max_layers;
3112 merged_scene->groups = groups;
3113 merged_scene->num_groups = num_groups;
3114 // copy color palette into the merged scene
3115 for (uint32_t color_index = 0; color_index < 256; color_index++)
3116 merged_scene->palette.color[color_index] = master_palette[color_index];
3117
3118 return merged_scene;
3119}
3120
3121#endif // #ifdef OGT_VOX_IMPLEMENTATION
3122
3123/* -------------------------------------------------------------------------------------------------------------------------------------------------
3124
3125 MIT License
3126
3127 Copyright (c) 2019 Justin Paver
3128
3129 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"),
3130 to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
3131 and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
3132
3133 The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
3134
3135 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
3136 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
3137 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
3138 IN THE SOFTWARE.
3139
3140------------------------------------------------------------------------------------------------------------------------------------------------- */
Definition ogt_vox.h:204
Definition ogt_vox.h:186
Definition ogt_vox.h:197
Definition ogt_vox.h:176
Definition ogt_vox.h:170
Definition ogt_vox.h:155
Definition ogt_vox.h:213
Definition ogt_vox.h:161