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