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