added stb, more binaryout changes"
[henge/apc.git] / stb / tests / caveview / cave_mesher.c
1 // This file takes minecraft chunks (decoded by cave_parse) and
2 // uses stb_voxel_render to turn them into vertex buffers.
3
4 #define STB_GLEXT_DECLARE "glext_list.h"
5 #include "stb_gl.h"
6 #include "stb_image.h"
7 #include "stb_glprog.h"
8
9 #include "caveview.h"
10 #include "cave_parse.h"
11 #include "stb.h"
12 #include "sdl.h"
13 #include "sdl_thread.h"
14 #include <math.h>
15
16 //#define VHEIGHT_TEST
17 //#define STBVOX_OPTIMIZED_VHEIGHT
18
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
30
31 #define STB_VOXEL_RENDER_IMPLEMENTATION
32 #include "stb_voxel_render.h"
33
34 extern void ods(char *fmt, ...);
35
36 //#define FANCY_LEAVES // nearly 2x the triangles when enabled (if underground is filled)
37 #define FAST_CHUNK
38 #define IN_PLACE
39
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
43
44 enum
45 {
46 C_empty,
47 C_solid,
48 C_trans,
49 C_cross,
50 C_water,
51 C_slab,
52 C_stair,
53 C_force,
54 };
55
56 unsigned char geom_map[] =
57 {
58 STBVOX_GEOM_empty,
59 STBVOX_GEOM_solid,
60 STBVOX_GEOM_transp,
61 STBVOX_GEOM_crossed_pair,
62 STBVOX_GEOM_solid,
63 STBVOX_GEOM_slab_lower,
64 STBVOX_GEOM_floor_slope_north_is_top,
65 STBVOX_GEOM_force,
66 };
67
68 unsigned char minecraft_info[256][7] =
69 {
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 },
78
79 // 8
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 },
88
89 // 16
90 { C_solid, 34,34,34,34,34,34 },
91 { C_solid, 20,20,20,20,21,21 },
92 #ifdef FANCY_LEAVES
93 { C_force, 52,52,52,52,52,52 }, // leaves
94 #else
95 { C_solid, 53,53,53,53,53,53 }, // leaves
96 #endif
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 },
102
103 // 24
104 { C_solid, 192,192,192,192, 176,176 },
105 { C_solid, 74,74,74,74,74,74 },
106 { C_empty }, // bed
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 },
112
113 // 32
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 },
122
123 // 40
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, },
132
133 // 48
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
137 { C_empty }, // fire
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
142
143 // 56
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 },
151 { C_empty }, // sign
152
153 // 64
154 { C_empty }, // door
155 { C_empty }, // ladder
156 { C_empty }, // rail
157 { C_stair, 16,16,16,16,16,16 }, // cobblestone stairs
158 { C_empty }, // sign
159 { C_empty }, // lever
160 { C_empty }, // stone pressure plate
161 { C_empty }, // iron door
162
163 // 72
164 { C_empty }, // wooden pressure
165 { C_solid, 51,51,51,51,51,51 },
166 { C_solid, 51,51,51,51,51,51 },
167 { C_empty },
168 { C_empty },
169 { C_empty },
170 { C_empty }, // snow on block below, do as half slab?
171 { C_solid, 67,67,67,67,67,67 },
172
173 // 80
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 },
182
183 // 88
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 },
188 { C_empty }, // cake
189 { C_empty }, // repeater
190 { C_empty }, // repeater
191 { C_solid, 49,49,49,49,49,49 }, // colored glass
192
193 // 96
194 { C_empty },
195 { C_empty },
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 },
199 { C_empty }, // bars
200 { C_trans, 49,49,49,49,49,49 }, // glass pane
201 { C_solid, 136,136,136,136,137,137 }, // melon
202
203 // 104
204 { C_empty }, // pumpkin stem
205 { C_empty }, // melon stem
206 { C_empty }, // vines
207 { C_empty }, // gate
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
212
213 // 112
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
222
223 // 120
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
232
233 // 128
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
237 { C_empty },
238 { C_empty },
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
242
243 // 136
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
252
253 // 144
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
262
263 // 152
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
272
273 // 160
274 { C_trans, 49,49,49,49,49,49 }, // stained glass pane
275 #ifdef FANCY_LEAVES
276 { C_force, 52,52,52,52,52,52 }, // leaves
277 #else
278 { C_solid, 53,53,53,53,53,53 }, // acacia leaves
279 #endif
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
284
285 { C_solid, 176,176,176,176,176,176 }, // red sandstone
286 { C_solid, 176,176,176,176,176,176 }, // red sandstone
287
288 // 168
289 { C_empty },
290 { C_empty },
291 { C_empty },
292 { C_empty },
293 { C_solid, 72,72,72,72,72,72 }, // hardened clay
294 { C_empty },
295 { C_empty },
296 { C_empty },
297
298 // 176
299 { C_empty },
300 { C_empty },
301 { C_solid, 176,176,176,176,176,176 }, // red sandstone
302 };
303
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];
308
309 uint8 build_buffer[BUILD_BUFFER_SIZE];
310 uint8 face_buffer[FACE_BUFFER_SIZE];
311
312 //GLuint vbuf, fbuf, fbuf_tex;
313
314 //unsigned char tex1_for_blocktype[256][6];
315
316 //unsigned char blocktype[34][34][257];
317 //unsigned char lighting[34][34][257];
318
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
321
322 #define SUPERCHUNK_X 4
323 #define SUPERCHUNK_Y 4
324
325 unsigned char remap_data[16][16];
326 unsigned char remap[256];
327 unsigned char rotate_data[4] = { 1,3,2,0 };
328
329 void convert_fastchunk_inplace(fast_chunk *fc)
330 {
331 int i;
332 int num_blocks=0, step=0;
333 unsigned char rot[4096];
334 #ifndef IN_PLACE
335 unsigned char *storage;
336 #endif
337
338 memset(rot, 0, 4096);
339
340 for (i=0; i < 16; ++i)
341 num_blocks += fc->blockdata[i] != NULL;
342
343 #ifndef IN_PLACE
344 storage = malloc(16*16*16*2 * num_blocks);
345 #endif
346
347 for (i=0; i < 16; ++i) {
348 if (fc->blockdata[i]) {
349 int o=0;
350 unsigned char *bd,*dd,*lt,*sky;
351 unsigned char *out, *outb;
352
353 // this ordering allows us to determine which data we can safely overwrite for in-place processing
354 bd = fc->blockdata[i];
355 dd = fc->data[i];
356 lt = fc->light[i];
357 sky = fc->skylight[i];
358
359 #ifdef IN_PLACE
360 out = bd;
361 #else
362 out = storage + 16*16*16*2*step;
363 #endif
364
365 // bd is written in place, but also reads from dd
366 for (o=0; o < 16*16*16/2; o += 1) {
367 unsigned char v1,v2;
368 unsigned char d = dd[o];
369 v1 = bd[o*2+0];
370 v2 = bd[o*2+1];
371
372 if (remap[v1])
373 {
374 //unsigned char d = bd[o] & 15;
375 v1 = remap_data[remap[v1]][d&15];
376 rot[o*2+0] = rotate_data[d&3];
377 } else
378 v1 = effective_blocktype[v1];
379
380 if (remap[v2])
381 {
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];
385 } else
386 v2 = effective_blocktype[v2];
387
388 out[o*2+0] = v1;
389 out[o*2+1] = v2;
390 }
391
392 // this reads from lt & sky
393 #ifndef IN_PLACE
394 outb = out + 16*16*16;
395 ++step;
396 #endif
397
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
401 #ifdef IN_PLACE
402 outb = dd;
403 #endif
404
405 for (o=0; o < 16*16*16/2; ++o) {
406 int bright;
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));
411
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));
416 }
417 } else {
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
420 #ifdef IN_PLACE
421 outb = (dd < sky) ? dd : sky;
422 if (lt < outb) lt = outb;
423 #endif
424
425 for (o=0; o < 16*16*16/2; ++o) {
426 int bright;
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));
431
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));
436 }
437
438 memcpy(outb, rot, 4096);
439 fc->data[i] = outb;
440 }
441
442 #ifndef IN_PLACE
443 fc->blockdata[i] = out;
444 fc->data[i] = outb;
445 #endif
446 }
447 }
448
449 #ifndef IN_PLACE
450 free(fc->pointer_to_free);
451 fc->pointer_to_free = storage;
452 #endif
453 }
454
455 void make_converted_fastchunk(fast_chunk *fc, int x, int y, int segment, uint8 *sv_blocktype, uint8 *sv_lighting)
456 {
457 int z;
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;
463 }
464 } else {
465 unsigned char *block = fc->blockdata[segment];
466 unsigned char *data = fc->data[segment];
467 y = 15-y;
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];
471 }
472 }
473 }
474
475
476 #define CHUNK_CACHE 64
477 typedef struct
478 {
479 int valid;
480 int chunk_x, chunk_y;
481 fast_chunk *fc;
482 } cached_converted_chunk;
483
484 cached_converted_chunk chunk_cache[CHUNK_CACHE][CHUNK_CACHE];
485 int cache_size = CHUNK_CACHE;
486
487 void reset_cache_size(int size)
488 {
489 int i,j;
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];
493 if (ccc->valid) {
494 if (ccc->fc) {
495 free(ccc->fc->pointer_to_free);
496 free(ccc->fc);
497 ccc->fc = NULL;
498 }
499 ccc->valid = 0;
500 }
501 }
502 }
503 cache_size = size;
504 }
505
506 // this must be called inside mutex
507 void deref_fastchunk(fast_chunk *fc)
508 {
509 if (fc) {
510 assert(fc->refcount > 0);
511 --fc->refcount;
512 if (fc->refcount == 0) {
513 free(fc->pointer_to_free);
514 free(fc);
515 }
516 }
517 }
518
519 SDL_mutex * chunk_cache_mutex;
520 SDL_mutex * chunk_get_mutex;
521
522 void lock_chunk_get_mutex(void)
523 {
524 SDL_LockMutex(chunk_get_mutex);
525 }
526 void unlock_chunk_get_mutex(void)
527 {
528 SDL_UnlockMutex(chunk_get_mutex);
529 }
530
531 fast_chunk *get_converted_fastchunk(int chunk_x, int chunk_y)
532 {
533 int slot_x = (chunk_x & (cache_size-1));
534 int slot_y = (chunk_y & (cache_size-1));
535 fast_chunk *fc;
536 cached_converted_chunk *ccc;
537 SDL_LockMutex(chunk_cache_mutex);
538 ccc = &chunk_cache[slot_y][slot_x];
539 if (ccc->valid) {
540 if (ccc->chunk_x == chunk_x && ccc->chunk_y == chunk_y) {
541 fast_chunk *fc = ccc->fc;
542 if (fc)
543 ++fc->refcount;
544 SDL_UnlockMutex(chunk_cache_mutex);
545 return fc;
546 }
547 if (ccc->fc) {
548 deref_fastchunk(ccc->fc);
549 ccc->fc = NULL;
550 ccc->valid = 0;
551 }
552 }
553 SDL_UnlockMutex(chunk_cache_mutex);
554
555 fc = get_decoded_fastchunk_uncached(chunk_x, -chunk_y);
556 if (fc)
557 convert_fastchunk_inplace(fc);
558
559 SDL_LockMutex(chunk_cache_mutex);
560 // another thread might have updated it, so before we overwrite it...
561 if (ccc->fc) {
562 deref_fastchunk(ccc->fc);
563 ccc->fc = NULL;
564 }
565
566 if (fc)
567 fc->refcount = 1; // 1 in the cache
568
569 ccc->chunk_x = chunk_x;
570 ccc->chunk_y = chunk_y;
571 ccc->valid = 1;
572 if (fc)
573 ++fc->refcount;
574 ccc->fc = fc;
575 SDL_UnlockMutex(chunk_cache_mutex);
576 return fc;
577 }
578
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])
580 {
581 int a,b;
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) {
586 int xo = a*16+1;
587 int yo = b*16+1;
588 int x,y;
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]);
594 }
595 }
596 }
597
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)
600 {
601 int a,b,z;
602 stbvox_input_description *map;
603
604 #ifdef VHEIGHT_TEST
605 unsigned char vheight[34][34][18];
606 #endif
607
608 #ifndef STBVOX_CONFIG_DISABLE_TEX2
609 unsigned char tex2_choice[34][34][18];
610 #endif
611
612 assert((chunk_x & 1) == 0);
613 assert((chunk_y & 1) == 0);
614
615 rm->cx = chunk_x;
616 rm->cy = chunk_y;
617
618 stbvox_set_input_stride(&rm->mm, 34*18, 18);
619
620 assert(rm->mm.input.geometry == NULL);
621
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;
626
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);
630
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];
633
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;
641 }
642 }
643
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);
655
656 s3 = s1*s2*s3;
657 tex2_choice[a][b][z] = 63 & (int) stb_linear_remap(s3,-1,1, -20,83);
658 }
659 }
660 }
661 #endif
662
663 for (z=256-16; z >= SKIP_TERRAIN; z -= 16)
664 {
665 int z0 = z;
666 int z1 = z+16;
667 if (z1 == 256) z1 = 255;
668
669 make_map_segment_for_superchunk_preconvert(chunk_x, chunk_y, z >> 4, fc_table, rm->sv_blocktype, rm->sv_lighting);
670
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];
675 #endif
676
677 #ifdef VHEIGHT_TEST
678 // hacky test of vheight
679 for (a=0; a < 34; ++a) {
680 for (b=0; b < 34; ++b) {
681 int c;
682 for (c=0; c < 17; ++c) {
683 if (rm->sv_blocktype[a][b][c] != 0 && rm->sv_blocktype[a][b][c+1] == 0) {
684 // topmost block
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) {
688 // bottommost block
689 vheight[a][b][c] = ((rand() % 3) << 6) + ((rand() % 3) << 4) + ((rand() % 3) << 2) + (rand() % 3);
690 rm->sv_blocktype[a][b][c] = 169;
691 }
692 }
693 vheight[a][b][c] = STBVOX_MAKE_VHEIGHT(2,2,2,2); // flat top
694 }
695 }
696 map->vheight = &vheight[1][1][1-z];
697 #endif
698
699 {
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);
703 }
704
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];
712 }
713 }
714 }
715
716 stbvox_set_mesh_coordinates(&rm->mm, chunk_x*16, chunk_y*16, 0);
717 stbvox_get_transform(&rm->mm, rm->transform);
718
719 stbvox_set_input_range(&rm->mm, 0,0,0, 32,32,255);
720 stbvox_get_bounds(&rm->mm, rm->bounds);
721
722 rm->num_quads = stbvox_get_quad_count(&rm->mm, 0);
723 }
724
725 int next_blocktype = 255;
726
727 unsigned char mc_rot[4] = { 1,3,2,0 };
728
729 // create blocktypes with rotation baked into type...
730 // @TODO we no longer need this now that we store rotations
731 // in lighting
732 void build_stair_rotations(int blocktype, unsigned char *map)
733 {
734 int i;
735
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];
740 }
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);
743
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;
747 }
748 --next_blocktype;
749 }
750
751 void build_wool_variations(int bt, unsigned char *map)
752 {
753 int i,k;
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) {
756 if (i == 0)
757 map[i] = bt;
758 else {
759 map[i] = next_blocktype;
760 for (k=0; k < 6; ++k) {
761 minecraft_tex1_for_blocktype[next_blocktype][k] = tex[i];
762 }
763 minecraft_geom_for_blocktype[next_blocktype] = minecraft_geom_for_blocktype[bt];
764 --next_blocktype;
765 }
766 }
767 }
768
769 void build_wood_variations(int bt, unsigned char *map)
770 {
771 int i,k;
772 unsigned char tex[4] = { 5, 198, 214, 199 };
773 for (i=0; i < 4; ++i) {
774 if (i == 0)
775 map[i] = bt;
776 else {
777 map[i] = next_blocktype;
778 for (k=0; k < 6; ++k) {
779 minecraft_tex1_for_blocktype[next_blocktype][k] = tex[i];
780 }
781 minecraft_geom_for_blocktype[next_blocktype] = minecraft_geom_for_blocktype[bt];
782 --next_blocktype;
783 }
784 }
785 map[i] = map[i-1];
786 ++i;
787 for (; i < 16; ++i)
788 map[i] = bt;
789 }
790
791 void remap_in_place(int bt, int rm)
792 {
793 int i;
794 remap[bt] = rm;
795 for (i=0; i < 16; ++i)
796 remap_data[rm][i] = bt;
797 }
798
799
800 void mesh_init(void)
801 {
802 int i;
803
804 chunk_cache_mutex = SDL_CreateMutex();
805 chunk_get_mutex = SDL_CreateMutex();
806
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]];
811 }
812 //effective_blocktype[50] = 0; // delete torches
813
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
825 }
826
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
834 }
835
836 #ifdef VHEIGHT_TEST
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;
853 #endif
854
855 remap[53] = 1;
856 remap[67] = 2;
857 remap[108] = 3;
858 remap[109] = 4;
859 remap[114] = 5;
860 remap[136] = 6;
861 remap[156] = 7;
862 for (i=0; i < 256; ++i)
863 if (remap[i])
864 build_stair_rotations(i, remap_data[remap[i]]);
865 remap[35] = 8;
866 build_wool_variations(35, remap_data[remap[35]]);
867 remap[5] = 11;
868 build_wood_variations(5, remap_data[remap[5]]);
869
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);
873 }
874
875 // Timing stats while optimizing the single-threaded builder
876
877 // 32..-32, 32..-32, SKIP_TERRAIN=0, !FANCY_LEAVES on 'mcrealm' data set
878
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
882
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
888
889 // 6.42s - non-preconvert, avoid dependency chain (not an error)
890 // 5.40s - non-preconvert, w/dependency chain (same as earlier)
891
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)
897
898 // 4.83s - building bitmasks but not using them (2 bits per block, one if empty, one if solid)
899
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
906
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'
911
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
917
918 // Bitmasks removed from the code as not worth the complexity increase
919
920
921
922 // Raw data for Q&A:
923 //
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