#include #include #include #include "nexus.h" #include "lrupserver.h" #include "queuepserver.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) { index_file = fopen((file + ".nxs").c_str(), "wb+"); if(!index_file) { cerr << "Could not create file: " << file << ".nxs\n"; return false; } signature = sig; totvert = 0; totface = 0; sphere = Sphere3f(); index.clear(); chunk_size = c_size; history.clear(); if(!patches.Create(file + ".nxp", signature, chunk_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", 1, 100)) { cerr << "Could not create file: " << file << ".nxb" << endl; return false; } history.clear(); return true; } bool Nexus::Load(const string &file, bool rdonly) { readonly = rdonly; index_file = fopen((file + ".nxs").c_str(), "rb+"); if(!index_file) return false; unsigned int readed; readed = fread(&signature, sizeof(unsigned int), 1, index_file); if(!readed) return false; readed = fread(&totvert, sizeof(unsigned int), 1, index_file); if(!readed) return false; readed = fread(&totface, sizeof(unsigned int), 1, index_file); if(!readed) return false; readed = fread(&sphere, sizeof(Sphere3f), 1, index_file); if(!readed) return false; readed = fread(&chunk_size, sizeof(unsigned int), 1, index_file); if(!readed) return false; unsigned int size; //size of index readed = fread(&size, sizeof(unsigned int), 1, index_file); if(!readed) return false; index.resize(size); readed = fread(&index[0], sizeof(PatchInfo), size, index_file); if(readed != size) return false; patches.ReadEntries(index_file); borders.ReadEntries(index_file); //history size; fread(&size, sizeof(unsigned int), 1, index_file); vector buffer; buffer.resize(size); fread(&(buffer[0]), sizeof(unsigned int), size, index_file); //number of history updates size = buffer[0]; history.resize(size); unsigned int pos = 1; for(unsigned int i = 0; i < size; i++) { unsigned int erased = buffer[pos++]; unsigned int created = buffer[pos++]; history[i].erased.resize(erased); history[i].created.resize(created); for(unsigned int e = 0; e < erased; e++) history[i].erased[e] = buffer[pos++]; for(unsigned int e = 0; e < created; e++) history[i].created[e] = buffer[pos++]; } if(readonly) { fclose(index_file); index_file = NULL; } //TODO support readonly if(!patches.Load(file + ".nxp", signature, chunk_size, readonly)) return false; if(!borders.Load(file + ".nxb", readonly, 1, 500)) return false; return true; } void Nexus::Close() { patches.Close(); borders.Close(); if(!index_file) return; rewind(index_file); fwrite(&signature, sizeof(unsigned int), 1, index_file); fwrite(&totvert, sizeof(unsigned int), 1, index_file); fwrite(&totface, sizeof(unsigned int), 1, index_file); fwrite(&sphere, sizeof(Sphere3f), 1, index_file); fwrite(&chunk_size, sizeof(unsigned int), 1, index_file); unsigned int size = index.size(); //size of index fwrite(&size, sizeof(unsigned int), 1, index_file); fwrite(&(index[0]), sizeof(PatchInfo), size, index_file); //TODO this should be moved to the end... //BUT it will break compatibility with existing models. patches.WriteEntries(index_file); borders.WriteEntries(index_file); vector buffer; buffer.push_back(history.size()); for(unsigned int i = 0; i < history.size(); i++) { Update &update = history[i]; buffer.push_back(update.erased.size()); buffer.push_back(update.created.size()); for(unsigned int e = 0; e < update.erased.size(); e++) buffer.push_back(update.erased[e]); for(unsigned int e = 0; e < update.created.size(); e++) buffer.push_back(update.created[e]); } size = buffer.size(); fwrite(&size, sizeof(unsigned int), 1, index_file); fwrite(&(buffer[0]), sizeof(unsigned int), size, index_file); fclose(index_file); index_file = NULL; } Patch &Nexus::GetPatch(unsigned int patch, bool flush) { assert(patch < index.size()); PatchInfo &info = index[patch]; return patches.Lookup(patch, info.nvert, info.nface); } Border Nexus::GetBorder(unsigned int patch, bool flush) { PatchInfo &info = index[patch]; return borders.GetBorder(patch); } void Nexus::AddBorder(unsigned int patch, Link &link) { Border border = GetBorder(patch); unsigned int pos = border.Size(); if(pos > 65500) { cerr << "Exceding border size!!!\n"; exit(0); } if(borders.ResizeBorder(patch, pos+1)) { border = GetBorder(patch); } assert(border.Available() > pos); border[pos] = link; } unsigned int Nexus::AddPatch(unsigned int nvert, unsigned int nface, unsigned int nbord) { PatchInfo info; info.nvert = nvert; info.nface = nface; patches.AddPatch(nvert, nface); borders.AddBorder(nbord); index.push_back(info); totvert += nvert; totface += nface; return index.size() -1; } void Nexus::MaxRamBuffer(unsigned int r_size) { patches.MaxRamBuffer(r_size); //TODO do the same with borders } void Nexus::Unify(float threshold) { //TODO what if colors or normals or strips? unsigned int duplicated = 0; unsigned int degenerate = 0; for(unsigned int p = 0; p < index.size(); p++) { PatchInfo &entry = index[p]; Patch patch = GetPatch(p); unsigned int vcount = 0; map vertices; vector remap; remap.resize(patch.nv); for(unsigned int i = 0; i < patch.nv; i++) { Point3f &point = patch.Vert(i); if(!vertices.count(point)) vertices[point] = vcount++; else duplicated++; remap[i] = vertices[point]; } assert(vertices.size() <= patch.nv); if(vertices.size() == patch.nv) //no need to unify continue; vector newvert; newvert.resize(vertices.size()); map::iterator k; for(k = vertices.begin(); k != vertices.end(); k++) { newvert[(*k).second] = (*k).first; } vector 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(signature, entry.nvert, entry.nface); memcpy(patch.VertBegin(), &(newvert[0]), entry.nvert*sizeof(Point3f)); memcpy(patch.FaceBegin(), &(newface[0]), entry.nface*3*sizeof(short)); //testiamo il tutto... TODO remove this of course 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); } } //fix patch borders now set close; //bordering pathes Border border = 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::iterator c; for(c = close.begin(); c != close.end(); c++) { Border bord = 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 < index.size(); p++) { Border border = GetBorder(p); set 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::iterator k = links.begin(); k != links.end(); k++) border[count++] = *k; borders.borders[p].border_used = links.size(); } totvert -= duplicated; if(duplicated) cerr << "Found " << duplicated << " duplicated vertices" << endl; if(degenerate) cerr << "Found " << degenerate << " degenerate face while unmifying\n"; }