bug fixes
[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.999
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.000025 ||
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 /* Debug stuff --
916 for( int i=0; i<vertex_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 for( int i=0; i<mesh->polys.count; i++ )
947 {
948 if( faces_tagged[i] != -1 ) continue;
949 faces_tagged[i] = i;
950
951 int *solid = &solid_buffer[ solid_buffer_len ];
952 int solid_len = 0;
953
954 solid[solid_len++] = i;
955
956 int search_start = 0;
957
958 // Iterative search that connects regions of planes governed by rules:
959 // - edge can add other face if the edge has less than two reflexes
960 // - the face can no longer be used in future searches
961
962 IL_SEARCH_CONTINUE:;
963
964 int changed = 0;
965 for( int j=search_start; j<solid_len; j++ )
966 {
967 struct cxr_polygon *poly = cxr_ab_ptr(&mesh->polys, solid[j]);
968
969 for( int k=0; k<poly->loop_total; k++ )
970 {
971 struct cxr_loop *loop = cxr_ab_ptr(&mesh->loops, poly->loop_start+k);
972 struct cxr_edge *edge = cxr_ab_ptr(&mesh->edges, loop->edge_index );
973
974 if( faces_tagged[ loop->poly_right ] == -1 )
975 {
976 if( !edge_tagged[loop->edge_index] )
977 {
978 // Need to look ahead 1 step to make sure he does not want
979 // to add any more planes that are coplanar with some of
980 // our existing group
981 //
982 // TODO: is this unused due to hotedge improvements? leaving for safety...
983
984 struct cxr_polygon *poly_to_add = cxr_ab_ptr(&mesh->polys, loop->poly_right );
985 for( int l=0; l < poly_to_add->loop_total; l++ )
986 {
987 struct cxr_loop *loop1 = cxr_ab_ptr(&mesh->loops, poly_to_add->loop_start+l );
988 struct cxr_polygon *future_face = cxr_ab_ptr(&mesh->polys, loop1->poly_right );
989
990 if( edge_tagged[ loop1->edge_index ] || loop1->poly_right == loop->poly_right )
991 goto IL_SKIP_SIMILAR_PLANES;
992
993 for( int m=0; m<solid_len; m++ )
994 if( solid[m] == loop1->poly_right )
995 goto IL_SKIP_SIMILAR_PLANES;
996
997 for( int m=0; m<solid_len; m++ )
998 {
999 struct cxr_polygon *polym = cxr_ab_ptr(&mesh->polys,solid[m]);
1000 if( v3_dot( polym->normal,future_face->normal) > CXR_PLANE_SIMILARITY_MAX)
1001 goto IL_SKIP_PLANE_ADD;
1002 }
1003
1004 IL_SKIP_SIMILAR_PLANES:;
1005 }
1006
1007 // This plane passed all checks so we can add it to the current solid
1008
1009 solid[ solid_len ++ ] = loop->poly_right;
1010 faces_tagged[ loop->poly_right ] = i;
1011 changed = 1;
1012 }
1013
1014 IL_SKIP_PLANE_ADD:;
1015 }
1016 }
1017 }
1018 search_start = solid_len;
1019 if(changed)
1020 goto IL_SEARCH_CONTINUE;
1021
1022 // Add entry
1023 struct csolid *csolid = &candidates[candidate_count ++];
1024 csolid->start = solid_buffer_len;
1025 csolid->count = solid_len;
1026 csolid->edge_count = 0;
1027
1028 v3_zero( csolid->center );
1029 for( int j=0; j<solid_len; j++ )
1030 {
1031 struct cxr_polygon *polyj = cxr_ab_ptr(&mesh->polys, solid[j]);
1032 v3_add( polyj->center, csolid->center, csolid->center );
1033 csolid->edge_count += polyj->loop_total;
1034 }
1035 v3_divs( csolid->center, solid_len, csolid->center );
1036
1037 solid_buffer_len += solid_len;
1038 }
1039
1040 // Create all candidates who have one or less non-manifolds edges
1041 // Loop each candidate, determine the manifold, and pick the best one
1042
1043 struct csolid *best_solid = NULL;
1044 int fewest_manifold_splits = INT32_MAX;
1045
1046 struct cxr_loop *best_manifold = malloc( mesh->loops.count *sizeof(struct cxr_loop) );
1047 int *best_manifold_splits = malloc( mesh->loops.count *sizeof(int) );
1048 int best_manifold_len = 0;
1049 int max_solid_faces = 0;
1050
1051 int *edge_list = malloc( mesh->edges.count *sizeof(int) );
1052 int *edge_lefts = malloc( mesh->edges.count *sizeof(int) );
1053 struct cxr_loop *manifold = malloc(mesh->edges.count*2*sizeof(struct cxr_loop));
1054 int *splits = malloc(mesh->edges.count*2*sizeof(int));
1055
1056 for( int i=0; i<candidate_count; i++ )
1057 {
1058 struct csolid *solid = &candidates[i];
1059 max_solid_faces = cxr_max(max_solid_faces,solid->count);
1060
1061 if( solid->count <= 2 )
1062 continue;
1063
1064 int init_reverse = 0;
1065 int unique_edge_count = 0;
1066
1067 for( int j=0; j<solid->count; j++ )
1068 {
1069 struct cxr_polygon *poly = cxr_ab_ptr(&mesh->polys, solid_buffer[solid->start+j]);
1070
1071 for( int k=0; k<poly->loop_total; k++ )
1072 {
1073 struct cxr_loop *loop = cxr_ab_ptr(&mesh->loops, poly->loop_start+k);
1074
1075 for( int l=0; l<unique_edge_count; l++ )
1076 if( edge_list[l] == loop->edge_index )
1077 goto IL_EDGE_ALREADY_PRESENT;
1078
1079 // Check if right edge references a polygon that is not
1080 // present inside the current solid candidate
1081 for( int l=0; l<solid->count; l++ )
1082 if( loop->poly_right == solid_buffer[solid->start+l] )
1083 goto IL_EDGE_ALREADY_PRESENT;
1084
1085 edge_list[ unique_edge_count ] = loop->edge_index;
1086 edge_lefts[ unique_edge_count ] = loop->poly_left;
1087
1088 if( unique_edge_count == 0 )
1089 {
1090 struct cxr_edge *edgeptr = cxr_ab_ptr(&mesh->edges, loop->edge_index);
1091 if( edgeptr->i1 == loop->index )
1092 init_reverse = 1;
1093 }
1094
1095 unique_edge_count ++;
1096 IL_EDGE_ALREADY_PRESENT:;
1097 }
1098 }
1099
1100 // This solid is already fully connected
1101 if( unique_edge_count == 0 )
1102 continue;
1103
1104 // Link edges together to create new manifold
1105 // Corners are created when two edges share a polygon face
1106 // This way we can split it into regions
1107
1108 for( int j=0; j<vert_buffer->count; j++ )
1109 vertex_tagged[j] = -1;
1110
1111 // Start with a loop edge which was tagged
1112 struct cxr_edge *current = cxr_ab_ptr(&mesh->edges, edge_list[0]);
1113
1114 int endpt = (!init_reverse)? current->i0: current->i1,
1115 start = endpt,
1116 curface = edge_lefts[0];
1117
1118 int manifold_len = 0;
1119 int split_count = 0;
1120
1121 IL_MANIFOLD_CONTINUE:
1122 for( int j=0; j<unique_edge_count; j++ )
1123 {
1124 struct cxr_edge *other = cxr_ab_ptr(&mesh->edges, edge_list[j]);
1125 if( other == current )
1126 continue;
1127
1128 if( other->i0 == endpt || other->i1 == endpt )
1129 {
1130 current = other;
1131 int lastpt = endpt;
1132
1133 if( other->i0 == endpt ) endpt = current->i1;
1134 else endpt = current->i0;
1135
1136 if( curface==edge_lefts[j] )
1137 {
1138 splits[ manifold_len ] = 1;
1139 split_count ++;
1140 }
1141 else
1142 splits[ manifold_len ] = 0;
1143
1144 // Append to intermidiary manifold
1145 manifold[ manifold_len ].edge_index = edge_list[j];
1146 manifold[ manifold_len ].poly_left = edge_lefts[j];
1147 manifold[ manifold_len ].index = lastpt;
1148 manifold[ manifold_len ].poly_right =
1149 polygon_edge_map[ edge_list[j]*2 ] == edge_lefts[j]?
1150 polygon_edge_map[ edge_list[j]*2+1 ]:
1151 polygon_edge_map[ edge_list[j]*2+0 ];
1152 manifold_len ++;
1153
1154 curface = edge_lefts[j];
1155
1156 if(endpt == start) goto IL_MANIFOLD_COMPLETE;
1157 goto IL_MANIFOLD_CONTINUE;
1158 }
1159 }
1160 cxr_log( "Failed to link manifold, count: %d\n", manifold_len );
1161
1162 for( int j=0; j<solid->count; j++ )
1163 {
1164 cxr_log( "p%d\n", solid_buffer[solid->start+j] );
1165 struct cxr_polygon *poly = cxr_ab_ptr(&mesh->polys, solid_buffer[solid->start+j]);
1166 cxr_debug_poly( mesh, poly, vertices, (v4f){0.2,0.0,0.0,1.0} );
1167 }
1168
1169 for( int j=0; j<unique_edge_count; j++ )
1170 {
1171 struct cxr_edge *uedge = cxr_ab_ptr(&mesh->edges, edge_list[j]);
1172 cxr_debug_line(vertices[uedge->i0],vertices[uedge->i1],(v4f){0.4,0.0,0.0,1.0});
1173 }
1174
1175 for( int j=0; j<manifold_len-1; j++ )
1176 {
1177 struct cxr_loop *lp0 = &manifold[j],
1178 *lp1 = &manifold[cxr_range(j+1,manifold_len)];
1179
1180 cxr_debug_line(vertices[lp0->index],vertices[lp1->index], colour_error );
1181 }
1182
1183 cxr_debug_mesh( mesh, vertices, (v4f){0.0,0.0,0.0, 0.9} );
1184 *error = CXR_ERROR_BAD_MANIFOLD;
1185
1186 free(edge_list);
1187 free(edge_lefts);
1188 free(manifold);
1189 free(splits);
1190 free(edge_tagged);
1191 free(vertex_tagged);
1192 free(hot_edge);
1193 free(faces_tagged);
1194 free(solid_buffer);
1195 free(candidates);
1196 free(best_manifold);
1197 free(best_manifold_splits);
1198 free(polygon_edge_map);
1199 return NULL;
1200
1201 IL_MANIFOLD_COMPLETE:;
1202
1203 if( manifold_len < unique_edge_count )
1204 continue;
1205 else
1206 {
1207 if( split_count < fewest_manifold_splits )
1208 {
1209 fewest_manifold_splits = split_count;
1210 best_solid = solid;
1211
1212 for( int j=0; j<manifold_len; j++ )
1213 {
1214 best_manifold[j] = manifold[j];
1215 best_manifold_splits[j] = splits[j];
1216 }
1217 best_manifold_len = manifold_len;
1218 }
1219 }
1220 }
1221
1222 free(edge_list);
1223 free(edge_lefts);
1224 free(manifold);
1225 free(splits);
1226
1227 if( max_solid_faces < 2 )
1228 {
1229 *error = CXR_ERROR_NO_SOLIDS;
1230 free(edge_tagged);
1231 free(vertex_tagged);
1232 free(hot_edge);
1233 free(faces_tagged);
1234 free(solid_buffer);
1235 free(candidates);
1236 free(best_manifold);
1237 free(best_manifold_splits);
1238 free(polygon_edge_map);
1239 return NULL;
1240 }
1241
1242 if( best_solid != NULL )
1243 {
1244 struct cxr_mesh *pullmesh =
1245 cxr_alloc_mesh( best_solid->edge_count, best_solid->edge_count, best_solid->count );
1246
1247 // Add existing faces to pullsolid, and delete from main mesh
1248 for( int i=0; i<best_solid->count; i++ )
1249 {
1250 int nface_id = pullmesh->polys.count;
1251
1252 struct cxr_polygon *exist_face = cxr_ab_ptr(&mesh->polys, solid_buffer[best_solid->start+i]);
1253 struct cxr_polygon *new_face = cxr_ab_empty(&pullmesh->polys);
1254
1255 *new_face = *exist_face;
1256 new_face->loop_start = pullmesh->loops.count;
1257
1258 for( int j=0; j<exist_face->loop_total; j++ )
1259 {
1260 struct cxr_loop *exist_loop = cxr_ab_ptr(&mesh->loops, exist_face->loop_start+j);
1261 struct cxr_loop *new_loop = cxr_ab_empty(&pullmesh->loops);
1262
1263 new_loop->index = exist_loop->index;
1264 new_loop->poly_left = nface_id;
1265 new_loop->poly_right = -1;
1266 new_loop->edge_index = 0;
1267 v2_copy( exist_loop->uv, new_loop->uv );
1268 }
1269
1270 exist_face->loop_total = -1;
1271 }
1272
1273 // Split manifold up by unique planes if it has more than 1
1274 // otherwise, just use that face
1275 //
1276 // TODO: Need to build new manifold in sections, stably
1277 // currently there is an unsupported case where the manifold splits
1278 // are on located on an implicit face, causing 1-length manifolds.
1279
1280 int new_polys = 0;
1281 int pullmesh_new_start = pullmesh->polys.count;
1282
1283 if( fewest_manifold_splits != 0 )
1284 {
1285 #if CXR_MANIFOLD_DEBUG
1286 for( int i=0; i<best_manifold_len; i++ )
1287 {
1288 int i0 = i,
1289 i1 = cxr_range(i+1,best_manifold_len);
1290
1291 cxr_debug_line( vertices[best_manifold[i0].index], vertices[best_manifold[i1].index], colour_error );
1292 if( best_manifold_splits[i] )
1293 cxr_debug_box( vertices[best_manifold[i0].index], 0.04, colour_success );
1294 }
1295 #endif
1296
1297 // This is a really strange observation, however it *seems* to apply to the kinds
1298 // of geometry we are dealing with. If the split count is odd, the manifold can be
1299 // created easily, no folding required.
1300 //
1301 // When it is even, it appears that internal implicit geometry is required, so we
1302 // need to fold the loops we create. Its really weird, but for some reason works on
1303 // the geometry rules we've defined.
1304 // TODO: Find a well defined rule here.
1305
1306 int collapse_used_segments = (u32)fewest_manifold_splits & 0x1? 0: 1;
1307
1308 IL_MANIFOLD_BUILD_REPEAT:
1309
1310 for( int j=0; j<best_manifold_len; j++ )
1311 {
1312 if( best_manifold_splits[j] )
1313 {
1314 struct cxr_loop *loop = &best_manifold[j];
1315
1316 for( int k=1; k<best_manifold_len; k++ )
1317 {
1318 int index1 = cxr_range(j+k,best_manifold_len);
1319 struct cxr_loop *loop1 = &best_manifold[index1];
1320
1321 if( best_manifold_splits[index1] )
1322 {
1323 if( k==1 )
1324 break;
1325
1326 new_polys ++;
1327
1328 if( new_polys > best_manifold_len )
1329 {
1330 cxr_log( "Programming error: Too many new polys!\n" );
1331 exit(1);
1332 }
1333
1334 cxr_create_poly( pullmesh, vertices, best_manifold, k+1, j, best_manifold_len );
1335
1336 // Remove new section from manifold
1337 if( collapse_used_segments )
1338 {
1339 best_manifold_splits[j] = 0;
1340 best_manifold_splits[index1] = 0;
1341
1342 int new_length = (best_manifold_len-(k-1));
1343
1344 struct cxr_loop *new_manifold = malloc( new_length*sizeof(struct cxr_loop) );
1345 int *new_manifold_splits = malloc( new_length*sizeof(int) );
1346
1347 for( int l=0; l<new_length; l ++ )
1348 {
1349 int i_src = cxr_range( j+k+l, best_manifold_len );
1350 new_manifold[l] = best_manifold[i_src];
1351 new_manifold_splits[l] = best_manifold_splits[i_src];
1352 }
1353
1354 free( best_manifold );
1355 free( best_manifold_splits );
1356 best_manifold = new_manifold;
1357 best_manifold_splits = new_manifold_splits;
1358
1359 best_manifold_len = new_length;
1360
1361 goto IL_MANIFOLD_BUILD_REPEAT;
1362 }
1363
1364 j=j+k-1;
1365 break;
1366 }
1367 }
1368 }
1369 }
1370
1371 if( best_manifold_len && collapse_used_segments )
1372 {
1373 cxr_create_poly( pullmesh, vertices, best_manifold, best_manifold_len, 0, best_manifold_len );
1374 new_polys ++;
1375 }
1376 }
1377 else
1378 {
1379 cxr_create_poly( pullmesh, vertices, best_manifold, best_manifold_len, 0, best_manifold_len );
1380 new_polys = 1;
1381 }
1382
1383 // vert_buffer may be reallocated by the next section of code,
1384 // force a NULLref on vertices to catch any errors
1385 vertices = NULL;
1386
1387 // Implicit geometry reconstruction
1388 // If there's 3 or more planes, collide them together to see if any new
1389 // vertices need to be created on the mesh
1390 if( new_polys >= 3 )
1391 {
1392 for( int i=0; i<new_polys-2; i++ )
1393 {
1394 for( int j=i+1; j<new_polys-1; j++ )
1395 {
1396 for( int k=j+1; k<new_polys; k++ )
1397 {
1398 struct cxr_polygon *ptri = cxr_ab_ptr( &pullmesh->polys, pullmesh_new_start+i ),
1399 *ptrj = cxr_ab_ptr( &pullmesh->polys, pullmesh_new_start+j ),
1400 *ptrk = cxr_ab_ptr( &pullmesh->polys, pullmesh_new_start+k );
1401
1402 v4f planei, planej, planek;
1403 normal_to_plane(ptri->normal,ptri->center,planei);
1404 normal_to_plane(ptrj->normal,ptrj->center,planej);
1405 normal_to_plane(ptrk->normal,ptrk->center,planek);
1406
1407 v3f intersect;
1408
1409 if( plane_intersect(planei,planej,planek,intersect) )
1410 {
1411 // cxr_debug_box( intersect, 0.05, colour_error );
1412
1413 // Make sure this point is within the convex region, otherwise treat
1414 // it as a degenerate case
1415
1416 int point_valid = 1;
1417 for( int l=0; l<pullmesh->polys.count; l++ )
1418 {
1419 struct cxr_polygon *ptrl = cxr_ab_ptr(&pullmesh->polys,l);
1420 v4f planel;
1421
1422 normal_to_plane(ptrl->normal, ptrl->center, planel);
1423
1424 if( plane_polarity( planel, intersect ) > 0.01 )
1425 {
1426 cxr_log( "degen vert, planes %d, %d, %d [max:%d]\n", i,j,k, new_polys );
1427 *error = CXR_ERROR_DEGEN_IMPLICIT;
1428
1429 cxr_debug_poly( pullmesh, ptri, cxr_ab_ptr(vert_buffer,0), colours_random[3] );
1430 cxr_debug_poly( pullmesh, ptrj, cxr_ab_ptr(vert_buffer,0), colours_random[1] );
1431 cxr_debug_poly( pullmesh, ptrk, cxr_ab_ptr(vert_buffer,0), colours_random[2] );
1432
1433 point_valid = 0;
1434 break;
1435 }
1436 }
1437
1438 if( !point_valid ) continue;
1439
1440 // Extend faces to include this point
1441 int nvertid = vert_buffer->count;
1442 cxr_ab_push( vert_buffer, intersect );
1443
1444 ptrj->loop_start += 1;
1445 ptrk->loop_start += 2;
1446
1447 cxr_ab_reserve(&pullmesh->loops, 3);
1448 struct cxr_loop *lloopi = cxr_ab_empty_at(&pullmesh->loops, ptri->loop_start+ptri->loop_total),
1449 *lloopj = cxr_ab_empty_at(&pullmesh->loops, ptrj->loop_start+ptrj->loop_total),
1450 *lloopk = cxr_ab_empty_at(&pullmesh->loops, ptrk->loop_start+ptrk->loop_total);
1451
1452 lloopi->index = nvertid;
1453 lloopj->index = nvertid;
1454 lloopk->index = nvertid;
1455 lloopi->edge_index = 0; lloopj->edge_index = 0; lloopk->edge_index = 0;
1456 lloopi->poly_left = pullmesh_new_start+i;
1457 lloopj->poly_left = pullmesh_new_start+j;
1458 lloopk->poly_left = pullmesh_new_start+k;
1459 lloopi->poly_right = -1; lloopj->poly_right = -1; lloopk->poly_right = -1;
1460
1461 v2_zero(lloopi->uv);
1462 v2_zero(lloopj->uv);
1463 v2_zero(lloopk->uv);
1464
1465 ptri->loop_total ++;
1466 ptrj->loop_total ++;
1467 ptrk->loop_total ++;
1468
1469 // Adjust centers of faces
1470 v3_lerp( ptri->center, intersect, 1.0/(double)ptri->loop_total, ptri->center );
1471 v3_lerp( ptrj->center, intersect, 1.0/(double)ptrj->loop_total, ptrj->center );
1472 v3_lerp( ptrk->center, intersect, 1.0/(double)ptrk->loop_total, ptrk->center );
1473 }
1474 }
1475 }
1476 }
1477 }
1478
1479 // Copy faces from pullsolid into orig mesh
1480
1481 for( int i=0; i<new_polys; i++ )
1482 {
1483 int rface_id = mesh->polys.count;
1484
1485 struct cxr_polygon *pface = cxr_ab_ptr(&pullmesh->polys,pullmesh_new_start+i);
1486 struct cxr_polygon *rip_face = cxr_ab_empty(&mesh->polys);
1487
1488 rip_face->loop_start = mesh->loops.count;
1489 rip_face->loop_total = pface->loop_total;
1490 rip_face->material_id = -1;
1491
1492 for( int j=0; j<rip_face->loop_total; j++ )
1493 {
1494 struct cxr_loop *ploop = cxr_ab_ptr(&pullmesh->loops, pface->loop_start+pface->loop_total-j-1),
1495 *rloop = cxr_ab_empty(&mesh->loops);
1496
1497 rloop->index = ploop->index;
1498 rloop->poly_left = rface_id;
1499 rloop->poly_right = -1;
1500 rloop->edge_index = 0;
1501 v2_copy( ploop->uv, rloop->uv );
1502 }
1503
1504 v3_copy( pface->center, rip_face->center );
1505 v3_negate( pface->normal, rip_face->normal );
1506 }
1507
1508 cxr_mesh_clean_faces( mesh );
1509 cxr_mesh_clean_faces( pullmesh );
1510 cxr_mesh_clean_edges( mesh );
1511 cxr_mesh_clean_edges( pullmesh );
1512
1513 free(edge_tagged);
1514 free(vertex_tagged);
1515 free(hot_edge);
1516 free(faces_tagged);
1517 free(solid_buffer);
1518 free(candidates);
1519 free(best_manifold);
1520 free(best_manifold_splits);
1521 free(polygon_edge_map);
1522
1523 return pullmesh;
1524 }
1525
1526 free(edge_tagged);
1527 free(vertex_tagged);
1528 free(hot_edge);
1529 free(faces_tagged);
1530 free(solid_buffer);
1531 free(candidates);
1532 free(best_manifold);
1533 free(best_manifold_splits);
1534 free(polygon_edge_map);
1535
1536 return NULL;
1537 }
1538
1539 static struct cxr_mesh *cxr_to_internal_format(struct cxr_input_mesh *src, struct cxr_auto_buffer *abverts)
1540 {
1541 // Split mesh into islands
1542 struct cxr_mesh *mesh = cxr_alloc_mesh( src->edge_count, src->loop_count, src->poly_count );
1543 cxr_ab_init( abverts, sizeof(v3f), src->vertex_count );
1544
1545 // Copy input data into working mesh
1546 memcpy( cxr_ab_ptr( &mesh->edges, 0 ), src->edges, src->edge_count*sizeof(struct cxr_edge));
1547 memcpy( cxr_ab_ptr( &mesh->polys, 0 ), src->polys, src->poly_count*sizeof(struct cxr_polygon));
1548 memcpy( cxr_ab_ptr( abverts, 0 ), src->vertices, src->vertex_count*sizeof(v3f));
1549 mesh->edges.count = src->edge_count;
1550 mesh->loops.count = src->loop_count;
1551 mesh->polys.count = src->poly_count;
1552
1553 for( int i=0; i<src->loop_count; i++ )
1554 {
1555 struct cxr_loop *lp = cxr_ab_ptr(&mesh->loops,i);
1556 lp->index = src->loops[i].index;
1557 lp->edge_index = src->loops[i].edge_index;
1558 v2_copy( src->loops[i].uv, lp->uv );
1559 }
1560
1561 abverts->count = src->vertex_count;
1562
1563 return mesh;
1564 }
1565
1566 // Find farthest dot product along direction
1567 static double support_distance( v3f verts[3], v3f dir, double coef )
1568 {
1569 return cxr_maxf
1570 (
1571 coef * v3_dot( verts[0], dir ),
1572 cxr_maxf
1573 (
1574 coef * v3_dot( verts[1], dir ),
1575 coef * v3_dot( verts[2], dir )
1576 )
1577 );
1578 }
1579
1580 // Main function
1581 static void cxr_calculate_axis(
1582 struct cxr_texinfo *transform,
1583 v3f verts[3],
1584 v2f uvs[3],
1585 v2f texture_res
1586 )
1587 {
1588 v2f tT, bT; // Tangent/bitangent pairs for UV space and world
1589 v3f tW, bW;
1590
1591 v2_sub( uvs[0], uvs[1], tT );
1592 v2_sub( uvs[2], uvs[1], bT );
1593 v3_sub( verts[0], verts[1], tW );
1594 v3_sub( verts[2], verts[1], bW );
1595
1596 // Use arbitrary projection if there is no UV
1597 if( v2_length( tT ) < 0.0001 || v2_length( bT ) < 0.0001 )
1598 {
1599 v3f uaxis, normal, vaxis;
1600
1601 v3_copy( tW, uaxis );
1602 v3_normalize( uaxis );
1603
1604 v3_cross( tW, bW, normal );
1605 v3_cross( normal, uaxis, vaxis );
1606 v3_normalize( vaxis );
1607
1608 v3_copy( uaxis, transform->uaxis );
1609 v3_copy( vaxis, transform->vaxis );
1610 v2_zero( transform->offset );
1611
1612 v2_div( (v2f){128.0, 128.0}, texture_res, transform->scale );
1613 transform->winding = 1.0;
1614 return;
1615 }
1616
1617 // Detect if UV is reversed
1618 double winding = v2_cross( tT, bT ) >= 0.0f? 1.0f: -1.0f;
1619
1620 // UV projection reference
1621 v2f vY, vX;
1622 v2_muls((v2f){1,0}, winding, vX);
1623 v2_muls((v2f){0,1}, winding, vY);
1624
1625 // Reproject reference into world space, including skew
1626 v3f uaxis1, vaxis1;
1627
1628 v3_muls( tW, v2_cross(vX,bT) / v2_cross(bT,tT), uaxis1 );
1629 v3_muladds( uaxis1, bW, v2_cross(vX, tT) / v2_cross(tT,bT), uaxis1 );
1630
1631 v3_muls( tW, v2_cross(vY,bT) / v2_cross(bT,tT), vaxis1 );
1632 v3_muladds( vaxis1, bW, v2_cross(vY,tT) / v2_cross(tT,bT), vaxis1 );
1633
1634 v3_normalize( uaxis1 );
1635 v3_normalize( vaxis1 );
1636
1637 // Apply source transform to axis (yes, they also need to be swapped)
1638 v3f norm, uaxis, vaxis;
1639
1640 v3_cross( bW, tW, norm );
1641 v3_normalize(norm);
1642 v3_cross( vaxis1, norm, uaxis );
1643 v3_cross( uaxis1, norm, vaxis );
1644
1645 // real UV scale
1646 v2f uvmin, uvmax, uvdelta;
1647 v2_minv( uvs[0], uvs[1], uvmin );
1648 v2_minv( uvmin, uvs[2], uvmin );
1649 v2_maxv( uvs[0], uvs[1], uvmax );
1650 v2_maxv( uvmax, uvs[2], uvmax );
1651
1652 v2_sub( uvmax, uvmin, uvdelta );
1653
1654 // world-uv scale
1655 v2f uvminw, uvmaxw, uvdeltaw;
1656 uvminw[0] = -support_distance( verts, uaxis, -1.0f );
1657 uvmaxw[0] = support_distance( verts, uaxis, 1.0f );
1658 uvminw[1] = -support_distance( verts, vaxis, -1.0f );
1659 uvmaxw[1] = support_distance( verts, vaxis, 1.0f );
1660
1661 v2_sub( uvmaxw, uvminw, uvdeltaw );
1662
1663 // VMf uv scale
1664 v2f uv_scale;
1665 v2_div( uvdeltaw, uvdelta, uv_scale );
1666 v2_div( uv_scale, texture_res, uv_scale );
1667
1668 // Find offset via 'natural' point
1669 v2f target_uv, natural_uv, tex_offset;
1670 v2_mul( uvs[0], texture_res, target_uv );
1671
1672 natural_uv[0] = v3_dot( uaxis, verts[0] );
1673 natural_uv[1] = -v3_dot( vaxis, verts[0] );
1674 v2_div( natural_uv, uv_scale, natural_uv );
1675
1676 tex_offset[0] = target_uv[0]-natural_uv[0];
1677 tex_offset[1] = -(target_uv[1]-natural_uv[1]);
1678
1679 // Copy everything into output
1680 v3_copy( uaxis, transform->uaxis );
1681 v3_copy( vaxis, transform->vaxis );
1682 v2_copy( tex_offset, transform->offset );
1683 v2_copy( uv_scale, transform->scale );
1684 transform->winding = winding;
1685 }
1686
1687 CXR_API struct cxr_input_mesh *cxr_decompose(struct cxr_input_mesh *src)
1688 {
1689 #ifdef CXR_DEBUG_WRITE_MESH
1690 FILE *yeet = fopen( "/home/harry/Documents/blender_addons_remote/addons/convexer/solid.h", "w" );
1691
1692 fprintf( yeet, "v3f test_verts[] = {\n" );
1693 for( int i=0; i<src->vertex_count; i ++ )
1694 {
1695 fprintf( yeet, " { %f, %f, %f },\n",
1696 src->vertices[i][0],
1697 src->vertices[i][1],
1698 src->vertices[i][2] );
1699 }
1700 fprintf( yeet, "};\n" );
1701
1702 fprintf( yeet, "struct cxr_input_loop test_loops[] = {\n" );
1703 for( int i=0; i<src->loop_count; i ++ )
1704 {
1705 fprintf( yeet, " {%d, %d},\n",
1706 src->loops[i].index,
1707 src->loops[i].edge_index);
1708 }
1709 fprintf( yeet, "};\n" );
1710
1711 fprintf( yeet, "struct cxr_polygon test_polys[] = {\n" );
1712 for( int i=0; i <src->poly_count; i++ )
1713 {
1714 fprintf( yeet, " {%d, %d, {%f, %f, %f}, {%f, %f, %f}},\n",
1715 src->polys[i].loop_start,
1716 src->polys[i].loop_total,
1717 src->polys[i].normal[0],
1718 src->polys[i].normal[1],
1719 src->polys[i].normal[2],
1720 src->polys[i].center[0],
1721 src->polys[i].center[1],
1722 src->polys[i].center[2] );
1723 }
1724 fprintf( yeet, "};\n" );
1725
1726 fprintf( yeet, "struct cxr_edge test_edges[] = {\n" );
1727 for( int i=0; i<src->edge_count; i++ )
1728 {
1729 fprintf( yeet, " {%d, %d},\n",
1730 src->edges[i].i0,
1731 src->edges[i].i1
1732 );
1733 }
1734 fprintf( yeet, "};\n" );
1735
1736 fprintf( yeet, "struct cxr_input_mesh test_mesh = {\n" );
1737 fprintf( yeet, " .vertices = test_verts,\n" );
1738 fprintf( yeet, " .loops = test_loops,\n" );
1739 fprintf( yeet, " .edges = test_edges,\n" );
1740 fprintf( yeet, " .polys = test_polys,\n" );
1741 fprintf( yeet, " .poly_count=%d,\n", src->poly_count );
1742 fprintf( yeet, " .vertex_count=%d,\n", src->vertex_count );
1743 fprintf( yeet, " .edge_count=%d,\n",src->edge_count );
1744 fprintf( yeet, " .loop_count=%d\n", src->loop_count );
1745 fprintf( yeet, "};\n" );
1746
1747 fclose( yeet );
1748 #endif
1749
1750 struct cxr_auto_buffer abverts;
1751 struct cxr_mesh *main_mesh = cxr_to_internal_format( src, &abverts );
1752
1753 u32 error = 0x00;
1754
1755 struct cxr_auto_buffer solids;
1756 cxr_ab_init( &solids, sizeof(struct cxr_mesh *), 2 );
1757
1758 // TODO: Preprocessor stages
1759 // - Split mesh up into islands before doing anything here
1760 // - Snap vertices to grid (0.25u) ?
1761 while(1)
1762 {
1763 struct cxr_mesh *res = cxr_pull_best_solid( main_mesh, &abverts, 0, &error );
1764 if( res )
1765 {
1766 cxr_ab_push( &solids, &res );
1767 if( error ) break;
1768 }
1769 else
1770 {
1771 if( error )
1772 {
1773 // If no solids error we can rety while preserving 'hot' edges
1774
1775 if( error & CXR_ERROR_NO_SOLIDS )
1776 {
1777 error = 0x00;
1778 res = cxr_pull_best_solid(main_mesh, &abverts, 1, &error);
1779
1780 if( res ) cxr_ab_push( &solids, &res );
1781 else break;
1782
1783 if( error ) break;
1784 }
1785 else break;
1786 }
1787 else
1788 break;
1789 }
1790 }
1791
1792 cxr_ab_push( &solids, &main_mesh );
1793
1794 if( !error )
1795 {
1796 for( int i=0; i<solids.count; i++ )
1797 {
1798 struct cxr_mesh **mptr = cxr_ab_ptr(&solids,i);
1799 cxr_debug_mesh( *mptr, cxr_ab_ptr(&abverts,0), colours_random[cxr_range(i,8)] );
1800 }
1801 }
1802
1803 for( int i=0; i<solids.count; i++ )
1804 {
1805 struct cxr_mesh **mptr = cxr_ab_ptr(&solids,i);
1806 cxr_free_mesh( *mptr );
1807 }
1808
1809 cxr_ab_free( &abverts );
1810 cxr_ab_free( &solids );
1811
1812 return NULL;
1813 }
1814
1815 static int cxr_cardinal( v3f a, int ignore )
1816 {
1817 int component = 0;
1818 double component_max = -CXR_BIG_NUMBER;
1819
1820 for( int i=0; i<3; i++ )
1821 {
1822 if( i == ignore ) continue;
1823
1824 if( fabs(a[i]) > component_max )
1825 {
1826 component_max = fabs(a[i]);
1827 component = i;
1828 }
1829 }
1830 double d = a[component] >= 0.0? 1.0: -1.0;
1831 v3_zero( a );
1832 a[component] = d;
1833
1834 return component;
1835 }
1836
1837 // Convert contiguous mesh to patch of displacments
1838 //
1839 static void cxr_write_disp(struct cxr_mesh *mesh, struct cxr_input_mesh *inputmesh,
1840 struct cxr_vdf *output,
1841 struct cxr_auto_buffer *abverts)
1842 {
1843 // Create a graph which maps vertices by their connections
1844 struct vertinfo
1845 {
1846 int con_start, con_count; // Index into the connection graph
1847 int boundary,
1848 used,
1849 search,
1850 corner;
1851
1852 double alpha;
1853 }
1854 *vertinfo = malloc( sizeof(struct vertinfo)*abverts->count );
1855 int *graph = malloc( sizeof(int) * mesh->edges.count*2 );
1856
1857 int con_pos = 0;
1858 for( int i=0; i<abverts->count; i++ )
1859 {
1860 struct vertinfo *info = &vertinfo[i];
1861 info->con_start = con_pos;
1862 info->con_count = 0;
1863 info->boundary = 0;
1864 info->corner = 0;
1865 info->used = 0;
1866 info->search = 0;
1867 info->alpha = 0.0;
1868
1869 for( int j=0; j<mesh->edges.count; j++ )
1870 {
1871 struct cxr_edge *edge = cxr_ab_ptr(&mesh->edges,j);
1872
1873 if( edge->i0 == i || edge->i1 == i )
1874 {
1875 graph[ con_pos ++ ] = edge->i0 == i? edge->i1: edge->i0;
1876 info->con_count ++;
1877
1878 if( edge->freestyle )
1879 info->boundary = 1;
1880 }
1881 }
1882 }
1883
1884 // Find best normal for brush patch. VBSP uses the original brush
1885 // as reference for decal projection.
1886 //
1887 // These are clamped to be cardinal directions as to make the VMF somewhat
1888 // human editable.
1889
1890 v3f avg_normal, refv, refu, refn;
1891 v3_zero(refv); v3_zero(refu); v3_zero(refn);
1892
1893 for( int i=0; i<mesh->polys.count; i++ )
1894 {
1895 struct cxr_polygon *poly = cxr_ab_ptr( &mesh->polys, i );
1896 v3_add( poly->normal, avg_normal, avg_normal );
1897 }
1898 v3_divs( avg_normal, mesh->polys.count, avg_normal );
1899 v3_normalize( avg_normal ); // TODO: This can be zero length. Should add a safety check
1900 // normalize function that checks for small length before
1901 // carrying out, otherwise we get inf/nan values...
1902 int n_cardinal = cxr_cardinal( avg_normal, -1 );
1903
1904 // Approximately matching the area of the result brush faces to the actual area
1905 // this is to assign a 'best guess' amount of lightmap texels.
1906 //
1907 double uv_area = 0.0, face_area = 0.0, sf;
1908 v2f uvboundmin, uvboundmax;
1909 v3f faceboundmin, faceboundmax;
1910 v2f uv_center;
1911 v3f face_center;
1912
1913 v2_fill( uvboundmin, CXR_BIG_NUMBER );
1914 v2_fill( uvboundmax, -CXR_BIG_NUMBER );
1915 v3_fill( faceboundmin, CXR_BIG_NUMBER );
1916 v3_fill( faceboundmax, -CXR_BIG_NUMBER );
1917
1918 for( int i=0; i<mesh->polys.count; i++ )
1919 {
1920 struct cxr_polygon *poly = cxr_ab_ptr( &mesh->polys, i );
1921
1922 for( int j=0; j<poly->loop_total; j++ )
1923 {
1924 struct cxr_loop *lp0 = cxr_ab_ptr(&mesh->loops, poly->loop_start+j);
1925 v2_minv( lp0->uv, uvboundmin, uvboundmin);
1926 v2_maxv( lp0->uv, uvboundmax, uvboundmax);
1927 v3_minv( cxr_ab_ptr(abverts,lp0->index), faceboundmin, faceboundmin );
1928 v3_maxv( cxr_ab_ptr(abverts,lp0->index), faceboundmax, faceboundmax );
1929 }
1930
1931 for( int j=0; j<poly->loop_total-2; j++ )
1932 {
1933 struct cxr_loop *lp0 = cxr_ab_ptr(&mesh->loops, poly->loop_start),
1934 *lp1 = cxr_ab_ptr(&mesh->loops, poly->loop_start+j+1),
1935 *lp2 = cxr_ab_ptr(&mesh->loops, poly->loop_start+j+2);
1936 v3f va, vb, orth;
1937 v3_sub( cxr_ab_ptr(abverts,lp1->index), cxr_ab_ptr(abverts,lp0->index), va );
1938 v3_sub( cxr_ab_ptr(abverts,lp2->index), cxr_ab_ptr(abverts,lp0->index), vb );
1939 v3_cross( va, vb, orth );
1940
1941 face_area += v3_length( orth ) / 2.0;
1942
1943 v2f uva, uvb;
1944 v2_sub( lp1->uv, lp0->uv, uva );
1945 v2_sub( lp2->uv, lp0->uv, uvb );
1946
1947 uv_area += fabs(v2_cross( uva, uvb )) / 2.0;
1948 }
1949 }
1950
1951 v3_add( faceboundmax, faceboundmin, face_center );
1952 v3_muls( face_center, 0.5, face_center );
1953 v2_add( uvboundmin, uvboundmax, uv_center );
1954 v2_muls( uv_center, 0.5, uv_center );
1955
1956 sf = sqrt( face_area / uv_area );
1957 int corner_count = 0;
1958
1959 // Vertex classification
1960 for( int i=0; i<abverts->count; i++ )
1961 {
1962 struct vertinfo *info = &vertinfo[i];
1963 if( !info->boundary ) continue;
1964
1965 int count = 0,
1966 non_manifold = 1;
1967
1968 for( int j=0; j<info->con_count; j++ )
1969 {
1970 int con = graph[info->con_start+j];
1971
1972 if( vertinfo[con].boundary )
1973 count ++;
1974 else
1975 non_manifold = 0;
1976 }
1977 if( count > 2 || non_manifold )
1978 {
1979 info->corner = 1;
1980 corner_count ++;
1981
1982 //cxr_debug_box( cxr_ab_ptr(abverts,i), 0.1, colour_success );
1983 }
1984 }
1985
1986 int dispedge[16];
1987 v2f corner_uvs[4];
1988 int dispedge_count;
1989 int disp_count = 0;
1990
1991 for( int i=0; i<mesh->polys.count; i++ )
1992 {
1993 struct cxr_polygon *basepoly = cxr_ab_ptr(&mesh->polys,i);
1994
1995 for( int h=0; h<basepoly->loop_total; h ++ )
1996 {
1997 int i0 = h,
1998 i1 = cxr_range(h+1,basepoly->loop_total);
1999
2000 struct cxr_loop *l0 = cxr_ab_ptr(&mesh->loops, basepoly->loop_start+i0),
2001 *l1 = cxr_ab_ptr(&mesh->loops, basepoly->loop_start+i1);
2002 struct vertinfo *info = &vertinfo[ l0->index ];
2003
2004 if( info->corner )
2005 {
2006 int corner_count = 1;
2007
2008 struct cxr_material *matptr =
2009 basepoly->material_id < 0 || inputmesh->material_count == 0?
2010 &cxr_nodraw:
2011 &inputmesh->materials[ basepoly->material_id ];
2012
2013 dispedge_count = 2;
2014 dispedge[0] = l0->index;
2015 dispedge[1] = l1->index;
2016 v2_copy( l0->uv, corner_uvs[0] );
2017
2018 // Consume (remove) faces we use for corners
2019 basepoly->loop_total = -1;
2020
2021 //cxr_debug_box( cxr_ab_ptr(abverts,l0->index),0.08,(v4f){0.0,0.0,1.0,1.0});
2022
2023 // Collect edges
2024 // --------------------
2025
2026 while( dispedge_count < 17 )
2027 {
2028 struct vertinfo *edge_head = &vertinfo[dispedge[dispedge_count-1]];
2029 int newvert = 0;
2030
2031 if( edge_head->corner )
2032 {
2033 // Find a polygon that has the edge C-1 -> C
2034 for( int j=0; j<mesh->polys.count && !newvert; j++ )
2035 {
2036 struct cxr_polygon *poly = cxr_ab_ptr(&mesh->polys,j);
2037
2038 for( int k=0; k<poly->loop_total; k ++ )
2039 {
2040 int i0 = k,
2041 i1 = cxr_range(k+1,poly->loop_total);
2042
2043 struct cxr_loop *l0 = cxr_ab_ptr(&mesh->loops, poly->loop_start+i0),
2044 *l1 = cxr_ab_ptr(&mesh->loops, poly->loop_start+i1);
2045
2046 if( l0->index == dispedge[dispedge_count-2] &&
2047 l1->index == dispedge[dispedge_count-1] )
2048 {
2049 // Take the vertex after that edge
2050 v2_copy( l1->uv, corner_uvs[corner_count ++] );
2051
2052 int i2 = cxr_range(i1+1,poly->loop_total);
2053 struct cxr_loop *l2 = cxr_ab_ptr(&mesh->loops, poly->loop_start+i2);
2054
2055 dispedge[dispedge_count ++] = l2->index;
2056 newvert = 1;
2057 poly->loop_total = -1;
2058 break;
2059 }
2060 }
2061 }
2062 }
2063 else
2064 {
2065 for( int j=0; j<edge_head->con_count; j++ )
2066 {
2067 int con = graph[edge_head->con_start+j];
2068
2069 if( con == -1 )
2070 continue;
2071
2072 if( dispedge_count > 1 )
2073 if( con == dispedge[dispedge_count-2] )
2074 continue;
2075
2076 struct vertinfo *coninfo = &vertinfo[con];
2077
2078 if( !coninfo->boundary )
2079 continue;
2080
2081 /*
2082 cxr_debug_arrow( cxr_ab_ptr(abverts,dispedge[dispedge_count-1]),
2083 cxr_ab_ptr(abverts,con),
2084 (v3f){0,0,1},
2085 0.1,
2086 colour_success );
2087 */
2088
2089 dispedge[ dispedge_count ++ ] = con;
2090 newvert = 1;
2091
2092 break;
2093 }
2094 }
2095
2096 if( !newvert )
2097 {
2098 cxr_debug_box(cxr_ab_ptr(abverts,dispedge[dispedge_count-1]), 0.1, colour_error);
2099 break;
2100 }
2101 }
2102
2103 // --------------------
2104 // Edges collected
2105
2106 v2f va, vb;
2107 v2_sub( corner_uvs[1], corner_uvs[0], va );
2108 v2_sub( corner_uvs[2], corner_uvs[0], vb );
2109
2110 // Connect up the grid
2111 //
2112 // 0 1 2 3 4
2113 // 15 a b c d
2114 // 14 e f g h
2115 // 13 i j k l
2116 // 12 m n o p
2117 //
2118 // Example: a := common unused vertex that is connected to
2119 // by 1 and 15. Or y-1, and x-1 on the grid.
2120 // g := c and f common vert ^
2121 //
2122 int grid[25];
2123
2124 for( int j=0; j<5; j++ ) grid[j] = dispedge[j];
2125 for( int j=1; j<5; j++ ) grid[j*5+4] = dispedge[j+4];
2126 for( int j=0; j<4; j++ ) grid[4*5+3-j] = dispedge[j+9];
2127 for( int j=1; j<4; j++ ) grid[j*5] = dispedge[16-j];
2128
2129 // Grid fill
2130 for( int j=1; j<4; j++ )
2131 {
2132 for( int k=1; k<4; k++ )
2133 {
2134 int s0 = grid[(j-1)*5+k],
2135 s1 = grid[j*5+k-1];
2136
2137 struct vertinfo *va = &vertinfo[s0],
2138 *vb = &vertinfo[s1];
2139
2140 // Find a common vertex between s0 and s1
2141
2142 for( int l=0; l<va->con_count; l ++ )
2143 {
2144 for( int m=0; m<vb->con_count; m ++ )
2145 {
2146 int cona = graph[va->con_start+l],
2147 conb = graph[vb->con_start+m];
2148
2149 if( cona == conb )
2150 {
2151 if( vertinfo[cona].used || vertinfo[cona].boundary )
2152 continue;
2153
2154 grid[ j*5+k ] = cona;
2155 vertinfo[cona].used = 1;
2156
2157 goto IL_MATCHED_DISP_INTERIOR_VERT;
2158 }
2159 }
2160 }
2161
2162 // Broken displacement
2163 cxr_log( "Broken displacement!\n" );
2164 free( graph );
2165 free( vertinfo );
2166 return;
2167
2168 IL_MATCHED_DISP_INTERIOR_VERT:;
2169 }
2170 }
2171
2172 // Create brush vertices based on UV map
2173
2174 // Create V reference based on first displacement.
2175 // TODO: This is not the moststable selection method!
2176 // faces can come in any order, so the first disp will of course
2177 // always vary. Additionaly the triangle can be oriented differently.
2178 //
2179 // Improvement can be made by selecting a first disp/triangle based
2180 // on deterministic factors.
2181 //
2182 if( disp_count == 0 )
2183 {
2184 struct cxr_texinfo tx;
2185 v3f tri_ref[3];
2186 v3_copy( cxr_ab_ptr(abverts,dispedge[0]), tri_ref[0] );
2187 v3_copy( cxr_ab_ptr(abverts,dispedge[4]), tri_ref[1] );
2188 v3_copy( cxr_ab_ptr(abverts,dispedge[8]), tri_ref[2] );
2189 cxr_calculate_axis( &tx, tri_ref, corner_uvs, (v2f){512,512} );
2190
2191 v3_muls( tx.vaxis, -1.0, refv );
2192 int v_cardinal = cxr_cardinal( refv, -1 );
2193
2194 v3_cross( tx.vaxis, tx.uaxis, refn );
2195 v3_muls( refn, -tx.winding, refn );
2196
2197 int n1_cardinal = cxr_cardinal( refn, v_cardinal );
2198
2199 //v3_copy( avg_normal, refn );
2200 int u_cardinal = 0;
2201 if( u_cardinal == n1_cardinal || u_cardinal == v_cardinal ) u_cardinal ++;
2202 if( u_cardinal == n1_cardinal || u_cardinal == v_cardinal ) u_cardinal ++;
2203
2204 v3_zero(refu);
2205 refu[u_cardinal] = tx.uaxis[u_cardinal] > 0.0? 1.0: -1.0;
2206
2207 v3f p0, pv, pu, pn;
2208
2209 v3_copy( face_center, p0 );
2210 v3_muladds( face_center, refn, 1.5, pn );
2211 v3_muladds( face_center, refv, 1.5, pv );
2212 v3_muladds( face_center, refu, 1.5, pu );
2213
2214 if( cxr_settings.debug )
2215 {
2216 cxr_debug_line( p0, pn, (v4f){0.0,0.0,1.0,1.0});
2217 cxr_debug_line( p0, pv, (v4f){0.0,1.0,0.0,1.0});
2218 cxr_debug_line( p0, pu, (v4f){1.0,0.0,0.0,1.0});
2219 cxr_debug_line( tri_ref[0], tri_ref[1], (v4f){1.0,1.0,1.0,1.0} );
2220 cxr_debug_line( tri_ref[1], tri_ref[2], (v4f){1.0,1.0,1.0,1.0} );
2221 cxr_debug_line( tri_ref[2], tri_ref[0], (v4f){1.0,1.0,1.0,1.0} );
2222 }
2223 }
2224
2225 // Create world cordinates
2226 v3f world_corners[8];
2227 v2f world_uv[4];
2228
2229 for( int j=0; j<4; j++ )
2230 {
2231 v2f local_uv;
2232 v2_sub( corner_uvs[j], uv_center, local_uv );
2233 v2_copy( corner_uvs[j], world_uv[j] );
2234 v2_muls( local_uv, sf, local_uv );
2235
2236 v3_muls( refu, local_uv[0], world_corners[j] );
2237 v3_muladds( world_corners[j], refv, local_uv[1], world_corners[j] );
2238 v3_add( face_center, world_corners[j], world_corners[j] );
2239 }
2240
2241 double *colour = colours_random[cxr_range(disp_count,8)];
2242
2243 for( int j=0; j<4; j++ )
2244 v3_muladds( world_corners[j], refn, -1.0, world_corners[j+4] );
2245
2246 if( cxr_settings.debug )
2247 {
2248 cxr_debug_arrow( world_corners[0], world_corners[1], avg_normal, 0.1, colour );
2249 cxr_debug_arrow( world_corners[1], world_corners[2], avg_normal, 0.1, colour );
2250 cxr_debug_arrow( world_corners[2], world_corners[3], avg_normal, 0.1, colour );
2251 cxr_debug_arrow( world_corners[3], world_corners[0], avg_normal, 0.1, colour );
2252 }
2253
2254 /*
2255 cxr_debug_arrow( world_corners[0+4], world_corners[1+4], avg_normal, 0.1, colour );
2256 cxr_debug_arrow( world_corners[1+4], world_corners[2+4], avg_normal, 0.1, colour );
2257 cxr_debug_arrow( world_corners[2+4], world_corners[3+4], avg_normal, 0.1, colour );
2258 cxr_debug_arrow( world_corners[3+4], world_corners[0+4], avg_normal, 0.1, colour );
2259 */
2260
2261 // Apply world transform
2262 for( int j=0; j<8; j++ )
2263 {
2264 v3_muls( world_corners[j], cxr_context.scale_factor, world_corners[j] );
2265 world_corners[j][2] += cxr_context.offset_z;
2266 }
2267
2268 struct cxr_texinfo texinfo_shared;
2269 cxr_calculate_axis( &texinfo_shared, world_corners, world_uv,
2270 (v2f){ matptr->res[0], matptr->res[1] } );
2271
2272 // Write brush
2273 cxr_vdf_node( output, "solid" );
2274 cxr_vdf_ki32( output, "id", ++ cxr_context.brush_count );
2275
2276 int sides[6][3] =
2277 {{ 0, 1, 2 },
2278 { 4, 6, 5 },
2279 { 4, 1, 0 },
2280 { 7, 0, 3 },
2281 { 6, 2, 1 },
2282 { 6, 3, 2 }};
2283
2284 v3f normals[25];
2285 double distances[25];
2286
2287 v3f lside0, lside1, lref, vdelta, vworld;
2288 double tx, ty;
2289
2290 for( int j=0; j<5; j++ )
2291 {
2292 ty = (double)j/(double)(5-1);
2293
2294 v3_lerp( world_corners[0], world_corners[3], ty, lside0 );
2295 v3_lerp( world_corners[1], world_corners[2], ty, lside1 );
2296
2297 for( int k=0; k<5; k++ )
2298 {
2299 int index = j*5+k;
2300
2301 tx = (double)k/(double)(5-1);
2302 v3_lerp( lside0, lside1, tx, lref );
2303 v3_muls( cxr_ab_ptr(abverts, grid[index]), cxr_context.scale_factor, vworld );
2304 vworld[2] += cxr_context.offset_z;
2305
2306 v3_sub( vworld, lref, vdelta );
2307 v3_copy( vdelta, normals[index] );
2308 v3_normalize( normals[index] );
2309 distances[index] = v3_dot( vdelta, normals[index] );
2310 }
2311 }
2312
2313 for( int j=0; j<6; j++ )
2314 {
2315 int *side = sides[j];
2316
2317 cxr_vdf_node( output, "side" );
2318 cxr_vdf_ki32( output, "id", ++ cxr_context.face_count );
2319 cxr_vdf_plane( output, "plane", world_corners[side[2]],
2320 world_corners[side[1]],
2321 world_corners[side[0]] );
2322
2323 cxr_vdf_kv( output, "material", matptr->vmt_path );
2324
2325 cxr_vdf_kaxis( output, "uaxis",
2326 texinfo_shared.uaxis,
2327 texinfo_shared.offset[0],
2328 texinfo_shared.scale[0] );
2329 cxr_vdf_kaxis( output, "vaxis",
2330 texinfo_shared.vaxis,
2331 texinfo_shared.offset[1],
2332 texinfo_shared.scale[1] );
2333
2334 cxr_vdf_kdouble( output, "rotation", 0.0 );
2335 cxr_vdf_ki32( output, "lightmapscale", cxr_settings.lightmap_scale );
2336 cxr_vdf_ki32( output, "smoothing_groups", 0 );
2337
2338 if( j == 0 )
2339 {
2340 cxr_vdf_node( output, "dispinfo" );
2341 cxr_vdf_ki32( output, "power", 2 );
2342 cxr_vdf_kv3f( output, "startposition", world_corners[0] );
2343 cxr_vdf_ki32( output, "flags", 0 );
2344 cxr_vdf_kdouble( output, "elevation", 0.0 );
2345 cxr_vdf_ki32( output, "subdiv", 0 );
2346
2347 cxr_vdf_node( output, "normals" );
2348 for( int k=0; k<5; k++ )
2349 cxr_vdf_karrv3f( output, "row", k, &normals[k*5], 5 );
2350 cxr_vdf_edon( output );
2351
2352 cxr_vdf_node( output, "distances" );
2353 for( int k=0; k<5; k++ )
2354 cxr_vdf_karrdouble( output, "row", k, &distances[k*5], 5 );
2355 cxr_vdf_edon( output );
2356
2357 // TODO: This might be needed for compiling...
2358 /*
2359 cxr_vdf_node( output, "offsets" );
2360 for( int k=0; k<5; k++ )
2361 cxr_vdf_printf( output, "\"row%d\" \"0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\"\n", k );
2362 cxr_vdf_edon( output );
2363
2364 cxr_vdf_node( output, "offset_normals" );
2365 for( int k=0; k<5; k++ )
2366 cxr_vdf_printf( output, "\"row%d\" \"0 0 1 0 0 1 0 0 1 0 0 1 0 0 1\"\n", k );
2367 cxr_vdf_edon( output );
2368
2369 cxr_vdf_node( output, "alphas" );
2370 for( int k=0; k<5; k++ )
2371 cxr_vdf_printf( output, "\"row%d\" \"0 0 0 0 0\"\n", k );
2372 cxr_vdf_edon( output );
2373
2374 cxr_vdf_node( output, "triangle_tags" );
2375 for( int k=0; k<5-1; k++ )
2376 cxr_vdf_printf( output, "\"row%d\" \"9 9 9 9 9 9 9 9\"\n", k );
2377 cxr_vdf_edon( output );
2378
2379 cxr_vdf_node( output, "allowed_verts" );
2380 cxr_vdf_printf( output, "\"10\" \"-1 -1 -1 -1 -1 -1 -1 -1 -1 -1\"\n" );
2381 cxr_vdf_edon( output );
2382 */
2383 cxr_vdf_edon( output );
2384 }
2385
2386 cxr_vdf_edon( output );
2387 }
2388
2389 cxr_vdf_node(output, "editor");
2390 cxr_vdf_colour255(output,"color", colours_random[cxr_range(cxr_context.brush_count,8)]);
2391 cxr_vdf_ki32(output,"visgroupshown",1);
2392 cxr_vdf_ki32(output,"visgroupautoshown",1);
2393 cxr_vdf_edon(output);
2394
2395 cxr_vdf_edon( output );
2396 disp_count ++;
2397 }
2398 }
2399 }
2400
2401 // Main loop
2402 #if 0
2403 int pool[25];
2404 for( int i=0; i<abverts->count; i++ )
2405 {
2406 struct vertinfo *info = &vertinfo[i];
2407 if( info->boundary || info->used )
2408 continue;
2409
2410 // Gather all vertices in this displacement
2411 int poolcount = 1,
2412 front_start = 0,
2413 front_count = 1;
2414 pool[0] = i;
2415 info->used = 1;
2416
2417 IL_GATHER_LOOP:;
2418
2419 int new_front_start = poolcount;
2420
2421 for( int j=0; j<front_count; j++ )
2422 {
2423 struct vertinfo *frontvert = &vertinfo[pool[front_start+j]];
2424
2425 for( int k=0; k<frontvert->con_count; k++ )
2426 {
2427 int conid = graph[frontvert->con_start+k];
2428 struct vertinfo *con = &vertinfo[conid];
2429
2430 if( frontvert->boundary && !con->boundary )
2431 continue;
2432
2433 if( con->used )
2434 continue;
2435
2436 if( poolcount == 25 )
2437 goto IL_DISP_ERROR_COUNT;
2438
2439 con->used = 1;
2440 pool[ poolcount ++ ] = conid;
2441 }
2442 }
2443
2444 if( poolcount > new_front_start )
2445 {
2446 front_start = new_front_start;
2447 front_count = poolcount-front_start;
2448
2449 goto IL_GATHER_LOOP;
2450 }
2451
2452 if( poolcount != 25 )
2453 {
2454 IL_DISP_ERROR_COUNT:
2455 for( int i=0; i<poolcount; i++ )
2456 cxr_debug_box( cxr_ab_ptr(abverts,pool[i]), 0.02, colour_error );
2457
2458 free(graph);
2459 free(vertinfo);
2460
2461 cxr_log("Invalid displacement (>25 verts)\n");
2462 return;
2463 }
2464
2465 int corners[4];
2466 int corner_count = 0;
2467 struct cxr_loop *cornerloops[4];
2468
2469 // Find corners, and get their loops (for uvs)
2470 // note: the mesh must be split where there is texture seams
2471 // so that two different uv'd loops cant ref the same vertex
2472 //
2473 for( int j=0; j<poolcount; j++ )
2474 {
2475 if( vertinfo[pool[j]].corner )
2476 {
2477 if( corner_count == 4 )
2478 {
2479 corner_count = -1;
2480 break;
2481 }
2482
2483 corners[corner_count] = j;
2484
2485 // find loop that includes this vert
2486 for( int k=0; k<mesh->loops.count; k++ )
2487 {
2488 struct cxr_loop *lp = cxr_ab_ptr(&mesh->loops,k);
2489 if( lp->index == pool[j] )
2490 {
2491 cornerloops[corner_count] = lp;
2492 break;
2493 }
2494 }
2495
2496 corner_count ++;
2497 }
2498 }
2499
2500 if( corner_count !=4 )
2501 {
2502 free(graph);
2503 free(vertinfo);
2504 cxr_log( "Invalid displacement (!=4 corners)\n" );
2505 return;
2506 }
2507
2508 int pivot = corners[0];
2509 }
2510 #endif
2511
2512 free( graph );
2513 free( vertinfo );
2514 }
2515
2516 CXR_API i32 cxr_convert_mesh_to_vmf(struct cxr_input_mesh *src, struct cxr_vdf *output)
2517 {
2518 // Split mesh into islands
2519 struct cxr_auto_buffer abverts;
2520 struct cxr_mesh *main_mesh = cxr_to_internal_format(src, &abverts);
2521
2522 u32 error = 0x00;
2523
2524 struct solidinf
2525 {
2526 struct cxr_mesh *pmesh;
2527 int is_displacement;
2528 };
2529
2530 struct cxr_auto_buffer solids;
2531 cxr_ab_init( &solids, sizeof(struct solidinf), 2 );
2532
2533 // TODO: Preprocessor stages
2534 // - Split mesh up into islands before doing anything here (DONE)
2535 // - Snap vertices to grid (0.25u) ?
2536
2537 // Preprocessor 1: Island seperation
2538 // ---------------
2539
2540 while(1)
2541 {
2542 struct cxr_mesh *res = cxr_pull_island( main_mesh );
2543 if( res )
2544 {
2545 cxr_ab_push( &solids, &(struct solidinf){ res, 0 });
2546 }
2547 else break;
2548 }
2549 cxr_ab_push( &solids, &(struct solidinf){main_mesh,0} );
2550
2551 // Preprocessor 2: Displacement break-out
2552 // ---------------
2553 for( int i=0; i<solids.count; i++ )
2554 {
2555 struct solidinf *pinf = cxr_ab_ptr(&solids,i);
2556
2557 for( int j=0; j<pinf->pmesh->polys.count; j++ )
2558 {
2559 struct cxr_polygon *poly = cxr_ab_ptr( &pinf->pmesh->polys, j );
2560
2561 for( int k=0; k<poly->loop_total; k++ )
2562 {
2563 struct cxr_loop *lp = cxr_ab_ptr( &pinf->pmesh->loops, poly->loop_start+k );
2564 struct cxr_edge *edge = cxr_ab_ptr( &pinf->pmesh->edges, lp->edge_index );
2565
2566 if( edge->freestyle )
2567 goto IL_SOLID_IS_DISPLACEMENT;
2568 }
2569 }
2570
2571 continue;
2572 IL_SOLID_IS_DISPLACEMENT:;
2573
2574 pinf->is_displacement = 1;
2575 cxr_write_disp( pinf->pmesh, src, output, &abverts );
2576 }
2577
2578 // Preprocessor 3: Breakup non-convex shapes into sub-solids
2579 // ---------------
2580 int sources_count = solids.count;
2581
2582 for( int i=0; i<sources_count; i++ )
2583 {
2584 struct solidinf pinf = *(struct solidinf *)cxr_ab_ptr(&solids, i);
2585
2586 if( pinf.is_displacement )
2587 continue;
2588
2589 while(1)
2590 {
2591 struct cxr_mesh *res = cxr_pull_best_solid( pinf.pmesh, &abverts, 0, &error );
2592
2593 if( res )
2594 {
2595 cxr_ab_push( &solids, &(struct solidinf){res,0} );
2596 if( error )
2597 break;
2598 }
2599 else
2600 {
2601 if( error )
2602 {
2603 // If no solids error we can rety while preserving 'hot' edges
2604
2605 if( error & CXR_ERROR_NO_SOLIDS )
2606 {
2607 error = 0x00;
2608 res = cxr_pull_best_solid(pinf.pmesh, &abverts, 1, &error);
2609
2610 if( res ) cxr_ab_push( &solids, &(struct solidinf){res,0} );
2611 else break;
2612
2613 if( error ) break;
2614 }
2615 else
2616 break;
2617 }
2618 else
2619 break;
2620 }
2621 }
2622 }
2623
2624 if( cxr_settings.debug )
2625 {
2626 for( int i=0; i<solids.count; i++ )
2627 {
2628 struct solidinf *solid = cxr_ab_ptr(&solids,i);
2629
2630 if( !solid->is_displacement )
2631 cxr_debug_mesh( solid->pmesh, cxr_ab_ptr(&abverts,0), colours_random[cxr_range(i,8)] );
2632 }
2633 }
2634
2635 // Turn all those solids into VMF brushes
2636 // --------------------------------------
2637 for( int i=0; i<solids.count; i++ )
2638 {
2639 struct solidinf *solid = cxr_ab_ptr(&solids,i);
2640
2641 if( solid->is_displacement ) continue;
2642
2643 cxr_vdf_node( output, "solid" );
2644 cxr_vdf_ki32( output, "id", ++ cxr_context.brush_count );
2645
2646 for( int j=0; j<solid->pmesh->polys.count; j++ )
2647 {
2648 struct cxr_polygon *poly = cxr_ab_ptr( &solid->pmesh->polys, j );
2649 struct cxr_loop *ploops = cxr_ab_ptr(&solid->pmesh->loops, poly->loop_start);
2650 struct cxr_material *matptr =
2651 poly->material_id < 0 || src->material_count == 0?
2652 &cxr_nodraw:
2653 &src->materials[ poly->material_id ];
2654
2655 cxr_vdf_node( output, "side" );
2656 cxr_vdf_ki32( output, "id", ++ cxr_context.face_count );
2657
2658 v3f verts[3]; v2f uvs[3];
2659
2660 v3_muls( cxr_ab_ptr(&abverts, ploops[0].index), cxr_context.scale_factor, verts[0] );
2661 v3_muls( cxr_ab_ptr(&abverts, ploops[1].index), cxr_context.scale_factor, verts[1] );
2662 v3_muls( cxr_ab_ptr(&abverts, ploops[2].index), cxr_context.scale_factor, verts[2] );
2663 verts[0][2] += cxr_context.offset_z;
2664 verts[1][2] += cxr_context.offset_z;
2665 verts[2][2] += cxr_context.offset_z;
2666
2667 v2_copy( ploops[0].uv, uvs[0] );
2668 v2_copy( ploops[1].uv, uvs[1] );
2669 v2_copy( ploops[2].uv, uvs[2] );
2670
2671 cxr_vdf_plane( output, "plane", verts[2], verts[1], verts[0] );
2672 cxr_vdf_kv( output, "material", matptr->vmt_path );
2673
2674 struct cxr_texinfo trans;
2675 cxr_calculate_axis(&trans, verts, uvs, (double[2]){ matptr->res[0], matptr->res[1] });
2676
2677 cxr_vdf_kaxis(output, "uaxis", trans.uaxis, trans.offset[0], trans.scale[0]);
2678 cxr_vdf_kaxis(output, "vaxis", trans.vaxis, trans.offset[1], trans.scale[1]);
2679
2680 cxr_vdf_kdouble(output, "rotation", 0.0 );
2681 cxr_vdf_ki32(output, "lightmapscale", cxr_settings.lightmap_scale );
2682 cxr_vdf_ki32(output, "smoothing_groups", 0);
2683
2684 cxr_vdf_edon( output );
2685 }
2686
2687 cxr_vdf_node(output, "editor");
2688 cxr_vdf_colour255(output,"color", colours_random[cxr_range(cxr_context.brush_count,8)]);
2689 cxr_vdf_ki32(output,"visgroupshown",1);
2690 cxr_vdf_ki32(output,"visgroupautoshown",1);
2691 cxr_vdf_edon(output);
2692
2693 cxr_vdf_edon( output );
2694 }
2695
2696 for( int i=0; i<solids.count; i++ )
2697 {
2698 struct solidinf *solid = cxr_ab_ptr(&solids,i);
2699 cxr_free_mesh( solid->pmesh );
2700 }
2701
2702 cxr_ab_free( &abverts );
2703 cxr_ab_free( &solids );
2704 return 0;
2705 }
2706
2707
2708 CXR_API void cxr_set_log_function( void (*func)(const char *str) )
2709 {
2710 cxr_log_func = func;
2711 }
2712
2713 CXR_API void cxr_set_line_function( void (*func)(v3f p0, v3f p1, v4f colour) )
2714 {
2715 cxr_line_func = func;
2716 }
2717
2718 CXR_API void cxr_settings_update( struct cxr_settings *settings )
2719 {
2720 cxr_settings = *settings;
2721 }
2722
2723 // Valve copyright stuff probably maybe
2724 // whatever, my previous copyright decleration ends here
2725 // ----------------------------------------------------------
2726
2727 #define HEADER_LUMPS 64
2728 #define LUMP_WORLDLIGHTS 54
2729
2730 #pragma pack(push,1)
2731
2732 struct header
2733 {
2734 int ident;
2735 int version;
2736
2737 struct lump
2738 {
2739 int fileofs, filelen;
2740 int version;
2741
2742 char fourCC[4];
2743 }
2744 lumps[ HEADER_LUMPS ];
2745
2746 int mapRevision;
2747 };
2748
2749 struct worldlight
2750 {
2751 float origin[3];
2752 float intensity[3];
2753 float normal[3];
2754 float shadow_cast_offset[3];
2755 int cluster;
2756 int type;
2757 int style;
2758 float stopdot;
2759 float stopdot2;
2760 float exponent;
2761 float radius;
2762 float constant_attn;
2763 float linear_attn;
2764 float quadratic_attn;
2765 int flags;
2766 int texinfo;
2767 int owner;
2768 };
2769 #pragma pack(pop)
2770
2771 // Utility for patching BSP tools to remove -1 distance lights (we set them
2772 // like that, because we want these lights to go away)
2773 //
2774 // Yes, there is no way to do this in hammer
2775 // Yes, the distance KV is unused but still gets compiled to this lump
2776 // No, Entities only compile will not do this for you
2777 //
2778 CXR_API int cxr_lightpatch_bsp( const char *path )
2779 {
2780 printf( "Lightpatch: %s\n", path );
2781
2782 FILE *fp = fopen( path, "r+b" );
2783
2784 if( !fp )
2785 {
2786 cxr_log( "Could not open BSP file for editing (r+b)\n" );
2787 return 0;
2788 }
2789
2790 // Read bsp
2791 struct header header;
2792 fread( &header, sizeof(struct header), 1, fp );
2793 struct lump *lump = &header.lumps[ LUMP_WORLDLIGHTS ];
2794
2795 // Read worldlight array
2796 struct worldlight *lights = malloc( lump->filelen );
2797 fseek( fp, lump->fileofs, SEEK_SET );
2798 fread( lights, lump->filelen, 1, fp );
2799
2800 // Remove all marked lights
2801 int light_count = lump->filelen / sizeof(struct worldlight);
2802 int new_count = 0;
2803
2804 for( int i = 0; i < light_count; i ++ )
2805 if( lights[i].radius >= 0.0f )
2806 lights[new_count++] = lights[i];
2807
2808 lump->filelen = new_count*sizeof(struct worldlight);
2809
2810 // Write changes
2811 fseek( fp, lump->fileofs, SEEK_SET );
2812 fwrite( lights, lump->filelen, 1, fp );
2813 fseek( fp, 0, SEEK_SET );
2814 fwrite( &header, sizeof(struct header), 1, fp );
2815 cxr_log( "removed %d marked lights\n", light_count-new_count );
2816
2817 fclose( fp );
2818 free( lights );
2819
2820 return 1;
2821 }