1 // This file takes minecraft chunks (decoded by cave_parse) and
2 // uses stb_voxel_render to turn them into vertex buffers.
4 #define STB_GLEXT_DECLARE "glext_list.h"
7 #include "stb_glprog.h"
10 #include "cave_parse.h"
13 #include "sdl_thread.h"
16 //#define VHEIGHT_TEST
17 //#define STBVOX_OPTIMIZED_VHEIGHT
19 #define STBVOX_CONFIG_MODE 1
20 #define STBVOX_CONFIG_OPENGL_MODELVIEW
21 #define STBVOX_CONFIG_PREFER_TEXBUFFER
22 //#define STBVOX_CONFIG_LIGHTING_SIMPLE
23 #define STBVOX_CONFIG_FOG_SMOOTHSTEP
24 //#define STBVOX_CONFIG_PREMULTIPLIED_ALPHA // this doesn't work properly alpha test without next #define
25 //#define STBVOX_CONFIG_UNPREMULTIPLY // slower, fixes alpha test makes windows & fancy leaves look better
26 //#define STBVOX_CONFIG_TEX1_EDGE_CLAMP
27 #define STBVOX_CONFIG_DISABLE_TEX2
28 //#define STBVOX_CONFIG_DOWN_TEXLERP_PACKED
29 #define STBVOX_CONFIG_ROTATION_IN_LIGHTING
31 #define STB_VOXEL_RENDER_IMPLEMENTATION
32 #include "stb_voxel_render.h"
34 extern void ods(char *fmt
, ...);
36 //#define FANCY_LEAVES // nearly 2x the triangles when enabled (if underground is filled)
40 #define SKIP_TERRAIN 48 // use to avoid building underground stuff
41 // allows you to see what perf would be like if underground was efficiently culled,
42 // or if you were making a game without underground
56 unsigned char geom_map
[] =
61 STBVOX_GEOM_crossed_pair
,
63 STBVOX_GEOM_slab_lower
,
64 STBVOX_GEOM_floor_slope_north_is_top
,
68 unsigned char minecraft_info
[256][7] =
70 { C_empty
, 0,0,0,0,0,0 },
71 { C_solid
, 1,1,1,1,1,1 },
72 { C_solid
, 3,3,3,3,40,2 },
73 { C_solid
, 2,2,2,2,2,2 },
74 { C_solid
, 16,16,16,16,16,16 },
75 { C_solid
, 4,4,4,4,4,4 },
76 { C_cross
, 15,15,15,15 },
77 { C_solid
, 17,17,17,17,17,17 },
80 { C_water
, 223,223,223,223,223,223 },
81 { C_water
, 223,223,223,223,223,223 },
82 { C_solid
, 255,255,255,255,255,255 },
83 { C_solid
, 255,255,255,255,255,255 },
84 { C_solid
, 18,18,18,18,18,18 },
85 { C_solid
, 19,19,19,19,19,19 },
86 { C_solid
, 32,32,32,32,32,32 },
87 { C_solid
, 33,33,33,33,33,33 },
90 { C_solid
, 34,34,34,34,34,34 },
91 { C_solid
, 20,20,20,20,21,21 },
93 { C_force
, 52,52,52,52,52,52 }, // leaves
95 { C_solid
, 53,53,53,53,53,53 }, // leaves
97 { C_solid
, 24,24,24,24,24,24 },
98 { C_trans
, 49,49,49,49,49,49 }, // glass
99 { C_solid
, 160,160,160,160,160,160 },
100 { C_solid
, 144,144,144,144,144,144 },
101 { C_solid
, 46,45,45,45,62,62 },
104 { C_solid
, 192,192,192,192, 176,176 },
105 { C_solid
, 74,74,74,74,74,74 },
107 { C_empty
}, // powered rail
108 { C_empty
}, // detector rail
109 { C_solid
, 106,108,109,108,108,108 },
110 { C_empty
}, // cobweb=11
111 { C_cross
, 39,39,39,39 },
114 { C_cross
, 55,55,55,55,0,0 },
115 { C_solid
, 107,108,109,108,108,108 },
116 { C_empty
}, // piston head
117 { C_solid
, 64,64,64,64,64,64 }, // various colors
118 { C_empty
}, // unused
119 { C_cross
, 13,13,13,13,0,0 },
120 { C_cross
, 12,12,12,12,0,0 },
121 { C_cross
, 29,29,29,29,0,0 },
124 { C_cross
, 28,28,28,28,0,0 },
125 { C_solid
, 23,23,23,23,23,23 },
126 { C_solid
, 22,22,22,22,22,22 },
127 { C_solid
, 5,5,5,5,6,6, },
128 { C_slab
, 5,5,5,5,6,6, },
129 { C_solid
, 7,7,7,7,7,7, },
130 { C_solid
, 8,8,8,8,9,10 },
131 { C_solid
, 35,35,35,35,4,4, },
134 { C_solid
, 36,36,36,36,36,36 },
135 { C_solid
, 37,37,37,37,37,37 },
136 { C_cross
, 80,80,80,80,80,80 }, // torch
138 { C_trans
, 65,65,65,65,65,65 },
139 { C_stair
, 4,4,4,4,4,4 },
140 { C_solid
, 26,26,26,27,25,25 },
141 { C_empty
}, // redstone
144 { C_solid
, 50,50,50,50,50,50 },
145 { C_solid
, 26,26,26,26,26,26 },
146 { C_solid
, 60,59,59,59,43,43 },
147 { C_cross
, 95,95,95,95 },
148 { C_solid
, 2,2,2,2,86,2 },
149 { C_solid
, 44,45,45,45,62,62 },
150 { C_solid
, 61,45,45,45,62,62 },
155 { C_empty
}, // ladder
157 { C_stair
, 16,16,16,16,16,16 }, // cobblestone stairs
159 { C_empty
}, // lever
160 { C_empty
}, // stone pressure plate
161 { C_empty
}, // iron door
164 { C_empty
}, // wooden pressure
165 { C_solid
, 51,51,51,51,51,51 },
166 { C_solid
, 51,51,51,51,51,51 },
170 { C_empty
}, // snow on block below, do as half slab?
171 { C_solid
, 67,67,67,67,67,67 },
174 { C_solid
, 66,66,66,66,66,66 },
175 { C_solid
, 70,70,70,70,69,71 },
176 { C_solid
, 72,72,72,72,72,72 },
177 { C_cross
, 73,73,73,73,73,73 },
178 { C_solid
, 74,74,74,74,75,74 },
179 { C_empty
}, // fence
180 { C_solid
,119,118,118,118,102,102 },
181 { C_solid
,103,103,103,103,103,103 },
184 { C_solid
, 104,104,104,104,104,104 },
185 { C_solid
, 105,105,105,105,105,105 },
186 { C_solid
, 167,167,167,167,167,167 },
187 { C_solid
, 120,118,118,118,102,102 },
189 { C_empty
}, // repeater
190 { C_empty
}, // repeater
191 { C_solid
, 49,49,49,49,49,49 }, // colored glass
196 { C_solid
, 54,54,54,54,54,54 },
197 { C_solid
, 125,125,125,125,125,125 },
198 { C_solid
, 126,126,126,126,126,126 },
200 { C_trans
, 49,49,49,49,49,49 }, // glass pane
201 { C_solid
, 136,136,136,136,137,137 }, // melon
204 { C_empty
}, // pumpkin stem
205 { C_empty
}, // melon stem
206 { C_empty
}, // vines
208 { C_stair
, 7,7,7,7,7,7, }, // brick stairs
209 { C_stair
, 54,54,54,54,54,54 }, // stone brick stairs
210 { C_empty
}, // mycelium
211 { C_empty
}, // lily pad
214 { C_solid
, 224,224,224,224,224,224 },
215 { C_empty
}, // nether brick fence
216 { C_stair
, 224,224,224,224,224,224 }, // nether brick stairs
217 { C_empty
}, // nether wart
218 { C_solid
, 182,182,182,182,166,183 },
219 { C_empty
}, // brewing stand
220 { C_empty
}, // cauldron
221 { C_empty
}, // end portal
224 { C_solid
, 159,159,159,159,158,158 },
225 { C_solid
, 175,175,175,175,175,175 },
226 { C_empty
}, // dragon egg
227 { C_solid
, 211,211,211,211,211,211 },
228 { C_solid
, 212,212,212,212,212,212 },
229 { C_solid
, 4,4,4,4,4,4, }, // wood double-slab
230 { C_slab
, 4,4,4,4,4,4, }, // wood slab
231 { C_empty
}, // cocoa
234 { C_solid
, 192,192,192,192,176,176 }, // sandstone stairs
235 { C_solid
, 32,32,32,32,32,32 }, // emerald ore
236 { C_solid
, 26,26,26,27,25,25 }, // ender chest
239 { C_solid
, 23,23,23,23,23,23 }, // emerald block
240 { C_solid
, 198,198,198,198,198,198 }, // spruce stairs
241 { C_solid
, 214,214,214,214,214,214 }, // birch stairs
244 { C_stair
, 199,199,199,199,199,199 }, // jungle stairs
245 { C_empty
}, // command block
246 { C_empty
}, // beacon
247 { C_slab
, 16,16,16,16,16,16 }, // cobblestone wall
248 { C_empty
}, // flower pot
249 { C_empty
}, // carrot
250 { C_empty
}, // potatoes
251 { C_empty
}, // wooden button
254 { C_empty
}, // mob head
255 { C_empty
}, // anvil
256 { C_solid
, 26,26,26,27,25,25 }, // trapped chest
257 { C_empty
}, // weighted pressure plate light
258 { C_empty
}, // weighted pressure plat eheavy
259 { C_empty
}, // comparator inactive
260 { C_empty
}, // comparator active
261 { C_empty
}, // daylight sensor
264 { C_solid
, 135,135,135,135,135,135 }, // redstone block
265 { C_solid
, 0,0,0,0,0,0, }, // nether quartz ore
266 { C_empty
}, // hopper
267 { C_solid
, 22,22,22,22,22,22 }, // quartz block
268 { C_stair
, 22,22,22,22,22,22 }, // quartz stairs
269 { C_empty
}, // activator rail
270 { C_solid
, 46,45,45,45,62,62 }, // dropper
271 { C_solid
, 72,72,72,72,72,72 }, // stained clay
274 { C_trans
, 49,49,49,49,49,49 }, // stained glass pane
276 { C_force
, 52,52,52,52,52,52 }, // leaves
278 { C_solid
, 53,53,53,53,53,53 }, // acacia leaves
280 { C_solid
, 20,20,20,20,21,21 }, // acacia tree
281 { C_solid
, 199,199,199,199,199,199 }, // acacia wood stairs
282 { C_solid
, 198,198,198,198,198,198 }, // dark oak stairs
283 { C_solid
, 146,146,146,146,146,146 }, // slime block
285 { C_solid
, 176,176,176,176,176,176 }, // red sandstone
286 { C_solid
, 176,176,176,176,176,176 }, // red sandstone
293 { C_solid
, 72,72,72,72,72,72 }, // hardened clay
301 { C_solid
, 176,176,176,176,176,176 }, // red sandstone
304 unsigned char minecraft_tex1_for_blocktype
[256][6];
305 unsigned char effective_blocktype
[256];
306 unsigned char minecraft_color_for_blocktype
[256][6];
307 unsigned char minecraft_geom_for_blocktype
[256];
309 uint8 build_buffer
[BUILD_BUFFER_SIZE
];
310 uint8 face_buffer
[FACE_BUFFER_SIZE
];
312 //GLuint vbuf, fbuf, fbuf_tex;
314 //unsigned char tex1_for_blocktype[256][6];
316 //unsigned char blocktype[34][34][257];
317 //unsigned char lighting[34][34][257];
319 // a superchunk is 64x64x256, with the border blocks computed as well,
320 // which means we need 4x4 chunks plus 16 border chunks plus 4 corner chunks
322 #define SUPERCHUNK_X 4
323 #define SUPERCHUNK_Y 4
325 unsigned char remap_data
[16][16];
326 unsigned char remap
[256];
327 unsigned char rotate_data
[4] = { 1,3,2,0 };
329 void convert_fastchunk_inplace(fast_chunk
*fc
)
332 int num_blocks
=0, step
=0;
333 unsigned char rot
[4096];
335 unsigned char *storage
;
338 memset(rot
, 0, 4096);
340 for (i
=0; i
< 16; ++i
)
341 num_blocks
+= fc
->blockdata
[i
] != NULL
;
344 storage
= malloc(16*16*16*2 * num_blocks
);
347 for (i
=0; i
< 16; ++i
) {
348 if (fc
->blockdata
[i
]) {
350 unsigned char *bd
,*dd
,*lt
,*sky
;
351 unsigned char *out
, *outb
;
353 // this ordering allows us to determine which data we can safely overwrite for in-place processing
354 bd
= fc
->blockdata
[i
];
357 sky
= fc
->skylight
[i
];
362 out
= storage
+ 16*16*16*2*step
;
365 // bd is written in place, but also reads from dd
366 for (o
=0; o
< 16*16*16/2; o
+= 1) {
368 unsigned char d
= dd
[o
];
374 //unsigned char d = bd[o] & 15;
375 v1
= remap_data
[remap
[v1
]][d
&15];
376 rot
[o
*2+0] = rotate_data
[d
&3];
378 v1
= effective_blocktype
[v1
];
382 //unsigned char d = bd[o] >> 4;
383 v2
= remap_data
[remap
[v2
]][d
>>4];
384 rot
[o
*2+1] = rotate_data
[(d
>>4)&3];
386 v2
= effective_blocktype
[v2
];
392 // this reads from lt & sky
394 outb
= out
+ 16*16*16;
398 // MC used to write in this order and it makes it possible to compute in-place
399 if (dd
< sky
&& sky
< lt
) {
400 // @TODO go this path always if !IN_PLACE
405 for (o
=0; o
< 16*16*16/2; ++o
) {
407 bright
= (lt
[o
]&15)*12 + 15 + (sky
[o
]&15)*16;
408 if (bright
> 255) bright
= 255;
409 if (bright
< 32) bright
= 32;
410 outb
[o
*2+0] = STBVOX_MAKE_LIGHTING_EXT((unsigned char) bright
, (rot
[o
*2+0]&3));
412 bright
= (lt
[o
]>>4)*12 + 15 + (sky
[o
]>>4)*16;
413 if (bright
> 255) bright
= 255;
414 if (bright
< 32) bright
= 32;
415 outb
[o
*2+1] = STBVOX_MAKE_LIGHTING_EXT((unsigned char) bright
, (rot
[o
*2+1]&3));
418 // @TODO: if blocktype is in between others, this breaks; need to find which side has two pointers, and use that
419 // overwrite rot[] array, then copy out
421 outb
= (dd
< sky
) ? dd
: sky
;
422 if (lt
< outb
) lt
= outb
;
425 for (o
=0; o
< 16*16*16/2; ++o
) {
427 bright
= (lt
[o
]&15)*12 + 15 + (sky
[o
]&15)*16;
428 if (bright
> 255) bright
= 255;
429 if (bright
< 32) bright
= 32;
430 rot
[o
*2+0] = STBVOX_MAKE_LIGHTING_EXT((unsigned char) bright
, (rot
[o
*2+0]&3));
432 bright
= (lt
[o
]>>4)*12 + 15 + (sky
[o
]>>4)*16;
433 if (bright
> 255) bright
= 255;
434 if (bright
< 32) bright
= 32;
435 rot
[o
*2+1] = STBVOX_MAKE_LIGHTING_EXT((unsigned char) bright
, (rot
[o
*2+1]&3));
438 memcpy(outb
, rot
, 4096);
443 fc
->blockdata
[i
] = out
;
450 free(fc
->pointer_to_free
);
451 fc
->pointer_to_free
= storage
;
455 void make_converted_fastchunk(fast_chunk
*fc
, int x
, int y
, int segment
, uint8
*sv_blocktype
, uint8
*sv_lighting
)
458 assert(fc
== NULL
|| (fc
->refcount
> 0 && fc
->refcount
< 64));
459 if (fc
== NULL
|| fc
->blockdata
[segment
] == NULL
) {
460 for (z
=0; z
< 16; ++z
) {
461 sv_blocktype
[z
] = C_empty
;
462 sv_lighting
[z
] = 255;
465 unsigned char *block
= fc
->blockdata
[segment
];
466 unsigned char *data
= fc
->data
[segment
];
468 for (z
=0; z
< 16; ++z
) {
469 sv_blocktype
[z
] = block
[z
*256 + y
*16 + x
];
470 sv_lighting
[z
] = data
[z
*256 + y
*16 + x
];
476 #define CHUNK_CACHE 64
480 int chunk_x
, chunk_y
;
482 } cached_converted_chunk
;
484 cached_converted_chunk chunk_cache
[CHUNK_CACHE
][CHUNK_CACHE
];
485 int cache_size
= CHUNK_CACHE
;
487 void reset_cache_size(int size
)
490 for (j
=size
; j
< cache_size
; ++j
) {
491 for (i
=size
; i
< cache_size
; ++i
) {
492 cached_converted_chunk
*ccc
= &chunk_cache
[j
][i
];
495 free(ccc
->fc
->pointer_to_free
);
506 // this must be called inside mutex
507 void deref_fastchunk(fast_chunk
*fc
)
510 assert(fc
->refcount
> 0);
512 if (fc
->refcount
== 0) {
513 free(fc
->pointer_to_free
);
519 SDL_mutex
* chunk_cache_mutex
;
520 SDL_mutex
* chunk_get_mutex
;
522 void lock_chunk_get_mutex(void)
524 SDL_LockMutex(chunk_get_mutex
);
526 void unlock_chunk_get_mutex(void)
528 SDL_UnlockMutex(chunk_get_mutex
);
531 fast_chunk
*get_converted_fastchunk(int chunk_x
, int chunk_y
)
533 int slot_x
= (chunk_x
& (cache_size
-1));
534 int slot_y
= (chunk_y
& (cache_size
-1));
536 cached_converted_chunk
*ccc
;
537 SDL_LockMutex(chunk_cache_mutex
);
538 ccc
= &chunk_cache
[slot_y
][slot_x
];
540 if (ccc
->chunk_x
== chunk_x
&& ccc
->chunk_y
== chunk_y
) {
541 fast_chunk
*fc
= ccc
->fc
;
544 SDL_UnlockMutex(chunk_cache_mutex
);
548 deref_fastchunk(ccc
->fc
);
553 SDL_UnlockMutex(chunk_cache_mutex
);
555 fc
= get_decoded_fastchunk_uncached(chunk_x
, -chunk_y
);
557 convert_fastchunk_inplace(fc
);
559 SDL_LockMutex(chunk_cache_mutex
);
560 // another thread might have updated it, so before we overwrite it...
562 deref_fastchunk(ccc
->fc
);
567 fc
->refcount
= 1; // 1 in the cache
569 ccc
->chunk_x
= chunk_x
;
570 ccc
->chunk_y
= chunk_y
;
575 SDL_UnlockMutex(chunk_cache_mutex
);
579 void make_map_segment_for_superchunk_preconvert(int chunk_x
, int chunk_y
, int segment
, fast_chunk
*fc_table
[4][4], uint8 sv_blocktype
[34][34][18], uint8 sv_lighting
[34][34][18])
582 assert((chunk_x
& 1) == 0);
583 assert((chunk_y
& 1) == 0);
584 for (b
=-1; b
< 3; ++b
) {
585 for (a
=-1; a
< 3; ++a
) {
589 fast_chunk
*fc
= fc_table
[b
+1][a
+1];
590 for (y
=0; y
< 16; ++y
)
591 for (x
=0; x
< 16; ++x
)
592 if (xo
+x
>= 0 && xo
+x
< 34 && yo
+y
>= 0 && yo
+y
< 34)
593 make_converted_fastchunk(fc
,x
,y
, segment
, sv_blocktype
[xo
+x
][yo
+y
], sv_lighting
[xo
+x
][yo
+y
]);
598 // build 1 mesh covering 2x2 chunks
599 void build_chunk(int chunk_x
, int chunk_y
, fast_chunk
*fc_table
[4][4], raw_mesh
*rm
)
602 stbvox_input_description
*map
;
605 unsigned char vheight
[34][34][18];
608 #ifndef STBVOX_CONFIG_DISABLE_TEX2
609 unsigned char tex2_choice
[34][34][18];
612 assert((chunk_x
& 1) == 0);
613 assert((chunk_y
& 1) == 0);
618 stbvox_set_input_stride(&rm
->mm
, 34*18, 18);
620 assert(rm
->mm
.input
.geometry
== NULL
);
622 map
= stbvox_get_input_description(&rm
->mm
);
623 map
->block_tex1_face
= minecraft_tex1_for_blocktype
;
624 map
->block_color_face
= minecraft_color_for_blocktype
;
625 map
->block_geometry
= minecraft_geom_for_blocktype
;
627 stbvox_reset_buffers(&rm
->mm
);
628 stbvox_set_buffer(&rm
->mm
, 0, 0, rm
->build_buffer
, BUILD_BUFFER_SIZE
);
629 stbvox_set_buffer(&rm
->mm
, 0, 1, rm
->face_buffer
, FACE_BUFFER_SIZE
);
631 map
->blocktype
= &rm
->sv_blocktype
[1][1][1]; // this is (0,0,0), but we need to be able to query off the edges
632 map
->lighting
= &rm
->sv_lighting
[1][1][1];
634 // fill in the top two rows of the buffer
635 for (a
=0; a
< 34; ++a
) {
636 for (b
=0; b
< 34; ++b
) {
637 rm
->sv_blocktype
[a
][b
][16] = 0;
638 rm
->sv_lighting
[a
][b
][16] = 255;
639 rm
->sv_blocktype
[a
][b
][17] = 0;
640 rm
->sv_lighting
[a
][b
][17] = 255;
644 #ifndef STBVOX_CONFIG_DISABLE_TEX2
645 for (a
=0; a
< 34; ++a
) {
646 for (b
=0; b
< 34; ++b
) {
647 int px
= chunk_x
*16 + a
- 1;
648 int py
= chunk_y
*16 + b
- 1;
649 float dist
= (float) sqrt(px
*px
+ py
*py
);
650 float s1
= (float) sin(dist
/ 16), s2
, s3
;
651 dist
= (float) sqrt((px
-80)*(px
-80) + (py
-50)*(py
-50));
652 s2
= (float) sin(dist
/ 11);
653 for (z
=0; z
< 18; ++z
) {
654 s3
= (float) sin(z
* 3.141592 / 8);
657 tex2_choice
[a
][b
][z
] = 63 & (int) stb_linear_remap(s3
,-1,1, -20,83);
663 for (z
=256-16; z
>= SKIP_TERRAIN
; z
-= 16)
667 if (z1
== 256) z1
= 255;
669 make_map_segment_for_superchunk_preconvert(chunk_x
, chunk_y
, z
>> 4, fc_table
, rm
->sv_blocktype
, rm
->sv_lighting
);
671 map
->blocktype
= &rm
->sv_blocktype
[1][1][1-z
]; // specify location of 0,0,0 so that accessing z0..z1 gets right data
672 map
->lighting
= &rm
->sv_lighting
[1][1][1-z
];
673 #ifndef STBVOX_CONFIG_DISABLE_TEX2
674 map
->tex2
= &tex2_choice
[1][1][1-z
];
678 // hacky test of vheight
679 for (a
=0; a
< 34; ++a
) {
680 for (b
=0; b
< 34; ++b
) {
682 for (c
=0; c
< 17; ++c
) {
683 if (rm
->sv_blocktype
[a
][b
][c
] != 0 && rm
->sv_blocktype
[a
][b
][c
+1] == 0) {
685 vheight
[a
][b
][c
] = rand() & 255;
686 rm
->sv_blocktype
[a
][b
][c
] = 168;
687 } else if (c
> 0 && rm
->sv_blocktype
[a
][b
][c
] != 0 && rm
->sv_blocktype
[a
][b
][c
-1] == 0) {
689 vheight
[a
][b
][c
] = ((rand() % 3) << 6) + ((rand() % 3) << 4) + ((rand() % 3) << 2) + (rand() % 3);
690 rm
->sv_blocktype
[a
][b
][c
] = 169;
693 vheight
[a
][b
][c
] = STBVOX_MAKE_VHEIGHT(2,2,2,2); // flat top
696 map
->vheight
= &vheight
[1][1][1-z
];
700 stbvox_set_input_range(&rm
->mm
, 0,0,z0
, 32,32,z1
);
701 stbvox_set_default_mesh(&rm
->mm
, 0);
702 stbvox_make_mesh(&rm
->mm
);
705 // copy the bottom two rows of data up to the top
706 for (a
=0; a
< 34; ++a
) {
707 for (b
=0; b
< 34; ++b
) {
708 rm
->sv_blocktype
[a
][b
][16] = rm
->sv_blocktype
[a
][b
][0];
709 rm
->sv_blocktype
[a
][b
][17] = rm
->sv_blocktype
[a
][b
][1];
710 rm
->sv_lighting
[a
][b
][16] = rm
->sv_lighting
[a
][b
][0];
711 rm
->sv_lighting
[a
][b
][17] = rm
->sv_lighting
[a
][b
][1];
716 stbvox_set_mesh_coordinates(&rm
->mm
, chunk_x
*16, chunk_y
*16, 0);
717 stbvox_get_transform(&rm
->mm
, rm
->transform
);
719 stbvox_set_input_range(&rm
->mm
, 0,0,0, 32,32,255);
720 stbvox_get_bounds(&rm
->mm
, rm
->bounds
);
722 rm
->num_quads
= stbvox_get_quad_count(&rm
->mm
, 0);
725 int next_blocktype
= 255;
727 unsigned char mc_rot
[4] = { 1,3,2,0 };
729 // create blocktypes with rotation baked into type...
730 // @TODO we no longer need this now that we store rotations
732 void build_stair_rotations(int blocktype
, unsigned char *map
)
736 // use the existing block type for floor stairs; allocate a new type for ceil stairs
737 for (i
=0; i
< 6; ++i
) {
738 minecraft_color_for_blocktype
[next_blocktype
][i
] = minecraft_color_for_blocktype
[blocktype
][i
];
739 minecraft_tex1_for_blocktype
[next_blocktype
][i
] = minecraft_tex1_for_blocktype
[blocktype
][i
];
741 minecraft_geom_for_blocktype
[next_blocktype
] = (unsigned char) STBVOX_MAKE_GEOMETRY(STBVOX_GEOM_ceil_slope_north_is_bottom
, 0, 0);
742 minecraft_geom_for_blocktype
[ blocktype
] = (unsigned char) STBVOX_MAKE_GEOMETRY(STBVOX_GEOM_floor_slope_north_is_top
, 0, 0);
744 for (i
=0; i
< 4; ++i
) {
745 map
[0+i
+8] = map
[0+i
] = blocktype
;
746 map
[4+i
+8] = map
[4+i
] = next_blocktype
;
751 void build_wool_variations(int bt
, unsigned char *map
)
754 unsigned char tex
[16] = { 64, 210, 194, 178, 162, 146, 130, 114, 225, 209, 193, 177, 161, 145, 129, 113 };
755 for (i
=0; i
< 16; ++i
) {
759 map
[i
] = next_blocktype
;
760 for (k
=0; k
< 6; ++k
) {
761 minecraft_tex1_for_blocktype
[next_blocktype
][k
] = tex
[i
];
763 minecraft_geom_for_blocktype
[next_blocktype
] = minecraft_geom_for_blocktype
[bt
];
769 void build_wood_variations(int bt
, unsigned char *map
)
772 unsigned char tex
[4] = { 5, 198, 214, 199 };
773 for (i
=0; i
< 4; ++i
) {
777 map
[i
] = next_blocktype
;
778 for (k
=0; k
< 6; ++k
) {
779 minecraft_tex1_for_blocktype
[next_blocktype
][k
] = tex
[i
];
781 minecraft_geom_for_blocktype
[next_blocktype
] = minecraft_geom_for_blocktype
[bt
];
791 void remap_in_place(int bt
, int rm
)
795 for (i
=0; i
< 16; ++i
)
796 remap_data
[rm
][i
] = bt
;
804 chunk_cache_mutex
= SDL_CreateMutex();
805 chunk_get_mutex
= SDL_CreateMutex();
807 for (i
=0; i
< 256; ++i
) {
808 memcpy(minecraft_tex1_for_blocktype
[i
], minecraft_info
[i
]+1, 6);
809 effective_blocktype
[i
] = (minecraft_info
[i
][0] == C_empty
? 0 : i
);
810 minecraft_geom_for_blocktype
[i
] = geom_map
[minecraft_info
[i
][0]];
812 //effective_blocktype[50] = 0; // delete torches
814 for (i
=0; i
< 6*256; ++i
) {
815 if (minecraft_tex1_for_blocktype
[0][i
] == 40)
816 minecraft_color_for_blocktype
[0][i
] = 38 | 64; // apply to tex1
817 if (minecraft_tex1_for_blocktype
[0][i
] == 39)
818 minecraft_color_for_blocktype
[0][i
] = 39 | 64; // apply to tex1
819 if (minecraft_tex1_for_blocktype
[0][i
] == 105)
820 minecraft_color_for_blocktype
[0][i
] = 63; // emissive
821 if (minecraft_tex1_for_blocktype
[0][i
] == 212)
822 minecraft_color_for_blocktype
[0][i
] = 63; // emissive
823 if (minecraft_tex1_for_blocktype
[0][i
] == 80)
824 minecraft_color_for_blocktype
[0][i
] = 63; // emissive
827 for (i
=0; i
< 6; ++i
) {
828 minecraft_color_for_blocktype
[172][i
] = 47 | 64; // apply to tex1
829 minecraft_color_for_blocktype
[178][i
] = 47 | 64; // apply to tex1
830 minecraft_color_for_blocktype
[18][i
] = 39 | 64; // green
831 minecraft_color_for_blocktype
[161][i
] = 37 | 64; // green
832 minecraft_color_for_blocktype
[10][i
] = 63; // emissive lava
833 minecraft_color_for_blocktype
[11][i
] = 63; // emissive
837 effective_blocktype
[168] = 168;
838 minecraft_tex1_for_blocktype
[168][0] = 1;
839 minecraft_tex1_for_blocktype
[168][1] = 1;
840 minecraft_tex1_for_blocktype
[168][2] = 1;
841 minecraft_tex1_for_blocktype
[168][3] = 1;
842 minecraft_tex1_for_blocktype
[168][4] = 1;
843 minecraft_tex1_for_blocktype
[168][5] = 1;
844 minecraft_geom_for_blocktype
[168] = STBVOX_GEOM_floor_vheight_12
;
845 effective_blocktype
[169] = 169;
846 minecraft_tex1_for_blocktype
[169][0] = 1;
847 minecraft_tex1_for_blocktype
[169][1] = 1;
848 minecraft_tex1_for_blocktype
[169][2] = 1;
849 minecraft_tex1_for_blocktype
[169][3] = 1;
850 minecraft_tex1_for_blocktype
[169][4] = 1;
851 minecraft_tex1_for_blocktype
[169][5] = 1;
852 minecraft_geom_for_blocktype
[169] = STBVOX_GEOM_ceil_vheight_03
;
862 for (i
=0; i
< 256; ++i
)
864 build_stair_rotations(i
, remap_data
[remap
[i
]]);
866 build_wool_variations(35, remap_data
[remap
[35]]);
868 build_wood_variations(5, remap_data
[remap
[5]]);
870 // set the remap flags for these so they write the rotation values
871 remap_in_place(54, 9);
872 remap_in_place(146, 10);
875 // Timing stats while optimizing the single-threaded builder
877 // 32..-32, 32..-32, SKIP_TERRAIN=0, !FANCY_LEAVES on 'mcrealm' data set
879 // 6.27s - reblocked to do 16 z at a time instead of 256 (still using 66x66x258), 4 meshes in parallel
880 // 5.96s - reblocked to use FAST_CHUNK (no intermediate data structure)
881 // 5.45s - unknown change, or previous measurement was wrong
883 // 6.12s - use preconverted data, not in-place
884 // 5.91s - use preconverted, in-place
885 // 5.34s - preconvert, in-place, avoid dependency chain (suggested by ryg)
886 // 5.34s - preconvert, in-place, avoid dependency chain, use bit-table instead of byte-table
887 // 5.50s - preconvert, in-place, branchless
889 // 6.42s - non-preconvert, avoid dependency chain (not an error)
890 // 5.40s - non-preconvert, w/dependency chain (same as earlier)
892 // 5.50s - non-FAST_CHUNK, reblocked outer loop for better cache reuse
893 // 4.73s - FAST_CHUNK non-preconvert, reblocked outer loop
894 // 4.25s - preconvert, in-place, reblocked outer loop
895 // 4.18s - preconvert, in-place, unrolled again
896 // 4.10s - 34x34 1 mesh instead of 66x66 and 4 meshes (will make it easier to do multiple threads)
898 // 4.83s - building bitmasks but not using them (2 bits per block, one if empty, one if solid)
900 // 5.16s - using empty bitmasks to early out
901 // 5.01s - using solid & empty bitmasks to early out - "foo"
902 // 4.64s - empty bitmask only, test 8 at a time, then test geom
903 // 4.72s - empty bitmask only, 8 at a time, then test bits
904 // 4.46s - split bitmask building into three loops (each byte is separate)
905 // 4.42s - further optimize computing bitmask
907 // 4.58s - using solid & empty bitmasks to early out, same as "foo" but faster bitmask building
908 // 4.12s - using solid & empty bitmasks to efficiently test neighbors
909 // 4.04s - using 16-bit fetches (not endian-independent)
910 // - note this is first place that beats previous best '4.10s - 34x34 1 mesh'
912 // 4.30s - current time with bitmasks disabled again (note was 4.10s earlier)
913 // 3.95s - bitmasks enabled again, no other changes
914 // 4.00s - current time with bitmasks disabled again, no other changes -- wide variation that is time dependent?
915 // (note that most of the numbers listed here are median of 3 values already)
916 // 3.98s - bitmasks enabled
918 // Bitmasks removed from the code as not worth the complexity increase
924 // 26% parsing & loading minecraft files (4/5ths of which is zlib decode)
925 // 39% building mesh from stb input format
926 // 18% converting from minecraft blocks to stb blocks
927 // 9% reordering from minecraft axis order to stb axis order
928 // 7% uploading vertex buffer to OpenGL