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
41 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_INTERIOR_ANGLE_MAX 0.998
64 #define CXR_DIRTY_OPTIMISATION 1
65 #define CXR_DEBUG_WRITE_MESH 1
66 #define CXR_DEBUG_ALLOCATORS 1
67 #define CXR_MANIFOLD_DEBUG 0
69 #define CXR_ERROR_DEGEN_IMPLICIT 0x1
70 #define CXR_ERROR_BAD_MANIFOLD 0x2
71 #define CXR_ERROR_NO_SOLIDS 0x4
77 // ============================================
79 static v4f colours_random
[] =
81 { 0.863, 0.078, 0.235, 0.4 },
82 { 0.000, 0.980, 0.604, 0.4 },
83 { 0.118, 0.565, 1.000, 0.4 },
84 { 0.855, 0.439, 0.839, 0.4 },
85 { 0.824, 0.412, 0.118, 0.4 },
86 { 0.125, 0.698, 0.667, 0.4 },
87 { 0.541, 0.169, 0.886, 0.4 },
88 { 1.000, 0.843, 0.000, 0.4 }
91 static int cxr_range(int x
, int bound
)
94 x
+= bound
* (x
/bound
+ 1);
110 struct cxr_input_loop
120 i32 loop_start
, loop_total
;
123 i32 material_id
; // -1: interior material
130 const char *vmt_path
;
157 struct cxr_auto_buffer
169 // simple VDF writing interface
176 static struct cxr_settings
185 .lightmap_scale
= 12,
187 .light_scale
= 1.0/5.0
190 static struct cxr_context
203 .scale_factor
= 32.0,
207 static struct cxr_material cxr_nodraw
= {
209 .vmt_path
= "tools/toolsnodraw"
212 // Debugging callbacks
213 // =============================================================================
215 static v4f colour_error
= { 1.0f
, 0.0f
, 0.0f
, 1.0f
};
216 static v4f colour_face_graph
= { 1.0f
, 1.0f
, 1.0f
, 0.03f
};
217 static v4f colour_success
= { 0.0f
, 1.0f
, 0.0f
, 1.0f
};
219 static void (*cxr_log_func
)(const char *str
);
220 static void (*cxr_line_func
)( v3f p0
, v3f p1
, v4f colour
);
222 static void cxr_log( const char *fmt
, ... )
227 va_start( args
, fmt
);
228 vsnprintf( buf
, sizeof(buf
)-1, fmt
, args
);
237 static void cxr_debug_line( v3f p0
, v3f p1
, v4f colour
)
240 cxr_line_func( p0
, p1
, colour
);
243 static void cxr_debug_box( v3f p0
, double sz
, v4f colour
)
247 v3_add(p0
, (v3f
){-sz
,-sz
,-sz
}, a
);
248 v3_add(p0
, (v3f
){-sz
, sz
,-sz
}, b
);
249 v3_add(p0
, (v3f
){ sz
, sz
,-sz
}, c
);
250 v3_add(p0
, (v3f
){ sz
,-sz
,-sz
}, d
);
251 v3_add(p0
, (v3f
){-sz
,-sz
,sz
}, a1
);
252 v3_add(p0
, (v3f
){-sz
, sz
,sz
}, b1
);
253 v3_add(p0
, (v3f
){ sz
, sz
,sz
}, c1
);
254 v3_add(p0
, (v3f
){ sz
,-sz
,sz
}, d1
);
256 cxr_debug_line( a
,b
, colour
);
257 cxr_debug_line( b
,c
, colour
);
258 cxr_debug_line( c
,d
, colour
);
259 cxr_debug_line( d
,a
, colour
);
260 cxr_debug_line( a1
,b1
, colour
);
261 cxr_debug_line( b1
,c1
, colour
);
262 cxr_debug_line( c1
,d1
, colour
);
263 cxr_debug_line( d1
,a1
, colour
);
264 cxr_debug_line( a
,a1
, colour
);
265 cxr_debug_line( b
,b1
, colour
);
266 cxr_debug_line( c
,c1
, colour
);
267 cxr_debug_line( d
,d1
, colour
);
270 static void cxr_debug_arrow( v3f p0
, v3f p1
, v3f normal
, double sz
, v4f colour
)
272 v3f dir
, tan
, p2
, p3
;
276 v3_cross(dir
,normal
,tan
);
277 v3_muladds( p1
,dir
, -sz
, p2
);
278 v3_muladds( p2
,tan
,sz
,p3
);
279 cxr_debug_line( p1
, p3
, colour
);
280 v3_muladds( p2
,tan
,-sz
,p3
);
281 cxr_debug_line( p1
, p3
, colour
);
282 cxr_debug_line( p0
, p1
, colour
);
286 // =========================================================================
288 CXR_API
void cxr_context_reset(void)
290 cxr_context
.brush_count
= 0;
291 cxr_context
.entity_count
= 0;
292 cxr_context
.face_count
= 0;
293 cxr_context
.offset_z
= 0.0;
294 cxr_context
.scale_factor
= 32.0;
297 CXR_API
void cxr_set_offset(double offset
)
299 cxr_context
.offset_z
= offset
;
302 CXR_API
void cxr_set_scale_factor(double scale
)
304 cxr_context
.scale_factor
= scale
;
307 CXR_API
struct cxr_vdf
*cxr_vdf_open(const char *path
)
309 struct cxr_vdf
*vdf
= malloc(sizeof(struct cxr_vdf
));
312 vdf
->fp
= fopen( path
, "w" );
323 CXR_API
void cxr_vdf_close(struct cxr_vdf
*vdf
)
328 CXR_API
void cxr_vdf_put(struct cxr_vdf
*vdf
, const char *str
)
330 for( int i
=0; i
<vdf
->level
; i
++ )
331 fputs( " ", vdf
->fp
);
333 fputs( str
, vdf
->fp
);
336 static void cxr_vdf_printf( struct cxr_vdf
*vdf
, const char *fmt
, ... )
341 va_start( args
, fmt
);
342 vfprintf( vdf
->fp
, fmt
, args
);
346 CXR_API
void cxr_vdf_node(struct cxr_vdf
*vdf
, const char *str
)
348 cxr_vdf_put( vdf
, str
);
349 putc( (u8
)'\n', vdf
->fp
);
350 cxr_vdf_put( vdf
, "{\n" );
355 CXR_API
void cxr_vdf_edon(struct cxr_vdf
*vdf
)
358 cxr_vdf_put( vdf
, "}\n" );
361 CXR_API
void cxr_vdf_kv(struct cxr_vdf
*vdf
, const char *strk
, const char *strv
)
363 cxr_vdf_printf( vdf
, "\"%s\" \"%s\"\n", strk
, strv
);
366 static void cxr_vdf_ki32(struct cxr_vdf
*vdf
, const char *strk
, i32 val
)
368 cxr_vdf_printf( vdf
, "\"%s\" \"%d\"\n", strk
, val
);
370 static void cxr_vdf_kdouble(struct cxr_vdf
*vdf
, const char *strk
, double val
)
372 cxr_vdf_printf( vdf
, "\"%s\" \"%f\"\n", strk
, val
);
374 static void cxr_vdf_kaxis(struct cxr_vdf
*vdf
, const char *strk
, v3f normal
, double offset
, double scale
)
376 cxr_vdf_printf( vdf
, "\"%s\" \"[%f %f %f %f] %f\"\n", strk
, normal
[0],normal
[1],normal
[2],offset
,scale
);
378 static void cxr_vdf_plane(struct cxr_vdf
*vdf
, const char *strk
, v3f a
, v3f b
, v3f c
)
380 cxr_vdf_printf( vdf
, "\"%s\" \"(%f %f %f) (%f %f %f) (%f %f %f)\"\n",
381 strk
, a
[0], a
[1], a
[2], b
[0], b
[1], b
[2], c
[0], c
[1], c
[2] );
383 static void cxr_vdf_colour255(struct cxr_vdf
*vdf
, const char *strk
, v4f colour
)
386 v4_muls( colour
, 255.0, scale
);
387 cxr_vdf_printf( vdf
, "\"%s\" \"%d %d %d %d\"\n",strk
,(int)scale
[0], (int)scale
[1], (int)scale
[2], (int)scale
[3]);
391 // =========================================================================
393 static void cxr_debug_poly(struct cxr_mesh
*mesh
, struct cxr_polygon
*poly
, v3f
*verts
, v4f colour
)
395 for( int i
=0; i
<poly
->loop_total
; i
++ )
397 struct cxr_loop
*loop0
= cxr_ab_ptr(&mesh
->loops
,poly
->loop_start
+i
),
398 *loop1
= cxr_ab_ptr(&mesh
->loops
,poly
->loop_start
+cxr_range(i
+1,poly
->loop_total
));
402 v3_lerp( verts
[loop0
->index
], poly
->center
, 0.02, p0
);
403 v3_lerp( verts
[loop1
->index
], poly
->center
, 0.02, p1
);
405 cxr_debug_arrow( p0
, p1
, poly
->normal
, 0.05, colour
);
409 v3_muladds( poly
->center
, poly
->normal
, 0.3, nrm0
);
411 cxr_debug_line( poly
->center
, nrm0
, colour
);
414 static void cxr_debug_mesh(struct cxr_mesh
*mesh
, v3f
*verts
, v4f colour
)
416 for( int i
=0; i
<mesh
->polys
.count
; i
++ )
418 struct cxr_polygon
*poly
= cxr_ab_ptr(&mesh
->polys
,i
);
419 cxr_debug_poly( mesh
, poly
, verts
, colour
);
423 static struct cxr_mesh
*cxr_alloc_mesh(int edge_count
, int loop_count
, int poly_count
)
425 struct cxr_mesh
*mesh
= malloc(sizeof(struct cxr_mesh
));
426 cxr_ab_init(&mesh
->edges
, sizeof(struct cxr_edge
), edge_count
);
427 cxr_ab_init(&mesh
->loops
, sizeof(struct cxr_loop
), loop_count
);
428 cxr_ab_init(&mesh
->polys
, sizeof(struct cxr_polygon
), poly_count
);
432 static void cxr_free_mesh(struct cxr_mesh
*mesh
)
434 cxr_ab_free(&mesh
->edges
);
435 cxr_ab_free(&mesh
->loops
);
436 cxr_ab_free(&mesh
->polys
);
440 // Rebuilds edge data and reallocates
442 static void cxr_mesh_clean_edges(struct cxr_mesh
*mesh
)
444 struct cxr_auto_buffer new_edges
;
445 cxr_ab_init( &new_edges
, sizeof(struct cxr_edge
), mesh
->edges
.count
);
447 for( int i
=0; i
<mesh
->polys
.count
; i
++ )
449 struct cxr_polygon
*poly
= cxr_ab_ptr(&mesh
->polys
,i
);
450 for( int j
=0; j
<poly
->loop_total
; j
++ )
453 *lp0
= cxr_ab_ptr(&mesh
->loops
,poly
->loop_start
+j
),
454 *lp1
= cxr_ab_ptr(&mesh
->loops
,poly
->loop_start
+cxr_range(j
+1,poly
->loop_total
));
456 int i0
= cxr_min(lp0
->index
, lp1
->index
),
457 i1
= cxr_max(lp0
->index
, lp1
->index
);
459 // See if edge exists before adding it
460 for( int k
=0; k
<new_edges
.count
; k
++ )
462 struct cxr_edge
*edge
= cxr_ab_ptr(&new_edges
,k
);
464 if( edge
->i0
== i0
&& edge
->i1
== i1
)
467 goto IL_EDGE_CREATED
;
471 int orig_edge_id
= lp0
->edge_index
;
472 lp0
->edge_index
= new_edges
.count
;
474 struct cxr_edge edge
= { i0
, i1
};
476 // Copy extra information (sharp,freestyle.. etc) here!
478 if( orig_edge_id
< mesh
->edges
.count
)
480 struct cxr_edge
*orig_edge
= cxr_ab_ptr( &mesh
->edges
, orig_edge_id
);
481 edge
.freestyle
= orig_edge
->freestyle
;
489 cxr_ab_push( &new_edges
, &edge
);
495 cxr_ab_free( &mesh
->edges
);
496 mesh
->edges
= new_edges
;
499 // Remove 0-length faces from mesh and correct loops
501 static void cxr_mesh_clean_faces(struct cxr_mesh
*mesh
)
503 struct cxr_auto_buffer loops_new
;
504 cxr_ab_init( &loops_new
, sizeof(struct cxr_loop
), mesh
->loops
.count
);
507 for( int i
=0; i
<mesh
->polys
.count
; i
++ )
509 struct cxr_polygon
*src
= cxr_ab_ptr(&mesh
->polys
,i
),
510 *dst
= cxr_ab_ptr(&mesh
->polys
,new_length
);
512 if( src
->loop_total
> 0 )
514 int src_start
= src
->loop_start
,
515 src_total
= src
->loop_total
;
518 dst
->loop_start
= loops_new
.count
;
520 for( int j
=0; j
<src_total
; j
++ )
522 struct cxr_loop
*loop
= cxr_ab_ptr(&mesh
->loops
,src_start
+j
),
523 *ldst
= cxr_ab_ptr(&loops_new
,dst
->loop_start
+j
);
525 ldst
->poly_left
= new_length
;
528 loops_new
.count
+= src_total
;
533 cxr_ab_free( &mesh
->loops
);
534 mesh
->loops
= loops_new
;
535 mesh
->polys
.count
= new_length
;
538 static i32
*cxr_mesh_link_loops(struct cxr_mesh
*mesh
)
540 i32
*polygon_edge_map
= malloc(mesh
->edges
.count
*2 *sizeof(i32
));
542 for( int i
= 0; i
< mesh
->edges
.count
*2; i
++ )
543 polygon_edge_map
[i
] = -1;
545 for( int i
= 0; i
< mesh
->polys
.count
; i
++ )
547 struct cxr_polygon
*poly
= cxr_ab_ptr(&mesh
->polys
, i
);
549 for( int j
= 0; j
< poly
->loop_total
; j
++ )
551 struct cxr_loop
*loop
= cxr_ab_ptr(&mesh
->loops
, poly
->loop_start
+j
);
554 for( int k
= 0; k
< 2; k
++ )
556 i32
*edge
= &polygon_edge_map
[loop
->edge_index
*2+k
];
566 for( int i
= 0; i
< mesh
->polys
.count
; i
++ )
568 struct cxr_polygon
*poly
= cxr_ab_ptr(&mesh
->polys
,i
);
570 for( int j
= 0; j
< poly
->loop_total
; j
++ )
572 struct cxr_loop
*loop
= cxr_ab_ptr(&mesh
->loops
,poly
->loop_start
+j
);
574 i32
*face_map
= &polygon_edge_map
[loop
->edge_index
*2];
576 if( face_map
[0] == loop
->poly_left
) loop
->poly_right
= face_map
[1];
577 else loop
->poly_right
= face_map
[0];
581 return polygon_edge_map
;
584 // Add polygon to mesh based on loop array
585 static struct cxr_polygon
*cxr_create_poly( struct cxr_mesh
*mesh
, v3f
*vertices
, struct cxr_loop poly
[],
586 int len
, int start
, int max
)
590 cxr_log( "tried to add new poly with length %d!\n", len
);
594 for( int j
=0; j
<len
; j
++ )
596 int i0
= poly
[j
].index
,
597 i1
= poly
[cxr_range(j
+1,len
)].index
;
598 cxr_debug_line( vertices
[i0
], vertices
[i1
], colour_error
);
605 int nface_id
= mesh
->polys
.count
;
606 struct cxr_polygon
*new_face
= cxr_ab_empty(&mesh
->polys
);
608 new_face
->loop_start
= mesh
->loops
.count
;
609 new_face
->loop_total
= len
;
610 new_face
->material_id
= -1;
612 // Calculate normal and center
613 v3_zero( new_face
->center
);
615 for( int j
=0; j
<len
; j
++ )
617 int i0
= poly
[cxr_range(start
+j
,max
)].index
;
618 struct cxr_loop
*new_loop
= cxr_ab_empty(&mesh
->loops
);
620 new_loop
->poly_left
= nface_id
;
621 new_loop
->poly_right
= -1;
622 new_loop
->index
= i0
;
623 new_loop
->edge_index
= 0;
624 v2_zero(new_loop
->uv
);
626 v3_add( new_face
->center
, vertices
[new_loop
->index
], new_face
->center
);
628 v3_divs( new_face
->center
, new_face
->loop_total
, new_face
->center
);
630 struct cxr_loop
*lp0
= cxr_ab_ptr( &mesh
->loops
, new_face
->loop_start
),
631 *lp1
= cxr_ab_ptr( &mesh
->loops
, new_face
->loop_start
+1 ),
632 *lp2
= cxr_ab_ptr( &mesh
->loops
, new_face
->loop_start
+2 );
634 tri_normal( vertices
[lp0
->index
], vertices
[lp1
->index
], vertices
[lp2
->index
], new_face
->normal
);
636 return cxr_ab_ptr(&mesh
->polys
, nface_id
);
639 // Get the 'next' mesh island
641 // Returns NULL if there is only one island
642 static struct cxr_mesh
*cxr_pull_island(struct cxr_mesh
*mesh
)
644 free(cxr_mesh_link_loops(mesh
));
646 int *island_current
= malloc(mesh
->polys
.count
*sizeof(int)),
651 island_current
[0] = 0;
654 last_count
= island_len
;
656 for( int i
=0; i
<island_len
; i
++ )
658 struct cxr_polygon
*poly
= cxr_ab_ptr(&mesh
->polys
,island_current
[i
]);
660 for( int j
=0; j
<poly
->loop_total
; j
++ )
662 struct cxr_loop
*loop
= cxr_ab_ptr(&mesh
->loops
, poly
->loop_start
+j
);
664 if( loop
->poly_right
!= -1 )
666 int face_present
= 0;
668 for( int k
=0; k
<island_len
; k
++ )
670 if( island_current
[k
] == loop
->poly_right
)
679 island_current
[ island_len
++ ] = loop
->poly_right
;
685 if( island_len
> last_count
)
686 goto IL_ISLAND_REPEAT
;
688 if( island_len
== mesh
->polys
.count
)
690 free( island_current
);
694 for( int i
=0; i
<island_len
; i
++ )
696 struct cxr_polygon
*poly
= cxr_ab_ptr(&mesh
->polys
, island_current
[i
]);
697 loop_count
+= poly
->loop_total
;
700 struct cxr_mesh
*newmesh
= cxr_alloc_mesh( mesh
->edges
.count
, loop_count
, island_len
);
702 for( int i
=0; i
<island_len
; i
++ )
704 struct cxr_polygon
*src
= cxr_ab_ptr(&mesh
->polys
, island_current
[i
]);
705 struct cxr_polygon
*dst
= cxr_ab_ptr(&newmesh
->polys
, i
);
708 dst
->loop_start
= newmesh
->loops
.count
;
710 for( int j
=0; j
<src
->loop_total
; j
++ )
712 struct cxr_loop
*lsrc
= cxr_ab_ptr(&mesh
->loops
, src
->loop_start
+j
),
713 *ldst
= cxr_ab_ptr(&newmesh
->loops
, dst
->loop_start
+j
);
717 ldst
->poly_right
= -1;
720 newmesh
->loops
.count
+= src
->loop_total
;
721 src
->loop_total
= -1;
724 newmesh
->polys
.count
= island_len
;
725 newmesh
->edges
.count
= mesh
->edges
.count
;
726 memcpy(cxr_ab_ptr(&newmesh
->edges
,0), cxr_ab_ptr(&mesh
->edges
,0), mesh
->edges
.count
*sizeof(struct cxr_edge
));
728 cxr_mesh_clean_faces(mesh
);
729 cxr_mesh_clean_edges(mesh
);
730 cxr_mesh_clean_edges(newmesh
);
731 free( island_current
);
736 // Return best availible solid from mesh, and patch existing mesh to fill the gap
739 // Returns NULL if shape is already convex or empty
740 // Destroys edge data!
741 static struct cxr_mesh
*cxr_pull_best_solid(
742 struct cxr_mesh
*mesh
,
743 struct cxr_auto_buffer
*vert_buffer
,
744 int preserve_hot_edges
,
747 v3f
*vertices
= cxr_ab_ptr( vert_buffer
, 0 );
749 i32
*polygon_edge_map
= cxr_mesh_link_loops(mesh
);
751 for( int i
=0; i
<mesh
->edges
.count
*2; i
++ )
752 if( polygon_edge_map
[i
] == -1 )
754 cxr_log( "non-manifold edges are in the mesh; implicit internal geometry does not have full support\n" );
755 free(polygon_edge_map
);
759 int *vertex_tagged
= malloc( vert_buffer
->count
*sizeof(int) );
760 int *edge_tagged
= malloc( mesh
->edges
.count
*sizeof(int) );
762 for( int i
=0; i
<mesh
->edges
.count
; i
++ )
764 struct cxr_polygon
*polya
= cxr_ab_ptr(&mesh
->polys
, polygon_edge_map
[i
*2+0]),
765 *polyb
= cxr_ab_ptr(&mesh
->polys
, polygon_edge_map
[i
*2+1]);
767 normal_to_plane(polyb
->normal
, polyb
->center
, planeb
);
770 for( int j
=0; j
<polya
->loop_total
; j
++ )
772 struct cxr_loop
*loop
= cxr_ab_ptr(&mesh
->loops
, polya
->loop_start
+j
);
773 if( plane_polarity( planeb
, vertices
[loop
->index
] ) > 0.001 ||
774 v3_dot(polya
->normal
,polyb
->normal
) > 0.98500 )
782 // Tag 'reflex' vertices
783 int *connected_planes
= malloc(mesh
->polys
.count
*sizeof(int));
785 for( int i
=0; i
<vert_buffer
->count
; i
++ )
789 int num_connected
= 0;
790 // Create a list of polys that ref this vert
791 for( int j
=0; j
<mesh
->polys
.count
; j
++ )
793 struct cxr_polygon
*poly
= cxr_ab_ptr(&mesh
->polys
,j
);
794 for( int k
=0; k
<poly
->loop_total
; k
++ )
796 struct cxr_loop
*loop
= cxr_ab_ptr(&mesh
->loops
,poly
->loop_start
+k
);
797 if( loop
->index
== i
)
799 connected_planes
[num_connected
++] = j
;
804 // Check all combinations for a similar normal
805 for( int j
=0; j
<num_connected
-1; j
++ )
807 for( int k
=j
+1; k
<num_connected
; k
++ )
809 struct cxr_polygon
*polyj
= cxr_ab_ptr(&mesh
->polys
,connected_planes
[j
]);
810 struct cxr_polygon
*polyk
= cxr_ab_ptr(&mesh
->polys
,connected_planes
[k
]);
812 if( v3_dot(polyj
->normal
, polyk
->normal
) > 0.98500 )
817 // Check if all connected planes not are:
818 // - bounded by other planes
821 for( int j
=0; j
<num_connected
; j
++ )
822 for( int k
=j
+1; k
<num_connected
; k
++ )
824 struct cxr_polygon
*jpoly
= cxr_ab_ptr(&mesh
->polys
, connected_planes
[j
]),
825 *kpoly
= cxr_ab_ptr(&mesh
->polys
, connected_planes
[k
]);
827 normal_to_plane( kpoly
->normal
, kpoly
->center
, plane
);
828 for( int l
=0; l
<jpoly
->loop_total
; l
++ )
830 struct cxr_loop
*loop
= cxr_ab_ptr(&mesh
->loops
, jpoly
->loop_start
+l
);
831 if( plane_polarity( plane
, vertices
[loop
->index
] ) > 0.001 )
836 goto IL_TAG_NEXT_VERT
;
837 IL_TAG_VERT
: vertex_tagged
[i
] = 1;
841 free( connected_planes
);
843 // Connect all marked verts that share an edge
844 // - We must take care not to completely isolate
845 // a polygon with marked edges all around it
847 int *hot_edge
= malloc(mesh
->edges
.count
*sizeof(int));
848 for( int i
=0; i
< mesh
->edges
.count
; i
++ )
851 for( int i
=0; i
<mesh
->polys
.count
; i
++ )
853 struct cxr_polygon
*poly
= cxr_ab_ptr(&mesh
->polys
,i
);
857 for( int j
=0; j
<poly
->loop_total
; j
++ )
859 struct cxr_loop
*loop
= cxr_ab_ptr(&mesh
->loops
, poly
->loop_start
+j
);
861 if( !edge_tagged
[ loop
->edge_index
] )
863 if( not_tagged
== -1 )
864 not_tagged
= loop
->edge_index
;
866 goto IL_SKIP_NO_HOT_EDGE
;
870 if( not_tagged
!= -1 )
871 hot_edge
[not_tagged
]=1;
873 IL_SKIP_NO_HOT_EDGE
:;
876 // Connect edges that have verts tagged, but is not a hot edge
877 for( int i
=0; i
<mesh
->edges
.count
; i
++ )
879 if( hot_edge
[i
] && preserve_hot_edges
) continue;
881 struct cxr_edge
*edge
= cxr_ab_ptr(&mesh
->edges
,i
);
882 if( vertex_tagged
[edge
->i0
] && vertex_tagged
[edge
->i1
] )
887 for( int i=0; i<vertex_count; i++ )
888 if( vertex_tagged[i] )
889 cxr_debug_box( vertices[i], 0.03, (v4f){0.0,0.0,0.0,1.0});
891 for( int i=0; i < mesh->edges.count; i++ )
893 struct cxr_edge *edge = cxr_ab_ptr( &mesh->edges, i );
895 cxr_debug_line( vertices[ edge->i0 ], vertices[ edge->i1 ], (v4f){0.0,0.0,0.0,1.0});
898 cxr_debug_line( vertices[ edge->i0 ], vertices[ edge->i1 ], (v4f){0.0,1.0,1.0,1.0});
903 int *faces_tagged
= malloc(mesh
->polys
.count
*sizeof(int));
904 for( int i
=0; i
<mesh
->polys
.count
; i
++ )
905 faces_tagged
[i
] = -1;
907 int *solid_buffer
= malloc( mesh
->polys
.count
*sizeof(int) );
908 int solid_buffer_len
= 0;
911 int start
,count
,edge_count
;
914 *candidates
= malloc( mesh
->polys
.count
*sizeof(struct csolid
) );
915 int candidate_count
= 0;
917 for( int i
=0; i
<mesh
->polys
.count
; i
++ )
919 if( faces_tagged
[i
] != -1 ) continue;
922 int *solid
= &solid_buffer
[ solid_buffer_len
];
925 solid
[solid_len
++] = i
;
927 int search_start
= 0;
929 // Iterative search that connects regions of planes governed by rules:
930 // - edge can add other face if the edge has less than two reflexes
931 // - the face can no longer be used in future searches
936 for( int j
=search_start
; j
<solid_len
; j
++ )
938 struct cxr_polygon
*poly
= cxr_ab_ptr(&mesh
->polys
, solid
[j
]);
940 for( int k
=0; k
<poly
->loop_total
; k
++ )
942 struct cxr_loop
*loop
= cxr_ab_ptr(&mesh
->loops
, poly
->loop_start
+k
);
943 struct cxr_edge
*edge
= cxr_ab_ptr(&mesh
->edges
, loop
->edge_index
);
945 if( faces_tagged
[ loop
->poly_right
] == -1 )
947 if( !edge_tagged
[loop
->edge_index
] )
949 // Need to look ahead 1 step to make sure he does not want
950 // to add any more planes that are coplanar with some of
951 // our existing group
953 // TODO: is this unused due to hotedge improvements? leaving for safety...
955 struct cxr_polygon
*poly_to_add
= cxr_ab_ptr(&mesh
->polys
, loop
->poly_right
);
956 for( int l
=0; l
< poly_to_add
->loop_total
; l
++ )
958 struct cxr_loop
*loop1
= cxr_ab_ptr(&mesh
->loops
, poly_to_add
->loop_start
+l
);
959 struct cxr_polygon
*future_face
= cxr_ab_ptr(&mesh
->polys
, loop1
->poly_right
);
961 if( edge_tagged
[ loop1
->edge_index
] || loop1
->poly_right
== loop
->poly_right
)
962 goto IL_SKIP_SIMILAR_PLANES
;
964 for( int m
=0; m
<solid_len
; m
++ )
965 if( solid
[m
] == loop1
->poly_right
)
966 goto IL_SKIP_SIMILAR_PLANES
;
968 for( int m
=0; m
<solid_len
; m
++ )
970 struct cxr_polygon
*polym
= cxr_ab_ptr(&mesh
->polys
,solid
[m
]);
971 if( v3_dot( polym
->normal
, future_face
->normal
) > 0.98500 )
972 goto IL_SKIP_PLANE_ADD
;
975 IL_SKIP_SIMILAR_PLANES
:;
978 // This plane passed all checks so we can add it to the current solid
980 solid
[ solid_len
++ ] = loop
->poly_right
;
981 faces_tagged
[ loop
->poly_right
] = i
;
989 search_start
= solid_len
;
991 goto IL_SEARCH_CONTINUE
;
994 struct csolid
*csolid
= &candidates
[candidate_count
++];
995 csolid
->start
= solid_buffer_len
;
996 csolid
->count
= solid_len
;
997 csolid
->edge_count
= 0;
999 v3_zero( csolid
->center
);
1000 for( int j
=0; j
<solid_len
; j
++ )
1002 struct cxr_polygon
*polyj
= cxr_ab_ptr(&mesh
->polys
, solid
[j
]);
1003 v3_add( polyj
->center
, csolid
->center
, csolid
->center
);
1004 csolid
->edge_count
+= polyj
->loop_total
;
1006 v3_divs( csolid
->center
, solid_len
, csolid
->center
);
1008 solid_buffer_len
+= solid_len
;
1011 // Create all candidates who have one or less non-manifolds edges
1012 // Loop each candidate, determine the manifold, and pick the best one
1014 struct csolid
*best_solid
= NULL
;
1015 int fewest_manifold_splits
= INT32_MAX
;
1017 struct cxr_loop
*best_manifold
= malloc( mesh
->loops
.count
*sizeof(struct cxr_loop
) );
1018 int *best_manifold_splits
= malloc( mesh
->loops
.count
*sizeof(int) );
1019 int best_manifold_len
= 0;
1020 int max_solid_faces
= 0;
1022 int *edge_list
= malloc( mesh
->edges
.count
*sizeof(int) );
1023 int *edge_lefts
= malloc( mesh
->edges
.count
*sizeof(int) );
1024 struct cxr_loop
*manifold
= malloc(mesh
->edges
.count
*2*sizeof(struct cxr_loop
));
1025 int *splits
= malloc(mesh
->edges
.count
*2*sizeof(int));
1027 for( int i
=0; i
<candidate_count
; i
++ )
1029 struct csolid
*solid
= &candidates
[i
];
1030 max_solid_faces
= cxr_max(max_solid_faces
,solid
->count
);
1032 if( solid
->count
<= 2 )
1035 int init_reverse
= 0;
1036 int unique_edge_count
= 0;
1038 for( int j
=0; j
<solid
->count
; j
++ )
1040 struct cxr_polygon
*poly
= cxr_ab_ptr(&mesh
->polys
, solid_buffer
[solid
->start
+j
]);
1042 for( int k
=0; k
<poly
->loop_total
; k
++ )
1044 struct cxr_loop
*loop
= cxr_ab_ptr(&mesh
->loops
, poly
->loop_start
+k
);
1046 for( int l
=0; l
<unique_edge_count
; l
++ )
1047 if( edge_list
[l
] == loop
->edge_index
)
1048 goto IL_EDGE_ALREADY_PRESENT
;
1050 // Check if right edge references a polygon that is not
1051 // present inside the current solid candidate
1052 for( int l
=0; l
<solid
->count
; l
++ )
1053 if( loop
->poly_right
== solid_buffer
[solid
->start
+l
] )
1054 goto IL_EDGE_ALREADY_PRESENT
;
1056 edge_list
[ unique_edge_count
] = loop
->edge_index
;
1057 edge_lefts
[ unique_edge_count
] = loop
->poly_left
;
1059 if( unique_edge_count
== 0 )
1061 struct cxr_edge
*edgeptr
= cxr_ab_ptr(&mesh
->edges
, loop
->edge_index
);
1062 if( edgeptr
->i1
== loop
->index
)
1066 unique_edge_count
++;
1067 IL_EDGE_ALREADY_PRESENT
:;
1071 // This solid is already fully connected
1072 if( unique_edge_count
== 0 )
1075 // Link edges together to create new manifold
1076 // Corners are created when two edges share a polygon face
1077 // This way we can split it into regions
1079 for( int j
=0; j
<vert_buffer
->count
; j
++ )
1080 vertex_tagged
[j
] = -1;
1082 // Start with a loop edge which was tagged
1083 struct cxr_edge
*current
= cxr_ab_ptr(&mesh
->edges
, edge_list
[0]);
1085 int endpt
= (!init_reverse
)? current
->i0
: current
->i1
,
1087 curface
= edge_lefts
[0];
1089 int manifold_len
= 0;
1090 int split_count
= 0;
1092 IL_MANIFOLD_CONTINUE
:
1093 for( int j
=0; j
<unique_edge_count
; j
++ )
1095 struct cxr_edge
*other
= cxr_ab_ptr(&mesh
->edges
, edge_list
[j
]);
1096 if( other
== current
)
1099 if( other
->i0
== endpt
|| other
->i1
== endpt
)
1104 if( other
->i0
== endpt
) endpt
= current
->i1
;
1105 else endpt
= current
->i0
;
1107 if( curface
==edge_lefts
[j
] )
1109 splits
[ manifold_len
] = 1;
1113 splits
[ manifold_len
] = 0;
1115 // Append to intermidiary manifold
1116 manifold
[ manifold_len
].edge_index
= edge_list
[j
];
1117 manifold
[ manifold_len
].poly_left
= edge_lefts
[j
];
1118 manifold
[ manifold_len
].index
= lastpt
;
1119 manifold
[ manifold_len
].poly_right
=
1120 polygon_edge_map
[ edge_list
[j
]*2 ] == edge_lefts
[j
]?
1121 polygon_edge_map
[ edge_list
[j
]*2+1 ]:
1122 polygon_edge_map
[ edge_list
[j
]*2+0 ];
1125 curface
= edge_lefts
[j
];
1127 if(endpt
== start
) goto IL_MANIFOLD_COMPLETE
;
1128 goto IL_MANIFOLD_CONTINUE
;
1131 cxr_log( "Failed to link manifold, count: %d\n", manifold_len
);
1133 for( int j
=0; j
<solid
->count
; j
++ )
1135 cxr_log( "p%d\n", solid_buffer
[solid
->start
+j
] );
1136 struct cxr_polygon
*poly
= cxr_ab_ptr(&mesh
->polys
, solid_buffer
[solid
->start
+j
]);
1137 cxr_debug_poly( mesh
, poly
, vertices
, (v4f
){0.2,0.0,0.0,1.0} );
1140 for( int j
=0; j
<unique_edge_count
; j
++ )
1142 struct cxr_edge
*uedge
= cxr_ab_ptr(&mesh
->edges
, edge_list
[j
]);
1143 cxr_debug_line(vertices
[uedge
->i0
],vertices
[uedge
->i1
],(v4f
){0.4,0.0,0.0,1.0});
1146 for( int j
=0; j
<manifold_len
-1; j
++ )
1148 struct cxr_loop
*lp0
= &manifold
[j
],
1149 *lp1
= &manifold
[cxr_range(j
+1,manifold_len
)];
1151 cxr_debug_line(vertices
[lp0
->index
],vertices
[lp1
->index
], colour_error
);
1154 cxr_debug_mesh( mesh
, vertices
, (v4f
){0.0,0.0,0.0, 0.9} );
1155 *error
= CXR_ERROR_BAD_MANIFOLD
;
1162 free(vertex_tagged
);
1167 free(best_manifold
);
1168 free(best_manifold_splits
);
1169 free(polygon_edge_map
);
1172 IL_MANIFOLD_COMPLETE
:;
1174 if( manifold_len
< unique_edge_count
)
1178 if( split_count
< fewest_manifold_splits
)
1180 fewest_manifold_splits
= split_count
;
1183 for( int j
=0; j
<manifold_len
; j
++ )
1185 best_manifold
[j
] = manifold
[j
];
1186 best_manifold_splits
[j
] = splits
[j
];
1188 best_manifold_len
= manifold_len
;
1198 if( max_solid_faces
< 2 )
1200 *error
= CXR_ERROR_NO_SOLIDS
;
1202 free(vertex_tagged
);
1207 free(best_manifold
);
1208 free(best_manifold_splits
);
1209 free(polygon_edge_map
);
1213 if( best_solid
!= NULL
)
1215 struct cxr_mesh
*pullmesh
=
1216 cxr_alloc_mesh( best_solid
->edge_count
, best_solid
->edge_count
, best_solid
->count
);
1218 // Add existing faces to pullsolid, and delete from main mesh
1219 for( int i
=0; i
<best_solid
->count
; i
++ )
1221 int nface_id
= pullmesh
->polys
.count
;
1223 struct cxr_polygon
*exist_face
= cxr_ab_ptr(&mesh
->polys
, solid_buffer
[best_solid
->start
+i
]);
1224 struct cxr_polygon
*new_face
= cxr_ab_empty(&pullmesh
->polys
);
1226 *new_face
= *exist_face
;
1227 new_face
->loop_start
= pullmesh
->loops
.count
;
1229 for( int j
=0; j
<exist_face
->loop_total
; j
++ )
1231 struct cxr_loop
*exist_loop
= cxr_ab_ptr(&mesh
->loops
, exist_face
->loop_start
+j
);
1232 struct cxr_loop
*new_loop
= cxr_ab_empty(&pullmesh
->loops
);
1234 new_loop
->index
= exist_loop
->index
;
1235 new_loop
->poly_left
= nface_id
;
1236 new_loop
->poly_right
= -1;
1237 new_loop
->edge_index
= 0;
1238 v2_copy( exist_loop
->uv
, new_loop
->uv
);
1241 exist_face
->loop_total
= -1;
1244 // Split manifold up by unique planes if it has more than 1
1245 // otherwise, just use that face
1247 // TODO: Need to build new manifold in sections, stably
1248 // currently there is an unsupported case where the manifold splits
1249 // are on located on an implicit face, causing 1-length manifolds.
1252 int pullmesh_new_start
= pullmesh
->polys
.count
;
1254 if( fewest_manifold_splits
!= 0 )
1256 #if CXR_MANIFOLD_DEBUG
1257 for( int i
=0; i
<best_manifold_len
; i
++ )
1260 i1
= cxr_range(i
+1,best_manifold_len
);
1262 cxr_debug_line( vertices
[best_manifold
[i0
].index
], vertices
[best_manifold
[i1
].index
], colour_error
);
1263 if( best_manifold_splits
[i
] )
1264 cxr_debug_box( vertices
[best_manifold
[i0
].index
], 0.04, colour_success
);
1268 // This is a really strange observation, however it *seems* to apply to the kinds
1269 // of geometry we are dealing with. If the split count is odd, the manifold can be
1270 // created easily, no folding required.
1272 // When it is even, it appears that internal implicit geometry is required, so we
1273 // need to fold the loops we create. Its really weird, but for some reason works on
1274 // the geometry rules we've defined.
1275 // TODO: Find a well defined rule here.
1277 int collapse_used_segments
= (u32
)fewest_manifold_splits
& 0x1? 0: 1;
1279 IL_MANIFOLD_BUILD_REPEAT
:
1281 for( int j
=0; j
<best_manifold_len
; j
++ )
1283 if( best_manifold_splits
[j
] )
1285 struct cxr_loop
*loop
= &best_manifold
[j
];
1287 for( int k
=1; k
<best_manifold_len
; k
++ )
1289 int index1
= cxr_range(j
+k
,best_manifold_len
);
1290 struct cxr_loop
*loop1
= &best_manifold
[index1
];
1292 if( best_manifold_splits
[index1
] )
1299 if( new_polys
> best_manifold_len
)
1301 cxr_log( "Programming error: Too many new polys!\n" );
1305 cxr_create_poly( pullmesh
, vertices
, best_manifold
, k
+1, j
, best_manifold_len
);
1307 // Remove new section from manifold
1308 if( collapse_used_segments
)
1310 best_manifold_splits
[j
] = 0;
1311 best_manifold_splits
[index1
] = 0;
1313 int new_length
= (best_manifold_len
-(k
-1));
1315 struct cxr_loop
*new_manifold
= malloc( new_length
*sizeof(struct cxr_loop
) );
1316 int *new_manifold_splits
= malloc( new_length
*sizeof(int) );
1318 for( int l
=0; l
<new_length
; l
++ )
1320 int i_src
= cxr_range( j
+k
+l
, best_manifold_len
);
1321 new_manifold
[l
] = best_manifold
[i_src
];
1322 new_manifold_splits
[l
] = best_manifold_splits
[i_src
];
1325 free( best_manifold
);
1326 free( best_manifold_splits
);
1327 best_manifold
= new_manifold
;
1328 best_manifold_splits
= new_manifold_splits
;
1330 best_manifold_len
= new_length
;
1332 goto IL_MANIFOLD_BUILD_REPEAT
;
1342 if( best_manifold_len
&& collapse_used_segments
)
1344 cxr_create_poly( pullmesh
, vertices
, best_manifold
, best_manifold_len
, 0, best_manifold_len
);
1350 cxr_create_poly( pullmesh
, vertices
, best_manifold
, best_manifold_len
, 0, best_manifold_len
);
1354 // vert_buffer may be reallocated by the next section of code,
1355 // force a NULLref on vertices to catch any errors
1358 // Implicit geometry reconstruction
1359 // If there's 3 or more planes, collide them together to see if any new
1360 // vertices need to be created on the mesh
1361 if( new_polys
>= 3 )
1363 for( int i
=0; i
<new_polys
-2; i
++ )
1365 for( int j
=i
+1; j
<new_polys
-1; j
++ )
1367 for( int k
=j
+1; k
<new_polys
; k
++ )
1369 struct cxr_polygon
*ptri
= cxr_ab_ptr( &pullmesh
->polys
, pullmesh_new_start
+i
),
1370 *ptrj
= cxr_ab_ptr( &pullmesh
->polys
, pullmesh_new_start
+j
),
1371 *ptrk
= cxr_ab_ptr( &pullmesh
->polys
, pullmesh_new_start
+k
);
1373 v4f planei
, planej
, planek
;
1374 normal_to_plane(ptri
->normal
,ptri
->center
,planei
);
1375 normal_to_plane(ptrj
->normal
,ptrj
->center
,planej
);
1376 normal_to_plane(ptrk
->normal
,ptrk
->center
,planek
);
1380 if( plane_intersect(planei
,planej
,planek
,intersect
) )
1382 // cxr_debug_box( intersect, 0.05, colour_error );
1384 // Make sure this point is within the convex region, otherwise treat
1385 // it as a degenerate case
1387 int point_valid
= 1;
1388 for( int l
=0; l
<pullmesh
->polys
.count
; l
++ )
1390 struct cxr_polygon
*ptrl
= cxr_ab_ptr(&pullmesh
->polys
,l
);
1393 normal_to_plane(ptrl
->normal
, ptrl
->center
, planel
);
1395 if( plane_polarity( planel
, intersect
) > 0.01 )
1397 cxr_log( "degen vert, planes %d, %d, %d [max:%d]\n", i
,j
,k
, new_polys
);
1398 *error
= CXR_ERROR_DEGEN_IMPLICIT
;
1400 cxr_debug_poly( pullmesh
, ptri
, cxr_ab_ptr(vert_buffer
,0), colours_random
[3] );
1401 cxr_debug_poly( pullmesh
, ptrj
, cxr_ab_ptr(vert_buffer
,0), colours_random
[1] );
1402 cxr_debug_poly( pullmesh
, ptrk
, cxr_ab_ptr(vert_buffer
,0), colours_random
[2] );
1409 if( !point_valid
) continue;
1411 // Extend faces to include this point
1412 int nvertid
= vert_buffer
->count
;
1413 cxr_ab_push( vert_buffer
, intersect
);
1415 ptrj
->loop_start
+= 1;
1416 ptrk
->loop_start
+= 2;
1418 cxr_ab_reserve(&pullmesh
->loops
, 3);
1419 struct cxr_loop
*lloopi
= cxr_ab_empty_at(&pullmesh
->loops
, ptri
->loop_start
+ptri
->loop_total
),
1420 *lloopj
= cxr_ab_empty_at(&pullmesh
->loops
, ptrj
->loop_start
+ptrj
->loop_total
),
1421 *lloopk
= cxr_ab_empty_at(&pullmesh
->loops
, ptrk
->loop_start
+ptrk
->loop_total
);
1423 lloopi
->index
= nvertid
;
1424 lloopj
->index
= nvertid
;
1425 lloopk
->index
= nvertid
;
1426 lloopi
->edge_index
= 0; lloopj
->edge_index
= 0; lloopk
->edge_index
= 0;
1427 lloopi
->poly_left
= pullmesh_new_start
+i
;
1428 lloopj
->poly_left
= pullmesh_new_start
+j
;
1429 lloopk
->poly_left
= pullmesh_new_start
+k
;
1430 lloopi
->poly_right
= -1; lloopj
->poly_right
= -1; lloopk
->poly_right
= -1;
1432 v2_zero(lloopi
->uv
);
1433 v2_zero(lloopj
->uv
);
1434 v2_zero(lloopk
->uv
);
1436 ptri
->loop_total
++;
1437 ptrj
->loop_total
++;
1438 ptrk
->loop_total
++;
1440 // Adjust centers of faces
1441 v3_lerp( ptri
->center
, intersect
, 1.0/(double)ptri
->loop_total
, ptri
->center
);
1442 v3_lerp( ptrj
->center
, intersect
, 1.0/(double)ptrj
->loop_total
, ptrj
->center
);
1443 v3_lerp( ptrk
->center
, intersect
, 1.0/(double)ptrk
->loop_total
, ptrk
->center
);
1450 // Copy faces from pullsolid into orig mesh
1452 for( int i
=0; i
<new_polys
; i
++ )
1454 int rface_id
= mesh
->polys
.count
;
1456 struct cxr_polygon
*pface
= cxr_ab_ptr(&pullmesh
->polys
,pullmesh_new_start
+i
);
1457 struct cxr_polygon
*rip_face
= cxr_ab_empty(&mesh
->polys
);
1459 rip_face
->loop_start
= mesh
->loops
.count
;
1460 rip_face
->loop_total
= pface
->loop_total
;
1461 rip_face
->material_id
= -1;
1463 for( int j
=0; j
<rip_face
->loop_total
; j
++ )
1465 struct cxr_loop
*ploop
= cxr_ab_ptr(&pullmesh
->loops
, pface
->loop_start
+pface
->loop_total
-j
-1),
1466 *rloop
= cxr_ab_empty(&mesh
->loops
);
1468 rloop
->index
= ploop
->index
;
1469 rloop
->poly_left
= rface_id
;
1470 rloop
->poly_right
= -1;
1471 rloop
->edge_index
= 0;
1472 v2_copy( ploop
->uv
, rloop
->uv
);
1475 v3_copy( pface
->center
, rip_face
->center
);
1476 v3_negate( pface
->normal
, rip_face
->normal
);
1479 cxr_mesh_clean_faces( mesh
);
1480 cxr_mesh_clean_faces( pullmesh
);
1481 cxr_mesh_clean_edges( mesh
);
1482 cxr_mesh_clean_edges( pullmesh
);
1485 free(vertex_tagged
);
1490 free(best_manifold
);
1491 free(best_manifold_splits
);
1492 free(polygon_edge_map
);
1498 free(vertex_tagged
);
1503 free(best_manifold
);
1504 free(best_manifold_splits
);
1505 free(polygon_edge_map
);
1510 static struct cxr_mesh
*cxr_to_internal_format(struct cxr_input_mesh
*src
, struct cxr_auto_buffer
*abverts
)
1512 // Split mesh into islands
1513 struct cxr_mesh
*mesh
= cxr_alloc_mesh( src
->edge_count
, src
->loop_count
, src
->poly_count
);
1514 cxr_ab_init( abverts
, sizeof(v3f
), src
->vertex_count
);
1516 // Copy input data into working mesh
1517 memcpy( cxr_ab_ptr( &mesh
->edges
, 0 ), src
->edges
, src
->edge_count
*sizeof(struct cxr_edge
));
1518 memcpy( cxr_ab_ptr( &mesh
->polys
, 0 ), src
->polys
, src
->poly_count
*sizeof(struct cxr_polygon
));
1519 memcpy( cxr_ab_ptr( abverts
, 0 ), src
->vertices
, src
->vertex_count
*sizeof(v3f
));
1520 mesh
->edges
.count
= src
->edge_count
;
1521 mesh
->loops
.count
= src
->loop_count
;
1522 mesh
->polys
.count
= src
->poly_count
;
1524 for( int i
=0; i
<src
->loop_count
; i
++ )
1526 struct cxr_loop
*lp
= cxr_ab_ptr(&mesh
->loops
,i
);
1527 lp
->index
= src
->loops
[i
].index
;
1528 lp
->edge_index
= src
->loops
[i
].edge_index
;
1529 v2_copy( src
->loops
[i
].uv
, lp
->uv
);
1532 abverts
->count
= src
->vertex_count
;
1537 // Find farthest dot product along direction
1538 static double support_distance( v3f verts
[3], v3f dir
, double coef
)
1542 coef
* v3_dot( verts
[0], dir
),
1545 coef
* v3_dot( verts
[1], dir
),
1546 coef
* v3_dot( verts
[2], dir
)
1552 static void cxr_calculate_axis(
1553 struct cxr_texinfo
*transform
,
1559 v2f tT
, bT
; // Tangent/bitangent pairs for UV space and world
1562 v2_sub( uvs
[0], uvs
[1], tT
);
1563 v2_sub( uvs
[2], uvs
[1], bT
);
1564 v3_sub( verts
[0], verts
[1], tW
);
1565 v3_sub( verts
[2], verts
[1], bW
);
1567 // Use arbitrary projection if there is no UV
1568 if( v2_length( tT
) < 0.0001 || v2_length( bT
) < 0.0001 )
1570 v3f uaxis
, normal
, vaxis
;
1572 v3_copy( tW
, uaxis
);
1573 v3_normalize( uaxis
);
1575 v3_cross( tW
, bW
, normal
);
1576 v3_cross( normal
, uaxis
, vaxis
);
1577 v3_normalize( vaxis
);
1579 v3_copy( uaxis
, transform
->uaxis
);
1580 v3_copy( vaxis
, transform
->vaxis
);
1581 v2_zero( transform
->offset
);
1583 v2_div( (v2f
){128.0, 128.0}, texture_res
, transform
->scale
);
1587 // Detect if UV is reversed
1588 double winding
= v2_cross( tT
, bT
) >= 0.0f
? 1.0f
: -1.0f
;
1590 // UV projection reference
1592 v2_muls((v2f
){1,0}, winding
, vX
);
1593 v2_muls((v2f
){0,1}, winding
, vY
);
1595 // Reproject reference into world space, including skew
1598 v3_muls( tW
, v2_cross(vX
,bT
) / v2_cross(bT
,tT
), uaxis1
);
1599 v3_muladds( uaxis1
, bW
, v2_cross(vX
, tT
) / v2_cross(tT
,bT
), uaxis1
);
1601 v3_muls( tW
, v2_cross(vY
,bT
) / v2_cross(bT
,tT
), vaxis1
);
1602 v3_muladds( vaxis1
, bW
, v2_cross(vY
,tT
) / v2_cross(tT
,bT
), vaxis1
);
1604 v3_normalize( uaxis1
);
1605 v3_normalize( vaxis1
);
1607 // Apply source transform to axis (yes, they also need to be swapped)
1608 v3f norm
, uaxis
, vaxis
;
1610 v3_cross( bW
, tW
, norm
);
1612 v3_cross( vaxis1
, norm
, uaxis
);
1613 v3_cross( uaxis1
, norm
, vaxis
);
1616 v2f uvmin
, uvmax
, uvdelta
;
1617 v2_minv( uvs
[0], uvs
[1], uvmin
);
1618 v2_minv( uvmin
, uvs
[2], uvmin
);
1619 v2_maxv( uvs
[0], uvs
[1], uvmax
);
1620 v2_maxv( uvmax
, uvs
[2], uvmax
);
1622 v2_sub( uvmax
, uvmin
, uvdelta
);
1625 v2f uvminw
, uvmaxw
, uvdeltaw
;
1626 uvminw
[0] = -support_distance( verts
, uaxis
, -1.0f
);
1627 uvmaxw
[0] = support_distance( verts
, uaxis
, 1.0f
);
1628 uvminw
[1] = -support_distance( verts
, vaxis
, -1.0f
);
1629 uvmaxw
[1] = support_distance( verts
, vaxis
, 1.0f
);
1631 v2_sub( uvmaxw
, uvminw
, uvdeltaw
);
1635 v2_div( uvdeltaw
, uvdelta
, uv_scale
);
1636 v2_div( uv_scale
, texture_res
, uv_scale
);
1638 // Find offset via 'natural' point
1639 v2f target_uv
, natural_uv
, tex_offset
;
1640 v2_mul( uvs
[0], texture_res
, target_uv
);
1642 natural_uv
[0] = v3_dot( uaxis
, verts
[0] );
1643 natural_uv
[1] = -v3_dot( vaxis
, verts
[0] );
1644 v2_div( natural_uv
, uv_scale
, natural_uv
);
1646 tex_offset
[0] = target_uv
[0]-natural_uv
[0];
1647 tex_offset
[1] = -(target_uv
[1]-natural_uv
[1]);
1649 // Copy everything into output
1650 v3_copy( uaxis
, transform
->uaxis
);
1651 v3_copy( vaxis
, transform
->vaxis
);
1652 v2_copy( tex_offset
, transform
->offset
);
1653 v2_copy( uv_scale
, transform
->scale
);
1656 CXR_API
struct cxr_input_mesh
*cxr_decompose(struct cxr_input_mesh
*src
)
1658 #ifdef CXR_DEBUG_WRITE_MESH
1659 FILE *yeet
= fopen( "/home/harry/Documents/blender_addons_remote/addons/convexer/solid.h", "w" );
1661 fprintf( yeet
, "v3f test_verts[] = {\n" );
1662 for( int i
=0; i
<src
->vertex_count
; i
++ )
1664 fprintf( yeet
, " { %f, %f, %f },\n",
1665 src
->vertices
[i
][0],
1666 src
->vertices
[i
][1],
1667 src
->vertices
[i
][2] );
1669 fprintf( yeet
, "};\n" );
1671 fprintf( yeet
, "struct cxr_input_loop test_loops[] = {\n" );
1672 for( int i
=0; i
<src
->loop_count
; i
++ )
1674 fprintf( yeet
, " {%d, %d},\n",
1675 src
->loops
[i
].index
,
1676 src
->loops
[i
].edge_index
);
1678 fprintf( yeet
, "};\n" );
1680 fprintf( yeet
, "struct cxr_polygon test_polys[] = {\n" );
1681 for( int i
=0; i
<src
->poly_count
; i
++ )
1683 fprintf( yeet
, " {%d, %d, {%f, %f, %f}, {%f, %f, %f}},\n",
1684 src
->polys
[i
].loop_start
,
1685 src
->polys
[i
].loop_total
,
1686 src
->polys
[i
].normal
[0],
1687 src
->polys
[i
].normal
[1],
1688 src
->polys
[i
].normal
[2],
1689 src
->polys
[i
].center
[0],
1690 src
->polys
[i
].center
[1],
1691 src
->polys
[i
].center
[2] );
1693 fprintf( yeet
, "};\n" );
1695 fprintf( yeet
, "struct cxr_edge test_edges[] = {\n" );
1696 for( int i
=0; i
<src
->edge_count
; i
++ )
1698 fprintf( yeet
, " {%d, %d},\n",
1703 fprintf( yeet
, "};\n" );
1705 fprintf( yeet
, "struct cxr_input_mesh test_mesh = {\n" );
1706 fprintf( yeet
, " .vertices = test_verts,\n" );
1707 fprintf( yeet
, " .loops = test_loops,\n" );
1708 fprintf( yeet
, " .edges = test_edges,\n" );
1709 fprintf( yeet
, " .polys = test_polys,\n" );
1710 fprintf( yeet
, " .poly_count=%d,\n", src
->poly_count
);
1711 fprintf( yeet
, " .vertex_count=%d,\n", src
->vertex_count
);
1712 fprintf( yeet
, " .edge_count=%d,\n",src
->edge_count
);
1713 fprintf( yeet
, " .loop_count=%d\n", src
->loop_count
);
1714 fprintf( yeet
, "};\n" );
1719 struct cxr_auto_buffer abverts
;
1720 struct cxr_mesh
*main_mesh
= cxr_to_internal_format( src
, &abverts
);
1724 struct cxr_auto_buffer solids
;
1725 cxr_ab_init( &solids
, sizeof(struct cxr_mesh
*), 2 );
1727 // TODO: Preprocessor stages
1728 // - Split mesh up into islands before doing anything here
1729 // - Snap vertices to grid (0.25u) ?
1732 struct cxr_mesh
*res
= cxr_pull_best_solid( main_mesh
, &abverts
, 0, &error
);
1735 cxr_ab_push( &solids
, &res
);
1742 // If no solids error we can rety while preserving 'hot' edges
1744 if( error
& CXR_ERROR_NO_SOLIDS
)
1747 res
= cxr_pull_best_solid(main_mesh
, &abverts
, 1, &error
);
1749 if( res
) cxr_ab_push( &solids
, &res
);
1761 cxr_ab_push( &solids
, &main_mesh
);
1765 for( int i
=0; i
<solids
.count
; i
++ )
1767 struct cxr_mesh
**mptr
= cxr_ab_ptr(&solids
,i
);
1768 cxr_debug_mesh( *mptr
, cxr_ab_ptr(&abverts
,0), colours_random
[cxr_range(i
,8)] );
1772 for( int i
=0; i
<solids
.count
; i
++ )
1774 struct cxr_mesh
**mptr
= cxr_ab_ptr(&solids
,i
);
1775 cxr_free_mesh( *mptr
);
1778 cxr_ab_free( &abverts
);
1779 cxr_ab_free( &solids
);
1784 // Convert contiguous mesh to patch of displacments
1786 static void cxr_write_disp(struct cxr_mesh
*mesh
, struct cxr_vdf
*output
,
1787 struct cxr_auto_buffer
*abverts
)
1789 // Create a graph which maps vertices by their connections
1792 int con_start
, con_count
; // Index into the connection graph
1800 *vertinfo
= malloc( sizeof(struct vertinfo
)*abverts
->count
);
1801 int *graph
= malloc( sizeof(int) * mesh
->edges
.count
*2 );
1804 for( int i
=0; i
<abverts
->count
; i
++ )
1806 struct vertinfo
*info
= &vertinfo
[i
];
1807 info
->con_start
= con_pos
;
1808 info
->con_count
= 0;
1815 for( int j
=0; j
<mesh
->edges
.count
; j
++ )
1817 struct cxr_edge
*edge
= cxr_ab_ptr(&mesh
->edges
,j
);
1819 if( edge
->i0
== i
|| edge
->i1
== i
)
1821 graph
[ con_pos
++ ] = edge
->i0
== i
? edge
->i1
: edge
->i0
;
1824 if( edge
->freestyle
)
1830 // Find best normal for brush patch. VBSP uses the original brush
1831 // as reference for decal projection.
1833 // These are clamped to be cardinal directions as to make the VMF somewhat
1838 for( int i
=0; i
<mesh
->polys
.count
; i
++ )
1840 struct cxr_polygon
*poly
= cxr_ab_ptr( &mesh
->polys
, i
);
1841 v3_add( poly
->normal
, avg_normal
, avg_normal
);
1843 v3_divs( avg_normal
, mesh
->polys
.count
, avg_normal
);
1844 v3_normalize( avg_normal
); // TODO: This can be zero length. Should add a safety check
1845 // normalize function that checks for small length before
1846 // carrying out, otherwise we get inf/nan values...
1848 double component_max
= fabs( avg_normal
[2] );
1851 for( int i
=0; i
<2; i
++ )
1853 if( fabs(avg_normal
[i
]) > component_max
)
1855 component_max
= fabs(avg_normal
[i
]);
1859 double d
= avg_normal
[component
] >= 0.0? 1.0: -1.0;
1860 v3_zero( avg_normal
);
1861 avg_normal
[component
] = d
;
1863 // Approximately matching the area of the result brush faces to the actual area
1864 // this is to assign a 'best guess' amount of lightmap texels.
1866 double uv_area
= 0.0, face_area
= 0.0, sf
;
1868 for( int i
=0; i
<mesh
->polys
.count
; i
++ )
1870 struct cxr_polygon
*poly
= cxr_ab_ptr( &mesh
->polys
, i
);
1872 for( int j
=0; j
<poly
->loop_total
-2; j
++ )
1874 struct cxr_loop
*lp0
= cxr_ab_ptr(&mesh
->loops
, poly
->loop_start
),
1875 *lp1
= cxr_ab_ptr(&mesh
->loops
, poly
->loop_start
+j
+1),
1876 *lp2
= cxr_ab_ptr(&mesh
->loops
, poly
->loop_start
+j
+2);
1878 v3_sub( cxr_ab_ptr(abverts
,lp1
->index
), cxr_ab_ptr(abverts
,lp0
->index
), va
);
1879 v3_sub( cxr_ab_ptr(abverts
,lp2
->index
), cxr_ab_ptr(abverts
,lp0
->index
), vb
);
1880 v3_cross( va
, vb
, orth
);
1882 face_area
+= v3_length( orth
) / 2.0;
1885 v2_sub( lp1
->uv
, lp0
->uv
, uva
);
1886 v2_sub( lp2
->uv
, lp0
->uv
, uvb
);
1888 uv_area
+= fabs(v2_cross( uva
, uvb
)) / 2.0;
1892 sf
= sqrt( face_area
/ uv_area
);
1893 int corner_count
= 0;
1895 // Vertex classification
1896 for( int i
=0; i
<abverts
->count
; i
++ )
1898 struct vertinfo
*info
= &vertinfo
[i
];
1899 if( !info
->boundary
) continue;
1904 for( int j
=0; j
<info
->con_count
; j
++ )
1906 int con
= graph
[info
->con_start
+j
];
1908 if( vertinfo
[con
].boundary
)
1913 if( count
> 2 || non_manifold
)
1918 //cxr_debug_box( cxr_ab_ptr(abverts,i), 0.1, colour_success );
1927 for( int i
=0; i
<mesh
->polys
.count
; i
++ )
1929 struct cxr_polygon
*basepoly
= cxr_ab_ptr(&mesh
->polys
,i
);
1931 for( int h
=0; h
<basepoly
->loop_total
; h
++ )
1934 i1
= cxr_range(h
+1,basepoly
->loop_total
);
1936 struct cxr_loop
*l0
= cxr_ab_ptr(&mesh
->loops
, basepoly
->loop_start
+i0
),
1937 *l1
= cxr_ab_ptr(&mesh
->loops
, basepoly
->loop_start
+i1
);
1938 struct vertinfo
*info
= &vertinfo
[ l0
->index
];
1942 int corner_count
= 1;
1945 dispedge
[0] = l0
->index
;
1946 dispedge
[1] = l1
->index
;
1947 v2_copy( l0
->uv
, corner_uvs
[0] );
1949 // Consume (remove) faces we use for corners
1950 basepoly
->loop_total
= -1;
1952 cxr_debug_box( cxr_ab_ptr(abverts
,l0
->index
),0.08,(v4f
){0.0,0.0,1.0,1.0});
1956 // --------------------
1958 while( dispedge_count
< 17 )
1960 struct vertinfo
*edge_head
= &vertinfo
[dispedge
[dispedge_count
-1]];
1963 if( edge_head
->corner
)
1965 // Find a polygon that has the edge C-1 -> C
1966 for( int j
=0; j
<mesh
->polys
.count
&& !newvert
; j
++ )
1968 struct cxr_polygon
*poly
= cxr_ab_ptr(&mesh
->polys
,j
);
1970 for( int k
=0; k
<poly
->loop_total
; k
++ )
1973 i1
= cxr_range(k
+1,poly
->loop_total
);
1975 struct cxr_loop
*l0
= cxr_ab_ptr(&mesh
->loops
, poly
->loop_start
+i0
),
1976 *l1
= cxr_ab_ptr(&mesh
->loops
, poly
->loop_start
+i1
);
1978 if( l0
->index
== dispedge
[dispedge_count
-2] &&
1979 l1
->index
== dispedge
[dispedge_count
-1] )
1981 // Take the vertex after that edge
1982 v2_copy( l1
->uv
, corner_uvs
[corner_count
++] );
1984 int i2
= cxr_range(i1
+1,poly
->loop_total
);
1985 struct cxr_loop
*l2
= cxr_ab_ptr(&mesh
->loops
, poly
->loop_start
+i2
);
1987 dispedge
[dispedge_count
++] = l2
->index
;
1989 poly
->loop_total
= -1;
1997 for( int j
=0; j
<edge_head
->con_count
; j
++ )
1999 int con
= graph
[edge_head
->con_start
+j
];
2004 if( dispedge_count
> 1 )
2005 if( con
== dispedge
[dispedge_count
-2] )
2008 struct vertinfo
*coninfo
= &vertinfo
[con
];
2010 if( !coninfo
->boundary
)
2013 cxr_debug_arrow( cxr_ab_ptr(abverts
,dispedge
[dispedge_count
-1]),
2014 cxr_ab_ptr(abverts
,con
),
2019 dispedge
[ dispedge_count
++ ] = con
;
2028 cxr_debug_box(cxr_ab_ptr(abverts
,dispedge
[dispedge_count
-1]), 0.1, colour_error
);
2033 // --------------------
2037 v2_sub( corner_uvs
[1], corner_uvs
[0], va
);
2038 v2_sub( corner_uvs
[2], corner_uvs
[0], vb
);
2040 if( v2_cross( va
,vb
) < 0.0 )
2041 cxr_log( "Uv is flipped!\n" );
2043 cxr_log( "Uv is normal\n" );
2045 // Connect up the grid
2053 // Example: a := common unused vertex that is connected to
2054 // by 1 and 15. Or y-1, and x-1 on the grid.
2055 // g := c and f common vert ^
2059 for( int j
=0; j
<25; j
++ ) grid
[j
] = 0;
2060 for( int j
=0; j
<5; j
++ )
2062 grid
[j
] = dispedge
[j
];
2063 vertinfo
[dispedge
[j
]].used
= 1;
2065 for( int j
=1; j
<5; j
++ )
2067 grid
[j
*5] = dispedge
[16-j
];
2068 vertinfo
[dispedge
[16-j
]].used
= 1;
2071 for( int j
=1; j
<5; j
++ )
2073 for( int k
=1; k
<5; k
++ )
2075 int s0
= grid
[(j
-1)*5+k
],
2078 struct vertinfo
*va
= &vertinfo
[s0
],
2079 *vb
= &vertinfo
[s1
];
2081 // Find a common vertex between s0 and s1
2083 for( int l
=0; l
<va
->con_count
; l
++ )
2085 for( int m
=0; m
<vb
->con_count
; m
++ )
2087 int cona
= graph
[va
->con_start
+l
],
2088 conb
= graph
[vb
->con_start
+m
];
2090 if( vertinfo
[cona
].used
|| vertinfo
[conb
].used
)
2095 grid
[ j
*5+k
] = cona
;
2096 vertinfo
[cona
].used
= 1;
2098 goto IL_MATCHED_DISP_INTERIOR_VERT
;
2103 // Broken displacement
2104 cxr_log( "Broken displacement!\n" );
2109 IL_MATCHED_DISP_INTERIOR_VERT
:;
2114 for( int j
=0; j
<25; j
++ )
2115 vertinfo
[grid
[j
]].used
= 0;
2120 cxr_log( "Disp count: %d\n", disp_count
);
2125 for( int i
=0; i
<abverts
->count
; i
++ )
2127 struct vertinfo
*info
= &vertinfo
[i
];
2128 if( info
->boundary
|| info
->used
)
2131 // Gather all vertices in this displacement
2140 int new_front_start
= poolcount
;
2142 for( int j
=0; j
<front_count
; j
++ )
2144 struct vertinfo
*frontvert
= &vertinfo
[pool
[front_start
+j
]];
2146 for( int k
=0; k
<frontvert
->con_count
; k
++ )
2148 int conid
= graph
[frontvert
->con_start
+k
];
2149 struct vertinfo
*con
= &vertinfo
[conid
];
2151 if( frontvert
->boundary
&& !con
->boundary
)
2157 if( poolcount
== 25 )
2158 goto IL_DISP_ERROR_COUNT
;
2161 pool
[ poolcount
++ ] = conid
;
2165 if( poolcount
> new_front_start
)
2167 front_start
= new_front_start
;
2168 front_count
= poolcount
-front_start
;
2170 goto IL_GATHER_LOOP
;
2173 if( poolcount
!= 25 )
2175 IL_DISP_ERROR_COUNT
:
2176 for( int i
=0; i
<poolcount
; i
++ )
2177 cxr_debug_box( cxr_ab_ptr(abverts
,pool
[i
]), 0.02, colour_error
);
2182 cxr_log("Invalid displacement (>25 verts)\n");
2187 int corner_count
= 0;
2188 struct cxr_loop
*cornerloops
[4];
2190 // Find corners, and get their loops (for uvs)
2191 // note: the mesh must be split where there is texture seams
2192 // so that two different uv'd loops cant ref the same vertex
2194 for( int j
=0; j
<poolcount
; j
++ )
2196 if( vertinfo
[pool
[j
]].corner
)
2198 if( corner_count
== 4 )
2204 corners
[corner_count
] = j
;
2206 // find loop that includes this vert
2207 for( int k
=0; k
<mesh
->loops
.count
; k
++ )
2209 struct cxr_loop
*lp
= cxr_ab_ptr(&mesh
->loops
,k
);
2210 if( lp
->index
== pool
[j
] )
2212 cornerloops
[corner_count
] = lp
;
2221 if( corner_count
!=4 )
2225 cxr_log( "Invalid displacement (!=4 corners)\n" );
2229 int pivot
= corners
[0];
2237 CXR_API i32
cxr_convert_mesh_to_vmf(struct cxr_input_mesh
*src
, struct cxr_vdf
*output
)
2239 // Split mesh into islands
2240 struct cxr_auto_buffer abverts
;
2241 struct cxr_mesh
*main_mesh
= cxr_to_internal_format(src
, &abverts
);
2247 struct cxr_mesh
*pmesh
;
2248 int is_displacement
;
2251 struct cxr_auto_buffer solids
;
2252 cxr_ab_init( &solids
, sizeof(struct solidinf
), 2 );
2254 // TODO: Preprocessor stages
2255 // - Split mesh up into islands before doing anything here (DONE)
2256 // - Snap vertices to grid (0.25u) ?
2258 // Preprocessor 1: Island seperation
2263 struct cxr_mesh
*res
= cxr_pull_island( main_mesh
);
2266 cxr_ab_push( &solids
, &(struct solidinf
){ res
, 0 });
2270 cxr_ab_push( &solids
, &(struct solidinf
){main_mesh
,0} );
2272 // Preprocessor 2: Displacement break-out
2274 for( int i
=0; i
<solids
.count
; i
++ )
2276 struct solidinf
*pinf
= cxr_ab_ptr(&solids
,i
);
2278 for( int j
=0; j
<pinf
->pmesh
->polys
.count
; j
++ )
2280 struct cxr_polygon
*poly
= cxr_ab_ptr( &pinf
->pmesh
->polys
, j
);
2282 for( int k
=0; k
<poly
->loop_total
; k
++ )
2284 struct cxr_loop
*lp
= cxr_ab_ptr( &pinf
->pmesh
->loops
, poly
->loop_start
+k
);
2285 struct cxr_edge
*edge
= cxr_ab_ptr( &pinf
->pmesh
->edges
, lp
->edge_index
);
2287 if( edge
->freestyle
)
2288 goto IL_SOLID_IS_DISPLACEMENT
;
2293 IL_SOLID_IS_DISPLACEMENT
:;
2295 pinf
->is_displacement
= 1;
2296 cxr_write_disp( pinf
->pmesh
, output
, &abverts
);
2299 // Preprocessor 3: Breakup non-convex shapes into sub-solids
2301 int sources_count
= solids
.count
;
2303 for( int i
=0; i
<sources_count
; i
++ )
2305 struct solidinf pinf
= *(struct solidinf
*)cxr_ab_ptr(&solids
, i
);
2307 if( pinf
.is_displacement
)
2312 struct cxr_mesh
*res
= cxr_pull_best_solid( pinf
.pmesh
, &abverts
, 0, &error
);
2316 cxr_ab_push( &solids
, &(struct solidinf
){res
,0} );
2324 // If no solids error we can rety while preserving 'hot' edges
2326 if( error
& CXR_ERROR_NO_SOLIDS
)
2329 res
= cxr_pull_best_solid(pinf
.pmesh
, &abverts
, 1, &error
);
2331 if( res
) cxr_ab_push( &solids
, &(struct solidinf
){res
,0} );
2343 if( cxr_settings
.debug
)
2345 for( int i
=0; i
<solids
.count
; i
++ )
2347 struct solidinf
*solid
= cxr_ab_ptr(&solids
,i
);
2349 if( !solid
->is_displacement
)
2350 cxr_debug_mesh( solid
->pmesh
, cxr_ab_ptr(&abverts
,0), colours_random
[cxr_range(i
,8)] );
2354 // Turn all those solids into VMF brushes
2355 // --------------------------------------
2356 for( int i
=0; i
<solids
.count
; i
++ )
2358 struct solidinf
*solid
= cxr_ab_ptr(&solids
,i
);
2360 if( solid
->is_displacement
) continue;
2362 cxr_vdf_node( output
, "solid" );
2363 cxr_vdf_ki32( output
, "id", ++ cxr_context
.brush_count
);
2365 for( int j
=0; j
<solid
->pmesh
->polys
.count
; j
++ )
2367 struct cxr_polygon
*poly
= cxr_ab_ptr( &solid
->pmesh
->polys
, j
);
2368 struct cxr_loop
*ploops
= cxr_ab_ptr(&solid
->pmesh
->loops
, poly
->loop_start
);
2369 struct cxr_material
*matptr
=
2370 poly
->material_id
< 0 || src
->material_count
== 0?
2372 &src
->materials
[ poly
->material_id
];
2374 cxr_vdf_node( output
, "side" );
2375 cxr_vdf_ki32( output
, "id", ++ cxr_context
.face_count
);
2377 v3f verts
[3]; v2f uvs
[3];
2379 v3_muls( cxr_ab_ptr(&abverts
, ploops
[0].index
), cxr_context
.scale_factor
, verts
[0] );
2380 v3_muls( cxr_ab_ptr(&abverts
, ploops
[1].index
), cxr_context
.scale_factor
, verts
[1] );
2381 v3_muls( cxr_ab_ptr(&abverts
, ploops
[2].index
), cxr_context
.scale_factor
, verts
[2] );
2382 verts
[0][2] += cxr_context
.offset_z
;
2383 verts
[1][2] += cxr_context
.offset_z
;
2384 verts
[2][2] += cxr_context
.offset_z
;
2386 v2_copy( ploops
[0].uv
, uvs
[0] );
2387 v2_copy( ploops
[1].uv
, uvs
[1] );
2388 v2_copy( ploops
[2].uv
, uvs
[2] );
2390 cxr_vdf_plane( output
, "plane", verts
[2], verts
[1], verts
[0] );
2391 cxr_vdf_kv( output
, "material", matptr
->vmt_path
);
2393 struct cxr_texinfo trans
;
2394 cxr_calculate_axis(&trans
, verts
, uvs
, (double[2]){ matptr
->res
[0], matptr
->res
[1] });
2396 cxr_vdf_kaxis(output
, "uaxis", trans
.uaxis
, trans
.offset
[0], trans
.scale
[0]);
2397 cxr_vdf_kaxis(output
, "vaxis", trans
.vaxis
, trans
.offset
[1], trans
.scale
[1]);
2399 cxr_vdf_kdouble(output
, "rotation", 0.0 );
2400 cxr_vdf_ki32(output
, "lightmapscale", cxr_settings
.lightmap_scale
);
2401 cxr_vdf_ki32(output
, "smoothing_groups", 0);
2403 cxr_vdf_edon( output
);
2406 cxr_vdf_node(output
, "editor");
2407 cxr_vdf_colour255(output
,"color", colours_random
[cxr_range(cxr_context
.brush_count
,8)]);
2408 cxr_vdf_ki32(output
,"visgroupshown",1);
2409 cxr_vdf_ki32(output
,"visgroupautoshown",1);
2410 cxr_vdf_edon(output
);
2412 cxr_vdf_edon( output
);
2415 for( int i
=0; i
<solids
.count
; i
++ )
2417 struct solidinf
*solid
= cxr_ab_ptr(&solids
,i
);
2418 cxr_free_mesh( solid
->pmesh
);
2421 cxr_ab_free( &abverts
);
2422 cxr_ab_free( &solids
);
2427 CXR_API
void cxr_set_log_function( void (*func
)(const char *str
) )
2429 cxr_log_func
= func
;
2432 CXR_API
void cxr_set_line_function( void (*func
)(v3f p0
, v3f p1
, v4f colour
) )
2434 cxr_line_func
= func
;
2437 CXR_API
void cxr_settings_update( struct cxr_settings
*settings
)
2439 cxr_settings
= *settings
;
2442 // Valve copyright stuff probably maybe
2443 // whatever, my previous copyright decleration ends here
2444 // ----------------------------------------------------------
2446 #define HEADER_LUMPS 64
2447 #define LUMP_WORLDLIGHTS 54
2449 #pragma pack(push,1)
2458 int fileofs
, filelen
;
2463 lumps
[ HEADER_LUMPS
];
2473 float shadow_cast_offset
[3];
2481 float constant_attn
;
2483 float quadratic_attn
;
2490 // Utility for patching BSP tools to remove -1 distance lights (we set them
2491 // like that, because we want these lights to go away)
2493 // Yes, there is no way to do this in hammer
2494 // Yes, the distance KV is unused but still gets compiled to this lump
2495 // No, Entities only compile will not do this for you
2497 CXR_API
int cxr_lightpatch_bsp( const char *path
)
2499 printf( "Lightpatch: %s\n", path
);
2501 FILE *fp
= fopen( path
, "r+b" );
2505 cxr_log( "Could not open BSP file for editing (r+b)\n" );
2510 struct header header
;
2511 fread( &header
, sizeof(struct header
), 1, fp
);
2512 struct lump
*lump
= &header
.lumps
[ LUMP_WORLDLIGHTS
];
2514 // Read worldlight array
2515 struct worldlight
*lights
= malloc( lump
->filelen
);
2516 fseek( fp
, lump
->fileofs
, SEEK_SET
);
2517 fread( lights
, lump
->filelen
, 1, fp
);
2519 // Remove all marked lights
2520 int light_count
= lump
->filelen
/ sizeof(struct worldlight
);
2523 for( int i
= 0; i
< light_count
; i
++ )
2524 if( lights
[i
].radius
>= 0.0f
)
2525 lights
[new_count
++] = lights
[i
];
2527 lump
->filelen
= new_count
*sizeof(struct worldlight
);
2530 fseek( fp
, lump
->fileofs
, SEEK_SET
);
2531 fwrite( lights
, lump
->filelen
, 1, fp
);
2532 fseek( fp
, 0, SEEK_SET
);
2533 fwrite( &header
, sizeof(struct header
), 1, fp
);
2534 cxr_log( "removed %d marked lights\n", light_count
-new_count
);