root/OpenSceneGraph/trunk/src/osgPlugins/txp/trpage_warchive.cpp @ 13041

Revision 13041, 44.3 kB (checked in by robert, 2 years ago)

Ran script to remove trailing spaces and tabs

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
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_warchive.cpp
23   This source file contains the implementations of trpgwArchive and trpgwGeomHelper.
24   The Write Archive is used to write TerraPage archives.  All its important methods
25   are virtual, so you shouldn't need to modify any of this code.  Simply subclass
26   and override.
27   The Geometry Helper is a class that's used to sort out polygons and build
28   trpgGeometry objects, containing triangle strips and fans out of them.  The one
29   contained here is fairly simple, but all its important methods are virtual.  So
30   again, subclass and override if you need to change them.
31*/
32
33#include <trpage_geom.h>
34#include <trpage_write.h>
35#include <trpage_compat.h>
36#include <trpage_read.h>
37
38// Constructor
39trpgwArchive::trpgwArchive(trpgEndian inNess,trpgwArchive::TileMode inTileMode,int majorVer, int minorVer)
40{
41    Init(inNess,inTileMode,majorVer, minorVer);
42}
43
44void trpgwArchive::Init(trpgEndian inNess, trpgwArchive::TileMode inTileMode,int majorVer, int minorVer)
45{
46    minorVersion = minorVer;
47    majorVersion = majorVer;
48    if (majorVersion < 1  || majorVersion >  TRPG_VERSION_MAJOR)
49        throw 1;
50    if(majorVersion == TRPG_VERSION_MAJOR)
51    {
52        if(minorVersion < 0 || minorVersion > TRPG_VERSION_MINOR)
53            throw 1;
54    }
55
56    fp = NULL;
57    strcpy(dir,".");
58    ness = inNess;
59    tileMode = inTileMode;
60    cpuNess = trpg_cpu_byte_order();
61    tileFile = NULL;
62    tileFileCount = 0;
63    isRegenerate = false;
64    maxTileFileLen = -1;
65
66    firstHeaderWrite = true;
67}
68
69// Constructor for regenerate
70trpgwArchive::trpgwArchive(char *inDir,char *inFile,trpg2dPoint &sw, trpg2dPoint &ne, int majorVer, int minorVer)
71{
72    Init(inDir,inFile,sw,ne, majorVer, minorVer);
73}
74
75void trpgwArchive::Init(char *inDir,char *inFile,trpg2dPoint &sw, trpg2dPoint &ne, int majorVer, int minorVer)
76{
77    maxTileFileLen = -1;
78    majorVersion = majorVer;
79    minorVersion = minorVer;
80    fp = NULL;
81    strcpy(dir,inDir);
82    cpuNess = trpg_cpu_byte_order();
83    tileFile = NULL;
84    tileFileCount = 0;
85    isRegenerate = true;
86    errMess[0] = '\0';
87
88    firstHeaderWrite = true;
89
90    // TODO: have a "setup from file" method for trpgwArchive
91
92    // Open a Read Archive to get the rest of the info we need
93    trpgr_Archive *inArch = this->GetArchiveReader();
94    inArch->SetDirectory(inDir);
95    if (!inArch->OpenFile(inFile))
96    {
97        delete inArch;
98        throw 1;
99    }
100    // Get the header (this is what we need)
101    if (!inArch->ReadHeader())
102    {
103        delete inArch;
104        throw 1;
105    }
106
107    ness = inArch->GetEndian();
108    const trpgHeader *inHeader = inArch->GetHeader();
109
110    // use the version in the archive instead.
111    inHeader->GetVersion(majorVersion,minorVersion);
112
113    // Expand the coverage
114    trpg2dPoint newSW,newNE;
115    trpg2dPoint oldSW,oldNE;
116
117    // Or not.  Have to add in something to avoid recalculation
118    // when merging geocentric databases.  We don't really support
119    // them, and everything goes to hell.  So: hack is:
120    // if sw=ne, don't change anything.
121    // This will also help a little with MMB TXP merge speed.
122
123    bool extentsUnchanged=false;
124    inHeader->GetExtents(oldSW,oldNE);
125    // just checking for equality right now.  Bad?
126    if ((sw==ne) || ((oldSW==sw) && (oldNE==ne)))
127    {
128        extentsUnchanged = true;
129        // set up passed-in SW and NE as well.
130        sw=newSW=oldSW;
131        ne=newNE=oldNE;
132    }
133    else
134    {
135        newSW.x = MIN(sw.x,oldSW.x);
136        newSW.y = MIN(sw.y,oldSW.y);
137        newNE.x = MAX(ne.x,oldNE.x);
138        newNE.y = MAX(ne.y,oldNE.y);
139    }
140
141    // Decide what the offset should be for new tiles
142    if (!extentsUnchanged)
143    {
144        trpg2dPoint blockSize;
145        inHeader->GetTileSize(0,blockSize);
146        double dx = (oldSW.x - newSW.x)/blockSize.x + 10e-10;
147        double dy = (oldSW.y - newSW.y)/blockSize.y + 10e-10;
148        addOffset.x = (int)dx;
149        addOffset.y = (int)dy;
150        if (dx - addOffset.x > 10e-4 ||
151            dy - addOffset.y > 10e-4) {
152            delete inArch;
153            throw 1;
154        }
155    }
156
157    // Header can mostly stay the same
158    header = *inHeader;
159    header.SetExtents(newSW,newNE);
160    header.GetNumLods(numLod);
161    // Update to the new MBR and tile grid sizes
162    if (!extentsUnchanged) {
163        for (int i=0;i<numLod;i++) {
164            // Figure out the tile grid size
165            trpg2dPoint tileSize;
166            inHeader->GetTileSize(i,tileSize);
167            trpg2iPoint newTileExt;
168            newTileExt.x = int((newNE.x - newSW.x)/tileSize.x + 10e-5);
169            newTileExt.y = int((newNE.y - newSW.y)/tileSize.y + 10e-15);
170            header.SetLodSize(i,newTileExt);
171        }
172    }
173
174    // These tables we can copy straight over
175    matTable = *inArch->GetMaterialTable();
176    texTable = *inArch->GetTexTable();
177    modelTable = *inArch->GetModelTable();
178
179    lightTable = *inArch->GetLightTable();
180    rangeTable = *inArch->GetRangeTable();
181    textStyleTable = *inArch->GetTextStyleTable();
182    supportStyleTable = *inArch->GetSupportStyleTable();
183    labelPropertyTable = *inArch->GetLabelPropertyTable();
184
185    // Need to resize the tile table (maybe)
186    // NOTE: Starting with version 2.1, the tile tables will contain only
187    // the lod 0 tiles
188    trpgTileTable::TileMode tileTableMode;
189    if (!extentsUnchanged) {
190        const trpgTileTable *oldTiles = inArch->GetTileTable();
191        oldTiles->GetMode(tileTableMode);
192        tileTable.SetMode(tileTableMode);
193        if(majorVersion == 2 && minorVersion >=1)
194        {
195            // Version 2.1. we store only lod 0, all other lod tiles are
196            // stored in the parent tile
197            tileTable.SetNumLod(0);
198            // Size the output tile table
199            trpg2iPoint tileSize;
200            header.GetLodSize(0,tileSize);
201            tileTable.SetNumTiles(tileSize.x, tileSize.y, 0);
202
203            // Copy over individual tiles
204            trpg2iPoint levelOffset;
205            levelOffset.x = addOffset.x;
206            levelOffset.y = addOffset.y;
207            trpg2iPoint oldTileSize;
208            inHeader->GetLodSize(0, oldTileSize);
209            for (int ix=0;ix<oldTileSize.x;ix++) {
210                for (int iy=0;iy<oldTileSize.y;iy++) {
211                    trpgwAppAddress addr;
212                    float zmin,zmax;
213                    oldTiles->GetTile(ix, iy, 0,addr,zmin,zmax);
214                    tileTable.SetTile(ix+addOffset.x, iy+addOffset.y ,0, addr, zmin, zmax);
215                }
216            }
217
218        }
219        else
220        {
221            tileTable.SetNumLod(numLod);
222            for (int lod=0;lod<numLod;lod++) {
223                // Size the output tile table
224                trpg2iPoint tileSize;
225                header.GetLodSize(lod,tileSize);
226                tileTable.SetNumTiles(tileSize.x,tileSize.y,lod);
227
228                // Copy over individual tiles
229                trpg2iPoint levelOffset;
230                levelOffset.x = addOffset.x*(lod+1);
231                levelOffset.y = addOffset.y*(lod+1);
232                trpg2iPoint oldTileSize;
233                inHeader->GetLodSize(lod,oldTileSize);
234                for (int ix=0;ix<oldTileSize.x;ix++) {
235                    for (int iy=0;iy<oldTileSize.y;iy++) {
236                        trpgwAppAddress addr;
237                        float zmin,zmax;
238                        oldTiles->GetTile(ix,iy,lod,addr,zmin,zmax);
239                        tileTable.SetTile(ix+addOffset.x,iy+addOffset.y,lod,addr,zmin,zmax);
240                    }
241                }
242            }
243        }
244    } else {
245        tileTable = *inArch->GetTileTable();
246        tileTable.GetMode(tileTableMode);
247    }
248
249    // Continue to work in the mode the original database is in
250    switch(tileTableMode)
251    {
252    case trpgTileTable::Local:
253        tileMode = TileLocal;
254        break;
255    case trpgTileTable::External:
256        tileMode = TileExternal;
257        break;
258    case trpgTileTable::ExternalSaved:
259        tileMode = TileExternalSaved;
260        break;
261    }
262
263
264    // That's it for the read archive
265    delete inArch;
266}
267
268// Destructor
269trpgwArchive::~trpgwArchive()
270{
271    if (fp)
272        fclose(fp);
273    if (tileFile) {
274        delete tileFile;
275        tileFile = NULL;
276    }
277}
278
279// WriteHeaderData
280int32 trpgwArchive::WriteHeaderData(const char *dataPtr, int length, FILE* /*filehandle*/)
281{
282    return fwrite(dataPtr,1,length,fp);
283}
284
285// IsValid()
286// Verifies that our file is open
287bool trpgwArchive::isValid() const
288{
289    if (!fp)
290    {
291        strcpy(errMess, "File object do not exist");
292        return false;
293    }
294
295    return true;
296}
297
298const char *trpgwArchive::getErrMess() const
299{
300    if(errMess[0] == '\0')
301        return 0;
302    else
303        return &errMess[0];
304}
305
306// Set the maximum advised size for a tile file
307
308void trpgwArchive::SetMaxTileFileLength(int max)
309{
310    maxTileFileLen = max;
311}
312
313/* Set Functions
314   These just copy tables and the header from the input.
315   If these aren't set, then empty ones are written.
316*/
317bool trpgwArchive::SetHeader(const trpgHeader &head)
318{
319    header = head;
320    return true;
321}
322bool trpgwArchive::SetMaterialTable(const trpgMatTable &mat)
323{
324    matTable = mat;
325    return true;
326}
327bool trpgwArchive::SetTextureTable(const trpgTexTable &tex)
328{
329    texTable = tex;
330    return true;
331}
332bool trpgwArchive::SetModelTable(const trpgModelTable &models)
333{
334    modelTable = models;
335    return true;
336}
337bool trpgwArchive::SetLightTable(const trpgLightTable &lights)
338{
339    lightTable = lights;
340    return true;
341}
342bool trpgwArchive::SetRangeTable(const trpgRangeTable &ranges)
343{
344    rangeTable = ranges;
345    return true;
346}
347
348bool trpgwArchive::SetTextStyleTable(const trpgTextStyleTable &styles)
349{
350    textStyleTable = styles;
351    return true;
352}
353
354bool trpgwArchive::SetLabelPropertyTable(const trpgLabelPropertyTable &properties)
355{
356    labelPropertyTable = properties;
357    return true;
358}
359bool trpgwArchive::SetSupportStyleTable(const trpgSupportStyleTable &styles)
360{
361
362    supportStyleTable = styles;
363    return true;
364}
365
366
367/* Get Methods
368   Used in regenerate.
369*/
370trpgHeader *trpgwArchive::GetHeader()
371{
372    return &header;
373}
374trpgMatTable *trpgwArchive::GetMatTable()
375{
376    return &matTable;
377}
378trpgTexTable *trpgwArchive::GetTextureTable()
379{
380    return &texTable;
381}
382trpgModelTable *trpgwArchive::GetModelTable()
383{
384    return &modelTable;
385}
386trpgLightTable *trpgwArchive::GetLightTable()
387{
388    return &lightTable;
389}
390trpgRangeTable *trpgwArchive::GetRangeTable()
391{
392    return &rangeTable;
393}
394trpgTextStyleTable *trpgwArchive::GetTextStyleTable()
395{
396    return &textStyleTable;
397}
398trpgSupportStyleTable *trpgwArchive::GetSupportStyleTable()
399{
400    return &supportStyleTable;
401}
402trpgLabelPropertyTable *trpgwArchive::GetLabelPropertyTable()
403{
404    return &labelPropertyTable;
405}
406
407// OpenFile
408// Same as above, only gets a basename as well
409bool trpgwArchive::OpenFile(const char *in_dir,const char *name)
410{
411    char filename[1024];
412
413    strncpy(dir,in_dir,1023);
414
415    sprintf(filename,"%s" PATHSEPERATOR "%s",dir,name);
416
417    if (!(fp = osgDB::fopen(filename,"wb")))
418        return false;
419
420    return true;
421}
422
423// CloseFile
424// Close the open file
425void trpgwArchive::CloseFile()
426{
427    if (fp)
428        fclose(fp);
429
430    fp = NULL;
431}
432
433/* Write Header
434   Flush out the header (checkpoint) and return.
435*/
436bool trpgwArchive::WriteHeader()
437{
438    bool ret = CheckpointHeader();
439
440    if (tileFile) {
441        delete tileFile;
442        tileFile=NULL;
443    }
444
445    return ret;
446}
447
448/* CheckpointHeader
449   The header lives in its own file, so we can write it at any point we
450   have a valid archive.
451   This includes all the tables, as well as basic header info.
452*/
453bool trpgwArchive::CheckpointHeader()
454{
455    trpgMemWriteBuffer buf(ness);
456
457    if (!isValid())
458        return false;
459
460    if (!header.isValid())
461    {
462        if(header.getErrMess())
463            strcpy(errMess, header.getErrMess());
464        return false;
465    }
466
467    // This will close the appendable files
468    if (tileFile) {
469        tileFile->Flush();
470    }
471
472    /* Build a Tile Table
473       We need to build one from scratch here.  However,
474       we have all the relevant information collected during
475       the WriteTile calls.
476    */
477
478
479    if(header.GetIsLocal()) {
480        int row = 0;
481        int col = 0;
482        header.GetBlocks(row,col);
483        tileTable.SetCurrentBlock(row,col,true);
484    }
485    if (tileMode == TileExternal) {
486        // External tiles are easy
487        tileTable.SetMode(trpgTileTable::External);
488    } else if( tileMode == TileExternalSaved) {
489
490        if(!isRegenerate && firstHeaderWrite)
491        {
492            // Set up the sizes
493            tileTable.SetMode(trpgTileTable::ExternalSaved);
494            tileTable.SetNumLod(1);
495            trpg2iPoint lodSize;
496            header.GetLodSize(0,lodSize);
497            tileTable.SetNumTiles(lodSize.x, lodSize.y, 0);
498            firstHeaderWrite = false;
499        }
500
501        // Now set the individual tile locations
502        for (unsigned int i=0;i<externalTiles.size();i++) {
503            TileFileEntry &te = externalTiles[i];
504            trpgwAppAddress addr;
505            addr.file = -1;
506            addr.offset = -1;
507            tileTable.SetTile(te.x,te.y,te.lod,addr,te.zmin,te.zmax);
508        }
509
510        externalTiles.clear();
511
512    } else {
513        if (!isRegenerate && firstHeaderWrite) {
514
515            // Local tiles require more work
516            tileTable.SetMode(trpgTileTable::Local);
517
518            if(majorVersion == 2 && minorVersion >= 1)
519            {
520                // Version 2.1, we store only lod 0 in the tile table
521
522                // Set up the sizes
523                tileTable.SetNumLod(1);
524                trpg2iPoint lodSize;
525                header.GetLodSize(0,lodSize);
526                tileTable.SetNumTiles(lodSize.x, lodSize.y, 0);
527
528            }
529            else
530            {
531
532                // Set up the sizes
533                int32 numLod;
534                header.GetNumLods(numLod);
535                tileTable.SetNumLod(numLod);
536                for (int i=0;i<numLod;i++) {
537                    trpg2iPoint lodSize;
538                    header.GetLodSize(i,lodSize);
539                    tileTable.SetNumTiles(lodSize.x,lodSize.y,i);
540                }
541
542            }
543            firstHeaderWrite = false;
544        }
545
546
547        // Now set the individual tile locations
548        // Nothing special need to be done with version 2.1 since
549        // only tile with lod 0 will be found in the tileFiles container
550        for (unsigned int i=0;i<tileFiles.size();i++) {
551            TileFile &tf = tileFiles[i];
552            for (unsigned int j=0;j<tf.tiles.size();j++) {
553                TileFileEntry &te = tf.tiles[j];
554                trpgwAppAddress addr;
555                addr.file = tf.id;
556                addr.offset = te.offset;
557                tileTable.SetTile(te.x,te.y,te.lod,addr,te.zmin,te.zmax);
558            }
559
560            tf.tiles.clear();
561
562
563        }
564    }
565
566
567    // Write all the headers into a buffer
568    if (!header.Write(buf))
569        return false;
570
571    // Do the mat table and texture table
572    // These can be different depending on the version
573    switch (majorVersion) {
574    case 1:
575    {
576        trpgMatTable1_0 matTable1_0(matTable);
577        trpgTexTable1_0 texTable1_0(texTable);
578        trpgTileTable1_0 tileTable1_0(tileTable);
579
580        if (!matTable1_0.Write(buf) ||
581            !texTable1_0.Write(buf) ||
582            !modelTable.Write(buf) ||
583            !tileTable1_0.Write(buf) ||
584            !lightTable.Write(buf) ||
585            !rangeTable.Write(buf))
586            return false;
587    }
588    break;
589    case 2:
590        if(!header.GetIsMaster()||texTable.isValid()) {
591            if(!texTable.Write(buf))
592            {
593                strcpy(errMess, "Error writing texture table");
594                if(texTable.getErrMess())
595                {
596                    strcat(errMess, ": ");
597                    strcat(errMess, texTable.getErrMess());
598                    return false;
599                }
600            }
601        }
602        //These tables will not be populated if this is the master table.
603        if(!header.GetIsMaster()) {
604            if (!matTable.Write(buf))
605            {
606                strcpy(errMess, "Error writing material table");
607                if(matTable.getErrMess())
608                {
609                    strcat(errMess, ": ");
610                    strcat(errMess, matTable.getErrMess());
611                    return false;
612                }
613            }
614
615
616            if(!modelTable.Write(buf) )
617            {
618                strcpy(errMess, "Error writing model table");
619                if(modelTable.getErrMess())
620                {
621                    strcat(errMess, ": ");
622                    strcat(errMess, modelTable.getErrMess());
623                    return false;
624                }
625            }
626        }
627        //always write the tile table, even if we are a master
628        if(!tileTable.Write(buf))
629        {
630            strcpy(errMess, "Error writing tile table");
631            if(tileTable.getErrMess())
632            {
633                strcat(errMess, ": ");
634                strcat(errMess, tileTable.getErrMess());
635                return false;
636            }
637        }
638        if(!header.GetIsMaster()) {
639            if(!lightTable.Write(buf))
640            {
641                strcpy(errMess, "Error writing light table");
642                if(lightTable.getErrMess())
643                {
644                    strcat(errMess, ": ");
645                    strcat(errMess, lightTable.getErrMess());
646                    return false;
647                }
648            }
649            if(!rangeTable.Write(buf))
650            {
651                strcpy(errMess, "Error writing range table");
652                if(rangeTable.getErrMess())
653                {
654                    strcat(errMess, ": ");
655                    strcat(errMess, rangeTable.getErrMess());
656                    return false;
657                }
658            }
659            if (!textStyleTable.Write(buf))
660            {
661                strcpy(errMess,"Error writing text style table");
662                if (textStyleTable.getErrMess())
663                {
664                    strcat(errMess, ": ");
665                    strcat(errMess, textStyleTable.getErrMess());
666                    return false;
667                }
668            }
669            if (!supportStyleTable.Write(buf))
670            {
671                strcpy(errMess,"Error writing support style table");
672                if (supportStyleTable.getErrMess())
673                {
674                    strcat(errMess, ": ");
675                    strcat(errMess, supportStyleTable.getErrMess());
676                    return false;
677                }
678            }
679            if (!labelPropertyTable.Write(buf))
680            {
681                strcpy(errMess,"Error writing label property table");
682                if (labelPropertyTable.getErrMess())
683                {
684                    strcat(errMess, ": ");
685                    strcat(errMess, labelPropertyTable.getErrMess());
686                    return false;
687                }
688            }
689        }
690        break;
691    }
692
693    // Write the disk header
694    int32 magic = GetMagicNumber();
695    if (ness != cpuNess)
696        magic = trpg_byteswap_int(magic);
697    if (fwrite(&magic,sizeof(int32),1,fp) != 1)
698    {
699        strcpy(errMess, "Could not write the magic number");
700        return false;
701    }
702
703    // Write the header length
704    int32 headerSize = buf.length();
705    int headLen = headerSize;
706    if (ness != cpuNess)
707        headerSize = trpg_byteswap_int(headerSize);
708    if (fwrite(&headerSize,1,sizeof(int32),fp) != sizeof(int32))
709    {
710        strcpy(errMess, "Could not write the header size");
711        return false;
712    }
713
714    // Write the buffer
715    const char *data = buf.getData();
716
717    if (WriteHeaderData(data,headLen,fp) != headLen)
718    {
719        strcpy(errMess, "Could not write the buffer");
720        return false;
721    }
722
723    // Note: Not sure what this is
724    char space[40];
725    if (fwrite(space,1,4,fp) != 4)
726        return false;
727
728    // Flush output
729    fflush(fp);
730    // Head back to the start of the file
731    rewind(fp);
732
733    return true;
734}
735
736/* Get a new appendable file.
737 */
738
739trpgwAppFile *trpgwArchive::GetNewWAppFile(trpgEndian inNess,const char *fileName,bool reuse)
740{
741    return new trpgwAppFile(inNess,fileName,reuse);
742}
743
744/* Get a new write image helper
745 */
746trpgwImageHelper *trpgwArchive::GetNewWImageHelper(trpgEndian ness,char *dir,trpgTexTable &inTexTable)
747{
748    bool separateGeo = false;
749    int majorVer,minorVer;
750    GetHeader()->GetVersion(majorVer,minorVer);
751    if((majorVer >= TRPG_NOMERGE_VERSION_MAJOR) && (minorVer>=TRPG_NOMERGE_VERSION_MINOR)) {
752        separateGeo = true;
753    }
754    return new trpgwImageHelper(ness,dir,inTexTable,separateGeo);
755}
756
757/* Increment Tile File.
758   Close the current tile file (if any) and open the next one.
759   Also update the records we're keeping of which tiles went in
760   which files.
761*/
762bool trpgwArchive::IncrementTileFile()
763{
764    if (tileMode != TileLocal)
765        return false;
766
767    // Closes the current tile file
768    if (tileFile) {
769        delete tileFile;
770        tileFile=NULL;
771    }
772
773    // Open the next one
774    char filename[1024];
775    sprintf(filename,"%s" PATHSEPERATOR "tileFile_%d.tpf",dir,tileFileCount++);
776    tileFile = GetNewWAppFile(ness,filename,true);
777    if (!tileFile->isValid())
778        return false;
779
780    // Add another TileFiles entry
781    tileFiles.resize(tileFiles.size()+1);
782    tileFiles[tileFiles.size()-1].id = tileFiles.size()-1;
783
784    return true;
785}
786
787/* Designate Tile File
788   Close the current tile file (if any) and open one with the
789   given base name.  This is used for regenerate.
790*/
791bool trpgwArchive::DesignateTileFile(int id)
792{
793    if (tileMode != TileLocal)
794        return false;
795
796    // Close the current tile file
797    if (tileFile) {
798        delete tileFile;
799        tileFile=NULL;
800    }
801
802    // Open a named on
803    char filename[1024];
804    sprintf(filename,"%s" PATHSEPERATOR "tileFile_%d.tpf",dir,id);
805    tileFile = GetNewWAppFile(ness,filename);
806    if (!tileFile->isValid())
807        return false;
808
809    // Add another TileFiles entry
810    tileFiles.resize(tileFiles.size()+1);
811    tileFiles[tileFiles.size()-1].id = id;
812
813    return true;
814}
815
816/* WriteTile.
817   Write the given tile (x,y,lod) in the appropriate mode (Local or External).
818   The tile header is given separately from the rest of the tile, but they are
819   appended together to the file.
820*/
821bool trpgwArchive::WriteTile(unsigned int x,unsigned int y,unsigned int lod, float zmin, float zmax,
822                             const trpgMemWriteBuffer *head,const trpgMemWriteBuffer *buf, int32& fileId, int32& fileOffset)
823{
824    FILE *tfp=NULL;
825
826    if (!isValid())
827        return false;
828
829    fileId = -1;
830    fileOffset = -1;
831
832    // External tiles get their own individual files
833    if (tileMode == TileExternal || tileMode == TileExternalSaved) {
834        // Make a new filename
835        char filename[1024];
836        // Note: Windows specific
837        sprintf(filename,"%s" PATHSEPERATOR "tile_%d_%d_%d.tpt",dir,x,y,lod);
838        if (!(tfp = osgDB::fopen(filename,"wb")))
839            return false;
840
841        // Write the header first
842        unsigned int len;
843        const char *data;
844        if (head) {
845            data = head->getData();
846            len = head->length();
847            if (fwrite(data,sizeof(char),len,tfp) != len) {
848                fclose(tfp);
849                return false;
850            }
851        }
852
853        // Write the buffer out
854        data = buf->getData();
855        len = buf->length();
856        if (fwrite(data,sizeof(char),len,tfp) != len) {
857            fclose(tfp);
858            return false;
859        }
860        fclose(tfp);
861
862        // In version 2.1 and over we still add an entry to the tile table
863        // to save the zmin and zmax value.
864        if(tileMode == TileExternalSaved && lod == 0)
865        {
866            externalTiles.push_back(TileFileEntry());
867            TileFileEntry& tf = externalTiles.back();
868            tf.x = x;
869            tf.y = y;
870            tf.lod = lod;
871            tf.offset = -1;
872            tf.zmax = zmax;
873            tf.zmin = zmin;
874        }
875
876    } else {
877        // Local tiles get appended to a tile file
878        if (!tileFile) {
879            if (!IncrementTileFile())
880                return false;
881        }
882        // See if we've exceeded the maximum advised size for a tile file
883        while (maxTileFileLen > 0 && tileFile->GetLengthWritten() > maxTileFileLen) {
884            if (!IncrementTileFile())
885                return false;
886        }
887
888        int32 pos = static_cast<int32>(tileFile->Pos());
889        if (!tileFile->Append(head,buf))
890            return false;
891        // Keep track of the fact that this went here
892        TileFile &tf = tileFiles[tileFiles.size()-1];
893        TileFileEntry te;
894        te.x = x;  te.y = y;  te.lod = lod;
895        te.zmin = zmin;  te.zmax = zmax;  te.offset = pos;
896        if(majorVersion == 2 && minorVersion >=1)
897        {
898            // Version 2.1, we need to keep track of lod 0 only
899            if(lod == 0)
900                tf.tiles.push_back(te);
901        }
902        else
903            tf.tiles.push_back(te);
904
905        fileOffset = pos;
906
907        fileId = tileFiles[tileFiles.size()-1].id;
908    }
909
910    return true;
911}
912
913/*  ****************
914    Geometry Stats
915    Used by the Geometry Helper
916    ****************
917    */
918trpgwGeomStats::trpgwGeomStats()
919{
920    totalTri = totalStripTri = totalFanTri = totalBagTri = 0;
921    for (int i=0;i<15;i++) {
922        stripStat[i] = fanStat[i] = 0;
923    }
924    stripGeom = fanGeom = bagGeom = 0;
925    stateChanges = 0;
926    numStrip = numFan = 0;
927    totalQuad = 0;
928}
929trpgwGeomStats::~trpgwGeomStats()
930{
931}
932
933/*  ****************
934    Geometry Helper
935    Here, since it's used with a write archive.
936    ****************
937    */
938trpgwGeomHelper::trpgwGeomHelper()
939{
940    buf = NULL;
941    mode = trpgGeometry::Triangles;
942}
943trpgwGeomHelper::~trpgwGeomHelper()
944{
945}
946void trpgwGeomHelper::SetMode(int m)
947{
948    if (m == trpgGeometry::Triangles || m == trpgGeometry::Quads)
949        mode = m;
950}
951trpgwGeomHelper::trpgwGeomHelper(trpgWriteBuffer *ibuf, int dtype)
952{
953    init(ibuf,dtype);
954}
955void trpgwGeomHelper::init(trpgWriteBuffer *ibuf,int dtype)
956{
957    buf = ibuf;
958    dataType = dtype;
959    zmin = 1e12;
960    zmax = -1e12;
961}
962// Reset back to a clean state (except for the buffer)
963void trpgwGeomHelper::Reset()
964{
965    ResetTri();
966    ResetPolygon();
967    zmin = 1e12;
968    zmax = -1e12;
969}
970
971// Reset triangle arrays (usually after a flush)
972void trpgwGeomHelper::ResetTri()
973{
974    strips.Reset();
975    fans.Reset();
976    bags.Reset();
977
978    tex.resize(0);
979    norm.resize(0);
980    vert.resize(0);
981}
982
983// Start a polygon definition
984void trpgwGeomHelper::StartPolygon()
985{
986    ResetPolygon();
987}
988
989// Finish a polygon definition
990void trpgwGeomHelper::EndPolygon()
991{
992    // See if we can add it to the current triangle arrays
993    if (vert.size() && (matTri != matPoly)) {
994        // Couldn't flush geometry and move on
995        FlushGeom();
996    }
997
998    // Turn the polygon into triangles
999    // Note: Only dealing with convex here
1000    matTri = matPoly;
1001    unsigned int numMats=matTri.size();
1002
1003    switch (mode) {
1004    case trpgGeometry::Triangles:
1005    {
1006        int num = polyVert.size() - 2;
1007        int id1,id2;
1008        for (int i=0;i<num;i++) {
1009            // Note: Handle color
1010
1011            /* Swap 1 and 2 positions
1012               This lets the Optimizer pick up on triangle fans
1013               If you're not using our optimizer this will do very weird things
1014               Probably it will screw up backface culling.
1015            */
1016            // Note: turned this off because it was broken.  Put it back
1017#if 0
1018            id1 = i+1;
1019            id2 = i+2;
1020            if (num > 1) {
1021                id1 = i+2;  id2 = i+1;
1022            }
1023#else
1024            id1 = i+1;
1025            id2 = i+2;
1026#endif
1027
1028            // Define the triangle
1029            vert.push_back(polyVert[0]);
1030            vert.push_back(polyVert[id1]);
1031            vert.push_back(polyVert[id2]);
1032
1033            norm.push_back(polyNorm[0]);
1034            norm.push_back(polyNorm[id1]);
1035            norm.push_back(polyNorm[id2]);
1036
1037            // multiple textures
1038            unsigned int loop;
1039            for (loop=0;loop<numMats;loop++) tex.push_back(polyTex[loop]);
1040            for (loop=0;loop<numMats;loop++) tex.push_back(polyTex[numMats*id1+loop]);
1041            for (loop=0;loop<numMats;loop++) tex.push_back(polyTex[numMats*id2+loop]);
1042        }
1043    }
1044    break;
1045    case trpgGeometry::Quads:
1046    {
1047        int num = polyVert.size();
1048        if (polyVert.size() == 4) {
1049            for (int i=0;i<num;i++) {
1050                vert.push_back(polyVert[i]);
1051                norm.push_back(polyNorm[i]);
1052                // multiple textures
1053                for (unsigned int loop=0;loop<numMats;loop++) tex.push_back(polyTex[numMats*i+loop]);
1054            }
1055        }
1056    }
1057    break;
1058    }
1059
1060    ResetPolygon();
1061}
1062
1063// Clean out the polygon arrays
1064void trpgwGeomHelper::ResetPolygon()
1065{
1066    tmpTex.resize(0);
1067    matPoly.resize(0);
1068    polyTex.resize(0);
1069    polyNorm.resize(0);
1070    polyVert.resize(0);
1071}
1072
1073// Set the current color
1074// Note: Required
1075void trpgwGeomHelper::SetColor(trpgColor& /*col*/)
1076{
1077//        tmpColor = col;
1078}
1079
1080// Set the current texture coord
1081// Note: Required
1082void trpgwGeomHelper::SetTexCoord(trpg2dPoint &pt)
1083{
1084    tmpTex.resize(0);
1085    tmpTex.push_back(pt);
1086}
1087
1088void trpgwGeomHelper::AddTexCoord(trpg2dPoint &pt)
1089{
1090    tmpTex.push_back(pt);
1091}
1092
1093// Set the current normal
1094// Note: required
1095void trpgwGeomHelper::SetNormal(trpg3dPoint &pt)
1096{
1097    tmpNorm = pt;
1098}
1099
1100// Set the current material
1101// Note: required
1102void trpgwGeomHelper::SetMaterial(int32 imat)
1103{
1104    matPoly.resize(0);
1105    matPoly.push_back(imat);
1106}
1107
1108void trpgwGeomHelper::AddMaterial(int32 imat)
1109{
1110    matPoly.push_back(imat);
1111}
1112
1113// Get the Z min/max we've collected so far
1114void trpgwGeomHelper::GetZMinMax(double &outZmin,double &outZmax)
1115{
1116    outZmin = zmin;
1117    outZmax = zmax;
1118}
1119
1120// Collect the current vertex data and add a new whole vertex
1121// Note: Deal with color
1122void trpgwGeomHelper::AddVertex(trpg3dPoint &pt)
1123{
1124    polyTex.insert(polyTex.end(),tmpTex.begin(),tmpTex.end());
1125    polyNorm.push_back(tmpNorm);
1126// Note: Turn this back on.  It's not right currently, though
1127#if 0
1128    if (buf->GetEndian() != trpg_cpu_byte_order())
1129    {
1130        trpg3dPoint tmpVert;
1131        tmpVert.x = trpg_byteswap_8bytes_to_double ((char *)&pt.x);
1132        tmpVert.y = trpg_byteswap_8bytes_to_double ((char *)&pt.y);
1133        tmpVert.z = trpg_byteswap_8bytes_to_double ((char *)&pt.z);
1134        polyVert.push_back(tmpVert);
1135    }
1136    else
1137#endif
1138    polyVert.push_back(pt);
1139
1140    // Update min/max
1141    zmin = MIN(pt.z,zmin);
1142    zmax = MAX(pt.z,zmax);
1143}
1144
1145// Flush the current set of geometry and move on
1146void trpgwGeomHelper::FlushGeom()
1147{
1148    bool hadGeom = false;
1149
1150    switch (mode) {
1151    case trpgGeometry::Triangles:
1152    {
1153        Optimize();
1154
1155        // Write only if we've got something
1156        int numPrim;
1157        if (strips.GetNumPrims(numPrim) && numPrim) {
1158            strips.Write(*buf);
1159            stats.stripGeom++;
1160            hadGeom = true;
1161        }
1162        if (fans.GetNumPrims(numPrim) && numPrim) {
1163            fans.Write(*buf);
1164            stats.fanGeom++;
1165            hadGeom = true;
1166        }
1167        if (bags.GetNumPrims(numPrim) && numPrim) {
1168            bags.Write(*buf);
1169            stats.bagGeom++;
1170            hadGeom = true;
1171        }
1172    }
1173    break;
1174    case trpgGeometry::Quads:
1175    {
1176        unsigned int numVert = vert.size();
1177        unsigned int numMat = matTri.size();
1178        unsigned int loop;
1179
1180        // Make sure we've got quads
1181        if (numVert % 4 == 0) {
1182            int dtype = (dataType == UseDouble ? trpgGeometry::DoubleData : trpgGeometry::FloatData);
1183            // Just dump the quads into single geometry node
1184            trpgGeometry quads;
1185            quads.SetPrimType(trpgGeometry::Quads);
1186            for (loop=0;loop<numMat;loop++) quads.AddTexCoords(trpgGeometry::PerVertex);
1187            for (unsigned int i=0;i<numVert;i++) {
1188                quads.AddVertex((trpgGeometry::DataType)dtype,vert[i]);
1189                quads.AddNormal((trpgGeometry::DataType)dtype,norm[i]);
1190                for (loop=0;loop<numMat;loop++) quads.AddTexCoord((trpgGeometry::DataType)dtype,tex[i*numMat+loop],loop);
1191            }
1192            quads.SetNumPrims(numVert/4);
1193            for (loop=0;loop<numMat;loop++) quads.AddMaterial(matTri[loop]);
1194
1195            quads.Write(*buf);
1196            stats.totalQuad++;
1197            hadGeom = true;
1198        }
1199    }
1200    break;
1201    }
1202
1203    if (hadGeom)
1204        stats.stateChanges++;
1205    ResetTri();
1206}
1207
1208/* Optimize
1209   Form triangle strips and fans and dump the rest into a "bag"
1210   of triangles.
1211   This works for TERREX, but won't do a whole lot for anyone else.
1212   It will produce valid output, but not particularly optimized.
1213*/
1214#define ADDVERT(dest,vt) {                                      \
1215        dest.AddVertex((trpgGeometry::DataType)dtype,vt.v);     \
1216        dest.AddNormal((trpgGeometry::DataType)dtype,vt.n);     \
1217        dest.AddTexCoord((trpgGeometry::DataType)dtype,vt.tex); \
1218    }
1219class optVert {
1220public:
1221    optVert() { valid = false; }
1222    optVert(trpg3dPoint &iv,trpg3dPoint &in,trpg2dPoint &itex) { v = iv; n = in; tex.resize(0); tex.push_back(itex); valid = true;}
1223    optVert(trpg3dPoint &iv,trpg3dPoint &in,std::vector<trpg2dPoint> &itex) { v = iv; n = in; tex=itex; valid = true;}
1224    optVert(int numMat, int vid, std::vector<trpg3dPoint> &iv, std::vector<trpg3dPoint> &in, std::vector<trpg2dPoint> &itex);
1225    trpg3dPoint v;
1226    trpg3dPoint n;
1227    std::vector<trpg2dPoint> tex;
1228    bool valid;
1229    int operator == (const optVert &in) const { return (v == in.v && n == in.n && tex == in.tex); }
1230};
1231optVert::optVert(int numMat, int vid, std::vector<trpg3dPoint> &iv, std::vector<trpg3dPoint> &in, std::vector<trpg2dPoint> &itex)
1232{
1233    v=iv[vid];
1234    n=in[vid];
1235    tex.resize(0);
1236    for (unsigned int loop=0; loop < (unsigned int)numMat; loop++) tex.push_back(itex[vid*numMat+loop]);
1237}
1238void trpgwGeomHelper::Optimize()
1239{
1240    int dtype = (dataType == UseDouble ? trpgGeometry::DoubleData : trpgGeometry::FloatData);
1241
1242    // Potentially writing to all of these
1243    strips.SetPrimType(trpgGeometry::TriStrips);
1244    fans.SetPrimType(trpgGeometry::TriFans);
1245    bags.SetPrimType(trpgGeometry::Triangles);
1246    unsigned int numMat = matTri.size();
1247    for (unsigned int loop =0; loop < numMat; loop++ ) {
1248        strips.AddMaterial(matTri[loop]);
1249        strips.AddTexCoords(trpgGeometry::PerVertex);
1250        fans.AddMaterial(matTri[loop]);
1251        fans.AddTexCoords(trpgGeometry::PerVertex);
1252        bags.AddMaterial(matTri[loop]);
1253        bags.AddTexCoords(trpgGeometry::PerVertex);
1254    }
1255
1256    int numTri = vert.size()/3;
1257
1258    if (numTri == 0)
1259        return;
1260
1261    // Iterate through the triangles
1262    enum {Strip,Fan,Bag};
1263    int type,triId;
1264    optVert a[3],b[3],c[3];
1265    for (triId = 0; triId<numTri; ) {
1266        // Triangle A
1267        int vid = 3*triId;
1268        a[0] = optVert(numMat,vid,vert,norm,tex);
1269        a[1] = optVert(numMat,vid+1,vert,norm,tex);
1270        a[2] = optVert(numMat,vid+2,vert,norm,tex);
1271        // If we've got two or more triangles to go, try to form something
1272        if (triId + 1 <numTri) {
1273            // Triangle B
1274            b[0] = optVert(numMat,vid+3,vert,norm,tex);
1275            b[1] = optVert(numMat,vid+4,vert,norm,tex);
1276            b[2] = optVert(numMat,vid+5,vert,norm,tex);
1277
1278            // Is it a triangle strip?
1279            if (a[1] == b[1] && a[2] == b[0])
1280                type = Strip;
1281            else {
1282                // Might be a Fan
1283                if (a[0] == b[0] && a[1] == b[2])
1284                    type = Fan;
1285                else
1286                    type = Bag;
1287            }
1288        } else
1289            type = Bag;
1290
1291        switch (type) {
1292        case Bag:
1293            ADDVERT(bags,a[0]);
1294            ADDVERT(bags,a[1]);
1295            ADDVERT(bags,a[2]);
1296            bags.AddPrim();
1297            triId++;
1298            stats.AddBagStat(1);
1299            break;
1300        case Strip:
1301        {
1302            bool isStrip=true, flip=true;
1303            int primLen = 0;
1304            // Dump A into the strip
1305            ADDVERT(strips,a[0]);
1306            ADDVERT(strips,a[1]);
1307            ADDVERT(strips,a[2]);
1308            triId++;
1309            primLen = 3;
1310            do {
1311                // Already checked that B was good on last go-round
1312                ADDVERT(strips,b[2]);  primLen++;
1313                triId++;
1314                vid = 3*triId;
1315
1316                if (triId < numTri) {
1317                    // B is the new primary, check it against the next
1318                    c[0] = optVert(numMat,vid,vert,norm,tex);
1319                    c[1] = optVert(numMat,vid+1,vert,norm,tex);
1320                    c[2] = optVert(numMat,vid+2,vert,norm,tex);
1321                    if (flip)
1322                        isStrip = (c[0] == b[0] && c[1] == b[2]);
1323                    else
1324                        isStrip = (c[0] == b[2] && c[1] == b[1]);
1325                    b[0] = c[0];  b[1] = c[1];  b[2] = c[2];
1326                }
1327                flip = !flip;
1328            } while (triId < numTri && isStrip);
1329
1330            strips.AddPrimLength(primLen);
1331            stats.AddStripStat(primLen);
1332        }
1333        break;
1334        case Fan:
1335        {
1336            bool isFan = true;
1337            int primLen = 0;
1338
1339            // Dump A into the Fan
1340            ADDVERT(fans,a[0]);
1341            ADDVERT(fans,a[2]);
1342            ADDVERT(fans,a[1]);
1343            triId++;
1344            primLen = 3;
1345            do {
1346                // Already know that B is good, add that
1347                ADDVERT(fans,b[1]);  primLen++;
1348                triId++;
1349                vid = 3*triId;
1350
1351                if (triId < numTri) {
1352                    // B is the new primary, check it agains the next
1353                    c[0] = optVert(numMat,vid,vert,norm,tex);
1354                    c[1] = optVert(numMat,vid+1,vert,norm,tex);
1355                    c[2] = optVert(numMat,vid+2,vert,norm,tex);
1356                    isFan = (c[0] == b[0] && c[2] == b[1]);
1357                    b[0] = c[0];  b[1] = c[1];  b[2] = c[2];
1358                }
1359            } while (triId < numTri && isFan);
1360
1361            fans.AddPrimLength(primLen);
1362            stats.AddFanStat(primLen);
1363        }
1364        break;
1365        }
1366    }
1367}
1368
1369/* *************************
1370   Image Write Helper class
1371   *************************
1372   */
1373
1374trpgwImageHelper::trpgwImageHelper(trpgEndian inNess,char *inDir,trpgTexTable &inTable,bool separateGeoTypical)
1375{
1376    Init(inNess,inDir,inTable,separateGeoTypical);
1377}
1378
1379void trpgwImageHelper::Init(trpgEndian inNess,char *inDir,trpgTexTable &inTable,bool separateGeoTypical)
1380{
1381    ness = inNess;
1382    strcpy(dir,inDir);
1383    texTable = &inTable;
1384    texFile = NULL;
1385    geotypFile = NULL;
1386    this->separateGeoTypical = separateGeoTypical;
1387    maxTexFileLen = -1;
1388}
1389
1390trpgwImageHelper::~trpgwImageHelper()
1391{
1392    if (texFile)
1393        delete texFile;
1394    if (geotypFile)
1395        delete geotypFile;
1396}
1397
1398bool trpgwImageHelper::AddExternal(char *name,int &texID,bool lookForExisting)
1399{
1400    trpgTexture tex;
1401    tex.SetImageMode(trpgTexture::External);
1402    tex.SetName(name);
1403    if (lookForExisting)
1404        texID = texTable->FindAddTexture(tex);
1405    else
1406        texID = texTable->AddTexture(tex);
1407
1408    return (texID != -1);
1409}
1410
1411void trpgwImageHelper::SetMaxTexFileLength(int len)
1412{
1413    maxTexFileLen = len;
1414}
1415
1416bool trpgwImageHelper::AddLocal(char *name,trpgTexture::ImageType type,int sizeX,int sizeY,
1417                                bool isMipmap,char *data,int &texID,bool deferWrite)
1418{
1419    // Set up the basic texture
1420    trpgTexture tex;
1421    if(texID!=-1)
1422        tex.SetHandle(texID);
1423    tex.SetName(name);
1424    tex.SetImageMode(trpgTexture::Local);
1425    tex.SetImageType(type);
1426    int depth;
1427    tex.GetImageDepth(depth);
1428    tex.SetNumLayer(depth);
1429    tex.SetImageSize(trpg2iPoint(sizeX,sizeY));
1430    tex.SetIsMipmap(isMipmap);
1431
1432    // Write the image out to disk
1433    trpgwAppAddress addr;
1434    if(!deferWrite)
1435        if (!WriteToArchive(tex,data,addr,true))
1436            return false;
1437
1438    // Now add the specifics to the texture table
1439    tex.SetImageAddr(addr);
1440    texID = texTable->AddTexture(tex);
1441
1442    return true;
1443}
1444
1445bool trpgwImageHelper::ReplaceLocal(char *data,int &texID)
1446{
1447    const trpgTexture *texRef=texTable->GetTextureRef(texID);
1448
1449    if (!texRef) return false;
1450
1451    // Write the image out to disk
1452    trpgwAppAddress addr;
1453    if (!WriteToArchive(*texRef,data,addr,true))
1454        return false;
1455
1456    // Now add the specifics to the texture table
1457    const_cast<trpgTexture *>(texRef)->SetImageAddr(addr);
1458
1459    return true;
1460}
1461
1462bool trpgwImageHelper::AddTileLocal(char *name,trpgTexture::ImageType type, int sizeX, int sizeY,
1463                                    bool isMipmap,char *data,int &texID,trpgwAppAddress &addr)
1464{
1465    // Set up the texture template and add to the table
1466    trpgTexture tex;
1467    if(texID!=-1)
1468        tex.SetHandle(texID);
1469    tex.SetName(name);
1470    tex.SetImageMode(trpgTexture::Template);
1471    tex.SetImageType(type);
1472    int depth;
1473    tex.GetImageDepth(depth);
1474    tex.SetNumLayer(depth);
1475    tex.SetImageSize(trpg2iPoint(sizeX,sizeY));
1476    tex.SetIsMipmap(isMipmap);
1477    texID = texTable->FindAddTexture(tex);
1478
1479    // Write the specific data out to an archive (return the address)
1480    if (!WriteToArchive(tex,data,addr,false))
1481        return false;
1482
1483
1484    return true;
1485}
1486
1487/* Get new appendable file.
1488 */
1489trpgwAppFile* trpgwImageHelper::GetNewWAppFile(trpgEndian inNess,const char *fileName,bool reuse) {
1490    return new trpgwAppFile(inNess,fileName,reuse);
1491}
1492
1493/* Increment Texture File.
1494   Close the current texture file (if any) and open the next one.
1495*/
1496trpgwAppFile * trpgwImageHelper::IncrementTextureFile(bool geotyp)
1497{
1498    char filename[1024];
1499    trpgwAppFile *thefile = texFile;
1500
1501    if(geotyp && separateGeoTypical) {
1502        thefile = geotypFile;
1503                sprintf(filename,"%s" PATHSEPERATOR "geotypFile_%d.txf",dir,static_cast<int>(geotypFileIDs.size()));
1504    }
1505    else {
1506                sprintf(filename,"%s" PATHSEPERATOR "texFile_%d.txf",dir,static_cast<int>(texFileIDs.size()));
1507    }
1508
1509    // Closes the current texture file
1510    if (thefile)  delete thefile;
1511    thefile = NULL;
1512
1513    // Open the next one
1514    thefile = GetNewWAppFile(ness,filename,true);
1515    if (!thefile->isValid())
1516        return NULL;
1517    if(geotyp && separateGeoTypical) {
1518        geotypFileIDs.push_back(geotypFileIDs.size());
1519        geotypFile = thefile;
1520    }
1521    else {
1522        texFileIDs.push_back(texFileIDs.size());
1523        texFile = thefile;
1524    }
1525    return thefile;
1526}
1527
1528// Flush current texture file (if any)
1529bool trpgwImageHelper::Flush()
1530{
1531    if (texFile)
1532        texFile->Flush();
1533    if (geotypFile)
1534        geotypFile->Flush();
1535    return true;
1536}
1537
1538/* Designate Texture File
1539   Close the curren texture file (if any) and open one with the given
1540   base name.
1541*/
1542bool trpgwImageHelper::DesignateTextureFile(int id)
1543{
1544    // Close the current texture file
1545    if (texFile)  delete texFile;
1546    texFile = NULL;
1547
1548    // Open one with the given base name
1549    char filename[1024];
1550    sprintf(filename,"%s" PATHSEPERATOR "texFile_%d.txf",dir,id);
1551    texFile = GetNewWAppFile(ness,filename);
1552    if (!texFile->isValid())
1553        return false;
1554    texFileIDs.push_back(id);
1555
1556    sprintf(filename,"%s" PATHSEPERATOR "geotypFile_%d.txf",dir,id);
1557    geotypFile = GetNewWAppFile(ness,filename);
1558    if (!geotypFile->isValid())
1559        return false;
1560    geotypFileIDs.push_back(id);
1561
1562
1563    return true;
1564}
1565
1566/* Write To Archive.
1567   Write the given image data out to an appropriate archive and
1568   return the address.  This is used for Local and Tile Local textures.
1569 */
1570bool trpgwImageHelper::WriteToArchive(const trpgTexture &tex,char *data,trpgwAppAddress &addr,bool geotyp)
1571{
1572    trpg2iPoint size;
1573    tex.GetImageSize(size);
1574    int32 depth;
1575    tex.GetImageDepth(depth);
1576    trpgwAppFile *thefile = texFile;
1577    if(geotyp && separateGeoTypical) {
1578        thefile = geotypFile;
1579    }
1580
1581
1582    // Get a usable texture archive file
1583    if (!thefile) {
1584        if (! (thefile=IncrementTextureFile(geotyp && separateGeoTypical)))
1585            return false;
1586    }
1587
1588    while (maxTexFileLen > 0 && thefile->GetLengthWritten() > maxTexFileLen) {
1589        if (!(thefile=IncrementTextureFile(geotyp && separateGeoTypical)))
1590            return false;
1591    }
1592
1593
1594    // Get the current address
1595    if(geotyp && separateGeoTypical) {
1596        addr.file = geotypFileIDs[geotypFileIDs.size()-1];
1597    }
1598    else {
1599        addr.file = texFileIDs[texFileIDs.size()-1];
1600    }
1601    addr.offset = (int32)thefile->Pos();
1602
1603    // Write the data out to the archive.
1604    int totSize = tex.CalcTotalSize();
1605    if (!thefile->Append(data,totSize))
1606        return false;
1607
1608    return true;
1609}
Note: See TracBrowser for help on using the browser.