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