dd7a8b83092dffc3612042b87aba4216abe6b54f
[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
1339 /* Try remove splitting faces first */
1340 {
1341 int split_total = 0;
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 {
1363 split_total ++;
1364 continue;
1365 }
1366
1367 temp_solid[ temp_solid_len ++ ] = solid_buffer[solid->start+j];
1368 }
1369
1370 if( temp_solid_len < 3 || (split_total & 0x2) /* unkown reasons */ )
1371 {
1372 }
1373 else
1374 {
1375 /* Overwrite original solid */
1376 for( int j=0; j<temp_solid_len; j++ )
1377 solid_buffer[ solid->start+j ] = temp_solid[ j ];
1378
1379 solid->count = temp_solid_len;
1380 }
1381
1382 free( temp_solid );
1383 }
1384
1385 for( int j=0; j<solid->count; j++ )
1386 {
1387 cxr_polygon *poly = &mesh->polys[ solid_buffer[solid->start+j] ];
1388
1389 /* when discarding, if a face has only one loop that points outwards,
1390 * we keep it */
1391
1392
1393 for( int k=0; k<poly->loop_total; k++ )
1394 {
1395 cxr_loop *loop = &mesh->loops[ poly->loop_start+k ];
1396
1397 for( int l=0; l<unique_edge_count; l++ )
1398 if( edge_list[l]->edge_index == loop->edge_index )
1399 goto skip_edge;
1400
1401 for( int l=0; l<solid->count; l++ )
1402 if( loop->poly_right == solid_buffer[solid->start+l] )
1403 goto skip_edge;
1404
1405 edge_list[ unique_edge_count ] = loop;
1406
1407 if( unique_edge_count == 0 )
1408 {
1409 cxr_edge *edgeptr = &mesh->edges[ loop->edge_index ];
1410 if( edgeptr->i1 == loop->index )
1411 init_reverse = 1;
1412 }
1413
1414 unique_edge_count ++;
1415 skip_edge:;
1416 }
1417 }
1418
1419 if( unique_edge_count == 0 )
1420 {
1421 free( edge_list );
1422 manifold->status = k_manifold_none;
1423 return;
1424 }
1425
1426 /* Link edges together to form manifold */
1427 manifold->loops = malloc( solid->edge_count*sizeof(struct manifold_loop));
1428 manifold->split_count = 0;
1429 manifold->loop_count = 0;
1430
1431 cxr_edge *current = &mesh->edges[ edge_list[0]->edge_index ];
1432
1433 int endpt = (!init_reverse)? current->i0: current->i1,
1434 start = endpt,
1435 curface = edge_list[0]->poly_left;
1436
1437 manifold_continue:
1438 for( int j=0; j<unique_edge_count; j++ )
1439 {
1440 cxr_edge *other = &mesh->edges[ edge_list[j]->edge_index ];
1441 if( other == current )
1442 continue;
1443
1444 if( other->i0 == endpt || other->i1 == endpt )
1445 {
1446 current = other;
1447 int lastpt = endpt;
1448
1449 if( other->i0 == endpt ) endpt = current->i1;
1450 else endpt = current->i0;
1451
1452 struct manifold_loop *ml = &manifold->loops[ manifold->loop_count ++ ];
1453
1454 if( curface==edge_list[j]->poly_left )
1455 {
1456 ml->split = 1;
1457 manifold->split_count ++;
1458 }
1459 else
1460 ml->split = 0;
1461
1462 ml->loop.edge_index = edge_list[j]->edge_index;
1463 ml->loop.poly_left = edge_list[j]->poly_left;
1464 ml->loop.index = lastpt;
1465 ml->loop.poly_right = edge_list[j]->poly_right;
1466
1467 curface = edge_list[j]->poly_left;
1468
1469 if(endpt == start)
1470 {
1471 if( manifold->loop_count < unique_edge_count )
1472 manifold->status = k_manifold_fragmented;
1473 else
1474 manifold->status = k_manifold_complete;
1475
1476 goto manifold_complete;
1477 }
1478
1479 goto manifold_continue;
1480 }
1481 }
1482
1483 /* Incomplete links */
1484 manifold->status = k_manifold_err;
1485
1486 manifold_complete:
1487
1488 free( edge_list );
1489 return;
1490 }
1491
1492 /*
1493 * Reconstruct implied internal geometry where the manifold doesn't have
1494 * enough information (vertices) to create a full result.
1495 */
1496 static int cxr_build_implicit_geo( cxr_mesh *mesh, int new_polys, int start )
1497 {
1498 for( int i=0; i<new_polys-2; i++ )
1499 {
1500 for( int j=i+1; j<new_polys-1; j++ )
1501 {
1502 for( int k=j+1; k<new_polys; k++ )
1503 {
1504 cxr_polygon *ptri = &mesh->polys[ start+i ],
1505 *ptrj = &mesh->polys[ start+j ],
1506 *ptrk = &mesh->polys[ start+k ];
1507
1508 v4f planei, planej, planek;
1509 normal_to_plane(ptri->normal,ptri->center,planei);
1510 normal_to_plane(ptrj->normal,ptrj->center,planej);
1511 normal_to_plane(ptrk->normal,ptrk->center,planek);
1512
1513 v3f intersect;
1514
1515 if( plane_intersect(planei,planej,planek,intersect) )
1516 {
1517 /* Make sure the point is inside the convex region */
1518
1519 int point_valid = 1;
1520 for( int l=0; l<mesh->abpolys.count; l++ )
1521 {
1522 cxr_polygon *ptrl = &mesh->polys[l];
1523 v4f planel;
1524
1525 normal_to_plane(ptrl->normal, ptrl->center, planel);
1526
1527 if( plane_polarity( planel, intersect ) > 0.01 )
1528 {
1529 #ifdef CXR_DEBUG
1530 cxr_log( "degen vert, planes %d, %d, %d [max:%d]\n",
1531 i,j,k, new_polys );
1532
1533 cxr_debug_poly( mesh, ptri, colours_random[3] );
1534 cxr_debug_poly( mesh, ptrj, colours_random[1] );
1535 cxr_debug_poly( mesh, ptrk, colours_random[2] );
1536 #endif
1537
1538 return 0;
1539 }
1540 }
1541
1542 /* Extend faces to include this vert */
1543
1544 int nvertid = mesh->p_abverts->count;
1545 cxr_ab_push( mesh->p_abverts, intersect );
1546
1547 ptrj->loop_start += 1;
1548 ptrk->loop_start += 2;
1549
1550 cxr_ab_reserve( &mesh->abloops, 3);
1551
1552 int newi = ptri->loop_start+ptri->loop_total,
1553 newj = ptrj->loop_start+ptrj->loop_total,
1554 newk = ptrk->loop_start+ptrk->loop_total;
1555
1556 cxr_loop
1557 *lloopi = cxr_ab_empty_at(&mesh->abloops, newi),
1558 *lloopj = cxr_ab_empty_at(&mesh->abloops, newj),
1559 *lloopk = cxr_ab_empty_at(&mesh->abloops, newk);
1560
1561 lloopi->index = nvertid;
1562 lloopi->edge_index = 0;
1563 lloopi->poly_left = start + i;
1564 lloopi->poly_right = -1;
1565
1566 lloopj->index = nvertid;
1567 lloopj->poly_left = start + j;
1568 lloopj->edge_index = 0;
1569 lloopj->poly_right = -1;
1570
1571 lloopk->index = nvertid;
1572 lloopk->edge_index = 0;
1573 lloopk->poly_left = start + k;
1574 lloopk->poly_right = -1;
1575
1576 v2_zero(lloopi->uv);
1577 v2_zero(lloopj->uv);
1578 v2_zero(lloopk->uv);
1579
1580 ptri->loop_total ++;
1581 ptrj->loop_total ++;
1582 ptrk->loop_total ++;
1583
1584 double qi = 1.0/(double)ptri->loop_total,
1585 qj = 1.0/(double)ptrj->loop_total,
1586 qk = 1.0/(double)ptrk->loop_total;
1587
1588 /* Adjust centers of faces */
1589 v3_lerp( ptri->center, intersect, qi, ptri->center );
1590 v3_lerp( ptrj->center, intersect, qj, ptrj->center );
1591 v3_lerp( ptrk->center, intersect, qk, ptrk->center );
1592 }
1593 }
1594 }
1595 }
1596
1597 return 1;
1598 }
1599
1600 static int cxr_reflex_err( cxr_mesh *mesh )
1601 {
1602 int error = 0;
1603 int *reflex_check = cxr_mesh_reflex_edges( mesh );
1604
1605 v3f *temp = cxr_ab_ptr(mesh->p_abverts, 0);
1606
1607 for( int i=0; i<mesh->abedges.count; i++ )
1608 {
1609 if( reflex_check[i] )
1610 {
1611 cxr_debug_line( temp[mesh->edges[i].i0],
1612 temp[mesh->edges[i].i1],
1613 colour_error );
1614 error ++;
1615 }
1616 }
1617
1618 free( reflex_check );
1619 return error;
1620 }
1621
1622 static int cxr_non_manifold_err( cxr_mesh *mesh )
1623 {
1624 if( !cxr_mesh_link_loops(mesh) )
1625 {
1626 #ifdef CXR_DEBUG
1627 cxr_log( "non-manifold edges are in the mesh: "
1628 "implicit internal geometry does not have full support\n" );
1629
1630 v3f *verts = cxr_ab_ptr( mesh->p_abverts, 0 );
1631
1632 for( int i=0; i<mesh->abloops.count; i++ )
1633 {
1634 cxr_loop *lp = &mesh->loops[i];
1635 cxr_edge *edge = &mesh->edges[lp->edge_index];
1636 cxr_debug_line( verts[edge->i0], verts[edge->i1], colours_random[1] );
1637
1638 if( lp->poly_left == -1 || lp->poly_right == -1 )
1639 {
1640 cxr_debug_line( verts[edge->i0], verts[edge->i1], colour_error );
1641 }
1642 }
1643 #endif
1644 return 1;
1645 }
1646
1647 return 0;
1648 }
1649
1650 /*
1651 * Convexer's main algorithm
1652 *
1653 * Return the best availible convex solid from mesh, and patch the existing mesh
1654 * to fill the gap where the new mesh left it.
1655 *
1656 * Returns NULL if shape is already convex or empty.
1657 * This function will not preserve edge data such as freestyle, sharp etc.
1658 */
1659 static cxr_mesh *cxr_pull_best_solid(
1660 cxr_mesh *mesh,
1661 int preserve_more_edges,
1662 enum cxr_soliderr *err )
1663 {
1664 *err = k_soliderr_none;
1665
1666 if( cxr_non_manifold_err( mesh ) )
1667 {
1668 *err = k_soliderr_non_manifold;
1669 return NULL;
1670 }
1671
1672 int *edge_tagged = cxr_mesh_reflex_edges( mesh );
1673 int *vertex_tagged = cxr_mesh_reflex_vertices( mesh );
1674
1675 /*
1676 * Connect all marked vertices that share an edge
1677 */
1678
1679 int *edge_important = malloc(mesh->abedges.count*sizeof(int));
1680 for( int i=0; i< mesh->abedges.count; i++ )
1681 edge_important[i] = 0;
1682
1683 for( int i=0; i<mesh->abpolys.count; i ++ )
1684 {
1685 cxr_polygon *poly = &mesh->polys[i];
1686 int not_tagged = -1,
1687 tag_count = 0;
1688
1689 for( int j=0; j<poly->loop_total; j++ )
1690 {
1691 cxr_loop *loop = &mesh->loops[ poly->loop_start+j ];
1692
1693 if( !edge_tagged[ loop->edge_index ] )
1694 {
1695 if( not_tagged == -1 )
1696 not_tagged = loop->edge_index;
1697 else
1698 goto edge_unimportant;
1699 }
1700 }
1701
1702 if( not_tagged != -1 )
1703 edge_important[not_tagged]=1;
1704
1705 edge_unimportant:;
1706 }
1707
1708 /*
1709 * Connect edges where both vertices are reflex, only if we are not
1710 * preserving them
1711 */
1712 for( int i=0; i<mesh->abedges.count; i ++ )
1713 {
1714 if( edge_important[i] && preserve_more_edges ) continue;
1715
1716 cxr_edge *edge = &mesh->edges[i];
1717 if( vertex_tagged[edge->i0] && vertex_tagged[edge->i1] )
1718 edge_tagged[i] = 1;
1719 }
1720
1721 free( edge_important );
1722
1723 int *faces_tagged = malloc(mesh->abpolys.count*sizeof(int));
1724 for( int i=0; i<mesh->abpolys.count; i++ )
1725 faces_tagged[i] = -1;
1726
1727 struct csolid *candidates;
1728 int *solid_buffer = malloc( mesh->abpolys.count*sizeof(int) ),
1729 solid_buffer_len = 0,
1730 candidate_count = 0;
1731
1732 candidates = malloc( mesh->abpolys.count *sizeof(struct csolid) );
1733
1734 /*
1735 * Create a valid, non-overlapping solid for every face present in the mesh
1736 */
1737 for( int i=0; i<mesh->abpolys.count; i++ )
1738 {
1739 if( faces_tagged[i] != -1 ) continue;
1740 faces_tagged[i] = i;
1741
1742 int *solid = &solid_buffer[ solid_buffer_len ];
1743 int len = cxr_buildsolid( mesh, i, solid, edge_tagged, faces_tagged );
1744
1745 /* add entry */
1746 struct csolid *csolid = &candidates[candidate_count ++];
1747 csolid->start = solid_buffer_len;
1748 csolid->count = len;
1749 csolid->edge_count = 0;
1750
1751 v3_zero( csolid->center );
1752 for( int j=0; j<len; j++ )
1753 {
1754 cxr_polygon *polyj = &mesh->polys[ solid[j] ];
1755 v3_add( polyj->center, csolid->center, csolid->center );
1756 csolid->edge_count += polyj->loop_total;
1757 }
1758 v3_divs( csolid->center, len, csolid->center );
1759 solid_buffer_len += len;
1760 }
1761
1762 free( edge_tagged );
1763 free( vertex_tagged );
1764 free( faces_tagged );
1765
1766 /*
1767 * Choosing the best solid: most defined manifold
1768 */
1769 struct csolid *best_solid = NULL;
1770 int fewest_manifold_splits = INT32_MAX;
1771
1772 struct temp_manifold best_manifold = { .loops = NULL, .loop_count = 0 };
1773 int max_solid_faces = 0;
1774
1775 for( int i=0; i<candidate_count; i++ )
1776 {
1777 struct csolid *solid = &candidates[i];
1778 max_solid_faces = cxr_max(max_solid_faces,solid->count);
1779
1780 if( solid->count <= 2 )
1781 continue;
1782
1783 struct temp_manifold manifold;
1784 cxr_link_manifold( mesh, solid, solid_buffer, &manifold);
1785
1786 if( manifold.status == k_manifold_err )
1787 {
1788 *err = k_soliderr_bad_manifold;
1789
1790 free(solid_buffer);
1791 free(candidates);
1792 free(manifold.loops);
1793 free(best_manifold.loops);
1794 return NULL;
1795 }
1796
1797 if( manifold.status == k_manifold_complete )
1798 {
1799 if( manifold.split_count < fewest_manifold_splits )
1800 {
1801 fewest_manifold_splits = manifold.split_count;
1802 best_solid = solid;
1803
1804 free( best_manifold.loops );
1805 best_manifold = manifold;
1806 continue;
1807 }
1808 }
1809
1810 if( manifold.status != k_manifold_none )
1811 free( manifold.loops );
1812 }
1813
1814 if( max_solid_faces < 2 )
1815 {
1816 *err = k_soliderr_no_solids;
1817 free(solid_buffer);
1818 free(candidates);
1819 free(best_manifold.loops);
1820 return NULL;
1821 }
1822
1823 if( best_solid != NULL )
1824 {
1825 cxr_mesh *pullmesh = cxr_alloc_mesh( best_solid->edge_count,
1826 best_solid->edge_count,
1827 best_solid->count,
1828 mesh->p_abverts );
1829
1830 for( int i=0; i<best_solid->count; i++ )
1831 {
1832 int nface_id = pullmesh->abpolys.count;
1833 int exist_plane_id = solid_buffer[best_solid->start+i];
1834
1835 cxr_polygon *exist_face = &mesh->polys[ exist_plane_id ],
1836 *new_face = cxr_ab_empty( &pullmesh->abpolys );
1837
1838 *new_face = *exist_face;
1839 new_face->loop_start = pullmesh->abloops.count;
1840
1841 for( int j=0; j<exist_face->loop_total; j++ )
1842 {
1843 cxr_loop *exist_loop = &mesh->loops[ exist_face->loop_start+j ],
1844 *new_loop = cxr_ab_empty(&pullmesh->abloops);
1845
1846 new_loop->index = exist_loop->index;
1847 new_loop->poly_left = nface_id;
1848 new_loop->poly_right = -1;
1849 new_loop->edge_index = 0;
1850 v2_copy( exist_loop->uv, new_loop->uv );
1851 }
1852
1853 exist_face->loop_total = -1;
1854 }
1855
1856 int new_polys = 0;
1857 int pullmesh_new_start = pullmesh->abpolys.count;
1858
1859 if( fewest_manifold_splits != 0 )
1860 {
1861 /* Unusual observation:
1862 * If the split count is odd, the manifold can be created easily
1863 *
1864 * If it is even, implicit internal geometry is needed to be
1865 * constructed. So the manifold gets folded as we create it segment
1866 * by segment.
1867 *
1868 * I'm not sure if this is a well defined rule of geometry, but seems
1869 * to apply to the data we care about.
1870 */
1871 int collapse_used_segments = (u32)fewest_manifold_splits & 0x1? 0: 1;
1872
1873 manifold_repeat:
1874
1875 for( int j=0; j < best_manifold.loop_count; j++ )
1876 {
1877 if( !best_manifold.loops[j].split ) continue;
1878
1879 cxr_loop *loop = &best_manifold.loops[j].loop;
1880
1881 for( int k=1; k< best_manifold.loop_count; k++ )
1882 {
1883 int index1 = cxr_range(j+k, best_manifold.loop_count );
1884 cxr_loop *loop1 = &best_manifold.loops[index1].loop;
1885
1886 if( best_manifold.loops[index1].split )
1887 {
1888 if( k==1 )
1889 break;
1890
1891 new_polys ++;
1892
1893 if( new_polys > best_manifold.loop_count )
1894 {
1895 #ifdef CXR_DEBUG
1896 cxr_log( "Programming error: Too many new polys!\n" );
1897 #endif
1898 exit(1);
1899 }
1900
1901 if( cxr_create_poly( pullmesh, k+1 ) )
1902 {
1903 for( int l=0; l<k+1; l++ )
1904 {
1905 int i0 = cxr_range(j+l, best_manifold.loop_count ),
1906 index = best_manifold.loops[ i0 ].loop.index;
1907
1908 cxr_poly_push_index( pullmesh, index );
1909 }
1910 cxr_poly_finish( pullmesh );
1911 }
1912
1913 /* Collapse down manifold */
1914 if( collapse_used_segments )
1915 {
1916 best_manifold.loops[j].split = 0;
1917 best_manifold.loops[index1].split = 0;
1918
1919 int new_length = (best_manifold.loop_count-(k-1));
1920
1921 struct temp_manifold new_manifold = {
1922 .loop_count = new_length
1923 };
1924 new_manifold.loops =
1925 malloc( new_length*sizeof(*new_manifold.loops) );
1926
1927 for( int l=0; l<new_length; l ++ )
1928 {
1929 int i_src = cxr_range( j+k+l, best_manifold.loop_count);
1930 new_manifold.loops[l] = best_manifold.loops[i_src];
1931 }
1932
1933 free( best_manifold.loops );
1934 best_manifold = new_manifold;
1935
1936 goto manifold_repeat;
1937 }
1938
1939 j=j+k-1;
1940 break;
1941 }
1942 }
1943 }
1944
1945 if( best_manifold.loop_count && collapse_used_segments )
1946 {
1947 cxr_create_poly_full( pullmesh, &best_manifold );
1948 new_polys ++;
1949 }
1950 }
1951 else
1952 {
1953 cxr_create_poly_full( pullmesh, &best_manifold );
1954 new_polys = 1;
1955 }
1956
1957 if( new_polys >= 3 )
1958 {
1959 if( !cxr_build_implicit_geo( pullmesh, new_polys, pullmesh_new_start ))
1960 {
1961 free(solid_buffer);
1962 free(candidates);
1963 free(best_manifold.loops);
1964
1965 cxr_free_mesh( pullmesh );
1966 *err = k_soliderr_degenerate_implicit;
1967 return NULL;
1968 }
1969 }
1970
1971 /*
1972 * Copy faces from the pullmesh into original, to patch up where there
1973 * would be gaps created
1974 */
1975 for( int i=0; i<new_polys; i++ )
1976 {
1977 int rface_id = mesh->abpolys.count;
1978 cxr_polygon *pface = &pullmesh->polys[pullmesh_new_start+i],
1979 *rip_face = cxr_ab_empty(&mesh->abpolys);
1980
1981 rip_face->loop_start = mesh->abloops.count;
1982 rip_face->loop_total = pface->loop_total;
1983 rip_face->material_id = -1;
1984
1985 for( int j=0; j<rip_face->loop_total; j++ )
1986 {
1987 cxr_loop *ploop =
1988 &pullmesh->loops[ pface->loop_start+pface->loop_total-j-1 ],
1989 *rloop = cxr_ab_empty(&mesh->abloops);
1990
1991 rloop->index = ploop->index;
1992 rloop->poly_left = rface_id;
1993 rloop->poly_right = -1;
1994 rloop->edge_index = 0;
1995 v2_copy( ploop->uv, rloop->uv );
1996 }
1997
1998 v3_copy( pface->center, rip_face->center );
1999 v3_negate( pface->normal, rip_face->normal );
2000 }
2001
2002 cxr_mesh_update( mesh );
2003 cxr_mesh_update( pullmesh );
2004
2005 cxr_mesh_clean_faces( mesh );
2006 cxr_mesh_clean_edges( mesh );
2007 cxr_mesh_clean_faces( pullmesh );
2008 cxr_mesh_clean_edges( pullmesh );
2009
2010 free(solid_buffer);
2011 free(candidates);
2012 free(best_manifold.loops);
2013
2014 /*
2015 * Do final checks on the mesh to make sure we diddn't introduce any
2016 * errors
2017 */
2018 if( cxr_non_manifold_err( pullmesh ) || cxr_reflex_err( pullmesh ) )
2019 {
2020 *err = k_soliderr_bad_result;
2021 return NULL;
2022 }
2023
2024 return pullmesh;
2025 }
2026
2027 free(solid_buffer);
2028 free(candidates);
2029 free(best_manifold.loops);
2030
2031 if( cxr_non_manifold_err( mesh ) || cxr_reflex_err( mesh ) )
2032 *err = k_soliderr_bad_result;
2033
2034 return NULL;
2035 }
2036
2037 /*
2038 * Convert from the format we recieve from blender into our internal format
2039 * with auto buffers.
2040 */
2041 static cxr_mesh *cxr_to_internal_format(
2042 cxr_static_mesh *src,
2043 cxr_abuffer *abverts
2044 ){
2045 cxr_mesh *mesh = cxr_alloc_mesh( src->edge_count, src->loop_count,
2046 src->poly_count, abverts );
2047
2048 cxr_ab_init( abverts, sizeof(v3f), src->vertex_count );
2049
2050 memcpy( mesh->abedges.arr, src->edges, src->edge_count*sizeof(cxr_edge));
2051 memcpy( mesh->abpolys.arr, src->polys, src->poly_count*sizeof(cxr_polygon));
2052 memcpy( abverts->arr, src->vertices, src->vertex_count*sizeof(v3f));
2053 mesh->abedges.count = src->edge_count;
2054 mesh->abloops.count = src->loop_count;
2055 mesh->abpolys.count = src->poly_count;
2056
2057 cxr_mesh_update( mesh );
2058
2059 for( int i=0; i<src->loop_count; i++ )
2060 {
2061 cxr_loop *lp = &mesh->loops[i];
2062
2063 lp->index = src->loops[i].index;
2064 lp->edge_index = src->loops[i].edge_index;
2065 v2_copy( src->loops[i].uv, lp->uv );
2066 }
2067
2068 abverts->count = src->vertex_count;
2069 return mesh;
2070 }
2071
2072 static int cxr_poly_convex( cxr_mesh *mesh, cxr_polygon *poly )
2073 {
2074 v3f *verts = cxr_ab_ptr( mesh->p_abverts, 0 );
2075
2076 for( int i=0; i<poly->loop_total; i++ )
2077 {
2078 int li0 = poly->loop_start + i,
2079 li1 = poly->loop_start + cxr_range( i+1, poly->loop_total ),
2080 li2 = poly->loop_start + cxr_range( i+2, poly->loop_total );
2081 int i0 = mesh->loops[li0].index,
2082 i1 = mesh->loops[li1].index,
2083 i2 = mesh->loops[li2].index;
2084
2085 v3f v0, v1, c;
2086
2087 v3_sub( verts[i1], verts[i0], v0 );
2088 v3_sub( verts[i2], verts[i1], v1 );
2089
2090 v3_cross( v0, v1, c );
2091 if( v3_dot( c, poly->normal ) <= 0.0 )
2092 {
2093 #if CXR_DEBUG
2094 cxr_debug_line( verts[i0], verts[i1], colour_error );
2095 cxr_debug_box( verts[i1], 0.1, colour_error );
2096 cxr_debug_line( verts[i1], verts[i2], colour_error );
2097 cxr_debug_line( verts[i1], poly->center, colour_error );
2098 #endif
2099 return 0;
2100 }
2101 }
2102
2103 return 1;
2104 }
2105
2106 static int cxr_solid_checkerr( cxr_mesh *mesh )
2107 {
2108 v3f *verts = cxr_ab_ptr( mesh->p_abverts, 0 );
2109 int err_count = 0;
2110
2111 for( int i=0; i<mesh->abpolys.count; i++ )
2112 {
2113 int plane_err = 0;
2114
2115 cxr_polygon *poly = &mesh->polys[i];
2116 v4f plane;
2117
2118 normal_to_plane( poly->normal, poly->center, plane );
2119
2120 for( int j=0; j<poly->loop_total; j++ )
2121 {
2122 cxr_loop *loop = &mesh->loops[ poly->loop_start+j ];
2123 double *vert = verts[ loop->index ];
2124
2125 if( fabs(plane_polarity(plane,vert)) > 0.0025 )
2126 {
2127 err_count ++;
2128 plane_err ++;
2129
2130 v3f ref;
2131 plane_project_point( plane, vert, ref );
2132
2133 #ifdef CXR_DEBUG
2134 cxr_debug_line( ref, vert, colour_error );
2135 cxr_debug_box( vert, 0.1, colour_error );
2136 #endif
2137 }
2138 }
2139
2140 #ifdef CXR_DEBUG
2141 if( plane_err )
2142 cxr_debug_poly( mesh, poly, colour_error );
2143 #endif
2144 }
2145
2146 return err_count;
2147 }
2148
2149 CXR_API void cxr_free_world( cxr_world *world )
2150 {
2151 for( int i=0; i<world->absolids.count; i++ )
2152 {
2153 cxr_solid *solid = cxr_ab_ptr( &world->absolids, i );
2154 cxr_free_mesh( solid->pmesh );
2155 }
2156
2157 cxr_ab_free( &world->abverts );
2158 cxr_ab_free( &world->absolids );
2159
2160 if( world->materials )
2161 {
2162 for( int i=0; i<world->material_count; i++ )
2163 free( world->materials[i].name );
2164
2165 free( world->materials );
2166 }
2167 free( world );
2168 }
2169
2170 CXR_API cxr_tri_mesh *cxr_world_preview( cxr_world *world )
2171 {
2172 cxr_tri_mesh *out = malloc( sizeof(cxr_tri_mesh) );
2173 out->vertex_count = 0;
2174 out->indices_count = 0;
2175
2176 for( int i=0; i<world->absolids.count; i++ )
2177 {
2178 cxr_solid *solid = cxr_ab_ptr( &world->absolids, i );
2179 cxr_mesh *mesh = solid->pmesh;
2180
2181 for( int j=0; j<mesh->abpolys.count; j ++ )
2182 {
2183 cxr_polygon *poly = &mesh->polys[j];
2184
2185 out->vertex_count += poly->loop_total * 3; /* Polygon, edge strip */
2186 out->indices_count += (poly->loop_total -2) * 3; /* Polygon */
2187 out->indices_count += poly->loop_total * 2 * 3; /* Edge strip */
2188 }
2189 }
2190
2191 out->colours = malloc( sizeof(v4f)*out->vertex_count );
2192 out->vertices = malloc( sizeof(v3f)*out->vertex_count );
2193 out->indices = malloc( sizeof(i32)*out->indices_count );
2194
2195 v3f *overts = out->vertices;
2196 v4f *colours = out->colours;
2197 i32 *indices = out->indices;
2198
2199 int vi = 0,
2200 ii = 0;
2201
2202 for( int i=0; i<world->absolids.count; i++ )
2203 {
2204 cxr_solid *solid = cxr_ab_ptr( &world->absolids, i );
2205 cxr_mesh *mesh = solid->pmesh;
2206
2207 v3f *verts = cxr_ab_ptr( mesh->p_abverts, 0 );
2208 v4f colour;
2209
2210 colour_random_brush( i, colour );
2211
2212 for( int j=0; j<mesh->abpolys.count; j ++ )
2213 {
2214 cxr_polygon *poly = &mesh->polys[j];
2215
2216 int istart = vi;
2217
2218 for( int k=0; k<poly->loop_total-2; k++ )
2219 {
2220 int i0 = 0,
2221 i1 = (k+1)*3,
2222 i2 = (k+2)*3;
2223
2224 indices[ ii ++ ] = istart+i0;
2225 indices[ ii ++ ] = istart+i1;
2226 indices[ ii ++ ] = istart+i2;
2227 }
2228
2229 for( int k=0; k<poly->loop_total; k++ )
2230 {
2231 cxr_loop *lp = &mesh->loops[poly->loop_start+k];
2232
2233 int i0r = k*3+1,
2234 i1r = cxr_range(k+1,poly->loop_total)*3+1,
2235 i0i = k*3+2,
2236 i1i = cxr_range(k+1,poly->loop_total)*3+2;
2237
2238 indices[ ii ++ ] = istart+i0i;
2239 indices[ ii ++ ] = istart+i1i;
2240 indices[ ii ++ ] = istart+i1r;
2241
2242 indices[ ii ++ ] = istart+i0i;
2243 indices[ ii ++ ] = istart+i1r;
2244 indices[ ii ++ ] = istart+i0r;
2245
2246 /* Main */
2247 v3_muladds( verts[lp->index], poly->normal, 0.02, overts[vi] );
2248 v4_copy( colour, colours[ vi ] );
2249 vi ++;
2250
2251 /* Trim */
2252 v3f inner;
2253 v3_lerp( verts[lp->index], poly->center, 0.2, inner );
2254 v3_muladds( inner, poly->normal, 0.015, overts[ vi ] );
2255 v4_copy( colour, colours[ vi ] );
2256 v4_copy( (v4f){ 0.0, 0.0, 0.0, 0.0 }, colours[vi] );
2257 vi ++;
2258
2259 v3_muladds(verts[lp->index], poly->normal, 0.0, overts[ vi ] );
2260 v4_copy( colour, colours[ vi ] );
2261 v4_copy( (v4f){ 1.0, 1.0, 1.0, 0.125 }, colours[vi] );
2262 vi ++;
2263 }
2264 }
2265 }
2266
2267 return out;
2268 }
2269
2270 CXR_API void cxr_free_tri_mesh( cxr_tri_mesh *mesh )
2271 {
2272 free( mesh->colours );
2273 free( mesh->indices );
2274 free( mesh->vertices );
2275 free( mesh );
2276 }
2277
2278 CXR_API cxr_world *cxr_decompose( cxr_static_mesh *src, i32 *perrcode )
2279 {
2280 u32 error = 0x00;
2281 cxr_world *world = malloc( sizeof(*world) );
2282
2283 /* Copy data to internal formats */
2284 cxr_mesh *main_mesh = cxr_to_internal_format( src, &world->abverts );
2285 cxr_ab_init( &world->absolids, sizeof(cxr_solid), 2 );
2286
2287 if( src->material_count )
2288 {
2289 size_t dsize = sizeof(cxr_material) * src->material_count;
2290 world->materials = malloc( dsize );
2291 memcpy( world->materials, src->materials, dsize );
2292
2293 for( int i=0; i<src->material_count; i++ )
2294 {
2295 world->materials[i].name = malloc(strlen(src->materials[i].name) +1);
2296 strcpy( world->materials[i].name, src->materials[i].name );
2297 }
2298 world->material_count = src->material_count;
2299 }
2300 else world->materials = NULL;
2301
2302 int invalid_count = 0;
2303
2304 /*
2305 * Preprocessor 1: Island seperation
2306 */
2307 while(1)
2308 {
2309 cxr_mesh *res = cxr_pull_island( main_mesh );
2310 if( res )
2311 {
2312 cxr_ab_push( &world->absolids, &(cxr_solid){ res, 0, 0 });
2313 }
2314 else break;
2315 }
2316 cxr_ab_push( &world->absolids, &(cxr_solid){ main_mesh, 0, 0 } );
2317
2318 /*
2319 * Preprocessor 2: Displacement processing & error checks
2320 */
2321 for( int i=0; i<world->absolids.count; i++ )
2322 {
2323 cxr_solid *pinf = cxr_ab_ptr(&world->absolids,i);
2324
2325 for( int j=0; j<pinf->pmesh->abpolys.count; j++ )
2326 {
2327 cxr_polygon *poly = &pinf->pmesh->polys[ j ];
2328
2329 for( int k=0; k<poly->loop_total; k++ )
2330 {
2331 cxr_loop *lp = &pinf->pmesh->loops[ poly->loop_start+k ];
2332 cxr_edge *edge = &pinf->pmesh->edges[ lp->edge_index ];
2333
2334 if( edge->freestyle )
2335 goto displacement;
2336 }
2337
2338 if( !cxr_poly_convex( pinf->pmesh, poly ) )
2339 {
2340 pinf->invalid = 1;
2341 invalid_count ++;
2342 error = k_soliderr_non_convex_poly;
2343 }
2344 }
2345
2346 if( cxr_solid_checkerr( pinf->pmesh ) )
2347 {
2348 pinf->invalid = 1;
2349 invalid_count ++;
2350 error = k_soliderr_non_coplanar_vertices;
2351 }
2352
2353 continue;
2354
2355 displacement:
2356 pinf->displacement = 1;
2357 }
2358
2359 /*
2360 * Main convex decomp algorithm
2361 */
2362 int sources_count = world->absolids.count;
2363
2364 if( invalid_count )
2365 goto decomp_failed;
2366
2367 for( int i=0; i<sources_count; i++ )
2368 {
2369 cxr_solid pinf = *(cxr_solid *)cxr_ab_ptr(&world->absolids, i);
2370
2371 if( pinf.displacement || pinf.invalid )
2372 continue;
2373
2374 while(1)
2375 {
2376 cxr_mesh *res = cxr_pull_best_solid( pinf.pmesh, 0, &error );
2377
2378 if( res )
2379 {
2380 cxr_ab_push( &world->absolids, &(cxr_solid){ res, 0, 0 } );
2381 }
2382 else
2383 {
2384 if( error == k_soliderr_no_solids )
2385 {
2386 /* Retry if non-critical error, with extra edges */
2387 res = cxr_pull_best_solid(pinf.pmesh, 1, &error);
2388
2389 if( res )
2390 cxr_ab_push( &world->absolids, &(cxr_solid){ res, 0, 0 } );
2391 else
2392 goto decomp_failed;
2393 }
2394 else
2395 if( error )
2396 goto decomp_failed;
2397 else
2398 break;
2399 }
2400 }
2401 }
2402
2403 return world;
2404
2405 decomp_failed:
2406 cxr_log( "Error %d\n", error );
2407 cxr_free_world( world );
2408
2409 if( perrcode )
2410 *perrcode = error;
2411
2412 return NULL;
2413 }
2414
2415 /*
2416 * format specific functions: vdf, vmf, (v)bsp
2417 * ----------------------------------------------------------------------------
2418 */
2419 #ifdef CXR_VALVE_MAP_FILE
2420
2421 CXR_API cxr_vdf *cxr_vdf_open(const char *path)
2422 {
2423 cxr_vdf *vdf = malloc(sizeof(cxr_vdf));
2424
2425 vdf->level = 0;
2426 vdf->fp = fopen( path, "w" );
2427
2428 if( !vdf->fp )
2429 {
2430 free( vdf );
2431 return NULL;
2432 }
2433
2434 return vdf;
2435 }
2436
2437 CXR_API void cxr_vdf_close(cxr_vdf *vdf)
2438 {
2439 fclose( vdf->fp );
2440 free( vdf );
2441 }
2442
2443 CXR_API void cxr_vdf_put(cxr_vdf *vdf, const char *str)
2444 {
2445 for( int i=0; i<vdf->level; i++ )
2446 fputs( " ", vdf->fp );
2447
2448 fputs( str, vdf->fp );
2449 }
2450
2451 static void cxr_vdf_printf( cxr_vdf *vdf, const char *fmt, ... )
2452 {
2453 cxr_vdf_put(vdf,"");
2454
2455 va_list args;
2456 va_start( args, fmt );
2457 vfprintf( vdf->fp, fmt, args );
2458 va_end(args);
2459 }
2460
2461 CXR_API void cxr_vdf_node(cxr_vdf *vdf, const char *str)
2462 {
2463 cxr_vdf_put( vdf, str );
2464 putc( (u8)'\n', vdf->fp );
2465 cxr_vdf_put( vdf, "{\n" );
2466
2467 vdf->level ++;
2468 }
2469
2470 CXR_API void cxr_vdf_edon( cxr_vdf *vdf )
2471 {
2472 vdf->level --;
2473 cxr_vdf_put( vdf, "}\n" );
2474 }
2475
2476 CXR_API void cxr_vdf_kv( cxr_vdf *vdf, const char *strk, const char *strv )
2477 {
2478 cxr_vdf_printf( vdf, "\"%s\" \"%s\"\n", strk, strv );
2479 }
2480
2481 /*
2482 * Data-type specific Keyvalues
2483 */
2484 static void cxr_vdf_ki32( cxr_vdf *vdf, const char *strk, i32 val )
2485 {
2486 cxr_vdf_printf( vdf, "\"%s\" \"%d\"\n", strk, val );
2487 }
2488
2489 static void cxr_vdf_kdouble( cxr_vdf *vdf, const char *strk, double val )
2490 {
2491 cxr_vdf_printf( vdf, "\"%s\" \"%f\"\n", strk, val );
2492 }
2493
2494 static void cxr_vdf_kaxis( cxr_vdf *vdf, const char *strk,
2495 v3f normal, double offset, double scale
2496 ){
2497 cxr_vdf_printf( vdf, "\"%s\" \"[%f %f %f %f] %f\"\n",
2498 strk, normal[0], normal[1],normal[2], offset, scale );
2499 }
2500
2501 static void cxr_vdf_kv3f( cxr_vdf *vdf, const char *strk, v3f v )
2502 {
2503 cxr_vdf_printf( vdf, "\"%s\" \"[%f %f %f]\"\n", strk, v[0], v[1], v[2] );
2504 }
2505
2506 static void cxr_vdf_karrdouble( cxr_vdf *vdf, const char *strk,
2507 int id, double *doubles, int count
2508 ){
2509 cxr_vdf_put(vdf,"");
2510 fprintf( vdf->fp, "\"%s%d\" \"", strk, id );
2511 for( int i=0; i<count; i++ )
2512 {
2513 if( i == count-1 ) fprintf( vdf->fp, "%f", doubles[i] );
2514 else fprintf( vdf->fp, "%f ", doubles[i] );
2515 }
2516 fprintf( vdf->fp, "\"\n" );
2517 }
2518
2519 static void cxr_vdf_karrv3f( cxr_vdf *vdf, const char *strk,
2520 int id, v3f *vecs, int count
2521 ){
2522 cxr_vdf_put(vdf,"");
2523 fprintf( vdf->fp, "\"%s%d\" \"", strk, id );
2524 for( int i=0; i<count; i++ )
2525 {
2526 const char *format = i == count-1? "%f %f %f": "%f %f %f ";
2527 fprintf( vdf->fp, format, vecs[i][0], vecs[i][1], vecs[i][2] );
2528 }
2529 fprintf( vdf->fp, "\"\n" );
2530 }
2531
2532 static void cxr_vdf_plane( cxr_vdf *vdf, const char *strk, v3f a, v3f b, v3f c )
2533 {
2534 cxr_vdf_printf( vdf, "\"%s\" \"(%f %f %f) (%f %f %f) (%f %f %f)\"\n",
2535 strk, a[0], a[1], a[2], b[0], b[1], b[2], c[0], c[1], c[2] );
2536 }
2537
2538 static void cxr_vdf_colour255(cxr_vdf *vdf, const char *strk, v4f colour)
2539 {
2540 v4f scale;
2541 v4_muls( colour, 255.0, scale );
2542 cxr_vdf_printf( vdf, "\"%s\" \"%d %d %d %d\"\n",
2543 strk,(int)scale[0], (int)scale[1], (int)scale[2], (int)scale[3]);
2544 }
2545
2546 static struct cxr_material cxr_nodraw =
2547 {
2548 .res = { 512, 512 },
2549 .name = "tools/toolsnodraw"
2550 };
2551
2552 /*
2553 * Find most extreme point along a given direction
2554 */
2555 static double support_distance( v3f verts[3], v3f dir, double coef )
2556 {
2557 return cxr_maxf
2558 (
2559 coef * v3_dot( verts[0], dir ),
2560 cxr_maxf
2561 (
2562 coef * v3_dot( verts[1], dir ),
2563 coef * v3_dot( verts[2], dir )
2564 )
2565 );
2566 }
2567
2568 /*
2569 * Convert regular UV'd triangle int Source's u/vaxis vectors
2570 *
2571 * This supports affine move, scale, rotation, parallel skewing
2572 */
2573 static void cxr_calculate_axis( cxr_texinfo *transform, v3f verts[3],
2574 v2f uvs[3], v2f texture_res
2575 ){
2576 v2f tT, bT; /* Tangent/bitangent pairs for UV space and world */
2577 v3f tW, bW;
2578
2579 v2_sub( uvs[0], uvs[1], tT );
2580 v2_sub( uvs[2], uvs[1], bT );
2581 v3_sub( verts[0], verts[1], tW );
2582 v3_sub( verts[2], verts[1], bW );
2583
2584 /* Use arbitrary projection if there is no UV */
2585 if( v2_length( tT ) < 0.0001 || v2_length( bT ) < 0.0001 )
2586 {
2587 v3f uaxis, normal, vaxis;
2588
2589 v3_copy( tW, uaxis );
2590 v3_normalize( uaxis );
2591
2592 v3_cross( tW, bW, normal );
2593 v3_cross( normal, uaxis, vaxis );
2594 v3_normalize( vaxis );
2595
2596 v3_copy( uaxis, transform->uaxis );
2597 v3_copy( vaxis, transform->vaxis );
2598 v2_zero( transform->offset );
2599
2600 v2_div( (v2f){128.0, 128.0}, texture_res, transform->scale );
2601 transform->winding = 1.0;
2602 return;
2603 }
2604
2605 /* Detect if UV is reversed */
2606 double winding = v2_cross( tT, bT ) >= 0.0f? 1.0f: -1.0f;
2607
2608 /* UV projection reference */
2609 v2f vY, vX;
2610 v2_muls((v2f){1,0}, winding, vX);
2611 v2_muls((v2f){0,1}, winding, vY);
2612
2613 /* Reproject reference into world space, including skew */
2614 v3f uaxis1, vaxis1;
2615
2616 v3_muls( tW, v2_cross(vX,bT) / v2_cross(bT,tT), uaxis1 );
2617 v3_muladds( uaxis1, bW, v2_cross(vX, tT) / v2_cross(tT,bT), uaxis1 );
2618
2619 v3_muls( tW, v2_cross(vY,bT) / v2_cross(bT,tT), vaxis1 );
2620 v3_muladds( vaxis1, bW, v2_cross(vY,tT) / v2_cross(tT,bT), vaxis1 );
2621
2622 v3_normalize( uaxis1 );
2623 v3_normalize( vaxis1 );
2624
2625 /* Apply source transform to axis (yes, they also need to be swapped) */
2626 v3f norm, uaxis, vaxis;
2627
2628 v3_cross( bW, tW, norm );
2629 v3_normalize(norm);
2630 v3_cross( vaxis1, norm, uaxis );
2631 v3_cross( uaxis1, norm, vaxis );
2632
2633 /* real UV scale */
2634 v2f uvmin, uvmax, uvdelta;
2635 v2_minv( uvs[0], uvs[1], uvmin );
2636 v2_minv( uvmin, uvs[2], uvmin );
2637 v2_maxv( uvs[0], uvs[1], uvmax );
2638 v2_maxv( uvmax, uvs[2], uvmax );
2639
2640 v2_sub( uvmax, uvmin, uvdelta );
2641
2642 /* world-uv scale */
2643 v2f uvminw, uvmaxw, uvdeltaw;
2644 uvminw[0] = -support_distance( verts, uaxis, -1.0f );
2645 uvmaxw[0] = support_distance( verts, uaxis, 1.0f );
2646 uvminw[1] = -support_distance( verts, vaxis, -1.0f );
2647 uvmaxw[1] = support_distance( verts, vaxis, 1.0f );
2648
2649 v2_sub( uvmaxw, uvminw, uvdeltaw );
2650
2651 /* VMf uv scale */
2652 v2f uv_scale;
2653 v2_div( uvdeltaw, uvdelta, uv_scale );
2654 v2_div( uv_scale, texture_res, uv_scale );
2655
2656 /* Find offset via 'natural' point */
2657 v2f target_uv, natural_uv, tex_offset;
2658 v2_mul( uvs[0], texture_res, target_uv );
2659
2660 natural_uv[0] = v3_dot( uaxis, verts[0] );
2661 natural_uv[1] = -v3_dot( vaxis, verts[0] );
2662 v2_div( natural_uv, uv_scale, natural_uv );
2663
2664 tex_offset[0] = target_uv[0]-natural_uv[0];
2665 tex_offset[1] = -(target_uv[1]-natural_uv[1]);
2666
2667 /* Copy everything into output */
2668 v3_copy( uaxis, transform->uaxis );
2669 v3_copy( vaxis, transform->vaxis );
2670 v2_copy( tex_offset, transform->offset );
2671 v2_copy( uv_scale, transform->scale );
2672 transform->winding = winding;
2673 }
2674
2675 /*
2676 * Get the maximal direction of a vector, while also ignoring an axis
2677 * specified
2678 */
2679 static int cxr_cardinal( v3f a, int ignore )
2680 {
2681 int component = 0;
2682 double component_max = -CXR_BIG_NUMBER;
2683
2684 for( int i=0; i<3; i++ )
2685 {
2686 if( i == ignore ) continue;
2687
2688 if( fabs(a[i]) > component_max )
2689 {
2690 component_max = fabs(a[i]);
2691 component = i;
2692 }
2693 }
2694 double d = a[component] >= 0.0? 1.0: -1.0;
2695 v3_zero( a );
2696 a[component] = d;
2697
2698 return component;
2699 }
2700
2701 /*
2702 * Convert contiguous mesh to displacement patch
2703 */
2704 static int cxr_write_disp( cxr_mesh *mesh, cxr_world *world,
2705 cxr_vmf_context *ctx, cxr_vdf *output
2706 ){
2707 v3f *verts = cxr_ab_ptr( mesh->p_abverts, 0 );
2708
2709 struct vertinfo
2710 {
2711 int con_start, con_count;
2712 int boundary,
2713 used,
2714 search,
2715 corner;
2716
2717 double alpha;
2718 }
2719 *vertinfo = malloc( sizeof(struct vertinfo)*mesh->p_abverts->count );
2720 int *graph = malloc( sizeof(int) * mesh->abedges.count*2 );
2721
2722 int con_pos = 0;
2723 for( int i=0; i<mesh->p_abverts->count; i++ )
2724 {
2725 struct vertinfo *info = &vertinfo[i];
2726 info->con_start = con_pos;
2727 info->con_count = 0;
2728 info->boundary = 0;
2729 info->corner = 0;
2730 info->used = 0;
2731 info->search = 0;
2732 info->alpha = 0.0;
2733
2734 for( int j=0; j<mesh->abedges.count; j++ )
2735 {
2736 cxr_edge *edge = &mesh->edges[j];
2737
2738 if( edge->i0 == i || edge->i1 == i )
2739 {
2740 graph[ con_pos ++ ] = edge->i0 == i? edge->i1: edge->i0;
2741 info->con_count ++;
2742
2743 if( edge->freestyle )
2744 info->boundary = 1;
2745 }
2746 }
2747 }
2748
2749 v3f refv, refu, refn;
2750 v3_zero(refv); v3_zero(refu); v3_zero(refn);
2751
2752 /*
2753 * Approximately match the area of the result brush faces to the actual
2754 * area.
2755 *
2756 * Necessary for accuracy and even lightmap texel allocation
2757 */
2758
2759 double uv_area = 0.0, face_area = 0.0, sf;
2760 v2f uvboundmin, uvboundmax;
2761 v3f faceboundmin, faceboundmax;
2762 v2f uv_center;
2763 v3f face_center;
2764
2765 v2_fill( uvboundmin, CXR_BIG_NUMBER );
2766 v2_fill( uvboundmax, -CXR_BIG_NUMBER );
2767 v3_fill( faceboundmin, CXR_BIG_NUMBER );
2768 v3_fill( faceboundmax, -CXR_BIG_NUMBER );
2769
2770 for( int i=0; i<mesh->abpolys.count; i++ )
2771 {
2772 cxr_polygon *poly = &mesh->polys[i];
2773
2774 for( int j=0; j<poly->loop_total; j++ )
2775 {
2776 cxr_loop *lp0 = &mesh->loops[ poly->loop_start+j ];
2777 v2_minv( lp0->uv, uvboundmin, uvboundmin);
2778 v2_maxv( lp0->uv, uvboundmax, uvboundmax);
2779 v3_minv( verts[lp0->index], faceboundmin, faceboundmin );
2780 v3_maxv( verts[lp0->index], faceboundmax, faceboundmax );
2781 }
2782
2783 for( int j=0; j<poly->loop_total-2; j++ )
2784 {
2785 cxr_loop *lp0 = &mesh->loops[poly->loop_start],
2786 *lp1 = &mesh->loops[poly->loop_start+j+1],
2787 *lp2 = &mesh->loops[poly->loop_start+j+2];
2788
2789 v3f va, vb, orth;
2790 v3_sub( verts[lp1->index], verts[lp0->index], va );
2791 v3_sub( verts[lp2->index], verts[lp0->index], vb );
2792 v3_cross( va, vb, orth );
2793
2794 face_area += v3_length( orth ) / 2.0;
2795
2796 v2f uva, uvb;
2797 v2_sub( lp1->uv, lp0->uv, uva );
2798 v2_sub( lp2->uv, lp0->uv, uvb );
2799
2800 uv_area += fabs(v2_cross( uva, uvb )) / 2.0;
2801 }
2802 }
2803
2804 v3_add( faceboundmax, faceboundmin, face_center );
2805 v3_muls( face_center, 0.5, face_center );
2806 v2_add( uvboundmin, uvboundmax, uv_center );
2807 v2_muls( uv_center, 0.5, uv_center );
2808
2809 sf = sqrt( face_area / uv_area );
2810 int corner_count = 0;
2811
2812 /*
2813 * Vertex classification
2814 * boundary vertices: they exist on a freestyle edge
2815 * corners: only connected to other boundaries
2816 */
2817 for( int i=0; i<mesh->p_abverts->count; i++ )
2818 {
2819 struct vertinfo *info = &vertinfo[i];
2820 if( !info->boundary ) continue;
2821
2822 int count = 0,
2823 non_manifold = 1;
2824
2825 for( int j=0; j<info->con_count; j++ )
2826 {
2827 int con = graph[info->con_start+j];
2828
2829 if( vertinfo[con].boundary )
2830 count ++;
2831 else
2832 non_manifold = 0;
2833 }
2834
2835 if( count > 2 || non_manifold )
2836 {
2837 info->corner = 1;
2838 corner_count ++;
2839 }
2840 }
2841
2842 /*
2843 * TODO(harry): This currently only supports power 2 displacements
2844 * its quite straightforward to upgrade it.
2845 *
2846 * TODO(harry): Error checking is needed here for bad input data
2847 */
2848
2849 int dispedge[17];
2850 v2f corner_uvs[4];
2851 int dispedge_count;
2852 int disp_count = 0;
2853
2854 for( int i=0; i<mesh->abpolys.count; i++ )
2855 {
2856 cxr_polygon *basepoly = &mesh->polys[i];
2857
2858 for( int h=0; h<basepoly->loop_total; h ++ )
2859 {
2860 int i0 = h,
2861 i1 = cxr_range(h+1,basepoly->loop_total);
2862
2863 cxr_loop *l0 = &mesh->loops[ basepoly->loop_start+i0 ],
2864 *l1 = &mesh->loops[ basepoly->loop_start+i1 ];
2865 struct vertinfo *info = &vertinfo[ l0->index ];
2866
2867 if( !info->corner )
2868 continue;
2869
2870 int corner_count = 1;
2871
2872 cxr_material *matptr =
2873 basepoly->material_id < 0 || !world->materials?
2874 &cxr_nodraw:
2875 &world->materials[ basepoly->material_id ];
2876
2877 dispedge_count = 2;
2878 dispedge[0] = l0->index;
2879 dispedge[1] = l1->index;
2880 v2_copy( l0->uv, corner_uvs[0] );
2881
2882 /* Consume (use) face from orignal mesh */
2883 basepoly->loop_total = -1;
2884
2885 while( dispedge_count < 17 )
2886 {
2887 struct vertinfo *edge_head =
2888 &vertinfo[dispedge[dispedge_count-1]];
2889
2890 int newvert = 0;
2891
2892 if( edge_head->corner )
2893 {
2894 /* Find polygon that has edge C-1 -> C */
2895 for( int j=0; j<mesh->abpolys.count && !newvert; j++ )
2896 {
2897 cxr_polygon *poly = &mesh->polys[j];
2898
2899 for( int k=0; k<poly->loop_total; k ++ )
2900 {
2901 int i0 = k,
2902 i1 = cxr_range(k+1,poly->loop_total);
2903
2904 cxr_loop *l0 = &mesh->loops[ poly->loop_start+i0 ],
2905 *l1 = &mesh->loops[ poly->loop_start+i1 ];
2906
2907 if( l0->index == dispedge[dispedge_count-2] &&
2908 l1->index == dispedge[dispedge_count-1] )
2909 {
2910 /* Take the next edge */
2911 v2_copy( l1->uv, corner_uvs[corner_count ++] );
2912
2913 int i2 = cxr_range(i1+1,poly->loop_total);
2914 cxr_loop *l2 = &mesh->loops[ poly->loop_start+i2 ];
2915
2916 dispedge[dispedge_count ++] = l2->index;
2917 newvert = 1;
2918 poly->loop_total = -1;
2919 break;
2920 }
2921 }
2922 }
2923 }
2924 else
2925 {
2926 for( int j=0; j<edge_head->con_count; j++ )
2927 {
2928 int con = graph[edge_head->con_start+j];
2929
2930 if( con == -1 )
2931 continue;
2932
2933 if( dispedge_count > 1 )
2934 if( con == dispedge[dispedge_count-2] )
2935 continue;
2936
2937 struct vertinfo *coninfo = &vertinfo[con];
2938
2939 if( !coninfo->boundary )
2940 continue;
2941
2942 dispedge[ dispedge_count ++ ] = con;
2943 newvert = 1;
2944
2945 break;
2946 }
2947 }
2948
2949 if( !newvert )
2950 {
2951 return 0;
2952 }
2953 }
2954
2955 /* All edges collected */
2956
2957 v2f va, vb;
2958 v2_sub( corner_uvs[1], corner_uvs[0], va );
2959 v2_sub( corner_uvs[2], corner_uvs[0], vb );
2960
2961 /* Connect up the grid
2962 *
2963 * 0 1 2 3 4
2964 * 15 a b c d
2965 * 14 e f g h
2966 * 13 i j k l
2967 * 12 m n o p
2968 *
2969 * Example: a := common unused vertex that is connected to
2970 * by 1 and 15. Or y-1, and x-1 on the grid.
2971 * g := c and f common vert ^
2972 */
2973
2974 int grid[25];
2975
2976 for( int j=0; j<5; j++ ) grid[j] = dispedge[j];
2977 for( int j=1; j<5; j++ ) grid[j*5+4] = dispedge[j+4];
2978 for( int j=0; j<4; j++ ) grid[4*5+3-j] = dispedge[j+9];
2979 for( int j=1; j<4; j++ ) grid[j*5] = dispedge[16-j];
2980
2981 /* Fill in grid */
2982 for( int j=1; j<4; j++ )
2983 {
2984 for( int k=1; k<4; k++ )
2985 {
2986 int s0 = grid[(j-1)*5+k],
2987 s1 = grid[j*5+k-1];
2988
2989 struct vertinfo *va = &vertinfo[s0],
2990 *vb = &vertinfo[s1];
2991
2992 /* Find common non-used vertex */
2993 for( int l=0; l<va->con_count; l ++ )
2994 {
2995 for( int m=0; m<vb->con_count; m ++ )
2996 {
2997 int cona = graph[va->con_start+l],
2998 conb = graph[vb->con_start+m];
2999
3000 if( cona == conb )
3001 {
3002 if( vertinfo[cona].used || vertinfo[cona].boundary )
3003 continue;
3004
3005 grid[ j*5+k ] = cona;
3006 vertinfo[cona].used = 1;
3007
3008 goto next_cell;
3009 }
3010 }
3011 }
3012
3013 #ifdef CXR_DEBUG
3014 cxr_log( "Broken displacement!\n" );
3015 #endif
3016 free( graph );
3017 free( vertinfo );
3018 return 0;
3019
3020 next_cell:;
3021 }
3022 }
3023
3024 /*
3025 * Create V reference based on first displacement.
3026 * TODO(harry): This is not the moststable selection method!
3027 * faces can come in any order, so the first disp will of
3028 * course always vary. Additionaly the triangle can be oriented
3029 * differently.
3030 *
3031 * Improvement can be made by selecting a first disp/triangle
3032 * based on deterministic factors.
3033 */
3034 if( disp_count == 0 )
3035 {
3036 cxr_texinfo tx;
3037 v3f tri_ref[3];
3038 v3_copy( verts[dispedge[0]], tri_ref[0] );
3039 v3_copy( verts[dispedge[4]], tri_ref[1] );
3040 v3_copy( verts[dispedge[8]], tri_ref[2] );
3041 cxr_calculate_axis( &tx, tri_ref, corner_uvs, (v2f){512,512} );
3042
3043 v3_muls( tx.vaxis, -1.0, refv );
3044 int v_cardinal = cxr_cardinal( refv, -1 );
3045
3046 v3_cross( tx.vaxis, tx.uaxis, refn );
3047 v3_muls( refn, -tx.winding, refn );
3048
3049 /* Computing new reference vectors */
3050 int n1_cardinal = cxr_cardinal( refn, v_cardinal );
3051
3052 int u_cardinal = 0;
3053
3054 for( int j=0; j<2; j++ )
3055 if( u_cardinal == n1_cardinal || u_cardinal == v_cardinal )
3056 u_cardinal ++;
3057
3058 v3_zero(refu);
3059 refu[u_cardinal] = tx.uaxis[u_cardinal] > 0.0? 1.0: -1.0;
3060
3061 v3f p0, pv, pu, pn;
3062
3063 v3_copy( face_center, p0 );
3064 v3_muladds( face_center, refn, 1.5, pn );
3065 v3_muladds( face_center, refv, 1.5, pv );
3066 v3_muladds( face_center, refu, 1.5, pu );
3067 }
3068
3069 /* Create world coordinates */
3070 v3f world_corners[8];
3071 v2f world_uv[4];
3072
3073 for( int j=0; j<4; j++ )
3074 {
3075 v2f local_uv;
3076 v2_sub( corner_uvs[j], uv_center, local_uv );
3077 v2_copy( corner_uvs[j], world_uv[j] );
3078 v2_muls( local_uv, sf, local_uv );
3079
3080 v3_muls( refu, local_uv[0], world_corners[j] );
3081 v3_muladds( world_corners[j],refv,local_uv[1],world_corners[j] );
3082 v3_add( face_center, world_corners[j], world_corners[j] );
3083 }
3084
3085 double *colour = colours_random[cxr_range(disp_count,8)];
3086
3087 for( int j=0; j<4; j++ )
3088 v3_muladds( world_corners[j], refn, -1.0, world_corners[j+4] );
3089
3090 /* Apply world transform */
3091 for( int j=0; j<8; j++ )
3092 {
3093 double *p0 = world_corners[j];
3094 v3_muls( p0, ctx->scale, p0 );
3095 v3_add( p0, ctx->offset, p0 );
3096 }
3097
3098 cxr_texinfo texinfo_shared;
3099 cxr_calculate_axis( &texinfo_shared, world_corners, world_uv,
3100 (v2f){ matptr->res[0], matptr->res[1] } );
3101
3102 /* Write brush */
3103 cxr_vdf_node( output, "solid" );
3104 cxr_vdf_ki32( output, "id", ++ ctx->brush_count );
3105
3106 int sides[6][3] =
3107 {{ 0, 1, 2 },
3108 { 4, 6, 5 },
3109 { 4, 1, 0 },
3110 { 7, 0, 3 },
3111 { 6, 2, 1 },
3112 { 6, 3, 2 }};
3113
3114 v3f normals[25];
3115 double distances[25];
3116
3117 v3f lside0, lside1, lref, vdelta, vworld;
3118 double tx, ty;
3119
3120 for( int j=0; j<5; j++ )
3121 {
3122 ty = (double)j/(double)(5-1);
3123
3124 v3_lerp( world_corners[0], world_corners[3], ty, lside0 );
3125 v3_lerp( world_corners[1], world_corners[2], ty, lside1 );
3126
3127 for( int k=0; k<5; k++ )
3128 {
3129 int index = j*5+k;
3130
3131 tx = (double)k/(double)(5-1);
3132 v3_lerp( lside0, lside1, tx, lref );
3133 v3_muls( verts[grid[index]], ctx->scale, vworld );
3134 v3_add( ctx->offset, vworld, vworld );
3135
3136 v3_sub( vworld, lref, vdelta );
3137 v3_copy( vdelta, normals[index] );
3138 v3_normalize( normals[index] );
3139 distances[index] = v3_dot( vdelta, normals[index] );
3140 }
3141 }
3142
3143 for( int j=0; j<6; j++ )
3144 {
3145 int *side = sides[j];
3146
3147 cxr_vdf_node( output, "side" );
3148 cxr_vdf_ki32( output, "id", ++ ctx->face_count );
3149 cxr_vdf_plane( output, "plane", world_corners[side[2]],
3150 world_corners[side[1]],
3151 world_corners[side[0]] );
3152
3153 cxr_vdf_kv( output, "material", matptr->name );
3154 cxr_vdf_kaxis( output, "uaxis",
3155 texinfo_shared.uaxis,
3156 texinfo_shared.offset[0],
3157 texinfo_shared.scale[0] );
3158 cxr_vdf_kaxis( output, "vaxis",
3159 texinfo_shared.vaxis,
3160 texinfo_shared.offset[1],
3161 texinfo_shared.scale[1] );
3162
3163 cxr_vdf_kdouble( output, "rotation", 0.0 );
3164 cxr_vdf_ki32( output, "lightmapscale", ctx->lightmap_scale);
3165 cxr_vdf_ki32( output, "smoothing_groups", 0 );
3166
3167 if( j == 0 )
3168 {
3169 cxr_vdf_node( output, "dispinfo" );
3170 cxr_vdf_ki32( output, "power", 2 );
3171 cxr_vdf_kv3f( output, "startposition", world_corners[0] );
3172 cxr_vdf_ki32( output, "flags", 0 );
3173 cxr_vdf_kdouble( output, "elevation", 0.0 );
3174 cxr_vdf_ki32( output, "subdiv", 0 );
3175
3176 cxr_vdf_node( output, "normals" );
3177 for( int k=0; k<5; k++ )
3178 cxr_vdf_karrv3f( output, "row", k, &normals[k*5], 5 );
3179 cxr_vdf_edon( output );
3180
3181 cxr_vdf_node( output, "distances" );
3182 for( int k=0; k<5; k++ )
3183 cxr_vdf_karrdouble( output, "row", k, &distances[k*5], 5 );
3184 cxr_vdf_edon( output );
3185
3186 /*
3187 * TODO: This might be needed for the compilers. Opens fine in
3188 * hammer
3189 */
3190
3191 /*
3192 cxr_vdf_node( output, "offsets" );
3193 for( int k=0; k<5; k++ )
3194 cxr_vdf_printf( output,
3195 "\"row%d\" \"0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\"\n", k );
3196 cxr_vdf_edon( output );
3197
3198 cxr_vdf_node( output, "offset_normals" );
3199 for( int k=0; k<5; k++ )
3200 cxr_vdf_printf( output,
3201 "\"row%d\" \"0 0 1 0 0 1 0 0 1 0 0 1 0 0 1\"\n", k );
3202 cxr_vdf_edon( output );
3203
3204 cxr_vdf_node( output, "alphas" );
3205 for( int k=0; k<5; k++ )
3206 cxr_vdf_printf( output, "\"row%d\" \"0 0 0 0 0\"\n", k );
3207 cxr_vdf_edon( output );
3208
3209 cxr_vdf_node( output, "triangle_tags" );
3210 for( int k=0; k<5-1; k++ )
3211 cxr_vdf_printf( output,
3212 "\"row%d\" \"9 9 9 9 9 9 9 9\"\n", k );
3213 cxr_vdf_edon( output );
3214
3215 cxr_vdf_node( output, "allowed_verts" );
3216 cxr_vdf_printf( output,
3217 "\"10\" \"-1 -1 -1 -1 -1 -1 -1 -1 -1 -1\"\n" );
3218 cxr_vdf_edon( output );
3219 */
3220
3221 cxr_vdf_edon( output );
3222 }
3223
3224 cxr_vdf_edon( output );
3225 }
3226
3227 cxr_vdf_node( output, "editor");
3228 cxr_vdf_colour255( output, "color",
3229 colours_random[cxr_range(ctx->brush_count,8)]);
3230
3231 cxr_vdf_ki32( output, "visgroupshown",1);
3232 cxr_vdf_ki32( output, "visgroupautoshown",1);
3233 cxr_vdf_edon( output );
3234
3235 cxr_vdf_edon( output );
3236 disp_count ++;
3237 }
3238 }
3239
3240 free( graph );
3241 free( vertinfo );
3242
3243 return 1;
3244 }
3245
3246 /*
3247 * Write header information for a vmf to vdf
3248 */
3249 CXR_API void cxr_begin_vmf( cxr_vmf_context *ctx, cxr_vdf *output )
3250 {
3251 cxr_vdf_node( output, "versioninfo" );
3252 cxr_vdf_ki32( output, "editorversion", 400 );
3253 cxr_vdf_ki32( output, "editorbuild", 8456 );
3254 cxr_vdf_ki32( output, "mapversion", ctx->mapversion );
3255 cxr_vdf_ki32( output, "formatversion", 100 );
3256 cxr_vdf_ki32( output, "prefab", 0 );
3257 cxr_vdf_edon( output );
3258
3259 cxr_vdf_node( output, "visgroups" );
3260 cxr_vdf_edon( output );
3261
3262 cxr_vdf_node( output, "viewsettings" );
3263 cxr_vdf_ki32( output, "bSnapToGrid", 1 );
3264 cxr_vdf_ki32( output, "bShowGrid", 1 );
3265 cxr_vdf_ki32( output, "bShowLogicalGrid", 0 );
3266 cxr_vdf_ki32( output, "nGridSpacing", 64 );
3267 cxr_vdf_ki32( output, "bShow3DGrid", 0 );
3268 cxr_vdf_edon( output );
3269
3270 cxr_vdf_node( output, "world" );
3271 cxr_vdf_ki32( output, "id", 1 );
3272 cxr_vdf_ki32( output, "mapversion", 1 ); /* ?? */
3273 cxr_vdf_kv( output, "classname", "worldspawn" );
3274 cxr_vdf_kv( output, "skyname", ctx->skyname );
3275 cxr_vdf_ki32( output, "maxpropscreenwidth", -1 );
3276 cxr_vdf_kv( output, "detailvbsp", ctx->detailvbsp );
3277 cxr_vdf_kv( output, "detailmaterial", ctx->detailmaterial );
3278 }
3279
3280 /* Fairly useless but might need in the future */
3281 CXR_API void cxr_vmf_begin_entities( cxr_vmf_context *ctx, cxr_vdf *vdf )
3282 {
3283 cxr_vdf_edon( vdf );
3284 }
3285
3286 CXR_API void cxr_end_vmf( cxr_vmf_context *ctx, cxr_vdf *vdf )
3287 {
3288 }
3289
3290 /*
3291 * Write solids (and displacements) to VMF file
3292 */
3293 CXR_API void cxr_push_world_vmf( cxr_world *world, cxr_vmf_context *ctx,
3294 cxr_vdf *output
3295 ){
3296 v3f *verts = cxr_ab_ptr( &world->abverts, 0 );
3297
3298 /* Write all solids as VMF brushes */
3299 for( int i=0; i<world->absolids.count; i++ )
3300 {
3301 cxr_solid *solid = cxr_ab_ptr(&world->absolids,i);
3302
3303 if( solid->displacement )
3304 {
3305 cxr_write_disp( solid->pmesh, world, ctx, output );
3306 continue;
3307 }
3308
3309 cxr_vdf_node( output, "solid" );
3310 cxr_vdf_ki32( output, "id", ++ ctx->brush_count );
3311
3312 for( int j=0; j<solid->pmesh->abpolys.count; j++ )
3313 {
3314 cxr_polygon *poly = &solid->pmesh->polys[j];
3315 cxr_loop *ploops = &solid->pmesh->loops[poly->loop_start];
3316
3317 cxr_material *matptr =
3318 poly->material_id < 0 || !world->materials?
3319 &cxr_nodraw:
3320 &world->materials[ poly->material_id ];
3321
3322 cxr_vdf_node( output, "side" );
3323 cxr_vdf_ki32( output, "id", ++ ctx->face_count );
3324
3325 v3f tri[3]; v2f uvs[3];
3326
3327 int i0 = ploops[0].index,
3328 i1 = ploops[1].index,
3329 i2 = ploops[2].index;
3330
3331 v3_muls( verts[i0], ctx->scale, tri[0] );
3332 v3_muls( verts[i1], ctx->scale, tri[1] );
3333 v3_muls( verts[i2], ctx->scale, tri[2] );
3334
3335 v3_add( ctx->offset, tri[0], tri[0] );
3336 v3_add( ctx->offset, tri[1], tri[1] );
3337 v3_add( ctx->offset, tri[2], tri[2] );
3338
3339 v2_copy( ploops[0].uv, uvs[0] );
3340 v2_copy( ploops[1].uv, uvs[1] );
3341 v2_copy( ploops[2].uv, uvs[2] );
3342
3343 cxr_vdf_plane( output, "plane", tri[2], tri[1], tri[0] );
3344 cxr_vdf_kv( output, "material", matptr->name );
3345
3346 cxr_texinfo tx;
3347 cxr_calculate_axis( &tx, tri, uvs,
3348 (double[2]){ matptr->res[0], matptr->res[1] });
3349
3350 cxr_vdf_kaxis( output, "uaxis", tx.uaxis, tx.offset[0], tx.scale[0]);
3351 cxr_vdf_kaxis( output, "vaxis", tx.vaxis, tx.offset[1], tx.scale[1]);
3352
3353 cxr_vdf_kdouble( output, "rotation", 0.0 );
3354 cxr_vdf_ki32( output, "lightmapscale", ctx->lightmap_scale );
3355 cxr_vdf_ki32( output, "smoothing_groups", 0);
3356
3357 cxr_vdf_edon( output );
3358 }
3359
3360 cxr_vdf_node( output, "editor" );
3361 cxr_vdf_colour255( output, "color",
3362 colours_random[cxr_range(ctx->brush_count,8)]);
3363
3364 cxr_vdf_ki32( output, "visgroupshown", 1 );
3365 cxr_vdf_ki32( output, "visgroupautoshown", 1 );
3366 cxr_vdf_edon( output );
3367
3368 cxr_vdf_edon( output );
3369 }
3370 }
3371
3372 /*
3373 * Valve Source SDK 2015 CS:GO
3374 */
3375 #define HEADER_LUMPS 64
3376 #define LUMP_WORLDLIGHTS 54
3377
3378 #pragma pack(push,1)
3379
3380 struct header
3381 {
3382 int ident;
3383 int version;
3384
3385 struct lump
3386 {
3387 int fileofs, filelen;
3388 int version;
3389
3390 char fourCC[4];
3391 }
3392 lumps[ HEADER_LUMPS ];
3393
3394 int mapRevision;
3395 };
3396
3397 struct worldlight
3398 {
3399 float origin[3];
3400 float intensity[3];
3401 float normal[3];
3402 float shadow_cast_offset[3];
3403 int cluster;
3404 int type;
3405 int style;
3406 float stopdot;
3407 float stopdot2;
3408 float exponent;
3409 float radius;
3410 float constant_attn;
3411 float linear_attn;
3412 float quadratic_attn;
3413 int flags;
3414 int texinfo;
3415 int owner;
3416 };
3417 #pragma pack(pop)
3418
3419 /*
3420 * Utility for patching BSP tools to remove -1 distance lights (we set them
3421 * like that, because we want these lights to go away)
3422 *
3423 * Yes, there is no way to do this in hammer
3424 * Yes, the distance KV is unused but still gets compiled to this lump
3425 * No, Entities only compile will not do this for you
3426 */
3427 CXR_API int cxr_lightpatch_bsp( const char *path )
3428 {
3429 printf( "Lightpatch: %s\n", path );
3430
3431 FILE *fp = fopen( path, "r+b" );
3432
3433 if( !fp )
3434 {
3435 #ifdef CXR_DEBUG
3436 cxr_log( "Could not open BSP file for editing (r+b)\n" );
3437 #endif
3438 return 0;
3439 }
3440
3441 /* Read bsp */
3442 struct header header;
3443 fread( &header, sizeof(struct header), 1, fp );
3444 struct lump *lump = &header.lumps[ LUMP_WORLDLIGHTS ];
3445
3446 /* Read worldlight array */
3447 struct worldlight *lights = malloc( lump->filelen );
3448 fseek( fp, lump->fileofs, SEEK_SET );
3449 fread( lights, lump->filelen, 1, fp );
3450
3451 /* Remove all marked lights */
3452 int light_count = lump->filelen / sizeof(struct worldlight);
3453 int new_count = 0;
3454
3455 for( int i = 0; i < light_count; i ++ )
3456 if( lights[i].radius >= 0.0f )
3457 lights[new_count++] = lights[i];
3458
3459 lump->filelen = new_count*sizeof(struct worldlight);
3460
3461 /* Write changes back to file */
3462 fseek( fp, lump->fileofs, SEEK_SET );
3463 fwrite( lights, lump->filelen, 1, fp );
3464 fseek( fp, 0, SEEK_SET );
3465 fwrite( &header, sizeof(struct header), 1, fp );
3466
3467 #ifdef CXR_DEBUG
3468 cxr_log( "removed %d marked lights\n", light_count-new_count );
3469 #endif
3470
3471 fclose( fp );
3472 free( lights );
3473
3474 return 1;
3475 }
3476 #endif /* CXR_VALVE_MAP_FILE */
3477 #endif /* CXR_IMPLEMENTATION */