created
This commit is contained in:
parent
fa6da0bbf3
commit
c35cead5ce
|
@ -0,0 +1,157 @@
|
||||||
|
#include "extraction.h"
|
||||||
|
#include "metric.h"
|
||||||
|
#include "nexusmt.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace nxs;
|
||||||
|
|
||||||
|
Extraction::Extraction(): target_error(4.0f), extr_max(0xffffffff),
|
||||||
|
draw_max(640), disk_max(100) {
|
||||||
|
metric = new FrustumMetric;
|
||||||
|
}
|
||||||
|
|
||||||
|
Extraction::~Extraction() {
|
||||||
|
if(metric) delete metric;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Extraction::Extract(NexusMt *_mt) {
|
||||||
|
mt = _mt;
|
||||||
|
|
||||||
|
//clear statistics
|
||||||
|
extr_used = draw_used = disk_used = 0;
|
||||||
|
|
||||||
|
//first we clear the visited flags
|
||||||
|
visited.clear();
|
||||||
|
visited.resize(mt->history.n_nodes(), false);
|
||||||
|
|
||||||
|
heap.clear();
|
||||||
|
|
||||||
|
History::Node *root = mt->history.Root();
|
||||||
|
HeapNode hroot(root, 0);
|
||||||
|
Diff(hroot);
|
||||||
|
extr_used += hroot.extr;
|
||||||
|
draw_used += hroot.draw;
|
||||||
|
disk_used += hroot.disk;
|
||||||
|
|
||||||
|
Visit(root);
|
||||||
|
|
||||||
|
while(heap.size()) {
|
||||||
|
pop_heap(heap.begin(), heap.end());
|
||||||
|
HeapNode hnode = heap.back();
|
||||||
|
heap.pop_back();
|
||||||
|
|
||||||
|
History::Node *node = hnode.node;
|
||||||
|
unsigned int id = node - root;
|
||||||
|
if(visited[id]) continue;
|
||||||
|
|
||||||
|
if(Expand(hnode)) {
|
||||||
|
extr_used += hnode.extr;
|
||||||
|
draw_used += hnode.draw;
|
||||||
|
disk_used += hnode.disk;
|
||||||
|
Visit(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Select();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Extraction::Select() {
|
||||||
|
selected.clear();
|
||||||
|
History::Node *root = mt->history.Root();
|
||||||
|
|
||||||
|
History::Node *nodes = mt->history.nodes;
|
||||||
|
for(unsigned int i = 0; i < visited.size(); i++) {
|
||||||
|
if(!visited[i]) continue;
|
||||||
|
History::Node &node = nodes[i];
|
||||||
|
|
||||||
|
History::Node::iterator n;
|
||||||
|
for(n = node.out_begin(); n != node.out_end(); n++) {
|
||||||
|
unsigned int n_out = (*n).node - root;
|
||||||
|
if(!visited[n_out]) {
|
||||||
|
History::Link &link = *n;
|
||||||
|
for(History::Link::iterator k = link.begin(); k != link.end(); k++) {
|
||||||
|
unsigned int patch = (*k).patch;
|
||||||
|
selected.push_back(patch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Extraction::Visit(History::Node *node) {
|
||||||
|
History::Node *root = mt->history.Root();
|
||||||
|
unsigned int n_node = node - root;
|
||||||
|
if(visited[n_node]) return;
|
||||||
|
|
||||||
|
visited[n_node] = true;
|
||||||
|
|
||||||
|
History::Node::iterator i;
|
||||||
|
for(i = node->in_begin(); i != node->in_end(); i++) {
|
||||||
|
unsigned int n_in = (*i).node - root;
|
||||||
|
if(visited[n_in]) continue;
|
||||||
|
HeapNode hin((*i).node, 0);
|
||||||
|
Diff(hin);
|
||||||
|
extr_used += hin.extr;
|
||||||
|
draw_used += hin.draw;
|
||||||
|
disk_used += hin.disk;
|
||||||
|
Visit((*i).node);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(i = node->out_begin(); i != node->out_end(); i++) {
|
||||||
|
float maxerror = 0;
|
||||||
|
History::Link &link = *i;
|
||||||
|
for(History::Link::iterator k = link.begin(); k != link.end(); k++) {
|
||||||
|
Entry &entry = (*mt)[(*k).patch];
|
||||||
|
float error = metric->GetError(entry);
|
||||||
|
if(error > maxerror) maxerror = error;
|
||||||
|
}
|
||||||
|
//TODO this check may be dangerous for non saturating things...
|
||||||
|
if(maxerror > target_error) {
|
||||||
|
HeapNode hnode((*i).node, maxerror);
|
||||||
|
Diff(hnode);
|
||||||
|
heap.push_back(hnode);
|
||||||
|
push_heap(heap.begin(), heap.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(HeapNode &hnode) {
|
||||||
|
History::Node &node = *(hnode.node);
|
||||||
|
History::Node::iterator i;
|
||||||
|
for(i = node.in_begin(); i != node.in_end(); i++) {
|
||||||
|
History::Link &link = *i;
|
||||||
|
for(History::Link::iterator k = link.begin(); k != link.end(); k++) {
|
||||||
|
unsigned int patch = (*k).patch;
|
||||||
|
Entry &entry = (*mt)[patch];
|
||||||
|
hnode.extr -= entry.ram_size;
|
||||||
|
vcg::Sphere3f &sphere = entry.sphere;
|
||||||
|
if(!frustum.IsOutside(sphere.Center(), sphere.Radius()))
|
||||||
|
hnode.draw -= entry.ram_size;
|
||||||
|
if(!entry.patch)
|
||||||
|
hnode.disk -= entry.disk_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(i = node.out_begin(); i != node.out_end(); i++) {
|
||||||
|
History::Link &link = *i;
|
||||||
|
for(History::Link::iterator k = link.begin(); k != link.end(); k++) {
|
||||||
|
unsigned int patch = (*k).patch;
|
||||||
|
Entry &entry = (*mt)[patch];
|
||||||
|
hnode.extr += entry.ram_size;
|
||||||
|
vcg::Sphere3f &sphere = entry.sphere;
|
||||||
|
if(!frustum.IsOutside(sphere.Center(), sphere.Radius()))
|
||||||
|
hnode.draw += entry.ram_size;
|
||||||
|
if(!entry.patch)
|
||||||
|
hnode.disk += entry.disk_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,61 @@
|
||||||
|
#ifndef NXS_EXTRACTION_H
|
||||||
|
#define NXS_EXTRACTION_H
|
||||||
|
|
||||||
|
#include "history.h"
|
||||||
|
#include <vector>
|
||||||
|
#include <wrap/gui/frustum.h>
|
||||||
|
|
||||||
|
namespace nxs {
|
||||||
|
|
||||||
|
class Metric;
|
||||||
|
class NexusMt;
|
||||||
|
|
||||||
|
class Extraction {
|
||||||
|
public:
|
||||||
|
struct HeapNode {
|
||||||
|
History::Node *node;
|
||||||
|
float error;
|
||||||
|
unsigned int extr;
|
||||||
|
unsigned int draw;
|
||||||
|
unsigned int disk;
|
||||||
|
HeapNode(History::Node *_node, float _error): node(_node), error(_error),
|
||||||
|
extr(0), draw(0), disk(0) {}
|
||||||
|
bool operator<(const HeapNode &node) const {
|
||||||
|
return error < node.error; }
|
||||||
|
};
|
||||||
|
|
||||||
|
Metric *metric;
|
||||||
|
|
||||||
|
vcg::Frustumf frustum;
|
||||||
|
|
||||||
|
float target_error;
|
||||||
|
unsigned int extr_used, extr_max;
|
||||||
|
unsigned int draw_used, draw_max;
|
||||||
|
unsigned int disk_used, disk_max;
|
||||||
|
|
||||||
|
std::vector<bool> visited;
|
||||||
|
std::vector<HeapNode> heap;
|
||||||
|
std::vector<unsigned int> selected;
|
||||||
|
|
||||||
|
Extraction();
|
||||||
|
~Extraction();
|
||||||
|
|
||||||
|
void Extract(NexusMt *mt);
|
||||||
|
// void Update(std::vector<unsigned int> &selected);
|
||||||
|
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void Select();
|
||||||
|
void Visit(History::Node *node);
|
||||||
|
|
||||||
|
bool Expand(HeapNode &node);
|
||||||
|
void Diff(HeapNode &node);
|
||||||
|
|
||||||
|
private:
|
||||||
|
NexusMt *mt;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}//namespace
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,297 @@
|
||||||
|
#include <assert.h>
|
||||||
|
#include <map>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "history.h"
|
||||||
|
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace nxs;
|
||||||
|
|
||||||
|
History::~History() {
|
||||||
|
if(buffer) delete []buffer;
|
||||||
|
nodes = NULL;
|
||||||
|
in_links= NULL;
|
||||||
|
out_links = NULL;
|
||||||
|
frags = 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) {
|
||||||
|
// cerr << "Load quick!\n";
|
||||||
|
success = LoadQuick(_size, mem);
|
||||||
|
} else if(is_quick == 32) {
|
||||||
|
// cerr << "Load updates\n";
|
||||||
|
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 + 5 * sizeof(int));
|
||||||
|
in_links = (Link *)(nodes + n_nodes());
|
||||||
|
out_links = in_links + n_in_links();
|
||||||
|
frags = (Cell *)(out_links + n_out_links());
|
||||||
|
|
||||||
|
//check size is ok;
|
||||||
|
assert(n_nodes() * sizeof(Node) +
|
||||||
|
(n_in_links() + n_out_links()) * sizeof(Link) +
|
||||||
|
n_frags() * sizeof(Cell) +
|
||||||
|
5 * 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_link_begin) <= n_in_links());
|
||||||
|
assert(((unsigned int)node.out_link_begin) <= n_out_links());
|
||||||
|
node.in_link_begin = in_links + (unsigned int)(node.in_link_begin);
|
||||||
|
node.out_link_begin = out_links + (unsigned int)(node.out_link_begin);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(unsigned int i = 0; i < n_in_links(); i++) {
|
||||||
|
Link &link = in_links[i];
|
||||||
|
assert(((unsigned int)link.node) <= n_nodes());
|
||||||
|
assert(((unsigned int)link.frag_begin) <= n_frags());
|
||||||
|
link.node = nodes + (unsigned int)(link.node);
|
||||||
|
link.frag_begin = frags + (unsigned int)(link.frag_begin);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(unsigned int i = 0; i < n_out_links(); i++) {
|
||||||
|
Link &link = out_links[i];
|
||||||
|
assert(((unsigned int)link.node) <= n_nodes());
|
||||||
|
assert(((unsigned int)link.frag_begin) <= n_frags());
|
||||||
|
link.node = nodes + (unsigned int)(link.node);
|
||||||
|
link.frag_begin = frags + (unsigned int)(link.frag_begin);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *History::Save(unsigned int &_size) {
|
||||||
|
if(buffer) {
|
||||||
|
// cerr << "SaveQuick!\n";
|
||||||
|
return SaveQuick(_size);
|
||||||
|
} else {
|
||||||
|
// cerr << "Save updates\n";
|
||||||
|
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_link_begin = (Link *)(node.in_link_begin - in_links);
|
||||||
|
node.out_link_begin = (Link *)(node.out_link_begin - out_links);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(unsigned int i = 0; i < n_in_links(); i++) {
|
||||||
|
Link &link = in_links[i];
|
||||||
|
link.node = (Node *)(link.node - nodes);
|
||||||
|
link.frag_begin = (Cell *)(link.frag_begin - frags);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(unsigned int i = 0; i < n_out_links(); i++) {
|
||||||
|
Link &link = out_links[i];
|
||||||
|
link.node = (Node *)(link.node - nodes);
|
||||||
|
link.frag_begin = (Cell *)(link.frag_begin - frags);
|
||||||
|
}
|
||||||
|
|
||||||
|
_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() {
|
||||||
|
//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<Cell> 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, we look also for max error.
|
||||||
|
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++) {
|
||||||
|
|
||||||
|
//node.in.push_back(innodes.size());
|
||||||
|
|
||||||
|
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.frag_begin = (Cell *)(tmp_frags.size());
|
||||||
|
inlink.frag_size = cells.size();
|
||||||
|
|
||||||
|
Link outlink;
|
||||||
|
outlink.node = (Node *)current_node;
|
||||||
|
outlink.frag_begin = (Cell *)(tmp_frags.size());
|
||||||
|
outlink.frag_size = cells.size();
|
||||||
|
|
||||||
|
//Fill it with erased cells.
|
||||||
|
|
||||||
|
vector<unsigned int>::iterator k;
|
||||||
|
for(k = cells.begin(); k != cells.end(); k++) {
|
||||||
|
Cell cell;
|
||||||
|
cell.patch = (*k);
|
||||||
|
tmp_frags.push_back(cell);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Add the new Frag to the node.
|
||||||
|
|
||||||
|
node_outlinks[floor_node].push_back(outlink);
|
||||||
|
node_inlinks[current_node].push_back(inlink);
|
||||||
|
|
||||||
|
//Update in and out of the nodes.
|
||||||
|
}
|
||||||
|
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_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();
|
||||||
|
|
||||||
|
for(unsigned int i = 0; i < links.size(); i++)
|
||||||
|
tmp_in_links.push_back(links[i]);
|
||||||
|
}
|
||||||
|
size = tmp_nodes.size() * sizeof(Node) +
|
||||||
|
tmp_in_links.size() * sizeof(Link) +
|
||||||
|
tmp_out_links.size() * sizeof(Link) +
|
||||||
|
tmp_frags.size() * sizeof(Cell) +
|
||||||
|
5 * 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();
|
||||||
|
n_frags() = tmp_frags.size();
|
||||||
|
|
||||||
|
nodes = (Node *)(buffer + 5 * sizeof(int));
|
||||||
|
in_links = (Link *)(nodes + n_nodes());
|
||||||
|
out_links = in_links + n_in_links();
|
||||||
|
frags = (Cell *)(out_links + n_out_links());
|
||||||
|
|
||||||
|
memcpy(nodes, &*tmp_nodes.begin(), tmp_nodes.size()*sizeof(Node));
|
||||||
|
memcpy(in_links, &*tmp_in_links.begin(), tmp_in_links.size()*sizeof(Node));
|
||||||
|
memcpy(out_links, &*tmp_out_links.begin(),
|
||||||
|
tmp_out_links.size()*sizeof(Node));
|
||||||
|
memcpy(frags, &*tmp_frags.begin(), tmp_frags.size() * sizeof(Cell));
|
||||||
|
|
||||||
|
return LoadPointers();
|
||||||
|
}
|
|
@ -0,0 +1,103 @@
|
||||||
|
#ifndef NXS_HISTORY_H
|
||||||
|
#define NXS_HISTORY_H
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
//TODO fix a bit better the quick <-> updates duality
|
||||||
|
|
||||||
|
namespace nxs {
|
||||||
|
|
||||||
|
class History {
|
||||||
|
public:
|
||||||
|
|
||||||
|
enum Mode { QUICK = 1, UPDATES = 2 };
|
||||||
|
|
||||||
|
struct Update {
|
||||||
|
std::vector<unsigned int> erased;
|
||||||
|
std::vector<unsigned int> created;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Cell {
|
||||||
|
unsigned int patch;
|
||||||
|
// float error;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Node;
|
||||||
|
|
||||||
|
struct Link {
|
||||||
|
Node *node;
|
||||||
|
|
||||||
|
typedef Cell *iterator;
|
||||||
|
iterator begin() { return frag_begin; }
|
||||||
|
iterator end() { return frag_begin + frag_size; }
|
||||||
|
unsigned int size() { return frag_size; }
|
||||||
|
|
||||||
|
Cell *frag_begin;
|
||||||
|
unsigned int frag_size;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Node {
|
||||||
|
typedef Link *iterator;
|
||||||
|
|
||||||
|
iterator in_begin() { return in_link_begin; }
|
||||||
|
iterator in_end() { return in_link_begin + in_link_size; }
|
||||||
|
unsigned int size() { return in_link_size; }
|
||||||
|
|
||||||
|
iterator out_begin() { return out_link_begin; }
|
||||||
|
iterator out_end() { return out_link_begin + out_link_size; }
|
||||||
|
unsigned int out_size() { return out_link_size; }
|
||||||
|
|
||||||
|
Link *in_link_begin;
|
||||||
|
unsigned int in_link_size;
|
||||||
|
Link *out_link_begin;
|
||||||
|
unsigned int out_link_size;
|
||||||
|
};
|
||||||
|
|
||||||
|
Node *nodes;
|
||||||
|
Link *in_links;
|
||||||
|
Link *out_links;
|
||||||
|
Cell *frags;
|
||||||
|
|
||||||
|
std::vector<Update> updates;
|
||||||
|
|
||||||
|
History(): nodes(NULL), in_links(NULL), out_links(NULL), frags(NULL),
|
||||||
|
buffer(NULL) {}
|
||||||
|
~History();
|
||||||
|
|
||||||
|
Node *Root() { return &nodes[0]; }
|
||||||
|
|
||||||
|
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();
|
||||||
|
bool IsQuick() { return buffer != NULL; }
|
||||||
|
|
||||||
|
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]; }
|
||||||
|
int &n_frags() { return ((int *)buffer)[4]; }
|
||||||
|
|
||||||
|
typedef Node *iterator;
|
||||||
|
iterator begin() { return nodes; }
|
||||||
|
iterator end() { return nodes + n_nodes(); }
|
||||||
|
protected:
|
||||||
|
unsigned int size;
|
||||||
|
char *buffer;
|
||||||
|
|
||||||
|
bool LoadPointers();
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -0,0 +1,79 @@
|
||||||
|
#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
|
|
@ -0,0 +1,40 @@
|
||||||
|
#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:
|
||||||
|
virtual void GetView() {}
|
||||||
|
virtual float GetError(Entry &entry) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class FlatMetric: public Metric {
|
||||||
|
public:
|
||||||
|
float GetError(Entry &entry) { return entry.error; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class FrustumMetric: public Metric {
|
||||||
|
public:
|
||||||
|
vcg::Frustumf frustum;
|
||||||
|
|
||||||
|
virtual void GetView() { frustum.GetView(); }
|
||||||
|
float GetError(Entry &entry) {
|
||||||
|
vcg::Sphere3f &sphere = entry.sphere;
|
||||||
|
float dist = Distance(sphere, frustum.ViewPoint());
|
||||||
|
if(dist < 0)
|
||||||
|
return 1e20f;
|
||||||
|
if(frustum.IsOutside(sphere.Center(), sphere.Radius()))
|
||||||
|
return -1;
|
||||||
|
return entry.error/frustum.Resolution(dist);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,159 @@
|
||||||
|
#include "preload.h"
|
||||||
|
#include "nexusmt.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace nxs;
|
||||||
|
|
||||||
|
void Preload::execute() {
|
||||||
|
assert(mt);
|
||||||
|
while(!get_signaled()) {
|
||||||
|
lock.enter();
|
||||||
|
while(!queue.size()) {
|
||||||
|
lock.leave();
|
||||||
|
pt::psleep(10);
|
||||||
|
lock.enter();
|
||||||
|
}
|
||||||
|
//TODO check we are not loading too much memory!
|
||||||
|
assert(queue.size());
|
||||||
|
unsigned int patch = queue.back();
|
||||||
|
mt->GetPatch(patch, false);
|
||||||
|
queue.pop_back();
|
||||||
|
lock.leave();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*void Preload::init(NexusMt *m, std::vector<unsigned int> &selected,
|
||||||
|
std::vector<PServer::Item> &visited) {
|
||||||
|
|
||||||
|
// cerr << "Init\n";
|
||||||
|
|
||||||
|
safety.lock();
|
||||||
|
mt = m;
|
||||||
|
missing.clear();
|
||||||
|
mt->todraw.clear();
|
||||||
|
float loaded = 0;
|
||||||
|
unsigned int notloaded = 0;
|
||||||
|
set<unsigned int> tmp;
|
||||||
|
//std::map<unsigned int, float> tmp;
|
||||||
|
vector<QueuePServer::Data> flush;
|
||||||
|
for(unsigned int i = 0; i < selected.size(); i++) {
|
||||||
|
unsigned int patch = selected[i];
|
||||||
|
tmp.insert(patch);
|
||||||
|
|
||||||
|
if(!mt->patches.entries[patch].patch) {
|
||||||
|
PServer::Entry &entry = mt->patches.entries[patch];
|
||||||
|
load.post(patch);
|
||||||
|
loaded += entry.disk_size;
|
||||||
|
} else {
|
||||||
|
PatchInfo &info = mt->index[patch];
|
||||||
|
//WORKING QueuePServer::Data &data = mt->patches.Lookup(patch, info.nvert, info.nface, 0.0f, flush);
|
||||||
|
QueuePServer::Data &data = mt->patches.Lookup(patch, info.nvert, info.nface, flush);
|
||||||
|
for(unsigned int i = 0; i < flush.size(); i++) {
|
||||||
|
QueuePServer::Data *data = new QueuePServer::Data;
|
||||||
|
*data = flush[i];
|
||||||
|
draw.post(FLUSH, (unsigned int)data);
|
||||||
|
}
|
||||||
|
// WORKING if(flush.size() != 0) {
|
||||||
|
// cerr << "Flushing!\n";
|
||||||
|
// exit(0);
|
||||||
|
//}
|
||||||
|
mt->todraw.push_back(&data);
|
||||||
|
}
|
||||||
|
//missing.push_back(PServer::Item(patch, 0.0f));
|
||||||
|
}
|
||||||
|
loading = 0.2 * loaded + 0.8 * loading;
|
||||||
|
|
||||||
|
for(unsigned int i = 0; i < visited.size(); i++) {
|
||||||
|
PServer::Item &item = visited[i];
|
||||||
|
if(tmp.count(item.patch)) continue;
|
||||||
|
// if(mt->patches.entries[item.patch].patch)
|
||||||
|
// tmp[item.patch] = item.priority;
|
||||||
|
if(item.priority != 0.0f)
|
||||||
|
missing.push_back(item);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
/* WORKING QueuePServer &ps = mt->patches;
|
||||||
|
for(unsigned int i = 0; i < ps.heap.size(); i++) {
|
||||||
|
PServer::Item &item = ps.heap[i];
|
||||||
|
if(tmp.count(item.patch))
|
||||||
|
item.priority = 0;
|
||||||
|
else {
|
||||||
|
if(item.priority == 0)
|
||||||
|
item.priority = 1;
|
||||||
|
item.priority *= 1.1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
make_heap(ps.heap.begin(), ps.heap.end());*/
|
||||||
|
|
||||||
|
/* sort(missing.begin(), missing.end()); //CRITICAL reverse pero'!
|
||||||
|
reverse(missing.begin(), missing.end());
|
||||||
|
load.post(0xffffffff);
|
||||||
|
|
||||||
|
safety.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Preload::execute() {
|
||||||
|
|
||||||
|
float preload;
|
||||||
|
prefetching = 0;
|
||||||
|
loading = 0;
|
||||||
|
while(1) {
|
||||||
|
if(get_signaled()) return;
|
||||||
|
vector<QueuePServer::Data> flush;
|
||||||
|
|
||||||
|
if(load.get_count() || missing.size() == 0) {
|
||||||
|
preload = 0;
|
||||||
|
pt::message *msg = load.getmessage();
|
||||||
|
if(msg->id != 0xffffffff) {
|
||||||
|
safety.lock();
|
||||||
|
PatchInfo &info = mt->index[msg->id];
|
||||||
|
PServer::Entry &entry = mt->patches.entries[msg->id];
|
||||||
|
loading += entry.disk_size;
|
||||||
|
//posting draw message
|
||||||
|
//WORKING QueuePServer::Data &data = mt->patches.Lookup(msg->id, info.nvert, info.nface, 0.0f, flush);
|
||||||
|
QueuePServer::Data &data = mt->patches.Lookup(msg->id, info.nvert, info.nface, flush);
|
||||||
|
pt::message *msg = new pt::message(DRAW, (unsigned int)&data);
|
||||||
|
msg->result = msg->id;
|
||||||
|
draw.post(msg);
|
||||||
|
|
||||||
|
//p;osting flush messages
|
||||||
|
for(unsigned int i = 0; i < flush.size(); i++) {
|
||||||
|
QueuePServer::Data *data = new QueuePServer::Data;
|
||||||
|
*data = flush[i];
|
||||||
|
draw.post(FLUSH, (unsigned int)data);
|
||||||
|
}
|
||||||
|
safety.unlock();
|
||||||
|
} else {
|
||||||
|
prefetching = 0.2 * preload + 0.8 * prefetching;
|
||||||
|
}
|
||||||
|
delete msg;
|
||||||
|
} else {
|
||||||
|
safety.lock();
|
||||||
|
if(missing.size() != 0) {
|
||||||
|
PServer::Item item = missing.back();
|
||||||
|
missing.pop_back();
|
||||||
|
|
||||||
|
/*Working if(item.priority > mt->patches.MaxPriority()) {
|
||||||
|
missing.clear();
|
||||||
|
|
||||||
|
} else { */
|
||||||
|
/*PatchInfo &info = mt->index[item.patch];
|
||||||
|
//cerr << "prefetching: " << item.patch << endl;
|
||||||
|
//WORKING mt->patches.Lookup(item.patch, info.nvert, info.nface, item.priority, flush);
|
||||||
|
if(!mt->patches.entries[item.patch].patch) {
|
||||||
|
PServer::Entry &entry = mt->patches.entries[item.patch];
|
||||||
|
preload += entry.disk_size;
|
||||||
|
|
||||||
|
mt->patches.Lookup(item.patch, info.nvert, info.nface, flush);
|
||||||
|
for(unsigned int i = 0; i < flush.size(); i++) {
|
||||||
|
QueuePServer::Data *data = new QueuePServer::Data;
|
||||||
|
*data = flush[i];
|
||||||
|
draw.post(FLUSH, (unsigned int)data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
safety.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}*/
|
|
@ -0,0 +1,40 @@
|
||||||
|
#ifndef NXS_PRELOAD_H
|
||||||
|
#define NXS_PRELOAD_H
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <ptypes/pasync.h>
|
||||||
|
|
||||||
|
namespace nxs {
|
||||||
|
|
||||||
|
class NexusMt;
|
||||||
|
|
||||||
|
class Preload: public pt::thread{
|
||||||
|
public:
|
||||||
|
|
||||||
|
NexusMt *mt;
|
||||||
|
|
||||||
|
pt::mutex lock;
|
||||||
|
|
||||||
|
std::vector<unsigned int> queue;
|
||||||
|
|
||||||
|
Preload(): thread(false) {}
|
||||||
|
~Preload() {
|
||||||
|
waitfor();
|
||||||
|
}
|
||||||
|
|
||||||
|
void execute();
|
||||||
|
|
||||||
|
void post(std::vector<unsigned int> &patches) {
|
||||||
|
lock.enter();
|
||||||
|
queue = patches;
|
||||||
|
lock.leave();
|
||||||
|
}
|
||||||
|
|
||||||
|
void cleanup() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
Loading…
Reference in New Issue