1 /* ************************
2    Copyright Terrain Experts Inc.
3    Terrain Experts Inc (TERREX) reserves all rights to this source code
4    unless otherwise specified in writing by the President of TERREX.
5    This copyright may be updated in the future, in which case that version
6    supercedes this one.
7    -------------------
8    Terrex Experts Inc.
9    4400 East Broadway #314
10    Tucson, AZ  85711
11    info@terrex.com
12    Tel: (520) 323-7990
13    ************************
14    */
15 
16 #include <osgDB/FileUtils>
17 
18 #include <stdlib.h>
19 #include <stdio.h>
20 #include <string.h>
21 
22 /* trpage_rarchive.cpp
23    This source file implements the methods for a trpgr_Archive.
24    The Read Archive is used to read a paging archive from disk.
25 */
26 
27 #include <trpage_read.h>
28 #include <trpage_compat.h>
29 
30 // Constructor
trpgr_Archive()31 trpgr_Archive::trpgr_Archive()
32 {
33     fp = NULL;
34     ness = LittleEndian;
35     strcpy(dir,".");
36     tileCache = NULL;
37 }
38 
39 // Destructor
~trpgr_Archive()40 trpgr_Archive::~trpgr_Archive()
41 {
42     if (fp)
43         fclose(fp);
44     fp = NULL;
45     if (tileCache)
46         delete tileCache;
47 }
48 
GetHeaderData(char * dataPtr,int length,FILE * filehandle)49 int32 trpgr_Archive::GetHeaderData(char *dataPtr, int length, FILE *filehandle)
50 {
51     return fread(dataPtr,1,length,filehandle);
52 }
53 
54 // Set the directory where the archive is
SetDirectory(const char * in_dir)55 void trpgr_Archive::SetDirectory(const char *in_dir)
56 {
57     strncpy(dir,in_dir,1024);
58 }
59 
60 // Open File
61 // Open the given file and look for the file specific info
OpenFile(const char * name)62 bool trpgr_Archive::OpenFile(const char *name)
63 {
64     char file[1024];
65     sprintf(file,"%s" PATHSEPERATOR "%s",dir,name);
66 
67     CloseFile();
68 
69     if (!(fp = osgDB::fopen(file,"rb")))
70         return false;
71 
72     // Look for a magic # and endianness
73     int32 magic;
74     if (fread(&magic,sizeof(int32),1,fp) != 1)
75         return false;
76 
77     headerRead = false;
78 
79     // Figure out the endianness from the magic number
80     trpgEndian cpuNess = trpg_cpu_byte_order();
81     if (magic == GetMagicNumber()) {
82         ness = cpuNess;
83         return true;
84     }
85     if (trpg_byteswap_int(magic) == GetMagicNumber()) {
86         if (cpuNess == LittleEndian)
87             ness = BigEndian;
88         else
89             ness = LittleEndian;
90         return true;
91     }
92     if (magic != GetMagicNumber())
93         return false;
94 
95     // Not one of our files
96     return false;
97 }
98 
99 // Get new reading app file cache
GetNewRAppFileCache(const char * fullBase,const char * ext)100 trpgrAppFileCache* trpgr_Archive::GetNewRAppFileCache(const char *fullBase, const char *ext)
101 {
102     return new trpgrAppFileCache(fullBase,ext);
103 }
104 
GetNewRImageHelper(trpgEndian ness,char * dir,const trpgMatTable & matTable,const trpgTexTable & texTable)105 trpgrImageHelper* trpgr_Archive::GetNewRImageHelper(trpgEndian ness,char *dir,const trpgMatTable &matTable,const trpgTexTable &texTable)
106 {
107     bool separateGeo = false;
108     int majorVer,minorVer;
109     GetHeader()->GetVersion(majorVer,minorVer);
110     if((majorVer >= TRPG_NOMERGE_VERSION_MAJOR) && (minorVer>=TRPG_NOMERGE_VERSION_MINOR)) {
111         separateGeo = true;
112     }
113     return new trpgrImageHelper(ness,dir,matTable,texTable,separateGeo);
114 }
115 
116 // Close File
117 // Close the currently open file
CloseFile()118 void trpgr_Archive::CloseFile()
119 {
120     if (fp)
121         fclose(fp);
122     fp = NULL;
123     if (tileCache)
124         delete tileCache;
125     tileCache = NULL;
126 }
127 
128 /**
129  * Read a sub block from a 2.2 TXP database. This can be called any time after ReadHeader is called
130  * if ReadHeader is called with the false parameter to specify not to read all the sub-archives.
131  * This can make a huge improvement in startup time for loading a very large archive with many blocks.
132  **/
ReadSubArchive(int row,int col,trpgEndian cpuNess)133 bool trpgr_Archive::ReadSubArchive(int row, int col, trpgEndian cpuNess)
134 {
135     int ret;
136     trpgHeader blockHeader;
137     trpgr_Parser bparser;
138 
139     char blockpath[1024];
140     //open the block archive
141     // the block archive will be in the base dir + \\cols\\row\\archive.txp
142     sprintf(blockpath,"%s%s%d%s%d%sarchive.txp",dir,PATHSEPERATOR,col,PATHSEPERATOR,row,PATHSEPERATOR);
143     FILE *bfp = osgDB::fopen(blockpath,"rb");
144     if(!bfp) {
145         return false;
146     }
147     // Look for a magic # and endianness
148     int32 bmagic;
149     if (fread(&bmagic,sizeof(int32),1,bfp) != 1)
150         return false;
151     // The block archive will always be the same endianness as the master
152     if ( (bmagic != GetMagicNumber()) && (trpg_byteswap_int(bmagic) != GetMagicNumber()) )
153         return false;
154 
155     int32 bheaderSize=0;
156     if (fread(&bheaderSize,sizeof(int32),1,bfp) != 1)
157         return false;
158     if (ness != cpuNess)
159         bheaderSize = trpg_byteswap_int(bheaderSize);
160     int bheadLen = bheaderSize;
161     if (bheadLen < 0)
162         return false;
163 
164     // Read in the header whole
165     trpgMemReadBuffer bbuf(ness);
166     bbuf.SetLength(bheadLen);
167     char *bdata = bbuf.GetDataPtr();
168     if ((ret = GetHeaderData(bdata,bheadLen,bfp)) != bheadLen)
169         return false;
170     //keep track of where this came from in the master table.
171     tileTable.SetCurrentBlock(row,col,true);
172     texTable.SetCurrentBlock(row,col);
173 
174     bparser.AddCallback(TRPGHEADER,&blockHeader);
175     bparser.AddCallback(TRPGMATTABLE,&materialTable);    // Went back to oldest style for 2.0
176     //if(!headerHasTexTable) {
177     bparser.AddCallback(TRPGTEXTABLE2,&texTable);            // Added for 2.0
178     //}
179     bparser.AddCallback(TRPGMODELTABLE,&modelTable);
180     bparser.AddCallback(TRPGLIGHTTABLE,&lightTable);                // Added for 2.0
181     bparser.AddCallback(TRPGRANGETABLE,&rangeTable);                // Added for 2.0
182     bparser.AddCallback(TRPG_TEXT_STYLE_TABLE,&textStyleTable);                // Added for 2.1
183     bparser.AddCallback(TRPG_SUPPORT_STYLE_TABLE,&supportStyleTable);
184     bparser.AddCallback(TRPG_LABEL_PROPERTY_TABLE,&labelPropertyTable);
185     // Don't read the tile table for v1.0 archives
186     // It's only really used for 2.0 archives
187     bparser.AddCallback(TRPGTILETABLE2,&tileTable);
188 
189     // Parse the buffer
190     if (!bparser.Parse(bbuf))
191         return false;
192     //close the block archive
193     fclose(bfp);
194 
195     tileTable.SetCurrentBlock(-1,-1,false);
196 
197     return true;
198 }
199 
ReadHeader()200 bool trpgr_Archive::ReadHeader()
201 {
202     return ReadHeader(true);
203 }
204 
205 // Read Header
206 // Run through the rest of the header information
ReadHeader(bool readAllBlocks)207 bool trpgr_Archive::ReadHeader(bool readAllBlocks)
208 {
209     int ret;
210 
211     if (!fp || headerRead)
212         return false;
213 
214     headerRead = true;
215 
216     // Next int64 should be the header size
217     trpgEndian cpuNess = trpg_cpu_byte_order();
218     int32 headerSize;
219     if (fread(&headerSize,sizeof(int32),1,fp) != 1)
220         return false;
221     if (ness != cpuNess)
222         headerSize = trpg_byteswap_int(headerSize);
223     int headLen = headerSize;
224     if (headLen < 0)
225         return false;
226 
227     // Read in the header whole
228     trpgMemReadBuffer buf(ness);
229     buf.SetLength(headLen);
230     char *data = buf.GetDataPtr();
231     if ((ret = GetHeaderData(data,headLen,fp)) != headLen)
232         return false;
233 
234     // Set up a parser
235     // Catch the tables we need for the archive
236     trpgMatTable1_0 oldMatTable;
237     trpgTexTable1_0 oldTexTable;
238     trpgr_Parser parser;
239     parser.AddCallback(TRPGHEADER,&header);
240     parser.AddCallback(TRPGMATTABLE,&materialTable);    // Went back to oldest style for 2.0
241     parser.AddCallback(TRPGMATTABLE2,&oldMatTable);     // Added 11-14-98 (1.0 material table)
242     parser.AddCallback(TRPGTEXTABLE,&oldTexTable);
243     parser.AddCallback(TRPGTEXTABLE2,&texTable);            // Added for 2.0
244     parser.AddCallback(TRPGMODELTABLE,&modelTable);
245     parser.AddCallback(TRPGLIGHTTABLE,&lightTable);                // Added for 2.0
246     parser.AddCallback(TRPGRANGETABLE,&rangeTable);                // Added for 2.0
247     parser.AddCallback(TRPG_TEXT_STYLE_TABLE,&textStyleTable);                // Added for 2.1
248     parser.AddCallback(TRPG_SUPPORT_STYLE_TABLE,&supportStyleTable);
249     parser.AddCallback(TRPG_LABEL_PROPERTY_TABLE,&labelPropertyTable);
250     // Don't read the tile table for v1.0 archives
251     // It's only really used for 2.0 archives
252     parser.AddCallback(TRPGTILETABLE2,&tileTable);
253 
254     // Parse the buffer
255     if (!parser.Parse(buf))
256         return false;
257 
258     if(header.GetIsMaster())
259     {
260         // bool firstBlock = true;
261         //if the master has textures, we want to use them instead of the tables in the
262         //block archives
263 
264         // int numTiles = 0;
265         //tileTable.
266         int totalrows,totalcols;
267         trpg2dPoint mhdr_swExtents;
268         trpg2dPoint mhdr_neExtents;
269         trpg3dPoint mhdr_Origin;
270         // integrate header information from the block header.
271         header.GetExtents(mhdr_swExtents,mhdr_neExtents);
272         header.GetOrigin(mhdr_Origin);
273         header.GetBlocks(totalrows,totalcols);
274         if(readAllBlocks) {
275             for(int row=0;row<totalrows;row++) {
276                 for(int col=0;col<totalcols;col++) {
277                     // Read each block -- Warning, this can take a while!!!
278                     ReadSubArchive( row, col, cpuNess);
279                 }
280             }
281         }
282         else {
283             ReadSubArchive( 0, 0, cpuNess);//Get the first archive!
284         }
285 
286     }
287     tileTable.SetCurrentBlock(-1,-1,false);
288 
289     // 1.0 Compatibility
290     // If we see an older style material table, convert it to the new style
291     // This isn't terribly memory efficient, but it does work
292     if (oldMatTable.isValid())
293         materialTable = oldMatTable;
294     if (oldTexTable.isValid())
295         texTable = oldTexTable;
296 
297     // Set up a tile cache, if needed
298     trpgTileTable::TileMode tileMode;
299     tileTable.GetMode(tileMode);
300     if (tileMode == trpgTileTable::Local) {
301         if (tileCache)  delete tileCache;
302         char fullBase[1024];
303         sprintf(fullBase,"%s" PATHSEPERATOR "tileFile",dir);
304         tileCache = GetNewRAppFileCache(fullBase,"tpf");
305     }
306 
307     valid = true;
308 
309     return true;
310 }
311 
312 // Read Tile
313 // Read a tile into a read buffer
314 // For version 2.1 only  tile with lod=0 are stored in the tile table, so an
315 // error will be returned if you try to use the table with a differrent lod.
ReadTile(uint32 x,uint32 y,uint32 lod,trpgMemReadBuffer & buf)316 bool trpgr_Archive::ReadTile(uint32 x,uint32 y,uint32 lod,trpgMemReadBuffer &buf)
317 {
318     if (!isValid())
319         return false;
320 
321     // Reality check the address
322     int32 numLods;
323     header.GetNumLods(numLods);
324     if (static_cast<int>(lod) >= numLods)
325         return false;
326     trpg2iPoint lodSize;
327     header.GetLodSize(lod,lodSize);
328     if (static_cast<int>(x) >= lodSize.x || static_cast<int>(y) >= lodSize.y)
329         return false;
330 
331     trpgTileTable::TileMode tileMode;
332     tileTable.GetMode(tileMode);
333 
334     bool status = true;
335     if (tileMode == trpgTileTable::External || tileMode == trpgTileTable::ExternalSaved) {
336         status = ReadExternalTile(x, y, lod, buf);
337 
338     } else {
339         // Local tile.  Figure out where it is (which file)
340         int majorVersion, minorVersion;
341         header.GetVersion(majorVersion, minorVersion);
342         if(majorVersion == 2 && minorVersion >=1)
343         {
344             // Version 2.1
345             // Tile table contains only lod 0 tiles
346             if(lod != 0)
347                 status = false;
348         }
349 
350         if(status)
351         {
352             trpgwAppAddress addr;
353             float zmin,zmax;
354             status = tileTable.GetTile(x,y,lod,addr,zmin,zmax);
355 
356             if(status)
357                 status = ReadTile(addr, buf);
358         }
359     }
360 
361     return status;
362 }
363 
ReadExternalTile(uint32 x,uint32 y,uint32 lod,trpgMemReadBuffer & buf)364 bool trpgr_Archive::ReadExternalTile(uint32 x,uint32 y,uint32 lod,trpgMemReadBuffer &buf)
365 {
366     // Figure out the file name
367     char filename[1024];
368     int majorVer,minorVer;
369     header.GetVersion(majorVer,minorVer);
370     if((majorVer >= TRPG_NOMERGE_VERSION_MAJOR) && (minorVer >= TRPG_NOMERGE_VERSION_MINOR)) {
371         int blockx,blocky;
372         unsigned int denom = (1 << lod); // this should work up to lod 31
373         blockx = x/denom;
374         blocky = y/denom;
375         sprintf(filename,"%s" PATHSEPERATOR "%d" PATHSEPERATOR "%d" PATHSEPERATOR "tile_%d_%d_%d.tpt",
376                 dir,blockx,blocky,x,y,lod);
377     }
378     else {
379         sprintf(filename,"%s" PATHSEPERATOR "tile_%d_%d_%d.tpt",dir,x,y,lod);
380     }
381     // Open the file and read the contents
382     FILE *fp= 0;
383     try {
384         if (!(fp = osgDB::fopen(filename,"rb")))  {
385 
386             throw 1;
387         }
388         // Find the file end
389         if (fseek(fp,0,SEEK_END))
390             throw 1;
391         // Note: This means tile is capped at 2 gigs
392         long pos = ftell(fp);
393         if (fseek(fp,0,SEEK_SET))
394             throw 1;
395         // Now we know the size.  Read the whole file
396         buf.SetLength(pos);
397         char *data = buf.GetDataPtr();
398         if (fread(data,pos,1,fp) != 1)
399             throw 1;
400         fclose(fp);
401         fp = NULL;
402     }
403     catch (...) {
404         if (fp)
405             fclose(fp);
406         return false;
407     }
408 
409     return true;
410 }
ReadTile(const trpgwAppAddress & addr,trpgMemReadBuffer & buf)411 bool trpgr_Archive::ReadTile(const trpgwAppAddress& addr, trpgMemReadBuffer &buf)
412 {
413     // Fetch the appendable file from the cache
414     trpgrAppFile *tf = tileCache->GetFile(ness,addr.file,addr.col,addr.row);
415     if (!tf)
416         return false;
417 
418     // Fetch the tile
419     if (!tf->Read(&buf,addr.offset))
420         return false;
421     else
422         return true;
423 }
424 
425 // Get methods
GetHeader() const426 const trpgHeader *trpgr_Archive::GetHeader() const
427 {
428     return &header;
429 }
GetMaterialTable() const430 const trpgMatTable *trpgr_Archive::GetMaterialTable() const
431 {
432     return &materialTable;
433 }
GetTexTable()434 trpgTexTable *trpgr_Archive::GetTexTable()
435 {
436     return &texTable;
437 }
GetModelTable() const438 const trpgModelTable *trpgr_Archive::GetModelTable() const
439 {
440     return &modelTable;
441 }
GetTileTable() const442 const trpgTileTable *trpgr_Archive::GetTileTable() const
443 {
444     return &tileTable;
445 }
GetLightTable() const446 const trpgLightTable *trpgr_Archive::GetLightTable() const
447 {
448     return &lightTable;
449 }
GetRangeTable() const450 const trpgRangeTable *trpgr_Archive::GetRangeTable() const
451 {
452     return &rangeTable;
453 }
GetTextStyleTable() const454 const trpgTextStyleTable *trpgr_Archive::GetTextStyleTable() const
455 {
456     return &textStyleTable;
457 }
GetSupportStyleTable() const458 const trpgSupportStyleTable *trpgr_Archive::GetSupportStyleTable() const
459 {
460     return &supportStyleTable;
461 }
GetLabelPropertyTable() const462 const trpgLabelPropertyTable *trpgr_Archive::GetLabelPropertyTable() const
463 {
464     return &labelPropertyTable;
465 }
GetEndian() const466 trpgEndian trpgr_Archive::GetEndian() const
467 {
468     return ness;
469 }
470 
471 // Utility MBR routine
trpgGetTileMBR(uint32 x,uint32 y,uint32 lod,trpg3dPoint & ll,trpg3dPoint & ur) const472 bool trpgr_Archive::trpgGetTileMBR(uint32 x,uint32 y,uint32 lod,trpg3dPoint &ll,trpg3dPoint &ur) const
473 {
474     if (!header.isValid())
475         return false;
476     int32 numLod;
477     header.GetNumLods(numLod);
478     trpg2iPoint maxXY;
479     header.GetLodSize(lod,maxXY);
480     if (static_cast<int>(x) >= maxXY.x || static_cast<int>(y)>= maxXY.y)
481         return false;
482 
483     trpg3dPoint origin;
484     header.GetOrigin(origin);
485     trpg2dPoint size;
486     header.GetTileSize(lod,size);
487 
488     ll.x = origin.x + size.x*x;
489     ll.y = origin.y + size.y*y;
490     ur.x = origin.x + size.x*(x+1);
491     ur.y = origin.y + size.y*(y+1);
492 
493     // If the tiles are local, we should have Z information
494     trpgwAppAddress addr;
495     float elev_min=0.0,elev_max=0.0;
496     tileTable.GetTile(x,y,lod,addr,elev_min,elev_max);
497     ll.z = elev_min;  ur.z = elev_max;
498 
499     return true;
500 }
501 
502 /* *****************
503    Read Image Helper
504    *****************
505    */
506 
trpgrImageHelper(trpgEndian inNess,char * inDir,const trpgMatTable & inMatTable,const trpgTexTable & inTexTable,bool separateGeoTyp)507 trpgrImageHelper::trpgrImageHelper(trpgEndian inNess,char *inDir,
508                                    const trpgMatTable &inMatTable,const trpgTexTable &inTexTable,bool separateGeoTyp)
509 {
510     Init(inNess,inDir,inMatTable,inTexTable,separateGeoTyp);
511 }
512 
Init(trpgEndian inNess,char * inDir,const trpgMatTable & inMatTable,const trpgTexTable & inTexTable,bool separateGeoTyp)513 void trpgrImageHelper::Init(trpgEndian inNess,char *inDir,
514                             const trpgMatTable &inMatTable,const trpgTexTable &inTexTable,bool separateGeoTyp)
515 {
516     ness = inNess;
517     strcpy(dir,inDir);
518     this->separateGeoTyp = separateGeoTyp;
519     matTable = &inMatTable;
520     texTable = &inTexTable;
521 
522     // Set up the texture cache
523     // It doesn't do anything until it's called anyway
524     char fullBase[1024];
525     sprintf(fullBase,"%s" PATHSEPERATOR "texFile",dir);
526     texCache = GetNewRAppFileCache(fullBase,"txf");
527     if(separateGeoTyp) {
528         sprintf(fullBase,"%s" PATHSEPERATOR "geotypFile",dir);
529         geotypCache = GetNewRAppFileCache(fullBase,"txf");
530     }
531     else {
532         geotypCache = texCache;
533     }
534 
535 }
536 
~trpgrImageHelper()537 trpgrImageHelper::~trpgrImageHelper()
538 {
539     if (texCache) {
540         delete texCache;
541         texCache = NULL;
542     }
543     if(separateGeoTyp && geotypCache) {
544         delete geotypCache;
545         geotypCache = NULL;
546     }
547 }
548 
GetNewRAppFileCache(const char * fullBase,const char *)549 trpgrAppFileCache* trpgrImageHelper::GetNewRAppFileCache(const char *fullBase,const char* /*ext*/)
550 {
551     return new trpgrAppFileCache(fullBase,"txf");
552 }
553 
GetLocalGL(const trpgTexture * tex,char * data,int32 size)554 bool trpgrImageHelper::GetLocalGL(const trpgTexture *tex,char *data,int32 size)
555 {
556     // Make sure the texture is Local
557     trpgTexture::ImageMode mode;
558     tex->GetImageMode(mode);
559     if (mode != trpgTexture::Local)
560         return false;
561 
562     // Fetch data data
563     trpgwAppAddress addr;
564     tex->GetImageAddr(addr);
565     trpgrAppFile *af = geotypCache->GetFile(ness,addr.file,addr.col,addr.row);
566     if (!af)
567         return false;
568     if (!af->Read(data,addr.offset,0,size))
569         return false;
570 
571     return true;
572 }
573 
GetMipLevelLocalGL(int miplevel,const trpgTexture * tex,char * data,int32 dataSize)574 bool trpgrImageHelper::GetMipLevelLocalGL(int miplevel, const trpgTexture *tex,char *data,int32 dataSize)
575 {
576     if ( miplevel >= tex->CalcNumMipmaps() || miplevel < 0 )
577         return false;
578 
579     // Make sure the texture is Local
580     trpgTexture::ImageMode mode;
581     tex->GetImageMode(mode);
582     if (mode != trpgTexture::Local)
583         return false;
584 
585     // Fetch data data
586     trpgwAppAddress addr;
587     tex->GetImageAddr(addr);
588     trpgrAppFile *af = texCache->GetFile(ness,addr.file,addr.col,addr.row);
589     if (!af)
590         return false;
591 
592     int level_offset = (const_cast<trpgTexture*>(tex))->MipLevelOffset(miplevel);
593     if (!af->Read(data,addr.offset,level_offset,dataSize))
594         return false;
595 
596     return true;
597 }
598 
599 
GetImageInfoForLocalMat(const trpgLocalMaterial * locMat,const trpgMaterial ** retMat,const trpgTexture ** retTex,int & totSize)600 bool trpgrImageHelper::GetImageInfoForLocalMat(const trpgLocalMaterial *locMat,
601                                                const trpgMaterial **retMat,const trpgTexture **retTex,int &totSize)
602 {
603     return GetNthImageInfoForLocalMat(locMat, 0, retMat, retTex, totSize);
604 }
605 
GetNthImageInfoForLocalMat(const trpgLocalMaterial * locMat,int index,const trpgMaterial ** retMat,const trpgTexture ** retTex,int & totSize)606 bool trpgrImageHelper::GetNthImageInfoForLocalMat(const trpgLocalMaterial *locMat, int index,
607                                                   const trpgMaterial **retMat,const trpgTexture **retTex,int &totSize)
608 {
609     // Get the base material for the Local Material
610     int32 matSubTable,matID;
611     locMat->GetBaseMaterial(matSubTable,matID);
612     // For right now, force the subtable number to match the index.
613     // Eventually, either store multiple base materials for each local material,
614     // or overhaul this in some other fashion.
615     int numTables;
616     if (!matTable->GetNumTable(numTables))
617         return false;
618     if (index>=numTables)
619         return false;
620     if (index>0) matSubTable=index; // otherwise, leave it alone - could be nonzero
621     const trpgMaterial *mat = matTable->GetMaterialRef(matSubTable,matID);
622     if (!mat)
623         return false;
624 
625     // Now get the texture (always the first one)
626     trpgTextureEnv texEnv;
627     int32 texID;
628     if (!mat->GetTexture(0,texID,texEnv))
629         return false;
630     const trpgTexture *tex = texTable->GetTextureRef(texID);
631     if (!tex)
632         return false;
633 
634     totSize = tex->CalcTotalSize();
635 
636     *retTex = tex;
637     *retMat = mat;
638     return true;
639 }
640 
GetImageForLocalMat(const trpgLocalMaterial * locMat,char * data,int dataSize)641 bool trpgrImageHelper::GetImageForLocalMat(const trpgLocalMaterial *locMat,char *data,int dataSize)
642 {
643     return GetNthImageForLocalMat(locMat, 0, data, dataSize);
644 }
645 
GetNthImageForLocalMat(const trpgLocalMaterial * locMat,int index,char * data,int dataSize)646 bool trpgrImageHelper::GetNthImageForLocalMat(const trpgLocalMaterial *locMat,int index, char *data,int dataSize)
647 {
648     if (!locMat->isValid())
649         return false;
650 
651     const trpgMaterial *mat;
652     const trpgTexture *tex;
653     int totSize;
654     if (!GetNthImageInfoForLocalMat(locMat,index,&mat,&tex,totSize))
655         return false;
656 
657     // Determine the type
658     trpgTexture::ImageMode imageMode;
659     tex->GetImageMode(imageMode);
660     switch (imageMode) {
661     case trpgTexture::Template:
662     {
663         // Read the image data out of the Local image (in an archive somewhere)
664         trpgwAppAddress addr;
665         if (!locMat->GetNthAddr(index,addr)) return false;
666         trpgrAppFile *af = texCache->GetFile(ness,addr.file,addr.col,addr.row);
667         if (!af)
668             return false;
669         if (!af->Read(data,addr.offset,0,dataSize))
670             return false;
671     }
672     break;
673     case trpgTexture::Global:
674         // Note: Not dealing with Global textures yet
675         return false;
676         break;
677     default:
678         // This is not a valid Local Material
679         return false;
680     };
681 
682     return true;
683 }
684 
GetMipLevelForLocalMat(int miplevel,const trpgLocalMaterial * locMat,char * data,int dataSize)685 bool trpgrImageHelper::GetMipLevelForLocalMat(int miplevel, const trpgLocalMaterial *locMat,char *data,int dataSize)
686 {
687     return GetNthImageMipLevelForLocalMat(miplevel, locMat, 0, data, dataSize);
688 }
689 
GetNthImageMipLevelForLocalMat(int miplevel,const trpgLocalMaterial * locMat,int index,char * data,int dataSize)690 bool trpgrImageHelper::GetNthImageMipLevelForLocalMat(int miplevel, const trpgLocalMaterial *locMat, int index, char *data,int dataSize)
691 {
692     if (index>0) return false; // not yet, folks, if ever.  index>1 means sensors for now.
693     if (!locMat->isValid()) return false;
694 
695     const trpgMaterial *mat;
696     const trpgTexture *tex;
697     int totSize;
698     if (!GetNthImageInfoForLocalMat(locMat,index,&mat,&tex,totSize))
699         return false;
700 
701     if ( miplevel >= tex->CalcNumMipmaps() || miplevel < 0 )
702         return false;
703 
704     // Determine the type
705     trpgTexture::ImageMode imageMode;
706     tex->GetImageMode(imageMode);
707     switch (imageMode) {
708     case trpgTexture::Template:
709     {
710         // Read the image data out of the Local image (in an archive somewhere)
711         trpgwAppAddress addr;
712         if (!locMat->GetNthAddr(index,addr)) return false;
713         trpgrAppFile *af = texCache->GetFile(ness,addr.file,addr.col,addr.row);
714         if (!af)  return false;
715 
716         int level_offset = (const_cast<trpgTexture*>(tex))->MipLevelOffset(miplevel);
717         if (!af->Read(data,addr.offset,level_offset,dataSize))
718             return false;
719     }
720     break;
721     case trpgTexture::Global:
722         // Note: Not dealing with Global textures yet
723         return false;
724         break;
725     default:
726         // This is not a valid Local Material
727         return false;
728     };
729 
730     return true;
731 }
732 
GetImagePath(const trpgTexture * tex,char * fullPath,int pathLen)733 bool trpgrImageHelper::GetImagePath(const trpgTexture *tex,char *fullPath,int pathLen)
734 {
735     char name[1024];
736     int nameLen=1024;
737     tex->GetName(name,nameLen);
738     nameLen = strlen(name);
739 
740     if (static_cast<int>(strlen(dir)) + nameLen + 2 > pathLen)
741         return false;
742 
743     sprintf(fullPath,"%s" PATHSEPERATOR "%s",dir,name);
744 
745     return true;
746 }
747