2005-02-08 13:43:03 +01:00
|
|
|
/****************************************************************************
|
|
|
|
* 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 $
|
|
|
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
2004-09-17 17:25:59 +02:00
|
|
|
#include <assert.h>
|
2004-12-13 01:44:48 +01:00
|
|
|
|
|
|
|
#include <iostream>
|
|
|
|
#include <set>
|
|
|
|
|
2004-07-02 15:00:02 +02:00
|
|
|
#include "nexus.h"
|
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
using namespace vcg;
|
|
|
|
using namespace nxs;
|
|
|
|
|
|
|
|
Nexus::~Nexus() {
|
|
|
|
Close();
|
|
|
|
}
|
|
|
|
|
2004-10-10 19:19:42 +02:00
|
|
|
bool Nexus::Create(const string &file, Signature sig, unsigned int c_size) {
|
2004-09-16 16:25:16 +02:00
|
|
|
signature = sig;
|
2004-07-02 15:00:02 +02:00
|
|
|
totvert = 0;
|
|
|
|
totface = 0;
|
|
|
|
sphere = Sphere3f();
|
2004-10-10 19:19:42 +02:00
|
|
|
chunk_size = c_size;
|
2005-01-14 16:25:29 +01:00
|
|
|
unsigned int header_size = 256;
|
|
|
|
if(chunk_size > header_size) header_size = chunk_size;
|
|
|
|
|
|
|
|
history.Clear();
|
|
|
|
ram_used = 0;
|
|
|
|
ram_max = 50 * (1<<20) / chunk_size;
|
2004-10-08 16:46:26 +02:00
|
|
|
|
2005-01-14 16:25:29 +01:00
|
|
|
if(!IndexFile<Entry>::Create(file + ".nxp", header_size)) {
|
2004-07-02 15:00:02 +02:00
|
|
|
cerr << "Could not create file: " << file << ".nxp" << endl;
|
|
|
|
return false;
|
|
|
|
}
|
2005-01-14 16:25:29 +01:00
|
|
|
|
2004-10-08 16:46:26 +02:00
|
|
|
//Important: chunk_size must be 1 so that i can use Region in VFile.
|
2005-01-14 16:25:29 +01:00
|
|
|
if(!borders.Create(file + ".nxb")) {
|
2004-07-04 16:26:46 +02:00
|
|
|
cerr << "Could not create file: " << file << ".nxb" << endl;
|
2004-07-02 15:00:02 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2004-12-13 01:44:48 +01:00
|
|
|
|
|
|
|
bool Nexus::Load(const string &file, bool rdonly) {
|
2005-01-14 16:25:29 +01:00
|
|
|
if(!IndexFile<Entry>::Load(file + ".nxp", rdonly)) return false;
|
|
|
|
ram_used = 0;
|
|
|
|
ram_max = 50 * (1<<20) / chunk_size;
|
2004-12-13 01:44:48 +01:00
|
|
|
|
2005-01-14 16:25:29 +01:00
|
|
|
history.Clear();
|
|
|
|
SetPosition(history_offset);
|
|
|
|
unsigned int history_size;
|
|
|
|
ReadBuffer(&history_size, sizeof(unsigned int));
|
2004-12-13 01:44:48 +01:00
|
|
|
|
2005-01-14 16:25:29 +01:00
|
|
|
char *buffer = new char[history_size];
|
|
|
|
ReadBuffer(buffer, history_size);
|
|
|
|
|
|
|
|
if(!history.Load(history_size, buffer)) {
|
|
|
|
cerr << "Error loading history\n";
|
2004-12-13 01:44:48 +01:00
|
|
|
return false;
|
2005-01-14 16:25:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
borders.Load(file + ".nxb", rdonly);
|
|
|
|
//TODO on nxsbuilder assure borders are loaded
|
2004-07-02 15:00:02 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2005-01-14 16:25:29 +01:00
|
|
|
void Nexus::Close() {
|
|
|
|
if(!Opened()) return;
|
|
|
|
|
|
|
|
Flush();
|
|
|
|
|
|
|
|
if(!IsReadOnly()) {
|
|
|
|
//set history_offset
|
|
|
|
if(!size()) history_offset = 0;
|
|
|
|
else
|
|
|
|
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;
|
|
|
|
}
|
2004-10-10 19:19:42 +02:00
|
|
|
borders.Close();
|
2005-01-14 16:25:29 +01:00
|
|
|
IndexFile<Entry>::Close();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Nexus::SaveHeader() {
|
|
|
|
unsigned int magic = 0x3053584e; // nxs0
|
|
|
|
WriteBuffer(&magic, sizeof(unsigned int));
|
|
|
|
WriteBuffer(&signature, sizeof(unsigned int));
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
ReadBuffer(&signature, sizeof(unsigned int));
|
|
|
|
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));
|
2005-01-18 23:25:32 +01:00
|
|
|
return true;
|
2005-01-14 16:25:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
2004-09-16 16:25:16 +02:00
|
|
|
}
|
2004-07-02 15:00:02 +02:00
|
|
|
}
|
|
|
|
|
2005-01-14 16:25:29 +01:00
|
|
|
|
|
|
|
|
|
|
|
Patch &Nexus::GetPatch(unsigned int patch, bool flush) {
|
|
|
|
Entry &entry = operator[](patch);
|
|
|
|
if(index.count(patch)) {
|
|
|
|
assert(entry.patch);
|
2005-01-18 23:25:32 +01:00
|
|
|
list<unsigned int>::iterator i = index[patch];
|
2005-01-14 16:25:29 +01:00
|
|
|
pqueue.erase(i);
|
|
|
|
pqueue.push_front(patch);
|
2005-01-18 23:25:32 +01:00
|
|
|
index[patch] = pqueue.begin();
|
2005-01-14 16:25:29 +01:00
|
|
|
} 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);
|
2004-07-04 16:26:46 +02:00
|
|
|
}
|
|
|
|
|
2005-01-21 18:09:13 +01:00
|
|
|
Border &Nexus::GetBorder(unsigned int patch, bool flush) {
|
2004-10-08 16:46:26 +02:00
|
|
|
return borders.GetBorder(patch);
|
2004-07-04 16:26:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
unsigned int Nexus::AddPatch(unsigned int nvert, unsigned int nface,
|
|
|
|
unsigned int nbord) {
|
2004-10-08 16:46:26 +02:00
|
|
|
|
2005-01-14 16:25:29 +01:00
|
|
|
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);
|
2004-07-04 16:26:46 +02:00
|
|
|
|
2004-10-08 16:46:26 +02:00
|
|
|
borders.AddBorder(nbord);
|
|
|
|
|
2004-08-27 02:38:34 +02:00
|
|
|
totvert += nvert;
|
|
|
|
totface += nface;
|
2005-01-14 16:25:29 +01:00
|
|
|
return size() - 1;
|
2004-10-15 18:45:27 +02:00
|
|
|
}
|
2004-10-08 16:46:26 +02:00
|
|
|
|
2005-01-14 16:25:29 +01:00
|
|
|
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 & NXS_COMPRESSED) == 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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
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 & NXS_COMPRESSED)) {
|
|
|
|
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->start, entry.disk_size * chunk_size);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
delete [](entry.patch->start);
|
|
|
|
delete entry.patch;
|
|
|
|
entry.patch = NULL;
|
|
|
|
ram_used -= entry.ram_size;
|
|
|
|
}
|