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