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