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