diff --git a/apps/nexus/crudeview.cpp b/apps/nexus/crudeview.cpp index 379f844e..14590ca7 100644 --- a/apps/nexus/crudeview.cpp +++ b/apps/nexus/crudeview.cpp @@ -24,6 +24,9 @@ History $Log: not supported by cvs2svn $ +Revision 1.2 2004/07/05 15:49:39 ponchio +Windows (DevCpp, mingw) port. + Revision 1.1 2004/07/04 15:30:00 ponchio Changed directory structure. @@ -140,9 +143,16 @@ int main(int argc, char *argv[]) { return -1; } - glClearColor(0, 0, 0, 0); + glClearColor(0, 0, 0, 0); + glEnable(GL_LIGHTING); + glEnable(GL_LIGHT0); + glEnable(GL_NORMALIZE); + glEnable(GL_COLOR_MATERIAL); + + + bool show_normals = true; int quit = 0; - SDL_Event event; + SDL_Event event; int x, y; float alpha = 0; while( !quit ) { @@ -206,10 +216,18 @@ int main(int argc, char *argv[]) { unsigned int val = face_remap[i]; glColor3ub((val * 27)%255, (val * 37)%255, (val * 87)%255); } - for(int k = 0; k < 3; k++) { - Point3f &p = crude.GetVertex(face[k]); - glVertex3f(p[0], p[1], p[2]); + Point3f &p0 = crude.GetVertex(face[0]); + Point3f &p1 = crude.GetVertex(face[1]); + Point3f &p2 = crude.GetVertex(face[2]); + + if(show_normals) { + Point3f n = ((p1 - p0) ^ (p2 - p0)); + glNormal3f(n[0], n[1], n[2]); } + glVertex3f(p0[0], p0[1], p0[2]); + glVertex3f(p1[0], p1[1], p1[2]); + glVertex3f(p2[0], p2[1], p2[2]); + } glEnd(); diff --git a/apps/nexus/decimate.cpp b/apps/nexus/decimate.cpp new file mode 100644 index 00000000..37f5c39b --- /dev/null +++ b/apps/nexus/decimate.cpp @@ -0,0 +1,242 @@ +#include +#include + +// stuff to define the mesh +#include +#include +#include +#include + +// io +//#include +//#include +// update +#include + +#include +#include + +#include +#include "border.h" + +class MyEdge; +class MyFace; +class MyVertex:public vcg::VertexAFVMVNf{public: +ScalarType w; +vcg::math::Quadric >q; +ScalarType & W(){return w;} +} ; +class MyFace : public vcg::FaceAV{}; + +class MyMesh: + public vcg::tri::TriMesh< std::vector, std::vector >{}; + +class MyTriEdgeCollapse: + public vcg::tri::TriEdgeCollapseQuadric< MyMesh, MyTriEdgeCollapse >{ +public: + typedef vcg::tri::TriEdgeCollapseQuadric TECQ; + typedef TECQ::PosType PosType; + MyTriEdgeCollapse(PosType p, int i):TECQ(p,i){} + ~MyTriEdgeCollapse(){} +}; + +using namespace vcg; +using namespace tri; +using namespace nxs; +using namespace std; + +void Cluster(MyMesh &mesh, unsigned int target_faces); + +float Decimate(unsigned int target_faces, + vector &newvert, + vector &newface, + vector &newbord, + vector &vert_remap) { + + MyMesh mesh; + + //build mesh + + for(unsigned int i = 0; i < newvert.size(); i++) { + MyVertex vertex; + vertex.ClearFlags(); + vertex.P() = newvert[i]; + mesh.vert.push_back(vertex); + } + mesh.vn = mesh.vert.size(); + + for(unsigned int i = 0; i < newface.size(); i+=3) { + MyFace face; + face.ClearFlags(); + for(int k = 0; k < 3; k++) { + assert(newface[i+k] < mesh.vn); + face.V(k) = &mesh.vert[newface[i+k]]; + } + mesh.face.push_back(face); + } + mesh.fn = mesh.face.size(); + + //emark borders + for(unsigned int i = 0; i < newbord.size(); i++) + mesh.vert[newbord[i].start_vert].ClearW(); + + // int FinalSize = mesh.face.size()/2; + // if(FinalSize > target_faces) FinalSize = target_faces; + int FinalSize = target_faces; + + int t0=clock(); + + printf("mesh loaded %d %d \n",mesh.vn,mesh.fn); + printf("reducing it to %i\n",FinalSize); + vcg::tri::UpdateTopology::VertexFace(mesh); + + // cerr << "topology ok" << endl; + int t1=clock(); + + //micro random semplificatore + + /* for(unsigned int i = 0; i < mesh.face.size(); i+= 2) { + MyFace &face = mesh.face[i]; + if(face.V(0)->IsW() && face.V(1)->IsW() && face.V(1)->IsW()) + mesh.face[i].SetD(); + } + + for(unsigned int i = 0; i < mesh.vert.size(); i++) { + if(mesh.vert[i].IsW()) + mesh.vert[i].SetD(); + } + + for(unsigned int i = 0; i < mesh.face.size(); i++) { + MyFace &face = mesh.face[i]; + if(face.IsD()) continue; + face.V(0)->ClearD(); + face.V(1)->ClearD(); + face.V(2)->ClearD(); + }*/ + + // Cluster(mesh, target_faces); + // cerr << "simplified" << endl; + + vcg::LocalOptimization DeciSession(mesh); + MyTriEdgeCollapse::SetDefaultParams(); + + DeciSession.Init(); + + int t2=clock(); + // printf("Initial Heap Size %i\n",DeciSession.h.size()); + + FinalSize = mesh.fn - FinalSize; //number of faces to remove + FinalSize/=2; //Number of vertices to remove + DeciSession.SetTargetOperations(FinalSize); + DeciSession.DoOptimization(); + float error = 1; //get error; + int t3=clock(); + + /* printf(" vol %d \n lkv %d \n lke %d \n lkf %d \n ood %d\n bor %d\n ", + MyTriEdgeCollapse::FailStat::Volume() , + MyTriEdgeCollapse::FailStat::LinkConditionFace(), + MyTriEdgeCollapse::FailStat::LinkConditionEdge(), + MyTriEdgeCollapse::FailStat::LinkConditionVert(), + MyTriEdgeCollapse::FailStat::OutOfDate() , + MyTriEdgeCollapse::FailStat::Border() + );*/ + + // printf("Completed in %i+%i+%i msec\n",t1-t0,t2-t1,t3-t2); + // printf("mesh %d %d \n",mesh.vn,mesh.fn); + + //recort vert start. + + + newvert.clear(); + newface.clear(); + + unsigned int totvert = 0; + vert_remap.resize(mesh.vert.size(), -1); + for(unsigned int i = 0; i < mesh.vert.size(); i++) { + if(mesh.vert[i].IsD()) continue; + newvert.push_back(mesh.vert[i].cP()); + vert_remap[i] = totvert++; + } + + MyMesh::VertexPointer vert_start = &mesh.vert[0]; + for(unsigned int i = 0; i < mesh.face.size(); i++) { + MyFace &face = mesh.face[i]; + if(face.IsD()) continue; + for(int k = 0; k < 3; k++) { + assert(vert_remap[face.V(k) - vert_start] != -1); + newface.push_back(vert_remap[face.V(k) - vert_start]); + } + } + + for(unsigned int i = 0; i < newbord.size(); i++) { + unsigned short &v = newbord[i].start_vert; + assert(vert_remap[v] != -1); + v = vert_remap[v]; + } + return error; +} + +void Cluster(MyMesh &mesh, unsigned int target_faces) { + unsigned int starting = mesh.vn; + cerr << "starting face: " << mesh.fn << endl; + //veramente brutale + vector remap; + remap.resize(mesh.vert.size()); + for(int i = 0; i < mesh.vert.size(); i++) + remap[i] = -1; + + int toremove = mesh.fn - target_faces; + + cerr << "counting" << endl; + map > dist; + for(int i = 0; i < mesh.vert.size(); i++) { + if(mesh.vert[i].IsD()) continue; + if(!mesh.vert[i].IsW()) continue; + for(int k = i+1; k < mesh.vert.size(); k++) { + if(mesh.vert[k].IsD()) continue; + if(!mesh.vert[k].IsW()) continue; + float d = (mesh.vert[i].P() - mesh.vert[k].P()).SquaredNorm(); + dist[d] = make_pair(i, k); + } + } + + cerr << "done" << endl; + map >::iterator s; + for(s = dist.begin(); s != dist.end(); s++) { + if(toremove < 0) break; + int target = (*s).second.first; + int source = (*s).second.second; + + if(remap[target] != -1) continue; + if(remap[source] != -1) continue; + + assert(!mesh.vert[target].IsD()); + assert(!mesh.vert[source].IsD()); + + mesh.vert[source].SetD(); + remap[source] = target; + remap[target] = target; + toremove -= 2; + mesh.vn--; + // if(mesh.vn < starting/2) break; + } + + //PULIAMO LE FACCE + for(int i = 0; i < mesh.face.size(); i++) { + MyFace &face = mesh.face[i]; + if(face.IsD()) continue; + for(int k = 0; k < 3; k++) { + if(face.V(k)->IsD()) { + face.V(k) = &mesh.vert[remap[face.V(k) - &mesh.vert[0]]]; + } + assert(!face.V(k)->IsD()); + } + if(face.V(0) == face.V(1) || face.V(0) == face.V(2) || + face.V(1) == face.V(2)) { + face.SetD(); + mesh.fn--; + } + } + cerr << "Ending faces: " << mesh.fn << endl; + +} diff --git a/apps/nexus/nexus.cpp b/apps/nexus/nexus.cpp index c0c51017..a263fbc4 100644 --- a/apps/nexus/nexus.cpp +++ b/apps/nexus/nexus.cpp @@ -1,4 +1,5 @@ #include +#include #include "nexus.h" using namespace std; @@ -10,7 +11,7 @@ Nexus::~Nexus() { Close(); } -bool Nexus::Create(const string &file, Patch::Signature sig) { +bool Nexus::Create(const string &file, Signature sig) { index_file = fopen((file + ".nxs").c_str(), "wb+"); if(!index_file) { cerr << "Could not create file: " << file << ".nxs\n"; @@ -132,7 +133,7 @@ Patch Nexus::GetPatch(unsigned int patch) { Border Nexus::GetBorder(unsigned int patch) { Entry &entry = index[patch]; Link *start = borders.GetRegion(entry.border_start, entry.border_size); - return Border(start, entry.border_size); + return Border(start, entry.border_used); } @@ -143,6 +144,7 @@ unsigned int Nexus::AddPatch(unsigned int nvert, unsigned int nface, entry.patch_size = Patch::ChunkSize(signature, nvert, nface); entry.border_start = borders.Size(); entry.border_size = nbord; + entry.border_used = 0; entry.nvert = nvert; entry.nface = nface; @@ -160,6 +162,11 @@ void Nexus::Join(const std::set &patches, std::vector &newbord) { map > remap; + set newborders; + set erased; + for(int u = 0; u < history.size(); u++) + for(int e = 0; e < history[u].erased.size(); e++) + erased.insert(history[u].erased[e]); set::const_iterator i; for(i = patches.begin(); i != patches.end(); i++) { @@ -167,29 +174,42 @@ void Nexus::Join(const std::set &patches, Nexus::Entry &entry = index[patch]; remap[*i].resize(entry.nvert, 0xffffffff); } + unsigned int vcount = 0; unsigned int fcount = 0; unsigned int bcount = 0; for(i = patches.begin(); i != patches.end(); i++) { unsigned int patch = *i; + vector &vmap = remap[*i]; + Nexus::Entry &entry = index[patch]; fcount += entry.nface; - assert(fcount < 0xffff); + // assert(fcount < 0xffff); for(unsigned int k = 0; k < entry.nvert; k++) { - if(remap[patch][k] == 0xffffffff) { //first time - remap[patch][k] = vcount++; + if(vmap[k] == 0xffffffff) { //first time + vmap[k] = vcount++; } } Border border = GetBorder(patch); for(unsigned int k = 0; k < border.Size(); k++) { - Link &link = border[k]; - if(!remap.count(link.end_patch)) { - bcount++; - continue; - } + Link link = border[k]; + if(link.IsNull()) continue; + + assert(link.start_vert < entry.nvert); + assert(vmap[link.start_vert] != 0xffffffff); + + if(!remap.count(link.end_patch)) { //external + //test if erased in history... in wich case we do not add border + if(!erased.count(link.end_patch)) { + link.start_vert = vmap[link.start_vert]; + newborders.insert(link); + } + continue; + } + //internal if(remap[link.end_patch][link.end_vert] == 0xffffffff) { //first time - remap[link.end_patch][link.end_vert] = remap[patch][link.start_vert]; + remap[link.end_patch][link.end_vert] = vmap[link.start_vert]; } } } @@ -198,32 +218,43 @@ void Nexus::Join(const std::set &patches, newvert.resize(vcount); newface.resize(fcount*3); - newbord.resize(bcount); + newbord.resize(0); fcount = 0; - bcount = 0; for(i = patches.begin(); i != patches.end(); i++) { Patch patch = GetPatch(*i); - Border border = GetBorder(*i); + // Border border = GetBorder(*i); + vector &vmap = remap[*i]; - for(unsigned int i = 0; i < patch.VertSize(); i++) + for(unsigned int i = 0; i < patch.nv; i++) { + assert(vmap[i] < vcount); newvert[vmap[i]] = patch.Vert(i); + } - for(unsigned int i = 0; i < patch.FaceSize(); i++) { + for(unsigned int i = 0; i < patch.nf; i++) { for(int k = 0; k < 3; k++) { newface[3*fcount + k] = vmap[patch.Face(i)[k]]; } fcount++; + assert(fcount *3 <= newface.size()); } - for(unsigned int i = 0; i < border.Size(); i++) { - Link &link = border[i]; - if(remap.count(link.end_patch)) continue; + /* for(unsigned int i = 0; i < border.Size(); i++) { + Link link = border[i]; + if(patches.count(link.end_patch)) continue; + link.start_vert = vmap[link.start_vert]; + newbord.push_back(link);*/ + + /* if(remap.count(link.end_patch)) continue; Link newlink = link; newlink.start_vert = vmap[link.start_vert]; - newbord[bcount++] = newlink; - } + newbord[bcount++] = newlink;*/ + // } } + set::iterator b; + for(b = newborders.begin(); b != newborders.end(); b++) + newbord.push_back(*b); + /* unsigned int newentry = AddPatch(vcount, fcount, bcount); Patch newpatch = GetPatch(newentry); Border newborder = GetBorder(newentry); @@ -238,3 +269,91 @@ void Nexus::Join(const std::set &patches, newbord.size() * sizeof(Link));*/ return; } + + +void Nexus::Unify(float threshold) { + //TODO what if colors or normals or strips? + //TODO update totvert + unsigned int duplicated = 0; + for(unsigned int p = 0; p < index.size(); p++) { + Nexus::Entry &entry = index[p]; + Patch patch = GetPatch(p); + + unsigned int vcount = 0; + map vertices; + vector remap; + remap.resize(patch.nv); + // map remap; + for(unsigned int i = 0; i < patch.nv; i++) { + Point3f &point = patch.Vert(i); + + if(!vertices.count(point)) { + vertices[point] = vcount++; + } else { + duplicated++; + } + + remap[i] = vertices[point]; + } + assert(vertices.size() <= patch.nv); + if(vertices.size() == patch.nv) //no need to unify + continue; + + vector newvert; + newvert.resize(vertices.size()); + map::iterator k; + for(k = vertices.begin(); k != vertices.end(); k++) { + newvert[(*k).second] = (*k).first; + } + + + vector newface; + newface.resize(patch.nf * 3); + for(unsigned int f = 0; f < newface.size(); f++) + newface[f] = remap[patch.FaceBegin()[f]]; + + //rewrite patch now. + entry.nvert = newvert.size(); + patch.Init(signature, entry.nvert, entry.nface); + + memcpy(patch.VertBegin(), &(newvert[0]), entry.nvert*sizeof(Point3f)); + memcpy(patch.FaceBegin(), &(newface[0]), entry.nface*3*sizeof(unsigned short)); + + //fix patch borders now + set close; //bordering pathes + Border border = GetBorder(p); + for(unsigned int b = 0; b < border.Size(); b++) { + if(border[b].IsNull()) continue; + close.insert(border[b].end_patch); + border[b].start_vert = remap[border[b].start_vert]; + } + + set::iterator c; + for(c = close.begin(); c != close.end(); c++) { + Border bord = GetBorder(*c); + for(unsigned int b = 0; b < bord.Size(); b++) { + if(bord[b].IsNull()) continue; + if(bord[b].end_patch == p) { + bord[b].end_vert = remap[bord[b].end_vert]; + } + } + } + } + //finally: there may be duplicated borders + for(unsigned int p = 0; p < index.size(); p++) { + Border border = GetBorder(p); + //Nexus::Entry &entry = index[p]; + + set links; + for(unsigned int b = 0; b < border.Size(); b++) { + if(border[b].IsNull()) continue; + if(links.count(border[b])) + border[b] = Link(); + else + links.insert(border[b]); + } + } + totvert -= duplicated; + // cout << "Found " << duplicated << " duplicated vertices" << endl; + +} diff --git a/apps/nexus/nexus.h b/apps/nexus/nexus.h index 3435accb..17e53ffa 100644 --- a/apps/nexus/nexus.h +++ b/apps/nexus/nexus.h @@ -19,17 +19,19 @@ class Nexus { struct Entry { Entry(): patch_start(0xffffffff), border_start(0xffffffff), - patch_size(0), border_size(0), + patch_size(0), border_size(0), border_used(0), nvert(0), nface(0), sphere(vcg::Sphere3f()) {} + unsigned int patch_start; //granularita' Chunk unsigned int border_start; //granuralita' Link unsigned short patch_size; //in cuhnks unsigned short border_size; //in Links + unsigned short border_used; //in Links + //Data used for extraction unsigned short nvert; unsigned short nface; vcg::Sphere3f sphere; - float error; unsigned short ram; unsigned short agp; @@ -43,13 +45,16 @@ class Nexus { Nexus(); ~Nexus(); - bool Create(const std::string &filename, Patch::Signature signature); + bool Create(const std::string &filename, Signature signature); bool Load(const std::string &filename); void Close(); Patch GetPatch(unsigned int patch); Border GetBorder(unsigned int patch); + + //MOVE to nexus_build.cpp + unsigned int AddPatch(unsigned int nvert, unsigned int nface, unsigned int nbord); @@ -59,12 +64,15 @@ class Nexus { std::vector &faces, std::vector &links); + void Unify(float threshold = 0.0f); + //TODO implement theese void CompactBorder(unsigned int patch); void CompactBorders(); void CompactPatches(); - - Patch::Signature signature; + + + Signature signature; unsigned int totvert; unsigned int totface; diff --git a/apps/nexus/nexusmt.cpp b/apps/nexus/nexusmt.cpp new file mode 100644 index 00000000..853c3295 --- /dev/null +++ b/apps/nexus/nexusmt.cpp @@ -0,0 +1,109 @@ +#include "nexusmt.h" +#include +#include + +using namespace nxs; +using namespace std; + +void NexusMt::LoadHistory() { + //The last update erases everything. + assert(history[0].erased.size() == 0); + + //maps cell -> node containing it + map cell_node; + nodes.resize(history.size()); + + //building fragments and nodes. + unsigned int current_node = 0; + vector::iterator u; + for(u = history.begin(); u != history.end(); u++) { + + Node &node = nodes[current_node]; + node.error = 0; + + //created cells belong to this node, we look also for max error. + for(unsigned int i = 0; i < (*u).created.size(); i++) { + unsigned int cell = (*u).created[i]; + if(index[cell].error > node.error) + node.error = index[cell].error; + + cell_node[cell] = current_node; + } + + //Every erased cell already belonged to a node. + //we record for each node its cells. + map > node_erased; + + for(unsigned int i = 0; i < (*u).erased.size(); i++) { + unsigned int cell = (*u).erased[i]; + assert(cell_node.count(cell)); + node_erased[cell_node[cell]].push_back(cell); + } + + //for every node with erased cells we build a frag and + //put the corresponding cells in it. + map >::iterator e; + for(e = node_erased.begin(); e != node_erased.end(); e++) { + //Build a new Frag. + Frag fr; + float max_err = -1; + + //Fill it with erased cells. + vector &cells = (*e).second; + vector::iterator k; + for(k = cells.begin(); k != cells.end(); k++) { + unsigned int cell = (*k); + fr.push_back(cell); + if(index[cell].error > max_err) + max_err = index[cell].error; + } + + //Add the new Frag to the node. + unsigned int floor_node = (*e).first; + Node &oldnode = nodes[floor_node]; + oldnode.frags.push_back(fr); + if(node.error < max_err) + node.error = max_err; + + //Update in and out of the nodes. + node.in.push_back(&oldnode); + oldnode.out.push_back(&node); + } + current_node++; + } +} + +void NexusMt::ClearHistory() { + nodes.clear(); +} + +void NexusMt::ExtractFixed(vector &selected, float error) { + std::vector::iterator n; + for(n = nodes.begin(); n != nodes.end(); n++) + (*n).visited = false; + + std::queue qnodo; + qnodo.push(&nodes[0]); + nodes[0].visited = true; + + for( ; !qnodo.empty(); qnodo.pop()) { + Node &node = *qnodo.front(); + + std::vector::iterator fragment; + std::vector::iterator on; + for(on = node.out.begin(), fragment = node.frags.begin(); + on != node.out.end(); ++on, ++fragment) { + + if((*on)->visited) continue; + + if(error < (*on)->error) { //need to expand this node. + qnodo.push(*on); + (*on)->visited = 1; + } else { + vector::iterator cell; + for(cell=(*fragment).begin(); cell != (*fragment).end(); ++cell) + selected.push_back(*cell); + } + } + } +} diff --git a/apps/nexus/nexusmt.h b/apps/nexus/nexusmt.h new file mode 100644 index 00000000..2d065fe6 --- /dev/null +++ b/apps/nexus/nexusmt.h @@ -0,0 +1,33 @@ +#ifndef NXS_NEXUS_MT_H +#define NXS_NEXUS_MT_H + + +#include "nexus.h" + +namespace nxs { + +class NexusMt: public Nexus { + private: + + class Frag:public std::vector {}; + + struct Node { + std::vector in; + std::vector out; + std::vector frags; + float error; + bool visited; + }; + + std::vector nodes; + public: + void LoadHistory(); + void ClearHistory(); + + void ExtractFixed(std::vector &selected, float error); + +}; + +} + +#endif diff --git a/apps/nexus/nexusview.cpp b/apps/nexus/nexusview.cpp index 7c7385fb..523aa97a 100644 --- a/apps/nexus/nexusview.cpp +++ b/apps/nexus/nexusview.cpp @@ -24,6 +24,9 @@ History $Log: not supported by cvs2svn $ +Revision 1.5 2004/09/16 14:25:16 ponchio +Backup. (lot of changes). + Revision 1.4 2004/08/27 00:38:34 ponchio Minor changes. @@ -161,6 +164,7 @@ int main(int argc, char *argv[]) { } bool rotate = true; + bool show_borders = true; glClearColor(0, 0, 0, 0); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); @@ -170,8 +174,7 @@ int main(int argc, char *argv[]) { SDL_Event event; int x, y; float alpha = 0; - while( !quit ) { - while( SDL_PollEvent( &event ) ){ + while( !quit ) { while( SDL_PollEvent( &event ) ){ switch( event.type ) { case SDL_QUIT: quit = 1; break; case SDL_KEYDOWN: @@ -245,7 +248,7 @@ int main(int argc, char *argv[]) { glBegin(GL_TRIANGLES); unsigned short *f = patch.FaceBegin(); - for(unsigned int j = 0; j < patch.FaceSize()*3; j+= 3) { + for(unsigned int j = 0; j < patch.nf*3; j+= 3) { Point3f &p1 = patch.Vert(f[j]); Point3f &p2 = patch.Vert(f[j+1]); Point3f &p3 = patch.Vert(f[j+2]); @@ -257,21 +260,28 @@ int main(int argc, char *argv[]) { glVertex3f(p3[0], p3[1], p3[2]); } glEnd(); - - //drawing borders - glColor3f(1, 1, 1); - - Border border = nexus.GetBorder(cell); - glPointSize(2); - glDisable(GL_LIGHTING); - glBegin(GL_POINTS); - for(unsigned int k = 0; k < border.Size(); k++) { - if(border[k].IsNull()) continue; - Point3f &p = patch.Vert(border[k].start_vert); - glVertex3f(p[0], p[1], p[2]); + } + if(show_borders) { + for(unsigned int i = 0; i < cells.size(); i++) { + unsigned int cell = cells[i]; + Patch patch = nexus.GetPatch(cell); + //drawing borders + glColor3f(1, 1, 1); + + Border border = nexus.GetBorder(cell); + glPointSize(4); + glDisable(GL_LIGHTING); + glDisable(GL_DEPTH_TEST); + glBegin(GL_POINTS); + for(unsigned int k = 0; k < border.Size(); k++) { + if(border[k].IsNull()) continue; + Point3f &p = patch.Vert(border[k].start_vert); + glVertex3f(p[0], p[1], p[2]); + } + glEnd(); + glEnable(GL_DEPTH_TEST); + glEnable(GL_LIGHTING); } - glEnd(); - glEnable(GL_LIGHTING); } diff --git a/apps/nexus/patch.cpp b/apps/nexus/patch.cpp new file mode 100644 index 00000000..73f75bac --- /dev/null +++ b/apps/nexus/patch.cpp @@ -0,0 +1,98 @@ +#include "patch.h" + +using namespace nxs; + + +Patch::Patch(Signature signature, Chunk *s, + unsigned short nvert, unsigned short nface): + start(s) { + Init(signature, nvert, nface); +} + +void Patch::Init(Signature signature, + unsigned short nvert, unsigned short nface) { + nv = nvert; + nf = nface; + + if(signature & HAS_FACES) + vstart = (float *)(((char *)start) + nf * sizeof(unsigned short) * 3); + else if(signature & HAS_STRIP) + vstart = (float *)(((char *)start) + nf * sizeof(unsigned short)); + else + vstart = (float *)start; + + //align memory + if(((int)vstart) & 0x2) vstart = (float *)(((char *)vstart) + 2); + + cstart = nv * sizeof(float) * 3; + nstart = cstart + nv * sizeof(unsigned int) * (signature & HAS_COLORS); + + if(signature & HAS_NORMALS_SHORT) + tstart = nstart + nv * sizeof(short) * 3; + else if(signature & HAS_NORMALS_FLOAT) + tstart = nstart + nv * sizeof(float) * 3; + else + tstart = nstart; + + if(signature & HAS_TEXTURES_SHORT) + dstart = tstart + nv * sizeof(short) * 2; + else if(signature & HAS_TEXTURES_FLOAT) + dstart = tstart + nv * sizeof(float) * 2; + else + dstart = tstart; +} + +unsigned int Patch::ChunkSize(Signature signature, + unsigned short nvert, + unsigned short nface) { + unsigned int size = ByteSize(signature, nvert, nface); + size = (size/sizeof(Chunk) + 1); + return size; +} + +unsigned int Patch::ByteSize(Signature signature, + unsigned short nvert, + unsigned short nface) { + unsigned int size = 0; + if(signature & HAS_STRIP) + size += nface * sizeof(unsigned short); + else if(signature & HAS_FACES) + size += nface * 3 * sizeof(unsigned short); + + //memory alignment + if(size & 0x2) size += 2; + + size += nvert * sizeof(vcg::Point3f); + + if(signature & HAS_COLORS) + size += nvert * sizeof(unsigned int); + + if(signature & HAS_NORMALS_SHORT) + size += nvert * 4 * sizeof(short); + + if(signature & HAS_NORMALS_FLOAT) + size += nvert * 3 * sizeof(float); + + if(signature & HAS_TEXTURES_SHORT) + size += nvert * 2 * sizeof(short); + + if(signature & HAS_TEXTURES_FLOAT) + size += nvert * 2 * sizeof(float); + + if(signature & HAS_DATA8) + size += nvert * sizeof(char); + if(signature & HAS_DATA16) + size += nvert * 2 * sizeof(char); + if(signature & HAS_DATA32) + size += nvert * 4 * sizeof(char); + if(signature & HAS_DATA64) + size += nvert * 8 * sizeof(char); + + + //this condition should really rarely happen but helps save space + //during construction + if(size < nface * 3 * sizeof(unsigned int)) + size = nface * 3 * sizeof(unsigned int); + + return size; +} diff --git a/apps/nexus/patch.h b/apps/nexus/patch.h index 05a42b9c..ddc01182 100644 --- a/apps/nexus/patch.h +++ b/apps/nexus/patch.h @@ -5,134 +5,73 @@ #include namespace nxs { +enum Signature { + HAS_FACES = 0x00000001, + HAS_STRIP = 0x00000002, + HAS_COLORS = 0x00000010, + HAS_NORMALS_SHORT = 0x00000100, + HAS_NORMALS_FLOAT = 0x00000200, + HAS_TEXTURES_SHORT = 0x00001000, + HAS_TEXTURES_FLOAT = 0x00002000, + HAS_DATA8 = 0x00010000, + HAS_DATA16 = 0x00020000, + HAS_DATA32 = 0x00040000, + HAS_DATA64 = 0x00080000 }; + struct Chunk { unsigned char p[4096]; }; + class Patch { public: - enum Signature { DEFAULT = 0, - HAS_STRIP = 0x002, //if true faces saved as strip - HAS_COLORS = 0x004, - HAS_NORMALS_SHORT = 0x008, - HAS_NORMALS_FLOAT = 0x008, - HAS_TEXTURES_SHORT = 0x010, - HAS_TEXTURES_FLOAT = 0x020, - HAS_DATA8 = 0x040, - HAS_DATA16 = 0x080, - HAS_DATA32 = 0x100, - HAS_DATA64 = 0x200 }; - - Patch(Signature signature, Chunk *s = NULL, - unsigned short nv = 0, unsigned short nf = 0): - start(s) { - Resize(signature, nv, nf); - } + Patch(Signature signature, Chunk *s, + unsigned short nv, unsigned short nf); - void Resize(Signature signature, unsigned short nv, unsigned short nf) { - nvert = nv; - nface = nf; - fstart = (unsigned short *)(((char *)start) + - VertSize() * sizeof(vcg::Point3f)); + void Init(Signature signature, unsigned short nv, unsigned short nf); - unsigned int size = nf * sizeof(unsigned short); - if(!(signature & HAS_STRIP)) size *= 3; - cstart = (void *)(((char *)fstart) + size); + inline vcg::Point3f *VertBegin(); + inline unsigned short *FaceBegin(); - if(signature & HAS_COLORS) size = nv * sizeof(unsigned int); - else size = 0; - - nstart = (void *)(((char *)cstart) + size); - - size = 0; - if(signature & HAS_NORMALS_SHORT) size = nv * 4*sizeof(short); - if(signature & HAS_NORMALS_FLOAT) size = nv * 4*sizeof(float); - - tstart = (void *)(((char *)cstart) + size); - - size = 0; - if(signature & HAS_TEXTURES_SHORT) size = nv * 2*sizeof(short); - if(signature & HAS_TEXTURES_FLOAT) size = nv * 2*sizeof(float); - - dstart = (void *)(((char *)tstart) + size); - } - - unsigned short VertSize() { return nvert; } - - vcg::Point3f *VertBegin() { return (vcg::Point3f *)(start); } - - unsigned short FaceSize() { return nface; } - - unsigned short *FaceBegin() { return fstart; } - - vcg::Point3f &Vert(unsigned int v) { return VertBegin()[v]; } - - unsigned short *Face(unsigned int f) { return FaceBegin() + f * 3; } + inline vcg::Point3f &Vert(unsigned short v); + inline unsigned short *Face(unsigned short f); - // unsigned int ChunkSize() { return ChunkSize(VertSize(), FaceSize()); } - - // unsigned int ByteSize() { return ByteSize(VertSize(), FaceSize()); } - static unsigned int ChunkSize(Signature signature, - unsigned short nvert, unsigned short nface) { - unsigned int size = ByteSize(signature, nvert, nface); - size = (size/sizeof(Chunk) + 1); - return size; - } + unsigned short nvert, + unsigned short nface); static unsigned int ByteSize(Signature signature, - unsigned short nvert, unsigned short nface) { - unsigned int size = nvert * sizeof(vcg::Point3f); - if(signature & HAS_STRIP) - size += nface * sizeof(unsigned short); - else - size += nface * 3 * sizeof(unsigned short); - - if(signature & HAS_COLORS) - size += nvert * sizeof(unsigned int); + unsigned short nvert, + unsigned short nface); - if(signature & HAS_NORMALS_SHORT) - size += nvert * 4 * sizeof(short); - - if(signature & HAS_NORMALS_FLOAT) - size += nvert * 3 * sizeof(float); - - if(signature & HAS_TEXTURES_SHORT) - size += nvert * 2 * sizeof(short); - - if(signature & HAS_TEXTURES_FLOAT) - size += nvert * 2 * sizeof(float); - - if(signature & HAS_DATA8) - size += nvert * sizeof(char); - if(signature & HAS_DATA16) - size += nvert * 2 * sizeof(char); - if(signature & HAS_DATA32) - size += nvert * 4 * sizeof(char); - if(signature & HAS_DATA64) - size += nvert * 8 * sizeof(char); - - - //this condition should really rarely happen but helps save space - //during construction - if(size < nface * 3 * sizeof(unsigned int)) - size = nface * 3 * sizeof(unsigned int); - - return size; - } - // private: - unsigned short nvert; - unsigned short nface; Chunk *start; - unsigned short *fstart; - void *cstart; - void *nstart; - void *tstart; - void *dstart; + + unsigned short nv; + unsigned short nf; + + float *vstart; + unsigned short cstart; + unsigned short nstart; + unsigned short tstart; + unsigned short dstart; }; -}; +inline vcg::Point3f *Patch::VertBegin() { + return (vcg::Point3f *)vstart; +} +inline unsigned short *Patch::FaceBegin() { + return (unsigned short *)start; +} + +inline vcg::Point3f &Patch::Vert(unsigned short v) { + return VertBegin()[v]; +} +inline unsigned short *Patch::Face(unsigned short f) { + return FaceBegin() + f * 3; +} + +} //namespace #endif diff --git a/apps/nexus/voronoichain.cpp b/apps/nexus/voronoichain.cpp index 4f4308a9..bfffe5bf 100644 --- a/apps/nexus/voronoichain.cpp +++ b/apps/nexus/voronoichain.cpp @@ -24,6 +24,9 @@ History $Log: not supported by cvs2svn $ +Revision 1.2 2004/09/16 14:25:16 ponchio +Backup. (lot of changes). + Revision 1.1 2004/08/26 18:03:47 ponchio First draft. @@ -173,7 +176,7 @@ void VoronoiChain::BuildLevel(Nexus &nexus, unsigned int offset) { for(unsigned int idx = offset; idx < nexus.index.size(); idx++) { Patch patch = nexus.GetPatch(idx); - for(unsigned int i = 0; i < patch.VertSize(); i++) { + for(unsigned int i = 0; i < patch.nv; i++) { Point3f &v = patch.Vert(i); unsigned int target_patch; diff --git a/apps/nexus/voronoinxs.cpp b/apps/nexus/voronoinxs.cpp index 0fa18f82..61bff6c0 100644 --- a/apps/nexus/voronoinxs.cpp +++ b/apps/nexus/voronoinxs.cpp @@ -24,6 +24,9 @@ History $Log: not supported by cvs2svn $ +Revision 1.2 2004/09/16 14:25:16 ponchio +Backup. (lot of changes). + Revision 1.1 2004/08/26 18:03:48 ponchio First draft. @@ -158,7 +161,7 @@ int main(int argc, char *argv[]) { string output = argv[optind+1]; - Patch::Signature signature = Patch::DEFAULT; + Signature signature = HAS_FACES; Nexus nexus; if(!nexus.Create(output, signature)) { cerr << "Could not create nexus output: " << output << endl; @@ -218,6 +221,9 @@ int main(int argc, char *argv[]) { update.created.push_back(i); nexus.history.push_back(update); + //unify vertices otherwise you may get cracks. + nexus.Unify(); + /* BUILDING OTHER LEVELS */ unsigned int oldoffset = 0; @@ -227,6 +233,7 @@ int main(int argc, char *argv[]) { unsigned int newoffset = nexus.index.size(); vchain.BuildLevel(nexus, oldoffset); + vector level_history; map >::iterator fragment; for(fragment = vchain.oldfragments.begin(); fragment != vchain.oldfragments.end(); fragment++) { @@ -235,12 +242,12 @@ int main(int argc, char *argv[]) { update.created.clear(); update.erased.clear(); - cerr << "Joining: "; + cerr << "Join "; set &fcells = (*fragment).second; set::iterator s; for(s = fcells.begin(); s != fcells.end(); s++) { update.erased.push_back(*s); - cerr << " " << (*s) << endl; + cerr << *s << " "; } cerr << endl; @@ -253,23 +260,26 @@ int main(int argc, char *argv[]) { //simplyfy mesh vector vert_remap; - float error = Decimate(newface.size() * scaling/3, newvert, - newface, newbord, vert_remap); + float error = Decimate((unsigned int)(newface.size() * scaling/3), + newvert, newface, newbord, vert_remap); NexusSplit(nexus, vchain, level, newvert, newface, newbord, update, error); - nexus.history.push_back(update); + level_history.push_back(update); } + for(int i = 0; i < level_history.size(); i++) + nexus.history.push_back(level_history[i]); //if(vchain.levels.back().size() == 1) break; if(vchain.oldfragments.size() == 1) break; vchain.oldfragments = vchain.newfragments; oldoffset = newoffset; } + //last level clean history: update.created.clear(); update.erased.clear(); @@ -284,7 +294,7 @@ int main(int argc, char *argv[]) { nexus.history.push_back(update); ReverseHistory(nexus.history); //debug: - for(unsigned int i = 0; i < nexus.history.size(); i++) { + /* for(unsigned int i = 0; i < nexus.history.size(); i++) { Nexus::Update &update = nexus.history[i]; cerr << "created:"; for(unsigned int c = 0; c < update.created.size(); c++) @@ -293,7 +303,7 @@ int main(int argc, char *argv[]) { for(unsigned int c = 0; c < update.erased.size(); c++) cerr << " " << update.erased[c]; cerr << "\n\n"; - } + }*/ //Clean up: nexus.Close(); @@ -359,9 +369,12 @@ void NexusAllocate(Crude &crude, unsigned int npatch = face_remap[i]; Nexus::Entry &entry = nexus.index[npatch]; + + //TODO this is slow because we have to initialize patch. + //just get patch.start. Patch patch = nexus.GetPatch(npatch); - Crude::Face *faces = (Crude::Face *)patch.VertBegin(); + Crude::Face *faces = (Crude::Face *)patch.start; faces[entry.nface] = face; entry.nface++; } @@ -385,20 +398,20 @@ void NexusFill(Crude &crude, Nexus::Entry &entry = nexus.index[i]; //make a copy of faces (we need to write there :P) - Crude::Face *faces = new Crude::Face[patch.FaceSize()]; - memcpy(faces, (Crude::Face *)patch.VertBegin(), - patch.FaceSize() * sizeof(Crude::Face)); - + Crude::Face *faces = new Crude::Face[patch.nf]; + memcpy(faces, (Crude::Face *)patch.start, + patch.nf * sizeof(Crude::Face)); + //collect all vertices we need. //TODO an hash_map would be faster? unsigned int count = 0; map remap; - for(unsigned int k = 0; k < patch.FaceSize(); k++) { + for(unsigned int k = 0; k < patch.nf; k++) { Crude::Face &face = faces[k]; for(int j = 0; j < 3; j++) { if(!remap.count(face[j])) { - assert(count < patch.VertSize()); + assert(count < patch.nv); Point3f &v = crude.vert[face[j]]; patch.VertBegin()[remap.size()] = v; entry.sphere.Add(v); @@ -433,7 +446,7 @@ void NexusFill(Crude &crude, } } //and number of borders: - entry.border_size = border_remap.Size() - entry.border_start; + entry.border_used = border_remap.Size() - entry.border_start; delete []faces; } @@ -446,36 +459,49 @@ void NexusFixBorder(Nexus &nexus, VFile &border_remap) { //and last convert RemapLinks into Links - nexus.borders.Resize(border_remap.Size()); + nexus.borders.Resize(border_remap.Size() * 2); + //* 2 is to accomodate future borders + + for(unsigned int i = 0; i < nexus.index.size(); i++) { + Nexus::Entry &local = nexus.index[i]; + local.border_start *= 2; + local.border_size = local.border_used * 2; + } for(unsigned int i = 0; i < nexus.index.size(); i++) { Nexus::Entry &local = nexus.index[i]; + unsigned int remap_start = local.border_start/2; + //* 2 is to accomodate future borders + + // K is the main iterator (where we write to in nexus.borders) - for(unsigned int k = local.border_start; - k < local.border_start + local.border_size; k++) { + for(unsigned int k = 0; k < local.border_used; k++) { + - RemapLink start_link = border_remap[k]; + RemapLink start_link = border_remap[k + remap_start]; assert(start_link.rel_vert < local.nvert); Nexus::Entry &remote = nexus.index[start_link.patch]; bool found = false; - for(unsigned int j = remote.border_start; - j < remote.border_start + remote.border_size; j++) { + + unsigned int remote_remap_start = remote.border_start/2; + for(unsigned int j = 0; j < remote.border_used; j++) { - RemapLink end_link = border_remap[j]; + RemapLink end_link = border_remap[j + remote_remap_start]; assert(end_link.rel_vert < remote.nvert); if(start_link.abs_vert == end_link.abs_vert && end_link.patch == i) { //found the match assert(!found); - nexus.borders[k] = Link(start_link.rel_vert, - end_link.rel_vert, start_link.patch); + nexus.borders[k + local.border_start] = Link(start_link.rel_vert, + end_link.rel_vert, + start_link.patch); found = true; } } - assert(nexus.borders[k].start_vert < local.nvert); + assert(nexus.borders[k + local.border_start].start_vert < local.nvert); assert(found); } } @@ -512,7 +538,7 @@ void NexusSplit(Nexus &nexus, VoronoiChain &vchain, Nexus::Update &update, float error) { - //if != -1 remap global index to cell index + //if != -1 remap global index to cell index (first arg) map > vert_remap; map vert_count; @@ -543,47 +569,113 @@ void NexusSplit(Nexus &nexus, VoronoiChain &vchain, if(v_remap[newface[f+i]] == -1) v_remap[newface[f+i]] = vert_count[cell]++; } - - + //TODO prune small count cells - //for every new cell + //lets count borders + map bord_count; + map::iterator c; for(c = vert_count.begin(); c != vert_count.end(); c++) { unsigned int cell = (*c).first; - cerr << "Processing cell: " << cell << endl; - - vector faces; - vector verts; - vector bords; - + unsigned int &count = bord_count[cell]; + count = 0; + vector &v_remap = vert_remap[cell]; - vector &f_remap = face_remap[cell]; + + //external borders + for(unsigned int i = 0; i < newbord.size(); i++) { + Link link = newbord[i]; + if(v_remap[link.start_vert] == -1) continue; + count++; + } + + //process internal borders; + //TODO higly inefficient!!! + map::iterator t; + for(t = vert_count.begin(); t != vert_count.end(); t++) { + if(cell == (*t).first) continue; + vector &vremapclose = vert_remap[(*t).first]; + for(unsigned int i = 0; i < newvert.size(); i++) { + if(v_remap[i] != -1 && vremapclose[i] != -1) { + count++; + } + } + } + } + + map cells2patches; + + //lets allocate space + for(c = vert_count.begin(); c != vert_count.end(); c++) { + unsigned int cell = (*c).first; + unsigned int patch_idx = nexus.AddPatch(vert_count[cell], + face_count[cell], + 3 * bord_count[cell]); + //why double border space? because at next level + //we will need to add those borders... + cells2patches[cell] = patch_idx; + vchain.newfragments[cell].insert(patch_idx); + update.created.push_back(patch_idx); + } + + + //fill it now. + for(c = vert_count.begin(); c != vert_count.end(); c++) { + unsigned int cell = (*c).first; + unsigned int patch_idx = cells2patches[cell]; + + //vertices first + vector &v_remap = vert_remap[cell]; + + vector verts; verts.resize(vert_count[cell]); for(unsigned int i = 0; i < newvert.size(); i++) { if(v_remap[i] != -1) verts[v_remap[i]] = newvert[i]; - // verts.push_back(newvert[v_remap[i]]); } - - assert(verts.size() == vert_count[cell]); - assert(f_remap.size()/3 == face_count[cell]); - + + //faces now + vector &f_remap = face_remap[cell]; + + vector faces; faces.resize(face_count[cell]*3); - + for(unsigned int i = 0; i < f_remap.size(); i++) { assert(v_remap[f_remap[i]] != -1); faces[i] = v_remap[f_remap[i]]; } - //process external borders + + if(patch_idx == 68) + cerr << "68 bord: " << bord_count[cell] << endl; + //borders last + vector bords; + + //process external borders + //for every esternal link we must update external patches! for(unsigned int i = 0; i < newbord.size(); i++) { Link link = newbord[i]; if(v_remap[link.start_vert] == -1) continue; link.start_vert = v_remap[link.start_vert]; bords.push_back(link); + + Nexus::Entry &rentry = nexus.index[link.end_patch]; + //TODO if !true reallocate borders. + if(rentry.border_used >= rentry.border_size) { + cerr << "patch: " << link.end_patch << endl; + cerr << "used: " << rentry.border_used << endl; + cerr << "size: " << rentry.border_size << endl; + } + assert(rentry.border_used < rentry.border_size); + Border rborder = nexus.GetBorder(link.end_patch); + + Link &newlink = rborder[rentry.border_used++]; + newlink.start_vert = link.end_vert; + newlink.end_vert = link.start_vert; + newlink.end_patch = patch_idx; } - + //process internal borders; //TODO higly inefficient!!! map::iterator t; @@ -593,19 +685,14 @@ void NexusSplit(Nexus &nexus, VoronoiChain &vchain, for(unsigned int i = 0; i < newvert.size(); i++) { if(v_remap[i] != -1 && vremapclose[i] != -1) { Link link; - link.end_patch = (*t).first; + link.end_patch = cells2patches[(*t).first]; link.start_vert = v_remap[i]; link.end_vert = vremapclose[i]; bords.push_back(link); } } } - //create new nexus patch - unsigned int patch_idx = nexus.AddPatch(verts.size(), - faces.size()/3, - bords.size()); - vchain.newfragments[cell].insert(patch_idx); - update.created.push_back(patch_idx); + Nexus::Entry &entry = nexus.index[patch_idx]; // entry.error = error; @@ -623,9 +710,9 @@ void NexusSplit(Nexus &nexus, VoronoiChain &vchain, } Border border = nexus.GetBorder(patch_idx); - memcpy(&border[0], &bords[0], bords.size()); + memcpy(&(border[0]), &(bords[0]), bords.size() * sizeof(Link)); + entry.border_used = bords.size(); } - cerr << "newfrag: " << vchain.newfragments.size() << endl; } void ReverseHistory(vector &history) {