First working (hopefully) release.

This commit is contained in:
Federico Ponchio 2004-09-17 15:25:59 +00:00
parent ad6b893cae
commit 92fa5a7e4a
11 changed files with 879 additions and 213 deletions

View File

@ -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.
@ -141,6 +144,13 @@ int main(int argc, char *argv[]) {
}
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;
int x, y;
@ -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();

242
apps/nexus/decimate.cpp Normal file
View File

@ -0,0 +1,242 @@
#include <vector>
#include <iostream>
// stuff to define the mesh
#include <vcg/simplex/vertex/with/afvmvn.h>
#include <vcg/math/quadric.h>
#include <vcg/complex/trimesh/base.h>
#include <vcg/simplex/face/with/av.h>
// io
//#include <wrap/io_trimesh/import_ply.h>
//#include <wrap/io_trimesh/export_ply.h>
// update
#include <vcg/complex/trimesh/update/topology.h>
#include <vcg/complex/local_optimization.h>
#include <vcg/complex/local_optimization/tri_edge_collapse_quadric.h>
#include <vcg/space/point3.h>
#include "border.h"
class MyEdge;
class MyFace;
class MyVertex:public vcg::VertexAFVMVNf<DUMMYEDGETYPE , MyFace,DUMMYTETRATYPE>{public:
ScalarType w;
vcg::math::Quadric<vcg::Plane3<ScalarType,false> >q;
ScalarType & W(){return w;}
} ;
class MyFace : public vcg::FaceAV<MyVertex,DUMMYEDGETYPE , MyFace>{};
class MyMesh:
public vcg::tri::TriMesh< std::vector<MyVertex>, std::vector<MyFace > >{};
class MyTriEdgeCollapse:
public vcg::tri::TriEdgeCollapseQuadric< MyMesh, MyTriEdgeCollapse >{
public:
typedef vcg::tri::TriEdgeCollapseQuadric<MyMesh, MyTriEdgeCollapse > 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<Point3f> &newvert,
vector<unsigned int> &newface,
vector<Link> &newbord,
vector<int> &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<MyMesh>::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<MyMesh> DeciSession(mesh);
MyTriEdgeCollapse::SetDefaultParams();
DeciSession.Init<MyTriEdgeCollapse>();
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<int> 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<float, pair<int, int> > 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<float, pair<int, int> >::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;
}

View File

@ -1,4 +1,5 @@
#include <iostream>
#include <assert.h>
#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<unsigned int> &patches,
std::vector<Link> &newbord) {
map<unsigned int, vector<unsigned int> > remap;
set<Link> newborders;
set<unsigned int> 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<unsigned int>::const_iterator i;
for(i = patches.begin(); i != patches.end(); i++) {
@ -167,29 +174,42 @@ void Nexus::Join(const std::set<unsigned int> &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<unsigned int> &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++;
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<unsigned int> &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<unsigned int> &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<Link>::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<unsigned int> &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<Point3f, unsigned short> vertices;
vector<unsigned short> remap;
remap.resize(patch.nv);
// map<unsigned short, unsigned short> 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<Point3f> newvert;
newvert.resize(vertices.size());
map<Point3f, unsigned short>::iterator k;
for(k = vertices.begin(); k != vertices.end(); k++) {
newvert[(*k).second] = (*k).first;
}
vector<unsigned short> 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<unsigned int> 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<unsigned int>::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<Link> 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;
}

View File

@ -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<unsigned int> &faces,
std::vector<Link> &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;

109
apps/nexus/nexusmt.cpp Normal file
View File

@ -0,0 +1,109 @@
#include "nexusmt.h"
#include <map>
#include <queue>
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<unsigned int, unsigned int> cell_node;
nodes.resize(history.size());
//building fragments and nodes.
unsigned int current_node = 0;
vector<Update>::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<unsigned int, vector<unsigned int> > 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<unsigned int, vector<unsigned int> >::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<unsigned int> &cells = (*e).second;
vector<unsigned int>::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<unsigned int> &selected, float error) {
std::vector<Node>::iterator n;
for(n = nodes.begin(); n != nodes.end(); n++)
(*n).visited = false;
std::queue<Node *> qnodo;
qnodo.push(&nodes[0]);
nodes[0].visited = true;
for( ; !qnodo.empty(); qnodo.pop()) {
Node &node = *qnodo.front();
std::vector<Frag>::iterator fragment;
std::vector<Node *>::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<unsigned int>::iterator cell;
for(cell=(*fragment).begin(); cell != (*fragment).end(); ++cell)
selected.push_back(*cell);
}
}
}
}

33
apps/nexus/nexusmt.h Normal file
View File

@ -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<unsigned int> {};
struct Node {
std::vector<Node *> in;
std::vector<Node *> out;
std::vector<Frag> frags;
float error;
bool visited;
};
std::vector<Node> nodes;
public:
void LoadHistory();
void ClearHistory();
void ExtractFixed(std::vector<unsigned int> &selected, float error);
};
}
#endif

View File

@ -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,13 +260,18 @@ int main(int argc, char *argv[]) {
glVertex3f(p3[0], p3[1], p3[2]);
}
glEnd();
}
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(2);
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;
@ -271,8 +279,10 @@ int main(int argc, char *argv[]) {
glVertex3f(p[0], p[1], p[2]);
}
glEnd();
glEnable(GL_DEPTH_TEST);
glEnable(GL_LIGHTING);
}
}
SDL_GL_SwapBuffers();

98
apps/nexus/patch.cpp Normal file
View File

@ -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;
}

View File

@ -5,134 +5,73 @@
#include <iostream>
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,
unsigned short nv, unsigned short nf);
Patch(Signature signature, Chunk *s = NULL,
unsigned short nv = 0, unsigned short nf = 0):
start(s) {
Resize(signature, nv, nf);
}
void Init(Signature signature, 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));
inline vcg::Point3f *VertBegin();
inline unsigned short *FaceBegin();
unsigned int size = nf * sizeof(unsigned short);
if(!(signature & HAS_STRIP)) size *= 3;
cstart = (void *)(((char *)fstart) + size);
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; }
// unsigned int ChunkSize() { return ChunkSize(VertSize(), FaceSize()); }
// unsigned int ByteSize() { return ByteSize(VertSize(), FaceSize()); }
inline vcg::Point3f &Vert(unsigned short v);
inline unsigned short *Face(unsigned short f);
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);
unsigned short nvert,
unsigned short nface);
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;
}
// 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

View File

@ -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;

View File

@ -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<Nexus::Update> level_history;
map<unsigned int, set<unsigned int> >::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<unsigned int> &fcells = (*fragment).second;
set<unsigned int>::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<int> 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<unsigned int, unsigned short> 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<RemapLink> &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];
// 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++) {
unsigned int remap_start = local.border_start/2;
//* 2 is to accomodate future borders
RemapLink start_link = border_remap[k];
// K is the main iterator (where we write to in nexus.borders)
for(unsigned int k = 0; k < local.border_used; 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++) {
RemapLink end_link = border_remap[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 + 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<unsigned int, vector<int> > vert_remap;
map<unsigned int, unsigned int> vert_count;
@ -544,44 +570,110 @@ void NexusSplit(Nexus &nexus, VoronoiChain &vchain,
v_remap[newface[f+i]] = vert_count[cell]++;
}
//TODO prune small count cells
//for every new cell
//lets count borders
map<unsigned int, unsigned int> bord_count;
map<unsigned int, unsigned int >::iterator c;
for(c = vert_count.begin(); c != vert_count.end(); c++) {
unsigned int cell = (*c).first;
cerr << "Processing cell: " << cell << endl;
vector<unsigned short> faces;
vector<Point3f> verts;
vector<Link> bords;
unsigned int &count = bord_count[cell];
count = 0;
vector<int> &v_remap = vert_remap[cell];
vector<int> &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<unsigned int, unsigned int >::iterator t;
for(t = vert_count.begin(); t != vert_count.end(); t++) {
if(cell == (*t).first) continue;
vector<int> &vremapclose = vert_remap[(*t).first];
for(unsigned int i = 0; i < newvert.size(); i++) {
if(v_remap[i] != -1 && vremapclose[i] != -1) {
count++;
}
}
}
}
map<unsigned int, unsigned int> 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<int> &v_remap = vert_remap[cell];
vector<Point3f> 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<int> &f_remap = face_remap[cell];
vector<unsigned short> 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]];
}
if(patch_idx == 68)
cerr << "68 bord: " << bord_count[cell] << endl;
//borders last
vector<Link> 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;
@ -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<Nexus::Update> &history) {