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