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
{
v3f uaxis, vaxis;
v2f offset, scale;
+ double winding;
};
// simple VDF writing interface
{
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;
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;
}
}
edge_tagged[i] = 1;
}
- /* Debug stuff --
- for( int i=0; i<vertex_count; i++ )
+
+ for( int i=0; i<vert_buffer->count; i++ )
if( vertex_tagged[i] )
cxr_debug_box( vertices[i], 0.03, (v4f){0.0,0.0,0.0,1.0});
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));
}
*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; i<mesh->polys.count; i++ )
{
{
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++ )
for( int m=0; m<solid_len; m++ )
{
struct cxr_polygon *polym = cxr_ab_ptr(&mesh->polys,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;
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; j<solid_len-1; j++ )
+ {
+ for( int k=j+1; k<solid_len; k++ )
+ {
+ struct cxr_polygon *polyj = cxr_ab_ptr(&mesh->polys, 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; l<solid_len; l++ )
+ faces_tagged[ solid[l] ] = -1;
+
+ goto IL_CANCEL_SOLID;
+ }
+ }
+ }
+
// Add entry
struct csolid *csolid = &candidates[candidate_count ++];
csolid->start = solid_buffer_len;
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
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;
// 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;
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);
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)
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 );
// 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; i<mesh->polys.count; 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
+ 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
}
}
+ // 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; i<mesh->polys.count; i++ )
{
// 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
// --------------------
}
}
- 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.
//
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;
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
}
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++ )
{
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" );
}
}
- cxr_log( "Disp count: %d\n", disp_count );
-
// Main loop
#if 0
int pool[25];
free( vertinfo );
}
+static int cxr_solid_checkerr(struct cxr_mesh *mesh, struct cxr_auto_buffer *abverts )
+{
+ int err_count = 0;
+
+ for( int i=0; i<mesh->polys.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; j<poly->loop_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
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
// ---------------
}
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; i<solids.count; i++ )
{
}
}
+ if( cxr_solid_checkerr( pinf->pmesh, &abverts ) )
+ {
+ pinf->invalid = 1;
+ invalid_count ++;
+ }
+
continue;
IL_SOLID_IS_DISPLACEMENT:;
{
struct solidinf pinf = *(struct solidinf *)cxr_ab_ptr(&solids, i);
- if( pinf.is_displacement )
+ if( pinf.is_displacement || pinf.invalid )
continue;
while(1)
if( error ) break;
}
+ else
+ break;
}
else
break;