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