4 A GNU/Linux-first Source1 Hammer replacement
5 built with Blender, for mapmakers
7 Copyright (C) 2022 Harry Godden (hgn)
9 LICENSE: GPLv3.0, please see COPYING and LICENSE for more information
12 - Brush decomposition into convex pieces for well defined geometry
13 - Freely form displacements without limits
14 - Build your entire map in Blender
15 - Compile models and model groups easily
16 - It runs at an ok speed!
17 - Light patch BSP files; remove unwanted realtime effects
18 - Bestest VTF compressor (thanks to Richgel999 and stb)
19 - Pack content automatically
23 File/folder Lang Purpose
25 __init__.py Python Blender plugin interface
28 cxr.h C Heavy lifting; brush decomp, mesh processing
29 cxr_math.h C Vector maths and other handy things
30 cxr_mem.h C Automatic resizing buffers
31 libcxr.c C Compile as SO
34 nbvtf.h C VTF processing interface
35 librgcx.h C++ Rich Geldreich's DXT1/DXT5 compressors
36 stb/ C Sean Barrets image I/O
52 #define CXR_EPSILON 0.001
53 #define CXR_PLANE_SIMILARITY_MAX 0.998
54 #define CXR_BIG_NUMBER 1e300
55 #define CXR_INTERIOR_ANGLE_MAX 0.998
58 #define CXR_IMPLEMENTATION
77 typedef unsigned int uint
;
79 typedef double v2f
[2];
80 typedef double v3f
[3];
81 typedef double v4f
[4];
89 typedef struct cxr_world cxr_world
;
90 typedef struct cxr_solid cxr_solid
;
92 typedef struct cxr_mesh cxr_mesh
;
93 typedef struct cxr_edge cxr_edge
;
94 typedef struct cxr_polygon cxr_polygon
;
95 typedef struct cxr_static_mesh cxr_static_mesh
;
96 typedef struct cxr_loop cxr_loop
;
97 typedef struct cxr_static_loop cxr_static_loop
;
98 typedef struct cxr_material cxr_material
;
99 typedef struct cxr_tri_mesh cxr_tri_mesh
;
101 #ifdef CXR_VALVE_MAP_FILE
102 typedef struct cxr_vdf cxr_vdf
;
103 typedef struct cxr_texinfo cxr_texinfo
;
104 typedef struct cxr_visgroup cxr_visgroup
;
105 typedef struct cxr_vmf_context cxr_vmf_context
;
106 #endif /* CXR_VALVE_MAP_FILE */
112 /* Main convexer algorithms */
113 /* Convex decomp from mesh */
114 CXR_API cxr_world
*cxr_decompose( cxr_static_mesh
*src
, i32
*perrcode
);
115 CXR_API
void cxr_free_world( cxr_world
*world
);
116 CXR_API cxr_tri_mesh
*cxr_world_preview( cxr_world
*world
);
117 CXR_API
void cxr_free_tri_mesh( cxr_tri_mesh
*mesh
);
119 #ifdef CXR_VALVE_MAP_FILE
121 CXR_API
void cxr_begin_vmf( cxr_vmf_context
*ctx
, cxr_vdf
*vdf
);
122 CXR_API
void cxr_vmf_begin_entities( cxr_vmf_context
*ctx
, cxr_vdf
*vdf
);
123 CXR_API
void cxr_push_world_vmf(
124 cxr_world
*world
, cxr_vmf_context
*ctx
, cxr_vdf
*vdf
);
125 CXR_API
void cxr_end_vmf( cxr_vmf_context
*ctx
, cxr_vdf
*vdf
);
128 CXR_API cxr_vdf
*cxr_vdf_open( const char *path
);
129 CXR_API
void cxr_vdf_close( cxr_vdf
*vdf
);
130 CXR_API
void cxr_vdf_put( cxr_vdf
*vdf
, const char *str
);
131 CXR_API
void cxr_vdf_node( cxr_vdf
*vdf
, const char *str
);
132 CXR_API
void cxr_vdf_edon( cxr_vdf
*vdf
);
133 CXR_API
void cxr_vdf_kv( cxr_vdf
*vdf
, const char *strk
, const char *strv
);
136 CXR_API
int cxr_lightpatch_bsp( const char *path
);
137 #endif /* CXR_VALVE_MAP_FILE */
141 CXR_API
void cxr_set_log_function( void (*func
)(const char *str
) );
142 CXR_API
void cxr_set_line_function( void (*func
)(v3f p0
, v3f p1
, v4f colour
) );
143 CXR_API
void cxr_write_test_data( cxr_static_mesh
*src
);
144 #endif /* CXR_DEBUG */
146 struct cxr_static_mesh
153 i32 freestyle
, sharp
;
157 struct cxr_static_loop
168 i32 loop_start
, loop_total
;
171 i32 material_id
; /* -1: interior material (nodraw) */
211 cxr_material
*materials
;
222 *p_abverts
; /* This data is stored externally because the data is often
223 shared between solids. */
225 /* Valid when update() is called on this mesh,
226 * Invalid when data is appended to them */
227 struct cxr_edge
*edges
;
228 struct cxr_polygon
*polys
;
229 struct cxr_loop
*loops
;
232 /* Simple mesh type mainly for debugging */
242 #ifdef CXR_VALVE_MAP_FILE
256 * Simplified VDF writing interface. No allocations or nodes, just write to file
264 struct cxr_vmf_context
272 cxr_visgroup
*visgroups
;
275 /* Transform settings */
286 #endif /* CXR_VALVE_MAP_FILE */
291 k_soliderr_non_manifold
,
292 k_soliderr_bad_manifold
,
293 k_soliderr_no_solids
,
294 k_soliderr_degenerate_implicit
,
295 k_soliderr_non_coplanar_vertices
,
296 k_soliderr_non_convex_poly
,
297 k_soliderr_bad_result
,
298 k_soliderr_invalid_input
303 * -----------------------------------------------------------------------------
305 #ifdef CXR_IMPLEMENTATION
307 const char *cxr_build_time
= __DATE__
" @" __TIME__
;
313 #warning 32 bit is not supported in blender 3.0
317 static void (*cxr_log_func
)(const char *str
);
318 static void (*cxr_line_func
)( v3f p0
, v3f p1
, v4f colour
);
320 static int cxr_range(int x
, int bound
)
323 x
+= bound
* (x
/bound
+ 1);
329 * This should be called after appending any data to those buffers
331 static void cxr_mesh_update( cxr_mesh
*mesh
)
333 mesh
->edges
= cxr_ab_ptr(&mesh
->abedges
, 0);
334 mesh
->polys
= cxr_ab_ptr(&mesh
->abpolys
, 0);
335 mesh
->loops
= cxr_ab_ptr(&mesh
->abloops
, 0);
338 static v4f colours_random
[] =
340 { 0.863, 0.078, 0.235, 0.4 },
341 { 0.000, 0.980, 0.604, 0.4 },
342 { 0.118, 0.565, 1.000, 0.4 },
343 { 0.855, 0.439, 0.839, 0.4 },
344 { 0.824, 0.412, 0.118, 0.4 },
345 { 0.125, 0.698, 0.667, 0.4 },
346 { 0.541, 0.169, 0.886, 0.4 },
347 { 1.000, 0.843, 0.000, 0.4 }
350 static v4f colours_solids
[] =
352 { 100, 143, 255, 200 },
353 { 120, 94, 240, 200 },
354 { 220, 38, 127, 200 },
359 static v4f colour_entity
= { 37, 241, 122, 255 };
360 static v4f colour_displacement_solid
= { 146, 146, 146, 120 };
361 static v4f colour_error
= { 1.0f
, 0.0f
, 0.0f
, 1.0f
};
362 static v4f colour_face_graph
= { 1.0f
, 1.0f
, 1.0f
, 0.03f
};
363 static v4f colour_success
= { 0.0f
, 1.0f
, 0.0f
, 1.0f
};
365 static void value_random(int n
, v4f colour
)
367 double val
= cxr_range(n
,8);
371 v3_muls( colour
, val
, colour
);
374 static void colour_random_brush(int n
, v4f colour
)
378 int colour_n
= cxr_range( n
, 5 );
379 v4_muls( colours_solids
[ colour_n
], 1.0/255.0, colour
);
380 value_random( value_n
, colour
);
382 int colour_n
= cxr_range( n
, 8 );
383 v4_copy( colours_random
[ colour_n
], colour
);
388 * Debugging and diagnostic utilities
389 * -----------------------------------------------------------------------------
394 static void cxr_log( const char *fmt
, ... )
399 va_start( args
, fmt
);
400 vsnprintf( buf
, sizeof(buf
)-1, fmt
, args
);
409 static void cxr_debug_line( v3f p0
, v3f p1
, v4f colour
)
412 cxr_line_func( p0
, p1
, colour
);
415 static void cxr_debug_box( v3f p0
, double sz
, v4f colour
)
419 v3_add(p0
, (v3f
){-sz
,-sz
,-sz
}, a
);
420 v3_add(p0
, (v3f
){-sz
, sz
,-sz
}, b
);
421 v3_add(p0
, (v3f
){ sz
, sz
,-sz
}, c
);
422 v3_add(p0
, (v3f
){ sz
,-sz
,-sz
}, d
);
423 v3_add(p0
, (v3f
){-sz
,-sz
,sz
}, a1
);
424 v3_add(p0
, (v3f
){-sz
, sz
,sz
}, b1
);
425 v3_add(p0
, (v3f
){ sz
, sz
,sz
}, c1
);
426 v3_add(p0
, (v3f
){ sz
,-sz
,sz
}, d1
);
428 cxr_debug_line( a
,b
, colour
);
429 cxr_debug_line( b
,c
, colour
);
430 cxr_debug_line( c
,d
, colour
);
431 cxr_debug_line( d
,a
, colour
);
432 cxr_debug_line( a1
,b1
, colour
);
433 cxr_debug_line( b1
,c1
, colour
);
434 cxr_debug_line( c1
,d1
, colour
);
435 cxr_debug_line( d1
,a1
, colour
);
436 cxr_debug_line( a
,a1
, colour
);
437 cxr_debug_line( b
,b1
, colour
);
438 cxr_debug_line( c
,c1
, colour
);
439 cxr_debug_line( d
,d1
, colour
);
443 * Draw arrow with the tips oriented along normal
445 static void cxr_debug_arrow( v3f p0
, v3f p1
, v3f normal
, double sz
, v4f colour
)
447 v3f dir
, tan
, p2
, p3
;
451 v3_cross(dir
,normal
,tan
);
452 v3_muladds( p1
,dir
, -sz
, p2
);
453 v3_muladds( p2
,tan
,sz
,p3
);
454 cxr_debug_line( p1
, p3
, colour
);
455 v3_muladds( p2
,tan
,-sz
,p3
);
456 cxr_debug_line( p1
, p3
, colour
);
457 cxr_debug_line( p0
, p1
, colour
);
461 * Draw arrows CCW around polygon, draw normal vector from center
463 static void cxr_debug_poly( cxr_mesh
*mesh
, cxr_polygon
*poly
, v4f colour
)
465 v3f
*verts
= cxr_ab_ptr( mesh
->p_abverts
, 0 );
467 for( int i
=0; i
<poly
->loop_total
; i
++ )
469 int lp0
= poly
->loop_start
+i
,
470 lp1
= poly
->loop_start
+cxr_range(i
+1,poly
->loop_total
);
472 int i0
= mesh
->loops
[ lp0
].index
,
473 i1
= mesh
->loops
[ lp1
].index
;
477 v3_lerp( verts
[i0
], poly
->center
, 0.0075, p0
);
478 v3_lerp( verts
[i1
], poly
->center
, 0.0075, p1
);
479 v3_muladds( p0
, poly
->normal
, 0.01, p0
);
480 v3_muladds( p1
, poly
->normal
, 0.01, p1
);
482 cxr_debug_arrow( p0
, p1
, poly
->normal
, 0.05, colour
);
486 v3_muladds( poly
->center
, poly
->normal
, 0.3, nrm0
);
488 cxr_debug_line( poly
->center
, nrm0
, colour
);
491 static void cxr_debug_mesh(cxr_mesh
*mesh
, v4f colour
)
493 for( int i
=0; i
<mesh
->abpolys
.count
; i
++ )
495 cxr_polygon
*poly
= &mesh
->polys
[i
];
496 cxr_debug_poly( mesh
, poly
, colour
);
500 CXR_API
void cxr_write_test_data( cxr_static_mesh
*src
)
503 "/home/harry/Documents/blender_addons_remote/addons/convexer/cxr/solid.h",
506 fprintf( fp
, "v3f test_verts[] = {\n" );
507 for( int i
=0; i
<src
->vertex_count
; i
++ )
509 fprintf( fp
, " { %f, %f, %f },\n",
512 src
->vertices
[i
][2] );
514 fprintf( fp
, "};\n" );
516 fprintf( fp
, "cxr_static_loop test_loops[] = {\n" );
517 for( int i
=0; i
<src
->loop_count
; i
++ )
519 fprintf( fp
, " {%d, %d, {%f, %f}, %f},\n",
521 src
->loops
[i
].edge_index
,
524 src
->loops
[i
].alpha
);
526 fprintf( fp
, "};\n" );
528 fprintf( fp
, "cxr_polygon test_polys[] = {\n" );
529 for( int i
=0; i
<src
->poly_count
; i
++ )
531 fprintf( fp
, " {%d, %d, {%f, %f, %f}, {%f, %f, %f}},\n",
532 src
->polys
[i
].loop_start
,
533 src
->polys
[i
].loop_total
,
534 src
->polys
[i
].normal
[0],
535 src
->polys
[i
].normal
[1],
536 src
->polys
[i
].normal
[2],
537 src
->polys
[i
].center
[0],
538 src
->polys
[i
].center
[1],
539 src
->polys
[i
].center
[2] );
541 fprintf( fp
, "};\n" );
543 fprintf( fp
, "cxr_edge test_edges[] = {\n" );
544 for( int i
=0; i
<src
->edge_count
; i
++ )
546 fprintf( fp
, " {%d, %d, %d, %d},\n",
549 src
->edges
[i
].freestyle
,
553 fprintf( fp
, "};\n" );
555 fprintf( fp
, "cxr_static_mesh test_mesh = {\n" );
556 fprintf( fp
, " .vertices = test_verts,\n" );
557 fprintf( fp
, " .loops = test_loops,\n" );
558 fprintf( fp
, " .edges = test_edges,\n" );
559 fprintf( fp
, " .polys = test_polys,\n" );
560 fprintf( fp
, " .poly_count=%d,\n", src
->poly_count
);
561 fprintf( fp
, " .vertex_count=%d,\n", src
->vertex_count
);
562 fprintf( fp
, " .edge_count=%d,\n",src
->edge_count
);
563 fprintf( fp
, " .loop_count=%d\n", src
->loop_count
);
564 fprintf( fp
, "};\n" );
569 CXR_API
void cxr_set_log_function( void (*func
)(const char *str
) )
574 CXR_API
void cxr_set_line_function( void (*func
)(v3f p0
, v3f p1
, v4f colour
) )
576 cxr_line_func
= func
;
579 #endif /* CXR_DEBUG */
583 * abverts is a pointer to an existing vertex buffer
585 static cxr_mesh
*cxr_alloc_mesh( int edge_count
, int loop_count
, int poly_count
,
588 cxr_mesh
*mesh
= malloc(sizeof(cxr_mesh
));
589 cxr_ab_init(&mesh
->abedges
, sizeof(cxr_edge
), edge_count
);
590 cxr_ab_init(&mesh
->abloops
, sizeof(cxr_loop
), loop_count
);
591 cxr_ab_init(&mesh
->abpolys
, sizeof(cxr_polygon
), poly_count
);
592 mesh
->p_abverts
= abverts
;
594 cxr_mesh_update( mesh
);
599 static void cxr_free_mesh( cxr_mesh
*mesh
)
601 cxr_ab_free(&mesh
->abedges
);
602 cxr_ab_free(&mesh
->abloops
);
603 cxr_ab_free(&mesh
->abpolys
);
608 * Rebuilds edge data for mesh (useful to get rid of orphaned edges)
610 static void cxr_mesh_clean_edges( cxr_mesh
*mesh
)
612 cxr_abuffer new_edges
;
613 cxr_ab_init( &new_edges
, sizeof(cxr_edge
), mesh
->abedges
.count
);
615 for( int i
=0; i
<mesh
->abpolys
.count
; i
++ )
617 cxr_polygon
*poly
= &mesh
->polys
[i
];
618 for( int j
=0; j
<poly
->loop_total
; j
++ )
621 *lp0
= &mesh
->loops
[poly
->loop_start
+j
],
622 *lp1
= &mesh
->loops
[poly
->loop_start
+cxr_range(j
+1,poly
->loop_total
)];
624 int i0
= cxr_min(lp0
->index
, lp1
->index
),
625 i1
= cxr_max(lp0
->index
, lp1
->index
);
627 /* Check if edge exists before adding */
628 for( int k
=0; k
<new_edges
.count
; k
++ )
630 cxr_edge
*edge
= cxr_ab_ptr(&new_edges
,k
);
632 if( edge
->i0
== i0
&& edge
->i1
== i1
)
635 goto IL_EDGE_CREATED
;
639 int orig_edge_id
= lp0
->edge_index
;
640 lp0
->edge_index
= new_edges
.count
;
642 cxr_edge edge
= { i0
, i1
};
645 * Copy extra information from original edges
648 if( orig_edge_id
< mesh
->abedges
.count
)
650 cxr_edge
*orig_edge
= &mesh
->edges
[ orig_edge_id
];
651 edge
.freestyle
= orig_edge
->freestyle
;
652 edge
.sharp
= orig_edge
->sharp
;
660 cxr_ab_push( &new_edges
, &edge
);
666 cxr_ab_free( &mesh
->abedges
);
667 mesh
->abedges
= new_edges
;
669 cxr_mesh_update( mesh
);
673 * Remove 0-length faces from mesh (we mark them light that for deletion
674 * Remove all unused loops as a result of removing those faces
676 static void cxr_mesh_clean_faces( cxr_mesh
*mesh
)
678 cxr_abuffer loops_new
;
679 cxr_ab_init( &loops_new
, sizeof(cxr_loop
), mesh
->abloops
.count
);
682 for( int i
=0; i
<mesh
->abpolys
.count
; i
++ )
684 cxr_polygon
*src
= &mesh
->polys
[i
],
685 *dst
= &mesh
->polys
[new_length
];
687 if( src
->loop_total
> 0 )
689 int src_start
= src
->loop_start
,
690 src_total
= src
->loop_total
;
693 dst
->loop_start
= loops_new
.count
;
695 for( int j
=0; j
<src_total
; j
++ )
697 cxr_loop
*loop
= &mesh
->loops
[src_start
+j
],
698 *ldst
= cxr_ab_ptr(&loops_new
,dst
->loop_start
+j
);
700 ldst
->poly_left
= new_length
;
703 loops_new
.count
+= src_total
;
708 cxr_ab_free( &mesh
->abloops
);
709 mesh
->abloops
= loops_new
;
710 mesh
->abpolys
.count
= new_length
;
712 cxr_mesh_update( mesh
);
716 * Links loop's poly_left and poly_right
717 * Does not support more than 2 polys to one edge
719 * Returns 0 if there is non-manifold geomtry (aka: not watertight)
721 static int cxr_mesh_link_loops( cxr_mesh
*mesh
)
723 i32
*polygon_edge_map
= malloc(mesh
->abedges
.count
*2 *sizeof(i32
));
725 for( int i
= 0; i
< mesh
->abedges
.count
*2; i
++ )
726 polygon_edge_map
[i
] = -1;
728 for( int i
= 0; i
< mesh
->abpolys
.count
; i
++ )
730 cxr_polygon
*poly
= &mesh
->polys
[i
];
732 for( int j
= 0; j
< poly
->loop_total
; j
++ )
734 cxr_loop
*loop
= &mesh
->loops
[ poly
->loop_start
+j
];
737 for( int k
= 0; k
< 2; k
++ )
739 i32
*edge
= &polygon_edge_map
[loop
->edge_index
*2+k
];
748 /* Overflowed edge mapping... Duplicated faces. */
749 free( polygon_edge_map
);
755 for( int i
= 0; i
< mesh
->abpolys
.count
; i
++ )
757 cxr_polygon
*poly
= &mesh
->polys
[i
];
759 for( int j
= 0; j
< poly
->loop_total
; j
++ )
761 cxr_loop
*loop
= &mesh
->loops
[ poly
->loop_start
+j
];
763 i32
*face_map
= &polygon_edge_map
[ loop
->edge_index
*2 ];
765 if( face_map
[0] == loop
->poly_left
) loop
->poly_right
= face_map
[1];
766 else loop
->poly_right
= face_map
[0];
771 for( int i
=0; i
<mesh
->abedges
.count
*2; i
++ )
773 if( polygon_edge_map
[i
] == -1 )
775 free( polygon_edge_map
);
780 free( polygon_edge_map
);
785 * Create new empty polygon with known loop count
786 * Must be filled and completed by the following functions!
788 static int cxr_create_poly( cxr_mesh
*mesh
, int loop_count
)
790 v3f
*verts
= cxr_ab_ptr( mesh
->p_abverts
, 0 );
795 cxr_log( "tried to add new poly with length %d!\n", loop_count
);
800 cxr_ab_reserve( &mesh
->abpolys
, 1 );
801 cxr_ab_reserve( &mesh
->abloops
, loop_count
);
802 cxr_mesh_update( mesh
);
804 cxr_polygon
*poly
= &mesh
->polys
[ mesh
->abpolys
.count
];
806 poly
->loop_start
= mesh
->abloops
.count
;
807 poly
->loop_total
= 0;
808 poly
->material_id
= -1;
809 v3_zero( poly
->center
);
815 * Add one index to the polygon created by the above function
817 static void cxr_poly_push_index( cxr_mesh
*mesh
, int id
)
819 v3f
*verts
= cxr_ab_ptr( mesh
->p_abverts
, 0 );
821 int nface_id
= mesh
->abpolys
.count
;
822 cxr_polygon
*poly
= &mesh
->polys
[ nface_id
];
824 cxr_loop
*new_loop
= &mesh
->loops
[ poly
->loop_start
+ poly
->loop_total
];
826 new_loop
->poly_left
= nface_id
;
827 new_loop
->poly_right
= -1;
828 new_loop
->index
= id
;
829 new_loop
->edge_index
= 0;
830 v2_zero(new_loop
->uv
);
832 v3_add( poly
->center
, verts
[new_loop
->index
], poly
->center
);
835 mesh
->abloops
.count
++;
839 * Finalize and commit polygon into mesh
841 static void cxr_poly_finish( cxr_mesh
*mesh
)
843 v3f
*verts
= cxr_ab_ptr( mesh
->p_abverts
, 0 );
845 int nface_id
= mesh
->abpolys
.count
;
846 cxr_polygon
*poly
= &mesh
->polys
[nface_id
];
848 /* Average center and calc normal */
850 v3_divs( poly
->center
, poly
->loop_total
, poly
->center
);
851 cxr_loop
*lp0
= &mesh
->loops
[ poly
->loop_start
],
852 *lp1
= &mesh
->loops
[ poly
->loop_start
+1 ],
853 *lp2
= &mesh
->loops
[ poly
->loop_start
+2 ];
856 verts
[lp0
->index
], verts
[lp1
->index
], verts
[lp2
->index
], poly
->normal
);
858 mesh
->abpolys
.count
++;
862 * Extract the next island from mesh
864 * Returns NULL if mesh is one contigous object
866 static cxr_mesh
*cxr_pull_island( cxr_mesh
*mesh
)
868 cxr_mesh_link_loops(mesh
);
870 int *island_current
= malloc(mesh
->abpolys
.count
*sizeof(int)),
875 island_current
[0] = 0;
878 last_count
= island_len
;
880 for( int i
=0; i
<island_len
; i
++ )
882 cxr_polygon
*poly
= &mesh
->polys
[ island_current
[i
] ];
884 for( int j
=0; j
<poly
->loop_total
; j
++ )
886 cxr_loop
*loop
= &mesh
->loops
[ poly
->loop_start
+j
];
888 if( loop
->poly_right
!= -1 )
890 int face_present
= 0;
892 for( int k
=0; k
<island_len
; k
++ )
894 if( island_current
[k
] == loop
->poly_right
)
902 island_current
[ island_len
++ ] = loop
->poly_right
;
907 if( island_len
> last_count
)
910 /* Check for complete object */
911 if( island_len
== mesh
->abpolys
.count
)
913 free( island_current
);
917 for( int i
=0; i
<island_len
; i
++ )
919 cxr_polygon
*poly
= &mesh
->polys
[ island_current
[i
] ];
920 loop_count
+= poly
->loop_total
;
923 /* Create and update meshes */
924 cxr_mesh
*newmesh
= cxr_alloc_mesh( mesh
->abedges
.count
,
929 for( int i
=0; i
<island_len
; i
++ )
931 cxr_polygon
*src
= &mesh
->polys
[ island_current
[i
] ];
932 cxr_polygon
*dst
= cxr_ab_ptr(&newmesh
->abpolys
, i
);
935 dst
->loop_start
= newmesh
->abloops
.count
;
937 for( int j
=0; j
<src
->loop_total
; j
++ )
940 *lsrc
= &mesh
->loops
[ src
->loop_start
+j
],
941 *ldst
= cxr_ab_ptr(&newmesh
->abloops
, dst
->loop_start
+j
);
945 ldst
->poly_right
= -1;
948 newmesh
->abloops
.count
+= src
->loop_total
;
949 src
->loop_total
= -1;
952 newmesh
->abpolys
.count
= island_len
;
953 newmesh
->abedges
.count
= mesh
->abedges
.count
;
954 memcpy( cxr_ab_ptr(&newmesh
->abedges
,0),
956 mesh
->abedges
.count
* sizeof(cxr_edge
));
958 cxr_mesh_clean_faces(mesh
);
959 cxr_mesh_clean_edges(mesh
);
960 cxr_mesh_clean_edges(newmesh
);
962 free( island_current
);
967 * Invalid solid is when there are vertices that are coplanar to a face, but are
968 * outside the polygons edges.
970 static int cxr_valid_solid( cxr_mesh
*mesh
, int *solid
, int len
)
972 v3f
*verts
= cxr_ab_ptr(mesh
->p_abverts
, 0);
974 for( int i
=0; i
<len
; i
++ )
976 cxr_polygon
*polyi
= &mesh
->polys
[ solid
[i
] ];
979 normal_to_plane(polyi
->normal
, polyi
->center
, plane
);
981 for( int j
=0; j
<len
; j
++ )
985 cxr_polygon
*polyj
= &mesh
->polys
[ solid
[j
] ];
987 for( int k
=0; k
<polyj
->loop_total
; k
++ )
989 cxr_loop
*lpj
= &mesh
->loops
[ polyj
->loop_start
+k
];
991 /* Test if the vertex is not referenced by the polygon */
992 for( int l
=0; l
<polyi
->loop_total
; l
++ )
994 cxr_loop
*lpi
= &mesh
->loops
[ polyi
->loop_start
+l
];
996 if( lpi
->index
== lpj
->index
)
1000 if( fabs(plane_polarity(plane
, verts
[lpj
->index
])) < 0.001 )
1012 * Use when iterating the loops array, to get a unique set of edges
1013 * Better than using the edges array and doing many more checks
1015 static int cxr_loop_unique_edge( cxr_loop
*lp
)
1017 if( lp
->poly_left
> lp
->poly_right
)
1024 * Identify edges in the mesh where the two connected face's normals
1025 * are opposing eachother (or close to identical)
1027 static int *cxr_mesh_reflex_edges( cxr_mesh
*mesh
)
1029 v3f
*verts
= cxr_ab_ptr( mesh
->p_abverts
, 0 );
1030 int *edge_tagged
= malloc( mesh
->abedges
.count
* sizeof(int) );
1032 for( int i
=0; i
<mesh
->abloops
.count
; i
++ )
1034 cxr_loop
*lp
= &mesh
->loops
[i
];
1035 if( !cxr_loop_unique_edge( lp
) ) continue;
1037 edge_tagged
[lp
->edge_index
] = 0;
1039 cxr_polygon
*polya
= &mesh
->polys
[ lp
->poly_left
],
1040 *polyb
= &mesh
->polys
[ lp
->poly_right
];
1043 normal_to_plane(polyb
->normal
, polyb
->center
, planeb
);
1045 for( int j
=0; j
<polya
->loop_total
; j
++ )
1047 cxr_loop
*lp1
= &mesh
->loops
[ polya
->loop_start
+j
];
1049 if(( plane_polarity( planeb
, verts
[lp1
->index
] ) > 0.001 ) ||
1050 ( v3_dot(polya
->normal
,polyb
->normal
) > CXR_PLANE_SIMILARITY_MAX
))
1052 edge_tagged
[lp
->edge_index
] = 1;
1062 * Same logic as above function except it will apply it to each vertex
1064 static int *cxr_mesh_reflex_vertices( cxr_mesh
*mesh
)
1066 v3f
*verts
= cxr_ab_ptr( mesh
->p_abverts
, 0 );
1068 int *vertex_tagged
= malloc( mesh
->p_abverts
->count
*sizeof(int) );
1069 int *connected_planes
= malloc( mesh
->abpolys
.count
*sizeof(int) );
1071 for( int i
=0; i
<mesh
->p_abverts
->count
; i
++ )
1074 int num_connected
= 0;
1076 /* Create a list of polygons that refer to this vertex */
1077 for( int j
=0; j
<mesh
->abpolys
.count
; j
++ )
1079 cxr_polygon
*poly
= &mesh
->polys
[j
];
1080 for( int k
=0; k
<poly
->loop_total
; k
++ )
1082 cxr_loop
*loop
= &mesh
->loops
[poly
->loop_start
+k
];
1083 if( loop
->index
== i
)
1085 connected_planes
[num_connected
++] = j
;
1091 /* Check all combinations for a similar normal */
1092 for( int j
=0; j
<num_connected
-1; j
++ )
1094 for( int k
=j
+1; k
<num_connected
; k
++ )
1096 cxr_polygon
*polyj
= &mesh
->polys
[connected_planes
[j
]],
1097 *polyk
= &mesh
->polys
[connected_planes
[k
]];
1099 if( v3_dot(polyj
->normal
,polyk
->normal
) > CXR_PLANE_SIMILARITY_MAX
)
1105 * Check if all connected planes either:
1107 * - Coplanar with it
1109 for( int j
=0; j
<num_connected
; j
++ )
1111 for( int k
=j
+1; k
<num_connected
; k
++ )
1113 cxr_polygon
*jpoly
= &mesh
->polys
[ connected_planes
[j
] ],
1114 *kpoly
= &mesh
->polys
[ connected_planes
[k
] ];
1117 normal_to_plane( kpoly
->normal
, kpoly
->center
, plane
);
1118 for( int l
=0; l
<jpoly
->loop_total
; l
++ )
1120 cxr_loop
*lp
= &mesh
->loops
[ jpoly
->loop_start
+l
];
1122 if( plane_polarity( plane
, verts
[lp
->index
] ) > 0.001 )
1130 vertex_tagged
[i
] = 1;
1133 free( connected_planes
);
1134 return vertex_tagged
;
1138 * Detect if potential future edges create a collision with any of the
1139 * existing edges in the mesh
1141 static int cxr_solid_overlap( cxr_mesh
*mesh
,
1144 int common_edge_index
1146 v3f
*verts
= cxr_ab_ptr( mesh
->p_abverts
, 0 );
1147 cxr_edge
*common_edge
= &mesh
->edges
[common_edge_index
];
1149 int unique_a
= pa
->loop_total
-2,
1150 unique_b
= pb
->loop_total
-2;
1152 int *unique_verts
= malloc( (unique_a
+unique_b
)*sizeof(int) );
1153 int unique_total
= 0;
1155 for( int j
=0; j
<2; j
++ )
1157 cxr_polygon
*poly
= (cxr_polygon
*[2]){pa
,pb
}[j
];
1159 for( int i
=0; i
<poly
->loop_total
; i
++ )
1161 cxr_loop
*lp
= &mesh
->loops
[poly
->loop_start
+i
];
1163 if( lp
->index
== common_edge
->i0
|| lp
->index
== common_edge
->i1
)
1166 unique_verts
[ unique_total
++ ] = lp
->index
;
1172 for( int i
=0; i
<unique_a
; i
++ )
1174 for( int j
=unique_a
; j
<unique_total
; j
++ )
1176 int i0
= unique_verts
[i
],
1177 i1
= unique_verts
[j
];
1179 for( int k
=0; k
<mesh
->abedges
.count
; k
++ )
1181 cxr_edge
*edge
= &mesh
->edges
[k
];
1183 if( edge
->i0
== i0
|| edge
->i0
== i1
||
1184 edge
->i1
== i0
|| edge
->i1
== i1
) continue;
1186 double *a0
= verts
[i0
],
1188 *b0
= verts
[edge
->i0
],
1189 *b1
= verts
[edge
->i1
];
1191 double dist
= segment_segment_dist( a0
, a1
, b0
, b1
, ca
, cb
);
1195 free( unique_verts
);
1202 free( unique_verts
);
1207 * Creates the 'maximal' solid that originates from this faceid
1209 * Returns the number of faces used
1211 static int cxr_buildsolid(
1218 faces_tagged
[faceid
] = faceid
;
1221 solid
[solid_len
++] = faceid
;
1223 int search_start
= 0;
1228 for( int j
=search_start
; j
<solid_len
; j
++ )
1230 cxr_polygon
*poly
= &mesh
->polys
[ solid
[j
] ];
1232 for( int k
=0; k
<poly
->loop_total
; k
++ )
1234 cxr_loop
*loop
= &mesh
->loops
[ poly
->loop_start
+k
];
1235 cxr_edge
*edge
= &mesh
->edges
[ loop
->edge_index
];
1237 if( faces_tagged
[ loop
->poly_right
] == -1 )
1239 if( !reflex_edges
[loop
->edge_index
] )
1241 /* Check for dodgy edges */
1242 cxr_polygon
*newpoly
= &mesh
->polys
[loop
->poly_right
];
1244 if( cxr_solid_overlap(mesh
,poly
,newpoly
,loop
->edge_index
))
1247 /* Looking ahead by one step gives us an early out for invalid
1248 * configurations. This might just all be handled by the new
1249 * edge overlap detector, though.
1251 for( int l
=0; l
< newpoly
->loop_total
; l
++ )
1253 cxr_loop
*lp1
= &mesh
->loops
[ newpoly
->loop_start
+l
];
1254 cxr_polygon
*future_face
= &mesh
->polys
[ lp1
->poly_right
];
1256 if( reflex_edges
[ lp1
->edge_index
]
1257 || lp1
->poly_right
== loop
->poly_right
)
1260 for( int m
=0; m
<solid_len
; m
++ )
1261 if( solid
[m
] == lp1
->poly_right
)
1264 for( int m
=0; m
<solid_len
; m
++ )
1266 cxr_polygon
*polym
= &mesh
->polys
[solid
[m
]];
1267 double pdist
= v3_dot( polym
->normal
,future_face
->normal
);
1269 if( pdist
> CXR_PLANE_SIMILARITY_MAX
)
1276 /* Check for vertices in the new polygon that exist on a current
1277 * plane. This condition is invalid */
1278 solid
[ solid_len
] = loop
->poly_right
;
1280 if( cxr_valid_solid(mesh
,solid
,solid_len
+1 ) )
1282 faces_tagged
[ loop
->poly_right
] = faceid
;
1292 search_start
= solid_len
;
1294 goto search_iterate
;
1301 int start
, count
, edge_count
;
1305 struct temp_manifold
1307 struct manifold_loop
1317 enum manifold_status
1321 k_manifold_fragmented
,
1322 k_manifold_complete
,
1328 * Create polygon from entire manifold structure.
1330 * Must be completely co-planar
1332 static void cxr_create_poly_full( cxr_mesh
*mesh
, struct temp_manifold
*src
)
1334 if( cxr_create_poly( mesh
, src
->loop_count
) )
1336 for( int l
=0; l
<src
->loop_count
; l
++ )
1337 cxr_poly_push_index( mesh
, src
->loops
[ l
].loop
.index
);
1339 cxr_poly_finish( mesh
);
1344 * Links up all edges into a potential new manifold
1346 * The return status can be:
1347 * (err): Critical programming error
1348 * none: No manifold to create
1349 * fragmented: Multiple sections exist, not just one
1350 * complete: Optimial manifold was created
1352 static void cxr_link_manifold(
1354 struct csolid
*solid
,
1356 struct temp_manifold
*manifold
1358 cxr_loop
**edge_list
= malloc( sizeof(*edge_list
) * solid
->edge_count
);
1359 int *temp_solid
= malloc( solid
->count
*sizeof(int) );
1360 int temp_solid_len
= 0;
1362 int init_reverse
= 0;
1363 int unique_edge_count
= 0;
1365 /* Try remove splitting faces first */
1367 int split_total
= 0;
1368 for( int j
=0; j
<solid
->count
; j
++ )
1370 cxr_polygon
*poly
= &mesh
->polys
[ solid_buffer
[solid
->start
+j
] ];
1371 int interior_count
= 0;
1373 for( int k
=0; k
<poly
->loop_total
; k
++ )
1375 cxr_loop
*loop
= &mesh
->loops
[ poly
->loop_start
+k
];
1377 for( int l
=0; l
<solid
->count
; l
++ )
1378 if( loop
->poly_right
== solid_buffer
[solid
->start
+l
] )
1387 if( interior_count
< poly
->loop_total
-1 )
1393 temp_solid
[ temp_solid_len
++ ] = solid_buffer
[solid
->start
+j
];
1396 if( temp_solid_len
< 3 || (split_total
& 0x2) /* unkown reasons */ )
1401 /* Overwrite original solid */
1402 for( int j
=0; j
<temp_solid_len
; j
++ )
1403 solid_buffer
[ solid
->start
+j
] = temp_solid
[ j
];
1405 solid
->count
= temp_solid_len
;
1411 for( int j
=0; j
<solid
->count
; j
++ )
1413 cxr_polygon
*poly
= &mesh
->polys
[ solid_buffer
[solid
->start
+j
] ];
1415 /* when discarding, if a face has only one loop that points outwards,
1419 for( int k
=0; k
<poly
->loop_total
; k
++ )
1421 cxr_loop
*loop
= &mesh
->loops
[ poly
->loop_start
+k
];
1423 for( int l
=0; l
<unique_edge_count
; l
++ )
1424 if( edge_list
[l
]->edge_index
== loop
->edge_index
)
1427 for( int l
=0; l
<solid
->count
; l
++ )
1428 if( loop
->poly_right
== solid_buffer
[solid
->start
+l
] )
1431 edge_list
[ unique_edge_count
] = loop
;
1433 if( unique_edge_count
== 0 )
1435 cxr_edge
*edgeptr
= &mesh
->edges
[ loop
->edge_index
];
1436 if( edgeptr
->i1
== loop
->index
)
1440 unique_edge_count
++;
1445 if( unique_edge_count
== 0 )
1448 manifold
->status
= k_manifold_none
;
1452 /* Link edges together to form manifold */
1453 manifold
->loops
= malloc( solid
->edge_count
*sizeof(struct manifold_loop
));
1454 manifold
->split_count
= 0;
1455 manifold
->loop_count
= 0;
1457 cxr_edge
*current
= &mesh
->edges
[ edge_list
[0]->edge_index
];
1459 int endpt
= (!init_reverse
)? current
->i0
: current
->i1
,
1461 curface
= edge_list
[0]->poly_left
;
1464 for( int j
=0; j
<unique_edge_count
; j
++ )
1466 cxr_edge
*other
= &mesh
->edges
[ edge_list
[j
]->edge_index
];
1467 if( other
== current
)
1470 if( other
->i0
== endpt
|| other
->i1
== endpt
)
1475 if( other
->i0
== endpt
) endpt
= current
->i1
;
1476 else endpt
= current
->i0
;
1478 struct manifold_loop
*ml
= &manifold
->loops
[ manifold
->loop_count
++ ];
1480 if( curface
==edge_list
[j
]->poly_left
)
1483 manifold
->split_count
++;
1488 ml
->loop
.edge_index
= edge_list
[j
]->edge_index
;
1489 ml
->loop
.poly_left
= edge_list
[j
]->poly_left
;
1490 ml
->loop
.index
= lastpt
;
1491 ml
->loop
.poly_right
= edge_list
[j
]->poly_right
;
1493 curface
= edge_list
[j
]->poly_left
;
1497 if( manifold
->loop_count
< unique_edge_count
)
1498 manifold
->status
= k_manifold_fragmented
;
1500 manifold
->status
= k_manifold_complete
;
1502 goto manifold_complete
;
1505 goto manifold_continue
;
1509 /* Incomplete links */
1510 manifold
->status
= k_manifold_err
;
1519 * Reconstruct implied internal geometry where the manifold doesn't have
1520 * enough information (vertices) to create a full result.
1522 static int cxr_build_implicit_geo( cxr_mesh
*mesh
, int new_polys
, int start
)
1524 for( int i
=0; i
<new_polys
-2; i
++ )
1526 for( int j
=i
+1; j
<new_polys
-1; j
++ )
1528 for( int k
=j
+1; k
<new_polys
; k
++ )
1530 cxr_polygon
*ptri
= &mesh
->polys
[ start
+i
],
1531 *ptrj
= &mesh
->polys
[ start
+j
],
1532 *ptrk
= &mesh
->polys
[ start
+k
];
1534 v4f planei
, planej
, planek
;
1535 normal_to_plane(ptri
->normal
,ptri
->center
,planei
);
1536 normal_to_plane(ptrj
->normal
,ptrj
->center
,planej
);
1537 normal_to_plane(ptrk
->normal
,ptrk
->center
,planek
);
1541 if( plane_intersect(planei
,planej
,planek
,intersect
) )
1543 /* Make sure the point is inside the convex region */
1545 int point_valid
= 1;
1546 for( int l
=0; l
<mesh
->abpolys
.count
; l
++ )
1548 cxr_polygon
*ptrl
= &mesh
->polys
[l
];
1551 normal_to_plane(ptrl
->normal
, ptrl
->center
, planel
);
1553 if( plane_polarity( planel
, intersect
) > 0.01 )
1556 cxr_log( "degen vert, planes %d, %d, %d [max:%d]\n",
1559 cxr_debug_poly( mesh
, ptri
, colours_random
[3] );
1560 cxr_debug_poly( mesh
, ptrj
, colours_random
[1] );
1561 cxr_debug_poly( mesh
, ptrk
, colours_random
[2] );
1568 /* Extend faces to include this vert */
1570 int nvertid
= mesh
->p_abverts
->count
;
1571 cxr_ab_push( mesh
->p_abverts
, intersect
);
1573 ptrj
->loop_start
+= 1;
1574 ptrk
->loop_start
+= 2;
1576 cxr_ab_reserve( &mesh
->abloops
, 3);
1578 int newi
= ptri
->loop_start
+ptri
->loop_total
,
1579 newj
= ptrj
->loop_start
+ptrj
->loop_total
,
1580 newk
= ptrk
->loop_start
+ptrk
->loop_total
;
1583 *lloopi
= cxr_ab_empty_at(&mesh
->abloops
, newi
),
1584 *lloopj
= cxr_ab_empty_at(&mesh
->abloops
, newj
),
1585 *lloopk
= cxr_ab_empty_at(&mesh
->abloops
, newk
);
1587 lloopi
->index
= nvertid
;
1588 lloopi
->edge_index
= 0;
1589 lloopi
->poly_left
= start
+ i
;
1590 lloopi
->poly_right
= -1;
1592 lloopj
->index
= nvertid
;
1593 lloopj
->poly_left
= start
+ j
;
1594 lloopj
->edge_index
= 0;
1595 lloopj
->poly_right
= -1;
1597 lloopk
->index
= nvertid
;
1598 lloopk
->edge_index
= 0;
1599 lloopk
->poly_left
= start
+ k
;
1600 lloopk
->poly_right
= -1;
1602 v2_zero(lloopi
->uv
);
1603 v2_zero(lloopj
->uv
);
1604 v2_zero(lloopk
->uv
);
1606 ptri
->loop_total
++;
1607 ptrj
->loop_total
++;
1608 ptrk
->loop_total
++;
1610 double qi
= 1.0/(double)ptri
->loop_total
,
1611 qj
= 1.0/(double)ptrj
->loop_total
,
1612 qk
= 1.0/(double)ptrk
->loop_total
;
1614 /* Adjust centers of faces */
1615 v3_lerp( ptri
->center
, intersect
, qi
, ptri
->center
);
1616 v3_lerp( ptrj
->center
, intersect
, qj
, ptrj
->center
);
1617 v3_lerp( ptrk
->center
, intersect
, qk
, ptrk
->center
);
1626 static int cxr_reflex_err( cxr_mesh
*mesh
)
1629 int *reflex_check
= cxr_mesh_reflex_edges( mesh
);
1631 v3f
*temp
= cxr_ab_ptr(mesh
->p_abverts
, 0);
1633 for( int i
=0; i
<mesh
->abedges
.count
; i
++ )
1635 if( reflex_check
[i
] )
1637 cxr_debug_line( temp
[mesh
->edges
[i
].i0
],
1638 temp
[mesh
->edges
[i
].i1
],
1644 free( reflex_check
);
1648 static int cxr_non_manifold_err( cxr_mesh
*mesh
)
1650 if( !cxr_mesh_link_loops(mesh
) )
1653 cxr_log( "non-manifold edges are in the mesh: "
1654 "implicit internal geometry does not have full support\n" );
1656 v3f
*verts
= cxr_ab_ptr( mesh
->p_abverts
, 0 );
1658 for( int i
=0; i
<mesh
->abloops
.count
; i
++ )
1660 cxr_loop
*lp
= &mesh
->loops
[i
];
1661 cxr_edge
*edge
= &mesh
->edges
[lp
->edge_index
];
1662 cxr_debug_line( verts
[edge
->i0
], verts
[edge
->i1
], colours_random
[1] );
1664 if( lp
->poly_left
== -1 || lp
->poly_right
== -1 )
1666 cxr_debug_line( verts
[edge
->i0
], verts
[edge
->i1
], colour_error
);
1677 * Convexer's main algorithm
1679 * Return the best availible convex solid from mesh, and patch the existing mesh
1680 * to fill the gap where the new mesh left it.
1682 * Returns NULL if shape is already convex or empty.
1683 * This function will not preserve edge data such as freestyle, sharp etc.
1685 static cxr_mesh
*cxr_pull_best_solid(
1687 int preserve_more_edges
,
1688 enum cxr_soliderr
*err
)
1690 *err
= k_soliderr_none
;
1692 if( cxr_non_manifold_err( mesh
) )
1694 *err
= k_soliderr_non_manifold
;
1698 int *edge_tagged
= cxr_mesh_reflex_edges( mesh
);
1699 int *vertex_tagged
= cxr_mesh_reflex_vertices( mesh
);
1702 * Connect all marked vertices that share an edge
1705 int *edge_important
= malloc(mesh
->abedges
.count
*sizeof(int));
1706 for( int i
=0; i
< mesh
->abedges
.count
; i
++ )
1707 edge_important
[i
] = 0;
1709 for( int i
=0; i
<mesh
->abpolys
.count
; i
++ )
1711 cxr_polygon
*poly
= &mesh
->polys
[i
];
1712 int not_tagged
= -1,
1715 for( int j
=0; j
<poly
->loop_total
; j
++ )
1717 cxr_loop
*loop
= &mesh
->loops
[ poly
->loop_start
+j
];
1719 if( !edge_tagged
[ loop
->edge_index
] )
1721 if( not_tagged
== -1 )
1722 not_tagged
= loop
->edge_index
;
1724 goto edge_unimportant
;
1728 if( not_tagged
!= -1 )
1729 edge_important
[not_tagged
]=1;
1735 * Connect edges where both vertices are reflex, only if we are not
1738 for( int i
=0; i
<mesh
->abedges
.count
; i
++ )
1740 if( edge_important
[i
] && preserve_more_edges
) continue;
1742 cxr_edge
*edge
= &mesh
->edges
[i
];
1743 if( vertex_tagged
[edge
->i0
] && vertex_tagged
[edge
->i1
] )
1747 free( edge_important
);
1749 int *faces_tagged
= malloc(mesh
->abpolys
.count
*sizeof(int));
1750 for( int i
=0; i
<mesh
->abpolys
.count
; i
++ )
1751 faces_tagged
[i
] = -1;
1753 struct csolid
*candidates
;
1754 int *solid_buffer
= malloc( mesh
->abpolys
.count
*sizeof(int) ),
1755 solid_buffer_len
= 0,
1756 candidate_count
= 0;
1758 candidates
= malloc( mesh
->abpolys
.count
*sizeof(struct csolid
) );
1761 * Create a valid, non-overlapping solid for every face present in the mesh
1763 for( int i
=0; i
<mesh
->abpolys
.count
; i
++ )
1765 if( faces_tagged
[i
] != -1 ) continue;
1766 faces_tagged
[i
] = i
;
1768 int *solid
= &solid_buffer
[ solid_buffer_len
];
1769 int len
= cxr_buildsolid( mesh
, i
, solid
, edge_tagged
, faces_tagged
);
1772 struct csolid
*csolid
= &candidates
[candidate_count
++];
1773 csolid
->start
= solid_buffer_len
;
1774 csolid
->count
= len
;
1775 csolid
->edge_count
= 0;
1777 v3_zero( csolid
->center
);
1778 for( int j
=0; j
<len
; j
++ )
1780 cxr_polygon
*polyj
= &mesh
->polys
[ solid
[j
] ];
1781 v3_add( polyj
->center
, csolid
->center
, csolid
->center
);
1782 csolid
->edge_count
+= polyj
->loop_total
;
1784 v3_divs( csolid
->center
, len
, csolid
->center
);
1785 solid_buffer_len
+= len
;
1788 free( edge_tagged
);
1789 free( vertex_tagged
);
1790 free( faces_tagged
);
1793 * Choosing the best solid: most defined manifold
1795 struct csolid
*best_solid
= NULL
;
1796 int fewest_manifold_splits
= INT32_MAX
;
1798 struct temp_manifold best_manifold
= { .loops
= NULL
, .loop_count
= 0 };
1799 int max_solid_faces
= 0;
1801 for( int i
=0; i
<candidate_count
; i
++ )
1803 struct csolid
*solid
= &candidates
[i
];
1804 max_solid_faces
= cxr_max(max_solid_faces
,solid
->count
);
1806 if( solid
->count
<= 2 )
1809 struct temp_manifold manifold
;
1810 cxr_link_manifold( mesh
, solid
, solid_buffer
, &manifold
);
1812 if( manifold
.status
== k_manifold_err
)
1814 *err
= k_soliderr_bad_manifold
;
1818 free(manifold
.loops
);
1819 free(best_manifold
.loops
);
1823 if( manifold
.status
== k_manifold_complete
)
1825 if( manifold
.split_count
< fewest_manifold_splits
)
1827 fewest_manifold_splits
= manifold
.split_count
;
1830 free( best_manifold
.loops
);
1831 best_manifold
= manifold
;
1836 if( manifold
.status
!= k_manifold_none
)
1837 free( manifold
.loops
);
1840 if( max_solid_faces
< 2 )
1842 *err
= k_soliderr_no_solids
;
1845 free(best_manifold
.loops
);
1849 if( best_solid
!= NULL
)
1851 cxr_mesh
*pullmesh
= cxr_alloc_mesh( best_solid
->edge_count
,
1852 best_solid
->edge_count
,
1856 for( int i
=0; i
<best_solid
->count
; i
++ )
1858 int nface_id
= pullmesh
->abpolys
.count
;
1859 int exist_plane_id
= solid_buffer
[best_solid
->start
+i
];
1861 cxr_polygon
*exist_face
= &mesh
->polys
[ exist_plane_id
],
1862 *new_face
= cxr_ab_empty( &pullmesh
->abpolys
);
1864 *new_face
= *exist_face
;
1865 new_face
->loop_start
= pullmesh
->abloops
.count
;
1867 for( int j
=0; j
<exist_face
->loop_total
; j
++ )
1869 cxr_loop
*exist_loop
= &mesh
->loops
[ exist_face
->loop_start
+j
],
1870 *new_loop
= cxr_ab_empty(&pullmesh
->abloops
);
1872 new_loop
->index
= exist_loop
->index
;
1873 new_loop
->poly_left
= nface_id
;
1874 new_loop
->poly_right
= -1;
1875 new_loop
->edge_index
= 0;
1876 v2_copy( exist_loop
->uv
, new_loop
->uv
);
1879 exist_face
->loop_total
= -1;
1883 int pullmesh_new_start
= pullmesh
->abpolys
.count
;
1885 if( fewest_manifold_splits
!= 0 )
1887 /* Unusual observation:
1888 * If the split count is odd, the manifold can be created easily
1890 * If it is even, implicit internal geometry is needed to be
1891 * constructed. So the manifold gets folded as we create it segment
1894 * I'm not sure if this is a well defined rule of geometry, but seems
1895 * to apply to the data we care about.
1897 int collapse_used_segments
= (u32
)fewest_manifold_splits
& 0x1? 0: 1;
1901 for( int j
=0; j
< best_manifold
.loop_count
; j
++ )
1903 if( !best_manifold
.loops
[j
].split
) continue;
1905 cxr_loop
*loop
= &best_manifold
.loops
[j
].loop
;
1907 for( int k
=1; k
< best_manifold
.loop_count
; k
++ )
1909 int index1
= cxr_range(j
+k
, best_manifold
.loop_count
);
1910 cxr_loop
*loop1
= &best_manifold
.loops
[index1
].loop
;
1912 if( best_manifold
.loops
[index1
].split
)
1919 if( new_polys
> best_manifold
.loop_count
)
1922 cxr_log( "Programming error: Too many new polys!\n" );
1927 if( cxr_create_poly( pullmesh
, k
+1 ) )
1929 for( int l
=0; l
<k
+1; l
++ )
1931 int i0
= cxr_range(j
+l
, best_manifold
.loop_count
),
1932 index
= best_manifold
.loops
[ i0
].loop
.index
;
1934 cxr_poly_push_index( pullmesh
, index
);
1936 cxr_poly_finish( pullmesh
);
1939 /* Collapse down manifold */
1940 if( collapse_used_segments
)
1942 best_manifold
.loops
[j
].split
= 0;
1943 best_manifold
.loops
[index1
].split
= 0;
1945 int new_length
= (best_manifold
.loop_count
-(k
-1));
1947 struct temp_manifold new_manifold
= {
1948 .loop_count
= new_length
1950 new_manifold
.loops
=
1951 malloc( new_length
*sizeof(*new_manifold
.loops
) );
1953 for( int l
=0; l
<new_length
; l
++ )
1955 int i_src
= cxr_range( j
+k
+l
, best_manifold
.loop_count
);
1956 new_manifold
.loops
[l
] = best_manifold
.loops
[i_src
];
1959 free( best_manifold
.loops
);
1960 best_manifold
= new_manifold
;
1962 goto manifold_repeat
;
1971 if( best_manifold
.loop_count
&& collapse_used_segments
)
1973 cxr_create_poly_full( pullmesh
, &best_manifold
);
1979 cxr_create_poly_full( pullmesh
, &best_manifold
);
1983 if( new_polys
>= 3 )
1985 if( !cxr_build_implicit_geo( pullmesh
, new_polys
, pullmesh_new_start
))
1989 free(best_manifold
.loops
);
1991 cxr_free_mesh( pullmesh
);
1992 *err
= k_soliderr_degenerate_implicit
;
1998 * Copy faces from the pullmesh into original, to patch up where there
1999 * would be gaps created
2001 for( int i
=0; i
<new_polys
; i
++ )
2003 int rface_id
= mesh
->abpolys
.count
;
2004 cxr_polygon
*pface
= &pullmesh
->polys
[pullmesh_new_start
+i
],
2005 *rip_face
= cxr_ab_empty(&mesh
->abpolys
);
2007 rip_face
->loop_start
= mesh
->abloops
.count
;
2008 rip_face
->loop_total
= pface
->loop_total
;
2009 rip_face
->material_id
= -1;
2011 for( int j
=0; j
<rip_face
->loop_total
; j
++ )
2014 &pullmesh
->loops
[ pface
->loop_start
+pface
->loop_total
-j
-1 ],
2015 *rloop
= cxr_ab_empty(&mesh
->abloops
);
2017 rloop
->index
= ploop
->index
;
2018 rloop
->poly_left
= rface_id
;
2019 rloop
->poly_right
= -1;
2020 rloop
->edge_index
= 0;
2021 v2_copy( ploop
->uv
, rloop
->uv
);
2024 v3_copy( pface
->center
, rip_face
->center
);
2025 v3_negate( pface
->normal
, rip_face
->normal
);
2028 cxr_mesh_update( mesh
);
2029 cxr_mesh_update( pullmesh
);
2031 cxr_mesh_clean_faces( mesh
);
2032 cxr_mesh_clean_edges( mesh
);
2033 cxr_mesh_clean_faces( pullmesh
);
2034 cxr_mesh_clean_edges( pullmesh
);
2038 free(best_manifold
.loops
);
2041 * Do final checks on the mesh to make sure we diddn't introduce any
2044 if( cxr_non_manifold_err( pullmesh
) || cxr_reflex_err( pullmesh
) )
2046 *err
= k_soliderr_bad_result
;
2055 free(best_manifold
.loops
);
2057 if( cxr_non_manifold_err( mesh
) || cxr_reflex_err( mesh
) )
2058 *err
= k_soliderr_bad_result
;
2064 * Convert from the format we recieve from blender into our internal format
2065 * with auto buffers.
2067 static cxr_mesh
*cxr_to_internal_format(
2068 cxr_static_mesh
*src
,
2069 cxr_abuffer
*abverts
2071 cxr_mesh
*mesh
= cxr_alloc_mesh( src
->edge_count
, src
->loop_count
,
2072 src
->poly_count
, abverts
);
2074 cxr_ab_init( abverts
, sizeof(v3f
), src
->vertex_count
);
2076 memcpy( mesh
->abedges
.arr
, src
->edges
, src
->edge_count
*sizeof(cxr_edge
));
2077 memcpy( mesh
->abpolys
.arr
, src
->polys
, src
->poly_count
*sizeof(cxr_polygon
));
2078 memcpy( abverts
->arr
, src
->vertices
, src
->vertex_count
*sizeof(v3f
));
2079 mesh
->abedges
.count
= src
->edge_count
;
2080 mesh
->abloops
.count
= src
->loop_count
;
2081 mesh
->abpolys
.count
= src
->poly_count
;
2083 cxr_mesh_update( mesh
);
2085 for( int i
=0; i
<src
->loop_count
; i
++ )
2087 cxr_loop
*lp
= &mesh
->loops
[i
];
2089 lp
->index
= src
->loops
[i
].index
;
2090 lp
->edge_index
= src
->loops
[i
].edge_index
;
2091 v2_copy( src
->loops
[i
].uv
, lp
->uv
);
2092 lp
->alpha
= src
->loops
[i
].alpha
;
2095 abverts
->count
= src
->vertex_count
;
2099 static int cxr_poly_convex( cxr_mesh
*mesh
, cxr_polygon
*poly
)
2101 v3f
*verts
= cxr_ab_ptr( mesh
->p_abverts
, 0 );
2103 for( int i
=0; i
<poly
->loop_total
; i
++ )
2105 int li0
= poly
->loop_start
+ i
,
2106 li1
= poly
->loop_start
+ cxr_range( i
+1, poly
->loop_total
),
2107 li2
= poly
->loop_start
+ cxr_range( i
+2, poly
->loop_total
);
2108 int i0
= mesh
->loops
[li0
].index
,
2109 i1
= mesh
->loops
[li1
].index
,
2110 i2
= mesh
->loops
[li2
].index
;
2114 v3_sub( verts
[i1
], verts
[i0
], v0
);
2115 v3_sub( verts
[i2
], verts
[i1
], v1
);
2117 v3_cross( v0
, v1
, c
);
2118 if( v3_dot( c
, poly
->normal
) <= 0.0 )
2121 cxr_debug_line( verts
[i0
], verts
[i1
], colour_error
);
2122 cxr_debug_box( verts
[i1
], 0.1, colour_error
);
2123 cxr_debug_line( verts
[i1
], verts
[i2
], colour_error
);
2124 cxr_debug_line( verts
[i1
], poly
->center
, colour_error
);
2133 static int cxr_solid_checkerr( cxr_mesh
*mesh
)
2135 v3f
*verts
= cxr_ab_ptr( mesh
->p_abverts
, 0 );
2138 for( int i
=0; i
<mesh
->abpolys
.count
; i
++ )
2142 cxr_polygon
*poly
= &mesh
->polys
[i
];
2145 normal_to_plane( poly
->normal
, poly
->center
, plane
);
2147 for( int j
=0; j
<poly
->loop_total
; j
++ )
2149 cxr_loop
*loop
= &mesh
->loops
[ poly
->loop_start
+j
];
2150 double *vert
= verts
[ loop
->index
];
2152 if( fabs(plane_polarity(plane
,vert
)) > 0.0025 )
2158 plane_project_point( plane
, vert
, ref
);
2161 cxr_debug_line( ref
, vert
, colour_error
);
2162 cxr_debug_box( vert
, 0.1, colour_error
);
2169 cxr_debug_poly( mesh
, poly
, colour_error
);
2176 CXR_API
void cxr_free_world( cxr_world
*world
)
2178 for( int i
=0; i
<world
->absolids
.count
; i
++ )
2180 cxr_solid
*solid
= cxr_ab_ptr( &world
->absolids
, i
);
2181 cxr_free_mesh( solid
->pmesh
);
2184 cxr_ab_free( &world
->abverts
);
2185 cxr_ab_free( &world
->absolids
);
2187 if( world
->materials
)
2189 for( int i
=0; i
<world
->material_count
; i
++ )
2190 free( world
->materials
[i
].name
);
2192 free( world
->materials
);
2197 CXR_API cxr_tri_mesh
*cxr_world_preview( cxr_world
*world
)
2199 cxr_tri_mesh
*out
= malloc( sizeof(cxr_tri_mesh
) );
2200 out
->vertex_count
= 0;
2201 out
->indices_count
= 0;
2203 for( int i
=0; i
<world
->absolids
.count
; i
++ )
2205 cxr_solid
*solid
= cxr_ab_ptr( &world
->absolids
, i
);
2206 cxr_mesh
*mesh
= solid
->pmesh
;
2208 for( int j
=0; j
<mesh
->abpolys
.count
; j
++ )
2210 cxr_polygon
*poly
= &mesh
->polys
[j
];
2212 out
->vertex_count
+= poly
->loop_total
* 3; /* Polygon, edge strip */
2213 out
->indices_count
+= (poly
->loop_total
-2) * 3; /* Polygon */
2214 out
->indices_count
+= poly
->loop_total
* 2 * 3; /* Edge strip */
2218 out
->colours
= malloc( sizeof(v4f
)*out
->vertex_count
);
2219 out
->vertices
= malloc( sizeof(v3f
)*out
->vertex_count
);
2220 out
->indices
= malloc( sizeof(i32
)*out
->indices_count
);
2222 v3f
*overts
= out
->vertices
;
2223 v4f
*colours
= out
->colours
;
2224 i32
*indices
= out
->indices
;
2229 for( int i
=0; i
<world
->absolids
.count
; i
++ )
2231 cxr_solid
*solid
= cxr_ab_ptr( &world
->absolids
, i
);
2232 cxr_mesh
*mesh
= solid
->pmesh
;
2234 v3f
*verts
= cxr_ab_ptr( mesh
->p_abverts
, 0 );
2237 colour_random_brush( i
, colour
);
2239 for( int j
=0; j
<mesh
->abpolys
.count
; j
++ )
2241 cxr_polygon
*poly
= &mesh
->polys
[j
];
2245 for( int k
=0; k
<poly
->loop_total
-2; k
++ )
2251 indices
[ ii
++ ] = istart
+i0
;
2252 indices
[ ii
++ ] = istart
+i1
;
2253 indices
[ ii
++ ] = istart
+i2
;
2256 for( int k
=0; k
<poly
->loop_total
; k
++ )
2258 cxr_loop
*lp
= &mesh
->loops
[poly
->loop_start
+k
];
2261 i1r
= cxr_range(k
+1,poly
->loop_total
)*3+1,
2263 i1i
= cxr_range(k
+1,poly
->loop_total
)*3+2;
2265 indices
[ ii
++ ] = istart
+i0i
;
2266 indices
[ ii
++ ] = istart
+i1i
;
2267 indices
[ ii
++ ] = istart
+i1r
;
2269 indices
[ ii
++ ] = istart
+i0i
;
2270 indices
[ ii
++ ] = istart
+i1r
;
2271 indices
[ ii
++ ] = istart
+i0r
;
2274 v3_muladds( verts
[lp
->index
], poly
->normal
, 0.02, overts
[vi
] );
2275 v4_copy( colour
, colours
[ vi
] );
2280 v3_lerp( verts
[lp
->index
], poly
->center
, 0.2, inner
);
2281 v3_muladds( inner
, poly
->normal
, 0.015, overts
[ vi
] );
2282 v4_copy( colour
, colours
[ vi
] );
2283 v4_copy( (v4f
){ 0.0, 0.0, 0.0, 0.0 }, colours
[vi
] );
2286 v3_muladds(verts
[lp
->index
], poly
->normal
, 0.0, overts
[ vi
] );
2287 v4_copy( colour
, colours
[ vi
] );
2288 v4_copy( (v4f
){ 1.0, 1.0, 1.0, 0.125 }, colours
[vi
] );
2297 CXR_API
void cxr_free_tri_mesh( cxr_tri_mesh
*mesh
)
2299 free( mesh
->colours
);
2300 free( mesh
->indices
);
2301 free( mesh
->vertices
);
2305 CXR_API cxr_world
*cxr_decompose( cxr_static_mesh
*src
, i32
*perrcode
)
2307 /* Make sure data is in the mesh and isn't empty */
2308 if( !src
->edge_count
|| !src
->loop_count
|| !src
->poly_count
)
2310 cxr_log( "Error %d\n", k_soliderr_invalid_input
);
2312 *perrcode
= k_soliderr_invalid_input
;
2318 cxr_world
*world
= malloc( sizeof(*world
) );
2320 /* Copy data to internal formats */
2321 cxr_mesh
*main_mesh
= cxr_to_internal_format( src
, &world
->abverts
);
2322 cxr_ab_init( &world
->absolids
, sizeof(cxr_solid
), 2 );
2324 if( src
->material_count
)
2326 size_t dsize
= sizeof(cxr_material
) * src
->material_count
;
2327 world
->materials
= malloc( dsize
);
2328 memcpy( world
->materials
, src
->materials
, dsize
);
2330 for( int i
=0; i
<src
->material_count
; i
++ )
2332 world
->materials
[i
].name
= malloc(strlen(src
->materials
[i
].name
) +1);
2333 strcpy( world
->materials
[i
].name
, src
->materials
[i
].name
);
2335 world
->material_count
= src
->material_count
;
2337 else world
->materials
= NULL
;
2339 int invalid_count
= 0;
2342 * Preprocessor 1: Island seperation
2346 cxr_mesh
*res
= cxr_pull_island( main_mesh
);
2349 cxr_ab_push( &world
->absolids
, &(cxr_solid
){ res
, 0, 0 });
2353 cxr_ab_push( &world
->absolids
, &(cxr_solid
){ main_mesh
, 0, 0 } );
2356 * Preprocessor 2: Displacement processing & error checks
2358 for( int i
=0; i
<world
->absolids
.count
; i
++ )
2360 cxr_solid
*pinf
= cxr_ab_ptr(&world
->absolids
,i
);
2362 for( int j
=0; j
<pinf
->pmesh
->abpolys
.count
; j
++ )
2364 cxr_polygon
*poly
= &pinf
->pmesh
->polys
[ j
];
2366 for( int k
=0; k
<poly
->loop_total
; k
++ )
2368 cxr_loop
*lp
= &pinf
->pmesh
->loops
[ poly
->loop_start
+k
];
2369 cxr_edge
*edge
= &pinf
->pmesh
->edges
[ lp
->edge_index
];
2371 if( edge
->freestyle
)
2375 if( !cxr_poly_convex( pinf
->pmesh
, poly
) )
2379 error
= k_soliderr_non_convex_poly
;
2383 if( cxr_solid_checkerr( pinf
->pmesh
) )
2387 error
= k_soliderr_non_coplanar_vertices
;
2393 pinf
->displacement
= 1;
2397 * Main convex decomp algorithm
2399 int sources_count
= world
->absolids
.count
;
2404 for( int i
=0; i
<sources_count
; i
++ )
2406 cxr_solid pinf
= *(cxr_solid
*)cxr_ab_ptr(&world
->absolids
, i
);
2408 if( pinf
.displacement
|| pinf
.invalid
)
2413 cxr_mesh
*res
= cxr_pull_best_solid( pinf
.pmesh
, 0, &error
);
2417 cxr_ab_push( &world
->absolids
, &(cxr_solid
){ res
, 0, 0 } );
2421 if( error
== k_soliderr_no_solids
)
2423 /* Retry if non-critical error, with extra edges */
2424 res
= cxr_pull_best_solid(pinf
.pmesh
, 1, &error
);
2427 cxr_ab_push( &world
->absolids
, &(cxr_solid
){ res
, 0, 0 } );
2443 cxr_log( "Error %d\n", error
);
2444 cxr_free_world( world
);
2453 * format specific functions: vdf, vmf, (v)bsp
2454 * ----------------------------------------------------------------------------
2456 #ifdef CXR_VALVE_MAP_FILE
2458 CXR_API cxr_vdf
*cxr_vdf_open(const char *path
)
2460 cxr_vdf
*vdf
= malloc(sizeof(cxr_vdf
));
2463 vdf
->fp
= fopen( path
, "w" );
2474 CXR_API
void cxr_vdf_close(cxr_vdf
*vdf
)
2480 CXR_API
void cxr_vdf_put(cxr_vdf
*vdf
, const char *str
)
2482 for( int i
=0; i
<vdf
->level
; i
++ )
2483 fputs( " ", vdf
->fp
);
2485 fputs( str
, vdf
->fp
);
2488 static void cxr_vdf_printf( cxr_vdf
*vdf
, const char *fmt
, ... )
2490 cxr_vdf_put(vdf
,"");
2493 va_start( args
, fmt
);
2494 vfprintf( vdf
->fp
, fmt
, args
);
2498 CXR_API
void cxr_vdf_node(cxr_vdf
*vdf
, const char *str
)
2500 cxr_vdf_put( vdf
, str
);
2501 putc( (u8
)'\n', vdf
->fp
);
2502 cxr_vdf_put( vdf
, "{\n" );
2507 CXR_API
void cxr_vdf_edon( cxr_vdf
*vdf
)
2510 cxr_vdf_put( vdf
, "}\n" );
2513 CXR_API
void cxr_vdf_kv( cxr_vdf
*vdf
, const char *strk
, const char *strv
)
2515 cxr_vdf_printf( vdf
, "\"%s\" \"%s\"\n", strk
, strv
);
2519 * Data-type specific Keyvalues
2521 static void cxr_vdf_ki32( cxr_vdf
*vdf
, const char *strk
, i32 val
)
2523 cxr_vdf_printf( vdf
, "\"%s\" \"%d\"\n", strk
, val
);
2526 static void cxr_vdf_kdouble( cxr_vdf
*vdf
, const char *strk
, double val
)
2528 cxr_vdf_printf( vdf
, "\"%s\" \"%f\"\n", strk
, val
);
2531 static void cxr_vdf_kaxis( cxr_vdf
*vdf
, const char *strk
,
2532 v3f normal
, double offset
, double scale
2534 cxr_vdf_printf( vdf
, "\"%s\" \"[%f %f %f %f] %f\"\n",
2535 strk
, normal
[0], normal
[1],normal
[2], offset
, scale
);
2538 static void cxr_vdf_kv3f( cxr_vdf
*vdf
, const char *strk
, v3f v
)
2540 cxr_vdf_printf( vdf
, "\"%s\" \"[%f %f %f]\"\n", strk
, v
[0], v
[1], v
[2] );
2543 static void cxr_vdf_karrdouble( cxr_vdf
*vdf
, const char *strk
,
2544 int id
, double *doubles
, int count
2546 cxr_vdf_put(vdf
,"");
2547 fprintf( vdf
->fp
, "\"%s%d\" \"", strk
, id
);
2548 for( int i
=0; i
<count
; i
++ )
2550 if( i
== count
-1 ) fprintf( vdf
->fp
, "%f", doubles
[i
] );
2551 else fprintf( vdf
->fp
, "%f ", doubles
[i
] );
2553 fprintf( vdf
->fp
, "\"\n" );
2556 static void cxr_vdf_karrv3f( cxr_vdf
*vdf
, const char *strk
,
2557 int id
, v3f
*vecs
, int count
2559 cxr_vdf_put(vdf
,"");
2560 fprintf( vdf
->fp
, "\"%s%d\" \"", strk
, id
);
2561 for( int i
=0; i
<count
; i
++ )
2563 const char *format
= i
== count
-1? "%f %f %f": "%f %f %f ";
2564 fprintf( vdf
->fp
, format
, vecs
[i
][0], vecs
[i
][1], vecs
[i
][2] );
2566 fprintf( vdf
->fp
, "\"\n" );
2569 static void cxr_vdf_plane( cxr_vdf
*vdf
, const char *strk
, v3f a
, v3f b
, v3f c
)
2571 cxr_vdf_printf( vdf
, "\"%s\" \"(%f %f %f) (%f %f %f) (%f %f %f)\"\n",
2572 strk
, a
[0], a
[1], a
[2], b
[0], b
[1], b
[2], c
[0], c
[1], c
[2] );
2575 static void cxr_vdf_colour255(cxr_vdf
*vdf
, const char *strk
, v4f colour
)
2578 v4_muls( colour
, 255.0, scale
);
2579 cxr_vdf_printf( vdf
, "\"%s\" \"%d %d %d %d\"\n",
2580 strk
,(int)scale
[0], (int)scale
[1], (int)scale
[2], (int)scale
[3]);
2583 static struct cxr_material cxr_nodraw
=
2585 .res
= { 512, 512 },
2586 .name
= "tools/toolsnodraw"
2590 * Find most extreme point along a given direction
2592 static double support_distance( v3f verts
[3], v3f dir
, double coef
)
2596 coef
* v3_dot( verts
[0], dir
),
2599 coef
* v3_dot( verts
[1], dir
),
2600 coef
* v3_dot( verts
[2], dir
)
2606 * Convert regular UV'd triangle int Source's u/vaxis vectors
2608 * This supports affine move, scale, rotation, parallel skewing
2610 static void cxr_calculate_axis( cxr_texinfo
*transform
, v3f verts
[3],
2611 v2f uvs
[3], v2f texture_res
2613 v2f tT
, bT
; /* Tangent/bitangent pairs for UV space and world */
2616 v2_sub( uvs
[0], uvs
[1], tT
);
2617 v2_sub( uvs
[2], uvs
[1], bT
);
2618 v3_sub( verts
[0], verts
[1], tW
);
2619 v3_sub( verts
[2], verts
[1], bW
);
2621 /* Use arbitrary projection if there is no UV */
2622 if( v2_length( tT
) < 0.0001 || v2_length( bT
) < 0.0001 )
2624 v3f uaxis
, normal
, vaxis
;
2626 v3_copy( tW
, uaxis
);
2627 v3_normalize( uaxis
);
2629 v3_cross( tW
, bW
, normal
);
2630 v3_cross( normal
, uaxis
, vaxis
);
2631 v3_normalize( vaxis
);
2633 v3_copy( uaxis
, transform
->uaxis
);
2634 v3_copy( vaxis
, transform
->vaxis
);
2635 v2_zero( transform
->offset
);
2637 v2_div( (v2f
){128.0, 128.0}, texture_res
, transform
->scale
);
2638 transform
->winding
= 1.0;
2642 /* Detect if UV is reversed */
2643 double winding
= v2_cross( tT
, bT
) >= 0.0f
? 1.0f
: -1.0f
;
2645 /* UV projection reference */
2647 v2_muls((v2f
){1,0}, winding
, vX
);
2648 v2_muls((v2f
){0,1}, winding
, vY
);
2650 /* Reproject reference into world space, including skew */
2653 v3_muls( tW
, v2_cross(vX
,bT
) / v2_cross(bT
,tT
), uaxis1
);
2654 v3_muladds( uaxis1
, bW
, v2_cross(vX
, tT
) / v2_cross(tT
,bT
), uaxis1
);
2656 v3_muls( tW
, v2_cross(vY
,bT
) / v2_cross(bT
,tT
), vaxis1
);
2657 v3_muladds( vaxis1
, bW
, v2_cross(vY
,tT
) / v2_cross(tT
,bT
), vaxis1
);
2659 v3_normalize( uaxis1
);
2660 v3_normalize( vaxis1
);
2662 /* Apply source transform to axis (yes, they also need to be swapped) */
2663 v3f norm
, uaxis
, vaxis
;
2665 v3_cross( bW
, tW
, norm
);
2667 v3_cross( vaxis1
, norm
, uaxis
);
2668 v3_cross( uaxis1
, norm
, vaxis
);
2671 v2f uvmin
, uvmax
, uvdelta
;
2672 v2_minv( uvs
[0], uvs
[1], uvmin
);
2673 v2_minv( uvmin
, uvs
[2], uvmin
);
2674 v2_maxv( uvs
[0], uvs
[1], uvmax
);
2675 v2_maxv( uvmax
, uvs
[2], uvmax
);
2677 v2_sub( uvmax
, uvmin
, uvdelta
);
2679 /* world-uv scale */
2680 v2f uvminw
, uvmaxw
, uvdeltaw
;
2681 uvminw
[0] = -support_distance( verts
, uaxis
, -1.0f
);
2682 uvmaxw
[0] = support_distance( verts
, uaxis
, 1.0f
);
2683 uvminw
[1] = -support_distance( verts
, vaxis
, -1.0f
);
2684 uvmaxw
[1] = support_distance( verts
, vaxis
, 1.0f
);
2686 v2_sub( uvmaxw
, uvminw
, uvdeltaw
);
2690 v2_div( uvdeltaw
, uvdelta
, uv_scale
);
2691 v2_div( uv_scale
, texture_res
, uv_scale
);
2693 /* Find offset via 'natural' point */
2694 v2f target_uv
, natural_uv
, tex_offset
;
2695 v2_mul( uvs
[0], texture_res
, target_uv
);
2697 natural_uv
[0] = v3_dot( uaxis
, verts
[0] );
2698 natural_uv
[1] = -v3_dot( vaxis
, verts
[0] );
2699 v2_div( natural_uv
, uv_scale
, natural_uv
);
2701 tex_offset
[0] = target_uv
[0]-natural_uv
[0];
2702 tex_offset
[1] = -(target_uv
[1]-natural_uv
[1]);
2704 /* Copy everything into output */
2705 v3_copy( uaxis
, transform
->uaxis
);
2706 v3_copy( vaxis
, transform
->vaxis
);
2707 v2_copy( tex_offset
, transform
->offset
);
2708 v2_copy( uv_scale
, transform
->scale
);
2709 transform
->winding
= winding
;
2713 * Get the maximal direction of a vector, while also ignoring an axis
2716 static int cxr_cardinal( v3f a
, int ignore
)
2719 double component_max
= -CXR_BIG_NUMBER
;
2721 for( int i
=0; i
<3; i
++ )
2723 if( i
== ignore
) continue;
2725 if( fabs(a
[i
]) > component_max
)
2727 component_max
= fabs(a
[i
]);
2731 double d
= a
[component
] >= 0.0? 1.0: -1.0;
2739 * Convert contiguous mesh to displacement patch
2741 static int cxr_write_disp( cxr_mesh
*mesh
, cxr_world
*world
,
2742 cxr_vmf_context
*ctx
, cxr_vdf
*output
2744 v3f
*verts
= cxr_ab_ptr( mesh
->p_abverts
, 0 );
2748 int con_start
, con_count
;
2756 *vertinfo
= malloc( sizeof(struct vertinfo
)*mesh
->p_abverts
->count
);
2757 int *graph
= malloc( sizeof(int) * mesh
->abedges
.count
*2 );
2760 for( int i
=0; i
<mesh
->p_abverts
->count
; i
++ )
2762 struct vertinfo
*info
= &vertinfo
[i
];
2763 info
->con_start
= con_pos
;
2764 info
->con_count
= 0;
2771 for( int j
=0; j
<mesh
->abedges
.count
; j
++ )
2773 cxr_edge
*edge
= &mesh
->edges
[j
];
2775 if( edge
->i0
== i
|| edge
->i1
== i
)
2777 graph
[ con_pos
++ ] = edge
->i0
== i
? edge
->i1
: edge
->i0
;
2780 if( edge
->freestyle
)
2786 /* Collect alphas from loops. This discards hard blend information */
2787 for( int i
=0; i
<mesh
->abloops
.count
; i
++ )
2789 cxr_loop
*loop
= &mesh
->loops
[i
];
2790 vertinfo
[loop
->index
].alpha
= loop
->alpha
* 255.0;
2793 v3f refv
, refu
, refn
;
2794 v3_zero(refv
); v3_zero(refu
); v3_zero(refn
);
2797 * Approximately match the area of the result brush faces to the actual
2800 * Necessary for accuracy and even lightmap texel allocation
2803 double uv_area
= 0.0, face_area
= 0.0, sf
;
2804 v2f uvboundmin
, uvboundmax
;
2805 v3f faceboundmin
, faceboundmax
;
2809 v2_fill( uvboundmin
, CXR_BIG_NUMBER
);
2810 v2_fill( uvboundmax
, -CXR_BIG_NUMBER
);
2811 v3_fill( faceboundmin
, CXR_BIG_NUMBER
);
2812 v3_fill( faceboundmax
, -CXR_BIG_NUMBER
);
2814 for( int i
=0; i
<mesh
->abpolys
.count
; i
++ )
2816 cxr_polygon
*poly
= &mesh
->polys
[i
];
2818 for( int j
=0; j
<poly
->loop_total
; j
++ )
2820 cxr_loop
*lp0
= &mesh
->loops
[ poly
->loop_start
+j
];
2821 v2_minv( lp0
->uv
, uvboundmin
, uvboundmin
);
2822 v2_maxv( lp0
->uv
, uvboundmax
, uvboundmax
);
2823 v3_minv( verts
[lp0
->index
], faceboundmin
, faceboundmin
);
2824 v3_maxv( verts
[lp0
->index
], faceboundmax
, faceboundmax
);
2827 for( int j
=0; j
<poly
->loop_total
-2; j
++ )
2829 cxr_loop
*lp0
= &mesh
->loops
[poly
->loop_start
],
2830 *lp1
= &mesh
->loops
[poly
->loop_start
+j
+1],
2831 *lp2
= &mesh
->loops
[poly
->loop_start
+j
+2];
2834 v3_sub( verts
[lp1
->index
], verts
[lp0
->index
], va
);
2835 v3_sub( verts
[lp2
->index
], verts
[lp0
->index
], vb
);
2836 v3_cross( va
, vb
, orth
);
2838 face_area
+= v3_length( orth
) / 2.0;
2841 v2_sub( lp1
->uv
, lp0
->uv
, uva
);
2842 v2_sub( lp2
->uv
, lp0
->uv
, uvb
);
2844 uv_area
+= fabs(v2_cross( uva
, uvb
)) / 2.0;
2848 v3_add( faceboundmax
, faceboundmin
, face_center
);
2849 v3_muls( face_center
, 0.5, face_center
);
2850 v2_add( uvboundmin
, uvboundmax
, uv_center
);
2851 v2_muls( uv_center
, 0.5, uv_center
);
2853 sf
= sqrt( face_area
/ uv_area
);
2854 int corner_count
= 0;
2857 * Vertex classification
2858 * boundary vertices: they exist on a freestyle edge
2859 * corners: only connected to other boundaries
2861 for( int i
=0; i
<mesh
->p_abverts
->count
; i
++ )
2863 struct vertinfo
*info
= &vertinfo
[i
];
2864 if( !info
->boundary
) continue;
2869 for( int j
=0; j
<info
->con_count
; j
++ )
2871 int con
= graph
[info
->con_start
+j
];
2873 if( vertinfo
[con
].boundary
)
2879 if( count
> 2 || non_manifold
)
2887 * TODO(harry): This currently only supports power 2 displacements
2888 * its quite straightforward to upgrade it.
2890 * TODO(harry): Error checking is needed here for bad input data
2898 for( int i
=0; i
<mesh
->abpolys
.count
; i
++ )
2900 cxr_polygon
*basepoly
= &mesh
->polys
[i
];
2902 for( int h
=0; h
<basepoly
->loop_total
; h
++ )
2905 i1
= cxr_range(h
+1,basepoly
->loop_total
);
2907 cxr_loop
*l0
= &mesh
->loops
[ basepoly
->loop_start
+i0
],
2908 *l1
= &mesh
->loops
[ basepoly
->loop_start
+i1
];
2909 struct vertinfo
*info
= &vertinfo
[ l0
->index
];
2914 int corner_count
= 1;
2916 cxr_material
*matptr
=
2917 basepoly
->material_id
< 0 || !world
->materials
?
2919 &world
->materials
[ basepoly
->material_id
];
2922 dispedge
[0] = l0
->index
;
2923 dispedge
[1] = l1
->index
;
2924 v2_copy( l0
->uv
, corner_uvs
[0] );
2926 /* Consume (use) face from orignal mesh */
2927 basepoly
->loop_total
= -1;
2929 while( dispedge_count
< 17 )
2931 struct vertinfo
*edge_head
=
2932 &vertinfo
[dispedge
[dispedge_count
-1]];
2936 if( edge_head
->corner
)
2938 /* Find polygon that has edge C-1 -> C */
2939 for( int j
=0; j
<mesh
->abpolys
.count
&& !newvert
; j
++ )
2941 cxr_polygon
*poly
= &mesh
->polys
[j
];
2943 for( int k
=0; k
<poly
->loop_total
; k
++ )
2946 i1
= cxr_range(k
+1,poly
->loop_total
);
2948 cxr_loop
*l0
= &mesh
->loops
[ poly
->loop_start
+i0
],
2949 *l1
= &mesh
->loops
[ poly
->loop_start
+i1
];
2951 if( l0
->index
== dispedge
[dispedge_count
-2] &&
2952 l1
->index
== dispedge
[dispedge_count
-1] )
2954 /* Take the next edge */
2955 v2_copy( l1
->uv
, corner_uvs
[corner_count
++] );
2957 int i2
= cxr_range(i1
+1,poly
->loop_total
);
2958 cxr_loop
*l2
= &mesh
->loops
[ poly
->loop_start
+i2
];
2960 dispedge
[dispedge_count
++] = l2
->index
;
2962 poly
->loop_total
= -1;
2970 for( int j
=0; j
<edge_head
->con_count
; j
++ )
2972 int con
= graph
[edge_head
->con_start
+j
];
2977 if( dispedge_count
> 1 )
2978 if( con
== dispedge
[dispedge_count
-2] )
2981 struct vertinfo
*coninfo
= &vertinfo
[con
];
2983 if( !coninfo
->boundary
)
2986 dispedge
[ dispedge_count
++ ] = con
;
3001 /* All edges collected */
3004 v2_sub( corner_uvs
[1], corner_uvs
[0], va
);
3005 v2_sub( corner_uvs
[2], corner_uvs
[0], vb
);
3007 /* Connect up the grid
3015 * Example: a := common unused vertex that is connected to
3016 * by 1 and 15. Or y-1, and x-1 on the grid.
3017 * g := c and f common vert ^
3022 for( int j
=0; j
<5; j
++ ) grid
[j
] = dispedge
[j
];
3023 for( int j
=1; j
<5; j
++ ) grid
[j
*5+4] = dispedge
[j
+4];
3024 for( int j
=0; j
<4; j
++ ) grid
[4*5+3-j
] = dispedge
[j
+9];
3025 for( int j
=1; j
<4; j
++ ) grid
[j
*5] = dispedge
[16-j
];
3028 for( int j
=1; j
<4; j
++ )
3030 for( int k
=1; k
<4; k
++ )
3032 int s0
= grid
[(j
-1)*5+k
],
3035 struct vertinfo
*va
= &vertinfo
[s0
],
3036 *vb
= &vertinfo
[s1
];
3038 /* Find common non-used vertex */
3039 for( int l
=0; l
<va
->con_count
; l
++ )
3041 for( int m
=0; m
<vb
->con_count
; m
++ )
3043 int cona
= graph
[va
->con_start
+l
],
3044 conb
= graph
[vb
->con_start
+m
];
3048 if( vertinfo
[cona
].used
|| vertinfo
[cona
].boundary
)
3051 grid
[ j
*5+k
] = cona
;
3052 vertinfo
[cona
].used
= 1;
3068 * Create V reference based on first displacement.
3069 * TODO(harry): This is not the moststable selection method!
3070 * faces can come in any order, so the first disp will of
3071 * course always vary. Additionaly the triangle can be oriented
3074 * Improvement can be made by selecting a first disp/triangle
3075 * based on deterministic factors.
3077 if( disp_count
== 0 )
3081 v3_copy( verts
[dispedge
[0]], tri_ref
[0] );
3082 v3_copy( verts
[dispedge
[4]], tri_ref
[1] );
3083 v3_copy( verts
[dispedge
[8]], tri_ref
[2] );
3084 cxr_calculate_axis( &tx
, tri_ref
, corner_uvs
, (v2f
){512,512} );
3086 v3_muls( tx
.vaxis
, -1.0, refv
);
3087 int v_cardinal
= cxr_cardinal( refv
, -1 );
3089 v3_cross( tx
.vaxis
, tx
.uaxis
, refn
);
3090 v3_muls( refn
, -tx
.winding
, refn
);
3092 /* Computing new reference vectors */
3093 int n1_cardinal
= cxr_cardinal( refn
, v_cardinal
);
3097 for( int j
=0; j
<2; j
++ )
3098 if( u_cardinal
== n1_cardinal
|| u_cardinal
== v_cardinal
)
3102 refu
[u_cardinal
] = tx
.uaxis
[u_cardinal
] > 0.0? 1.0: -1.0;
3106 v3_copy( face_center
, p0
);
3107 v3_muladds( face_center
, refn
, 1.5, pn
);
3108 v3_muladds( face_center
, refv
, 1.5, pv
);
3109 v3_muladds( face_center
, refu
, 1.5, pu
);
3111 v3_muladds( face_center
, refn
, 2.0, face_center
);
3114 /* Create world coordinates */
3115 v3f world_corners
[8];
3118 for( int j
=0; j
<4; j
++ )
3121 v2_sub( corner_uvs
[j
], uv_center
, local_uv
);
3122 v2_copy( corner_uvs
[j
], world_uv
[j
] );
3123 v2_muls( local_uv
, sf
, local_uv
);
3125 v3_muls( refu
, local_uv
[0], world_corners
[j
] );
3126 v3_muladds( world_corners
[j
],refv
,local_uv
[1],world_corners
[j
] );
3127 v3_add( face_center
, world_corners
[j
], world_corners
[j
] );
3130 double *colour
= colours_random
[cxr_range(disp_count
,8)];
3132 for( int j
=0; j
<4; j
++ )
3133 v3_muladds( world_corners
[j
], refn
, -1.0, world_corners
[j
+4] );
3135 /* Apply world transform */
3136 for( int j
=0; j
<8; j
++ )
3138 double *p0
= world_corners
[j
];
3139 v3_muls( p0
, ctx
->scale
, p0
);
3140 v3_add( p0
, ctx
->offset
, p0
);
3143 cxr_texinfo texinfo_shared
;
3144 cxr_calculate_axis( &texinfo_shared
, world_corners
, world_uv
,
3145 (v2f
){ matptr
->res
[0], matptr
->res
[1] } );
3148 cxr_vdf_node( output
, "solid" );
3149 cxr_vdf_ki32( output
, "id", ++ ctx
->brush_count
);
3160 double distances
[25];
3163 v3f lside0
, lside1
, lref
, vdelta
, vworld
;
3166 for( int j
=0; j
<5; j
++ )
3168 ty
= (double)j
/(double)(5-1);
3170 v3_lerp( world_corners
[0], world_corners
[3], ty
, lside0
);
3171 v3_lerp( world_corners
[1], world_corners
[2], ty
, lside1
);
3173 for( int k
=0; k
<5; k
++ )
3177 tx
= (double)k
/(double)(5-1);
3178 v3_lerp( lside0
, lside1
, tx
, lref
);
3179 v3_muls( verts
[grid
[index
]], ctx
->scale
, vworld
);
3180 v3_add( ctx
->offset
, vworld
, vworld
);
3182 v3_sub( vworld
, lref
, vdelta
);
3183 v3_copy( vdelta
, normals
[index
] );
3184 v3_normalize( normals
[index
] );
3185 distances
[index
] = v3_dot( vdelta
, normals
[index
] );
3187 alphas
[index
] = vertinfo
[grid
[index
]].alpha
;
3191 for( int j
=0; j
<6; j
++ )
3193 int *side
= sides
[j
];
3195 cxr_vdf_node( output
, "side" );
3196 cxr_vdf_ki32( output
, "id", ++ ctx
->face_count
);
3197 cxr_vdf_plane( output
, "plane", world_corners
[side
[2]],
3198 world_corners
[side
[1]],
3199 world_corners
[side
[0]] );
3201 cxr_vdf_kv( output
, "material", matptr
->name
);
3202 cxr_vdf_kaxis( output
, "uaxis",
3203 texinfo_shared
.uaxis
,
3204 texinfo_shared
.offset
[0],
3205 texinfo_shared
.scale
[0] );
3206 cxr_vdf_kaxis( output
, "vaxis",
3207 texinfo_shared
.vaxis
,
3208 texinfo_shared
.offset
[1],
3209 texinfo_shared
.scale
[1] );
3211 cxr_vdf_kdouble( output
, "rotation", 0.0 );
3212 cxr_vdf_ki32( output
, "lightmapscale", ctx
->lightmap_scale
);
3213 cxr_vdf_ki32( output
, "smoothing_groups", 0 );
3217 cxr_vdf_node( output
, "dispinfo" );
3218 cxr_vdf_ki32( output
, "power", 2 );
3219 cxr_vdf_kv3f( output
, "startposition", world_corners
[0] );
3220 cxr_vdf_ki32( output
, "flags", 0 );
3221 cxr_vdf_kdouble( output
, "elevation", 0.0 );
3222 cxr_vdf_ki32( output
, "subdiv", 0 );
3224 cxr_vdf_node( output
, "normals" );
3225 for( int k
=0; k
<5; k
++ )
3226 cxr_vdf_karrv3f( output
, "row", k
, &normals
[k
*5], 5 );
3227 cxr_vdf_edon( output
);
3229 cxr_vdf_node( output
, "distances" );
3230 for( int k
=0; k
<5; k
++ )
3231 cxr_vdf_karrdouble( output
, "row", k
, &distances
[k
*5], 5 );
3232 cxr_vdf_edon( output
);
3234 cxr_vdf_node( output
, "alphas" );
3235 for( int k
=0; k
<5; k
++ )
3236 cxr_vdf_karrdouble( output
, "row", k
, &alphas
[k
*5], 5 );
3237 cxr_vdf_edon( output
);
3240 * TODO: This might be needed for the compilers. Opens fine in
3245 cxr_vdf_node( output, "offsets" );
3246 for( int k=0; k<5; k++ )
3247 cxr_vdf_printf( output,
3248 "\"row%d\" \"0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\"\n", k );
3249 cxr_vdf_edon( output );
3251 cxr_vdf_node( output, "offset_normals" );
3252 for( int k=0; k<5; k++ )
3253 cxr_vdf_printf( output,
3254 "\"row%d\" \"0 0 1 0 0 1 0 0 1 0 0 1 0 0 1\"\n", k );
3255 cxr_vdf_edon( output );
3257 cxr_vdf_node( output, "triangle_tags" );
3258 for( int k=0; k<5-1; k++ )
3259 cxr_vdf_printf( output,
3260 "\"row%d\" \"9 9 9 9 9 9 9 9\"\n", k );
3261 cxr_vdf_edon( output );
3263 cxr_vdf_node( output, "allowed_verts" );
3264 cxr_vdf_printf( output,
3265 "\"10\" \"-1 -1 -1 -1 -1 -1 -1 -1 -1 -1\"\n" );
3266 cxr_vdf_edon( output );
3269 cxr_vdf_edon( output
);
3272 cxr_vdf_edon( output
);
3275 cxr_vdf_node( output
, "editor");
3276 cxr_vdf_colour255( output
, "color",
3277 colours_random
[cxr_range(ctx
->brush_count
,8)]);
3279 cxr_vdf_ki32( output
, "visgroupid", ctx
->visgroupid
);
3280 cxr_vdf_ki32( output
, "visgroupshown",1);
3281 cxr_vdf_ki32( output
, "visgroupautoshown",1);
3282 cxr_vdf_edon( output
);
3284 cxr_vdf_edon( output
);
3296 * Write header information for a vmf to vdf
3298 CXR_API
void cxr_begin_vmf( cxr_vmf_context
*ctx
, cxr_vdf
*output
)
3300 cxr_vdf_node( output
, "versioninfo" );
3301 cxr_vdf_ki32( output
, "editorversion", 400 );
3302 cxr_vdf_ki32( output
, "editorbuild", 8456 );
3303 cxr_vdf_ki32( output
, "mapversion", ctx
->mapversion
);
3304 cxr_vdf_ki32( output
, "formatversion", 100 );
3305 cxr_vdf_ki32( output
, "prefab", 0 );
3306 cxr_vdf_edon( output
);
3308 cxr_vdf_node( output
, "visgroups" );
3310 for( int i
=0; i
<ctx
->visgroup_count
; i
++ )
3312 cxr_vdf_node( output
, "visgroup" );
3313 cxr_vdf_kv( output
, "name", ctx
->visgroups
[i
].name
);
3314 cxr_vdf_ki32( output
, "visgroupid", i
+1 );
3315 cxr_vdf_edon( output
);
3318 cxr_vdf_edon( output
);
3320 cxr_vdf_node( output
, "viewsettings" );
3321 cxr_vdf_ki32( output
, "bSnapToGrid", 1 );
3322 cxr_vdf_ki32( output
, "bShowGrid", 1 );
3323 cxr_vdf_ki32( output
, "bShowLogicalGrid", 0 );
3324 cxr_vdf_ki32( output
, "nGridSpacing", 64 );
3325 cxr_vdf_ki32( output
, "bShow3DGrid", 0 );
3326 cxr_vdf_edon( output
);
3328 cxr_vdf_node( output
, "world" );
3329 cxr_vdf_ki32( output
, "id", 1 );
3330 cxr_vdf_ki32( output
, "mapversion", 1 ); /* ?? */
3331 cxr_vdf_kv( output
, "classname", "worldspawn" );
3332 cxr_vdf_kv( output
, "skyname", ctx
->skyname
);
3333 cxr_vdf_ki32( output
, "maxpropscreenwidth", -1 );
3334 cxr_vdf_kv( output
, "detailvbsp", ctx
->detailvbsp
);
3335 cxr_vdf_kv( output
, "detailmaterial", ctx
->detailmaterial
);
3338 /* Fairly useless but might need in the future */
3339 CXR_API
void cxr_vmf_begin_entities( cxr_vmf_context
*ctx
, cxr_vdf
*vdf
)
3341 cxr_vdf_edon( vdf
);
3344 CXR_API
void cxr_end_vmf( cxr_vmf_context
*ctx
, cxr_vdf
*vdf
)
3349 * Write solids (and displacements) to VMF file
3351 CXR_API
void cxr_push_world_vmf( cxr_world
*world
, cxr_vmf_context
*ctx
,
3354 v3f
*verts
= cxr_ab_ptr( &world
->abverts
, 0 );
3356 /* Write all solids as VMF brushes */
3357 for( int i
=0; i
<world
->absolids
.count
; i
++ )
3359 cxr_solid
*solid
= cxr_ab_ptr(&world
->absolids
,i
);
3361 if( solid
->displacement
)
3363 if( !cxr_write_disp( solid
->pmesh
, world
, ctx
, output
) )
3365 cxr_log( "Warning: Invalid displacement\n" );
3370 cxr_vdf_node( output
, "solid" );
3371 cxr_vdf_ki32( output
, "id", ++ ctx
->brush_count
);
3373 for( int j
=0; j
<solid
->pmesh
->abpolys
.count
; j
++ )
3375 cxr_polygon
*poly
= &solid
->pmesh
->polys
[j
];
3376 cxr_loop
*ploops
= &solid
->pmesh
->loops
[poly
->loop_start
];
3378 cxr_material
*matptr
=
3379 poly
->material_id
< 0 || !world
->materials
?
3381 &world
->materials
[ poly
->material_id
];
3383 cxr_vdf_node( output
, "side" );
3384 cxr_vdf_ki32( output
, "id", ++ ctx
->face_count
);
3386 v3f tri
[3]; v2f uvs
[3];
3388 int i0
= ploops
[0].index
,
3389 i1
= ploops
[1].index
,
3390 i2
= ploops
[2].index
;
3392 v3_muls( verts
[i0
], ctx
->scale
, tri
[0] );
3393 v3_muls( verts
[i1
], ctx
->scale
, tri
[1] );
3394 v3_muls( verts
[i2
], ctx
->scale
, tri
[2] );
3396 v3_add( ctx
->offset
, tri
[0], tri
[0] );
3397 v3_add( ctx
->offset
, tri
[1], tri
[1] );
3398 v3_add( ctx
->offset
, tri
[2], tri
[2] );
3400 v2_copy( ploops
[0].uv
, uvs
[0] );
3401 v2_copy( ploops
[1].uv
, uvs
[1] );
3402 v2_copy( ploops
[2].uv
, uvs
[2] );
3404 cxr_vdf_plane( output
, "plane", tri
[2], tri
[1], tri
[0] );
3405 cxr_vdf_kv( output
, "material", matptr
->name
);
3408 cxr_calculate_axis( &tx
, tri
, uvs
,
3409 (double[2]){ matptr
->res
[0], matptr
->res
[1] });
3411 cxr_vdf_kaxis( output
, "uaxis", tx
.uaxis
, tx
.offset
[0], tx
.scale
[0]);
3412 cxr_vdf_kaxis( output
, "vaxis", tx
.vaxis
, tx
.offset
[1], tx
.scale
[1]);
3414 cxr_vdf_kdouble( output
, "rotation", 0.0 );
3415 cxr_vdf_ki32( output
, "lightmapscale", ctx
->lightmap_scale
);
3416 cxr_vdf_ki32( output
, "smoothing_groups", 0);
3418 cxr_vdf_edon( output
);
3421 cxr_vdf_node( output
, "editor" );
3422 cxr_vdf_colour255( output
, "color",
3423 colours_random
[cxr_range(ctx
->brush_count
,8)]);
3425 cxr_vdf_ki32( output
, "visgroupid", ctx
->visgroupid
);
3426 cxr_vdf_ki32( output
, "visgroupshown", 1 );
3427 cxr_vdf_ki32( output
, "visgroupautoshown", 1 );
3428 cxr_vdf_edon( output
);
3430 cxr_vdf_edon( output
);
3435 * Valve Source SDK 2015 CS:GO
3437 #define HEADER_LUMPS 64
3438 #define LUMP_WORLDLIGHTS 54
3440 #pragma pack(push,1)
3449 int fileofs
, filelen
;
3454 lumps
[ HEADER_LUMPS
];
3464 float shadow_cast_offset
[3];
3472 float constant_attn
;
3474 float quadratic_attn
;
3482 * Utility for patching BSP tools to remove -1 distance lights (we set them
3483 * like that, because we want these lights to go away)
3485 * Yes, there is no way to do this in hammer
3486 * Yes, the distance KV is unused but still gets compiled to this lump
3487 * No, Entities only compile will not do this for you
3489 CXR_API
int cxr_lightpatch_bsp( const char *path
)
3491 printf( "Lightpatch: %s\n", path
);
3493 FILE *fp
= fopen( path
, "r+b" );
3498 cxr_log( "Could not open BSP file for editing (r+b)\n" );
3504 struct header header
;
3505 fread( &header
, sizeof(struct header
), 1, fp
);
3506 struct lump
*lump
= &header
.lumps
[ LUMP_WORLDLIGHTS
];
3508 /* Read worldlight array */
3509 struct worldlight
*lights
= malloc( lump
->filelen
);
3510 fseek( fp
, lump
->fileofs
, SEEK_SET
);
3511 fread( lights
, lump
->filelen
, 1, fp
);
3513 /* Remove all marked lights */
3514 int light_count
= lump
->filelen
/ sizeof(struct worldlight
);
3517 for( int i
= 0; i
< light_count
; i
++ )
3518 if( lights
[i
].radius
>= 0.0f
)
3519 lights
[new_count
++] = lights
[i
];
3521 lump
->filelen
= new_count
*sizeof(struct worldlight
);
3523 /* Write changes back to file */
3524 fseek( fp
, lump
->fileofs
, SEEK_SET
);
3525 fwrite( lights
, lump
->filelen
, 1, fp
);
3526 fseek( fp
, 0, SEEK_SET
);
3527 fwrite( &header
, sizeof(struct header
), 1, fp
);
3530 cxr_log( "removed %d marked lights\n", light_count
-new_count
);
3538 #endif /* CXR_VALVE_MAP_FILE */
3539 #endif /* CXR_IMPLEMENTATION */