IMPLEMENTATION
*/
-#define CXR_API
+#define CXR_API
#define CXR_EPSILON 0.001
#define CXR_PLANE_SIMILARITY_MAX 0.998
#define CXR_BIG_NUMBER 1e300
struct cxr_edge
{
i32 i0, i1;
- i32 freestyle;
+ i32 freestyle, sharp;
}
*edges;
struct cxr_material
{
i32 res[2];
- const char *name;
+ char *name;
}
*materials;
k_soliderr_no_solids,
k_soliderr_degenerate_implicit,
k_soliderr_non_coplanar_vertices,
- k_soliderr_non_convex_poly
+ k_soliderr_non_convex_poly,
+ k_soliderr_bad_result
};
/*
}
fprintf( fp, "};\n" );
- fprintf( fp, "struct cxr_static_loop test_loops[] = {\n" );
+ fprintf( fp, "cxr_static_loop test_loops[] = {\n" );
for( int i=0; i<src->loop_count; i ++ )
{
fprintf( fp, " {%d, %d},\n",
}
fprintf( fp, "};\n" );
- fprintf( fp, "struct cxr_polygon test_polys[] = {\n" );
+ fprintf( fp, "cxr_polygon test_polys[] = {\n" );
for( int i=0; i <src->poly_count; i++ )
{
fprintf( fp, " {%d, %d, {%f, %f, %f}, {%f, %f, %f}},\n",
}
fprintf( fp, "};\n" );
- fprintf( fp, "struct cxr_edge test_edges[] = {\n" );
+ fprintf( fp, "cxr_edge test_edges[] = {\n" );
for( int i=0; i<src->edge_count; i++ )
{
- fprintf( fp, " {%d, %d, %d},\n",
+ fprintf( fp, " {%d, %d, %d, %d},\n",
src->edges[i].i0,
src->edges[i].i1,
- src->edges[i].freestyle
+ src->edges[i].freestyle,
+ src->edges[i].sharp
);
}
fprintf( fp, "};\n" );
- fprintf( fp, "struct cxr_static_mesh test_mesh = {\n" );
+ fprintf( fp, "cxr_static_mesh test_mesh = {\n" );
fprintf( fp, " .vertices = test_verts,\n" );
fprintf( fp, " .loops = test_loops,\n" );
fprintf( fp, " .edges = test_edges,\n" );
{
cxr_edge *orig_edge = &mesh->edges[ orig_edge_id ];
edge.freestyle = orig_edge->freestyle;
+ edge.sharp = orig_edge->sharp;
}
else
{
edge.freestyle = 0;
+ edge.sharp = 0;
}
cxr_ab_push( &new_edges, &edge );
if( *edge == -1 )
{
*edge = i;
- break;
+ goto next;
}
}
+
+ /* Overflowed edge mapping... Duplicated faces. */
+ free( polygon_edge_map );
+ return 0;
+
+ next:;
}
}
for( int i = 0; i < mesh->abpolys.count; i ++ )
edge_tagged[lp->edge_index] = 0;
cxr_polygon *polya = &mesh->polys[ lp->poly_left ],
- *polyb = &mesh->polys[ lp->poly_right ];
+ *polyb = &mesh->polys[ lp->poly_right ];
v4f planeb;
normal_to_plane(polyb->normal, polyb->center, planeb);
struct temp_manifold *manifold
){
cxr_loop **edge_list = malloc( sizeof(*edge_list) * solid->edge_count );
+ int *temp_solid = malloc( solid->count *sizeof(int) );
+ int temp_solid_len = 0;
int init_reverse = 0;
int unique_edge_count = 0;
+
+ /* Try remove splitting faces first */
+ {
+ int split_total = 0;
+ for( int j=0; j<solid->count; j++ )
+ {
+ cxr_polygon *poly = &mesh->polys[ solid_buffer[solid->start+j] ];
+ int interior_count = 0;
+
+ for( int k=0; k<poly->loop_total; k++ )
+ {
+ cxr_loop *loop = &mesh->loops[ poly->loop_start+k ];
- /* Gather list of unique edges */
+ for( int l=0; l<solid->count; l++ )
+ if( loop->poly_right == solid_buffer[solid->start+l] )
+ {
+ interior_count ++;
+ goto next;
+ }
+
+ next:;
+ }
+
+ if( interior_count < poly->loop_total-1 )
+ {
+ split_total ++;
+ continue;
+ }
+
+ temp_solid[ temp_solid_len ++ ] = solid_buffer[solid->start+j];
+ }
+
+ if( temp_solid_len < 3 || (split_total & 0x2) /* unkown reasons */ )
+ {
+ }
+ else
+ {
+ /* Overwrite original solid */
+ for( int j=0; j<temp_solid_len; j++ )
+ solid_buffer[ solid->start+j ] = temp_solid[ j ];
+
+ solid->count = temp_solid_len;
+ }
+
+ free( temp_solid );
+ }
for( int j=0; j<solid->count; j++ )
{
cxr_polygon *poly = &mesh->polys[ solid_buffer[solid->start+j] ];
+ /* when discarding, if a face has only one loop that points outwards,
+ * we keep it */
+
+
for( int k=0; k<poly->loop_total; k++ )
{
cxr_loop *loop = &mesh->loops[ poly->loop_start+k ];
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,
- enum cxr_soliderr *err )
+static int cxr_reflex_err( cxr_mesh *mesh )
{
- *err = k_soliderr_none;
+ int error = 0;
+ int *reflex_check = cxr_mesh_reflex_edges( mesh );
+
+ v3f *temp = cxr_ab_ptr(mesh->p_abverts, 0);
+
+ for( int i=0; i<mesh->abedges.count; i++ )
+ {
+ if( reflex_check[i] )
+ {
+ cxr_debug_line( temp[mesh->edges[i].i0],
+ temp[mesh->edges[i].i1],
+ colour_error );
+ error ++;
+ }
+ }
+ free( reflex_check );
+ return error;
+}
+
+static int cxr_non_manifold_err( cxr_mesh *mesh )
+{
if( !cxr_mesh_link_loops(mesh) )
{
#ifdef CXR_DEBUG
for( int i=0; i<mesh->abloops.count; i++ )
{
cxr_loop *lp = &mesh->loops[i];
+ cxr_edge *edge = &mesh->edges[lp->edge_index];
+ cxr_debug_line( verts[edge->i0], verts[edge->i1], colours_random[1] );
if( lp->poly_left == -1 || lp->poly_right == -1 )
{
- cxr_edge *edge = &mesh->edges[lp->edge_index];
cxr_debug_line( verts[edge->i0], verts[edge->i1], colour_error );
}
}
#endif
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ * 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,
+ enum cxr_soliderr *err )
+{
+ *err = k_soliderr_none;
+
+ if( cxr_non_manifold_err( mesh ) )
+ {
*err = k_soliderr_non_manifold;
return NULL;
}
-
+
int *edge_tagged = cxr_mesh_reflex_edges( mesh );
int *vertex_tagged = cxr_mesh_reflex_vertices( mesh );
struct temp_manifold manifold;
cxr_link_manifold( mesh, solid, solid_buffer, &manifold);
-
+
if( manifold.status == k_manifold_err )
{
*err = k_soliderr_bad_manifold;
free(solid_buffer);
free(candidates);
free(best_manifold.loops);
-
+
+ /*
+ * Do final checks on the mesh to make sure we diddn't introduce any
+ * errors
+ */
+ if( cxr_non_manifold_err( pullmesh ) || cxr_reflex_err( pullmesh ) )
+ {
+ *err = k_soliderr_bad_result;
+ return NULL;
+ }
+
return pullmesh;
}
free(candidates);
free(best_manifold.loops);
+ if( cxr_non_manifold_err( mesh ) || cxr_reflex_err( mesh ) )
+ *err = k_soliderr_bad_result;
+
return NULL;
}
cxr_ab_free( &world->abverts );
cxr_ab_free( &world->absolids );
- free( world->materials );
+
+ if( world->materials )
+ {
+ for( int i=0; i<world->material_count; i++ )
+ free( world->materials[i].name );
+
+ free( world->materials );
+ }
free( world );
}
size_t dsize = sizeof(cxr_material) * src->material_count;
world->materials = malloc( dsize );
memcpy( world->materials, src->materials, dsize );
+
+ for( int i=0; i<src->material_count; i++ )
+ {
+ world->materials[i].name = malloc(strlen(src->materials[i].name) +1);
+ strcpy( world->materials[i].name, src->materials[i].name );
+ }
+ world->material_count = src->material_count;
}
else world->materials = NULL;
* TODO(harry): Error checking is needed here for bad input data
*/
- int dispedge[16];
+ int dispedge[17];
v2f corner_uvs[4];
int dispedge_count;
int disp_count = 0;
tx = (double)k/(double)(5-1);
v3_lerp( lside0, lside1, tx, lref );
v3_muls( verts[grid[index]], ctx->scale, vworld );
- v3_add( ctx->offset, vworld, ctx->offset );
+ v3_add( ctx->offset, vworld, vworld );
v3_sub( vworld, lref, vdelta );
v3_copy( vdelta, normals[index] );
world_corners[side[0]] );
cxr_vdf_kv( output, "material", matptr->name );
-
cxr_vdf_kaxis( output, "uaxis",
texinfo_shared.uaxis,
texinfo_shared.offset[0],