diff --git a/apps/nexus/decimate.cpp b/apps/nexus/decimate.cpp index b18f911c..36826841 100644 --- a/apps/nexus/decimate.cpp +++ b/apps/nexus/decimate.cpp @@ -161,9 +161,9 @@ float Quadric(MyMesh &mesh, unsigned int target_faces) { } } error /= count; - cerr << "Error: " << error << endl; + // cerr << "Error: " << error << endl; cerr << "faces: " << mesh.fn << endl; - cerr << "verts: " << mesh.vn << endl; + // cerr << "verts: " << mesh.vn << endl; return error; } @@ -201,8 +201,6 @@ float Cluster(MyMesh &mesh, unsigned int target_faces) { part.SetBox(box); part.Init(); - cerr << "inited points\n"; - vector centroid; vector count; for(unsigned int i = 0; i < 3; i++) { @@ -226,8 +224,6 @@ float Cluster(MyMesh &mesh, unsigned int target_faces) { mesh.vert[remap[i]].P() = part[i].p; } - cerr << "remapping faces\n"; - float error = 0; //rimappiamo le facce..... for(unsigned int i = 0; i < mesh.face.size(); i++) { @@ -245,7 +241,6 @@ float Cluster(MyMesh &mesh, unsigned int target_faces) { } } - cerr << "Deleting faces\n"; for(unsigned int i = 0; i < mesh.face.size(); i++) { MyFace &face = mesh.face[i]; assert(!face.IsD()); @@ -260,17 +255,15 @@ float Cluster(MyMesh &mesh, unsigned int target_faces) { } } - cerr << "deleting vertices\n"; - for(unsigned int i = 0; i < mesh.vert.size(); i++) if(!mesh.vert[i].IsV() && mesh.vert[i].IsW()) { mesh.vert[i].SetD(); mesh.vn--; } - cerr << "Error: " << error << endl; - cerr << "faces: " << mesh.fn << endl; - cerr << "verts: " << mesh.vn << endl; + // cerr << "Error: " << error << endl; + // cerr << "faces: " << mesh.fn << endl; + // cerr << "verts: " << mesh.vn << endl; return error; } diff --git a/apps/nexus/nxsalgo.cpp b/apps/nexus/nxsalgo.cpp index e64cd922..b25381c8 100644 --- a/apps/nexus/nxsalgo.cpp +++ b/apps/nexus/nxsalgo.cpp @@ -15,18 +15,35 @@ using namespace vcg; using namespace triangle_stripper; void nxs::ComputeNormals(Nexus &nexus) { - /* WARNING pathological cases may require a lot of memory - expecially if one patch borders with many many other patches */ - assert(nexus.signature & NXS_NORMALS_SHORT || nexus.signature & NXS_NORMALS_FLOAT); bool use_short = (nexus.signature & NXS_NORMALS_SHORT) != 0; + //TODO use a temporary file to store border normals + unsigned int tmpb_offset = 0; + vector tmpb_start; + VFile tmpb; + if(!tmpb.Create("tmpb.tmp")) { + cerr << "Could not create temporary border file\n"; + exit(0); + } + + for(unsigned int p = 0; p < nexus.index.size(); p++) { + Border border = nexus.GetBorder(p); + tmpb_start.push_back(tmpb_offset); + tmpb_offset += border.Size(); + } + + Point3f zero(0.0f, 0.0f, 0.0f); + tmpb.Resize(tmpb_offset); + for(unsigned int i = 0; i < tmpb.Size(); i++) + tmpb[i] = zero; + //first step normals in the same patch. for(unsigned int p = 0; p < nexus.index.size(); p++) { Patch &patch = nexus.GetPatch(p); - + vector normals; normals.resize(patch.nv, Point3f(0, 0, 0)); @@ -72,62 +89,54 @@ void nxs::ComputeNormals(Nexus &nexus) { memcpy(patch.Norm16Begin(), &*normals.begin(), normals.size() * sizeof(Point3f)); } + Border border = nexus.GetBorder(p); + + set close; + for(unsigned int i = 0; i < border.Size(); i++) { + Link &link = border[i]; + if(link.IsNull()) continue; + unsigned int off = tmpb_start[p]; + tmpb[off + i] += normals[link.start_vert]; + close.insert(link.end_patch); + } + + set::iterator k; + for(k = close.begin(); k != close.end(); k++) { + Border remote = nexus.GetBorder(*k); + unsigned int off = tmpb_start[*k]; + + for(unsigned int i = 0; i < remote.Size(); i++) { + Link &link = remote[i]; + if(link.IsNull()) continue; + if(link.end_patch != p) continue; + tmpb[off + i] += normals[link.end_vert]; + } + } } + //Second step unify normals across borders for(unsigned int p = 0; p < nexus.index.size(); p++) { - //notice now ew allow flushing of old patches - Patch &patch = nexus.GetPatch(p); Border border = nexus.GetBorder(p); - //first pass we collect all normals - map normals; for(unsigned int i = 0; i < border.Size(); i++) { Link &link = border[i]; if(link.IsNull()) continue; - - if(!normals.count(link.start_vert)) { - assert(link.start_vert < patch.nv); - if(use_short) { - short *n = patch.Norm16(link.start_vert); - normals[link.start_vert] = Point3f(n[0], n[1], n[2]); - } else - normals[link.start_vert] = patch.Norm32(link.start_vert); - } - - //no flushing now! - Patch &remote = nexus.GetPatch(link.end_patch, false); - assert(link.end_vert < remote.nv); - - if(use_short) { - short *n = remote.Norm16(link.end_vert); - normals[link.start_vert] += Point3f(n[0], n[1], n[2]); - } else - normals[link.start_vert] += remote.Norm32(link.end_vert); - } - - //second pass we update values in all the patches involved - for(unsigned int i = 0; i < border.Size(); i++) { - Link &link = border[i]; - if(link.IsNull()) continue; - - Patch &remote = nexus.GetPatch(link.end_patch, false); - Point3f &n = normals[link.start_vert]; - n.Normalize(); - + unsigned int off = tmpb_start[p]; + Point3f &n = tmpb[off + i]; + n.Normalize(); if(use_short) { n *= 32767; - short *nr = remote.Norm16(link.end_vert); short *np = patch.Norm16(link.start_vert); - nr[0] = np[0] = (short)n[0]; - nr[1] = np[1] = (short)n[1]; - nr[2] = np[2] = (short)n[2]; + np[0] = (short)n[0]; + np[1] = (short)n[1]; + np[2] = (short)n[2]; } else { - remote.Norm32(link.end_vert) = n; - patch.Norm32(link.end_vert) = n; + patch.Norm32(link.start_vert) = n; } } } + //TODO remove temporary file. } /*void nxs::ComputeTriStrip(unsigned short nfaces, unsigned short *faces, diff --git a/apps/nexus/patch.cpp b/apps/nexus/patch.cpp index 9c89ac06..7c0c79d3 100644 --- a/apps/nexus/patch.cpp +++ b/apps/nexus/patch.cpp @@ -14,6 +14,7 @@ static double wrkmem[LZO1X_1_MEM_COMPRESS/sizeof(double) +1]; static double wrkmem[LZO1X_999_MEM_COMPRESS/sizeof(double) +1]; #endif + void pad(unsigned int &size) { while(size&0x3) size++; } @@ -183,9 +184,13 @@ char *Patch::Compress(unsigned int ram_size, unsigned int &size) { (unsigned char *)buffer + sizeof(int), &size, (char *)wrkmem); #else - lzo1x_999_compress(((unsigned char *)start), ram_size, - (unsigned char *)buffer + sizeof(int), &size, + lzo1x_999_compress(((unsigned char *)start), ram_size, + (unsigned char *)buffer + sizeof(int), &size, (char *)wrkmem); + + lzo1x_optimize((unsigned char *)buffer + sizeof(int), size, + ((unsigned char *)start), &ram_size, + NULL); #endif *(int *)buffer = size; @@ -193,10 +198,7 @@ char *Patch::Compress(unsigned int ram_size, unsigned int &size) { // memcpy(buffer, start, ram_size); // size = ram_size; - //TODO optimize! - // lzo1x_optimize((unsigned char *)entry.patch->start, - // entry.ram_size * chunk_size, - // compressed, &compressed_size, NULL); + return buffer; } diff --git a/apps/nexus/pvoronoi.cpp b/apps/nexus/pvoronoi.cpp index 6b4ab3af..f8e179c9 100644 --- a/apps/nexus/pvoronoi.cpp +++ b/apps/nexus/pvoronoi.cpp @@ -24,6 +24,9 @@ History $Log: not supported by cvs2svn $ +Revision 1.5 2004/09/28 10:26:21 ponchio +Rewrote. + Revision 1.4 2004/09/21 00:53:23 ponchio Lotsa changes. @@ -87,3 +90,28 @@ float VoronoiPartition::Closest(const vcg::Point3f &p, return mindist; } +Point3f VoronoiPartition::FindBorder(vcg::Point3f &p, float radius) { + Point3f a = p; + unsigned int atarget = Locate(a); + Point3f &seed = operator[](atarget).p; + + if((a - seed).Norm() < radius/100) return p; //Bad luck. + + Point3f dir = (a - seed).Normalize(); + Point3f b = seed + dir*radius*1.1; + unsigned int btarget = Locate(b); + + if(atarget == btarget) { + //probably nothing on the side we are looking gor; + return p; + } + Point3f m; + for(unsigned int i = 0; i < 10; i++) { + m = (a + b)/2; + unsigned int mtarget = Locate(m); + if(mtarget == atarget) a = m; + else if(mtarget == btarget) b = m; + else break; //something in the middle + } + return m; +} diff --git a/apps/nexus/pvoronoi.h b/apps/nexus/pvoronoi.h index 53afc7ae..bb56bfa1 100644 --- a/apps/nexus/pvoronoi.h +++ b/apps/nexus/pvoronoi.h @@ -24,6 +24,9 @@ History $Log: not supported by cvs2svn $ +Revision 1.7 2004/09/28 10:26:21 ponchio +Rewrote. + Revision 1.6 2004/09/21 00:53:23 ponchio Lotsa changes. @@ -101,7 +104,8 @@ namespace nxs { void Init(); float Closest(const vcg::Point3f &p, unsigned int &target, float radius = 0); - + + vcg::Point3f FindBorder(vcg::Point3f &p, float radius); unsigned int Locate(const vcg::Point3f &p) { unsigned int target; Closest(p, target); diff --git a/apps/nexus/voronoichain.cpp b/apps/nexus/voronoichain.cpp index 401854b7..0cb7a06e 100644 --- a/apps/nexus/voronoichain.cpp +++ b/apps/nexus/voronoichain.cpp @@ -24,6 +24,9 @@ History $Log: not supported by cvs2svn $ +Revision 1.11 2004/10/10 17:19:42 ponchio +Added compression and debugged. + Revision 1.10 2004/10/09 14:46:47 ponchio Windows porting small changes. @@ -143,12 +146,14 @@ void VoronoiChain::Init(Crude &crude, float scaling, int steps) { //Coarse optimization. vector ccentroids; vector ccount; + vector radius; for(int i = 0; i < steps; i++) { cerr << "Optimization step 0: " << i << "/" << steps << endl; ccentroids.clear(); ccount.clear(); - ccentroids.resize(fine.size(), Point3f(0, 0, 0)); - ccount.resize(fine.size(), 0); + ccentroids.resize(coarse.size(), Point3f(0, 0, 0)); + ccount.resize(coarse.size(), 0); + radius.resize(coarse.size(), 0); for(unsigned int v = 0; v < crude.Vertices(); v++) { unsigned int ctarget = 0xffffffff; @@ -156,12 +161,37 @@ void VoronoiChain::Init(Crude &crude, float scaling, int steps) { assert(ctarget != 0xffffffff); ccentroids[ctarget] += crude.vert[v]; ccount[ctarget]++; + if(dist > radius[ctarget]) radius[ctarget] = dist; } for(unsigned int v = 0; v < coarse.size(); v++) { if(ccount[v] == 0) continue; - + coarse[v].p = ccentroids[v]/(float)ccount[v]; coarse[v].weight = (float)pow(ccount[v]/(float)coarse_vmean, 0.3f); + + if(radius[v] == 0) continue; + + //repel from fine seeds + unsigned int atarget; + float closest = fine.Closest(coarse[v].p, atarget); + Point3f dir = (coarse[v].p - fine[atarget].p).Normalize(); + Point3f a = coarse[v].p; + Point3f b = fine[atarget].p + dir*radius[v]*1.1; + unsigned int btarget; + closest = fine.Closest(b, btarget); + if(atarget == btarget) { + continue; + } + Point3f m; + for(unsigned int i = 0; i < 10; i++) { + m = (a + b)/2; + unsigned int mtarget; + fine.Closest(m, mtarget); + if(mtarget == atarget) a = m; + else if(mtarget == btarget) b = m; + else break; + } + coarse[v].p = m; } coarse.Init(); } @@ -343,7 +373,7 @@ void VoronoiChain::BuildLevel(Nexus &nexus, unsigned int offset, VoronoiPartition &coarse = levels[levels.size()-1]; VoronoiPartition &fine = levels[levels.size()-2]; coarse.SetBox(fine.box); - + fine.Init(); unsigned int tot_coarse = (unsigned int)(fine.size() * scaling); @@ -373,13 +403,15 @@ void VoronoiChain::BuildLevel(Nexus &nexus, unsigned int offset, //Coarse optimization. vector ccentroids; vector ccount; + vector radius; for(int i = 0; i < steps; i++) { cerr << "Optimization step 0: " << i << "/" << steps << endl; ccentroids.clear(); ccount.clear(); - ccentroids.resize(fine.size(), Point3f(0, 0, 0)); - ccount.resize(fine.size(), 0); - + ccentroids.resize(coarse.size(), Point3f(0, 0, 0)); + ccount.resize(coarse.size(), 0); + radius.resize(coarse.size(), 0); + for(unsigned int idx = offset; idx < nexus.index.size(); idx++) { Patch patch = nexus.GetPatch(idx); for(unsigned int i = 0; i < patch.nv; i++) { @@ -389,6 +421,7 @@ void VoronoiChain::BuildLevel(Nexus &nexus, unsigned int offset, assert(ctarget != 0xffffffff); ccentroids[ctarget] += patch.Vert(i); ccount[ctarget]++; + if(dist > radius[ctarget]) radius[ctarget] = dist; } } for(unsigned int v = 0; v < coarse.size(); v++) { @@ -397,7 +430,11 @@ void VoronoiChain::BuildLevel(Nexus &nexus, unsigned int offset, coarse[v].p = ccentroids[v]/(float)ccount[v]; //0.3 is related to the fact is doubled the box size. coarse[v].weight = (float)pow(ccount[v]/(float)coarse_vmean, 0.3f); - // fine.bbox.Add(fine[v].p); + + if(radius[v] == 0) continue; + + //repel from fine seeds + } // fine.Init(fine.bbox); coarse.Init(); diff --git a/apps/nexus/voronoinxs.cpp b/apps/nexus/voronoinxs.cpp index b870abec..17ed2cac 100644 --- a/apps/nexus/voronoinxs.cpp +++ b/apps/nexus/voronoinxs.cpp @@ -24,6 +24,9 @@ History $Log: not supported by cvs2svn $ +Revision 1.14 2004/10/10 17:19:42 ponchio +Added compression and debugged. + Revision 1.13 2004/10/09 17:32:25 ponchio Ram buffer option added (last) @@ -289,7 +292,6 @@ int main(int argc, char *argv[]) { //unify vertices otherwise you may get cracks. nexus.Unify(); nexus.patches.FlushAll(); - TestPatches(nexus); /* BUILDING OTHER LEVELS */ unsigned int oldoffset = 0; @@ -377,6 +379,46 @@ void NexusSplit(Nexus &nexus, VoronoiChain &vchain, Nexus::Update &update, float error) { + cerr << "Counting nearby cells" << endl; + + map centroids; + map counts; + + Point3f centroid(0, 0, 0); + Box3f box; + for(unsigned int f = 0; f < newface.size(); f += 3) { + Point3f bari = (newvert[newface[f]] + + newvert[newface[f+1]] + + newvert[newface[f+2]])/3; + centroid += bari; + box.Add(bari); + unsigned int cell = vchain.Locate(level+1, bari); + if(!centroids.count(cell)) centroids[cell] = Point3f(0, 0, 0); + if(!counts.count(cell)) counts[cell] = 0; + centroids[cell] += bari; + counts[cell]++; + } + centroid /= newface.size()/3; + //prune small cells: + float min_size = (newface.size()/3) / 20; + + vector cellremap; + VoronoiPartition local; + local.SetBox(vchain.levels[level].box); + map::iterator r; + for(r = centroids.begin(); r != centroids.end(); r++) { + unsigned int cell = (*r).first; + if(counts[cell] < min_size) continue; + + Point3f seed = (*r).second/counts[cell]; + Point3f orig = vchain.levels[level+1][cell].p; + // seed = (seed + orig*2)/3; + seed = orig; + local.push_back(seed); + cellremap.push_back(cell); + } + local.Init(); + //if != -1 remap global index to cell index (first arg) map > vert_remap; map vert_count; @@ -390,7 +432,9 @@ void NexusSplit(Nexus &nexus, VoronoiChain &vchain, newvert[newface[f+1]] + newvert[newface[f+2]])/3; - unsigned int cell = vchain.Locate(level+1, bari); + // unsigned int cell = vchain.Locate(level+1, bari); + unsigned int cell = cellremap[local.Locate(bari)]; + vector &f_remap = face_remap[cell]; f_remap.push_back(newface[f]); f_remap.push_back(newface[f+1]); @@ -409,7 +453,7 @@ void NexusSplit(Nexus &nexus, VoronoiChain &vchain, v_remap[newface[f+i]] = vert_count[cell]++; } - //TODO prune small count cells + //TODO prune small count cells and assure no big ones. //lets count borders map bord_count;