4 A GNU/Linux-first Source1 Hammer replacement
5 built with Blender, for mapmakers
7 Copyright (C) 2022 Harry Godden (hgn)
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 - Light patch BSP files; remove unwanted realtime effects
15 - Fastest VTF compressor (thanks to Richgel999 and stb)
18 - high quality level overviews automatically for CS:GO (csRadar)
22 File/folder Lang Purpose
24 __init__.py Python Blender plugin interface
25 convexer.c 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
29 nbvtf.h C VTF processing interface
30 librgcx.h C++ Rich Geldreich's DXT1/DXT5 compressors
31 stb/ C Sean Barrets image I/O
34 const char *cxr_build_time
= __DATE__
" @" __TIME__
;
52 typedef unsigned int uint
;
54 typedef double v2f
[2];
55 typedef double v3f
[3];
56 typedef double v4f
[4];
61 #define CXR_EPSILON 0.001
62 #define CXR_PLANE_SIMILARITY_MAX 0.998
63 #define CXR_BIG_NUMBER 1e300
64 #define CXR_INTERIOR_ANGLE_MAX 0.998
66 #define CXR_DIRTY_OPTIMISATION 1
67 #define CXR_DEBUG_WRITE_MESH 1
68 #define CXR_DEBUG_ALLOCATORS 1
69 #define CXR_MANIFOLD_DEBUG 0
71 #define CXR_ERROR_DEGEN_IMPLICIT 0x1
72 #define CXR_ERROR_BAD_MANIFOLD 0x2
73 #define CXR_ERROR_NO_SOLIDS 0x4
79 // ============================================
81 static v4f colours_random
[] =
83 { 0.863, 0.078, 0.235, 0.4 },
84 { 0.000, 0.980, 0.604, 0.4 },
85 { 0.118, 0.565, 1.000, 0.4 },
86 { 0.855, 0.439, 0.839, 0.4 },
87 { 0.824, 0.412, 0.118, 0.4 },
88 { 0.125, 0.698, 0.667, 0.4 },
89 { 0.541, 0.169, 0.886, 0.4 },
90 { 1.000, 0.843, 0.000, 0.4 }
93 static int cxr_range(int x
, int bound
)
96 x
+= bound
* (x
/bound
+ 1);
101 struct cxr_input_mesh
112 struct cxr_input_loop
122 i32 loop_start
, loop_total
;
125 i32 material_id
; // -1: interior material
132 const char *vmt_path
;
159 struct cxr_auto_buffer
172 // simple VDF writing interface
179 static struct cxr_settings
188 .lightmap_scale
= 12,
190 .light_scale
= 1.0/5.0
193 static struct cxr_context
206 .scale_factor
= 32.0,
210 static struct cxr_material cxr_nodraw
= {
212 .vmt_path
= "tools/toolsnodraw"
215 // Debugging callbacks
216 // =============================================================================
218 static v4f colour_error
= { 1.0f
, 0.0f
, 0.0f
, 1.0f
};
219 static v4f colour_face_graph
= { 1.0f
, 1.0f
, 1.0f
, 0.03f
};
220 static v4f colour_success
= { 0.0f
, 1.0f
, 0.0f
, 1.0f
};
222 static void (*cxr_log_func
)(const char *str
);
223 static void (*cxr_line_func
)( v3f p0
, v3f p1
, v4f colour
);
225 static void cxr_log( const char *fmt
, ... )
230 va_start( args
, fmt
);
231 vsnprintf( buf
, sizeof(buf
)-1, fmt
, args
);
240 static void cxr_debug_line( v3f p0
, v3f p1
, v4f colour
)
243 cxr_line_func( p0
, p1
, colour
);
246 static void cxr_debug_box( v3f p0
, double sz
, v4f colour
)
250 v3_add(p0
, (v3f
){-sz
,-sz
,-sz
}, a
);
251 v3_add(p0
, (v3f
){-sz
, sz
,-sz
}, b
);
252 v3_add(p0
, (v3f
){ sz
, sz
,-sz
}, c
);
253 v3_add(p0
, (v3f
){ sz
,-sz
,-sz
}, d
);
254 v3_add(p0
, (v3f
){-sz
,-sz
,sz
}, a1
);
255 v3_add(p0
, (v3f
){-sz
, sz
,sz
}, b1
);
256 v3_add(p0
, (v3f
){ sz
, sz
,sz
}, c1
);
257 v3_add(p0
, (v3f
){ sz
,-sz
,sz
}, d1
);
259 cxr_debug_line( a
,b
, colour
);
260 cxr_debug_line( b
,c
, colour
);
261 cxr_debug_line( c
,d
, colour
);
262 cxr_debug_line( d
,a
, colour
);
263 cxr_debug_line( a1
,b1
, colour
);
264 cxr_debug_line( b1
,c1
, colour
);
265 cxr_debug_line( c1
,d1
, colour
);
266 cxr_debug_line( d1
,a1
, colour
);
267 cxr_debug_line( a
,a1
, colour
);
268 cxr_debug_line( b
,b1
, colour
);
269 cxr_debug_line( c
,c1
, colour
);
270 cxr_debug_line( d
,d1
, colour
);
273 static void cxr_debug_arrow( v3f p0
, v3f p1
, v3f normal
, double sz
, v4f colour
)
275 v3f dir
, tan
, p2
, p3
;
279 v3_cross(dir
,normal
,tan
);
280 v3_muladds( p1
,dir
, -sz
, p2
);
281 v3_muladds( p2
,tan
,sz
,p3
);
282 cxr_debug_line( p1
, p3
, colour
);
283 v3_muladds( p2
,tan
,-sz
,p3
);
284 cxr_debug_line( p1
, p3
, colour
);
285 cxr_debug_line( p0
, p1
, colour
);
289 // =========================================================================
291 CXR_API
void cxr_context_reset(void)
293 cxr_context
.brush_count
= 0;
294 cxr_context
.entity_count
= 0;
295 cxr_context
.face_count
= 0;
296 cxr_context
.offset_z
= 0.0;
297 cxr_context
.scale_factor
= 32.0;
300 CXR_API
void cxr_set_offset(double offset
)
302 cxr_context
.offset_z
= offset
;
305 CXR_API
void cxr_set_scale_factor(double scale
)
307 cxr_context
.scale_factor
= scale
;
310 CXR_API
struct cxr_vdf
*cxr_vdf_open(const char *path
)
312 struct cxr_vdf
*vdf
= malloc(sizeof(struct cxr_vdf
));
315 vdf
->fp
= fopen( path
, "w" );
326 CXR_API
void cxr_vdf_close(struct cxr_vdf
*vdf
)
331 CXR_API
void cxr_vdf_put(struct cxr_vdf
*vdf
, const char *str
)
333 for( int i
=0; i
<vdf
->level
; i
++ )
334 fputs( " ", vdf
->fp
);
336 fputs( str
, vdf
->fp
);
339 static void cxr_vdf_printf( struct cxr_vdf
*vdf
, const char *fmt
, ... )
344 va_start( args
, fmt
);
345 vfprintf( vdf
->fp
, fmt
, args
);
349 CXR_API
void cxr_vdf_node(struct cxr_vdf
*vdf
, const char *str
)
351 cxr_vdf_put( vdf
, str
);
352 putc( (u8
)'\n', vdf
->fp
);
353 cxr_vdf_put( vdf
, "{\n" );
358 CXR_API
void cxr_vdf_edon(struct cxr_vdf
*vdf
)
361 cxr_vdf_put( vdf
, "}\n" );
364 CXR_API
void cxr_vdf_kv(struct cxr_vdf
*vdf
, const char *strk
, const char *strv
)
366 cxr_vdf_printf( vdf
, "\"%s\" \"%s\"\n", strk
, strv
);
369 static void cxr_vdf_ki32(struct cxr_vdf
*vdf
, const char *strk
, i32 val
)
371 cxr_vdf_printf( vdf
, "\"%s\" \"%d\"\n", strk
, val
);
373 static void cxr_vdf_kdouble(struct cxr_vdf
*vdf
, const char *strk
, double val
)
375 cxr_vdf_printf( vdf
, "\"%s\" \"%f\"\n", strk
, val
);
377 static void cxr_vdf_kaxis(struct cxr_vdf
*vdf
, const char *strk
, v3f normal
, double offset
, double scale
)
379 cxr_vdf_printf( vdf
, "\"%s\" \"[%f %f %f %f] %f\"\n", strk
, normal
[0],normal
[1],normal
[2],offset
,scale
);
381 static void cxr_vdf_kv3f(struct cxr_vdf
*vdf
, const char *strk
, v3f v
)
383 cxr_vdf_printf( vdf
, "\"%s\" \"[%f %f %f]\"\n", strk
, v
[0], v
[1], v
[2] );
385 static void cxr_vdf_karrdouble(struct cxr_vdf
*vdf
, const char *strk
, int id
, double *doubles
, int count
)
388 fprintf( vdf
->fp
, "\"%s%d\" \"", strk
, id
);
389 for( int i
=0; i
<count
; i
++ )
391 if( i
== count
-1 ) fprintf( vdf
->fp
, "%f", doubles
[i
] );
392 else fprintf( vdf
->fp
, "%f ", doubles
[i
] );
394 fprintf( vdf
->fp
, "\"\n" );
396 static void cxr_vdf_karrv3f(struct cxr_vdf
*vdf
, const char *strk
, int id
, v3f
*vecs
, int count
)
399 fprintf( vdf
->fp
, "\"%s%d\" \"", strk
, id
);
400 for( int i
=0; i
<count
; i
++ )
402 if( i
== count
-1 ) fprintf( vdf
->fp
, "%f %f %f", vecs
[i
][0], vecs
[i
][1], vecs
[i
][2] );
403 else fprintf( vdf
->fp
, "%f %f %f ", vecs
[i
][0], vecs
[i
][1], vecs
[i
][2] );
405 fprintf( vdf
->fp
, "\"\n" );
407 static void cxr_vdf_plane(struct cxr_vdf
*vdf
, const char *strk
, v3f a
, v3f b
, v3f c
)
409 cxr_vdf_printf( vdf
, "\"%s\" \"(%f %f %f) (%f %f %f) (%f %f %f)\"\n",
410 strk
, a
[0], a
[1], a
[2], b
[0], b
[1], b
[2], c
[0], c
[1], c
[2] );
412 static void cxr_vdf_colour255(struct cxr_vdf
*vdf
, const char *strk
, v4f colour
)
415 v4_muls( colour
, 255.0, scale
);
416 cxr_vdf_printf( vdf
, "\"%s\" \"%d %d %d %d\"\n",strk
,(int)scale
[0], (int)scale
[1], (int)scale
[2], (int)scale
[3]);
420 // =========================================================================
422 static void cxr_debug_poly(struct cxr_mesh
*mesh
, struct cxr_polygon
*poly
, v3f
*verts
, v4f colour
)
424 for( int i
=0; i
<poly
->loop_total
; i
++ )
426 struct cxr_loop
*loop0
= cxr_ab_ptr(&mesh
->loops
,poly
->loop_start
+i
),
427 *loop1
= cxr_ab_ptr(&mesh
->loops
,poly
->loop_start
+cxr_range(i
+1,poly
->loop_total
));
431 v3_lerp( verts
[loop0
->index
], poly
->center
, 0.02, p0
);
432 v3_lerp( verts
[loop1
->index
], poly
->center
, 0.02, p1
);
434 cxr_debug_arrow( p0
, p1
, poly
->normal
, 0.05, colour
);
438 v3_muladds( poly
->center
, poly
->normal
, 0.3, nrm0
);
440 cxr_debug_line( poly
->center
, nrm0
, colour
);
443 static void cxr_debug_mesh(struct cxr_mesh
*mesh
, v3f
*verts
, v4f colour
)
445 for( int i
=0; i
<mesh
->polys
.count
; i
++ )
447 struct cxr_polygon
*poly
= cxr_ab_ptr(&mesh
->polys
,i
);
448 cxr_debug_poly( mesh
, poly
, verts
, colour
);
452 static struct cxr_mesh
*cxr_alloc_mesh(int edge_count
, int loop_count
, int poly_count
)
454 struct cxr_mesh
*mesh
= malloc(sizeof(struct cxr_mesh
));
455 cxr_ab_init(&mesh
->edges
, sizeof(struct cxr_edge
), edge_count
);
456 cxr_ab_init(&mesh
->loops
, sizeof(struct cxr_loop
), loop_count
);
457 cxr_ab_init(&mesh
->polys
, sizeof(struct cxr_polygon
), poly_count
);
461 static void cxr_free_mesh(struct cxr_mesh
*mesh
)
463 cxr_ab_free(&mesh
->edges
);
464 cxr_ab_free(&mesh
->loops
);
465 cxr_ab_free(&mesh
->polys
);
469 // Rebuilds edge data and reallocates
471 static void cxr_mesh_clean_edges(struct cxr_mesh
*mesh
)
473 struct cxr_auto_buffer new_edges
;
474 cxr_ab_init( &new_edges
, sizeof(struct cxr_edge
), mesh
->edges
.count
);
476 for( int i
=0; i
<mesh
->polys
.count
; i
++ )
478 struct cxr_polygon
*poly
= cxr_ab_ptr(&mesh
->polys
,i
);
479 for( int j
=0; j
<poly
->loop_total
; j
++ )
482 *lp0
= cxr_ab_ptr(&mesh
->loops
,poly
->loop_start
+j
),
483 *lp1
= cxr_ab_ptr(&mesh
->loops
,poly
->loop_start
+cxr_range(j
+1,poly
->loop_total
));
485 int i0
= cxr_min(lp0
->index
, lp1
->index
),
486 i1
= cxr_max(lp0
->index
, lp1
->index
);
488 // See if edge exists before adding it
489 for( int k
=0; k
<new_edges
.count
; k
++ )
491 struct cxr_edge
*edge
= cxr_ab_ptr(&new_edges
,k
);
493 if( edge
->i0
== i0
&& edge
->i1
== i1
)
496 goto IL_EDGE_CREATED
;
500 int orig_edge_id
= lp0
->edge_index
;
501 lp0
->edge_index
= new_edges
.count
;
503 struct cxr_edge edge
= { i0
, i1
};
505 // Copy extra information (sharp,freestyle.. etc) here!
507 if( orig_edge_id
< mesh
->edges
.count
)
509 struct cxr_edge
*orig_edge
= cxr_ab_ptr( &mesh
->edges
, orig_edge_id
);
510 edge
.freestyle
= orig_edge
->freestyle
;
518 cxr_ab_push( &new_edges
, &edge
);
524 cxr_ab_free( &mesh
->edges
);
525 mesh
->edges
= new_edges
;
528 // Remove 0-length faces from mesh and correct loops
530 static void cxr_mesh_clean_faces(struct cxr_mesh
*mesh
)
532 struct cxr_auto_buffer loops_new
;
533 cxr_ab_init( &loops_new
, sizeof(struct cxr_loop
), mesh
->loops
.count
);
536 for( int i
=0; i
<mesh
->polys
.count
; i
++ )
538 struct cxr_polygon
*src
= cxr_ab_ptr(&mesh
->polys
,i
),
539 *dst
= cxr_ab_ptr(&mesh
->polys
,new_length
);
541 if( src
->loop_total
> 0 )
543 int src_start
= src
->loop_start
,
544 src_total
= src
->loop_total
;
547 dst
->loop_start
= loops_new
.count
;
549 for( int j
=0; j
<src_total
; j
++ )
551 struct cxr_loop
*loop
= cxr_ab_ptr(&mesh
->loops
,src_start
+j
),
552 *ldst
= cxr_ab_ptr(&loops_new
,dst
->loop_start
+j
);
554 ldst
->poly_left
= new_length
;
557 loops_new
.count
+= src_total
;
562 cxr_ab_free( &mesh
->loops
);
563 mesh
->loops
= loops_new
;
564 mesh
->polys
.count
= new_length
;
567 static i32
*cxr_mesh_link_loops(struct cxr_mesh
*mesh
)
569 i32
*polygon_edge_map
= malloc(mesh
->edges
.count
*2 *sizeof(i32
));
571 for( int i
= 0; i
< mesh
->edges
.count
*2; i
++ )
572 polygon_edge_map
[i
] = -1;
574 for( int i
= 0; i
< mesh
->polys
.count
; i
++ )
576 struct cxr_polygon
*poly
= cxr_ab_ptr(&mesh
->polys
, i
);
578 for( int j
= 0; j
< poly
->loop_total
; j
++ )
580 struct cxr_loop
*loop
= cxr_ab_ptr(&mesh
->loops
, poly
->loop_start
+j
);
583 for( int k
= 0; k
< 2; k
++ )
585 i32
*edge
= &polygon_edge_map
[loop
->edge_index
*2+k
];
595 for( int i
= 0; i
< mesh
->polys
.count
; i
++ )
597 struct cxr_polygon
*poly
= cxr_ab_ptr(&mesh
->polys
,i
);
599 for( int j
= 0; j
< poly
->loop_total
; j
++ )
601 struct cxr_loop
*loop
= cxr_ab_ptr(&mesh
->loops
,poly
->loop_start
+j
);
603 i32
*face_map
= &polygon_edge_map
[loop
->edge_index
*2];
605 if( face_map
[0] == loop
->poly_left
) loop
->poly_right
= face_map
[1];
606 else loop
->poly_right
= face_map
[0];
610 return polygon_edge_map
;
613 // Add polygon to mesh based on loop array
614 static struct cxr_polygon
*cxr_create_poly( struct cxr_mesh
*mesh
, v3f
*vertices
, struct cxr_loop poly
[],
615 int len
, int start
, int max
)
619 cxr_log( "tried to add new poly with length %d!\n", len
);
623 for( int j
=0; j
<len
; j
++ )
625 int i0
= poly
[j
].index
,
626 i1
= poly
[cxr_range(j
+1,len
)].index
;
627 cxr_debug_line( vertices
[i0
], vertices
[i1
], colour_error
);
634 int nface_id
= mesh
->polys
.count
;
635 struct cxr_polygon
*new_face
= cxr_ab_empty(&mesh
->polys
);
637 new_face
->loop_start
= mesh
->loops
.count
;
638 new_face
->loop_total
= len
;
639 new_face
->material_id
= -1;
641 // Calculate normal and center
642 v3_zero( new_face
->center
);
644 for( int j
=0; j
<len
; j
++ )
646 int i0
= poly
[cxr_range(start
+j
,max
)].index
;
647 struct cxr_loop
*new_loop
= cxr_ab_empty(&mesh
->loops
);
649 new_loop
->poly_left
= nface_id
;
650 new_loop
->poly_right
= -1;
651 new_loop
->index
= i0
;
652 new_loop
->edge_index
= 0;
653 v2_zero(new_loop
->uv
);
655 v3_add( new_face
->center
, vertices
[new_loop
->index
], new_face
->center
);
657 v3_divs( new_face
->center
, new_face
->loop_total
, new_face
->center
);
659 struct cxr_loop
*lp0
= cxr_ab_ptr( &mesh
->loops
, new_face
->loop_start
),
660 *lp1
= cxr_ab_ptr( &mesh
->loops
, new_face
->loop_start
+1 ),
661 *lp2
= cxr_ab_ptr( &mesh
->loops
, new_face
->loop_start
+2 );
663 tri_normal( vertices
[lp0
->index
], vertices
[lp1
->index
], vertices
[lp2
->index
], new_face
->normal
);
665 return cxr_ab_ptr(&mesh
->polys
, nface_id
);
668 // Get the 'next' mesh island
670 // Returns NULL if there is only one island
671 static struct cxr_mesh
*cxr_pull_island(struct cxr_mesh
*mesh
)
673 free(cxr_mesh_link_loops(mesh
));
675 int *island_current
= malloc(mesh
->polys
.count
*sizeof(int)),
680 island_current
[0] = 0;
683 last_count
= island_len
;
685 for( int i
=0; i
<island_len
; i
++ )
687 struct cxr_polygon
*poly
= cxr_ab_ptr(&mesh
->polys
,island_current
[i
]);
689 for( int j
=0; j
<poly
->loop_total
; j
++ )
691 struct cxr_loop
*loop
= cxr_ab_ptr(&mesh
->loops
, poly
->loop_start
+j
);
693 if( loop
->poly_right
!= -1 )
695 int face_present
= 0;
697 for( int k
=0; k
<island_len
; k
++ )
699 if( island_current
[k
] == loop
->poly_right
)
708 island_current
[ island_len
++ ] = loop
->poly_right
;
714 if( island_len
> last_count
)
715 goto IL_ISLAND_REPEAT
;
717 if( island_len
== mesh
->polys
.count
)
719 free( island_current
);
723 for( int i
=0; i
<island_len
; i
++ )
725 struct cxr_polygon
*poly
= cxr_ab_ptr(&mesh
->polys
, island_current
[i
]);
726 loop_count
+= poly
->loop_total
;
729 struct cxr_mesh
*newmesh
= cxr_alloc_mesh( mesh
->edges
.count
, loop_count
, island_len
);
731 for( int i
=0; i
<island_len
; i
++ )
733 struct cxr_polygon
*src
= cxr_ab_ptr(&mesh
->polys
, island_current
[i
]);
734 struct cxr_polygon
*dst
= cxr_ab_ptr(&newmesh
->polys
, i
);
737 dst
->loop_start
= newmesh
->loops
.count
;
739 for( int j
=0; j
<src
->loop_total
; j
++ )
741 struct cxr_loop
*lsrc
= cxr_ab_ptr(&mesh
->loops
, src
->loop_start
+j
),
742 *ldst
= cxr_ab_ptr(&newmesh
->loops
, dst
->loop_start
+j
);
746 ldst
->poly_right
= -1;
749 newmesh
->loops
.count
+= src
->loop_total
;
750 src
->loop_total
= -1;
753 newmesh
->polys
.count
= island_len
;
754 newmesh
->edges
.count
= mesh
->edges
.count
;
755 memcpy(cxr_ab_ptr(&newmesh
->edges
,0), cxr_ab_ptr(&mesh
->edges
,0), mesh
->edges
.count
*sizeof(struct cxr_edge
));
757 cxr_mesh_clean_faces(mesh
);
758 cxr_mesh_clean_edges(mesh
);
759 cxr_mesh_clean_edges(newmesh
);
760 free( island_current
);
765 // Does some checks to determine if solid is valid or not
766 static int cxr_valid_solid( struct cxr_mesh
*mesh
, struct cxr_auto_buffer
*abverts
, int *solid
, int len
)
768 // Invalid 1: Similar normals
769 // Invalid 2: Co-planar point, that is not referenced by the polygon.
771 for( int i
=0; i
<len
; i
++ )
773 struct cxr_polygon
*polyi
= cxr_ab_ptr(&mesh
->polys
,solid
[i
]);
776 normal_to_plane(polyi
->normal
, polyi
->center
, plane
);
778 for( int j
=0; j
<len
; j
++ )
782 struct cxr_polygon
*polyj
= cxr_ab_ptr(&mesh
->polys
,solid
[j
]);
784 for( int k
=0; k
<polyj
->loop_total
; k
++ )
786 struct cxr_loop
*lpj
= cxr_ab_ptr(&mesh
->loops
, polyj
->loop_start
+k
);
788 // Make sure this point isnt in our original poly
789 for( int l
=0; l
<polyi
->loop_total
; l
++ )
791 struct cxr_loop
*lpi
= cxr_ab_ptr(&mesh
->loops
, polyi
->loop_start
+l
);
792 if( lpi
->index
== lpj
->index
)
796 if( fabs(plane_polarity(plane
,cxr_ab_ptr(abverts
,lpj
->index
))) < 0.001 )
807 // Return best availible solid from mesh, and patch existing mesh to fill the gap
810 // Returns NULL if shape is already convex or empty
811 // Destroys edge data!
812 static struct cxr_mesh
*cxr_pull_best_solid(
813 struct cxr_mesh
*mesh
,
814 struct cxr_auto_buffer
*vert_buffer
,
815 int preserve_hot_edges
,
818 v3f
*vertices
= cxr_ab_ptr( vert_buffer
, 0 );
820 i32
*polygon_edge_map
= cxr_mesh_link_loops(mesh
);
822 for( int i
=0; i
<mesh
->edges
.count
*2; i
++ )
823 if( polygon_edge_map
[i
] == -1 )
825 cxr_log( "non-manifold edges are in the mesh; implicit internal geometry does not have full support\n" );
826 free(polygon_edge_map
);
830 int *vertex_tagged
= malloc( vert_buffer
->count
*sizeof(int) );
831 int *edge_tagged
= malloc( mesh
->edges
.count
*sizeof(int) );
833 for( int i
=0; i
<mesh
->edges
.count
; i
++ )
835 struct cxr_polygon
*polya
= cxr_ab_ptr(&mesh
->polys
, polygon_edge_map
[i
*2+0]),
836 *polyb
= cxr_ab_ptr(&mesh
->polys
, polygon_edge_map
[i
*2+1]);
838 normal_to_plane(polyb
->normal
, polyb
->center
, planeb
);
841 for( int j
=0; j
<polya
->loop_total
; j
++ )
843 struct cxr_loop
*loop
= cxr_ab_ptr(&mesh
->loops
, polya
->loop_start
+j
);
844 if( plane_polarity( planeb
, vertices
[loop
->index
] ) > 0.001 ||
845 v3_dot(polya
->normal
,polyb
->normal
) > CXR_PLANE_SIMILARITY_MAX
)
853 // Tag 'reflex' vertices
854 int *connected_planes
= malloc(mesh
->polys
.count
*sizeof(int));
856 for( int i
=0; i
<vert_buffer
->count
; i
++ )
860 int num_connected
= 0;
861 // Create a list of polys that ref this vert
862 for( int j
=0; j
<mesh
->polys
.count
; j
++ )
864 struct cxr_polygon
*poly
= cxr_ab_ptr(&mesh
->polys
,j
);
865 for( int k
=0; k
<poly
->loop_total
; k
++ )
867 struct cxr_loop
*loop
= cxr_ab_ptr(&mesh
->loops
,poly
->loop_start
+k
);
868 if( loop
->index
== i
)
870 connected_planes
[num_connected
++] = j
;
875 // Check all combinations for a similar normal
876 for( int j
=0; j
<num_connected
-1; j
++ )
878 for( int k
=j
+1; k
<num_connected
; k
++ )
880 struct cxr_polygon
*polyj
= cxr_ab_ptr(&mesh
->polys
,connected_planes
[j
]);
881 struct cxr_polygon
*polyk
= cxr_ab_ptr(&mesh
->polys
,connected_planes
[k
]);
883 if( v3_dot(polyj
->normal
, polyk
->normal
) > CXR_PLANE_SIMILARITY_MAX
)
888 // Check if all connected planes not are:
889 // - bounded by other planes
892 for( int j
=0; j
<num_connected
; j
++ )
893 for( int k
=j
+1; k
<num_connected
; k
++ )
895 struct cxr_polygon
*jpoly
= cxr_ab_ptr(&mesh
->polys
, connected_planes
[j
]),
896 *kpoly
= cxr_ab_ptr(&mesh
->polys
, connected_planes
[k
]);
898 normal_to_plane( kpoly
->normal
, kpoly
->center
, plane
);
899 for( int l
=0; l
<jpoly
->loop_total
; l
++ )
901 struct cxr_loop
*loop
= cxr_ab_ptr(&mesh
->loops
, jpoly
->loop_start
+l
);
902 if( plane_polarity( plane
, vertices
[loop
->index
] ) > 0.001 )
907 goto IL_TAG_NEXT_VERT
;
908 IL_TAG_VERT
: vertex_tagged
[i
] = 1;
912 free( connected_planes
);
914 // Connect all marked verts that share an edge
915 // - We must take care not to completely isolate
916 // a polygon with marked edges all around it
918 int *hot_edge
= malloc(mesh
->edges
.count
*sizeof(int));
919 for( int i
=0; i
< mesh
->edges
.count
; i
++ )
922 for( int i
=0; i
<mesh
->polys
.count
; i
++ )
924 struct cxr_polygon
*poly
= cxr_ab_ptr(&mesh
->polys
,i
);
928 for( int j
=0; j
<poly
->loop_total
; j
++ )
930 struct cxr_loop
*loop
= cxr_ab_ptr(&mesh
->loops
, poly
->loop_start
+j
);
932 if( !edge_tagged
[ loop
->edge_index
] )
934 if( not_tagged
== -1 )
935 not_tagged
= loop
->edge_index
;
937 goto IL_SKIP_NO_HOT_EDGE
;
941 if( not_tagged
!= -1 )
942 hot_edge
[not_tagged
]=1;
944 IL_SKIP_NO_HOT_EDGE
:;
947 // Connect edges that have verts tagged, but is not a hot edge
948 for( int i
=0; i
<mesh
->edges
.count
; i
++ )
950 if( hot_edge
[i
] && preserve_hot_edges
) continue;
952 struct cxr_edge
*edge
= cxr_ab_ptr(&mesh
->edges
,i
);
953 if( vertex_tagged
[edge
->i0
] && vertex_tagged
[edge
->i1
] )
958 for( int i
=0; i
<vert_buffer
->count
; i
++ )
959 if( vertex_tagged
[i
] )
960 cxr_debug_box( vertices
[i
], 0.03, (v4f
){0.0,0.0,0.0,1.0});
962 for( int i
=0; i
< mesh
->edges
.count
; i
++ )
964 struct cxr_edge
*edge
= cxr_ab_ptr( &mesh
->edges
, i
);
966 cxr_debug_line( vertices
[ edge
->i0
], vertices
[ edge
->i1
], (v4f
){0.0,0.0,0.0,1.0});
969 cxr_debug_line( vertices
[ edge
->i0
], vertices
[ edge
->i1
], (v4f
){0.0,1.0,1.0,1.0});
974 int *faces_tagged
= malloc(mesh
->polys
.count
*sizeof(int));
975 for( int i
=0; i
<mesh
->polys
.count
; i
++ )
976 faces_tagged
[i
] = -1;
978 int *solid_buffer
= malloc( mesh
->polys
.count
*sizeof(int) );
979 int solid_buffer_len
= 0;
982 int start
,count
,edge_count
;
985 *candidates
= malloc( mesh
->polys
.count
*sizeof(struct csolid
) );
986 int candidate_count
= 0;
992 *edge_references
= malloc( mesh
->edges
.count
*sizeof(struct tedge
) );
994 for( int i
=0; i
<mesh
->polys
.count
; i
++ )
996 if( faces_tagged
[i
] != -1 ) continue;
999 int *solid
= &solid_buffer
[ solid_buffer_len
];
1002 solid
[solid_len
++] = i
;
1004 int search_start
= 0;
1006 // Iterative search that connects regions of planes governed by rules:
1007 // - edge can add other face if the edge has less than two reflexes
1008 // - the face can no longer be used in future searches
1010 IL_SEARCH_CONTINUE
:;
1013 for( int j
=search_start
; j
<solid_len
; j
++ )
1015 struct cxr_polygon
*poly
= cxr_ab_ptr(&mesh
->polys
, solid
[j
]);
1017 for( int k
=0; k
<poly
->loop_total
; k
++ )
1019 struct cxr_loop
*loop
= cxr_ab_ptr(&mesh
->loops
, poly
->loop_start
+k
);
1020 struct cxr_edge
*edge
= cxr_ab_ptr(&mesh
->edges
, loop
->edge_index
);
1022 if( faces_tagged
[ loop
->poly_right
] == -1 )
1024 if( !edge_tagged
[loop
->edge_index
] )
1028 // Need to look ahead 1 step to make sure he does not want
1029 // to add any more planes that are coplanar with some of
1030 // our existing group
1032 // This can sort out SOME invalid configs, but not all.
1033 // It would be nice to find a more robust clustering algorithm for this.
1036 struct cxr_polygon
*poly_to_add
= cxr_ab_ptr(&mesh
->polys
, loop
->poly_right
);
1037 for( int l
=0; l
< poly_to_add
->loop_total
; l
++ )
1039 struct cxr_loop
*loop1
= cxr_ab_ptr(&mesh
->loops
, poly_to_add
->loop_start
+l
);
1040 struct cxr_polygon
*future_face
= cxr_ab_ptr(&mesh
->polys
, loop1
->poly_right
);
1042 if( edge_tagged
[ loop1
->edge_index
] || loop1
->poly_right
== loop
->poly_right
)
1043 goto IL_SKIP_SIMILAR_PLANES
;
1045 for( int m
=0; m
<solid_len
; m
++ )
1046 if( solid
[m
] == loop1
->poly_right
)
1047 goto IL_SKIP_SIMILAR_PLANES
;
1049 for( int m
=0; m
<solid_len
; m
++ )
1051 struct cxr_polygon
*polym
= cxr_ab_ptr(&mesh
->polys
,solid
[m
]);
1052 if( v3_dot( polym
->normal
,future_face
->normal
) > CXR_PLANE_SIMILARITY_MAX
)
1053 goto IL_SKIP_PLANE_ADD
;
1056 IL_SKIP_SIMILAR_PLANES
:;
1059 // Check for vertices in the new poly that exist on a current plane.
1060 // this condition is an invalid configuration and should not be added.
1062 solid
[ solid_len
] = loop
->poly_right
;
1064 if( cxr_valid_solid(mesh
,vert_buffer
,solid
,solid_len
+1 ) )
1066 faces_tagged
[ loop
->poly_right
] = i
;
1076 search_start
= solid_len
;
1078 goto IL_SEARCH_CONTINUE
;
1080 // The current method can create some invalid configurations
1081 // filter those out that dont work and un-tag the faces
1082 for( int j
=0; j
<solid_len
-1; j
++ )
1084 for( int k
=j
+1; k
<solid_len
; k
++ )
1086 struct cxr_polygon
*polyj
= cxr_ab_ptr(&mesh
->polys
, solid
[j
]),
1087 *polyk
= cxr_ab_ptr(&mesh
->polys
, solid
[k
]);
1089 if( v3_dot( polyj
->normal
, polyk
->normal
) > CXR_PLANE_SIMILARITY_MAX
)
1091 for( int l
=0; l
<solid_len
; l
++ )
1092 faces_tagged
[ solid
[l
] ] = -1;
1094 goto IL_CANCEL_SOLID
;
1100 struct csolid
*csolid
= &candidates
[candidate_count
++];
1101 csolid
->start
= solid_buffer_len
;
1102 csolid
->count
= solid_len
;
1103 csolid
->edge_count
= 0;
1105 v3_zero( csolid
->center
);
1106 for( int j
=0; j
<solid_len
; j
++ )
1108 struct cxr_polygon
*polyj
= cxr_ab_ptr(&mesh
->polys
, solid
[j
]);
1109 v3_add( polyj
->center
, csolid
->center
, csolid
->center
);
1110 csolid
->edge_count
+= polyj
->loop_total
;
1112 v3_divs( csolid
->center
, solid_len
, csolid
->center
);
1114 solid_buffer_len
+= solid_len
;
1119 free( edge_references
);
1121 // Create all candidates who have one or less non-manifolds edges
1122 // Loop each candidate, determine the manifold, and pick the best one
1124 struct csolid
*best_solid
= NULL
;
1125 int fewest_manifold_splits
= INT32_MAX
;
1127 struct cxr_loop
*best_manifold
= malloc( mesh
->loops
.count
*sizeof(struct cxr_loop
) );
1128 int *best_manifold_splits
= malloc( mesh
->loops
.count
*sizeof(int) );
1129 int best_manifold_len
= 0;
1130 int max_solid_faces
= 0;
1132 int *edge_list
= malloc( mesh
->edges
.count
*sizeof(int) );
1133 int *edge_lefts
= malloc( mesh
->edges
.count
*sizeof(int) );
1134 struct cxr_loop
*manifold
= malloc(mesh
->edges
.count
*2*sizeof(struct cxr_loop
));
1135 int *splits
= malloc(mesh
->edges
.count
*2*sizeof(int));
1137 for( int i
=0; i
<candidate_count
; i
++ )
1139 struct csolid
*solid
= &candidates
[i
];
1140 max_solid_faces
= cxr_max(max_solid_faces
,solid
->count
);
1142 if( solid
->count
<= 2 )
1145 int init_reverse
= 0;
1146 int unique_edge_count
= 0;
1148 for( int j
=0; j
<solid
->count
; j
++ )
1150 struct cxr_polygon
*poly
= cxr_ab_ptr(&mesh
->polys
, solid_buffer
[solid
->start
+j
]);
1152 for( int k
=0; k
<poly
->loop_total
; k
++ )
1154 struct cxr_loop
*loop
= cxr_ab_ptr(&mesh
->loops
, poly
->loop_start
+k
);
1156 for( int l
=0; l
<unique_edge_count
; l
++ )
1157 if( edge_list
[l
] == loop
->edge_index
)
1158 goto IL_EDGE_ALREADY_PRESENT
;
1160 // Check if right edge references a polygon that is not
1161 // present inside the current solid candidate
1162 for( int l
=0; l
<solid
->count
; l
++ )
1163 if( loop
->poly_right
== solid_buffer
[solid
->start
+l
] )
1164 goto IL_EDGE_ALREADY_PRESENT
;
1166 edge_list
[ unique_edge_count
] = loop
->edge_index
;
1167 edge_lefts
[ unique_edge_count
] = loop
->poly_left
;
1169 if( unique_edge_count
== 0 )
1171 struct cxr_edge
*edgeptr
= cxr_ab_ptr(&mesh
->edges
, loop
->edge_index
);
1172 if( edgeptr
->i1
== loop
->index
)
1176 unique_edge_count
++;
1177 IL_EDGE_ALREADY_PRESENT
:;
1181 // This solid is already fully connected
1182 if( unique_edge_count
== 0 )
1185 // Link edges together to create new manifold
1186 // Corners are created when two edges share a polygon face
1187 // This way we can split it into regions
1189 for( int j
=0; j
<vert_buffer
->count
; j
++ )
1190 vertex_tagged
[j
] = -1;
1192 // Start with a loop edge which was tagged
1193 struct cxr_edge
*current
= cxr_ab_ptr(&mesh
->edges
, edge_list
[0]);
1195 int endpt
= (!init_reverse
)? current
->i0
: current
->i1
,
1197 curface
= edge_lefts
[0];
1199 int manifold_len
= 0;
1200 int split_count
= 0;
1202 IL_MANIFOLD_CONTINUE
:
1203 for( int j
=0; j
<unique_edge_count
; j
++ )
1205 struct cxr_edge
*other
= cxr_ab_ptr(&mesh
->edges
, edge_list
[j
]);
1206 if( other
== current
)
1209 if( other
->i0
== endpt
|| other
->i1
== endpt
)
1214 if( other
->i0
== endpt
) endpt
= current
->i1
;
1215 else endpt
= current
->i0
;
1217 if( curface
==edge_lefts
[j
] )
1219 splits
[ manifold_len
] = 1;
1223 splits
[ manifold_len
] = 0;
1225 // Append to intermidiary manifold
1226 manifold
[ manifold_len
].edge_index
= edge_list
[j
];
1227 manifold
[ manifold_len
].poly_left
= edge_lefts
[j
];
1228 manifold
[ manifold_len
].index
= lastpt
;
1229 manifold
[ manifold_len
].poly_right
=
1230 polygon_edge_map
[ edge_list
[j
]*2 ] == edge_lefts
[j
]?
1231 polygon_edge_map
[ edge_list
[j
]*2+1 ]:
1232 polygon_edge_map
[ edge_list
[j
]*2+0 ];
1235 curface
= edge_lefts
[j
];
1237 if(endpt
== start
) goto IL_MANIFOLD_COMPLETE
;
1238 goto IL_MANIFOLD_CONTINUE
;
1241 cxr_log( "Failed to link manifold, count: %d\n", manifold_len
);
1243 for( int j
=0; j
<solid
->count
; j
++ )
1245 cxr_log( "p%d\n", solid_buffer
[solid
->start
+j
] );
1246 struct cxr_polygon
*poly
= cxr_ab_ptr(&mesh
->polys
, solid_buffer
[solid
->start
+j
]);
1247 cxr_debug_poly( mesh
, poly
, vertices
, (v4f
){0.2,0.0,0.0,1.0} );
1250 for( int j
=0; j
<unique_edge_count
; j
++ )
1252 struct cxr_edge
*uedge
= cxr_ab_ptr(&mesh
->edges
, edge_list
[j
]);
1253 cxr_debug_line(vertices
[uedge
->i0
],vertices
[uedge
->i1
],(v4f
){0.4,0.0,0.0,1.0});
1256 for( int j
=0; j
<manifold_len
-1; j
++ )
1258 struct cxr_loop
*lp0
= &manifold
[j
],
1259 *lp1
= &manifold
[cxr_range(j
+1,manifold_len
)];
1261 cxr_debug_line(vertices
[lp0
->index
],vertices
[lp1
->index
], colour_error
);
1264 cxr_debug_mesh( mesh
, vertices
, (v4f
){0.0,0.0,0.0, 0.9} );
1265 *error
= CXR_ERROR_BAD_MANIFOLD
;
1272 free(vertex_tagged
);
1277 free(best_manifold
);
1278 free(best_manifold_splits
);
1279 free(polygon_edge_map
);
1282 IL_MANIFOLD_COMPLETE
:;
1284 if( manifold_len
< unique_edge_count
)
1288 if( split_count
< fewest_manifold_splits
)
1290 fewest_manifold_splits
= split_count
;
1293 for( int j
=0; j
<manifold_len
; j
++ )
1295 best_manifold
[j
] = manifold
[j
];
1296 best_manifold_splits
[j
] = splits
[j
];
1298 best_manifold_len
= manifold_len
;
1308 if( max_solid_faces
< 2 )
1310 *error
= CXR_ERROR_NO_SOLIDS
;
1312 free(vertex_tagged
);
1317 free(best_manifold
);
1318 free(best_manifold_splits
);
1319 free(polygon_edge_map
);
1323 if( best_solid
!= NULL
)
1325 struct cxr_mesh
*pullmesh
=
1326 cxr_alloc_mesh( best_solid
->edge_count
, best_solid
->edge_count
, best_solid
->count
);
1328 // Add existing faces to pullsolid, and delete from main mesh
1329 for( int i
=0; i
<best_solid
->count
; i
++ )
1331 int nface_id
= pullmesh
->polys
.count
;
1333 struct cxr_polygon
*exist_face
= cxr_ab_ptr(&mesh
->polys
, solid_buffer
[best_solid
->start
+i
]);
1334 struct cxr_polygon
*new_face
= cxr_ab_empty(&pullmesh
->polys
);
1336 *new_face
= *exist_face
;
1337 new_face
->loop_start
= pullmesh
->loops
.count
;
1339 for( int j
=0; j
<exist_face
->loop_total
; j
++ )
1341 struct cxr_loop
*exist_loop
= cxr_ab_ptr(&mesh
->loops
, exist_face
->loop_start
+j
);
1342 struct cxr_loop
*new_loop
= cxr_ab_empty(&pullmesh
->loops
);
1344 new_loop
->index
= exist_loop
->index
;
1345 new_loop
->poly_left
= nface_id
;
1346 new_loop
->poly_right
= -1;
1347 new_loop
->edge_index
= 0;
1348 v2_copy( exist_loop
->uv
, new_loop
->uv
);
1351 exist_face
->loop_total
= -1;
1355 int pullmesh_new_start
= pullmesh
->polys
.count
;
1357 if( fewest_manifold_splits
!= 0 )
1359 #if CXR_MANIFOLD_DEBUG
1360 for( int i
=0; i
<best_manifold_len
; i
++ )
1363 i1
= cxr_range(i
+1,best_manifold_len
);
1365 cxr_debug_line( vertices
[best_manifold
[i0
].index
], vertices
[best_manifold
[i1
].index
], colour_error
);
1366 if( best_manifold_splits
[i
] )
1367 cxr_debug_box( vertices
[best_manifold
[i0
].index
], 0.04, colour_success
);
1371 // This is a really strange observation, however it *seems* to apply to the kinds
1372 // of geometry we are dealing with. If the split count is odd, the manifold can be
1373 // created easily, no folding required.
1375 // When it is even, it appears that internal implicit geometry is required, so we
1376 // need to fold the loops we create. Its really weird, but for some reason works on
1377 // the geometry rules we've defined.
1378 // TODO(harry): Find a well defined rule here.
1380 int collapse_used_segments
= (u32
)fewest_manifold_splits
& 0x1? 0: 1;
1382 IL_MANIFOLD_BUILD_REPEAT
:
1384 for( int j
=0; j
<best_manifold_len
; j
++ )
1386 if( best_manifold_splits
[j
] )
1388 struct cxr_loop
*loop
= &best_manifold
[j
];
1390 for( int k
=1; k
<best_manifold_len
; k
++ )
1392 int index1
= cxr_range(j
+k
,best_manifold_len
);
1393 struct cxr_loop
*loop1
= &best_manifold
[index1
];
1395 if( best_manifold_splits
[index1
] )
1402 if( new_polys
> best_manifold_len
)
1404 cxr_log( "Programming error: Too many new polys!\n" );
1408 cxr_create_poly( pullmesh
, vertices
, best_manifold
, k
+1, j
, best_manifold_len
);
1410 // Remove new section from manifold
1411 if( collapse_used_segments
)
1413 best_manifold_splits
[j
] = 0;
1414 best_manifold_splits
[index1
] = 0;
1416 int new_length
= (best_manifold_len
-(k
-1));
1418 struct cxr_loop
*new_manifold
= malloc( new_length
*sizeof(struct cxr_loop
) );
1419 int *new_manifold_splits
= malloc( new_length
*sizeof(int) );
1421 for( int l
=0; l
<new_length
; l
++ )
1423 int i_src
= cxr_range( j
+k
+l
, best_manifold_len
);
1424 new_manifold
[l
] = best_manifold
[i_src
];
1425 new_manifold_splits
[l
] = best_manifold_splits
[i_src
];
1428 free( best_manifold
);
1429 free( best_manifold_splits
);
1430 best_manifold
= new_manifold
;
1431 best_manifold_splits
= new_manifold_splits
;
1433 best_manifold_len
= new_length
;
1435 goto IL_MANIFOLD_BUILD_REPEAT
;
1445 if( best_manifold_len
&& collapse_used_segments
)
1447 cxr_create_poly( pullmesh
, vertices
, best_manifold
, best_manifold_len
, 0, best_manifold_len
);
1453 cxr_create_poly( pullmesh
, vertices
, best_manifold
, best_manifold_len
, 0, best_manifold_len
);
1457 // vert_buffer may be reallocated by the next section of code,
1458 // force a NULLref on vertices to catch any errors
1461 // Implicit geometry reconstruction
1462 // If there's 3 or more planes, collide them together to see if any new
1463 // vertices need to be created on the mesh
1464 if( new_polys
>= 3 )
1466 for( int i
=0; i
<new_polys
-2; i
++ )
1468 for( int j
=i
+1; j
<new_polys
-1; j
++ )
1470 for( int k
=j
+1; k
<new_polys
; k
++ )
1472 struct cxr_polygon
*ptri
= cxr_ab_ptr( &pullmesh
->polys
, pullmesh_new_start
+i
),
1473 *ptrj
= cxr_ab_ptr( &pullmesh
->polys
, pullmesh_new_start
+j
),
1474 *ptrk
= cxr_ab_ptr( &pullmesh
->polys
, pullmesh_new_start
+k
);
1476 v4f planei
, planej
, planek
;
1477 normal_to_plane(ptri
->normal
,ptri
->center
,planei
);
1478 normal_to_plane(ptrj
->normal
,ptrj
->center
,planej
);
1479 normal_to_plane(ptrk
->normal
,ptrk
->center
,planek
);
1483 if( plane_intersect(planei
,planej
,planek
,intersect
) )
1485 // cxr_debug_box( intersect, 0.05, colour_error );
1487 // Make sure this point is within the convex region, otherwise treat
1488 // it as a degenerate case
1490 int point_valid
= 1;
1491 for( int l
=0; l
<pullmesh
->polys
.count
; l
++ )
1493 struct cxr_polygon
*ptrl
= cxr_ab_ptr(&pullmesh
->polys
,l
);
1496 normal_to_plane(ptrl
->normal
, ptrl
->center
, planel
);
1498 if( plane_polarity( planel
, intersect
) > 0.01 )
1500 cxr_log( "degen vert, planes %d, %d, %d [max:%d]\n", i
,j
,k
, new_polys
);
1501 *error
= CXR_ERROR_DEGEN_IMPLICIT
;
1503 cxr_debug_poly( pullmesh
, ptri
, cxr_ab_ptr(vert_buffer
,0), colours_random
[3] );
1504 cxr_debug_poly( pullmesh
, ptrj
, cxr_ab_ptr(vert_buffer
,0), colours_random
[1] );
1505 cxr_debug_poly( pullmesh
, ptrk
, cxr_ab_ptr(vert_buffer
,0), colours_random
[2] );
1512 if( !point_valid
) continue;
1514 // Extend faces to include this point
1515 int nvertid
= vert_buffer
->count
;
1516 cxr_ab_push( vert_buffer
, intersect
);
1518 ptrj
->loop_start
+= 1;
1519 ptrk
->loop_start
+= 2;
1521 cxr_ab_reserve(&pullmesh
->loops
, 3);
1522 struct cxr_loop
*lloopi
= cxr_ab_empty_at(&pullmesh
->loops
, ptri
->loop_start
+ptri
->loop_total
),
1523 *lloopj
= cxr_ab_empty_at(&pullmesh
->loops
, ptrj
->loop_start
+ptrj
->loop_total
),
1524 *lloopk
= cxr_ab_empty_at(&pullmesh
->loops
, ptrk
->loop_start
+ptrk
->loop_total
);
1526 lloopi
->index
= nvertid
;
1527 lloopj
->index
= nvertid
;
1528 lloopk
->index
= nvertid
;
1529 lloopi
->edge_index
= 0; lloopj
->edge_index
= 0; lloopk
->edge_index
= 0;
1530 lloopi
->poly_left
= pullmesh_new_start
+i
;
1531 lloopj
->poly_left
= pullmesh_new_start
+j
;
1532 lloopk
->poly_left
= pullmesh_new_start
+k
;
1533 lloopi
->poly_right
= -1; lloopj
->poly_right
= -1; lloopk
->poly_right
= -1;
1535 v2_zero(lloopi
->uv
);
1536 v2_zero(lloopj
->uv
);
1537 v2_zero(lloopk
->uv
);
1539 ptri
->loop_total
++;
1540 ptrj
->loop_total
++;
1541 ptrk
->loop_total
++;
1543 // Adjust centers of faces
1544 v3_lerp( ptri
->center
, intersect
, 1.0/(double)ptri
->loop_total
, ptri
->center
);
1545 v3_lerp( ptrj
->center
, intersect
, 1.0/(double)ptrj
->loop_total
, ptrj
->center
);
1546 v3_lerp( ptrk
->center
, intersect
, 1.0/(double)ptrk
->loop_total
, ptrk
->center
);
1553 // Copy faces from pullsolid into orig mesh
1555 for( int i
=0; i
<new_polys
; i
++ )
1557 int rface_id
= mesh
->polys
.count
;
1559 struct cxr_polygon
*pface
= cxr_ab_ptr(&pullmesh
->polys
,pullmesh_new_start
+i
);
1560 struct cxr_polygon
*rip_face
= cxr_ab_empty(&mesh
->polys
);
1562 rip_face
->loop_start
= mesh
->loops
.count
;
1563 rip_face
->loop_total
= pface
->loop_total
;
1564 rip_face
->material_id
= -1;
1566 for( int j
=0; j
<rip_face
->loop_total
; j
++ )
1568 struct cxr_loop
*ploop
= cxr_ab_ptr(&pullmesh
->loops
, pface
->loop_start
+pface
->loop_total
-j
-1),
1569 *rloop
= cxr_ab_empty(&mesh
->loops
);
1571 rloop
->index
= ploop
->index
;
1572 rloop
->poly_left
= rface_id
;
1573 rloop
->poly_right
= -1;
1574 rloop
->edge_index
= 0;
1575 v2_copy( ploop
->uv
, rloop
->uv
);
1578 v3_copy( pface
->center
, rip_face
->center
);
1579 v3_negate( pface
->normal
, rip_face
->normal
);
1582 cxr_mesh_clean_faces( mesh
);
1583 cxr_mesh_clean_faces( pullmesh
);
1584 cxr_mesh_clean_edges( mesh
);
1585 cxr_mesh_clean_edges( pullmesh
);
1588 free(vertex_tagged
);
1593 free(best_manifold
);
1594 free(best_manifold_splits
);
1595 free(polygon_edge_map
);
1601 free(vertex_tagged
);
1606 free(best_manifold
);
1607 free(best_manifold_splits
);
1608 free(polygon_edge_map
);
1613 static struct cxr_mesh
*cxr_to_internal_format(struct cxr_input_mesh
*src
, struct cxr_auto_buffer
*abverts
)
1615 // Split mesh into islands
1616 struct cxr_mesh
*mesh
= cxr_alloc_mesh( src
->edge_count
, src
->loop_count
, src
->poly_count
);
1617 cxr_ab_init( abverts
, sizeof(v3f
), src
->vertex_count
);
1619 // Copy input data into working mesh
1620 memcpy( cxr_ab_ptr( &mesh
->edges
, 0 ), src
->edges
, src
->edge_count
*sizeof(struct cxr_edge
));
1621 memcpy( cxr_ab_ptr( &mesh
->polys
, 0 ), src
->polys
, src
->poly_count
*sizeof(struct cxr_polygon
));
1622 memcpy( cxr_ab_ptr( abverts
, 0 ), src
->vertices
, src
->vertex_count
*sizeof(v3f
));
1623 mesh
->edges
.count
= src
->edge_count
;
1624 mesh
->loops
.count
= src
->loop_count
;
1625 mesh
->polys
.count
= src
->poly_count
;
1627 for( int i
=0; i
<src
->loop_count
; i
++ )
1629 struct cxr_loop
*lp
= cxr_ab_ptr(&mesh
->loops
,i
);
1630 lp
->index
= src
->loops
[i
].index
;
1631 lp
->edge_index
= src
->loops
[i
].edge_index
;
1632 v2_copy( src
->loops
[i
].uv
, lp
->uv
);
1635 abverts
->count
= src
->vertex_count
;
1640 // Find farthest dot product along direction
1641 static double support_distance( v3f verts
[3], v3f dir
, double coef
)
1645 coef
* v3_dot( verts
[0], dir
),
1648 coef
* v3_dot( verts
[1], dir
),
1649 coef
* v3_dot( verts
[2], dir
)
1655 static void cxr_calculate_axis(
1656 struct cxr_texinfo
*transform
,
1662 v2f tT
, bT
; // Tangent/bitangent pairs for UV space and world
1665 v2_sub( uvs
[0], uvs
[1], tT
);
1666 v2_sub( uvs
[2], uvs
[1], bT
);
1667 v3_sub( verts
[0], verts
[1], tW
);
1668 v3_sub( verts
[2], verts
[1], bW
);
1670 // Use arbitrary projection if there is no UV
1671 if( v2_length( tT
) < 0.0001 || v2_length( bT
) < 0.0001 )
1673 v3f uaxis
, normal
, vaxis
;
1675 v3_copy( tW
, uaxis
);
1676 v3_normalize( uaxis
);
1678 v3_cross( tW
, bW
, normal
);
1679 v3_cross( normal
, uaxis
, vaxis
);
1680 v3_normalize( vaxis
);
1682 v3_copy( uaxis
, transform
->uaxis
);
1683 v3_copy( vaxis
, transform
->vaxis
);
1684 v2_zero( transform
->offset
);
1686 v2_div( (v2f
){128.0, 128.0}, texture_res
, transform
->scale
);
1687 transform
->winding
= 1.0;
1691 // Detect if UV is reversed
1692 double winding
= v2_cross( tT
, bT
) >= 0.0f
? 1.0f
: -1.0f
;
1694 // UV projection reference
1696 v2_muls((v2f
){1,0}, winding
, vX
);
1697 v2_muls((v2f
){0,1}, winding
, vY
);
1699 // Reproject reference into world space, including skew
1702 v3_muls( tW
, v2_cross(vX
,bT
) / v2_cross(bT
,tT
), uaxis1
);
1703 v3_muladds( uaxis1
, bW
, v2_cross(vX
, tT
) / v2_cross(tT
,bT
), uaxis1
);
1705 v3_muls( tW
, v2_cross(vY
,bT
) / v2_cross(bT
,tT
), vaxis1
);
1706 v3_muladds( vaxis1
, bW
, v2_cross(vY
,tT
) / v2_cross(tT
,bT
), vaxis1
);
1708 v3_normalize( uaxis1
);
1709 v3_normalize( vaxis1
);
1711 // Apply source transform to axis (yes, they also need to be swapped)
1712 v3f norm
, uaxis
, vaxis
;
1714 v3_cross( bW
, tW
, norm
);
1716 v3_cross( vaxis1
, norm
, uaxis
);
1717 v3_cross( uaxis1
, norm
, vaxis
);
1720 v2f uvmin
, uvmax
, uvdelta
;
1721 v2_minv( uvs
[0], uvs
[1], uvmin
);
1722 v2_minv( uvmin
, uvs
[2], uvmin
);
1723 v2_maxv( uvs
[0], uvs
[1], uvmax
);
1724 v2_maxv( uvmax
, uvs
[2], uvmax
);
1726 v2_sub( uvmax
, uvmin
, uvdelta
);
1729 v2f uvminw
, uvmaxw
, uvdeltaw
;
1730 uvminw
[0] = -support_distance( verts
, uaxis
, -1.0f
);
1731 uvmaxw
[0] = support_distance( verts
, uaxis
, 1.0f
);
1732 uvminw
[1] = -support_distance( verts
, vaxis
, -1.0f
);
1733 uvmaxw
[1] = support_distance( verts
, vaxis
, 1.0f
);
1735 v2_sub( uvmaxw
, uvminw
, uvdeltaw
);
1739 v2_div( uvdeltaw
, uvdelta
, uv_scale
);
1740 v2_div( uv_scale
, texture_res
, uv_scale
);
1742 // Find offset via 'natural' point
1743 v2f target_uv
, natural_uv
, tex_offset
;
1744 v2_mul( uvs
[0], texture_res
, target_uv
);
1746 natural_uv
[0] = v3_dot( uaxis
, verts
[0] );
1747 natural_uv
[1] = -v3_dot( vaxis
, verts
[0] );
1748 v2_div( natural_uv
, uv_scale
, natural_uv
);
1750 tex_offset
[0] = target_uv
[0]-natural_uv
[0];
1751 tex_offset
[1] = -(target_uv
[1]-natural_uv
[1]);
1753 // Copy everything into output
1754 v3_copy( uaxis
, transform
->uaxis
);
1755 v3_copy( vaxis
, transform
->vaxis
);
1756 v2_copy( tex_offset
, transform
->offset
);
1757 v2_copy( uv_scale
, transform
->scale
);
1758 transform
->winding
= winding
;
1761 CXR_API
struct cxr_input_mesh
*cxr_decompose(struct cxr_input_mesh
*src
)
1763 #ifdef CXR_DEBUG_WRITE_MESH
1764 FILE *yeet
= fopen( "/home/harry/Documents/blender_addons_remote/addons/convexer/solid.h", "w" );
1766 fprintf( yeet
, "v3f test_verts[] = {\n" );
1767 for( int i
=0; i
<src
->vertex_count
; i
++ )
1769 fprintf( yeet
, " { %f, %f, %f },\n",
1770 src
->vertices
[i
][0],
1771 src
->vertices
[i
][1],
1772 src
->vertices
[i
][2] );
1774 fprintf( yeet
, "};\n" );
1776 fprintf( yeet
, "struct cxr_input_loop test_loops[] = {\n" );
1777 for( int i
=0; i
<src
->loop_count
; i
++ )
1779 fprintf( yeet
, " {%d, %d},\n",
1780 src
->loops
[i
].index
,
1781 src
->loops
[i
].edge_index
);
1783 fprintf( yeet
, "};\n" );
1785 fprintf( yeet
, "struct cxr_polygon test_polys[] = {\n" );
1786 for( int i
=0; i
<src
->poly_count
; i
++ )
1788 fprintf( yeet
, " {%d, %d, {%f, %f, %f}, {%f, %f, %f}},\n",
1789 src
->polys
[i
].loop_start
,
1790 src
->polys
[i
].loop_total
,
1791 src
->polys
[i
].normal
[0],
1792 src
->polys
[i
].normal
[1],
1793 src
->polys
[i
].normal
[2],
1794 src
->polys
[i
].center
[0],
1795 src
->polys
[i
].center
[1],
1796 src
->polys
[i
].center
[2] );
1798 fprintf( yeet
, "};\n" );
1800 fprintf( yeet
, "struct cxr_edge test_edges[] = {\n" );
1801 for( int i
=0; i
<src
->edge_count
; i
++ )
1803 fprintf( yeet
, " {%d, %d},\n",
1808 fprintf( yeet
, "};\n" );
1810 fprintf( yeet
, "struct cxr_input_mesh test_mesh = {\n" );
1811 fprintf( yeet
, " .vertices = test_verts,\n" );
1812 fprintf( yeet
, " .loops = test_loops,\n" );
1813 fprintf( yeet
, " .edges = test_edges,\n" );
1814 fprintf( yeet
, " .polys = test_polys,\n" );
1815 fprintf( yeet
, " .poly_count=%d,\n", src
->poly_count
);
1816 fprintf( yeet
, " .vertex_count=%d,\n", src
->vertex_count
);
1817 fprintf( yeet
, " .edge_count=%d,\n",src
->edge_count
);
1818 fprintf( yeet
, " .loop_count=%d\n", src
->loop_count
);
1819 fprintf( yeet
, "};\n" );
1824 struct cxr_auto_buffer abverts
;
1825 struct cxr_mesh
*main_mesh
= cxr_to_internal_format( src
, &abverts
);
1829 struct cxr_auto_buffer solids
;
1830 cxr_ab_init( &solids
, sizeof(struct cxr_mesh
*), 2 );
1834 struct cxr_mesh
*res
= cxr_pull_best_solid( main_mesh
, &abverts
, 0, &error
);
1837 cxr_ab_push( &solids
, &res
);
1844 // If no solids error we can rety while preserving 'hot' edges
1846 if( error
& CXR_ERROR_NO_SOLIDS
)
1849 res
= cxr_pull_best_solid(main_mesh
, &abverts
, 1, &error
);
1851 if( res
) cxr_ab_push( &solids
, &res
);
1863 cxr_ab_push( &solids
, &main_mesh
);
1867 for( int i
=0; i
<solids
.count
; i
++ )
1869 struct cxr_mesh
**mptr
= cxr_ab_ptr(&solids
,i
);
1870 cxr_debug_mesh( *mptr
, cxr_ab_ptr(&abverts
,0), colours_random
[cxr_range(i
,8)] );
1874 for( int i
=0; i
<solids
.count
; i
++ )
1876 struct cxr_mesh
**mptr
= cxr_ab_ptr(&solids
,i
);
1877 cxr_free_mesh( *mptr
);
1880 cxr_ab_free( &abverts
);
1881 cxr_ab_free( &solids
);
1886 static int cxr_cardinal( v3f a
, int ignore
)
1889 double component_max
= -CXR_BIG_NUMBER
;
1891 for( int i
=0; i
<3; i
++ )
1893 if( i
== ignore
) continue;
1895 if( fabs(a
[i
]) > component_max
)
1897 component_max
= fabs(a
[i
]);
1901 double d
= a
[component
] >= 0.0? 1.0: -1.0;
1908 // Convert contiguous mesh to patch of displacments
1910 static void cxr_write_disp(struct cxr_mesh
*mesh
, struct cxr_input_mesh
*inputmesh
,
1911 struct cxr_vdf
*output
,
1912 struct cxr_auto_buffer
*abverts
)
1914 // Create a graph which maps vertices by their connections
1917 int con_start
, con_count
; // Index into the connection graph
1925 *vertinfo
= malloc( sizeof(struct vertinfo
)*abverts
->count
);
1926 int *graph
= malloc( sizeof(int) * mesh
->edges
.count
*2 );
1929 for( int i
=0; i
<abverts
->count
; i
++ )
1931 struct vertinfo
*info
= &vertinfo
[i
];
1932 info
->con_start
= con_pos
;
1933 info
->con_count
= 0;
1940 for( int j
=0; j
<mesh
->edges
.count
; j
++ )
1942 struct cxr_edge
*edge
= cxr_ab_ptr(&mesh
->edges
,j
);
1944 if( edge
->i0
== i
|| edge
->i1
== i
)
1946 graph
[ con_pos
++ ] = edge
->i0
== i
? edge
->i1
: edge
->i0
;
1949 if( edge
->freestyle
)
1955 // Find best normal for brush patch. VBSP uses the original brush
1956 // as reference for decal projection.
1958 // These are clamped to be cardinal directions as to make the VMF somewhat
1961 v3f avg_normal
, refv
, refu
, refn
;
1962 v3_zero(refv
); v3_zero(refu
); v3_zero(refn
);
1964 for( int i
=0; i
<mesh
->polys
.count
; i
++ )
1966 struct cxr_polygon
*poly
= cxr_ab_ptr( &mesh
->polys
, i
);
1967 v3_add( poly
->normal
, avg_normal
, avg_normal
);
1969 v3_divs( avg_normal
, mesh
->polys
.count
, avg_normal
);
1970 v3_normalize( avg_normal
); // TODO(harry): This can be zero length. Should add a safety check
1971 // normalize function that checks for small length before
1972 // carrying out, otherwise we get inf/nan values...
1974 int n_cardinal
= cxr_cardinal( avg_normal
, -1 );
1976 // Approximately matching the area of the result brush faces to the actual area
1977 // this is to assign a 'best guess' amount of lightmap texels.
1979 double uv_area
= 0.0, face_area
= 0.0, sf
;
1980 v2f uvboundmin
, uvboundmax
;
1981 v3f faceboundmin
, faceboundmax
;
1985 v2_fill( uvboundmin
, CXR_BIG_NUMBER
);
1986 v2_fill( uvboundmax
, -CXR_BIG_NUMBER
);
1987 v3_fill( faceboundmin
, CXR_BIG_NUMBER
);
1988 v3_fill( faceboundmax
, -CXR_BIG_NUMBER
);
1990 for( int i
=0; i
<mesh
->polys
.count
; i
++ )
1992 struct cxr_polygon
*poly
= cxr_ab_ptr( &mesh
->polys
, i
);
1994 for( int j
=0; j
<poly
->loop_total
; j
++ )
1996 struct cxr_loop
*lp0
= cxr_ab_ptr(&mesh
->loops
, poly
->loop_start
+j
);
1997 v2_minv( lp0
->uv
, uvboundmin
, uvboundmin
);
1998 v2_maxv( lp0
->uv
, uvboundmax
, uvboundmax
);
1999 v3_minv( cxr_ab_ptr(abverts
,lp0
->index
), faceboundmin
, faceboundmin
);
2000 v3_maxv( cxr_ab_ptr(abverts
,lp0
->index
), faceboundmax
, faceboundmax
);
2003 for( int j
=0; j
<poly
->loop_total
-2; j
++ )
2005 struct cxr_loop
*lp0
= cxr_ab_ptr(&mesh
->loops
, poly
->loop_start
),
2006 *lp1
= cxr_ab_ptr(&mesh
->loops
, poly
->loop_start
+j
+1),
2007 *lp2
= cxr_ab_ptr(&mesh
->loops
, poly
->loop_start
+j
+2);
2009 v3_sub( cxr_ab_ptr(abverts
,lp1
->index
), cxr_ab_ptr(abverts
,lp0
->index
), va
);
2010 v3_sub( cxr_ab_ptr(abverts
,lp2
->index
), cxr_ab_ptr(abverts
,lp0
->index
), vb
);
2011 v3_cross( va
, vb
, orth
);
2013 face_area
+= v3_length( orth
) / 2.0;
2016 v2_sub( lp1
->uv
, lp0
->uv
, uva
);
2017 v2_sub( lp2
->uv
, lp0
->uv
, uvb
);
2019 uv_area
+= fabs(v2_cross( uva
, uvb
)) / 2.0;
2023 v3_add( faceboundmax
, faceboundmin
, face_center
);
2024 v3_muls( face_center
, 0.5, face_center
);
2025 v2_add( uvboundmin
, uvboundmax
, uv_center
);
2026 v2_muls( uv_center
, 0.5, uv_center
);
2028 sf
= sqrt( face_area
/ uv_area
);
2029 int corner_count
= 0;
2031 // Vertex classification
2032 for( int i
=0; i
<abverts
->count
; i
++ )
2034 struct vertinfo
*info
= &vertinfo
[i
];
2035 if( !info
->boundary
) continue;
2040 for( int j
=0; j
<info
->con_count
; j
++ )
2042 int con
= graph
[info
->con_start
+j
];
2044 if( vertinfo
[con
].boundary
)
2049 if( count
> 2 || non_manifold
)
2054 //cxr_debug_box( cxr_ab_ptr(abverts,i), 0.1, colour_success );
2058 // TODO(harry): This currently only supports power 2 displacements
2059 // its quite straightforward to upgrade it.
2066 for( int i
=0; i
<mesh
->polys
.count
; i
++ )
2068 struct cxr_polygon
*basepoly
= cxr_ab_ptr(&mesh
->polys
,i
);
2070 for( int h
=0; h
<basepoly
->loop_total
; h
++ )
2073 i1
= cxr_range(h
+1,basepoly
->loop_total
);
2075 struct cxr_loop
*l0
= cxr_ab_ptr(&mesh
->loops
, basepoly
->loop_start
+i0
),
2076 *l1
= cxr_ab_ptr(&mesh
->loops
, basepoly
->loop_start
+i1
);
2077 struct vertinfo
*info
= &vertinfo
[ l0
->index
];
2081 int corner_count
= 1;
2083 struct cxr_material
*matptr
=
2084 basepoly
->material_id
< 0 || inputmesh
->material_count
== 0?
2086 &inputmesh
->materials
[ basepoly
->material_id
];
2089 dispedge
[0] = l0
->index
;
2090 dispedge
[1] = l1
->index
;
2091 v2_copy( l0
->uv
, corner_uvs
[0] );
2093 // Consume (remove) faces we use for corners
2094 basepoly
->loop_total
= -1;
2096 //cxr_debug_box( cxr_ab_ptr(abverts,l0->index),0.08,(v4f){0.0,0.0,1.0,1.0});
2099 // --------------------
2101 while( dispedge_count
< 17 )
2103 struct vertinfo
*edge_head
= &vertinfo
[dispedge
[dispedge_count
-1]];
2106 if( edge_head
->corner
)
2108 // Find a polygon that has the edge C-1 -> C
2109 for( int j
=0; j
<mesh
->polys
.count
&& !newvert
; j
++ )
2111 struct cxr_polygon
*poly
= cxr_ab_ptr(&mesh
->polys
,j
);
2113 for( int k
=0; k
<poly
->loop_total
; k
++ )
2116 i1
= cxr_range(k
+1,poly
->loop_total
);
2118 struct cxr_loop
*l0
= cxr_ab_ptr(&mesh
->loops
, poly
->loop_start
+i0
),
2119 *l1
= cxr_ab_ptr(&mesh
->loops
, poly
->loop_start
+i1
);
2121 if( l0
->index
== dispedge
[dispedge_count
-2] &&
2122 l1
->index
== dispedge
[dispedge_count
-1] )
2124 // Take the vertex after that edge
2125 v2_copy( l1
->uv
, corner_uvs
[corner_count
++] );
2127 int i2
= cxr_range(i1
+1,poly
->loop_total
);
2128 struct cxr_loop
*l2
= cxr_ab_ptr(&mesh
->loops
, poly
->loop_start
+i2
);
2130 dispedge
[dispedge_count
++] = l2
->index
;
2132 poly
->loop_total
= -1;
2140 for( int j
=0; j
<edge_head
->con_count
; j
++ )
2142 int con
= graph
[edge_head
->con_start
+j
];
2147 if( dispedge_count
> 1 )
2148 if( con
== dispedge
[dispedge_count
-2] )
2151 struct vertinfo
*coninfo
= &vertinfo
[con
];
2153 if( !coninfo
->boundary
)
2157 cxr_debug_arrow( cxr_ab_ptr(abverts,dispedge[dispedge_count-1]),
2158 cxr_ab_ptr(abverts,con),
2164 dispedge
[ dispedge_count
++ ] = con
;
2173 cxr_debug_box(cxr_ab_ptr(abverts
,dispedge
[dispedge_count
-1]), 0.1, colour_error
);
2178 // --------------------
2182 v2_sub( corner_uvs
[1], corner_uvs
[0], va
);
2183 v2_sub( corner_uvs
[2], corner_uvs
[0], vb
);
2185 // Connect up the grid
2193 // Example: a := common unused vertex that is connected to
2194 // by 1 and 15. Or y-1, and x-1 on the grid.
2195 // g := c and f common vert ^
2199 for( int j
=0; j
<5; j
++ ) grid
[j
] = dispedge
[j
];
2200 for( int j
=1; j
<5; j
++ ) grid
[j
*5+4] = dispedge
[j
+4];
2201 for( int j
=0; j
<4; j
++ ) grid
[4*5+3-j
] = dispedge
[j
+9];
2202 for( int j
=1; j
<4; j
++ ) grid
[j
*5] = dispedge
[16-j
];
2205 for( int j
=1; j
<4; j
++ )
2207 for( int k
=1; k
<4; k
++ )
2209 int s0
= grid
[(j
-1)*5+k
],
2212 struct vertinfo
*va
= &vertinfo
[s0
],
2213 *vb
= &vertinfo
[s1
];
2215 // Find a common vertex between s0 and s1
2217 for( int l
=0; l
<va
->con_count
; l
++ )
2219 for( int m
=0; m
<vb
->con_count
; m
++ )
2221 int cona
= graph
[va
->con_start
+l
],
2222 conb
= graph
[vb
->con_start
+m
];
2226 if( vertinfo
[cona
].used
|| vertinfo
[cona
].boundary
)
2229 grid
[ j
*5+k
] = cona
;
2230 vertinfo
[cona
].used
= 1;
2232 goto IL_MATCHED_DISP_INTERIOR_VERT
;
2237 // Broken displacement
2238 cxr_log( "Broken displacement!\n" );
2243 IL_MATCHED_DISP_INTERIOR_VERT
:;
2247 // Create brush vertices based on UV map
2249 // Create V reference based on first displacement.
2250 // TODO(harry): This is not the moststable selection method!
2251 // faces can come in any order, so the first disp will of course
2252 // always vary. Additionaly the triangle can be oriented differently.
2254 // Improvement can be made by selecting a first disp/triangle based
2255 // on deterministic factors.
2257 if( disp_count
== 0 )
2259 struct cxr_texinfo tx
;
2261 v3_copy( cxr_ab_ptr(abverts
,dispedge
[0]), tri_ref
[0] );
2262 v3_copy( cxr_ab_ptr(abverts
,dispedge
[4]), tri_ref
[1] );
2263 v3_copy( cxr_ab_ptr(abverts
,dispedge
[8]), tri_ref
[2] );
2264 cxr_calculate_axis( &tx
, tri_ref
, corner_uvs
, (v2f
){512,512} );
2266 v3_muls( tx
.vaxis
, -1.0, refv
);
2267 int v_cardinal
= cxr_cardinal( refv
, -1 );
2269 v3_cross( tx
.vaxis
, tx
.uaxis
, refn
);
2270 v3_muls( refn
, -tx
.winding
, refn
);
2272 int n1_cardinal
= cxr_cardinal( refn
, v_cardinal
);
2274 //v3_copy( avg_normal, refn );
2276 if( u_cardinal
== n1_cardinal
|| u_cardinal
== v_cardinal
) u_cardinal
++;
2277 if( u_cardinal
== n1_cardinal
|| u_cardinal
== v_cardinal
) u_cardinal
++;
2280 refu
[u_cardinal
] = tx
.uaxis
[u_cardinal
] > 0.0? 1.0: -1.0;
2284 v3_copy( face_center
, p0
);
2285 v3_muladds( face_center
, refn
, 1.5, pn
);
2286 v3_muladds( face_center
, refv
, 1.5, pv
);
2287 v3_muladds( face_center
, refu
, 1.5, pu
);
2289 if( cxr_settings
.debug
)
2291 cxr_debug_line( p0
, pn
, (v4f
){0.0,0.0,1.0,1.0});
2292 cxr_debug_line( p0
, pv
, (v4f
){0.0,1.0,0.0,1.0});
2293 cxr_debug_line( p0
, pu
, (v4f
){1.0,0.0,0.0,1.0});
2294 cxr_debug_line( tri_ref
[0], tri_ref
[1], (v4f
){1.0,1.0,1.0,1.0} );
2295 cxr_debug_line( tri_ref
[1], tri_ref
[2], (v4f
){1.0,1.0,1.0,1.0} );
2296 cxr_debug_line( tri_ref
[2], tri_ref
[0], (v4f
){1.0,1.0,1.0,1.0} );
2300 // Create world cordinates
2301 v3f world_corners
[8];
2304 for( int j
=0; j
<4; j
++ )
2307 v2_sub( corner_uvs
[j
], uv_center
, local_uv
);
2308 v2_copy( corner_uvs
[j
], world_uv
[j
] );
2309 v2_muls( local_uv
, sf
, local_uv
);
2311 v3_muls( refu
, local_uv
[0], world_corners
[j
] );
2312 v3_muladds( world_corners
[j
], refv
, local_uv
[1], world_corners
[j
] );
2313 v3_add( face_center
, world_corners
[j
], world_corners
[j
] );
2316 double *colour
= colours_random
[cxr_range(disp_count
,8)];
2318 for( int j
=0; j
<4; j
++ )
2319 v3_muladds( world_corners
[j
], refn
, -1.0, world_corners
[j
+4] );
2321 if( cxr_settings
.debug
)
2323 cxr_debug_arrow( world_corners
[0], world_corners
[1], avg_normal
, 0.1, colour
);
2324 cxr_debug_arrow( world_corners
[1], world_corners
[2], avg_normal
, 0.1, colour
);
2325 cxr_debug_arrow( world_corners
[2], world_corners
[3], avg_normal
, 0.1, colour
);
2326 cxr_debug_arrow( world_corners
[3], world_corners
[0], avg_normal
, 0.1, colour
);
2330 cxr_debug_arrow( world_corners[0+4], world_corners[1+4], avg_normal, 0.1, colour );
2331 cxr_debug_arrow( world_corners[1+4], world_corners[2+4], avg_normal, 0.1, colour );
2332 cxr_debug_arrow( world_corners[2+4], world_corners[3+4], avg_normal, 0.1, colour );
2333 cxr_debug_arrow( world_corners[3+4], world_corners[0+4], avg_normal, 0.1, colour );
2336 // Apply world transform
2337 for( int j
=0; j
<8; j
++ )
2339 v3_muls( world_corners
[j
], cxr_context
.scale_factor
, world_corners
[j
] );
2340 world_corners
[j
][2] += cxr_context
.offset_z
;
2343 struct cxr_texinfo texinfo_shared
;
2344 cxr_calculate_axis( &texinfo_shared
, world_corners
, world_uv
,
2345 (v2f
){ matptr
->res
[0], matptr
->res
[1] } );
2348 cxr_vdf_node( output
, "solid" );
2349 cxr_vdf_ki32( output
, "id", ++ cxr_context
.brush_count
);
2360 double distances
[25];
2362 v3f lside0
, lside1
, lref
, vdelta
, vworld
;
2365 for( int j
=0; j
<5; j
++ )
2367 ty
= (double)j
/(double)(5-1);
2369 v3_lerp( world_corners
[0], world_corners
[3], ty
, lside0
);
2370 v3_lerp( world_corners
[1], world_corners
[2], ty
, lside1
);
2372 for( int k
=0; k
<5; k
++ )
2376 tx
= (double)k
/(double)(5-1);
2377 v3_lerp( lside0
, lside1
, tx
, lref
);
2378 v3_muls( cxr_ab_ptr(abverts
, grid
[index
]), cxr_context
.scale_factor
, vworld
);
2379 vworld
[2] += cxr_context
.offset_z
;
2381 v3_sub( vworld
, lref
, vdelta
);
2382 v3_copy( vdelta
, normals
[index
] );
2383 v3_normalize( normals
[index
] );
2384 distances
[index
] = v3_dot( vdelta
, normals
[index
] );
2388 for( int j
=0; j
<6; j
++ )
2390 int *side
= sides
[j
];
2392 cxr_vdf_node( output
, "side" );
2393 cxr_vdf_ki32( output
, "id", ++ cxr_context
.face_count
);
2394 cxr_vdf_plane( output
, "plane", world_corners
[side
[2]],
2395 world_corners
[side
[1]],
2396 world_corners
[side
[0]] );
2398 cxr_vdf_kv( output
, "material", matptr
->vmt_path
);
2400 cxr_vdf_kaxis( output
, "uaxis",
2401 texinfo_shared
.uaxis
,
2402 texinfo_shared
.offset
[0],
2403 texinfo_shared
.scale
[0] );
2404 cxr_vdf_kaxis( output
, "vaxis",
2405 texinfo_shared
.vaxis
,
2406 texinfo_shared
.offset
[1],
2407 texinfo_shared
.scale
[1] );
2409 cxr_vdf_kdouble( output
, "rotation", 0.0 );
2410 cxr_vdf_ki32( output
, "lightmapscale", cxr_settings
.lightmap_scale
);
2411 cxr_vdf_ki32( output
, "smoothing_groups", 0 );
2415 cxr_vdf_node( output
, "dispinfo" );
2416 cxr_vdf_ki32( output
, "power", 2 );
2417 cxr_vdf_kv3f( output
, "startposition", world_corners
[0] );
2418 cxr_vdf_ki32( output
, "flags", 0 );
2419 cxr_vdf_kdouble( output
, "elevation", 0.0 );
2420 cxr_vdf_ki32( output
, "subdiv", 0 );
2422 cxr_vdf_node( output
, "normals" );
2423 for( int k
=0; k
<5; k
++ )
2424 cxr_vdf_karrv3f( output
, "row", k
, &normals
[k
*5], 5 );
2425 cxr_vdf_edon( output
);
2427 cxr_vdf_node( output
, "distances" );
2428 for( int k
=0; k
<5; k
++ )
2429 cxr_vdf_karrdouble( output
, "row", k
, &distances
[k
*5], 5 );
2430 cxr_vdf_edon( output
);
2432 // TODO: This might be needed for compiling...
2434 cxr_vdf_node( output, "offsets" );
2435 for( int k=0; k<5; k++ )
2436 cxr_vdf_printf( output, "\"row%d\" \"0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\"\n", k );
2437 cxr_vdf_edon( output );
2439 cxr_vdf_node( output, "offset_normals" );
2440 for( int k=0; k<5; k++ )
2441 cxr_vdf_printf( output, "\"row%d\" \"0 0 1 0 0 1 0 0 1 0 0 1 0 0 1\"\n", k );
2442 cxr_vdf_edon( output );
2444 cxr_vdf_node( output, "alphas" );
2445 for( int k=0; k<5; k++ )
2446 cxr_vdf_printf( output, "\"row%d\" \"0 0 0 0 0\"\n", k );
2447 cxr_vdf_edon( output );
2449 cxr_vdf_node( output, "triangle_tags" );
2450 for( int k=0; k<5-1; k++ )
2451 cxr_vdf_printf( output, "\"row%d\" \"9 9 9 9 9 9 9 9\"\n", k );
2452 cxr_vdf_edon( output );
2454 cxr_vdf_node( output, "allowed_verts" );
2455 cxr_vdf_printf( output, "\"10\" \"-1 -1 -1 -1 -1 -1 -1 -1 -1 -1\"\n" );
2456 cxr_vdf_edon( output );
2458 cxr_vdf_edon( output
);
2461 cxr_vdf_edon( output
);
2464 cxr_vdf_node(output
, "editor");
2465 cxr_vdf_colour255(output
,"color", colours_random
[cxr_range(cxr_context
.brush_count
,8)]);
2466 cxr_vdf_ki32(output
,"visgroupshown",1);
2467 cxr_vdf_ki32(output
,"visgroupautoshown",1);
2468 cxr_vdf_edon(output
);
2470 cxr_vdf_edon( output
);
2479 for( int i
=0; i
<abverts
->count
; i
++ )
2481 struct vertinfo
*info
= &vertinfo
[i
];
2482 if( info
->boundary
|| info
->used
)
2485 // Gather all vertices in this displacement
2494 int new_front_start
= poolcount
;
2496 for( int j
=0; j
<front_count
; j
++ )
2498 struct vertinfo
*frontvert
= &vertinfo
[pool
[front_start
+j
]];
2500 for( int k
=0; k
<frontvert
->con_count
; k
++ )
2502 int conid
= graph
[frontvert
->con_start
+k
];
2503 struct vertinfo
*con
= &vertinfo
[conid
];
2505 if( frontvert
->boundary
&& !con
->boundary
)
2511 if( poolcount
== 25 )
2512 goto IL_DISP_ERROR_COUNT
;
2515 pool
[ poolcount
++ ] = conid
;
2519 if( poolcount
> new_front_start
)
2521 front_start
= new_front_start
;
2522 front_count
= poolcount
-front_start
;
2524 goto IL_GATHER_LOOP
;
2527 if( poolcount
!= 25 )
2529 IL_DISP_ERROR_COUNT
:
2530 for( int i
=0; i
<poolcount
; i
++ )
2531 cxr_debug_box( cxr_ab_ptr(abverts
,pool
[i
]), 0.02, colour_error
);
2536 cxr_log("Invalid displacement (>25 verts)\n");
2541 int corner_count
= 0;
2542 struct cxr_loop
*cornerloops
[4];
2544 // Find corners, and get their loops (for uvs)
2545 // note: the mesh must be split where there is texture seams
2546 // so that two different uv'd loops cant ref the same vertex
2548 for( int j
=0; j
<poolcount
; j
++ )
2550 if( vertinfo
[pool
[j
]].corner
)
2552 if( corner_count
== 4 )
2558 corners
[corner_count
] = j
;
2560 // find loop that includes this vert
2561 for( int k
=0; k
<mesh
->loops
.count
; k
++ )
2563 struct cxr_loop
*lp
= cxr_ab_ptr(&mesh
->loops
,k
);
2564 if( lp
->index
== pool
[j
] )
2566 cornerloops
[corner_count
] = lp
;
2575 if( corner_count
!=4 )
2579 cxr_log( "Invalid displacement (!=4 corners)\n" );
2583 int pivot
= corners
[0];
2591 static int cxr_solid_checkerr(struct cxr_mesh
*mesh
, struct cxr_auto_buffer
*abverts
)
2595 for( int i
=0; i
<mesh
->polys
.count
; i
++ )
2599 struct cxr_polygon
*poly
= cxr_ab_ptr(&mesh
->polys
,i
);
2602 normal_to_plane( poly
->normal
, poly
->center
, plane
);
2604 for( int j
=0; j
<poly
->loop_total
; j
++ )
2606 struct cxr_loop
*loop
= cxr_ab_ptr(&mesh
->loops
, poly
->loop_start
+j
);
2607 double *vert
= cxr_ab_ptr(abverts
,loop
->index
);
2609 if( fabs(plane_polarity(plane
,vert
)) > 0.0025 )
2615 plane_project_point( plane
, vert
, ref
);
2617 cxr_debug_line( ref
, vert
, colour_error
);
2618 cxr_debug_box( vert
, 0.1, colour_error
);
2623 cxr_debug_poly( mesh
, poly
, cxr_ab_ptr(abverts
,0), colour_error
);
2629 CXR_API i32
cxr_convert_mesh_to_vmf(struct cxr_input_mesh
*src
, struct cxr_vdf
*output
)
2631 // Split mesh into islands
2632 struct cxr_auto_buffer abverts
;
2633 struct cxr_mesh
*main_mesh
= cxr_to_internal_format(src
, &abverts
);
2636 int invalid_count
= 0;
2640 struct cxr_mesh
*pmesh
;
2641 int is_displacement
, invalid
;
2644 struct cxr_auto_buffer solids
;
2645 cxr_ab_init( &solids
, sizeof(struct solidinf
), 2 );
2647 // Preprocessor 1: Island seperation
2652 struct cxr_mesh
*res
= cxr_pull_island( main_mesh
);
2655 cxr_ab_push( &solids
, &(struct solidinf
){ res
, 0 });
2659 cxr_ab_push( &solids
, &(struct solidinf
){main_mesh
,0} );
2661 // Preprocessor 2: Displacement break-out and error checking
2663 for( int i
=0; i
<solids
.count
; i
++ )
2665 struct solidinf
*pinf
= cxr_ab_ptr(&solids
,i
);
2667 for( int j
=0; j
<pinf
->pmesh
->polys
.count
; j
++ )
2669 struct cxr_polygon
*poly
= cxr_ab_ptr( &pinf
->pmesh
->polys
, j
);
2671 for( int k
=0; k
<poly
->loop_total
; k
++ )
2673 struct cxr_loop
*lp
= cxr_ab_ptr( &pinf
->pmesh
->loops
, poly
->loop_start
+k
);
2674 struct cxr_edge
*edge
= cxr_ab_ptr( &pinf
->pmesh
->edges
, lp
->edge_index
);
2676 if( edge
->freestyle
)
2677 goto IL_SOLID_IS_DISPLACEMENT
;
2681 if( cxr_solid_checkerr( pinf
->pmesh
, &abverts
) )
2688 IL_SOLID_IS_DISPLACEMENT
:;
2690 pinf
->is_displacement
= 1;
2691 cxr_write_disp( pinf
->pmesh
, src
, output
, &abverts
);
2694 // Preprocessor 3: Breakup non-convex shapes into sub-solids
2696 int sources_count
= solids
.count
;
2698 for( int i
=0; i
<sources_count
; i
++ )
2700 struct solidinf pinf
= *(struct solidinf
*)cxr_ab_ptr(&solids
, i
);
2702 if( pinf
.is_displacement
|| pinf
.invalid
)
2707 struct cxr_mesh
*res
= cxr_pull_best_solid( pinf
.pmesh
, &abverts
, 0, &error
);
2711 cxr_ab_push( &solids
, &(struct solidinf
){res
,0} );
2719 // If no solids error we can rety while preserving 'hot' edges
2721 if( error
& CXR_ERROR_NO_SOLIDS
)
2724 res
= cxr_pull_best_solid(pinf
.pmesh
, &abverts
, 1, &error
);
2726 if( res
) cxr_ab_push( &solids
, &(struct solidinf
){res
,0} );
2740 if( cxr_settings
.debug
)
2742 for( int i
=0; i
<solids
.count
; i
++ )
2744 struct solidinf
*solid
= cxr_ab_ptr(&solids
,i
);
2746 if( !solid
->is_displacement
)
2747 cxr_debug_mesh( solid
->pmesh
, cxr_ab_ptr(&abverts
,0), colours_random
[cxr_range(i
,8)] );
2753 for( int i
=0; i
<solids
.count
; i
++ )
2755 struct solidinf
*solid
= cxr_ab_ptr(&solids
,i
);
2756 cxr_free_mesh( solid
->pmesh
);
2759 cxr_ab_free( &abverts
);
2760 cxr_ab_free( &solids
);
2764 // Turn all those solids into VMF brushes
2765 // --------------------------------------
2766 for( int i
=0; i
<solids
.count
; i
++ )
2768 struct solidinf
*solid
= cxr_ab_ptr(&solids
,i
);
2770 if( solid
->is_displacement
) continue;
2772 cxr_vdf_node( output
, "solid" );
2773 cxr_vdf_ki32( output
, "id", ++ cxr_context
.brush_count
);
2775 for( int j
=0; j
<solid
->pmesh
->polys
.count
; j
++ )
2777 struct cxr_polygon
*poly
= cxr_ab_ptr( &solid
->pmesh
->polys
, j
);
2778 struct cxr_loop
*ploops
= cxr_ab_ptr(&solid
->pmesh
->loops
, poly
->loop_start
);
2779 struct cxr_material
*matptr
=
2780 poly
->material_id
< 0 || src
->material_count
== 0?
2782 &src
->materials
[ poly
->material_id
];
2784 cxr_vdf_node( output
, "side" );
2785 cxr_vdf_ki32( output
, "id", ++ cxr_context
.face_count
);
2787 v3f verts
[3]; v2f uvs
[3];
2789 v3_muls( cxr_ab_ptr(&abverts
, ploops
[0].index
), cxr_context
.scale_factor
, verts
[0] );
2790 v3_muls( cxr_ab_ptr(&abverts
, ploops
[1].index
), cxr_context
.scale_factor
, verts
[1] );
2791 v3_muls( cxr_ab_ptr(&abverts
, ploops
[2].index
), cxr_context
.scale_factor
, verts
[2] );
2792 verts
[0][2] += cxr_context
.offset_z
;
2793 verts
[1][2] += cxr_context
.offset_z
;
2794 verts
[2][2] += cxr_context
.offset_z
;
2796 v2_copy( ploops
[0].uv
, uvs
[0] );
2797 v2_copy( ploops
[1].uv
, uvs
[1] );
2798 v2_copy( ploops
[2].uv
, uvs
[2] );
2800 cxr_vdf_plane( output
, "plane", verts
[2], verts
[1], verts
[0] );
2801 cxr_vdf_kv( output
, "material", matptr
->vmt_path
);
2803 struct cxr_texinfo trans
;
2804 cxr_calculate_axis(&trans
, verts
, uvs
, (double[2]){ matptr
->res
[0], matptr
->res
[1] });
2806 cxr_vdf_kaxis(output
, "uaxis", trans
.uaxis
, trans
.offset
[0], trans
.scale
[0]);
2807 cxr_vdf_kaxis(output
, "vaxis", trans
.vaxis
, trans
.offset
[1], trans
.scale
[1]);
2809 cxr_vdf_kdouble(output
, "rotation", 0.0 );
2810 cxr_vdf_ki32(output
, "lightmapscale", cxr_settings
.lightmap_scale
);
2811 cxr_vdf_ki32(output
, "smoothing_groups", 0);
2813 cxr_vdf_edon( output
);
2816 cxr_vdf_node(output
, "editor");
2817 cxr_vdf_colour255(output
,"color", colours_random
[cxr_range(cxr_context
.brush_count
,8)]);
2818 cxr_vdf_ki32(output
,"visgroupshown",1);
2819 cxr_vdf_ki32(output
,"visgroupautoshown",1);
2820 cxr_vdf_edon(output
);
2822 cxr_vdf_edon( output
);
2825 for( int i
=0; i
<solids
.count
; i
++ )
2827 struct solidinf
*solid
= cxr_ab_ptr(&solids
,i
);
2828 cxr_free_mesh( solid
->pmesh
);
2831 cxr_ab_free( &abverts
);
2832 cxr_ab_free( &solids
);
2837 CXR_API
void cxr_set_log_function( void (*func
)(const char *str
) )
2839 cxr_log_func
= func
;
2842 CXR_API
void cxr_set_line_function( void (*func
)(v3f p0
, v3f p1
, v4f colour
) )
2844 cxr_line_func
= func
;
2847 CXR_API
void cxr_settings_update( struct cxr_settings
*settings
)
2849 cxr_settings
= *settings
;
2852 // Valve copyright stuff probably maybe
2853 // whatever, my previous copyright decleration ends here
2854 // ----------------------------------------------------------
2856 #define HEADER_LUMPS 64
2857 #define LUMP_WORLDLIGHTS 54
2859 #pragma pack(push,1)
2868 int fileofs
, filelen
;
2873 lumps
[ HEADER_LUMPS
];
2883 float shadow_cast_offset
[3];
2891 float constant_attn
;
2893 float quadratic_attn
;
2900 // Utility for patching BSP tools to remove -1 distance lights (we set them
2901 // like that, because we want these lights to go away)
2903 // Yes, there is no way to do this in hammer
2904 // Yes, the distance KV is unused but still gets compiled to this lump
2905 // No, Entities only compile will not do this for you
2907 CXR_API
int cxr_lightpatch_bsp( const char *path
)
2909 printf( "Lightpatch: %s\n", path
);
2911 FILE *fp
= fopen( path
, "r+b" );
2915 cxr_log( "Could not open BSP file for editing (r+b)\n" );
2920 struct header header
;
2921 fread( &header
, sizeof(struct header
), 1, fp
);
2922 struct lump
*lump
= &header
.lumps
[ LUMP_WORLDLIGHTS
];
2924 // Read worldlight array
2925 struct worldlight
*lights
= malloc( lump
->filelen
);
2926 fseek( fp
, lump
->fileofs
, SEEK_SET
);
2927 fread( lights
, lump
->filelen
, 1, fp
);
2929 // Remove all marked lights
2930 int light_count
= lump
->filelen
/ sizeof(struct worldlight
);
2933 for( int i
= 0; i
< light_count
; i
++ )
2934 if( lights
[i
].radius
>= 0.0f
)
2935 lights
[new_count
++] = lights
[i
];
2937 lump
->filelen
= new_count
*sizeof(struct worldlight
);
2940 fseek( fp
, lump
->fileofs
, SEEK_SET
);
2941 fwrite( lights
, lump
->filelen
, 1, fp
);
2942 fseek( fp
, 0, SEEK_SET
);
2943 fwrite( &header
, sizeof(struct header
), 1, fp
);
2944 cxr_log( "removed %d marked lights\n", light_count
-new_count
);