1 /*---------------------------------------------------------------------*
2 Project: tc library
3 File: TCTPLToolbox.cpp
4
5 Copyright 1998-2001 Nintendo. All rights reserved.
6
7 These coded instructions, statements and computer programs contain
8 proprietary information of Nintendo of America Inc. and/or Nintendo
9 Company Ltd., and are protected by Federal copyright law. They may
10 not be disclosed to third parties or copied or duplicated in any form,
11 in whole or in part, without the prior written consent of Nintendo.
12
13 Change History:
14
15 $Log: TCTPLToolbox.cpp,v $
16 Revision 1.2 2008/05/23 04:26:10 iwai_yuma
17 Improved for handling of VC2005.
18
19 Revision 1.1 2006/02/17 09:01:53 mitu
20 1st version
21
22
23 13 4/11/01 3:08p John
24 Updated header copyrights and pathname.
25
26 12 3/13/01 3:53p John
27 Added error checking for user-defined wrap modes. If a dimension is
28 not a power of two, the wrap mode must be GX_CLAMP.
29
30 11 3/09/01 2:51p John
31 Modified TCWriteTplFile. Added ability to specify wrapS and wrapT mode
32 using TCS script file.
33
34 10 8/15/00 4:45p Mikepc
35 fixed bug in TCWriteCachedScriptFile - changed fwrite to run in a loop
36 to zero out "imCached and "plCached" blocks.
37
38 9 8/10/00 6:03p Mikepc
39
40 8 3/17/00 1:19p Mikepc
41 change tc to use indices numbered from 0.
42
43 7 2/15/00 5:55p Mikepc
44 updated tpl version # to from 10141999 to 2142000 to reflect CMPR
45 format change.
46
47 6 2/11/00 4:43p Mikepc
48
49 5 2/11/00 12:51p Mikepc
50
51 4 1/20/00 2:00p Mikepc
52 change to default wrap mode in TCWriteTplFile:
53 power of 2 image is set to REPEAT,
54 non-power 2 image is set to CLAMP
55
56 3 1/13/00 4:42p Mikepc
57 added .tpl partial update code.
58
59 2 1/11/00 5:40p Mikepc
60 added tpl partial update code.
61
62 1 12/03/99 3:45p Ryan
63
64 $NoKeywords: $
65
66 -----------------------------------------------------------------------*/
67
68 #include <string.h> // .tpl partial update name comparison
69 #include <io.h> // _open(), _close(), _access(), _chmod()
70 #include <fcntl.h> // flags for above functions
71 #include <sys/types.h> // file status types
72 #include <sys/stat.h> // file status functions
73 #include <sys/utime.h> // _utime()
74 #include <time.h> // time structures, functions
75 #include <direct.h> // _mkDir()
76
77 #include <stdio.h>
78
79 #include <charPipeline/tc/TCCommon.h>
80
81 #include "TCTPLToolbox.h"
82 #include "TCImageList.h"
83 #include "TCPaletteList.h"
84 #include "TCTextureList.h"
85 #include "TCSrcImageList.h"
86 #include "TCGXDefs.h"
87 #include "TCMem.h"
88 #include "TCLayerInternal.h"
89 #include "TCMipmap.h"
90 #include "TCFileInternal.h"
91
92 /********************************/
93
94 // #define for endian format of .tpl header values:
95
96 // this define turns TCFixEndian() on and off.
97
98 // note: applies to header values and
99 // image/palette/texture descriptor blocks only.
100 // all of these values are passed to TCFixEndian()
101 // before being written to the .tpl file.
102
103 // data blocks are always packed big-endian
104 // in dolphin hw format.
105
106 // if TPL_BIG_END is defined,
107 // TCFixEndian() reverses byte order.
108 // otherwise, TCFixEndian() does nothing
109
110 #define TPL_BIG_END 1
111
112 // uncomment this to pack in little-end format
113 /*
114 #ifdef TPL_BIG_END
115 #undef TPL_BIG_END
116 #endif
117 */
118
119 /********************************/
120
121 // size of fixed .tpl components in bytes
122 #define TPL_HDR_SIZE 12
123 #define TPL_TEX_DESC_SIZE 8
124 #define TPL_IMG_DESC_SIZE 36
125 #define TPL_PAL_DESC_SIZE 12
126
127 // translation of windows file access levels from _access() ( io.h )
128 #define FILE_ACCESS_READ_WRITE 6
129 #define FILE_ACCESS_READ_ONLY 4
130 #define FILE_ACCESS_WRITE_ONLY 2
131 #define FILE_ACCESS_NONE 0
132
133 #pragma warning(disable : 4996)
134
135 /********************************/
136
137 // cached image data from last-used script file
138 typedef struct TCCachedImage
139 {
140
141 u32 colorSrcImage; // srcImage index for color layer
142 u32 alphaSrcImage; // srcImage index for alpha layer; 0 if no alpha layer
143
144 struct tm colorModTime; // mod. date of the color srcImage file
145 struct tm alphaModTime; // mod. date of the alpha srcImage file
146
147 u32 texelFormat; // Dolphin texture format ( TPL_IMAGE_TEXEL_FMT_X )
148
149 u32 minLOD; // minimum LOD level desired relative to srcImage
150 u32 maxLOD; // maximum LOD level desired relative to srcImage
151 u32 remapMinLOD; // remapped (actual) minLOD for .tpl file
152
153 u32 tplImageBankOffset; // bytes from top of .tpl file to image texel data
154 u32 tplBufferSize; // size of image buffer including padding to 32B tiles
155
156 } TCCachedImage, *TCCachedImagePtr;
157
158
159 typedef struct TCCachedPalette
160 {
161 u32 srcImage; // source image file providing
162 // both color and alpha components of CLUT
163
164 struct tm srcModTime; // mod. date of the srcImage
165
166 u32 entryFormat; // Dolphin format of CLUT entries
167
168 u32 tplPaletteBankOffset; // number of bytes from top of file to palette data block
169 u32 tplBufferSize; // size of palette data block
170
171 } TCCachedPalette, *TCCachedPalettePtr;
172
173
174 typedef struct TCCsfHeader
175 {
176 u32 header;
177 u32 tplNameOffset;
178 struct tm tplModTime;
179
180 u32 numCachedImage;
181 u32 cachedImageOffset;
182 u32 numCachedPalette;
183 u32 cachedPaletteOffset;
184 u32 stringBankOffset;
185 u32 stringBankSize;
186
187 } TCCsfHeader, *TCCsfHeaderPtr;
188
189 /***************************************/
190
191 /*
192
193 CACHED FILE FORMAT (.csf file)
194
195 u32 header // blank
196
197 u32 tplFileName offset // bytes from start of string bank
198 struct tm tplModTime ( s32 x 5 ) // mod. time of this .tpl
199
200 u32 TCCachedImage count // TCCachedImage block array size
201 u32 TCCachedImage offset // bytes from start of .csf file
202
203 u32 TCCachedPalette count // TCCachedPalette block array size
204 u32 TCCachedPalette offset // bytes from start of .csf file
205
206 u32 string bank offset // bytes from start of .csf file
207 u32 string bank size
208
209 TCCachedImage block // array of TCCachedImage structures
210
211 TCCachedPalette block // array of TCCachedPalette structures
212
213 string bank // tpl file name, source image file names,
214 // source palette file names packed end to end.
215
216 */
217
218 /***************************************/
219
220 // global number, size, counters for .tpl blocks
221 u32 NumTex = 0;
222 u32 NumImage = 0;
223 u32 NumPalette = 0;
224
225 const u32 TplHdrSize = TPL_HDR_SIZE;
226 const u32 TexDescSize = TPL_TEX_DESC_SIZE;
227 u32 TexDescBlockSize = 0;
228
229 const u32 PaletteDescSize = TPL_PAL_DESC_SIZE;
230 u32 PaletteDescBlockSize = 0;
231 u32 PaletteDescPad = 0;
232 u32 PaletteBankSize = 0;
233
234 const u32 ImageDescSize = TPL_IMG_DESC_SIZE;
235 u32 ImageDescBlockSize = 0;
236 u32 ImageDescPad = 0;
237 u32 ImageBankSize = 0;
238
239 const u32 TplVersion = 2142000; // tpl version number:
240 // literally 'Feb. 14, 2000'
241
242
243 const char* CsfPath = "C:/Temp"; // in case C:Temp folder doesn't exist
244 const char* CsfName = "C:/Temp/tplCache.csf"; // hard coded .csf file name
245
246 TCCachedImage* CachedImArray = NULL; // array of cached images from .csf file
247 u32 NumCachedIm = 0;
248
249 TCCachedPalette* CachedPlArray = NULL; // array of cached palettes from .csf file
250 u32 NumCachedPl = 0;
251
252 u32* ImFlags = NULL; // array of image/palette partial update flags.
253 u32* PlFlags = NULL; // if flag[n] is 0, full conversion required.
254 // if flag[n] is set, value is the byte offset to
255 // pre-converted data in the existing.tpl file
256
257 /*>*******************************(*)*******************************<*/
258
259 static void TCSetTplPaletteValues ( void );
260 static void TCSetTplImageValues ( void );
261 static void TCSetTplTextureValues ( void );
262
263 static u32 TCWriteTplPaletteBank ( FILE* fp, u32 total, u8* tplPrev, u32* imFlags );
264 static u32 TCWriteTplImageBank ( FILE* fp, u32 total, u8* tplPrev, u32* imFlags );
265
266 static u32 TCComputeTplImageBufferSize_4Bit ( TCImage* thisImage );
267 static u32 TCComputeTplImageBufferSize_8Bit ( TCImage* thisImage );
268 static u32 TCComputeTplImageBufferSize_16Bit ( TCImage* thisImage );
269 static u32 TCComputeTplImageBufferSize_32Bit ( TCImage* thisImage );
270 static u32 TCComputeTplImageBufferSize_Cmp ( TCImage* thisImage );
271
272 static u32 TCWritePaletteBlock_R5G6B5 ( FILE* fp, TCPalette* pal, u32 start );
273 static u32 TCWritePaletteBlock_RGB5A3 ( FILE* fp, TCPalette* pal, u32 start );
274
275 static void TCPackTile_I4 ( TCLayer* srcLayer, u32 x, u32 y, u8* dstPtr );
276 static void TCPackTile_I8 ( TCLayer* srcLayer, u32 x, u32 y, u8* dstPtr );
277
278 static void TCPackTile_IA4 ( TCLayer* colorLayer, TCLayer* alphaLayer, u32 x, u32 y, u8* dstPtr );
279 static void TCPackTile_IA8 ( TCLayer* colorLayer, TCLayer* alphaLayer, u32 x, u32 y, u8* dstPtr );
280
281 static void TCPackTile_R5G6B5 ( TCLayer* colorLayer, u32 x, u32 y, u8* dstPtr );
282
283 static void TCPackTile_RGB5A3 ( TCLayer* colorLayer, TCLayer* alphaLayer, u32 x, u32 y, u8* dstPtr );
284
285 static void TCPackTile_RGBA8 ( TCLayer* colorLayer, TCLayer* alphaLayer, u32 x, u32 y, u8* dstPtr );
286
287 static void TCPackTile_CI4 ( TCLayer* srcLayer, u32 x, u32 y, u8* dstPtr );
288 static void TCPackTile_CI8 ( TCLayer* srcLayer, u32 x, u32 y, u8* dstPtr );
289 static void TCPackTile_CI14_X2 ( TCLayer* colorLayer, u32 x, u32 y, u8* dstPtr );
290
291 static void TCPackTile_CMP ( TCLayer* layer, u32 tileX, u32 tileY, u16* dstPtr );
292 static void TCFixCMPWord ( u16* data );
293
294 static void TCGetFileModTime ( const char* tplName, struct tm* refTmPtr );
295 static void TCGetTime ( struct tm* tmPtr );
296 static s32 TCGetFileAccess ( const char* fileName );
297 static void TCSetFileAccess ( const char* fileName, s32 axs );
298 static void TCSetFileModTime ( const char* fileName, struct tm* refTm );
299 static s32 TCCompareTime ( struct tm* time1, struct tm* time2 );
300 static u32 TCGetTplVersion ( const char* tplName );
301
302 static u32 TCWriteTplValue ( FILE* fp, u32 cursor, void* value, u32 numBytes );
303 static u32 TCWriteTplBlock ( FILE* fp, u32 cursor, void* block, u32 numBytes );
304
305 static void TCFixEndian ( u8* src, u32 numBytes );
306
307 static u32 TCSetFilterModeByDim ( TCImage* thisImage );
308 static u32 TCCheckPowerOfTwo ( u32 num );
309
310 static void TCWriteCachedScriptFile ( const char* tplName, struct tm* refTmPtr );
311 static u32 TCReadCachedScriptFile ( const char* newTplName, u8** tplPrev );
312
313 static u32 TCCompareToCachedScriptData ( const char* prevTplName, struct tm* prevTplModTime, u8** tplPrev );
314 static u32 TCCompareImToCachedIm ( struct tm* refTimePtr, TCImage* imPtr, TCCachedImage* cImPtr );
315 static u32 TCComparePlToCachedPl ( struct tm* refTimePtr, TCPalette* plPtr, TCCachedPalette* cPlPtr );
316
317 /*>*******************************(*)*******************************<*/
318 // this computes the size of the various blocks within the .tpl file;
319 // it also computes the offsets (eg image n data offset) for each descriptor
320 // at this point, the actual data is not yet transformed to hw format
321 /*>*******************************(*)*******************************<*/
TCComputeTplSizes(void)322 void TCComputeTplSizes ( void )
323 {
324 TCImage* imPtr;
325 TCPalette* plPtr;
326 TCTexture* txPtr;
327
328
329 // get the image, palette and texture list sizes
330 NumImage = 0;
331 imPtr = ImHead;
332 while( imPtr )
333 {
334 NumImage++;
335 imPtr = imPtr->next;
336 }
337
338 NumPalette = 0;
339 plPtr = PlHead;
340 while( plPtr )
341 {
342 NumPalette++;
343 plPtr = plPtr->next;
344 }
345
346 NumTex = 0;
347 txPtr = TxHead;
348 while( txPtr )
349 {
350 NumTex++;
351 txPtr = txPtr->next;
352 }
353
354 // there must be at least 1 texture and 1 image to create a tpl file
355 TCAssertMsg( (NumTex), "TCComputeTplSizes: NumTex = 0\n" );
356 TCAssertMsg( (NumImage), "TCComputeTplSizes: NumImage = 0\n" );
357
358 // set file descriptor block sizes
359 TexDescBlockSize = NumTex * TexDescSize;
360 ImageDescBlockSize = NumImage * ImageDescSize;
361 PaletteDescBlockSize = NumPalette * PaletteDescSize;
362
363 // set .tpl values for images and palettes, compute total bank sizes
364 // order is important as palette descriptors and palette bank come before image descriptors, image bank
365 // values are stored in the appropriate palette/image structures in ImHead, PlHead lists
366 TCSetTplPaletteValues();
367 TCSetTplImageValues();
368
369 // compute the actual texture descriptor block offsets for the .tpl file
370 // this must be done last as the location of the image descriptors depends on the size of
371 // the palette descriptor block and palette bank
372 TCSetTplTextureValues();
373 }
374
375 /*>*******************************(*)*******************************<*/
376 // note: header values are packed according to status of TPL_BIG_END flag;
377 // data blocks are always packed big-end for Dolphin hw
378 /*>*******************************(*)*******************************<*/
TCWriteTplFile(char * tplFile)379 void TCWriteTplFile ( char* tplFile )
380 {
381 FILE* fp;
382 TCTexture* texPtr;
383 TCPalette* palPtr;
384 TCImage* imgPtr;
385 u32 total;
386 u8 cTmp;
387 u16 sTmp;
388 u32 iTmp, iTmp1;
389
390 struct tm tplModTime; // modification date of the new .tpl
391 u8* tplPrev = NULL; // buffer for previous .tpl file
392 u32 partialUpdate = 0;
393
394 u32 pad[8] = { 0,0,0,0,0,0,0,0 }; // up to 32B pad between header blocks
395
396
397 // tpl file must contain at least 1 texture, image.
398 TCAssertMsg( (NumTex), "TCWriteTplFile: NumTex = 0\n" );
399 TCAssertMsg( (NumImage), "TCWriteTplFile: NumImage = 0\n" );
400
401
402 // read the cached .csf file, compare cached to current data,
403 // initialize ImFlags, PlFlags arrays.
404 // if any partial update is possible, the previous .tpl file will be stored
405 // in a buffer allocated to tplPrev.
406 partialUpdate = TCReadCachedScriptFile( tplFile, &tplPrev );
407
408 //---------------------------------------------------------------------------
409
410 // create/overwrite the .tpl file
411 TCSetFileAccess ( tplFile, FILE_ACCESS_READ_WRITE ); // in case the srcTree locked it.
412
413 fp = fopen(tplFile, "wb");
414 TCAssertMsg( (fp != NULL), "TCWriteTplFile: couldn't create .tpl file %s for write\n", tplFile );
415
416 //-------------------------------------------------------------------------------------------
417
418 // number of bytes written to new .tpl file
419 total = 0;
420
421 // TPL HEADER BLOCK
422 // (12B)
423
424
425 // VERSION NUMBER
426 // (4B)
427 total += TCWriteTplValue( fp, total, (void*)&TplVersion, 4 );
428
429
430 // NUMBER OF TEXTURE DESCRIPTORS
431 // (4B)
432 total += TCWriteTplValue( fp, total, (void*)&NumTex, 4 );
433
434
435 // OFFSET TO TEXTURE DESCRIPTOR BLOCK
436 // (4B, VALUE = 12)
437 total += TCWriteTplValue( fp, total, (void*)&TplHdrSize, 4 );
438
439 //-------------------------------------------------------------------------------------------
440
441 // TEXTURE DESCRIPTOR BLOCK
442 // (8B x NumTex)
443 texPtr = TxHead;
444 while( texPtr )
445 {
446 // OFFSET TO IMAGE DESCRIPTOR
447 // (4B)
448 total += TCWriteTplValue( fp, total, (void*)&texPtr->tplImageOffset, 4 );
449
450
451 // OFFSET TO CLUT DESCRIPTOR
452 // (4B)
453 total += TCWriteTplValue( fp, total, (void*)&texPtr->tplPaletteOffset, 4 );
454
455
456 texPtr = texPtr->next;
457 }
458
459 //-------------------------------------------------------------------------------------------
460
461 // PALETTE DESCRIPTOR BLOCK
462 // (12B x NumPalette)
463
464
465 // note: if no palettes are used by textures,
466 // there will not be a palette descriptor block in the file
467
468
469 palPtr = PlHead;
470 while( palPtr )
471 {
472 // NUMBER OF PALETTE ENTRIES
473 // (2B)
474 total += TCWriteTplValue( fp, total, (void*)&palPtr->palPtr->numEntry, 2 );
475
476
477 // PAD
478 // (2B)
479 total += TCWriteTplValue( fp, total, (void*)pad, 2 );
480
481
482 // PALETTE ENTRY FORMAT
483 // (4B)
484 total += TCWriteTplValue( fp, total, (void*)&palPtr->entryFormat, 4 );
485
486
487
488 // OFFSET TO PALETTE DATA
489 // (4B)
490 total += TCWriteTplValue( fp, total, (void*)&palPtr->tplPaletteBankOffset, 4 );
491
492
493 palPtr = palPtr->next;
494 }
495
496 //------------------------------------------------------
497
498 // PALETTE DESCRIPTOR BLOCK PAD
499 // (ROUND OUT TO 32B)
500
501 // if there is no palette descriptor block, pad will be 0
502 if(PaletteDescPad != 0)
503 {
504 total += TCWriteTplBlock( fp, total, (void*)pad, PaletteDescPad );
505 }
506
507 //-------------------------------------------------------------------------------------------
508
509
510 // PALETTE DATA BLOCK
511
512 total += TCWriteTplPaletteBank( fp, total, tplPrev, PlFlags );
513
514
515 //-------------------------------------------------------------------------------------------
516
517 // IMAGE DESCRIPTOR BLOCK
518 // (36B x NumImage)
519
520 imgPtr = ImHead;
521 while( imgPtr )
522 {
523 // note: height and width refer to the original
524 // unpadded image dimensions.
525 // however, if image->minLOD is not 0, width and height
526 // must be remapped to reflect the size of the 1st LOD
527 // actually stored in the .tpl file.
528 // this is achieved by shifting sTmp by imgPtr->minLOD.
529
530
531 // image height: convert to 2-byte value // IMAGE HEIGHT
532 sTmp = (u16)( (imgPtr->lyColor).height ); // (2B)
533 sTmp >>= imgPtr->minLOD;
534 total += TCWriteTplValue( fp, total, (void*)&sTmp, 2 );
535
536
537 // image width: convert to 2-byte value
538 sTmp = (u16)( (imgPtr->lyColor).width ); // IMAGE WIDTH
539 sTmp >>= imgPtr->minLOD; // (2B)
540 total += TCWriteTplValue( fp, total, (void*)&sTmp, 2 );
541
542
543 // IMAGE PIXEL FORMAT
544 // (4B)
545 total += TCWriteTplValue( fp, total, (void*)&imgPtr->texelFormat, 4 );
546
547
548 // OFFSET TO IMAGE DATA
549 // (4B)
550 total += TCWriteTplValue( fp, total, (void*)&imgPtr->tplImageBankOffset, 4 );
551
552
553 if( imgPtr->wrapS == TPL_WRAP_MODE_NONE ||
554 imgPtr->wrapT == TPL_WRAP_MODE_NONE )
555 {
556 // SET DEFAULT FILTER MODES:
557 // TPL_WRAP_MODE_REPEAT for power of 2 images
558 // TPL_WRAP_MODE_CLAMP for non-power 2 images
559 imgPtr->wrapS = imgPtr->wrapT = TCSetFilterModeByDim( imgPtr );
560 }
561 else
562 {
563 // Check wrap mode with dimensions. If wrap mode is repeat or mirror (not clamp),
564 // then dimension must be power of two. Only need to check for these errors
565 // when user has defined wrap modes. TCSetFilterModeByDim will do the right thing.
566 if( imgPtr->wrapS != TPL_WRAP_MODE_CLAMP &&
567 !TCCheckPowerOfTwo( imgPtr->lyColor.width ) )
568 {
569 TCErrorMsg( "TCWriteTplFile: since width %d is not a power of two, wrapS mode must be GX_CLAMP for image %d in script file\n", imgPtr->lyColor.width, imgPtr->index );
570 }
571 if( imgPtr->wrapT != TPL_WRAP_MODE_CLAMP &&
572 !TCCheckPowerOfTwo( imgPtr->lyColor.height ) )
573 {
574 TCErrorMsg( "TCWriteTplFile: since height %d is not a power of two, wrapT mode must be GX_CLAMP for image %d in script file\n", imgPtr->lyColor.height, imgPtr->index );
575 }
576 }
577
578 // WRAP S
579 // (4B)
580 total += TCWriteTplValue( fp, total, (void*)&imgPtr->wrapS, 4 );
581
582 // WRAP T
583 // (4B)
584 total += TCWriteTplValue( fp, total, (void*)&imgPtr->wrapT, 4 );
585
586
587 // MIN, MAG FILTER MODES
588 // BASED ON IMAGE TYPE, NUM LOD
589
590 // 4 byte each for default tex filter min and mag modes.
591 switch( imgPtr->texelFormat )
592 {
593 case TPL_IMAGE_TEXEL_FMT_CI4: // palettized image
594 case TPL_IMAGE_TEXEL_FMT_CI8:
595 case TPL_IMAGE_TEXEL_FMT_CI14_X2:
596
597 iTmp = TPL_TEX_FILTER_LINEAR; // min
598 iTmp1 = TPL_TEX_FILTER_LINEAR; // mag
599 break;
600
601 default: // true color image
602
603 if( ( imgPtr->maxLOD - imgPtr->minLOD + 1 ) == 1 ) // single LOD
604 {
605 iTmp = TPL_TEX_FILTER_LINEAR; // min
606 iTmp1 = TPL_TEX_FILTER_LINEAR; // mag
607 }
608 else // mip mapped
609 {
610 iTmp = TPL_TEX_FILTER_LIN_MIP_LIN; // min
611 iTmp1 = TPL_TEX_FILTER_LINEAR; // mag
612 }
613 break;
614 }
615
616 // MIN TEX FILTER MODE
617 // (4B)
618 total += TCWriteTplValue( fp, total, (void*)&iTmp, 4 );
619
620
621 // MAG TEX FILTER MODE
622 // (4B)
623 total += TCWriteTplValue( fp, total, (void*)&iTmp1, 4 );
624
625
626 iTmp = 0; // LOD BIAS
627 // (4B, DEFAULT = 0)
628 total += TCWriteTplValue( fp, total, (void*)&iTmp, 4 );
629
630
631 cTmp = 0; // LOD EDGE ENABLE
632 // (1B, DEFAULT = 0)
633 total += TCWriteTplValue( fp, total, (void*)&cTmp, 1 );
634
635
636 // IMAGE MIN. LOD
637 cTmp = (u8)(imgPtr->remapMinLOD); // (1B)
638 total += TCWriteTplValue( fp, total, (void*)&cTmp, 1 );
639
640
641 // IMAGE MAX. LOD
642 // (1B)
643 // new max LOD is ( remapped minLOD + numLOD - 1 )
644 cTmp = (u8)( imgPtr->remapMinLOD + (imgPtr->maxLOD - imgPtr->minLOD) );
645 total += TCWriteTplValue( fp, total, (void*)&cTmp, 1 );
646
647
648 // PAD
649 // (1B, DEFAULT = 0)
650 total += TCWriteTplValue( fp, total, (void*)pad, 1 );
651
652
653 imgPtr = imgPtr->next;
654 }
655
656 //------------------------------------------------------
657
658 // IMAGE DESCRIPTOR BLOCK PAD
659 // (ROUND OUT TO 32B)
660 if(ImageDescPad != 0)
661 {
662 total += TCWriteTplBlock( fp, total, (void*)pad, ImageDescPad );
663 }
664
665 //-------------------------------------------------------------------------------------------
666
667 // IMAGE DATA BLOCK
668
669 total += TCWriteTplImageBank( fp, total, tplPrev, ImFlags );
670
671
672 //------------------------------------------------------
673
674 fclose(fp);
675
676 // explicitly set/update the .tpl modification date.
677 // do this before calling TCWriteCachedScriptFile
678 TCGetTime( &tplModTime );
679 TCSetFileModTime( tplFile, &tplModTime );
680
681 // cache the new .tpl file's script data in a .csf file
682 TCWriteCachedScriptFile( tplFile, &tplModTime );
683
684 //------------------------------
685
686 // free memory, reset variables related to .csf cache
687
688 if( tplPrev != NULL )
689 {
690 TCFree( (void**)(&tplPrev) );
691 tplPrev = NULL;
692 }
693
694 if( CachedImArray != NULL )
695 {
696 TCFree( (void**)( &CachedImArray ) );
697 CachedImArray = NULL;
698 }
699 NumCachedIm = 0;
700
701 if( CachedPlArray != NULL )
702 {
703 TCFree( (void**)( &CachedPlArray ) );
704 CachedPlArray = NULL;
705 }
706 NumCachedPl = 0;
707
708 if( ImFlags != NULL )
709 {
710 TCFree( (void**)( &ImFlags ) );
711 ImFlags = NULL;
712 }
713
714 if( PlFlags != NULL )
715 {
716 TCFree( (void**)( &PlFlags ) );
717 PlFlags = NULL;
718 }
719
720 //------------------------------
721 }
722
723 /*>*******************************(*)*******************************<*/
724 // traverse the sorted palette list and compute the 'tpl' values including the
725 // data buffer sizes
726 /*>*******************************(*)*******************************<*/
TCSetTplPaletteValues(void)727 static void TCSetTplPaletteValues ( void )
728 {
729 TCPalette* thisPalette;
730 u32 bankOffset;
731 u32 paletteEntrySize;
732 u32 size;
733
734
735 // if a palette descriptor block is present, compute the pad needed to round it out to 32B alignment.
736 // if not present, pad will remain 0.
737 PaletteDescPad = 0;
738 if(PaletteDescBlockSize != 0)
739 {
740 size = TplHdrSize + TexDescBlockSize + PaletteDescBlockSize;
741
742 if(size < 32)
743 {
744 PaletteDescPad = 32 - size;
745 }
746 else if( (size % 32) != 0 )
747 {
748 PaletteDescPad = 32 - (size % 32);
749 }
750 }
751
752 // offset to this palette's data from the top of the file
753 bankOffset = TplHdrSize + TexDescBlockSize + PaletteDescBlockSize + PaletteDescPad;
754
755 PaletteBankSize = 0;
756
757 thisPalette = PlHead;
758 while( thisPalette )
759 {
760
761 thisPalette->tplPaletteBankOffset = bankOffset;
762
763 // compute the size of the required tpl buffer for this palette
764 // note: IA8 formatis not supported in this version.
765 switch(thisPalette->entryFormat)
766 {
767 case TPL_PALETTE_ENTRY_FMT_R5G6B5:
768 paletteEntrySize = 2;
769 break;
770 case TPL_PALETTE_ENTRY_FMT_RGB5A3:
771 paletteEntrySize = 2;
772 break;
773 default:
774 TCErrorMsg( "TCSetTplPaletteValues: unknown entry format for palette %d\n", thisPalette->index );
775 return;
776 break;
777 }
778
779 // compute buffer size for palette.
780 // all of these will align to 32B automatically
781 // in final data conversion, unused entries will be zeroed out.
782 // maximum palette size is 16k entries
783 if( (thisPalette->palPtr->numEntry == 0) || (thisPalette->palPtr->numEntry > 16384) )
784 {
785 TCErrorMsg( "TCSetTplPaletteValues: num entries out of range for palette %d\n", thisPalette->index );
786 return;
787 }
788 else
789 {
790 thisPalette->tplBufferSize = ((thisPalette->palPtr->numEntry + 15) & 0xFFF0) * paletteEntrySize;
791 }
792
793 // bank offset and total bank size update continuously
794 bankOffset += thisPalette->tplBufferSize;
795 PaletteBankSize += thisPalette->tplBufferSize;
796
797 thisPalette = thisPalette->next;
798
799 } // end while
800 }
801
802 /*>*******************************(*)*******************************<*/
803 // traverse the sorted image list and compute the 'tpl' values including the
804 // data buffer sizes
805 /*>*******************************(*)*******************************<*/
TCSetTplImageValues(void)806 static void TCSetTplImageValues ( void )
807 {
808 TCImage* thisImage;
809 u32 bankOffset;
810 u32 size;
811
812
813 // compute the pad needed to round the image descriptor block out to 32B alignment.
814 ImageDescPad = 0;
815
816 size = TplHdrSize + TexDescBlockSize + PaletteDescBlockSize
817 + PaletteDescPad + PaletteBankSize + ImageDescBlockSize;
818
819 if(size < 32)
820 {
821 ImageDescPad = 32 - size;
822 }
823 else if( (size % 32) != 0 )
824 {
825 ImageDescPad = 32 - (size % 32);
826 }
827
828 // offset to image data from the top of the file
829 bankOffset = TplHdrSize + TexDescBlockSize + PaletteDescBlockSize
830 + PaletteDescPad + PaletteBankSize + ImageDescBlockSize + ImageDescPad;
831
832 ImageBankSize = 0;
833
834 thisImage = ImHead;
835 while( thisImage )
836 {
837 // note: image buffer size is determined by colorLayer->height, colorLayer->width,
838 // final pixel format, mipmaps and padding requirements.
839
840 thisImage->tplImageBankOffset = bankOffset;
841 thisImage->tplBufferSize = TCComputeTplMipMapImageBufferSize( thisImage );
842
843 // bank offset and total bank size update continuously
844 bankOffset += thisImage->tplBufferSize;
845 ImageBankSize += thisImage->tplBufferSize;
846
847 thisImage = thisImage->next;
848 }
849 }
850
851 /*>*******************************(*)*******************************<*/
852 // compute the actual .tpl file offsets for each texture descriptor.
853 // this must be called after .tpl values have been set for images and
854 // palettes. all lists must already be sorted
855 /*>*******************************(*)*******************************<*/
TCSetTplTextureValues(void)856 static void TCSetTplTextureValues ( void )
857 {
858 TCTexture* thisTex;
859 TCImage* thisImage;
860 TCPalette* thisPalette;
861 u32 paletteDescOffset, imageDescOffset;
862 u32 pos;
863
864
865 // offsets from top of file to the start of each descriptor block
866 paletteDescOffset = TplHdrSize + TexDescBlockSize;
867
868 imageDescOffset = TplHdrSize + TexDescBlockSize + PaletteDescBlockSize +
869 PaletteDescPad + PaletteBankSize;
870
871 thisTex = TxHead;
872 while( thisTex )
873 {
874 // compute offsets from the top of the file
875 // to the given image/palette descriptor (NOT to the actual data)
876
877 thisImage = TCFindImageByIndex( thisTex->image );
878 TCAssertMsg( (thisImage != NULL), "TCSetTplTextureValues: no matching image for texture %d\n", thisTex->index );
879
880 // find thisImage's position in the list
881 pos = TCFindImagePos( thisImage );
882 thisTex->tplImageOffset = imageDescOffset + ( pos * ImageDescSize);
883
884 // note: a texture must have an image, but doesn't require a palette
885 thisTex->tplPaletteOffset = 0;
886 if( thisTex->palette != TC_UNUSED )
887 {
888 thisPalette = TCFindPaletteByIndex( thisTex->palette );
889 pos = TCFindPalettePos( thisPalette );
890 thisTex->tplPaletteOffset = paletteDescOffset + ( pos * PaletteDescSize);
891 }
892
893 thisTex = thisTex->next;
894 }
895 }
896
897 /*>*******************************(*)*******************************<*/
898 // compute the size in bytes of a .tpl file image buffer
899 // include row and column padding to 32 byte alignment
900 // return the required buffer size on success or 0 on failure
901 /*>*******************************(*)*******************************<*/
TCComputeTplImageBufferSize(TCImage * thisImage)902 u32 TCComputeTplImageBufferSize ( TCImage* thisImage )
903 {
904 u32 size;
905
906
907 switch(thisImage->texelFormat)
908 {
909 case TPL_IMAGE_TEXEL_FMT_I4:
910 size = TCComputeTplImageBufferSize_4Bit(thisImage); break;
911 case TPL_IMAGE_TEXEL_FMT_I8:
912 size = TCComputeTplImageBufferSize_8Bit(thisImage); break;
913 case TPL_IMAGE_TEXEL_FMT_IA4:
914 size = TCComputeTplImageBufferSize_8Bit(thisImage); break;
915 case TPL_IMAGE_TEXEL_FMT_IA8:
916 size = TCComputeTplImageBufferSize_16Bit(thisImage); break;
917 case TPL_IMAGE_TEXEL_FMT_R5G6B5:
918 size = TCComputeTplImageBufferSize_16Bit(thisImage); break;
919 case TPL_IMAGE_TEXEL_FMT_RGB5A3:
920 size = TCComputeTplImageBufferSize_16Bit(thisImage); break;
921 case TPL_IMAGE_TEXEL_FMT_RGBA8:
922 size = TCComputeTplImageBufferSize_32Bit(thisImage); break;
923 case TPL_IMAGE_TEXEL_FMT_CI4:
924 size = TCComputeTplImageBufferSize_4Bit(thisImage); break;
925 case TPL_IMAGE_TEXEL_FMT_CI8:
926 size = TCComputeTplImageBufferSize_8Bit(thisImage); break;
927 case TPL_IMAGE_TEXEL_FMT_CI14_X2:
928 size = TCComputeTplImageBufferSize_16Bit(thisImage); break;
929 case TPL_IMAGE_TEXEL_FMT_CMP:
930 size = TCComputeTplImageBufferSize_Cmp(thisImage); break;
931 default:
932 TCErrorMsg( "TCComputeTplImageBufferSize: unknown output format for image %d\n", thisImage->index );
933 return 0;
934 break;
935 }
936
937 return size;
938 }
939
940 /*>*******************************(*)*******************************<*/
941 // 4-bit format = 8x8 texel block / 32B cache line
942 /*>*******************************(*)*******************************<*/
TCComputeTplImageBufferSize_4Bit(TCImage * thisImage)943 static u32 TCComputeTplImageBufferSize_4Bit ( TCImage* thisImage )
944 {
945 u32 tileCols, tileRows, size;
946 u32 width, height;
947
948 width = (thisImage->lyColor).width;
949 height = (thisImage->lyColor).height;
950
951 // need to pad tile columns out to 8 texels
952 tileCols = ((width + 7) >> 3);
953
954 // need to pad total # rows out to 8 texels
955 tileRows = ((height + 7) >> 3);
956
957 // = total # of tiles * 32B per tile
958 size = tileCols * tileRows * 32;
959 return size;
960 }
961
962 /*>*******************************(*)*******************************<*/
963 // 8-bit format = 4x8 texel block / 32B cache line
964 /*>*******************************(*)*******************************<*/
TCComputeTplImageBufferSize_8Bit(TCImage * thisImage)965 static u32 TCComputeTplImageBufferSize_8Bit ( TCImage* thisImage )
966 {
967 u32 tileCols, tileRows, size;
968 u32 width, height;
969
970
971 width = (thisImage->lyColor).width;
972 height = (thisImage->lyColor).height;
973
974 // need to pad tile columns out to 8 texels
975 tileCols = ((width + 7) >> 3);
976
977 // need to pad total # rows out to 4 texels
978 tileRows = ((height + 3) >> 2);
979
980 // = total # of tiles * 32B per tile
981 size = tileCols * tileRows * 32;
982 return size;
983 }
984
985 /*>*******************************(*)*******************************<*/
986 // 16-bit format = 4x4 texel block / 32B cache line
987 /*>*******************************(*)*******************************<*/
TCComputeTplImageBufferSize_16Bit(TCImage * thisImage)988 static u32 TCComputeTplImageBufferSize_16Bit ( TCImage* thisImage )
989 {
990 u32 tileCols, tileRows, size;
991 u32 width, height;
992
993
994 width = (thisImage->lyColor).width;
995 height = (thisImage->lyColor).height;
996
997 // need to pad final tile out to 4 texels
998 tileCols = ((width + 3) >> 2);
999
1000 // need to pad total # rows out to 4 texels
1001 tileRows = ((height + 3) >> 2);
1002
1003 // = total # of tiles * 32B per tile
1004 size = tileCols * tileRows * 32;
1005 return size;
1006 }
1007
1008 /*>*******************************(*)*******************************<*/
1009 // 32-bit format = 4x4 texel block, 32B cache line, 2 lines needed
1010 /*>*******************************(*)*******************************<*/
TCComputeTplImageBufferSize_32Bit(TCImage * thisImage)1011 static u32 TCComputeTplImageBufferSize_32Bit (TCImage* thisImage )
1012 {
1013 u32 tileCols, tileRows, size;
1014 u32 width, height;
1015
1016
1017 width = (thisImage->lyColor).width;
1018 height = (thisImage->lyColor).height;
1019
1020 // need to pad final tile out to 4 texels
1021 tileCols = ((width + 3) >> 2);
1022
1023 // need to pad total # rows out to 4 texels
1024 tileRows = ((height + 3) >> 2);
1025
1026 // = total # of tiles in the padded image * 32B per tile * 2 blocks of data
1027 size = tileCols * tileRows * 32 * 2;
1028 return size;
1029 }
1030
1031 /*>*******************************(*)*******************************<*/
1032 // CMP format = 8x8 texel block / 32B cache line
1033 // breakdown: 1 4x4 texel block = 32-bits for texel indices, + 32-bits for 2 16-bit colors
1034 // total = 64b or 8B per 4x4 texel block.
1035 /*>*******************************(*)*******************************<*/
TCComputeTplImageBufferSize_Cmp(TCImage * thisImage)1036 static u32 TCComputeTplImageBufferSize_Cmp ( TCImage* thisImage )
1037 {
1038 u32 tileRows, tileCols, size;
1039 u32 width, height;
1040
1041
1042 width = (thisImage->lyColor).width;
1043 height = (thisImage->lyColor).height;
1044
1045 // must pad any image < 8 texels out to 8 texel boundary
1046
1047 // these are the 8x8 tpl tiles
1048 tileCols = ((width + 7) >> 3);
1049 tileRows = ((height + 7) >> 3);
1050
1051 size = (tileRows * tileCols * 32);
1052 return size;
1053 }
1054
1055 /*>*******************************(*)*******************************<*/
1056 // palettes are stored at 16-entry granularity, 32B word
1057 // (entries 0x0 to 0xF) per line with 0x00 at address 0.
1058 /*>*******************************(*)*******************************<*/
TCWriteTplPaletteBank(FILE * fp,u32 total,u8 * tplPrev,u32 * plFlags)1059 static u32 TCWriteTplPaletteBank ( FILE* fp, u32 total, u8* tplPrev, u32* plFlags )
1060 {
1061 u32 i;
1062 u32 numBlocks;
1063 u32 bytesWritten = 0;
1064 TCPalette* plPtr;
1065 u32 blockSize = 32; // ( 16 entry/block x 2B/entry )
1066 void* dataPtr;
1067 u32 (*palFn)( FILE* fp, TCPalette* pal, u32 start ) = NULL;
1068 u32 pos;
1069
1070
1071 TCAssertMsg( (fp != NULL), "TCWriteTplPaletteBank: NULL file ptr\n" );
1072
1073
1074 // this list is already sorted from 1->n
1075 plPtr = PlHead;
1076 while( plPtr )
1077 {
1078 // if this palette's data can be copied over from the existing .tpl file,
1079 // use the offset stored in tplFlags
1080 if( tplPrev && plFlags )
1081 {
1082 pos = TCFindPalettePos( plPtr );
1083
1084 if( plFlags[pos] )
1085 {
1086 dataPtr = (void*)( tplPrev + plFlags[pos] );
1087 fwrite( dataPtr, plPtr->tplBufferSize, 1, fp );
1088 bytesWritten += plPtr->tplBufferSize;
1089
1090 plPtr = plPtr->next;
1091 continue;
1092 }
1093 }
1094
1095 // compute # of 16-entry blocks needed for actual entries
1096 numBlocks = ((plPtr->palPtr->numEntry + 15) >> 4);
1097
1098 // set the palette function depending on entry format
1099 switch( plPtr->entryFormat )
1100 {
1101 case TPL_PALETTE_ENTRY_FMT_R5G6B5:
1102 palFn = TCWritePaletteBlock_R5G6B5;
1103 break;
1104
1105 case TPL_PALETTE_ENTRY_FMT_RGB5A3: // note: if no alpha layer, all alphas are set to max.
1106 palFn = TCWritePaletteBlock_RGB5A3;
1107 break;
1108 default:
1109 TCErrorMsg( "TCWritePaletteBank: unknown entry format for palette %d\n", plPtr->index );
1110 return 0;
1111 break;
1112 }
1113
1114 for(i=0; i<numBlocks; i++)
1115 {
1116 bytesWritten += palFn( fp, plPtr, (i*16) );
1117 }
1118
1119 plPtr = plPtr->next;
1120
1121 } // end while( plPtr )
1122
1123 return bytesWritten;
1124 }
1125
1126 /*>*******************************(*)*******************************<*/
TCWritePaletteBlock_R5G6B5(FILE * fp,TCPalette * pal,u32 start)1127 static u32 TCWritePaletteBlock_R5G6B5 ( FILE* fp, TCPalette* pal, u32 start )
1128 {
1129 u8 r, g, b;
1130 u8* tplPtr;
1131 u16 u16Tmp;
1132 u32 entry, realEntries;
1133 u32 bytesWritten = 0, count = 0;
1134
1135
1136 realEntries = pal->palPtr->numEntry - start;
1137 if( realEntries > 16)
1138 {
1139 realEntries = 16;
1140 }
1141
1142 tplPtr = (u8*)(&u16Tmp);
1143
1144 for(entry=0; entry< realEntries; entry++)
1145 {
1146 TCGetPalTableValue( pal->palPtr, (start + entry), &r, &g, &b, NULL );
1147
1148 // pack entries in big-endian format
1149 *tplPtr = ( ( r & 0xF8) | (g >> 5) ); // byte 0 is 5 bits red, upper 3 bits of green
1150 *(tplPtr + 1) = ( ((g & 0x1C) << 3) | (b >> 3) ); // byte 1 is lower 3 bits of green, 5 bits blue
1151
1152 if( (count = fwrite( &u16Tmp, 2, 1, fp )) != 1 )
1153 {
1154 TCErrorMsg( "WritePaletteBlockRGB565: error in fwrite for palette %d\n", pal->index );
1155 return 0;
1156 }
1157
1158 bytesWritten += 2;
1159 }
1160
1161 // pad unused entries with zeros
1162 u16Tmp = 0;
1163 for(entry; entry<16; entry++)
1164 {
1165 if( (count = fwrite( &u16Tmp, 2, 1, fp )) != 1 )
1166 {
1167 TCErrorMsg( "WritePaletteBlockRGB565: error in fwrite for palette %d\n", pal->index );
1168 return 0;
1169 }
1170 bytesWritten += 2;
1171 }
1172
1173 return bytesWritten;
1174 }
1175
1176 /*>*******************************(*)*******************************<*/
TCWritePaletteBlock_RGB5A3(FILE * fp,TCPalette * pal,u32 start)1177 static u32 TCWritePaletteBlock_RGB5A3 ( FILE* fp, TCPalette* pal, u32 start )
1178 {
1179 u8 r, g, b, a;
1180 u8* tplPtr;
1181 u32 entry, realEntries;
1182 u16 u16Tmp;
1183 u32 bytesWritten = 0, count = 0;
1184
1185
1186 realEntries = pal->palPtr->numEntry - start;
1187 if( realEntries > 16)
1188 {
1189 realEntries = 16;
1190 }
1191
1192 tplPtr = (u8*)(&u16Tmp);
1193
1194 for(entry=0; entry< realEntries; entry++)
1195 {
1196 TCGetPalTableValue( pal->palPtr, (start + entry), &r, &g, &b, &a );
1197
1198 if( a == 0xFF ) // fully opaque texel- set alpha to 1-bit format
1199 {
1200 // pack in 5551 format, alpha bit is set to 1
1201 *tplPtr = ( (a & 0x80) | ((r & 0xF8) >> 1) | (g >> 6) ); // byte0 is 1 bit alpha, upper 5-bits
1202 *(tplPtr + 1) = ( ((g & 0x38) << 2) | (b >> 3) ); // byte1 is bits 3-5 of green, upper 5 of blue
1203 }
1204
1205 else // 03444 format
1206 {
1207 a = (a >> 1) & 0x70; // keep 3 msbs shifted over by 1, msb set to 0
1208
1209 *tplPtr = ( a | ((r & 0xF0) >> 4) ); // byte0 is msb = 0, 3 bits alpha, 4 bits red
1210 *(tplPtr + 1) = ( (g & 0xF0) | ( b >> 4) ); // byte1 is 4 bits green, 4 bits blue
1211 }
1212
1213 if( (count = fwrite( &u16Tmp, 2, 1, fp )) != 1 )
1214 {
1215 TCErrorMsg( "WritePaletteBlockRGB5A3: error in fwrite for palette %d\n", pal->index );
1216 return 0;
1217 }
1218 bytesWritten += 2;
1219 }
1220
1221 // pad unused entries with zeros
1222 u16Tmp = 0;
1223 for(entry; entry<16; entry++)
1224 {
1225 if( (count = fwrite( &u16Tmp, 2, 1, fp )) != 1 )
1226 {
1227 TCErrorMsg( "WritePaletteBlockRGB5A3: error in fwrite for palette %d\n", pal->index );
1228 return 0;
1229 }
1230 bytesWritten += 2;
1231 }
1232
1233 return bytesWritten;
1234 }
1235
1236 /*>*******************************(*)*******************************<*/
1237 // do this after all .tpl values have been set.
1238 // allocate a (tpl) data buffer, perform image conversion
1239 // using colorLayer + alphaLayer to specific .tpl format
1240 /*>*******************************(*)*******************************<*/
TCWriteTplImageBank(FILE * fp,u32 total,u8 * tplPrev,u32 * imFlags)1241 static u32 TCWriteTplImageBank ( FILE* fp, u32 total, u8* tplPrev, u32* imFlags )
1242 {
1243 TCImage* imPtr;
1244 TCSrcImage* siPtr;
1245 TCFilePtr dfPtr;
1246 u32 bytesWritten = 0;
1247 void* dataPtr;
1248 u32 pos;
1249
1250
1251 TCAssertMsg( (fp != NULL), "TCWriteTplImageBank: NULL file ptr\n" );
1252
1253
1254 // this list is already sorted in ascending order
1255 imPtr = ImHead;
1256 while( imPtr )
1257 {
1258 // this data block can be copied over from the existing .tpl file
1259 // using the offset stored in tplFlags
1260 if( tplPrev && imFlags )
1261 {
1262 pos = TCFindImagePos( imPtr );
1263 if( imFlags[pos] )
1264 {
1265 dataPtr = (void*)( tplPrev + imFlags[pos] );
1266 fwrite( dataPtr, imPtr->tplBufferSize, 1, fp );
1267 bytesWritten += imPtr->tplBufferSize;
1268
1269 imPtr = imPtr->next;
1270 continue;
1271 }
1272 }
1273
1274 // otherwise, if the .tpl file is new or if a partial update is required,
1275 // convert and write the image block
1276
1277
1278 // if alpha layer comes from a different srcImage, read another file.
1279 // note: do this first so that dfPtr is read second for color layer.
1280 // this allows the same dfPtr to be used in the switch statements
1281 // below for layer conversion .
1282 if( imPtr->alphaSrcImage != TC_UNUSED )
1283 {
1284 siPtr = TCFindSrcImageByIndex( imPtr->alphaSrcImage );
1285 dfPtr = TCReadFile( siPtr->fileName );
1286
1287 TCMakeImAlphaLayer( dfPtr, &(imPtr->lyAlpha) );
1288 }
1289
1290 // if color index == alpha index, ReadFile will simply
1291 // return the cached file
1292 siPtr = TCFindSrcImageByIndex( imPtr->colorSrcImage );
1293 dfPtr = TCReadFile( siPtr->fileName );
1294
1295 // make the color layer from the decoded file.
1296 TCMakeImColorLayer( dfPtr, &(imPtr->lyColor) );
1297
1298 // perform any required layer conversions:
1299 // there are only 2 color layer types at this point: RGB24 and CI16
1300 // color info. must be present; alpha may not be
1301 switch( imPtr->lyColor.type )
1302 {
1303 // if layer format is CI16 but conversion format is
1304 // truecolor, convert the CI layer to an rgb format.
1305 case LY_IMAGE_COLOR_CI16:
1306
1307 switch( imPtr->texelFormat )
1308 {
1309 case TPL_IMAGE_TEXEL_FMT_I4: // all fall through
1310 case TPL_IMAGE_TEXEL_FMT_I8:
1311
1312 case TPL_IMAGE_TEXEL_FMT_IA4:
1313 case TPL_IMAGE_TEXEL_FMT_IA8:
1314
1315 case TPL_IMAGE_TEXEL_FMT_R5G6B5:
1316
1317 case TPL_IMAGE_TEXEL_FMT_RGB5A3:
1318 case TPL_IMAGE_TEXEL_FMT_RGBA8:
1319
1320 case TPL_IMAGE_TEXEL_FMT_CMP:
1321
1322 TCConvertCI_To_RGB( dfPtr, imPtr );
1323 break;
1324 }
1325 break;
1326
1327 // if layer format is RGB24, and destination format is CI,
1328 // tc cannot convert it.
1329 case LY_IMAGE_COLOR_RGB24:
1330
1331 switch( imPtr->texelFormat )
1332 {
1333 case TPL_IMAGE_TEXEL_FMT_CI4: // all fall through
1334 case TPL_IMAGE_TEXEL_FMT_CI8:
1335 case TPL_IMAGE_TEXEL_FMT_CI14_X2:
1336
1337 TCErrorMsg( "WriteTplImageBank: attempt to convert an RGB image %s to CI format\n", dfPtr->name );
1338 return 0;
1339 break;
1340 }
1341 break;
1342
1343 } // end switch( imPtr->lyColor.type )
1344
1345 // once pre-conversion is complete, convert and write the image
1346 bytesWritten += TCWriteTplImageMipMaps( fp, imPtr );
1347
1348 // free up image layer memory for the next pass
1349 if( imPtr->lyColor.data != NULL )
1350 {
1351 TCFree( (void**)(&imPtr->lyColor.data) );
1352 imPtr->lyColor.data = NULL;
1353 }
1354 if( imPtr->alphaSrcImage != 0 )
1355 {
1356 if( (imPtr->lyAlpha).data != NULL )
1357 {
1358 TCFree( (void**)(&imPtr->lyAlpha.data) );
1359 imPtr->lyAlpha.data = NULL;
1360 }
1361 }
1362
1363 imPtr = imPtr->next;
1364
1365 } // end while
1366
1367 return bytesWritten;
1368 }
1369
1370 /*>*******************************(*)*******************************<*/
1371 // WriteTplImage_I4
1372 //
1373 // convert from layer to final hw format
1374 // 8x8 texel tiles @ 4B per row, 32B per tile
1375 //
1376 // note: intensity comes in 3 flavors:
1377 // LY_IMAGE_COLOR_I8, LY_IMAGE_COLOR_RGB24, LY_IMAGE_COLOR_CI16
1378 // for color-indexed, use the indices directly as intensity values
1379 /*>*******************************(*)*******************************<*/
TCWriteTplImage_I4(TCLayer * colorLayer,u8 * tplBuffer)1380 void TCWriteTplImage_I4 ( TCLayer* colorLayer, u8* tplBuffer )
1381 {
1382 u32 numTileRows, tileRow;
1383 u32 numTileCols, tileCol;
1384 u8* dstPtr;
1385 u32 width, height;
1386
1387
1388 width = colorLayer->width;
1389 height = colorLayer->height;
1390
1391 // number of 8x8 texel tile cols, rows including any partial tiles
1392 numTileCols = ((width + 7) >> 3);
1393 numTileRows = ((height + 7) >> 3);
1394
1395 dstPtr = tplBuffer;
1396
1397 // numTileRows, numTileCols includes any partial tiles
1398 for( tileRow=0; tileRow<numTileRows; tileRow++ )
1399 {
1400 for(tileCol=0; tileCol<numTileCols; tileCol++)
1401 {
1402 TCPackTile_I4( colorLayer, (tileCol * 8), (tileRow * 8), dstPtr);
1403 dstPtr += 32; // next 32B cache line
1404 }
1405 }
1406 }
1407
1408 /*>*******************************(*)*******************************<*/
1409 // TCPackTile_I4
1410 //
1411 // 8x8 tile
1412 // x and y represent starting texel position of this tile
1413 /*>*******************************(*)*******************************<*/
TCPackTile_I4(TCLayer * srcLayer,u32 x,u32 y,u8 * dstPtr)1414 static void TCPackTile_I4 ( TCLayer* srcLayer, u32 x, u32 y, u8* dstPtr )
1415 {
1416 u16 ria;
1417 u8 g, b;
1418 u32 row, col;
1419 u32 realRows, realCols;
1420 u8* tilePtr;
1421
1422
1423 // dstPtr is already zeroed out, so this will take care of padding issue
1424 // 'realRows', 'realCols' represent actual source image texels remaining
1425 realRows = srcLayer->height - y;
1426 realCols = srcLayer->width - x;
1427
1428 if( realRows > 8)
1429 realRows = 8;
1430
1431 if(realCols > 8)
1432 realCols = 8;
1433
1434 // pack 32B tile from most-sig. texel to least sig. texel
1435 for(row=0; row<realRows; row++)
1436 {
1437 tilePtr = dstPtr + (row * 4); // move 4 bytes (8 4-bit texels) per row
1438 // need to reset ptr each row to account for
1439 // column padding
1440 for(col=0; col<realCols; col++)
1441 {
1442
1443 TCGetLayerValue( srcLayer, (x+col), (y+row), &ria, &g, &b );
1444
1445 // for LY_IMAGE_COLOR_CI16, use low 4 bits of ria (0 to 15).
1446 // for LY_IMAGE_COLOR_RGB24, average the 3 color values
1447 if( srcLayer->type == LY_IMAGE_COLOR_RGB24 )
1448 {
1449 ria = ( ( ria + g + b ) / 3 );
1450 }
1451 else if( srcLayer->type == LY_IMAGE_COLOR_CI16 )
1452 {
1453 ria <<= 4;
1454 }
1455
1456 if( (col % 2) == 0 ) // on even iterations, pack the high 4-bits
1457 {
1458 *tilePtr = (ria & 0x00F0);
1459 }
1460 else // on odd iterations, pack the high 4-bits
1461 { // and move to the next byte
1462 *tilePtr |= ((ria & 0x00F0) >> 4);
1463 tilePtr++;
1464 }
1465 }
1466 }
1467 }
1468
1469
1470 /*>*******************************(*)*******************************<*/
1471 // WriteTplImage_I8
1472 //
1473 // convert from layer to final hw format
1474 // 4x8 texel tiles @ 8B per row, 32B per tile
1475 //
1476 // note: color layer comes in 3 formats:
1477 // LY_IMAGE_COLOR_I8, LY_IMAGE_COLOR_RGB24, LY_IMAGE_COLOR_CI16.
1478 // for indexed color, use the index directly as the
1479 // intensity value
1480 /*>*******************************(*)*******************************<*/
TCWriteTplImage_I8(TCLayer * colorLayer,u8 * tplBuffer)1481 void TCWriteTplImage_I8 ( TCLayer* colorLayer, u8* tplBuffer )
1482 {
1483 u32 numTileRows, tileRow;
1484 u32 numTileCols, tileCol;
1485 u8* dstPtr;
1486 u32 width, height;
1487
1488
1489 width = colorLayer->width;
1490 height = colorLayer->height;
1491
1492 // number of 4x8 texel tile cols, rows including any partial tiles
1493 numTileCols = ((width + 7) >> 3);
1494 numTileRows = ((height + 3) >> 2);
1495
1496 dstPtr = tplBuffer;
1497
1498 // numTileRows, numTileCols includes any partial tiles
1499 for( tileRow=0; tileRow<numTileRows; tileRow++ )
1500 {
1501 for(tileCol=0; tileCol<numTileCols; tileCol++)
1502 {
1503 TCPackTile_I8( colorLayer, (tileCol * 8), (tileRow * 4), dstPtr);
1504 dstPtr += 32; // next 32B cache line
1505 }
1506 }
1507 }
1508
1509 /*>*******************************(*)*******************************<*/
1510 // TCPackTile_I8
1511 //
1512 // 4x8 tile
1513 // x and y represent starting texel position of this tile
1514 /*>*******************************(*)*******************************<*/
TCPackTile_I8(TCLayer * srcLayer,u32 x,u32 y,u8 * dstPtr)1515 static void TCPackTile_I8 ( TCLayer* srcLayer, u32 x, u32 y, u8* dstPtr )
1516 {
1517 u16 ria;
1518 u8 g, b;
1519 u32 row, col;
1520 u32 realRows, realCols;
1521 u8* tilePtr;
1522
1523
1524 // dstPtr is already zeroed out, so this will take care of padding issue
1525 // 'realRows', 'realCols' represent actual source image texels remaining
1526 realRows = srcLayer->height - y;
1527 realCols = srcLayer->width - x;
1528
1529 if( realRows > 4)
1530 realRows = 4;
1531
1532 if(realCols > 8)
1533 realCols = 8;
1534
1535 // pack 32B tile
1536 for(row=0; row<realRows; row++)
1537 {
1538 tilePtr = dstPtr + (row * 8); // move 8 bytes (8 8-bit texels) per row
1539 // need to reset ptr each row to account for
1540 // column padding
1541 for(col=0; col<realCols; col++)
1542 {
1543 TCGetLayerValue( srcLayer, (x+col), (y+row), &ria, &g, &b ); // fetch an 8-bit intensity value
1544
1545 // for LY_IMAGE_COLOR_CI16, use ria (index) directly as intensity value.
1546 // for LY_IMAGE_COLOR_RGB24, average the 3 color values
1547 if( srcLayer->type == LY_IMAGE_COLOR_RGB24 )
1548 {
1549 ria = ( ( ria + g + b ) / 3 );
1550 }
1551
1552 *tilePtr = (unsigned char)ria;
1553 tilePtr++;
1554 }
1555 }
1556 }
1557
1558 /*>*******************************(*)*******************************<*/
1559 // WriteTplImage_IA4
1560 //
1561 // convert from layer to final hw format
1562 // 4x8 texel tiles @ 4B per row, 32B per tile
1563 //
1564 // note: source color layer must be in the format LY_IMAGE_COLOR_I8
1565 // if no alpha layer provided, all alphas set to max. value
1566 /*>*******************************(*)*******************************<*/
TCWriteTplImage_IA4(TCLayer * colorLayer,TCLayer * alphaLayer,u8 * tplBuffer)1567 void TCWriteTplImage_IA4 ( TCLayer* colorLayer, TCLayer* alphaLayer, u8* tplBuffer )
1568 {
1569 u32 numTileRows, tileRow;
1570 u32 numTileCols, tileCol;
1571 u8* dstPtr;
1572 u32 width, height;
1573
1574
1575 width = colorLayer->width;
1576 height = colorLayer->height;
1577
1578 // number of 4x8 texel tile cols, rows including any partial tiles
1579 numTileCols = ((width + 7) >> 3);
1580 numTileRows = ((height + 3) >> 2);
1581
1582 dstPtr = tplBuffer;
1583
1584 // numTileRows, numTileCols includes any partial tiles
1585 for( tileRow=0; tileRow<numTileRows; tileRow++ )
1586 {
1587 for(tileCol=0; tileCol<numTileCols; tileCol++)
1588 {
1589 TCPackTile_IA4( colorLayer, alphaLayer, (tileCol * 8), (tileRow * 4), dstPtr);
1590 dstPtr += 32; // next 32B cache line
1591 }
1592 }
1593 }
1594
1595 /*>*******************************(*)*******************************<*/
1596 // TCPackTile_IA4
1597 //
1598 // 4x8 tile
1599 // x and y represent starting texel position of this tile
1600 /*>*******************************(*)*******************************<*/
TCPackTile_IA4(TCLayer * colorLayer,TCLayer * alphaLayer,u32 x,u32 y,u8 * dstPtr)1601 static void TCPackTile_IA4 ( TCLayer* colorLayer, TCLayer* alphaLayer, u32 x, u32 y, u8* dstPtr )
1602 {
1603 u16 ria, a;
1604 u8 g, b;
1605 u32 row, col;
1606 u32 realRows, realCols;
1607 u8* tilePtr;
1608
1609
1610 // dstPtr is already zeroed out, so this will take care of padding issue
1611 // 'realRows', 'realCols' represent actual source image texels remaining
1612 realRows = colorLayer->height - y;
1613 realCols = colorLayer->width - x;
1614
1615 if( realRows > 4)
1616 realRows = 4;
1617
1618 if(realCols > 8)
1619 realCols = 8;
1620
1621 // pack 32B tile
1622 for(row=0; row<realRows; row++)
1623 {
1624 tilePtr = dstPtr + (row * 8); // move 8 bytes (8 8-bit texels) per row
1625 // need to reset ptr each row to account for
1626 // column padding
1627 for(col=0; col<realCols; col++)
1628 {
1629 if(alphaLayer)
1630 {
1631 TCGetLayerValue( alphaLayer, (x+col), (y+row), &a, 0, 0 );
1632 }
1633 else // set high 4 bits to max. alpha
1634 {
1635 a = 0x00F0;
1636 }
1637
1638 TCGetLayerValue( colorLayer, (x+col), (y+row), &ria, &g, &b );
1639
1640 // for LY_IMAGE_COLOR_CI16, use low 4 bits of ria.
1641 // for LY_IMAGE_COLOR_RGB24, average the 3 color values
1642 if( colorLayer->type == LY_IMAGE_COLOR_RGB24 )
1643 {
1644 ria = ( ( ria + g + b ) / 3 );
1645 }
1646 else if( colorLayer->type == LY_IMAGE_COLOR_CI16 )
1647 {
1648 ria <<= 4;
1649 }
1650
1651 *tilePtr = ( (a & 0xF0) | ((ria & 0x00F0) >> 4) ); // high 4-bits are alpha, low 4-bits are intensity
1652 tilePtr++;
1653 } // end for col loop
1654 } // end for row loop
1655 }
1656
1657 /*>*******************************(*)*******************************<*/
1658 // WriteTplImage_IA8
1659 //
1660 // convert from layer to final hw format
1661 // 4x4 texel tiles @ 8B per row, 32B per tile
1662 //
1663 // note: source color layer must be in the format LY_IMAGE_COLOR_I8.
1664 // if no alpha layer found, set all alphas to max. value
1665 /*>*******************************(*)*******************************<*/
TCWriteTplImage_IA8(TCLayer * colorLayer,TCLayer * alphaLayer,u8 * tplBuffer)1666 void TCWriteTplImage_IA8 ( TCLayer* colorLayer, TCLayer* alphaLayer, u8* tplBuffer )
1667 {
1668 u32 numTileRows, tileRow;
1669 u32 numTileCols, tileCol;
1670 u8* dstPtr;
1671 u32 width, height;
1672
1673
1674 width = colorLayer->width;
1675 height = colorLayer->height;
1676
1677 // number of 4x4 texel tile cols, rows including any partial tiles
1678 numTileCols = ((width + 3) >> 2);
1679 numTileRows = ((height + 3) >> 2);
1680
1681 dstPtr = tplBuffer;
1682
1683 // numTileRows, numTileCols includes any partial tiles
1684 for( tileRow=0; tileRow<numTileRows; tileRow++ )
1685 {
1686 for(tileCol=0; tileCol<numTileCols; tileCol++)
1687 {
1688 TCPackTile_IA8( colorLayer, alphaLayer, (tileCol * 4), (tileRow * 4), dstPtr);
1689 dstPtr += 32; // next 32B cache line
1690 }
1691 }
1692 }
1693
1694 /*>*******************************(*)*******************************<*/
1695 // TCPackTile_IA8
1696 //
1697 // 4x4 tile, 16-bit texels
1698 // x and y represent starting texel position of this tile
1699 /*>*******************************(*)*******************************<*/
TCPackTile_IA8(TCLayer * colorLayer,TCLayer * alphaLayer,u32 x,u32 y,u8 * dstPtr)1700 static void TCPackTile_IA8 ( TCLayer* colorLayer, TCLayer* alphaLayer, u32 x, u32 y, u8* dstPtr)
1701 {
1702 u16 ria;
1703 u8 g, b;
1704 u32 row, col;
1705 u32 realRows, realCols;
1706 u8* tilePtr;
1707
1708
1709 // dstPtr is already zeroed out, so this will take care of padding issue
1710 // 'realRows', 'realCols' represent actual source image texels remaining
1711 realRows = colorLayer->height - y;
1712 realCols = colorLayer->width - x;
1713
1714 if( realRows > 4)
1715 realRows = 4;
1716
1717 if(realCols > 4)
1718 realCols = 4;
1719
1720 // pack 32B tile
1721 for(row=0; row<realRows; row++)
1722 {
1723 tilePtr = dstPtr + (row * 8); // move 8 bytes (4 16-bit texels) per row
1724 // need to reset ptr each row to account for
1725 // column padding
1726 for(col=0; col<realCols; col++)
1727 {
1728 if(alphaLayer) // alpha is byte 0
1729 {
1730 TCGetLayerValue( alphaLayer, (x+col), (y+row), &ria, 0, 0 );
1731
1732 *tilePtr = (u8)ria;
1733 }
1734 else // set byte 0 to max. alpha
1735 {
1736 *tilePtr = 0xFF;
1737 }
1738 // color is byte 1
1739 TCGetLayerValue( colorLayer, (x+col), (y+row), &ria, &g, &b );
1740
1741 // for LY_IMAGE_COLOR_CI16, use ria (index) directly as intensity value.
1742 // for LY_IMAGE_COLOR_RGB24, average the 3 color values
1743 if( colorLayer->type == LY_IMAGE_COLOR_RGB24 )
1744 {
1745 ria = ( ( ria + g + b ) / 3 );
1746 }
1747
1748 *(tilePtr + 1) = (u8)ria;
1749
1750 tilePtr += 2;
1751 } // end for col loop
1752 } // end for row loop
1753 }
1754
1755 /*>*******************************(*)*******************************<*/
1756 // WriteTplImage_R5G6B5
1757 //
1758 // convert from layer to final hw format
1759 // 4x4 texel tiles @ 8B per row, 32B per tile
1760 // note: color layer must be in LY_IMAGE_COLOR_RGB24 format
1761 /*>*******************************(*)*******************************<*/
TCWriteTplImage_R5G6B5(TCLayer * colorLayer,u8 * tplBuffer)1762 void TCWriteTplImage_R5G6B5 ( TCLayer* colorLayer, u8* tplBuffer )
1763 {
1764 u32 numTileRows, tileRow;
1765 u32 numTileCols, tileCol;
1766 u8* dstPtr;
1767 u32 width, height;
1768
1769
1770 width = colorLayer->width;
1771 height = colorLayer->height;
1772
1773 // number of 4x4 texel tile cols, rows including any partial tiles
1774 numTileCols = ((width + 3) >> 2);
1775 numTileRows = ((height + 3) >> 2);
1776
1777 dstPtr = tplBuffer;
1778
1779 // numTileRows, numTileCols includes any partial tiles
1780 for( tileRow=0; tileRow<numTileRows; tileRow++ )
1781 {
1782 for(tileCol=0; tileCol<numTileCols; tileCol++)
1783 {
1784 TCPackTile_R5G6B5( colorLayer, (tileCol * 4), (tileRow * 4), dstPtr);
1785 dstPtr += 32; // next 32B cache line
1786 }
1787 }
1788 }
1789
1790 /*>*******************************(*)*******************************<*/
1791 // TCPackTile_R5G6B5
1792 //
1793 // 4x4 tile, 16-bit texels
1794 // x and y represent starting texel position of this tile
1795 /*>*******************************(*)*******************************<*/
TCPackTile_R5G6B5(TCLayer * colorLayer,u32 x,u32 y,u8 * dstPtr)1796 static void TCPackTile_R5G6B5 ( TCLayer* colorLayer, u32 x, u32 y, u8* dstPtr)
1797 {
1798 u16 ria;
1799 u32 row, col;
1800 u32 realRows, realCols;
1801 u8* tilePtr;
1802 u8 g, b;
1803
1804
1805 // dstPtr is already zeroed out, so this will take care of padding issue
1806 // 'realRows', 'realCols' represent actual source image texels remaining
1807 realRows = colorLayer->height - y;
1808 realCols = colorLayer->width - x;
1809
1810 if( realRows > 4)
1811 realRows = 4;
1812
1813 if(realCols > 4)
1814 realCols = 4;
1815
1816 // pack 32B tile
1817 for(row=0; row<realRows; row++)
1818 {
1819 tilePtr = dstPtr + (row * 8); // move 8 bytes (4 16-bit texels) per row
1820 // need to reset ptr each row to account for // column padding
1821 for(col=0; col<realCols; col++)
1822 {
1823 TCGetLayerValue( colorLayer, (x+col), (y+row), &ria, &g, &b );
1824
1825 *tilePtr = ( (ria & 0x00F8) | ((g & 0xE0) >> 5) ); // byte0 is upper 5 bits of red, upper 3 of green
1826 *(tilePtr + 1) = ( ((g & 0x1C) << 3) | ( b >> 3) ); // byte1 is lower 3 bits of green, upper 5 of blue
1827
1828 tilePtr += 2;
1829 }
1830 }
1831 }
1832
1833 /*>*******************************(*)*******************************<*/
1834 // WriteTplImage_RGB5A3
1835 //
1836 // convert from layer to final hw format
1837 // 4x4 texel tiles @ 8B per row, 32B per tile
1838 //
1839 // note: source color layer must be in the format LY_IMAGE_COLOR_RGB24.
1840 // if no alpha layer found, set all alphas to max. value
1841 /*>*******************************(*)*******************************<*/
TCWriteTplImage_RGB5A3(TCLayer * colorLayer,TCLayer * alphaLayer,u8 * tplBuffer)1842 void TCWriteTplImage_RGB5A3 ( TCLayer* colorLayer, TCLayer* alphaLayer, u8* tplBuffer )
1843 {
1844 u32 numTileRows, tileRow;
1845 u32 numTileCols, tileCol;
1846 u8* dstPtr;
1847 u32 width, height;
1848
1849
1850 width = colorLayer->width;
1851 height = colorLayer->height;
1852
1853 // number of 4x4 texel tile cols, rows including any partial tiles
1854 numTileCols = ((width + 3) >> 2);
1855 numTileRows = ((height + 3) >> 2);
1856
1857 dstPtr = tplBuffer;
1858
1859 // numTileRows, numTileCols includes any partial tiles
1860 for( tileRow=0; tileRow<numTileRows; tileRow++ )
1861 {
1862 for(tileCol=0; tileCol<numTileCols; tileCol++)
1863 {
1864 TCPackTile_RGB5A3( colorLayer, alphaLayer, (tileCol * 4), (tileRow * 4), dstPtr);
1865 dstPtr += 32; // next 32B cache line
1866 }
1867 }
1868 }
1869
1870 /*>*******************************(*)*******************************<*/
1871 // TCPackTile_RGB5A3
1872 //
1873 // 4x4 tile, 16-bit texels
1874 // x and y represent starting texel position of this tile
1875 /*>*******************************(*)*******************************<*/
TCPackTile_RGB5A3(TCLayer * colorLayer,TCLayer * alphaLayer,u32 x,u32 y,u8 * dstPtr)1876 static void TCPackTile_RGB5A3 ( TCLayer* colorLayer, TCLayer* alphaLayer, u32 x, u32 y, u8* dstPtr )
1877 {
1878 u32 row, col;
1879 u32 realRows, realCols;
1880 u8* tilePtr;
1881 u8 g, b;
1882 u16 ria, a;
1883
1884
1885 // dstPtr is already zeroed out, so this will take care of padding issue
1886 // 'realRows', 'realCols' represent actual source image texels remaining
1887 realRows = colorLayer->height - y;
1888 realCols = colorLayer->width - x;
1889
1890 if( realRows > 4)
1891 realRows = 4;
1892
1893 if(realCols > 4)
1894 realCols = 4;
1895
1896 // pack 32B tile
1897 for(row=0; row<realRows; row++)
1898 {
1899 tilePtr = dstPtr + (row * 8); // move 8 bytes (4 16-bit texels) per row
1900 // need to reset ptr each row to account for
1901 // column padding
1902 for(col=0; col<realCols; col++)
1903 {
1904 if(alphaLayer)
1905 {
1906 TCGetLayerValue( alphaLayer, (x+col), (y+row), &a, 0, 0 );
1907 }
1908 else
1909 {
1910 a = 0x00FF;
1911 }
1912
1913 TCGetLayerValue( colorLayer, (x+col), (y+row), &ria, &g, &b );
1914
1915 // check alpha to determine whether to pack color 5551 or 4443
1916
1917 // since hw replicates msbs, everything >= 224 of original alpha
1918 // will unpack as 255 ( 1110 0000 unpacks as 1111 1111 )
1919
1920 if( a >= 224 ) // pixel is opaque
1921 {
1922 // pack in 5551 format, msb is set to 1
1923 *tilePtr = ( (0x0080) | ((ria & 0xF8) >> 1) | (g >> 6) ); // byte0 is 1 bit alpha, upper 5-bits
1924 // of red, upper 2-bits of green
1925 *(tilePtr + 1) = ( ((g & 0x38) << 2) | (b >> 3) ); // byte1 is bits 3-5 of green, upper 5 of blue
1926 }
1927 else // pixel is translucent
1928 {
1929 // pack in 4443 format, shift alpha by 1 and set msb to 0
1930 *tilePtr = ( ( (a >> 1) & 0x70 ) | ((ria & 0xF0) >> 4) ); // byte0 is 1 bit 0, 3 alpha, 4-bits red
1931
1932 *(tilePtr + 1) = ( (g & 0xF0) | ((b & 0xF0) >> 4) ); // 4-bits green, 4-bits blue
1933 }
1934
1935 tilePtr += 2;
1936
1937 } // end for col loop
1938 } // end for row loop
1939 }
1940
1941 /*>*******************************(*)*******************************<*/
1942 // WriteTplImage_RGBA8
1943 //
1944 // convert from layer to final hw format
1945 // 2 4x4 texel tiles @ 8B per tile row, 32B per tile, 2 cache lines (64B) total
1946 //
1947 // AR tiles are stored contiguously in the low half of image->tplBuffer;
1948 // GB tiles are stored contiguously in the high half of image->tplBuffer;
1949 //
1950 // note: source color layer must be in the format LY_IMAGE_COLOR_RGB24.
1951 // if no alpha layer found, set all alphas to max. value
1952 /*>*******************************(*)*******************************<*/
TCWriteTplImage_RGBA8(TCLayer * colorLayer,TCLayer * alphaLayer,u8 * tplBuffer)1953 void TCWriteTplImage_RGBA8 ( TCLayer* colorLayer, TCLayer* alphaLayer, u8* tplBuffer )
1954 {
1955 u32 numTileRows, tileRow;
1956 u32 numTileCols, tileCol;
1957 u8* dstPtr;
1958 u32 width, height;
1959
1960
1961 width = colorLayer->width;
1962 height = colorLayer->height;
1963
1964 // number of 4x4 texel tile cols, rows including any partial tiles
1965 numTileCols = ((width + 3) >> 2);
1966 numTileRows = ((height + 3) >> 2);
1967
1968 dstPtr = tplBuffer;
1969
1970 // numTileRows, numTileCols includes any partial tiles
1971 for( tileRow=0; tileRow<numTileRows; tileRow++ )
1972 {
1973 for(tileCol=0; tileCol<numTileCols; tileCol++)
1974 {
1975 TCPackTile_RGBA8( colorLayer, alphaLayer, (tileCol * 4), (tileRow * 4), dstPtr );
1976 dstPtr += 64; // move to next 2 (32B) cache lines
1977 }
1978 }
1979 }
1980
1981 /*>*******************************(*)*******************************<*/
1982 // TCPackTile_RGBA8
1983 //
1984 // 4x4 tile, 16-bit texels
1985 // x and y represent starting texel position of this tile
1986 // pack AR in low half, GB in high half dest. buffer
1987 /*>*******************************(*)*******************************<*/
TCPackTile_RGBA8(TCLayer * colorLayer,TCLayer * alphaLayer,u32 x,u32 y,u8 * dstPtr)1988 static void TCPackTile_RGBA8 ( TCLayer* colorLayer, TCLayer* alphaLayer, u32 x, u32 y, u8* dstPtr )
1989 {
1990 u16 ria, a;
1991 u32 row, col;
1992 u32 realRows, realCols;
1993 u8* arPtr, *gbPtr;
1994 u8 g, b;
1995
1996
1997 // dstPtr is already zeroed out, so this will take care of padding issue
1998 // 'realRows', 'realCols' represent actual source image texels remaining
1999 realRows = colorLayer->height - y;
2000 realCols = colorLayer->width - x;
2001
2002 if( realRows > 4)
2003 realRows = 4;
2004
2005 if(realCols > 4)
2006 realCols = 4;
2007
2008 // pack 2 32B tiles
2009 for(row=0; row<realRows; row++)
2010 {
2011 // pack 2 cache lines at once
2012 arPtr = dstPtr + (row * 8); // move 8 bytes (4 16-bit texels) per row
2013 gbPtr = dstPtr + 32 + (row * 8); // need to reset ptr each row to account for
2014 // column padding
2015
2016 for(col=0; col<realCols; col++)
2017 {
2018 TCGetLayerValue( colorLayer, (x+col), (y+row), &ria, &g, &b );
2019
2020 if(alphaLayer)
2021 {
2022 TCGetLayerValue( alphaLayer, (x+col), (y+row), &a, 0, 0 );
2023 }
2024 else // set to max. alpha
2025 {
2026 a = 0xFF;
2027 }
2028
2029 *arPtr = (u8)a; // alpha is byte 0, red is byte 1
2030 *(arPtr + 1) = (u8)ria;
2031
2032 *gbPtr = g; // green is byte 0, blue is byte 1
2033 *(gbPtr + 1) = b;
2034
2035 arPtr += 2;
2036 gbPtr += 2;
2037
2038 } // end for col loop
2039 } // end for row loop
2040 }
2041
2042 /*>*******************************(*)*******************************<*/
2043 // WriteTplImage_CI4
2044 //
2045 // convert from layer to final hw format
2046 // 8x8 texel tiles @ 4B per row, 32B per tile
2047 //
2048 // note: source color layer must be in the format LY_IMAGE_COLOR_CI8
2049 /*>*******************************(*)*******************************<*/
TCWriteTplImage_CI4(TCLayer * colorLayer,u8 * tplBuffer)2050 void TCWriteTplImage_CI4 ( TCLayer* colorLayer, u8* tplBuffer )
2051 {
2052 u32 numTileRows, tileRow;
2053 u32 numTileCols, tileCol;
2054 u8* dstPtr;
2055 u32 width, height;
2056
2057
2058 width = colorLayer->width;
2059 height = colorLayer->height;
2060
2061 // number of 8x8 texel tile cols, rows including any partial tiles
2062 numTileCols = ((width + 7) >> 3);
2063 numTileRows = ((height + 7) >> 3);
2064
2065 dstPtr = tplBuffer;
2066
2067 // numTileRows, numTileCols includes any partial tiles
2068 for( tileRow=0; tileRow<numTileRows; tileRow++ )
2069 {
2070 for(tileCol=0; tileCol<numTileCols; tileCol++)
2071 {
2072 TCPackTile_CI4( colorLayer, (tileCol * 8), (tileRow * 8), dstPtr);
2073 dstPtr += 32; // next 32B cache line
2074 }
2075 }
2076 }
2077
2078 /*>*******************************(*)*******************************<*/
2079 // TCPackTile_CI4
2080 //
2081 // 8x8 tile
2082 // x and y represent starting texel position of this tile
2083 // assume the 8-bit layer indices only run from 0 to 15,
2084 // so take the low 4 bits as is.
2085 /*>*******************************(*)*******************************<*/
TCPackTile_CI4(TCLayer * srcLayer,u32 x,u32 y,u8 * dstPtr)2086 static void TCPackTile_CI4 ( TCLayer* srcLayer, u32 x, u32 y, u8* dstPtr )
2087 {
2088 u16 ria;
2089 u32 row, col;
2090 u32 realRows, realCols;
2091 u8* tilePtr;
2092
2093
2094 // dstPtr is already zeroed out, so this will take care of padding issue
2095 // 'realRows', 'realCols' represent actual source image texels remaining
2096 realRows = srcLayer->height - y;
2097 realCols = srcLayer->width - x;
2098
2099 if( realRows > 8)
2100 realRows = 8;
2101
2102 if(realCols > 8)
2103 realCols = 8;
2104
2105 // pack 32B tile
2106 for(row=0; row<realRows; row++)
2107 {
2108 tilePtr = dstPtr + (row * 4); // move 4 bytes (8 4-bit texels) per row
2109 // need to reset ptr each row to account for
2110 // column padding
2111 for(col=0; col<realCols; col++)
2112 {
2113 TCGetLayerValue( srcLayer, (x+col), (y+row), &ria, 0, 0 ); // fetch an 8-bit color-index value
2114 // and keep just the low 4 bits.
2115 if( col %2 == 0 )
2116 {
2117 *tilePtr = ((ria & 0x000F) << 4);
2118 }
2119
2120 else
2121 {
2122 *tilePtr |= (ria & 0x000F);
2123 tilePtr++;
2124 }
2125 }
2126 }
2127 }
2128
2129 /*>*******************************(*)*******************************<*/
2130 // WriteTplImage_CI8
2131 //
2132 // convert from layer to final hw format
2133 // 4x8 texel tiles @ 8B per row, 32B per tile
2134 //
2135 // note: source color layer must be in the format LY_IMAGE_COLOR_CI8
2136 /*>*******************************(*)*******************************<*/
TCWriteTplImage_CI8(TCLayer * colorLayer,u8 * tplBuffer)2137 void TCWriteTplImage_CI8 ( TCLayer* colorLayer, u8* tplBuffer )
2138 {
2139 u32 numTileRows, tileRow;
2140 u32 numTileCols, tileCol;
2141 u8* dstPtr;
2142 u32 width, height;
2143
2144
2145 width = colorLayer->width;
2146 height = colorLayer->height;
2147
2148 // number of 4x8 texel tile cols, rows including any partial tiles
2149 numTileCols = ((width + 7) >> 3);
2150 numTileRows = ((height + 3) >> 2);
2151
2152 dstPtr = tplBuffer;
2153
2154 // numTileRows, numTileCols includes any partial tiles
2155 for( tileRow=0; tileRow<numTileRows; tileRow++ )
2156 {
2157 for(tileCol=0; tileCol<numTileCols; tileCol++)
2158 {
2159 TCPackTile_CI8( colorLayer, (tileCol * 8), (tileRow * 4), dstPtr);
2160 dstPtr += 32; // next 32B cache line
2161 }
2162 }
2163 }
2164
2165 /*>*******************************(*)*******************************<*/
2166 // TCPackTile_CI8
2167 //
2168 // 4x8 tile
2169 // x and y represent starting texel position of this tile
2170 /*>*******************************(*)*******************************<*/
TCPackTile_CI8(TCLayer * srcLayer,u32 x,u32 y,u8 * dstPtr)2171 static void TCPackTile_CI8 ( TCLayer* srcLayer, u32 x, u32 y, u8* dstPtr )
2172 {
2173 u16 ria;
2174 u32 row, col;
2175 u32 realRows, realCols;
2176 u8* tilePtr;
2177
2178
2179 // dstPtr is already zeroed out, so this will take care of padding issue
2180 // 'realRows', 'realCols' represent actual source image texels remaining
2181 realRows = srcLayer->height - y;
2182 realCols = srcLayer->width - x;
2183
2184 if( realRows > 4)
2185 realRows = 4;
2186
2187 if(realCols > 8)
2188 realCols = 8;
2189
2190 // pack 32B tile
2191 for(row=0; row<realRows; row++)
2192 {
2193 tilePtr = dstPtr + (row * 8); // move 8 bytes (8 8-bit texels) per row
2194 // need to reset ptr each row to account for
2195 // column padding
2196 for(col=0; col<realCols; col++)
2197 {
2198 TCGetLayerValue( srcLayer, (x+col), (y+row), &ria, 0, 0 ); // fetch an 8-bit color index value
2199
2200 *tilePtr = (unsigned char)ria;
2201 tilePtr++;
2202 }
2203 }
2204 }
2205
2206 /*>*******************************(*)*******************************<*/
2207 // WriteTplImage_CI12_A4
2208 //
2209 // convert from layer to final hw format
2210 // 4x4 texel tiles @ 8B per row, 32B per tile
2211 //
2212 // note: source color layer must be in the format LY_IMAGE_COLOR_CI16
2213 /*>*******************************(*)*******************************<*/
TCWriteTplImage_CI14_X2(TCLayer * colorLayer,u8 * tplBuffer)2214 void TCWriteTplImage_CI14_X2 ( TCLayer* colorLayer, u8* tplBuffer )
2215 {
2216 u32 numTileRows, tileRow;
2217 u32 numTileCols, tileCol;
2218 u8* dstPtr;
2219 u32 width, height;
2220
2221
2222 width = colorLayer->width;
2223 height = colorLayer->height;
2224
2225 // number of 4x4 texel tile cols, rows including any partial tiles
2226 numTileCols = ((width + 3) >> 2);
2227 numTileRows = ((height + 3) >> 2);
2228
2229 dstPtr = tplBuffer;
2230
2231 // numTileRows, numTileCols includes any partial tiles
2232 for( tileRow=0; tileRow<numTileRows; tileRow++ )
2233 {
2234 for(tileCol=0; tileCol<numTileCols; tileCol++)
2235 {
2236 TCPackTile_CI14_X2( colorLayer, (tileCol * 4), (tileRow * 4), dstPtr);
2237 dstPtr += 32; // next 32B cache line
2238 }
2239 }
2240 }
2241
2242 /*>*******************************(*)*******************************<*/
2243 // TCPackTile_CI14_X2
2244 //
2245 // 4x4 tile, 16-bit texels
2246 // x and y represent starting texel position of this tile
2247 //
2248 // note: for color index, although 16-bits are read, we are only
2249 // expecting indices to reach a max. of 12-bits; no down-shifting
2250 // of lower 4-bits is used
2251 /*>*******************************(*)*******************************<*/
TCPackTile_CI14_X2(TCLayer * colorLayer,u32 x,u32 y,u8 * dstPtr)2252 static void TCPackTile_CI14_X2 ( TCLayer* colorLayer, u32 x, u32 y, u8* dstPtr )
2253 {
2254 u16 ria;
2255 u32 row, col;
2256 u32 realRows, realCols;
2257 u16* tilePtr;
2258
2259
2260 // dstPtr is already zeroed out, so this will take care of padding issue
2261 // 'realRows', 'realCols' represent actual source image texels remaining
2262 realRows = colorLayer->height - y;
2263 realCols = colorLayer->width - x;
2264
2265 if( realRows > 4)
2266 realRows = 4;
2267
2268 if(realCols > 4)
2269 realCols = 4;
2270
2271 // pack 32B tile
2272 for(row=0; row<realRows; row++)
2273 {
2274 tilePtr = (u16*)( (u8*)dstPtr + (row * 8) ); // move 8 bytes (4 16-bit texels) per row
2275 // need to reset ptr each row to account for
2276 // column padding
2277 for(col=0; col<realCols; col++)
2278 {
2279 TCGetLayerValue( colorLayer, (x+col), (y+row), &ria, 0, 0 );
2280
2281 // keep only the low 14 bits
2282 ria = ria & 0x3FFF;
2283
2284 // pack in big-endian format
2285 TCFixEndian( (u8*)(&ria), 2 );
2286 *tilePtr++ = ria;
2287 }
2288 }
2289 }
2290
2291 /*>*******************************(*)*******************************<*/
2292 // TCWriteTplImage_CMP
2293 //
2294 /*>*******************************(*)*******************************<*/
TCWriteTplImage_CMP(TCLayer * colorLayer,u8 * tplBuffer)2295 void TCWriteTplImage_CMP ( TCLayer* colorLayer, u8* tplBuffer )
2296 {
2297 u32 tileRow, tileCol;
2298 u32 srcTileRows, srcTileCols;
2299 u16* dstPtr;
2300
2301 // each source tile is 4x4 texels, 8B
2302 srcTileRows = ((colorLayer->height + 3) >> 2);
2303 srcTileCols = ((colorLayer->width + 3) >> 2);
2304
2305 dstPtr = (u16*)(tplBuffer);
2306
2307 // each dst tile is 2x2 source tiles, so move by 2 each iteration
2308 for(tileRow = 0; tileRow < srcTileRows; tileRow += 2 )
2309 {
2310 for(tileCol = 0; tileCol < srcTileCols; tileCol += 2 )
2311 {
2312 TCPackTile_CMP( colorLayer, tileCol, tileRow, dstPtr );
2313 dstPtr += 16; // 32B per dst tile, short ptr
2314 }
2315 }
2316 }
2317
2318 /*>*******************************(*)*******************************<*/
2319 // TCPackTile_CMP
2320 //
2321 // pack a 2x2 tile block, each tile of 4x4 texels, into a single
2322 // 32B dst tile note: this assumes s3 algorithm pads out to a minimum
2323 // block size of 4x4 texels
2324 /*>*******************************(*)*******************************<*/
TCPackTile_CMP(TCLayer * layer,u32 tileX,u32 tileY,u16 * dstPtr)2325 static void TCPackTile_CMP ( TCLayer* layer, u32 tileX, u32 tileY, u16* dstPtr)
2326 {
2327 u32 x, y;
2328 u16* srcPtr;
2329 u16 tmp;
2330 u32 srcTileOffset;
2331 u32 subTileRows, subRowShorts; // number of s3 4x4 tiles
2332 u32 srcPadWidth, srcPadHeight;
2333 u16* buffPtr;
2334
2335 // set the padded size of the s3 source image out to a 4-texel boundary
2336 srcPadWidth = ( (layer->width + 3) >> 2 );
2337 srcPadHeight = ( (layer->height + 3) >> 2 );
2338
2339 // number of bytes in a single row of 4x4 texel source tiles
2340 srcTileOffset = srcPadWidth * 8;
2341
2342 // number of 4x4 (source) tile rows to copy ( will be 1 or 2 )
2343 subTileRows = 2;
2344 if( (srcPadHeight - tileY) < 2 )
2345 subTileRows = 1;
2346
2347 // number of 4x4 tile cols to copy translated into number of short values
2348 // ( will be 4 or 8 )
2349 subRowShorts = 8;
2350 if( (srcPadWidth - tileX) < 2 )
2351 subRowShorts = 4;
2352
2353 for( y=0; y < subTileRows; y++ )
2354 {
2355 srcPtr = (u16*)( (u8*)(layer->data) + ((tileY + y) * srcTileOffset) + (tileX*8) );
2356 buffPtr = ( dstPtr + (y * 8) ); // 16 bytes per subRow = 8 shorts
2357
2358 // process one or both 4x4 row tiles at once- 4 short each
2359 for( x=0; x < subRowShorts; x++ )
2360 {
2361 switch( x )
2362 {
2363
2364 // color table entries - switch bytes within a 16-bit world only
2365 case 0:
2366 case 1:
2367 case 4:
2368 case 5:
2369 tmp = *srcPtr++;
2370 TCFixEndian( (u8*)(&tmp), 2 );
2371 *buffPtr++ = tmp;
2372 break;
2373
2374 // 2-bit color tuples;
2375 // reverse tuple order within bytes of a word
2376 case 2:
2377 case 3:
2378 case 6:
2379 case 7:
2380 tmp = *srcPtr++;
2381 TCFixCMPWord( &tmp );
2382 *buffPtr++ = tmp;
2383 break;
2384
2385 } // end switch
2386 } // end for( subRowShorts )
2387 } // end for( subTileRows )
2388 }
2389
2390 /*>*******************************(*)*******************************<*/
2391 // switch tuple and byte order within 16-bit words of an s3-packed tile
2392 // to match hw.
2393 // 1) switch 2-bit tuple order within bytes
2394 // from ( 0,1,2,3 ) to ( 3,2,1,0 ).
2395 // 2) leave byte order within the word as is.
2396 /*>*******************************(*)*******************************<*/
TCFixCMPWord(u16 * data)2397 static void TCFixCMPWord( u16* data )
2398 {
2399 u16 tmp;
2400
2401
2402 tmp = *data;
2403
2404 // reverse tuple order within bytes
2405 *data = ( (tmp & 0x3 ) << 6 ) |
2406 ( (tmp & 0xC ) << 2 ) |
2407 ( (tmp & 0x30) >> 2 ) |
2408 ( (tmp & 0xC0) >> 6 ) |
2409
2410 ( (tmp & 0x300 ) << 6 ) |
2411 ( (tmp & 0xC00 ) << 2 ) |
2412 ( (tmp & 0x3000) >> 2 ) |
2413 ( (tmp & 0xC000) >> 6 ) ;
2414 }
2415
2416 /*>*******************************(*)*******************************<*/
2417 // get a reference date for the tpl file for use when comparing
2418 // source image mod. dates refTmPtr is the date structure to be filled
2419 // fp is a ptr to the open tpl file dateType determines which type of
2420 // date to use 0 indicates file properties ( struct _stat type
2421 // accessed by _fstat ) 1 indicates a byte stream ( date field )
2422 // within the tpl file
2423 /*>*******************************(*)*******************************<*/
TCGetFileModTime(const char * fileName,struct tm * modTmPtr)2424 static void TCGetFileModTime ( const char* fileName, struct tm* modTmPtr )
2425 {
2426 struct _stat statBuff;
2427 struct tm* localPtr = NULL;
2428 FILE* fp;
2429
2430
2431 memset( modTmPtr, 0, sizeof(struct tm) );
2432
2433 fp = fopen( fileName, "rb" );
2434 TCAssertMsg( (fp != NULL), "TCGetFileModTime: couldn't open file %s\n", fileName );
2435
2436
2437 // date is set from file properties
2438 if( ( _fstat( fp->_file, &statBuff )) != 0 )
2439 {
2440 TCErrorMsg( "TCGetFileModTime: error in _fstat() for file %s call\n", fileName );
2441 return;
2442 }
2443
2444 // use file modification date
2445 localPtr = localtime( &statBuff.st_mtime );
2446 *modTmPtr = *localPtr;
2447
2448 fclose( fp );
2449 }
2450
2451 /*>*******************************(*)*******************************<*/
2452 // set a 'struct tm' variable to the current time
2453 /*>*******************************(*)*******************************<*/
TCGetTime(struct tm * tmPtr)2454 static void TCGetTime ( struct tm* tmPtr )
2455 {
2456 time_t tm;
2457 struct tm* localPtr = NULL;
2458
2459
2460 tm = time( NULL );
2461
2462 localPtr = localtime( &tm );
2463
2464 *tmPtr = *localPtr;
2465 }
2466
2467 /*>*******************************(*)*******************************<*/
2468 // determine the original access permission for a file
2469 /*>*******************************(*)*******************************<*/
TCGetFileAccess(const char * fileName)2470 static s32 TCGetFileAccess ( const char* fileName )
2471 {
2472 s32 axs = FILE_ACCESS_NONE;
2473
2474
2475 // check for file existence:
2476 // if the file doesn't exist, leave access as 0
2477 if( ( _access( fileName, 0 )) == -1 )
2478 {
2479 return FILE_ACCESS_NONE;
2480 }
2481 // otherwise, determine access
2482 else if( ( _access( fileName, 6 )) != -1 ) // read and write permission
2483 {
2484 axs = FILE_ACCESS_READ_WRITE;
2485 }
2486 else if( ( _access( fileName, 2 )) != -1 ) // write permission
2487 {
2488 axs = FILE_ACCESS_WRITE_ONLY;
2489 }
2490 else if( ( _access( fileName, 4 )) != -1 ) // read permission
2491 {
2492 axs = FILE_ACCESS_READ_ONLY;
2493 }
2494
2495 return axs;
2496 }
2497
2498 /*>*******************************(*)*******************************<*/
2499 // set the access permission for a file
2500 /*>*******************************(*)*******************************<*/
TCSetFileAccess(const char * fileName,s32 axs)2501 static void TCSetFileAccess ( const char* fileName, s32 axs )
2502 {
2503 s32 pmode;
2504
2505
2506 // make sure file exists before calling _chmod
2507 if( (TCGetFileAccess ( fileName )) == FILE_ACCESS_NONE )
2508 {
2509 return;
2510 }
2511
2512 switch( axs )
2513 {
2514 case FILE_ACCESS_READ_WRITE:
2515 pmode = ( _S_IREAD | _S_IWRITE );
2516 break;
2517
2518 case FILE_ACCESS_READ_ONLY:
2519 pmode = _S_IREAD;
2520 break;
2521
2522 case FILE_ACCESS_WRITE_ONLY:
2523 pmode = _S_IWRITE;
2524 break;
2525
2526 case FILE_ACCESS_NONE: // if 'no access',
2527 default: // or if unknown axs flag, leave the current permission as is.
2528 return;
2529 break;
2530 }
2531
2532 if( ( _chmod( fileName, pmode )) != 0 )
2533 {
2534 TCErrorMsg( "TCSetFileAccess: couldn't change file %s permissions\n", fileName );
2535 return;
2536 }
2537 }
2538
2539 /*>*******************************(*)*******************************<*/
2540 // set the modification date of a file after it has been closed.
2541 // we use a closed file so an explicit time can be set without regard to
2542 // the behavior of fclose().
2543 /*>*******************************(*)*******************************<*/
TCSetFileModTime(const char * fileName,struct tm * refTm)2544 static void TCSetFileModTime ( const char* fileName, struct tm* refTm )
2545 {
2546 s32 saveAxs;
2547 struct _utimbuf utBuff;
2548 struct _stat stBuff;
2549
2550
2551 // save the original file access level
2552 if( (saveAxs = TCGetFileAccess( fileName )) == FILE_ACCESS_NONE )
2553 {
2554 TCErrorMsg( "TCSetFileModTime: file %s does not exist\n", fileName );
2555 return;
2556 }
2557
2558 // set file access to read/write
2559 TCSetFileAccess( fileName, FILE_ACCESS_READ_WRITE );
2560
2561 // get the access, modification stats of this file
2562 _stat( fileName, &stBuff );
2563
2564 // save the access time; set the modification time to 'refTm'
2565 utBuff.actime = stBuff.st_atime;
2566 utBuff.modtime = mktime( refTm );
2567
2568 // update the modification time
2569 _utime( fileName, &utBuff );
2570
2571 // restore the original access level
2572 TCSetFileAccess( fileName, saveAxs );
2573 }
2574
2575 /*>*******************************(*)*******************************<*/
2576 // compare two struct tms for year, year-day, hour, min, sec:
2577
2578 // return 1 if time 1 is > time 2
2579 // return 0 if time 1 is = time 2
2580 // return -1 if time 1 is < time 2
2581 /*>*******************************(*)*******************************<*/
TCCompareTime(struct tm * time1,struct tm * time2)2582 static s32 TCCompareTime ( struct tm* time1, struct tm* time2 )
2583 {
2584
2585 if( time1->tm_year > time2->tm_year )
2586 return 1;
2587 else if( time1->tm_year < time2->tm_year )
2588 return -1;
2589
2590 if( time1->tm_yday > time2->tm_yday )
2591 return 1;
2592 else if( time1->tm_yday < time2->tm_yday )
2593 return -1;
2594
2595 if( time1->tm_hour > time2->tm_hour )
2596 return 1;
2597 else if( time1->tm_hour < time2->tm_hour )
2598 return -1;
2599
2600 if( time1->tm_min > time2->tm_min )
2601 return 1;
2602 else if( time1->tm_min < time2->tm_min )
2603 return -1;
2604
2605 if( time1->tm_sec > time2->tm_sec )
2606 return 1;
2607 else if( time1->tm_sec < time2->tm_sec )
2608 return -1;
2609
2610
2611 return 0;
2612 }
2613
2614 /*>*******************************(*)*******************************<*/
2615 // get the version of a pre-existing tpl file
2616 /*>*******************************(*)*******************************<*/
TCGetTplVersion(const char * tplName)2617 static u32 TCGetTplVersion ( const char* tplName )
2618 {
2619 FILE* fp;
2620 u32 version;
2621
2622
2623 fp = fopen( tplName, "rb");
2624 TCAssertMsg( (fp != NULL), "TCGetTplVersion: couldn't open existing tpl %s for read\n", tplName );
2625
2626 // version is the 1st 4 bytes of the file
2627 if( (fread( &version, 4, 1, fp )) != 1 )
2628 {
2629 fclose( fp );
2630 TCErrorMsg( "TCGetTplVersion: fread failed for %s version number\n", tplName );
2631 return 0;
2632 }
2633
2634 // tpl was packed big-endian
2635 TCFixEndian( (u8*)&version, 4 );
2636
2637 return version;
2638 }
2639
2640 /*>*******************************(*)*******************************<*/
TCWriteTplValue(FILE * fp,u32 cursor,void * value,u32 numBytes)2641 static u32 TCWriteTplValue ( FILE* fp, u32 cursor, void* value, u32 numBytes )
2642 {
2643 u8 buff[8];
2644 u8* buffPtr = buff;
2645
2646
2647 // copy 'value' to 'buff' based on its 'type'
2648 switch( numBytes )
2649 {
2650 case 1:
2651 *(u8*)buffPtr = *(u8*)value;
2652 break;
2653 case 2:
2654 *(u16*)buffPtr = *(u16*)value;
2655 break;
2656 case 4:
2657 *(u32*)buffPtr = *(u32*)value;
2658 break;
2659 case 8:
2660 *(f64*)buffPtr = *(f64*)value;
2661 break;
2662 default:
2663 TCErrorMsg("TCWriteTplValue: error in numBytes value\n" );
2664 return 0;
2665 break;
2666 }
2667
2668 TCFixEndian( buff, numBytes );
2669 if( (fwrite( buff, numBytes, 1, fp )) != 1 )
2670 {
2671 fclose( fp );
2672 TCErrorMsg("TCWriteTplValue: error in fwrite\n" );
2673 return 0;
2674 }
2675
2676 return numBytes;
2677 }
2678
2679 /*>*******************************(*)*******************************<*/
TCWriteTplBlock(FILE * fp,u32 cursor,void * block,u32 numBytes)2680 static u32 TCWriteTplBlock ( FILE* fp, u32 cursor, void* block, u32 numBytes )
2681 {
2682
2683 if( (fwrite( block, 1, numBytes, fp )) != numBytes )
2684 {
2685 fclose( fp );
2686 TCErrorMsg("TCWriteTplBlock: error in fwrite\n" );
2687 return 0;
2688 }
2689
2690 return numBytes;
2691 }
2692
2693 /*>*******************************(*)*******************************<*/
2694 // reverse the byte order within a block of bytes.
2695 // do this only if TPL_BIG_END is defined
2696 /*>*******************************(*)*******************************<*/
TCFixEndian(u8 * src,u32 numBytes)2697 static void TCFixEndian( u8* src, u32 numBytes )
2698 {
2699
2700 #ifdef TPL_BIG_END
2701
2702 u8 tmp[8]; // large enough to hold a double
2703 u32 max, i;
2704
2705
2706 TCAssertMsg( (numBytes <= 8), "TCFixEndian: numBytes > 8\n" );
2707
2708 if( (numBytes == 0) || (numBytes == 1) )
2709 {
2710 return;
2711 }
2712
2713 max = numBytes - 1;
2714 for(i=0; i< numBytes; i++)
2715 {
2716 tmp[(max - i)] = src[i];
2717 }
2718
2719 for(i=0; i< numBytes; i++)
2720 {
2721 src[i] = tmp[i];
2722 }
2723
2724 #endif
2725 }
2726
2727 /*>*******************************(*)*******************************<*/
2728 // compute wrap filter mode based on image dimensions.
2729 // this function is used by TCWriteTplFile to set filter mode.
2730 // return TPL_WRAP_MODE_REPEAT if image is power of 2.
2731 // return TPL_WRAP_MODE_CLAMP if image is not power of 2.
2732 /*>*******************************(*)*******************************<*/
TCSetFilterModeByDim(TCImage * thisImage)2733 static u32 TCSetFilterModeByDim( TCImage* thisImage )
2734 {
2735 u32 i;
2736 u32 width = (thisImage->lyColor).width;
2737 u32 height = (thisImage->lyColor).height;
2738 u32* dimPtr = &width;
2739
2740
2741 for( i=0; i<2; i++ )
2742 {
2743 switch( *dimPtr )
2744 {
2745 case 1024: // fall through
2746 case 512:
2747 case 256:
2748 case 128:
2749 case 64:
2750 case 32:
2751 case 16:
2752 case 8:
2753 case 4:
2754 case 2:
2755 case 1:
2756
2757 *dimPtr = TPL_WRAP_MODE_REPEAT;
2758 break;
2759
2760 default:
2761 *dimPtr = TPL_WRAP_MODE_CLAMP;
2762 break;
2763 }
2764
2765 // check both dimensions
2766 dimPtr = &height;
2767
2768 } // end for
2769
2770
2771 // if both dimensions are a power of 2, return TPL_WRAP_MODE_REPEAT.
2772 // if both dimensions are non-power 2, return TPL_WRAP_MODE_CLAMP.
2773 if( width == height )
2774 {
2775 return width;
2776 }
2777
2778 // if dimensions are a mix of power of 2/non-power of 2,
2779 // default to TPL_WRAP_MODE_CLAMP.
2780 return TPL_WRAP_MODE_CLAMP;
2781 }
2782
2783 /*>*******************************(*)*******************************<*/
2784 // returns num if num is a power of two. returns 0 if num is not.
2785 // this function is only valid for numbers 1024 or less since this is
2786 // the maximum dimension of a texture.
2787 /*>*******************************(*)*******************************<*/
TCCheckPowerOfTwo(u32 num)2788 static u32 TCCheckPowerOfTwo( u32 num )
2789 {
2790 switch( num )
2791 {
2792 case 1024: // max. dimension size is 1024
2793 case 512:
2794 case 256:
2795 case 128:
2796 case 64:
2797 case 32:
2798 case 16:
2799 case 8:
2800 case 4:
2801 case 2:
2802 case 1:
2803 return num;
2804 }
2805
2806 return 0;
2807 }
2808
2809 /*>*******************************(*)*******************************<*/
2810 /*>*******************************(*)*******************************<*/
2811 // write a .csf file using information in ImHead, PlHead.
2812 // tplName and refTmPtr provide the .tpl file name and mod. time
2813 // use hard-coded 'CsfName' for cached script file name.
2814 // ".csf" extension stands for "cached script file"
2815 /*>*******************************(*)*******************************<*/
TCWriteCachedScriptFile(const char * tplName,struct tm * refTmPtr)2816 static void TCWriteCachedScriptFile( const char* tplName, struct tm* refTmPtr )
2817 {
2818 const char* csfNamePtr = CsfName; // use the hard-coded .csf name for now
2819 FILE* fp;
2820
2821 TCImage* imPtr;
2822 TCPalette* plPtr;
2823 TCSrcImage* siPtr;
2824 TCCsfHeader csfHdr;
2825
2826 u32 imCount;
2827 u32 plCount;
2828 TCCachedImage imCached;
2829 TCCachedPalette plCached;
2830
2831 u32 strSize;
2832 u32 cursor, strBase, strCursor;
2833 u32 count;
2834
2835
2836 TCAssertMsg( (tplName != NULL), "TCWriteCachedScriptFile: NULL tplName\n" );
2837 TCAssertMsg( (*tplName != '\0'), "TCWriteCachedScriptFile: NULL tplName\n" );
2838 TCAssertMsg( (refTmPtr != NULL), "TCWriteCachedScriptFile: NULL refTmPtr\n" );
2839
2840 // zero out the data structures for initial write
2841 memset( &csfHdr, 0, sizeof(TCCsfHeader) );
2842 memset( &imCached, 0, sizeof(TCCachedImage) );
2843 memset( &plCached, 0, sizeof(TCCachedPalette) );
2844
2845
2846 _mkdir( CsfPath ); // if this directory already exists, _mkdir does nothing
2847 TCSetFileAccess ( csfNamePtr, FILE_ACCESS_READ_WRITE ); // in case srcTree locked the previous one
2848 if( (fp = fopen( csfNamePtr, "wb" )) == NULL )
2849 {
2850 // if it doesn't work, the result is just a forced reconvert of this .tpl next time.
2851 remove( csfNamePtr );
2852 return;
2853 }
2854
2855 // these are the global counters from TCSetTplValues
2856 imCount = NumImage;
2857 plCount = NumPalette;
2858
2859 //---------------------------
2860
2861 // compute file header values (the rest default to 0)
2862 // except string bank size- this isn't known until the end.
2863
2864 // store the mod. date for the just-written .tpl file
2865 csfHdr.tplModTime = *refTmPtr;
2866
2867 if( imCount )
2868 {
2869 csfHdr.numCachedImage = imCount;
2870 csfHdr.cachedImageOffset = sizeof(TCCsfHeader);
2871 }
2872
2873 if( plCount )
2874 {
2875 csfHdr.numCachedPalette = plCount;
2876 csfHdr.cachedPaletteOffset = sizeof(TCCsfHeader) + ( imCount * sizeof(TCCachedImage) );
2877 }
2878
2879 csfHdr.stringBankOffset = sizeof(TCCsfHeader) + ( imCount * sizeof(TCCachedImage) )
2880 + ( plCount * sizeof(TCCachedPalette) );
2881
2882 //---------------------------
2883
2884 // write out the header.
2885 // note: the 'stringBankSize' field will be overwritten at the end
2886 fwrite( &csfHdr, sizeof(TCCsfHeader), 1, fp );
2887
2888 // write 0's to the file up to the start of the string bank
2889 // so we can write the string bank
2890 // simultaneously with the image and palette banks
2891 if( imCount )
2892 {
2893 for( count = 0; count < imCount; count++ )
2894 {
2895 fwrite( &imCached, sizeof(TCCachedImage), 1, fp );
2896 }
2897 }
2898 if( plCount )
2899 {
2900 for( count = 0; count < plCount; count++ )
2901 {
2902 fwrite( &plCached, sizeof(TCCachedPalette), 1, fp );
2903 }
2904 }
2905 rewind(fp);
2906
2907 // set cursors so we can move the file ptr between
2908 // cached image/palette blocks and string bank
2909 cursor = sizeof(TCCsfHeader);
2910 strBase = csfHdr.stringBankOffset; // offset to string bank
2911 strCursor = 0; // local offset within string bank
2912
2913 // write the .tpl file name as the first string in the string bank
2914 strSize = strlen( tplName ) + 1;
2915 fseek( fp, (strBase + strCursor), SEEK_SET );
2916 fwrite( tplName, strSize, 1, fp );
2917 strCursor += strSize;
2918
2919
2920 // write cached images sequentially from ImHead list.
2921 // write image file names simultaneously to the string bank
2922 imPtr = ImHead;
2923 while( imPtr )
2924 {
2925 // zero out the cached image structure
2926 memset( &imCached, 0, sizeof(TCCachedImage) );
2927
2928 // find imPtr's color src image name
2929 siPtr = TCFindSrcImageByIndex( imPtr->colorSrcImage );
2930
2931 strSize = strlen( siPtr->fileName ) + 1;
2932
2933 // store the mod. date of the color source image
2934 TCGetFileModTime( siPtr->fileName, &imCached.colorModTime );
2935
2936 // store the string bank offset in imCached and
2937 // write the colorSrcImage string to the string bank
2938 imCached.colorSrcImage = strCursor;
2939
2940 fseek( fp, (strBase + strCursor), SEEK_SET );
2941 fwrite( siPtr->fileName, strSize, 1, fp );
2942 strCursor += strSize;
2943
2944 // find imPtr's alpha src image name
2945 imCached.alphaSrcImage = TC_UNUSED;
2946 if( imPtr->alphaSrcImage != TC_UNUSED )
2947 {
2948 siPtr = TCFindSrcImageByIndex( imPtr->alphaSrcImage );
2949
2950 strSize = strlen( siPtr->fileName ) + 1;
2951
2952 // store the mod. date of the alpha source image
2953 TCGetFileModTime( siPtr->fileName, &imCached.alphaModTime );
2954
2955 // store the string bank offset in imCached and
2956 // write the colorSrcImage string to the string bank
2957 imCached.alphaSrcImage = strCursor;
2958
2959 fseek( fp, (strBase + strCursor), SEEK_SET );
2960 fwrite( siPtr->fileName, strSize, 1, fp );
2961 strCursor += strSize;
2962 }
2963
2964 // set the remainder of the cached image fields
2965 imCached.texelFormat = imPtr->texelFormat;
2966 imCached.minLOD = imPtr->minLOD;
2967 imCached.maxLOD = imPtr->maxLOD;
2968 imCached.remapMinLOD = imPtr->remapMinLOD;
2969 imCached.tplImageBankOffset = imPtr->tplImageBankOffset;
2970 imCached.tplBufferSize = imPtr->tplBufferSize;
2971
2972 // write out the cached image in one block
2973 fseek( fp, cursor, SEEK_SET );
2974 fwrite( &imCached, sizeof(TCCachedImage), 1, fp );
2975 cursor += sizeof(TCCachedImage);
2976
2977 imPtr = imPtr->next;
2978 }
2979
2980 // write cached palettes sequentially from PlHead list.
2981 // write palette file names simultaneously to the string bank
2982 plPtr = PlHead;
2983 while( plPtr )
2984 {
2985 // zero out the cached palette structure
2986 memset( &plCached, 0, sizeof(TCCachedPalette) );
2987
2988 // find plPtr's src image name
2989 siPtr = TCFindSrcImageByIndex( plPtr->srcImage );
2990
2991 strSize = strlen( siPtr->fileName ) + 1;
2992
2993 // store the mod. date of the palette source image
2994 TCGetFileModTime( siPtr->fileName, &plCached.srcModTime );
2995
2996 // store the string bank offset in plCached and
2997 // write the srcImage string to the string bank
2998 plCached.srcImage = strCursor;
2999
3000 fseek( fp, (strBase + strCursor), SEEK_SET );
3001 fwrite( siPtr->fileName, strSize, 1, fp );
3002 strCursor += strSize;
3003
3004 // set the remainder of the cached palette fields
3005 plCached.entryFormat = plPtr->entryFormat;
3006 plCached.tplPaletteBankOffset = plPtr->tplPaletteBankOffset;
3007 plCached.tplBufferSize = plPtr->tplBufferSize;
3008
3009 // write out the cached palette in one block
3010 fseek( fp, cursor, SEEK_SET );
3011 fwrite( &plCached, sizeof(TCCachedPalette), 1, fp );
3012 cursor += sizeof(TCCachedPalette);
3013
3014 plPtr = plPtr->next;
3015 }
3016
3017 // write the final string bank size out to the header
3018 csfHdr.stringBankSize = strCursor;
3019 fseek( fp, (u32)( (u32)(&csfHdr.stringBankSize) - (u32)(&csfHdr) ), SEEK_SET );
3020 fwrite( &csfHdr.stringBankSize, 4, 1, fp );
3021
3022 fseek(fp, 0, SEEK_END);
3023 fclose(fp);
3024 }
3025
3026 /*>*******************************(*)*******************************<*/
3027 // read a .csf file and transfer its data to arrays of
3028 // TCCachedImage and TCCachedPalette structures.
3029 // if a partial update is possible, allocate *tplPrev and store the cached .tpl file
3030 // return 0 if full conversion is required,
3031 // 1 if partial update is possible.
3032 /*>*******************************(*)*******************************<*/
TCReadCachedScriptFile(const char * newTplName,u8 ** tplPrev)3033 static u32 TCReadCachedScriptFile( const char* newTplName, u8** tplPrev )
3034 {
3035 const char* csfNamePtr = CsfName; // use the hard-coded cache file name
3036 FILE* fp;
3037
3038 TCCsfHeader csfHdr;
3039 TCCachedImage* cImPtr;
3040 TCCachedPalette* cPlPtr;
3041 TCSrcImage* siPtr;
3042
3043 char* strPtr;
3044 char* cachedStrBank;
3045
3046 u32 i;
3047 u32 found;
3048 u32 partialUpdate = 0;
3049
3050
3051 // set array values to defaults
3052 NumCachedIm = 0;
3053 CachedImArray = NULL;
3054 NumCachedPl = 0;
3055 CachedPlArray = NULL;
3056
3057 // check if the cached .csf file exists.
3058 // if it doesn't, do a full conversion
3059 if( (fp = fopen( csfNamePtr, "rb" )) == NULL )
3060 {
3061 return 0;
3062 }
3063
3064 // fetch the file header
3065 fread( &csfHdr, sizeof(TCCsfHeader), 1, fp );
3066
3067 // allocate the TCCachedImage, TCCachedPalette arrays
3068 // and read their data sequentially
3069 NumCachedIm = csfHdr.numCachedImage;
3070 if( NumCachedIm )
3071 {
3072 CachedImArray = (TCCachedImage*)TCCalloc( NumCachedIm, sizeof(TCCachedImage) );
3073 fseek( fp, csfHdr.cachedImageOffset, SEEK_SET );
3074 fread( CachedImArray, sizeof(TCCachedImage), NumCachedIm, fp );
3075 }
3076
3077 NumCachedPl = csfHdr.numCachedPalette;
3078 if( NumCachedPl )
3079 {
3080 CachedPlArray = (TCCachedPalette*)TCCalloc( NumCachedPl, sizeof(TCCachedPalette) );
3081 fseek( fp, csfHdr.cachedPaletteOffset, SEEK_SET );
3082 fread( CachedPlArray, sizeof(TCCachedPalette), NumCachedPl, fp );
3083 }
3084
3085 // allocate the string bank- keep all of the strings together and set
3086 // TCImageArray[n]->colorSrcImage etc. to point here.
3087 if( csfHdr.stringBankSize == 0 )
3088 {
3089 fclose( fp );
3090 return 0;
3091 }
3092
3093 cachedStrBank = (char*)TCCalloc( 1, csfHdr.stringBankSize );
3094 fseek( fp, csfHdr.stringBankOffset, SEEK_SET );
3095 fread( cachedStrBank, csfHdr.stringBankSize, 1, fp );
3096
3097 // traverse the SrcImage list, compare file name strings to those in the
3098 // CachedImArray and CachedPlArray and convert matching offsets to indices
3099
3100 // CachedImArray
3101 cImPtr = CachedImArray;
3102 for( i=0; i< NumCachedIm; i++, cImPtr++ )
3103 {
3104 // traverse SiHead twice- once for color, once for alpha
3105
3106 // match cImPtr->colorSrcImage name to siPtr->fileName
3107 found = 0;
3108 strPtr = cachedStrBank + cImPtr->colorSrcImage;
3109 siPtr = SiHead;
3110 while( siPtr )
3111 {
3112 if( (strcmp( strPtr, siPtr->fileName )) == 0 )
3113 {
3114 cImPtr->colorSrcImage = siPtr->index;
3115 found = 1;
3116 break;
3117 }
3118 siPtr = siPtr->next;
3119 }
3120
3121 // no matching filename in SiHead; set index to 0
3122 if( found == 0 )
3123 {
3124 cImPtr->colorSrcImage = TC_UNUSED;
3125 }
3126
3127 //------------------------------
3128
3129 // match cImPtr->alphaSrcImage name to siPtr->fileName
3130 if( cImPtr->alphaSrcImage != TC_UNUSED )
3131 {
3132 found = 0;
3133 strPtr = cachedStrBank + cImPtr->alphaSrcImage;
3134 siPtr = SiHead;
3135 while( siPtr )
3136 {
3137 if( (strcmp( strPtr, siPtr->fileName )) == 0 )
3138 {
3139 cImPtr->alphaSrcImage = siPtr->index;
3140 found = 1;
3141 break;
3142 }
3143 siPtr = siPtr->next;
3144 }
3145
3146 // no matching filename in SiHead; set index to 0
3147 if( found == 0 )
3148 {
3149 cImPtr->alphaSrcImage = TC_UNUSED;
3150 }
3151
3152 } // end if
3153
3154 //--------------------------------
3155
3156 } // end for
3157
3158 //------------------------------------------------------------
3159
3160 // CachedPlArray
3161 cPlPtr = CachedPlArray;
3162 for( i=0; i< NumCachedPl; i++, cPlPtr++ )
3163 {
3164 // match cPlPtr->srcImage name to siPtr->fileName
3165 found = 0;
3166 strPtr = cachedStrBank + cPlPtr->srcImage;
3167 siPtr = SiHead;
3168 while( siPtr )
3169 {
3170 if( (strcmp( strPtr, siPtr->fileName )) == 0 )
3171 {
3172 cPlPtr->srcImage = siPtr->index;
3173 found = 1;
3174 break;
3175 }
3176 siPtr = siPtr->next;
3177 }
3178
3179 // no matching filename in SiHead; set index to 0
3180 if( found == 0 )
3181 {
3182 cPlPtr->srcImage = TC_UNUSED;
3183 }
3184
3185 } // end for
3186
3187 fclose(fp);
3188
3189 // compare cached information to current script information
3190 // including source image modification dates.
3191 // initialize ImFlags, PlFlags arrays if partial update is possible.
3192 // return 0 if full conversion is required, 1 if partial update is possible.
3193
3194 // previous .tpl file name is the 1st string in cachedStrBank.
3195 // note: call this fn BEFORE freeing cachedStrBank!
3196 partialUpdate = TCCompareToCachedScriptData( (char*)(cachedStrBank + csfHdr.tplNameOffset),
3197 &csfHdr.tplModTime, tplPrev );
3198
3199 if( cachedStrBank )
3200 {
3201 TCFree( (void**)&cachedStrBank );
3202 cachedStrBank = NULL;
3203 }
3204
3205 return partialUpdate;
3206 }
3207
3208 /*>*******************************(*)*******************************<*/
3209 // compare ImHead, PlHead lists to ImCached, PlCached arrays;
3210 // (includes check for source image modification dates)
3211 // set corresponding ImFlags, PlFlags array entries.
3212 //
3213 // array values: 0 = new conversion required for this image/palette;
3214 // any other value = u32 offset to this image/palette's data block
3215 // within the pre-existing tpl file.
3216 //
3217 // return 0 if full conversion is required for .tpl file,
3218 // 1 if partial update is possible
3219 /*>*******************************(*)*******************************<*/
TCCompareToCachedScriptData(const char * prevTplName,struct tm * prevTplModTime,u8 ** tplPrev)3220 static u32 TCCompareToCachedScriptData( const char* prevTplName, struct tm* prevTplModTime, u8** tplPrev )
3221 {
3222 FILE* fp;
3223 s32 fh;
3224 s32 size;
3225
3226 TCImage* imPtr;
3227 TCCachedImage* cImPtr;
3228
3229 TCPalette* plPtr;
3230 TCCachedPalette* cPlPtr;
3231
3232 struct tm tplRefTime;
3233
3234 u32 i;
3235 u32 update = 0;
3236 u32 pos;
3237
3238
3239 // initialize both flag arrays to 0
3240 // (default = full update required for all data blocks)
3241 if( NumImage )
3242 {
3243 ImFlags = (u32*)TCCalloc( (NumImage), sizeof(u32) );
3244 }
3245 if( NumPalette )
3246 {
3247 PlFlags = (u32*)TCCalloc( (NumPalette), sizeof(u32) );
3248 }
3249
3250
3251 // check if a cached .tpl exists;
3252 if( (TCGetFileAccess( prevTplName )) == FILE_ACCESS_NONE )
3253 {
3254 return 0;
3255 }
3256
3257 // if prev .tpl exists but version number is old, full update is required
3258 if( (TCGetTplVersion( prevTplName )) != TplVersion )
3259 {
3260 return 0;
3261 }
3262
3263 // get the reference date for the existing .tpl file.
3264 // source image files will be checked against this date
3265 TCGetFileModTime( prevTplName, &tplRefTime );
3266
3267 // compare the existing file's reference date against the cached reference date;
3268 // this protects against accidental renaming of another .tpl file
3269 // to the name stored in the .csf file
3270 if( (TCCompareTime( prevTplModTime, &tplRefTime)) != 0 ) // they must be equal
3271 {
3272 return 0;
3273 }
3274
3275 // flag all image and palette blocks where pre-converted data exists.
3276 imPtr = ImHead;
3277 pos = 0;
3278 while( imPtr )
3279 {
3280 cImPtr = CachedImArray;
3281 for( i=0; i< NumCachedIm; i++, cImPtr++ )
3282 {
3283 // if image is the same as cached image,
3284 // use ImFlags to save converted data's location in the cached .tpl
3285 if( (TCCompareImToCachedIm( &tplRefTime, imPtr, cImPtr )) == 1 )
3286 {
3287 ImFlags[pos] = cImPtr->tplImageBankOffset;
3288 update = 1;
3289 break; // stop once a match is found
3290 }
3291 }
3292 pos++;
3293 imPtr = imPtr->next;
3294 }
3295
3296 //------------------------
3297
3298 plPtr = PlHead;
3299 pos = 0;
3300 while( plPtr )
3301 {
3302 cPlPtr = CachedPlArray;
3303 for( i=0; i< NumCachedPl; i++, cPlPtr++ )
3304 {
3305 // if palette is the same as cached palette;
3306 // use PlFlags to save converted data's location in 'prevTpl'
3307 if( (TCComparePlToCachedPl( &tplRefTime, plPtr, cPlPtr )) == 1 )
3308 {
3309 PlFlags[pos] = cPlPtr->tplPaletteBankOffset;
3310 update = 1;
3311 break; // stop once a match is found
3312 }
3313 }
3314 pos++;
3315 plPtr = plPtr->next;
3316 }
3317
3318 if( update == 1 )
3319 {
3320 // if any partial update is possible, read the previous .tpl into a buffer
3321 if( (fp = fopen( prevTplName, "rb" )) == NULL )
3322 {
3323 return 0; // *tplPrev is still NULL; this forces a full update
3324 }
3325
3326 // get the file size and read into a buffer
3327 fh = _fileno( fp );
3328 size = _filelength( fh );
3329
3330 *tplPrev = (u8*)TCMalloc( size );
3331 fseek( fp, 0, SEEK_SET );
3332 fread( *tplPrev, size, 1, fp );
3333 fclose( fp );
3334 }
3335
3336 return update;
3337 }
3338
3339 /*>*******************************(*)*******************************<*/
3340 // compare a TCImage to a TCCachedImage:
3341 // this includes checking source image modification dates against .tpl reference date
3342 // return 1 if the image and cached image are the same,
3343 // 0 if they are different.
3344 /*>*******************************(*)*******************************<*/
TCCompareImToCachedIm(struct tm * refTimePtr,TCImage * imPtr,TCCachedImage * cImPtr)3345 static u32 TCCompareImToCachedIm( struct tm* refTimePtr, TCImage* imPtr, TCCachedImage* cImPtr )
3346 {
3347 struct tm siTime;
3348 TCSrcImage* siPtr;
3349
3350
3351 // check image fields first
3352 if( imPtr->colorSrcImage != cImPtr->colorSrcImage )
3353 return 0;
3354 if( imPtr->alphaSrcImage != cImPtr->alphaSrcImage )
3355 return 0;
3356 if( imPtr->texelFormat != cImPtr->texelFormat )
3357 return 0;
3358 if( imPtr->minLOD != cImPtr->minLOD )
3359 return 0;
3360 if( imPtr->maxLOD != cImPtr->maxLOD )
3361 return 0;
3362 if( imPtr->remapMinLOD != cImPtr->remapMinLOD )
3363 return 0;
3364 if( imPtr->tplBufferSize != cImPtr->tplBufferSize )
3365 return 0;
3366
3367 // compare the .tpl reference date to the source image modification date.
3368 // if the source image is newer, force an update
3369 // note: this covers changes to source content, format and dimensions.
3370
3371 // compare srcImage to .tpl
3372 siPtr = TCFindSrcImageByIndex( imPtr->colorSrcImage );
3373
3374 TCGetFileModTime( siPtr->fileName, &siTime );
3375 if( (TCCompareTime( &siTime, refTimePtr )) != -1 ) // srcImage is not older than .tpl
3376 return 0;
3377
3378 // compare srcImage mod. date to cached srcImage mod. date
3379 // this protects against accidental renaming of an older source image
3380 // to the same name as that stored in the .csf file
3381 if( (TCCompareTime( &siTime, &cImPtr->colorModTime )) != 0 ) // cached mod date is different
3382 return 0;
3383
3384
3385 if( imPtr->alphaSrcImage != TC_UNUSED )
3386 {
3387 siPtr = TCFindSrcImageByIndex( imPtr->alphaSrcImage );
3388
3389 TCGetFileModTime ( siPtr->fileName, &siTime );
3390 if( (TCCompareTime( &siTime, refTimePtr )) != -1 ) // srcImage is not older than .tpl
3391 return 0;
3392
3393 // compare srcImage to cached srcImage
3394 // this protects against accidental renaming of an older source image
3395 // to the same name as that stored in the .csf file
3396 if( (TCCompareTime( &siTime, &cImPtr->alphaModTime )) != 0 ) // cached mod date is different
3397 return 0;
3398 }
3399
3400 return 1;
3401 }
3402
3403 /*>*******************************(*)*******************************<*/
3404 // compare a TCPalette against a TCCachedPalette:
3405 // this includes checking source image modification dates against .tpl reference date
3406 // return 1 if the palette and cached palette are the same,
3407 // 0 if they are different.
3408 /*>*******************************(*)*******************************<*/
TCComparePlToCachedPl(struct tm * refTimePtr,TCPalette * plPtr,TCCachedPalette * cPlPtr)3409 static u32 TCComparePlToCachedPl( struct tm* refTimePtr, TCPalette* plPtr, TCCachedPalette* cPlPtr )
3410 {
3411 struct tm siTime;
3412 TCSrcImage* siPtr;
3413
3414
3415 if( plPtr->srcImage != cPlPtr->srcImage )
3416 return 0;
3417 if( plPtr->entryFormat != cPlPtr->entryFormat )
3418 return 0;
3419 if( plPtr->tplBufferSize != cPlPtr->tplBufferSize )
3420 return 0;
3421
3422 // compare the .tpl reference date to the source image modification date.
3423 // if the source image is newer, force an update
3424 // note: this covers changes to source content, format and dimensions.
3425 siPtr = TCFindSrcImageByIndex( plPtr->srcImage );
3426
3427 TCGetFileModTime( siPtr->fileName, &siTime );
3428 if( (TCCompareTime( &siTime, refTimePtr )) != -1 ) // srcImage is not older than .tpl
3429 return 0;
3430
3431 // compare srcImage to cached srcImage
3432 // this protects against accidental renaming of an older source image
3433 // to the same name as that stored in the .csf file
3434 if( (TCCompareTime( &siTime, &cPlPtr->srcModTime )) != 0 ) // cached mod date is different
3435 return 0;
3436
3437 return 1;
3438 }
3439
3440 /*>*******************************(*)*******************************<*/
3441
3442