/************ * * This file is part of a tool for producing 3D content in the PRC format. * Copyright (C) 2008 Orest Shardt * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * *************/ #include "oPRCFile.h" #include #include using std::string; uint32_t PRCentity::getGraphicsIndex() { if(useMaterial) return parent->colourMap.size()+parent->getMaterialIndex(material); else return parent->getColourIndex(colour); } void PRCline::writeRepresentationItem(PRCbitStream &out,uint32_t index) { out << (uint32_t)(PRC_TYPE_RI_Curve); ContentPRCBase(&EMPTY_ATTRIBUTES,name,true,makeCADID(),0,makePRCID()).write(out); writeGraphics(out,m1,getGraphicsIndex(),1); out << (uint32_t)0 // index_local_coordinate_system+1 << (uint32_t)0; // index_tessellation out << true // has wire body << (uint32_t)index+1 // index of context in geometry section << (uint32_t)1; // body index in topological context UserData(0,0).write(out); } void PRCline::writeTopologicalContext(PRCbitStream &out) { // topological context out << (uint32_t)(PRC_TYPE_TOPO_Context); EMPTY_CONTENTPRCBASE.write(out); out << (uint8_t)0 // behaviour << 0.0 // granularity << 0.0 // tolerance << false // have smallest face thickness << false; // have scale out << (uint32_t)1; // number of bodies // body out << (uint32_t)PRC_TYPE_TOPO_SingleWireBody; out << false // base topology: no base information << (uint8_t)0; // content body: behaviour // Not sure what a 0 means, since it satisfies no #define, // but I think it means no bbox // wire edge out << false // not already stored << (uint32_t)PRC_TYPE_TOPO_WireEdge << false; // base topology: no base information // polyline out << false // not already stored << (uint32_t)PRC_TYPE_CRV_PolyLine << false // base topology: no base information << (uint32_t)KEPRCExtendTypeNone // extend info << true // is 3d << false // no transformation << 0.0 << static_cast(numberOfPoints-1) // parameterization interval << 1.0 // no reparameterization << 0.0 // no reparameterization << (uint32_t)numberOfPoints; // points for(uint32_t i = 0; i < numberOfPoints; ++i) out << points[i][0]*scale << points[i][1]*scale << points[i][2]*scale; // ending of wire edge out << false; // trim surface domain } void PRCline::writeExtraGeometryContext(PRCbitStream &out) { //geometry summary out << (uint32_t)1; // number of bodies out << (uint32_t)PRC_TYPE_TOPO_SingleWireBody; // body's serial type //context graphics out << (uint32_t)0; // number of treat types } void PRCcurve::writeRepresentationItem(PRCbitStream &out,uint32_t index) { out << (uint32_t)(PRC_TYPE_RI_Curve); ContentPRCBase(&EMPTY_ATTRIBUTES,name,true,makeCADID(),0,makePRCID()).write(out); writeGraphics(out,m1,getGraphicsIndex(),1); out << (uint32_t)0 // index_local_coordinate_system+1 << (uint32_t)0; // index_tessellation out << true // has wire body << (uint32_t)index+1 // index of context in geometry section << (uint32_t)1; // body index in topological context UserData(0,0).write(out); } void PRCcurve::writeTopologicalContext(PRCbitStream &out) { // topological context out << (uint32_t)(PRC_TYPE_TOPO_Context); EMPTY_CONTENTPRCBASE.write(out); out << (uint8_t)0 // behaviour << 0.0 // granularity << 0.0 // tolerance << false // have smallest face thickness << false; // have scale out << (uint32_t)1; // number of bodies // body out << (uint32_t)PRC_TYPE_TOPO_SingleWireBody; out << false // base topology: no base information << (uint8_t)0; // content body: behaviour // Not sure what a 0 means, since it satisfies no #define, // but I think it means no bbox // wire edge out << false // not already stored << (uint32_t)PRC_TYPE_TOPO_WireEdge << false; // base topology: no base information // curve out << false // not already stored << (uint32_t)PRC_TYPE_CRV_NURBS << false // base topology: no base information << (uint32_t)KEPRCExtendTypeNone // extend info << true // is 3D << isRational << (uint32_t)degree // degree << (uint32_t)numberOfControlPoints-1 // control points - 1 << (uint32_t)degree+numberOfControlPoints; // knots - 1 // control points for(uint32_t i = 0; i < numberOfControlPoints; ++i) { double Scale=scale; if(isRational) Scale *= weights[i]; out << controlPoints[i][0]*Scale << controlPoints[i][1]*Scale << controlPoints[i][2]*Scale; if(isRational) out << weights[i]; } writeKnots(out); out << (uint32_t)KEPRCKnotTypeUnspecified // KEPRCKnotTypePiecewiseBezierKnots << (uint32_t)KEPRCBSplineCurveFormUnspecified; // curve form // ending of wire edge out << false; // trim surface domain } void PRCcurve::writeExtraGeometryContext(PRCbitStream &out) { //geometry summary out << (uint32_t)1; // number of bodies out << (uint32_t)PRC_TYPE_TOPO_SingleWireBody; // body's serial type //context graphics out << (uint32_t)0; // number of treat types } void PRCsurface::writeRepresentationItem(PRCbitStream &out,uint32_t index) { out << (uint32_t)(PRC_TYPE_RI_BrepModel); ContentPRCBase(&EMPTY_ATTRIBUTES,name,true,makeCADID(),0,makePRCID()).write(out); writeGraphics(out,0,getGraphicsIndex(),1); out << (uint32_t)0 // index_local_coordinate_system+1 << (uint32_t)0; // index_tessellation out << true // has brep data << (uint32_t)index+1 // index of context in geometry section << (uint32_t)1 // body index in topological context << false; // is closed???? when is it closed? UserData(0,0).write(out); } void PRCsurface::writeTopologicalContext(PRCbitStream &out) { // topological context out << (uint32_t)(PRC_TYPE_TOPO_Context); EMPTY_CONTENTPRCBASE.write(out); out << (uint8_t)0 // behaviour << granularity // granularity << 0.0 // tolerance << false // have smallest face thickness << false; // have scale out << (uint32_t)1; // number of bodies // body out << (uint32_t)PRC_TYPE_TOPO_BrepData; out << false // base topology: no base information << (uint8_t)0 // content body: behaviour. Not sure what a 0 means, since it satisfies no #define, but I think it means no bbox << (uint32_t)1; // number of connex // connex out << false // not already stored << (uint32_t)PRC_TYPE_TOPO_Connex << false // base topology: no base information << (uint32_t)1; // number of shells // shell out << false // not already stored << (uint32_t)PRC_TYPE_TOPO_Shell << false // base topology: no base information << false // shell is closed << (uint32_t)1; // number of faces // face out << false // not already stored << (uint32_t)PRC_TYPE_TOPO_Face << false; // base topology: no base information // NURBS out << false // not already stored << (uint32_t)PRC_TYPE_SURF_NURBS << false // base topology: no base information << (uint32_t)KEPRCExtendTypeNone // Extend Info << isRational // is rational << (uint32_t)degreeU // degree in u << (uint32_t)degreeV // degree in v << (uint32_t)numberOfControlPointsU-1 // control points in u - 1 << (uint32_t)numberOfControlPointsV-1 // control points in v - 1 << (uint32_t)degreeU+numberOfControlPointsU // knots in u - 1 << (uint32_t)degreeV+numberOfControlPointsV; // knots in v -1 // control points for(uint32_t i = 0; i < numberOfControlPointsU*numberOfControlPointsV; ++i) { double Scale=scale; if(isRational) Scale *= weights[i]; out << controlPoints[i][0]*Scale << controlPoints[i][1]*Scale << controlPoints[i][2]*Scale; if(isRational) out << weights[i]; } writeKnots(out); out << (uint32_t)KEPRCKnotTypeUnspecified // KEPRCKnotTypePiecewiseBezierKnots << (uint32_t)KEPRCBSplineSurfaceFormUnspecified; // surface form // ending of face out << false // trim surface domain << false // have tolerance << (uint32_t)0 // number of loops << (int32_t)-1; // outer loop index // ending of shell out << (uint8_t)1; // orientation of surface normal w.r.t. face normal: // 0: same, 1: opposite, 2: unknown, 1 used in example } void PRCsurface::writeExtraGeometryContext(PRCbitStream &out) { //geometry summary out << (uint32_t)1; // number of bodies out << (uint32_t)PRC_TYPE_TOPO_BrepData; // body's serial type //context graphics out << (uint32_t)0; // number of treat types } void PRCCompressedSection::write(std::ostream &out) { if(prepared) out.write((char*)data,getSize()); } void PRCCompressedSection::prepare() { writeData(); compress(); prepared = true; } uint32_t PRCCompressedSection::getSize() { if(!prepared) return m1; else return out.getSize(); } void PRCGlobalsSection::writeData() { // even though this is technically not part of this section, // it is handled here for convenience out << (uint32_t)(0); // number of schemas out << (uint32_t)PRC_TYPE_ASM_FileStructureGlobals; SingleAttributeData value = {PRCVersion}; SingleAttribute sa(false,EMPTY_ATTRIBUTE_TITLE,KEPRCModellerAttributeTypeInt,value); AttributeTitle iv; iv.text = "__PRC_RESERVED_ATTRIBUTE_PRCInternalVersion"; Attribute a(false,iv,1,&sa); Attributes as(1,&a); ContentPRCBase(&as).write(out); out << numberOfReferencedFileStructures; // no referencing of file structures out << tessellationChordHeightRatio; out << tessellationAngleDegrees; out << defaultFontFamilyName; // markup serialization helper out << numberOfFonts << (uint32_t)parent->colourMap.size(); for(std::vector::iterator i = parent->colourMap.begin(); i != parent->colourMap.end(); i++) { out << i->R << i->G << i->B; } out << numberOfPictures << numberOfTextureDefinitions; out << (uint32_t)parent->materialMap.size(); // number of materials for(std::vector::iterator i = parent->materialMap.begin(); i != parent->materialMap.end(); i++) { out << (uint32_t)PRC_TYPE_GRAPH_Material; ContentPRCBase(&EMPTY_ATTRIBUTES,"",true,makeCADID(),0,makePRCID()).write(out); out << 3*parent->getColourIndex(i->ambient)+1 // ambient + 1 << 3*parent->getColourIndex(i->diffuse)+1 // diffuse + 1 << 3*parent->getColourIndex(i->emissive)+1 // emissive + 1 << 3*parent->getColourIndex(i->specular)+1 // specular + 1 << i->shininess // shininess << i->ambient.A // ambient_alpha << i->diffuse.A // diffuse_alpha << i->emissive.A // emissive_alpha << i->specular.A; // specular_alpha } out << (uint32_t)1 // number of line patterns hard coded for now << (uint32_t)PRC_TYPE_GRAPH_LinePattern; ContentPRCBase(&EMPTY_ATTRIBUTES,"",true,makeCADID(),0,makePRCID()).write(out); out << (uint32_t)0 // number of lengths << 0.0 // phase << false; // is real length out << (uint32_t)(parent->colourMap.size()+parent->materialMap.size()); // number of styles uint32_t index = 0; // colours are written first for(std::vector::iterator i = parent->colourMap.begin(); i != parent->colourMap.end(); i++, ++index) { out << (uint32_t)PRC_TYPE_GRAPH_Style; ContentPRCBase(&EMPTY_ATTRIBUTES,"",true,makeCADID(),0,makePRCID()).write(out); out << 0.0 // line width in mm << false // is vpicture << (uint32_t)1 // line pattern index+1 << false // is material << (uint32_t)(3*index+1); // 3*color_index+1 if(i->A < 1.0) out << true << (uint8_t)(i->A * 256); else out << false; out << false // additional 1 not defined << false // additional 2 not defined << false; // additional 3 not defined } // materials are after colours index = 0; for(std::vector::iterator i = parent->materialMap.begin(); i != parent->materialMap.end(); i++, ++index) { out << (uint32_t)PRC_TYPE_GRAPH_Style; ContentPRCBase(&EMPTY_ATTRIBUTES,"",true,makeCADID(),0,makePRCID()).write(out); out << 0.0 // line width in mm << false // is vpicture << (uint32_t)1 // line pattern index+1 << true // is material << index+1; // material_index+1 if(i->alpha < 1.0) out << true << (uint8_t)(i->alpha * 256); else out << false; out << false // additional 1 not defined << false // additional 2 not defined << false; // additional 3 not defined } out << numberOfFillPatterns << numberOfReferenceCoordinateSystems; userData.write(out); } void PRCTreeSection::writeData() { out << (uint32_t)(PRC_TYPE_ASM_FileStructureTree); EMPTY_CONTENTPRCBASE.write(out); out << (uint32_t)1; // number of part definitions // part definitions out << (uint32_t)(PRC_TYPE_ASM_PartDefinition); ContentPRCBase(&EMPTY_ATTRIBUTES,"",true,makeCADID(),0,makePRCID()).write(out); writeGraphics(out,m1,m1,1,true); Point3d M=Point3d(1e20,1e20,1e20); Point3d m=Point3d(-1e20,-1e20,-1e20); Extent3d(M,m).write(out); out << (uint32_t)parent->fileEntities.size(); // number of representation items for(uint32_t i = 0; i < parent->fileEntities.size(); ++i) { parent->fileEntities[i]->writeRepresentationItem(out,i); } writeEmptyMarkups(out); out << (uint32_t)0; // no views UserData(0,0).write(out); out << (uint32_t)1; // number of product occurrences // only one product occurrence out << (uint32_t)(PRC_TYPE_ASM_ProductOccurence); SingleAttribute sas[3]; SingleAttributeData sad; AttributeTitle at; at.text = "FilePath"; sad.text = "file name not specified"; sas[0] = SingleAttribute(false,at,KEPRCModellerAttributeTypeString,sad); at.text = "FileSize"; sad.integer = 1234; sas[1] = SingleAttribute(false,at,KEPRCModellerAttributeTypeInt,sad); at.text = "FileModificationTime"; sad.time = time(NULL); sas[2] = SingleAttribute(false,at,KEPRCModellerAttributeTypeInt,sad); at.text = "__PRC_RESERVED_ATTRIBUTE_A3DF_ProductInformation"; Attribute attr(false,at,3,sas); Attributes attrs(1,&attr); ContentPRCBase(&attrs,"root",true,makeCADID(),0,makePRCID()).write(out); writeGraphics(out,m1,m1,1,true); out << (uint32_t)1 // index_part+1 << (uint32_t)0 // index_prototype+1 << (uint32_t)0 // index_external_data+1 << (uint32_t)0 // number of son product occurrences << (uint8_t)0; // product behaviour writeUnit(out,true,10.0); out << (uint8_t)0 // product information flags << (uint32_t)KEPRCProductLoadStatus_Loaded; // product_load_status out << false // has location << (uint32_t)0; // number of references writeEmptyMarkups(out); out << (uint32_t)0 // number_of_views << false // has entity filter << (uint32_t)0 // number_of_display_filters << (uint32_t)0; // number_of_scene_display_parameters UserData(0,0).write(out); // File Structure Internal Data out << (uint32_t)(PRC_TYPE_ASM_FileStructure); EMPTY_CONTENTPRCBASE.write(out); out << makePRCID(); // next available index out << (uint32_t)1; // product occurrence index UserData(0,0).write(out); } void PRCTessellationSection::writeData() { out << (uint32_t)(PRC_TYPE_ASM_FileStructureTessellation); EMPTY_CONTENTPRCBASE.write(out); out << (uint32_t)0; // number of tessellations UserData(0,0).write(out); // no user data } void PRCGeometrySection::writeData() { out << (uint32_t)(PRC_TYPE_ASM_FileStructureGeometry); EMPTY_CONTENTPRCBASE.write(out); out << (uint32_t)parent->fileEntities.size(); // number of topological contexts for(uint32_t i = 0; i < parent->fileEntities.size(); ++i) { parent->fileEntities[i]->writeTopologicalContext(out); } UserData(0,0).write(out); } void PRCExtraGeometrySection::writeData() { out << (uint32_t)(PRC_TYPE_ASM_FileStructureExtraGeometry); EMPTY_CONTENTPRCBASE.write(out); out << (uint32_t)parent->fileEntities.size(); // number of contexts for(uint32_t i = 0; i < parent->fileEntities.size(); ++i) { parent->fileEntities[i]->writeExtraGeometryContext(out); } UserData(0,0).write(out); } void PRCModelFile::writeData() { // even though this is technically not part of this section, // it is handled here for convenience out << (uint32_t)(0); // number of schemas out << (uint32_t)(PRC_TYPE_ASM_ModelFile); SingleAttributeData value = {PRCVersion}; SingleAttribute sa(false,EMPTY_ATTRIBUTE_TITLE,KEPRCModellerAttributeTypeInt,value); AttributeTitle at; at.text = "__PRC_RESERVED_ATTRIBUTE_PRCInternalVersion"; Attribute a(false,at,1,&sa); Attributes as(1,&a); ContentPRCBase(&as,"PRC file").write(out); writeUnit(out,true,10); // unit is 10 mm, and happens to come from a CAD file out << (uint32_t)1; // 1 product occurrence //UUID out << parent->fileStructures[0]->header.fileStructureUUID[0] << parent->fileStructures[0]->header.fileStructureUUID[1] << parent->fileStructures[0]->header.fileStructureUUID[2] << parent->fileStructures[0]->header.fileStructureUUID[3]; // index+1 out << (uint32_t)1; // active out << true; out << (uint32_t)0; // index in model file UserData(0,0).write(out); } void makeFileUUID(uint32_t *UUID) { // make a UUID static uint32_t count = 0; ++count; // the minimum requirement on UUIDs is that all must be unique in the file UUID[0] = 0x33595341; // some constant UUID[1] = time(NULL); // the time UUID[2] = count; UUID[3] = 0xa5a55a5a; // Something random, not seeded by the time, would be nice. But for now, a constant // maybe add something else to make it more unique // so multiple files can be combined // a hash of some data perhaps? } void makeAppUUID(uint32_t *UUID) { UUID[0] = UUID[1] = UUID[2] = UUID[3] = 0; } void writeUINT32_T(std::ostream &out, uint32_t data) { #ifdef WORDS_BIGENDIAN out.write(((char*)&data)+3,1); out.write(((char*)&data)+2,1); out.write(((char*)&data)+1,1); out.write(((char*)&data)+0,1); #else out.write(((char*)&data)+0,1); out.write(((char*)&data)+1,1); out.write(((char*)&data)+2,1); out.write(((char*)&data)+3,1); #endif } void PRCUncompressedFile::write(std::ostream &out) { writeUINT32_T(out,file_size); out.write((char*)data,file_size); } uint32_t PRCUncompressedFile::getSize() { return sizeof(file_size)+file_size; } void PRCStartHeader::write(std::ostream &out) { out.write("PRC",3); writeUINT32_T(out,minimal_version_for_read); writeUINT32_T(out,authoring_version); writeUINT32_T(out,fileStructureUUID[0]); writeUINT32_T(out,fileStructureUUID[1]); writeUINT32_T(out,fileStructureUUID[2]); writeUINT32_T(out,fileStructureUUID[3]); writeUINT32_T(out,applicationUUID[0]); writeUINT32_T(out,applicationUUID[1]); writeUINT32_T(out,applicationUUID[2]); writeUINT32_T(out,applicationUUID[3]); } uint32_t PRCStartHeader::getSize() { return 3+(2+2*4)*sizeof(uint32_t); } void PRCFileStructure::write(std::ostream &out) { header.write(out); writeUINT32_T(out,number_of_uncompressed_files); for(uint32_t i = 0; i < number_of_uncompressed_files; ++i) { uncompressedFiles[i].write(out); } globals.write(out); tree.write(out); tessellations.write(out); geometry.write(out); extraGeometry.write(out); } void PRCFileStructure::prepare() { globals.prepare(); resetGraphicsAndName(); tree.prepare(); resetGraphicsAndName(); tessellations.prepare(); resetGraphicsAndName(); geometry.prepare(); resetGraphicsAndName(); extraGeometry.prepare(); resetGraphicsAndName(); } uint32_t PRCFileStructure::getSize() { uint32_t size = 0; size += header.getSize(); size += sizeof(uint32_t); for(uint32_t i = 0; i < number_of_uncompressed_files; ++i) size += uncompressedFiles[i].getSize(); size += globals.getSize(); size += tree.getSize(); size += tessellations.getSize(); size += geometry.getSize(); size += extraGeometry.getSize(); return size; } void PRCFileStructureInformation::write(std::ostream &out) { writeUINT32_T(out,UUID[0]); writeUINT32_T(out,UUID[1]); writeUINT32_T(out,UUID[2]); writeUINT32_T(out,UUID[3]); writeUINT32_T(out,reserved); writeUINT32_T(out,number_of_offsets); for(uint32_t i = 0; i < number_of_offsets; ++i) { writeUINT32_T(out,offsets[i]); } } uint32_t PRCFileStructureInformation::getSize() { return (4+2+number_of_offsets)*sizeof(uint32_t); } void PRCHeader::write(std::ostream &out) { startHeader.write(out); writeUINT32_T(out,number_of_file_structures); for(uint32_t i = 0; i < number_of_file_structures; ++i) { fileStructureInformation[i].write(out); } writeUINT32_T(out,model_file_offset); writeUINT32_T(out,file_size); writeUINT32_T(out,number_of_uncompressed_files); for(uint32_t i = 0; i < number_of_uncompressed_files; ++i) { uncompressedFiles[i].write(out); } } uint32_t PRCHeader::getSize() { uint32_t size = startHeader.getSize() + sizeof(uint32_t); for(uint32_t i = 0; i < number_of_file_structures; ++i) size += fileStructureInformation[i].getSize(); size += 3*sizeof(uint32_t); for(uint32_t i = 0; i < number_of_uncompressed_files; ++i) size += uncompressedFiles[i].getSize(); return size; } bool oPRCFile::add(PRCentity *p) { fileEntities.push_back(p); if(p->useMaterial) { if(getMaterialIndex(p->material) == m1) { materialMap.push_back(p->material); if(getColourIndex(p->material.ambient) == m1) colourMap.push_back(p->material.ambient); if(getColourIndex(p->material.diffuse) == m1) colourMap.push_back(p->material.diffuse); if(getColourIndex(p->material.emissive) == m1) colourMap.push_back(p->material.emissive); if(getColourIndex(p->material.specular) == m1) colourMap.push_back(p->material.specular); } } else { if(getColourIndex(p->colour) == m1) { colourMap.push_back(p->colour); } } return true; } bool oPRCFile::finish() { // only one file structure is currently used // prepare data fileStructures[0] = new PRCFileStructure(this,0); fileStructures[0]->header.minimal_version_for_read = PRCVersion; fileStructures[0]->header.authoring_version = PRCVersion; makeFileUUID(fileStructures[0]->header.fileStructureUUID); makeAppUUID(fileStructures[0]->header.applicationUUID); fileStructures[0]->number_of_uncompressed_files = 0; // write each section's bit data fileStructures[0]->prepare(); modelFile.prepare(); // create the header // fill out enough info so that sizes can be computed correctly header.number_of_uncompressed_files = 0; header.number_of_file_structures = number_of_file_structures; header.fileStructureInformation = new PRCFileStructureInformation[number_of_file_structures]; for(uint32_t i = 0; i < number_of_file_structures; ++i) { header.fileStructureInformation[i].UUID[0] = fileStructures[i]->header.fileStructureUUID[0]; header.fileStructureInformation[i].UUID[1] = fileStructures[i]->header.fileStructureUUID[1]; header.fileStructureInformation[i].UUID[2] = fileStructures[i]->header.fileStructureUUID[2]; header.fileStructureInformation[i].UUID[3] = fileStructures[i]->header.fileStructureUUID[3]; header.fileStructureInformation[i].reserved = 0; header.fileStructureInformation[i].number_of_offsets = 6; header.fileStructureInformation[i].offsets = new uint32_t[6]; } header.startHeader.minimal_version_for_read = PRCVersion; header.startHeader.authoring_version = PRCVersion; makeFileUUID(header.startHeader.fileStructureUUID); makeAppUUID(header.startHeader.applicationUUID); header.file_size = getSize(); header.model_file_offset = header.file_size - modelFile.getSize(); uint32_t currentOffset = header.getSize(); for(uint32_t i = 0; i < number_of_file_structures; ++i) { header.fileStructureInformation[i].offsets[0] = currentOffset; // header offset currentOffset += fileStructures[i]->header.getSize() + sizeof(uint32_t); for(uint32_t j = 0; j < fileStructures[i]->number_of_uncompressed_files; ++j) currentOffset += fileStructures[i]->uncompressedFiles[j].getSize(); header.fileStructureInformation[i].offsets[1] = currentOffset; // globals offset currentOffset += fileStructures[i]->globals.getSize(); header.fileStructureInformation[i].offsets[2] = currentOffset; // tree offset currentOffset += fileStructures[i]->tree.getSize(); header.fileStructureInformation[i].offsets[3] = currentOffset; // tessellations offset currentOffset += fileStructures[i]->tessellations.getSize(); header.fileStructureInformation[i].offsets[4] = currentOffset; // geometry offset currentOffset += fileStructures[i]->geometry.getSize(); header.fileStructureInformation[i].offsets[5] = currentOffset; // extra geometry offset currentOffset += fileStructures[i]->extraGeometry.getSize(); } // write the data header.write(output); for(uint32_t i = 0; i < number_of_file_structures; ++i) { fileStructures[i]->write(output); } modelFile.write(output); output.flush(); for(uint32_t i = 0; i < number_of_file_structures; ++i) delete[] header.fileStructureInformation[i].offsets; delete[] header.fileStructureInformation; return true; } uint32_t oPRCFile::getColourIndex(const RGBAColour &c) { for(uint32_t i = 0; i < colourMap.size(); ++i) { if(colourMap[i] == c) return i; } return m1; } uint32_t oPRCFile::getMaterialIndex(const PRCMaterial &m) { for(uint32_t i = 0; i < materialMap.size(); ++i) { if(materialMap[i] == m) return i; } return m1; } uint32_t oPRCFile::getSize() { uint32_t size = header.getSize(); for(uint32_t i = 0; i < number_of_file_structures; ++i) { size += fileStructures[i]->getSize(); } size += modelFile.getSize(); return size; }