/** * Read a sub block from a 2.2 TXP database. This can be called any time after ReadHeader is called * if ReadHeader is called with the false parameter to specify not to read all the sub-archives. * This can make a huge improvement in startup time for loading a very large archive with many blocks. **/ bool trpgr_Archive::ReadSubArchive(int row, int col, trpgEndian cpuNess) { int ret; trpgHeader blockHeader; trpgr_Parser bparser; char blockpath[1060]; //open the block archive // the block archive will be in the base dir + \\cols\\row\\archive.txp sprintf(blockpath,"%s%s%d%s%d%sarchive.txp",dir,PATHSEPERATOR,col,PATHSEPERATOR,row,PATHSEPERATOR); FILE *bfp = osgDB::fopen(blockpath,"rb"); if(!bfp) { return false; } // Look for a magic # and endianness int32 bmagic; if (fread(&bmagic,sizeof(int32),1,bfp) != 1) { //close the block archive fclose(bfp); return false; } // The block archive will always be the same endianness as the master if ( (bmagic != GetMagicNumber()) && (trpg_byteswap_int(bmagic) != GetMagicNumber()) ) { //close the block archive fclose(bfp); return false; } int32 bheaderSize=0; if (fread(&bheaderSize,sizeof(int32),1,bfp) != 1) { //close the block archive fclose(bfp); return false; } if (ness != cpuNess) bheaderSize = trpg_byteswap_int(bheaderSize); int bheadLen = bheaderSize; if (bheadLen < 0) { //close the block archive fclose(bfp); return false; } // Read in the header whole trpgMemReadBuffer bbuf(ness); bbuf.SetLength(bheadLen); char *bdata = bbuf.GetDataPtr(); if ((ret = GetHeaderData(bdata,bheadLen,bfp)) != bheadLen) { //close the block archive fclose(bfp); return false; } //keep track of where this came from in the master table. tileTable.SetCurrentBlock(row,col,true); texTable.SetCurrentBlock(row,col); bparser.AddCallback(TRPGHEADER,&blockHeader); bparser.AddCallback(TRPGMATTABLE,&materialTable); // Went back to oldest style for 2.0 //if(!headerHasTexTable) { bparser.AddCallback(TRPGTEXTABLE2,&texTable); // Added for 2.0 //} bparser.AddCallback(TRPGMODELTABLE,&modelTable); bparser.AddCallback(TRPGLIGHTTABLE,&lightTable); // Added for 2.0 bparser.AddCallback(TRPGRANGETABLE,&rangeTable); // Added for 2.0 bparser.AddCallback(TRPG_TEXT_STYLE_TABLE,&textStyleTable); // Added for 2.1 bparser.AddCallback(TRPG_SUPPORT_STYLE_TABLE,&supportStyleTable); bparser.AddCallback(TRPG_LABEL_PROPERTY_TABLE,&labelPropertyTable); // Don't read the tile table for v1.0 archives // It's only really used for 2.0 archives bparser.AddCallback(TRPGTILETABLE2,&tileTable); // Parse the buffer if (!bparser.Parse(bbuf)) return false; //close the block archive fclose(bfp); tileTable.SetCurrentBlock(-1,-1,false); return true; }
/* CheckpointHeader The header lives in its own file, so we can write it at any point we have a valid archive. This includes all the tables, as well as basic header info. */ bool trpgwArchive::CheckpointHeader() { trpgMemWriteBuffer buf(ness); if (!isValid()) return false; if (!header.isValid()) { if(header.getErrMess()) strcpy(errMess, header.getErrMess()); return false; } // This will close the appendable files if (tileFile) { tileFile->Flush(); } /* Build a Tile Table We need to build one from scratch here. However, we have all the relevant information collected during the WriteTile calls. */ if(header.GetIsLocal()) { int row = 0; int col = 0; header.GetBlocks(row,col); tileTable.SetCurrentBlock(row,col,true); } if (tileMode == TileExternal) { // External tiles are easy tileTable.SetMode(trpgTileTable::External); } else if( tileMode == TileExternalSaved) { if(!isRegenerate && firstHeaderWrite) { // Set up the sizes tileTable.SetMode(trpgTileTable::ExternalSaved); tileTable.SetNumLod(1); trpg2iPoint lodSize; header.GetLodSize(0,lodSize); tileTable.SetNumTiles(lodSize.x, lodSize.y, 0); firstHeaderWrite = false; } // Now set the individual tile locations for (unsigned int i=0;i<externalTiles.size();i++) { TileFileEntry &te = externalTiles[i]; trpgwAppAddress addr; addr.file = -1; addr.offset = -1; tileTable.SetTile(te.x,te.y,te.lod,addr,te.zmin,te.zmax); } externalTiles.clear(); } else { if (!isRegenerate && firstHeaderWrite) { // Local tiles require more work tileTable.SetMode(trpgTileTable::Local); if(majorVersion == 2 && minorVersion >= 1) { // Version 2.1, we store only lod 0 in the tile table // Set up the sizes tileTable.SetNumLod(1); trpg2iPoint lodSize; header.GetLodSize(0,lodSize); tileTable.SetNumTiles(lodSize.x, lodSize.y, 0); } else { // Set up the sizes int32 numLod; header.GetNumLods(numLod); tileTable.SetNumLod(numLod); for (int i=0;i<numLod;i++) { trpg2iPoint lodSize; header.GetLodSize(i,lodSize); tileTable.SetNumTiles(lodSize.x,lodSize.y,i); } } firstHeaderWrite = false; } // Now set the individual tile locations // Nothing special need to be done with version 2.1 since // only tile with lod 0 will be found in the tileFiles container for (unsigned int i=0;i<tileFiles.size();i++) { TileFile &tf = tileFiles[i]; for (unsigned int j=0;j<tf.tiles.size();j++) { TileFileEntry &te = tf.tiles[j]; trpgwAppAddress addr; addr.file = tf.id; addr.offset = te.offset; tileTable.SetTile(te.x,te.y,te.lod,addr,te.zmin,te.zmax); } tf.tiles.clear(); } } // Write all the headers into a buffer if (!header.Write(buf)) return false; // Do the mat table and texture table // These can be different depending on the version switch (majorVersion) { case 1: { trpgMatTable1_0 matTable1_0(matTable); trpgTexTable1_0 texTable1_0(texTable); trpgTileTable1_0 tileTable1_0(tileTable); if (!matTable1_0.Write(buf) || !texTable1_0.Write(buf) || !modelTable.Write(buf) || !tileTable1_0.Write(buf) || !lightTable.Write(buf) || !rangeTable.Write(buf)) return false; } break; case 2: if(!header.GetIsMaster()||texTable.isValid()) { if(!texTable.Write(buf)) { strcpy(errMess, "Error writing texture table"); if(texTable.getErrMess()) { strcat(errMess, ": "); strcat(errMess, texTable.getErrMess()); return false; } } } //These tables will not be populated if this is the master table. if(!header.GetIsMaster()) { if (!matTable.Write(buf)) { strcpy(errMess, "Error writing material table"); if(matTable.getErrMess()) { strcat(errMess, ": "); strcat(errMess, matTable.getErrMess()); return false; } } if(!modelTable.Write(buf) ) { strcpy(errMess, "Error writing model table"); if(modelTable.getErrMess()) { strcat(errMess, ": "); strcat(errMess, modelTable.getErrMess()); return false; } } } //always write the tile table, even if we are a master if(!tileTable.Write(buf)) { strcpy(errMess, "Error writing tile table"); if(tileTable.getErrMess()) { strcat(errMess, ": "); strcat(errMess, tileTable.getErrMess()); return false; } } if(!header.GetIsMaster()) { if(!lightTable.Write(buf)) { strcpy(errMess, "Error writing light table"); if(lightTable.getErrMess()) { strcat(errMess, ": "); strcat(errMess, lightTable.getErrMess()); return false; } } if(!rangeTable.Write(buf)) { strcpy(errMess, "Error writing range table"); if(rangeTable.getErrMess()) { strcat(errMess, ": "); strcat(errMess, rangeTable.getErrMess()); return false; } } if (!textStyleTable.Write(buf)) { strcpy(errMess,"Error writing text style table"); if (textStyleTable.getErrMess()) { strcat(errMess, ": "); strcat(errMess, textStyleTable.getErrMess()); return false; } } if (!supportStyleTable.Write(buf)) { strcpy(errMess,"Error writing support style table"); if (supportStyleTable.getErrMess()) { strcat(errMess, ": "); strcat(errMess, supportStyleTable.getErrMess()); return false; } } if (!labelPropertyTable.Write(buf)) { strcpy(errMess,"Error writing label property table"); if (labelPropertyTable.getErrMess()) { strcat(errMess, ": "); strcat(errMess, labelPropertyTable.getErrMess()); return false; } } } break; } // Write the disk header int32 magic = GetMagicNumber(); if (ness != cpuNess) magic = trpg_byteswap_int(magic); if (fwrite(&magic,sizeof(int32),1,fp) != 1) { strcpy(errMess, "Could not write the magic number"); return false; } // Write the header length int32 headerSize = buf.length(); int headLen = headerSize; if (ness != cpuNess) headerSize = trpg_byteswap_int(headerSize); if (fwrite(&headerSize,1,sizeof(int32),fp) != sizeof(int32)) { strcpy(errMess, "Could not write the header size"); return false; } // Write the buffer const char *data = buf.getData(); if (WriteHeaderData(data,headLen,fp) != headLen) { strcpy(errMess, "Could not write the buffer"); return false; } // Note: Not sure what this is char space[40]; if (fwrite(space,1,4,fp) != 4) return false; // Flush output fflush(fp); // Head back to the start of the file rewind(fp); return true; }