*** empty log message ***
This commit is contained in:
parent
644fca68bf
commit
76617c2a7f
|
@ -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
|
|
@ -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));
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
@ -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) = |
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
}
|
||||
|
|
@ -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
|
|
@ -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 ¢er, 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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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 |
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
} */
|
|
@ -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
|
|
@ -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]);
|
||||
}
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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 ¢er = 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);
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
|
@ -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> ¢roids,
|
||||
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;
|
||||
}
|
|
@ -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> ¢roids,
|
||||
std::vector<unsigned int> &counts,
|
||||
bool join);
|
||||
|
||||
int GetBest(VPartition &part, unsigned int seed,
|
||||
std::vector<bool> &mark,
|
||||
std::vector<unsigned int> &counts);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -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]);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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]);
|
||||
}
|
|
@ -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
|
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -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
|
Loading…
Reference in New Issue