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