X-Git-Url: https://harrygodden.com/git/?a=blobdiff_plain;f=src%2Fconvexer.c;h=adcaf6007a2ae626a9b8d94b9bd9e52ce4523673;hb=4a01d99d563ce228c13591bbed3e24f05241c586;hp=7669e97e1ce3550e3f5f3764f10300785b73d01e;hpb=6c3271c6e76e1e3d3b0a5ab6ea466827832d3046;p=convexer.git diff --git a/src/convexer.c b/src/convexer.c index 7669e97..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 @@ -103,6 +105,7 @@ struct cxr_input_mesh struct cxr_edge { i32 i0, i1; + i32 freestyle; } *edges; @@ -163,6 +166,7 @@ struct cxr_texinfo { v3f uaxis, vaxis; v2f offset, scale; + double winding; }; // simple VDF writing interface @@ -374,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", @@ -473,8 +503,17 @@ static void cxr_mesh_clean_edges(struct cxr_mesh *mesh) struct cxr_edge edge = { i0, i1 }; // --- ! --- // Copy extra information (sharp,freestyle.. etc) here! - // - // if orig_edge_id < mesh->edges.count: edge.foo = mesh->edges[orig].foo + + if( orig_edge_id < mesh->edges.count ) + { + struct cxr_edge *orig_edge = cxr_ab_ptr( &mesh->edges, orig_edge_id ); + edge.freestyle = orig_edge->freestyle; + } + else + { + edge.freestyle = 0; + } + // --- ! --- cxr_ab_push( &new_edges, &edge ); @@ -760,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; @@ -799,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; } } @@ -958,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; } @@ -1571,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); @@ -1641,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) @@ -1771,6 +1812,707 @@ 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_input_mesh *inputmesh, + struct cxr_vdf *output, + struct cxr_auto_buffer *abverts) +{ + // Create a graph which maps vertices by their connections + struct vertinfo + { + int con_start, con_count; // Index into the connection graph + int boundary, + used, + search, + corner; + + double alpha; + } + *vertinfo = malloc( sizeof(struct vertinfo)*abverts->count ); + int *graph = malloc( sizeof(int) * mesh->edges.count*2 ); + + int con_pos = 0; + for( int i=0; icount; i++ ) + { + struct vertinfo *info = &vertinfo[i]; + info->con_start = con_pos; + info->con_count = 0; + info->boundary = 0; + info->corner = 0; + info->used = 0; + info->search = 0; + info->alpha = 0.0; + + for( int j=0; jedges.count; j++ ) + { + struct cxr_edge *edge = cxr_ab_ptr(&mesh->edges,j); + + if( edge->i0 == i || edge->i1 == i ) + { + graph[ con_pos ++ ] = edge->i0 == i? edge->i1: edge->i0; + info->con_count ++; + + if( edge->freestyle ) + info->boundary = 1; + } + } + } + + // 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. + + v3f avg_normal, refv, refu, refn; + v3_zero(refv); v3_zero(refu); v3_zero(refn); + + for( int i=0; ipolys.count; i++ ) + { + struct cxr_polygon *poly = cxr_ab_ptr( &mesh->polys, i ); + 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 + // 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 + // 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++ ) + { + struct cxr_loop *lp0 = cxr_ab_ptr(&mesh->loops, poly->loop_start), + *lp1 = cxr_ab_ptr(&mesh->loops, poly->loop_start+j+1), + *lp2 = cxr_ab_ptr(&mesh->loops, poly->loop_start+j+2); + v3f va, vb, orth; + v3_sub( cxr_ab_ptr(abverts,lp1->index), cxr_ab_ptr(abverts,lp0->index), va ); + v3_sub( cxr_ab_ptr(abverts,lp2->index), cxr_ab_ptr(abverts,lp0->index), vb ); + v3_cross( va, vb, orth ); + + face_area += v3_length( orth ) / 2.0; + + v2f uva, uvb; + v2_sub( lp1->uv, lp0->uv, uva ); + v2_sub( lp2->uv, lp0->uv, uvb ); + + uv_area += fabs(v2_cross( uva, uvb )) / 2.0; + } + } + + 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; + + // Vertex classification + for( int i=0; icount; i++ ) + { + struct vertinfo *info = &vertinfo[i]; + if( !info->boundary ) continue; + + int count = 0, + non_manifold = 1; + + for( int j=0; jcon_count; j++ ) + { + int con = graph[info->con_start+j]; + + if( vertinfo[con].boundary ) + count ++; + 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 ); + } + } + + int dispedge[16]; + v2f corner_uvs[4]; + int dispedge_count; + int disp_count = 0; + + for( int i=0; ipolys.count; i++ ) + { + struct cxr_polygon *basepoly = cxr_ab_ptr(&mesh->polys,i); + + for( int h=0; hloop_total; h ++ ) + { + int i0 = h, + i1 = cxr_range(h+1,basepoly->loop_total); + + struct cxr_loop *l0 = cxr_ab_ptr(&mesh->loops, basepoly->loop_start+i0), + *l1 = cxr_ab_ptr(&mesh->loops, basepoly->loop_start+i1); + struct vertinfo *info = &vertinfo[ l0->index ]; + + 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; + 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 + // -------------------- + + while( dispedge_count < 17 ) + { + struct vertinfo *edge_head = &vertinfo[dispedge[dispedge_count-1]]; + int newvert = 0; + + if( edge_head->corner ) + { + // Find a polygon that has the edge C-1 -> C + for( int j=0; jpolys.count && !newvert; j++ ) + { + struct cxr_polygon *poly = cxr_ab_ptr(&mesh->polys,j); + + for( int k=0; kloop_total; k ++ ) + { + int i0 = k, + i1 = cxr_range(k+1,poly->loop_total); + + struct cxr_loop *l0 = cxr_ab_ptr(&mesh->loops, poly->loop_start+i0), + *l1 = cxr_ab_ptr(&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); + struct cxr_loop *l2 = cxr_ab_ptr(&mesh->loops, poly->loop_start+i2); + + dispedge[dispedge_count ++] = l2->index; + newvert = 1; + poly->loop_total = -1; + break; + } + } + } + } + else + { + for( int j=0; jcon_count; j++ ) + { + int con = graph[edge_head->con_start+j]; + + if( con == -1 ) + continue; + + if( dispedge_count > 1 ) + if( con == dispedge[dispedge_count-2] ) + continue; + + struct vertinfo *coninfo = &vertinfo[con]; + + 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; + + break; + } + } + + if( !newvert ) + { + cxr_debug_box(cxr_ab_ptr(abverts,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++ ) + { + for( int k=1; k<4; k++ ) + { + int s0 = grid[(j-1)*5+k], + s1 = grid[j*5+k-1]; + + struct vertinfo *va = &vertinfo[s0], + *vb = &vertinfo[s1]; + + // Find a common vertex between s0 and s1 + + for( int l=0; lcon_count; l ++ ) + { + for( int m=0; mcon_count; 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; + + grid[ j*5+k ] = cona; + vertinfo[cona].used = 1; + + goto IL_MATCHED_DISP_INTERIOR_VERT; + } + } + } + + // Broken displacement + cxr_log( "Broken displacement!\n" ); + free( graph ); + free( vertinfo ); + return; + + IL_MATCHED_DISP_INTERIOR_VERT:; + } + } + + // Create brush vertices based on UV map + + // 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 ++; + } + } + } + + // Main loop +#if 0 + int pool[25]; + for( int i=0; icount; i++ ) + { + struct vertinfo *info = &vertinfo[i]; + if( info->boundary || info->used ) + continue; + + // Gather all vertices in this displacement + int poolcount = 1, + front_start = 0, + front_count = 1; + pool[0] = i; + info->used = 1; + + IL_GATHER_LOOP:; + + int new_front_start = poolcount; + + for( int j=0; jcon_count; k++ ) + { + int conid = graph[frontvert->con_start+k]; + struct vertinfo *con = &vertinfo[conid]; + + if( frontvert->boundary && !con->boundary ) + continue; + + if( con->used ) + continue; + + if( poolcount == 25 ) + goto IL_DISP_ERROR_COUNT; + + con->used = 1; + pool[ poolcount ++ ] = conid; + } + } + + if( poolcount > new_front_start ) + { + front_start = new_front_start; + front_count = poolcount-front_start; + + goto IL_GATHER_LOOP; + } + + if( poolcount != 25 ) + { +IL_DISP_ERROR_COUNT: + for( int i=0; i25 verts)\n"); + return; + } + + int corners[4]; + int corner_count = 0; + struct cxr_loop *cornerloops[4]; + + // Find corners, and get their loops (for uvs) + // note: the mesh must be split where there is texture seams + // so that two different uv'd loops cant ref the same vertex + // + for( int j=0; jloops.count; k++ ) + { + struct cxr_loop *lp = cxr_ab_ptr(&mesh->loops,k); + if( lp->index == pool[j] ) + { + cornerloops[corner_count] = lp; + break; + } + } + + corner_count ++; + } + } + + if( corner_count !=4 ) + { + free(graph); + free(vertinfo); + cxr_log( "Invalid displacement (!=4 corners)\n" ); + return; + } + + int pivot = corners[0]; + } +#endif + + free( graph ); + free( vertinfo ); +} + CXR_API i32 cxr_convert_mesh_to_vmf(struct cxr_input_mesh *src, struct cxr_vdf *output) { // Split mesh into islands @@ -1808,6 +2550,30 @@ CXR_API i32 cxr_convert_mesh_to_vmf(struct cxr_input_mesh *src, struct cxr_vdf * // Preprocessor 2: Displacement break-out // --------------- + for( int i=0; ipmesh->polys.count; j++ ) + { + struct cxr_polygon *poly = cxr_ab_ptr( &pinf->pmesh->polys, j ); + + for( int k=0; kloop_total; k++ ) + { + struct cxr_loop *lp = cxr_ab_ptr( &pinf->pmesh->loops, poly->loop_start+k ); + struct cxr_edge *edge = cxr_ab_ptr( &pinf->pmesh->edges, lp->edge_index ); + + if( edge->freestyle ) + goto IL_SOLID_IS_DISPLACEMENT; + } + } + + continue; + IL_SOLID_IS_DISPLACEMENT:; + + pinf->is_displacement = 1; + cxr_write_disp( pinf->pmesh, src, output, &abverts ); + } // Preprocessor 3: Breakup non-convex shapes into sub-solids // --------------- @@ -1818,7 +2584,6 @@ 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 ) - // TODO: write displacements here... continue; while(1) @@ -1847,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; @@ -1859,7 +2626,9 @@ CXR_API i32 cxr_convert_mesh_to_vmf(struct cxr_input_mesh *src, struct cxr_vdf * for( int i=0; ipmesh, cxr_ab_ptr(&abverts,0), colours_random[cxr_range(i,8)] ); + + if( !solid->is_displacement ) + cxr_debug_mesh( solid->pmesh, cxr_ab_ptr(&abverts,0), colours_random[cxr_range(i,8)] ); } }