*** empty log message ***

This commit is contained in:
ganovelli 2005-10-06 10:08:51 +00:00
parent 644fca68bf
commit 76617c2a7f
66 changed files with 0 additions and 13883 deletions

View File

@ -1,97 +0,0 @@
/****************************************************************************
* VCGLib o o *
* Visual and Computer Graphics Library o o *
* _ O _ *
* Copyright(C) 2004 \/)\/ *
* Visual Computing Lab /\/| *
* ISTI - Italian National Research Council | *
* \ *
* All rights reserved. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
* for more details. *
* *
****************************************************************************/
/****************************************************************************
History
$Log: not supported by cvs2svn $
Revision 1.6 2005/01/21 17:09:12 ponchio
Porting and debug.
Revision 1.5 2004/10/08 14:46:26 ponchio
Working version.
Revision 1.4 2004/09/30 00:27:08 ponchio
Added used counter.
Revision 1.3 2004/07/05 17:02:17 ponchio
Couple of const missing.
Revision 1.2 2004/07/04 14:21:31 ponchio
Added operator< to Link
Revision 1.1 2004/07/02 13:00:02 ponchio
Created.
****************************************************************************/
#ifndef NXS_BORDER_H
#define NXS_BORDER_H
namespace nxs {
struct Link {
Link(): start_vert(0xffff), end_vert(0xffff), end_patch(0xffffffff) {}
Link(unsigned short sv, unsigned short ev, unsigned int ep):
start_vert(sv), end_vert(ev), end_patch(ep) {}
unsigned short start_vert;
unsigned short end_vert;
unsigned int end_patch;
bool IsNull() { return end_patch == 0xffffffff; }
bool operator==(const Link &l) const {
return end_patch == l.end_patch &&
end_vert == l.end_vert &&
start_vert == l.start_vert;
}
bool operator<(const Link &l) const {
if(end_patch == l.end_patch) {
if(start_vert == l.start_vert) {
return end_vert < l.end_vert;
} else
return start_vert < l.start_vert;
} else
return end_patch < l.end_patch;
}
};
class Border {
public:
Border(Link *l = NULL, unsigned short _used = 0, unsigned short _size = 0):
links(l), used(_used), size(_size), start(0) {}
unsigned int Size() { return used; }
//TODO rename available to capacity.
unsigned int Capacity() { return size; }
Link &operator[](unsigned int i) { return links[i]; }
Link *Start() { return links; }
//TODO implement an iterator!
Link *links;
unsigned int used;
unsigned int size;
unsigned int start;
};
}
#endif

View File

@ -1,176 +0,0 @@
/****************************************************************************
* VCGLib o o *
* Visual and Computer Graphics Library o o *
* _ O _ *
* Copyright(C) 2004 \/)\/ *
* Visual Computing Lab /\/| *
* ISTI - Italian National Research Council | *
* \ *
* All rights reserved. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
* for more details. *
* *
****************************************************************************/
/****************************************************************************
History
$Log: not supported by cvs2svn $
Revision 1.10 2005/02/08 12:43:03 ponchio
Added copyright
****************************************************************************/
#include "borderserver.h"
#include <iostream>
using namespace std;
using namespace nxs;
bool BorderServer::Create(const string &file) {
ram_used = 0;
return IndexFile<Border>::Create(file, 2 * sizeof(Link));
}
bool BorderServer::Load(const string &file, bool rdonly) {
ram_used = 0;
bool success = IndexFile<Border>::Load(file, rdonly);
if(!success) return false;
for(unsigned int i = 0; i < size(); i++)
operator[](i).links = NULL;
return true;
}
void BorderServer::Close() {
if(!Opened()) return;
Flush();
IndexFile<Border>::Close();
}
void BorderServer::Flush() {
std::map<unsigned int, list<unsigned int>::iterator>::iterator i;
for(i = index.begin(); i != index.end(); i++) {
unsigned int patch = (*i).first;
FlushBorder(patch);
}
pqueue.clear();
index.clear();
}
void BorderServer::AddBorder(unsigned short _size, unsigned int used) {
Border entry;
assert((Length() % sizeof(Link)) == 0);
entry.start = Length()/ sizeof(Link);
entry.size = _size;
entry.used = used;
entry.links = NULL;
push_back(entry);
Redim((int64)entry.start * (int64)sizeof(Link) + (int64)_size * (int64)sizeof(Link));
}
Border &BorderServer::GetBorder(unsigned int border, bool flush) {
Border &entry = operator[](border);
//assert(entry.size != 0);
if(index.count(border)) {
//assert(entry.links);
list<unsigned int>::iterator i = index[border];
pqueue.erase(i);
pqueue.push_front(border);
index[border] = pqueue.begin();
} else {
while(flush && ram_used > ram_max) {
if(!pqueue.size()) {
cerr << "Ram used: " << ram_used << " ram max: " << ram_max << endl;
}
assert(pqueue.size());
unsigned int to_flush = pqueue.back();
pqueue.pop_back();
index.erase(to_flush);
FlushBorder(to_flush);
}
entry.links = GetRegion(entry.start, entry.size);
pqueue.push_front(border);
index[border] = pqueue.begin();
ram_used += entry.size;
}
return entry;
}
//TODO Change when remving borderentry class.
void BorderServer::ResizeBorder(unsigned int border, unsigned int used) {
assert(border < size());
Border &entry = GetBorder(border);
if(used <= entry.size) {
entry.used = used;
return;
}
int capacity = used;
if(capacity < entry.size * 2)
capacity = entry.size * 2;
unsigned int newstart = Length()/sizeof(Link);
Redim((int64)(newstart + capacity) * (int64)sizeof(Link));
Link *newlinks = new Link[capacity];
ram_used += (capacity - entry.size);
if(entry.used > 0) {
assert(entry.links);
memcpy(newlinks, entry.links, entry.used * sizeof(Link));
delete []entry.links;
entry.links = NULL;
}
assert(entry.links == NULL);
entry.links = newlinks;
entry.start = newstart;
entry.size = capacity;
entry.used = used;
}
void BorderServer::FlushBorder(unsigned int border) {
Border &entry = operator[](border);
//assert(entry.links);
if(entry.size && !MFile::IsReadOnly()) { //write back patch
MFile::SetPosition((int64)entry.start * (int64)sizeof(Link));
MFile::WriteBuffer(entry.links, entry.used * (int64)sizeof(Link));
}
if(entry.links)
delete [](entry.links);
entry.links = NULL;
ram_used -= entry.size;
}
Link *BorderServer::GetRegion(unsigned int start, unsigned int size) {
if(size == 0) return NULL;
SetPosition((int64)start * (int64)sizeof(Link));
Link *buf = new Link[size];
assert(buf);
ReadBuffer(buf, (int64)size * (int64)sizeof(Link));
return buf;
}
bool BorderServer::LoadHeader() {
unsigned int magic;
ReadBuffer(&magic, sizeof(unsigned int));
if(magic != 0x3042584e) { //NXB0
cerr << "Invalid magic. Not a nxs file\n";
return false;
}
ReadBuffer(&offset, sizeof(int64));
return true;
}
void BorderServer::SaveHeader() {
unsigned int magic = 0x3042584e; // NXB0
WriteBuffer(&magic, sizeof(unsigned int));
WriteBuffer(&offset, sizeof(int64));
}

View File

@ -1,77 +0,0 @@
/****************************************************************************
* VCGLib o o *
* Visual and Computer Graphics Library o o *
* _ O _ *
* Copyright(C) 2004 \/)\/ *
* Visual Computing Lab /\/| *
* ISTI - Italian National Research Council | *
* \ *
* All rights reserved. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
* for more details. *
* *
****************************************************************************/
/****************************************************************************
History
$Log: not supported by cvs2svn $
Revision 1.5 2005/02/08 12:43:03 ponchio
Added copyright
****************************************************************************/
#ifndef NXS_BORDERSERVER_H
#define NXS_BORDERSERVER_H
#include <list>
#include <map>
#include "index_file.h"
#include "border.h"
/*nell'header ci sta scritto solo:
spazio riservato: 2 * sizeof(Link);
magic: nxb0 (4 bytes)
offset: (int64) */
namespace nxs {
class BorderServer: public IndexFile<Border> {
public:
BorderServer(): ram_max(1000000), ram_used(0) {}
~BorderServer() { Close(); }
bool Create(const std::string &file);
bool Load(const std::string &file, bool readonly = true);
void Close();
void Flush();
void AddBorder(unsigned short size, unsigned int used = 0);
Border &GetBorder(unsigned int border, bool flush = true);
void ResizeBorder(unsigned int border, unsigned int size);
unsigned int ram_max;
unsigned int ram_used;
protected:
std::list<unsigned int> pqueue;
std::map<unsigned int, std::list<unsigned int>::iterator> index;
bool LoadHeader();
void SaveHeader();
void FlushBorder(unsigned int border);
Link *GetRegion(unsigned int start, unsigned int size); //size in links.
};
}
#endif

View File

@ -1,147 +0,0 @@
/****************************************************************************
* VCGLib o o *
* Visual and Computer Graphics Library o o *
* _ O _ *
* Copyright(C) 2004 \/)\/ *
* Visual Computing Lab /\/| *
* ISTI - Italian National Research Council | *
* \ *
* All rights reserved. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
* for more details. *
* *
****************************************************************************/
/****************************************************************************
History
$Log: not supported by cvs2svn $
Revision 1.3 2004/11/30 22:50:30 ponchio
Level 0.
Revision 1.2 2004/07/02 13:08:11 ponchio
Changed extension to .cri, crv, crf
Revision 1.1 2004/06/24 14:32:45 ponchio
Moved from wrap/nexus
Revision 1.1 2004/06/22 15:31:54 ponchio
Created
****************************************************************************/
#include <stdio.h>
#include "crude.h"
using namespace std;
using namespace vcg;
using namespace nxs;
Crude::~Crude() {
if(fp)
Close();
}
bool Crude::Create(const std::string &file, unsigned int nv, unsigned int nf) {
if(!vert.Create(file + ".crv")) return false;
if(!face.Create(file + ".crf")) return false;
fp = fopen((file + ".cri").c_str(), "wb+");
if(!fp) return false;
Resize(nv, nf);
return true;
}
bool Crude::Load(const std::string &file, bool rdonly) {
if(!vert.Load(file + ".crv", rdonly)) return false;
if(!face.Load(file + ".crf", rdonly)) return false;
fp = fopen((file + ".cri").c_str(), "rb+");
if(!fp) return false;
fread(&nvert, sizeof(unsigned int), 1, fp);
fread(&nface, sizeof(unsigned int), 1, fp);
fread(&box, sizeof(Box3f), 1, fp);
return true;
}
void Crude::Close() {
vert.Close();
face.Close();
rewind(fp);
fwrite(&nvert, sizeof(unsigned int), 1, fp);
fwrite(&nface, sizeof(unsigned int), 1, fp);
fwrite(&box, sizeof(Box3f), 1, fp);
fclose(fp);
fp = NULL;
}
void Crude::Resize(unsigned int nv, unsigned int nf) {
nvert = nv;
nface = nf;
vert.Resize(nv);
face.Resize(nf);
}
unsigned int Crude::Vertices() {
return nvert;
}
unsigned int Crude::Faces() {
return nface;
}
void Crude::SetVertex(unsigned int i, Point3f &f) {
Point3f &p = vert[i];
p[0] = f[0];
p[1] = f[1];
p[2] = f[2];
}
void Crude::SetVertex(unsigned int i, float *f) {
Point3f &p = vert[i];
p[0] = f[0];
p[1] = f[1];
p[2] = f[2];
}
Point3f Crude::GetVertex(unsigned int i) {
return vert[i];
}
Crude::Face Crude::GetFace(unsigned int i) {
return face[i];
}
void Crude::SetFace(unsigned int i, Face &f) {
Face &ff = face[i];
ff[0] = f[0];
ff[1] = f[1];
ff[2] = f[2];
}
void Crude::SetFace(unsigned int i, unsigned int *f) {
Face &ff = face[i];
ff[0] = f[0];
ff[1] = f[1];
ff[2] = f[2];
}
vcg::Point3f Crude::GetBari(unsigned int i) {
Point3f bari(0, 0, 0);
Face &f = face[i];
for(int k = 0; k < 3; k++)
bari += vert[f[k]];
bari /= 3;
return bari;
}
vcg::Box3f &Crude::GetBox() {
return box;
}

View File

@ -1,129 +0,0 @@
/****************************************************************************
* VCGLib o o *
* Visual and Computer Graphics Library o o *
* _ O _ *
* Copyright(C) 2004 \/)\/ *
* Visual Computing Lab /\/| *
* ISTI - Italian National Research Council | *
* \ *
* All rights reserved. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
* for more details. *
* *
****************************************************************************/
/****************************************************************************
History
$Log: not supported by cvs2svn $
Revision 1.5 2004/11/30 22:50:30 ponchio
Level 0.
Revision 1.4 2004/07/05 15:49:38 ponchio
Windows (DevCpp, mingw) port.
Revision 1.3 2004/07/04 15:25:33 ponchio
Backup (work in progress)
Revision 1.2 2004/06/25 16:47:13 ponchio
Various debug
Revision 1.1 2004/06/24 14:32:45 ponchio
Moved from wrap/nexus
Revision 1.1 2004/06/22 15:31:40 ponchio
Created
****************************************************************************/
#ifndef NXS_CRUDE_H
#define NXS_CRUDE_H
#include <string>
#include <vcg/space/point3.h>
#include <vcg/space/box3.h>
#include "vfile.h"
namespace nxs {
class Crude {
public:
struct Face {
Face() {}
Face(unsigned int a, unsigned int b, unsigned int c) {
v[0] = a; v[1] = b; v[2] = c;
}
unsigned int v[3];
unsigned int &operator[](int k) { return v[k]; }
unsigned int *ptr() { return v; }
};
VFile<vcg::Point3f> vert;
VFile<Face> face;
Crude(): fp(NULL), nvert(0), nface(0) {}
~Crude();
bool Create(const std::string &file, unsigned int nvert = 0,
unsigned int nface = 0);
bool Load(const std::string &file, bool rdonly = false);
void Close();
void Resize(unsigned int nvert, unsigned int nface);
unsigned int Vertices();
unsigned int Faces();
vcg::Point3f GetVertex(unsigned int i);
void SetVertex(unsigned int i, vcg::Point3f &p);
void SetVertex(unsigned int i, float *p);
Face GetFace(unsigned int i);
void SetFace(unsigned int i, Face &f);
void SetFace(unsigned int i, unsigned int *f);
vcg::Point3f GetBari(unsigned int i);
vcg::Box3f &GetBox();
/*template <class MESH> void Export(MESH &mesh) {
MESH::VertexType v;
v.ClearFlags();
for(unsigned int i = 0; i < <Vertices(); i++) {
v.P().Import(GetVertex(i));
mesh.vert.push_back(v);
}
MESH::FaceType f;
f.ClearFlags();
for(unsigned int i = 0; i < Faces(); i++) {
for(int k = 0; k < 3; k++) {
f.
mesh.vert.push_back(GetVertex(i));
}
}
}*/
protected:
FILE *fp;
unsigned int nvert;
unsigned int nface;
vcg::Box3f box;
};
} //namespace
#endif

View File

@ -1,264 +0,0 @@
/****************************************************************************
* VCGLib o o *
* Visual and Computer Graphics Library o o *
* _ O _ *
* Copyright(C) 2004 \/)\/ *
* Visual Computing Lab /\/| *
* ISTI - Italian National Research Council | *
* \ *
* All rights reserved. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
* for more details. *
* *
****************************************************************************/
/****************************************************************************
History
$Log: not supported by cvs2svn $
Revision 1.7 2005/01/14 15:49:42 ponchio
VertRemap removed.
Revision 1.6 2004/12/01 03:24:30 ponchio
Level 2.
Revision 1.5 2004/10/19 17:04:32 ponchio
#include <trackball> on the top
Revision 1.4 2004/10/19 04:23:57 ponchio
Added trackball.
Revision 1.3 2004/09/17 15:25:09 ponchio
First working (hopefully) release.
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.
Revision 1.3 2004/07/02 13:03:34 ponchio
*** empty log message ***
Revision 1.2 2004/07/01 21:33:46 ponchio
Added remap reading.
Revision 1.1 2004/06/23 00:10:38 ponchio
Created
****************************************************************************/
#include <iostream>
using namespace std;
#include <wrap/gui/trackball.h>
#include <SDL/SDL.h>
#ifdef WIN32
#include <windows.h>
#endif
#include <GL/gl.h>
#include <GL/glu.h>
#include <apps/nexus/crude.h>
using namespace vcg;
using namespace nxs;
bool fullscreen = false;
int width =1024;
int height = 768;
SDL_Surface *screen = NULL;
bool init() {
if(SDL_Init(SDL_INIT_VIDEO) != 0) {
return false;
}
const SDL_VideoInfo *info = SDL_GetVideoInfo();
int bpp = info->vfmt->BitsPerPixel;
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
int flags = SDL_OPENGL;
if(fullscreen)
flags |= SDL_FULLSCREEN;
screen = SDL_SetVideoMode(width, height, bpp, flags);
if(!screen) {
return false;
}
SDL_WM_SetCaption("Crudeview", "Crudeview");
glDisable(GL_DITHER);
glShadeModel(GL_SMOOTH);
glHint( GL_FOG_HINT, GL_NICEST );
glEnable(GL_DEPTH_TEST);
glDepthFunc( GL_LEQUAL );
glDisable(GL_LIGHTING);
glEnableClientState(GL_VERTEX_ARRAY);
return true;
}
int main(int argc, char *argv[]) {
if(argc < 2) {
cerr << "Usage: " << argv[0] << " <crude file>\n";
return -1;
}
Crude crude;
if(!crude.Load(argv[1])) {
cerr << "Could not load crude file: " << argv[1] << endl;
return -1;
}
Box3f box = crude.GetBox();
bool vremap = false;
bool fremap = false;
VFile<unsigned int> face_remap;
if(face_remap.Load(argv[1] + string(".rfm"), true)) {
cerr << "Found face remap.\n";
fremap = true;
} else {
cerr << "Face remap not found.\n";
}
if(!init()) {
cerr << "Could not init SDL window\n";
return -1;
}
Trackball track;
glClearColor(0, 0, 0, 0);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_NORMALIZE);
glEnable(GL_COLOR_MATERIAL);
bool redraw = false;
bool show_normals = true;
int quit = 0;
SDL_Event event;
int x, y;
float alpha = 0;
while( !quit ) {
bool first = true;
SDL_WaitEvent(&event);
while( first || SDL_PollEvent( &event ) ){
first = false;
switch( event.type ) {
case SDL_QUIT: quit = 1; break;
case SDL_KEYDOWN:
switch(event.key.keysym.sym) {
case SDLK_RCTRL:
case SDLK_LCTRL:
track.ButtonDown(Trackball::KEY_CTRL); break;
case SDLK_q: exit(0); break;
}
break;
case SDL_MOUSEBUTTONDOWN:
x = event.button.x;
y = event.button.y;
if(event.button.button == SDL_BUTTON_WHEELUP)
track.MouseWheel(1);
else if(event.button.button == SDL_BUTTON_WHEELDOWN)
track.MouseWheel(-1);
else if(event.button.button == SDL_BUTTON_LEFT)
track.MouseDown(x, y, Trackball::BUTTON_LEFT);
else if(event.button.button == SDL_BUTTON_RIGHT)
track.MouseDown(x, y, Trackball::BUTTON_RIGHT);
break;
case SDL_MOUSEBUTTONUP:
x = event.button.x;
y = event.button.y;
if(event.button.button == SDL_BUTTON_LEFT)
track.MouseUp(x, y, Trackball::BUTTON_LEFT);
else if(event.button.button == SDL_BUTTON_RIGHT)
track.MouseUp(x, y, Trackball::BUTTON_RIGHT);
break;
case SDL_MOUSEMOTION:
while(SDL_PeepEvents(&event, 1, SDL_GETEVENT, SDL_MOUSEMOTIONMASK));
x = event.motion.x;
y = event.motion.y;
track.MouseMove(x, y);
break;
default: break;
}
redraw = true;
}
if(!redraw) continue;
redraw = false;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60, 1, 0.1, 100);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0,0,3, 0,0,0, 0,1,0);
track.GetView();
track.Apply();
float scale = 3/box.Diag();
glScalef(0.4, 0.4, 0.4);
glScalef(scale, scale, scale);
Point3f center = box.Center();
glTranslatef(-center[0], -center[1], -center[2]);
glColor3f(0, 1, 0);
glBegin(GL_TRIANGLES);
for(unsigned int i = 0;i < crude.Faces(); i++) {
Crude::Face face = crude.GetFace(i);
if(fremap) {
unsigned int val = face_remap[i];
glColor3ub((val * 27)%255, (val * 37)%255, (val * 87)%255);
}
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();
SDL_GL_SwapBuffers();
}
SDL_Quit();
return -1;
}

View File

@ -1,265 +0,0 @@
#include <iostream>
// stuff to define the mesh
#include <vcg/simplex/vertex/with/afvmvn.h>
#include <vcg/simplex/edge/edge.h>
#include <vcg/math/quadric.h>
#include <vcg/complex/trimesh/base.h>
#include <vcg/simplex/face/with/av.h>
#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 "vpartition.h"
#include "fragment.h"
#include "decimate.h"
#include <wrap/io_trimesh/export_ply.h>
using namespace vcg;
using namespace tri;
using namespace nxs;
using namespace std;
class MyEdge;
class MyFace;
class MyVertex:
public vcg::VertexAFVMVNf<MyEdge, MyFace,DUMMYTETRATYPE> {
public:
ScalarType w;
vcg::math::Quadric<double> q;
ScalarType & W() { return w; }
};
struct MyEdge: public Edge<double,MyEdge,MyVertex> {
inline MyEdge():Edge<double,MyEdge,MyVertex>(){UberFlags()=0;}
inline MyEdge(MyVertex* a,MyVertex* b):Edge<double,MyEdge,MyVertex>(a,b){
UberFlags()=0;}
};
class MyFace : public vcg::FaceAV<MyVertex, MyEdge, 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::EdgeType EdgeType;
inline MyTriEdgeCollapse( EdgeType p, int i) :TECQ(p,i){}
};
float Cluster(MyMesh &mesh, unsigned int target_faces);
float Quadric(MyMesh &mesh, unsigned int target_faces);
float nxs::Decimate(Decimation mode,
unsigned int target_faces,
vector<Point3f> &newvert,
vector<unsigned int> &newface,
vector<BigLink> &newbord) {
for(unsigned int i = 0; i < newface.size(); i+= 3) {
assert(newface[i] != newface[i+1]);
assert(newface[i] != newface[i+2]);
assert(newface[i+1] != newface[i+2]);
}
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.vert.size());
face.V(k) = &mesh.vert[newface[i+k]];
}
mesh.face.push_back(face);
}
mesh.fn = mesh.face.size();
//mark borders
for(unsigned int i = 0; i < newbord.size(); i++)
mesh.vert[newbord[i].start_vert].ClearW();
float error;
switch(mode) {
case CLUSTER: error = Cluster(mesh, target_faces); break;
case QUADRIC: error = Quadric(mesh, target_faces); break;
default: cerr << "Unknown simplification mode: " << mode << endl;
exit(0);
}
newvert.clear();
newface.clear();
unsigned int totvert = 0;
vector<int> vert_remap;
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++)
newface.push_back(vert_remap[face.V(k) - vert_start]);
}
for(unsigned int i = 0; i < newbord.size(); i++) {
unsigned int &v = newbord[i].start_vert;
assert(vert_remap[v] != -1);
v = vert_remap[v];
}
return error;
}
float Quadric(MyMesh &mesh, unsigned int target_faces) {
vcg::tri::UpdateTopology<MyMesh>::VertexFace(mesh);
vcg::tri::UpdateBounding<MyMesh>::Box(mesh);
vcg::LocalOptimization<MyMesh> DeciSession(mesh);
MyTriEdgeCollapse::SetDefaultParams();
DeciSession.Init<MyTriEdgeCollapse>();
DeciSession.SetTargetSimplices(target_faces);
DeciSession.DoOptimization();
float error = 0;
int count = 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++) {
error += (face.cV(k)->cP() - face.cV((k+1)%3)->cP()).Norm();
count++;
}
}
error /= count;
return error;
return 0;
}
float Cluster(MyMesh &mesh, unsigned int target_faces) {
unsigned int starting = mesh.vn;
unsigned int nseeds = target_faces/2;
#ifndef NDEBUG
if(nseeds >= mesh.vert.size()) {
cerr << "Strange! nseeds > vert.size(): " << nseeds
<< " >= "<< mesh.vert.size() << endl;
}
#endif
vector<unsigned int> remap;
VPartition part;
for(unsigned int i = 0; i < mesh.vert.size(); i++) {
const Point3f &p = mesh.vert[i].cP();
if(!mesh.vert[i].IsW()) {
part.push_back(p);
remap.push_back(i);
nseeds--;
}
}
unsigned int nborder = part.size();
//Todo I should supersample before
while(nseeds > 0 && part.size() < mesh.vn) {
unsigned int i = rand() % mesh.vert.size();
if(mesh.vert[i].IsW() && !mesh.vert[i].IsV()) {
const Point3f &p = mesh.vert[i].cP();
part.push_back(p);
mesh.vert[i].SetV();
remap.push_back(i);
nseeds--;
}
}
if(part.size() == 0) {
cerr << "WARNING: could not simplyfiy... everything was border.\n";
return 0; //everything is locked...
}
part.Init();
vector<Point3f> centroid;
vector<unsigned int> count;
for(unsigned int i = 0; i < 3; i++) {
centroid.clear();
centroid.resize(mesh.vert.size(), Point3f(0, 0, 0));
count.clear();
count.resize(mesh.vert.size(), 0);
for(unsigned int i = 0; i < mesh.vert.size(); i++) {
unsigned int target = part.Locate(mesh.vert[i].cP());
centroid[target] += mesh.vert[i].cP();
count[target]++;
}
for(unsigned int i = nborder; i < part.size(); i++) {
if(count[i] > 0)
part[i] = centroid[i]/count[i];
}
}
for(unsigned int i = nborder; i < part.size(); i++) {
assert(mesh.vert[remap[i]].IsV());
mesh.vert[remap[i]].P() = part[i];
}
float error = 0;
//rimappiamo le facce.....
for(unsigned int i = 0; i < mesh.face.size(); i++) {
MyFace &face = mesh.face[i];
for(int k = 0; k < 3; k++) {
unsigned int target = part.Locate(face.V(k)->cP());
assert(target < remap.size());
assert(remap[target] < mesh.vert.size());
MyVertex &vert = mesh.vert[remap[target]];
float dist = Distance(vert.cP(), face.V(k)->cP());
if(dist > error) error = dist;
face.V(k) = &vert;
}
}
for(unsigned int i = 0; i < mesh.face.size(); i++) {
MyFace &face = mesh.face[i];
assert(!face.IsD());
for(int k = 0; k < 3; k++) {
assert(face.cV(k)->IsV() || !face.cV(k)->IsW());
}
if(face.cV(0) == face.cV(1) ||
face.cV(0) == face.cV(2) ||
face.cV(1) == face.cV(2)) {
face.SetD();
mesh.fn--;
}
}
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--;
}
return error;
}

View File

@ -1,49 +0,0 @@
/****************************************************************************
* VCGLib o o *
* Visual and Computer Graphics Library o o *
* _ O _ *
* Copyright(C) 2004 \/)\/ *
* Visual Computing Lab /\/| *
* ISTI - Italian National Research Council | *
* \ *
* All rights reserved. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
* for more details. *
* *
****************************************************************************/
/****************************************************************************
History
$Log: not supported by cvs2svn $
****************************************************************************/
#ifndef NXS_DECIMATE_H
#define NXS_DECIMATE_H
#include <vector>
#include "border.h"
#include "fragment.h"
#include <vcg/space/point3.h>
namespace nxs {
enum Decimation { QUADRIC, CLUSTER };
class BigLink;
float Decimate(Decimation mode,
unsigned int target_faces,
std::vector<vcg::Point3f> &newvert,
std::vector<unsigned int> &newface,
std::vector<BigLink> &newbord);
}
#endif

View File

@ -1,108 +0,0 @@
#include <stdlib.h>
#include <iostream>
#include "nexus.h"
using namespace nxs;
using namespace vcg;
using namespace std;
Point3f explode(Point3f &v, Point3f &center, Point3f &dir, float mag) {
v = ((v - center) * mag + center) + dir;
return v;
}
int main(int argc, char *argv[]) {
if(argc < 3) {
cerr << "Usage: " << argv[0] << " <input> <output> [factor]\n";
return -1;
}
string input = argv[1];
string output = argv[2];
float factor = 2;
if(argc == 4) {
factor = atoi(argv[3]);
if(factor == 0) {
cerr << "Invalid factor: " << argv[3] << endl;
return -1;
}
}
Nexus in;
if(!in.Load(input, true)) {
cerr << "Could not load nexus: " << input << endl;
return -1;
}
Nexus out;
if(!out.Create(output, in.signature, in.chunk_size)) {
cerr << "Could not create nexus: " << output << endl;
return -1;
}
out.sphere = in.sphere;
out.history = in.history;
for(unsigned int i = 0; i < in.index.size(); i++) {
unsigned int patch = i;
Nexus::PatchInfo &src_entry = in.index[patch];
Patch &src_patch = in.GetPatch(patch);
Border src_border = in.GetBorder(patch);
out.AddPatch(src_entry.nvert, src_entry.nface, src_border.Available());
Nexus::PatchInfo &dst_entry = out.index[patch];
Patch dst_patch = out.GetPatch(patch);
Point3f dir = src_entry.sphere.Center() - in.sphere.Center();
dir.Normalize();
dir *= 10 * src_entry.error;
memcpy(dst_patch.VertBegin(), src_patch.VertBegin(),
src_patch.nv * sizeof(Point3f));
Point3f *ptr = dst_patch.VertBegin();
for(int i = 0; i < dst_patch.nv; i++) {
ptr[i] = explode(ptr[i], src_entry.sphere.Center(), dir,
0.5 *src_entry.error);
}
if(in.signature & NXS_STRIP) {
memcpy(dst_patch.FaceBegin(), src_patch.FaceBegin(),
src_patch.nf * sizeof(unsigned short));
} else {
memcpy(dst_patch.FaceBegin(), src_patch.FaceBegin(),
src_patch.nf * sizeof(unsigned short) * 3);
}
if((in.signature & NXS_COLORS) && (out.signature & NXS_COLORS))
memcpy(dst_patch.ColorBegin(), src_patch.ColorBegin(),
src_patch.nv * sizeof(unsigned int));
if((in.signature & NXS_NORMALS_SHORT) &&
(out.signature & NXS_NORMALS_SHORT))
memcpy(dst_patch.Norm16Begin(), src_patch.Norm16Begin(),
src_patch.nv * sizeof(short)*4);
//reordering
//WATCH OUT BORDERS!
// Reorder(out.signature, dst_patch);
//copying entry information;
dst_entry.sphere = src_entry.sphere;
dst_entry.error = src_entry.error;
//adding borders.
for(unsigned int i = 0; i < src_border.Size(); i++) {
Link &link = src_border[i];
if(link.IsNull()) continue;
assert(link.end_patch < in.index.size());
}
Border dst_border = out.GetBorder(patch);
out.borders.ResizeBorder(patch, src_border.Size());
memcpy(dst_border.Start(), src_border.Start(),
src_border.Size() * sizeof(Link));
}
in.Close();
out.Close();
return 0;
}

View File

@ -1,485 +0,0 @@
/****************************************************************************
* VCGLib o o *
* Visual and Computer Graphics Library o o *
* _ O _ *
* Copyright(C) 2004 \/)\/ *
* Visual Computing Lab /\/| *
* ISTI - Italian National Research Council | *
* \ *
* All rights reserved. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
* for more details. *
* *
****************************************************************************/
/****************************************************************************
History
$Log: not supported by cvs2svn $
Revision 1.12 2005/03/02 10:40:17 ponchio
Extraction rewrittten (to fix recusive problems).
Revision 1.11 2005/02/20 19:49:44 ponchio
cleaning (a bit more).
Revision 1.10 2005/02/20 18:07:00 ponchio
cleaning.
Revision 1.9 2005/02/20 00:43:23 ponchio
Less memory x extraction. (removed frags)
Revision 1.8 2005/02/19 16:22:45 ponchio
Minor changes (visited and Cell)
Revision 1.7 2005/02/10 09:18:20 ponchio
Statistics.
Revision 1.6 2005/02/08 12:43:03 ponchio
Added copyright
****************************************************************************/
#include "extraction.h"
#include "metric.h"
#include "nexus.h"
#include <algorithm>
using namespace std;
using namespace nxs;
/* Updateing strategy:
if i can refine (not at leaves,
have draw and extr buffer,
not past target_error)
i try to refine BUT
i can fail because i finish some buffer
(then i put the operation back on the stack)
if i have finished disk i should just quit
if i cannot refine i consider coarsening:
i need 1) not be at root (eheh)
2) have finished draw and extr buffer
(unless i am at error < target so i want to coarse
3) do not make global error worse
(unless it is error < target_error...)
a stability term is added (1.1) so that we do not flip
nodes in and out quickly
i try to coarse BUT
i can fail because i need disk
(then i put the operation back on the stack)
if i cannt coarse i just quit
*/
Extraction::Extraction(): target_error(4.0f), extr_max(10000),
draw_max(10000), disk_max(100) {
metric = new FrustumMetric;
}
Extraction::~Extraction() {
if(metric) delete metric;
}
void Extraction::SetMetric(Metric *m) {
if(metric)
delete metric;
metric = m;
}
void Extraction::Extract(Nexus *_mt) {
mt = _mt;
root = mt->history.Root();
sink = root + (mt->history.n_nodes()-1);
//clear statistics
extr_used = draw_used = disk_used = 0;
//first we clear the visited flags
visited.clear();
visited.resize(mt->history.n_nodes(), false);
visible.clear();
visible.resize(mt->size(), true);
node_errors.clear();
node_errors.resize(mt->history.n_nodes(), -1);
front.clear();
Visit(root);
while(front.size()) {
pop_heap(front.begin(), front.end());
HeapNode hnode = front.back();
front.pop_back();
Node *node = hnode.node;
if(Visited(node)) continue;
if(Expand(hnode))
Visit(node);
}
Select();
draw_size = selected.size();
}
void Extraction::Init() {
//I want to add all coarsable nodes
//and all refinable node (being careful about recursive dependencies)
for(Node *node = root; node != sink; node++) {
if(!Visited(node)) continue;
if(node != root && CanCoarse(node))
back.push_back(HeapNode(node, GetNodeError(node)));
for(Node::iterator n = node->out_begin; n != node->out_end; n++) {
Node *child = n->node;
if(Visited(child)) continue;
if(node_errors[child - root] != -1) continue; //already visited
float *error = GetNodeError(child);
if(CanRefine(node)) // TODO? && error > target_error
front.push_back(HeapNode(child, error));
if(*error > max_error) max_error = *error;
}
}
//recursively fix error
for(Node *node = root; node != sink; node++)
if(node_errors[node - root] != -1)
SetError(node, node_errors[node-root]);
//estimate cost of all the cut arcs (i need the visible info)
Cost cost;
for(Node *node = root; node != sink; node++) {
if(!Visited(node)) continue;
for(Node::iterator n = node->out_begin; n != node->out_end; n++) {
Link &link = *n;
if(Visited((*n).node)) continue;
for(unsigned int patch = link.begin; patch != link.end; patch++) {
Entry &entry = (*mt)[patch];
cost.extr += entry.ram_size;
if(Visible(patch)) cost.draw += entry.ram_size;
if(!entry.patch) cost.disk += entry.disk_size;
}
}
}
make_heap(front.begin(), front.end());
make_heap(back.begin(), back.end(), greater<HeapNode>());
extr_used = cost.extr;
draw_used = cost.draw;
disk_used = cost.disk;
}
void Extraction::Update(Nexus *_mt) {
mt = _mt;
root = mt->history.Root();
sink = mt->history.Sink();
if(!visited.size()) {
visited.resize(mt->history.n_nodes(), false);
SetVisited(root, true);
}
visible.clear();
visible.resize(mt->size(), true);
node_errors.clear();
node_errors.resize(mt->history.n_nodes(), -1);
front.clear();
back.clear();
max_error = -1;
Init();
bool can_refine = true;
while(1) {
while(can_refine) { //we have available budget
if(!front.size()) break; //we are at max level
if(*front[0].error < target_error) break; //already at target_error
max_error = *front[0].error;
pop_heap(front.begin(), front.end());
HeapNode hnode = front.back();
front.pop_back();
if(!Visited(hnode.node) && CanRefine(hnode.node)) {
if(!Refine(hnode)) {
can_refine = false;
front.push_back(hnode);
push_heap(front.begin(), front.end());
}
}
}
if(!back.size()) //nothing to coarse (happen only on extr_max < root.extr)
break;
if(*back.front().error >= target_error &&
(!front.size() ||
(*back.front().error * 1.4) >= *front.front().error))
break;
pop_heap(back.begin(), back.end(), greater<HeapNode>());
HeapNode hnode = back.back();
back.pop_back();
if(Visited(hnode.node) && //not already coarsed
CanCoarse(hnode.node) && //all children !visited
!Coarse(hnode)) { //no more disk
back.push_back(hnode);
push_heap(back.begin(), back.end(), greater<HeapNode>());
break;
}
can_refine = true;
}
Select();
draw_size = selected.size();
//Preloading now
for(unsigned int i = 0; i < 1000; i++) {
if(!front.size() && !back.size()) break;
if((i%2) && front.size()) {
pop_heap(front.begin(), front.end());
HeapNode hnode = front.back();
Node *node = hnode.node;
front.pop_back();
Node::iterator l;
for(l = node->out_begin; l != node->out_end; l++) {
Link &link = (*l);
for(unsigned int k = link.begin; k != link.end; k++) {
selected.push_back(Item(k, i));
}
}
} else if(back.size()) {
pop_heap(back.begin(), back.end(), greater<HeapNode>());
HeapNode hnode = back.back();
Node *node = hnode.node;
back.pop_back();
for(Node::iterator l = node->in_begin; l != node->in_end; l++) {
Link &link = (*l);
for(unsigned int k = link.begin; k != link.end; k++) {
selected.push_back(Item(k, i));
}
}
}
}
}
float *Extraction::GetNodeError(Node *node) {
float &maxerror = node_errors[node-root];
for(Node::iterator i = node->in_begin; i != node->in_end; i++) {
Link &link = *i;
for(unsigned int p = link.begin; p != link.end; p++) {
Entry &entry = (*mt)[p];
bool visible;
float error = metric->GetError(entry, visible);
// cerr << "Error for patch: " << p << " -> " << error << endl;
if(error > maxerror) maxerror = error;
SetVisible(p, visible);
}
}
return &maxerror;
}
bool Extraction::Refine(HeapNode hnode) {
Node *node = hnode.node;
Cost cost;
Diff(node, cost);
if(disk_used + cost.disk > disk_max ||
extr_used + cost.extr > extr_max ||
draw_used + cost.draw > draw_max)
return false;
extr_used += cost.extr;
draw_used += cost.draw;
disk_used += cost.disk;
SetVisited(node, true);
//now add to the front children (unless sink node)
for(Node::iterator i = node->out_begin; i != node->out_end; i++) {
Link &link = *i;
if(link.node == sink) continue;
float *error = &node_errors[link.node - root];
if(*error == -1)
error = GetNodeError(link.node);
if(*hnode.error < *error) *hnode.error = *error;
//TODO if(maxerror > target_error)
if(CanRefine((*i).node)) {
front.push_back(HeapNode((*i).node, error));
push_heap(front.begin(), front.end());
}
}
back.push_back(hnode);
push_heap(back.begin(), back.end(), greater<HeapNode>());
return true;
}
bool Extraction::Coarse(HeapNode hnode) {
Node *node = hnode.node;
Cost cost;
Diff(node, cost);
extr_used -= cost.extr;
draw_used -= cost.draw;
disk_used -= cost.disk;
if(disk_used > disk_max) return false;
SetVisited(node, false);
//now add to the back parents (unless root node)
for(Node::iterator i = node->in_begin; i != node->in_end; i++) {
Link &link = *i;
if(link.node == root) continue;
float *error = &node_errors[link.node - root];
if(*error == -1)
error = GetNodeError(link.node);
if(*error < *hnode.error) *error = *hnode.error;
if(CanCoarse(link.node)) {
back.push_back(HeapNode(link.node, error));
push_heap(back.begin(), back.end(), greater<HeapNode>());
}
}
front.push_back(hnode);
push_heap(front.begin(), front.end());
return true;
}
void Extraction::Select() {
selected.clear();
Node *root = mt->history.Root();
Node *nodes = mt->history.nodes;
for(unsigned int i = 0; i < visited.size(); i++) {
if(!visited[i]) continue;
Node &node = nodes[i];
Node::iterator n;
for(n = node.out_begin; n != node.out_end; n++) {
unsigned int n_out = (*n).node - root;
if(!visited[n_out]) {
Link &link = *n;
for(unsigned int p = link.begin; p != link.end; p++) {
selected.push_back(Item(p, 0));
}
}
}
}
}
void Extraction::Visit(Node *node) {
assert(!Visited(node));
SetVisited(node, true);
for(Node::iterator i = node->in_begin; i != node->in_end; i++) {
if(Visited((*i).node)) continue;
Visit((*i).node);
}
Cost cost;
Diff(node, cost);
extr_used += cost.extr;
draw_used += cost.draw;
disk_used += cost.disk;
for(Node::iterator i = node->out_begin; i != node->out_end; i++) {
float maxerror = -1;
Link &link = *i;
for(unsigned int p = link.begin; p != link.end; p++) {
Entry &entry = (*mt)[p];
bool visible;
float error = metric->GetError(entry, visible);
if(error > maxerror) maxerror = error;
SetVisible(p, visible);
}
//TODO this check may be dangerous for non saturating things...
if(maxerror > target_error) {
node_errors[(*i).node - root] = maxerror;
HeapNode hnode((*i).node, &node_errors[(*i).node - root]);
front.push_back(hnode);
push_heap(front.begin(), front.end());
}
}
}
bool Extraction::Expand(HeapNode &node) {
if(extr_used >= extr_max) return false;
if(draw_used >= draw_max) return false;
// if(disk_used >= disk_max) return false;
return *node.error > target_error;
}
void Extraction::Diff(Node *node, Cost &cost) {
Node::iterator i;
for(i = node->in_begin; i != node->in_end; i++) {
Link &link = *i;
for(unsigned int p = link.begin; p != link.end; p++) {
Entry &entry = (*mt)[p];
cost.extr -= entry.ram_size;
if(Visible(p)) cost.draw -= entry.ram_size;
if(!entry.patch) cost.disk -= entry.disk_size;
}
}
for(i = node->out_begin; i != node->out_end; i++) {
Link &link = *i;
for(unsigned int p = link.begin; p != link.end; p++) {
Entry &entry = (*mt)[p];
cost.extr += entry.ram_size;
if(Visible(p)) cost.draw += entry.ram_size;
if(!entry.patch) cost.disk += entry.disk_size;
}
}
}
void Extraction::SetError(Node *node, float error) {
for(Node::iterator i = node->in_begin; i != node->in_end; i++)
if(node_errors[(*i).node - root] != -1 &&
node_errors[(*i).node - root] < error) {
node_errors[(*i).node - root] = error;
SetError((*i).node, error);
}
}
bool Extraction::CanRefine(Node *node) {
for(Node::iterator i = node->in_begin; i != node->in_end; i++)
if(!Visited((*i).node))
return false;
return true;
}
bool Extraction::CanCoarse(Node *node) {
for(Node::iterator i = node->out_begin; i != node->out_end; i++)
if(Visited((*i).node))
return false;
return true;
}

View File

@ -1,155 +0,0 @@
/****************************************************************************
* VCGLib o o *
* Visual and Computer Graphics Library o o *
* _ O _ *
* Copyright(C) 2004 \/)\/ *
* Visual Computing Lab /\/| *
* ISTI - Italian National Research Council | *
* \ *
* All rights reserved. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
* for more details. *
* *
****************************************************************************/
/****************************************************************************
History
$Log: not supported by cvs2svn $
Revision 1.10 2005/03/02 10:40:17 ponchio
Extraction rewrittten (to fix recusive problems).
Revision 1.9 2005/02/20 18:07:01 ponchio
cleaning.
Revision 1.8 2005/02/19 16:22:45 ponchio
Minor changes (visited and Cell)
Revision 1.7 2005/02/10 09:18:20 ponchio
Statistics.
Revision 1.6 2005/02/08 12:43:03 ponchio
Added copyright
****************************************************************************/
#ifndef NXS_EXTRACTION_H
#define NXS_EXTRACTION_H
#include <set>
#include <vector>
#include <wrap/gui/frustum.h>
#include "history.h"
namespace nxs {
class Metric;
class Nexus;
struct Item {
float error;
unsigned int id;
Item(unsigned int i = 0, float e = 0): id(i), error(e) {}
bool operator<(const Item &item) const {
return error < item.error;
}
};
class Extraction {
public:
typedef History::Node Node;
typedef History::Link Link;
struct Cost {
unsigned int extr;
unsigned int draw;
unsigned int disk;
Cost(): extr(0), draw(0), disk(0) {}
};
struct HeapNode {
Node *node;
float *error;
HeapNode(Node *_node, float *_error): node(_node), error(_error) {}
bool operator<(const HeapNode &node) const {
return *error < *node.error; }
bool operator>(const HeapNode &node) const {
return *error > *node.error; }
};
Metric *metric;
float target_error;
float max_error; //actual error at end of extraction
unsigned int extr_used, extr_max;
unsigned int draw_used, draw_max;
unsigned int disk_used, disk_max;
std::vector<bool> visited;
std::vector<bool> visible;
std::vector<float> node_errors;
std::vector<Item> selected;
unsigned int draw_size; //first in selected should be drawn
// std::vector<HeapNode> heap; //no realtime extraxtion TODO (use front)
std::vector<HeapNode> front; //nodes that i can expand to
std::vector<HeapNode> back; //nodes that i can contract
Extraction();
~Extraction();
void Extract(Nexus *mt);
void Update(Nexus *mt);
bool Visible(unsigned int p) { return visible[p]; }
void SetVisible(unsigned int p, bool v) { visible[p] = v; }
void SetMetric(Metric *m);
protected:
void Select();
void Visit(Node *node);
bool Expand(HeapNode &node);
void Diff(Node *node, Cost &cost);
void Init();
bool Refine(HeapNode node);
bool Coarse(HeapNode node);
bool Visited(Node *node) { return visited[node - root]; }
void SetVisited(Node *node, bool v) { visited[node - root] = v; }
private:
Nexus *mt;
Node *root;
Node *sink;
//return inbound links max error. remember to update patch visibility
float *GetNodeError(Node *node);
//this look for parent nodes with error and fix it should be <
void SetError(Node *node, float error);
bool CanCoarse(Node *node);
bool CanRefine(Node *node);
};
}//namespace
#endif

View File

@ -1,130 +0,0 @@
#include "file.h"
#include <assert.h>
using namespace std;
using namespace nxs;
bool File::Create(const string &filename) {
size = 0;
readonly = false;
#ifdef WIN32
fp = CreateFile(filename.c_str(), GENERIC_READ | GENERIC_WRITE, 0,
NULL, CREATE_ALWAYS, 0, NULL);
if(fp == INVALID_HANDLE_VALUE) return false;
#else
fp = fopen(filename.c_str(), "wb+");
if(!fp) return false;
#endif
return true;
}
bool File::Load(const string &filename, bool ronly) {
readonly = ronly;
#ifdef WIN32
fp = CreateFile(filename.c_str(), GENERIC_READ | GENERIC_WRITE,
0, NULL, OPEN_EXISTING, 0, NULL);
if(fp == INVALID_HANDLE_VALUE) return false;
#else
if(readonly)
fp = fopen(filename.c_str(), "rb");
else
fp = fopen(filename.c_str(), "rb+");
if(!fp) return false;
#endif
#ifdef WIN32
size = GetFileSize(fp, NULL);
#else
//TODO use stat()
fseek(fp, 0, SEEK_END);
size = ftell(fp);
#endif
return true;
}
void File::Close() {
if(fp) {
#ifdef WIN32
CloseHandle(fp);
#else
fclose(fp);
#endif
fp = NULL;
}
}
void File::Redim(unsigned int elem) {
assert(fp);
assert(!readonly);
if(elem > size) {
#ifdef WIN32
LONG zero = 0;
if(INVALID_SET_FILE_POINTER ==
SetFilePointer(fp, elem - 1, &zero, FILE_BEGIN))
#else
if(-1 == fseek(fp, elem - 1, SEEK_SET))
#endif
assert(0 && "Could not resize");
unsigned char a;
#ifdef WIN32
DWORD tmp;
WriteFile(fp, &a, 1, &tmp, NULL);
#else
fwrite(&a, sizeof(unsigned char), 1, fp);
#endif
} else {
//TODO optimize: we do not need flush for buffers over elem.
#ifndef WIN32
int fd = fileno(fp);
ftruncate(fd, elem);
#else
LONG zero = 0;
SetFilePointer(fp, elem, &zero, FILE_BEGIN);
SetEndOfFile(fp);
#endif
}
size = elem;
}
void File::SetPosition(unsigned int pos) {
#ifdef WIN32
LONG zero = 0;
SetFilePointer(fp, pos, &zero, FILE_BEGIN);
#else
fseek(fp, pos, SEEK_SET);
#endif
}
void File::ReadBuffer(void *data, unsigned int sz) {
#ifdef WIN32
DWORD tmp;
ReadFile(fp, data, sz, &tmp, NULL);
if(tmp != sz)
assert(0 && "Could not read");
#else
if(sz != fread(data, 1, sz, fp))
assert(0 && "Could not read");
#endif
}
void File::WriteBuffer(void *data, unsigned int sz) {
assert(!readonly);
#ifdef WIN32
DWORD tmp;
WriteFile(fp, data, sz, &tmp, NULL);
assert(tmp == sz);
#else
if(sz != fwrite(data, 1, sz, fp))
assert(0 && "Could not write");
#endif
}
void File::Delete(const string &filename) {
#ifdef WIN32
DeleteFile(filename.c_str());
#else
unlink(filename.c_str());
#endif
}

View File

@ -1,58 +0,0 @@
#ifndef NXS_FILE_H
#define NXS_FILE_H
//TODO move includes in cpp
#ifdef WIN32
#ifndef _WINDOWS_
#define _WINSOCKAPI_
#include <windows.h>
#endif
#else
#include <unistd.h>
#endif
#include <stdio.h>
#include <string>
namespace nxs {
class File {
public:
File(): fp(NULL) {}
~File() { Close(); }
File(const File &file) {
fp = file.fp;
size = file.size;
readonly = file.readonly;
((File &)file).fp = NULL;
}
bool Create(const std::string &filename);
bool Load(const std::string &filename, bool readonly = false);
void Close();
unsigned int Length() { return size; }
void Redim(unsigned int elem);
void SetPosition(unsigned int chunk);
void ReadBuffer(void *data, unsigned int size);
void WriteBuffer(void *data, unsigned int size);
bool IsReadOnly() { return readonly; }
static void Delete(const std::string &filename);
#ifdef WIN32
HANDLE fp;
#else
FILE *fp;
#endif
unsigned int size;
bool readonly;
};
}
#endif

View File

@ -1,431 +0,0 @@
/****************************************************************************
* VCGLib o o *
* Visual and Computer Graphics Library o o *
* _ O _ *
* Copyright(C) 2004 \/)\/ *
* Visual Computing Lab /\/| *
* ISTI - Italian National Research Council | *
* \ *
* All rights reserved. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
* for more details. *
* *
****************************************************************************/
/****************************************************************************
History
$Log: not supported by cvs2svn $
Revision 1.9 2005/02/08 12:43:03 ponchio
Added copyright
****************************************************************************/
#include <set>
#include <iostream>
#include "fragment.h"
#include "border.h"
#include "nxsalgo.h"
//#include "pvoronoi.h"
using namespace std;
using namespace vcg;
using namespace nxs;
using namespace pt;
void NxsPatch::Write(outstm *out) {
out->write(&sphere, sizeof(Sphere3f));
out->write(&cone, sizeof(ANCone3f));
int vsize = vert.size();
int fsize = face.size();
int bsize = bord.size();
out->write(&patch, sizeof(unsigned int));
out->write(&vsize, sizeof(unsigned int));
out->write(&fsize, sizeof(unsigned int));
out->write(&bsize, sizeof(unsigned int));
out->write(&*vert.begin(), vert.size() * sizeof(Point3f));
out->write(&*face.begin(), face.size() * sizeof(unsigned short));
out->write(&*bord.begin(), bord.size() * sizeof(Link));
}
void NxsPatch::Read(instm *in) {
in->read(&sphere, sizeof(Sphere3f));
in->read(&cone, sizeof(ANCone3f));
int vsize;
int fsize;
int bsize;
in->read(&patch, sizeof(unsigned int));
in->read(&vsize, sizeof(unsigned int));
in->read(&fsize, sizeof(unsigned int));
in->read(&bsize, sizeof(unsigned int));
vert.resize(vsize);
face.resize(fsize);
bord.resize(bsize);
in->read(&*vert.begin(), vert.size() * sizeof(Point3f));
in->read(&*face.begin(), face.size() * sizeof(unsigned short));
in->read(&*bord.begin(), bord.size() * sizeof(Link));
}
bool Fragment::Write(outstm *out) {
try {
out->write(&id, sizeof(unsigned int));
out->write(&error, sizeof(float));
unsigned int ssize = seeds.size();
out->write(&ssize, sizeof(unsigned int));
out->write(&*seeds.begin(), ssize * sizeof(Point3f));
out->write(&*seeds_id.begin(), ssize * sizeof(unsigned int));
unsigned int psize = pieces.size();
out->write(&psize, sizeof(unsigned int));
for(unsigned int i = 0; i < pieces.size(); i++)
pieces[i].Write(out);
return true;
} catch (estream *e) {
perr.putf("Error: %s\n", pconst(e->get_message()));
delete e;
return false;
}
}
bool Fragment::Read(instm *in) {
try {
in->read(&id, sizeof(unsigned int));
in->read(&error, sizeof(float));
//TODO move this control to all read!
unsigned int ssize;
if(sizeof(int) != in->read(&ssize, sizeof(unsigned int)))
return false;
seeds.resize(ssize);
seeds_id.resize(ssize);
in->read(&*seeds.begin(), ssize * sizeof(Point3f));
in->read(&*seeds_id.begin(), ssize * sizeof(unsigned int));
unsigned int psize;
in->read(&psize, sizeof(unsigned int));
pieces.resize(psize);
for(unsigned int i = 0; i < psize; i++) {
pieces[i].Read(in);
}
return true;
} catch (estream *e) {
perr.putf("Error: %s\n", pconst(e->get_message()));
delete e;
return false;
}
}
void nxs::Join(Fragment &in,
vector<Point3f> &newvert,
vector<unsigned int> &newface,
vector<BigLink> &newbord) {
map<unsigned int, unsigned int> patch_remap;
vector<unsigned int> offsets;
unsigned int totvert = 0;
for(unsigned int i = 0; i < in.pieces.size(); i++) {
offsets.push_back(totvert);
patch_remap[in.pieces[i].patch] = i;
totvert += in.pieces[i].vert.size();
}
vector<unsigned int> remap;
remap.resize(totvert, 0xffffffff);
//TODO what if totvert > 1<<22?
//todo we really need a set?
// set<Link> newborders;
unsigned int vcount = 0;
unsigned int fcount = 0;
unsigned int bcount = 0;
for(unsigned int i = 0; i < in.pieces.size(); i++) {
unsigned int offset = offsets[i];
vector<Point3f> &vert = in.pieces[i].vert;
vector<unsigned short> &face = in.pieces[i].face;
vector<Link> &bord = in.pieces[i].bord;
for(unsigned int k = 0; k < face.size(); k+=3) {
assert(face[k] != face[k+1]);
assert(face[k] != face[k+2]);
assert(face[k+1] != face[k+2]);
}
fcount += face.size()/3;
for(unsigned int k = 0; k < vert.size(); k++) {
assert(offset + k < remap.size());
if(remap[offset + k] == 0xffffffff)
remap[offset + k] = vcount++;
}
for(unsigned int k = 0; k < bord.size(); k++) {
Link link = bord[k];
if(link.IsNull()) continue;
if(patch_remap.count(link.end_patch)) {//internal
unsigned int idx = patch_remap[link.end_patch];
assert(link.end_patch != in.pieces[i].patch);
unsigned int extoffset = offsets[idx];
assert(extoffset + link.end_vert < remap.size());
if(remap[extoffset + link.end_vert] == 0xffffffff) //first time
remap[extoffset + link.end_vert] = remap[offset + link.start_vert];
}
}
}
assert(vcount < (1<<16));
set<BigLink> newborders;
for(unsigned int i = 0; i < in.pieces.size(); i++) {
unsigned int offset = offsets[i];
vector<Link> &bord = in.pieces[i].bord;
for(unsigned int k = 0; k < bord.size(); k++) {
Link llink = bord[k];
if(llink.IsNull()) continue;
if(!patch_remap.count(llink.end_patch)) {//external
BigLink link;
link.start_vert = remap[offset + llink.start_vert];
link.end_patch = in.pieces[i].patch;
link.end_vert = llink.start_vert;
newborders.insert(link);
}
}
}
newvert.resize(vcount);
newface.resize(fcount*3);
newbord.resize(newborders.size());
fcount = 0;
for(unsigned int i = 0; i < in.pieces.size(); i++) {
unsigned int offset = offsets[i];
vector<Point3f> &vert = in.pieces[i].vert;
vector<unsigned short> &face = in.pieces[i].face;
vector<Link> &bord = in.pieces[i].bord;
for(unsigned int i = 0; i < vert.size(); i++) {
assert(offset + i < remap.size());
assert(remap[offset + i] < vcount);
newvert[remap[offset + i]] = vert[i];
}
for(unsigned int i = 0; i < face.size(); i++) {
assert(offset + face[i] < remap.size());
assert(remap[offset + face[i]] < newvert.size());
assert(fcount < newface.size());
newface[fcount++] = remap[offset + face[i]];
}
}
set<BigLink>::iterator b;
for(b = newborders.begin(); b != newborders.end(); b++) {
newbord[bcount++] = *b;
}
for(unsigned int i = 0; i < newface.size(); i+= 3) {
if(newface[i] == newface[i+1] ||
newface[i] == newface[i+2] ||
newface[i+1] == newface[i+2]) {
cerr << "i: " << i << endl;
for(unsigned int k = 0; k < newface.size(); k+=3) {
cerr << k << ": " << newface[k] << " "
<< newface[k+1] << " "
<< newface[k+2] << endl;
}
exit(0);
}
}
}
void nxs::Split(Fragment &out,
vector<Point3f> &newvert,
vector<unsigned int> &newface,
vector<BigLink> &newbord) {
unsigned int nseeds = out.seeds.size();
vector<Point3f> &seeds = out.seeds;
vector<unsigned int> &seeds_id = out.seeds_id;
//preliminary count
vector<unsigned int> count;
count.resize(nseeds, 0);
for(unsigned int f = 0; f < newface.size(); f += 3) {
Point3f bari = (newvert[newface[f]] +
newvert[newface[f+1]] +
newvert[newface[f+2]])/3;
unsigned int seed = out.Locate(bari);
assert(seed < nseeds);
count[seed]++;
}
//pruning small patches
float min_size = (newface.size()/3) / 20.0f;
vector<Point3f> newseeds;
vector<unsigned int> newseeds_id;
for(unsigned int seed = 0; seed < nseeds; seed++) {
if(count[seed] > min_size) {
newseeds.push_back(seeds[seed]);
newseeds_id.push_back(seeds_id[seed]);
}
if(count[seed] > (1<<16)) {
cerr << "Ooops a cell came too big... quitting\n";
exit(0);
}
}
seeds = newseeds;
seeds_id = newseeds_id;
nseeds = seeds.size();
//if != -1 remap global index to cell index (first arg)
vector< vector<int> > vert_remap;
vector< vector<int> > face_remap;
vector<int> vert_count;
vector<int> face_count;
vert_remap.resize(nseeds);
face_remap.resize(nseeds);
vert_count.resize(nseeds, 0);
face_count.resize(nseeds, 0);
for(unsigned int seed = 0; seed < nseeds; seed++)
vert_remap[seed].resize(newvert.size(), -1);
for(unsigned int f = 0; f < newface.size(); f += 3) {
Point3f bari = (newvert[newface[f]] +
newvert[newface[f+1]] +
newvert[newface[f+2]])/3;
unsigned int seed = out.Locate(bari);
vector<int> &f_remap = face_remap[seed];
f_remap.push_back(newface[f]);
f_remap.push_back(newface[f+1]);
f_remap.push_back(newface[f+2]);
face_count[seed]++;
vector<int> &v_remap = vert_remap[seed];
for(int i = 0; i < 3; i++)
if(v_remap[newface[f+i]] == -1)
v_remap[newface[f+i]] = vert_count[seed]++;
}
//TODO assure no big ones.
out.pieces.resize(nseeds);
for(unsigned int seed = 0; seed != nseeds; seed++) {
NxsPatch &patch = out.pieces[seed];
patch.patch = seeds_id[seed];
//vertices first
vector<int> &v_remap = vert_remap[seed];
assert(vert_count[seed] > 0);
vector<Point3f> &verts = patch.vert;
verts.resize(vert_count[seed]);
for(unsigned int i = 0; i < newvert.size(); i++) {
if(v_remap[i] != -1)
verts[v_remap[i]] = newvert[i];
}
//faces now
vector<int> &f_remap = face_remap[seed];
vector<unsigned short> &faces = patch.face;
faces.resize(face_count[seed]*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]];
}
//borders last
vector<Link> &bords = patch.bord;
//process downward borders
for(unsigned int i = 0; i < newbord.size(); i++) {
BigLink link = newbord[i];
/* cerr << "Newbord: " << link.start_vert << " "
<< link.end_patch << " "
<< link.end_vert << endl;*/
if(v_remap[link.start_vert] == -1) continue;
Link llink;
llink.start_vert = v_remap[link.start_vert];
llink.end_patch = link.end_patch;
llink.end_vert = link.end_vert;
bords.push_back(llink);
}
//process internal borders;
//TODO higly inefficient!!!
for(unsigned int rseed = 0; rseed < nseeds; rseed++) {
if(seed == rseed) continue;
vector<int> &vremapclose = vert_remap[rseed];
for(unsigned int i = 0; i < newvert.size(); i++) {
if(v_remap[i] != -1 && vremapclose[i] != -1) {
Link link;
link.end_patch = rseed + (1<<31);
link.start_vert = v_remap[i];
link.end_vert = vremapclose[i];
bords.push_back(link);
}
}
}
}
//process Cone and sphere
for(unsigned int seed = 0; seed != nseeds; seed++) {
NxsPatch &patch = out.pieces[seed];
Sphere3f &sphere = patch.sphere;
sphere.CreateTight(patch.vert.size(), &*patch.vert.begin());
//NORMALS CONE
vector<Point3f> normals;
for(unsigned int i = 0; i < patch.face.size(); i += 3) {
unsigned short *f = &(patch.face[i]);
Point3f &v0 = patch.vert[f[0]];
Point3f &v1 = patch.vert[f[1]];
Point3f &v2 = patch.vert[f[2]];
Point3f norm = (v1 - v0) ^ (v2 - v0);
normals.push_back(norm.Normalize());
}
patch.cone.AddNormals(normals, 0.99f);
}
}
unsigned int Fragment::Locate(const Point3f &p) {
float max_dist = 1e20f;
unsigned int id = 0xffffffff;
for(unsigned int i = 0; i < seeds.size(); i++) {
float dist = Distance(seeds[i], p);
if(dist < max_dist) {
max_dist = dist;
id = i;
}
}
assert(id != 0xffffffff);
return id;
}

View File

@ -1,106 +0,0 @@
/****************************************************************************
* VCGLib o o *
* Visual and Computer Graphics Library o o *
* _ O _ *
* Copyright(C) 2004 \/)\/ *
* Visual Computing Lab /\/| *
* ISTI - Italian National Research Council | *
* \ *
* All rights reserved. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
* for more details. *
* *
****************************************************************************/
/****************************************************************************
History
$Log: not supported by cvs2svn $
Revision 1.6 2005/02/08 12:43:03 ponchio
Added copyright
****************************************************************************/
#ifndef NXS_FRAGMENT_H
#define NXS_FRAGMENT_H
#include <vector>
#include <ptypes/pstreams.h>
#include "nexus.h"
namespace nxs {
class VoronoiPartition;
struct BigLink {
unsigned int start_vert;
unsigned int end_patch;
unsigned int end_vert;
bool operator<(const BigLink &l) const {
if(end_patch == l.end_patch) {
if(start_vert == l.start_vert) {
return end_vert < l.end_vert;
} else
return start_vert < l.start_vert;
} else
return end_patch < l.end_patch;
}
};
class NxsPatch {
public:
//this fields is the patch number in the infragment
//and the seeds id in the outfragment
unsigned int patch;
vcg::Sphere3f sphere;
ANCone3f cone;
std::vector<vcg::Point3f> vert;
std::vector<unsigned short> face;
std::vector<Link> bord;
void Write(pt::outstm *out);
void Read(pt::instm *in);
};
class Fragment {
public:
unsigned int id;
float error;
std::vector<vcg::Point3f> seeds;
std::vector<unsigned int> seeds_id;
std::vector<NxsPatch> pieces;
bool Write(pt::outstm *out);
bool Read(pt::instm *in);
//returns the index of the seed
unsigned int Locate(const vcg::Point3f &p);
};
void Join(Fragment &in,
std::vector<vcg::Point3f> &newvert,
std::vector<unsigned int> &newface,
std::vector<BigLink> &newbord);
void Split(Fragment &out,
std::vector<vcg::Point3f> &newvert,
std::vector<unsigned int> &newface,
std::vector<BigLink> &newbord);
}
#endif

View File

@ -1,400 +0,0 @@
/****************************************************************************
* VCGLib o o *
* Visual and Computer Graphics Library o o *
* _ O _ *
* Copyright(C) 2004 \/)\/ *
* Visual Computing Lab /\/| *
* ISTI - Italian National Research Council | *
* \ *
* All rights reserved. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
* for more details. *
* *
****************************************************************************/
/****************************************************************************
History
$Log: not supported by cvs2svn $
Revision 1.9 2005/02/20 00:43:23 ponchio
Less memory x extraction. (removed frags)
Revision 1.8 2005/02/19 17:14:02 ponchio
History quick by default.
Revision 1.7 2005/02/19 16:22:45 ponchio
Minor changes (visited and Cell)
Revision 1.6 2005/02/17 16:40:35 ponchio
Optimized BuildLevels.
Revision 1.5 2005/02/08 12:43:03 ponchio
Added copyright
****************************************************************************/
#include <assert.h>
#include <map>
#include <iostream>
#include "history.h"
#include "nexus.h"
using namespace std;
using namespace nxs;
History::~History() {
if(buffer) delete []buffer;
nodes = NULL;
in_links= NULL;
out_links = NULL;
}
void History::Clear() {
if(buffer) delete []buffer;
buffer = NULL;
updates.clear();
}
void History::ClearQuick() {
if(buffer) delete []buffer;
buffer = NULL;
}
void History::ClearUpdates() {
updates.clear();
}
bool History::Load(unsigned int _size, char *mem) {
if(buffer) delete []buffer;
unsigned int is_quick = *(unsigned int *)mem;
bool success;
if(is_quick == 53) {
success = LoadQuick(_size, mem);
} else if(is_quick == 32) {
success = LoadUpdates(_size, mem);
} else {
cerr << "Invalid history: " << is_quick << "\n";
return false;
}
return success;
}
bool History::LoadQuick(unsigned int _size, char *mem) {
buffer = mem;
nodes = (Node *)(buffer + 4 * sizeof(int));
in_links = (Link *)(nodes + n_nodes());
out_links = in_links + n_in_links();
//check size is ok;
assert(n_nodes() * sizeof(Node) +
(n_in_links() + n_out_links()) * sizeof(Link) +
4 * sizeof(int) == _size);
size = _size;
return LoadPointers();
}
bool History::LoadUpdates(unsigned int _size, char *mem) {
unsigned int *tmp = (unsigned int *)mem;
updates.resize(tmp[1]);
unsigned int pos = 2;
for(unsigned int i = 0; i < updates.size(); i++) {
unsigned int erased = tmp[pos++];
unsigned int created = tmp[pos++];
updates[i].erased.resize(erased);
updates[i].created.resize(created);
for(unsigned int e = 0; e < erased; e++)
updates[i].erased[e] = tmp[pos++];
for(unsigned int e = 0; e < created; e++)
updates[i].created[e] = tmp[pos++];
}
delete []mem;
buffer = 0;
return true;
}
bool History::LoadPointers() {
//now convert integer to pointers
for(unsigned int i = 0; i < n_nodes(); i++) {
Node &node = nodes[i];
assert(((unsigned int)node.in_begin) <= n_in_links());
assert(((unsigned int)node.out_begin) <= n_out_links());
node.in_begin = in_links + (unsigned int)(node.in_begin);
node.in_end = in_links + (unsigned int)(node.in_end);
node.out_begin = out_links + (unsigned int)(node.out_begin);
node.out_end = out_links + (unsigned int)(node.out_end);
}
for(unsigned int i = 0; i < n_in_links(); i++) {
Link &link = in_links[i];
assert(((unsigned int)link.node) <= n_nodes());
link.node = nodes + (unsigned int)(link.node);
}
for(unsigned int i = 0; i < n_out_links(); i++) {
Link &link = out_links[i];
assert(((unsigned int)link.node) <= n_nodes());
link.node = nodes + (unsigned int)(link.node);
}
return true;
}
char *History::Save(unsigned int &_size) {
if(buffer)
return SaveQuick(_size);
else
return SaveUpdates(_size);
}
char *History::SaveQuick(unsigned int &_size) {
assert(buffer);
for(unsigned int i = 0; i < n_nodes(); i++) {
Node &node = nodes[i];
node.in_begin = (Link *)(node.in_begin - in_links);
node.in_end = (Link *)(node.in_end - in_links);
node.out_begin = (Link *)(node.out_begin - out_links);
node.out_end = (Link *)(node.out_end - out_links);
}
for(unsigned int i = 0; i < n_in_links(); i++) {
Link &link = in_links[i];
link.node = (Node *)(link.node - nodes);
}
for(unsigned int i = 0; i < n_out_links(); i++) {
Link &link = out_links[i];
link.node = (Node *)(link.node - nodes);
}
assert(n_nodes() * sizeof(Node) +
(n_in_links() + n_out_links()) * sizeof(Link) +
4 * sizeof(int) == size);
_size = size;
char *tmp = buffer;
buffer = NULL;
return tmp;
}
char *History::SaveUpdates(unsigned int &_size) {
vector<unsigned int> buf;
buf.push_back(32);
buf.push_back(updates.size());
for(unsigned int i = 0; i < updates.size(); i++) {
Update &update = updates[i];
buf.push_back(update.erased.size());
buf.push_back(update.created.size());
for(unsigned int e = 0; e < update.erased.size(); e++)
buf.push_back(update.erased[e]);
for(unsigned int e = 0; e < update.created.size(); e++)
buf.push_back(update.created[e]);
}
_size = buf.size() * sizeof(unsigned int);
char *mem = new char[_size];
memcpy(mem, &*buf.begin(), _size);
return mem;
}
bool History::UpdatesToQuick(Nexus &nexus) {
//maps cell -> node containing it
map<unsigned int, unsigned int> cell_node;
//maps node -> Links
map<unsigned int, vector<Link> > node_inlinks;
map<unsigned int, vector<Link> > node_outlinks;
vector<Node> tmp_nodes;
tmp_nodes.resize(updates.size());
vector<Link> tmp_in_links;
vector<Link> tmp_out_links;
vector<unsigned int> tmp_frags;
unsigned int current_node = 0;
vector<Update>::iterator u;
for(u = updates.begin(); u != updates.end(); u++) {
Node &node = tmp_nodes[current_node];
//created cells belong to this node,
for(unsigned int i = 0; i < (*u).created.size(); i++) {
unsigned int cell = (*u).created[i];
cell_node[cell] = current_node;
}
//Every erased cell already belonged to a node //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 fragment 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++) {
unsigned int floor_node = (*e).first;
vector<unsigned int> &cells = (*e).second;
Node &parent = tmp_nodes[floor_node];
Link inlink;
inlink.node = (Node *)floor_node;
inlink.begin = tmp_frags.size();
inlink.end = inlink.begin + cells.size();
Link outlink;
outlink.node = (Node *)current_node;
outlink.begin = tmp_frags.size();
outlink.end = outlink.begin + cells.size();
//Fill it with erased cells.
vector<unsigned int>::iterator k;
for(k = cells.begin(); k != cells.end(); k++)
tmp_frags.push_back(*k);
//Add the new Frag to the nodes (in and out)
node_outlinks[floor_node].push_back(outlink);
node_inlinks[current_node].push_back(inlink);
}
current_node++;
}
map<unsigned int, vector<Link> >::iterator k;
for(k = node_outlinks.begin(); k != node_outlinks.end(); k++) {
unsigned int inode = (*k).first;
vector<Link> &links = (*k).second;
tmp_nodes[inode].out_begin = (Link *)(tmp_out_links.size());
tmp_nodes[inode].out_end = (Link *)(tmp_out_links.size() + links.size());
// tmp_nodes[inode].out_link_begin = (Link *)(tmp_out_links.size());
// tmp_nodes[inode].out_link_size = links.size();
for(unsigned int i = 0; i < links.size(); i++)
tmp_out_links.push_back(links[i]);
}
for(k = node_inlinks.begin(); k != node_inlinks.end(); k++) {
unsigned int inode = (*k).first;
vector<Link> &links = (*k).second;
// tmp_nodes[inode].in_link_begin = (Link *)(tmp_in_links.size());
// tmp_nodes[inode].in_link_size = links.size();
tmp_nodes[inode].in_begin = (Link *)(tmp_in_links.size());
tmp_nodes[inode].in_end = (Link *)(tmp_in_links.size() + links.size());
for(unsigned int i = 0; i < links.size(); i++)
tmp_in_links.push_back(links[i]);
}
//Here we reorder entries in nexus...
nexus.Flush();
vector<Entry> entries;
entries.resize(nexus.size());
for(unsigned int i = 0; i < nexus.size(); i++) {
assert(!nexus[i].patch);
entries[i] = nexus[i];
}
assert(tmp_frags.size() == nexus.size());
for(unsigned int i = 0; i < tmp_frags.size(); i++) {
nexus[i] = entries[tmp_frags[i]];
}
//WARNING CRITICAL TODOHey we should do the same on the borders!
vector<unsigned int> backward;
backward.resize(tmp_frags.size());
for(unsigned int i = 0; i < backward.size(); i++)
backward[tmp_frags[i]] = i;
for(unsigned int i = 0; i < nexus.borders.size(); i++) {
Border &border = nexus.borders.GetBorder(i);
for(unsigned int k = 0; k < border.Size(); k++)
border[k].end_patch = backward[border[k].end_patch];
}
nexus.borders.Flush();
vector<Border> borders;
borders.resize(nexus.borders.size());
for(unsigned int i = 0; i < nexus.borders.size(); i++) {
borders[i] = nexus.borders[i];
}
assert(tmp_frags.size() == nexus.borders.size());
for(unsigned int i = 0; i < tmp_frags.size(); i++) {
nexus.borders[i] = borders[tmp_frags[i]];
}
size = tmp_nodes.size() * sizeof(Node) +
tmp_in_links.size() * sizeof(Link) +
tmp_out_links.size() * sizeof(Link) +
4 * sizeof(int);
if(buffer) delete []buffer;
buffer = new char[size];
quick() = 53;
n_nodes() = tmp_nodes.size();
n_in_links() = tmp_in_links.size();
n_out_links() = tmp_out_links.size();
nodes = (Node *)(buffer + 4 * sizeof(int));
in_links = (Link *)(nodes + n_nodes());
out_links = in_links + n_in_links();
memcpy(nodes, &*tmp_nodes.begin(), tmp_nodes.size()*sizeof(Node));
memcpy(in_links, &*tmp_in_links.begin(), tmp_in_links.size()*sizeof(Link));
memcpy(out_links, &*tmp_out_links.begin(),
tmp_out_links.size()*sizeof(Link));
return LoadPointers();
}
void History::BuildLevels(vector<int> &levels) {
levels.clear();
if(buffer) {
//Saved in quick mode:
for(unsigned int n = 0; n < n_nodes(); n++) {
Node *node = nodes+n;
Node::iterator l;
unsigned int current = 0;
if(node != nodes) { //not root
Link *inlink = node->in_begin;
unsigned int p = inlink->begin;
assert(p < levels.size());
assert(p >= 0);
current = levels[p]+1;
}
for(l = node->out_begin; l != node->out_end; l++) {
Link &link = *l;
for(unsigned int p = link.begin; p != link.end; p++) {
while(p >= levels.size()) levels.push_back(-1);
levels[p] = current;
}
}
}
} else {
//Saved in updates mode:
for(unsigned int i = 0; i < updates.size(); i++) {
Update &u = updates[i];
unsigned int current = 0;
if(!u.erased.size()) current = 0;
else current = levels[u.erased[0]] + 1;
for(unsigned int i = 0; i < u.created.size(); i++) {
unsigned int p = u.created[i];
while(p >= levels.size()) levels.push_back(-1);
levels[p] = current;
}
}
}
}

View File

@ -1,130 +0,0 @@
/****************************************************************************
* VCGLib o o *
* Visual and Computer Graphics Library o o *
* _ O _ *
* Copyright(C) 2004 \/)\/ *
* Visual Computing Lab /\/| *
* ISTI - Italian National Research Council | *
* \ *
* All rights reserved. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
* for more details. *
* *
****************************************************************************/
/****************************************************************************
History
$Log: not supported by cvs2svn $
Revision 1.7 2005/02/20 19:49:44 ponchio
cleaning (a bit more).
Revision 1.6 2005/02/20 00:43:23 ponchio
Less memory x extraction. (removed frags)
Revision 1.5 2005/02/19 16:22:45 ponchio
Minor changes (visited and Cell)
Revision 1.4 2005/02/17 16:40:35 ponchio
Optimized BuildLevels.
Revision 1.3 2005/02/08 12:43:03 ponchio
Added copyright
****************************************************************************/
#ifndef NXS_HISTORY_H
#define NXS_HISTORY_H
#include <vector>
#include <map>
//TODO fix a bit better the quick <-> updates duality
namespace nxs {
class Nexus;
class History {
public:
enum Mode { QUICK = 1, UPDATES = 2 };
struct Update {
std::vector<unsigned int> erased;
std::vector<unsigned int> created;
};
struct Node;
struct Link {
Node *node;
unsigned int begin; //begin patch of the fragment
unsigned int end; //end patch of the fragment
typedef unsigned int iterator;
unsigned int size() { return end - begin; }
};
struct Node {
typedef Link *iterator;
Link *in_begin, *in_end;
Link *out_begin, *out_end;
};
Node *nodes;
Link *in_links;
Link *out_links;
std::vector<Update> updates;
History(): nodes(NULL), in_links(NULL), out_links(NULL),// frags(NULL),
buffer(NULL) {}
~History();
Node *Root() { return &nodes[0]; }
Node *Sink() { return Root() + n_nodes() -1; }
void Clear();
void ClearQuick();
void ClearUpdates();
//Owns memory afterwards.. do not free mem.
bool Load(unsigned int size, char *mem);
bool LoadQuick(unsigned int size, char *mem);
bool LoadUpdates(unsigned int size, char *mem);
//after these call history is invalid! and memory returned must be freed...
char *Save(unsigned int &size); //autodetect
char *SaveQuick(unsigned int &size);
char *SaveUpdates(unsigned int &size);
bool QuickToUpdates();
bool UpdatesToQuick(Nexus &nexus);
bool IsQuick() { return buffer != NULL; }
void BuildLevels(std::vector<int> &levels);
int &quick() { return ((int *)buffer)[0]; }
int &n_nodes() { return ((int *)buffer)[1]; }
int &n_in_links() { return ((int *)buffer)[2]; }
int &n_out_links() { return ((int *)buffer)[3]; }
// typedef Node *iterator;
// iterator begin() { return nodes; }
// iterator end() { return nodes + n_nodes(); }
protected:
unsigned int size;
char *buffer;
bool LoadPointers();
};
}
#endif

View File

@ -1,108 +0,0 @@
/****************************************************************************
* VCGLib o o *
* Visual and Computer Graphics Library o o *
* _ O _ *
* Copyright(C) 2004 \/)\/ *
* Visual Computing Lab /\/| *
* ISTI - Italian National Research Council | *
* \ *
* All rights reserved. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
* for more details. *
* *
****************************************************************************/
/****************************************************************************
History
$Log: not supported by cvs2svn $
****************************************************************************/
#ifndef NXS_INDEX_FILE_H
#define NXS_INDEX_FILE_H
#include <assert.h>
#include <vector>
#include "mfile.h"
namespace nxs {
/* WARINING when subclassing this class you must add a Close()
in the destructor! */
template <class T>
class IndexFile: public MFile, public std::vector<T> {
public:
virtual ~IndexFile() {}
bool Create(const std::string &filename, unsigned int header_size,
unsigned int max_file_size = MFILE_MAX_SIZE) {
clear();
if(!MFile::Create(filename, max_file_size)) return false;
MFile::Redim(header_size);
offset = header_size;
return true;
}
bool Load(const std::string &filename, bool readonly = false) {
clear();
if(!MFile::Load(filename, readonly)) return false;
SetPosition(0);
LoadHeader();
SetPosition(offset);
unsigned int tot;
ReadBuffer(&tot, sizeof(unsigned int));
resize(tot);
ReadBuffer(&*begin(), size() * sizeof(T));
return true;
}
void Close() {
if(IsReadOnly()) return;
if(files.size() == 0) return; //not loaded, not created or closed
MFile::Redim(offset + size() * sizeof(T));
SetPosition(offset);
unsigned int tot = size();
WriteBuffer(&tot, sizeof(unsigned int));
WriteBuffer(&*begin(), size() * sizeof(T));
SetPosition(0);
SaveHeader();
MFile::Close();
}
int64 Length() { //count the header but not the index...
return offset;
}
void Redim(int64 size) {
MFile::Redim(size);
offset = size;
assert(MFile::Length() == offset);
}
protected:
int64 offset;
//MUST set offset to its correct value
virtual bool LoadHeader() = 0;
//MUST save offset somewhere
virtual void SaveHeader() = 0;
};
} //namespace
#endif

View File

@ -1,109 +0,0 @@
/****************************************************************************
* VCGLib o o *
* Visual and Computer Graphics Library o o *
* _ O _ *
* Copyright(C) 2004 \/)\/ *
* Visual Computing Lab /\/| *
* ISTI - Italian National Research Council | *
* \ *
* All rights reserved. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
* for more details. *
* *
****************************************************************************/
/****************************************************************************
History
$Log: not supported by cvs2svn $
Revision 1.9 2005/02/22 10:37:55 ponchio
Debug, cleaning and optimization.
Revision 1.8 2005/02/21 20:49:30 ponchio
some culling bug.
Revision 1.7 2005/02/20 19:49:44 ponchio
cleaning (a bit more).
Revision 1.6 2005/02/20 18:07:01 ponchio
cleaning.
Revision 1.5 2005/02/19 16:22:45 ponchio
Minor changes (visited and Cell)
Revision 1.4 2005/02/08 12:43:03 ponchio
Added copyright
****************************************************************************/
#ifndef NXS_METRIC_H
#define NXS_METRIC_H
#include <wrap/gui/frustum.h>
#include <vcg/space/sphere3.h>
#include "nexus.h"
namespace nxs {
enum MetricKind { FRUSTUM, FLAT, DELTA };
class Metric {
public:
vcg::Frustumf frustum;
bool culling;
Metric(): culling(true) {}
virtual void GetView() { frustum.GetView(); }
virtual float GetError(Entry &entry, bool &visible) = 0;
};
class FlatMetric: public Metric {
public:
float GetError(Entry &entry, bool &visible) {
visible = true;
return entry.error;
}
};
class FrustumMetric: public Metric {
public:
float GetError(Entry &entry, bool &visible) {
visible = true;
vcg::Sphere3f &sph = entry.sphere;
float dist = (sph.Center() - frustum.ViewPoint()).Norm() - sph.Radius();
if(dist < 0) return 1e20f;
float error = entry.error/frustum.Resolution(dist);
if(culling) {
float remote = frustum.Remoteness(sph.Center(), sph.Radius());
if(frustum.IsOutside(sph.Center(), sph.Radius())) {
visible = false;
// TODO FIXME remoteness is bugged... (not much only bit
//if we are close to the surface, the projection of
//the bounding sphere in screen space comes out too small
//just using resolution and radius. Im too lazy to fix it.
if(remote > 0)
error /= remote;
} else if(entry.cone.Backface(sph, frustum.ViewPoint())) {
visible = false;
}
}
return error;
}
};
}
#endif

View File

@ -1,192 +0,0 @@
/****************************************************************************
* VCGLib o o *
* Visual and Computer Graphics Library o o *
* _ O _ *
* Copyright(C) 2004 \/)\/ *
* Visual Computing Lab /\/| *
* ISTI - Italian National Research Council | *
* \ *
* All rights reserved. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
* for more details. *
* *
****************************************************************************/
/****************************************************************************
History
$Log: not supported by cvs2svn $
****************************************************************************/
#include "mfile.h"
#include <assert.h>
#include <iostream>
using namespace std;
using namespace nxs;
bool MFile::Create(const string &fname, unsigned int mxs) {
Close();
filename = fname;
_size = 0;
readonly = false;
assert(mxs <= MFILE_MAX_SIZE);
max_size = mxs;
return AddFile();
}
bool MFile::Load(const string &fname, bool ronly) {
Close();
filename = fname;
readonly = ronly;
max_size = MFILE_MAX_SIZE;
_size = 0;
while(1) {
string name = Name(files.size());
File *file = new File;
files.push_back(file);
if(!file->Load(name, ronly)) {
files.pop_back();
break;
}
_size += file->Length();
}
if(files.size() == 0) return false;
if(files.size() == 1) {
assert(_size <= max_size);
} else {
//SANITY TEST
for(unsigned int i = 0; i < files.size() -2; i++) {
if(files[i]->Length() != files[i++]->Length()) {
//"Inconsistent file size for some file.\n";
return false;
}
max_size = files[0]->Length();
}
}
return true;
}
void MFile::Close() {
for(unsigned int i = 0; i < files.size(); i++)
delete files[i];
files.clear();
}
void MFile::Delete() {
while(files.size())
RemoveFile();
}
void MFile::Redim(int64 sz) {
assert(!readonly);
if(sz > _size) {
unsigned int totfile = (unsigned int)(sz/max_size);
//TODO test rhis!!!!
while(files.size() <= totfile) {
RedimLast(max_size);
assert(_size == (int64)max_size * (int64)(files.size()));
AddFile();
}
assert(_size <= sz);
assert(sz - _size < max_size);
assert(files.back()->Length() + (unsigned int)(sz - _size) < max_size);
RedimLast(files.back()->Length() + (unsigned int)(sz - _size));
} else {
while(_size - files.back()->Length() > sz)
RemoveFile();
assert(sz <= _size);
RedimLast(files.back()->Length() - (unsigned int)(_size - sz));
}
assert(sz == _size);
}
void MFile::SetPosition(int64 pos) {
assert(pos <= _size);
curr_fp = (unsigned int)(pos/(int64)max_size);
curr_pos = (unsigned int)(pos - (int64)max_size * (int64)curr_fp);
assert(curr_pos < max_size);
assert(curr_fp < files.size());
files[curr_fp]->SetPosition(curr_pos);
}
void MFile::ReadBuffer(void *data, unsigned int sz) {
while(sz + curr_pos > max_size) {
unsigned int n = max_size - curr_pos;
files[curr_fp]->ReadBuffer(data, n);
data = ((char *)data) + n;
sz -= n;
curr_fp++;
assert(curr_fp < files.size());
curr_pos = 0;
files[curr_fp]->SetPosition(curr_pos);
}
files[curr_fp]->ReadBuffer(data, sz);
}
void MFile::WriteBuffer(void *data, unsigned int sz) {
assert(!readonly);
while(sz + curr_pos > max_size) {
unsigned int n = max_size - curr_pos;
files[curr_fp]->WriteBuffer(data, n);
data = ((char *)data) + n;
sz -= n;
curr_fp++;
assert(curr_fp < files.size());
curr_pos = 0;
files[curr_fp]->SetPosition(curr_pos);
}
files[curr_fp]->WriteBuffer(data, sz);
}
bool MFile::AddFile() {
string name = Name(files.size());
File *file = new File;
files.push_back(file);
return file->Create(name);
}
void MFile::RemoveFile() {
assert(files.size());
string name = Name(files.size()-1);
File *file = files.back();
unsigned int last_size = file->Length();
delete file;
files.pop_back();
_size -= last_size;
cerr << "Removing file: " << name << endl;
#ifdef WIN32
DeleteFile(name.c_str());
#else
unlink(name.c_str());
#endif
}
void MFile::RedimLast(unsigned int sz) {
assert(sz <= max_size);
File &file = *files.back();
unsigned int last_size = (int64)file.Length();
file.Redim(sz);
_size += sz - (int64)last_size;
}
std::string MFile::Name(unsigned int n) {
char buffer[1024];
if(n == 0)
sprintf(buffer, "%s", filename.c_str());
else
sprintf(buffer, "%s%d", filename.c_str(), n);
return string(buffer);
}

View File

@ -1,91 +0,0 @@
/****************************************************************************
* VCGLib o o *
* Visual and Computer Graphics Library o o *
* _ O _ *
* Copyright(C) 2004 \/)\/ *
* Visual Computing Lab /\/| *
* ISTI - Italian National Research Council | *
* \ *
* All rights reserved. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
* for more details. *
* *
****************************************************************************/
/****************************************************************************
History
$Log: not supported by cvs2svn $
****************************************************************************/
#ifndef NXS_MFILE_H
#define NXS_MFILE_H
#include <string>
#include <vector>
#include "file.h"
#include "nxstypes.h"
namespace nxs {
/*#ifdef WIN32
typedef __int64 int64;
#else
typedef unsigned long long int64;
#endif*/
#define MFILE_MAX_SIZE (1<<30)
class MFile {
public:
MFile() {}
~MFile() { Close(); }
//max is so default is 1 G
bool Create(const std::string &filename,
unsigned int max_file_size = MFILE_MAX_SIZE);
bool Load(const std::string &filename, bool readonly = false);
void Close();
void Delete();
int64 Length() { return _size; }
void Redim(int64 size);
void SetPosition(int64 pos);
void ReadBuffer(void *data, unsigned int size);
void WriteBuffer(void *data, unsigned int size);
bool Opened() { return files.size() > 0; }
bool IsReadOnly() { return readonly; }
void SetReadOnly(bool rd) { readonly = rd; } //USE WITH CARE!!!!
protected:
std::string filename;
std::vector<File *> files;
unsigned int curr_pos;
unsigned int curr_fp;
int64 _size;
unsigned int max_size;
bool readonly;
private:
//all theese refer to the last in the fp.
bool AddFile();
void RemoveFile();
void RedimLast(unsigned int sz);
unsigned int GetSize();
std::string Name(unsigned int n);
};
}
#endif

View File

@ -1,319 +0,0 @@
/****************************************************************************
* VCGLib o o *
* Visual and Computer Graphics Library o o *
* _ O _ *
* Copyright(C) 2004 \/)\/ *
* Visual Computing Lab /\/| *
* ISTI - Italian National Research Council | *
* \ *
* All rights reserved. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
* for more details. *
* *
****************************************************************************/
/****************************************************************************
History
$Log: not supported by cvs2svn $
Revision 1.29 2005/02/19 10:45:04 ponchio
Patch generalized and small fixes.
Revision 1.28 2005/02/08 12:43:03 ponchio
Added copyright
****************************************************************************/
#include <assert.h>
#include <iostream>
#include <set>
#include "nexus.h"
using namespace std;
using namespace vcg;
using namespace nxs;
Nexus::~Nexus() {
Close();
}
bool Nexus::Create(const string &file, Signature &sig, unsigned int c_size) {
signature = sig;
totvert = 0;
totface = 0;
sphere = Sphere3f();
chunk_size = c_size;
unsigned int header_size = 256; //a bit more than 64 needed
if(chunk_size > header_size) header_size = chunk_size;
history.Clear();
ram_used = 0;
ram_max = 50 * (1<<20) / chunk_size;
if(!IndexFile<Entry>::Create(file + ".nxp", header_size)) {
cerr << "Could not create file: " << file << ".nxp" << endl;
return false;
}
//Important: chunk_size must be 1 so that i can use Region in VFile.
if(!borders.Create(file + ".nxb")) {
cerr << "Could not create file: " << file << ".nxb" << endl;
return false;
}
return true;
}
bool Nexus::Load(const string &file, bool rdonly) {
if(!IndexFile<Entry>::Load(file + ".nxp", rdonly)) return false;
ram_used = 0;
ram_max = 50 * (1<<20) / chunk_size;
history.Clear();
SetPosition(history_offset);
unsigned int history_size;
ReadBuffer(&history_size, sizeof(unsigned int));
char *buffer = new char[history_size];
ReadBuffer(buffer, history_size);
if(!history.Load(history_size, buffer)) {
cerr << "Error loading history\n";
return false;
}
borders.Load(file + ".nxb", rdonly);
//TODO on nxsbuilder assure borders are loaded
return true;
}
void Nexus::Close() {
if(!Opened()) return;
Flush();
if(!IsReadOnly()) {
//set history_offset
history_offset = 0;
if(size()) {
//we need to discover where is the last patch
for(unsigned int i = 0; i < size(); i++) {
Entry &e = operator[](i);
if(e.patch_start + e.disk_size > history_offset)
history_offset = e.patch_start + e.disk_size;
}
// history_offset = (back().patch_start + back().disk_size);
}
history_offset *= chunk_size;
unsigned int history_size;
char *mem = history.Save(history_size);
Redim(history_offset + history_size + sizeof(unsigned int));
SetPosition(history_offset);
WriteBuffer(&history_size, sizeof(unsigned int));
WriteBuffer(mem, history_size);
delete []mem;
}
borders.Close();
IndexFile<Entry>::Close();
}
void Nexus::SaveHeader() {
unsigned int magic = 0x3053584e; // nxs0
WriteBuffer(&magic, sizeof(unsigned int));
unsigned int version = 1;
WriteBuffer(&version, sizeof(unsigned int));
WriteBuffer(&signature, sizeof(Signature));
WriteBuffer(&chunk_size, sizeof(unsigned int));
WriteBuffer(&offset, sizeof(int64));
WriteBuffer(&history_offset, sizeof(int64));
WriteBuffer(&totvert, sizeof(unsigned int));
WriteBuffer(&totface, sizeof(unsigned int));
WriteBuffer(&sphere, sizeof(Sphere3f));
}
bool Nexus::LoadHeader() {
unsigned int magic;
ReadBuffer(&magic, sizeof(unsigned int));
if(magic != 0x3053584e) {
cerr << "Invalid magic. Not a nxs file\n";
return false;
}
//Current version is 1
unsigned int version;
ReadBuffer(&version, sizeof(unsigned int));
if(version != NXS_CURRENT_VERSION) {
cerr << "Old version. Sorry.\n";
return false;
}
ReadBuffer(&signature, sizeof(Signature));
ReadBuffer(&chunk_size, sizeof(unsigned int));
ReadBuffer(&offset, sizeof(int64));
ReadBuffer(&history_offset, sizeof(int64));
ReadBuffer(&totvert, sizeof(unsigned int));
ReadBuffer(&totface, sizeof(unsigned int));
ReadBuffer(&sphere, sizeof(Sphere3f));
return true;
}
void Nexus::Flush(bool all) {
if(all) {
std::map<unsigned int, list<unsigned int>::iterator>::iterator i;
for(i = index.begin(); i != index.end(); i++) {
unsigned int patch = (*i).first;
FlushPatch(patch);
}
pqueue.clear();
index.clear();
} else {
while(ram_used > ram_max) {
unsigned int to_flush = pqueue.back();
pqueue.pop_back();
index.erase(to_flush);
FlushPatch(to_flush);
}
}
}
Patch &Nexus::GetPatch(unsigned int patch, bool flush) {
Entry &entry = operator[](patch);
if(index.count(patch)) {
assert(entry.patch);
list<unsigned int>::iterator i = index[patch];
pqueue.erase(i);
pqueue.push_front(patch);
index[patch] = pqueue.begin();
} else {
while(flush && ram_used > ram_max) {
unsigned int to_flush = pqueue.back();
pqueue.pop_back();
index.erase(to_flush);
FlushPatch(to_flush);
}
assert(!entry.patch);
entry.patch = LoadPatch(patch);
pqueue.push_front(patch);
list<unsigned int>::iterator i = pqueue.begin();
index[patch] = i;
}
return *(entry.patch);
}
Border &Nexus::GetBorder(unsigned int patch, bool flush) {
return borders.GetBorder(patch);
}
unsigned int Nexus::AddPatch(unsigned int nvert, unsigned int nface,
unsigned int nbord) {
Entry entry;
entry.patch_start = 0xffffffff;
entry.ram_size = Patch::ChunkSize(signature, nvert, nface, chunk_size);
entry.disk_size = 0xffff;
entry.nvert = nvert;
entry.nface = nface;
entry.error = 0;
//sphere undefined.
entry.patch = NULL;
entry.vbo_array = 0;
entry.vbo_element = 0;
push_back(entry);
borders.AddBorder(nbord);
totvert += nvert;
totface += nface;
return size() - 1;
}
Patch *Nexus::LoadPatch(unsigned int idx) {
assert(idx < size());
Entry &entry = operator[](idx);
if(entry.patch) return entry.patch;
char *ram = new char[entry.ram_size * chunk_size];
#ifndef NDEBUG
if(!ram) {
cerr << "COuld not allocate ram!\n";
exit(0);
}
#endif
Patch *patch = new Patch(signature, ram, entry.nvert, entry.nface);
if(entry.patch_start != 0xffffffff) { //was allocated.
assert(entry.disk_size != 0xffff);
MFile::SetPosition((int64)entry.patch_start * (int64)chunk_size);
if(signature.compr == 0) { //not compressed
MFile::ReadBuffer(ram, entry.disk_size * chunk_size);
} else {
unsigned char *disk = new unsigned char[entry.disk_size * chunk_size];
MFile::ReadBuffer(disk, entry.disk_size * chunk_size);
patch->Decompress(entry.ram_size * chunk_size,
disk, entry.disk_size * chunk_size);
delete []disk;
}
} else {
//zero all bytes... so compressio gets better with padding.
memset(ram, 0, entry.ram_size * chunk_size);
}
ram_used += entry.ram_size;
entry.patch = patch;
return patch;
}
void Nexus::FlushPatch(unsigned int id) {
Entry &entry = operator[](id);
assert(entry.patch);
if(!MFile::IsReadOnly()) { //write back patch
if(signature.compr) {
unsigned int compressed_size;
char *compressed = entry.patch->Compress(entry.ram_size * chunk_size,
compressed_size);
if(entry.disk_size == 0xffff) {//allocate space
assert(entry.patch_start == 0xffffffff);
entry.disk_size = (unsigned int)((compressed_size-1)/chunk_size) + 1;
entry.patch_start = (unsigned int)(Length()/chunk_size);
Redim(Length() + entry.disk_size * chunk_size);
} else {
//cerr << "OOOOPSPPPS not supported!" << endl;
exit(-1);
}
MFile::SetPosition((int64)entry.patch_start * (int64)chunk_size);
MFile::WriteBuffer(compressed, entry.disk_size * chunk_size);
delete []compressed;
} else {
if(entry.disk_size == 0xffff) {
entry.disk_size = entry.ram_size;
entry.patch_start = (unsigned int)(Length()/chunk_size);
Redim(Length() + entry.disk_size * chunk_size);
}
MFile::SetPosition((int64)entry.patch_start * (int64)chunk_size);
MFile::WriteBuffer(entry.patch->fstart, entry.disk_size * chunk_size);
}
}
delete [](entry.patch->fstart);
delete entry.patch;
entry.patch = NULL;
ram_used -= entry.ram_size;
}

View File

@ -1,146 +0,0 @@
/****************************************************************************
* VCGLib o o *
* Visual and Computer Graphics Library o o *
* _ O _ *
* Copyright(C) 2004 \/)\/ *
* Visual Computing Lab /\/| *
* ISTI - Italian National Research Council | *
* \ *
* All rights reserved. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
* for more details. *
* *
****************************************************************************/
/****************************************************************************
History
$Log: not supported by cvs2svn $
Revision 1.21 2005/02/19 10:45:04 ponchio
Patch generalized and small fixes.
Revision 1.20 2005/02/08 12:43:03 ponchio
Added copyright
****************************************************************************/
#ifndef NXS_NEXUS_H
#define NXS_NEXUS_H
#include <string>
#include <vector>
#include <list>
#include <map>
#include <vcg/space/sphere3.h>
#include "normalscone.h"
#include "patch.h"
#include "index_file.h"
#include "history.h"
#include "borderserver.h"
namespace nxs {
/* Header fo nexus:
1Kb riservato per dati globali:
Magic: 'n' 'x' 's' 0x00
Signature: unsigned int (maschera di bit)
Chunk size: unsigned int
Index offset: unsigned int (offset to the index begin,
must be a multiple of chunk size)
History offset: unsigned int: multiple of chunk_size
Tot vert: unsigned int
Tot face: unsigned int
Bound sphere: Sphere3f (4 float: Point3f center (x, y, z), (radius))
11 * 4 = 44 bytes -> 4k per alignment purpoouses and reserving space. */
struct Entry {
unsigned int patch_start; //granularita' Chunk
unsigned short ram_size; //in chunks
unsigned short disk_size; // in chunks (used when compressed)
unsigned short nvert;
unsigned short nface;
vcg::Sphere3f sphere;
float error;
NCone3s cone;
Patch *patch;
unsigned int vbo_array;
unsigned int vbo_element;
};
class Nexus: public IndexFile<Entry> {
public:
enum Version { NXS_CURRENT_VERSION = 1 };
//HEader data:
Signature signature;
unsigned int chunk_size;
//unsigned int .IndexFile::offset;
int64 history_offset;
unsigned int totvert;
unsigned int totface;
vcg::Sphere3f sphere;
History history;
BorderServer borders;
Nexus() {}
~Nexus();
bool Create(const std::string &filename, Signature &signature,
unsigned int chunk_size = 1024);
bool Load(const std::string &filename, bool readonly = false);
void Close();
void Flush(bool all = true);
unsigned int AddPatch(unsigned int nv, unsigned int nf, unsigned int nb);
Patch &GetPatch(unsigned int patch, bool flush = true);
Border &GetBorder(unsigned int patch, bool flush = true);
unsigned int &MaxRam() { return ram_max; }
// void AddBorder(unsigned int patch, Link &link);
//move to nxsalgo!
void Unify(float threshold = 0.0f);
bool IsCompressed() { return signature.compr != 0; }
bool HasStrips() { return signature.face == Signature::STRIPS; }
bool HasColors() { return signature.vcolor != 0; }
bool HasNormals() { return signature.vnorm != 0; }
bool HasTextures() { return signature.vtext != 0; }
unsigned int ram_max;
unsigned int ram_used;
protected:
std::list<unsigned int> pqueue;
std::map<unsigned int, std::list<unsigned int>::iterator> index;
Patch *LoadPatch(unsigned int id);
virtual void FlushPatch(unsigned int id);
bool LoadHeader();
void SaveHeader();
};
}
#endif

View File

@ -1,174 +0,0 @@
<html>
<style type="text/css"><!--
body { margin-left: 10%; margin-right: 10%; }
h1 { font-size: 150%; margin-left: 3%; page-break-before: always;}
h2 { font-size: 120%; margin-left: 1%; }
h3 { font-size: 110%; margin-left: 0%; }
ul { list-style: none; }
ul { padding: 0 0 0 1.5em; }
li { padding: 0 0 0.5em 0; }
em {font-size: 133%; font-family:monospace}
--></style>
<body>
<p>
<center><img src="nexus_logo_midi.png"></center>
<p>
<h2>Index:</h2>
<p>
<ul>
<li><a href="#picture">Big picture</a></li>
<li><a href="#struct">Structures and interfaces</a></li>
<ul>
<li><a href="#vfile">VFile</a></li>
<li><a href="#crude">Crude</a></li>
<li><a href="#pchain">PChain</a></li>
<li><a href="#nexus">Nexus</a></li>
<li><a href="#bmt">Bmt</a></li>
</ul>
<li><a href="#algo">Algorithms</a></li>
<ul>
<li><a href="#plyto">Plys to Crude</a></li>
<li><a href="#crudeto">Crude to PChain</a></li>
<li><a href="#crudepchainto">Crude + Pchain to Nexus</a></li>
<li><a href="#nexusto">Nexus to Bmt</a></li>
</ul>
</ul>
<a name="picture"><h1>Big picture</h1></a>
La truttura nexus divide la mesh in tante piccole parti.<br>
Ciascuna parte ha le facce indicizzate localmente, e sono codificate
esplicitamente le corrispondenze tra vertici di patches diverse.<br>
<a name="struct"><h1>Structures and interfaces</h1></a>
<a name="vfile"><h2>VFile</h2></a>
VFile dovrebbe avere piu' o meno la stessa interfaccia di <em>vector</em>
ma usare un file per storare i dati (un mmapping, ma non limitato a 4Gb).<br>
<a name="crude"><h2>Crude</h2></a>
<pre>
Crude e' un formato tipo il ply... solo che usa dei VFile per
storare i dati.(3 unsigned int per una faccia e 3 float per un vertice).
Per cui e' composto di 3 files:
Header (<b>.crd</b>)
Magic: 'c' 'r' 'd' 0x00 (4 bytes)
N vertici: unsigned int (4 bytes)
N facce: unsigned int (4 bytes)
Box: Box3f (6 float min(x, y, z) e max(x, y, z))
File dei vertici: Point3f in sequenza (3 float, x, y, z)
File delle facce: 3 unsigned int
opzionalmente file degli attributi dei vertici e delle facce.
Come interfaccia e' sufficente che dia accesso casuale a facce e vertici...
</pre>
<a name="pchain"><h2>PChain</h2></a>
Sta per 'partition chain' cioe' una catena di partizioni dello
spazio.<br>
Una <em>PChain</em> detto in matematichese e' una funzione da
[0..L] X R^3 -> N (cioe' dato un livello e un punto nello spazio
restituisce un numero naturale. (una patch)<br>
Oltre a questo va aggiunta una funzione che dato un punto e una patch
ne restituisce la distanza (o un valore 'equivalente').<br>
Si deve poter salvare su disco e recuperare una pchain<br>
<a name="nexus"><h2>Nexus</h2></a>
<pre>
E' una struttura con 2 files:
File delle patches: (<b>.nxs</b>)
1Kb riservato per dati globali:
Magic: 'n' 'x' 's' 0x00
Signature: unsigned int (maschera di bit)
Chunk size: unsigned int
Index offset: int64 (offset to the index begin,
must be a multiple of chunk size)
History offset: int64: multiple of chunk_size
Tot vert: unsigned int
Tot face: unsigned int
Bound sphere: Sphere3f (4 float: Point3f center (x, y, z), (radius))
Dati (la sequenza di patches)
Index
History
'Index' contiene l'indice delle patches, per ogni patch viene storato:
offset, size dei dati geometrici nel file delle patches etc.
'History' vedi history.h
Index e History sono tenuti in memoria se il file e' aperto per creare
o per modificare, e sono salvati quando si chiude il file.
File dei bordi:
Links.
Index (offset, size tot size used)
Ogni link fa riferimento ad un vertice di bordo
tra la patch A (V_a) e la B (V_b) e contiene (V_a, V_b, B) (A e' implicito).
L'informazione e' replicata nei bordi relativi a B con (V_b, V_a, A)
</pre>
<br>
<a name="bmt"><h2>Bmt</h2></a>
Bmt (batched multi triangulation) e' il formato per la
multirisoluzione:<br>
E' un vettore di 'Cell' scritti su disco + un 'Index' e una 'History'.
Cell contiene i dati da visualizzare: vertici e strip (e altro?).<br>
Index contiene per ogni cell 'offset' per trovare la cell
corrispondente, error e bounding sphere (e per il face o vertex
count?).<br>
History e' la storia della multirisoluzione.<br>
<a name="algo"><h1>Algorithms</h1></a>
<a name="plyto"><h2>Plys to Crude</h2></a>
Si copiano i vertici un ply dopo l'altro nel crude.<br>
Per le facce si copiano sommando un offset ai vertici<br>
Se si montano insieme piu' ply i vertici rimangono duplicati.<br>
E' piu' semplice fare il join dentro Nexus.<br>
<a name="crudeto"><h2>Crude + PChain to Remap</h2></a>
Come prima cosa si costruisce il pchain passandogli il Crude.<br>
Asegnamo per ogni faccia la sua patch al livello 0.<br>
Per ogni patch sappiamo quante ce ne sono.<br>
Ridistribuiamo le patch troppo piccole (e rimappiamo i numeri delle
patches per rimuovere i buchi (anche dentro il PChain).<br>
Per risparmiare nella stessa passata ci segnamo dove vanno i vertici<br>
Poi facciamo un'altra passate per contare i bordi<br>
Infine si sortano le facce secondo l'ordine delle patches.<br>
<a name="crudepchainto"><h2>Crude + Remap to Nexus</h2></a>
Per ogni patch raccogliamo le facce, e i vertici (ma non li
unifichiamo) e costruiamo una patch nel Nexus.<br>
Ci dobbiamo segnare i bordi mano a mano che lo facciamo:
per ogni patch ci salviamo una lista di triplette: il numero assoluto
del vertice di bordo, il numero relativo nella patch che stiamo
salvando, e il numero della patch (o delle patch) con la quale
confina.<br>
Queste informazioni le tiriamo fuori dal Remap dei vertici<br>
Una volta salvate tutte le patches ci smazziamo i bordi:
per ogni patch prendiamo quella lista e la incrociamo con quella
delle patches confinanti per costruire i bordi da passare a nexus.<br>
<a name="nexusto"><h2>Nexus + PChain to Bmt</h2></a>
Per costruire il file multirisoluzione aggiungeremo semplicemente
nuove patches al file nexus.<br>
Ad ogni passo selezioniamo un gruppo di patches (il PChain ci dice i
gruppi), li joiniamo insieme usando i bordi per riunificare i vertici
e per marcare i bordi esterni.<br>
Poi semplifichiamo e splittiamo (e sempre il PChain ci dice quali
nuove patches creare), ridistribuiamo le patches troppo piccole.<br>
E aggiungiamo le nuove patches al Nexus, e i nuovi bordi.<br>
Ci salviamo anche la storia da qualche parte.<br>
</body>
</html>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

View File

@ -1,464 +0,0 @@
/****************************************************************************
* VCGLib o o *
* Visual and Computer Graphics Library o o *
* _ O _ *
* Copyright(C) 2004 \/)\/ *
* Visual Computing Lab /\/| *
* ISTI - Italian National Research Council | *
* \ *
* All rights reserved. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
* for more details. *
* *
****************************************************************************/
/****************************************************************************
History
$Log: not supported by cvs2svn $
Revision 1.37 2005/03/02 10:40:17 ponchio
Extraction rewrittten (to fix recusive problems).
Revision 1.36 2005/02/22 10:38:06 ponchio
Debug, cleaning and optimization.
Revision 1.35 2005/02/20 19:49:44 ponchio
cleaning (a bit more).
Revision 1.34 2005/02/20 18:07:01 ponchio
cleaning.
Revision 1.33 2005/02/20 00:43:23 ponchio
Less memory x extraction. (removed frags)
Revision 1.32 2005/02/19 12:06:53 ponchio
Debug...
Revision 1.31 2005/02/19 10:45:04 ponchio
Patch generalized and small fixes.
Revision 1.30 2005/02/17 15:39:44 ponchio
Reorderes statistics a bit.
Revision 1.29 2005/02/14 17:11:07 ponchio
aggiunta delle sphere
Revision 1.28 2005/02/08 12:43:03 ponchio
Added copyright
****************************************************************************/
#ifndef WIN32
#include <fcntl.h>
#endif
#include <map>
#include <queue>
#include <GL/glew.h>
#include <ptypes/pasync.h>
#include "nexusmt.h"
using namespace nxs;
using namespace vcg;
using namespace std;
void Stats::Start() {
tri = extr = disk_tri = 0;
watch.Start();
}
void Stats::Disk(float _disk) {
disk.push_front(_disk);
if(disk.size() > log_size) disk.pop_back();
}
void Stats::Error(float _error) {
error.push_front(_error);
if(error.size() > log_size) error.pop_back();
}
void Stats::Stop() {
time.push_front((float)watch.Time());
if(time.size() > log_size) time.pop_back();
fps = (7*fps + 1/time[0])/8.0f;
}
NexusMt::NexusMt() {
preload.mt = this;
preload.start();
}
NexusMt::~NexusMt() {
preload.signal();
preload.waitfor();
}
void NexusMt::SetPreload(bool on) {
if(on == (preload.get_running() && !preload.get_finished())) return;
if(on) preload.start();
else {
preload.signal();
// preload.waitfor();
}
}
bool NexusMt::Load(const string &filename) {
if(!Nexus::Load(filename, true)) return false;
if(!history.IsQuick() && !history.UpdatesToQuick(*this))
return false;
#ifndef WIN32
//i will read data only once usually.
// for(unsigned int i = 0; i < files.size(); i++) {
// int fd = fileno(files[i]->fp);
// posix_fadvise(fd, 0, 0, POSIX_FADV_NOREUSE);
// }
#endif
return true;
}
bool NexusMt::InitGL(bool vbo) {
use_vbo = vbo;
GLenum ret = glewInit();
if(ret != GLEW_OK) return false;
if(vbo && !GLEW_ARB_vertex_buffer_object) {
cerr << "No vbo available!" << endl;
use_vbo = false;
}
return true;
}
void NexusMt::Render(DrawContest contest) {
Extraction extraction;
extraction.metric->GetView();
extraction.Extract(this);
Render(extraction, contest);
}
void NexusMt::Render(Extraction &extraction, DrawContest &contest,
Stats *stats) {
static ::GLUquadricObj * spr = gluNewQuadric();
//Updating heap errors
map<unsigned int, float> errors;
for(unsigned int i = 0; i < extraction.selected.size(); i++) {
Item &item = extraction.selected[i];
errors[item.id] = item.error;
}
for(unsigned int i = 0; i < heap.size(); i++) {
Item &item = heap[i];
if(!errors.count(item.id)) {
item.error = 1e20;
} else
item.error = errors[item.id];
}
make_heap(heap.begin(), heap.end());
preload.post(extraction.selected);
glEnableClientState(GL_VERTEX_ARRAY);
if(signature.vcolor && (contest.attrs & DrawContest::COLOR))
glEnableClientState(GL_COLOR_ARRAY);
if(signature.vnorm && (contest.attrs & DrawContest::NORMAL))
glEnableClientState(GL_NORMAL_ARRAY);
vector<Item> skipped;
for(unsigned int i = 0; i < extraction.draw_size; i++) {
unsigned int patch = extraction.selected[i].id;
Entry &entry = operator[](patch);
if(stats) stats->extr += 2*entry.nvert;
if(!extraction.Visible(patch))
continue;
if(stats) stats->tri += 2*entry.nvert;
if(!entry.patch) {
skipped.push_back(extraction.selected[i]);
continue;
}
Draw(patch, contest);
}
preload.trigger.reset();
preload.lock.enter();
// if(skipped.size()) cerr << "Skipped: " << skipped.size() << endl;
for(vector<Item>::iterator i = skipped.begin(); i != skipped.end(); i++) {
GetPatch((*i).id, (*i).error);
Draw((*i).id, contest);
}
Flush(false); //in case there are no skipped... :P
if(stats) {
stats->Error(extraction.max_error);
stats->Disk(preload.disk);
stats->disk_tri += preload.disk_tri;
preload.disk = 0;
}
preload.trigger.post();
preload.lock.leave();
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
}
void NexusMt::Draw(unsigned int cell, DrawContest &contest) {
static ::GLUquadricObj * spr = gluNewQuadric();
Entry &entry = operator[](cell);
Patch &patch = *(entry.patch);
char *fstart;
char *vstart;
char *cstart;
char *nstart;
if(contest.attrs & DrawContest::SPHERES){
vcg::Sphere3f &sphere = entry.sphere;
glPushAttrib(GL_POLYGON_BIT);
glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
glPushMatrix();
glTranslatef(sphere.Center().X(),sphere.Center().Y(),sphere.Center().Z());
gluSphere(spr,sphere.Radius(),15,15);
glPopMatrix();
glPopAttrib();
}
if(use_vbo) {
if(!entry.vbo_element)
LoadVbo(entry);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, entry.vbo_array);
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, entry.vbo_element);
fstart = NULL;
vstart = NULL;
cstart = (char *)(patch.vstartc - patch.vstart);
nstart = (char *)(patch.vstartn - patch.vstart);
} else {
fstart = (char *)patch.FaceBegin();
vstart = (char *)patch.Vert3fBegin();
cstart = (char *)patch.VColorBegin();
nstart = (char *)patch.VNormBegin();
}
assert(signature.vert == Signature::POINT3F);
glVertexPointer(3, GL_FLOAT, 0, vstart);
if(signature.vcolor && contest.attrs & DrawContest::COLOR) {
assert(signature.vcolor == Encodings::BYTE4);
glColorPointer(4, GL_UNSIGNED_BYTE, 0, cstart);
}
if(signature.vnorm && contest.attrs & DrawContest::NORMAL) {
// assert(signature.vnorm == Encodings::SHORT4);
if(signature.vnorm == Encodings::SHORT4)
glNormalPointer(GL_SHORT, 8, nstart);
else
glNormalPointer(GL_FLOAT, 0, nstart);
}
switch(contest.mode) {
case DrawContest::POINTS:
glDrawArrays(GL_POINTS, 0, patch.nv); break;
case DrawContest::PATCHES:
glColor3ub((cell * 27)%225 + 30, (cell * 37)%225 + 30, (cell * 87)%225 + 30);
case DrawContest::SMOOTH:
if(signature.face == Signature::TRIANGLES)
glDrawElements(GL_TRIANGLES, patch.nf * 3,
GL_UNSIGNED_SHORT, fstart);
else if(signature.face == Signature::STRIPS)
glDrawElements(GL_TRIANGLE_STRIP, patch.nf,
GL_UNSIGNED_SHORT, fstart);
break;
case DrawContest::FLAT:
if(use_vbo) {
cerr << "Unsupported rendering mode sorry\n";
} else {
if(signature.face == Signature::TRIANGLES) {
glBegin(GL_TRIANGLES);
unsigned short *f = patch.Face(0);
for(int i = 0; i < patch.nf; i++) {
Point3f &p0 = patch.Vert3f(f[0]);
Point3f &p1 = patch.Vert3f(f[1]);
Point3f &p2 = patch.Vert3f(f[2]);
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]);
f += 3;
}
glEnd();
} else if(signature.face = Signature::STRIPS) {
cerr << "Unsupported rendering mode sorry\n";
}
}
break;
default:
cerr << "Unsupported rendering mode sorry\n";
exit(0);
break;
}
}
Patch &NexusMt::GetPatch(unsigned int patch, float error, bool flush) {
Entry &entry = operator[](patch);
if(entry.patch) return *(entry.patch);
while(flush && ram_used > ram_max) {
if(heap[0].error == 0) break;
unsigned int to_flush = heap[0].id;
pop_heap(heap.begin(), heap.end());
heap.pop_back();
FlushPatch(to_flush);
}
entry.patch = LoadPatch(patch);
heap.push_back(Item(patch, error));
push_heap(heap.begin(), heap.end());
return *(entry.patch);
}
void NexusMt::Flush(bool all) {
if(all) {
for(unsigned int i = 0; i < heap.size(); i++) {
unsigned int patch = heap[i].id;
FlushPatch(patch);
}
heap.clear();
} else {
while(heap.size() && ram_used > ram_max) {
if(heap[0].error == 0) break;
unsigned int to_flush = heap[0].id;
pop_heap(heap.begin(), heap.end());
heap.pop_back();
FlushPatch(to_flush);
}
}
}
bool NexusMt::CanAdd(Item &item) {
if(!heap.size()) return true;
Entry &entry = operator[](item.id);
if(ram_used + entry.ram_size < ram_max)
return true;
return heap[0].error > item.error;
}
void NexusMt::FlushPatch(unsigned int id) {
Entry &entry = operator[](id);
if(entry.vbo_element)
FlushVbo(entry);
if(entry.patch->fstart)
delete [](entry.patch->fstart);
delete entry.patch;
entry.patch = NULL;
ram_used -= entry.ram_size;
}
void NexusMt::LoadVbo(Entry &entry) {
assert(entry.vbo_element == 0);
// if(entry.vbo_element) return;
Patch &patch = *entry.patch;
unsigned int size = patch.nf * sizeof(unsigned short);
if(signature.face == Signature::TRIANGLES)
size *= 3;
else if(signature.face != Signature::STRIPS)
assert(0);
glGenBuffersARB(1, &entry.vbo_element);
assert(entry.vbo_element);
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, entry.vbo_element);
glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, size, patch.FaceBegin(),
GL_STATIC_DRAW_ARB);
vbo_used += size;
//TODO fix this when we allow data :p
size = patch.vstartd - patch.vstart;
glGenBuffersARB(1, &entry.vbo_array);
assert(entry.vbo_array);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, entry.vbo_array);
glBufferDataARB(GL_ARRAY_BUFFER_ARB, size, patch.Vert3fBegin(),
GL_STATIC_DRAW_ARB);
vbo_used += size;
delete [](entry.patch->fstart);
entry.patch->fstart = NULL;
}
void NexusMt::FlushVbo(Entry &entry) {
if(!entry.vbo_element) return;
glDeleteBuffersARB(1, &entry.vbo_element);
glDeleteBuffersARB(1, &entry.vbo_array);
entry.vbo_element = 0;
entry.vbo_array = 0;
Patch &patch = *entry.patch;
vbo_used -= patch.nf * sizeof(unsigned short);
vbo_used -= sizeof(float) * (patch.vstart - patch.vstartd);
}
//Kept for historical reasons.
/*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);
}
}
}
} */

View File

@ -1,162 +0,0 @@
/****************************************************************************
* VCGLib o o *
* Visual and Computer Graphics Library o o *
* _ O _ *
* Copyright(C) 2004 \/)\/ *
* Visual Computing Lab /\/| *
* ISTI - Italian National Research Council | *
* \ *
* All rights reserved. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
* for more details. *
* *
****************************************************************************/
/****************************************************************************
History
$Log: not supported by cvs2svn $
Revision 1.24 2005/02/17 15:39:44 ponchio
Reorderes statistics a bit.
Revision 1.23 2005/02/14 17:11:07 ponchio
aggiunta delle sphere
Revision 1.22 2005/02/10 09:18:20 ponchio
Statistics.
Revision 1.21 2005/02/08 12:43:03 ponchio
Added copyright
****************************************************************************/
#ifndef NXS_MT_H
#define NXS_MT_H
#include <vector>
#include <queue>
#include <wrap/gui/frustum.h>
#include "nexus.h"
#include "history.h"
#include "extraction.h"
#include "metric.h"
#include "preload.h"
#include "watch.h"
namespace nxs {
struct DrawContest {
enum Mode { POINTS, SMOOTH, XRAY, HIDDEN_LINE, FLAT_WIRE, FLAT, PATCHES };
enum Attr { COLOR = 0x1, NORMAL = 0x2, TEXTURE = 0x4, DATA = 0x8, SPHERES = 0x10 };
Mode mode;
unsigned int attrs;
DrawContest(Mode m = SMOOTH, unsigned int a = 0xf): mode(m), attrs(a) {}
void SetAttr(Attr attr, bool value);
bool HasComponent(Attr attr);
};
struct Stats {
//per frame data...
float tri; //k triangles rendered.
float extr; //k triangles extracted
float disk_tri; //k triangles readed from disk
int log_size;
deque<float> error; //max error in extraction (push_front pop_back)
deque<float> time;
deque<float> disk; //kdisk readed per frame
float fps; //averaged over 8 frames
Watch watch;
Stats(): log_size(48), fps(0.0f) {}
void Start();
void Disk(float disk);
void Error(float error);
void Stop();
};
class NexusMt: public Nexus {
public:
bool use_vbo;
bool prefetch;
unsigned int vbo_used; //TODO remember to zero it!
Preload preload;
NexusMt();
~NexusMt();
bool Load(const std::string &filename);
// void Close();
bool InitGL(bool use_vbo = true);
void Render(DrawContest contest = DrawContest());
void Render(Extraction &extraction,
DrawContest &contest,
Stats *stats = NULL);
void SetPreload(bool on);
void Flush(bool all = true);
Patch &GetPatch(unsigned int patch, float error, bool flush = true);
bool CanAdd(Item &item);
protected:
std::vector<Item> heap;
void FlushPatch(unsigned int id);
void LoadVbo(Entry &entry);
void FlushVbo(Entry &entry);
void Draw(unsigned int cell, DrawContest &contest);
};
/* class NexusViewer {
public:
NexusMt &mt;
DrawContest contest;
Extraction extraction;
Statistics stats;
NexusViewer(NexyusMt &_mt): mt(&mt) {}
void Render();
bool SetMode(DrawContest::Mode mode);
bool SetComponent(DrawContest::Component c, bool on);
bool SetComponents(unsigned int mask);
void SetMetric(MetricKind kind);
void SetError(float error);
//Uinits expressed in Kb
void SetExtractionSize(unsigned int ksize);
void SetDrawSize(unsigned int ksize);
void SetDiskDelta(unsigned int kdelta);
//void SetPrefetchSize(unsigned int size);
};*/
}
#endif

View File

@ -1,749 +0,0 @@
/****************************************************************************
* VCGLib o o *
* Visual and Computer Graphics Library o o *
* _ O _ *
* Copyright(C) 2004 \/)\/ *
* Visual Computing Lab /\/| *
* ISTI - Italian National Research Council | *
* \ *
* All rights reserved. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
* for more details. *
* *
****************************************************************************/
/****************************************************************************
History
$Log: not supported by cvs2svn $
Revision 1.46 2005/04/04 14:27:53 ponchio
*** empty log message ***
Revision 1.45 2005/03/02 10:40:17 ponchio
Extraction rewrittten (to fix recusive problems).
Revision 1.44 2005/03/01 11:20:22 ponchio
nothing really
Revision 1.43 2005/02/20 18:07:01 ponchio
cleaning.
Revision 1.42 2005/02/20 00:43:24 ponchio
Less memory x extraction. (removed frags)
Revision 1.41 2005/02/19 12:06:55 ponchio
Debug...
Revision 1.40 2005/02/17 15:39:44 ponchio
Reorderes statistics a bit.
Revision 1.39 2005/02/17 14:02:03 ponchio
Full screen options...
Revision 1.38 2005/02/16 15:52:09 ponchio
qualche opzione in piu' , tolti i grafici
Revision 1.37 2005/02/15 15:55:36 ponchio
aggiunta delle sphere
Revision 1.36 2005/02/14 17:11:08 ponchio
aggiunta delle sphere
Revision 1.35 2005/02/14 14:49:09 ponchio
*** empty log message ***
Revision 1.34 2005/02/14 14:21:24 ponchio
Preload disabled at startap (-p)
Revision 1.33 2005/02/10 09:18:20 ponchio
Statistics.
Revision 1.32 2005/02/03 12:35:01 ponchio
Patch cache -> heap
Revision 1.31 2005/02/01 16:42:30 ponchio
Trigger
Revision 1.30 2005/01/21 17:09:13 ponchio
Porting and debug.
Revision 1.29 2005/01/17 17:35:47 ponchio
Small changes and adding realtime extr.
Revision 1.28 2005/01/14 15:25:29 ponchio
Revolution.
Revision 1.27 2004/12/15 16:37:55 ponchio
Optimizing realtime vis.
Revision 1.26 2004/12/15 13:50:32 ponchio
Optimizing realtime vis.
Revision 1.25 2004/12/15 08:46:16 ponchio
Optimizing realtime vis.
Revision 1.24 2004/12/13 00:44:48 ponchio
Lotsa changes...
Revision 1.23 2004/12/01 18:46:21 ponchio
Microchanges.
Revision 1.22 2004/11/28 04:16:19 ponchio
*** empty log message ***
Revision 1.21 2004/11/28 01:23:26 ponchio
Fixing borders... let's hope.
Revision 1.20 2004/11/18 18:30:14 ponchio
Using baricenters... lotsa changes.
Revision 1.19 2004/10/30 20:17:03 ponchio
Fixed big patches problem.
Revision 1.18 2004/10/21 13:40:16 ponchio
Debugging.
Revision 1.17 2004/10/21 12:22:21 ponchio
Small changes.
Revision 1.16 2004/10/19 01:23:02 ponchio
Daily backup (fragment...)
Revision 1.15 2004/10/15 16:45:27 ponchio
Vbo added.
Revision 1.14 2004/10/14 13:52:02 ponchio
Small changes.
Revision 1.13 2004/10/14 13:41:34 ponchio
Added statistics.
Revision 1.12 2004/10/09 14:46:47 ponchio
Windows porting small changes.
Revision 1.11 2004/10/04 16:49:54 ponchio
Daily backup. Preparing for compression.
Revision 1.10 2004/10/01 16:54:57 ponchio
Daily backup.
Revision 1.9 2004/09/30 23:56:33 ponchio
Backup (added strips and normals)
Revision 1.8 2004/09/30 00:27:42 ponchio
Lot of changes. Backup.
Revision 1.7 2004/09/28 10:26:35 ponchio
Backup
Revision 1.6 2004/09/17 15:25:09 ponchio
First working (hopefully) release.
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.
Revision 1.3 2004/07/15 14:32:49 ponchio
Debug.
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.
Revision 1.2 2004/07/04 15:16:01 ponchio
*** empty log message ***
Revision 1.1 2004/07/02 17:41:57 ponchio
Created.
Revision 1.3 2004/07/02 13:03:34 ponchio
*** empty log message ***
Revision 1.2 2004/07/01 21:33:46 ponchio
Added remap reading.
Revision 1.1 2004/06/23 00:10:38 ponchio
Created
****************************************************************************/
#ifdef WIN32
#include <wrap/system/getopt.h>
#else
#include <unistd.h>
#endif
#include <deque>
#include <iostream>
#include <fstream>
using namespace std;
#include <SDL/SDL.h>
//this include MUST precede GL includes.
#include <apps/nexus/nexusmt.h>
#ifdef WIN32
#include <windows.h>
#endif
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>
#include <wrap/gui/trackball.h>
#include "watch.h"
using namespace vcg;
using namespace nxs;
bool fullscreen = false;
int width = 1024;
int height = 768;
Point3f view(0, 0, 5);
Point3f target(0, 0, 0);
void gl_print(float x, float y, char *str);
SDL_Surface *screen = NULL;
bool init(const string &str) {
if(SDL_Init(SDL_INIT_VIDEO) != 0) {
return false;
}
const SDL_VideoInfo *info = SDL_GetVideoInfo();
int bpp = info->vfmt->BitsPerPixel;
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
int flags = SDL_OPENGL;
if(fullscreen)
flags |= SDL_FULLSCREEN;
screen = SDL_SetVideoMode(width, height, bpp, flags);
if(!screen) {
return false;
}
// SDL_WM_SetIcon(SDL_LoadBMP("icon.bmp"), NULL);
SDL_WM_SetCaption(str.c_str(), str.c_str());
glDisable(GL_DITHER);
glShadeModel(GL_SMOOTH);
glHint( GL_FOG_HINT, GL_NICEST );
glEnable(GL_DEPTH_TEST);
glDepthFunc( GL_LEQUAL );
glDisable(GL_LIGHTING);
glEnableClientState(GL_VERTEX_ARRAY);
return true;
}
int main(int argc, char *argv[]) {
int level = 0;
int apatch = -1;
float error = 4;
string file;
Trackball track;
if(argc < 2) {
cerr << "Usage: " << argv[0] << " <nexus file> [options]\n";
cerr << "-e <error> : set initial target error\n"
<< "-m <ram> : max ram used\n"
<< "-x <ram> : max extraction size\n"
<< "-r <ram> : max draw size\n"
<< "-d <ram> : max disk read per frame\n"
<< "-p : no preload\n"
<< "-w <pixels>: window width\n"
<< "-h <pixels>: window height\n"
<< "-f : fullscreen mode\n"
<< "-l <file> : log timing on file\n"
<< "-o namefile: ouput stats";
return -1;
}
NexusMt nexus;
if(!nexus.Load(argv[1])) {
cerr << "Could not load nexus file: " << argv[1] << endl;
return -1;
}
Sphere3f sphere = nexus.sphere;
Extraction extraction;
DrawContest contest;
Stats stats;
stats.Start();
bool rotate = false;
bool show_borders = false;
bool do_render = true;
bool show_statistics = true;
bool extract = true;
bool realtime = true;
bool preload = true;
Point4f light(1, -1, 1, 0);
bool output_stats = false;
char output_filename[100];
char window_name [100];
sprintf(window_name,"%s", argv[1]);
int option;
while((option = getopt(argc, argv, "e:m:x:r:d:l:o:w:h:p:f")) != EOF) {
switch(option) {
case 'e': extraction.target_error = atof(optarg); break;
case 'm': nexus.MaxRam() = atoi(optarg); break;
case 'x': extraction.extr_max = atoi(optarg); break;
case 'r': extraction.draw_max = atoi(optarg); break;
case 'd': extraction.disk_max = atoi(optarg); break;
case 'l': file = optarg; break;
case 'o': output_stats = true; sprintf(output_filename,"%s",optarg); break;
case 'w': width = atoi(optarg); break;
case 'h': height = atoi(optarg); break;
case 'p': preload = false; nexus.SetPreload(preload); break;
case 'f': fullscreen = true; break;
default:
cerr << "Unknow option.\n"; break;
}
}
FILE *fp = NULL;
if(file != "") {
fp = fopen(file.c_str(), "rwb+");
if(!fp) {
cerr << "Could not open log file: " << file << endl;
return -1;
}
fprintf(fp, "timeMs, error, extrTri, drawTri, diskTri, diskKb\n");
}
if(!init(window_name)) {
cerr << "Could not init SDL window\n";
return -1;
}
cerr << "Commands: \n"
" q : quit\n"
" t : toggle statistics\n"
" right arrow: increase memory buffer\n"
" left arrow : decrease memory buffer\n"
" page up : increase disk space\n"
" page down : increase disk space\n"
" 0 : decrease extraction size\n"
" 1 : increase extraction size\n"
" s : toggle preload\n"
" l : change light\n"
" d: debug mode (show patches colored)\n"
" f: flat shading mode\n"
" m: smooth mode\n"
" p: draw points\n"
" h: draw bounding spheres\n"
" w: disable glcalls\n"
" c: show colors\n"
" n: show normals\n"
" r: rotate model\n"
" -: decrease error\n"
" +: increase error (= too)\n";
Watch watch;
if(!nexus.InitGL()) {
cerr << "Could not init glew.\n";
return -1;
}
glClearColor(0, 0, 0, 0);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_NORMALIZE);
glEnable(GL_COLOR_MATERIAL);
glEnable(GL_CULL_FACE);
int quit = 0;
SDL_Event event;
int x, y;
float alpha = 0;
float fps = 0;
unsigned int nave = 5;
unsigned int offset = 0;
deque<float> tframe;
deque<float> terror;
unsigned int tlen = 256;
bool keepdrawing = true;
watch.Start();
while( !quit ) {
unsigned int anything = SDL_PollEvent(&event);
if(!anything && !keepdrawing) {
SDL_WaitEvent(&event);
anything = true;
}
while(anything) {
switch( event.type ) {
case SDL_QUIT: quit = 1; break;
case SDL_KEYDOWN:
switch(event.key.keysym.sym) {
case SDLK_RCTRL:
case SDLK_LCTRL: track.ButtonDown(Trackball::KEY_CTRL); break;
case SDLK_q: exit(0); break;
case SDLK_k: keepdrawing = !keepdrawing; break;
case SDLK_e: extract = !extract; break;
case SDLK_c:
if(contest.attrs & DrawContest::COLOR)
contest.attrs &= ~DrawContest::COLOR;
else
contest.attrs |= DrawContest::COLOR; break;
case SDLK_n:
if(contest.attrs & DrawContest::NORMAL)
contest.attrs &= ~DrawContest::NORMAL;
else
contest.attrs |= DrawContest::NORMAL; break;
case SDLK_w: do_render = !do_render; break;
case SDLK_LEFT: nexus.MaxRam() *= 0.8; break;
case SDLK_RIGHT: nexus.MaxRam() *= 1.3; break;
case SDLK_UP: extraction.draw_max *= 1.3; break;
case SDLK_DOWN: extraction.draw_max *= 0.8; break;
case SDLK_PAGEUP: extraction.disk_max *= 1.3; break;
case SDLK_PAGEDOWN: extraction.disk_max *= 0.8; break;
case SDLK_0: extraction.extr_max *= 1.3; break;
case SDLK_9: extraction.extr_max *= 0.8; break;
case SDLK_p: contest.mode = DrawContest::POINTS; break;
case SDLK_d: contest.mode = DrawContest::PATCHES; break;
case SDLK_f: contest.mode = DrawContest::FLAT; break;
case SDLK_m: contest.mode = DrawContest::SMOOTH; break;
case SDLK_h: if(contest.attrs&DrawContest::SPHERES)
contest.attrs &=~DrawContest::SPHERES;
else
contest.attrs |=DrawContest::SPHERES;
break;
case SDLK_l:
light[0] = rand();
light[1] = rand();
light[2] = rand();
light.Normalize();
break;
case SDLK_o: realtime = !realtime; break;
case SDLK_s: preload = !preload; nexus.SetPreload(preload); break;
case SDLK_t: show_statistics = !show_statistics; break;
case SDLK_r:
case SDLK_SPACE: rotate = !rotate; break;
case SDLK_MINUS:
extraction.target_error *= 0.9f;
cerr << "Error: " << extraction.target_error << endl;
break;
case SDLK_EQUALS:
case SDLK_PLUS:
extraction.target_error *= 1.1f;
cerr << "Error: " << extraction.target_error << endl;
break;
}
break;
case SDL_KEYUP:
switch(event.key.keysym.sym) {
case SDLK_RCTRL:
case SDLK_LCTRL:
track.ButtonUp(Trackball::KEY_CTRL); break;
}
break;
case SDL_MOUSEBUTTONDOWN:
x = event.button.x;
y = height - event.button.y;
#ifdef SDL_BUTTON_WHEELUP
if(event.button.button == SDL_BUTTON_WHEELUP)
track.MouseWheel(1);
else if(event.button.button == SDL_BUTTON_WHEELDOWN)
track.MouseWheel(-1);
else
#endif
if(event.button.button == SDL_BUTTON_LEFT)
track.MouseDown(x, y, Trackball::BUTTON_LEFT);
else if(event.button.button == SDL_BUTTON_RIGHT)
track.MouseDown(x, y, Trackball::BUTTON_RIGHT);
break;
case SDL_MOUSEBUTTONUP:
x = event.button.x;
y = height - event.button.y;
if(event.button.button == SDL_BUTTON_LEFT)
track.MouseUp(x, y, Trackball::BUTTON_LEFT);
else if(event.button.button == SDL_BUTTON_RIGHT)
track.MouseUp(x, y, Trackball::BUTTON_RIGHT);
break;
case SDL_MOUSEMOTION:
while(SDL_PeepEvents(&event, 1, SDL_GETEVENT, SDL_MOUSEMOTIONMASK));
x = event.motion.x;
y = height - event.motion.y;
track.MouseMove(x, y);
break;
case SDL_VIDEOEXPOSE:
default: break;
}
anything = SDL_PeepEvents(&event, 1, SDL_GETEVENT,
SDL_ALLEVENTS);
}
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(40, width/(float)height, 0.1, 100);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// gluLookAt(0,0,5, 0,0,0, 0,1,0);
gluLookAt(view[0],view[1], view[2],
target[0],target[1],target[2], 0,1,0);
track.GetView();
track.Apply();
glLightfv(GL_LIGHT0, GL_POSITION, &light[0]);
glViewport(0,0,width,height);
glRotatef(alpha, 0, 1, 0);
if(rotate) {
alpha++;
if(alpha > 360) alpha = 0;
if(!keepdrawing) {
SDL_Event redraw;
redraw.type = SDL_VIDEOEXPOSE;
SDL_PushEvent(&redraw);
}
}
float scale = 2/sphere.Radius();
glScalef(scale, scale, scale);
Point3f center = sphere.Center();
glTranslatef(-center[0], -center[1], -center[2]);
// Point3f &p = nexus.sphere.Center();
// float r = nexus.sphere.Radius();
glColor3f(0.8f, 0.8f, 0.8f);
if(extract) {
// Sould we want a different view from metric and extraction
// extraction.frustum->GetView();
extraction.metric->GetView();
if(!realtime) {
extraction.visited.clear();
extraction.Extract(&nexus);
extraction.Update(&nexus);
} else {
extraction.Update(&nexus);
}
}
stats.Stop();
stats.Start();
if(do_render)
nexus.Render(extraction, contest, &stats);
/* if(show_borders) {
for(unsigned int i = 0; i < cells.size(); i++) {
Border &border = nexus.GetBorder(cells[i]);
Patch &patch = nexus.GetPatch(cells[i]);
glPointSize(4);
glColor3f(1.0f, 1.0f, 1.0f);
glBegin(GL_POINTS);
for(unsigned int b = 0; b < border.Size(); b++) {
Link &link = border[b];
Point3f &p = patch.Vert(link.start_vert);
glVertex3f(p[0], p[1], p[2]);
}
glEnd();
glPointSize(1);
}
}*/
tframe.push_front(watch.Time());
if(tframe.size() > tlen) tframe.pop_back();
terror.push_front(extraction.max_error);
if(terror.size() > tlen) terror.pop_back();
if(show_statistics) {
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
gluOrtho2D(0, 1, 0, 1);
glDisable(GL_DEPTH_TEST);
glDisable(GL_LIGHTING);
//show frame and error graphics
if(false){
glColor4f(0.6f, 0.6f, 0.6f, 0.5f);
glBegin(GL_LINE_STRIP);
for(unsigned int i = 0; i < tframe.size() -1; i++) {
double diff = (tframe[i] - tframe[i+1]);
//glVertex2f(i/1024.0f,0);
glVertex2f(i/1024.0f,2*diff);
}
glEnd();
glColor4f(0.0f, 0.6f, 0.2f, 0.5f);
glBegin(GL_LINE_STRIP);
for(unsigned int i = 0; i < terror.size() -1; i++) {
// glVertex2f(i/1024.0f,0);
glVertex2f(i/1024.0f,terror[i]/300);
}
glEnd();
}
glColor3f(1.0f, 1.0f, 1.0f);
char buffer[1024];
sprintf(buffer, "Ram size : %.2f / %.2f Mb",
nexus.ram_used * nexus.chunk_size/(float)(1<<20),
nexus.ram_max * nexus.chunk_size/(float)(1<<20));
gl_print(0.03, 0.15, buffer);
sprintf(buffer, "Extr size: %.2f / %.2f Mb",
extraction.extr_used * nexus.chunk_size/(float)(1<<20),
extraction.extr_max * nexus.chunk_size/(float)(1<<20));
gl_print(0.03, 0.12, buffer);
sprintf(buffer, "Draw size: %.2f / %.2f Mb",
extraction.draw_used * nexus.chunk_size/(float)(1<<20),
extraction.draw_max * nexus.chunk_size/(float)(1<<20));
gl_print(0.03, 0.09, buffer);
sprintf(buffer, "Disk size: %.2f / %.2f Mb",
extraction.disk_max * nexus.chunk_size/(float)(1<<20),
extraction.disk_used * nexus.chunk_size/(float)(1<<20));
gl_print(0.03, 0.06, buffer);
sprintf(buffer, "%.2f KTri %.2f FPS %.0f M/s",
stats.tri/(float)(1<<10),
stats.fps, stats.fps * stats.tri/(float)(1<<20));
gl_print(0.03, 0.03, buffer);
glEnable(GL_DEPTH_TEST);
glEnable(GL_LIGHTING);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
/* statistics: output on file
if(output_stats){
static Stats statsAcc;
static float ram_used;
static float extr_used;
static float draw_used;
static float disk_used;
static std::ofstream outf(output_filename);
static bool first=true;
if(first) {
outf<< "ktri\t fps\t ram \t extr \t draw \t disk \n"
<< " \t \t"
<< nexus.ram_max * nexus.chunk_size/(float)(1<<20) << "\t"
<< extraction.extr_max * nexus.chunk_size/(float)(1<<20) << "\t"
<< extraction.draw_max * nexus.chunk_size/(float)(1<<20)<<"\t"
<< extraction.disk_max * nexus.chunk_size/(float)(1<<20)<< "\n";
first = false;
}
statsAcc.count++ ;
if((statsAcc.count%30)==0) {
outf
<< (statsAcc.tri/(float)statsAcc.count)/(float)(1<<10) << "\t"
<< (statsAcc.fps/(float)statsAcc.count) << "\t"
// << (statsAcc.kdisk/(float)statsAcc.count) << "\t"
<< ram_used/(float)statsAcc.count*nexus.chunk_size/(float)(1<<20) << "\t"
<< extr_used/(float)statsAcc.count*nexus.chunk_size/(float)(1<<20) << "\t"
<< draw_used/(float)statsAcc.count*nexus.chunk_size/(float)(1<<20) << "\t"
<< disk_used/(float)statsAcc.count*nexus.chunk_size/(float)(1<<20) << "\t"
<< "\n";
statsAcc.Init();
statsAcc.count = 0;
statsAcc.fps = 0;
ram_used = extr_used = draw_used = disk_used = 0.0;
} else {
statsAcc.fps += stats.fps;
statsAcc.kdisk += stats.kdisk;
statsAcc.ktri += stats.ktri;
ram_used += nexus.ram_used;
extr_used += extraction.extr_used;
draw_used += extraction.draw_used;
disk_used += extraction.disk_used;
}
}*/
}
SDL_GL_SwapBuffers();
if(fp && stats.time.size()) {
//fprintf(fp, "timeMs, error, extrTri, drawTri, diskTri, diskKb\n");
assert(stats.time.size() && stats.error.size() && stats.disk.size());
fprintf(fp, "%d, %f, %d, %d, %d, %d\n",
(*stats.time.begin())*1000,
stats.error.begin(),
(int)stats.extr,
(int)stats.tri,
(int)stats.disk_tri,
(int)((*stats.disk.begin())/1024)*nexus.chunk_size);
}
}
if(fp)
fclose(fp);
SDL_Quit();
return -1;
}
void gl_print(float x, float y, char *str) {
glRasterPos2f(x, y);
int len = (int)strlen(str);
for(int i = 0; i < len; i++)
glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, str[i]);
}

View File

@ -1,180 +0,0 @@
#include "normalscone.h"
#include <iostream>
using namespace std;
using namespace vcg;
using namespace nxs;
ANCone3f::ANCone3f() {
scaledNormal = Point3f(0,0,0);
frontAnchor = Point3f(0,0,0);
backAnchor = Point3f(0,0,0);
}
bool ANCone3f::Frontface(const Point3f &viewPoint) {
Point3f d = frontAnchor - viewPoint; //Vector from viewPoint to frontAnchor.
float f = - d * scaledNormal;
if (f < 0.001 || f * f < d * d)
return false;
return true;
}
bool ANCone3f::Backface(const Point3f &viewPoint) {
Point3f d = backAnchor - viewPoint; //Vector from viewPoint to frontAnchor.
float f = d * scaledNormal;
if (f < 0.001 || f * f < d * d)
return false;
return true;
}
void ANCone3f::AddNormals(vector<Point3f> &normal, vector<float> &area, float threshold) {
assert(normal.size() == area.size());
scaledNormal = Point3f(0,0,0);
int count = 0;
vector<Point3f>::iterator i;
for(i = normal.begin(); i != normal.end(); i++) {
scaledNormal += *i;
count++;
}
scaledNormal /= count;
scaledNormal.Normalize();
double distr[50];
for(int k = 0; k < 50; k++)
distr[k] = 0;
double tot_area = 0;
vector<float>::iterator j;
for(i = normal.begin(), j = area.begin(); i != normal.end(); i++, j++) {
int pos = (int)(49.0 * Angle(scaledNormal, *i)/M_PI);
if(pos < 0) continue;
assert(pos >=0 && pos < 50);
distr[pos] += *j;
tot_area += *j;
}
float tot = 0;
int best;
for(best = 0; best < 50; best++) {
tot += distr[best];
if(tot > threshold * tot_area)
break;
}
double alpha = M_PI * (best + 1) / 50;
if(alpha >= M_PI/ 2 - 0.1)
scaledNormal = Point3f(0,0,0);
else
scaledNormal /= cos(M_PI/2 - alpha);
}
void ANCone3f::AddNormals(vector<Point3f> &normal, float threshold) {
assert(normal.size() > 0);
scaledNormal = Point3f(0,0,0);
int count = 0;
vector<Point3f>::iterator i;
for(i = normal.begin(); i != normal.end(); i++) {
Point3f norm = *i;
if(norm.Norm() < 0.00001) continue;
norm.Normalize();
scaledNormal += norm;
count++;
}
scaledNormal /= count;
float len = scaledNormal.Norm();
if(len == 0) return;
scaledNormal /= len;
int distr[50];
for(int k = 0; k < 50; k++)
distr[k] =0;
for(i = normal.begin(); i != normal.end(); i++) {
int pos = (int)(50.0 * Angle(scaledNormal, *i)/M_PI);
distr[pos]++;
}
int tot = 0;
int best;
for(best = 0; best < 50; best++) {
tot += distr[best];
if(tot >= threshold * normal.size())
break;
}
double alpha = M_PI * (best +1) / 50;
if(alpha >= M_PI/ 2 - 0.1) {
scaledNormal = Point3f(0,0,0);
} else {
scaledNormal /= cos(M_PI/2 - alpha);
}
}
void ANCone3f::AddAnchors(vector<Point3f> &anchors) {
assert(anchors.size() > 0);
frontAnchor = anchors[0];
backAnchor = anchors[0];
float fa = frontAnchor * scaledNormal;
float fb = -backAnchor * scaledNormal;
vector<Point3f>::iterator i;
for(i = anchors.begin(); i != anchors.end(); i++) {
Point3f &anchor = *i;
float na = anchor * scaledNormal;
if(na < fa) {
frontAnchor = anchor;
fa = na;
}
if(-na < fb) {
backAnchor = anchor;
fb = -na;
}
}
}
void NCone3s::Import(const ANCone3f &c) {
Point3f normal = c.scaledNormal;
float len = normal.Norm();
if(len != 0)
normal /= len;
for(int i = 0; i < 3; i++) {
assert(normal[i] < 1.01 && normal[i] > -1.01);
if(normal[i] > 1.0f) normal[i] = 1;
if(normal[i] < -1.0f) normal[i] = -1;
}
n[0] = (short)(normal[0] * 32766);
n[1] = (short)(normal[1] * 32766);
n[2] = (short)(normal[2] * 32766);
//i want to rapresent number from 1 to 10
if(len > 10.0f) len = 10.0f;
if(len < -10.0f) len = -10.0f;
n[3] = (short)(len * 3276);
}
bool NCone3s::Backface(const vcg::Sphere3f &sphere,
const vcg::Point3f &view) const {
vcg::Point3f norm(n[0]/32766.0f, n[1]/32766.0f, n[2]/32766.0f);
vcg::Point3f d = (sphere.Center() - norm * sphere.Radius()) - view;
norm *= n[3]/3276.0f;
float f = d * norm;
if (f < 0.001 || f * f < d * d)
return false;
return true;
}
bool NCone3s::Frontface(const vcg::Sphere3f &sphere,
const vcg::Point3f &view) const {
vcg::Point3f norm(n[0]/32766.0f, n[1]/32766.0f, n[2]/32766.0f);
vcg::Point3f d = (sphere.Center() + norm * sphere.Radius()) - view;
norm *= n[3]/3276.0f;
float f = -d * norm;
if (f < 0.001 || f * f < d * d)
return false;
return true;
}

View File

@ -1,53 +0,0 @@
#ifndef NXS_NORMALS_CONE_H
#define NXS_NORMALS_CONE_H
#include <vector>
#include <vcg/space/point3.h>
#include <vcg/space/sphere3.h>
namespace nxs {
//anchored normal cone.
class ANCone3f {
public:
ANCone3f();
bool Frontface(const vcg::Point3f &viewPoint);
bool Backface(const vcg::Point3f &viewPoint);
//threshold [0, 1]: percentage of normals to left out
void AddNormals(std::vector<vcg::Point3f> &normals,
float threshold = 1.0f);
void AddNormals(std::vector<vcg::Point3f> &normals,
std::vector<float> &areas,
float threshold = 1.0f);
void AddAnchors(std::vector<vcg::Point3f> &anchors);
protected:
vcg::Point3f scaledNormal;
vcg::Point3f frontAnchor;
vcg::Point3f backAnchor;
friend class NCone3s;
};
//this is not anchored... need a bounding sphere to report something
class NCone3s {
public:
void Import(const ANCone3f &c);
bool Backface(const vcg::Sphere3f &sphere,
const vcg::Point3f &view) const;
bool Frontface(const vcg::Sphere3f &sphere,
const vcg::Point3f &view) const;
//encode normal and sin(alpha) in n[3]
short n[4];
};
}
#endif

View File

@ -1,72 +0,0 @@
// mesh definition
#include <vcg/simplex/vertex/with/afvn.h>
#include <vcg/simplex/face/with/af.h>
#include <vcg/complex/trimesh/base.h>
#include <vcg/complex/trimesh/update/normal.h>
// input output
#include <wrap/io_trimesh/import_ply.h>
#include <wrap/io_trimesh/export_ply.h>
#include "nxsexport.h"
#include "extraction.h"
#include "metric.h"
using namespace vcg;
using namespace nxs;
struct MyFace;
struct MyTetra;
struct MyEdge;
struct MyVertex: public VertexAFVNf<MyEdge,MyFace,MyTetra>{};
struct MyFace: public FaceAF<MyVertex,MyEdge,MyFace>{};
struct MyMesh: public tri::TriMesh< vector<MyVertex>, vector<MyFace> >{};
int main(int argc, char *argv[]) {
string input;
string output;
float target_error = 0;
int option;
while((option = getopt(argc, argv, "e:")) != EOF) {
switch(option) {
case 'e': target_error = atof(optarg); break;
case 'o': output = optarg; break;
}
}
if(optind != argc -1) {
cerr << "Usage: " << argv[0] << " <nexus> [options]\n"
<< " -e <float> : extraction target error\n"
<< " -o <file.ply>: output name\n\n";
return -1;
}
input = argv[optind];
if(!output.size()) output = input + ".ply";
Nexus nexus;
if(!nexus.Load(input.c_str())) {
cerr << "Could not open file: " << input.c_str() << ".nxs\n";
return -1;
}
Extraction extr;
extr.SetMetric(new FlatMetric);
extr.target_error = target_error;
extr.Extract(&nexus);
vector<unsigned int> selected;
for(unsigned int i = 0; i < extr.selected.size(); i++)
selected.push_back(extr.selected[i].id);
MyMesh m;
ExportTriMesh<MyMesh>(nexus, selected, m);
//write to ply:
vcg::tri::io::PlyInfo pi;
vcg::tri::io::ExporterPLY<MyMesh>::Save(m, output.c_str(), pi.mask);
return 0;
}

View File

@ -1,796 +0,0 @@
/****************************************************************************
* VCGLib o o *
* Visual and Computer Graphics Library o o *
* _ O _ *
* Copyright(C) 2004 \/)\/ *
* Visual Computing Lab /\/| *
* ISTI - Italian National Research Council | *
* \ *
* All rights reserved. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
* for more details. *
* *
****************************************************************************/
/****************************************************************************
History
$Log: not supported by cvs2svn $
Revision 1.26 2005/03/02 10:40:18 ponchio
Extraction rewrittten (to fix recusive problems).
Revision 1.25 2005/03/01 11:21:20 ponchio
Added line intersection
Revision 1.24 2005/02/22 14:20:44 ponchio
debug and mostly vertex unifying across borders
(still not perfect... :P)
Revision 1.23 2005/02/22 10:38:10 ponchio
Debug, cleaning and optimization.
Revision 1.22 2005/02/21 17:55:36 ponchio
debug debug debug
Revision 1.21 2005/02/20 18:07:01 ponchio
cleaning.
Revision 1.20 2005/02/19 10:45:04 ponchio
Patch generalized and small fixes.
Revision 1.19 2005/02/18 13:04:12 ponchio
Added patch reordering.
Revision 1.18 2005/02/17 16:40:35 ponchio
Optimized BuildLevels.
Revision 1.17 2005/02/08 12:43:03 ponchio
Added copyright
****************************************************************************/
#include <vector>
#include <map>
#include <set>
#include <algorithm>
#include <iostream>
//#include <wrap/strip/tristrip.h>
#include "nxsalgo.h"
#include "extraction.h"
#include "vpartition.h"
#include "vfile.h"
#include "nexus.h"
#include "zcurve.h"
#include "watch.h"
#include <vcg/space/line3.h>
#include <vcg/space/intersection3.h>
using namespace std;
using namespace nxs;
using namespace vcg;
void nxs::Connect(Nexus &nexus, std::vector< set<unsigned int> > &close,
float threshold) {
VPartition grid;
float max_radius = 0;
for(unsigned int patch = 0; patch < nexus.size(); patch++) {
Sphere3f &sphere = nexus[patch].sphere;
grid.push_back(sphere.Center());
float r = sphere.Radius();
if(r > max_radius) max_radius = r;
}
grid.Init();
close.clear();
close.resize(nexus.size());
vector<int> targets;
vector<double> dists;
for(unsigned int patch = 0; patch < nexus.size(); patch++) {
float radius = nexus[patch].sphere.Radius();
float max_distance = radius + max_radius + threshold;
max_distance *= max_distance;
grid.Closest(grid[patch], targets, dists, max_distance);
for(unsigned int i = 0; i < targets.size(); i++) {
unsigned int target = targets[i];
if(target == patch) continue;
float dist = radius + nexus[target].sphere.Radius() + threshold;
dist *= dist;
if(dist >= dists[i]) {
close[patch].insert(target);
}
}
}
//DOUBLECROSS CHECK
for(unsigned int patch = 0; patch < nexus.size(); patch++) {
set<unsigned int>::iterator i;
for(i = close[patch].begin(); i != close[patch].end(); i++) {
if(!close[*i].count(patch)) {
cerr << "Some problem width sphere intersection. Have alook.\n";
cerr << "Meanwhile i fix it.\n";
close[*i].insert(patch);
}
}
}
}
void nxs::ComputeNormals(Nexus &nexus) {
assert(nexus.signature.vnorm);
assert(!nexus.borders.IsReadOnly());
//first calculate level 0 normals
//I load all patches in a fragment
//calculate normals
//fix external borders getting from level below
//first try naive approach just load neighborough get normals and
//fix border with lower level
vector<int> levels;
nexus.history.BuildLevels(levels);
Report report(nexus.size(), 15);
//TODO check level 0 is the finer one
int current_level = 0;
while(1) {
int count = 0;
for(unsigned int p = 0; p < nexus.size(); p++) {
if(levels[p] != current_level) continue;
count++;
report.Step(p);
Border &border = nexus.GetBorder(p);
map<unsigned int, vector<Point3f> > normals;
normals[p] = vector<Point3f>();
for(unsigned int i = 0; i < border.Size(); i++) {
Link &link = border[i];
if(levels[link.end_patch] == current_level)
normals[link.end_patch] = vector<Point3f>();
}
map<unsigned int, vector<Point3f> >::iterator k;
for(k = normals.begin(); k != normals.end(); k++) {
Patch &patch = nexus.GetPatch((*k).first);
vector<Point3f> &normal = (*k).second;
normal.resize(patch.nv, Point3f(0, 0, 0));
if(nexus.signature.face == Signature::TRIANGLES) {
for(unsigned int i = 0; i < patch.nf; i++) {
unsigned short *f = patch.Face(i);
Point3f &v0 = patch.Vert3f(f[0]);
Point3f &v1 = patch.Vert3f(f[1]);
Point3f &v2 = patch.Vert3f(f[2]);
Point3f a = (v1 - v0);
Point3f b = (v2 - v0);
float n = a.Norm() * b.Norm();
if(n == 0) continue;
Point3f norm = a^b;
float rn = norm.Norm();
norm *= asin(rn/n)/n;
normal[f[0]] += norm;
normal[f[1]] += norm;
normal[f[2]] += norm;
}
} else if(nexus.signature.face == Signature::STRIPS) {
for(int i = 0; i < patch.nf - 2; i++) {
unsigned short *f = patch.FaceBegin() + i;
Point3f &v0 = patch.Vert3f(f[0]);
Point3f &v1 = patch.Vert3f(f[1]);
Point3f &v2 = patch.Vert3f(f[2]);
Point3f a = (v1 - v0);
Point3f b = (v2 - v0);
float n = a.Norm() * b.Norm();
if(n == 0) continue;
Point3f norm = a^b;
float rn = norm.Norm();
norm *= asin(rn/n)/n;
if(i%2) norm = -norm;
normal[f[0]] += norm;
normal[f[1]] += norm;
normal[f[2]] += norm;
}
} else
assert(0);
}
//now fix borders
map<unsigned int, vector<Link> > lowers;
for(unsigned int i = 0; i < border.Size(); i++) {
Link &link = border[i];
if(levels[link.end_patch] == current_level) {
//TODO remove these asserts
assert(normals[p].size() > link.start_vert);
assert(normals.count(link.end_patch));
assert(normals[link.end_patch].size() > link.end_vert);
normals[p][link.start_vert] += normals[link.end_patch][link.end_vert];
} else if (levels[link.end_patch] < current_level) {
lowers[link.end_patch].push_back(link);
}
}
map<unsigned int, vector<Link> >::iterator s;
for(s = lowers.begin(); s != lowers.end(); s++) {
Patch &patch = nexus.GetPatch((*s).first);
for(unsigned int i = 0; i < (*s).second.size(); i++) {
Link &link = (*s).second[i];
if(nexus.signature.vnorm == Encodings::FLOAT3)
normals[p][link.start_vert] =
((Point3f *)patch.VNormBegin())[link.end_vert];
else if(nexus.signature.vnorm == Encodings::SHORT4) {
Point3f &nor = normals[p][link.start_vert];
short *n = ((short *)patch.VNormBegin()) + 4*link.end_vert;
nor[0] = n[0];
nor[1] = n[1];
nor[2] = n[2];
}
}
}
//copy and normalize
Patch &patch = nexus.GetPatch(p);
Entry &entry = nexus[p];
Point3f *norm = (Point3f *)patch.VNormBegin();
vector<Point3f> &newnormals = normals[p];
assert(newnormals.size() == patch.nv);
for(unsigned int i = 0; i < patch.nv; i++) {
newnormals[i].Normalize();
if(nexus.signature.vnorm == Encodings::SHORT4) {
newnormals[i] *= 32766;
short *np = ((short *)norm) + 4 * i;
np[0] = (short)newnormals[i][0];
np[1] = (short)newnormals[i][1];
np[2] = (short)newnormals[i][2];
np[3] = 0;
} else if(nexus.signature.vnorm == Encodings::FLOAT3)
norm[i] = newnormals[i];
}
}
if(count == 0) break;
current_level++;
}
}
/*void nxs::ComputeNormals(Nexus &nexus) {
assert(nexus.signature.vnorm);
//setting borders readonly:
assert(!nexus.borders.IsReadOnly());
nexus.borders.SetReadOnly(true);
//TODO use a temporary file to store border normals
unsigned int tmpb_offset = 0;
vector<unsigned int> tmpb_start;
VFile<Point3f> tmpb;
if(!tmpb.Create("tmpb.tmp")) {
cerr << "Could not create temporary border file\n";
exit(0);
}
for(unsigned int p = 0; p < nexus.size(); p++) {
Border &border = nexus.borders[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;
tmpb.Flush();
vector<int> levels;
nexus.history.BuildLevels(levels);
//first step normals in the same patch.
cerr << "First Step\n";
Report report(nexus.size(), 5);
vector<Point3f> normals;
for(unsigned int p = 0; p < nexus.size(); p++) {
int current_level = levels[p];
report.Step(p);
Patch &patch = nexus.GetPatch(p);
normals.clear();
normals.resize(patch.nv, Point3f(0, 0, 0));
if(nexus.signature.face == Signature::TRIANGLES)
for(unsigned int i = 0; i < patch.nf; i++) {
unsigned short *f = patch.Face(i);
Point3f &v0 = patch.Vert3f(f[0]);
Point3f &v1 = patch.Vert3f(f[1]);
Point3f &v2 = patch.Vert3f(f[2]);
Point3f norm = (v1 - v0) ^ (v2 - v0);
normals[f[0]] += norm;
normals[f[1]] += norm;
normals[f[2]] += norm;
}
if(nexus.signature.face == Signature::STRIPS)
for(int i = 0; i < patch.nf - 2; i++) {
unsigned short *f = patch.FaceBegin() + i;
Point3f &v0 = patch.Vert3f(f[0]);
Point3f &v1 = patch.Vert3f(f[1]);
Point3f &v2 = patch.Vert3f(f[2]);
Point3f norm = (v1 - v0) ^ (v2 - v0);
if(i%2) norm = -norm;
normals[f[0]] += norm;
normals[f[1]] += norm;
normals[f[2]] += norm;
}
if(nexus.signature.vnorm == Encodings::SHORT4) {
short *n = (short *)patch.VNormBegin();
for(unsigned int i = 0; i < patch.nv; i++, n += 4) {
Point3f &norm = normals[i];
norm.Normalize();
for(int k = 0; k < 3; k++)
n[k] = (short)(norm[k] * 32766);
n[3] = 0;
}
} else if(nexus.signature.vnorm == Encodings::FLOAT3) {
Point3f *n = (Point3f *)patch.VNormBegin();
for(unsigned int i = 0; i < patch.nv; i++) {
n[i] = normals[i];
n[i].Normalize();
}
}
Border &border = nexus.GetBorder(p);
map<unsigned int, map<unsigned short, Point3f> > bnorm;
map<unsigned int, Link> bcopy;
unsigned int poff = tmpb_start[p];
for(unsigned int i = 0; i < border.Size(); i++) {
Link &link = border[i];
if(link.IsNull()) continue; //this should never happen now.
Point3f pt = normals[link.start_vert];
if(levels[link.end_patch] == current_level) {
bnorm[link.end_patch][link.end_vert] = pt;
tmpb[poff + i] += pt;
} else if(levels[link.end_patch] > current_level) {
bcopy[i] = link;
}
}
map<unsigned int, map<unsigned short, Point3f> >::iterator k;
for(k = bnorm.begin(); k != bnorm.end(); k++) {
unsigned int patch = (*k).first;
Border &rborder = nexus.GetBorder(patch);
unsigned int offset = tmpb_start[patch];
for(unsigned int i = 0; i < rborder.Size(); i++) {
Link &link = rborder[i];
//assert(!link.IsNull());
//TODO not accurate
if(link.end_patch != p) continue;
if((*k).second.count(link.start_vert))
tmpb[offset + i] += (*k).second[link.start_vert];
}
}
//Uncomment this only when links are ok!
map<unsigned int, Link>::iterator j;
for(j = bcopy.begin(); j != bcopy.end(); j++) {
unsigned int b = (*j).first;
Link link = (*j).second;
Border &rborder = nexus.GetBorder(link.end_patch, false);
unsigned int offset = tmpb_start[link.end_patch];
for(unsigned int i = 0; i < rborder.Size(); i++) {
Link &rlink = rborder[i];
if(rlink.end_patch == p && rlink.start_vert == link.end_vert) {
assert(rlink.end_vert == link.start_vert);
tmpb[poff + b] = tmpb[offset + i];
}
}
}
}
//Second step unify normals across borders
cerr << "Second step\n";
report.Init(nexus.size());
for(unsigned int p = 0; p < nexus.size(); p++) {
report.Step(p);
Patch &patch = nexus.GetPatch(p);
Border &border = nexus.GetBorder(p);
Point3f *normf = (Point3f *)patch.VNormBegin();
short *norms = (short *)patch.VNormBegin();
for(unsigned int i = 0; i < border.Size(); i++) {
Link &link = border[i];
if(link.IsNull()) continue;
unsigned int off = tmpb_start[p];
// Point3f &n = tmpb[off + i];
Point3f n = tmpb[off + i];
if(n == Point3f(0.0f,0.0f,0.0f)) continue;
n.Normalize();
if(nexus.signature.vnorm == Encodings::SHORT4) {
n *= 32766;
short *np = norms + 4 * link.start_vert;
np[0] = (short)n[0];
np[1] = (short)n[1];
np[2] = (short)n[2];
np[3] = 0;
} else if(nexus.signature.vnorm == Encodings::FLOAT3) {
normf[link.start_vert] = n;
}
}
}
tmpb.Close();
tmpb.Delete();
//TODO remove temporary file.
nexus.borders.SetReadOnly(false);
}*/
/*
//TODO why i created this function? wonder...void nxs::Reorder(Signature &signature, Patch &patch) {
vector<unsigned> remap;
remap.resize(patch.nv, 0xffff);
int nf = patch.nf;
if(signature.face == Signature::TRIANGLES)
nf *= 3;
else if(signature.face != Signature::STRIPS) {
assert(0); //mah...
}
//building remap
unsigned short *f = patch.FaceBegin();
unsigned int count = 0;
for(int i = 0; i < nf; i++) {
assert(f[i] < remap.size());
if(remap[f[i]] == 0xffff) {
remap[f[i]] = count++;
}
}
//test no unreferenced vertices
for(int i = 0; i < patch.nv; i++)
if(remap[i] == 0xffff)
remap[i] = i;
//converting faces
for(int i = 0; i < nf; i++)
f[i] = remap[f[i]];
vector<Point3f> vert;
vert.resize(patch.nv);
memcpy(&*vert.begin(), patch.Vert3fBegin(), patch.nv * sizeof(Point3f));
for(int i = 0; i < patch.nv; i++)
patch.Vert3f(remap[i]) = vert[i];
}*/
//TODO actually use threshold
void nxs::Unify(vector<Point3f> &points, vector<unsigned short> &faces,
vector<unsigned int> &remap, float threshold) {
vector<unsigned short> newfaces = faces;
VPartition grid;
for(unsigned int i = 0; i < points.size(); i++)
grid.push_back(points[i]);
grid.Init();
remap.resize(points.size());
vector<int> targets;
vector<double> dists;
points.clear();
unsigned int count = 0;
for(unsigned int i = 0; i < grid.size(); i++) {
grid.Closest(grid[i], targets, dists, threshold);
if(targets.size() > 1) {
unsigned int p;
for(p = 0; p < targets.size(); p++) {
if(targets[p] < i) {
remap[i] = remap[targets[p]];
break;
}
}
if(p < targets.size()) continue;
}
remap[i] = count++;
points.push_back(grid[i]);
}
//fixing faces now
faces.clear();
for(unsigned int i = 0; i < newfaces.size(); i += 3) {
unsigned short f[3];
f[0] = remap[newfaces[i]];
f[1] = remap[newfaces[i+1]];
f[2] = remap[newfaces[i+2]];
if(f[0] == f[1] || f[0] == f[2] || f[1] == f[2])
continue;
for(int k = 0; k < 3; k++)
faces.push_back(f[k]);
}
}
/*void nxs::Unify(Nexus &nexus, float threshold) {
threshold = 0.00001;
unsigned int duplicated = 0;
unsigned int degenerate = 0;
for(unsigned int p = 0; p < nexus.size(); p++) {
if(levels[p] != current_level) continue;
count++;
report.Step(p);
Border &border = nexus.GetBorder(p);
map<unsigned int, vector<Point3f> > normals;
normals[p] = vector<Point3f>();
for(unsigned int i = 0; i < border.Size(); i++) {
Link &link = border[i];
if(levels[link.end_patch] == current_level)
normals[link.end_patch] = vector<Point3f>();
}
map<unsigned int, vector<Point3f> >::iterator k;
for(k = normals.begin(); k != normals.end(); k++) {
Patch &patch = nexus.GetPatch((*k).first);
}
}
}*/
/*
void nxs::Unify(Nexus &nexus, float threshold) {
threshold = 0.001;
//TODO what if colors or normals or strips?
unsigned int duplicated = 0;
unsigned int degenerate = 0;
for(unsigned int p = 0; p < nexus.size(); p++) {
Entry &entry = nexus[p];
Patch &patch = nexus.GetPatch(p);
VPartition part;
for(unsigned int i = 0; i < patch.nv; i++) {
Point3f &point = patch.Vert3f(i);
part.push_back(point);
}
part.Init();
unsigned int vcount = 0;
vector<unsigned short> remap;
remap.resize(patch.nv);
int targets[8];
double dists[8];
//TODO CRITICAL FIX this unifying routine.
for(unsigned int i = 0; i < patch.nv; i++) {
Point3f &point = patch.Vert3f(i);
part.Closest(point, 8, targets, dists);
int k = 0;
for(k = 0; k < 8; k++) {
if(dists[k] > threshold) {
remap[i] = vcount++;
break;
}
if(targets[k] < i) {
remap[i] = remap[targets[k]];
duplicated++;
break;
}
}
if(k == 8)
remap[i] = vcount++;
}
if(vcount == patch.nv) //no need to unify
continue;
vector<Point3f> newvert;
newvert.resize(vcount);
for(unsigned int i = 0; i < patch.nv; i++)
newvert[remap[i]] = patch.Vert3f(i);
vector<unsigned short> newface;
//check no degenerate faces get created.
for(unsigned int f = 0; f < entry.nface; f++) {
unsigned short *face = patch.Face(f);
if(face[0] != face[1] && face[1] != face[2] && face[0] != face[2] &&
newvert[remap[face[0]]] != newvert[remap[face[1]]] &&
newvert[remap[face[0]]] != newvert[remap[face[2]]] &&
newvert[remap[face[1]]] != newvert[remap[face[2]]]) {
newface.push_back(remap[face[0]]);
newface.push_back(remap[face[1]]);
newface.push_back(remap[face[2]]);
} else {
degenerate++;
}
}
//rewrite patch now.
entry.nvert = newvert.size();
entry.nface = newface.size()/3;
patch.Init(nexus.signature, entry.nvert, entry.nface);
memcpy(patch.Vert3fBegin(), &(newvert[0]), entry.nvert*sizeof(Point3f));
memcpy(patch.FaceBegin(), &(newface[0]), entry.nface*3*sizeof(short));
//testiamo il tutto... TODO remove this of course
#ifdef NDEBUG
for(unsigned int i =0; i < patch.nf; i++) {
for(int k =0 ; k < 3; k++)
if(patch.Face(i)[k] >= patch.nv) {
cerr <<" Unify has problems\n";
exit(0);
}
}
#endif
//TODO CRITICAL FIX unify vertices across borders..... HOW??????
//fix patch borders now
set<unsigned int> close; //bordering pathes
Border &border = nexus.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 = nexus.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];
}
}
}
}
//better to compact directly borders than setting them null.
//finally: there may be duplicated borders
for(unsigned int p = 0; p < nexus.size(); p++) {
Border &border = nexus.GetBorder(p);
set<Link> links;
for(unsigned int b = 0; b < border.Size(); b++) {
Link &link = border[b];
assert(!link.IsNull());
//if(border[b].IsNull()) continue;
links.insert(link);
}
int count = 0;
for(set<Link>::iterator k = links.begin(); k != links.end(); k++)
border[count++] = *k;
nexus.borders[p].used = links.size();
}
nexus.totvert -= duplicated;
if(duplicated)
cerr << "Found " << duplicated << " duplicated vertices" << endl;
if(degenerate)
cerr << "Found " << degenerate << " degenerate face while unmifying\n";
}
*/
void nxs::ZSort(Nexus &nexus, vector<unsigned int> &forward,
vector<unsigned int> &backward) {
//lets get a bounding box from the sphere:
ZCurve zcurve;
float r = nexus.sphere.Radius();
Point3f radius(r, r, r);
zcurve.Set(nexus.sphere.Center());
zcurve.Add(nexus.sphere.Center() - radius);
zcurve.Add(nexus.sphere.Center() + radius);
vector<int> levels;
nexus.history.BuildLevels(levels);
forward.clear();
vector< vector<ZEntry> > entries;
for(unsigned int i = 0; i < nexus.size(); i++) {
int level = levels[i];
while(level >= entries.size()) entries.push_back(vector<ZEntry>());
ZEntry e;
e.id = i;
e.pos = zcurve.Pos(nexus[i].sphere.Center());
entries[level].push_back(e);
}
for(unsigned int i = 0; i < entries.size(); i++) {
vector<ZEntry> &lev = entries[i];
std::sort(lev.begin(), lev.end());
for(unsigned int k = 0; k < lev.size(); k++)
forward.push_back(lev[k].id);
}
backward.resize(forward.size());
for(unsigned int i = 0; i < backward.size(); i++)
backward[forward[i]] = i;
}
bool nxs::LineIntersect(Nexus &nexus, Extraction &extraction,
Line3f line, Point3f &hit) {
//seguiamo la history;
Point3f tmp;
if(!Intersection(nexus.sphere, line, hit, tmp))
return false;
bool found = false;
float min_dist = -1;
float bar1, bar2, dist;
for(unsigned int i = 0; i < extraction.draw_size; i++) {
unsigned int p = extraction.selected[i].id;
if(!Intersection(nexus[p].sphere, line, hit, tmp))
continue;
Patch &patch = nexus.GetPatch(p);
if(nexus.signature.face == Signature::TRIANGLES) {
for(unsigned int i = 0; i < patch.nf; i++) {
unsigned short *f = patch.Face(i);
Point3f &v0 = patch.Vert3f(f[0]);
Point3f &v1 = patch.Vert3f(f[1]);
Point3f &v2 = patch.Vert3f(f[2]);
if(Intersection(line, v0, v1, v2, bar1, bar2, dist) &&
dist > 0 &&
(min_dist == -1 || min_dist > dist)) {
hit = v0*(1-bar1-bar2) + v1*bar1 + v2*bar2;
min_dist = dist;
found = true;
}
}
} else if(nexus.signature.face == Signature::STRIPS) {
for(int i = 0; i < patch.nf - 2; i++) {
unsigned short *f = patch.FaceBegin() + i;
Point3f &v0 = patch.Vert3f(f[0]);
Point3f &v1 = patch.Vert3f(f[1]);
Point3f &v2 = patch.Vert3f(f[2]);
if(Intersection(line, v0, v1, v2, bar1, bar2, dist) &&
dist > 0 &&
(min_dist == -1 || min_dist > dist)) {
hit = v0*(1-bar1-bar2) + v1*bar1 + v2*bar2;
min_dist = dist;
found = true;
}
}
} else
assert(0);
}
return found;
}

View File

@ -1,93 +0,0 @@
/****************************************************************************
* VCGLib o o *
* Visual and Computer Graphics Library o o *
* _ O _ *
* Copyright(C) 2004 \/)\/ *
* Visual Computing Lab /\/| *
* ISTI - Italian National Research Council | *
* \ *
* All rights reserved. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
* for more details. *
* *
****************************************************************************/
/****************************************************************************
History
$Log: not supported by cvs2svn $
Revision 1.11 2005/03/01 11:21:20 ponchio
Added line intersection
Revision 1.10 2005/02/22 14:20:44 ponchio
debug and mostly vertex unifying across borders
(still not perfect... :P)
Revision 1.9 2005/02/22 10:38:11 ponchio
Debug, cleaning and optimization.
Revision 1.8 2005/02/21 17:55:36 ponchio
debug debug debug
Revision 1.7 2005/02/20 18:07:01 ponchio
cleaning.
Revision 1.6 2005/02/19 10:45:04 ponchio
Patch generalized and small fixes.
Revision 1.5 2005/02/18 13:04:13 ponchio
Added patch reordering.
Revision 1.4 2005/02/08 12:43:03 ponchio
Added copyright
****************************************************************************/
#ifndef NXS_ALGO_H
#define NXS_ALGO_H
#include <set>
#include <vector>
#include "patch.h"
#include <vcg/space/sphere3.h>
#include <vcg/space/line3.h>
namespace nxs {
class Nexus;
class Patch;
class Extraction;
struct ZEntry {
unsigned int id;
unsigned int pos;
bool operator<(const ZEntry &e) const { return pos < e.pos; }
};
//for every patch return close by (sphere intersecting) //threshold is added to the distance to make sure we do not miss anything
void Connect(Nexus &nexus, std::vector< std::set<unsigned int> > &close,
float threshold);
void ComputeNormals(Nexus &nexus);
void Unify(std::vector<vcg::Point3f> &points,
std::vector<unsigned short> &faces,
std::vector<unsigned int> &vremap, float threshold);
void ZSort(Nexus &nexus, std::vector<unsigned int> &forward,
std::vector<unsigned int> &backward);
bool LineIntersect(Nexus &nexus, Extraction &extraction,
vcg::Line3f line, vcg::Point3f &hit);
}
#endif

View File

@ -1,972 +0,0 @@
/****************************************************************************
* VCGLib o o *
* Visual and Computer Graphics Library o o *
* _ O _ *
* Copyright(C) 2004 \/)\/ *
* Visual Computing Lab /\/| *
* ISTI - Italian National Research Council | *
* \ *
* All rights reserved. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
* for more details. *
* *
****************************************************************************/
/****************************************************************************
History
$Log: not supported by cvs2svn $
Revision 1.22 2005/02/22 14:20:44 ponchio
debug and mostly vertex unifying across borders
(still not perfect... :P)
Revision 1.21 2005/02/22 10:38:11 ponchio
Debug, cleaning and optimization.
Revision 1.20 2005/02/21 17:55:47 ponchio
debug debug debug
Revision 1.19 2005/02/20 18:07:01 ponchio
cleaning.
Revision 1.18 2005/02/20 00:43:24 ponchio
Less memory x extraction. (removed frags)
Revision 1.17 2005/02/19 17:14:02 ponchio
History quick by default.
Revision 1.16 2005/02/19 10:45:04 ponchio
Patch generalized and small fixes.
Revision 1.15 2005/02/14 15:17:36 ponchio
Cleaning up.
Revision 1.14 2005/01/21 17:09:13 ponchio
Porting and debug.
Revision 1.13 2005/01/17 17:35:48 ponchio
Small changes and adding realtime extr.
Revision 1.12 2005/01/14 15:25:29 ponchio
Revolution.
Revision 1.11 2004/12/13 00:44:48 ponchio
Lotsa changes...
Revision 1.10 2004/12/09 22:33:28 ponchio
Different splitting optimization.
Revision 1.9 2004/12/04 13:22:55 ponchio
*** empty log message ***
Revision 1.8 2004/12/03 21:19:00 ponchio
Fixed a couple of memory leak...
Revision 1.7 2004/12/03 01:20:56 ponchio
Debug
Revision 1.6 2004/12/02 20:22:42 ponchio
Level 5;
Revision 1.5 2004/12/02 19:10:18 ponchio
Bounding sphere fix.
Revision 1.4 2004/12/01 16:00:35 ponchio
Level 3
Revision 1.3 2004/12/01 03:32:46 ponchio
Level 2 (debug).
Revision 1.2 2004/12/01 03:24:32 ponchio
Level 2.
Revision 1.1 2004/12/01 01:15:03 ponchio
Level 0.
Revision 1.26 2004/11/30 22:49:39 ponchio
Level 0.
****************************************************************************/
#ifdef WIN32
#include <wrap/system/getopt.h>
#else
#include <unistd.h>
#endif
#ifdef WIN32
#include <hash_map>
#endif
#include <iostream>
#include "nxstypes.h"
#include "crude.h"
#include "remapping.h"
#include "decimate.h"
#include "fragment.h"
#include "nxsalgo.h"
#include "nxsdispatcher.h"
#include "watch.h"
#include "nexus.h"
using namespace std;
using namespace vcg;
using namespace nxs;
void BuildFragment(Nexus &nexus, VPartition &part,
set<unsigned int> &patches,
Fragment &fragment);
void SaveFragment(Nexus &nexus, VChain &chain,
Fragment &fragin,
Fragment &fragout);
void ReverseHistory(vector<History::Update> &history);
unsigned int current_level;
vector<unsigned int> patch_levels;
void usage() {
cerr << "Usage: voronoinxs <crude> <output> [options]\n"
" Options:\n"
" -f N: use N faces per patch (default 1000, max 32000)\n"
" -t N: mini faces per patch (default 200)\n"
" -l N: number of levels\n"
" -s F: scaling factor (0 < F < 1, default 0.5)\n"
" -o N: number of optimization steps\n"
" -d <method>: decimation method: quadric, cluster. (default quadric)\n"
" -b N: ram buffer size (in bytes)\n"
" -p N: which fase perform:\n"
" 0) Remap faces\n"
" 1) Sort faces\n"
" 2) Build patches\n"
" 3) Build borders\n"
" 4) Build levels\n\n"
" If you use the step option, all other parameters MUST stay the same\n\n";
}
void FirstStep(const string &crudefile, const string &output,
unsigned int patch_size, unsigned int patch_threshold,
float scaling, unsigned int optimization_steps) {
Crude crude;
if(!crude.Load(crudefile, true)) {
cerr << "Could not open crude input: " << crudefile << endl;
exit(0);
}
if(patch_size > crude.vert.Size()/2) {
cerr << "Patch size too big: " << patch_size << " * 2 > "
<< crude.vert.Size() << endl;
exit(0);
}
if(patch_threshold == 0xffffffff)
patch_threshold = patch_size/4;
VChain vchain;
VFile<unsigned int> face_remap;
if(!face_remap.Create(output + ".rfm")) {
cerr << "Could not create remap files: " << output << ".rmf\n";
exit(0);
}
face_remap.Resize(crude.Faces());
VFile<Point3f> baricenters;
if(!baricenters.Create(output + ".bvr")) {
cerr << "Could not create temporary baricenters file\n";
exit(0);
}
baricenters.Resize(crude.Faces());
for(unsigned int i = 0; i < crude.Faces(); i++) {
baricenters[i] = crude.GetBari(i);
}
BlockIndex face_index;
Remap(vchain, baricenters, face_remap, face_index,
patch_size, patch_threshold, 65000, scaling,
optimization_steps);
if(!vchain.Save(output + ".vchain")) {
cerr << "Could not save file: " << output << ".vchain\n";
exit(0);
}
if(!face_index.Save(output + ".rfi")) {
cerr << "Could not save file: " << output << ".rmi\n";
exit(0);
}
baricenters.Delete();
}
void SecondStep(const string &crudefile, const string &output) {
Crude crude;
if(!crude.Load(crudefile, true)) {
cerr << "Could not open crude input: " << crudefile << endl;
exit(0);
}
VFile<unsigned int> face_remap;
if(!face_remap.Load(output + ".rfm", true)) {
cerr << "Could not load: " << output << ".rmf\n;";
exit(0);
}
assert(face_remap.Size() == crude.Faces());
VFile<Crude::Face> sorted;
if(!sorted.Create(output + ".faces")) {
cerr << "Could not create sorted faces\n";
exit(0);
}
sorted.Resize(face_remap.Size());
BlockIndex face_index;
if(!face_index.Load(output + ".rfi")) {
cerr << "Could not load index\n";
exit(0);
}
//Sorting now.
vector<unsigned int> done;
done.resize(face_index.size(), 0);
for(unsigned int i = 0; i < face_remap.Size(); i++) {
unsigned int patch = face_remap[i];
assert(patch < face_index.size());
int64 offset = face_index[patch].offset + done[patch]++;
sorted[offset] = crude.GetFace(i);
}
//once sorted
crude.Close();
sorted.Close();
/* TODO fix this (after debug!)
WARNING what if multiple files?
if(0 != unlink((crudefile + ".crf").c_str())) {
cerr << "Could not remove " << crudefile << ".crf\n";
exit(0);
}
if(0 != rename((output + ".faces").c_str(), (crudefile + ".crf").c_str())) {
cerr << "Could not rename to: " << crudefile + ".crf\n";
exit(0);
}
face_remap.Close(); */
//TODO remove the file... (after finishing debug!)
// face_remap.Delete();
}
void ThirdStep(const string &crudefile, const string &output,
unsigned int chunk_size) {
cerr << "Third step!\n";
Crude crude;
if(!crude.Load(crudefile, true)) {
cerr << "Could not open crude input: " << crudefile << endl;
exit(0);
}
VFile<Crude::Face> sorted;
if(!sorted.Load(crudefile + ".faces", true)) {
cerr << "Could not load sorted faces\n";
exit(0);
}
BlockIndex face_index;
if(!face_index.Load(output + ".rfi")) {
cerr << "Could not load index\n";
exit(0);
}
VFile<unsigned int> vert_remap;
if(!vert_remap.Create(output + ".rvm")) {
cerr << "Could not create: " << output << ".rvm\n";
exit(0);
}
BlockIndex vert_index;
Nexus nexus;
//TODO here i really need no ram_buffer.....
nexus.MaxRam() = 0;
Signature signature; //default triangles and vertices3f
if(!nexus.Create(output, signature, chunk_size)) {
cerr << "Could not create nexus output: " << output << endl;
getchar();
exit(0);
}
Report report(face_index.size());
for(unsigned int patch = 0; patch < face_index.size(); patch++) {
report.Step(patch);
unsigned int vcount = 0;
unsigned int fcount = 0;
map<unsigned int, unsigned short> vremap;
vector<Point3f> vertices;
vector<unsigned short> faces;
int64 &offset = face_index[patch].offset;
unsigned int size = face_index[patch].size;
for(unsigned int i = offset; i < offset + size; i++) {
//TODO fix this after debug
Crude::Face face = sorted[i];
if(face[0] == face[1] || face[1] == face[2] || face[0] == face[2])
continue; //degenerate
for(int j = 0; j < 3; j++) {
assert(face[j] < crude.Vertices());
if(!vremap.count(face[j])) {
Point3f &v = crude.vert[face[j]];
vertices.push_back(v);
vremap[face[j]] = vcount++;
}
faces.push_back(vremap[face[j]]);
fcount++;
}
}
vector<unsigned int> remap;
nxs::Unify(vertices, faces, remap, 0.0001);
//fixing vremap
map<unsigned int, unsigned short>::iterator q;
for(q = vremap.begin(); q != vremap.end(); q++)
(*q).second = remap[(*q).second];
vcount = vertices.size();
fcount = faces.size();
//TODO deal with this case adding another patch at the end...
//its not that difficult!
//This can happen on degenerate cases when we have a lot of detached faces.
if(vcount > 65000 && fcount > 65000) {
cerr << "Too many vertices or faces in patch: " << patch
<< " v: " << vcount << " f: " << fcount << endl;
exit(0);
}
unsigned int patch_idx = nexus.AddPatch(vertices.size(),
faces.size()/3,
0); //no borders!
Patch &patch = nexus.GetPatch(patch_idx);
memcpy(patch.FaceBegin(), &*faces.begin(), fcount * sizeof(short));
memcpy(patch.Vert3fBegin(), &*vertices.begin(), vcount * sizeof(Point3f));
//Fixing sphere
Sphere3f &sphere = nexus[patch_idx].sphere;
sphere.CreateTight(vertices.size(), &*vertices.begin());
//Fixing normalscone
vector<Point3f> normals;
normals.reserve(patch.nf);
for(unsigned int i = 0; i < patch.nf; i++) {
unsigned short *f = patch.Face(i);
Point3f &v0 = patch.Vert3f(f[0]);
Point3f &v1 = patch.Vert3f(f[1]);
Point3f &v2 = patch.Vert3f(f[2]);
Point3f norm = (v1 - v0) ^ (v2 - v0);
float len = norm.Norm();
if(len == 0) {
cerr << "Degenerate face... should not be here.\n";
continue;
}
norm /= len;
#ifndef WIN32
if(isnan(norm[0]) || isnan(norm[1]) || isnan(norm[2])) {
cerr << "Invalid normal computation. Strange.\n";
continue;
}
#endif
normals.push_back(norm);
}
ANCone3f cone;
cone.AddNormals(normals, 0.99f);
nexus[patch_idx].cone.Import(cone);
//saving vert_remap
int64 vroffset = vert_remap.Size();
vert_index.push_back(BlockEntry(vroffset, vcount));
vert_remap.Resize(vroffset + vcount);
map<unsigned int, unsigned short>::iterator r;
for(r = vremap.begin(); r != vremap.end(); r++) {
assert((*r).second < vcount);
assert(vroffset + (*r).second < vert_remap.Size());
vert_remap[vroffset + (*r).second] = (*r).first;
}
if(vcount < 100) {
cerr << "Small patch: " << vcount << "\n";
}
}
//we can now update bounding sphere.
for(unsigned int i = 0; i < nexus.size(); i++)
nexus.sphere.Add(nexus[i].sphere);
History::Update update;
for(unsigned int i = 1; i < nexus.size(); i++)
update.created.push_back(i);
nexus.history.updates.push_back(update);
update.created.clear();
update.created.push_back(0);
for(unsigned int i = 1; i < nexus.size(); i++)
update.erased.push_back(i);
nexus.history.updates.push_back(update);
if(!vert_index.Save(output + ".rvi")) {
cerr << "Could not save: " << output << ".rvi\n";
exit(0);
}
nexus.Close();
}
void FourthStep(const string &crudefile, const string &output,
unsigned int ram_buffer) {
float threshold = 0.0001;
cerr << "Creating borders\n";
Nexus nexus;
if(!nexus.Load(output)) {
cerr << "Could not load nexus " << output << endl;
exit(0);
}
nexus.MaxRam() = ram_buffer / nexus.chunk_size;
VFile<unsigned int> vert_remap;
if(!vert_remap.Load(output + ".rvm", true)) {
cerr << "Could not load: " << crudefile << ".rvm\n";
exit(0);
}
BlockIndex vert_index;
if(!vert_index.Load(output + ".rvi")) {
cerr << "Could not load index\n";
exit(0);
}
vector<set<unsigned int> > close;
Connect(nexus, close, 0.0001);
Report report(nexus.size());
//WARNING this is not robust at all!!!!
//TO make all this work we should neeed to quantize
//vertex position with 2 * threshold step (at least)
for(int start = 0; start < nexus.size(); start++) {
report.Step(start);
vector<Link> links;
set<unsigned int>::iterator t;
for(t = close[start].begin(); t != close[start].end(); t++) {
unsigned int end = (*t);
Patch &pend = nexus.GetPatch(end);
VPartition grid;
for(int i = 0; i < pend.nv; i++) {
grid.push_back(pend.Vert3f(i));
}
grid.Init();
vector<int> targets;
vector<double> dists;
Patch &patch = nexus.GetPatch(start);
for(int i = 0; i < patch.nv; i++) {
grid.Closest(patch.Vert3f(i), targets, dists, threshold);
for(unsigned int k = 0; k < targets.size(); k++) {
Link link;
link.start_vert = i;
link.end_vert = targets[k];
link.end_patch = end;
links.push_back(link);
patch.Vert3f(i) = grid[targets[k]];
}
}
}
Border &border = nexus.GetBorder(start);
nexus.borders.ResizeBorder(start, 3 * links.size());
border.used = links.size();
memcpy(&(border[0]), &*links.begin(), links.size() * sizeof(Link));
}
/*old way..
for(int start = 0; start < nexus.size(); start++) {
report.Step(start);
vector<Link> links;
map<unsigned int, unsigned short> vremap;
for(unsigned int i = 0; i < vert_index[start].size; i++) {
unsigned int global = vert_remap[vert_index[start].offset + i];
vremap[global] = i;
}
set<unsigned int>::iterator t;
for(t = close[start].begin(); t != close[start].end(); t++) {
unsigned int end = (*t);
for(unsigned int i = 0; i < vert_index[end].size; i++) {
unsigned int global = vert_remap[vert_index[end].offset + i];
if(vremap.count(global)) {
Link link;
link.start_vert = vremap[global];
link.end_vert = i;
link.end_patch = end;
links.push_back(link);
}
}
}
Border &border = nexus.GetBorder(start);
nexus.borders.ResizeBorder(start, 3 * links.size());
border.used = links.size();
memcpy(&(border[0]), &*links.begin(), links.size() * sizeof(Link));
}*/
}
void FifthStep(const string &crudefile, const string &output,
unsigned int ram_buffer,
unsigned int optimization_steps,
unsigned int patch_size,
unsigned int patch_threshold,
Decimation decimation,
float scaling,
unsigned int max_level) {
Nexus nexus;
if(!nexus.Load(output)) {
cerr << "Could not load nexus " << output << endl;
exit(0);
}
nexus.MaxRam() = ram_buffer / nexus.chunk_size;
VChain vchain;
if(!vchain.Load(output + ".vchain")) {
cerr << "Could not load : " << output << ".vchain\n";
exit(0);
}
nexus.history.Clear();
History::Update update;
for(unsigned int i = 0; i < nexus.size(); i++) {
update.created.push_back(i);
patch_levels.push_back(0);
}
nexus.history.updates.push_back(update);
// Unify(nexus, 0.0f);
// nexus.Unify();
nexus.Flush();
Dispatcher dispatcher(&nexus, &vchain);
dispatcher.mode = decimation;
dispatcher.scaling = scaling;
if(!dispatcher.Init("servers.txt")) {
cerr << "Could not parse server file: " << "servers.txt"
<< " proceding locally\n";
}
unsigned int oldoffset = 0;
for(unsigned int level = 1; level < max_level; level++) {
current_level = level;
cerr << "Level: " << level << endl;
unsigned int newoffset = nexus.size();
BuildLevel(vchain, nexus, oldoffset, scaling,
patch_size, patch_threshold, 65000,
optimization_steps);
Report report(vchain.oldfragments.size());
unsigned int fcount = 0;
map<unsigned int, set<unsigned int> >::iterator fragment;
for(fragment = vchain.oldfragments.begin();
fragment != vchain.oldfragments.end(); fragment++) {
report.Step(fcount++);
Fragment *fragin = new Fragment;
BuildFragment(nexus, *vchain[level+1],
(*fragment).second, *fragin);
dispatcher.SendFragment(fragin);
/*
//this can be executed on a remote host
//TODO move this part to remote....
vector<Point3f> newvert;
vector<unsigned int> newface;
vector<BigLink> newbord;
Join(fragin, newvert, newface, newbord);
float error = Decimate(decimation,
(unsigned int)((newface.size()/3) * scaling),
newvert, newface, newbord);
Fragment fragout;
fragout.error = error;
fragout.id = fragin.id;
fragout.seeds = fragin.seeds;
fragout.seeds_id = fragin.seeds_id;
Split(fragout, newvert, newface, newbord);//, vchain.levels[level+1]);
SaveFragment(nexus, vchain, fragin, fragout);
*/
dispatcher.processmsgs();
}
//TODO porcata!!!!
while(dispatcher.frags.size()) {
// cerr << "frags: " << dispatcher.frags.size() << endl;
dispatcher.processmsgs();
}
report.Finish();
if(vchain.oldfragments.size() == 1) break;
vchain.oldfragments = vchain.newfragments;
oldoffset = newoffset;
}
//last level clean history:
update.created.clear();
update.erased.clear();
map<unsigned int, set<unsigned int> >::iterator fragment;
for(fragment = vchain.newfragments.begin();
fragment != vchain.newfragments.end(); fragment++) {
set<unsigned int> &fcells = (*fragment).second;
set<unsigned int>::iterator s;
for(s = fcells.begin(); s != fcells.end(); s++)
update.erased.push_back(*s);
}
nexus.history.updates.push_back(update);
ReverseHistory(nexus.history.updates);
nexus.borders.Flush();
if(!nexus.history.IsQuick())
nexus.history.UpdatesToQuick(nexus);
// TestBorders(nexus);
nexus.Close();
}
int main(int argc, char *argv[]) {
/* Parameters: */
unsigned int patch_size = 1000; //step 0
unsigned int patch_threshold = 0xffffffff; //Step 0
float scaling = 0.5; //step 0, 4
unsigned int optimization_steps = 5; //step 0, 4
Decimation decimation = CLUSTER; //step 4
unsigned int max_level = 0xffffffff; //step 4
unsigned int ram_buffer = 128000000; //step 2, 3, 4
unsigned int chunk_size = 1024; //step 2, 3, 4
int step = -1; //means all of them.
int option;
while((option = getopt(argc, argv, "f:t:l:s:d:o:b:c:p:")) != EOF) {
switch(option) {
case 'f': patch_size = atoi(optarg);
if(patch_size == 0 || patch_size > 32000) {
cerr << "Invalid number of faces per patch: " << optarg << endl;
return -1;
}
break;
case 't': patch_threshold = atoi(optarg);
if(patch_threshold == 0 || patch_threshold > patch_size) {
cerr << "Invalid patch threshold: " << optarg << endl;
return -1;
}
break;
case 'l': max_level = atoi(optarg);
if(max_level == 0) {
cerr << "Invalid number of levels: " << optarg << endl;
return -1;
}
break;
case 's': scaling = (float)atof(optarg);
if(scaling <= 0 || scaling >= 1) {
cerr << "Invalid scaling: " << optarg << endl;
cerr << "Must be 0 < scaling < 1" << endl;
}
break;
case 'd':
if(!strcmp("quadric", optarg))
decimation = QUADRIC;
else if(!strcmp("cluster", optarg))
decimation = CLUSTER;
else {
cerr << "Unknown decimation method: " << optarg << endl;
return -1;
}
break;
case 'o': optimization_steps = atoi(optarg); break;
case 'p': step = atoi(optarg); break;
case 'b': ram_buffer = atoi(optarg);
if(ram_buffer == 0) {
cerr << "Invalid ram buffer: " << optarg << endl;
return -1;
}
break;
case 'c': chunk_size = atoi(optarg);
if(chunk_size == 0) {
cerr << "Invalid chunk size: " << optarg << endl;
return -1;
}
break;
default: cerr << "Unknown option: " << (char)option << endl;
return -1;
}
}
if(optind != argc -2) {
usage();
return -1;
}
string crudefile = argv[optind];
string output = argv[optind+1];
if(step < 0 || step == 0)
FirstStep(crudefile, output, patch_size, patch_threshold,
scaling, optimization_steps);
if(step < 0 || step == 1)
SecondStep(crudefile, output);
if(step < 0 || step == 2)
ThirdStep(crudefile, output, chunk_size);
if(step < 0 || step == 3)
FourthStep(crudefile, output, ram_buffer);
if(step < 0 || step == 4)
FifthStep(crudefile, output,
ram_buffer,
optimization_steps,
patch_size, patch_threshold,
decimation,
scaling, max_level);
return 0;
}
void BuildFragment(Nexus &nexus, VPartition &part,
set<unsigned int> &patches,
Fragment &fragment) {
set<unsigned int>::iterator f;
for(f = patches.begin(); f != patches.end(); f++) {
fragment.pieces.push_back(NxsPatch());
NxsPatch &nxs = fragment.pieces.back();
nxs.patch = *f;
Patch &patch = nexus.GetPatch(*f);
Border &border = nexus.GetBorder(*f);
for(unsigned int k = 0; k < patch.nf; k++) {
assert(patch.FaceBegin()[3*k + 0] != patch.FaceBegin()[3*k + 1]);
assert(patch.FaceBegin()[3*k + 0] != patch.FaceBegin()[3*k + 2]);
assert(patch.FaceBegin()[3*k + 1] != patch.FaceBegin()[3*k + 2]);
}
nxs.vert.resize(patch.nv);
nxs.face.resize(patch.nf * 3);
memcpy(&*nxs.vert.begin(), patch.Vert3fBegin(), patch.nv * sizeof(Point3f));
memcpy(&*nxs.face.begin(), patch.FaceBegin(), patch.nf * 3*sizeof(short));
for(unsigned int i = 0; i < border.Size(); i++) {
Link &link = border[i];
if(!link.IsNull() &&
patch_levels[link.end_patch] == current_level-1) {
assert(link.end_patch != *f);
nxs.bord.push_back(link);
}
}
}
//TODO Use the closest with threshold here instead of a cracnut number??
set<unsigned int> seeds;
vector<int> nears;
vector<float> dists;
int nnears = 10;
if(part.size() < 10) nnears = part.size();
for(f = patches.begin(); f != patches.end(); f++) {
Point3f &center = nexus[*f].sphere.Center();
part.Closest(center, nnears, nears, dists);
for(int i = 0; i < nnears; i++)
seeds.insert(nears[i]);
}
for(f = seeds.begin(); f != seeds.end(); f++) {
Point3f &p = part[*f];
fragment.seeds.push_back(p);
fragment.seeds_id.push_back(*f);
}
}
void SaveFragment(Nexus &nexus, VChain &chain,
Fragment &fragin,
Fragment &fragout) {
set<unsigned int> orig_patches;
History::Update update;
for(unsigned int i = 0; i < fragin.pieces.size(); i++) {
NxsPatch &patch = fragin.pieces[i];
update.erased.push_back(patch.patch);
orig_patches.insert(patch.patch);
}
vector<unsigned int> patch_remap;
patch_remap.resize(fragout.pieces.size());
for(unsigned int i = 0; i < fragout.pieces.size(); i++) {
NxsPatch &patch = fragout.pieces[i];
//TODO detect best parameter below for bordersize...
unsigned int bordsize = 6 * patch.bord.size();
if(bordsize > 65500) bordsize = 65499;
unsigned int patch_idx = nexus.AddPatch(patch.vert.size(),
patch.face.size()/3,
bordsize);
patch_levels.push_back(current_level);
Entry &entry = nexus[patch_idx];
entry.error = fragout.error;
entry.sphere = patch.sphere;
entry.cone.Import(patch.cone);
patch_remap[i] = patch_idx;
chain.newfragments[patch.patch].insert(patch_idx);
update.created.push_back(patch_idx);
}
//here i put for every patch all its new links.
map<unsigned int, set<Link> > newlinks;
for(unsigned int i = 0; i < fragout.pieces.size(); i++) {
NxsPatch &outpatch = fragout.pieces[i];
unsigned int patch_idx = patch_remap[i];
for(unsigned int k = 0; k < outpatch.face.size(); k += 3) {
assert(k+2 < outpatch.face.size());
assert(outpatch.face[k] != outpatch.face[k+1]);
assert(outpatch.face[k] != outpatch.face[k+2]);
assert(outpatch.face[k+1] != outpatch.face[k+2]);
}
Patch &patch = nexus.GetPatch(patch_idx);
memcpy(patch.FaceBegin(), &outpatch.face[0],
outpatch.face.size() * sizeof(unsigned short));
memcpy(patch.Vert3fBegin(), &outpatch.vert[0],
outpatch.vert.size() * sizeof(Point3f));
Entry &entry = nexus[patch_idx];
//remap internal borders
for(unsigned int k = 0; k < outpatch.bord.size(); k++) {
Link &link = outpatch.bord[k];
if(link.end_patch >= (1<<31)) { //internal
link.end_patch = patch_remap[link.end_patch - (1<<31)];
assert(link.end_patch != patch_remap[i]);
newlinks[patch_idx].insert(link);
}
}
//TODO not efficient!
//processing external borders
for(unsigned int l = 0; l < outpatch.bord.size(); l++) {
Link &link = outpatch.bord[l];
if(link.end_patch >= (1<<31)) continue;
unsigned short &start_vert = link.start_vert;
unsigned int &start_patch = patch_idx;
//Adding vertical connection
newlinks[patch_idx].insert(link);
Link up(link.end_vert, link.start_vert, patch_idx);
newlinks[link.end_patch].insert(up);
assert(link.end_patch != patch_idx);
Border &cborder = nexus.GetBorder(link.end_patch);
for(unsigned int k = 0; k < cborder.Size(); k++) {
//cerr << "Cborder.size: " << cborder.Size() << endl;
//cerr << "K: " << k << endl;
Link &clink = cborder[k];
assert(!clink.IsNull());
if(clink.start_vert != link.end_vert) continue;
if(patch_levels[clink.end_patch] < current_level-1) continue;
//boy i want only the external links!
if(orig_patches.count(clink.end_patch)) continue;
unsigned short &end_vert = clink.end_vert;
unsigned int &end_patch = clink.end_patch;
//TODO FIX THIS!!!!
assert(clink.end_patch != start_patch);
assert(clink.end_patch != link.end_patch);
Link newlink;
newlink.start_vert = start_vert;
newlink.end_vert = end_vert;
newlink.end_patch = end_patch;
newlinks[patch_idx].insert(newlink);
newlink.start_vert = end_vert;
newlink.end_vert = start_vert;
newlink.end_patch = start_patch;
newlinks[end_patch].insert(newlink);
}
}
}
map<unsigned int, set<Link> >::iterator n;
for(n = newlinks.begin(); n != newlinks.end(); n++) {
set<Link>::iterator l;
unsigned int patch = (*n).first;
set<Link> &links = (*n).second;
Border &border = nexus.GetBorder(patch);
unsigned int bstart = border.Size();
nexus.borders.ResizeBorder(patch, border.Size() + links.size());
for(l = links.begin(); l != links.end(); l++) {
Link link = *l;
border[bstart++] = link;
}
}
nexus.history.updates.push_back(update);
}
void ReverseHistory(vector<History::Update> &history) {
vector<History::Update> revert = history;
history.clear();
for(int i = revert.size()-1; i >= 0; i--)
history.push_back(revert[i]);
//std::reverse(history.begin(), history.end());
vector<History::Update>::iterator i;
for(i = history.begin(); i != history.end(); i++)
swap((*i).erased, (*i).created);
}

View File

@ -1,71 +0,0 @@
/****************************************************************************
* VCGLib o o *
* Visual and Computer Graphics Library o o *
* _ O _ *
* Copyright(C) 2004 \/)\/ *
* Visual Computing Lab /\/| *
* ISTI - Italian National Research Council | *
* \ *
* All rights reserved. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
* for more details. *
* *
****************************************************************************/
/****************************************************************************
History
$Log: not supported by cvs2svn $
****************************************************************************/
#include <ptypes/pinet.h>
class NxsClientPool {
vector<NxsClient> clients;
void Push(NxsRequest *request);
};
class NxsClient: public pt::ipstream {
public:
queue<NxsRequest *> requests;
void Push(NxsRequest *request);
};
ipaddress addr = phostbyname("nb-ponchio.isti.cnr.it");
ipstream client;
client.set_ip(addr);
client.set_port(testport);
try
{
client.open();
pout.put("Sending a request to the server...\n");
client.write("Hello", 6);
client.flush();
// receive the response
string rsp = client.line(maxtoken);
pout.putf("Received: %s\n", pconst(rsp));
// need to close the socket explicitly to gracefully shutdown
// the peer host too. otherwise, ~ipstream() will call cancel()
// and leave the peer in a waiting state (not forever though).
client.close();
}
catch(estream* e)
{
perr.putf("Error: %s\n", pconst(e->get_message()));
delete e;
}

View File

@ -1,221 +0,0 @@
/****************************************************************************
* VCGLib o o *
* Visual and Computer Graphics Library o o *
* _ O _ *
* Copyright(C) 2004 \/)\/ *
* Visual Computing Lab /\/| *
* ISTI - Italian National Research Council | *
* \ *
* All rights reserved. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
* for more details. *
* *
****************************************************************************/
/****************************************************************************
History
$Log: not supported by cvs2svn $
****************************************************************************/
#include "nxsdispatcher.h"
#include "fragment.h"
#include "decimate.h"
#include <iostream>
#include <ptypes/ptypes.h>
using namespace std;
using namespace vcg;
using namespace nxs;
using namespace pt;
void SaveFragment(Nexus &nexus, VChain &chain,
Fragment &fragin,
Fragment &fragout);
void Opener::execute() {
// cerr << "Trying to connect to: " << server->get_host() << endl;
server->reading.lock();
server->writing.lock();
while(1) {
if(get_signaled())
return;
// cerr << "Trying to connect to: " << server->get_host() << endl;
try {
server->open();
server->connected = true;
server->queue = 0;
// cerr << "Connected to: " << server->get_host() << endl;
break;
} catch(...) {
}
psleep(4000);
}
server->reading.unlock();
server->writing.unlock();
}
void FragIO::execute() {
pincrement(&(server->queue));
server->writing.lock();
// cerr << "Writing frag...: " << fragin->id << "\n";
outmemory outm;
outm.open();
fragin->Write(&outm);
pt::string a = outm.get_strdata();
try {
server->write((const char *)a, length(a));
server->flush();
} catch (estream *e) {
perr.putf("Error reading: %s\n", pconst(e->get_message()));
delete e;
server->close();
server->connected = false;
server->writing.unlock();
message *msg = new message(MSG_FAIL, (int)fragin);
dispatcher->post(msg);
server->opener.start();
return;
}
server->reading.lock();
server->writing.unlock();
Fragment *out = new Fragment;
if(!server->waitfor(10000) || (!out->Read(server))) {
perr.putf("Error reading!!\n");
server->close();
server->connected = false;
server->reading.unlock();
message *msg = new message(MSG_FAIL, (int)fragin);
dispatcher->post(msg);
server->opener.start();
return;
}
server->reading.unlock();
pdecrement(&(server->queue));
// cerr << "Received frag: " << out->id << endl;
message *msg = new message(MSG_RECEIVE, (int)fragin);
msg->result = (int)out;
dispatcher->post(msg);
}
bool Dispatcher::Init(const std::string &file) {
FILE *fp = fopen(file.c_str(), "rb");
if(!fp) return false;
char host[256];
int port;
while(fscanf(fp, "%s %d\n", host, &port) == 2) {
cerr << "Host: " << host << " port: " << port << endl;
Server *server = new Server(host, port);
server->opener.start();
servers.push_back(server);
}
fclose(fp);
if(servers.size() == 0) {
cerr << "Empty server file!\n";
return false;
}
return true;
}
Dispatcher::~Dispatcher() {
for(unsigned int i = 0; i < servers.size(); i++) {
Server *server = servers[i];
server->opener.signal();
server->close();
delete server;
}
}
void Dispatcher::SendFragment(Fragment *frag) {
//WARNING this handles no more than 1<<31 fragments!
frag->id = count++;
message *msg = new message(MSG_SEND, (int)frag);
post(msg);
}
Server *Dispatcher::BestServer() {
Server *best = NULL;
for(unsigned int i = 0; i < servers.size(); i++){
if(servers[i]->connected) {
if((servers[i]->queue <= maxqueue) &&
(!best || servers[i]->queue < best->queue)) {
best = servers[i];
// cerr << "best: " << i << " queue: " << best->queue << endl;
}
}
}
return best;
}
void Dispatcher::ReceiveFragment(Fragment *in, Fragment *out) {
//lock nexus if run in thread.
// cerr << "Saving: " << in->id << endl;
SaveFragment(*nexus, *chain, *in, *out);
if(frags.count(in->id)) {
FragIO *frag = frags[in->id];
delete frag;
frags.erase(frags.find(in->id));
}
delete in;
delete out;
}
void Dispatcher::msghandler(message &msg) {
switch(msg.id) {
case MSG_FAIL:
case MSG_SEND: {
//get server!
Server *best = BestServer();
Fragment *fragin = (Fragment *)(msg.param);
if(!best || mode == CLUSTER) { //no server process locally....
// cerr << "Local: " << fragin->id << endl;
vector<Point3f> newvert;
vector<unsigned int> newface;
vector<BigLink> newbord;
Join(*fragin, newvert, newface, newbord);
float error = Decimate(mode,
(unsigned int)((newface.size()/3) * scaling),
newvert, newface, newbord);
Fragment *fragout = new Fragment;
fragout->error = error;
fragout->id = fragin->id;
fragout->seeds = fragin->seeds;
fragout->seeds_id = fragin->seeds_id;
Split(*fragout, newvert, newface, newbord);
ReceiveFragment(fragin, fragout);
} else {
// cerr << "Server: " << fragin->id << endl;
FragIO *frag = new FragIO(best, this, fragin);
if(msg.id == MSG_SEND)
assert(!frags.count(fragin->id));
frags[fragin->id] = frag;
frag->start();
}
} break;
case MSG_RECEIVE:
ReceiveFragment((Fragment *)(msg.param), (Fragment *)(msg.result));
break;
default:
defhandler(msg);
}
}

View File

@ -1,120 +0,0 @@
/****************************************************************************
* VCGLib o o *
* Visual and Computer Graphics Library o o *
* _ O _ *
* Copyright(C) 2004 \/)\/ *
* Visual Computing Lab /\/| *
* ISTI - Italian National Research Council | *
* \ *
* All rights reserved. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
* for more details. *
* *
****************************************************************************/
/****************************************************************************
History
$Log: not supported by cvs2svn $
****************************************************************************/
#ifndef NXS_DISPATCHER_H
#define NXS_DISPATCHER_H
#include <ptypes/pinet.h>
#include <ptypes/pasync.h>
#include <vector>
#include <map>
#include <string>
#include "decimate.h"
namespace nxs {
#define MSG_SEND MSG_USER + 1
#define MSG_RECEIVE MSG_USER + 2
#define MSG_FAIL MSG_USER + 3
class Fragment;
class Nexus;
class VChain;
class Server;
class FragIO;
class Dispatcher;
class Opener: public pt::thread {
public:
Opener(Server *s): thread(false), server(s) {}
~Opener() { waitfor(); }
void execute();
void cleanup() {}
Server *server;
};
class Server: public pt::ipstream {
public:
Server(pt::string host, int port): ipstream(host, port), queue(0),
connected(false), opener(this) {}
int queue;
pt::mutex reading;
pt::mutex writing;
bool connected;
Opener opener;
};
class Dispatcher: public pt::msgqueue {
public:
Dispatcher(Nexus *nx, VChain *ch):
count(0), maxqueue(3), nexus(nx), chain(ch) {}
~Dispatcher();
bool Init(const std::string &file);
void SendFragment(Fragment *frag);
void ReceiveFragment(Fragment *in, Fragment *out);
Server *BestServer();
void msghandler(pt::message &msg);
int count;
int maxqueue;
Nexus *nexus;
VChain *chain;
Decimation mode;
float scaling;
std::vector<Server *> servers;
std::map<int, FragIO *> frags;
};
class FragIO: public pt::thread {
public:
FragIO(Server *se, Dispatcher *di, Fragment *frag):
thread(false), server(se), dispatcher(di), fragin(frag) {}
~FragIO() { waitfor(); }
void execute();
void cleanup() {}
Server *server;
Dispatcher *dispatcher;
Fragment *fragin;
};
}
#endif

View File

@ -1,670 +0,0 @@
/****************************************************************************
* VCGLib o o *
* Visual and Computer Graphics Library o o *
* _ O _ *
* Copyright(C) 2004 \/)\/ *
* Visual Computing Lab /\/| *
* ISTI - Italian National Research Council | *
* \ *
* All rights reserved. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
* for more details. *
* *
****************************************************************************/
/****************************************************************************
History
$Log: not supported by cvs2svn $
Revision 1.26 2005/02/22 10:38:14 ponchio
Debug, cleaning and optimization.
Revision 1.25 2005/02/21 17:55:47 ponchio
debug debug debug
Revision 1.24 2005/02/20 19:49:44 ponchio
cleaning (a bit more).
Revision 1.23 2005/02/20 18:07:01 ponchio
cleaning.
Revision 1.22 2005/02/20 00:43:24 ponchio
Less memory x extraction. (removed frags)
Revision 1.21 2005/02/19 17:14:02 ponchio
History quick by default.
Revision 1.20 2005/02/19 10:45:04 ponchio
Patch generalized and small fixes.
Revision 1.19 2005/02/18 13:04:13 ponchio
Added patch reordering.
Revision 1.18 2005/02/08 12:43:03 ponchio
Added copyright
****************************************************************************/
#ifdef WIN32
#include <wrap/system/getopt.h>
#else
#include <unistd.h>
#endif
#include <assert.h>
#include <iostream>
#include <vcg/simplex/vertex/with/vc.h>
#include <vcg/simplex/face/face.h>
#include <vcg/complex/trimesh/base.h>
//WARNING WARNING this must be included AFTER mesh includes....
#include <wrap/io_trimesh/import_ply.h>
#include <vcg/space/index/grid_static_ptr.h>
#include "nxsalgo.h"
#include "strip.h"
#include "nexus.h"
#include "watch.h"
using namespace nxs;
using namespace vcg;
using namespace std;
using namespace tri;
class CFace;
class CVertex: public VertexVCf<DUMMYEDGETYPE,CFace ,DUMMYTETRATYPE> {};
class CFace: public Face<CVertex, DUMMYEDGETYPE , CFace>{};
class CMesh: public tri::TriMesh<vector<CVertex>, vector<CFace> > {};
string getSuffix(Signature &signature) {
string suff;
if(signature.compr) suff += "Z";
if(signature.face == Signature::STRIPS) suff += "S";
if(signature.vcolor) suff += "C";
if(signature.vnorm) suff += "N";
if(signature.vtext) suff += "T";
if(signature.vdata) suff += "D";
return suff;
}
void printInfo(Nexus &nexus, bool verbose, bool dump_history);
int main(int argc, char *argv[]) {
string input;
string output;
string plysource;
bool info = false;
bool verbose = false;
bool dump_history = false;
unsigned int ram_size = 128000000;
unsigned int chunk_size = 0;
bool add = false;
bool add_strips = false;
bool add_colors = false;
unsigned char add_normals = 0;
bool add_textures = false;
bool add_data = false;
bool remove = false;
bool remove_strips = false;
bool remove_colors = false;
bool remove_normals = false;
bool remove_textures = false;
bool remove_data = false;
bool compress = false;
bool uncompress = false;
bool zsort = false;
float qvertex = 0;
float qnormal = 0;
float qcolor = 0;
float qtexture = 0;
float cone_threshold = 0;
int option;
while((option = getopt(argc, argv, "ilho:a:r:zxsv:n:k:t:b:c:V:")) != EOF) {
switch(option) {
case 'i': info = true; break;
case 'l': verbose = true; break;
case 'h': dump_history = true; break;
case 'o': output = optarg; break;
case 'p': plysource = optarg; break;
case 'a': {
if(strstr(optarg, "strips")) { add_strips = true; add = true; }
if(strstr(optarg, "colors")) { add_colors = true; add = true; }
if(strstr(optarg, "normals")) {
add_normals = Encodings::SHORT4; add = true; }
if(strstr(optarg, "normalf")) {
add_normals = Encodings::FLOAT3; add = true; }
if(strstr(optarg, "textures")) { add_textures = true; add = true; }
if(strstr(optarg, "data")) { add_data = true; add = true; }
if(add == false) {
cerr << "Invalid -a argument: " << optarg << "\n"
<< "Valid options are: strips, colors, normals, textures, data\n";
return -1;
}
break;
}
case 'r': {
if(strstr(optarg, "strips")) {
cerr << "Strips removing not supported!\n";
return -1;
}
if(strstr(optarg, "colors")) { remove_colors = true; remove = true; }
if(strstr(optarg, "normals")) { remove_normals = true; remove = true; }
if(strstr(optarg, "textures")) { remove_textures = true; remove = true; }
if(strstr(optarg, "data")) { remove_data = true; remove = true; }
if(remove == false) {
cerr << "Invalid -a argument: " << optarg << "\n"
<< "Valid options are: strip, colors, normals, normalf, "
<< "textures, data\n";
return -1;
}
break;
}
case 'z': compress = true; break;
case 'x': uncompress = true; break;
case 's': zsort = true; break;
case 'V': cone_threshold = atof(optarg); break;
case 'v': qvertex = (float)atof(optarg);
if(qvertex == 0) {
cerr << "Invalid value for quantization: " << optarg << endl;
return -1;
}
break;
case 'n': qnormal = (float)atof(optarg);
if(qnormal == 0) {
cerr << "Invalid value for quantization: " << optarg << endl;
return -1;
}
break;
case 'k': qcolor = (float)atof(optarg);
if(qcolor == 0) {
cerr << "Invalid value for quantization: " << optarg << endl;
return -1;
}
break;
case 't': qtexture = (float)atof(optarg);
if(qtexture == 0) {
cerr << "Invalid value for quantization: " << optarg << endl;
return -1;
}
break;
case 'b': ram_size = atoi(optarg);
if(ram_size == 0) {
cerr << "Invalid ram_size: " << optarg << endl;
return -1;
}
break;
case 'c': chunk_size = atoi(optarg);
if(chunk_size == 0) {
cerr << "Invalid chunk_size: " << optarg << endl;
return -1;
}
break;
default: cerr << "Unknown option: " << (char)option << endl;
return -1;
}
}
if(optind != argc - 1) {
cerr << "Usage: " << argv[0] << " <nexus file> [options]\n"
<< " -i : display some info about nexus file\n"
<< " -l : list nodes\n"
<< " -h : list history\n"
<< " -o <file>: output filename (default is adding 00 to nexus)\n"
<< " -a <what>: Add [colors|normals|normalf|strips|textures|data|borders]\n"
<< " -r <what>: As add...\n"
<< " -p <ply> : Ply source for colors or textures or data\n"
<< " -z : compress\n"
<< " -x : uncompress\n"
<< " -s : sort using zcurve\n"
<< " -v<float>: Vertex quantization (float is the 0 level amount)\n"
<< " -n<float>: Normal quantization\n"
<< " -c<float>: Color quantization\n"
<< " -t<float>: Texture quantization\n"
<< " -V<float>: Normal cone threshold [0, 1] (0.95 default)\n\n"
<< " This option will not create a new nexus file\n";
return -1;
}
input = argv[optind];
//Sanity test of options...
if(compress && uncompress) {
cerr << "x and z are obviously exclusive :P\n";
return -1;
}
if(add_normals && compress) {
cerr << "Its not possible to add normals and compress in the same step\n"
<< "Because normals requires 2 passes to be calculated\n\n";
return -1;
}
bool compute_cones = false;
if(!add && !remove && !compress && !uncompress && !zsort &&
!qvertex && !qcolor && !qnormal && !qtexture && cone_threshold != 0)
compute_cones = true;
Nexus nexus;
if(!nexus.Load(input, true)) {
cerr << "Could not open nexus file: " << input << "\n";
return -1;
}
nexus.MaxRam() = ram_size / nexus.chunk_size;
//Sanity tests
if(remove_strips && !(nexus.signature.face != Signature::STRIPS)) {
cerr << "Nexus file does not have strips\n";
return -1;
}
if(remove_colors && !nexus.signature.vcolor) {
cerr << "Nexus file does not have colors\n";
return -1;
}
if(remove_normals && !nexus.signature.vnorm) {
cerr << "Nexus file does not have normals\n";
return -1;
}
if(remove_textures && !nexus.signature.vtext) {
cerr << "Nexus file does not have textures\n";
return -1;
}
if(remove_data && !nexus.signature.vdata) {
cerr << "Nexus file does not have data\n";
return -1;
}
if(add_strips && (nexus.signature.face == Signature::STRIPS)) {
cerr << "Nexus file already has strips\n";
return -1;
}
if(add_colors && nexus.signature.vcolor) {
cerr << "Nexus file already has colors\n";
return -1;
}
if(add_normals && nexus.signature.vnorm) {
cerr << "Nexus file already has normals\n";
return -1;
}
if(add_textures && nexus.signature.vtext) {
cerr << "Nexus file already has textures\n";
return -1;
}
if(add_data && nexus.signature.vdata) {
cerr << "Nexus file already has data\n";
return -1;
}
if(nexus.IsCompressed() && compress) {
cerr << "File already compressed.\n";
return -1;
}
if(!nexus.IsCompressed() && uncompress) {
cerr << "File not compressed.\n";
return -1;
}
if(info) {
cout << "Nexus file: " << input << "\n";
printInfo(nexus, verbose, dump_history);
}
//determine if we must proceed:
if(!add && !remove && !compress && !uncompress && !zsort &&
qvertex == 0 && qnormal == 0 && qcolor == 0 && qtexture == 0 &&
cone_threshold == 0) {
nexus.Close();
return 0;
}
if(compute_cones) {//just recalculate normal cones
cerr << "Unimplemented at the moment...\n";
/*vector<NCone3s> cones;
// ComputeCones(Nexus &nexus, float cone_threshold);
nexus.Close();
nexus.Load(intput, false);
for(unsigned int i = 0; i < nexus.size(); i++) {
nexus[i].cone = cones[i];
}*/
nexus.Close();
return 0;
}
CMesh mesh;
GridStaticPtr<CMesh::FaceContainer> grid;
if(add_colors) {
if(!plysource.size()) {
cerr << "No plysource specified when adding color (-p option)\n";
} else {
if(!tri::io::ImporterPLY<CMesh>::Open(mesh, plysource.c_str())) {
cerr << "Could not load ply: " << plysource << endl;
return -1;
}
//calcoliamo il box:
Box3f box;
for(unsigned int i = 0; i < mesh.vert.size(); i++)
box.Add(mesh.vert[i].P());
grid.SetBBox(box);
grid.Set(mesh.face);
}
}
Signature signature = nexus.signature;
if(add_strips) signature.face = Signature::STRIPS;
if(add_normals) signature.vnorm = add_normals;
if(add_colors) signature.vcolor = Encodings::BYTE4;
if(remove_normals) signature.vnorm = 0;
if(remove_colors) signature.vcolor = 0;
if(compress) signature.compr = Signature::LZO;
if(uncompress) signature.compr = 0;
if(!output.size()) output = input + getSuffix(signature);
if(output == input) {
cerr << "Output and input files are the same.\n"
<< "Use option -o <filename>\n"
<< "You do not want to overwrite your data. Trust me.\n";
return -1;
}
cout << "Writing to nexus: " << output << endl;
Nexus out;
if(!chunk_size)
chunk_size = nexus.chunk_size;
if(!out.Create(output, signature, chunk_size)) {
cerr << "Could not open output: " << output << endl;
return -1;
}
//TODO fix this broken interface (you should not care abou chunk_size
out.MaxRam() = ram_size / out.chunk_size;
//TODO set rambuffer low (or even direct access!)
vector<unsigned int> forward;
vector<unsigned int> backward;
if(zsort)
ZSort(nexus, forward, backward);
//Fixing history
assert(nexus.history.IsQuick());
unsigned int hsize;
char *buffer = nexus.history.Save(hsize);
out.history.Load(hsize, buffer);
if(zsort) {
assert(0);
//TODO FIX THIS...
/* if(out.history.IsQuick()) {
for(unsigned int i = 0; i < out.history.n_frags(); i++)
out.history.frags[i] = backward[out.history.frags[i]];
} else {
for(unsigned int i = 0; i < out.history.updates.size(); i++) {
History::Update &update = out.history.updates[i];
for(unsigned int k = 0; k < update.created.size(); k++)
update.created[k] = backward[update.created[k]];
for(unsigned int k = 0; k < update.erased.size(); k++)
update.erased[k] = backward[update.erased[k]];
}
}*/
}
Report report(nexus.size());
cout << "Copying and allocating...\n";
for(unsigned int p = 0; p < nexus.size(); p++) {
unsigned int patch = p;
report.Step(patch);
if(zsort) patch = forward[patch];
Entry &src_entry = nexus[patch];
Patch &src_patch = nexus.GetPatch(patch);
Border &src_border = nexus.GetBorder(patch);
vector<unsigned short> strip;
if(add_strips) {
ComputeTriStrip(src_patch.nf, src_patch.FaceBegin(), strip);
assert(strip.size() < 65000);
out.AddPatch(src_entry.nvert, strip.size(), src_border.Capacity());
if(verbose) {
cerr << "tri: " << src_patch.nf << " strip: " << strip.size()
<< " ratio: " << (float)strip.size()/(float)src_patch.nf
<< endl;
}
} else
out.AddPatch(src_entry.nvert, src_entry.nface, src_border.Capacity());
Entry &dst_entry = out[p];
Patch &dst_patch = out.GetPatch(p);
//copy vertices:
assert(out.signature.vert == Signature::POINT3F);
assert(out.signature.vert = nexus.signature.vert);
memcpy(dst_patch.Vert3fBegin(), src_patch.Vert3fBegin(),
src_patch.nv * sizeof(Point3f));
if(qvertex && !add_normals) {
float *ptr = (float *)dst_patch.Vert3fBegin();
for(int i = 0; i < dst_patch.nv*3; i++)
ptr[i] = qvertex * (int)(ptr[i]/qvertex);
}
//now faces.
if(add_strips) {
assert(out.signature.face == Signature::STRIPS);
memcpy(dst_patch.FaceBegin(), &*strip.begin(),
strip.size() * sizeof(short));
} else {
assert(nexus.signature.face == out.signature.face);
if(nexus.signature.face == Signature::STRIPS) {
memcpy(dst_patch.FaceBegin(), src_patch.FaceBegin(),
src_patch.nf * sizeof(unsigned short));
} else if(nexus.signature.face == Signature::TRIANGLES) {
memcpy(dst_patch.FaceBegin(), src_patch.FaceBegin(),
src_patch.nf * sizeof(unsigned short) * 3);
} else {
assert(0);
}
}
if(nexus.signature.vcolor) {
if(nexus.signature.vcolor == out.signature.vcolor) {
memcpy(dst_patch.VColorBegin(), src_patch.VColorBegin(),
Patch::encodings[out.signature.vcolor].size(dst_patch.nv));
} else {
assert(0);
}
}
if(nexus.signature.vnorm) {
if(nexus.signature.vnorm == out.signature.vnorm) {
memcpy(dst_patch.VNormBegin(), src_patch.VNormBegin(),
Patch::encodings[out.signature.vnorm].size(dst_patch.nv));
} else {
assert(0);
}
}
//copying entry information;
dst_entry.sphere = src_entry.sphere;
dst_entry.error = src_entry.error;
dst_entry.cone = src_entry.cone;
out.borders.ResizeBorder(p, src_border.Size());
Border &dst_border = out.GetBorder(p);
memcpy(dst_border.Start(), src_border.Start(),
src_border.Size() * sizeof(Link));
//TODO test this
if(zsort)
for(unsigned i = 0; i < dst_border.Size(); i++)
dst_border[i].end_patch = backward[dst_border[i].end_patch];
}
report.Finish();
//TODO this is ok only if we have faces still!
if(add_normals) {
cout << "Computing normals" << endl;
ComputeNormals(out);
}
if(add_colors) {
// if(!plysource.size())
//source of color:
// cerr << "Unsupported color\n";
// return -1;
}
if(qvertex && add_normals) {
report.Init(nexus.size());
cout << "Quantizing vertices\n";
for(unsigned int patch = 0; patch < nexus.size(); patch++) {
report.Step(patch);
Patch src_patch = nexus.GetPatch(patch);
float *ptr = (float *)src_patch.Vert3fBegin();
for(int i = 0; i < src_patch.nv*3; i++)
ptr[i] = qvertex * (int)(ptr[i]/qvertex);
}
report.Finish();
}
out.sphere = nexus.sphere;
out.Close();
nexus.Close();
return 0;
}
void printInfo(Nexus &nexus, bool verbose, bool dump_history) {
//perform locality statistics
double meandist = 0;
vcg::Sphere3f last = nexus[0].sphere;
for(unsigned int i = 1; i < nexus.size(); i++) {
vcg::Sphere3f &sphere = nexus[i].sphere;
double dist = vcg::Distance(last.Center(), sphere.Center());
meandist += dist;
last = sphere;
}
meandist /= nexus.size() -1;
cout << "\n\tCompressed: " << nexus.IsCompressed()
<< "\n\tStripped : "
<< (int)(nexus.signature.face == Signature::STRIPS)
<< "\n\tColor : " << (int)(nexus.signature.vcolor)
<< "\n\tNormal : " << (int)(nexus.signature.vnorm)
<< "\n\tTexture : " << (int)(nexus.signature.vtext)
<< "\n\tData : " << (int)(nexus.signature.vdata)
<< "\n\n\tVertices: " << nexus.totvert
<< "\tFaces : " << nexus.totface
<< "\tPatches : " << nexus.size()
<< "\n\tSphere : "
<< nexus.sphere.Center()[0] << " "
<< nexus.sphere.Center()[1] << " "
<< nexus.sphere.Center()[2] << " R: "
<< nexus.sphere.Radius()
<< "\n\tAverage distance: " << meandist
<< "\n\tChunk size " << nexus.chunk_size << endl;
if(dump_history) {
if(nexus.history.IsQuick()) {
cout << "Quick format\n";
for(unsigned int i = 0; i < nexus.history.n_nodes(); i++) {
cout << "Node: " << i << " out: ";
History::Node node = nexus.history.nodes[i];
for(History::Link *l = node.out_begin; l != node.out_end; l++) {
cout << ".";
for(unsigned int p = l->begin; p != l->end; p++) {
cout << p << " ";
}
}
cout << " in: ";
for(History::Link *j = node.in_begin; j != node.in_end; j++) {
cout << ".";
for(unsigned int p = j->begin; p != j->end; p++) {
cout << p << " ";
}
}
cout << endl;
}
} else {
cout << "Update format\n";
for(unsigned int i = 0; i < nexus.history.updates.size(); i++) {
History::Update &update = nexus.history.updates[i];
cout << "Created: ";
for(unsigned int k = 0; k < update.created.size(); k++) {
cout << update.created[k] << " ";
}
cout << "\nErased: ";
for(unsigned int k = 0; k < update.erased.size(); k++) {
cout << update.erased[k] << " ";
}
cout << "\n\n";
}
}
}
if(verbose) {
for(unsigned int i = 0; i < nexus.size(); i++) {
Entry &entry = nexus[i];
cout << i << " -> nv: " << entry.nvert << " nf: " << entry.nface
<< " error: " << entry.error
<< " disk_size: " << entry.disk_size
<< " start: " << entry.patch_start << endl;
cout << " Cone: " << entry.cone.n[0] << " "
<< entry.cone.n[1] << " "
<< entry.cone.n[2] << " "
<< entry.cone.n[3] << "\n";
}
cout << endl;
}
}

View File

@ -1,119 +0,0 @@
#ifndef NXS_EXPORT_H
#define NXS_EXPORT_H
#include <map>
#include <vector>
#include "nexus.h"
#include "extraction.h"
namespace nxs {
template <class MESH> void ExportTriMesh(Nexus &nexus,
vector<unsigned int> &patches,
MESH &mesh) {
typedef typename MESH::VertexType VertexType;
typedef typename MESH::FaceType FaceType;
typedef typename MESH::ScalarType ScalarType;
//for every patch record the global position of the vertices
std::map<unsigned int, std::vector<unsigned int> > remap;
//Resize all remapping vectors
for(unsigned int p = 0; p < patches.size(); p++) {
unsigned int npatch = patches[p];
remap[npatch].resize(nexus[npatch].nvert, 0xffffffff);
}
//Filling remapping vectors
unsigned int vcount = 0;
for(unsigned int p = 0; p < patches.size(); p++) {
unsigned int npatch = patches[p];
Patch &patch = nexus.GetPatch(npatch);
std::vector<unsigned int> &rmp = remap[npatch];
for(unsigned int v = 0; v < patch.nv; v++)
if(rmp[v] == 0xffffffff)
rmp[v] = vcount++;
Border &border = nexus.GetBorder(npatch);
for(unsigned int k = 0; k < border.Size(); k++) {
Link link = border[k];
if(link.IsNull()) continue;
if(remap.count(link.end_patch)) //internal
if(remap[link.end_patch][link.end_vert] == 0xffffffff)
remap[link.end_patch][link.end_vert] = rmp[link.start_vert];
}
}
mesh.vert.resize(vcount);
mesh.VertexNumber() = vcount;
//copying vectors and faces
for(unsigned int p = 0; p < patches.size(); p++) {
unsigned int npatch = patches[p];
Patch &patch = nexus.GetPatch(npatch);
std::vector<unsigned int> &rmp = remap[npatch];
//coping vertices
VertexType vertex;
vertex.ClearFlags();
for(unsigned int v = 0; v < patch.nv; v++) {
vertex.P()[0] = (ScalarType)patch.Vert3f(v)[0];
vertex.P()[1] = (ScalarType)patch.Vert3f(v)[1];
vertex.P()[2] = (ScalarType)patch.Vert3f(v)[2];
if(mesh.HasPerVertexNormal()) {
if(nexus.signature.vnorm == Encodings::SHORT4) {
vertex.N()[0] = (ScalarType)((short *)patch.VNormBegin())[v*4];
vertex.N()[1] = (ScalarType)((short *)patch.VNormBegin())[v*4 +1];
vertex.N()[2] = (ScalarType)((short *)patch.VNormBegin())[v*4 +2];
} else if(nexus.signature.vnorm == Encodings::FLOAT3) {
vertex.N()[0] = (ScalarType)((float *)patch.VNormBegin())[v*3];
vertex.N()[0] = (ScalarType)((float *)patch.VNormBegin())[v*3 +1];
vertex.N()[0] = (ScalarType)((float *)patch.VNormBegin())[v*3 +2];
} else if(nexus.signature.vnorm) {
//i should write other exporters
assert(0);
}
}
if(mesh.HasPerVertexColor() && nexus.signature.vcolor) {
if(nexus.signature.vcolor == Encodings::BYTE4) {
vertex.C()[0] = ((unsigned char *)patch.VColorBegin())[v*4];
vertex.C()[1] = ((unsigned char *)patch.VColorBegin())[v*4+1];
vertex.C()[2] = ((unsigned char *)patch.VColorBegin())[v*4+2];
vertex.C()[3] = ((unsigned char *)patch.VColorBegin())[v*4+3];
} else if(nexus.signature.vcolor) {
//i should write other exporters
assert(0);
}
}
if(mesh.HasPerVertexTexture() && nexus.signature.vtext) {
//i should write other exporters
assert(0);
}
assert(rmp[v] < mesh.vert.size());
mesh.vert[rmp[v]] = vertex;
}
//remap faces now
FaceType face;
if(nexus.signature.face == Signature::TRIANGLES) {
for(unsigned int f = 0; f < patch.nf; f++) {
face.V(0) = &mesh.vert[rmp[patch.Face(f)[0]]];
face.V(1) = &mesh.vert[rmp[patch.Face(f)[1]]];
face.V(2) = &mesh.vert[rmp[patch.Face(f)[2]]];
mesh.face.push_back(face);
mesh.SimplexNumber()++;
/*static bool HasPerFaceColor() {return FaceType::HasFaceColor() ;}
static bool HasPerFaceNormal() {return FaceType::HasFaceNormal();}
static bool HasPerFaceMark() {return FaceType::HasFaceMark() ;}
static bool HasPerFaceQuality(){return FaceType::HasFaceQuality();}*/
}
}
}
}
}//namespace
#endif

View File

@ -1,48 +0,0 @@
#include <iostream>
#include "crude.h"
using namespace nxs;
using namespace vcg;
using namespace std;
int main(int argc, char *argv[]) {
if(argc != 2) {
cerr << "Uso: " << argv[0] << " <side>\n";
return -1;
}
unsigned int side = atoi(argv[1]);
if(side > 1000 || side == 0) {
cerr << "Invalid side: " << argv[1] << endl;
return -1;
}
Crude crude;
if(!crude.Create("square")) {
cerr << "Could not create square" << endl;
return -1;
}
int half = side/2;
crude.Resize(side * side, (side-1) * (side-1) * 2);
for(unsigned int x = 0; x < side; x++)
for(unsigned int y = 0; y < side; y++) {
// Point3f p(x*x*x/((float)side),
// y*y*y/((float)side), x*y/((float)side));
Point3f p(x, y, sqrt((float)x*x + y*y));
crude.SetVertex(x + side * y, p);
crude.GetBox().Add(p);
}
for(unsigned int x = 0; x < side-1; x++)
for(unsigned int y = 0; y < side-1; y++) {
unsigned int pos = x + side*y;
Crude::Face face(pos, pos + 1, pos + side);
crude.SetFace(0 + 2*x + (side-1)*y*2, face);
face = Crude::Face(pos + 1, pos + 1 + side, pos +side);
crude.SetFace(1 + 2*x + (side-1)*y*2, face);
}
crude.Close();
return 0;
}

View File

@ -1,223 +0,0 @@
/****************************************************************************
* VCGLib o o *
* Visual and Computer Graphics Library o o *
* _ O _ *
* Copyright(C) 2004 \/)\/ *
* Visual Computing Lab /\/| *
* ISTI - Italian National Research Council | *
* \ *
* All rights reserved. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
* for more details. *
* *
****************************************************************************/
/****************************************************************************
History
$Log: not supported by cvs2svn $
****************************************************************************/
#include <ptypes/ptime.h>
#include <ptypes/pinet.h>
#include <ptypes/pasync.h>
#include "fragment.h"
#include "decimate.h"
using namespace pt;
using namespace nxs;
using namespace vcg;
using namespace std;
class FragOutQueue: public msgqueue {
public:
FragOutQueue(ipstream &cli): client(cli) {}
void msghandler(message &msg) {
if(msg.id != MSG_USER) {
defhandler(msg);
return;
}
Fragment &fragment = *(Fragment *)(msg.param);
// pout.putf("Sending: %d\n", fragment.id);
outmemory outm;
outm.open();
fragment.Write(&outm);
pt::string a = outm.get_strdata();
try {
client.write((const char *)a, length(a));
client.flush();
pout.putf("Sent fragment id: %d\n", fragment.id);
} catch (estream *e) {
perr.putf("Error: %s\n", pconst(e->get_message()));
delete e;
posturgent(MSG_QUIT);
}
delete (Fragment *)(msg.param);
}
ipstream &client;
};
class FragInQueue: public msgqueue {
public:
FragInQueue(FragOutQueue &o): out(o) {}
void msghandler(message &msg) {
if(msg.id != MSG_USER) {
if(msg.id == MSG_QUIT)
out.posturgent(MSG_QUIT);
defhandler(msg);
return;
}
Fragment &fragin = *(Fragment *)(msg.param);
// pout.putf("Processing: %d\n", fragin.id);
vector<Point3f> newvert;
vector<unsigned int> newface;
vector<BigLink> newbord;
Join(fragin, newvert, newface, newbord);
float error = Decimate(QUADRIC,
(unsigned int)((newface.size()/3) * 0.5),
newvert, newface, newbord);
message *outmsg = new message(MSG_USER);
outmsg->param = (int)(new Fragment);
Fragment &fragout = *(Fragment *)(outmsg->param);
fragout.error = error;
fragout.id = fragin.id;
fragout.seeds = fragin.seeds;
fragout.seeds_id = fragin.seeds_id;
Split(fragout, newvert, newface, newbord);
out.post(outmsg);
delete (Fragment *)(msg.param);
}
FragOutQueue &out;
};
class Reader: public thread {
public:
Reader(ipstream &cli, FragInQueue &que):
thread(false), client(cli), queue(que) {}
~Reader() {waitfor(); }
void execute() {
while(1) {
if(get_signaled()) return;
message *msg = new message(MSG_USER);
msg->param = (int)(new Fragment);
Fragment &fragment = *(Fragment *)(msg->param);
if(!fragment.Read(&client)) {
pout.putf("Could not read!\n");
queue.posturgent(MSG_QUIT);
return;
}
queue.post(msg);
// pout.putf("Incoming: %d\n", fragment.id);
}
}
void cleanup() {}
ipstream &client;
FragInQueue &queue;
};
class Worker: public thread {
public:
Worker(FragInQueue &que): thread(false), queue(que) {}
~Worker() { waitfor(); }
void execute() {
queue.run();
}
void cleanup() {}
FragInQueue &queue;
};
class Writer: public thread {
public:
Writer(FragOutQueue &que): thread(false), queue(que) {}
~Writer() {waitfor(); }
void execute() {
queue.run();
}
void cleanup() {}
FragOutQueue &queue;
};
void servermain(ipstmserver& svr) {
ipstream client;
while(true) {
// serve() will wait for a connection request and will prepare
// the supplied ipstream object for talking to the peer.
svr.serve(client);
perr.putf("Serving clients!\n");
if (client.get_active()) {
try {
pout.putf("Incoming connection\n");
FragOutQueue out(client);
FragInQueue in(out);
Reader reader(client, in);
Worker worker(in);
Writer writer(out);
reader.start();
worker.start();
writer.start();
reader.waitfor();
worker.waitfor();
writer.waitfor();
client.flush();
client.close();
} catch(estream* e) {
perr.putf("Error: %s\n", pconst(e->get_message()));
delete e;
}
}
perr.putf("Restarting\n");
}
}
int main(int argc, char *argv[]) {
ipstmserver svr;
int port = 10102;
if(argc == 2) {
port = atoi(argv[1]);
if(port < 1024) {
perr.putf("Error: invalid port: %s\n", argv[1]);
return -1;
}
}
try {
// bind to all local addresses on port 8085
svr.bindall(port);
pout.putf("Ready to answer queries on port %d\n", port);
// enter an infinite loop of serving requests
servermain(svr);
} catch(estream* e) {
perr.putf("FATAL: %s\n", pconst(e->get_message()));
delete e;
}
return 0;
}

View File

@ -1,163 +0,0 @@
/****************************************************************************
* VCGLib o o *
* Visual and Computer Graphics Library o o *
* _ O _ *
* Copyright(C) 2004 \/)\/ *
* Visual Computing Lab /\/| *
* ISTI - Italian National Research Council | *
* \ *
* All rights reserved. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
* for more details. *
* *
****************************************************************************/
/****************************************************************************
History
$Log: not supported by cvs2svn $
Revision 1.5 2005/02/08 12:43:03 ponchio
Added copyright
****************************************************************************/
#include <iostream>
#include "nexus.h"
#include "watch.h"
using namespace vcg;
using namespace std;
using namespace nxs;
int main(int argc, char *argv[]) {
if(argc != 2) {
cerr << "Usage: " << argv[0] << " <nexusfile>\n";
return -1;
}
Nexus nexus;
if(!nexus.Load(argv[1], true)) {
cerr << "Could not open file: " << argv[1] << endl;
return -1;
}
Report report(nexus.size());
for(unsigned int patchid = 0; patchid < nexus.size(); patchid++) {
report.Step(patchid);
Entry &info = nexus[patchid];
Patch &patch = nexus.GetPatch(patchid);
for(int f = 0; f < patch.nf; f++) {
unsigned short *face = patch.Face(f);
for(int k = 0; k < 3; k++) {
if(face[k] > patch.nv) {
cerr << "Invalid face number: " << face[k] << " > "
<< patch.nv << endl;
cerr << "At patch: " << patchid << endl;
cerr << "start: " << info.patch_start << endl;
cerr << "nf: " << info.nface << " nv: " << info.nvert << endl;
//exit(0);
}
}
}
Sphere3f &sphere = info.sphere;
for(int v = 0; v < patch.nv; v++) {
Point3f &p = patch.Vert3f(v);
float dist = Distance(sphere, p);
if(dist > 0.001) {
//if(!info.sphere.IsIn(p)) {
cerr << "Vertex outside bound: (" << p[0] << " " << p[1] << " " << p[2] << ")\n";
Point3f &c = sphere.Center();
cerr << "Sphere: (" << c[0] << " " << c[1] << " " << c[2] << ") R: " << sphere.Radius() << endl;;
cerr << "Distance: " << dist << endl;
cerr << "At patch: " << patchid << endl;
}
}
}
report.Finish();
cerr << "Testing borders\n";
for(unsigned int patchid = 0; patchid < nexus.size(); patchid++) {
Entry &info = nexus[patchid];
Border &border = nexus.GetBorder(patchid);
for(unsigned int i = 0; i < border.Size(); i++) {
Link &link = border[i];
if(link.start_vert == 0 && link.end_vert == 0 && link.end_patch == 0) {
cerr << "patch: " << patchid << " corrupted memory?" << endl;
}
if(link.IsNull()) {
cerr << "Null link: " << i << " at patch: " << patchid << endl;
exit(0);
}
if(link.end_patch < 0 || link.end_patch >= nexus.size()) {
cerr << "Invalid link end patch: " << link.end_patch << " at patch: " << patchid << endl;
exit(0);
}
if(link.start_vert > info.nvert) {
cerr << "Invalid link start_vert: " << link.start_vert << " at patch: " << patchid << endl;
exit(0);
}
if(link.end_vert > nexus[link.end_patch].nvert) {
cerr << "Invalid link end vert: " << link.end_vert << " at patch: " << patchid << endl;
exit(0);
}
}
}
cerr << "Reciprocity borders test\n";
for(unsigned int patchid = 0; patchid < nexus.size(); patchid++) {
Entry &info = nexus[patchid];
Border &border = nexus.GetBorder(patchid);
vector<Link> links;
links.resize(border.Size());
memcpy(&*links.begin(),&(border[0]),links.size() * sizeof(Link));
for(unsigned int i = 0; i < links.size(); i++) {
Link &link = links[i];
Border &rborder = nexus.GetBorder(link.end_patch, false);
bool found = false;
for(unsigned int k = 0; k < rborder.Size(); k++) {
Link rlink = rborder[k];
if(rlink.end_patch == patchid) {
if(rlink.end_vert == link.start_vert) {
if(rlink.start_vert != link.end_vert) {
cerr << "Something wrong with links!\n";
exit(0);
}
found = true;
break;
}
if(rlink.start_vert == link.end_vert) {
if(rlink.end_vert != link.start_vert) {
cerr << "Something wrong with links!\n";
exit(0);
}
found = true;
break;
}
}
}
if(!found) {
cerr << "A link is one way from patch: " << patchid << " vert: " << link.start_vert
<< " to patch: " << link.end_patch << " vert: " << link.end_vert << endl;
for(unsigned int t = 0; t < rborder.Size(); t++) {
Link &rlink = rborder[t];
cerr << rlink.start_vert << " -> p: " << rlink.end_patch << " v: " << rlink.end_vert << endl;
}
exit(0);
}
}
}
return 0;
}

View File

@ -1,43 +0,0 @@
/****************************************************************************
* VCGLib o o *
* Visual and Computer Graphics Library o o *
* _ O _ *
* Copyright(C) 2004 \/)\/ *
* Visual Computing Lab /\/| *
* ISTI - Italian National Research Council | *
* \ *
* All rights reserved. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
* for more details. *
* *
****************************************************************************/
/****************************************************************************
History
$Log: not supported by cvs2svn $
****************************************************************************/
#ifndef NXS_TYPES_H
#define NXS_TYPES_H
#ifdef WIN32
typedef __int64 int64;
#else
typedef unsigned long long int64;
//typedef unsigned long long uint64;
#endif
typedef int int32;
typedef unsigned int uint32;
#endif

View File

@ -1,386 +0,0 @@
/****************************************************************************
* VCGLib o o *
* Visual and Computer Graphics Library o o *
* _ O _ *
* Copyright(C) 2004 \/)\/ *
* Visual Computing Lab /\/| *
* ISTI - Italian National Research Council | *
* \ *
* All rights reserved. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
* for more details. *
* *
****************************************************************************/
/****************************************************************************
History
$Log: not supported by cvs2svn $
Revision 1.13 2005/02/22 10:38:15 ponchio
Debug, cleaning and optimization.
Revision 1.12 2005/02/21 19:05:58 ponchio
i already fixed this bug. I hate you cvs.
Revision 1.11 2005/02/19 12:06:55 ponchio
Debug...
Revision 1.10 2005/02/19 10:45:05 ponchio
Patch generalized and small fixes.
Revision 1.9 2005/02/08 12:43:03 ponchio
Added copyright
****************************************************************************/
#include "patch.h"
#ifdef WIN32
#include "minilzo.108/minilzo.h"
#else
#include <lzo1x.h>
#endif
#include <iostream>
using namespace std;
using namespace nxs;
#ifdef WIN32
static double wrkmem[LZO1X_1_MEM_COMPRESS/sizeof(double) +1];
#else
static double wrkmem[LZO1X_999_MEM_COMPRESS/sizeof(double) +1];
#endif
Encodings Patch::encodings;
Encodings::Encodings() {
for(unsigned int i = 0; i < 17; i++) {
e[i].bytes = 0;
e[i].comps = 0;
e[i].pack = NULL;
e[i].unpack = NULL;
}
e[1].bytes = 1;
e[2].bytes = 2;
e[3].bytes = 4;
e[4].bytes = 8;
e[1].comps = e[2].comps = e[3].comps = e[4].comps = 1;
e[5].bytes = 1;
e[6].bytes = 2;
e[7].bytes = 4;
e[8].bytes = 8;
e[5].comps = e[6].comps = e[7].comps = e[8].comps = 2;
e[9].bytes = 1;
e[10].bytes = 2;
e[11].bytes = 4;
e[12].bytes = 8;
e[9].comps = e[10].comps = e[11].comps = e[12].comps = 3;
e[13].bytes = 1;
e[14].bytes = 2;
e[15].bytes = 4;
e[16].bytes = 8;
e[13].comps = e[14].comps = e[15].comps = e[16].comps = 4;
}
void pad8(unsigned int &s) {
if((s & 0x00000007) != 0) {
s>>=3; s++; s<<=3;
}
}
void pad(unsigned int &size) {
while(size&0x3) size++;
}
void shuffle(float *buffer, unsigned int size, unsigned int stride) {
float *tmp = new float[size];
unsigned int count = 0;
unsigned int nelem = size/stride;
for(unsigned int s = 0; s < stride; s++) {
float *ptr = buffer + s;
for(unsigned int i = 0; i < nelem; i++) {
tmp[count++] = *ptr;
ptr += stride;
}
}
memcpy(buffer, tmp, size * sizeof(float));
delete []tmp;
}
void unshuffle(float *buffer, unsigned int size, unsigned int stride) {
float *tmp = new float[size];
unsigned int count = 0;
unsigned int nelem = size/stride;
for(unsigned int s = 0; s < stride; s++) {
float *ptr = tmp + s;
for(unsigned int i = 0; i < nelem; i++) {
*ptr = buffer[count++];
ptr += stride;
}
}
memcpy(buffer, tmp, size * sizeof(float));
delete []tmp;
}
void subtract(float *buffer, unsigned int size) {
float p = buffer[0];
float q;
for(unsigned int i = 1; i < size; i++) {
q = buffer[i];
buffer[i] -= p;
p = q;
}
}
void unsubtract(float *buffer, unsigned int size) {
for(unsigned int i = 1; i < size; i++)
buffer[i] += buffer[i-1];
}
Patch::Patch(Signature &signature, char *s,
unsigned short nvert, unsigned short nface):
fstart(s) {
Init(signature, nvert, nface);
}
void Patch::Init(Signature &signature,
unsigned short nvert, unsigned short nface) {
nv = nvert;
nf = nface;
unsigned int offset = 0;
if(signature.face == Signature::TRIANGLES)
offset += nf * 3 * sizeof(unsigned short);
else if (signature.face == Signature::STRIPS)
offset += nf * sizeof(unsigned short);
else if (signature.face == Signature::TETRAS)
offset += nf * 4 * sizeof(unsigned short);
else if (signature.face == Signature::SLICE) {
assert(0);
//non lo so...
}
pad8(offset);
fstartc = fstart + offset;
offset += encodings[signature.fcolor].size(nf);
fstartn = fstart + offset;
offset += encodings[signature.fnorm].size(nf);
fstartt = fstart + offset;
offset += encodings[signature.ftext].size(nf);
fstartd = fstart + offset;
offset += encodings[signature.fdata].size(nf);
vstart = fstart + offset;
if(signature.vert == Signature::POINT3F)
offset += nv * sizeof(float) * 3;
else if(signature.vert == Signature::POINT4F)
offset += nv * sizeof(float) * 4;
else
assert(0);
pad8(offset);
vstartc = fstart + offset;
offset += encodings[signature.vcolor].size(nv);
vstartn = fstart + offset;
offset += encodings[signature.vnorm].size(nv);
vstartt = fstart + offset;
offset += encodings[signature.vtext].size(nv);
vstartd = fstart + offset;
offset += encodings[signature.vdata].size(nv);
/* if(signature & NXS_FACES)
vstart = (float *)(((char *)start) + nf * sizeof(unsigned short) * 3);
else if(signature & NXS_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 * 3;
if(signature & NXS_COLORS)
nstart = cstart + nv;
else
nstart = cstart;
if(signature & NXS_NORMALS_SHORT)
tstart = nstart + nv * 2;
else if(signature & NXS_NORMALS_FLOAT)
tstart = nstart + nv * 3;
else
tstart = nstart;
if(signature & NXS_TEXTURES_SHORT)
dstart = tstart + nv;
else if(signature & NXS_TEXTURES_FLOAT)
dstart = tstart + nv;
else
dstart = tstart;*/
}
unsigned int Patch::ChunkSize(Signature &signature,
unsigned short nvert,
unsigned short nface,
unsigned int chunk_size) {
unsigned int size = ByteSize(signature, nvert, nface);
size = (size/chunk_size + 1);
return size;
}
unsigned int Patch::ByteSize(Signature &signature,
unsigned short nvert,
unsigned short nface) {
unsigned int size = 0;
if(signature.face == Signature::TRIANGLES)
size += nface * 3 * sizeof(unsigned short);
else if (signature.face == Signature::STRIPS)
size += nface * sizeof(unsigned short);
else if (signature.face == Signature::TETRAS)
size += nface * 4 * sizeof(unsigned short);
else if (signature.face == Signature::SLICE) {
assert(0);
//non lo so...
}
pad8(size);
size += encodings[signature.fcolor].size(nface);
size += encodings[signature.fnorm].size(nface);
size += encodings[signature.ftext].size(nface);
size += encodings[signature.fdata].size(nface);
if(signature.vert == Signature::POINT3F)
size += nvert * sizeof(float) * 3;
else if(signature.vert == Signature::POINT4F)
size += nvert * sizeof(float) * 4;
else
assert(0);
pad8(size);
size += encodings[signature.vcolor].size(nvert);
size += encodings[signature.vnorm].size(nvert);
size += encodings[signature.vtext].size(nvert);
size += encodings[signature.vdata].size(nvert);
//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;
/* unsigned int size = 0;
if(signature & NXS_STRIP)
size += nface * sizeof(unsigned short);
else if(signature & NXS_FACES)
size += nface * 3 * sizeof(unsigned short);
//memory alignment
pad(size);
size += nvert * sizeof(vcg::Point3f);
if(signature & NXS_COLORS)
size += nvert * sizeof(unsigned int);
if(signature & NXS_NORMALS_SHORT)
size += nvert * 4 * sizeof(short);
if(signature & NXS_NORMALS_FLOAT)
size += nvert * 3 * sizeof(float);
if(signature & NXS_TEXTURES_SHORT)
size += nvert * 2 * sizeof(short);
if(signature & NXS_TEXTURES_FLOAT)
size += nvert * 2 * sizeof(float);
if(signature & NXS_DATA8)
size += nvert * sizeof(char);
pad(size);
if(signature & NXS_DATA16)
size += nvert * 2 * sizeof(char);
pad(size);
if(signature & NXS_DATA32)
size += nvert * 4 * sizeof(char);
if(signature & NXS_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;*/
}
char *Patch::Compress(unsigned int ram_size, unsigned int &size) {
//lets use differences
// shuffle((float *)VertBegin(), nv * 3, 3);
// subtract((float *)VertBegin(), nv * 3);
//TODO use OVERLAP and test speed
//TODO fill chunk padding with zeroes?
size = ram_size + ram_size/64 + 23;
char *buffer = new char[size];
#ifdef WIN32
lzo1x_1_compress(((unsigned char *)fstart), ram_size,
(unsigned char *)buffer + sizeof(int), &size,
(char *)wrkmem);
#else
lzo1x_999_compress(((unsigned char *)fstart), ram_size,
(unsigned char *)buffer + sizeof(int), &size,
(char *)wrkmem);
lzo1x_optimize((unsigned char *)buffer + sizeof(int), size,
((unsigned char *)fstart), &ram_size,
NULL);
#endif
*(int *)buffer = size;
size += sizeof(int);
// memcpy(buffer, start, ram_size);
// size = ram_size;
return buffer;
}
void Patch::Decompress(unsigned int ram_size, void *src, unsigned int src_sz) {
unsigned int size = *(int *)src;
assert(size < src_sz + sizeof(int));
unsigned int dst_size = ram_size;
int ret = lzo1x_decompress_safe(((unsigned char *)src) + sizeof(int), size,
(unsigned char *)fstart, &dst_size, 0);
if(ret != 0) {
cerr << "Ret from decompress: " << ret << endl;
exit(-1);
}
assert(dst_size == ram_size);
//TODO add 3 to start... so we can use asm_fast decompressor
// unsubtract((float *)VertBegin(), nv * 3);
// unshuffle((float *)VertBegin(), nv * 3, 3);
}

View File

@ -1,169 +0,0 @@
/****************************************************************************
* VCGLib o o *
* Visual and Computer Graphics Library o o *
* _ O _ *
* Copyright(C) 2004 \/)\/ *
* Visual Computing Lab /\/| *
* ISTI - Italian National Research Council | *
* \ *
* All rights reserved. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
* for more details. *
* *
****************************************************************************/
/****************************************************************************
History
$Log: not supported by cvs2svn $
Revision 1.13 2005/02/19 12:06:55 ponchio
Debug...
Revision 1.12 2005/02/19 10:45:05 ponchio
Patch generalized and small fixes.
Revision 1.11 2005/02/08 12:43:03 ponchio
Added copyright
****************************************************************************/
#ifndef NXS_PATCH_H
#define NXS_PATCH_H
#include <vcg/space/point3.h>
#include <vcg/space/sphere3.h>
namespace nxs {
struct Signature {
enum Face { TRIANGLES = 1, STRIPS = 2, TETRAS = 3, SLICE = 4 };
enum Vert { POINT2F = 1, POINT2D = 2,
POINT3F = 2, POINT3D = 3,
POINT4F = 4, POINT4D = 5 };
enum Compr { LZO = 1 };
unsigned char face;
unsigned char vert;
unsigned char compr;
unsigned char future; //who knows...
unsigned char fcolor;
unsigned char fnorm;
unsigned char ftext;
unsigned char fdata;
unsigned char vcolor;
unsigned char vnorm;
unsigned char vtext;
unsigned char vdata;
Signature(): face(1), vert(2), compr(0), future(0),
fcolor(0), fnorm(0), ftext(0), fdata(0),
vcolor(0), vnorm(0), vtext(0), vdata(0) {}
};
struct Encoding {
unsigned char bytes; //size per element
unsigned char comps; //number of components
void (*pack)(char *start, unsigned int nelem);
void (*unpack)(char *start, unsigned int nelem);
unsigned int size(unsigned short n) {
unsigned int s = (int)n * (int)bytes * (int)comps;
//padding a 8 bytes
if((s & 0x0000007) != 0) {
s>>=3; s++; s<<=3;
}
return s;
}
};
struct Encodings {
enum Name { EMPTY = 0,
BYTE1 = 1, SHORT1 = 2, FLOAT1 = 3, DOUBLE1 = 4,
BYTE2 = 5, SHORT2 = 6, FLOAT2 = 7, DOUBLE2 = 8,
BYTE3 = 9, SHORT3 = 10, FLOAT3 = 11, DOUBLE3 = 12,
BYTE4 = 13, SHORT4 = 14, FLOAT4 = 15, DOUBLE4 = 16 };
Encodings();
Encoding &operator[](int n) { return e[n]; }
protected:
Encoding e[17];
};
class Patch {
public:
static Encodings encodings;
Patch(Signature &signature, char *s,
unsigned short nv, unsigned short nf);
void Init(Signature &signature, unsigned short nv, unsigned short nf);
vcg::Point3f *Vert3fBegin() { return (vcg::Point3f *)vstart; }
vcg::Point3f &Vert3f(int n) { return Vert3fBegin()[n]; }
unsigned short *FaceBegin() { return (unsigned short *)fstart; }
unsigned short *Face(int n) { return FaceBegin() + 3 * n; }
//vcg::Point3f &Vert(unsigned short v) { return VertBegin()[v]; }
// unsigned short *Face(unsigned short f) { return FaceBegin() + f * 3; }
char *VColorBegin() { return vstartc; }
char *VNormBegin() { return vstartn; }
char *VTextBegin() { return vstartt; }
char *VDataBegin() { return vstartd; }
char *FColorBegin() { return fstartc; }
char *FNormBegin() { return fstartn; }
char *FTextBegin() { return fstartt; }
char *FDataBegin() { return fstartd; }
static unsigned int ChunkSize(Signature &signature,
unsigned short nvert,
unsigned short nface,
unsigned int chunk_size);
static unsigned int ByteSize(Signature &signature,
unsigned short nvert,
unsigned short nface);
char *Compress(unsigned int ram_size, unsigned int &size);
void Decompress(unsigned int ram_size, void *src, unsigned int src_sz);
char *fstart;
char *vstart;
unsigned short nf;
unsigned short nv;
char *fstartc;
char *fstartn;
char *fstartt;
char *fstartd;
char *vstartc;
char *vstartn;
char *vstartt;
char *vstartd;
};
} //namespace
#endif

View File

@ -1,167 +0,0 @@
/****************************************************************************
* VCGLib o o *
* Visual and Computer Graphics Library o o *
* _ O _ *
* Copyright(C) 2004 \/)\/ *
* Visual Computing Lab /\/| *
* ISTI - Italian National Research Council | *
* \ *
* All rights reserved. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
* for more details. *
* *
****************************************************************************/
/****************************************************************************
History
$Log: not supported by cvs2svn $
Revision 1.3 2004/07/15 14:32:49 ponchio
Debug.
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.
Revision 1.2 2004/07/02 13:09:57 ponchio
*** empty log message ***
Revision 1.1 2004/06/23 00:08:05 ponchio
Created
****************************************************************************/
///TODO: allow other kinds of ply to be readed.
#include <string>
#include <iostream>
#include <wrap/ply/plylib.h>
#include "crude.h"
using namespace std;
using namespace vcg;
using namespace vcg::ply;
using namespace nxs;
struct PlyVertex {
float v[3];
};
struct PlyFace {
unsigned int f[3];
unsigned char flags;
};
PropDescriptor plyprop1[3]= {
{"vertex","x",T_FLOAT,T_FLOAT,offsetof(PlyVertex,v[0]),0,0,0,0,0},
{"vertex","y",T_FLOAT,T_FLOAT,offsetof(PlyVertex,v[1]),0,0,0,0,0},
{"vertex","z",T_FLOAT,T_FLOAT,offsetof(PlyVertex,v[2]),0,0,0,0,0}
};
PropDescriptor plyprop2[1]= {
{"face", "vertex_indices",T_INT,T_UINT,offsetof(PlyFace,f[0]),
1,0,T_UCHAR,T_UCHAR,offsetof(PlyFace,flags) }
};
int main(int argc, char *argv[]) {
if(argc <= 2) {
cerr << "Usage: " << argv[0] << " <input1.ply> <...> <inputN.ply> <output>\n";
return 0;
}
string output = argv[argc-1];
//test last one is not a ply
if(output.size() > 4 &&
output.substr(output.size()-4, output.size()) == ".ply") {
cerr << "Last argument is output (so not a .ply)\n";
return -1;
}
Crude crude;
if(!crude.Create(output, 0, 0)) {
cerr << "Could not create crude output\n";
return -1;
}
Box3f box;
box.SetNull();
for(int k = 1; k < argc-1; k++) {
PlyFile pf;
//Opening ply file
int val = pf.Open(argv[k], PlyFile::MODE_READ);
if(val == -1) {
cerr << "Could not open file '" << argv[k] << "'\n";
return false;
}
//testing for required vertex fields.
if( pf.AddToRead(plyprop1[0])==-1 ||
pf.AddToRead(plyprop1[1])==-1 ||
pf.AddToRead(plyprop1[2])==-1) {
cerr << "Error Ply file has not one of the required elements :"
<< "xyz coords\n";
return false;
}
//testing for required face fields.
if( pf.AddToRead(plyprop2[0])==-1 ) {
cerr << "Error Ply file has not one of the required elements:"
<< "faces\n";
return false;
}
unsigned int vertex_offset = crude.Vertices();
for(unsigned int i = 0; i < pf.elements.size(); i++) {
if(!strcmp( pf.ElemName(i),"vertex")) {
unsigned int n_vertices = pf.ElemNumber(i);
unsigned int offset = crude.Vertices();
crude.Resize(offset + n_vertices, crude.Faces());
cerr << "Adding " << n_vertices << " n_vertices" << endl;
pf.SetCurElement(i);
PlyVertex vertex;
Point3f p;
for(unsigned v = offset; v < offset + n_vertices; v++) {
pf.Read((void *) &vertex);
p[0] = vertex.v[0];
p[1] = vertex.v[1];
p[2] = vertex.v[2];
box.Add(p);
crude.SetVertex(v, vertex.v);
}
} else if( !strcmp( pf.ElemName(i),"face") ) {
unsigned int n_faces = pf.ElemNumber(i);
unsigned int offset = crude.Faces();
crude.Resize(crude.Vertices(), offset + n_faces);
cerr << "Adding " << n_faces << " n_faces" << endl;
pf.SetCurElement(i);
PlyFace face;
for(unsigned v = offset; v < offset + n_faces; v++) {
pf.Read((void *) &face);
face.f[0] += vertex_offset;
face.f[1] += vertex_offset;
face.f[2] += vertex_offset;
assert(face.f[0] < crude.Vertices() &&
face.f[1] < crude.Vertices() &&
face.f[2] < crude.Vertices());
crude.SetFace(v, face.f);
}
}
}
pf.Destroy();
}
crude.GetBox() = box;
return 0;
}

View File

@ -1,82 +0,0 @@
/****************************************************************************
* VCGLib o o *
* Visual and Computer Graphics Library o o *
* _ O _ *
* Copyright(C) 2004 \/)\/ *
* Visual Computing Lab /\/| *
* ISTI - Italian National Research Council | *
* \ *
* All rights reserved. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
* for more details. *
* *
****************************************************************************/
/****************************************************************************
History
$Log: not supported by cvs2svn $
Revision 1.7 2005/02/17 15:39:44 ponchio
Reorderes statistics a bit.
Revision 1.6 2005/02/08 12:43:03 ponchio
Added copyright
****************************************************************************/
#include "preload.h"
#include "nexusmt.h"
#include <iostream>
using namespace std;
using namespace nxs;
void Preload::execute() {
total_disk = 0;
disk = 0;
assert(mt);
while(!get_signaled()) {
trigger.wait();
lock.enter();
while(!queue.size()) {
trigger.reset();
lock.leave();
trigger.wait();
lock.enter();
}
//TODO check we are not loading too much memory!
assert(queue.size());
Item &item = queue.back();
if(item.error == 0 || mt->CanAdd(item)) {
//we cannot flush since we are not in the openGL thread
//and flushing includes VBO buffer flushing also.
Entry &entry = (*mt)[item.id];
if(!entry.patch) {
disk += entry.disk_size;
disk_tri += entry.nvert * 2;
}
Patch &patch = mt->GetPatch(item.id, item.error, false);
//test... make sure memory is in ram (if not on vbo that is.
if(!entry.vbo_array)
total_disk += patch.Face(0)[0];
queue.pop_back();
} else
queue.clear();
lock.leave();
}
}

View File

@ -1,87 +0,0 @@
/****************************************************************************
* VCGLib o o *
* Visual and Computer Graphics Library o o *
* _ O _ *
* Copyright(C) 2004 \/)\/ *
* Visual Computing Lab /\/| *
* ISTI - Italian National Research Council | *
* \ *
* All rights reserved. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
* for more details. *
* *
****************************************************************************/
/****************************************************************************
History
$Log: not supported by cvs2svn $
Revision 1.5 2005/02/17 15:39:44 ponchio
Reorderes statistics a bit.
Revision 1.4 2005/02/08 12:43:03 ponchio
Added copyright
****************************************************************************/
#ifndef NXS_PRELOAD_H
#define NXS_PRELOAD_H
#include <assert.h>
#include <vector>
#include <ptypes/pasync.h>
#include "extraction.h"
namespace nxs {
class NexusMt;
class Preload: public pt::thread{
public:
NexusMt *mt;
pt::mutex lock;
pt::trigger trigger;
std::vector<Item> queue;
unsigned int disk; //kbytes readed from disk
unsigned int disk_tri; //number of triangles readed from disk
unsigned int total_disk;
Preload(): thread(false), trigger(false, false) {}
~Preload() {
waitfor();
}
void execute();
void post(std::vector<Item> &patches) {
trigger.reset();
lock.enter();
queue.reserve(patches.size());
for(int i = patches.size() -1; i >= 0; i--)
queue.push_back(patches[i]);
trigger.post();
lock.leave();
}
void cleanup() {}
};
}
#endif

View File

@ -1,520 +0,0 @@
/****************************************************************************
* VCGLib o o *
* Visual and Computer Graphics Library o o *
* _ O _ *
* Copyright(C) 2004 \/)\/ *
* Visual Computing Lab /\/| *
* ISTI - Italian National Research Council | *
* \ *
* All rights reserved. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
* for more details. *
* *
****************************************************************************/
/****************************************************************************
History
$Log: not supported by cvs2svn $
Revision 1.11 2005/02/19 14:00:43 ponchio
Small opt.
Revision 1.10 2005/02/19 10:45:05 ponchio
Patch generalized and small fixes.
Revision 1.9 2005/02/08 12:43:03 ponchio
Added copyright
****************************************************************************/
#include <iostream>
#include "remapping.h"
#include "watch.h"
using namespace std;
using namespace vcg;
using namespace nxs;
bool BlockIndex::Save(const string &file) {
FILE *fp = fopen(file.c_str(), "wb+");
if(!fp) {
cerr << "Could not save: " << file << endl;
return false;
}
unsigned int nsize = size();
fwrite(&nsize, sizeof(unsigned int), 1, fp);
fwrite(&*begin(), sizeof(BlockEntry), nsize, fp);
fclose(fp);
return true;
}
bool BlockIndex::Load(const string &file) {
FILE *fp = fopen(file.c_str(), "rb");
if(!fp) {
cerr << "Could not load: " << file << endl;
return false;
}
unsigned int nsize;
fread(&nsize, sizeof(unsigned int), 1, fp);
resize(nsize);
fread(&*begin(), sizeof(BlockEntry), nsize, fp);
fclose(fp);
return true;
}
void nxs::Remap(VChain &chain,
VFile<vcg::Point3f> &points,
VFile<unsigned int> &remap,
BlockIndex &index,
unsigned int target_size,
unsigned int min_size,
unsigned int max_size,
float scaling,
int steps) {
VPartition *finepart = new VPartition;
chain.push_back(finepart);
BuildPartition(*finepart, points, target_size, min_size, max_size, steps);
VPartition *coarsepart = new VPartition;
chain.push_back(coarsepart);
BuildPartition(*coarsepart, points,
(int)(target_size/scaling), min_size, max_size, steps);
cerr << "Fine size: " << finepart->size() << endl;
cerr << "Coarse size: " << coarsepart->size() << endl;
// typedef map<pair<unsigned int, unsigned int>, unsigned int> FragIndex;
typedef map<unsigned int, map<unsigned int, unsigned int> > FragIndex;
FragIndex patches;
unsigned int totpatches = 0;
vector<unsigned int> count;
Point3f bari;
for(unsigned int i = 0; i < points.Size(); i++) {
bari = points[i];
unsigned int fine = finepart->Locate(bari);
unsigned int coarse = coarsepart->Locate(bari);
unsigned int patch;
if(!patches.count(coarse) || !patches[coarse].count(fine)) {
patch = totpatches;
patches[coarse][fine] = totpatches++;
} else
patch = patches[coarse][fine];
remap[i] = patch;
while(count.size() <= patch)
count.push_back(0);
count[patch]++;
}
for(unsigned int i = 0; i < totpatches; i++) {
if(count[i] > 32000) {
//TODO do something to reduce patch size... :P
cerr << "Found a patch too big... sorry\n";
exit(0);
}
}
unsigned int mean = 0;
for(unsigned int i = 0; i < count.size(); i++)
mean += count[i];
mean /= count.size();
min_size /= 4;
cerr << "Pruning small patches... < " << min_size << " mean: " << mean << endl;
//prune small patches
vector<int> patch_map;
patch_map.resize(totpatches);
for(unsigned int i = 0; i < totpatches; i++)
patch_map[i] = i;
for(FragIndex::iterator s = patches.begin(); s != patches.end(); s++) {
map<unsigned int, unsigned int> &fines = (*s).second;
while(1) {
if(fines.size() <= 1) break;
unsigned int inf_fine = 0xffffffff;
unsigned int inf_count, min_count;
unsigned int min_fine = 0xffffffff;
unsigned int min_patch, inf_patch;
map<unsigned int, unsigned int>::iterator t;
for(t = fines.begin(); t != fines.end(); t++) {
unsigned int c = count[(*t).second];
if(inf_fine == 0xffffffff || c < inf_count) {
if(inf_fine != 0xffffffff) {
min_fine = inf_fine;
min_count = inf_count;
min_patch = inf_patch;
}
inf_fine = (*t).first;
inf_count = c;
inf_patch = (*t).second;
} else if(min_fine == 0xffffffff || c < min_count) {
min_fine = (*t).first;
min_count = c;
min_patch = (*t).second;
}
}
if(inf_count >= min_size ||
inf_count + min_count > max_size) break;
count[min_patch] += count[inf_patch];
patch_map[inf_patch] = min_patch;
fines.erase(inf_fine);
}
}
for(unsigned int i = 0; i < totpatches; i++)
while(patch_map[patch_map[i]] != patch_map[i])
patch_map[i] = patch_map[patch_map[i]];
//now we remap remaining patches into 0 - n.
unsigned int new_totpatches = 0;
vector<int> patch_remap;
patch_remap.resize(totpatches, -1);
for(unsigned int i = 0; i < totpatches; i++) {
unsigned int p = patch_map[i];
if(patch_remap[p] == -1)
patch_remap[p] = new_totpatches++;
patch_remap[i] = patch_remap[p];
}
cerr << "Building fragments\n";
//building fragments
for(FragIndex::iterator s = patches.begin(); s != patches.end(); s++) {
unsigned int coarse = (*s).first;
map<unsigned int, unsigned int> &fines = (*s).second;
map<unsigned int, unsigned int>::iterator t;
for(t = fines.begin(); t != fines.end(); t++) {
unsigned int fine = (*t).first;
unsigned int oldpatch = (*t).second;
assert(oldpatch < patch_remap.size());
unsigned int patch = patch_remap[oldpatch];
if(patch != -1) //not deleted...
chain.oldfragments[coarse].insert(patch);
}
}
cerr << "remapping faces again\n";
//remapping faces
index.resize(new_totpatches);
for(unsigned int i = 0; i < remap.Size(); i++) {
unsigned int patch = remap[i];
#ifdef CONTROLS
if(patch == 0xffffffff) {
cerr << "RESIGH\n";
exit(0);
}
if(patch_remap[patch] == -1) {//must relocate this thing....
//TODO
cerr << "Could not do this\n";
exit(0);
}
#endif
unsigned int newpatch = patch_remap[patch];
assert(newpatch < index.size());
remap[i] = newpatch;
BlockEntry &entry = index[newpatch];
entry.size++;
}
cerr << "fixing offsets in index\n";
//Fixing offset
int64 offset = 0;
for(unsigned int i = 0; i < index.size(); i++) {
assert(index[i].size < 65000);
index[i].offset = offset;
offset += index[i].size;
}
}
void nxs::BuildPartition(VPartition &part,
VFile<vcg::Point3f> &points,
unsigned int target_size,
unsigned int min_size,
unsigned int max_size,
int steps) {
//TODO: improve quality of patches and implement threshold.
unsigned int ncells = points.Size()/target_size;
cerr << "Target partition size: " << ncells
<< " mean: " << points.Size()/ncells << endl;
srand(0);
for(unsigned int i = 0; i < points.Size(); i++) {
int f = (int)(target_size * (float)rand()/(RAND_MAX + 1.0));
if(f == 2) {
Point3f &point = points[i];
part.push_back(point);
}
}
//TODO! Check for duplicates (use the closest :P)
part.Init();
vector<Point3f> centroids;
vector<unsigned int> counts;
for(int step = 0; step < steps; step++) {
cerr << "Optimization step: " << step+1 << "/" << steps << endl;
centroids.clear();
counts.clear();
centroids.resize(part.size(), Point3f(0, 0, 0));
counts.resize(part.size(), 0);
Report report(points.Size());
for(unsigned int v = 0; v < points.Size(); v++) {
if(v & 0xffff == 0xffff)
report.Step(v);
unsigned int target = part.Locate(points[v]);
centroids[target] += points[v];
counts[target]++;
}
for(unsigned int v = 0; v < centroids.size(); v++)
if(counts[v] != 0)
centroids[v]/= counts[v];
double quality = 0;
for(int i = 0; i < part.size(); i++)
quality += (counts[i] - target_size) * (counts[i] - target_size);
cerr << "Quality: " << quality << endl;
if(step == steps-1) {
if(!Optimize(part, ncells, target_size, min_size, max_size,
centroids, counts, false))
step--;
} else
Optimize(part, ncells, target_size, min_size, max_size,
centroids, counts, true);
}
cerr << "Partition size: " << part.size()
<< " mean: " << (float)(points.Size()/part.size()) << endl << endl;
}
void nxs::BuildLevel(VChain &chain,
Nexus &nexus,
unsigned int offset,
float scaling,
unsigned int target_size,
unsigned int min_size,
unsigned int max_size,
int steps) {
unsigned int totface = 0;
unsigned int totvert = 0;
for(unsigned int idx = offset; idx < nexus.size(); idx++) {
totface += nexus[idx].nface;
totvert += nexus[idx].nvert;
}
VPartition *fine = chain[chain.size()-1];
fine->Init();
VPartition *coarse = new VPartition;
chain.push_back(coarse);
//unsigned int ncells = (unsigned int)(fine.size() * scaling);
unsigned int ncells = (unsigned int)(scaling * totface/target_size);
//TODO this method for selecting the seeds is ugly!
float ratio = ncells/(float)(nexus.size() - offset);
float cratio = 0;
for(unsigned int idx = offset; idx < nexus.size(); idx++) {
cratio += ratio;
if(cratio > 1) {
Patch patch = nexus.GetPatch(idx);
Point3f &v = patch.Vert3f(0);
coarse->push_back(v);
cratio -= 1;
}
}
if(coarse->size() == 0) {
Patch patch = nexus.GetPatch(0);
coarse->push_back(patch.Vert3f(0));
}
float coarse_vmean = totface/(float)coarse->size();
coarse->Init();
cerr << "Ncells: " << ncells << endl;
cerr << "Coarse size: " << coarse->size() << endl;
cerr << "Coarse mean: " << coarse_vmean << " mean_size: " << target_size << endl;
//here goes some optimization pass.
//Coarse optimization.
vector<Point3f> centroids;
vector<unsigned int> counts;
for(int step = 0; step < steps; step++) {
cerr << "Optimization step: " << step+1 << "/" << steps << endl;
centroids.clear();
counts.clear();
centroids.resize(coarse->size(), Point3f(0, 0, 0));
counts.resize(coarse->size(), 0);
Report report(nexus.size());
for(unsigned int idx = offset; idx < nexus.size(); idx++) {
report.Step(idx);
Patch patch = nexus.GetPatch(idx);
for(unsigned int i = 0; i < patch.nf; i++) {
unsigned short *face = patch.Face(i);
Point3f bari = (patch.Vert3f(face[0]) +
patch.Vert3f(face[1]) +
patch.Vert3f(face[2]))/3;
assert(coarse->size() > 0);
unsigned int target = coarse->Locate(bari);
assert(target < coarse->size());
centroids[target] += bari;
counts[target]++;
}
}
for(unsigned int v = 0; v < centroids.size(); v++)
if(counts[v] != 0)
centroids[v]/= counts[v];
if(step == steps-1) {
if(!Optimize(*coarse, ncells, (int)coarse_vmean, min_size, max_size,
centroids, counts, false))
step--;
} else
Optimize(*coarse, ncells, (int)coarse_vmean, min_size, max_size,
centroids, counts, true);
}
chain.newfragments.clear();
}
int nxs::GetBest(VPartition &part, unsigned int seed,
vector<bool> &mark,
vector<unsigned int> &counts) {
vector<int> nears;
vector<float> dists;
int nnear = 7;
if(part.size() < 7) nnear = part.size()/2;
if(!nnear) return -1;
part.Closest(part[seed], nnear, nears, dists);
int best = -1;
int bestcount = -1;
int bestdist = -1;
for(int k = 0; k < nnear; k++) {
int c = nears[k];
if(c == seed) continue;
assert(c >= 0);
assert(c < part.size());
if(mark[c]) continue;
if(bestcount < 0 ||
(counts[c] < bestcount)) {
best = c;
bestcount = counts[c];
}
}
return best;
}
bool nxs::Optimize(VPartition &part,
unsigned int target_cells,
unsigned int target_size,
unsigned int min_size,
unsigned int max_size,
vector<Point3f> &centroids,
vector<unsigned int> &counts,
bool join) {
if(max_size > target_size *3)
max_size = target_size * 3;
min_size = (unsigned int)(target_size * 0.3f);
unsigned int toobig = 0;
unsigned int toosmall = 0;
for(unsigned int i = 0; i < part.size(); i++) {
if(counts[i] > max_size) toobig++;
if(counts[i] < min_size) toosmall--;
}
unsigned int close = part.size()/2;
if(close < 1) close = 1;
if(close > 10) close = 10;
unsigned int failed = 0;
vector<Point3f> seeds;
vector<bool> mark;
mark.resize(part.size(), false);
vector<int> nears;
vector<float> dists;
//removing small ones.
for(unsigned int i = 0; i < part.size(); i++) {
if(counts[i] > max_size) {
float radius;
if(part.size() == 1)
radius = 0.00001;
else
radius = part.Radius(i)/4;
seeds.push_back(centroids[i] + Point3f(1, -1, 1) * radius);
seeds.push_back(centroids[i] + Point3f(-1, 1, 1) * radius);
seeds.push_back(centroids[i] + Point3f(-1, -1, -1) * radius);
seeds.push_back(centroids[i] + Point3f(1, 1, -1) * radius);
continue;
}
if(counts[i] < min_size)
continue;
part.Closest(part[i], close, nears, dists);
Point3f dir(0,0,0);
for(unsigned int k = 0; k < close; k++) {
unsigned int n = nears[k];
float c = (target_size - (float)counts[n])/
((float)target_size * close);
dir += (centroids[i] - part[n]) * c;
}
seeds.push_back(centroids[i] + dir);
}
part.clear();
for(unsigned int i = 0; i < seeds.size(); i++)
part.push_back(seeds[i]);
if(part.size() == 0) {
cerr << "OOOPS i accidentally deleted all seeds... backup :P\n";
part.push_back(Point3f(0,0,0));
}
part.Init();
return true;
}

View File

@ -1,95 +0,0 @@
/****************************************************************************
* VCGLib o o *
* Visual and Computer Graphics Library o o *
* _ O _ *
* Copyright(C) 2004 \/)\/ *
* Visual Computing Lab /\/| *
* ISTI - Italian National Research Council | *
* \ *
* All rights reserved. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
* for more details. *
* *
****************************************************************************/
/****************************************************************************
History
$Log: not supported by cvs2svn $
****************************************************************************/
#ifndef NXS_REMAPPING_H
#define NXS_REMAPPING_H
#include <vector>
#include <string>
#include "nxstypes.h"
#include "vchain.h"
#include "nexus.h"
#include "vfile.h"
namespace nxs {
struct BlockEntry {
BlockEntry(int64 o = 0, unsigned int s = 0): offset(o), size(s) {}
int64 offset;
unsigned int size;
};
class BlockIndex: public std::vector<nxs::BlockEntry> {
public:
bool Save(const std::string &file);
bool Load(const std::string &file);
};
void Remap(VChain &chain,
VFile<vcg::Point3f> &points,
VFile<unsigned int> &remap,
BlockIndex &index,
unsigned int target_size,
unsigned int min_size,
unsigned int max_size,
float scaling,
int step);
void BuildPartition(VPartition &part,
VFile<vcg::Point3f> &points,
unsigned int target_size,
unsigned int min_size,
unsigned int max_size,
int steps);
void BuildLevel(VChain &chain,
Nexus &nexus,
unsigned int offset,
float scaling,
unsigned int target_size,
unsigned int min_size,
unsigned int max_size,
int steps);
//removes small or really big patches.
bool Optimize(VPartition &part,
unsigned int target_cells,
unsigned int target_size,
unsigned int min_size,
unsigned int max_size,
std::vector<vcg::Point3f> &centroids,
std::vector<unsigned int> &counts,
bool join);
int GetBest(VPartition &part, unsigned int seed,
std::vector<bool> &mark,
std::vector<unsigned int> &counts);
}
#endif

View File

@ -1,67 +0,0 @@
#include <assert.h>
//These header are neede byt tristipper...
#include <list>
#include <vector>
#include <map>
#include "tristripper/tri_stripper.h"
using namespace triangle_stripper;
#include "strip.h"
using namespace std;
using namespace nxs;
void nxs::ComputeTriStrip(unsigned short nfaces, unsigned short *faces,
vector<unsigned short> &strip) {
vector<unsigned int> index;
index.resize(nfaces*3);
for(int i = 0; i < nfaces*3; i++)
index[i] = faces[i];
int cache_size = 16;
tri_stripper stripper(index);
stripper.SetCacheSize(cache_size);
// = 0 will disable the cache optimizer
stripper.SetMinStripSize(0);
tri_stripper::primitives_vector primitives;
stripper.Strip(&primitives);
if(primitives.back().m_Indices.size() < 3)
primitives.pop_back();
//TODO do this when mounting strips together.
if(primitives.back().m_Type == tri_stripper::PT_Triangles) {
tri_stripper::primitives p;
p = primitives.back();
primitives.pop_back();
for(unsigned int i = 0; i < p.m_Indices.size(); i += 3) {
tri_stripper::primitives s;
s.m_Type = tri_stripper::PT_Triangle_Strip;
s.m_Indices.push_back(p.m_Indices[i]);
s.m_Indices.push_back(p.m_Indices[i+1]);
s.m_Indices.push_back(p.m_Indices[i+2]);
primitives.push_back(s);
}
}
for(unsigned int i = 0; i < primitives.size(); i++) {
tri_stripper::primitives &primitive = primitives[i];
assert(primitive.m_Indices.size() != 0);
int len = primitive.m_Indices.size();
for(int l = 0; l < len; l++)
strip.push_back(primitive.m_Indices[l]);
if(i < primitives.size()-1) { //not the last primitive.
strip.push_back(primitive.m_Indices[len-1]);
//TODO optimize this!
if((len%2) == 1) //do not change orientation....
strip.push_back(primitive.m_Indices[len-1]);
strip.push_back(primitives[i+1].m_Indices[0]);
}
}
}

View File

@ -1,12 +0,0 @@
#ifndef NXS_TRISTRIP_H
#define NXS_TRISTRIP_H
#include <vector>
namespace nxs {
void ComputeTriStrip(unsigned short nfaces, unsigned short *faces,
std::vector<unsigned short> &strip);
}
#endif

View File

@ -1,419 +0,0 @@
// graph_array.h: interface for the graph_array class.
//
//////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2002 Tanguy Fautré.
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
//
// Tanguy Fautré
// softdev@pandora.be
//
//////////////////////////////////////////////////////////////////////
//
// Semi-dynamic directed graph
// ***************************
//
// Current version: 3.00 BETA 3 (04/12/2002)
//
// Comment: graph_array is equivalent to an array of nodes linked by
// arcs.
// This means you can't change the size (the number of nodes)
// of the graph once you created it (setsize() will delete
// any previous nodes and arcs).
// But you can add or remove arcs.
//
// History: - 3.00 BETA 3 (04/12/2002) - Added empty()
// - Changed some parameters from copy to reference
// - Fixed a bug with erase_arc
// - Un-inlined external functions
// - Added "insert_arc" which is equivalent to "insert"
// - 3.00 BETA 2 (16/11/2002) - Improved portability
// - 3.00 BETA 1 (27/08/2002) - First public release
//
//////////////////////////////////////////////////////////////////////
#pragma once
// namespace common_structures
namespace common_structures {
// graph_array main class
template <class nodetype, class arctype>
class graph_array
{
public:
class arc;
class node;
// New types
typedef size_t nodeid;
typedef std::vector<node>::iterator node_iterator;
typedef std::vector<node>::const_iterator const_node_iterator;
typedef std::vector<node>::reverse_iterator node_reverse_iterator;
typedef std::vector<node>::const_reverse_iterator const_node_reverse_iterator;
typedef graph_array<nodetype, arctype> _mytype;
// graph_array::arc class
class arc
{
public:
arc & mark() { m_Marker = true; return (* this); }
arc & unmark() { m_Marker = false; return (* this); }
bool marked() const { return m_Marker; }
node_iterator initial() const { return m_Initial; }
node_iterator terminal() const { return m_Terminal; }
arctype & operator * () { return m_Elem; }
arctype * operator -> () { return &m_Elem; }
const arctype & operator * () const { return m_Elem; }
const arctype * operator -> () const { return &m_Elem; }
protected:
friend class graph_array<nodetype, arctype>;
arc(const node_iterator & Initial, const node_iterator & Terminal)
: m_Initial(Initial), m_Terminal(Terminal), m_Marker(false) { }
arc(const node_iterator & Initial, const node_iterator & Terminal, const arctype & Elem)
: m_Initial(Initial), m_Terminal(Terminal), m_Elem(Elem), m_Marker(false) { }
node_iterator m_Initial;
node_iterator m_Terminal;
arctype m_Elem;
bool m_Marker;
};
// New types
typedef std::list<arc>::iterator out_arc_iterator;
typedef std::list<arc>::const_iterator const_out_arc_iterator;
// graph_array::node class
class node
{
public:
node & mark() { m_Marker = true; return (* this); }
node & unmark() { m_Marker = false; return (* this); }
bool marked() const { return m_Marker; }
bool out_empty() const { return m_OutArcs.empty(); }
size_t number_of_out_arcs() const { return m_OutArcs.size(); }
out_arc_iterator out_begin() { return m_OutArcs.begin(); }
out_arc_iterator out_end() { return m_OutArcs.end(); }
const_out_arc_iterator out_begin() const { return m_OutArcs.begin(); }
const_out_arc_iterator out_end() const { return m_OutArcs.end(); }
nodetype & operator * () { return m_Elem; }
nodetype * operator -> () { return &m_Elem; }
const nodetype & operator * () const { return m_Elem; }
const nodetype * operator -> () const { return &m_Elem; }
nodetype & operator = (const nodetype & Elem) { return (m_Elem = Elem); }
protected:
friend class graph_array<nodetype, arctype>;
friend class std::vector<node>;
node() : m_Marker(false) { }
std::list<arc> m_OutArcs;
nodetype m_Elem;
bool m_Marker;
};
// Construction/Destruction
graph_array();
explicit graph_array(const size_t NbNodes);
// Node related member functions
void clear();
bool empty() const;
void setsize(const size_t NbNodes);
size_t size() const;
node & operator [] (const nodeid & i);
const node & operator [] (const nodeid & i) const;
node_iterator begin();
node_iterator end();
const_node_iterator begin() const;
const_node_iterator end() const;
node_reverse_iterator rbegin();
node_reverse_iterator rend();
const_node_reverse_iterator rbegin() const;
const_node_reverse_iterator rend() const;
// Arc related member functions
size_t number_of_arcs() const;
void erase_arcs();
void erase_arcs(const node_iterator & Initial);
out_arc_iterator erase_arc(const out_arc_iterator & Pos);
out_arc_iterator insert_arc(const nodeid & Initial, const nodeid & Terminal);
out_arc_iterator insert_arc(const nodeid & Initial, const nodeid & Terminal, const arctype & Elem);
out_arc_iterator insert_arc(const node_iterator & Initial, const node_iterator & Terminal);
out_arc_iterator insert_arc(const node_iterator & Initial, const node_iterator & Terminal, const arctype & Elem);
// Another interface for insert_arc
out_arc_iterator insert(const nodeid & Initial, const nodeid & Terminal) { return insert_arc(Initial, Terminal); }
out_arc_iterator insert(const nodeid & Initial, const nodeid & Terminal, const arctype & Elem) { return insert_arc(Initial, Terminal, Elem); }
out_arc_iterator insert(const node_iterator & Initial, const node_iterator & Terminal) { return insert_arc(Initial, Terminal); }
out_arc_iterator insert(const node_iterator & Initial, const node_iterator & Terminal, const arctype & Elem) { return insert_arc(Initial, Terminal, Elem); }
// Optimized (overloaded) functions
void swap(_mytype & Right);
friend void swap(_mytype & Left, _mytype & Right) { Left.swap(Right); }
protected:
size_t m_NbArcs;
std::vector<node> m_Nodes;
};
// Additional "low level", graph related, functions
template <class nodetype, class arctype>
void unmark_nodes(graph_array<nodetype, arctype> & G);
template <class nodetype, class arctype>
void unmark_arcs_from_node(graph_array<nodetype, arctype>::node & N);
template <class nodetype, class arctype>
void unmark_arcs(graph_array<nodetype, arctype> & G);
//////////////////////////////////////////////////////////////////////////
// graph_array Inline functions
//////////////////////////////////////////////////////////////////////////
template <class nodetype, class arctype>
inline graph_array<nodetype, arctype>::graph_array() : m_NbArcs(0) { }
template <class nodetype, class arctype>
inline graph_array<nodetype, arctype>::graph_array(const size_t NbNodes) : m_NbArcs(0), m_Nodes(NbNodes) { }
template <class nodetype, class arctype>
inline void graph_array<nodetype, arctype>::clear() {
m_NbArcs = 0;
m_Nodes.clear();
}
template <class nodetype, class arctype>
inline bool graph_array<nodetype, arctype>::empty() const {
return m_Nodes.empty();
}
template <class nodetype, class arctype>
inline size_t graph_array<nodetype, arctype>::size() const {
return m_Nodes.size();
}
template <class nodetype, class arctype>
inline void graph_array<nodetype, arctype>::setsize(const size_t NbNodes) {
clear();
m_Nodes.resize(NbNodes);
}
template <class nodetype, class arctype>
inline graph_array<nodetype, arctype>::node & graph_array<nodetype, arctype>::operator [] (const nodeid & i) {
// Debug check
assert(i < size());
return m_Nodes[i];
}
template <class nodetype, class arctype>
inline const graph_array<nodetype, arctype>::node & graph_array<nodetype, arctype>::operator [] (const nodeid & i) const {
// Debug check
assert(i < size());
return m_Nodes[i];
}
template <class nodetype, class arctype>
inline graph_array<nodetype, arctype>::node_iterator graph_array<nodetype, arctype>::begin() {
return m_Nodes.begin();
}
template <class nodetype, class arctype>
inline graph_array<nodetype, arctype>::node_iterator graph_array<nodetype, arctype>::end() {
return m_Nodes.end();
}
template <class nodetype, class arctype>
inline graph_array<nodetype, arctype>::const_node_iterator graph_array<nodetype, arctype>::begin() const {
return m_Nodes.begin();
}
template <class nodetype, class arctype>
inline graph_array<nodetype, arctype>::const_node_iterator graph_array<nodetype, arctype>::end() const {
return m_Nodes.end();
}
template <class nodetype, class arctype>
inline graph_array<nodetype, arctype>::node_reverse_iterator graph_array<nodetype, arctype>::rbegin() {
return m_Nodes.rbegin();
}
template <class nodetype, class arctype>
inline graph_array<nodetype, arctype>::node_reverse_iterator graph_array<nodetype, arctype>::rend() {
return m_Nodes.rend();
}
template <class nodetype, class arctype>
inline graph_array<nodetype, arctype>::const_node_reverse_iterator graph_array<nodetype, arctype>::rbegin() const {
return m_Nodes.rbegin();
}
template <class nodetype, class arctype>
inline graph_array<nodetype, arctype>::const_node_reverse_iterator graph_array<nodetype, arctype>::rend() const {
return m_Nodes.rend();
}
template <class nodetype, class arctype>
inline size_t graph_array<nodetype, arctype>::number_of_arcs() const {
return m_NbArcs;
}
template <class nodetype, class arctype>
inline graph_array<nodetype, arctype>::out_arc_iterator graph_array<nodetype, arctype>::insert_arc(const nodeid & Initial, const nodeid & Terminal) {
return (insert(begin() + Initial, begin() + Terminal));
}
template <class nodetype, class arctype>
inline graph_array<nodetype, arctype>::out_arc_iterator graph_array<nodetype, arctype>::insert_arc(const nodeid & Initial, const nodeid & Terminal, const arctype & Elem) {
return (insert(begin() + Initial, begin() + Terminal, Elem));
}
template <class nodetype, class arctype>
inline graph_array<nodetype, arctype>::out_arc_iterator graph_array<nodetype, arctype>::insert_arc(const node_iterator & Initial, const node_iterator & Terminal) {
++m_NbArcs;
Initial->m_OutArcs.push_back(arc(Initial, Terminal));
return (--(Initial->m_OutArcs.end()));
}
template <class nodetype, class arctype>
inline graph_array<nodetype, arctype>::out_arc_iterator graph_array<nodetype, arctype>::insert_arc(const node_iterator & Initial, const node_iterator & Terminal, const arctype & Elem) {
++m_NbArcs;
Initial->m_OutArcs.push_back(arc(Initial, Terminal, Elem));
return (--(Initial->m_OutArcs.end()));
}
template <class nodetype, class arctype>
inline graph_array<nodetype, arctype>::out_arc_iterator graph_array<nodetype, arctype>::erase_arc(const out_arc_iterator & Pos) {
--m_NbArcs;
return (Pos->initial()->m_OutArcs.erase(Pos));
}
template <class nodetype, class arctype>
inline void graph_array<nodetype, arctype>::erase_arcs(const node_iterator & Initial) {
m_NbArcs -= (Initial->m_OutArcs.size());
Initial->m_OutArcs.clear();
}
template <class nodetype, class arctype>
inline void graph_array<nodetype, arctype>::erase_arcs() {
m_NbArcs = 0;
for (nodeid i = 0; i < Size(); ++i)
m_Nodes[i].m_OutArcs.clear();
}
template <class nodetype, class arctype>
inline void graph_array<nodetype, arctype>::swap(_mytype & Right) {
std::swap(m_NbArcs, Right.m_NbArcs);
std::swap(m_Nodes, Right.m_Nodes);
}
//////////////////////////////////////////////////////////////////////////
// additional functions
//////////////////////////////////////////////////////////////////////////
template <class nodetype, class arctype>
void unmark_nodes(graph_array<nodetype, arctype> & G)
{
typedef graph_array<nodetype, arctype>::node_iterator node_it;
for (node_it NodeIt = G.begin(); NodeIt != G.end(); ++NodeIt)
NodeIt->unmark();
}
template <class nodetype, class arctype>
void unmark_arcs_from_node(graph_array<nodetype, arctype>::node & N)
{
typedef graph_array<nodetype, arctype>::out_arc_iterator arc_it;
for (arc_it ArcIt = N.out_begin(); ArcIt != N.out_end(); ++ArcIt)
ArcIt->unmark();
}
template <class nodetype, class arctype>
void unmark_arcs(graph_array<nodetype, arctype> & G)
{
typedef graph_array<nodetype, arctype>::node_iterator node_it;
for (node_it NodeIt = G.begin(); NodeIt != G.end(); ++NodeIt)
unmark_arcs_from_node(* NodeIt);
}
}; // namespace common_structures

View File

@ -1,275 +0,0 @@
// heap_array.h: interface for the heap_array class.
//
//////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2002 Tanguy Fautré.
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
//
// Tanguy Fautré
// softdev@pandora.be
//
//////////////////////////////////////////////////////////////////////
//
// Semi-dynamic indexed heap
// *************************
//
// Current version: 1.00 BETA 1 (24/10/2002)
//
// Comment: heap_array acts like a normal heap, you can push elements
// and then get the greatest one.
// However you cannot push any more element once an element
// has been removed (pop, erase, etc...).
// Elements can be modified after they've been pushed into
// the heap via their indice.
//
// History: -
//
//////////////////////////////////////////////////////////////////////
#pragma once
// namespace common_structures
namespace common_structures {
template <class T, class CmpT = std::less<T> >
class heap_array
{
public:
struct heap_is_locked { };
// heap_array main interface. Pre = PreCondition, Post = PostCondition
heap_array() : m_Locked(false) { } // Post: ((size() == 0) && ! locked())
void clear(); // Post: ((size() == 0) && ! locked())
void reserve(size_t Size);
size_t size() const;
bool empty() const;
bool locked() const;
bool removed(size_t i) const; // Pre: (valid(i))
bool valid(size_t i) const;
const T & top() const; // Pre: (! empty())
const T & peek(size_t i) const; // Pre: (valid(i) && ! removed(i))
const T & operator [] (size_t i) const; // Pre: (valid(i) && ! removed(i))
size_t push(const T & Elem); // Pre: (! locked()) else throw (heap_is_locked)
void pop(); // Pre: (! empty()) Post: (locked())
void erase(size_t i); // Pre: (valid(i) && ! removed(i)) Post: (locked())
void update(size_t i, const T & Elem); // Pre: (valid(i) && ! removed(i)) Post: (locked())
protected:
struct linker {
linker(const T & Elem, size_t i) : m_Elem(Elem), m_Indice(i) { }
T m_Elem;
size_t m_Indice;
};
typedef std::vector<linker> linked_heap;
typedef std::vector<size_t> finder;
void Adjust(size_t i);
void Swap(size_t a, size_t b);
bool Less(const linker & a, const linker & b) const;
linked_heap m_Heap;
finder m_Finder;
CmpT m_Compare;
bool m_Locked;
};
//////////////////////////////////////////////////////////////////////////
// heap_indexed Inline functions
//////////////////////////////////////////////////////////////////////////
template <class T, class CmpT>
inline void heap_array<T, CmpT>::clear() {
m_Heap.clear();
m_Finder.clear();
m_Locked = false;
}
template <class T, class CmpT>
inline bool heap_array<T, CmpT>::empty() const {
return m_Heap.empty();
}
template <class T, class CmpT>
inline bool heap_array<T, CmpT>::locked() const {
return m_Locked;
}
template <class T, class CmpT>
inline void heap_array<T, CmpT>::reserve(size_t Size) {
m_Heap.reserve(Size);
m_Finder.reserve(Size);
}
template <class T, class CmpT>
inline size_t heap_array<T, CmpT>::size() const {
return m_Heap.size();
}
template <class T, class CmpT>
inline const T & heap_array<T, CmpT>::top() const {
// Debug check to ensure heap is not empty
assert(! empty());
return m_Heap.front().m_Elem;
}
template <class T, class CmpT>
inline const T & heap_array<T, CmpT>::peek(size_t i) const {
// Debug check to ensure element is still present
assert(! removed(i));
return (m_Heap[m_Finder[i]].m_Elem);
}
template <class T, class CmpT>
inline const T & heap_array<T, CmpT>::operator [] (size_t i) const {
return peek(i);
}
template <class T, class CmpT>
inline void heap_array<T, CmpT>::pop() {
m_Locked = true;
// Debug check to ensure heap is not empty
assert(! empty());
Swap(0, size() - 1);
m_Heap.pop_back();
Adjust(0);
}
template <class T, class CmpT>
inline size_t heap_array<T, CmpT>::push(const T & Elem) {
if (m_Locked)
throw heap_is_locked();
size_t Id = size();
m_Finder.push_back(Id);
m_Heap.push_back(linker(Elem, Id));
Adjust(Id);
return Id;
}
template <class T, class CmpT>
inline void heap_array<T, CmpT>::erase(size_t i) {
m_Locked = true;
// Debug check to ensure element is still present
assert(! removed(i));
size_t j = m_Finder[i];
Swap(j, size() - 1);
m_Heap.pop_back();
Adjust(j);
}
template <class T, class CmpT>
inline bool heap_array<T, CmpT>::removed(size_t i) const {
return (m_Finder[i] >= m_Heap.size());
}
template <class T, class CmpT>
inline bool heap_array<T, CmpT>::valid(size_t i) const {
return (i < m_Finder.size());
}
template <class T, class CmpT>
inline void heap_array<T, CmpT>::update(size_t i, const T & Elem) {
// Debug check to ensure element is still present
assert(! removed(i));
size_t j = m_Finder[i];
m_Heap[j].m_Elem = Elem;
Adjust(j);
}
template <class T, class CmpT>
inline void heap_array<T, CmpT>::Adjust(size_t i) {
size_t j;
// Check the upper part of the heap
for (j = i; (j > 0) && (Less(m_Heap[(j - 1) / 2], m_Heap[j])); j = ((j - 1) / 2))
Swap(j, (j - 1) / 2);
// Check the lower part of the heap
for (i = j; (j = 2 * i + 1) < size(); i = j) {
if ((j + 1 < size()) && (Less(m_Heap[j], m_Heap[j + 1])))
++j;
if (Less(m_Heap[j], m_Heap[i]))
return;
Swap(i, j);
}
}
template <class T, class CmpT>
inline void heap_array<T, CmpT>::Swap(size_t a, size_t b) {
std::swap(m_Heap[a], m_Heap[b]);
// use (size_t &) to get rid of a bogus compile warning
(size_t &) (m_Finder[(m_Heap[a].m_Indice)]) = a;
(size_t &) (m_Finder[(m_Heap[b].m_Indice)]) = b;
}
template <class T, class CmpT>
inline bool heap_array<T, CmpT>::Less(const linker & a, const linker & b) const {
return m_Compare(a.m_Elem, b.m_Elem);
}
}; // namespace common_structures

View File

@ -1,586 +0,0 @@
// tri_stripper.cpp: implementation of the Tri Stripper class.
//
// Copyright (C) 2002 Tanguy Fautré.
// For conditions of distribution and use,
// see copyright notice in tri_stripper.h
//
//////////////////////////////////////////////////////////////////////
#include <cassert>
#include <cstdlib>
#include <algorithm>
#include <deque>
//#include <fstream>
//#include <iostream.h>
#include <list>
#include <map>
#include <string>
#include <vector>
using namespace std;
#include "tri_stripper.h"
// namespace triangle_stripper
namespace triangle_stripper {
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
// Members Functions
//////////////////////////////////////////////////////////////////////
void tri_stripper::Strip(primitives_vector * out_pPrimitivesVector)
{
// verify that the number of indices is correct
if (m_TriIndices.size() % 3 != 0)
throw triangles_indices_error();
// clear possible garbage
m_PrimitivesVector.clear();
out_pPrimitivesVector->clear();
// Initialize the triangle graph
InitTriGraph();
// Initialize the triangle priority queue
InitTriHeap();
// Initialize the cache simulator
InitCache();
// Launch the triangle strip generator
Stripify();
// Add the triangles that couldn't be stripped
AddLeftTriangles();
// Free ressources
m_Triangles.clear();
// Put the results into the user's vector
std::swap(m_PrimitivesVector, (* out_pPrimitivesVector));
}
void tri_stripper::InitTriGraph()
{
// Set up the graph size and complete the triangles data
// note: setsize() completely resets the graph as well as the node markers
m_Triangles.setsize(m_TriIndices.size() / 3);
size_t i;
for (i = 0; i < m_Triangles.size(); ++i)
m_Triangles[i] = triangle(m_TriIndices[i * 3 + 0], m_TriIndices[i * 3 + 1], m_TriIndices[i * 3 + 2]);
// Build the edges lookup table
triangle_edges TriInterface;
TriInterface.reserve(m_Triangles.size() * 3);
for (i = 0; i < m_Triangles.size(); ++i) {
TriInterface.push_back(triangle_edge(m_Triangles[i]->A(), m_Triangles[i]->B(), i));
TriInterface.push_back(triangle_edge(m_Triangles[i]->B(), m_Triangles[i]->C(), i));
TriInterface.push_back(triangle_edge(m_Triangles[i]->C(), m_Triangles[i]->A(), i));
}
// Sort the lookup table for faster searches
std::sort(TriInterface.begin(), TriInterface.end(), _cmp_tri_interface_lt());
// Link neighbour triangles together using the edges lookup table
for (i = 0; i < m_Triangles.size(); ++i) {
const triangle_edge EdgeBA(m_Triangles[i]->B(), m_Triangles[i]->A(), i);
const triangle_edge EdgeCB(m_Triangles[i]->C(), m_Triangles[i]->B(), i);
const triangle_edge EdgeAC(m_Triangles[i]->A(), m_Triangles[i]->C(), i);
LinkNeighboursTri(TriInterface, EdgeBA);
LinkNeighboursTri(TriInterface, EdgeCB);
LinkNeighboursTri(TriInterface, EdgeAC);
}
}
void tri_stripper::LinkNeighboursTri(const triangle_edges & TriInterface, const triangle_edge Edge)
{
typedef triangle_edges::const_iterator edge_const_it;
// Find the first edge equal to Edge
edge_const_it It = std::lower_bound(TriInterface.begin(), TriInterface.end(), Edge, _cmp_tri_interface_lt());
// See if there are any other edges that are equal
// (if so, it means that more than 2 triangles are sharing the same edge,
// which is unlikely but not impossible)
for (; (It != TriInterface.end()) && ((It->A() == Edge.A()) && (It->B() == Edge.B())); ++It)
m_Triangles.insert(Edge.TriPos(), It->TriPos());
// Note: degenerated triangles will also point themselves as neighbour triangles
}
void tri_stripper::InitTriHeap()
{
m_TriHeap.clear();
m_TriHeap.reserve(m_Triangles.size());
// Set up the triangles priority queue
// The lower the number of available neighbour triangles, the higher the priority.
for (size_t i = 0; i < m_Triangles.size(); ++i)
m_TriHeap.push(triangle_degree(i, m_Triangles[i].number_of_out_arcs()));
// Remove useless triangles
// (Note: we had to put all of them into the heap before to ensure coherency of the heap_array object)
while ((! m_TriHeap.empty()) && (m_TriHeap.top().Degree() == 0))
m_TriHeap.pop();
}
void tri_stripper::InitCache()
{
m_IndicesCache.clear();
if (m_CacheSize > 0)
m_IndicesCache.resize(m_CacheSize, static_cast<size_t>(-1));
}
void tri_stripper::Stripify()
{
// Reset the triangle strip id selector
m_StripID = 0;
// Reset the candidate list
m_NextCandidates.clear();
// Loop untill there is no available candidate triangle left
while (! m_TriHeap.empty()) {
// There is no triangle in the candidates list, refill it with the loneliest triangle
const size_t HeapTop = m_TriHeap.top().TriPos();
m_NextCandidates.push_back(HeapTop);
// Loop while BuildStrip can find good candidates for us
while (! m_NextCandidates.empty()) {
// Choose the best strip containing that triangle
// Note: FindBestStrip empties m_NextCandidates
const triangle_strip TriStrip = FindBestStrip();
// Build it if it's long enough, otherwise discard it
// Note: BuildStrip refills m_NextCandidates
if (TriStrip.Size() >= m_MinStripSize)
BuildStrip(TriStrip);
}
// We must discard the triangle we inserted in the candidate list from the heap
// if it led to nothing. (We simply removed it if it hasn't been removed by BuildStrip() yet)
if (! m_TriHeap.removed(HeapTop))
m_TriHeap.erase(HeapTop);
// Eliminate all the triangles that have now become useless
while ((! m_TriHeap.empty()) && (m_TriHeap.top().Degree() == 0))
m_TriHeap.pop();
}
}
inline tri_stripper::triangle_strip tri_stripper::FindBestStrip()
{
triangle_strip BestStrip;
size_t BestStripDegree = 0;
size_t BestStripCacheHits = 0;
// Backup the cache, because it'll be erased during the simulations
indices_cache CacheBackup = m_IndicesCache;
while (! m_NextCandidates.empty()) {
// Discard useless triangles from the candidates list
if ((m_Triangles[m_NextCandidates.back()].marked()) || (m_TriHeap[m_NextCandidates.back()].Degree() == 0)) {
m_NextCandidates.pop_back();
// "continue" is evil! But it really makes things easier here.
// The useless triangle is discarded, and the "while" just rebegins again
continue;
}
// Invariant: (CandidateTri's Degree() >= 1) && (CandidateTri is not marked).
// So it can directly be used.
const size_t CandidateTri = m_NextCandidates.back();
m_NextCandidates.pop_back();
// Try to extend the triangle in the 3 possible directions
for (size_t i = 0; i < 3; ++i) {
// Reset the cache hit count
m_CacheHits = 0;
// Try a new strip with that triangle in a particular direction
const triangle_strip TempStrip = ExtendTriToStrip(CandidateTri, triangle_strip::start_order(i));
// Restore the cache (modified by ExtendTriToStrip)
m_IndicesCache = CacheBackup;
// We want to keep the best strip
// Discard strips that don't match the minimum required size
if (TempStrip.Size() >= m_MinStripSize) {
// Cache simulator disabled?
if (m_CacheSize == 0) {
// Cache is disabled, take the longest strip
if (TempStrip.Size() > BestStrip.Size())
BestStrip = TempStrip;
// Cache simulator enabled
// Use other criteria to find the "best" strip
} else {
// Priority 1: Keep the strip with the best cache hit count
if (m_CacheHits > BestStripCacheHits) {
BestStrip = TempStrip;
BestStripDegree = m_TriHeap[TempStrip.StartTriPos()].Degree();
BestStripCacheHits = m_CacheHits;
} else if (m_CacheHits == BestStripCacheHits) {
// Priority 2: Keep the strip with the loneliest start triangle
if ((BestStrip.Size() != 0) && (m_TriHeap[TempStrip.StartTriPos()].Degree() < BestStripDegree)) {
BestStrip = TempStrip;
BestStripDegree = m_TriHeap[TempStrip.StartTriPos()].Degree();
// Priority 3: Keep the longest strip
} else if (TempStrip.Size() > BestStrip.Size()) {
BestStrip = TempStrip;
BestStripDegree = m_TriHeap[TempStrip.StartTriPos()].Degree();
}
}
}
}
}
}
return BestStrip;
}
tri_stripper::triangle_strip tri_stripper::ExtendTriToStrip(const size_t StartTriPos, const triangle_strip::start_order StartOrder)
{
typedef triangles_graph::const_out_arc_iterator const_tri_link_iter;
typedef triangles_graph::node_iterator tri_node_iter;
size_t Size = 1;
bool ClockWise = false;
triangle_strip::start_order Order = StartOrder;
// Begin a new strip
++m_StripID;
// Mark the first triangle as used for this strip
m_Triangles[StartTriPos]->SetStripID(m_StripID);
// Update the indice cache
AddTriToCache((* m_Triangles[StartTriPos]), Order);
// Loop while we can further extend the strip
for (tri_node_iter TriNodeIt = (m_Triangles.begin() + StartTriPos);
(TriNodeIt != m_Triangles.end()) && ((m_CacheSize <= 0) || ((Size + 2) < m_CacheSize));
++Size) {
// Get the triangle edge that would lead to the next triangle
const triangle_edge Edge = GetLatestEdge(** TriNodeIt, Order);
// Link to a neighbour triangle
const_tri_link_iter LinkIt;
for (LinkIt = TriNodeIt->out_begin(); LinkIt != TriNodeIt->out_end(); ++LinkIt) {
// Get the reference to the possible next triangle
const triangle & Tri = (** ((*LinkIt).terminal()));
// Check whether it's already been used
if ((Tri.StripID() != m_StripID) && (! ((*LinkIt).terminal()->marked()))) {
// Does the current candidate triangle match the required for the strip?
if ((Edge.B() == Tri.A()) && (Edge.A() == Tri.B())) {
Order = (ClockWise) ? triangle_strip::ABC : triangle_strip::BCA;
AddIndiceToCache(Tri.C(), true);
break;
}
else if ((Edge.B() == Tri.B()) && (Edge.A() == Tri.C())) {
Order = (ClockWise) ? triangle_strip::BCA : triangle_strip::CAB;
AddIndiceToCache(Tri.A(), true);
break;
}
else if ((Edge.B() == Tri.C()) && (Edge.A() == Tri.A())) {
Order = (ClockWise) ? triangle_strip::CAB : triangle_strip::ABC;
AddIndiceToCache(Tri.B(), true);
break;
}
}
}
// Is it the end of the strip?
if (LinkIt == TriNodeIt->out_end()) {
TriNodeIt = m_Triangles.end();
--Size;
} else {
TriNodeIt = (*LinkIt).terminal();
// Setup for the next triangle
(* TriNodeIt)->SetStripID(m_StripID);
ClockWise = ! ClockWise;
}
}
return triangle_strip(StartTriPos, StartOrder, Size);
}
inline tri_stripper::triangle_edge tri_stripper::GetLatestEdge(const triangle & Triangle, const triangle_strip::start_order Order) const
{
switch (Order) {
case triangle_strip::ABC:
return triangle_edge(Triangle.B(), Triangle.C(), 0);
case triangle_strip::BCA:
return triangle_edge(Triangle.C(), Triangle.A(), 0);
case triangle_strip::CAB:
return triangle_edge(Triangle.A(), Triangle.B(), 0);
default:
return triangle_edge(0, 0, 0);
}
}
void tri_stripper::BuildStrip(const triangle_strip TriStrip)
{
typedef triangles_graph::const_out_arc_iterator const_tri_link_iter;
typedef triangles_graph::node_iterator tri_node_iter;
const size_t StartTriPos = TriStrip.StartTriPos();
bool ClockWise = false;
triangle_strip::start_order Order = TriStrip.StartOrder();
// Create a new strip
m_PrimitivesVector.push_back(primitives());
m_PrimitivesVector.back().m_Type = PT_Triangle_Strip;
// Put the first triangle into the strip
AddTriToIndices((* m_Triangles[StartTriPos]), Order);
// Mark the first triangle as used
MarkTriAsTaken(StartTriPos);
// Loop while we can further extend the strip
tri_node_iter TriNodeIt = (m_Triangles.begin() + StartTriPos);
for (size_t Size = 1; Size < TriStrip.Size(); ++Size) {
// Get the triangle edge that would lead to the next triangle
const triangle_edge Edge = GetLatestEdge(** TriNodeIt, Order);
// Link to a neighbour triangle
const_tri_link_iter LinkIt;
for (LinkIt = TriNodeIt->out_begin(); LinkIt != TriNodeIt->out_end(); ++LinkIt) {
// Get the reference to the possible next triangle
const triangle & Tri = (** ((*LinkIt).terminal()));
// Check whether it's already been used
if (! ((*LinkIt).terminal()->marked())) {
// Does the current candidate triangle match the required for the strip?
// If it does, then add it to the Indices
if ((Edge.B() == Tri.A()) && (Edge.A() == Tri.B())) {
Order = (ClockWise) ? triangle_strip::ABC : triangle_strip::BCA;
AddIndice(Tri.C());
break;
}
else if ((Edge.B() == Tri.B()) && (Edge.A() == Tri.C())) {
Order = (ClockWise) ? triangle_strip::BCA : triangle_strip::CAB;
AddIndice(Tri.A());
break;
}
else if ((Edge.B() == Tri.C()) && (Edge.A() == Tri.A())) {
Order = (ClockWise) ? triangle_strip::CAB : triangle_strip::ABC;
AddIndice(Tri.B());
break;
}
}
}
// Debug check: we must have found the next triangle
assert(LinkIt != TriNodeIt->out_end());
// Go to the next triangle
TriNodeIt = (*LinkIt).terminal();
MarkTriAsTaken(TriNodeIt - m_Triangles.begin());
// Setup for the next triangle
ClockWise = ! ClockWise;
}
}
void tri_stripper::MarkTriAsTaken(const size_t i)
{
typedef triangles_graph::node_iterator tri_node_iter;
typedef triangles_graph::out_arc_iterator tri_link_iter;
// Mark the triangle node
m_Triangles[i].mark();
// Remove triangle from priority queue if it isn't yet
if (! m_TriHeap.removed(i))
m_TriHeap.erase(i);
// Adjust the degree of available neighbour triangles
for (tri_link_iter LinkIt = m_Triangles[i].out_begin(); LinkIt != m_Triangles[i].out_end(); ++LinkIt) {
const size_t j = (*LinkIt).terminal() - m_Triangles.begin();
if ((! m_Triangles[j].marked()) && (! m_TriHeap.removed(j))) {
triangle_degree NewDegree = m_TriHeap.peek(j);
NewDegree.SetDegree(NewDegree.Degree() - 1);
m_TriHeap.update(j, NewDegree);
// Update the candidate list if cache is enabled
if ((m_CacheSize > 0) && (NewDegree.Degree() > 0))
m_NextCandidates.push_back(j);
}
}
}
inline void tri_stripper::AddIndiceToCache(const indice i, bool CacheHitCount)
{
// Cache simulator enabled?
if (m_CacheSize > 0) {
// Should we simulate the cache hits and count them?
if (CacheHitCount) {
if (std::find(m_IndicesCache.begin(), m_IndicesCache.end(), i) != m_IndicesCache.end())
++m_CacheHits;
}
// Manage the indices cache as a FIFO structure
m_IndicesCache.pop_back();
m_IndicesCache.push_front(i);
}
}
inline void tri_stripper::AddIndice(const indice i)
{
// Add the indice to the current indices array
m_PrimitivesVector.back().m_Indices.push_back(i);
// Run cache simulator
AddIndiceToCache(i);
}
inline void tri_stripper::AddTriToCache(const triangle & Tri, const triangle_strip::start_order Order)
{
// Add Tri indices in the right order into the indices cache simulator.
// And enable the cache hit count
switch (Order) {
case triangle_strip::ABC:
AddIndiceToCache(Tri.A(), true);
AddIndiceToCache(Tri.B(), true);
AddIndiceToCache(Tri.C(), true);
return;
case triangle_strip::BCA:
AddIndiceToCache(Tri.B(), true);
AddIndiceToCache(Tri.C(), true);
AddIndiceToCache(Tri.A(), true);
return;
case triangle_strip::CAB:
AddIndiceToCache(Tri.C(), true);
AddIndiceToCache(Tri.A(), true);
AddIndiceToCache(Tri.B(), true);
return;
}
}
inline void tri_stripper::AddTriToIndices(const triangle & Tri, const triangle_strip::start_order Order)
{
// Add Tri indices in the right order into the latest Indices vector.
switch (Order) {
case triangle_strip::ABC:
AddIndice(Tri.A());
AddIndice(Tri.B());
AddIndice(Tri.C());
return;
case triangle_strip::BCA:
AddIndice(Tri.B());
AddIndice(Tri.C());
AddIndice(Tri.A());
return;
case triangle_strip::CAB:
AddIndice(Tri.C());
AddIndice(Tri.A());
AddIndice(Tri.B());
return;
}
}
void tri_stripper::AddLeftTriangles()
{
// Create the latest indices array
// and fill it with all the triangles that couldn't be stripped
primitives Primitives;
Primitives.m_Type = PT_Triangles;
m_PrimitivesVector.push_back(Primitives);
indices & Indices = m_PrimitivesVector.back().m_Indices;
for (size_t i = 0; i < m_Triangles.size(); ++i)
if (! m_Triangles[i].marked()) {
Indices.push_back(m_Triangles[i]->A());
Indices.push_back(m_Triangles[i]->B());
Indices.push_back(m_Triangles[i]->C());
}
// Undo if useless
if (Indices.size() == 0)
m_PrimitivesVector.pop_back();
}
}; // namespace triangle_stripper

View File

@ -1,372 +0,0 @@
// tri_stripper.h: interface for the tri_stripper class.
//
//////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2002 Tanguy Fautré.
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
//
// Tanguy Fautré
// softdev@pandora.be
//
//////////////////////////////////////////////////////////////////////
//
// Tri Stripper
// ************
//
// Current version: 1.00 BETA 5 (10/12/2002)
//
// Comment: Triangle stripper in O(n.log(n)).
//
// Currently there are no protection against crazy values
// given via SetMinStripSize() and SetCacheSize().
// So be careful. (Min. strip size should be equal or greater
// than 2, cache size should be about 10 for GeForce 256/2
// and about 16-18 for GeForce 3/4.)
//
// History: - 1.00 BETA 5 (10/12/2002) - Fixed a bug in Stripify() that could sometimes
// cause it to go into an infinite loop.
// (thanks to Remy for the bug report)
// - 1.00 BETA 4 (18/11/2002) - Removed the dependency on OpenGL:
// modified gl_primitives to primitives,
// and gl_primitives_vector to primitives_vector;
// and added primitive_type.
// (thanks to Patrik for noticing this useless dependency)
// - 1.00 BETA 3 (18/11/2002) - Fixed a bug in LinkNeightboursTri() that could cause a crash
// (thanks to Nicolas for finding it)
// - 1.00 BETA 2 (16/11/2002) - Improved portability
// - 1.00 BETA 1 (27/10/2002) - First public release
//
//////////////////////////////////////////////////////////////////////
#pragma once
#include <deque>
// namespace triangle_stripper
namespace triangle_stripper {
//#include "../Common Structures/graph_array.h"
//#include "../Common Structures/heap_array.h"
#include "graph_array.h"
#include "heap_array.h"
class tri_stripper
{
public:
// New Public types
typedef unsigned int indice;
typedef std::vector<indice> indices;
enum primitive_type {
PT_Triangles = 0x0004, // = GL_TRIANGLES
PT_Triangle_Strip = 0x0005 // = GL_TRIANGLE_STRIP
};
struct primitives
{
indices m_Indices;
primitive_type m_Type;
};
typedef std::vector<primitives> primitives_vector;
struct triangles_indices_error { };
// constructor/initializer
tri_stripper(const indices & TriIndices);
// Settings functions
void SetCacheSize(const size_t CacheSize = 16); // = 0 will disable the cache optimizer
void SetMinStripSize(const size_t MinStripSize = 2);
// Stripper
void Strip(primitives_vector * out_pPrimitivesVector); // throw triangles_indices_error();
private:
friend struct _cmp_tri_interface_lt;
class triangle
{
public:
triangle();
triangle(const indice A, const indice B, const indice C);
void SetStripID(const size_t StripID);
indice A() const;
indice B() const;
indice C() const;
size_t StripID() const;
private:
indice m_A;
indice m_B;
indice m_C;
size_t m_StripID;
};
class triangle_edge
{
public:
triangle_edge(const indice A, const indice B, const size_t TriPos);
indice A() const;
indice B() const;
size_t TriPos() const;
private:
indice m_A;
indice m_B;
size_t m_TriPos;
};
class triangle_degree
{
public:
triangle_degree();
triangle_degree(const size_t TriPos, const size_t Degree);
size_t Degree() const;
size_t TriPos() const;
void SetDegree(const size_t Degree);
private:
size_t m_TriPos;
size_t m_Degree;
};
class triangle_strip
{
public:
enum start_order { ABC = 0, BCA = 1, CAB = 2 };
triangle_strip();
triangle_strip(size_t StartTriPos, start_order StartOrder, size_t Size);
size_t StartTriPos() const;
start_order StartOrder() const;
size_t Size() const;
private:
size_t m_StartTriPos;
start_order m_StartOrder;
size_t m_Size;
};
struct _cmp_tri_interface_lt
{
bool operator() (const triangle_edge & a, const triangle_edge & b) const;
};
struct _cmp_tri_degree_gt
{
bool operator () (const triangle_degree & a, const triangle_degree & b) const;
};
typedef common_structures::graph_array<triangle, char> triangles_graph;
typedef common_structures::heap_array<triangle_degree, _cmp_tri_degree_gt> triangles_heap;
typedef std::vector<triangle_edge> triangle_edges;
typedef std::vector<size_t> triangle_indices;
typedef std::deque<indice> indices_cache;
void InitCache();
void InitTriGraph();
void InitTriHeap();
void Stripify();
void AddLeftTriangles();
void LinkNeighboursTri(const triangle_edges & TriInterface, const triangle_edge Edge);
void MarkTriAsTaken(const size_t i);
triangle_edge GetLatestEdge(const triangle & Triangle, const triangle_strip::start_order Order) const;
triangle_strip FindBestStrip();
triangle_strip ExtendTriToStrip(const size_t StartTriPos, const triangle_strip::start_order StartOrder);
void BuildStrip(const triangle_strip TriStrip);
void AddIndice(const indice i);
void AddIndiceToCache(const indice i, bool CacheHitCount = false);
void AddTriToCache(const triangle & Tri, const triangle_strip::start_order Order);
void AddTriToIndices(const triangle & Tri, const triangle_strip::start_order Order);
const indices & m_TriIndices;
size_t m_MinStripSize;
size_t m_CacheSize;
primitives_vector m_PrimitivesVector;
triangles_graph m_Triangles;
triangles_heap m_TriHeap;
triangle_indices m_NextCandidates;
indices_cache m_IndicesCache;
size_t m_StripID;
size_t m_CacheHits;
};
//////////////////////////////////////////////////////////////////////////
// tri_stripper Inline functions
//////////////////////////////////////////////////////////////////////////
inline tri_stripper::tri_stripper(const indices & TriIndices) : m_TriIndices(TriIndices) {
SetCacheSize();
SetMinStripSize();
}
inline void tri_stripper::SetCacheSize(const size_t CacheSize) {
m_CacheSize = CacheSize;
}
inline void tri_stripper::SetMinStripSize(const size_t MinStripSize) {
m_MinStripSize = MinStripSize;
}
inline tri_stripper::triangle::triangle() { }
inline tri_stripper::triangle::triangle(const indice A, const indice B, const indice C) : m_A(A), m_B(B), m_C(C), m_StripID(0) { }
inline void tri_stripper::triangle::SetStripID(const size_t StripID) {
m_StripID = StripID;
}
inline tri_stripper::indice tri_stripper::triangle::A() const {
return m_A;
}
inline tri_stripper::indice tri_stripper::triangle::B() const {
return m_B;
}
inline tri_stripper::indice tri_stripper::triangle::C() const {
return m_C;
}
inline size_t tri_stripper::triangle::StripID() const {
return m_StripID;
}
inline tri_stripper::triangle_edge::triangle_edge(const indice A, const indice B, const size_t TriPos) : m_A(A), m_B(B), m_TriPos(TriPos) { }
inline tri_stripper::indice tri_stripper::triangle_edge::A() const {
return m_A;
}
inline tri_stripper::indice tri_stripper::triangle_edge::B() const {
return m_B;
}
inline size_t tri_stripper::triangle_edge::TriPos() const {
return m_TriPos;
}
inline tri_stripper::triangle_degree::triangle_degree() { }
inline tri_stripper::triangle_degree::triangle_degree(const size_t TriPos, const size_t Degree) : m_TriPos(TriPos), m_Degree(Degree) { }
inline size_t tri_stripper::triangle_degree::Degree() const {
return m_Degree;
}
inline size_t tri_stripper::triangle_degree::TriPos() const {
return m_TriPos;
}
inline void tri_stripper::triangle_degree::SetDegree(const size_t Degree) {
m_Degree = Degree;
}
inline tri_stripper::triangle_strip::triangle_strip() : m_StartTriPos(0), m_StartOrder(ABC), m_Size(0) { }
inline tri_stripper::triangle_strip::triangle_strip(const size_t StartTriPos, const start_order StartOrder, const size_t Size)
: m_StartTriPos(StartTriPos), m_StartOrder(StartOrder), m_Size(Size) { }
inline size_t tri_stripper::triangle_strip::StartTriPos() const {
return m_StartTriPos;
}
inline tri_stripper::triangle_strip::start_order tri_stripper::triangle_strip::StartOrder() const {
return m_StartOrder;
}
inline size_t tri_stripper::triangle_strip::Size() const {
return m_Size;
}
inline bool tri_stripper::_cmp_tri_interface_lt::operator() (const triangle_edge & a, const triangle_edge & b) const {
const tri_stripper::indice A1 = a.A();
const tri_stripper::indice B1 = a.B();
const tri_stripper::indice A2 = b.A();
const tri_stripper::indice B2 = b.B();
if ((A1 < A2) || ((A1 == A2) && (B1 < B2)))
return true;
else
return false;
}
inline bool tri_stripper::_cmp_tri_degree_gt::operator () (const triangle_degree & a, const triangle_degree & b) const {
// the triangle with a smaller degree has more priority
return a.Degree() > b.Degree();
}
}; // namespace triangle_stripper

View File

@ -1,134 +0,0 @@
/****************************************************************************
* VCGLib o o *
* Visual and Computer Graphics Library o o *
* _ O _ *
* Copyright(C) 2004 \/)\/ *
* Visual Computing Lab /\/| *
* ISTI - Italian National Research Council | *
* \ *
* All rights reserved. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
* for more details. *
* *
****************************************************************************/
/****************************************************************************
History
$Log: not supported by cvs2svn $
****************************************************************************/
#include "vchain.h"
#include <stdio.h>
#include <iostream>
using namespace std;
using namespace vcg;
using namespace nxs;
VChain::~VChain() {
for(iterator i = begin(); i != end(); i++)
delete *i;
}
bool VChain::Save(const string &file) {
FILE *fp = fopen(file.c_str(), "wb+");
if(!fp) {
cerr << "Could not save vchain data.\n";
return false;
}
unsigned int nlevels = size();
fwrite(&nlevels, sizeof(unsigned int), 1, fp);
for(unsigned int i = 0; i < nlevels; i++) {
VPartition &level = *operator[](i);
unsigned int npoints = level.size();
fwrite(&npoints, sizeof(unsigned int), 1, fp);
fwrite(&(level[0]), sizeof(Point3f), npoints, fp);
}
//writing fragments
unsigned int nfrag = newfragments.size();
fwrite(&nfrag, sizeof(unsigned int), 1, fp);
std::map<unsigned int, std::set<unsigned int> >::iterator j;
for(j = newfragments.begin(); j != newfragments.end(); j++) {
unsigned int n = (*j).second.size();
fwrite(&((*j).first), sizeof(unsigned int), 1, fp);
fwrite(&n, sizeof(unsigned int), 1, fp);
set<unsigned int>::iterator k;
for(k = (*j).second.begin(); k != (*j).second.end(); k++)
fwrite(&*k, sizeof(unsigned int), 1, fp);
}
nfrag = oldfragments.size();
fwrite(&nfrag, sizeof(unsigned int), 1, fp);
for(j = oldfragments.begin(); j != oldfragments.end(); j++) {
unsigned int n = (*j).second.size();
fwrite(&((*j).first), sizeof(unsigned int), 1, fp);
fwrite(&n, sizeof(unsigned int), 1, fp);
set<unsigned int>::iterator k;
for(k = (*j).second.begin(); k != (*j).second.end(); k++)
fwrite(&*k, sizeof(unsigned int), 1, fp);
}
fclose(fp);
return true;
}
bool VChain::Load(const string &file) {
FILE *fp = fopen(file.c_str(), "rb");
if(!fp) {
cerr << "Could not load vchain data\n";
return false;
}
unsigned int nlevels;
fread(&nlevels, sizeof(unsigned int), 1, fp);
for(unsigned int i = 0; i < nlevels; i++) {
push_back(new VPartition());
VPartition &level = *back();
unsigned int npoints;
fread(&npoints, sizeof(unsigned int), 1, fp);
level.resize(npoints);
fread(&(level[0]), sizeof(Point3f), npoints, fp);
level.Init();
}
//reading fragments
unsigned int nfrag;
fread(&nfrag, sizeof(unsigned int), 1, fp);
for(unsigned int i = 0; i < nfrag; i++) {
unsigned int p, n;
fread(&p, sizeof(unsigned int), 1, fp);
set<unsigned int> &s = newfragments[p];
fread(&n, sizeof(unsigned int), 1, fp);
for(unsigned int k = 0; k < n; k++) {
unsigned int j;
fread(&j, sizeof(unsigned int), 1, fp);
s.insert(j);
}
}
fread(&nfrag, sizeof(unsigned int), 1, fp);
for(unsigned int i = 0; i < nfrag; i++) {
unsigned int p, n;
fread(&p, sizeof(unsigned int), 1, fp);
set<unsigned int> &s = oldfragments[p];
fread(&n, sizeof(unsigned int), 1, fp);
for(unsigned int k = 0; k < n; k++) {
unsigned int j;
fread(&j, sizeof(unsigned int), 1, fp);
s.insert(j);
}
}
fclose(fp);
return true;
}

View File

@ -1,51 +0,0 @@
/****************************************************************************
* VCGLib o o *
* Visual and Computer Graphics Library o o *
* _ O _ *
* Copyright(C) 2004 \/)\/ *
* Visual Computing Lab /\/| *
* ISTI - Italian National Research Council | *
* \ *
* All rights reserved. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
* for more details. *
* *
****************************************************************************/
/****************************************************************************
History
$Log: not supported by cvs2svn $
****************************************************************************/
#ifndef NXS_VCHAIN_H
#define NXS_VCHAIN_H
#include <vector>
#include <map>
#include <set>
#include "vpartition.h"
namespace nxs {
class VChain: public std::vector<VPartition *> {
public:
~VChain();
bool Save(const std::string &file);
bool Load(const std::string &file);
std::map<unsigned int, std::set<unsigned int> > newfragments;
std::map<unsigned int, std::set<unsigned int> > oldfragments;
};
}
#endif

View File

@ -1,317 +0,0 @@
/****************************************************************************
* VCGLib o o *
* Visual and Computer Graphics Library o o *
* _ O _ *
* Copyright(C) 2004 \/)\/ *
* Visual Computing Lab /\/| *
* ISTI - Italian National Research Council | *
* \ *
* All rights reserved. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
* for more details. *
* *
****************************************************************************/
/****************************************************************************
History
$Log: not supported by cvs2svn $
Revision 1.19 2004/12/03 01:20:56 ponchio
Debug
Revision 1.18 2004/12/01 03:24:32 ponchio
Level 2.
Revision 1.17 2004/11/30 22:49:39 ponchio
Level 0.
Revision 1.16 2004/11/28 04:12:04 ponchio
winsockapi include problem
Revision 1.15 2004/11/18 18:30:14 ponchio
Using baricenters... lotsa changes.
Revision 1.14 2004/10/19 16:50:27 ponchio
Added row file access ....
Revision 1.13 2004/10/08 15:12:04 ponchio
Working version (maybe)
Revision 1.12 2004/10/04 16:49:54 ponchio
Daily backup. Preparing for compression.
Revision 1.11 2004/10/01 16:00:12 ponchio
Added include <assert.h>
Revision 1.10 2004/09/30 23:56:33 ponchio
Backup (added strips and normals)
Revision 1.9 2004/07/20 14:04:32 ponchio
Improved efficience in operator[]
Revision 1.8 2004/07/15 14:32:49 ponchio
Debug.
Revision 1.7 2004/07/05 15:49:39 ponchio
Windows (DevCpp, mingw) port.
Revision 1.6 2004/07/04 15:23:48 ponchio
Debug
Revision 1.5 2004/07/02 17:41:37 ponchio
Debug.
Revision 1.4 2004/07/02 13:02:39 ponchio
Added GetRegion, Read and Write
Revision 1.3 2004/07/01 21:36:54 ponchio
*** empty log message ***
Revision 1.2 2004/06/25 16:47:13 ponchio
Various debug
Revision 1.1 2004/06/24 14:32:45 ponchio
Moved from wrap/nexus
Revision 1.3 2004/06/22 15:32:09 ponchio
Tested
Revision 1.2 2004/06/22 10:27:16 ponchio
*** empty log message ***
Revision 1.1 2004/06/22 00:39:56 ponchio
Created
****************************************************************************/
#ifndef VFILE_H
#define VFILE_H
#include "mfile.h"
#include <assert.h>
#include <map>
#include <list>
#include <string>
/**Vector structure on file with simulated mmapping.
* a priority queue of buffers is used
* TODO: port to over 4Gb usable space
* add interface for readonly reads even when file is readwrite...
* instead of queue size use ramsize!!!!
* some mechanism to report errors?
* use an Iterator?
*/
namespace nxs {
template <class T> class VFile: public MFile {
public:
struct Buffer {
unsigned int key;
unsigned int size; //in number of elements
T *data;
};
protected:
unsigned int n_elements;
std::list<Buffer> buffers;
typedef typename std::list<Buffer>::iterator list_iterator;
std::map<unsigned int, list_iterator> index; //TODO move to hash_map
Buffer *last_buffer;
unsigned int chunk_size; //default buffer size (expressed in number of T)
unsigned int queue_size;
public:
class iterator {
public:
iterator(unsigned int p = 0, VFile *b = 0): n(p), buffer(b) {}
T &operator*() { return (*buffer)[n]; }
void operator++() { n++; }
bool operator!=(const iterator &i) { return i.n != n; }
private:
unsigned int n;
VFile *buffer;
};
VFile(): last_buffer(NULL) {}
~VFile() { Close(); }
bool Create(const std::string &filename,
unsigned int _chunk_size = 4096/sizeof(T),
unsigned int _queue_size = 1000) {
assert(_chunk_size > 0);
n_elements = 0;
last_buffer = NULL;
chunk_size = _chunk_size;
queue_size = _queue_size;
return MFile::Create(filename);
}
bool Load(const std:: string &filename, bool rdonly = false,
unsigned int _chunk_size = 4096/sizeof(T),
unsigned int _queue_size = 1000) {
assert(_chunk_size > 0);
last_buffer = NULL;
chunk_size = _chunk_size;
queue_size = _queue_size;
if(!MFile::Load(filename, rdonly)) return false;
n_elements = _size/sizeof(T);
return true;
}
void Close() {
Flush();
}
void Delete() {
Flush();
MFile::Delete();
}
void Flush() {
list_iterator i;
for(i = buffers.begin(); i != buffers.end(); i++)
FlushBuffer(*i);
buffers.clear();
index.clear();
last_buffer = NULL;
}
void FlushBuffer(Buffer buffer) {
if(!readonly) {
SetPosition((int64)buffer.key * (int64)chunk_size * (int64)sizeof(T));
WriteBuffer((char *)(buffer.data), buffer.size * sizeof(T));
}
delete []buffer.data;
}
void Resize(unsigned int elem) {
//TODO do i really need to flush?
Flush();
MFile::Redim((int64)elem * (int64)sizeof(T));
n_elements = elem;
}
/** Remember that T is a valid pointer only until next call of
* getElement or setElement
*/
T &operator[](unsigned int n) {
assert(n < n_elements);
unsigned int chunk = n/chunk_size;
unsigned int offset = n - chunk*chunk_size;
assert(offset < chunk_size * sizeof(T));
if(last_buffer && last_buffer->key == chunk)
return *(last_buffer->data + offset);
if(index.count(chunk)) {
last_buffer = &*index[chunk];
return *((*(index[chunk])).data + offset);
}
if(buffers.size() > queue_size) {
Buffer &buffer= buffers.back();
assert(buffer.key != chunk);
FlushBuffer(buffer);
index.erase(buffer.key);
buffers.pop_back();
}
Buffer buffer;
buffer.key = chunk;
buffer.size = chunk_size;
if(buffer.size + chunk * chunk_size > n_elements)
buffer.size = n_elements - chunk * chunk_size;
buffer.data = new T[buffer.size];
buffers.push_front(buffer);
index[buffer.key] = buffers.begin();
last_buffer = &*buffers.begin();
SetPosition((int64)chunk * (int64)chunk_size * (int64)sizeof(T));
ReadBuffer((char *)(buffer.data), buffer.size * sizeof(T));
return *(buffer.data + offset);
}
/** you can get a region instead of an element but:
1)region must be Chunk aligned.
2)you get impredictable results if regions overlap or mix with operator[]
*/
T *GetRegion(unsigned int start, unsigned int size, bool flush = true) {
assert(start + size <= n_elements);
assert((size % chunk_size) == 0);
assert((start % chunk_size) == 0);
if(size == 0) return NULL;
unsigned int chunk = start/chunk_size;
if(index.count(chunk))
return ((*(index[chunk])).data);
while(flush && buffers.size() > queue_size) {
Buffer &buffer= buffers.back();
FlushBuffer(buffer);
index.erase(buffer.key);
buffers.pop_back();
}
Buffer buffer;
buffer.key = chunk;
buffer.size = size;
buffer.data = new T[buffer.size];
buffers.push_front(buffer);
index[chunk] = buffers.begin();
SetPosition((int64)chunk * (int64)chunk_size * (int64)sizeof(T));
ReadBuffer((char *)(buffer.data), buffer.size * sizeof(T));
return buffer.data;
}
//non buffered read only acces.
T read(unsigned int element) {
SetPosition((int64)element * (int64)sizeof(T));
T t;
ReadBuffer(&t, sizeof(T));
return t;
}
void write(unsigned int element, T &t) {
SetPosition((int64)element * (int64)sizeof(T));
WriteBuffer(&t, sizeof(T));
}
void PushBack(const T &t) {
Resize(n_elements+1);
operator[](n_elements-1) = t;
}
unsigned int Size() { return n_elements; }
unsigned int ChunkSize() { return chunk_size; }
unsigned int QueueSize() { return queue_size; }
iterator Begin() { return iterator(0, this); }
iterator End() { return iterator(Size(), this); }
};
}//namespace
#endif

View File

@ -1,171 +0,0 @@
/****************************************************************************
* VCGLib o o *
* Visual and Computer Graphics Library o o *
* _ O _ *
* Copyright(C) 2004 \/)\/ *
* Visual Computing Lab /\/| *
* ISTI - Italian National Research Council | *
* \ *
* All rights reserved. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
* for more details. *
* *
****************************************************************************/
/****************************************************************************
History
$Log: not supported by cvs2svn $
Revision 1.5 2005/02/22 10:38:17 ponchio
Debug, cleaning and optimization.
Revision 1.4 2005/02/21 17:55:48 ponchio
debug debug debug
Revision 1.3 2005/01/21 17:09:13 ponchio
Porting and debug.
Revision 1.2 2004/12/04 13:24:27 ponchio
Fixed a couple of memory leak...
Revision 1.1 2004/11/30 22:50:30 ponchio
Level 0.
****************************************************************************/
#include <stdio.h>
#include "vpartition.h"
#include <ANN/ANN.h>
using namespace std;
using namespace vcg;
using namespace nxs;
VPartition::~VPartition() {
if(bd) delete bd;
}
void VPartition::Init() {
if(bd) delete bd;
buffer.resize(size() * 3);
for(unsigned int i = 0; i < size(); i++) {
for(int k = 0; k < 3; k++)
buffer[i*3+k] = operator[](i)[k];
}
points.resize(size());
for(unsigned int i = 0; i < size(); i++) {
points[i] = &buffer[i*3];
}
bd = new ANNkd_tree(&*points.begin(), size(), 3);
}
void VPartition::Closest(const vcg::Point3f &p, unsigned int nsize,
vector<int> &nears,
vector<float> &dist) {
double point[3];
point[0] = p[0];
point[1] = p[1];
point[2] = p[2];
if(nsize > size()) nsize = size();
nears.resize(nsize);
dist.resize(nsize);
vector<double> dists;
dists.resize(nsize);
bd->annkSearch(&point[0], nsize, &*nears.begin(), &*dists.begin());
for(unsigned int i = 0; i < nsize; i++)
dist[i] = (float)dists[i];
}
void VPartition::Closest(const vcg::Point3f &p,
int &target, float &dist) {
double point[3];
point[0] = p[0];
point[1] = p[1];
point[2] = p[2];
double dists;
bd->annkSearch(&point[0], 1, &target, &dists);
assert(target >= 0);
assert(target < size());
dist = (float)dists;
}
void VPartition::Closest(const vcg::Point3f &p,
vector<int> &targets,
vector<double> &dists,
float max_distance) {
double point[3]; point[0] = p[0]; point[1] = p[1]; point[2] = p[2];
int seeds = 6;
while(1) {
if(seeds > size()) seeds = size();
targets.resize(seeds);
dists.resize(seeds);
bd->annkSearch(&point[0], seeds, &(targets[0]), &(dists[0]));
for(int i = 0; i < seeds; i++) {
if(dists[i] > max_distance) {
targets.resize(i);
dists.resize(i);
break;
}
}
if(targets.size() < seeds) break;
if(seeds == size()) break;
seeds *= 2;
}
}
void VPartition::Closest(const vcg::Point3f &p, unsigned int nsize,
int *targets,
double *dists) {
double point[3];
point[0] = p[0];
point[1] = p[1];
point[2] = p[2];
bd->annkSearch(&point[0], nsize, targets, dists);
}
int VPartition::Locate(const vcg::Point3f &p) {
double point[3];
point[0] = p[0];
point[1] = p[1];
point[2] = p[2];
int target = -1;
double dists;
bd->annkSearch(&point[0], 1, &target, &dists);
return target;
}
float VPartition::Radius(unsigned int seed) {
assert(size() > 1);
int nears[2];
double dists[2];
double point[3];
Point3f &p = operator[](seed);
point[0] = p[0];
point[1] = p[1];
point[2] = p[2];
bd->annkSearch(&point[0], 2, nears, dists);
if(dists[1] == 0) return 0.0f;
assert(nears[0] == seed);
assert(dists[0] == 0);
return (float)sqrt(dists[1]);
}

View File

@ -1,99 +0,0 @@
/****************************************************************************
* VCGLib o o *
* Visual and Computer Graphics Library o o *
* _ O _ *
* Copyright(C) 2004 \/)\/ *
* Visual Computing Lab /\/| *
* ISTI - Italian National Research Council | *
* \ *
* All rights reserved. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
* for more details. *
* *
****************************************************************************/
/****************************************************************************
History
$Log: not supported by cvs2svn $
Revision 1.4 2005/02/21 17:55:49 ponchio
debug debug debug
Revision 1.3 2005/01/18 22:46:58 ponchio
Small changes.
Revision 1.2 2004/12/04 13:24:28 ponchio
Fixed a couple of memory leak...
Revision 1.1 2004/11/30 22:50:30 ponchio
Level 0.
****************************************************************************/
#ifndef NXS_VPARTITION_H
#define NXS_VPARTITION_H
#include <vector>
#include <string>
#include <vcg/space/point3.h>
//TODO provide a Sort function, to sort spatially the seeds.
class ANNkd_tree;
class ANNbd_tree;
class ANNbruteForce;
namespace nxs {
//WARNING: all distances returned are SQUARED!!!!
class VPartition: public std::vector<vcg::Point3f> {
public:
VPartition(): bd(NULL) {}
~VPartition();
private:
VPartition &operator=(const VPartition &part) {
for(unsigned int i = 0; i < part.size(); i++)
push_back(part[i]);
Init();
return *this;
}
public:
void Init();
int Locate(const vcg::Point3f &p);
//looks for the min distance point from seed.
float Radius(unsigned int seed);
void Closest(const vcg::Point3f &p, unsigned int nsize,
std::vector<int> &nears,
std::vector<float> &dist);
void Closest(const vcg::Point3f &p,
int &target, float &dist);
//return all targets widthin that distance (SQUARED!!!)
void Closest(const vcg::Point3f &p, std::vector<int> &targets,
std::vector<double> &dists,
float max_distance);
//most efficient!
void Closest(const vcg::Point3f &p, unsigned int nsize,
int *targets,
double *dists);
ANNkd_tree *bd;
std::vector<double> buffer;
std::vector<double *> points;
};
} //namespace nxs
#endif

View File

@ -1,155 +0,0 @@
/****************************************************************************
* VCGLib o o *
* Visual and Computer Graphics Library o o *
* _ O _ *
* Copyright(C) 2004 \/)\/ *
* Visual Computing Lab /\/| *
* ISTI - Italian National Research Council | *
* \ *
* All rights reserved. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
* for more details. *
* *
****************************************************************************/
/****************************************************************************
History
$Log: not supported by cvs2svn $
Revision 1.3 2004/10/21 13:40:16 ponchio
Debugging.
Revision 1.2 2004/10/21 12:14:02 ponchio
Support for mfile (>4Gb)
Revision 1.1 2004/10/19 17:20:24 ponchio
renamed
Revision 1.5 2004/10/19 17:16:52 ponchio
Changed interface
Revision 1.4 2004/07/30 12:44:14 ponchio
#ifdef corrected
Revision 1.3 2004/07/20 14:03:47 ponchio
Changed interface.
Revision 1.2 2004/07/05 15:49:39 ponchio
Windows (DevCpp, mingw) port.
Revision 1.1 2004/07/01 21:38:30 ponchio
First draft created.
****************************************************************************/
#include "watch.h"
#include <stdio.h>
#ifdef WIN32
Watch::Watch(): elapsed(0) {
QueryPerformanceFrequency(&freq);
}
void Watch::Start(void) {
QueryPerformanceCounter(&tstart);
elapsed = 0;
}
double Watch::Pause() {
QueryPerformanceCounter(&tend);
elapsed += Diff();
return (double)elapsed;
}
void Watch::Continue() {
QueryPerformanceCounter(&tstart);
}
double Watch::Time() {
QueryPerformanceCounter(&tend);
return (double)(elapsed + Diff());
}
double Watch::Diff() {
return ((double)tend.QuadPart -
(double)tstart.QuadPart)/
((double)freq.QuadPart);
}
#else
Watch::Watch(): elapsed() {}
void Watch::Start() {
gettimeofday(&tstart, &tz);
elapsed = 0;
}
double Watch::Pause() {
gettimeofday(&tend, &tz);
elapsed += Diff();
return (double)elapsed;
}
void Watch::Continue() {
gettimeofday(&tstart, &tz);
}
double Watch::Time() {
gettimeofday(&tend, &tz);
return (double)(elapsed + Diff());
}
double Watch::Diff() {
double t1 = (double)tstart.tv_sec + (double)tstart.tv_usec/(1000*1000);
double t2 = (double)tend.tv_sec + (double)tend.tv_usec/(1000*1000);
return t2 - t1;
}
#endif
void Watch::Reset() {
elapsed = 0;
}
int Watch::Usec() {
#ifdef WIN32
return 0;
#else
struct timeval ttime;
gettimeofday(&ttime, &tz);
return ttime.tv_usec;
#endif
}
void Report::Init(unsigned int t, double inter) {
watch.Start();
tot = t;
last = 0;
interval = inter;
}
void Report::Step(unsigned int count) {
if(count == 0) return;
double now = watch.Time();
if(now - last < interval) return;
//estimate final time
double tot_time = now * tot/(double)count;
printf("%d/%d\telapsed: %.1f\tremaining: %.1f\ttotal: %.1f\n",
count, tot, now, tot_time - now, tot_time);
last = now;
}
void Report::Finish() {
double now = watch.Time();
printf("Tot: %.1f\tN: %d\tN/sec: %.1f\n",
now, tot, tot/now);
}

View File

@ -1,108 +0,0 @@
/****************************************************************************
* VCGLib o o *
* Visual and Computer Graphics Library o o *
* _ O _ *
* Copyright(C) 2004 \/)\/ *
* Visual Computing Lab /\/| *
* ISTI - Italian National Research Council | *
* \ *
* All rights reserved. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
* for more details. *
* *
****************************************************************************/
/****************************************************************************
History
$Log: not supported by cvs2svn $
Revision 1.6 2004/12/15 13:50:32 ponchio
Optimizing realtime vis.
Revision 1.5 2004/12/01 16:00:35 ponchio
Level 3
Revision 1.4 2004/11/28 04:10:59 ponchio
winsockapi include problem
Revision 1.3 2004/10/21 13:40:16 ponchio
Debugging.
Revision 1.2 2004/10/21 12:14:02 ponchio
Support for mfile (>4Gb)
Revision 1.1 2004/10/19 17:20:24 ponchio
renamed
Revision 1.4 2004/10/19 17:16:53 ponchio
Changed interface
Revision 1.3 2004/07/20 14:03:47 ponchio
Changed interface.
Revision 1.2 2004/07/05 15:49:39 ponchio
Windows (DevCpp, mingw) port.
Revision 1.1 2004/07/01 21:38:30 ponchio
First draft created.
****************************************************************************/
#ifndef VCG_WATCH_H
#define VCG_WATCH_H
#ifdef WIN32
#ifndef _WINDOWS_
#define _WINSOCKAPI_
#include <windows.h>
#endif
#else
#include <sys/time.h>
#include <unistd.h>
#endif
class Watch {
public:
Watch();
void Start();
double Pause();
void Continue();
void Reset();
double Time();
int Usec();
private:
double Diff();
#ifdef WIN32
LARGE_INTEGER tstart, tend;
LARGE_INTEGER freq;
#else
struct timeval tstart, tend;
struct timezone tz;
#endif
double elapsed;
};
class Report {
public:
Report(unsigned int tot = 1, double inter = 30.0f) { Init(tot, inter); }
void Init(unsigned int tot, double inter = 30.0f);
void Step(unsigned int count);
void Finish();
private:
Watch watch;
int tot;
double last;
double interval;
};
#endif

View File

@ -1,46 +0,0 @@
#ifndef VCG_ZCURVE_H
#include <vcg/space/box3.h>
namespace vcg {
class ZCurve: public Box3f {
public:
unsigned int side;
ZCurve(): side(1024) {}
void SetSide(int s) { assert(s <= (1<<10)); side = s; }
unsigned int Pos(const Point3f &p) const {
assert(!IsNull());
unsigned int position = 0;
float x = (p[0] - min[0])/(max[0] - min[0]);
float y = (p[1] - min[1])/(max[1] - min[1]);
float z = (p[2] - min[2])/(max[2] - min[2]);
unsigned int s = side;
while(s > 1) {
position *= 8;
x *= 2;
y *= 2;
z *= 2;
int dx = (int)floor(x);
int dy = (int)floor(y);
int dz = (int)floor(z);
position += dx + 2 * dy + 4 * dz;
x -= dx;
y -= dy;
z -= dz;
s /= 2;
}
return position;
}
};
}
#endif