X-Git-Url: https://harrygodden.com/git/?a=blobdiff_plain;f=src%2Fconvexer.c;h=adcaf6007a2ae626a9b8d94b9bd9e52ce4523673;hb=4a01d99d563ce228c13591bbed3e24f05241c586;hp=ed04caf6899c6b86eef2ca90910b609166137d73;hpb=730fbd0939c0f334b40840a1e97757f642366448;p=convexer.git diff --git a/src/convexer.c b/src/convexer.c index ed04caf..adcaf60 100644 --- a/src/convexer.c +++ b/src/convexer.c @@ -31,6 +31,8 @@ stb/ C Sean Barrets image I/O */ +const char *cxr_build_time = __DATE__ " @" __TIME__; + #include #include #include @@ -38,8 +40,6 @@ #include #include -const char *cxr_build_time = __DATE__ " @" __TIME__; - typedef uint8_t u8; typedef uint16_t u16; typedef uint32_t u32; @@ -59,6 +59,8 @@ typedef v3f m4x3f[4]; typedef v3f boxf[2]; #define CXR_EPSILON 0.001 +#define CXR_PLANE_SIMILARITY_MAX 0.999 +#define CXR_BIG_NUMBER 1e300 #define CXR_INTERIOR_ANGLE_MAX 0.998 #define CXR_API #define CXR_DIRTY_OPTIMISATION 1 @@ -164,6 +166,7 @@ struct cxr_texinfo { v3f uaxis, vaxis; v2f offset, scale; + double winding; }; // simple VDF writing interface @@ -375,6 +378,32 @@ static void cxr_vdf_kaxis(struct cxr_vdf *vdf, const char *strk, v3f normal, dou { 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(struct 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(struct 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; ifp, "%f", doubles[i] ); + else fprintf( vdf->fp, "%f ", doubles[i] ); + } + fprintf( vdf->fp, "\"\n" ); +} +static void cxr_vdf_karrv3f(struct 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; ifp, "%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] ); + } + fprintf( vdf->fp, "\"\n" ); +} static void cxr_vdf_plane(struct 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", @@ -770,8 +799,8 @@ static struct cxr_mesh *cxr_pull_best_solid( for( int j=0; jloop_total; j++ ) { 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 ) + if( plane_polarity( planeb, vertices[loop->index] ) > 0.000025 || + v3_dot(polya->normal,polyb->normal) > CXR_PLANE_SIMILARITY_MAX ) { edge_tagged[i] = 1; break; @@ -809,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; } } @@ -968,7 +997,7 @@ 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; } @@ -1581,12 +1610,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); @@ -1651,6 +1681,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) @@ -1781,9 +1812,32 @@ CXR_API struct cxr_input_mesh *cxr_decompose(struct cxr_input_mesh *src) return NULL; } +static int cxr_cardinal( v3f a, int ignore ) +{ + int component = 0; + double component_max = -CXR_BIG_NUMBER; + + for( int i=0; i<3; i++ ) + { + if( i == ignore ) continue; + + if( fabs(a[i]) > component_max ) + { + component_max = fabs(a[i]); + component = i; + } + } + double d = a[component] >= 0.0? 1.0: -1.0; + v3_zero( a ); + a[component] = d; + + return component; +} + // Convert contiguous mesh to patch of displacments // -static void cxr_write_disp(struct cxr_mesh *mesh, struct cxr_vdf *output, +static void cxr_write_disp(struct cxr_mesh *mesh, struct cxr_input_mesh *inputmesh, + struct cxr_vdf *output, struct cxr_auto_buffer *abverts) { // Create a graph which maps vertices by their connections @@ -1833,7 +1887,8 @@ static void cxr_write_disp(struct cxr_mesh *mesh, struct cxr_vdf *output, // These are clamped to be cardinal directions as to make the VMF somewhat // human editable. - v3f avg_normal; + v3f avg_normal, refv, refu, refn; + v3_zero(refv); v3_zero(refu); v3_zero(refn); for( int i=0; ipolys.count; i++ ) { @@ -1844,30 +1899,34 @@ static void cxr_write_disp(struct cxr_mesh *mesh, struct cxr_vdf *output, v3_normalize( avg_normal ); // TODO: 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... - - double component_max = fabs( avg_normal[2] ); - int component = 2; + int n_cardinal = cxr_cardinal( avg_normal, -1 ); - for( int i=0; i<2; i++ ) - { - if( fabs(avg_normal[i]) > component_max ) - { - component_max = fabs(avg_normal[i]); - component = i; - } - } - double d = avg_normal[component] >= 0.0? 1.0: -1.0; - v3_zero( avg_normal ); - avg_normal[component] = d; - // 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; + v2f uv_center; + v3f face_center; + + v2_fill( uvboundmin, CXR_BIG_NUMBER ); + v2_fill( uvboundmax, -CXR_BIG_NUMBER ); + v3_fill( faceboundmin, CXR_BIG_NUMBER ); + v3_fill( faceboundmax, -CXR_BIG_NUMBER ); + for( int i=0; ipolys.count; i++ ) { struct cxr_polygon *poly = cxr_ab_ptr( &mesh->polys, i ); + + for( int j=0; jloop_total; j++ ) + { + struct cxr_loop *lp0 = cxr_ab_ptr(&mesh->loops, poly->loop_start+j); + v2_minv( lp0->uv, uvboundmin, uvboundmin); + v2_maxv( lp0->uv, uvboundmax, uvboundmax); + v3_minv( cxr_ab_ptr(abverts,lp0->index), faceboundmin, faceboundmin ); + v3_maxv( cxr_ab_ptr(abverts,lp0->index), faceboundmax, faceboundmax ); + } for( int j=0; jloop_total-2; j++ ) { @@ -1889,6 +1948,11 @@ static void cxr_write_disp(struct cxr_mesh *mesh, struct cxr_vdf *output, } } + v3_add( faceboundmax, faceboundmin, face_center ); + v3_muls( face_center, 0.5, face_center ); + v2_add( uvboundmin, uvboundmax, uv_center ); + v2_muls( uv_center, 0.5, uv_center ); + sf = sqrt( face_area / uv_area ); int corner_count = 0; @@ -1940,6 +2004,11 @@ static void cxr_write_disp(struct cxr_mesh *mesh, struct cxr_vdf *output, if( info->corner ) { int corner_count = 1; + + struct 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; @@ -1948,9 +2017,8 @@ static void cxr_write_disp(struct cxr_mesh *mesh, struct cxr_vdf *output, // 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}); - disp_count ++; + + //cxr_debug_box( cxr_ab_ptr(abverts,l0->index),0.08,(v4f){0.0,0.0,1.0,1.0}); // Collect edges // -------------------- @@ -2009,12 +2077,14 @@ static void cxr_write_disp(struct cxr_mesh *mesh, struct cxr_vdf *output, if( !coninfo->boundary ) 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; @@ -2036,12 +2106,7 @@ static void cxr_write_disp(struct cxr_mesh *mesh, struct cxr_vdf *output, v2f va, vb; v2_sub( corner_uvs[1], corner_uvs[0], va ); v2_sub( corner_uvs[2], corner_uvs[0], vb ); - - if( v2_cross( va,vb ) < 0.0 ) - cxr_log( "Uv is flipped!\n" ); - else - cxr_log( "Uv is normal\n" ); - + // Connect up the grid // // 0 1 2 3 4 @@ -2056,21 +2121,15 @@ static void cxr_write_disp(struct cxr_mesh *mesh, struct cxr_vdf *output, // int grid[25]; - for( int j=0; j<25; j++ ) grid[j] = 0; - for( int j=0; j<5; j++ ) - { - grid[j] = dispedge[j]; - vertinfo[dispedge[j]].used = 1; - } - for( int j=1; j<5; j++ ) - { - grid[j*5] = dispedge[16-j]; - vertinfo[dispedge[16-j]].used = 1; - } + 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]; - for( int j=1; j<5; j++ ) + // Grid fill + for( int j=1; j<4; j++ ) { - for( int k=1; k<5; k++ ) + for( int k=1; k<4; k++ ) { int s0 = grid[(j-1)*5+k], s1 = grid[j*5+k-1]; @@ -2087,11 +2146,11 @@ static void cxr_write_disp(struct cxr_mesh *mesh, struct cxr_vdf *output, int cona = graph[va->con_start+l], conb = graph[vb->con_start+m]; - if( vertinfo[cona].used || vertinfo[conb].used ) - continue; - if( cona == conb ) { + if( vertinfo[cona].used || vertinfo[cona].boundary ) + continue; + grid[ j*5+k ] = cona; vertinfo[cona].used = 1; @@ -2109,16 +2168,236 @@ static void cxr_write_disp(struct cxr_mesh *mesh, struct cxr_vdf *output, IL_MATCHED_DISP_INTERIOR_VERT:; } } + + // Create brush vertices based on UV map - // Release grid - for( int j=0; j<25; j++ ) - vertinfo[grid[j]].used = 0; + // Create V reference based on first displacement. + // TODO: 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 ) + { + struct cxr_texinfo tx; + v3f tri_ref[3]; + v3_copy( cxr_ab_ptr(abverts,dispedge[0]), tri_ref[0] ); + v3_copy( cxr_ab_ptr(abverts,dispedge[4]), tri_ref[1] ); + v3_copy( cxr_ab_ptr(abverts,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 ); + + 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 ++; + + v3_zero(refu); + refu[u_cardinal] = tx.uaxis[u_cardinal] > 0.0? 1.0: -1.0; + + v3f p0, pv, pu, pn; + + 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} ); + } + } + + // Create world cordinates + v3f world_corners[8]; + v2f world_uv[4]; + + 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 *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 ) + { + 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++ ) + { + v3_muls( world_corners[j], cxr_context.scale_factor, world_corners[j] ); + world_corners[j][2] += cxr_context.offset_z; + } + + 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" ); + 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); + + v3_lerp( world_corners[0], world_corners[3], ty, lside0 ); + v3_lerp( world_corners[1], world_corners[2], ty, lside1 ); + + 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( cxr_ab_ptr(abverts, 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] ); + } + } + + 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]] ); + + 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 ); + + 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_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_log( "Disp count: %d\n", disp_count ); - // Main loop #if 0 int pool[25]; @@ -2293,7 +2572,7 @@ CXR_API i32 cxr_convert_mesh_to_vmf(struct cxr_input_mesh *src, struct cxr_vdf * IL_SOLID_IS_DISPLACEMENT:; pinf->is_displacement = 1; - cxr_write_disp( pinf->pmesh, output, &abverts ); + cxr_write_disp( pinf->pmesh, src, output, &abverts ); } // Preprocessor 3: Breakup non-convex shapes into sub-solids @@ -2333,6 +2612,8 @@ CXR_API i32 cxr_convert_mesh_to_vmf(struct cxr_input_mesh *src, struct cxr_vdf * if( error ) break; } + else + break; } else break;