5fac72984d2f489a9aefdc7632d39e8c0489871e
[convexer.git] / src / convexer.c
1 /*
2 CONVEXER v0.8
3
4 A GNU/Linux-first Source1 Hammer replacement
5 built with Blender, for mapmakers
6
7 Copyright (C) 2022 Harry Godden (hgn)
8
9 Features:
10 - Brush decomposition into convex pieces for well defined geometry
11 - Freely form displacements without limits
12 - Build your entire map in Blender
13 - Compile models and model groups easily
14 - Light patch BSP files; remove unwanted realtime effects
15 - Fastest VTF compressor (thanks to Richgel999 and stb)
16
17 To come:
18 - high quality level overviews automatically for CS:GO (csRadar)
19
20 Program structure:
21
22 File/folder Lang Purpose
23 src/
24 __init__.py Python Blender plugin interface
25 convexer.c C Heavy lifting; brush decomp, mesh processing
26 cxr_math.h C Vector maths and other handy things
27 cxr_mem.h C Automatic resizing buffers
28 nbvtf/
29 nbvtf.h C VTF processing interface
30 librgcx.h C++ Rich Geldreich's DXT1/DXT5 compressors
31 stb/ C Sean Barrets image I/O
32 */
33
34 const char *cxr_build_time = __DATE__ " @" __TIME__;
35
36 #include <stdio.h>
37 #include <math.h>
38 #include <stdint.h>
39 #include <stdarg.h>
40 #include <stdlib.h>
41 #include <string.h>
42
43 typedef uint8_t u8;
44 typedef uint16_t u16;
45 typedef uint32_t u32;
46 typedef uint64_t u64;
47 typedef int8_t i8;
48 typedef int16_t i16;
49 typedef int32_t i32;
50 typedef int64_t i64;
51
52 typedef unsigned int uint;
53
54 typedef double v2f[2];
55 typedef double v3f[3];
56 typedef double v4f[4];
57 typedef v3f m3x3f[3];
58 typedef v3f m4x3f[4];
59 typedef v3f boxf[2];
60
61 #define CXR_EPSILON 0.001
62 #define CXR_PLANE_SIMILARITY_MAX 0.998
63 #define CXR_BIG_NUMBER 1e300
64 #define CXR_INTERIOR_ANGLE_MAX 0.998
65 #define CXR_API
66 #define CXR_DIRTY_OPTIMISATION 1
67 #define CXR_DEBUG_WRITE_MESH 1
68 #define CXR_DEBUG_ALLOCATORS 1
69 #define CXR_MANIFOLD_DEBUG 0
70
71 #define CXR_ERROR_DEGEN_IMPLICIT 0x1
72 #define CXR_ERROR_BAD_MANIFOLD 0x2
73 #define CXR_ERROR_NO_SOLIDS 0x4
74
75 #include "cxr_math.h"
76 #include "cxr_mem.h"
77
78 // Utility
79 // ============================================
80
81 static v4f colours_random[] =
82 {
83 { 0.863, 0.078, 0.235, 0.4 },
84 { 0.000, 0.980, 0.604, 0.4 },
85 { 0.118, 0.565, 1.000, 0.4 },
86 { 0.855, 0.439, 0.839, 0.4 },
87 { 0.824, 0.412, 0.118, 0.4 },
88 { 0.125, 0.698, 0.667, 0.4 },
89 { 0.541, 0.169, 0.886, 0.4 },
90 { 1.000, 0.843, 0.000, 0.4 }
91 };
92
93 static int cxr_range(int x, int bound)
94 {
95 if( x < 0 )
96 x += bound * (x/bound + 1);
97
98 return x % bound;
99 }
100
101 struct cxr_input_mesh
102 {
103 v3f *vertices;
104
105 struct cxr_edge
106 {
107 i32 i0, i1;
108 i32 freestyle;
109 }
110 *edges;
111
112 struct cxr_input_loop
113 {
114 i32 index,
115 edge_index;
116 v2f uv;
117 }
118 *loops;
119
120 struct cxr_polygon
121 {
122 i32 loop_start, loop_total;
123 v3f normal;
124 v3f center;
125 i32 material_id; // -1: interior material
126 }
127 *polys;
128
129 struct cxr_material
130 {
131 i32 res[2];
132 const char *vmt_path;
133 }
134 *materials;
135
136 i32 poly_count,
137 vertex_count,
138 edge_count,
139 loop_count,
140 material_count;
141 };
142
143 struct cxr_loop
144 {
145 i32 poly_left,
146 poly_right,
147 edge_index,
148 index;
149 v2f uv;
150 };
151
152 struct cxr_solid
153 {
154 i32 *polygons;
155 };
156
157 struct cxr_mesh
158 {
159 struct cxr_auto_buffer
160 edges,
161 loops,
162 polys;
163 };
164
165 struct cxr_texinfo
166 {
167 v3f uaxis, vaxis;
168 v2f offset, scale;
169 double winding;
170 };
171
172 // simple VDF writing interface
173 struct cxr_vdf
174 {
175 FILE *fp;
176 i32 level;
177 };
178
179 static struct cxr_settings
180 {
181 i32 debug,
182 lightmap_scale;
183
184 double light_scale;
185 }
186 cxr_settings = {
187 .debug = 0,
188 .lightmap_scale = 12,
189
190 .light_scale = 1.0/5.0
191 };
192
193 static struct cxr_context
194 {
195 i32 brush_count,
196 entity_count,
197 face_count;
198
199 double scale_factor;
200 double offset_z;
201 }
202 cxr_context = {
203 .brush_count = 0,
204 .entity_count = 0,
205 .face_count = 0,
206 .scale_factor = 32.0,
207 .offset_z = 0.0
208 };
209
210 static struct cxr_material cxr_nodraw = {
211 .res = { 512, 512 },
212 .vmt_path = "tools/toolsnodraw"
213 };
214
215 // Debugging callbacks
216 // =============================================================================
217
218 static v4f colour_error = { 1.0f, 0.0f, 0.0f, 1.0f };
219 static v4f colour_face_graph = { 1.0f, 1.0f, 1.0f, 0.03f };
220 static v4f colour_success = { 0.0f, 1.0f, 0.0f, 1.0f };
221
222 static void (*cxr_log_func)(const char *str);
223 static void (*cxr_line_func)( v3f p0, v3f p1, v4f colour );
224
225 static void cxr_log( const char *fmt, ... )
226 {
227 char buf[512];
228
229 va_list args;
230 va_start( args, fmt );
231 vsnprintf( buf, sizeof(buf)-1, fmt, args );
232 va_end(args);
233
234 if( cxr_log_func )
235 cxr_log_func( buf );
236
237 fputs(buf,stdout);
238 }
239
240 static void cxr_debug_line( v3f p0, v3f p1, v4f colour )
241 {
242 if( cxr_line_func )
243 cxr_line_func( p0, p1, colour );
244 }
245
246 static void cxr_debug_box( v3f p0, double sz, v4f colour )
247 {
248 v3f a,b,c,d,
249 a1,b1,c1,d1;
250 v3_add(p0, (v3f){-sz,-sz,-sz}, a);
251 v3_add(p0, (v3f){-sz, sz,-sz}, b);
252 v3_add(p0, (v3f){ sz, sz,-sz}, c);
253 v3_add(p0, (v3f){ sz,-sz,-sz}, d);
254 v3_add(p0, (v3f){-sz,-sz,sz}, a1);
255 v3_add(p0, (v3f){-sz, sz,sz}, b1);
256 v3_add(p0, (v3f){ sz, sz,sz}, c1);
257 v3_add(p0, (v3f){ sz,-sz,sz}, d1);
258
259 cxr_debug_line( a,b, colour );
260 cxr_debug_line( b,c, colour );
261 cxr_debug_line( c,d, colour );
262 cxr_debug_line( d,a, colour );
263 cxr_debug_line( a1,b1, colour );
264 cxr_debug_line( b1,c1, colour );
265 cxr_debug_line( c1,d1, colour );
266 cxr_debug_line( d1,a1, colour );
267 cxr_debug_line( a,a1, colour );
268 cxr_debug_line( b,b1, colour );
269 cxr_debug_line( c,c1, colour );
270 cxr_debug_line( d,d1, colour );
271 }
272
273 static void cxr_debug_arrow( v3f p0, v3f p1, v3f normal, double sz, v4f colour )
274 {
275 v3f dir, tan, p2, p3;
276 v3_sub(p1,p0,dir);
277 v3_normalize(dir);
278
279 v3_cross(dir,normal,tan);
280 v3_muladds( p1,dir, -sz, p2 );
281 v3_muladds( p2,tan,sz,p3 );
282 cxr_debug_line( p1, p3, colour );
283 v3_muladds( p2,tan,-sz,p3 );
284 cxr_debug_line( p1, p3, colour );
285 cxr_debug_line( p0, p1, colour );
286 }
287
288 // Public API
289 // =========================================================================
290
291 CXR_API void cxr_context_reset(void)
292 {
293 cxr_context.brush_count = 0;
294 cxr_context.entity_count = 0;
295 cxr_context.face_count = 0;
296 cxr_context.offset_z = 0.0;
297 cxr_context.scale_factor = 32.0;
298 }
299
300 CXR_API void cxr_set_offset(double offset)
301 {
302 cxr_context.offset_z = offset;
303 }
304
305 CXR_API void cxr_set_scale_factor(double scale)
306 {
307 cxr_context.scale_factor = scale;
308 }
309
310 CXR_API struct cxr_vdf *cxr_vdf_open(const char *path)
311 {
312 struct cxr_vdf *vdf = malloc(sizeof(struct cxr_vdf));
313
314 vdf->level = 0;
315 vdf->fp = fopen( path, "w" );
316
317 if( !vdf->fp )
318 {
319 free( vdf );
320 return NULL;
321 }
322
323 return vdf;
324 }
325
326 CXR_API void cxr_vdf_close(struct cxr_vdf *vdf)
327 {
328 fclose( vdf->fp );
329 }
330
331 CXR_API void cxr_vdf_put(struct cxr_vdf *vdf, const char *str)
332 {
333 for( int i=0; i<vdf->level; i++ )
334 fputs( " ", vdf->fp );
335
336 fputs( str, vdf->fp );
337 }
338
339 static void cxr_vdf_printf( struct cxr_vdf *vdf, const char *fmt, ... )
340 {
341 cxr_vdf_put(vdf,"");
342
343 va_list args;
344 va_start( args, fmt );
345 vfprintf( vdf->fp, fmt, args );
346 va_end(args);
347 }
348
349 CXR_API void cxr_vdf_node(struct cxr_vdf *vdf, const char *str)
350 {
351 cxr_vdf_put( vdf, str );
352 putc( (u8)'\n', vdf->fp );
353 cxr_vdf_put( vdf, "{\n" );
354
355 vdf->level ++;
356 }
357
358 CXR_API void cxr_vdf_edon(struct cxr_vdf *vdf)
359 {
360 vdf->level --;
361 cxr_vdf_put( vdf, "}\n" );
362 }
363
364 CXR_API void cxr_vdf_kv(struct cxr_vdf *vdf, const char *strk, const char *strv)
365 {
366 cxr_vdf_printf( vdf, "\"%s\" \"%s\"\n", strk, strv );
367 }
368
369 static void cxr_vdf_ki32(struct cxr_vdf *vdf, const char *strk, i32 val)
370 {
371 cxr_vdf_printf( vdf, "\"%s\" \"%d\"\n", strk, val );
372 }
373 static void cxr_vdf_kdouble(struct cxr_vdf *vdf, const char *strk, double val)
374 {
375 cxr_vdf_printf( vdf, "\"%s\" \"%f\"\n", strk, val );
376 }
377 static void cxr_vdf_kaxis(struct cxr_vdf *vdf, const char *strk, v3f normal, double offset, double scale)
378 {
379 cxr_vdf_printf( vdf, "\"%s\" \"[%f %f %f %f] %f\"\n", strk, normal[0],normal[1],normal[2],offset,scale );
380 }
381 static void cxr_vdf_kv3f(struct cxr_vdf *vdf, const char *strk, v3f v)
382 {
383 cxr_vdf_printf( vdf, "\"%s\" \"[%f %f %f]\"\n", strk, v[0], v[1], v[2] );
384 }
385 static void cxr_vdf_karrdouble(struct cxr_vdf *vdf, const char *strk, int id, double *doubles, int count)
386 {
387 cxr_vdf_put(vdf,"");
388 fprintf( vdf->fp, "\"%s%d\" \"", strk, id );
389 for( int i=0; i<count; i++ )
390 {
391 if( i == count-1 ) fprintf( vdf->fp, "%f", doubles[i] );
392 else fprintf( vdf->fp, "%f ", doubles[i] );
393 }
394 fprintf( vdf->fp, "\"\n" );
395 }
396 static void cxr_vdf_karrv3f(struct cxr_vdf *vdf, const char *strk, int id, v3f *vecs, int count)
397 {
398 cxr_vdf_put(vdf,"");
399 fprintf( vdf->fp, "\"%s%d\" \"", strk, id );
400 for( int i=0; i<count; i++ )
401 {
402 if( i == count-1 ) fprintf( vdf->fp, "%f %f %f", vecs[i][0], vecs[i][1], vecs[i][2] );
403 else fprintf( vdf->fp, "%f %f %f ", vecs[i][0], vecs[i][1], vecs[i][2] );
404 }
405 fprintf( vdf->fp, "\"\n" );
406 }
407 static void cxr_vdf_plane(struct cxr_vdf *vdf, const char *strk, v3f a, v3f b, v3f c )
408 {
409 cxr_vdf_printf( vdf, "\"%s\" \"(%f %f %f) (%f %f %f) (%f %f %f)\"\n",
410 strk, a[0], a[1], a[2], b[0], b[1], b[2], c[0], c[1], c[2] );
411 }
412 static void cxr_vdf_colour255(struct cxr_vdf *vdf, const char *strk, v4f colour)
413 {
414 v4f scale;
415 v4_muls( colour, 255.0, scale );
416 cxr_vdf_printf( vdf, "\"%s\" \"%d %d %d %d\"\n",strk,(int)scale[0], (int)scale[1], (int)scale[2], (int)scale[3]);
417 }
418
419 // Public API
420 // =========================================================================
421
422 static void cxr_debug_poly(struct cxr_mesh *mesh, struct cxr_polygon *poly, v3f *verts, v4f colour )
423 {
424 for( int i=0; i<poly->loop_total; i++ )
425 {
426 struct cxr_loop *loop0 = cxr_ab_ptr(&mesh->loops,poly->loop_start+i),
427 *loop1 = cxr_ab_ptr(&mesh->loops,poly->loop_start+cxr_range(i+1,poly->loop_total));
428
429 v3f p0, p1;
430
431 v3_lerp( verts[loop0->index], poly->center, 0.02, p0 );
432 v3_lerp( verts[loop1->index], poly->center, 0.02, p1 );
433
434 cxr_debug_arrow( p0, p1, poly->normal, 0.05, colour );
435 }
436
437 v3f nrm0;
438 v3_muladds( poly->center, poly->normal, 0.3, nrm0 );
439
440 cxr_debug_line( poly->center, nrm0, colour );
441 }
442
443 static void cxr_debug_mesh(struct cxr_mesh *mesh, v3f *verts, v4f colour )
444 {
445 for( int i=0; i<mesh->polys.count; i++ )
446 {
447 struct cxr_polygon *poly = cxr_ab_ptr(&mesh->polys,i);
448 cxr_debug_poly( mesh, poly, verts, colour );
449 }
450 }
451
452 static struct cxr_mesh *cxr_alloc_mesh(int edge_count, int loop_count, int poly_count )
453 {
454 struct cxr_mesh *mesh = malloc(sizeof(struct cxr_mesh));
455 cxr_ab_init(&mesh->edges, sizeof(struct cxr_edge), edge_count);
456 cxr_ab_init(&mesh->loops, sizeof(struct cxr_loop), loop_count);
457 cxr_ab_init(&mesh->polys, sizeof(struct cxr_polygon), poly_count);
458 return mesh;
459 }
460
461 static void cxr_free_mesh(struct cxr_mesh *mesh)
462 {
463 cxr_ab_free(&mesh->edges);
464 cxr_ab_free(&mesh->loops);
465 cxr_ab_free(&mesh->polys);
466 free(mesh);
467 }
468
469 // Rebuilds edge data and reallocates
470 //
471 static void cxr_mesh_clean_edges(struct cxr_mesh *mesh)
472 {
473 struct cxr_auto_buffer new_edges;
474 cxr_ab_init( &new_edges, sizeof(struct cxr_edge), mesh->edges.count );
475
476 for( int i=0; i<mesh->polys.count; i++ )
477 {
478 struct cxr_polygon *poly = cxr_ab_ptr(&mesh->polys,i);
479 for( int j=0; j<poly->loop_total; j++ )
480 {
481 struct cxr_loop
482 *lp0 = cxr_ab_ptr(&mesh->loops,poly->loop_start+j),
483 *lp1 = cxr_ab_ptr(&mesh->loops,poly->loop_start+cxr_range(j+1,poly->loop_total));
484
485 int i0 = cxr_min(lp0->index, lp1->index),
486 i1 = cxr_max(lp0->index, lp1->index);
487
488 // See if edge exists before adding it
489 for( int k=0; k<new_edges.count; k++ )
490 {
491 struct cxr_edge *edge = cxr_ab_ptr(&new_edges,k);
492
493 if( edge->i0 == i0 && edge->i1 == i1 )
494 {
495 lp0->edge_index = k;
496 goto IL_EDGE_CREATED;
497 }
498 }
499
500 int orig_edge_id = lp0->edge_index;
501 lp0->edge_index = new_edges.count;
502
503 struct cxr_edge edge = { i0, i1 };
504 // --- ! ---
505 // Copy extra information (sharp,freestyle.. etc) here!
506
507 if( orig_edge_id < mesh->edges.count )
508 {
509 struct cxr_edge *orig_edge = cxr_ab_ptr( &mesh->edges, orig_edge_id );
510 edge.freestyle = orig_edge->freestyle;
511 }
512 else
513 {
514 edge.freestyle = 0;
515 }
516
517 // --- ! ---
518 cxr_ab_push( &new_edges, &edge );
519
520 IL_EDGE_CREATED:;
521 }
522 }
523
524 cxr_ab_free( &mesh->edges );
525 mesh->edges = new_edges;
526 }
527
528 // Remove 0-length faces from mesh and correct loops
529 //
530 static void cxr_mesh_clean_faces(struct cxr_mesh *mesh)
531 {
532 struct cxr_auto_buffer loops_new;
533 cxr_ab_init( &loops_new, sizeof(struct cxr_loop), mesh->loops.count );
534
535 int new_length=0;
536 for( int i=0; i<mesh->polys.count; i++ )
537 {
538 struct cxr_polygon *src = cxr_ab_ptr(&mesh->polys,i),
539 *dst = cxr_ab_ptr(&mesh->polys,new_length);
540
541 if( src->loop_total > 0 )
542 {
543 int src_start = src->loop_start,
544 src_total = src->loop_total;
545
546 *dst = *src;
547 dst->loop_start = loops_new.count;
548
549 for( int j=0; j<src_total; j++ )
550 {
551 struct cxr_loop *loop = cxr_ab_ptr(&mesh->loops,src_start+j),
552 *ldst = cxr_ab_ptr(&loops_new,dst->loop_start+j);
553 *ldst = *loop;
554 ldst->poly_left = new_length;
555 }
556
557 loops_new.count += src_total;
558 new_length ++;
559 }
560 }
561
562 cxr_ab_free( &mesh->loops );
563 mesh->loops = loops_new;
564 mesh->polys.count = new_length;
565 }
566
567 static i32 *cxr_mesh_link_loops(struct cxr_mesh *mesh)
568 {
569 i32 *polygon_edge_map = malloc(mesh->edges.count*2 *sizeof(i32));
570
571 for( int i = 0; i < mesh->edges.count*2; i ++ )
572 polygon_edge_map[i] = -1;
573
574 for( int i = 0; i < mesh->polys.count; i ++ )
575 {
576 struct cxr_polygon *poly = cxr_ab_ptr(&mesh->polys, i);
577
578 for( int j = 0; j < poly->loop_total; j ++ )
579 {
580 struct cxr_loop *loop = cxr_ab_ptr(&mesh->loops, poly->loop_start+j);
581 loop->poly_left = i;
582
583 for( int k = 0; k < 2; k ++ )
584 {
585 i32 *edge = &polygon_edge_map[loop->edge_index*2+k];
586
587 if( *edge == -1 )
588 {
589 *edge = i;
590 break;
591 }
592 }
593 }
594 }
595 for( int i = 0; i < mesh->polys.count; i ++ )
596 {
597 struct cxr_polygon *poly = cxr_ab_ptr(&mesh->polys,i);
598
599 for( int j = 0; j < poly->loop_total; j ++ )
600 {
601 struct cxr_loop *loop = cxr_ab_ptr(&mesh->loops,poly->loop_start+j);
602
603 i32 *face_map = &polygon_edge_map[loop->edge_index*2];
604
605 if( face_map[0] == loop->poly_left ) loop->poly_right = face_map[1];
606 else loop->poly_right = face_map[0];
607 }
608 }
609
610 return polygon_edge_map;
611 }
612
613 // Add polygon to mesh based on loop array
614 static struct cxr_polygon *cxr_create_poly( struct cxr_mesh *mesh, v3f *vertices, struct cxr_loop poly[],
615 int len, int start, int max )
616 {
617 if( len < 3 )
618 {
619 cxr_log( "tried to add new poly with length %d!\n", len );
620
621 if( len >= 2 )
622 {
623 for( int j=0; j<len; j++ )
624 {
625 int i0 = poly[j].index,
626 i1 = poly[cxr_range(j+1,len)].index;
627 cxr_debug_line( vertices[i0], vertices[i1], colour_error );
628 }
629 }
630
631 return NULL;
632 }
633
634 int nface_id = mesh->polys.count;
635 struct cxr_polygon *new_face = cxr_ab_empty(&mesh->polys);
636
637 new_face->loop_start = mesh->loops.count;
638 new_face->loop_total = len;
639 new_face->material_id = -1;
640
641 // Calculate normal and center
642 v3_zero( new_face->center );
643
644 for( int j=0; j<len; j++ )
645 {
646 int i0 = poly[cxr_range(start+j,max)].index;
647 struct cxr_loop *new_loop = cxr_ab_empty(&mesh->loops);
648
649 new_loop->poly_left = nface_id;
650 new_loop->poly_right = -1;
651 new_loop->index = i0;
652 new_loop->edge_index = 0;
653 v2_zero(new_loop->uv);
654
655 v3_add( new_face->center, vertices[new_loop->index], new_face->center );
656 }
657 v3_divs( new_face->center, new_face->loop_total, new_face->center );
658
659 struct cxr_loop *lp0 = cxr_ab_ptr( &mesh->loops, new_face->loop_start ),
660 *lp1 = cxr_ab_ptr( &mesh->loops, new_face->loop_start+1 ),
661 *lp2 = cxr_ab_ptr( &mesh->loops, new_face->loop_start+2 );
662
663 tri_normal( vertices[lp0->index], vertices[lp1->index], vertices[lp2->index], new_face->normal );
664
665 return cxr_ab_ptr(&mesh->polys, nface_id);
666 }
667
668 // Get the 'next' mesh island
669 //
670 // Returns NULL if there is only one island
671 static struct cxr_mesh *cxr_pull_island(struct cxr_mesh *mesh)
672 {
673 free(cxr_mesh_link_loops(mesh));
674
675 int *island_current = malloc(mesh->polys.count*sizeof(int)),
676 island_len = 1,
677 loop_count = 0,
678 last_count;
679
680 island_current[0] = 0;
681
682 IL_ISLAND_REPEAT:
683 last_count = island_len;
684
685 for( int i=0; i<island_len; i++ )
686 {
687 struct cxr_polygon *poly = cxr_ab_ptr(&mesh->polys,island_current[i]);
688
689 for( int j=0; j<poly->loop_total; j++ )
690 {
691 struct cxr_loop *loop = cxr_ab_ptr(&mesh->loops, poly->loop_start+j);
692
693 if( loop->poly_right != -1 )
694 {
695 int face_present = 0;
696
697 for( int k=0; k<island_len; k++ )
698 {
699 if( island_current[k] == loop->poly_right )
700 {
701 face_present = 1;
702 break;
703 }
704 }
705
706 if( !face_present )
707 {
708 island_current[ island_len ++ ] = loop->poly_right;
709 }
710 }
711 }
712 }
713
714 if( island_len > last_count )
715 goto IL_ISLAND_REPEAT;
716
717 if( island_len == mesh->polys.count )
718 {
719 free( island_current );
720 return NULL;
721 }
722
723 for( int i=0; i<island_len; i++ )
724 {
725 struct cxr_polygon *poly = cxr_ab_ptr(&mesh->polys, island_current[i]);
726 loop_count += poly->loop_total;
727 }
728
729 struct cxr_mesh *newmesh = cxr_alloc_mesh( mesh->edges.count, loop_count, island_len );
730
731 for( int i=0; i<island_len; i++ )
732 {
733 struct cxr_polygon *src = cxr_ab_ptr(&mesh->polys, island_current[i]);
734 struct cxr_polygon *dst = cxr_ab_ptr(&newmesh->polys, i);
735
736 *dst = *src;
737 dst->loop_start = newmesh->loops.count;
738
739 for( int j=0; j<src->loop_total; j++ )
740 {
741 struct cxr_loop *lsrc = cxr_ab_ptr(&mesh->loops, src->loop_start+j),
742 *ldst = cxr_ab_ptr(&newmesh->loops, dst->loop_start+j);
743
744 *ldst = *lsrc;
745 ldst->poly_left = i;
746 ldst->poly_right = -1;
747 }
748
749 newmesh->loops.count += src->loop_total;
750 src->loop_total = -1;
751 }
752
753 newmesh->polys.count = island_len;
754 newmesh->edges.count = mesh->edges.count;
755 memcpy(cxr_ab_ptr(&newmesh->edges,0), cxr_ab_ptr(&mesh->edges,0), mesh->edges.count*sizeof(struct cxr_edge));
756
757 cxr_mesh_clean_faces(mesh);
758 cxr_mesh_clean_edges(mesh);
759 cxr_mesh_clean_edges(newmesh);
760 free( island_current );
761
762 return newmesh;
763 }
764
765 // Return best availible solid from mesh, and patch existing mesh to fill the gap
766 // creted by it.
767 //
768 // Returns NULL if shape is already convex or empty
769 // Destroys edge data!
770 static struct cxr_mesh *cxr_pull_best_solid(
771 struct cxr_mesh *mesh,
772 struct cxr_auto_buffer *vert_buffer,
773 int preserve_hot_edges,
774 u32 *error )
775 {
776 v3f *vertices = cxr_ab_ptr( vert_buffer, 0 );
777
778 i32 *polygon_edge_map = cxr_mesh_link_loops(mesh);
779
780 for( int i=0; i<mesh->edges.count*2; i++ )
781 if( polygon_edge_map[i] == -1 )
782 {
783 cxr_log( "non-manifold edges are in the mesh; implicit internal geometry does not have full support\n" );
784 free(polygon_edge_map);
785 return NULL;
786 }
787
788 int *vertex_tagged = malloc( vert_buffer->count*sizeof(int) );
789 int *edge_tagged = malloc( mesh->edges.count*sizeof(int) );
790
791 for( int i=0; i<mesh->edges.count; i++ )
792 {
793 struct cxr_polygon *polya = cxr_ab_ptr(&mesh->polys, polygon_edge_map[i*2+0]),
794 *polyb = cxr_ab_ptr(&mesh->polys, polygon_edge_map[i*2+1]);
795 v4f planeb;
796 normal_to_plane(polyb->normal, polyb->center, planeb);
797
798 edge_tagged[i] = 0;
799 for( int j=0; j<polya->loop_total; j++ )
800 {
801 struct cxr_loop *loop = cxr_ab_ptr(&mesh->loops, polya->loop_start+j);
802 if( plane_polarity( planeb, vertices[loop->index] ) > 0.001 ||
803 v3_dot(polya->normal,polyb->normal) > CXR_PLANE_SIMILARITY_MAX )
804 {
805 edge_tagged[i] = 1;
806 break;
807 }
808 }
809 }
810
811 // Tag 'reflex' vertices
812 int *connected_planes = malloc(mesh->polys.count*sizeof(int));
813
814 for( int i=0; i<vert_buffer->count; i++ )
815 {
816 vertex_tagged[i]=0;
817
818 int num_connected = 0;
819 // Create a list of polys that ref this vert
820 for( int j=0; j<mesh->polys.count; j++ )
821 {
822 struct cxr_polygon *poly = cxr_ab_ptr(&mesh->polys,j);
823 for( int k=0; k<poly->loop_total; k++ )
824 {
825 struct cxr_loop *loop = cxr_ab_ptr(&mesh->loops,poly->loop_start+k);
826 if( loop->index == i )
827 {
828 connected_planes[num_connected ++] = j;
829 break;
830 }
831 }
832 }
833 // Check all combinations for a similar normal
834 for( int j=0; j<num_connected-1; j++ )
835 {
836 for( int k=j+1; k<num_connected; k++ )
837 {
838 struct cxr_polygon *polyj = cxr_ab_ptr(&mesh->polys,connected_planes[j]);
839 struct cxr_polygon *polyk = cxr_ab_ptr(&mesh->polys,connected_planes[k]);
840
841 if( v3_dot(polyj->normal, polyk->normal) > CXR_PLANE_SIMILARITY_MAX )
842 goto IL_TAG_VERT;
843 }
844 }
845
846 // Check if all connected planes not are:
847 // - bounded by other planes
848 // - or coplanar
849
850 for( int j=0; j<num_connected; j++ )
851 for( int k=j+1; k<num_connected; k++ )
852 {
853 struct cxr_polygon *jpoly = cxr_ab_ptr(&mesh->polys, connected_planes[j]),
854 *kpoly = cxr_ab_ptr(&mesh->polys, connected_planes[k]);
855 v4f plane;
856 normal_to_plane( kpoly->normal, kpoly->center, plane );
857 for( int l=0; l<jpoly->loop_total; l++ )
858 {
859 struct cxr_loop *loop = cxr_ab_ptr(&mesh->loops, jpoly->loop_start+l);
860 if( plane_polarity( plane, vertices[loop->index] ) > 0.001 )
861 goto IL_TAG_VERT;
862 }
863 }
864
865 goto IL_TAG_NEXT_VERT;
866 IL_TAG_VERT: vertex_tagged[i] = 1;
867 IL_TAG_NEXT_VERT:;
868 }
869
870 free( connected_planes );
871
872 // Connect all marked verts that share an edge
873 // - We must take care not to completely isolate
874 // a polygon with marked edges all around it
875
876 int *hot_edge = malloc(mesh->edges.count*sizeof(int));
877 for( int i=0; i< mesh->edges.count; i++ )
878 hot_edge[i] = 0;
879
880 for( int i=0; i<mesh->polys.count; i ++ )
881 {
882 struct cxr_polygon *poly = cxr_ab_ptr(&mesh->polys,i);
883 int not_tagged = -1,
884 tag_count = 0;
885
886 for( int j=0; j<poly->loop_total; j++ )
887 {
888 struct cxr_loop *loop = cxr_ab_ptr(&mesh->loops, poly->loop_start+j);
889
890 if( !edge_tagged[ loop->edge_index ] )
891 {
892 if( not_tagged == -1 )
893 not_tagged = loop->edge_index;
894 else
895 goto IL_SKIP_NO_HOT_EDGE;
896 }
897 }
898
899 if( not_tagged != -1 )
900 hot_edge[not_tagged]=1;
901
902 IL_SKIP_NO_HOT_EDGE:;
903 }
904
905 // Connect edges that have verts tagged, but is not a hot edge
906 for( int i=0; i<mesh->edges.count; i ++ )
907 {
908 if( hot_edge[i] && preserve_hot_edges ) continue;
909
910 struct cxr_edge *edge = cxr_ab_ptr(&mesh->edges,i);
911 if( vertex_tagged[edge->i0] && vertex_tagged[edge->i1] )
912 edge_tagged[i] = 1;
913 }
914
915
916 for( int i=0; i<vert_buffer->count; i++ )
917 if( vertex_tagged[i] )
918 cxr_debug_box( vertices[i], 0.03, (v4f){0.0,0.0,0.0,1.0});
919
920 for( int i=0; i < mesh->edges.count; i++ )
921 {
922 struct cxr_edge *edge = cxr_ab_ptr( &mesh->edges, i );
923 if( edge_tagged[i] )
924 cxr_debug_line( vertices[ edge->i0 ], vertices[ edge->i1 ], (v4f){0.0,0.0,0.0,1.0});
925
926 if( hot_edge[i] )
927 cxr_debug_line( vertices[ edge->i0 ], vertices[ edge->i1 ], (v4f){0.0,1.0,1.0,1.0});
928 }
929
930
931 // count regions
932 int *faces_tagged = malloc(mesh->polys.count*sizeof(int));
933 for( int i=0; i<mesh->polys.count; i++ )
934 faces_tagged[i] = -1;
935
936 int *solid_buffer = malloc( mesh->polys.count*sizeof(int) );
937 int solid_buffer_len = 0;
938 struct csolid
939 {
940 int start,count,edge_count;
941 v3f center;
942 }
943 *candidates = malloc( mesh->polys.count *sizeof(struct csolid) );
944 int candidate_count = 0;
945
946 struct tedge
947 {
948 int i0, i1;
949 }
950 *edge_references = malloc( mesh->edges.count *sizeof(struct tedge) );
951
952 for( int i=0; i<mesh->polys.count; i++ )
953 {
954 if( faces_tagged[i] != -1 ) continue;
955 faces_tagged[i] = i;
956
957 int *solid = &solid_buffer[ solid_buffer_len ];
958 int solid_len = 0;
959
960 solid[solid_len++] = i;
961
962 int search_start = 0;
963
964 // Iterative search that connects regions of planes governed by rules:
965 // - edge can add other face if the edge has less than two reflexes
966 // - the face can no longer be used in future searches
967
968 IL_SEARCH_CONTINUE:;
969
970 int changed = 0;
971 for( int j=search_start; j<solid_len; j++ )
972 {
973 struct cxr_polygon *poly = cxr_ab_ptr(&mesh->polys, solid[j]);
974
975 for( int k=0; k<poly->loop_total; k++ )
976 {
977 struct cxr_loop *loop = cxr_ab_ptr(&mesh->loops, poly->loop_start+k);
978 struct cxr_edge *edge = cxr_ab_ptr(&mesh->edges, loop->edge_index );
979
980 if( faces_tagged[ loop->poly_right ] == -1 )
981 {
982 if( !edge_tagged[loop->edge_index] )
983 {
984 // TODO(harry):
985 //
986 // Need to look ahead 1 step to make sure he does not want
987 // to add any more planes that are coplanar with some of
988 // our existing group
989 //
990 // This can sort out SOME invalid configs, but not all.
991 // It would be nice to find a more robust clustering algorithm for this.
992 //
993
994 struct cxr_polygon *poly_to_add = cxr_ab_ptr(&mesh->polys, loop->poly_right );
995 for( int l=0; l < poly_to_add->loop_total; l++ )
996 {
997 struct cxr_loop *loop1 = cxr_ab_ptr(&mesh->loops, poly_to_add->loop_start+l );
998 struct cxr_polygon *future_face = cxr_ab_ptr(&mesh->polys, loop1->poly_right );
999
1000 if( edge_tagged[ loop1->edge_index ] || loop1->poly_right == loop->poly_right )
1001 goto IL_SKIP_SIMILAR_PLANES;
1002
1003 for( int m=0; m<solid_len; m++ )
1004 if( solid[m] == loop1->poly_right )
1005 goto IL_SKIP_SIMILAR_PLANES;
1006
1007 for( int m=0; m<solid_len; m++ )
1008 {
1009 struct cxr_polygon *polym = cxr_ab_ptr(&mesh->polys,solid[m]);
1010 if( v3_dot( polym->normal,future_face->normal) > CXR_PLANE_SIMILARITY_MAX)
1011 goto IL_SKIP_PLANE_ADD;
1012 }
1013
1014 IL_SKIP_SIMILAR_PLANES:;
1015 }
1016
1017 solid[ solid_len ++ ] = loop->poly_right;
1018 faces_tagged[ loop->poly_right ] = i;
1019 changed = 1;
1020 }
1021
1022 IL_SKIP_PLANE_ADD:;
1023 }
1024 }
1025 }
1026 search_start = solid_len;
1027 if(changed)
1028 goto IL_SEARCH_CONTINUE;
1029
1030 // The current method can create some invalid configurations
1031 // filter those out that dont work and un-tag the faces
1032 for( int j=0; j<solid_len-1; j++ )
1033 {
1034 for( int k=j+1; k<solid_len; k++ )
1035 {
1036 struct cxr_polygon *polyj = cxr_ab_ptr(&mesh->polys, solid[j]),
1037 *polyk = cxr_ab_ptr(&mesh->polys, solid[k]);
1038
1039 if( v3_dot( polyj->normal, polyk->normal ) > CXR_PLANE_SIMILARITY_MAX )
1040 {
1041 for( int l=0; l<solid_len; l++ )
1042 faces_tagged[ solid[l] ] = -1;
1043
1044 goto IL_CANCEL_SOLID;
1045 }
1046 }
1047 }
1048
1049 // Add entry
1050 struct csolid *csolid = &candidates[candidate_count ++];
1051 csolid->start = solid_buffer_len;
1052 csolid->count = solid_len;
1053 csolid->edge_count = 0;
1054
1055 v3_zero( csolid->center );
1056 for( int j=0; j<solid_len; j++ )
1057 {
1058 struct cxr_polygon *polyj = cxr_ab_ptr(&mesh->polys, solid[j]);
1059 v3_add( polyj->center, csolid->center, csolid->center );
1060 csolid->edge_count += polyj->loop_total;
1061 }
1062 v3_divs( csolid->center, solid_len, csolid->center );
1063
1064 solid_buffer_len += solid_len;
1065
1066 IL_CANCEL_SOLID:;
1067 }
1068
1069 free( edge_references );
1070
1071 // Create all candidates who have one or less non-manifolds edges
1072 // Loop each candidate, determine the manifold, and pick the best one
1073
1074 struct csolid *best_solid = NULL;
1075 int fewest_manifold_splits = INT32_MAX;
1076
1077 struct cxr_loop *best_manifold = malloc( mesh->loops.count *sizeof(struct cxr_loop) );
1078 int *best_manifold_splits = malloc( mesh->loops.count *sizeof(int) );
1079 int best_manifold_len = 0;
1080 int max_solid_faces = 0;
1081
1082 int *edge_list = malloc( mesh->edges.count *sizeof(int) );
1083 int *edge_lefts = malloc( mesh->edges.count *sizeof(int) );
1084 struct cxr_loop *manifold = malloc(mesh->edges.count*2*sizeof(struct cxr_loop));
1085 int *splits = malloc(mesh->edges.count*2*sizeof(int));
1086
1087 for( int i=0; i<candidate_count; i++ )
1088 {
1089 struct csolid *solid = &candidates[i];
1090 max_solid_faces = cxr_max(max_solid_faces,solid->count);
1091
1092 if( solid->count <= 2 )
1093 continue;
1094
1095 int init_reverse = 0;
1096 int unique_edge_count = 0;
1097
1098 for( int j=0; j<solid->count; j++ )
1099 {
1100 struct cxr_polygon *poly = cxr_ab_ptr(&mesh->polys, solid_buffer[solid->start+j]);
1101
1102 for( int k=0; k<poly->loop_total; k++ )
1103 {
1104 struct cxr_loop *loop = cxr_ab_ptr(&mesh->loops, poly->loop_start+k);
1105
1106 for( int l=0; l<unique_edge_count; l++ )
1107 if( edge_list[l] == loop->edge_index )
1108 goto IL_EDGE_ALREADY_PRESENT;
1109
1110 // Check if right edge references a polygon that is not
1111 // present inside the current solid candidate
1112 for( int l=0; l<solid->count; l++ )
1113 if( loop->poly_right == solid_buffer[solid->start+l] )
1114 goto IL_EDGE_ALREADY_PRESENT;
1115
1116 edge_list[ unique_edge_count ] = loop->edge_index;
1117 edge_lefts[ unique_edge_count ] = loop->poly_left;
1118
1119 if( unique_edge_count == 0 )
1120 {
1121 struct cxr_edge *edgeptr = cxr_ab_ptr(&mesh->edges, loop->edge_index);
1122 if( edgeptr->i1 == loop->index )
1123 init_reverse = 1;
1124 }
1125
1126 unique_edge_count ++;
1127 IL_EDGE_ALREADY_PRESENT:;
1128 }
1129 }
1130
1131 // This solid is already fully connected
1132 if( unique_edge_count == 0 )
1133 continue;
1134
1135 // Link edges together to create new manifold
1136 // Corners are created when two edges share a polygon face
1137 // This way we can split it into regions
1138
1139 for( int j=0; j<vert_buffer->count; j++ )
1140 vertex_tagged[j] = -1;
1141
1142 // Start with a loop edge which was tagged
1143 struct cxr_edge *current = cxr_ab_ptr(&mesh->edges, edge_list[0]);
1144
1145 int endpt = (!init_reverse)? current->i0: current->i1,
1146 start = endpt,
1147 curface = edge_lefts[0];
1148
1149 int manifold_len = 0;
1150 int split_count = 0;
1151
1152 IL_MANIFOLD_CONTINUE:
1153 for( int j=0; j<unique_edge_count; j++ )
1154 {
1155 struct cxr_edge *other = cxr_ab_ptr(&mesh->edges, edge_list[j]);
1156 if( other == current )
1157 continue;
1158
1159 if( other->i0 == endpt || other->i1 == endpt )
1160 {
1161 current = other;
1162 int lastpt = endpt;
1163
1164 if( other->i0 == endpt ) endpt = current->i1;
1165 else endpt = current->i0;
1166
1167 if( curface==edge_lefts[j] )
1168 {
1169 splits[ manifold_len ] = 1;
1170 split_count ++;
1171 }
1172 else
1173 splits[ manifold_len ] = 0;
1174
1175 // Append to intermidiary manifold
1176 manifold[ manifold_len ].edge_index = edge_list[j];
1177 manifold[ manifold_len ].poly_left = edge_lefts[j];
1178 manifold[ manifold_len ].index = lastpt;
1179 manifold[ manifold_len ].poly_right =
1180 polygon_edge_map[ edge_list[j]*2 ] == edge_lefts[j]?
1181 polygon_edge_map[ edge_list[j]*2+1 ]:
1182 polygon_edge_map[ edge_list[j]*2+0 ];
1183 manifold_len ++;
1184
1185 curface = edge_lefts[j];
1186
1187 if(endpt == start) goto IL_MANIFOLD_COMPLETE;
1188 goto IL_MANIFOLD_CONTINUE;
1189 }
1190 }
1191 cxr_log( "Failed to link manifold, count: %d\n", manifold_len );
1192
1193 for( int j=0; j<solid->count; j++ )
1194 {
1195 cxr_log( "p%d\n", solid_buffer[solid->start+j] );
1196 struct cxr_polygon *poly = cxr_ab_ptr(&mesh->polys, solid_buffer[solid->start+j]);
1197 cxr_debug_poly( mesh, poly, vertices, (v4f){0.2,0.0,0.0,1.0} );
1198 }
1199
1200 for( int j=0; j<unique_edge_count; j++ )
1201 {
1202 struct cxr_edge *uedge = cxr_ab_ptr(&mesh->edges, edge_list[j]);
1203 cxr_debug_line(vertices[uedge->i0],vertices[uedge->i1],(v4f){0.4,0.0,0.0,1.0});
1204 }
1205
1206 for( int j=0; j<manifold_len-1; j++ )
1207 {
1208 struct cxr_loop *lp0 = &manifold[j],
1209 *lp1 = &manifold[cxr_range(j+1,manifold_len)];
1210
1211 cxr_debug_line(vertices[lp0->index],vertices[lp1->index], colour_error );
1212 }
1213
1214 cxr_debug_mesh( mesh, vertices, (v4f){0.0,0.0,0.0, 0.9} );
1215 *error = CXR_ERROR_BAD_MANIFOLD;
1216
1217 free(edge_list);
1218 free(edge_lefts);
1219 free(manifold);
1220 free(splits);
1221 free(edge_tagged);
1222 free(vertex_tagged);
1223 free(hot_edge);
1224 free(faces_tagged);
1225 free(solid_buffer);
1226 free(candidates);
1227 free(best_manifold);
1228 free(best_manifold_splits);
1229 free(polygon_edge_map);
1230 return NULL;
1231
1232 IL_MANIFOLD_COMPLETE:;
1233
1234 if( manifold_len < unique_edge_count )
1235 continue;
1236 else
1237 {
1238 if( split_count < fewest_manifold_splits )
1239 {
1240 fewest_manifold_splits = split_count;
1241 best_solid = solid;
1242
1243 for( int j=0; j<manifold_len; j++ )
1244 {
1245 best_manifold[j] = manifold[j];
1246 best_manifold_splits[j] = splits[j];
1247 }
1248 best_manifold_len = manifold_len;
1249 }
1250 }
1251 }
1252
1253 free(edge_list);
1254 free(edge_lefts);
1255 free(manifold);
1256 free(splits);
1257
1258 if( max_solid_faces < 2 )
1259 {
1260 *error = CXR_ERROR_NO_SOLIDS;
1261 free(edge_tagged);
1262 free(vertex_tagged);
1263 free(hot_edge);
1264 free(faces_tagged);
1265 free(solid_buffer);
1266 free(candidates);
1267 free(best_manifold);
1268 free(best_manifold_splits);
1269 free(polygon_edge_map);
1270 return NULL;
1271 }
1272
1273 if( best_solid != NULL )
1274 {
1275 struct cxr_mesh *pullmesh =
1276 cxr_alloc_mesh( best_solid->edge_count, best_solid->edge_count, best_solid->count );
1277
1278 // Add existing faces to pullsolid, and delete from main mesh
1279 for( int i=0; i<best_solid->count; i++ )
1280 {
1281 int nface_id = pullmesh->polys.count;
1282
1283 struct cxr_polygon *exist_face = cxr_ab_ptr(&mesh->polys, solid_buffer[best_solid->start+i]);
1284 struct cxr_polygon *new_face = cxr_ab_empty(&pullmesh->polys);
1285
1286 *new_face = *exist_face;
1287 new_face->loop_start = pullmesh->loops.count;
1288
1289 for( int j=0; j<exist_face->loop_total; j++ )
1290 {
1291 struct cxr_loop *exist_loop = cxr_ab_ptr(&mesh->loops, exist_face->loop_start+j);
1292 struct cxr_loop *new_loop = cxr_ab_empty(&pullmesh->loops);
1293
1294 new_loop->index = exist_loop->index;
1295 new_loop->poly_left = nface_id;
1296 new_loop->poly_right = -1;
1297 new_loop->edge_index = 0;
1298 v2_copy( exist_loop->uv, new_loop->uv );
1299 }
1300
1301 exist_face->loop_total = -1;
1302 }
1303
1304 int new_polys = 0;
1305 int pullmesh_new_start = pullmesh->polys.count;
1306
1307 if( fewest_manifold_splits != 0 )
1308 {
1309 #if CXR_MANIFOLD_DEBUG
1310 for( int i=0; i<best_manifold_len; i++ )
1311 {
1312 int i0 = i,
1313 i1 = cxr_range(i+1,best_manifold_len);
1314
1315 cxr_debug_line( vertices[best_manifold[i0].index], vertices[best_manifold[i1].index], colour_error );
1316 if( best_manifold_splits[i] )
1317 cxr_debug_box( vertices[best_manifold[i0].index], 0.04, colour_success );
1318 }
1319 #endif
1320
1321 // This is a really strange observation, however it *seems* to apply to the kinds
1322 // of geometry we are dealing with. If the split count is odd, the manifold can be
1323 // created easily, no folding required.
1324 //
1325 // When it is even, it appears that internal implicit geometry is required, so we
1326 // need to fold the loops we create. Its really weird, but for some reason works on
1327 // the geometry rules we've defined.
1328 // TODO(harry): Find a well defined rule here.
1329
1330 int collapse_used_segments = (u32)fewest_manifold_splits & 0x1? 0: 1;
1331
1332 IL_MANIFOLD_BUILD_REPEAT:
1333
1334 for( int j=0; j<best_manifold_len; j++ )
1335 {
1336 if( best_manifold_splits[j] )
1337 {
1338 struct cxr_loop *loop = &best_manifold[j];
1339
1340 for( int k=1; k<best_manifold_len; k++ )
1341 {
1342 int index1 = cxr_range(j+k,best_manifold_len);
1343 struct cxr_loop *loop1 = &best_manifold[index1];
1344
1345 if( best_manifold_splits[index1] )
1346 {
1347 if( k==1 )
1348 break;
1349
1350 new_polys ++;
1351
1352 if( new_polys > best_manifold_len )
1353 {
1354 cxr_log( "Programming error: Too many new polys!\n" );
1355 exit(1);
1356 }
1357
1358 cxr_create_poly( pullmesh, vertices, best_manifold, k+1, j, best_manifold_len );
1359
1360 // Remove new section from manifold
1361 if( collapse_used_segments )
1362 {
1363 best_manifold_splits[j] = 0;
1364 best_manifold_splits[index1] = 0;
1365
1366 int new_length = (best_manifold_len-(k-1));
1367
1368 struct cxr_loop *new_manifold = malloc( new_length*sizeof(struct cxr_loop) );
1369 int *new_manifold_splits = malloc( new_length*sizeof(int) );
1370
1371 for( int l=0; l<new_length; l ++ )
1372 {
1373 int i_src = cxr_range( j+k+l, best_manifold_len );
1374 new_manifold[l] = best_manifold[i_src];
1375 new_manifold_splits[l] = best_manifold_splits[i_src];
1376 }
1377
1378 free( best_manifold );
1379 free( best_manifold_splits );
1380 best_manifold = new_manifold;
1381 best_manifold_splits = new_manifold_splits;
1382
1383 best_manifold_len = new_length;
1384
1385 goto IL_MANIFOLD_BUILD_REPEAT;
1386 }
1387
1388 j=j+k-1;
1389 break;
1390 }
1391 }
1392 }
1393 }
1394
1395 if( best_manifold_len && collapse_used_segments )
1396 {
1397 cxr_create_poly( pullmesh, vertices, best_manifold, best_manifold_len, 0, best_manifold_len );
1398 new_polys ++;
1399 }
1400 }
1401 else
1402 {
1403 cxr_create_poly( pullmesh, vertices, best_manifold, best_manifold_len, 0, best_manifold_len );
1404 new_polys = 1;
1405 }
1406
1407 // vert_buffer may be reallocated by the next section of code,
1408 // force a NULLref on vertices to catch any errors
1409 vertices = NULL;
1410
1411 // Implicit geometry reconstruction
1412 // If there's 3 or more planes, collide them together to see if any new
1413 // vertices need to be created on the mesh
1414 if( new_polys >= 3 )
1415 {
1416 for( int i=0; i<new_polys-2; i++ )
1417 {
1418 for( int j=i+1; j<new_polys-1; j++ )
1419 {
1420 for( int k=j+1; k<new_polys; k++ )
1421 {
1422 struct cxr_polygon *ptri = cxr_ab_ptr( &pullmesh->polys, pullmesh_new_start+i ),
1423 *ptrj = cxr_ab_ptr( &pullmesh->polys, pullmesh_new_start+j ),
1424 *ptrk = cxr_ab_ptr( &pullmesh->polys, pullmesh_new_start+k );
1425
1426 v4f planei, planej, planek;
1427 normal_to_plane(ptri->normal,ptri->center,planei);
1428 normal_to_plane(ptrj->normal,ptrj->center,planej);
1429 normal_to_plane(ptrk->normal,ptrk->center,planek);
1430
1431 v3f intersect;
1432
1433 if( plane_intersect(planei,planej,planek,intersect) )
1434 {
1435 // cxr_debug_box( intersect, 0.05, colour_error );
1436
1437 // Make sure this point is within the convex region, otherwise treat
1438 // it as a degenerate case
1439
1440 int point_valid = 1;
1441 for( int l=0; l<pullmesh->polys.count; l++ )
1442 {
1443 struct cxr_polygon *ptrl = cxr_ab_ptr(&pullmesh->polys,l);
1444 v4f planel;
1445
1446 normal_to_plane(ptrl->normal, ptrl->center, planel);
1447
1448 if( plane_polarity( planel, intersect ) > 0.01 )
1449 {
1450 cxr_log( "degen vert, planes %d, %d, %d [max:%d]\n", i,j,k, new_polys );
1451 *error = CXR_ERROR_DEGEN_IMPLICIT;
1452
1453 cxr_debug_poly( pullmesh, ptri, cxr_ab_ptr(vert_buffer,0), colours_random[3] );
1454 cxr_debug_poly( pullmesh, ptrj, cxr_ab_ptr(vert_buffer,0), colours_random[1] );
1455 cxr_debug_poly( pullmesh, ptrk, cxr_ab_ptr(vert_buffer,0), colours_random[2] );
1456
1457 point_valid = 0;
1458 break;
1459 }
1460 }
1461
1462 if( !point_valid ) continue;
1463
1464 // Extend faces to include this point
1465 int nvertid = vert_buffer->count;
1466 cxr_ab_push( vert_buffer, intersect );
1467
1468 ptrj->loop_start += 1;
1469 ptrk->loop_start += 2;
1470
1471 cxr_ab_reserve(&pullmesh->loops, 3);
1472 struct cxr_loop *lloopi = cxr_ab_empty_at(&pullmesh->loops, ptri->loop_start+ptri->loop_total),
1473 *lloopj = cxr_ab_empty_at(&pullmesh->loops, ptrj->loop_start+ptrj->loop_total),
1474 *lloopk = cxr_ab_empty_at(&pullmesh->loops, ptrk->loop_start+ptrk->loop_total);
1475
1476 lloopi->index = nvertid;
1477 lloopj->index = nvertid;
1478 lloopk->index = nvertid;
1479 lloopi->edge_index = 0; lloopj->edge_index = 0; lloopk->edge_index = 0;
1480 lloopi->poly_left = pullmesh_new_start+i;
1481 lloopj->poly_left = pullmesh_new_start+j;
1482 lloopk->poly_left = pullmesh_new_start+k;
1483 lloopi->poly_right = -1; lloopj->poly_right = -1; lloopk->poly_right = -1;
1484
1485 v2_zero(lloopi->uv);
1486 v2_zero(lloopj->uv);
1487 v2_zero(lloopk->uv);
1488
1489 ptri->loop_total ++;
1490 ptrj->loop_total ++;
1491 ptrk->loop_total ++;
1492
1493 // Adjust centers of faces
1494 v3_lerp( ptri->center, intersect, 1.0/(double)ptri->loop_total, ptri->center );
1495 v3_lerp( ptrj->center, intersect, 1.0/(double)ptrj->loop_total, ptrj->center );
1496 v3_lerp( ptrk->center, intersect, 1.0/(double)ptrk->loop_total, ptrk->center );
1497 }
1498 }
1499 }
1500 }
1501 }
1502
1503 // Copy faces from pullsolid into orig mesh
1504
1505 for( int i=0; i<new_polys; i++ )
1506 {
1507 int rface_id = mesh->polys.count;
1508
1509 struct cxr_polygon *pface = cxr_ab_ptr(&pullmesh->polys,pullmesh_new_start+i);
1510 struct cxr_polygon *rip_face = cxr_ab_empty(&mesh->polys);
1511
1512 rip_face->loop_start = mesh->loops.count;
1513 rip_face->loop_total = pface->loop_total;
1514 rip_face->material_id = -1;
1515
1516 for( int j=0; j<rip_face->loop_total; j++ )
1517 {
1518 struct cxr_loop *ploop = cxr_ab_ptr(&pullmesh->loops, pface->loop_start+pface->loop_total-j-1),
1519 *rloop = cxr_ab_empty(&mesh->loops);
1520
1521 rloop->index = ploop->index;
1522 rloop->poly_left = rface_id;
1523 rloop->poly_right = -1;
1524 rloop->edge_index = 0;
1525 v2_copy( ploop->uv, rloop->uv );
1526 }
1527
1528 v3_copy( pface->center, rip_face->center );
1529 v3_negate( pface->normal, rip_face->normal );
1530 }
1531
1532 cxr_mesh_clean_faces( mesh );
1533 cxr_mesh_clean_faces( pullmesh );
1534 cxr_mesh_clean_edges( mesh );
1535 cxr_mesh_clean_edges( pullmesh );
1536
1537 free(edge_tagged);
1538 free(vertex_tagged);
1539 free(hot_edge);
1540 free(faces_tagged);
1541 free(solid_buffer);
1542 free(candidates);
1543 free(best_manifold);
1544 free(best_manifold_splits);
1545 free(polygon_edge_map);
1546
1547 return pullmesh;
1548 }
1549
1550 free(edge_tagged);
1551 free(vertex_tagged);
1552 free(hot_edge);
1553 free(faces_tagged);
1554 free(solid_buffer);
1555 free(candidates);
1556 free(best_manifold);
1557 free(best_manifold_splits);
1558 free(polygon_edge_map);
1559
1560 return NULL;
1561 }
1562
1563 static struct cxr_mesh *cxr_to_internal_format(struct cxr_input_mesh *src, struct cxr_auto_buffer *abverts)
1564 {
1565 // Split mesh into islands
1566 struct cxr_mesh *mesh = cxr_alloc_mesh( src->edge_count, src->loop_count, src->poly_count );
1567 cxr_ab_init( abverts, sizeof(v3f), src->vertex_count );
1568
1569 // Copy input data into working mesh
1570 memcpy( cxr_ab_ptr( &mesh->edges, 0 ), src->edges, src->edge_count*sizeof(struct cxr_edge));
1571 memcpy( cxr_ab_ptr( &mesh->polys, 0 ), src->polys, src->poly_count*sizeof(struct cxr_polygon));
1572 memcpy( cxr_ab_ptr( abverts, 0 ), src->vertices, src->vertex_count*sizeof(v3f));
1573 mesh->edges.count = src->edge_count;
1574 mesh->loops.count = src->loop_count;
1575 mesh->polys.count = src->poly_count;
1576
1577 for( int i=0; i<src->loop_count; i++ )
1578 {
1579 struct cxr_loop *lp = cxr_ab_ptr(&mesh->loops,i);
1580 lp->index = src->loops[i].index;
1581 lp->edge_index = src->loops[i].edge_index;
1582 v2_copy( src->loops[i].uv, lp->uv );
1583 }
1584
1585 abverts->count = src->vertex_count;
1586
1587 return mesh;
1588 }
1589
1590 // Find farthest dot product along direction
1591 static double support_distance( v3f verts[3], v3f dir, double coef )
1592 {
1593 return cxr_maxf
1594 (
1595 coef * v3_dot( verts[0], dir ),
1596 cxr_maxf
1597 (
1598 coef * v3_dot( verts[1], dir ),
1599 coef * v3_dot( verts[2], dir )
1600 )
1601 );
1602 }
1603
1604 // Main function
1605 static void cxr_calculate_axis(
1606 struct cxr_texinfo *transform,
1607 v3f verts[3],
1608 v2f uvs[3],
1609 v2f texture_res
1610 )
1611 {
1612 v2f tT, bT; // Tangent/bitangent pairs for UV space and world
1613 v3f tW, bW;
1614
1615 v2_sub( uvs[0], uvs[1], tT );
1616 v2_sub( uvs[2], uvs[1], bT );
1617 v3_sub( verts[0], verts[1], tW );
1618 v3_sub( verts[2], verts[1], bW );
1619
1620 // Use arbitrary projection if there is no UV
1621 if( v2_length( tT ) < 0.0001 || v2_length( bT ) < 0.0001 )
1622 {
1623 v3f uaxis, normal, vaxis;
1624
1625 v3_copy( tW, uaxis );
1626 v3_normalize( uaxis );
1627
1628 v3_cross( tW, bW, normal );
1629 v3_cross( normal, uaxis, vaxis );
1630 v3_normalize( vaxis );
1631
1632 v3_copy( uaxis, transform->uaxis );
1633 v3_copy( vaxis, transform->vaxis );
1634 v2_zero( transform->offset );
1635
1636 v2_div( (v2f){128.0, 128.0}, texture_res, transform->scale );
1637 transform->winding = 1.0;
1638 return;
1639 }
1640
1641 // Detect if UV is reversed
1642 double winding = v2_cross( tT, bT ) >= 0.0f? 1.0f: -1.0f;
1643
1644 // UV projection reference
1645 v2f vY, vX;
1646 v2_muls((v2f){1,0}, winding, vX);
1647 v2_muls((v2f){0,1}, winding, vY);
1648
1649 // Reproject reference into world space, including skew
1650 v3f uaxis1, vaxis1;
1651
1652 v3_muls( tW, v2_cross(vX,bT) / v2_cross(bT,tT), uaxis1 );
1653 v3_muladds( uaxis1, bW, v2_cross(vX, tT) / v2_cross(tT,bT), uaxis1 );
1654
1655 v3_muls( tW, v2_cross(vY,bT) / v2_cross(bT,tT), vaxis1 );
1656 v3_muladds( vaxis1, bW, v2_cross(vY,tT) / v2_cross(tT,bT), vaxis1 );
1657
1658 v3_normalize( uaxis1 );
1659 v3_normalize( vaxis1 );
1660
1661 // Apply source transform to axis (yes, they also need to be swapped)
1662 v3f norm, uaxis, vaxis;
1663
1664 v3_cross( bW, tW, norm );
1665 v3_normalize(norm);
1666 v3_cross( vaxis1, norm, uaxis );
1667 v3_cross( uaxis1, norm, vaxis );
1668
1669 // real UV scale
1670 v2f uvmin, uvmax, uvdelta;
1671 v2_minv( uvs[0], uvs[1], uvmin );
1672 v2_minv( uvmin, uvs[2], uvmin );
1673 v2_maxv( uvs[0], uvs[1], uvmax );
1674 v2_maxv( uvmax, uvs[2], uvmax );
1675
1676 v2_sub( uvmax, uvmin, uvdelta );
1677
1678 // world-uv scale
1679 v2f uvminw, uvmaxw, uvdeltaw;
1680 uvminw[0] = -support_distance( verts, uaxis, -1.0f );
1681 uvmaxw[0] = support_distance( verts, uaxis, 1.0f );
1682 uvminw[1] = -support_distance( verts, vaxis, -1.0f );
1683 uvmaxw[1] = support_distance( verts, vaxis, 1.0f );
1684
1685 v2_sub( uvmaxw, uvminw, uvdeltaw );
1686
1687 // VMf uv scale
1688 v2f uv_scale;
1689 v2_div( uvdeltaw, uvdelta, uv_scale );
1690 v2_div( uv_scale, texture_res, uv_scale );
1691
1692 // Find offset via 'natural' point
1693 v2f target_uv, natural_uv, tex_offset;
1694 v2_mul( uvs[0], texture_res, target_uv );
1695
1696 natural_uv[0] = v3_dot( uaxis, verts[0] );
1697 natural_uv[1] = -v3_dot( vaxis, verts[0] );
1698 v2_div( natural_uv, uv_scale, natural_uv );
1699
1700 tex_offset[0] = target_uv[0]-natural_uv[0];
1701 tex_offset[1] = -(target_uv[1]-natural_uv[1]);
1702
1703 // Copy everything into output
1704 v3_copy( uaxis, transform->uaxis );
1705 v3_copy( vaxis, transform->vaxis );
1706 v2_copy( tex_offset, transform->offset );
1707 v2_copy( uv_scale, transform->scale );
1708 transform->winding = winding;
1709 }
1710
1711 CXR_API struct cxr_input_mesh *cxr_decompose(struct cxr_input_mesh *src)
1712 {
1713 #ifdef CXR_DEBUG_WRITE_MESH
1714 FILE *yeet = fopen( "/home/harry/Documents/blender_addons_remote/addons/convexer/solid.h", "w" );
1715
1716 fprintf( yeet, "v3f test_verts[] = {\n" );
1717 for( int i=0; i<src->vertex_count; i ++ )
1718 {
1719 fprintf( yeet, " { %f, %f, %f },\n",
1720 src->vertices[i][0],
1721 src->vertices[i][1],
1722 src->vertices[i][2] );
1723 }
1724 fprintf( yeet, "};\n" );
1725
1726 fprintf( yeet, "struct cxr_input_loop test_loops[] = {\n" );
1727 for( int i=0; i<src->loop_count; i ++ )
1728 {
1729 fprintf( yeet, " {%d, %d},\n",
1730 src->loops[i].index,
1731 src->loops[i].edge_index);
1732 }
1733 fprintf( yeet, "};\n" );
1734
1735 fprintf( yeet, "struct cxr_polygon test_polys[] = {\n" );
1736 for( int i=0; i <src->poly_count; i++ )
1737 {
1738 fprintf( yeet, " {%d, %d, {%f, %f, %f}, {%f, %f, %f}},\n",
1739 src->polys[i].loop_start,
1740 src->polys[i].loop_total,
1741 src->polys[i].normal[0],
1742 src->polys[i].normal[1],
1743 src->polys[i].normal[2],
1744 src->polys[i].center[0],
1745 src->polys[i].center[1],
1746 src->polys[i].center[2] );
1747 }
1748 fprintf( yeet, "};\n" );
1749
1750 fprintf( yeet, "struct cxr_edge test_edges[] = {\n" );
1751 for( int i=0; i<src->edge_count; i++ )
1752 {
1753 fprintf( yeet, " {%d, %d},\n",
1754 src->edges[i].i0,
1755 src->edges[i].i1
1756 );
1757 }
1758 fprintf( yeet, "};\n" );
1759
1760 fprintf( yeet, "struct cxr_input_mesh test_mesh = {\n" );
1761 fprintf( yeet, " .vertices = test_verts,\n" );
1762 fprintf( yeet, " .loops = test_loops,\n" );
1763 fprintf( yeet, " .edges = test_edges,\n" );
1764 fprintf( yeet, " .polys = test_polys,\n" );
1765 fprintf( yeet, " .poly_count=%d,\n", src->poly_count );
1766 fprintf( yeet, " .vertex_count=%d,\n", src->vertex_count );
1767 fprintf( yeet, " .edge_count=%d,\n",src->edge_count );
1768 fprintf( yeet, " .loop_count=%d\n", src->loop_count );
1769 fprintf( yeet, "};\n" );
1770
1771 fclose( yeet );
1772 #endif
1773
1774 struct cxr_auto_buffer abverts;
1775 struct cxr_mesh *main_mesh = cxr_to_internal_format( src, &abverts );
1776
1777 u32 error = 0x00;
1778
1779 struct cxr_auto_buffer solids;
1780 cxr_ab_init( &solids, sizeof(struct cxr_mesh *), 2 );
1781
1782 while(1)
1783 {
1784 struct cxr_mesh *res = cxr_pull_best_solid( main_mesh, &abverts, 0, &error );
1785 if( res )
1786 {
1787 cxr_ab_push( &solids, &res );
1788 if( error ) break;
1789 }
1790 else
1791 {
1792 if( error )
1793 {
1794 // If no solids error we can rety while preserving 'hot' edges
1795
1796 if( error & CXR_ERROR_NO_SOLIDS )
1797 {
1798 error = 0x00;
1799 res = cxr_pull_best_solid(main_mesh, &abverts, 1, &error);
1800
1801 if( res ) cxr_ab_push( &solids, &res );
1802 else break;
1803
1804 if( error ) break;
1805 }
1806 else break;
1807 }
1808 else
1809 break;
1810 }
1811 }
1812
1813 cxr_ab_push( &solids, &main_mesh );
1814
1815 if( !error )
1816 {
1817 for( int i=0; i<solids.count; i++ )
1818 {
1819 struct cxr_mesh **mptr = cxr_ab_ptr(&solids,i);
1820 cxr_debug_mesh( *mptr, cxr_ab_ptr(&abverts,0), colours_random[cxr_range(i,8)] );
1821 }
1822 }
1823
1824 for( int i=0; i<solids.count; i++ )
1825 {
1826 struct cxr_mesh **mptr = cxr_ab_ptr(&solids,i);
1827 cxr_free_mesh( *mptr );
1828 }
1829
1830 cxr_ab_free( &abverts );
1831 cxr_ab_free( &solids );
1832
1833 return NULL;
1834 }
1835
1836 static int cxr_cardinal( v3f a, int ignore )
1837 {
1838 int component = 0;
1839 double component_max = -CXR_BIG_NUMBER;
1840
1841 for( int i=0; i<3; i++ )
1842 {
1843 if( i == ignore ) continue;
1844
1845 if( fabs(a[i]) > component_max )
1846 {
1847 component_max = fabs(a[i]);
1848 component = i;
1849 }
1850 }
1851 double d = a[component] >= 0.0? 1.0: -1.0;
1852 v3_zero( a );
1853 a[component] = d;
1854
1855 return component;
1856 }
1857
1858 // Convert contiguous mesh to patch of displacments
1859 //
1860 static void cxr_write_disp(struct cxr_mesh *mesh, struct cxr_input_mesh *inputmesh,
1861 struct cxr_vdf *output,
1862 struct cxr_auto_buffer *abverts)
1863 {
1864 // Create a graph which maps vertices by their connections
1865 struct vertinfo
1866 {
1867 int con_start, con_count; // Index into the connection graph
1868 int boundary,
1869 used,
1870 search,
1871 corner;
1872
1873 double alpha;
1874 }
1875 *vertinfo = malloc( sizeof(struct vertinfo)*abverts->count );
1876 int *graph = malloc( sizeof(int) * mesh->edges.count*2 );
1877
1878 int con_pos = 0;
1879 for( int i=0; i<abverts->count; i++ )
1880 {
1881 struct vertinfo *info = &vertinfo[i];
1882 info->con_start = con_pos;
1883 info->con_count = 0;
1884 info->boundary = 0;
1885 info->corner = 0;
1886 info->used = 0;
1887 info->search = 0;
1888 info->alpha = 0.0;
1889
1890 for( int j=0; j<mesh->edges.count; j++ )
1891 {
1892 struct cxr_edge *edge = cxr_ab_ptr(&mesh->edges,j);
1893
1894 if( edge->i0 == i || edge->i1 == i )
1895 {
1896 graph[ con_pos ++ ] = edge->i0 == i? edge->i1: edge->i0;
1897 info->con_count ++;
1898
1899 if( edge->freestyle )
1900 info->boundary = 1;
1901 }
1902 }
1903 }
1904
1905 // Find best normal for brush patch. VBSP uses the original brush
1906 // as reference for decal projection.
1907 //
1908 // These are clamped to be cardinal directions as to make the VMF somewhat
1909 // human editable.
1910
1911 v3f avg_normal, refv, refu, refn;
1912 v3_zero(refv); v3_zero(refu); v3_zero(refn);
1913
1914 for( int i=0; i<mesh->polys.count; i++ )
1915 {
1916 struct cxr_polygon *poly = cxr_ab_ptr( &mesh->polys, i );
1917 v3_add( poly->normal, avg_normal, avg_normal );
1918 }
1919 v3_divs( avg_normal, mesh->polys.count, avg_normal );
1920 v3_normalize( avg_normal ); // TODO(harry): This can be zero length. Should add a safety check
1921 // normalize function that checks for small length before
1922 // carrying out, otherwise we get inf/nan values...
1923
1924 int n_cardinal = cxr_cardinal( avg_normal, -1 );
1925
1926 // Approximately matching the area of the result brush faces to the actual area
1927 // this is to assign a 'best guess' amount of lightmap texels.
1928 //
1929 double uv_area = 0.0, face_area = 0.0, sf;
1930 v2f uvboundmin, uvboundmax;
1931 v3f faceboundmin, faceboundmax;
1932 v2f uv_center;
1933 v3f face_center;
1934
1935 v2_fill( uvboundmin, CXR_BIG_NUMBER );
1936 v2_fill( uvboundmax, -CXR_BIG_NUMBER );
1937 v3_fill( faceboundmin, CXR_BIG_NUMBER );
1938 v3_fill( faceboundmax, -CXR_BIG_NUMBER );
1939
1940 for( int i=0; i<mesh->polys.count; i++ )
1941 {
1942 struct cxr_polygon *poly = cxr_ab_ptr( &mesh->polys, i );
1943
1944 for( int j=0; j<poly->loop_total; j++ )
1945 {
1946 struct cxr_loop *lp0 = cxr_ab_ptr(&mesh->loops, poly->loop_start+j);
1947 v2_minv( lp0->uv, uvboundmin, uvboundmin);
1948 v2_maxv( lp0->uv, uvboundmax, uvboundmax);
1949 v3_minv( cxr_ab_ptr(abverts,lp0->index), faceboundmin, faceboundmin );
1950 v3_maxv( cxr_ab_ptr(abverts,lp0->index), faceboundmax, faceboundmax );
1951 }
1952
1953 for( int j=0; j<poly->loop_total-2; j++ )
1954 {
1955 struct cxr_loop *lp0 = cxr_ab_ptr(&mesh->loops, poly->loop_start),
1956 *lp1 = cxr_ab_ptr(&mesh->loops, poly->loop_start+j+1),
1957 *lp2 = cxr_ab_ptr(&mesh->loops, poly->loop_start+j+2);
1958 v3f va, vb, orth;
1959 v3_sub( cxr_ab_ptr(abverts,lp1->index), cxr_ab_ptr(abverts,lp0->index), va );
1960 v3_sub( cxr_ab_ptr(abverts,lp2->index), cxr_ab_ptr(abverts,lp0->index), vb );
1961 v3_cross( va, vb, orth );
1962
1963 face_area += v3_length( orth ) / 2.0;
1964
1965 v2f uva, uvb;
1966 v2_sub( lp1->uv, lp0->uv, uva );
1967 v2_sub( lp2->uv, lp0->uv, uvb );
1968
1969 uv_area += fabs(v2_cross( uva, uvb )) / 2.0;
1970 }
1971 }
1972
1973 v3_add( faceboundmax, faceboundmin, face_center );
1974 v3_muls( face_center, 0.5, face_center );
1975 v2_add( uvboundmin, uvboundmax, uv_center );
1976 v2_muls( uv_center, 0.5, uv_center );
1977
1978 sf = sqrt( face_area / uv_area );
1979 int corner_count = 0;
1980
1981 // Vertex classification
1982 for( int i=0; i<abverts->count; i++ )
1983 {
1984 struct vertinfo *info = &vertinfo[i];
1985 if( !info->boundary ) continue;
1986
1987 int count = 0,
1988 non_manifold = 1;
1989
1990 for( int j=0; j<info->con_count; j++ )
1991 {
1992 int con = graph[info->con_start+j];
1993
1994 if( vertinfo[con].boundary )
1995 count ++;
1996 else
1997 non_manifold = 0;
1998 }
1999 if( count > 2 || non_manifold )
2000 {
2001 info->corner = 1;
2002 corner_count ++;
2003
2004 //cxr_debug_box( cxr_ab_ptr(abverts,i), 0.1, colour_success );
2005 }
2006 }
2007
2008 // TODO(harry): This currently only supports power 2 displacements
2009 // its quite straightforward to upgrade it.
2010 //
2011 int dispedge[16];
2012 v2f corner_uvs[4];
2013 int dispedge_count;
2014 int disp_count = 0;
2015
2016 for( int i=0; i<mesh->polys.count; i++ )
2017 {
2018 struct cxr_polygon *basepoly = cxr_ab_ptr(&mesh->polys,i);
2019
2020 for( int h=0; h<basepoly->loop_total; h ++ )
2021 {
2022 int i0 = h,
2023 i1 = cxr_range(h+1,basepoly->loop_total);
2024
2025 struct cxr_loop *l0 = cxr_ab_ptr(&mesh->loops, basepoly->loop_start+i0),
2026 *l1 = cxr_ab_ptr(&mesh->loops, basepoly->loop_start+i1);
2027 struct vertinfo *info = &vertinfo[ l0->index ];
2028
2029 if( info->corner )
2030 {
2031 int corner_count = 1;
2032
2033 struct cxr_material *matptr =
2034 basepoly->material_id < 0 || inputmesh->material_count == 0?
2035 &cxr_nodraw:
2036 &inputmesh->materials[ basepoly->material_id ];
2037
2038 dispedge_count = 2;
2039 dispedge[0] = l0->index;
2040 dispedge[1] = l1->index;
2041 v2_copy( l0->uv, corner_uvs[0] );
2042
2043 // Consume (remove) faces we use for corners
2044 basepoly->loop_total = -1;
2045
2046 //cxr_debug_box( cxr_ab_ptr(abverts,l0->index),0.08,(v4f){0.0,0.0,1.0,1.0});
2047
2048 // Collect edges
2049 // --------------------
2050
2051 while( dispedge_count < 17 )
2052 {
2053 struct vertinfo *edge_head = &vertinfo[dispedge[dispedge_count-1]];
2054 int newvert = 0;
2055
2056 if( edge_head->corner )
2057 {
2058 // Find a polygon that has the edge C-1 -> C
2059 for( int j=0; j<mesh->polys.count && !newvert; j++ )
2060 {
2061 struct cxr_polygon *poly = cxr_ab_ptr(&mesh->polys,j);
2062
2063 for( int k=0; k<poly->loop_total; k ++ )
2064 {
2065 int i0 = k,
2066 i1 = cxr_range(k+1,poly->loop_total);
2067
2068 struct cxr_loop *l0 = cxr_ab_ptr(&mesh->loops, poly->loop_start+i0),
2069 *l1 = cxr_ab_ptr(&mesh->loops, poly->loop_start+i1);
2070
2071 if( l0->index == dispedge[dispedge_count-2] &&
2072 l1->index == dispedge[dispedge_count-1] )
2073 {
2074 // Take the vertex after that edge
2075 v2_copy( l1->uv, corner_uvs[corner_count ++] );
2076
2077 int i2 = cxr_range(i1+1,poly->loop_total);
2078 struct cxr_loop *l2 = cxr_ab_ptr(&mesh->loops, poly->loop_start+i2);
2079
2080 dispedge[dispedge_count ++] = l2->index;
2081 newvert = 1;
2082 poly->loop_total = -1;
2083 break;
2084 }
2085 }
2086 }
2087 }
2088 else
2089 {
2090 for( int j=0; j<edge_head->con_count; j++ )
2091 {
2092 int con = graph[edge_head->con_start+j];
2093
2094 if( con == -1 )
2095 continue;
2096
2097 if( dispedge_count > 1 )
2098 if( con == dispedge[dispedge_count-2] )
2099 continue;
2100
2101 struct vertinfo *coninfo = &vertinfo[con];
2102
2103 if( !coninfo->boundary )
2104 continue;
2105
2106 /*
2107 cxr_debug_arrow( cxr_ab_ptr(abverts,dispedge[dispedge_count-1]),
2108 cxr_ab_ptr(abverts,con),
2109 (v3f){0,0,1},
2110 0.1,
2111 colour_success );
2112 */
2113
2114 dispedge[ dispedge_count ++ ] = con;
2115 newvert = 1;
2116
2117 break;
2118 }
2119 }
2120
2121 if( !newvert )
2122 {
2123 cxr_debug_box(cxr_ab_ptr(abverts,dispedge[dispedge_count-1]), 0.1, colour_error);
2124 break;
2125 }
2126 }
2127
2128 // --------------------
2129 // Edges collected
2130
2131 v2f va, vb;
2132 v2_sub( corner_uvs[1], corner_uvs[0], va );
2133 v2_sub( corner_uvs[2], corner_uvs[0], vb );
2134
2135 // Connect up the grid
2136 //
2137 // 0 1 2 3 4
2138 // 15 a b c d
2139 // 14 e f g h
2140 // 13 i j k l
2141 // 12 m n o p
2142 //
2143 // Example: a := common unused vertex that is connected to
2144 // by 1 and 15. Or y-1, and x-1 on the grid.
2145 // g := c and f common vert ^
2146 //
2147 int grid[25];
2148
2149 for( int j=0; j<5; j++ ) grid[j] = dispedge[j];
2150 for( int j=1; j<5; j++ ) grid[j*5+4] = dispedge[j+4];
2151 for( int j=0; j<4; j++ ) grid[4*5+3-j] = dispedge[j+9];
2152 for( int j=1; j<4; j++ ) grid[j*5] = dispedge[16-j];
2153
2154 // Grid fill
2155 for( int j=1; j<4; j++ )
2156 {
2157 for( int k=1; k<4; k++ )
2158 {
2159 int s0 = grid[(j-1)*5+k],
2160 s1 = grid[j*5+k-1];
2161
2162 struct vertinfo *va = &vertinfo[s0],
2163 *vb = &vertinfo[s1];
2164
2165 // Find a common vertex between s0 and s1
2166
2167 for( int l=0; l<va->con_count; l ++ )
2168 {
2169 for( int m=0; m<vb->con_count; m ++ )
2170 {
2171 int cona = graph[va->con_start+l],
2172 conb = graph[vb->con_start+m];
2173
2174 if( cona == conb )
2175 {
2176 if( vertinfo[cona].used || vertinfo[cona].boundary )
2177 continue;
2178
2179 grid[ j*5+k ] = cona;
2180 vertinfo[cona].used = 1;
2181
2182 goto IL_MATCHED_DISP_INTERIOR_VERT;
2183 }
2184 }
2185 }
2186
2187 // Broken displacement
2188 cxr_log( "Broken displacement!\n" );
2189 free( graph );
2190 free( vertinfo );
2191 return;
2192
2193 IL_MATCHED_DISP_INTERIOR_VERT:;
2194 }
2195 }
2196
2197 // Create brush vertices based on UV map
2198
2199 // Create V reference based on first displacement.
2200 // TODO(harry): This is not the moststable selection method!
2201 // faces can come in any order, so the first disp will of course
2202 // always vary. Additionaly the triangle can be oriented differently.
2203 //
2204 // Improvement can be made by selecting a first disp/triangle based
2205 // on deterministic factors.
2206 //
2207 if( disp_count == 0 )
2208 {
2209 struct cxr_texinfo tx;
2210 v3f tri_ref[3];
2211 v3_copy( cxr_ab_ptr(abverts,dispedge[0]), tri_ref[0] );
2212 v3_copy( cxr_ab_ptr(abverts,dispedge[4]), tri_ref[1] );
2213 v3_copy( cxr_ab_ptr(abverts,dispedge[8]), tri_ref[2] );
2214 cxr_calculate_axis( &tx, tri_ref, corner_uvs, (v2f){512,512} );
2215
2216 v3_muls( tx.vaxis, -1.0, refv );
2217 int v_cardinal = cxr_cardinal( refv, -1 );
2218
2219 v3_cross( tx.vaxis, tx.uaxis, refn );
2220 v3_muls( refn, -tx.winding, refn );
2221
2222 int n1_cardinal = cxr_cardinal( refn, v_cardinal );
2223
2224 //v3_copy( avg_normal, refn );
2225 int u_cardinal = 0;
2226 if( u_cardinal == n1_cardinal || u_cardinal == v_cardinal ) u_cardinal ++;
2227 if( u_cardinal == n1_cardinal || u_cardinal == v_cardinal ) u_cardinal ++;
2228
2229 v3_zero(refu);
2230 refu[u_cardinal] = tx.uaxis[u_cardinal] > 0.0? 1.0: -1.0;
2231
2232 v3f p0, pv, pu, pn;
2233
2234 v3_copy( face_center, p0 );
2235 v3_muladds( face_center, refn, 1.5, pn );
2236 v3_muladds( face_center, refv, 1.5, pv );
2237 v3_muladds( face_center, refu, 1.5, pu );
2238
2239 if( cxr_settings.debug )
2240 {
2241 cxr_debug_line( p0, pn, (v4f){0.0,0.0,1.0,1.0});
2242 cxr_debug_line( p0, pv, (v4f){0.0,1.0,0.0,1.0});
2243 cxr_debug_line( p0, pu, (v4f){1.0,0.0,0.0,1.0});
2244 cxr_debug_line( tri_ref[0], tri_ref[1], (v4f){1.0,1.0,1.0,1.0} );
2245 cxr_debug_line( tri_ref[1], tri_ref[2], (v4f){1.0,1.0,1.0,1.0} );
2246 cxr_debug_line( tri_ref[2], tri_ref[0], (v4f){1.0,1.0,1.0,1.0} );
2247 }
2248 }
2249
2250 // Create world cordinates
2251 v3f world_corners[8];
2252 v2f world_uv[4];
2253
2254 for( int j=0; j<4; j++ )
2255 {
2256 v2f local_uv;
2257 v2_sub( corner_uvs[j], uv_center, local_uv );
2258 v2_copy( corner_uvs[j], world_uv[j] );
2259 v2_muls( local_uv, sf, local_uv );
2260
2261 v3_muls( refu, local_uv[0], world_corners[j] );
2262 v3_muladds( world_corners[j], refv, local_uv[1], world_corners[j] );
2263 v3_add( face_center, world_corners[j], world_corners[j] );
2264 }
2265
2266 double *colour = colours_random[cxr_range(disp_count,8)];
2267
2268 for( int j=0; j<4; j++ )
2269 v3_muladds( world_corners[j], refn, -1.0, world_corners[j+4] );
2270
2271 if( cxr_settings.debug )
2272 {
2273 cxr_debug_arrow( world_corners[0], world_corners[1], avg_normal, 0.1, colour );
2274 cxr_debug_arrow( world_corners[1], world_corners[2], avg_normal, 0.1, colour );
2275 cxr_debug_arrow( world_corners[2], world_corners[3], avg_normal, 0.1, colour );
2276 cxr_debug_arrow( world_corners[3], world_corners[0], avg_normal, 0.1, colour );
2277 }
2278
2279 /*
2280 cxr_debug_arrow( world_corners[0+4], world_corners[1+4], avg_normal, 0.1, colour );
2281 cxr_debug_arrow( world_corners[1+4], world_corners[2+4], avg_normal, 0.1, colour );
2282 cxr_debug_arrow( world_corners[2+4], world_corners[3+4], avg_normal, 0.1, colour );
2283 cxr_debug_arrow( world_corners[3+4], world_corners[0+4], avg_normal, 0.1, colour );
2284 */
2285
2286 // Apply world transform
2287 for( int j=0; j<8; j++ )
2288 {
2289 v3_muls( world_corners[j], cxr_context.scale_factor, world_corners[j] );
2290 world_corners[j][2] += cxr_context.offset_z;
2291 }
2292
2293 struct cxr_texinfo texinfo_shared;
2294 cxr_calculate_axis( &texinfo_shared, world_corners, world_uv,
2295 (v2f){ matptr->res[0], matptr->res[1] } );
2296
2297 // Write brush
2298 cxr_vdf_node( output, "solid" );
2299 cxr_vdf_ki32( output, "id", ++ cxr_context.brush_count );
2300
2301 int sides[6][3] =
2302 {{ 0, 1, 2 },
2303 { 4, 6, 5 },
2304 { 4, 1, 0 },
2305 { 7, 0, 3 },
2306 { 6, 2, 1 },
2307 { 6, 3, 2 }};
2308
2309 v3f normals[25];
2310 double distances[25];
2311
2312 v3f lside0, lside1, lref, vdelta, vworld;
2313 double tx, ty;
2314
2315 for( int j=0; j<5; j++ )
2316 {
2317 ty = (double)j/(double)(5-1);
2318
2319 v3_lerp( world_corners[0], world_corners[3], ty, lside0 );
2320 v3_lerp( world_corners[1], world_corners[2], ty, lside1 );
2321
2322 for( int k=0; k<5; k++ )
2323 {
2324 int index = j*5+k;
2325
2326 tx = (double)k/(double)(5-1);
2327 v3_lerp( lside0, lside1, tx, lref );
2328 v3_muls( cxr_ab_ptr(abverts, grid[index]), cxr_context.scale_factor, vworld );
2329 vworld[2] += cxr_context.offset_z;
2330
2331 v3_sub( vworld, lref, vdelta );
2332 v3_copy( vdelta, normals[index] );
2333 v3_normalize( normals[index] );
2334 distances[index] = v3_dot( vdelta, normals[index] );
2335 }
2336 }
2337
2338 for( int j=0; j<6; j++ )
2339 {
2340 int *side = sides[j];
2341
2342 cxr_vdf_node( output, "side" );
2343 cxr_vdf_ki32( output, "id", ++ cxr_context.face_count );
2344 cxr_vdf_plane( output, "plane", world_corners[side[2]],
2345 world_corners[side[1]],
2346 world_corners[side[0]] );
2347
2348 cxr_vdf_kv( output, "material", matptr->vmt_path );
2349
2350 cxr_vdf_kaxis( output, "uaxis",
2351 texinfo_shared.uaxis,
2352 texinfo_shared.offset[0],
2353 texinfo_shared.scale[0] );
2354 cxr_vdf_kaxis( output, "vaxis",
2355 texinfo_shared.vaxis,
2356 texinfo_shared.offset[1],
2357 texinfo_shared.scale[1] );
2358
2359 cxr_vdf_kdouble( output, "rotation", 0.0 );
2360 cxr_vdf_ki32( output, "lightmapscale", cxr_settings.lightmap_scale );
2361 cxr_vdf_ki32( output, "smoothing_groups", 0 );
2362
2363 if( j == 0 )
2364 {
2365 cxr_vdf_node( output, "dispinfo" );
2366 cxr_vdf_ki32( output, "power", 2 );
2367 cxr_vdf_kv3f( output, "startposition", world_corners[0] );
2368 cxr_vdf_ki32( output, "flags", 0 );
2369 cxr_vdf_kdouble( output, "elevation", 0.0 );
2370 cxr_vdf_ki32( output, "subdiv", 0 );
2371
2372 cxr_vdf_node( output, "normals" );
2373 for( int k=0; k<5; k++ )
2374 cxr_vdf_karrv3f( output, "row", k, &normals[k*5], 5 );
2375 cxr_vdf_edon( output );
2376
2377 cxr_vdf_node( output, "distances" );
2378 for( int k=0; k<5; k++ )
2379 cxr_vdf_karrdouble( output, "row", k, &distances[k*5], 5 );
2380 cxr_vdf_edon( output );
2381
2382 // TODO: This might be needed for compiling...
2383 /*
2384 cxr_vdf_node( output, "offsets" );
2385 for( int k=0; k<5; k++ )
2386 cxr_vdf_printf( output, "\"row%d\" \"0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\"\n", k );
2387 cxr_vdf_edon( output );
2388
2389 cxr_vdf_node( output, "offset_normals" );
2390 for( int k=0; k<5; k++ )
2391 cxr_vdf_printf( output, "\"row%d\" \"0 0 1 0 0 1 0 0 1 0 0 1 0 0 1\"\n", k );
2392 cxr_vdf_edon( output );
2393
2394 cxr_vdf_node( output, "alphas" );
2395 for( int k=0; k<5; k++ )
2396 cxr_vdf_printf( output, "\"row%d\" \"0 0 0 0 0\"\n", k );
2397 cxr_vdf_edon( output );
2398
2399 cxr_vdf_node( output, "triangle_tags" );
2400 for( int k=0; k<5-1; k++ )
2401 cxr_vdf_printf( output, "\"row%d\" \"9 9 9 9 9 9 9 9\"\n", k );
2402 cxr_vdf_edon( output );
2403
2404 cxr_vdf_node( output, "allowed_verts" );
2405 cxr_vdf_printf( output, "\"10\" \"-1 -1 -1 -1 -1 -1 -1 -1 -1 -1\"\n" );
2406 cxr_vdf_edon( output );
2407 */
2408 cxr_vdf_edon( output );
2409 }
2410
2411 cxr_vdf_edon( output );
2412 }
2413
2414 cxr_vdf_node(output, "editor");
2415 cxr_vdf_colour255(output,"color", colours_random[cxr_range(cxr_context.brush_count,8)]);
2416 cxr_vdf_ki32(output,"visgroupshown",1);
2417 cxr_vdf_ki32(output,"visgroupautoshown",1);
2418 cxr_vdf_edon(output);
2419
2420 cxr_vdf_edon( output );
2421 disp_count ++;
2422 }
2423 }
2424 }
2425
2426 // Main loop
2427 #if 0
2428 int pool[25];
2429 for( int i=0; i<abverts->count; i++ )
2430 {
2431 struct vertinfo *info = &vertinfo[i];
2432 if( info->boundary || info->used )
2433 continue;
2434
2435 // Gather all vertices in this displacement
2436 int poolcount = 1,
2437 front_start = 0,
2438 front_count = 1;
2439 pool[0] = i;
2440 info->used = 1;
2441
2442 IL_GATHER_LOOP:;
2443
2444 int new_front_start = poolcount;
2445
2446 for( int j=0; j<front_count; j++ )
2447 {
2448 struct vertinfo *frontvert = &vertinfo[pool[front_start+j]];
2449
2450 for( int k=0; k<frontvert->con_count; k++ )
2451 {
2452 int conid = graph[frontvert->con_start+k];
2453 struct vertinfo *con = &vertinfo[conid];
2454
2455 if( frontvert->boundary && !con->boundary )
2456 continue;
2457
2458 if( con->used )
2459 continue;
2460
2461 if( poolcount == 25 )
2462 goto IL_DISP_ERROR_COUNT;
2463
2464 con->used = 1;
2465 pool[ poolcount ++ ] = conid;
2466 }
2467 }
2468
2469 if( poolcount > new_front_start )
2470 {
2471 front_start = new_front_start;
2472 front_count = poolcount-front_start;
2473
2474 goto IL_GATHER_LOOP;
2475 }
2476
2477 if( poolcount != 25 )
2478 {
2479 IL_DISP_ERROR_COUNT:
2480 for( int i=0; i<poolcount; i++ )
2481 cxr_debug_box( cxr_ab_ptr(abverts,pool[i]), 0.02, colour_error );
2482
2483 free(graph);
2484 free(vertinfo);
2485
2486 cxr_log("Invalid displacement (>25 verts)\n");
2487 return;
2488 }
2489
2490 int corners[4];
2491 int corner_count = 0;
2492 struct cxr_loop *cornerloops[4];
2493
2494 // Find corners, and get their loops (for uvs)
2495 // note: the mesh must be split where there is texture seams
2496 // so that two different uv'd loops cant ref the same vertex
2497 //
2498 for( int j=0; j<poolcount; j++ )
2499 {
2500 if( vertinfo[pool[j]].corner )
2501 {
2502 if( corner_count == 4 )
2503 {
2504 corner_count = -1;
2505 break;
2506 }
2507
2508 corners[corner_count] = j;
2509
2510 // find loop that includes this vert
2511 for( int k=0; k<mesh->loops.count; k++ )
2512 {
2513 struct cxr_loop *lp = cxr_ab_ptr(&mesh->loops,k);
2514 if( lp->index == pool[j] )
2515 {
2516 cornerloops[corner_count] = lp;
2517 break;
2518 }
2519 }
2520
2521 corner_count ++;
2522 }
2523 }
2524
2525 if( corner_count !=4 )
2526 {
2527 free(graph);
2528 free(vertinfo);
2529 cxr_log( "Invalid displacement (!=4 corners)\n" );
2530 return;
2531 }
2532
2533 int pivot = corners[0];
2534 }
2535 #endif
2536
2537 free( graph );
2538 free( vertinfo );
2539 }
2540
2541 static int cxr_solid_checkerr(struct cxr_mesh *mesh, struct cxr_auto_buffer *abverts )
2542 {
2543 int err_count = 0;
2544
2545 for( int i=0; i<mesh->polys.count; i++ )
2546 {
2547 int plane_err = 0;
2548
2549 struct cxr_polygon *poly = cxr_ab_ptr(&mesh->polys,i);
2550 v4f plane;
2551
2552 normal_to_plane( poly->normal, poly->center, plane );
2553
2554 for( int j=0; j<poly->loop_total; j++ )
2555 {
2556 struct cxr_loop *loop = cxr_ab_ptr(&mesh->loops, poly->loop_start+j);
2557 double *vert = cxr_ab_ptr(abverts,loop->index);
2558
2559 if( fabs(plane_polarity(plane,vert)) > 0.0025 )
2560 {
2561 err_count ++;
2562 plane_err ++;
2563
2564 v3f ref;
2565 plane_project_point( plane, vert, ref );
2566
2567 cxr_debug_line( ref, vert, colour_error );
2568 cxr_debug_box( vert, 0.1, colour_error );
2569 }
2570 }
2571
2572 if( plane_err )
2573 cxr_debug_poly( mesh, poly, cxr_ab_ptr(abverts,0), colour_error );
2574 }
2575
2576 return err_count;
2577 }
2578
2579 CXR_API i32 cxr_convert_mesh_to_vmf(struct cxr_input_mesh *src, struct cxr_vdf *output)
2580 {
2581 // Split mesh into islands
2582 struct cxr_auto_buffer abverts;
2583 struct cxr_mesh *main_mesh = cxr_to_internal_format(src, &abverts);
2584
2585 u32 error = 0x00;
2586 int invalid_count = 0;
2587
2588 struct solidinf
2589 {
2590 struct cxr_mesh *pmesh;
2591 int is_displacement, invalid;
2592 };
2593
2594 struct cxr_auto_buffer solids;
2595 cxr_ab_init( &solids, sizeof(struct solidinf), 2 );
2596
2597 // Preprocessor 1: Island seperation
2598 // ---------------
2599
2600 while(1)
2601 {
2602 struct cxr_mesh *res = cxr_pull_island( main_mesh );
2603 if( res )
2604 {
2605 cxr_ab_push( &solids, &(struct solidinf){ res, 0 });
2606 }
2607 else break;
2608 }
2609 cxr_ab_push( &solids, &(struct solidinf){main_mesh,0} );
2610
2611 // Preprocessor 2: Displacement break-out and error checking
2612 // ---------------
2613 for( int i=0; i<solids.count; i++ )
2614 {
2615 struct solidinf *pinf = cxr_ab_ptr(&solids,i);
2616
2617 for( int j=0; j<pinf->pmesh->polys.count; j++ )
2618 {
2619 struct cxr_polygon *poly = cxr_ab_ptr( &pinf->pmesh->polys, j );
2620
2621 for( int k=0; k<poly->loop_total; k++ )
2622 {
2623 struct cxr_loop *lp = cxr_ab_ptr( &pinf->pmesh->loops, poly->loop_start+k );
2624 struct cxr_edge *edge = cxr_ab_ptr( &pinf->pmesh->edges, lp->edge_index );
2625
2626 if( edge->freestyle )
2627 goto IL_SOLID_IS_DISPLACEMENT;
2628 }
2629 }
2630
2631 if( cxr_solid_checkerr( pinf->pmesh, &abverts ) )
2632 {
2633 pinf->invalid = 1;
2634 invalid_count ++;
2635 }
2636
2637 continue;
2638 IL_SOLID_IS_DISPLACEMENT:;
2639
2640 pinf->is_displacement = 1;
2641 cxr_write_disp( pinf->pmesh, src, output, &abverts );
2642 }
2643
2644 // Preprocessor 3: Breakup non-convex shapes into sub-solids
2645 // ---------------
2646 int sources_count = solids.count;
2647
2648 for( int i=0; i<sources_count; i++ )
2649 {
2650 struct solidinf pinf = *(struct solidinf *)cxr_ab_ptr(&solids, i);
2651
2652 if( pinf.is_displacement || pinf.invalid )
2653 continue;
2654
2655 while(1)
2656 {
2657 struct cxr_mesh *res = cxr_pull_best_solid( pinf.pmesh, &abverts, 0, &error );
2658
2659 if( res )
2660 {
2661 cxr_ab_push( &solids, &(struct solidinf){res,0} );
2662 if( error )
2663 break;
2664 }
2665 else
2666 {
2667 if( error )
2668 {
2669 // If no solids error we can rety while preserving 'hot' edges
2670
2671 if( error & CXR_ERROR_NO_SOLIDS )
2672 {
2673 error = 0x00;
2674 res = cxr_pull_best_solid(pinf.pmesh, &abverts, 1, &error);
2675
2676 if( res ) cxr_ab_push( &solids, &(struct solidinf){res,0} );
2677 else break;
2678
2679 if( error ) break;
2680 }
2681 else
2682 break;
2683 }
2684 else
2685 break;
2686 }
2687 }
2688 }
2689
2690 if( cxr_settings.debug )
2691 {
2692 for( int i=0; i<solids.count; i++ )
2693 {
2694 struct solidinf *solid = cxr_ab_ptr(&solids,i);
2695
2696 if( !solid->is_displacement )
2697 cxr_debug_mesh( solid->pmesh, cxr_ab_ptr(&abverts,0), colours_random[cxr_range(i,8)] );
2698 }
2699 }
2700
2701 // Turn all those solids into VMF brushes
2702 // --------------------------------------
2703 for( int i=0; i<solids.count; i++ )
2704 {
2705 struct solidinf *solid = cxr_ab_ptr(&solids,i);
2706
2707 if( solid->is_displacement ) continue;
2708
2709 cxr_vdf_node( output, "solid" );
2710 cxr_vdf_ki32( output, "id", ++ cxr_context.brush_count );
2711
2712 for( int j=0; j<solid->pmesh->polys.count; j++ )
2713 {
2714 struct cxr_polygon *poly = cxr_ab_ptr( &solid->pmesh->polys, j );
2715 struct cxr_loop *ploops = cxr_ab_ptr(&solid->pmesh->loops, poly->loop_start);
2716 struct cxr_material *matptr =
2717 poly->material_id < 0 || src->material_count == 0?
2718 &cxr_nodraw:
2719 &src->materials[ poly->material_id ];
2720
2721 cxr_vdf_node( output, "side" );
2722 cxr_vdf_ki32( output, "id", ++ cxr_context.face_count );
2723
2724 v3f verts[3]; v2f uvs[3];
2725
2726 v3_muls( cxr_ab_ptr(&abverts, ploops[0].index), cxr_context.scale_factor, verts[0] );
2727 v3_muls( cxr_ab_ptr(&abverts, ploops[1].index), cxr_context.scale_factor, verts[1] );
2728 v3_muls( cxr_ab_ptr(&abverts, ploops[2].index), cxr_context.scale_factor, verts[2] );
2729 verts[0][2] += cxr_context.offset_z;
2730 verts[1][2] += cxr_context.offset_z;
2731 verts[2][2] += cxr_context.offset_z;
2732
2733 v2_copy( ploops[0].uv, uvs[0] );
2734 v2_copy( ploops[1].uv, uvs[1] );
2735 v2_copy( ploops[2].uv, uvs[2] );
2736
2737 cxr_vdf_plane( output, "plane", verts[2], verts[1], verts[0] );
2738 cxr_vdf_kv( output, "material", matptr->vmt_path );
2739
2740 struct cxr_texinfo trans;
2741 cxr_calculate_axis(&trans, verts, uvs, (double[2]){ matptr->res[0], matptr->res[1] });
2742
2743 cxr_vdf_kaxis(output, "uaxis", trans.uaxis, trans.offset[0], trans.scale[0]);
2744 cxr_vdf_kaxis(output, "vaxis", trans.vaxis, trans.offset[1], trans.scale[1]);
2745
2746 cxr_vdf_kdouble(output, "rotation", 0.0 );
2747 cxr_vdf_ki32(output, "lightmapscale", cxr_settings.lightmap_scale );
2748 cxr_vdf_ki32(output, "smoothing_groups", 0);
2749
2750 cxr_vdf_edon( output );
2751 }
2752
2753 cxr_vdf_node(output, "editor");
2754 cxr_vdf_colour255(output,"color", colours_random[cxr_range(cxr_context.brush_count,8)]);
2755 cxr_vdf_ki32(output,"visgroupshown",1);
2756 cxr_vdf_ki32(output,"visgroupautoshown",1);
2757 cxr_vdf_edon(output);
2758
2759 cxr_vdf_edon( output );
2760 }
2761
2762 for( int i=0; i<solids.count; i++ )
2763 {
2764 struct solidinf *solid = cxr_ab_ptr(&solids,i);
2765 cxr_free_mesh( solid->pmesh );
2766 }
2767
2768 cxr_ab_free( &abverts );
2769 cxr_ab_free( &solids );
2770 return 0;
2771 }
2772
2773
2774 CXR_API void cxr_set_log_function( void (*func)(const char *str) )
2775 {
2776 cxr_log_func = func;
2777 }
2778
2779 CXR_API void cxr_set_line_function( void (*func)(v3f p0, v3f p1, v4f colour) )
2780 {
2781 cxr_line_func = func;
2782 }
2783
2784 CXR_API void cxr_settings_update( struct cxr_settings *settings )
2785 {
2786 cxr_settings = *settings;
2787 }
2788
2789 // Valve copyright stuff probably maybe
2790 // whatever, my previous copyright decleration ends here
2791 // ----------------------------------------------------------
2792
2793 #define HEADER_LUMPS 64
2794 #define LUMP_WORLDLIGHTS 54
2795
2796 #pragma pack(push,1)
2797
2798 struct header
2799 {
2800 int ident;
2801 int version;
2802
2803 struct lump
2804 {
2805 int fileofs, filelen;
2806 int version;
2807
2808 char fourCC[4];
2809 }
2810 lumps[ HEADER_LUMPS ];
2811
2812 int mapRevision;
2813 };
2814
2815 struct worldlight
2816 {
2817 float origin[3];
2818 float intensity[3];
2819 float normal[3];
2820 float shadow_cast_offset[3];
2821 int cluster;
2822 int type;
2823 int style;
2824 float stopdot;
2825 float stopdot2;
2826 float exponent;
2827 float radius;
2828 float constant_attn;
2829 float linear_attn;
2830 float quadratic_attn;
2831 int flags;
2832 int texinfo;
2833 int owner;
2834 };
2835 #pragma pack(pop)
2836
2837 // Utility for patching BSP tools to remove -1 distance lights (we set them
2838 // like that, because we want these lights to go away)
2839 //
2840 // Yes, there is no way to do this in hammer
2841 // Yes, the distance KV is unused but still gets compiled to this lump
2842 // No, Entities only compile will not do this for you
2843 //
2844 CXR_API int cxr_lightpatch_bsp( const char *path )
2845 {
2846 printf( "Lightpatch: %s\n", path );
2847
2848 FILE *fp = fopen( path, "r+b" );
2849
2850 if( !fp )
2851 {
2852 cxr_log( "Could not open BSP file for editing (r+b)\n" );
2853 return 0;
2854 }
2855
2856 // Read bsp
2857 struct header header;
2858 fread( &header, sizeof(struct header), 1, fp );
2859 struct lump *lump = &header.lumps[ LUMP_WORLDLIGHTS ];
2860
2861 // Read worldlight array
2862 struct worldlight *lights = malloc( lump->filelen );
2863 fseek( fp, lump->fileofs, SEEK_SET );
2864 fread( lights, lump->filelen, 1, fp );
2865
2866 // Remove all marked lights
2867 int light_count = lump->filelen / sizeof(struct worldlight);
2868 int new_count = 0;
2869
2870 for( int i = 0; i < light_count; i ++ )
2871 if( lights[i].radius >= 0.0f )
2872 lights[new_count++] = lights[i];
2873
2874 lump->filelen = new_count*sizeof(struct worldlight);
2875
2876 // Write changes
2877 fseek( fp, lump->fileofs, SEEK_SET );
2878 fwrite( lights, lump->filelen, 1, fp );
2879 fseek( fp, 0, SEEK_SET );
2880 fwrite( &header, sizeof(struct header), 1, fp );
2881 cxr_log( "removed %d marked lights\n", light_count-new_count );
2882
2883 fclose( fp );
2884 free( lights );
2885
2886 return 1;
2887 }