void Test2( void ) { int i, j, k; int v1, v2; int tri; for ( i = 0; i < vertexnum; i++ ) { tri = 0; for ( j = 0; j < verts[i].edgenum; j++ ) { v1 = verts[i].edges[j]; #if 0 fprintf( handle, "%f %f %f\n", vertices[i][0]/SCL, vertices[i][1]/SCL, vertices[i][2]/SCL ); fprintf( handle, "%f %f %f\n", vertices[v1][0]/SCL, vertices[v1][1]/SCL, vertices[v1][2]/SCL ); fprintf( handle, "%f %f %f\n", vertices[v1][0]/SCL, vertices[v1][1]/SCL, vertices[v1][2]/SCL ); fprintf( handle, "\n" ); #else for ( k = 0; k < verts[i].edgenum; k++ ) { if ( j == k ) continue; v2 = verts[i].edges[k]; if ( TestEdge( v1, v2 ) || TestEdge( v2, v1 ) ) { if ( TestTri( i, v1, v2 ) || TestTri( v1, i, v2 ) || TestTri( v2, i, v1 ) ) continue; AddTri( i, v1, v2 ); AddTri( v1, i, v2 ); AddTri( v2, i, v1 ); #if 0 fprintf( handle, "%f %f %f\n", vertices[i][0]/SCL, vertices[i][1]/SCL, vertices[i][2]/SCL ); fprintf( handle, "%f %f %f\n", vertices[v1][0]/SCL, vertices[v1][1]/SCL, vertices[v1][2]/SCL ); fprintf( handle, "%f %f %f\n", vertices[v2][0]/SCL, vertices[v2][1]/SCL, vertices[v2][2]/SCL ); #else fprintf( handle, "%d %d %d\n", i, v1, v2 ); #endif fprintf( handle, "\n" ); tri++; } } #endif } printf( "v%d: %d tris\n", i, tri ); } }
/** * @note Can be recursively reentered */ static void TestEdge (vec_t start, vec_t end, int p1, int p2, int startvert) { int k; vec_t dist, error; vec3_t delta, exact, off, p; if (p1 == p2) { c_degenerate++; return; /* degenerate edge */ } for (k = startvert; k < num_edge_verts; k++) { const int j = edge_verts[k]; if (j == p1 || j == p2) continue; VectorCopy(curTile->vertexes[j].point, p); VectorSubtract(p, edge_start, delta); dist = DotProduct(delta, edge_dir); if (dist <= start || dist >= end) continue; /* off an end */ VectorMA(edge_start, dist, edge_dir, exact); VectorSubtract(p, exact, off); error = VectorLength(off); if (fabs(error) > OFF_EPSILON) continue; /* not on the edge */ /* break the edge */ c_tjunctions++; TestEdge(start, dist, p1, j, k + 1); TestEdge(dist, end, j, p2, k + 1); return; } /* the edge p1 to p2 is now free of tjunctions */ if (numsuperverts >= MAX_SUPERVERTS) Sys_Error("MAX_SUPERVERTS (%i)", numsuperverts); superverts[numsuperverts] = p1; numsuperverts++; }
static void FixFaceEdges (node_t* node, face_t* f) { int i, base; vec3_t e2; int count[MAX_SUPERVERTS], start[MAX_SUPERVERTS]; if (f->merged || f->split[0] || f->split[1]) return; numsuperverts = 0; for (i = 0; i < f->numpoints; i++) { const int p1 = f->vertexnums[i]; const int p2 = f->vertexnums[(i + 1) % f->numpoints]; VectorCopy(curTile->vertexes[p1].point, edge_start); VectorCopy(curTile->vertexes[p2].point, e2); FindEdgeVerts(edge_start, e2); VectorSubtract(e2, edge_start, edge_dir); vec_t len = VectorNormalize(edge_dir); start[i] = numsuperverts; TestEdge(0, len, p1, p2, 0); count[i] = numsuperverts - start[i]; } /* entire face collapsed */ if (numsuperverts < 3) { f->numpoints = 0; c_facecollapse++; return; } /* we want to pick a vertex that doesn't have tjunctions * on either side, which can cause artifacts on trifans, * especially underwater */ for (i = 0; i < f->numpoints; i++) { if (count[i] == 1 && count[(i + f->numpoints - 1) % f->numpoints] == 1) break; } if (i == f->numpoints) { c_badstartverts++; base = 0; } else { /* rotate the vertex order */ base = start[i]; } /* this may fragment the face if > MAXEDGES */ FaceFromSuperverts(node, f, base); }
void CBuild::BuildCForm () { // Collecting data Phase ("CFORM: creating..."); vecFace* cfFaces = new vecFace(); vecVertex* cfVertices = new vecVertex(); { xr_vector<bool> cfVertexMarks; cfVertexMarks.assign (lc_global_data()->g_vertices().size(),false); Status("Sorting..."); std::sort(lc_global_data()->g_vertices().begin(),lc_global_data()->g_vertices().end()); Status("Collecting faces..."); cfFaces->reserve (lc_global_data()->g_faces().size()); for (vecFaceIt I=lc_global_data()->g_faces().begin(); I!=lc_global_data()->g_faces().end(); ++I) { Face* F = *I; if (F->Shader().flags.bCollision) { cfFaces->push_back(F); int index = GetVertexIndex(F->v[0]); cfVertexMarks[index] = true; index = GetVertexIndex(F->v[1]); cfVertexMarks[index] = true; index = GetVertexIndex(F->v[2]); cfVertexMarks[index] = true; } } Status("Collecting vertices..."); cfVertices->reserve (lc_global_data()->g_vertices().size()); std::sort(cfFaces->begin(),cfFaces->end()); for (u32 V=0; V<lc_global_data()->g_vertices().size(); V++) if (cfVertexMarks[V]) cfVertices->push_back(lc_global_data()->g_vertices()[V]); } float p_total = 0; float p_cost = 1.f/(cfVertices->size()); Fbox BB; BB.invalidate(); for (vecVertexIt it = cfVertices->begin(); it!=cfVertices->end(); it++) BB.modify((*it)->P ); // CForm Phase ("CFORM: collision model..."); Status ("Items to process: %d", cfFaces->size()); p_total = 0; p_cost = 1.f/(cfFaces->size()); // Collect faces CDB::CollectorPacked CL (BB,cfVertices->size(),cfFaces->size()); for (vecFaceIt F = cfFaces->begin(); F!=cfFaces->end(); F++) { Face* T = *F; TestEdge (T->v[0],T->v[1],T); TestEdge (T->v[1],T->v[2],T); TestEdge (T->v[2],T->v[0],T); CL.add_face ( T->v[0]->P, T->v[1]->P, T->v[2]->P, T->dwMaterialGame, materials()[T->dwMaterial].sector, T->sm_group ); Progress(p_total+=p_cost); // progress } if (bCriticalErrCnt) { err_save (); clMsg ("MultipleEdges: %d faces",bCriticalErrCnt); } xr_delete (cfFaces); xr_delete (cfVertices); // Models Status ("Models..."); for (u32 ref=0; ref<mu_refs().size(); ref++) mu_refs()[ref]->export_cform_game(CL); // Simplification if (g_params().m_quality!=ebqDraft) SimplifyCFORM (CL); // bb? BB.invalidate (); for (size_t it = 0; it<CL.getVS(); it++) BB.modify( CL.getV()[it] ); // Saving string_path fn; IWriter* MFS = FS.w_open (strconcat(sizeof(fn),fn,pBuild->path,"level.cform")); Status ("Saving..."); // Header hdrCFORM hdr; hdr.version = CFORM_CURRENT_VERSION; hdr.vertcount = (u32)CL.getVS(); hdr.facecount = (u32)CL.getTS(); hdr.aabb = BB; MFS->w (&hdr,sizeof(hdr)); // Data MFS->w (CL.getV(),(u32)CL.getVS()*sizeof(Fvector)); MFS->w (CL.getT(),(u32)CL.getTS()*sizeof(CDB::TRI)); // Clear pDeflector (it is stored in the same memory space with dwMaterialGame) for (vecFaceIt I=lc_global_data()->g_faces().begin(); I!=lc_global_data()->g_faces().end(); I++) { Face* F = *I; F->pDeflector = NULL; } FS.w_close (MFS); }
void CBuild::BuildCForm () { Phase ("CFORM: construction..."); //Status ("Building base mesh : vertices..."); _mesh mesh; // a mesh object _decimater decimater(mesh); // a decimater object, connected to a mesh _HModQuadric hModQuadric; // use a quadric module decimater.add (hModQuadric); // register module at the decimater decimater.module(hModQuadric).set_max_err (0.0001,false); // error-limit 0.0001 // Initializing mesh Status ("Building base mesh : vertices[%d]...",g_vertices.size()); for (vecVertexIt _v=g_vertices.begin(); _v!=g_vertices.end(); _v++) (*_v)->handle = _mesh::InvalidVertexHandle.idx(); Status ("Building base mesh : base faces[%d]...",g_faces.size()); std::vector <_mesh::VertexHandle> fhandles; xr_vector <cform_FailFace> failedfaces; cform_mergeprops fmergeprops; for (vecFaceIt I=g_faces.begin(); I!=g_faces.end(); I++) { Progress (float(I-g_faces.begin())/float(g_faces.size())); Face* F = *I; if (F->Shader().flags.bCollision) { // test correctness TestEdge (F->v[0],F->v[1],F); TestEdge (F->v[1],F->v[2],F); TestEdge (F->v[2],F->v[0],F); // add vertices fhandles.clear (); for (u32 v=0; v<3; v++) { _mesh::VertexHandle h = _mesh::VertexHandle(F->v[v]->handle); if (_mesh::InvalidVertexHandle == h) { Fvector& p = F->v[v]->P; h = mesh.add_vertex (_mesh::Point(p.x,p.y,p.z)); F->v[v]->handle = h.idx(); } fhandles.push_back (h); } // add face fmergeprops.material = F->dwMaterialGame; fmergeprops.sector = materials[F->dwMaterial].sector; _mesh::FaceHandle hface = mesh.add_face (fhandles); if (hface == _mesh::InvalidFaceHandle) { failedfaces.push_back (cform_FailFace()); failedfaces.back().P[0] = F->v[0]->P; failedfaces.back().P[1] = F->v[1]->P; failedfaces.back().P[2] = F->v[2]->P; failedfaces.back().props = fmergeprops.props; } else mesh.face(hface).set_props (fmergeprops.props); } } if (bCriticalErrCnt) { err_save (); clMsg ("MultipleEdges: %d faces",bCriticalErrCnt); } Status ("Building base mesh : models[%d]...",mu_refs.size()); mesh.garbage_collection (); for (u32 ref=0; ref<mu_refs.size(); ref++) mu_refs[ref]->export_cform_game(mesh,failedfaces); Status ("Building base mesh : normals..."); mesh.garbage_collection (); mesh.request_vertex_normals (); mesh.update_vertex_normals (); // Decimate Status ("Reconstructing mesh-topology..."); clMsg ("%d faces failed topology check", failedfaces.size()); clMsg ("%f%% geometry/artist quality", 100.f * (1-float(failedfaces.size())/float(mesh.n_faces()))); decimater.initialize (); // let the decimater initialize the mesh and the modules int nf_before = int (mesh.n_faces()); int nv_before = int (mesh.n_vertices()); int nc = decimater.decimate (nv_before); // do decimation, as large, as possible mesh.garbage_collection (); int nf_after = int (mesh.n_faces()); int nv_after = int (mesh.n_vertices()); clMsg ("vertices: was[%d], now[%d] => %f %% left",nv_before,nv_after, 100.f*float(nv_after)/float(nv_before) ); clMsg (" faces: was[%d], now[%d] => %f %% left",nf_before,nf_after, 100.f*float(nf_after)/float(nf_before) ); // Decimate Status ("Refactoring CFORM..."); Fbox BB; BB.invalidate(); _mesh::VertexIter vit =mesh.vertices_begin(),vend=mesh.vertices_end(); for (; vit!=vend; ++vit) BB.modify( reinterpret_cast<Fvector&>(mesh.point(vit)) ); CDB::CollectorPacked CL(BB,mesh.n_vertices(),mesh.n_faces()); _mesh::FaceIter fit=mesh.faces_begin(),fend=mesh.faces_end(); for (; fit!=fend; ++fit){ // get vertex-handles fhandles.clear (); for (_mesh::CFVIter fv_it=mesh.cfv_iter(fit); fv_it; ++fv_it) fhandles.push_back (fv_it.handle()); CL.add_face_D ( reinterpret_cast<Fvector&>(mesh.point (fhandles[0])), reinterpret_cast<Fvector&>(mesh.point (fhandles[1])), reinterpret_cast<Fvector&>(mesh.point (fhandles[2])), fit->props () ); } Status ("Restoring fail-faces..."); for (u32 it=0; it<failedfaces.size(); it++) { cform_FailFace& F = failedfaces[it]; CL.add_face_D ( F.P[0], F.P[1], F.P[2], F.props ); } // Saving Status ("Saving..."); nf_after = int (CL.getTS()); nv_after = int (CL.getVS()); clMsg ("vertices: was[%d], now[%d] => %f %% left",nv_before,nv_after, 100.f*float(nv_after)/float(nv_before) ); clMsg (" faces: was[%d], now[%d] => %f %% left",nf_before,nf_after, 100.f*float(nf_after)/float(nf_before) ); string512 fn; IWriter* MFS = FS.w_open (strconcat(fn,pBuild->path,"level.cform")); // Header hdrCFORM hdr; hdr.version = CFORM_CURRENT_VERSION; hdr.vertcount = (u32)CL.getVS(); hdr.facecount = (u32)CL.getTS(); hdr.aabb = BB; MFS->w (&hdr,sizeof(hdr)); // Data MFS->w (CL.getV(),(u32)CL.getVS()*sizeof(Fvector)); MFS->w (CL.getT(),(u32)CL.getTS()*sizeof(CDB::TRI)); // Clear pDeflector (it is stored in the same memory space with dwMaterialGame) for (vecFaceIt I=g_faces.begin(); I!=g_faces.end(); I++) { Face* F = *I; F->pDeflector = NULL; } FS.w_close (MFS); }