X-Git-Url: https://harrygodden.com/git/?a=blobdiff_plain;f=src%2Fconvexer.c;h=5fac72984d2f489a9aefdc7632d39e8c0489871e;hb=4b19eaf2f9c56078172b3979e856da7abf372e91;hp=185917a615b6bd069760e55d57b63073aaf2187c;hpb=48fae7bf7445a7913f84cdfba5d8633d554b6c9b;p=convexer.git diff --git a/src/convexer.c b/src/convexer.c index 185917a..5fac729 100644 --- a/src/convexer.c +++ b/src/convexer.c @@ -59,6 +59,7 @@ typedef v3f m4x3f[4]; typedef v3f boxf[2]; #define CXR_EPSILON 0.001 +#define CXR_PLANE_SIMILARITY_MAX 0.998 #define CXR_BIG_NUMBER 1e300 #define CXR_INTERIOR_ANGLE_MAX 0.998 #define CXR_API @@ -165,6 +166,7 @@ struct cxr_texinfo { v3f uaxis, vaxis; v2f offset, scale; + double winding; }; // simple VDF writing interface @@ -798,7 +800,7 @@ static struct cxr_mesh *cxr_pull_best_solid( { struct cxr_loop *loop = cxr_ab_ptr(&mesh->loops, polya->loop_start+j); if( plane_polarity( planeb, vertices[loop->index] ) > 0.001 || - v3_dot(polya->normal,polyb->normal) > 0.98500 ) + v3_dot(polya->normal,polyb->normal) > CXR_PLANE_SIMILARITY_MAX ) { edge_tagged[i] = 1; break; @@ -836,7 +838,7 @@ static struct cxr_mesh *cxr_pull_best_solid( struct cxr_polygon *polyj = cxr_ab_ptr(&mesh->polys,connected_planes[j]); struct cxr_polygon *polyk = cxr_ab_ptr(&mesh->polys,connected_planes[k]); - if( v3_dot(polyj->normal, polyk->normal) > 0.98500 ) + if( v3_dot(polyj->normal, polyk->normal) > CXR_PLANE_SIMILARITY_MAX ) goto IL_TAG_VERT; } } @@ -910,8 +912,8 @@ IL_TAG_NEXT_VERT:; edge_tagged[i] = 1; } - /* Debug stuff -- - for( int i=0; icount; i++ ) if( vertex_tagged[i] ) cxr_debug_box( vertices[i], 0.03, (v4f){0.0,0.0,0.0,1.0}); @@ -924,7 +926,7 @@ IL_TAG_NEXT_VERT:; if( hot_edge[i] ) cxr_debug_line( vertices[ edge->i0 ], vertices[ edge->i1 ], (v4f){0.0,1.0,1.0,1.0}); } - */ + // count regions int *faces_tagged = malloc(mesh->polys.count*sizeof(int)); @@ -940,6 +942,12 @@ IL_TAG_NEXT_VERT:; } *candidates = malloc( mesh->polys.count *sizeof(struct csolid) ); int candidate_count = 0; + + struct tedge + { + int i0, i1; + } + *edge_references = malloc( mesh->edges.count *sizeof(struct tedge) ); for( int i=0; ipolys.count; i++ ) { @@ -973,11 +981,15 @@ IL_TAG_NEXT_VERT:; { 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 // - // TODO: is this unused due to hotedge improvements? leaving for safety... + // This can sort out SOME invalid configs, but not all. + // It would be nice to find a more robust clustering algorithm for this. + // struct cxr_polygon *poly_to_add = cxr_ab_ptr(&mesh->polys, loop->poly_right ); for( int l=0; l < poly_to_add->loop_total; l++ ) @@ -995,15 +1007,13 @@ IL_TAG_NEXT_VERT:; for( int m=0; mpolys,solid[m]); - if( v3_dot( polym->normal, future_face->normal ) > 0.98500 ) + if( v3_dot( polym->normal,future_face->normal) > CXR_PLANE_SIMILARITY_MAX) goto IL_SKIP_PLANE_ADD; } IL_SKIP_SIMILAR_PLANES:; } - // This plane passed all checks so we can add it to the current solid - solid[ solid_len ++ ] = loop->poly_right; faces_tagged[ loop->poly_right ] = i; changed = 1; @@ -1017,6 +1027,25 @@ IL_TAG_NEXT_VERT:; 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 + for( int j=0; jpolys, 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; lstart = solid_buffer_len; @@ -1033,8 +1062,12 @@ IL_TAG_NEXT_VERT:; v3_divs( csolid->center, solid_len, csolid->center ); solid_buffer_len += solid_len; + + IL_CANCEL_SOLID:; } + 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 @@ -1267,13 +1300,6 @@ IL_TAG_NEXT_VERT:; exist_face->loop_total = -1; } - - // Split manifold up by unique planes if it has more than 1 - // otherwise, just use that face - // - // TODO: Need to build new manifold in sections, stably - // currently there is an unsupported case where the manifold splits - // are on located on an implicit face, causing 1-length manifolds. int new_polys = 0; int pullmesh_new_start = pullmesh->polys.count; @@ -1299,7 +1325,7 @@ IL_TAG_NEXT_VERT:; // 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: Find a well defined rule here. + // TODO(harry): Find a well defined rule here. int collapse_used_segments = (u32)fewest_manifold_splits & 0x1? 0: 1; @@ -1608,12 +1634,13 @@ static void cxr_calculate_axis( v2_zero( transform->offset ); v2_div( (v2f){128.0, 128.0}, texture_res, transform->scale ); + transform->winding = 1.0; return; } // Detect if UV is reversed double winding = v2_cross( tT, bT ) >= 0.0f? 1.0f: -1.0f; - + // UV projection reference v2f vY, vX; v2_muls((v2f){1,0}, winding, vX); @@ -1678,6 +1705,7 @@ static void cxr_calculate_axis( v3_copy( vaxis, transform->vaxis ); v2_copy( tex_offset, transform->offset ); v2_copy( uv_scale, transform->scale ); + transform->winding = winding; } CXR_API struct cxr_input_mesh *cxr_decompose(struct cxr_input_mesh *src) @@ -1751,9 +1779,6 @@ CXR_API struct cxr_input_mesh *cxr_decompose(struct cxr_input_mesh *src) struct cxr_auto_buffer solids; cxr_ab_init( &solids, sizeof(struct cxr_mesh *), 2 ); - // TODO: Preprocessor stages - // - Split mesh up into islands before doing anything here - // - Snap vertices to grid (0.25u) ? while(1) { struct cxr_mesh *res = cxr_pull_best_solid( main_mesh, &abverts, 0, &error ); @@ -1884,7 +1909,7 @@ static void cxr_write_disp(struct cxr_mesh *mesh, struct cxr_input_mesh *inputme // human editable. v3f avg_normal, refv, refu, refn; - v3_zero(refv); v3_zero(refu); v4_zero(refn); + v3_zero(refv); v3_zero(refu); v3_zero(refn); for( int i=0; ipolys.count; i++ ) { @@ -1892,9 +1917,10 @@ static void cxr_write_disp(struct cxr_mesh *mesh, struct cxr_input_mesh *inputme v3_add( poly->normal, avg_normal, avg_normal ); } v3_divs( avg_normal, mesh->polys.count, avg_normal ); - v3_normalize( avg_normal ); // TODO: This can be zero length. Should add a safety check + 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 ); // Approximately matching the area of the result brush faces to the actual area @@ -1979,11 +2005,13 @@ static void cxr_write_disp(struct cxr_mesh *mesh, struct cxr_input_mesh *inputme } } + // TODO(harry): This currently only supports power 2 displacements + // its quite straightforward to upgrade it. + // int dispedge[16]; v2f corner_uvs[4]; int dispedge_count; int disp_count = 0; - struct cxr_texinfo texinfo_shared; for( int i=0; ipolys.count; i++ ) { @@ -2014,8 +2042,8 @@ static void cxr_write_disp(struct cxr_mesh *mesh, struct cxr_input_mesh *inputme // 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}); + + //cxr_debug_box( cxr_ab_ptr(abverts,l0->index),0.08,(v4f){0.0,0.0,1.0,1.0}); // Collect edges // -------------------- @@ -2166,15 +2194,10 @@ static void cxr_write_disp(struct cxr_mesh *mesh, struct cxr_input_mesh *inputme } } - for( int j=0; j<5; j++ ) - { - cxr_log( "%d %d %d %d %d\n", grid[j*5+0],grid[j*5+1],grid[j*5+2],grid[j*5+3],grid[j*5+4]); - } - // Create brush vertices based on UV map // Create V reference based on first displacement. - // TODO: This is not the most stable selection method! + // 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. // @@ -2191,11 +2214,17 @@ static void cxr_write_disp(struct cxr_mesh *mesh, struct cxr_input_mesh *inputme cxr_calculate_axis( &tx, tri_ref, corner_uvs, (v2f){512,512} ); v3_muls( tx.vaxis, -1.0, refv ); - int v_cardinal = cxr_cardinal( refv, n_cardinal ); - v3_copy( avg_normal, refn ); + int v_cardinal = cxr_cardinal( refv, -1 ); + + v3_cross( tx.vaxis, tx.uaxis, refn ); + v3_muls( refn, -tx.winding, refn ); + + int n1_cardinal = cxr_cardinal( refn, v_cardinal ); + + //v3_copy( avg_normal, refn ); int u_cardinal = 0; - if( u_cardinal == n_cardinal || u_cardinal == v_cardinal ) u_cardinal ++; - if( u_cardinal == n_cardinal || u_cardinal == v_cardinal ) u_cardinal ++; + if( u_cardinal == n1_cardinal || u_cardinal == v_cardinal ) u_cardinal ++; + if( u_cardinal == n1_cardinal || u_cardinal == v_cardinal ) u_cardinal ++; v3_zero(refu); refu[u_cardinal] = tx.uaxis[u_cardinal] > 0.0? 1.0: -1.0; @@ -2206,13 +2235,16 @@ static void cxr_write_disp(struct cxr_mesh *mesh, struct cxr_input_mesh *inputme v3_muladds( face_center, refn, 1.5, pn ); v3_muladds( face_center, refv, 1.5, pv ); v3_muladds( face_center, refu, 1.5, pu ); - - 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} ); + + 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} ); + } } // Create world cordinates @@ -2232,14 +2264,25 @@ static void cxr_write_disp(struct cxr_mesh *mesh, struct cxr_input_mesh *inputme } double *colour = colours_random[cxr_range(disp_count,8)]; - 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 ); 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_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 ); + */ + // Apply world transform for( int j=0; j<8; j++ ) { @@ -2247,11 +2290,9 @@ static void cxr_write_disp(struct cxr_mesh *mesh, struct cxr_input_mesh *inputme world_corners[j][2] += cxr_context.offset_z; } - if( disp_count == 0 ) - { - cxr_calculate_axis( &texinfo_shared, world_corners, world_uv, - (v2f){ matptr->res[0], matptr->res[1] } ); - } + struct 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" ); @@ -2382,8 +2423,6 @@ static void cxr_write_disp(struct cxr_mesh *mesh, struct cxr_input_mesh *inputme } } - cxr_log( "Disp count: %d\n", disp_count ); - // Main loop #if 0 int pool[25]; @@ -2499,6 +2538,44 @@ IL_DISP_ERROR_COUNT: free( vertinfo ); } +static int cxr_solid_checkerr(struct cxr_mesh *mesh, struct cxr_auto_buffer *abverts ) +{ + int err_count = 0; + + for( int i=0; ipolys.count; i++ ) + { + int plane_err = 0; + + struct cxr_polygon *poly = cxr_ab_ptr(&mesh->polys,i); + v4f plane; + + normal_to_plane( poly->normal, poly->center, plane ); + + for( int j=0; jloop_total; j++ ) + { + struct cxr_loop *loop = cxr_ab_ptr(&mesh->loops, poly->loop_start+j); + double *vert = cxr_ab_ptr(abverts,loop->index); + + if( fabs(plane_polarity(plane,vert)) > 0.0025 ) + { + err_count ++; + plane_err ++; + + v3f ref; + plane_project_point( plane, vert, ref ); + + cxr_debug_line( ref, vert, colour_error ); + cxr_debug_box( vert, 0.1, colour_error ); + } + } + + if( plane_err ) + cxr_debug_poly( mesh, poly, cxr_ab_ptr(abverts,0), colour_error ); + } + + return err_count; +} + CXR_API i32 cxr_convert_mesh_to_vmf(struct cxr_input_mesh *src, struct cxr_vdf *output) { // Split mesh into islands @@ -2506,20 +2583,17 @@ CXR_API i32 cxr_convert_mesh_to_vmf(struct cxr_input_mesh *src, struct cxr_vdf * struct cxr_mesh *main_mesh = cxr_to_internal_format(src, &abverts); u32 error = 0x00; + int invalid_count = 0; struct solidinf { struct cxr_mesh *pmesh; - int is_displacement; + int is_displacement, invalid; }; struct cxr_auto_buffer solids; cxr_ab_init( &solids, sizeof(struct solidinf), 2 ); - // TODO: Preprocessor stages - // - Split mesh up into islands before doing anything here (DONE) - // - Snap vertices to grid (0.25u) ? - // Preprocessor 1: Island seperation // --------------- @@ -2534,7 +2608,7 @@ CXR_API i32 cxr_convert_mesh_to_vmf(struct cxr_input_mesh *src, struct cxr_vdf * } cxr_ab_push( &solids, &(struct solidinf){main_mesh,0} ); - // Preprocessor 2: Displacement break-out + // Preprocessor 2: Displacement break-out and error checking // --------------- for( int i=0; ipmesh, &abverts ) ) + { + pinf->invalid = 1; + invalid_count ++; + } + continue; IL_SOLID_IS_DISPLACEMENT:; @@ -2569,7 +2649,7 @@ CXR_API i32 cxr_convert_mesh_to_vmf(struct cxr_input_mesh *src, struct cxr_vdf * { struct solidinf pinf = *(struct solidinf *)cxr_ab_ptr(&solids, i); - if( pinf.is_displacement ) + if( pinf.is_displacement || pinf.invalid ) continue; while(1) @@ -2598,6 +2678,8 @@ CXR_API i32 cxr_convert_mesh_to_vmf(struct cxr_input_mesh *src, struct cxr_vdf * if( error ) break; } + else + break; } else break;