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