1018 lines
28 KiB
C++
1018 lines
28 KiB
C++
#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::Init() {
|
|
ktri = 0;
|
|
kdisk = 0;
|
|
if(count == 25) count = 0;
|
|
if(!count) {
|
|
fps = 25/watch.Time();
|
|
watch.Start();
|
|
}
|
|
count++;
|
|
}
|
|
|
|
/*float ExtractContest::GetError(PatchInfo &entry) {
|
|
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);
|
|
}*/
|
|
|
|
/*
|
|
float Metric::GetError(Node *node) {
|
|
float max_error = 0;
|
|
vector<Frag>::iterator frag;
|
|
for(frag = node->frags.begin(); frag != node->frags.end(); frag++) {
|
|
float error = GetError(*frag);
|
|
if(max_error < error) max_error = error;
|
|
}
|
|
return max_error;
|
|
}
|
|
|
|
float Metric::GetError(Frag &frag) {
|
|
float max_error = 0;
|
|
vector<unsigned int>::iterator cell;
|
|
for(cell = frag.begin(); cell != frag.end(); cell++) {
|
|
float error = GetError(*cell);
|
|
if(max_error < error) max_error = error;
|
|
}
|
|
return max_error;
|
|
}
|
|
|
|
float FrustumMetric::GetError(unsigned int cell) {
|
|
float max_error = 0;
|
|
PatchInfo &entry = (*index)[cell];
|
|
Sphere3f &sphere = entry.sphere;
|
|
float dist = Distance(sphere, frustum.ViewPoint());
|
|
if(dist < 0) return 1e20f;
|
|
float error = entry.error/frustum.Resolution(dist);
|
|
if(frustum.IsOutside(sphere.Center(), sphere.Radius()))
|
|
error /= 32;
|
|
return error;
|
|
}
|
|
|
|
bool NexusMt::Expand(TNode &tnode) {
|
|
//expand if node error > target error
|
|
if(extraction_used >= extraction_max) return false;
|
|
if(draw_used >= draw_max) return false;
|
|
if(disk_used >= disk_max) {
|
|
float ratio = disk_max / (float)disk_used;
|
|
float error = tnode.error * ratio;
|
|
return error > target_error;
|
|
}
|
|
return tnode.error > target_error;
|
|
}*/
|
|
|
|
/*void NexusMt::NodeVisited(Node *node) {
|
|
//TODO write this a bit more elegant.
|
|
//first we process arcs removed:
|
|
|
|
for(unsigned int i = 0; i < node->out.size(); i++) {
|
|
//assert(!(node->out[i]->visited));
|
|
Frag &frag = node->frags[i];
|
|
for(unsigned int k = 0; k < frag.size(); k++) {
|
|
unsigned int patch = frag[k];
|
|
PServer::Entry &entry = patches.entries[patch];
|
|
unsigned int ram_size = entry.ram_size;
|
|
extraction_used += ram_size;
|
|
PatchInfo &info = index[patch];
|
|
if(!frustum.IsOutside(info.sphere.Center(), info.sphere.Radius()))
|
|
draw_used += ram_size;
|
|
if(!patches.entries[patch].patch)
|
|
disk_used += ram_size;
|
|
}
|
|
}
|
|
|
|
vector<Node *>::iterator from;
|
|
for(from = node->in.begin(); from != node->in.end(); from++) {
|
|
assert((*from)->visited);
|
|
vector<Frag> &frags = (*from)->frags;
|
|
for(unsigned int i = 0; i < frags.size(); i++) {
|
|
if((*from)->out[i] == node) {
|
|
vector<unsigned int> &frag = frags[i];
|
|
for(unsigned int k = 0; k < frag.size(); k++) {
|
|
unsigned int patch = frag[k];
|
|
PServer::Entry &entry = patches.entries[patch];
|
|
extraction_used -= entry.ram_size;
|
|
PatchInfo &info = index[patch];
|
|
if(!frustum.IsOutside(info.sphere.Center(), info.sphere.Radius()))
|
|
draw_used -= entry.ram_size;
|
|
if(!patches.entries[patch].patch)
|
|
disk_used -= entry.ram_size;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}*/
|
|
|
|
NexusMt::NexusMt() {
|
|
preload.mt = this;
|
|
preload.start();
|
|
|
|
cerr << "Ramsize: " << ram_max << endl;
|
|
// SetPrefetchSize(patches.ram_max/2);
|
|
// prefetch.start();
|
|
}
|
|
|
|
NexusMt::~NexusMt() {
|
|
preload.signal();
|
|
preload.waitfor();
|
|
}
|
|
|
|
bool NexusMt::Load(const string &filename) {
|
|
if(!Nexus::Load(filename, true)) return false;
|
|
if(!history.IsQuick() && !history.UpdatesToQuick())
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
//void NexusMt::Close() {
|
|
// prefetch.signal();
|
|
// prefetch.waitfor();
|
|
// patches.Close();
|
|
//}
|
|
|
|
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.frustum.GetView();
|
|
extraction.metric->GetView();
|
|
extraction.Extract(this);
|
|
Render(extraction, contest);
|
|
}
|
|
|
|
void NexusMt::Render(Extraction &extraction, DrawContest &contest,
|
|
Stats *stats) {
|
|
if(stats) stats->Init();
|
|
|
|
preload.post(extraction.selected);
|
|
|
|
glEnableClientState(GL_VERTEX_ARRAY);
|
|
if((signature & NXS_COLORS) && (contest.attrs & DrawContest::COLOR))
|
|
glEnableClientState(GL_COLOR_ARRAY);
|
|
if((signature & NXS_NORMALS_SHORT) && (contest.attrs & DrawContest::NORMAL))
|
|
glEnableClientState(GL_NORMAL_ARRAY);
|
|
|
|
vector<unsigned int> skipped;
|
|
|
|
vector<unsigned int>::iterator i;
|
|
for(i = extraction.selected.begin(); i != extraction.selected.end(); i++) {
|
|
Entry &entry = operator[](*i);
|
|
vcg::Sphere3f &sphere = entry.sphere;
|
|
if(extraction.frustum.IsOutside(sphere.Center(), sphere.Radius()))
|
|
continue;
|
|
|
|
if(stats) stats->ktri += entry.nface;
|
|
|
|
if(!entry.patch) {
|
|
skipped.push_back(*i);
|
|
continue;
|
|
}
|
|
|
|
Draw(*i, contest);
|
|
}
|
|
|
|
preload.lock.enter();
|
|
for(i = skipped.begin(); i != skipped.end(); i++) {
|
|
GetPatch(*i);
|
|
Draw(*i, contest);
|
|
}
|
|
// Flush(false); //not useful now
|
|
preload.lock.leave();
|
|
|
|
glDisableClientState(GL_VERTEX_ARRAY);
|
|
glDisableClientState(GL_COLOR_ARRAY);
|
|
glDisableClientState(GL_NORMAL_ARRAY);
|
|
|
|
//flushing mem
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/*void NexusMt::Draw(vector<unsigned int> &cells) {
|
|
stats.start();
|
|
|
|
todraw.clear();
|
|
vector<QueuePServer::Data> flush;
|
|
for(unsigned int i = 0; i < cells.size(); i++) {
|
|
PatchInfo &entry = index[cells[i]];
|
|
QueuePServer::Data &data = patches.Lookup(cells[i], entry.nvert,
|
|
entry.nface, flush);
|
|
todraw.push_back(&data);
|
|
}
|
|
|
|
glEnableClientState(GL_VERTEX_ARRAY);
|
|
if(draw_cnt.use_colors)
|
|
glEnableClientState(GL_COLOR_ARRAY);
|
|
if(draw_cnt.use_normals)
|
|
glEnableClientState(GL_NORMAL_ARRAY);
|
|
//TODO textures and data.
|
|
|
|
|
|
// unsigned int count = draw.size();
|
|
unsigned int count = todraw.size();
|
|
while(count > 0 || prefetch.draw.get_count()) {
|
|
if(todraw.size()) {
|
|
QueuePServer::Data *data = todraw.back();
|
|
todraw.pop_back();
|
|
Draw((unsigned int)(data->patch), *data);
|
|
} else {
|
|
// cerr << "Getting message: " << count << endl;
|
|
pt::message *msg = prefetch.draw.getmessage();
|
|
QueuePServer::Data *data = (QueuePServer::Data *)(msg->param);
|
|
if(msg->id == Prefetch::FLUSH) {
|
|
patches.FlushVbo(*data);
|
|
// if(data->vbo_element) {
|
|
//glDeleteBuffersARB(1, &(data->vbo_element));
|
|
//glDeleteBuffersARB(1, &(data->vbo_array));
|
|
delete data;
|
|
delete msg;
|
|
continue;
|
|
}
|
|
|
|
if(msg->id != Prefetch::DRAW) {
|
|
cerr << "Unknown message!\n";
|
|
continue;
|
|
}
|
|
|
|
unsigned int cell = msg->result;
|
|
Draw(cell, *data);
|
|
|
|
delete msg;
|
|
}
|
|
count--;
|
|
}
|
|
glDisableClientState(GL_VERTEX_ARRAY);
|
|
glDisableClientState(GL_COLOR_ARRAY);
|
|
glDisableClientState(GL_NORMAL_ARRAY);
|
|
}*/
|
|
|
|
void NexusMt::Draw(unsigned int cell, DrawContest &contest) {
|
|
Entry &entry = operator[](cell);
|
|
Patch &patch = *(entry.patch);
|
|
char *fstart;
|
|
char *vstart;
|
|
char *cstart;
|
|
char *nstart;
|
|
|
|
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 *)(sizeof(float) * patch.cstart);
|
|
nstart = (char *)(sizeof(float) * patch.nstart);
|
|
} else {
|
|
fstart = (char *)patch.FaceBegin();
|
|
vstart = (char *)patch.VertBegin();
|
|
cstart = (char *)patch.ColorBegin();
|
|
nstart = (char *)patch.Norm16Begin();
|
|
}
|
|
|
|
glVertexPointer(3, GL_FLOAT, 0, vstart);
|
|
if(contest.attrs & DrawContest::COLOR)
|
|
glColorPointer(4, GL_UNSIGNED_BYTE, 0, cstart);
|
|
if(contest.attrs & DrawContest::NORMAL)
|
|
glNormalPointer(GL_SHORT, 8, nstart);
|
|
|
|
switch(contest.mode) {
|
|
case DrawContest::POINTS:
|
|
glDrawArrays(GL_POINTS, 0, patch.nv); break;
|
|
case DrawContest::PATCHES:
|
|
glColor3ub((cell * 27)%255, (cell * 37)%255, (cell * 87)%255);
|
|
case DrawContest::SMOOTH:
|
|
if(signature & NXS_FACES)
|
|
glDrawElements(GL_TRIANGLES, patch.nf * 3,
|
|
GL_UNSIGNED_SHORT, fstart);
|
|
else if(signature & NXS_STRIP)
|
|
glDrawElements(GL_TRIANGLE_STRIP, patch.nf,
|
|
GL_UNSIGNED_SHORT, fstart);
|
|
break;
|
|
case DrawContest::FLAT:
|
|
if(signature & NXS_FACES) {
|
|
glBegin(GL_TRIANGLES);
|
|
for(int i = 0; i < patch.nf; i++) {
|
|
unsigned short *f = patch.Face(i);
|
|
Point3f &p0 = patch.Vert(f[0]);
|
|
Point3f &p1 = patch.Vert(f[1]);
|
|
Point3f &p2 = patch.Vert(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]);
|
|
}
|
|
glEnd();
|
|
} else if(signature & NXS_STRIP) {
|
|
cerr << "Unsupported rendering mode sorry\n";
|
|
exit(0);
|
|
}
|
|
break;
|
|
default:
|
|
cerr << "Unsupported rendering mode sorry\n";
|
|
exit(0);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void NexusMt::FlushPatch(unsigned int id) {
|
|
Entry &entry = operator[](id);
|
|
if(entry.vbo_element)
|
|
FlushVbo(entry);
|
|
|
|
if(entry.patch->start)
|
|
delete [](entry.patch->start);
|
|
delete entry.patch;
|
|
entry.patch = NULL;
|
|
ram_used -= entry.ram_size;
|
|
}
|
|
|
|
void NexusMt::LoadVbo(Entry &entry) {
|
|
if(entry.vbo_element) return;
|
|
glGenBuffersARB(1, &entry.vbo_element);
|
|
assert(entry.vbo_element);
|
|
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, entry.vbo_element);
|
|
|
|
Patch &patch = *entry.patch;
|
|
unsigned int size = patch.nf * sizeof(unsigned short);
|
|
if((signature & NXS_FACES) != 0) size *= 3;
|
|
|
|
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 = sizeof(float) * patch.dstart;
|
|
|
|
glGenBuffersARB(1, &entry.vbo_array);
|
|
assert(entry.vbo_array);
|
|
glBindBufferARB(GL_ARRAY_BUFFER_ARB, entry.vbo_array);
|
|
|
|
glBufferDataARB(GL_ARRAY_BUFFER_ARB, size, patch.VertBegin(),
|
|
GL_STATIC_DRAW_ARB);
|
|
|
|
vbo_used += size;
|
|
delete [](entry.patch->start);
|
|
entry.patch->start = 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.dstart;
|
|
}
|
|
|
|
/*void NexusMt::SetExtractionSize(unsigned int r_size) {
|
|
extract_cnt.extraction_max = r_size/patches.chunk_size;
|
|
}
|
|
|
|
//void NexusMt::SetMetric(NexusMt::MetricKind kind) {
|
|
//do nothing at the moment.
|
|
|
|
//}
|
|
|
|
void NexusMt::SetError(float error) {
|
|
extract_cnt.target_error = error;
|
|
}
|
|
|
|
//void NexusMt::SetVboSize(unsigned int _vbo_max) {
|
|
//WORKING patches.vbo_max = _vbo_max;
|
|
//}
|
|
|
|
void NexusMt::SetPrefetchSize(unsigned int size) {
|
|
//TODO do something reasonable with this.
|
|
}
|
|
|
|
bool NexusMt::SetMode(DrawContest::Mode _mode) {
|
|
draw_cnt.mode = _mode;
|
|
return true;
|
|
}
|
|
|
|
bool NexusMt::SetComponent(DrawContest::Component c, bool on) {
|
|
if(c == DrawContest::COLOR && (signature & NXS_COLORS))
|
|
draw_cnt.use_colors = on;
|
|
if(c == DrawContest::NORMAL && (signature & NXS_NORMALS_SHORT))
|
|
draw_cnt.use_normals = on;
|
|
if(c == DrawContest::TEXTURE && (signature & NXS_TEXTURES_SHORT))
|
|
draw_cnt.use_textures = on;
|
|
if(c == DrawContest::DATA && (signature & NXS_DATA32))
|
|
draw_cnt.use_data = on;
|
|
|
|
// unsigned int components = DrawContest::COLOR * use_colors +
|
|
// DrawContest::NORMAL * use_normals +
|
|
// DrawContest::TEXTURE * use_textures +
|
|
// DrawContest::DATA * use_data;
|
|
return true;
|
|
}
|
|
|
|
bool NexusMt::SetComponents(unsigned int mask) {
|
|
SetComponent(DrawContest::COLOR, (mask & DrawContest::COLOR) != 0);
|
|
SetComponent(DrawContest::NORMAL, (mask & DrawContest::NORMAL) != 0);
|
|
SetComponent(DrawContest::TEXTURE, (mask & DrawContest::TEXTURE) != 0);
|
|
SetComponent(DrawContest::DATA, (mask & DrawContest::DATA) != 0);
|
|
|
|
// unsigned int components = mask;
|
|
|
|
if( ((mask & DrawContest::COLOR) && !(signature & NXS_COLORS)) ||
|
|
((mask & DrawContest::NORMAL) && !(signature & NXS_NORMALS_SHORT)) ||
|
|
((mask & DrawContest::TEXTURE) && !(signature & NXS_TEXTURES_SHORT)) ||
|
|
((mask & DrawContest::DATA) && !(signature & NXS_DATA32)) )
|
|
return false;
|
|
return true;
|
|
}*/
|
|
|
|
//TODO: nodes and fragment sholuld be kept in another way,
|
|
// so we can save that structure instead of the history!
|
|
|
|
|
|
|
|
/*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);
|
|
}
|
|
}
|
|
}
|
|
} */
|
|
|
|
/*void NexusMt::Expand(Node &node, vector<HeapNode> &expand) {
|
|
if(node.visited) return;
|
|
cerr << "Expanding\n";
|
|
for(unsigned int i = 0; i < node.in_size; i++) {
|
|
Link &link = innodes[node.in + i];
|
|
Node &parent = nodes[link.node];
|
|
if(!parent.visited)
|
|
Expand(parent, expand);
|
|
}
|
|
|
|
for(unsigned int o = 0; o < node.out_size; o++) {
|
|
Link &link = outnodes[node.out + o];
|
|
Node &outnode = nodes[link.node];
|
|
if(outnode.visited) continue;
|
|
assert(link.error != -1);
|
|
if(link.error > extract_cnt.target_error) {
|
|
HeapNode hnode(&outnode, node.error - extract_cnt.target_error);
|
|
expand.push_back(hnode);
|
|
push_heap(expand.begin(), expand.end());
|
|
}
|
|
}
|
|
|
|
unsigned int d_extr = 0;
|
|
unsigned int d_draw = 0;
|
|
unsigned int d_disk = 0;
|
|
Diff(node, d_extr, d_draw, d_disk);
|
|
extract_cnt.extraction_used += d_extr;
|
|
extract_cnt.draw_used += d_draw;
|
|
extract_cnt.disk_used += d_disk;
|
|
node.visited = true;
|
|
}
|
|
|
|
void NexusMt::Contract(Node &node) {
|
|
if(!node.visited) return;
|
|
cerr << "Contracting...\n";
|
|
for(unsigned int i = 0; i < node.out_size; i++) {
|
|
Link &link = outnodes[node.out + i];
|
|
Node &child = nodes[link.node];
|
|
if(child.visited)
|
|
Contract(child);
|
|
}
|
|
|
|
unsigned int d_extr = 0;
|
|
unsigned int d_draw = 0;
|
|
unsigned int d_disk = 0;
|
|
Diff(node, d_extr, d_draw, d_disk);
|
|
extract_cnt.extraction_used -= d_extr;
|
|
extract_cnt.draw_used -= d_draw;
|
|
extract_cnt.disk_used -= d_disk;
|
|
node.visited = false;
|
|
}
|
|
|
|
void NexusMt::GetErrorLink(Node &node, Link &link) {
|
|
if(link.error != -1) return;
|
|
for(unsigned int c = link.frag; frags[c].patch != 0xffffffff; c++) {
|
|
Cell &cell = frags[c];
|
|
if(cell.error != -1) continue;
|
|
PatchInfo &info = index[cell.patch];
|
|
cell.error = extract_cnt.GetError(info);
|
|
cerr << "Cell.error: " << cell.error << endl;
|
|
if(link.error < cell.error) link.error = cell.error;
|
|
}
|
|
}
|
|
|
|
void NexusMt::GetErrorNode(Node &node) {
|
|
if(node.error != -1) return;
|
|
for(unsigned int o = 0; o < node.out_size; o++) {
|
|
Link &link = outnodes[node.out + o];
|
|
GetErrorLink(node, link);
|
|
if(node.error < link.error) node.error = link.error;
|
|
}
|
|
}
|
|
|
|
void NexusMt::NodeExplore(Node &node,
|
|
vector<HeapNode> &expand,
|
|
vector<HeapNode> &contract) {
|
|
assert(node.visited);
|
|
GetErrorNode(node);
|
|
|
|
cerr << "node.error: " << node.error <<
|
|
" target: " << extract_cnt.target_error << endl;
|
|
if(node.error > extract_cnt.target_error) {
|
|
cerr << "Expandible node...\n";
|
|
for(unsigned int o = 0; o < node.out_size; o++) {
|
|
Link &link = outnodes[node.out + o];
|
|
assert(link.error != -1);
|
|
Node &outnode = nodes[link.node];
|
|
if(outnode.visited) continue;
|
|
|
|
if(link.error > extract_cnt.target_error) {
|
|
HeapNode hnode(&outnode, node.error - extract_cnt.target_error);
|
|
expand.push_back(hnode);
|
|
push_heap(expand.begin(), expand.end());
|
|
}
|
|
}
|
|
}
|
|
|
|
float max_err = -1;
|
|
|
|
bool can_contract = true;
|
|
for(unsigned int o = 0; o < node.out_size; o++) {
|
|
Link &link = outnodes[node.out + o];
|
|
Node &outnode = nodes[link.node];
|
|
if(node.visited) {
|
|
can_contract = false;
|
|
break;
|
|
}
|
|
}
|
|
if(can_contract) {
|
|
for(unsigned int o = 0; o < node.in_size; o++) {
|
|
Link &link = innodes[node.in + o];
|
|
GetErrorLink(node, link);
|
|
if(max_err < link.error) max_err = link.error;
|
|
}
|
|
HeapNode hnode(&node, extract_cnt.target_error - max_err);
|
|
contract.push_back(hnode);
|
|
push_heap(contract.begin(), contract.end());
|
|
}
|
|
}
|
|
|
|
void NexusMt::FrontExplore(vector<HeapNode> &expand,
|
|
vector<HeapNode> &contract) {
|
|
|
|
|
|
extract_cnt.extraction_used = 0;
|
|
extract_cnt.draw_used = 0;
|
|
extract_cnt.disk_used = 0;
|
|
|
|
std::vector<Node>::iterator i;
|
|
for(i = nodes.begin(); i != nodes.end(); i++) {
|
|
Node &node = *i;
|
|
if(!node.visited)
|
|
continue;
|
|
|
|
for(int k = 0; k < node.out_size; k++) {
|
|
Link &link = outnodes[node.out + k];
|
|
assert(link.node < nodes.size());
|
|
Node &children = nodes[link.node];
|
|
if(!children.visited) {
|
|
cerr << "Exploting child...\n";
|
|
NodeExplore(node, expand, contract);
|
|
|
|
for(unsigned int c = link.frag; frags[c].patch != 0xffffffff; c++) {
|
|
PServer::Entry &entry = patches.entries[c];
|
|
if(!entry.patch) extract_cnt.disk_used += entry.disk_size;
|
|
extract_cnt.extraction_used += entry.ram_size;
|
|
vcg::Sphere3f &sphere = index[c].sphere;
|
|
if(!extract_cnt.frustum.IsOutside(sphere.Center(), sphere.Radius()))
|
|
extract_cnt.draw_used += entry.ram_size;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void NexusMt::Diff(Node &node,
|
|
unsigned int &d_extr,
|
|
unsigned int &d_draw,
|
|
unsigned int &d_disk) {
|
|
d_extr = 0;
|
|
d_draw = 0;
|
|
d_disk = 0;
|
|
for(unsigned int o = 0; o < node.out_size; o++) {
|
|
Link &link = outnodes[node.out + o];
|
|
for(unsigned int c = link.frag; frags[c].patch != 0xffffffff; c++) {
|
|
PServer::Entry &entry = patches.entries[c];
|
|
if(!entry.patch) d_disk += entry.disk_size;
|
|
d_extr += entry.ram_size;
|
|
Sphere3f &sphere = index[c].sphere;
|
|
if(!extract_cnt.frustum.IsOutside(sphere.Center(), sphere.Radius()))
|
|
d_draw += entry.ram_size;
|
|
}
|
|
}
|
|
for(unsigned int o = 0; o < node.in_size; o++) {
|
|
Link &link = innodes[node.in + o];
|
|
for(unsigned int c = link.frag; frags[c].patch != 0xffffffff; c++) {
|
|
PServer::Entry &entry = patches.entries[c];
|
|
if(!entry.patch) d_disk -= entry.disk_size;
|
|
d_extr -= entry.ram_size;
|
|
if(!extract_cnt.frustum.IsOutside(sphere.Center(), sphere.Radius()))
|
|
d_draw -= entry.ram_size;
|
|
}
|
|
}
|
|
}*/
|
|
|
|
/*void NexusMt::Extract(std::vector<unsigned int> &selected) {
|
|
extract_cnt.frustum.GetView();
|
|
|
|
|
|
//clear error (no more valid...)
|
|
for(unsigned int i = 0; i < nodes.size(); i++)
|
|
nodes[i].error = -1;
|
|
for(unsigned int i = 0; i < outnodes.size(); i++)
|
|
outnodes[i].error = -1;
|
|
for(unsigned int i = 0; i < innodes.size(); i++)
|
|
innodes[i].error = -1;
|
|
for(unsigned int i = 0; i < frags.size(); i++)
|
|
frags[i].error = -1;
|
|
|
|
|
|
std::vector<HeapNode> expand;
|
|
std::vector<HeapNode> contract;
|
|
|
|
if(!nodes[0].visited)
|
|
nodes[0].visited = true;
|
|
//explore front
|
|
FrontExplore(expand, contract);
|
|
|
|
bool can_expand = true;
|
|
bool can_contract = true;
|
|
float current_error = 1e30;
|
|
while(can_expand || can_contract) {
|
|
if(can_expand) {
|
|
if(!expand.size()) {
|
|
can_expand = false;
|
|
continue;
|
|
}
|
|
cerr << "trying to expand..\n";
|
|
pop_heap(expand.begin(), expand.end());
|
|
HeapNode hnode = expand.back();
|
|
|
|
Node *node = hnode.node;
|
|
// if(node->visited) {
|
|
//cerr << "Failed cause already visited\n";
|
|
// expand.pop_back();
|
|
//continue; //already expanded...
|
|
// }
|
|
unsigned int d_extr = 0;
|
|
unsigned int d_draw = 0;
|
|
unsigned int d_disk = 0;
|
|
Diff(*node, d_extr, d_draw, d_disk);
|
|
|
|
if(extract_cnt.disk_used + d_disk > extract_cnt.disk_max) {
|
|
cerr << "Failed cause disk...\n";
|
|
cerr << "d_disl: " << d_disk << " extract_cnt.disk_max "
|
|
<< extract_cnt.disk_max << endl;
|
|
expand.pop_back();
|
|
continue;
|
|
}
|
|
if(extract_cnt.extraction_used + d_extr > extract_cnt.extraction_max ||
|
|
extract_cnt.draw_used + d_draw > extract_cnt.draw_max) {
|
|
cerr << "Failed...\n";
|
|
can_expand = false;
|
|
push_heap(expand.begin(), expand.end());
|
|
continue;
|
|
} else {
|
|
cerr << "Expanding...\n";
|
|
current_error = hnode.error;
|
|
expand.pop_back();
|
|
Expand(*node, expand);
|
|
}
|
|
} else if(can_contract) {
|
|
if(!contract.size()) {
|
|
can_contract = false;
|
|
continue;
|
|
}
|
|
pop_heap(contract.begin(), contract.end());
|
|
HeapNode hnode = contract.back();
|
|
|
|
if(hnode.error < extract_cnt.target_error - current_error) {
|
|
can_contract = false;
|
|
continue;
|
|
}
|
|
Node *node = hnode.node;
|
|
if(!node->visited) {
|
|
contract.pop_back();
|
|
continue;//already contracted
|
|
}
|
|
|
|
unsigned int d_extr = 0;
|
|
unsigned int d_draw = 0;
|
|
unsigned int d_disk = 0;
|
|
Diff(*node, d_extr, d_draw, d_disk);
|
|
|
|
if(extract_cnt.disk_used - d_disk > extract_cnt.disk_max) {
|
|
expand.pop_back();
|
|
continue;
|
|
}
|
|
if(extract_cnt.extraction_used - d_extr < extract_cnt.extraction_max &&
|
|
extract_cnt.draw_used - d_draw < extract_cnt.draw_max) {
|
|
can_expand = true;
|
|
}
|
|
current_error = hnode.error;
|
|
contract.pop_back();
|
|
Contract(*node);
|
|
}
|
|
}
|
|
Select(selected);
|
|
}*/
|
|
|
|
/*void NexusMt::Extract(std::vector<unsigned int> &selected, Policy *policy) {
|
|
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 i;
|
|
std::vector<Node *>::iterator on;
|
|
for(i = node.frags.begin(), on = node.out.begin();
|
|
i != node.frags.end(); i++, on++) {
|
|
if((*on)->visited) continue;
|
|
Frag &frag = (*i);
|
|
std::vector<unsigned int>::iterator cell;
|
|
for(cell = frag.begin(); cell != frag.end(); cell++) {
|
|
if(policy->Expand(*cell, index[*cell]))
|
|
policy->Visit(*on, qnodo);
|
|
}
|
|
}
|
|
}
|
|
Select(selected);
|
|
} */
|
|
|
|
/*void NexusMt::Select(vector<unsigned int> &selected) {
|
|
selected.clear();
|
|
std::vector<Node>::iterator i;
|
|
for(i = nodes.begin(); i != nodes.end(); i++) {
|
|
Node &node = *i;
|
|
if(!node.visited)
|
|
continue;
|
|
|
|
for(unsigned int o = 0; o < node.out_size; o++) {
|
|
Link &link = outnodes[node.out + o];
|
|
for(unsigned int c = link.frag; frags[c].patch != 0xffffffff; c++) {
|
|
Cell &cell = frags[c];
|
|
selected.push_back(cell.patch);
|
|
}
|
|
}
|
|
}*/
|
|
// for(unsigned int i = 0; i < selected.size(); i++) {
|
|
// cerr << "Sel: " << selected[i] << endl;
|
|
// }
|
|
|
|
/* std::vector<Node *>::iterator n;
|
|
std::vector<>::iterator f;
|
|
for(n = node.out.begin(), f = node.frags.begin();
|
|
n != node.out.end(); n++, f++) {
|
|
if(!(*n)->visited || (*n)->error == 0) {
|
|
vector<unsigned int>::iterator c;
|
|
Frag &frag = (*f);
|
|
for(c = frag.begin(); c != frag.end(); c++)
|
|
selected.push_back(*c);
|
|
}
|
|
}
|
|
}*/
|
|
//}
|
|
/*bool NexusMt::TestCurrent(Node *node) {
|
|
if(!visited) return;
|
|
for(unsigned int i = 0; i < node->out.size(); i++)
|
|
if(!node->out[k].visited) {
|
|
node->current = true;
|
|
return true;
|
|
}
|
|
node->current = false;
|
|
return false;
|
|
} */
|
|
|
|
/*void NexusMt::VisitNode(Node *node, vector<TNode> &heap) {
|
|
//TestCurrent(*i);
|
|
|
|
if(node->visited) return;
|
|
node->visited = true;
|
|
|
|
|
|
vector<Node *>::iterator i;
|
|
for(i = node->in.begin(); i != node->in.end(); i++) {
|
|
VisitNode(*i, heap);
|
|
}
|
|
|
|
for(unsigned int k = 0; k < node->out.size(); k++) {
|
|
Node *outnode = node->out[k];
|
|
float max_error = metric->GetError(outnode);
|
|
for(unsigned int j = 0; j < node->frags[k].size(); j++) {
|
|
unsigned int patch = node->frags[k][j];
|
|
float error = metric->GetError(patch);
|
|
if(max_error < error) max_error = error;
|
|
visited.push_back(PServer::Item(patch, fabs(error - target_error)));
|
|
// push_heap(visited.begin(), visited.end());
|
|
}
|
|
|
|
heap.push_back(TNode(outnode, max_error));
|
|
push_heap(heap.begin(), heap.end());
|
|
}
|
|
|
|
sequence.push_back(node);
|
|
NodeVisited(node);
|
|
}*/
|
|
|
|
/*void NexusMt::UnvisitNode(Node *node, vector<TNode> &heap) {
|
|
node->current = false;
|
|
vector<Node *>::iterator i;
|
|
for(i = node->in.begin(); i != node->in.end(); i++)
|
|
if(TestCurrent(*i)) {
|
|
float error = metric->GetError(*i);
|
|
heap.push_back(TNode(*i, error));
|
|
push_heap(heap.begin(), heap.end());
|
|
}
|
|
} */
|
|
|
|
|
|
/*void NexusMt::LoadHistory() {
|
|
//The last update erases everything.
|
|
assert(history[0].erased.size() == 0);
|
|
|
|
//maps cell -> node containing it
|
|
map<unsigned int, unsigned int> cell_node;
|
|
//maps node -> Links
|
|
map<unsigned int, vector<Link> > node_inlinks;
|
|
map<unsigned int, vector<Link> > node_outlinks;
|
|
nodes.resize(history.size());
|
|
|
|
//building fragments and nodes.
|
|
unsigned int current_node = 0;
|
|
vector<Update>::iterator u;
|
|
for(u = history.begin(); u != history.end(); u++) {
|
|
|
|
Node &node = nodes[current_node];
|
|
node.error = 0;
|
|
|
|
//created cells belong to this node, we look also for max error.
|
|
for(unsigned int i = 0; i < (*u).created.size(); i++) {
|
|
unsigned int cell = (*u).created[i];
|
|
if(index[cell].error > node.error)
|
|
node.error = index[cell].error;
|
|
cell_node[cell] = current_node;
|
|
}
|
|
|
|
//Every erased cell already belonged to a node.
|
|
//we record for each node its cells.
|
|
map<unsigned int, vector<unsigned int> > node_erased;
|
|
|
|
for(unsigned int i = 0; i < (*u).erased.size(); i++) {
|
|
unsigned int cell = (*u).erased[i];
|
|
assert(cell_node.count(cell));
|
|
node_erased[cell_node[cell]].push_back(cell);
|
|
}
|
|
|
|
//for every node with erased cells we build a frag and
|
|
//put the corresponding cells in it.
|
|
map<unsigned int, vector<unsigned int> >::iterator e;
|
|
for(e = node_erased.begin(); e != node_erased.end(); e++) {
|
|
|
|
//node.in.push_back(innodes.size());
|
|
|
|
unsigned int floor_node = (*e).first;
|
|
Node &oldnode = nodes[floor_node];
|
|
|
|
Link inlink;
|
|
inlink.node = floor_node;
|
|
inlink.frag = frags.size();
|
|
|
|
Link outlink;
|
|
outlink.node = current_node;
|
|
outlink.frag = frags.size();
|
|
|
|
float max_err = -1;
|
|
|
|
//Fill it with erased cells.
|
|
vector<unsigned int> &cells = (*e).second;
|
|
vector<unsigned int>::iterator k;
|
|
for(k = cells.begin(); k != cells.end(); k++) {
|
|
Cell cell;
|
|
cell.patch = (*k);
|
|
assert(cell.patch < index.size());
|
|
frags.push_back(cell);
|
|
if(index[cell.patch].error > max_err)
|
|
max_err = index[cell.patch].error;
|
|
}
|
|
Cell cell;
|
|
cell.patch = 0xffffffff;
|
|
cell.error = -1;
|
|
frags.push_back(cell);
|
|
|
|
inlink.error = max_err;
|
|
outlink.error = max_err;
|
|
|
|
//Add the new Frag to the node.
|
|
|
|
node_outlinks[floor_node].push_back(outlink);
|
|
node_outlinks[current_node].push_back(inlink);
|
|
if(node.error < max_err)
|
|
node.error = max_err;
|
|
|
|
//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;
|
|
nodes[inode].out = outnodes.size();
|
|
nodes[inode].out_size = links.size();
|
|
|
|
for(unsigned int i = 0; i < links.size(); i++)
|
|
outnodes.push_back(links[i]);
|
|
}
|
|
|
|
for(k = node_inlinks.begin(); k != node_inlinks.end(); k++) {
|
|
unsigned int inode = (*k).first;
|
|
vector<Link> &links = (*k).second;
|
|
nodes[inode].in = innodes.size();
|
|
nodes[inode].in_size = links.size();
|
|
|
|
for(unsigned int i = 0; i < links.size(); i++)
|
|
innodes.push_back(links[i]);
|
|
}
|
|
}
|
|
|
|
void NexusMt::ClearHistory() {
|
|
nodes.clear();
|
|
innodes.clear();
|
|
outnodes.clear();
|
|
frags.clear();
|
|
}*/
|