X-Git-Url: https://harrygodden.com/git/?a=blobdiff_plain;ds=inline;f=cxr%2Fcxr.h;h=dd7a8b83092dffc3612042b87aba4216abe6b54f;hb=2ed5781b6391a9bb28c94ee83b9bbafd918a356c;hp=5a4542af6d1a3f4055233c6611630e13b771e10b;hpb=2937c186209f5ff766cacc9f17a118744ede7b7a;p=convexer.git diff --git a/cxr/cxr.h b/cxr/cxr.h index 5a4542a..dd7a8b8 100644 --- a/cxr/cxr.h +++ b/cxr/cxr.h @@ -45,7 +45,7 @@ IMPLEMENTATION */ -#define CXR_API +#define CXR_API #define CXR_EPSILON 0.001 #define CXR_PLANE_SIMILARITY_MAX 0.998 #define CXR_BIG_NUMBER 1e300 @@ -107,7 +107,7 @@ typedef struct cxr_tri_mesh cxr_tri_mesh; /* Main convexer algorithms */ /* Convex decomp from mesh */ -CXR_API cxr_world *cxr_decompose( cxr_static_mesh *src ); +CXR_API cxr_world *cxr_decompose( cxr_static_mesh *src, i32 *perrcode ); CXR_API void cxr_free_world( cxr_world *world ); CXR_API cxr_tri_mesh *cxr_world_preview( cxr_world *world ); CXR_API void cxr_free_tri_mesh( cxr_tri_mesh *mesh ); @@ -146,7 +146,7 @@ struct cxr_static_mesh struct cxr_edge { i32 i0, i1; - i32 freestyle; + i32 freestyle, sharp; } *edges; @@ -170,7 +170,7 @@ struct cxr_static_mesh struct cxr_material { i32 res[2]; - const char *name; + char *name; } *materials; @@ -276,7 +276,10 @@ enum cxr_soliderr k_soliderr_non_manifold, k_soliderr_bad_manifold, k_soliderr_no_solids, - k_soliderr_degenerate_implicit + k_soliderr_degenerate_implicit, + k_soliderr_non_coplanar_vertices, + k_soliderr_non_convex_poly, + k_soliderr_bad_result }; /* @@ -487,7 +490,7 @@ CXR_API void cxr_write_test_data( cxr_static_mesh *src ) } fprintf( fp, "};\n" ); - fprintf( fp, "struct cxr_static_loop test_loops[] = {\n" ); + fprintf( fp, "cxr_static_loop test_loops[] = {\n" ); for( int i=0; iloop_count; i ++ ) { fprintf( fp, " {%d, %d},\n", @@ -496,7 +499,7 @@ CXR_API void cxr_write_test_data( cxr_static_mesh *src ) } fprintf( fp, "};\n" ); - fprintf( fp, "struct cxr_polygon test_polys[] = {\n" ); + fprintf( fp, "cxr_polygon test_polys[] = {\n" ); for( int i=0; i poly_count; i++ ) { fprintf( fp, " {%d, %d, {%f, %f, %f}, {%f, %f, %f}},\n", @@ -511,18 +514,19 @@ CXR_API void cxr_write_test_data( cxr_static_mesh *src ) } fprintf( fp, "};\n" ); - fprintf( fp, "struct cxr_edge test_edges[] = {\n" ); + fprintf( fp, "cxr_edge test_edges[] = {\n" ); for( int i=0; iedge_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" ); @@ -619,10 +623,12 @@ static void cxr_mesh_clean_edges( cxr_mesh *mesh ) { 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 ); @@ -709,9 +715,15 @@ static int cxr_mesh_link_loops( cxr_mesh *mesh ) 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 ++ ) @@ -999,7 +1011,7 @@ static int *cxr_mesh_reflex_edges( cxr_mesh *mesh ) 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); @@ -1318,16 +1330,66 @@ static void cxr_link_manifold( 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; jcount; j++ ) + { + cxr_polygon *poly = &mesh->polys[ solid_buffer[solid->start+j] ]; + int interior_count = 0; + + for( int k=0; kloop_total; k++ ) + { + cxr_loop *loop = &mesh->loops[ poly->loop_start+k ]; + + for( int l=0; lcount; 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; jstart+j ] = temp_solid[ j ]; + + solid->count = temp_solid_len; + } - /* Gather list of unique edges */ + free( temp_solid ); + } for( int j=0; jcount; 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; kloop_total; k++ ) { cxr_loop *loop = &mesh->loops[ poly->loop_start+k ]; @@ -1535,6 +1597,56 @@ static int cxr_build_implicit_geo( cxr_mesh *mesh, int new_polys, int start ) return 1; } +static int cxr_reflex_err( cxr_mesh *mesh ) +{ + int error = 0; + int *reflex_check = cxr_mesh_reflex_edges( mesh ); + + v3f *temp = cxr_ab_ptr(mesh->p_abverts, 0); + + for( int i=0; iabedges.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 + cxr_log( "non-manifold edges are in the mesh: " + "implicit internal geometry does not have full support\n" ); + + v3f *verts = cxr_ab_ptr( mesh->p_abverts, 0 ); + + for( int i=0; iabloops.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_debug_line( verts[edge->i0], verts[edge->i1], colour_error ); + } + } +#endif + return 1; + } + + return 0; +} + /* * Convexer's main algorithm * @@ -1551,16 +1663,12 @@ static cxr_mesh *cxr_pull_best_solid( { *err = k_soliderr_none; - if( !cxr_mesh_link_loops(mesh) ) + if( cxr_non_manifold_err( mesh ) ) { -#ifdef CXR_DEBUG - cxr_log( "non-manifold edges are in the mesh: " - "implicit internal geometry does not have full support\n" ); -#endif *err = k_soliderr_non_manifold; return NULL; } - + int *edge_tagged = cxr_mesh_reflex_edges( mesh ); int *vertex_tagged = cxr_mesh_reflex_vertices( mesh ); @@ -1674,7 +1782,7 @@ static cxr_mesh *cxr_pull_best_solid( struct temp_manifold manifold; cxr_link_manifold( mesh, solid, solid_buffer, &manifold); - + if( manifold.status == k_manifold_err ) { *err = k_soliderr_bad_manifold; @@ -1902,7 +2010,17 @@ static cxr_mesh *cxr_pull_best_solid( 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; } @@ -1910,6 +2028,9 @@ static cxr_mesh *cxr_pull_best_solid( free(candidates); free(best_manifold.loops); + if( cxr_non_manifold_err( mesh ) || cxr_reflex_err( mesh ) ) + *err = k_soliderr_bad_result; + return NULL; } @@ -1948,6 +2069,40 @@ static cxr_mesh *cxr_to_internal_format( return mesh; } +static int cxr_poly_convex( cxr_mesh *mesh, cxr_polygon *poly ) +{ + v3f *verts = cxr_ab_ptr( mesh->p_abverts, 0 ); + + for( int i=0; iloop_total; i++ ) + { + int li0 = poly->loop_start + i, + li1 = poly->loop_start + cxr_range( i+1, poly->loop_total ), + li2 = poly->loop_start + cxr_range( i+2, poly->loop_total ); + int i0 = mesh->loops[li0].index, + i1 = mesh->loops[li1].index, + i2 = mesh->loops[li2].index; + + v3f v0, v1, c; + + v3_sub( verts[i1], verts[i0], v0 ); + v3_sub( verts[i2], verts[i1], v1 ); + + v3_cross( v0, v1, c ); + if( v3_dot( c, poly->normal ) <= 0.0 ) + { +#if CXR_DEBUG + cxr_debug_line( verts[i0], verts[i1], colour_error ); + cxr_debug_box( verts[i1], 0.1, colour_error ); + cxr_debug_line( verts[i1], verts[i2], colour_error ); + cxr_debug_line( verts[i1], poly->center, colour_error ); +#endif + return 0; + } + } + + return 1; +} + static int cxr_solid_checkerr( cxr_mesh *mesh ) { v3f *verts = cxr_ab_ptr( mesh->p_abverts, 0 ); @@ -2001,7 +2156,14 @@ CXR_API void cxr_free_world( cxr_world *world ) cxr_ab_free( &world->abverts ); cxr_ab_free( &world->absolids ); - free( world->materials ); + + if( world->materials ) + { + for( int i=0; imaterial_count; i++ ) + free( world->materials[i].name ); + + free( world->materials ); + } free( world ); } @@ -2113,8 +2275,9 @@ CXR_API void cxr_free_tri_mesh( cxr_tri_mesh *mesh ) free( mesh ); } -CXR_API cxr_world *cxr_decompose( cxr_static_mesh *src ) +CXR_API cxr_world *cxr_decompose( cxr_static_mesh *src, i32 *perrcode ) { + u32 error = 0x00; cxr_world *world = malloc( sizeof(*world) ); /* Copy data to internal formats */ @@ -2126,6 +2289,13 @@ CXR_API cxr_world *cxr_decompose( cxr_static_mesh *src ) size_t dsize = sizeof(cxr_material) * src->material_count; world->materials = malloc( dsize ); memcpy( world->materials, src->materials, dsize ); + + for( int i=0; imaterial_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; @@ -2164,12 +2334,20 @@ CXR_API cxr_world *cxr_decompose( cxr_static_mesh *src ) if( edge->freestyle ) goto displacement; } + + if( !cxr_poly_convex( pinf->pmesh, poly ) ) + { + pinf->invalid = 1; + invalid_count ++; + error = k_soliderr_non_convex_poly; + } } if( cxr_solid_checkerr( pinf->pmesh ) ) { pinf->invalid = 1; invalid_count ++; + error = k_soliderr_non_coplanar_vertices; } continue; @@ -2182,7 +2360,6 @@ CXR_API cxr_world *cxr_decompose( cxr_static_mesh *src ) * Main convex decomp algorithm */ int sources_count = world->absolids.count; - u32 error = 0x00; if( invalid_count ) goto decomp_failed; @@ -2228,6 +2405,10 @@ CXR_API cxr_world *cxr_decompose( cxr_static_mesh *src ) decomp_failed: cxr_log( "Error %d\n", error ); cxr_free_world( world ); + + if( perrcode ) + *perrcode = error; + return NULL; } @@ -2665,7 +2846,7 @@ static int cxr_write_disp( cxr_mesh *mesh, cxr_world *world, * 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; @@ -2950,7 +3131,7 @@ static int cxr_write_disp( cxr_mesh *mesh, cxr_world *world, 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] ); @@ -2970,7 +3151,6 @@ static int cxr_write_disp( cxr_mesh *mesh, cxr_world *world, world_corners[side[0]] ); cxr_vdf_kv( output, "material", matptr->name ); - cxr_vdf_kaxis( output, "uaxis", texinfo_shared.uaxis, texinfo_shared.offset[0],