- Light patch BSP files; remove unwanted realtime effects
- Fastest VTF compressor (thanks to Richgel999 and stb)
- To come:
- - high quality level overviews automatically for CS:GO (csRadar)
-
Program structure:
File/folder Lang Purpose
#include "cxr_math.h"
#include "cxr_mem.h"
-// Utility
-// ============================================
-
static v4f colours_random[] =
{
{ 0.863, 0.078, 0.235, 0.4 },
return x % bound;
}
-
typedef struct cxr_edge cxr_edge;
typedef struct cxr_input_mesh cxr_input_mesh;
typedef struct cxr_input_loop cxr_input_loop;
i32 loop_start, loop_total;
v3f normal;
v3f center;
- i32 material_id; // -1: interior material
+ i32 material_id; /* -1: interior material (nodraw) */
}
*polys;
struct cxr_mesh
{
- struct cxr_auto_buffer
+ struct cxr_abuffer
abedges,
abloops,
abpolys,
double winding;
};
-// simple VDF writing interface
+/*
+ * Simplified VDF writing interface. No allocations or nodes, just write to file
+ */
struct cxr_vdf
{
FILE *fp;
mesh->loops = cxr_ab_ptr(&mesh->abloops, 0);
}
-// Debugging callbacks
-// =============================================================================
-
static v4f colour_error = { 1.0f, 0.0f, 0.0f, 1.0f };
static v4f colour_face_graph = { 1.0f, 1.0f, 1.0f, 0.03f };
static v4f colour_success = { 0.0f, 1.0f, 0.0f, 1.0f };
fputs(buf,stdout);
}
-static void cxr_debug_line( v3f p0, v3f p1, v4f colour )
-{
- if( cxr_line_func )
- cxr_line_func( p0, p1, colour );
-}
-
-static void cxr_debug_box( v3f p0, double sz, v4f colour )
-{
- v3f a,b,c,d,
- a1,b1,c1,d1;
- v3_add(p0, (v3f){-sz,-sz,-sz}, a);
- v3_add(p0, (v3f){-sz, sz,-sz}, b);
- v3_add(p0, (v3f){ sz, sz,-sz}, c);
- v3_add(p0, (v3f){ sz,-sz,-sz}, d);
- v3_add(p0, (v3f){-sz,-sz,sz}, a1);
- v3_add(p0, (v3f){-sz, sz,sz}, b1);
- v3_add(p0, (v3f){ sz, sz,sz}, c1);
- v3_add(p0, (v3f){ sz,-sz,sz}, d1);
-
- cxr_debug_line( a,b, colour );
- cxr_debug_line( b,c, colour );
- cxr_debug_line( c,d, colour );
- cxr_debug_line( d,a, colour );
- cxr_debug_line( a1,b1, colour );
- cxr_debug_line( b1,c1, colour );
- cxr_debug_line( c1,d1, colour );
- cxr_debug_line( d1,a1, colour );
- cxr_debug_line( a,a1, colour );
- cxr_debug_line( b,b1, colour );
- cxr_debug_line( c,c1, colour );
- cxr_debug_line( d,d1, colour );
-}
-
-static void cxr_debug_arrow( v3f p0, v3f p1, v3f normal, double sz, v4f colour )
-{
- v3f dir, tan, p2, p3;
- v3_sub(p1,p0,dir);
- v3_normalize(dir);
-
- v3_cross(dir,normal,tan);
- v3_muladds( p1,dir, -sz, p2 );
- v3_muladds( p2,tan,sz,p3 );
- cxr_debug_line( p1, p3, colour );
- v3_muladds( p2,tan,-sz,p3 );
- cxr_debug_line( p1, p3, colour );
- cxr_debug_line( p0, p1, colour );
-}
-
-// Public API
-// =========================================================================
CXR_API void cxr_context_reset(void)
{
vdf->level ++;
}
-CXR_API void cxr_vdf_edon(cxr_vdf *vdf)
+CXR_API void cxr_vdf_edon( cxr_vdf *vdf )
{
vdf->level --;
cxr_vdf_put( vdf, "}\n" );
}
-CXR_API void cxr_vdf_kv(cxr_vdf *vdf, const char *strk, const char *strv)
+CXR_API void cxr_vdf_kv( cxr_vdf *vdf, const char *strk, const char *strv )
{
cxr_vdf_printf( vdf, "\"%s\" \"%s\"\n", strk, strv );
}
-static void cxr_vdf_ki32(cxr_vdf *vdf, const char *strk, i32 val)
+/*
+ * Data-type specific Keyvalues
+ */
+static void cxr_vdf_ki32( cxr_vdf *vdf, const char *strk, i32 val )
{
cxr_vdf_printf( vdf, "\"%s\" \"%d\"\n", strk, val );
}
-static void cxr_vdf_kdouble(cxr_vdf *vdf, const char *strk, double val)
+
+static void cxr_vdf_kdouble( cxr_vdf *vdf, const char *strk, double val )
{
cxr_vdf_printf( vdf, "\"%s\" \"%f\"\n", strk, val );
}
-static void cxr_vdf_kaxis(cxr_vdf *vdf, const char *strk, v3f normal, double offset, double scale)
-{
- cxr_vdf_printf( vdf, "\"%s\" \"[%f %f %f %f] %f\"\n", strk, normal[0],normal[1],normal[2],offset,scale );
+
+static void cxr_vdf_kaxis( cxr_vdf *vdf, const char *strk,
+ v3f normal, double offset, double scale
+){
+ cxr_vdf_printf( vdf, "\"%s\" \"[%f %f %f %f] %f\"\n",
+ strk, normal[0], normal[1],normal[2], offset, scale );
}
-static void cxr_vdf_kv3f(cxr_vdf *vdf, const char *strk, v3f v)
+
+static void cxr_vdf_kv3f( cxr_vdf *vdf, const char *strk, v3f v )
{
cxr_vdf_printf( vdf, "\"%s\" \"[%f %f %f]\"\n", strk, v[0], v[1], v[2] );
}
-static void cxr_vdf_karrdouble(cxr_vdf *vdf, const char *strk, int id, double *doubles, int count)
-{
+
+static void cxr_vdf_karrdouble( cxr_vdf *vdf, const char *strk,
+ int id, double *doubles, int count
+){
cxr_vdf_put(vdf,"");
fprintf( vdf->fp, "\"%s%d\" \"", strk, id );
for( int i=0; i<count; i++ )
}
fprintf( vdf->fp, "\"\n" );
}
-static void cxr_vdf_karrv3f(cxr_vdf *vdf, const char *strk, int id, v3f *vecs, int count)
-{
+
+static void cxr_vdf_karrv3f( cxr_vdf *vdf, const char *strk,
+ int id, v3f *vecs, int count
+){
cxr_vdf_put(vdf,"");
fprintf( vdf->fp, "\"%s%d\" \"", strk, id );
for( int i=0; i<count; i++ )
{
- if( i == count-1 ) fprintf( vdf->fp, "%f %f %f", vecs[i][0], vecs[i][1], vecs[i][2] );
- else fprintf( vdf->fp, "%f %f %f ", vecs[i][0], vecs[i][1], vecs[i][2] );
+ const char *format = i == count-1? "%f %f %f": "%f %f %f ";
+ fprintf( vdf->fp, format, vecs[i][0], vecs[i][1], vecs[i][2] );
}
fprintf( vdf->fp, "\"\n" );
}
-static void cxr_vdf_plane(cxr_vdf *vdf, const char *strk, v3f a, v3f b, v3f c )
+
+static void cxr_vdf_plane( cxr_vdf *vdf, const char *strk, v3f a, v3f b, v3f c )
{
cxr_vdf_printf( vdf, "\"%s\" \"(%f %f %f) (%f %f %f) (%f %f %f)\"\n",
strk, a[0], a[1], a[2], b[0], b[1], b[2], c[0], c[1], c[2] );
}
+
static void cxr_vdf_colour255(cxr_vdf *vdf, const char *strk, v4f colour)
{
v4f scale;
v4_muls( colour, 255.0, scale );
- cxr_vdf_printf( vdf, "\"%s\" \"%d %d %d %d\"\n",strk,(int)scale[0], (int)scale[1], (int)scale[2], (int)scale[3]);
+ cxr_vdf_printf( vdf, "\"%s\" \"%d %d %d %d\"\n",
+ strk,(int)scale[0], (int)scale[1], (int)scale[2], (int)scale[3]);
+}
+
+/*
+ * Debugging line drawing
+ */
+static void cxr_debug_line( v3f p0, v3f p1, v4f colour )
+{
+ if( cxr_line_func )
+ cxr_line_func( p0, p1, colour );
+}
+
+static void cxr_debug_box( v3f p0, double sz, v4f colour )
+{
+ v3f a,b,c,d,
+ a1,b1,c1,d1;
+ v3_add(p0, (v3f){-sz,-sz,-sz}, a);
+ v3_add(p0, (v3f){-sz, sz,-sz}, b);
+ v3_add(p0, (v3f){ sz, sz,-sz}, c);
+ v3_add(p0, (v3f){ sz,-sz,-sz}, d);
+ v3_add(p0, (v3f){-sz,-sz,sz}, a1);
+ v3_add(p0, (v3f){-sz, sz,sz}, b1);
+ v3_add(p0, (v3f){ sz, sz,sz}, c1);
+ v3_add(p0, (v3f){ sz,-sz,sz}, d1);
+
+ cxr_debug_line( a,b, colour );
+ cxr_debug_line( b,c, colour );
+ cxr_debug_line( c,d, colour );
+ cxr_debug_line( d,a, colour );
+ cxr_debug_line( a1,b1, colour );
+ cxr_debug_line( b1,c1, colour );
+ cxr_debug_line( c1,d1, colour );
+ cxr_debug_line( d1,a1, colour );
+ cxr_debug_line( a,a1, colour );
+ cxr_debug_line( b,b1, colour );
+ cxr_debug_line( c,c1, colour );
+ cxr_debug_line( d,d1, colour );
}
-// Public API
-// =========================================================================
+/*
+ * Draw arrow with the tips oriented along normal
+ */
+static void cxr_debug_arrow( v3f p0, v3f p1, v3f normal, double sz, v4f colour )
+{
+ v3f dir, tan, p2, p3;
+ v3_sub(p1,p0,dir);
+ v3_normalize(dir);
+
+ v3_cross(dir,normal,tan);
+ v3_muladds( p1,dir, -sz, p2 );
+ v3_muladds( p2,tan,sz,p3 );
+ cxr_debug_line( p1, p3, colour );
+ v3_muladds( p2,tan,-sz,p3 );
+ cxr_debug_line( p1, p3, colour );
+ cxr_debug_line( p0, p1, colour );
+}
-static void cxr_debug_poly(cxr_mesh *mesh,
- cxr_polygon *poly,
- v4f colour )
+/*
+ * Draw arrows CCW around polygon, draw normal vector from center
+ */
+static void cxr_debug_poly( cxr_mesh *mesh, cxr_polygon *poly, v4f colour )
{
v3f *verts = cxr_ab_ptr( mesh->p_abverts, 0 );
}
}
-static cxr_mesh *cxr_alloc_mesh(int edge_count,
- int loop_count,
- int poly_count,
- cxr_auto_buffer *abverts)
-{
+/*
+ * abverts is a pointer to an existing vertex buffer
+ */
+static cxr_mesh *cxr_alloc_mesh( int edge_count, int loop_count, int poly_count,
+ cxr_abuffer *abverts
+){
cxr_mesh *mesh = malloc(sizeof(cxr_mesh));
cxr_ab_init(&mesh->abedges, sizeof(cxr_edge), edge_count);
cxr_ab_init(&mesh->abloops, sizeof(cxr_loop), loop_count);
return mesh;
}
-static void cxr_free_mesh(cxr_mesh *mesh)
+static void cxr_free_mesh( cxr_mesh *mesh )
{
cxr_ab_free(&mesh->abedges);
cxr_ab_free(&mesh->abloops);
/*
* Rebuilds edge data for mesh (useful to get rid of orphaned edges)
*/
-static void cxr_mesh_clean_edges(cxr_mesh *mesh)
+static void cxr_mesh_clean_edges( cxr_mesh *mesh )
{
- cxr_auto_buffer new_edges;
+ cxr_abuffer new_edges;
cxr_ab_init( &new_edges, sizeof(cxr_edge), mesh->abedges.count );
for( int i=0; i<mesh->abpolys.count; i++ )
int i0 = cxr_min(lp0->index, lp1->index),
i1 = cxr_max(lp0->index, lp1->index);
- // See if edge exists before adding it
+ /* Check if edge exists before adding */
for( int k=0; k<new_edges.count; k++ )
{
cxr_edge *edge = cxr_ab_ptr(&new_edges,k);
lp0->edge_index = new_edges.count;
cxr_edge edge = { i0, i1 };
- // --- ! ---
- // Copy extra information (sharp,freestyle.. etc) here!
+
+ /*
+ * Copy extra information from original edges
+ */
if( orig_edge_id < mesh->abedges.count )
{
edge.freestyle = 0;
}
- // --- ! ---
cxr_ab_push( &new_edges, &edge );
IL_EDGE_CREATED:;
* Remove 0-length faces from mesh (we mark them light that for deletion
* Remove all unused loops as a result of removing those faces
*/
-static void cxr_mesh_clean_faces(cxr_mesh *mesh)
+static void cxr_mesh_clean_faces( cxr_mesh *mesh )
{
- cxr_auto_buffer loops_new;
+ cxr_abuffer loops_new;
cxr_ab_init( &loops_new, sizeof(cxr_loop), mesh->abloops.count );
int new_length=0;
*
* Returns 0 if there is non-manifold geomtry (aka: not watertight)
*/
-static int cxr_mesh_link_loops(cxr_mesh *mesh)
+static int cxr_mesh_link_loops( cxr_mesh *mesh )
{
i32 *polygon_edge_map = malloc(mesh->abedges.count*2 *sizeof(i32));
}
/*
- * Add polygon to mesh based on array of loops
+ * Create new empty polygon with known loop count
+ * Must be filled and completed by the following functions!
*/
-static cxr_polygon *cxr_create_poly(
- cxr_mesh *mesh,
- cxr_loop poly[],
- int len,
- int start,
- int max )
+static int cxr_create_poly( cxr_mesh *mesh, int loop_count )
{
v3f *verts = cxr_ab_ptr( mesh->p_abverts, 0 );
- if( len < 3 )
+ if( loop_count < 3 )
{
- cxr_log( "tried to add new poly with length %d!\n", len );
-
- if( len >= 2 )
- {
- for( int j=0; j<len; j++ )
- {
- int i0 = poly[j].index,
- i1 = poly[cxr_range(j+1,len)].index;
+ cxr_log( "tried to add new poly with length %d!\n", loop_count );
+ return 0;
+ }
- cxr_debug_line( verts[i0], verts[i1], colour_error );
- }
- }
+ cxr_ab_reserve( &mesh->abpolys, 1 );
+ cxr_ab_reserve( &mesh->abloops, loop_count );
+ cxr_mesh_update( mesh );
- return NULL;
- }
+ cxr_polygon *poly = &mesh->polys[ mesh->abpolys.count ];
+
+ poly->loop_start = mesh->abloops.count;
+ poly->loop_total = 0;
+ poly->material_id = -1;
+ v3_zero( poly->center );
+
+ return 1;
+}
+
+/*
+ * Add one index to the polygon created by the above function
+ */
+static void cxr_poly_push_index( cxr_mesh *mesh, int id )
+{
+ v3f *verts = cxr_ab_ptr( mesh->p_abverts, 0 );
int nface_id = mesh->abpolys.count;
- cxr_polygon *new_face = cxr_ab_empty(&mesh->abpolys);
+ cxr_polygon *poly = &mesh->polys[ nface_id ];
- /* Calculate new face information; normal, center etc */
+ cxr_loop *new_loop = &mesh->loops[ poly->loop_start + poly->loop_total ];
- new_face->loop_start = mesh->abloops.count;
- new_face->loop_total = len;
- new_face->material_id = -1;
- v3_zero( new_face->center );
+ new_loop->poly_left = nface_id;
+ new_loop->poly_right = -1;
+ new_loop->index = id;
+ new_loop->edge_index = 0;
+ v2_zero(new_loop->uv);
- for( int j=0; j<len; j++ )
- {
- int i0 = poly[cxr_range(start+j,max)].index;
- cxr_loop *new_loop = cxr_ab_empty(&mesh->abloops);
+ v3_add( poly->center, verts[new_loop->index], poly->center );
- new_loop->poly_left = nface_id;
- new_loop->poly_right = -1;
- new_loop->index = i0;
- new_loop->edge_index = 0;
- v2_zero(new_loop->uv);
+ poly->loop_total ++;
+ mesh->abloops.count ++;
+}
- v3_add( new_face->center, verts[new_loop->index], new_face->center );
- }
- v3_divs( new_face->center, new_face->loop_total, new_face->center );
-
- cxr_loop *lp0 = cxr_ab_ptr( &mesh->abloops, new_face->loop_start ),
- *lp1 = cxr_ab_ptr( &mesh->abloops, new_face->loop_start+1 ),
- *lp2 = cxr_ab_ptr( &mesh->abloops, new_face->loop_start+2 );
+/*
+ * Finalize and commit polygon into mesh
+ */
+static void cxr_poly_finish( cxr_mesh *mesh )
+{
+ v3f *verts = cxr_ab_ptr( mesh->p_abverts, 0 );
+
+ int nface_id = mesh->abpolys.count;
+ cxr_polygon *poly = &mesh->polys[nface_id];
+
+ /* Average center and calc normal */
+
+ v3_divs( poly->center, poly->loop_total, poly->center );
+ cxr_loop *lp0 = &mesh->loops[ poly->loop_start],
+ *lp1 = &mesh->loops[ poly->loop_start+1 ],
+ *lp2 = &mesh->loops[ poly->loop_start+2 ];
tri_normal(
- verts[lp0->index], verts[lp1->index], verts[lp2->index], new_face->normal);
-
- cxr_mesh_update( mesh );
- return &mesh->polys[ nface_id ];
+ verts[lp0->index], verts[lp1->index], verts[lp2->index], poly->normal);
+
+ mesh->abpolys.count ++;
}
/*
cxr_loop *lp1 = &mesh->loops[ newpoly->loop_start+l ];
cxr_polygon *future_face = &mesh->polys[ lp1->poly_right ];
- if( reflex_edges[ lp1->edge_index ] || lp1->poly_right == loop->poly_right )
+ if( reflex_edges[ lp1->edge_index ]
+ || lp1->poly_right == loop->poly_right )
goto dont_check;
for( int m=0; m<solid_len; m++ )
for( int m=0; m<solid_len; m++ )
{
cxr_polygon *polym = &mesh->polys[solid[m]];
- if( v3_dot( polym->normal,future_face->normal) > CXR_PLANE_SIMILARITY_MAX)
+ double pdist = v3_dot( polym->normal,future_face->normal);
+
+ if( pdist > CXR_PLANE_SIMILARITY_MAX )
goto dont_check;
}
dont_check:;
}
- // Check for vertices in the new poly that exist on a current plane.
- // this condition is an invalid configuration and should not be added.
-
+ /* Check for vertices in the new polygon that exist on a current
+ * plane. This condition is invalid */
solid[ solid_len ] = loop->poly_right;
-
if( cxr_valid_solid(mesh,solid,solid_len+1 ) )
{
faces_tagged[ loop->poly_right ] = faceid;
goto search_iterate;
return solid_len;
+}
- // The current method can create some invalid configurations
- // filter those out that dont work and un-tag the faces
+struct csolid
+{
+ int start, count, edge_count;
+ v3f center;
+};
- /* TODO(harry):
- *
- * I think we have good enough filters now to ignore these,
- * probably should make them show as warnings
- *
- */
-#if 0
- if( !cxr_valid_solid( mesh, solid, solid_len ) )
+struct temp_manifold
+{
+ struct manifold_loop
{
- for( int l=0; l<solid_len; l++ )
- faces_tagged[ solid[l] ] = -1;
-
- goto IL_CANCEL_SOLID;
+ cxr_loop loop;
+ int split;
}
- for( int j=0; j<solid_len-1; j++ )
+ *loops;
+
+ int loop_count,
+ split_count;
+
+ enum manifold_status
{
- for( int k=j+1; k<solid_len; k++ )
- {
- cxr_polygon *polyj = cxr_ab_ptr(&mesh->polys, solid[j]),
- *polyk = cxr_ab_ptr(&mesh->polys, solid[k]);
-
- if( v3_dot( polyj->normal, polyk->normal ) > CXR_PLANE_SIMILARITY_MAX )
- {
- for( int l=0; l<solid_len; l++ )
- faces_tagged[ solid[l] ] = -1;
-
- goto IL_CANCEL_SOLID;
- }
- }
+ k_manifold_err,
+ k_manifold_none,
+ k_manifold_fragmented,
+ k_manifold_complete,
}
- /*
- */
-#endif
-}
-
+ status;
+};
-/*
- * Return the best availible solid from mesh, and patch the existing mesh to
- * fill the gap where the new mesh left it.
+/*
+ * Create polygon from entire manifold structure.
*
- * Returns NULL if shape is already convex or empty.
- * This function will not preserve edge data such as freestyle, sharp etc.
+ * Must be completely co-planar
*/
-static cxr_mesh *cxr_pull_best_solid(
- cxr_mesh *mesh,
- int preserve_more_edges,
- u32 *error )
+static void cxr_create_poly_full( cxr_mesh *mesh, struct temp_manifold *src )
{
- if( !cxr_mesh_link_loops(mesh) )
+ if( cxr_create_poly( mesh, src->loop_count ) )
{
- cxr_log( "non-manifold edges are in the mesh: "
- "implicit internal geometry does not have full support\n" );
+ for( int l=0; l<src->loop_count; l++ )
+ cxr_poly_push_index( mesh, src->loops[ l ].loop.index);
- return NULL;
+ cxr_poly_finish( mesh );
}
-
- v3f *verts = cxr_ab_ptr( mesh->p_abverts, 0 );
- int *edge_tagged = cxr_mesh_reflex_edges( mesh );
- int *vertex_tagged = cxr_mesh_reflex_vertices( mesh );
+}
- /*
- * Connect all marked vertices that share an edge
- */
+/*
+ * Links up all edges into a potential new manifold
+ *
+ * The return status can be:
+ * (err): Critical programming error
+ * none: No manifold to create
+ * fragmented: Multiple sections exist, not just one
+ * complete: Optimial manifold was created
+ */
+static void cxr_link_manifold(
+ cxr_mesh *mesh,
+ struct csolid *solid,
+ int *solid_buffer,
+ struct temp_manifold *manifold
+ )
+{
+ cxr_loop **edge_list = malloc( sizeof(*edge_list) * solid->edge_count );
- int *edge_important = malloc(mesh->abedges.count*sizeof(int));
- for( int i=0; i< mesh->abedges.count; i++ )
- edge_important[i] = 0;
+ int init_reverse = 0;
+ int unique_edge_count = 0;
- for( int i=0; i<mesh->abpolys.count; i ++ )
+ /* Gather list of unique edges */
+
+ for( int j=0; j<solid->count; j++ )
{
- cxr_polygon *poly = &mesh->polys[i];
- int not_tagged = -1,
- tag_count = 0;
+ cxr_polygon *poly = &mesh->polys[ solid_buffer[solid->start+j] ];
- for( int j=0; j<poly->loop_total; j++ )
+ for( int k=0; k<poly->loop_total; k++ )
{
- cxr_loop *loop = &mesh->loops[ poly->loop_start+j ];
+ cxr_loop *loop = &mesh->loops[ poly->loop_start+k ];
- if( !edge_tagged[ loop->edge_index ] )
+ for( int l=0; l<unique_edge_count; l++ )
+ if( edge_list[l]->edge_index == loop->edge_index )
+ goto skip_edge;
+
+ for( int l=0; l<solid->count; l++ )
+ if( loop->poly_right == solid_buffer[solid->start+l] )
+ goto skip_edge;
+
+ edge_list[ unique_edge_count ] = loop;
+
+ if( unique_edge_count == 0 )
{
- if( not_tagged == -1 )
- not_tagged = loop->edge_index;
- else
- goto edge_unimportant;
+ cxr_edge *edgeptr = &mesh->edges[ loop->edge_index ];
+ if( edgeptr->i1 == loop->index )
+ init_reverse = 1;
}
- }
-
- if( not_tagged != -1 )
- edge_important[not_tagged]=1;
- edge_unimportant:;
+ unique_edge_count ++;
+ skip_edge:;
+ }
}
-
- // Connect edges that have verts tagged, but is not a hot edge
- for( int i=0; i<mesh->abedges.count; i ++ )
+
+ if( unique_edge_count == 0 )
{
- if( edge_important[i] && preserve_more_edges ) continue;
-
- cxr_edge *edge = &mesh->edges[i];
- if( vertex_tagged[edge->i0] && vertex_tagged[edge->i1] )
- edge_tagged[i] = 1;
+ free( edge_list );
+ manifold->status = k_manifold_none;
+ return;
}
+
+ /* Link edges together to form manifold */
+ manifold->loops = malloc( solid->edge_count*sizeof(struct manifold_loop));
+ manifold->split_count = 0;
+ manifold->loop_count = 0;
- free( edge_important );
+ cxr_edge *current = &mesh->edges[ edge_list[0]->edge_index ];
-#if 0
- for( int i=0; i<vert_buffer->count; i++ )
- if( vertex_tagged[i] )
- cxr_debug_box( vertices[i], 0.03, (v4f){0.0,0.0,0.0,1.0});
+ int endpt = (!init_reverse)? current->i0: current->i1,
+ start = endpt,
+ curface = edge_list[0]->poly_left;
- for( int i=0; i < mesh->edges.count; i++ )
+ manifold_continue:
+ for( int j=0; j<unique_edge_count; j++ )
{
- cxr_edge *edge = cxr_ab_ptr( &mesh->edges, i );
- if( edge_tagged[i] )
- cxr_debug_line( vertices[ edge->i0 ], vertices[ edge->i1 ], (v4f){0.0,0.0,0.0,1.0});
+ cxr_edge *other = &mesh->edges[ edge_list[j]->edge_index ];
+ if( other == current )
+ continue;
- if( hot_edge[i] )
- cxr_debug_line( vertices[ edge->i0 ], vertices[ edge->i1 ], (v4f){0.0,1.0,1.0,1.0});
- }
-#endif
+ if( other->i0 == endpt || other->i1 == endpt )
+ {
+ current = other;
+ int lastpt = endpt;
- // count regions
- int *faces_tagged = malloc(mesh->abpolys.count*sizeof(int));
- for( int i=0; i<mesh->abpolys.count; i++ )
- faces_tagged[i] = -1;
-
- int *solid_buffer = malloc( mesh->abpolys.count*sizeof(int) );
- int solid_buffer_len = 0;
- struct csolid
- {
- int start,count,edge_count;
- v3f center;
- }
- *candidates = malloc( mesh->abpolys.count *sizeof(struct csolid) );
- int candidate_count = 0;
-
- struct tedge
- {
- int i0, i1;
- }
- *edge_references = malloc( mesh->abedges.count *sizeof(struct tedge) );
-
- for( int i=0; i<mesh->abpolys.count; i++ )
- {
- if( faces_tagged[i] != -1 ) continue;
- faces_tagged[i] = i;
-
- int *solid = &solid_buffer[ solid_buffer_len ];
- int solid_len = 0;
-
- solid[solid_len++] = i;
-
- int search_start = 0;
-
- // Iterative search that connects regions of planes governed by rules:
- // - edge can add other face if the edge has less than two reflexes
- // - the face can no longer be used in future searches
+ if( other->i0 == endpt ) endpt = current->i1;
+ else endpt = current->i0;
- IL_SEARCH_CONTINUE:;
+ struct manifold_loop *ml = &manifold->loops[ manifold->loop_count ++ ];
+
+ if( curface==edge_list[j]->poly_left )
+ {
+ ml->split = 1;
+ manifold->split_count ++;
+ }
+ else
+ ml->split = 0;
+
+ ml->loop.edge_index = edge_list[j]->edge_index;
+ ml->loop.poly_left = edge_list[j]->poly_left;
+ ml->loop.index = lastpt;
+ ml->loop.poly_right = edge_list[j]->poly_right;
- int changed = 0;
- for( int j=search_start; j<solid_len; j++ )
- {
- cxr_polygon *poly = &mesh->polys[solid[j]];
+ curface = edge_list[j]->poly_left;
- for( int k=0; k<poly->loop_total; k++ )
+ if(endpt == start)
{
- cxr_loop *loop = &mesh->loops[poly->loop_start+k];
- cxr_edge *edge = &mesh->edges[loop->edge_index];
-
- if( faces_tagged[ loop->poly_right ] == -1 )
- {
- if( !edge_tagged[loop->edge_index] )
- {
- // TODO(harry):
- //
- // Need to look ahead 1 step to make sure he does not want
- // to add any more planes that are coplanar with some of
- // our existing group
- //
- // This can sort out SOME invalid configs, but not all.
- // It would be nice to find a more robust clustering algorithm for this.
- //
-
- cxr_polygon *poly_to_add = &mesh->polys[loop->poly_right];
-
- if( cxr_solid_overlap(mesh, poly, poly_to_add, loop->edge_index, 0 ))
- goto IL_SKIP_PLANE_ADD;
+ if( manifold->loop_count < unique_edge_count )
+ manifold->status = k_manifold_fragmented;
+ else
+ manifold->status = k_manifold_complete;
- for( int l=0; l < poly_to_add->loop_total; l++ )
- {
- cxr_loop *loop1 = &mesh->loops[poly_to_add->loop_start+l];
- cxr_polygon *future_face = &mesh->polys[loop1->poly_right];
+ goto manifold_complete;
+ }
- if( edge_tagged[ loop1->edge_index ] || loop1->poly_right == loop->poly_right )
- goto IL_SKIP_SIMILAR_PLANES;
+ goto manifold_continue;
+ }
+ }
+
+ /* Incomplete links */
+ manifold->status = k_manifold_err;
- for( int m=0; m<solid_len; m++ )
- if( solid[m] == loop1->poly_right )
- goto IL_SKIP_SIMILAR_PLANES;
-
- for( int m=0; m<solid_len; m++ )
- {
- cxr_polygon *polym = &mesh->polys[solid[m]];
- if( v3_dot( polym->normal,future_face->normal) > CXR_PLANE_SIMILARITY_MAX)
- goto IL_SKIP_PLANE_ADD;
- }
+manifold_complete:
- IL_SKIP_SIMILAR_PLANES:;
- }
+ free( edge_list );
+ return;
+}
- // Check for vertices in the new poly that exist on a current plane.
- // this condition is an invalid configuration and should not be added.
+/*
+ * Reconstruct implied internal geometry where the manifold doesn't have
+ * enough information (vertices) to create a full result.
+ */
+static int cxr_build_implicit_geo( cxr_mesh *mesh, int new_polys, int start )
+{
+ for( int i=0; i<new_polys-2; i++ )
+ {
+ for( int j=i+1; j<new_polys-1; j++ )
+ {
+ for( int k=j+1; k<new_polys; k++ )
+ {
+ cxr_polygon *ptri = &mesh->polys[ start+i ],
+ *ptrj = &mesh->polys[ start+j ],
+ *ptrk = &mesh->polys[ start+k ];
+
+ v4f planei, planej, planek;
+ normal_to_plane(ptri->normal,ptri->center,planei);
+ normal_to_plane(ptrj->normal,ptrj->center,planej);
+ normal_to_plane(ptrk->normal,ptrk->center,planek);
+
+ v3f intersect;
- solid[ solid_len ] = loop->poly_right;
+ if( plane_intersect(planei,planej,planek,intersect) )
+ {
+ /* Make sure the point is inside the convex region */
+
+ int point_valid = 1;
+ for( int l=0; l<mesh->abpolys.count; l++ )
+ {
+ cxr_polygon *ptrl = &mesh->polys[l];
+ v4f planel;
+ normal_to_plane(ptrl->normal, ptrl->center, planel);
- if( cxr_valid_solid(mesh,solid,solid_len+1 ) )
+ if( plane_polarity( planel, intersect ) > 0.01 )
{
- faces_tagged[ loop->poly_right ] = i;
- changed = 1;
- solid_len ++;
+ cxr_log( "degen vert, planes %d, %d, %d [max:%d]\n",
+ i,j,k, new_polys );
+
+ cxr_debug_poly( mesh, ptri, colours_random[3] );
+ cxr_debug_poly( mesh, ptrj, colours_random[1] );
+ cxr_debug_poly( mesh, ptrk, colours_random[2] );
+
+ return 0;
}
}
+
+ /* Extend faces to include this vert */
+
+ int nvertid = mesh->p_abverts->count;
+ cxr_ab_push( mesh->p_abverts, intersect );
- IL_SKIP_PLANE_ADD:;
+ ptrj->loop_start += 1;
+ ptrk->loop_start += 2;
+
+ cxr_ab_reserve( &mesh->abloops, 3);
+
+ int newi = ptri->loop_start+ptri->loop_total,
+ newj = ptrj->loop_start+ptrj->loop_total,
+ newk = ptrk->loop_start+ptrk->loop_total;
+
+ cxr_loop
+ *lloopi = cxr_ab_empty_at(&mesh->abloops, newi),
+ *lloopj = cxr_ab_empty_at(&mesh->abloops, newj),
+ *lloopk = cxr_ab_empty_at(&mesh->abloops, newk);
+
+ lloopi->index = nvertid;
+ lloopi->edge_index = 0;
+ lloopi->poly_left = start + i;
+ lloopi->poly_right = -1;
+
+ lloopj->index = nvertid;
+ lloopj->poly_left = start + j;
+ lloopj->edge_index = 0;
+ lloopj->poly_right = -1;
+
+ lloopk->index = nvertid;
+ lloopk->edge_index = 0;
+ lloopk->poly_left = start + k;
+ lloopk->poly_right = -1;
+
+ v2_zero(lloopi->uv);
+ v2_zero(lloopj->uv);
+ v2_zero(lloopk->uv);
+
+ ptri->loop_total ++;
+ ptrj->loop_total ++;
+ ptrk->loop_total ++;
+
+ double qi = 1.0/(double)ptri->loop_total,
+ qj = 1.0/(double)ptrj->loop_total,
+ qk = 1.0/(double)ptrk->loop_total;
+
+ /* Adjust centers of faces */
+ v3_lerp( ptri->center, intersect, qi, ptri->center );
+ v3_lerp( ptrj->center, intersect, qj, ptrj->center );
+ v3_lerp( ptrk->center, intersect, qk, ptrk->center );
}
}
}
- search_start = solid_len;
- if(changed)
- goto IL_SEARCH_CONTINUE;
-
- // The current method can create some invalid configurations
- // filter those out that dont work and un-tag the faces
-
- /* TODO(harry):
- *
- * I think we have good enough filters now to ignore these,
- * probably should make them show as warnings
- *
- */
- if( !cxr_valid_solid( mesh, solid, solid_len ) )
- {
- for( int l=0; l<solid_len; l++ )
- faces_tagged[ solid[l] ] = -1;
-
- goto IL_CANCEL_SOLID;
- }
- for( int j=0; j<solid_len-1; j++ )
+ }
+
+ return 1;
+}
+
+/*
+ * Convexer's main algorithm
+ *
+ * Return the best availible convex solid from mesh, and patch the existing mesh
+ * to fill the gap where the new mesh left it.
+ *
+ * Returns NULL if shape is already convex or empty.
+ * This function will not preserve edge data such as freestyle, sharp etc.
+ */
+static cxr_mesh *cxr_pull_best_solid(
+ cxr_mesh *mesh,
+ int preserve_more_edges,
+ u32 *error )
+{
+ if( !cxr_mesh_link_loops(mesh) )
+ {
+ cxr_log( "non-manifold edges are in the mesh: "
+ "implicit internal geometry does not have full support\n" );
+
+ return NULL;
+ }
+
+ int *edge_tagged = cxr_mesh_reflex_edges( mesh );
+ int *vertex_tagged = cxr_mesh_reflex_vertices( mesh );
+
+ /*
+ * Connect all marked vertices that share an edge
+ */
+
+ int *edge_important = malloc(mesh->abedges.count*sizeof(int));
+ for( int i=0; i< mesh->abedges.count; i++ )
+ edge_important[i] = 0;
+
+ for( int i=0; i<mesh->abpolys.count; i ++ )
+ {
+ cxr_polygon *poly = &mesh->polys[i];
+ int not_tagged = -1,
+ tag_count = 0;
+
+ for( int j=0; j<poly->loop_total; j++ )
{
- for( int k=j+1; k<solid_len; k++ )
+ cxr_loop *loop = &mesh->loops[ poly->loop_start+j ];
+
+ if( !edge_tagged[ loop->edge_index ] )
{
- cxr_polygon *polyj = &mesh->polys[solid[j]],
- *polyk = &mesh->polys[ solid[k] ];
-
- if( v3_dot( polyj->normal, polyk->normal ) > CXR_PLANE_SIMILARITY_MAX )
- {
- for( int l=0; l<solid_len; l++ )
- faces_tagged[ solid[l] ] = -1;
-
- goto IL_CANCEL_SOLID;
- }
+ if( not_tagged == -1 )
+ not_tagged = loop->edge_index;
+ else
+ goto edge_unimportant;
}
}
- /*
- */
+
+ if( not_tagged != -1 )
+ edge_important[not_tagged]=1;
- // Add entry
+ edge_unimportant:;
+ }
+
+ /*
+ * Connect edges where both vertices are reflex, only if we are not
+ * preserving them
+ */
+ for( int i=0; i<mesh->abedges.count; i ++ )
+ {
+ if( edge_important[i] && preserve_more_edges ) continue;
+
+ cxr_edge *edge = &mesh->edges[i];
+ if( vertex_tagged[edge->i0] && vertex_tagged[edge->i1] )
+ edge_tagged[i] = 1;
+ }
+
+ free( edge_important );
+
+ int *faces_tagged = malloc(mesh->abpolys.count*sizeof(int));
+ for( int i=0; i<mesh->abpolys.count; i++ )
+ faces_tagged[i] = -1;
+
+ struct csolid *candidates;
+ int *solid_buffer = malloc( mesh->abpolys.count*sizeof(int) ),
+ solid_buffer_len = 0,
+ candidate_count = 0;
+
+ candidates = malloc( mesh->abpolys.count *sizeof(struct csolid) );
+
+ /*
+ * Create a valid, non-overlapping solid for every face present in the mesh
+ */
+ for( int i=0; i<mesh->abpolys.count; i++ )
+ {
+ if( faces_tagged[i] != -1 ) continue;
+ faces_tagged[i] = i;
+
+ int *solid = &solid_buffer[ solid_buffer_len ];
+ int len = cxr_buildsolid( mesh, i, solid, edge_tagged, faces_tagged );
+
+ /* add entry */
struct csolid *csolid = &candidates[candidate_count ++];
csolid->start = solid_buffer_len;
- csolid->count = solid_len;
+ csolid->count = len;
csolid->edge_count = 0;
v3_zero( csolid->center );
- for( int j=0; j<solid_len; j++ )
+ for( int j=0; j<len; j++ )
{
cxr_polygon *polyj = &mesh->polys[ solid[j] ];
v3_add( polyj->center, csolid->center, csolid->center );
csolid->edge_count += polyj->loop_total;
}
- v3_divs( csolid->center, solid_len, csolid->center );
-
- solid_buffer_len += solid_len;
-
- IL_CANCEL_SOLID:;
+ v3_divs( csolid->center, len, csolid->center );
+ solid_buffer_len += len;
}
- free( edge_references );
-
- // Create all candidates who have one or less non-manifolds edges
- // Loop each candidate, determine the manifold, and pick the best one
+ free( edge_tagged );
+ free( vertex_tagged );
+ free( faces_tagged );
+ /*
+ * Choosing the best solid: most defined manifold
+ */
struct csolid *best_solid = NULL;
int fewest_manifold_splits = INT32_MAX;
- cxr_loop *best_manifold = malloc( mesh->abloops.count *sizeof(cxr_loop) );
- int *best_manifold_splits = malloc( mesh->abloops.count *sizeof(int) );
- int best_manifold_len = 0;
+ struct temp_manifold best_manifold = { .loops = NULL, .loop_count = 0 };
int max_solid_faces = 0;
- /*
- int *edge_list = malloc( mesh->edges.count *sizeof(int) );
- int *edge_lefts = malloc( mesh->edges.count *sizeof(int) );
- */
- cxr_loop **edge_list = malloc( sizeof(*edge_list) *mesh->abedges.count);
-
- cxr_loop *manifold = malloc(mesh->abedges.count*2*sizeof(cxr_loop));
- int *splits = malloc(mesh->abedges.count*2*sizeof(int));
-
for( int i=0; i<candidate_count; i++ )
{
struct csolid *solid = &candidates[i];
if( solid->count <= 2 )
continue;
-
- int init_reverse = 0;
- int unique_edge_count = 0;
-
- for( int j=0; j<solid->count; j++ )
- {
- cxr_polygon *poly = cxr_ab_ptr(&mesh->abpolys, solid_buffer[solid->start+j]);
-
- for( int k=0; k<poly->loop_total; k++ )
- {
- cxr_loop *loop = cxr_ab_ptr(&mesh->abloops, poly->loop_start+k);
-
- for( int l=0; l<unique_edge_count; l++ )
- if( edge_list[l]->edge_index == loop->edge_index )
- goto IL_EDGE_ALREADY_PRESENT;
-
- // Check if right edge references a polygon that is not
- // present inside the current solid candidate
- for( int l=0; l<solid->count; l++ )
- if( loop->poly_right == solid_buffer[solid->start+l] )
- goto IL_EDGE_ALREADY_PRESENT;
-
- edge_list[ unique_edge_count ] = loop;
-
- if( unique_edge_count == 0 )
- {
- cxr_edge *edgeptr = cxr_ab_ptr(&mesh->abedges, loop->edge_index);
- if( edgeptr->i1 == loop->index )
- init_reverse = 1;
- }
-
- unique_edge_count ++;
- IL_EDGE_ALREADY_PRESENT:;
- }
- }
-
- // This solid is already fully connected
- if( unique_edge_count == 0 )
- continue;
- // Link edges together to create new manifold
- // Corners are created when two edges share a polygon face
- // This way we can split it into regions
+ struct temp_manifold manifold;
+ cxr_link_manifold( mesh, solid, solid_buffer, &manifold);
- for( int j=0; j<mesh->p_abverts->count; j++ )
- vertex_tagged[j] = -1;
-
- // Start with a loop edge which was tagged
- cxr_edge *current = &mesh->edges[edge_list[0]->edge_index];
-
- int endpt = (!init_reverse)? current->i0: current->i1,
- start = endpt,
- curface = edge_list[0]->poly_left;
-
- int manifold_len = 0;
- int split_count = 0;
-
- IL_MANIFOLD_CONTINUE:
- for( int j=0; j<unique_edge_count; j++ )
- {
- cxr_edge *other = &mesh->edges[ edge_list[j]->edge_index ];
- if( other == current )
- continue;
-
- if( other->i0 == endpt || other->i1 == endpt )
- {
- current = other;
- int lastpt = endpt;
-
- if( other->i0 == endpt ) endpt = current->i1;
- else endpt = current->i0;
-
- if( curface==edge_list[j]->poly_left )
- {
- splits[ manifold_len ] = 1;
- split_count ++;
- }
- else
- splits[ manifold_len ] = 0;
-
- // Append to intermidiary manifold
- manifold[ manifold_len ].edge_index = edge_list[j]->edge_index;
- manifold[ manifold_len ].poly_left = edge_list[j]->poly_left;
- manifold[ manifold_len ].index = lastpt;
- manifold[ manifold_len ].poly_right = edge_list[j]->poly_right;
- manifold_len ++;
-
- curface = edge_list[j]->poly_left;
-
- if(endpt == start) goto IL_MANIFOLD_COMPLETE;
- goto IL_MANIFOLD_CONTINUE;
- }
- }
- cxr_log( "Failed to link manifold, count: %d\n", manifold_len );
-
- for( int j=0; j<solid->count; j++ )
- {
- cxr_log( "p%d\n", solid_buffer[solid->start+j] );
- cxr_polygon *poly = &mesh->polys[ solid_buffer[solid->start+j] ];
- cxr_debug_poly( mesh, poly, (v4f){0.2,0.0,0.0,1.0} );
- }
-
- for( int j=0; j<unique_edge_count; j++ )
+ if( manifold.status == k_manifold_err )
{
- cxr_edge *uedge = &mesh->edges[ edge_list[j]->edge_index ];
- cxr_debug_line( verts[uedge->i0], verts[uedge->i1],
- (v4f){0.4,0.0,0.0,1.0});
+ *error = CXR_ERROR_BAD_MANIFOLD;
+ free(solid_buffer);
+ free(candidates);
+ free(manifold.loops);
+ free(best_manifold.loops);
+ return NULL;
}
- for( int j=0; j<manifold_len-1; j++ )
+ if( manifold.status == k_manifold_complete )
{
- cxr_loop *lp0 = &manifold[j],
- *lp1 = &manifold[cxr_range(j+1,manifold_len)];
-
- cxr_debug_line(verts[lp0->index],verts[lp1->index], colour_error );
- }
-
- cxr_debug_mesh( mesh, (v4f){0.0,0.0,0.0, 0.9} );
- *error = CXR_ERROR_BAD_MANIFOLD;
-
- free(edge_list);
- free(manifold);
- free(splits);
- free(edge_tagged);
- free(vertex_tagged);
- free(faces_tagged);
- free(solid_buffer);
- free(candidates);
- free(best_manifold);
- free(best_manifold_splits);
- return NULL;
-
- IL_MANIFOLD_COMPLETE:;
-
- if( manifold_len < unique_edge_count )
- continue;
- else
- {
- if( split_count < fewest_manifold_splits )
+ if( manifold.split_count < fewest_manifold_splits )
{
- fewest_manifold_splits = split_count;
+ fewest_manifold_splits = manifold.split_count;
best_solid = solid;
- for( int j=0; j<manifold_len; j++ )
- {
- best_manifold[j] = manifold[j];
- best_manifold_splits[j] = splits[j];
- }
- best_manifold_len = manifold_len;
+ free( best_manifold.loops );
+ best_manifold = manifold;
+ continue;
}
}
+
+ if( manifold.status != k_manifold_none )
+ free( manifold.loops );
}
- free(edge_list);
- free(manifold);
- free(splits);
-
if( max_solid_faces < 2 )
{
*error = CXR_ERROR_NO_SOLIDS;
- free(edge_tagged);
- free(vertex_tagged);
- free(faces_tagged);
free(solid_buffer);
free(candidates);
- free(best_manifold);
- free(best_manifold_splits);
+ free(best_manifold.loops);
return NULL;
}
if( best_solid != NULL )
{
- cxr_mesh *pullmesh =
- cxr_alloc_mesh( best_solid->edge_count, best_solid->edge_count, best_solid->count, mesh->p_abverts );
+ cxr_mesh *pullmesh = cxr_alloc_mesh( best_solid->edge_count,
+ best_solid->edge_count,
+ best_solid->count,
+ mesh->p_abverts );
- // Add existing faces to pullsolid, and delete from main mesh
for( int i=0; i<best_solid->count; i++ )
{
int nface_id = pullmesh->abpolys.count;
+ int exist_plane_id = solid_buffer[best_solid->start+i];
- cxr_polygon *exist_face = &mesh->polys[ solid_buffer[best_solid->start+i] ];
- cxr_polygon *new_face = cxr_ab_empty( &pullmesh->abpolys );
+ cxr_polygon *exist_face = &mesh->polys[ exist_plane_id ],
+ *new_face = cxr_ab_empty( &pullmesh->abpolys );
*new_face = *exist_face;
new_face->loop_start = pullmesh->abloops.count;
for( int j=0; j<exist_face->loop_total; j++ )
{
- cxr_loop *exist_loop = cxr_ab_ptr(&mesh->abloops, exist_face->loop_start+j);
- cxr_loop *new_loop = cxr_ab_empty(&pullmesh->abloops);
+ cxr_loop *exist_loop = &mesh->loops[ exist_face->loop_start+j ],
+ *new_loop = cxr_ab_empty(&pullmesh->abloops);
new_loop->index = exist_loop->index;
new_loop->poly_left = nface_id;
if( fewest_manifold_splits != 0 )
{
- // This is a really strange observation, however it *seems* to apply to the kinds
- // of geometry we are dealing with. If the split count is odd, the manifold can be
- // created easily, no folding required.
- //
- // When it is even, it appears that internal implicit geometry is required, so we
- // need to fold the loops we create. Its really weird, but for some reason works on
- // the geometry rules we've defined.
- // TODO(harry): Find a well defined rule here.
-
+ /* Unusual observation:
+ * If the split count is odd, the manifold can be created easily
+ *
+ * If it is even, implicit internal geometry is needed to be
+ * constructed. So the manifold gets folded as we create it segment
+ * by segment.
+ *
+ * I'm not sure if this is a well defined rule of geometry, but seems
+ * to apply to the data we care about.
+ */
int collapse_used_segments = (u32)fewest_manifold_splits & 0x1? 0: 1;
- IL_MANIFOLD_BUILD_REPEAT:
+ manifold_repeat:
- for( int j=0; j<best_manifold_len; j++ )
+ for( int j=0; j < best_manifold.loop_count; j++ )
{
- if( best_manifold_splits[j] )
+ if( !best_manifold.loops[j].split ) continue;
+
+ cxr_loop *loop = &best_manifold.loops[j].loop;
+
+ for( int k=1; k< best_manifold.loop_count; k++ )
{
- cxr_loop *loop = &best_manifold[j];
+ int index1 = cxr_range(j+k, best_manifold.loop_count );
+ cxr_loop *loop1 = &best_manifold.loops[index1].loop;
- for( int k=1; k<best_manifold_len; k++ )
+ if( best_manifold.loops[index1].split )
{
- int index1 = cxr_range(j+k,best_manifold_len);
- cxr_loop *loop1 = &best_manifold[index1];
-
- if( best_manifold_splits[index1] )
- {
- if( k==1 )
- break;
+ if( k==1 )
+ break;
- new_polys ++;
+ new_polys ++;
- if( new_polys > best_manifold_len )
+ if( new_polys > best_manifold.loop_count )
+ {
+ cxr_log( "Programming error: Too many new polys!\n" );
+ exit(1);
+ }
+
+ if( cxr_create_poly( pullmesh, k+1 ) )
+ {
+ for( int l=0; l<k+1; l++ )
{
- cxr_log( "Programming error: Too many new polys!\n" );
- exit(1);
+ int i0 = cxr_range(j+l, best_manifold.loop_count ),
+ index = best_manifold.loops[ i0 ].loop.index;
+
+ cxr_poly_push_index( pullmesh, index );
}
+ cxr_poly_finish( pullmesh );
+ }
- cxr_create_poly( pullmesh, best_manifold, k+1, j, best_manifold_len );
+ /* Collapse down manifold */
+ if( collapse_used_segments )
+ {
+ best_manifold.loops[j].split = 0;
+ best_manifold.loops[index1].split = 0;
- // Remove new section from manifold
- if( collapse_used_segments )
+ int new_length = (best_manifold.loop_count-(k-1));
+
+ struct temp_manifold new_manifold = {
+ .loop_count = new_length
+ };
+ new_manifold.loops =
+ malloc( new_length*sizeof(*new_manifold.loops) );
+
+ for( int l=0; l<new_length; l ++ )
{
- best_manifold_splits[j] = 0;
- best_manifold_splits[index1] = 0;
-
- int new_length = (best_manifold_len-(k-1));
-
- cxr_loop *new_manifold = malloc( new_length*sizeof(cxr_loop) );
- int *new_manifold_splits = malloc( new_length*sizeof(int) );
-
- for( int l=0; l<new_length; l ++ )
- {
- int i_src = cxr_range( j+k+l, best_manifold_len );
- new_manifold[l] = best_manifold[i_src];
- new_manifold_splits[l] = best_manifold_splits[i_src];
- }
-
- free( best_manifold );
- free( best_manifold_splits );
- best_manifold = new_manifold;
- best_manifold_splits = new_manifold_splits;
-
- best_manifold_len = new_length;
-
- goto IL_MANIFOLD_BUILD_REPEAT;
+ int i_src = cxr_range( j+k+l, best_manifold.loop_count);
+ new_manifold.loops[l] = best_manifold.loops[i_src];
}
- j=j+k-1;
- break;
+ free( best_manifold.loops );
+ best_manifold = new_manifold;
+
+ goto manifold_repeat;
}
+
+ j=j+k-1;
+ break;
}
}
}
- if( best_manifold_len && collapse_used_segments )
+ if( best_manifold.loop_count && collapse_used_segments )
{
- cxr_create_poly( pullmesh, best_manifold, best_manifold_len, 0, best_manifold_len );
+ cxr_create_poly_full( pullmesh, &best_manifold );
new_polys ++;
}
}
else
{
- cxr_create_poly( pullmesh, best_manifold, best_manifold_len, 0, best_manifold_len );
+ cxr_create_poly_full( pullmesh, &best_manifold );
new_polys = 1;
}
- // vert_buffer may be reallocated by the next section of code,
- // force a NULLref on vertices to catch any errors
- verts = NULL;
- struct cxr_auto_buffer *abverts = mesh->p_abverts;
-
- // Implicit geometry reconstruction
- // If there's 3 or more planes, collide them together to see if any new
- // vertices need to be created on the mesh
if( new_polys >= 3 )
{
- for( int i=0; i<new_polys-2; i++ )
+ if( !cxr_build_implicit_geo( pullmesh, new_polys, pullmesh_new_start ))
{
- for( int j=i+1; j<new_polys-1; j++ )
- {
- for( int k=j+1; k<new_polys; k++ )
- {
- cxr_polygon *ptri = &pullmesh->polys[ pullmesh_new_start+i ],
- *ptrj = &pullmesh->polys[ pullmesh_new_start+j ],
- *ptrk = &pullmesh->polys[ pullmesh_new_start+k ];
-
- v4f planei, planej, planek;
- normal_to_plane(ptri->normal,ptri->center,planei);
- normal_to_plane(ptrj->normal,ptrj->center,planej);
- normal_to_plane(ptrk->normal,ptrk->center,planek);
-
- v3f intersect;
-
- if( plane_intersect(planei,planej,planek,intersect) )
- {
- // cxr_debug_box( intersect, 0.05, colour_error );
-
- // Make sure this point is within the convex region, otherwise treat
- // it as a degenerate case
-
- int point_valid = 1;
- for( int l=0; l<pullmesh->abpolys.count; l++ )
- {
- cxr_polygon *ptrl = &pullmesh->polys[l];
- v4f planel;
-
- normal_to_plane(ptrl->normal, ptrl->center, planel);
-
- if( plane_polarity( planel, intersect ) > 0.01 )
- {
- cxr_log( "degen vert, planes %d, %d, %d [max:%d]\n", i,j,k, new_polys );
- *error = CXR_ERROR_DEGEN_IMPLICIT;
-
- cxr_debug_poly( pullmesh, ptri, colours_random[3] );
- cxr_debug_poly( pullmesh, ptrj, colours_random[1] );
- cxr_debug_poly( pullmesh, ptrk, colours_random[2] );
-
- point_valid = 0;
- break;
- }
- }
-
- if( !point_valid ) continue;
-
- // Extend faces to include this point
- int nvertid = abverts->count;
- cxr_ab_push( abverts, intersect );
-
- ptrj->loop_start += 1;
- ptrk->loop_start += 2;
-
- cxr_ab_reserve( &pullmesh->abloops, 3);
-
- int newi = ptri->loop_start+ptri->loop_total,
- newj = ptrj->loop_start+ptrj->loop_total,
- newk = ptrk->loop_start+ptrk->loop_total;
-
- cxr_loop
- *lloopi = cxr_ab_empty_at(&pullmesh->abloops, newi),
- *lloopj = cxr_ab_empty_at(&pullmesh->abloops, newj),
- *lloopk = cxr_ab_empty_at(&pullmesh->abloops, newk);
-
- lloopi->index = nvertid;
- lloopi->edge_index = 0;
- lloopi->poly_left = pullmesh_new_start+i;
- lloopi->poly_right = -1;
-
- lloopj->index = nvertid;
- lloopj->poly_left = pullmesh_new_start+j;
- lloopj->edge_index = 0;
- lloopj->poly_right = -1;
-
- lloopk->index = nvertid;
- lloopk->edge_index = 0;
- lloopk->poly_left = pullmesh_new_start+k;
- lloopk->poly_right = -1;
-
- v2_zero(lloopi->uv);
- v2_zero(lloopj->uv);
- v2_zero(lloopk->uv);
-
- ptri->loop_total ++;
- ptrj->loop_total ++;
- ptrk->loop_total ++;
-
- // Adjust centers of faces
- v3_lerp( ptri->center, intersect, 1.0/(double)ptri->loop_total, ptri->center );
- v3_lerp( ptrj->center, intersect, 1.0/(double)ptrj->loop_total, ptrj->center );
- v3_lerp( ptrk->center, intersect, 1.0/(double)ptrk->loop_total, ptrk->center );
- }
- }
- }
+ free(solid_buffer);
+ free(candidates);
+ free(best_manifold.loops);
+
+ cxr_free_mesh( pullmesh );
+ *error = CXR_ERROR_DEGEN_IMPLICIT;
+ return NULL;
}
}
- // Copy faces from pullsolid into orig mesh
-
+ /*
+ * Copy faces from the pullmesh into original, to patch up where there
+ * would be gaps created
+ */
for( int i=0; i<new_polys; i++ )
{
int rface_id = mesh->abpolys.count;
-
- cxr_polygon *pface = cxr_ab_ptr(&pullmesh->abpolys,pullmesh_new_start+i);
- cxr_polygon *rip_face = cxr_ab_empty(&mesh->abpolys);
+ cxr_polygon *pface = &pullmesh->polys[pullmesh_new_start+i],
+ *rip_face = cxr_ab_empty(&mesh->abpolys);
rip_face->loop_start = mesh->abloops.count;
rip_face->loop_total = pface->loop_total;
for( int j=0; j<rip_face->loop_total; j++ )
{
- cxr_loop *ploop = cxr_ab_ptr(&pullmesh->abloops, pface->loop_start+pface->loop_total-j-1),
- *rloop = cxr_ab_empty(&mesh->abloops);
+ cxr_loop *ploop =
+ &pullmesh->loops[ pface->loop_start+pface->loop_total-j-1 ],
+ *rloop = cxr_ab_empty(&mesh->abloops);
rloop->index = ploop->index;
rloop->poly_left = rface_id;
cxr_mesh_update( pullmesh );
cxr_mesh_clean_faces( mesh );
- cxr_mesh_clean_faces( pullmesh );
cxr_mesh_clean_edges( mesh );
+ cxr_mesh_clean_faces( pullmesh );
cxr_mesh_clean_edges( pullmesh );
- free(edge_tagged);
- free(vertex_tagged);
- free(faces_tagged);
free(solid_buffer);
free(candidates);
- free(best_manifold);
- free(best_manifold_splits);
+ free(best_manifold.loops);
return pullmesh;
}
- free(edge_tagged);
- free(vertex_tagged);
- free(faces_tagged);
free(solid_buffer);
free(candidates);
- free(best_manifold);
- free(best_manifold_splits);
+ free(best_manifold.loops);
return NULL;
}
* Convert from the format we recieve from blender into our internal format
* with auto buffers.
*/
-static cxr_mesh *cxr_to_internal_format(cxr_input_mesh *src, cxr_auto_buffer *abverts)
-{
- cxr_mesh *mesh = cxr_alloc_mesh( src->edge_count, src->loop_count, src->poly_count, abverts );
+static cxr_mesh *cxr_to_internal_format(
+ cxr_input_mesh *src,
+ cxr_abuffer *abverts
+){
+ cxr_mesh *mesh = cxr_alloc_mesh( src->edge_count, src->loop_count,
+ src->poly_count, abverts );
+
cxr_ab_init( abverts, sizeof(v3f), src->vertex_count );
- memcpy( cxr_ab_ptr( &mesh->abedges, 0 ), src->edges, src->edge_count*sizeof(cxr_edge));
- memcpy( cxr_ab_ptr( &mesh->abpolys, 0 ), src->polys, src->poly_count*sizeof(cxr_polygon));
- memcpy( cxr_ab_ptr( abverts, 0 ), src->vertices, src->vertex_count*sizeof(v3f));
+ memcpy( mesh->abedges.arr, src->edges, src->edge_count*sizeof(cxr_edge));
+ memcpy( mesh->abpolys.arr, src->polys, src->poly_count*sizeof(cxr_polygon));
+ memcpy( abverts->arr, src->vertices, src->vertex_count*sizeof(v3f));
mesh->abedges.count = src->edge_count;
mesh->abloops.count = src->loop_count;
mesh->abpolys.count = src->poly_count;
);
}
-// Main function
-static void cxr_calculate_axis(
- cxr_texinfo *transform,
- v3f verts[3],
- v2f uvs[3],
- v2f texture_res
- )
-{
- v2f tT, bT; // Tangent/bitangent pairs for UV space and world
+/*
+ * Convert regular UV'd triangle int Source's u/vaxis vectors
+ *
+ * This supports affine move, scale, rotation, parallel skewing
+ */
+static void cxr_calculate_axis( cxr_texinfo *transform, v3f verts[3],
+ v2f uvs[3], v2f texture_res
+){
+ v2f tT, bT; /* Tangent/bitangent pairs for UV space and world */
v3f tW, bW;
v2_sub( uvs[0], uvs[1], tT );
v3_sub( verts[0], verts[1], tW );
v3_sub( verts[2], verts[1], bW );
- // Use arbitrary projection if there is no UV
+ /* Use arbitrary projection if there is no UV */
if( v2_length( tT ) < 0.0001 || v2_length( bT ) < 0.0001 )
{
v3f uaxis, normal, vaxis;
return;
}
- // Detect if UV is reversed
+ /* Detect if UV is reversed */
double winding = v2_cross( tT, bT ) >= 0.0f? 1.0f: -1.0f;
- // UV projection reference
+ /* UV projection reference */
v2f vY, vX;
v2_muls((v2f){1,0}, winding, vX);
v2_muls((v2f){0,1}, winding, vY);
- // Reproject reference into world space, including skew
+ /* Reproject reference into world space, including skew */
v3f uaxis1, vaxis1;
v3_muls( tW, v2_cross(vX,bT) / v2_cross(bT,tT), uaxis1 );
v3_normalize( uaxis1 );
v3_normalize( vaxis1 );
- // Apply source transform to axis (yes, they also need to be swapped)
+ /* Apply source transform to axis (yes, they also need to be swapped) */
v3f norm, uaxis, vaxis;
v3_cross( bW, tW, norm );
v3_cross( vaxis1, norm, uaxis );
v3_cross( uaxis1, norm, vaxis );
- // real UV scale
+ /* real UV scale */
v2f uvmin, uvmax, uvdelta;
v2_minv( uvs[0], uvs[1], uvmin );
v2_minv( uvmin, uvs[2], uvmin );
v2_sub( uvmax, uvmin, uvdelta );
- // world-uv scale
+ /* world-uv scale */
v2f uvminw, uvmaxw, uvdeltaw;
uvminw[0] = -support_distance( verts, uaxis, -1.0f );
uvmaxw[0] = support_distance( verts, uaxis, 1.0f );
v2_sub( uvmaxw, uvminw, uvdeltaw );
- // VMf uv scale
+ /* VMf uv scale */
v2f uv_scale;
v2_div( uvdeltaw, uvdelta, uv_scale );
v2_div( uv_scale, texture_res, uv_scale );
- // Find offset via 'natural' point
+ /* Find offset via 'natural' point */
v2f target_uv, natural_uv, tex_offset;
v2_mul( uvs[0], texture_res, target_uv );
tex_offset[0] = target_uv[0]-natural_uv[0];
tex_offset[1] = -(target_uv[1]-natural_uv[1]);
- // Copy everything into output
+ /* Copy everything into output */
v3_copy( uaxis, transform->uaxis );
v3_copy( vaxis, transform->vaxis );
v2_copy( tex_offset, transform->offset );
transform->winding = winding;
}
-CXR_API cxr_input_mesh *cxr_decompose(cxr_input_mesh *src)
+CXR_API cxr_input_mesh *cxr_write_test_data( cxr_input_mesh *src )
{
- FILE *yeet = fopen( "/home/harry/Documents/blender_addons_remote/addons/convexer/src/solid.h", "w" );
+ FILE *fp = fopen(
+ "/home/harry/Documents/blender_addons_remote/addons/convexer/src/solid.h",
+ "w" );
- fprintf( yeet, "v3f test_verts[] = {\n" );
+ fprintf( fp, "v3f test_verts[] = {\n" );
for( int i=0; i<src->vertex_count; i ++ )
{
- fprintf( yeet, " { %f, %f, %f },\n",
+ fprintf( fp, " { %f, %f, %f },\n",
src->vertices[i][0],
src->vertices[i][1],
src->vertices[i][2] );
}
- fprintf( yeet, "};\n" );
+ fprintf( fp, "};\n" );
- fprintf( yeet, "struct cxr_input_loop test_loops[] = {\n" );
+ fprintf( fp, "struct cxr_input_loop test_loops[] = {\n" );
for( int i=0; i<src->loop_count; i ++ )
{
- fprintf( yeet, " {%d, %d},\n",
+ fprintf( fp, " {%d, %d},\n",
src->loops[i].index,
src->loops[i].edge_index);
}
- fprintf( yeet, "};\n" );
+ fprintf( fp, "};\n" );
- fprintf( yeet, "struct cxr_polygon test_polys[] = {\n" );
+ fprintf( fp, "struct cxr_polygon test_polys[] = {\n" );
for( int i=0; i <src->poly_count; i++ )
{
- fprintf( yeet, " {%d, %d, {%f, %f, %f}, {%f, %f, %f}},\n",
+ fprintf( fp, " {%d, %d, {%f, %f, %f}, {%f, %f, %f}},\n",
src->polys[i].loop_start,
src->polys[i].loop_total,
src->polys[i].normal[0],
src->polys[i].center[1],
src->polys[i].center[2] );
}
- fprintf( yeet, "};\n" );
+ fprintf( fp, "};\n" );
- fprintf( yeet, "struct cxr_edge test_edges[] = {\n" );
+ fprintf( fp, "struct cxr_edge test_edges[] = {\n" );
for( int i=0; i<src->edge_count; i++ )
{
- fprintf( yeet, " {%d, %d, %d},\n",
+ fprintf( fp, " {%d, %d, %d},\n",
src->edges[i].i0,
src->edges[i].i1,
src->edges[i].freestyle
);
}
- fprintf( yeet, "};\n" );
-
- fprintf( yeet, "struct cxr_input_mesh test_mesh = {\n" );
- fprintf( yeet, " .vertices = test_verts,\n" );
- fprintf( yeet, " .loops = test_loops,\n" );
- fprintf( yeet, " .edges = test_edges,\n" );
- fprintf( yeet, " .polys = test_polys,\n" );
- fprintf( yeet, " .poly_count=%d,\n", src->poly_count );
- fprintf( yeet, " .vertex_count=%d,\n", src->vertex_count );
- fprintf( yeet, " .edge_count=%d,\n",src->edge_count );
- fprintf( yeet, " .loop_count=%d\n", src->loop_count );
- fprintf( yeet, "};\n" );
+ fprintf( fp, "};\n" );
+
+ fprintf( fp, "struct cxr_input_mesh test_mesh = {\n" );
+ fprintf( fp, " .vertices = test_verts,\n" );
+ fprintf( fp, " .loops = test_loops,\n" );
+ fprintf( fp, " .edges = test_edges,\n" );
+ fprintf( fp, " .polys = test_polys,\n" );
+ fprintf( fp, " .poly_count=%d,\n", src->poly_count );
+ fprintf( fp, " .vertex_count=%d,\n", src->vertex_count );
+ fprintf( fp, " .edge_count=%d,\n",src->edge_count );
+ fprintf( fp, " .loop_count=%d\n", src->loop_count );
+ fprintf( fp, "};\n" );
- fclose( yeet );
+ fclose( fp );
return NULL;
}
return component;
}
-// Convert contiguous mesh to patch of displacments
-//
-static void cxr_write_disp(cxr_mesh *mesh, cxr_input_mesh *inputmesh,
- cxr_vdf *output )
-{
+/*
+ * Convert contiguous mesh to displacement patch
+ */
+static void cxr_write_disp( cxr_mesh *mesh, cxr_input_mesh *inputmesh,
+ cxr_vdf *output
+){
v3f *verts = cxr_ab_ptr( mesh->p_abverts, 0 );
- // Create a graph which maps vertices by their connections
struct vertinfo
{
- int con_start, con_count; // Index into the connection graph
+ int con_start, con_count;
int boundary,
used,
search,
}
}
- // Find best normal for brush patch. VBSP uses the original brush
- // as reference for decal projection.
- //
- // These are clamped to be cardinal directions as to make the VMF somewhat
- // human editable.
+ /*
+ * Find best normal for brush patch. VBSP uses the original brush as an
+ * reference for decal projection in-game
+ */
v3f avg_normal, refv, refu, refn;
v3_zero(refv); v3_zero(refu); v3_zero(refn);
v3_add( poly->normal, avg_normal, avg_normal );
}
v3_divs( avg_normal, mesh->abpolys.count, avg_normal );
- v3_normalize( avg_normal ); // TODO(harry): This can be zero length. Should add a safety check
- // normalize function that checks for small length before
- // carrying out, otherwise we get inf/nan values...
- int n_cardinal = cxr_cardinal( avg_normal, -1 );
+ if( v3_length( avg_normal ) <= 1e-6 )
+ v3_copy( (v3f){ 0.0, 0.0, 1.0 }, avg_normal );
+ else
+ v3_normalize( avg_normal );
+
+ /*
+ * Approximately match the area of the result brush faces to the actual
+ * area.
+ *
+ * Necessary for accuracy and even lightmap texel allocation
+ */
- // Approximately matching the area of the result brush faces to the actual area
- // this is to assign a 'best guess' amount of lightmap texels.
- //
double uv_area = 0.0, face_area = 0.0, sf;
v2f uvboundmin, uvboundmax;
v3f faceboundmin, faceboundmax;
for( int i=0; i<mesh->abpolys.count; i++ )
{
- cxr_polygon *poly = cxr_ab_ptr( &mesh->abpolys, i );
+ cxr_polygon *poly = &mesh->polys[i];
for( int j=0; j<poly->loop_total; j++ )
{
- cxr_loop *lp0 = cxr_ab_ptr(&mesh->abloops, poly->loop_start+j);
+ cxr_loop *lp0 = &mesh->loops[ poly->loop_start+j ];
v2_minv( lp0->uv, uvboundmin, uvboundmin);
v2_maxv( lp0->uv, uvboundmax, uvboundmax);
- v3_minv( cxr_ab_ptr(mesh->p_abverts,lp0->index), faceboundmin, faceboundmin );
- v3_maxv( cxr_ab_ptr(mesh->p_abverts,lp0->index), faceboundmax, faceboundmax );
+ v3_minv( verts[lp0->index], faceboundmin, faceboundmin );
+ v3_maxv( verts[lp0->index], faceboundmax, faceboundmax );
}
for( int j=0; j<poly->loop_total-2; j++ )
sf = sqrt( face_area / uv_area );
int corner_count = 0;
- // Vertex classification
+ /*
+ * Vertex classification
+ * boundary vertices: they exist on a freestyle edge
+ * corners: only connected to other boundaries
+ */
for( int i=0; i<mesh->p_abverts->count; i++ )
{
struct vertinfo *info = &vertinfo[i];
else
non_manifold = 0;
}
+
if( count > 2 || non_manifold )
{
info->corner = 1;
corner_count ++;
-
- //cxr_debug_box( cxr_ab_ptr(abverts,i), 0.1, colour_success );
}
}
- // TODO(harry): This currently only supports power 2 displacements
- // its quite straightforward to upgrade it.
- //
+ /*
+ * TODO(harry): This currently only supports power 2 displacements
+ * its quite straightforward to upgrade it.
+ *
+ * TODO(harry): Error checking is needed here for bad input data
+ */
+
int dispedge[16];
v2f corner_uvs[4];
int dispedge_count;
cxr_loop *l0 = &mesh->loops[ basepoly->loop_start+i0 ],
*l1 = &mesh->loops[ basepoly->loop_start+i1 ];
struct vertinfo *info = &vertinfo[ l0->index ];
+
+ if( !info->corner )
+ continue;
- if( info->corner )
- {
- int corner_count = 1;
-
- cxr_material *matptr =
- basepoly->material_id < 0 || inputmesh->material_count == 0?
- &cxr_nodraw:
- &inputmesh->materials[ basepoly->material_id ];
-
- dispedge_count = 2;
- dispedge[0] = l0->index;
- dispedge[1] = l1->index;
- v2_copy( l0->uv, corner_uvs[0] );
-
- // Consume (remove) faces we use for corners
- basepoly->loop_total = -1;
-
- //cxr_debug_box( cxr_ab_ptr(abverts,l0->index),0.08,(v4f){0.0,0.0,1.0,1.0});
-
- // Collect edges
- // --------------------
+ int corner_count = 1;
+
+ cxr_material *matptr =
+ basepoly->material_id < 0 || inputmesh->material_count == 0?
+ &cxr_nodraw:
+ &inputmesh->materials[ basepoly->material_id ];
+
+ dispedge_count = 2;
+ dispedge[0] = l0->index;
+ dispedge[1] = l1->index;
+ v2_copy( l0->uv, corner_uvs[0] );
+
+ /* Consume (use) face from orignal mesh */
+ basepoly->loop_total = -1;
+
+ while( dispedge_count < 17 )
+ {
+ struct vertinfo *edge_head =
+ &vertinfo[dispedge[dispedge_count-1]];
- while( dispedge_count < 17 )
+ int newvert = 0;
+
+ if( edge_head->corner )
{
- struct vertinfo *edge_head = &vertinfo[dispedge[dispedge_count-1]];
- int newvert = 0;
-
- if( edge_head->corner )
+ /* Find polygon that has edge C-1 -> C */
+ for( int j=0; j<mesh->abpolys.count && !newvert; j++ )
{
- // Find a polygon that has the edge C-1 -> C
- for( int j=0; j<mesh->abpolys.count && !newvert; j++ )
+ cxr_polygon *poly = &mesh->polys[j];
+
+ for( int k=0; k<poly->loop_total; k ++ )
{
- cxr_polygon *poly = &mesh->polys[j];
+ int i0 = k,
+ i1 = cxr_range(k+1,poly->loop_total);
+
+ cxr_loop *l0 = &mesh->loops[ poly->loop_start+i0 ],
+ *l1 = &mesh->loops[ poly->loop_start+i1 ];
- for( int k=0; k<poly->loop_total; k ++ )
+ if( l0->index == dispedge[dispedge_count-2] &&
+ l1->index == dispedge[dispedge_count-1] )
{
- int i0 = k,
- i1 = cxr_range(k+1,poly->loop_total);
-
- cxr_loop *l0 = &mesh->loops[ poly->loop_start+i0 ],
- *l1 = &mesh->loops[ poly->loop_start+i1 ];
-
- if( l0->index == dispedge[dispedge_count-2] &&
- l1->index == dispedge[dispedge_count-1] )
- {
- // Take the vertex after that edge
- v2_copy( l1->uv, corner_uvs[corner_count ++] );
-
- int i2 = cxr_range(i1+1,poly->loop_total);
- cxr_loop *l2 = &mesh->loops[ poly->loop_start+i2 ];
-
- dispedge[dispedge_count ++] = l2->index;
- newvert = 1;
- poly->loop_total = -1;
- break;
- }
+ /* Take the next edge */
+ v2_copy( l1->uv, corner_uvs[corner_count ++] );
+
+ int i2 = cxr_range(i1+1,poly->loop_total);
+ cxr_loop *l2 = &mesh->loops[ poly->loop_start+i2 ];
+
+ dispedge[dispedge_count ++] = l2->index;
+ newvert = 1;
+ poly->loop_total = -1;
+ break;
}
}
}
- else
+ }
+ else
+ {
+ for( int j=0; j<edge_head->con_count; j++ )
{
- for( int j=0; j<edge_head->con_count; j++ )
- {
- int con = graph[edge_head->con_start+j];
+ int con = graph[edge_head->con_start+j];
- if( con == -1 )
- continue;
+ if( con == -1 )
+ continue;
- if( dispedge_count > 1 )
- if( con == dispedge[dispedge_count-2] )
- continue;
-
- struct vertinfo *coninfo = &vertinfo[con];
-
- if( !coninfo->boundary )
+ if( dispedge_count > 1 )
+ if( con == dispedge[dispedge_count-2] )
continue;
-
- /*
- cxr_debug_arrow( cxr_ab_ptr(abverts,dispedge[dispedge_count-1]),
- cxr_ab_ptr(abverts,con),
- (v3f){0,0,1},
- 0.1,
- colour_success );
- */
-
- dispedge[ dispedge_count ++ ] = con;
- newvert = 1;
-
- break;
- }
- }
+
+ struct vertinfo *coninfo = &vertinfo[con];
+
+ if( !coninfo->boundary )
+ continue;
+
+ dispedge[ dispedge_count ++ ] = con;
+ newvert = 1;
- if( !newvert )
- {
- cxr_debug_box(verts[dispedge[dispedge_count-1]], 0.1, colour_error);
break;
}
}
-
- // --------------------
- // Edges collected
-
- v2f va, vb;
- v2_sub( corner_uvs[1], corner_uvs[0], va );
- v2_sub( corner_uvs[2], corner_uvs[0], vb );
-
- // Connect up the grid
- //
- // 0 1 2 3 4
- // 15 a b c d
- // 14 e f g h
- // 13 i j k l
- // 12 m n o p
- //
- // Example: a := common unused vertex that is connected to
- // by 1 and 15. Or y-1, and x-1 on the grid.
- // g := c and f common vert ^
- //
- int grid[25];
-
- for( int j=0; j<5; j++ ) grid[j] = dispedge[j];
- for( int j=1; j<5; j++ ) grid[j*5+4] = dispedge[j+4];
- for( int j=0; j<4; j++ ) grid[4*5+3-j] = dispedge[j+9];
- for( int j=1; j<4; j++ ) grid[j*5] = dispedge[16-j];
- // Grid fill
- for( int j=1; j<4; j++ )
+ if( !newvert )
{
- for( int k=1; k<4; k++ )
- {
- int s0 = grid[(j-1)*5+k],
- s1 = grid[j*5+k-1];
+ cxr_debug_box( verts[dispedge[dispedge_count-1]], 0.1,
+ colour_error);
+ break;
+ }
+ }
+
+ /* All edges collected */
+
+ v2f va, vb;
+ v2_sub( corner_uvs[1], corner_uvs[0], va );
+ v2_sub( corner_uvs[2], corner_uvs[0], vb );
+
+ /* Connect up the grid
+ *
+ * 0 1 2 3 4
+ * 15 a b c d
+ * 14 e f g h
+ * 13 i j k l
+ * 12 m n o p
+ *
+ * Example: a := common unused vertex that is connected to
+ * by 1 and 15. Or y-1, and x-1 on the grid.
+ * g := c and f common vert ^
+ */
+
+ int grid[25];
+
+ for( int j=0; j<5; j++ ) grid[j] = dispedge[j];
+ for( int j=1; j<5; j++ ) grid[j*5+4] = dispedge[j+4];
+ for( int j=0; j<4; j++ ) grid[4*5+3-j] = dispedge[j+9];
+ for( int j=1; j<4; j++ ) grid[j*5] = dispedge[16-j];
- struct vertinfo *va = &vertinfo[s0],
- *vb = &vertinfo[s1];
+ /* Fill in grid */
+ for( int j=1; j<4; j++ )
+ {
+ for( int k=1; k<4; k++ )
+ {
+ int s0 = grid[(j-1)*5+k],
+ s1 = grid[j*5+k-1];
- // Find a common vertex between s0 and s1
-
- for( int l=0; l<va->con_count; l ++ )
+ struct vertinfo *va = &vertinfo[s0],
+ *vb = &vertinfo[s1];
+
+ /* Find common non-used vertex */
+ for( int l=0; l<va->con_count; l ++ )
+ {
+ for( int m=0; m<vb->con_count; m ++ )
{
- for( int m=0; m<vb->con_count; m ++ )
- {
- int cona = graph[va->con_start+l],
- conb = graph[vb->con_start+m];
+ int cona = graph[va->con_start+l],
+ conb = graph[vb->con_start+m];
- if( cona == conb )
- {
- if( vertinfo[cona].used || vertinfo[cona].boundary )
- continue;
+ if( cona == conb )
+ {
+ if( vertinfo[cona].used || vertinfo[cona].boundary )
+ continue;
- grid[ j*5+k ] = cona;
- vertinfo[cona].used = 1;
+ grid[ j*5+k ] = cona;
+ vertinfo[cona].used = 1;
- goto IL_MATCHED_DISP_INTERIOR_VERT;
- }
+ goto next_cell;
}
}
+ }
- // Broken displacement
- cxr_log( "Broken displacement!\n" );
- free( graph );
- free( vertinfo );
- return;
+ cxr_log( "Broken displacement!\n" );
+ free( graph );
+ free( vertinfo );
+ return;
- IL_MATCHED_DISP_INTERIOR_VERT:;
- }
+ next_cell:;
}
-
- // Create brush vertices based on UV map
+ }
+
+ /*
+ * Create V reference based on first displacement.
+ * TODO(harry): This is not the moststable selection method!
+ * faces can come in any order, so the first disp will of
+ * course always vary. Additionaly the triangle can be oriented
+ * differently.
+ *
+ * Improvement can be made by selecting a first disp/triangle
+ * based on deterministic factors.
+ */
+ if( disp_count == 0 )
+ {
+ cxr_texinfo tx;
+ v3f tri_ref[3];
+ v3_copy( verts[dispedge[0]], tri_ref[0] );
+ v3_copy( verts[dispedge[4]], tri_ref[1] );
+ v3_copy( verts[dispedge[8]], tri_ref[2] );
+ cxr_calculate_axis( &tx, tri_ref, corner_uvs, (v2f){512,512} );
+
+ v3_muls( tx.vaxis, -1.0, refv );
+ int v_cardinal = cxr_cardinal( refv, -1 );
+
+ v3_cross( tx.vaxis, tx.uaxis, refn );
+ v3_muls( refn, -tx.winding, refn );
- // Create V reference based on first displacement.
- // TODO(harry): This is not the moststable selection method!
- // faces can come in any order, so the first disp will of course
- // always vary. Additionaly the triangle can be oriented differently.
- //
- // Improvement can be made by selecting a first disp/triangle based
- // on deterministic factors.
- //
- if( disp_count == 0 )
- {
- cxr_texinfo tx;
- v3f tri_ref[3];
- v3_copy( verts[dispedge[0]], tri_ref[0] );
- v3_copy( verts[dispedge[4]], tri_ref[1] );
- v3_copy( verts[dispedge[8]], tri_ref[2] );
- cxr_calculate_axis( &tx, tri_ref, corner_uvs, (v2f){512,512} );
+ /* Computing new reference vectors */
+ int n1_cardinal = cxr_cardinal( refn, v_cardinal );
+
+ int u_cardinal = 0;
- v3_muls( tx.vaxis, -1.0, refv );
- int v_cardinal = cxr_cardinal( refv, -1 );
+ for( int j=0; j<2; j++ )
+ if( u_cardinal == n1_cardinal || u_cardinal == v_cardinal )
+ u_cardinal ++;
- v3_cross( tx.vaxis, tx.uaxis, refn );
- v3_muls( refn, -tx.winding, refn );
+ v3_zero(refu);
+ refu[u_cardinal] = tx.uaxis[u_cardinal] > 0.0? 1.0: -1.0;
- int n1_cardinal = cxr_cardinal( refn, v_cardinal );
-
- //v3_copy( avg_normal, refn );
- int u_cardinal = 0;
- if( u_cardinal == n1_cardinal || u_cardinal == v_cardinal ) u_cardinal ++;
- if( u_cardinal == n1_cardinal || u_cardinal == v_cardinal ) u_cardinal ++;
+ v3f p0, pv, pu, pn;
- v3_zero(refu);
- refu[u_cardinal] = tx.uaxis[u_cardinal] > 0.0? 1.0: -1.0;
+ v3_copy( face_center, p0 );
+ v3_muladds( face_center, refn, 1.5, pn );
+ v3_muladds( face_center, refv, 1.5, pv );
+ v3_muladds( face_center, refu, 1.5, pu );
+
+ /* Draw reference vectors */
+ if( cxr_settings.debug )
+ {
+ cxr_debug_line( p0, pn, (v4f){0.0,0.0,1.0,1.0});
+ cxr_debug_line( p0, pv, (v4f){0.0,1.0,0.0,1.0});
+ cxr_debug_line( p0, pu, (v4f){1.0,0.0,0.0,1.0});
+ cxr_debug_line(tri_ref[0],tri_ref[1],(v4f){1.0,1.0,1.0,1.0});
+ cxr_debug_line(tri_ref[1],tri_ref[2],(v4f){1.0,1.0,1.0,1.0});
+ cxr_debug_line(tri_ref[2],tri_ref[0],(v4f){1.0,1.0,1.0,1.0});
+ }
+ }
- v3f p0, pv, pu, pn;
+ /* Create world coordinates */
+ v3f world_corners[8];
+ v2f world_uv[4];
- v3_copy( face_center, p0 );
- v3_muladds( face_center, refn, 1.5, pn );
- v3_muladds( face_center, refv, 1.5, pv );
- v3_muladds( face_center, refu, 1.5, pu );
-
- if( cxr_settings.debug )
- {
- cxr_debug_line( p0, pn, (v4f){0.0,0.0,1.0,1.0});
- cxr_debug_line( p0, pv, (v4f){0.0,1.0,0.0,1.0});
- cxr_debug_line( p0, pu, (v4f){1.0,0.0,0.0,1.0});
- cxr_debug_line( tri_ref[0], tri_ref[1], (v4f){1.0,1.0,1.0,1.0} );
- cxr_debug_line( tri_ref[1], tri_ref[2], (v4f){1.0,1.0,1.0,1.0} );
- cxr_debug_line( tri_ref[2], tri_ref[0], (v4f){1.0,1.0,1.0,1.0} );
- }
- }
+ for( int j=0; j<4; j++ )
+ {
+ v2f local_uv;
+ v2_sub( corner_uvs[j], uv_center, local_uv );
+ v2_copy( corner_uvs[j], world_uv[j] );
+ v2_muls( local_uv, sf, local_uv );
+
+ v3_muls( refu, local_uv[0], world_corners[j] );
+ v3_muladds( world_corners[j],refv,local_uv[1],world_corners[j] );
+ v3_add( face_center, world_corners[j], world_corners[j] );
+ }
- // Create world cordinates
- v3f world_corners[8];
- v2f world_uv[4];
+ double *colour = colours_random[cxr_range(disp_count,8)];
+ for( int j=0; j<4; j++ )
+ v3_muladds( world_corners[j], refn, -1.0, world_corners[j+4] );
+
+ if( cxr_settings.debug )
+ {
for( int j=0; j<4; j++ )
{
- v2f local_uv;
- v2_sub( corner_uvs[j], uv_center, local_uv );
- v2_copy( corner_uvs[j], world_uv[j] );
- v2_muls( local_uv, sf, local_uv );
-
- v3_muls( refu, local_uv[0], world_corners[j] );
- v3_muladds( world_corners[j], refv, local_uv[1], world_corners[j] );
- v3_add( face_center, world_corners[j], world_corners[j] );
+ double *p0 = world_corners[j],
+ *p1 = world_corners[cxr_range(j+1,4)];
+
+ cxr_debug_arrow( p0, p1, avg_normal, 0.1, colour );
}
+ }
+
+ /* Apply world transform */
+ for( int j=0; j<8; j++ )
+ {
+ double *p0 = world_corners[j];
+ v3_muls( p0, cxr_context.scale_factor, p0 );
- double *colour = colours_random[cxr_range(disp_count,8)];
+ p0[2] += cxr_context.offset_z;
+ }
- for( int j=0; j<4; j++ )
- v3_muladds( world_corners[j], refn, -1.0, world_corners[j+4] );
-
- if( cxr_settings.debug )
- {
- cxr_debug_arrow( world_corners[0], world_corners[1], avg_normal, 0.1, colour );
- cxr_debug_arrow( world_corners[1], world_corners[2], avg_normal, 0.1, colour );
- cxr_debug_arrow( world_corners[2], world_corners[3], avg_normal, 0.1, colour );
- cxr_debug_arrow( world_corners[3], world_corners[0], avg_normal, 0.1, colour );
- }
+ cxr_texinfo texinfo_shared;
+ cxr_calculate_axis( &texinfo_shared, world_corners, world_uv,
+ (v2f){ matptr->res[0], matptr->res[1] } );
+
+ /* Write brush */
+ cxr_vdf_node( output, "solid" );
+ cxr_vdf_ki32( output, "id", ++ cxr_context.brush_count );
+
+ int sides[6][3] =
+ {{ 0, 1, 2 },
+ { 4, 6, 5 },
+ { 4, 1, 0 },
+ { 7, 0, 3 },
+ { 6, 2, 1 },
+ { 6, 3, 2 }};
+
+ v3f normals[25];
+ double distances[25];
+
+ v3f lside0, lside1, lref, vdelta, vworld;
+ double tx, ty;
+
+ for( int j=0; j<5; j++ )
+ {
+ ty = (double)j/(double)(5-1);
- /*
- cxr_debug_arrow( world_corners[0+4], world_corners[1+4], avg_normal, 0.1, colour );
- cxr_debug_arrow( world_corners[1+4], world_corners[2+4], avg_normal, 0.1, colour );
- cxr_debug_arrow( world_corners[2+4], world_corners[3+4], avg_normal, 0.1, colour );
- cxr_debug_arrow( world_corners[3+4], world_corners[0+4], avg_normal, 0.1, colour );
- */
+ v3_lerp( world_corners[0], world_corners[3], ty, lside0 );
+ v3_lerp( world_corners[1], world_corners[2], ty, lside1 );
- // Apply world transform
- for( int j=0; j<8; j++ )
+ for( int k=0; k<5; k++ )
{
- v3_muls( world_corners[j], cxr_context.scale_factor, world_corners[j] );
- world_corners[j][2] += cxr_context.offset_z;
+ int index = j*5+k;
+
+ tx = (double)k/(double)(5-1);
+ v3_lerp( lside0, lside1, tx, lref );
+ v3_muls( verts[grid[index]], cxr_context.scale_factor, vworld );
+ vworld[2] += cxr_context.offset_z;
+
+ v3_sub( vworld, lref, vdelta );
+ v3_copy( vdelta, normals[index] );
+ v3_normalize( normals[index] );
+ distances[index] = v3_dot( vdelta, normals[index] );
}
+ }
- cxr_texinfo texinfo_shared;
- cxr_calculate_axis( &texinfo_shared, world_corners, world_uv,
- (v2f){ matptr->res[0], matptr->res[1] } );
-
- // Write brush
- cxr_vdf_node( output, "solid" );
- cxr_vdf_ki32( output, "id", ++ cxr_context.brush_count );
-
- int sides[6][3] =
- {{ 0, 1, 2 },
- { 4, 6, 5 },
- { 4, 1, 0 },
- { 7, 0, 3 },
- { 6, 2, 1 },
- { 6, 3, 2 }};
+ for( int j=0; j<6; j++ )
+ {
+ int *side = sides[j];
+
+ cxr_vdf_node( output, "side" );
+ cxr_vdf_ki32( output, "id", ++ cxr_context.face_count );
+ cxr_vdf_plane( output, "plane", world_corners[side[2]],
+ world_corners[side[1]],
+ world_corners[side[0]] );
- v3f normals[25];
- double distances[25];
+ cxr_vdf_kv( output, "material", matptr->vmt_path );
+
+ cxr_vdf_kaxis( output, "uaxis",
+ texinfo_shared.uaxis,
+ texinfo_shared.offset[0],
+ texinfo_shared.scale[0] );
+ cxr_vdf_kaxis( output, "vaxis",
+ texinfo_shared.vaxis,
+ texinfo_shared.offset[1],
+ texinfo_shared.scale[1] );
+
+ cxr_vdf_kdouble( output, "rotation", 0.0 );
+ cxr_vdf_ki32( output, "lightmapscale", cxr_settings.lightmap_scale);
+ cxr_vdf_ki32( output, "smoothing_groups", 0 );
- v3f lside0, lside1, lref, vdelta, vworld;
- double tx, ty;
-
- for( int j=0; j<5; j++ )
+ if( j == 0 )
{
- ty = (double)j/(double)(5-1);
-
- v3_lerp( world_corners[0], world_corners[3], ty, lside0 );
- v3_lerp( world_corners[1], world_corners[2], ty, lside1 );
-
+ cxr_vdf_node( output, "dispinfo" );
+ cxr_vdf_ki32( output, "power", 2 );
+ cxr_vdf_kv3f( output, "startposition", world_corners[0] );
+ cxr_vdf_ki32( output, "flags", 0 );
+ cxr_vdf_kdouble( output, "elevation", 0.0 );
+ cxr_vdf_ki32( output, "subdiv", 0 );
+
+ cxr_vdf_node( output, "normals" );
for( int k=0; k<5; k++ )
- {
- int index = j*5+k;
-
- tx = (double)k/(double)(5-1);
- v3_lerp( lside0, lside1, tx, lref );
- v3_muls( verts[grid[index]], cxr_context.scale_factor, vworld );
- vworld[2] += cxr_context.offset_z;
-
- v3_sub( vworld, lref, vdelta );
- v3_copy( vdelta, normals[index] );
- v3_normalize( normals[index] );
- distances[index] = v3_dot( vdelta, normals[index] );
- }
- }
+ cxr_vdf_karrv3f( output, "row", k, &normals[k*5], 5 );
+ cxr_vdf_edon( output );
+
+ cxr_vdf_node( output, "distances" );
+ for( int k=0; k<5; k++ )
+ cxr_vdf_karrdouble( output, "row", k, &distances[k*5], 5 );
+ cxr_vdf_edon( output );
+
+ /*
+ * TODO: This might be needed for the compilers. Opens fine in
+ * hammer
+ */
- for( int j=0; j<6; j++ )
- {
- int *side = sides[j];
+ /*
+ cxr_vdf_node( output, "offsets" );
+ for( int k=0; k<5; k++ )
+ cxr_vdf_printf( output,
+ "\"row%d\" \"0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\"\n", k );
+ cxr_vdf_edon( output );
- cxr_vdf_node( output, "side" );
- cxr_vdf_ki32( output, "id", ++ cxr_context.face_count );
- cxr_vdf_plane( output, "plane", world_corners[side[2]],
- world_corners[side[1]],
- world_corners[side[0]] );
+ cxr_vdf_node( output, "offset_normals" );
+ for( int k=0; k<5; k++ )
+ cxr_vdf_printf( output,
+ "\"row%d\" \"0 0 1 0 0 1 0 0 1 0 0 1 0 0 1\"\n", k );
+ cxr_vdf_edon( output );
- cxr_vdf_kv( output, "material", matptr->vmt_path );
-
- cxr_vdf_kaxis( output, "uaxis",
- texinfo_shared.uaxis,
- texinfo_shared.offset[0],
- texinfo_shared.scale[0] );
- cxr_vdf_kaxis( output, "vaxis",
- texinfo_shared.vaxis,
- texinfo_shared.offset[1],
- texinfo_shared.scale[1] );
-
- cxr_vdf_kdouble( output, "rotation", 0.0 );
- cxr_vdf_ki32( output, "lightmapscale", cxr_settings.lightmap_scale );
- cxr_vdf_ki32( output, "smoothing_groups", 0 );
+ cxr_vdf_node( output, "alphas" );
+ for( int k=0; k<5; k++ )
+ cxr_vdf_printf( output, "\"row%d\" \"0 0 0 0 0\"\n", k );
+ cxr_vdf_edon( output );
- if( j == 0 )
- {
- cxr_vdf_node( output, "dispinfo" );
- cxr_vdf_ki32( output, "power", 2 );
- cxr_vdf_kv3f( output, "startposition", world_corners[0] );
- cxr_vdf_ki32( output, "flags", 0 );
- cxr_vdf_kdouble( output, "elevation", 0.0 );
- cxr_vdf_ki32( output, "subdiv", 0 );
-
- cxr_vdf_node( output, "normals" );
- for( int k=0; k<5; k++ )
- cxr_vdf_karrv3f( output, "row", k, &normals[k*5], 5 );
- cxr_vdf_edon( output );
-
- cxr_vdf_node( output, "distances" );
- for( int k=0; k<5; k++ )
- cxr_vdf_karrdouble( output, "row", k, &distances[k*5], 5 );
- cxr_vdf_edon( output );
-
- // TODO: This might be needed for compiling...
- /*
- cxr_vdf_node( output, "offsets" );
- for( int k=0; k<5; k++ )
- cxr_vdf_printf( output, "\"row%d\" \"0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\"\n", k );
- cxr_vdf_edon( output );
-
- cxr_vdf_node( output, "offset_normals" );
- for( int k=0; k<5; k++ )
- cxr_vdf_printf( output, "\"row%d\" \"0 0 1 0 0 1 0 0 1 0 0 1 0 0 1\"\n", k );
- cxr_vdf_edon( output );
-
- cxr_vdf_node( output, "alphas" );
- for( int k=0; k<5; k++ )
- cxr_vdf_printf( output, "\"row%d\" \"0 0 0 0 0\"\n", k );
- cxr_vdf_edon( output );
-
- cxr_vdf_node( output, "triangle_tags" );
- for( int k=0; k<5-1; k++ )
- cxr_vdf_printf( output, "\"row%d\" \"9 9 9 9 9 9 9 9\"\n", k );
- cxr_vdf_edon( output );
-
- cxr_vdf_node( output, "allowed_verts" );
- cxr_vdf_printf( output, "\"10\" \"-1 -1 -1 -1 -1 -1 -1 -1 -1 -1\"\n" );
- cxr_vdf_edon( output );
- */
- cxr_vdf_edon( output );
- }
+ cxr_vdf_node( output, "triangle_tags" );
+ for( int k=0; k<5-1; k++ )
+ cxr_vdf_printf( output,
+ "\"row%d\" \"9 9 9 9 9 9 9 9\"\n", k );
+ cxr_vdf_edon( output );
+
+ cxr_vdf_node( output, "allowed_verts" );
+ cxr_vdf_printf( output,
+ "\"10\" \"-1 -1 -1 -1 -1 -1 -1 -1 -1 -1\"\n" );
+ cxr_vdf_edon( output );
+ */
cxr_vdf_edon( output );
}
- cxr_vdf_node(output, "editor");
- cxr_vdf_colour255(output,"color", colours_random[cxr_range(cxr_context.brush_count,8)]);
- cxr_vdf_ki32(output,"visgroupshown",1);
- cxr_vdf_ki32(output,"visgroupautoshown",1);
- cxr_vdf_edon(output);
-
cxr_vdf_edon( output );
- disp_count ++;
}
+
+ cxr_vdf_node( output, "editor");
+ cxr_vdf_colour255( output, "color",
+ colours_random[cxr_range(cxr_context.brush_count,8)]);
+
+ cxr_vdf_ki32( output, "visgroupshown",1);
+ cxr_vdf_ki32( output, "visgroupautoshown",1);
+ cxr_vdf_edon( output );
+
+ cxr_vdf_edon( output );
+ disp_count ++;
}
}
free( vertinfo );
}
-static int cxr_solid_checkerr(cxr_mesh *mesh, cxr_auto_buffer *abverts )
+static int cxr_solid_checkerr( cxr_mesh *mesh )
{
+ v3f *verts = cxr_ab_ptr( mesh->p_abverts, 0 );
int err_count = 0;
for( int i=0; i<mesh->abpolys.count; i++ )
for( int j=0; j<poly->loop_total; j++ )
{
cxr_loop *loop = &mesh->loops[ poly->loop_start+j ];
- double *vert = cxr_ab_ptr(abverts,loop->index);
+ double *vert = verts[ loop->index ];
if( fabs(plane_polarity(plane,vert)) > 0.0025 )
{
CXR_API i32 cxr_convert_mesh_to_vmf(cxr_input_mesh *src, cxr_vdf *output)
{
- // Split mesh into islands
- cxr_auto_buffer abverts;
+ cxr_abuffer abverts;
cxr_mesh *main_mesh = cxr_to_internal_format(src, &abverts);
u32 error = 0x00;
int is_displacement, invalid;
};
- cxr_auto_buffer solids;
+ cxr_abuffer solids;
cxr_ab_init( &solids, sizeof(struct solidinf), 2 );
- // Preprocessor 1: Island seperation
- // ---------------
-
+ /*
+ * Preprocessor 1: Island seperation
+ */
while(1)
{
cxr_mesh *res = cxr_pull_island( main_mesh );
}
cxr_ab_push( &solids, &(struct solidinf){main_mesh,0} );
- // Preprocessor 2: Displacement break-out and error checking
- // ---------------
+ /*
+ * Preprocessor 2: Displacement processing & error checks
+ */
for( int i=0; i<solids.count; i++ )
{
struct solidinf *pinf = cxr_ab_ptr(&solids,i);
for( int j=0; j<pinf->pmesh->abpolys.count; j++ )
{
- cxr_polygon *poly = cxr_ab_ptr( &pinf->pmesh->abpolys, j );
+ cxr_polygon *poly = &pinf->pmesh->polys[ j ];
for( int k=0; k<poly->loop_total; k++ )
{
- cxr_loop *lp = cxr_ab_ptr( &pinf->pmesh->abloops, poly->loop_start+k );
- cxr_edge *edge = cxr_ab_ptr( &pinf->pmesh->abedges, lp->edge_index );
+ cxr_loop *lp = &pinf->pmesh->loops[ poly->loop_start+k ];
+ cxr_edge *edge = &pinf->pmesh->edges[ lp->edge_index ];
if( edge->freestyle )
goto IL_SOLID_IS_DISPLACEMENT;
}
}
- if( cxr_solid_checkerr( pinf->pmesh, &abverts ) )
+ if( cxr_solid_checkerr( pinf->pmesh ) )
{
pinf->invalid = 1;
invalid_count ++;
cxr_write_disp( pinf->pmesh, src, output );
}
- // Preprocessor 3: Breakup non-convex shapes into sub-solids
- // ---------------
+ /*
+ * Main convex decomp algorithm
+ */
int sources_count = solids.count;
for( int i=0; i<sources_count; i++ )
{
if( error )
{
- // If no solids error we can rety while preserving 'hot' edges
+ /* Retry if non-critical error, with extra edges */
if( error & CXR_ERROR_NO_SOLIDS )
{
return error;
}
- // Turn all those solids into VMF brushes
- // --------------------------------------
+ /* Write all solids as VMF brushes */
for( int i=0; i<solids.count; i++ )
{
struct solidinf *solid = cxr_ab_ptr(&solids,i);
for( int j=0; j<solid->pmesh->abpolys.count; j++ )
{
- cxr_polygon *poly = cxr_ab_ptr( &solid->pmesh->abpolys, j );
- cxr_loop *ploops = cxr_ab_ptr(&solid->pmesh->abloops, poly->loop_start);
+ cxr_polygon *poly = &solid->pmesh->polys[j];
+ cxr_loop *ploops = &solid->pmesh->loops[poly->loop_start];
+
cxr_material *matptr =
poly->material_id < 0 || src->material_count == 0?
&cxr_nodraw:
v3f verts[3]; v2f uvs[3];
- v3_muls( cxr_ab_ptr(&abverts, ploops[0].index), cxr_context.scale_factor, verts[0] );
- v3_muls( cxr_ab_ptr(&abverts, ploops[1].index), cxr_context.scale_factor, verts[1] );
- v3_muls( cxr_ab_ptr(&abverts, ploops[2].index), cxr_context.scale_factor, verts[2] );
+ int i0 = ploops[0].index,
+ i1 = ploops[1].index,
+ i2 = ploops[2].index;
+
+ v3_muls( cxr_ab_ptr(&abverts,i0), cxr_context.scale_factor, verts[0] );
+ v3_muls( cxr_ab_ptr(&abverts,i1), cxr_context.scale_factor, verts[1] );
+ v3_muls( cxr_ab_ptr(&abverts,i2), cxr_context.scale_factor, verts[2] );
+
verts[0][2] += cxr_context.offset_z;
verts[1][2] += cxr_context.offset_z;
verts[2][2] += cxr_context.offset_z;
cxr_vdf_plane( output, "plane", verts[2], verts[1], verts[0] );
cxr_vdf_kv( output, "material", matptr->vmt_path );
- cxr_texinfo trans;
- cxr_calculate_axis(&trans, verts, uvs, (double[2]){ matptr->res[0], matptr->res[1] });
+ cxr_texinfo tx;
+ cxr_calculate_axis( &tx, verts, uvs,
+ (double[2]){ matptr->res[0], matptr->res[1] });
- cxr_vdf_kaxis(output, "uaxis", trans.uaxis, trans.offset[0], trans.scale[0]);
- cxr_vdf_kaxis(output, "vaxis", trans.vaxis, trans.offset[1], trans.scale[1]);
+ cxr_vdf_kaxis( output, "uaxis", tx.uaxis, tx.offset[0], tx.scale[0]);
+ cxr_vdf_kaxis( output, "vaxis", tx.vaxis, tx.offset[1], tx.scale[1]);
- cxr_vdf_kdouble(output, "rotation", 0.0 );
- cxr_vdf_ki32(output, "lightmapscale", cxr_settings.lightmap_scale );
- cxr_vdf_ki32(output, "smoothing_groups", 0);
+ cxr_vdf_kdouble( output, "rotation", 0.0 );
+ cxr_vdf_ki32( output, "lightmapscale", cxr_settings.lightmap_scale );
+ cxr_vdf_ki32( output, "smoothing_groups", 0);
cxr_vdf_edon( output );
}
- cxr_vdf_node(output, "editor");
- cxr_vdf_colour255(output,"color", colours_random[cxr_range(cxr_context.brush_count,8)]);
- cxr_vdf_ki32(output,"visgroupshown",1);
- cxr_vdf_ki32(output,"visgroupautoshown",1);
- cxr_vdf_edon(output);
+ cxr_vdf_node( output, "editor" );
+ cxr_vdf_colour255( output, "color",
+ colours_random[cxr_range(cxr_context.brush_count,8)]);
+
+ cxr_vdf_ki32( output, "visgroupshown", 1 );
+ cxr_vdf_ki32( output, "visgroupautoshown", 1 );
+ cxr_vdf_edon( output );
cxr_vdf_edon( output );
}
cxr_settings = *settings;
}
-// Valve copyright stuff probably maybe
-// whatever, my previous copyright decleration ends here
-// ----------------------------------------------------------
-
+/*
+ * Valve Source SDK 2015 CS:GO
+ */
#define HEADER_LUMPS 64
#define LUMP_WORLDLIGHTS 54
};
#pragma pack(pop)
-// Utility for patching BSP tools to remove -1 distance lights (we set them
-// like that, because we want these lights to go away)
-//
-// Yes, there is no way to do this in hammer
-// Yes, the distance KV is unused but still gets compiled to this lump
-// No, Entities only compile will not do this for you
-//
+/*
+ * Utility for patching BSP tools to remove -1 distance lights (we set them
+ * like that, because we want these lights to go away)
+ *
+ * Yes, there is no way to do this in hammer
+ * Yes, the distance KV is unused but still gets compiled to this lump
+ * No, Entities only compile will not do this for you
+ */
CXR_API int cxr_lightpatch_bsp( const char *path )
{
printf( "Lightpatch: %s\n", path );
return 0;
}
- // Read bsp
+ /* Read bsp */
struct header header;
fread( &header, sizeof(struct header), 1, fp );
struct lump *lump = &header.lumps[ LUMP_WORLDLIGHTS ];
- // Read worldlight array
+ /* Read worldlight array */
struct worldlight *lights = malloc( lump->filelen );
fseek( fp, lump->fileofs, SEEK_SET );
fread( lights, lump->filelen, 1, fp );
- // Remove all marked lights
+ /* Remove all marked lights */
int light_count = lump->filelen / sizeof(struct worldlight);
int new_count = 0;
lump->filelen = new_count*sizeof(struct worldlight);
- // Write changes
+ /* Write changes back to file */
fseek( fp, lump->fileofs, SEEK_SET );
fwrite( lights, lump->filelen, 1, fp );
fseek( fp, 0, SEEK_SET );