Rice Video Plugin for GLES1.1
[mupen64plus-pandora.git] / source / rice_gles / src / ConvertImage.cpp
1 /*
2 Copyright (C) 2003 Rice1964
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
17
18 */
19
20 #include "Config.h"
21 #include "ConvertImage.h"
22 #include "RenderBase.h"
23
24 ConvertFunction     gConvertFunctions_FullTMEM[ 8 ][ 4 ] = 
25 {
26     // 4bpp             8bpp            16bpp               32bpp
27     {  Convert4b,       Convert8b,      Convert16b,         ConvertRGBA32 },        // RGBA
28     {  NULL,            NULL,           ConvertYUV,         NULL },                 // YUV
29     {  Convert4b,       Convert8b,      NULL,               NULL },                 // CI
30     {  Convert4b,       Convert8b,      Convert16b,         NULL },                 // IA
31     {  Convert4b,       Convert8b,      Convert16b,         NULL },                 // I
32     {  NULL,            NULL,           NULL,               NULL },                 // ?
33     {  NULL,            NULL,           NULL,               NULL },                 // ?
34     {  NULL,            NULL,           NULL,               NULL }                  // ?
35 };
36 ConvertFunction     gConvertFunctions[ 8 ][ 4 ] = 
37 {
38     // 4bpp             8bpp            16bpp               32bpp
39     {  ConvertCI4,      ConvertCI8,     ConvertRGBA16,      ConvertRGBA32 },        // RGBA
40     {  NULL,            NULL,           ConvertYUV,         NULL },                 // YUV
41     {  ConvertCI4,      ConvertCI8,     NULL,               NULL },                 // CI
42     {  ConvertIA4,      ConvertIA8,     ConvertIA16,        NULL },                 // IA
43     {  ConvertI4,       ConvertI8,      ConvertIA16,        NULL },                 // I
44     {  NULL,            NULL,           NULL,               NULL },                 // ?
45     {  NULL,            NULL,           NULL,               NULL },                 // ?
46     {  NULL,            NULL,           NULL,               NULL }                  // ?
47 };
48
49 ConvertFunction     gConvertTlutFunctions[ 8 ][ 4 ] = 
50 {
51     // 4bpp             8bpp            16bpp               32bpp
52     {  ConvertCI4,      ConvertCI8,     ConvertRGBA16,      ConvertRGBA32 },        // RGBA
53     {  NULL,            NULL,           ConvertYUV,         NULL },                 // YUV
54     {  ConvertCI4,      ConvertCI8,     NULL,               NULL },                 // CI
55     {  ConvertCI4,      ConvertCI8,     ConvertIA16,        NULL },                 // IA
56     {  ConvertCI4,      ConvertCI8,     ConvertIA16,        NULL },                 // I
57     {  NULL,            NULL,           NULL,               NULL },                 // ?
58     {  NULL,            NULL,           NULL,               NULL },                 // ?
59     {  NULL,            NULL,           NULL,               NULL }                  // ?
60 };
61
62 extern bool conkerSwapHack;
63
64 void ConvertRGBA16(CTexture *pTexture, const TxtrInfo &tinfo)
65 {
66     DrawInfo dInfo;
67
68     // Copy of the base pointer
69     uint16 * pSrc = (uint16*)(tinfo.pPhysicalAddress);
70
71     uint8 * pByteSrc = (uint8 *)pSrc;
72     if (!pTexture->StartUpdate(&dInfo))
73         return;
74
75     uint32 nFiddle;
76
77     if (tinfo.bSwapped)
78     {
79         for (uint32 y = 0; y < tinfo.HeightToLoad; y++)
80         {
81             if ((y&1) == 0)
82                 nFiddle = 0x2;
83             else
84                 nFiddle = 0x2 | 0x4;
85
86             // dwDst points to start of destination row
87             uint32 * dwDst = (uint32 *)((uint8 *)dInfo.lpSurface + y*dInfo.lPitch);
88
89             // DWordOffset points to the current dword we're looking at
90             // (process 2 pixels at a time). May be a problem if we don't start on even pixel
91             uint32 dwWordOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad * 2);
92
93             for (uint32 x = 0; x < tinfo.WidthToLoad; x++)
94             {
95                 uint16 w = *(uint16 *)&pByteSrc[dwWordOffset ^ nFiddle];
96
97                 dwDst[x] = Convert555ToRGBA(w);
98                 
99                 // Increment word offset to point to the next two pixels
100                 dwWordOffset += 2;
101             }
102         }
103     }
104     else
105     {
106         for (uint32 y = 0; y < tinfo.HeightToLoad; y++)
107         {
108             // dwDst points to start of destination row
109             uint32 * dwDst = (uint32 *)((uint8 *)dInfo.lpSurface + y*dInfo.lPitch);
110
111             // DWordOffset points to the current dword we're looking at
112             // (process 2 pixels at a time). May be a problem if we don't start on even pixel
113             uint32 dwWordOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad * 2);
114
115             for (uint32 x = 0; x < tinfo.WidthToLoad; x++)
116             {
117                 uint16 w = *(uint16 *)&pByteSrc[dwWordOffset ^ 0x2];
118
119                 dwDst[x] = Convert555ToRGBA(w);
120                 
121                 // Increment word offset to point to the next two pixels
122                 dwWordOffset += 2;
123             }
124         }
125     }
126
127     pTexture->EndUpdate(&dInfo);
128     pTexture->SetOthersVariables();
129 }
130
131 void ConvertRGBA32(CTexture *pTexture, const TxtrInfo &tinfo)
132 {
133     DrawInfo dInfo;
134     if (!pTexture->StartUpdate(&dInfo))
135         return;
136
137     uint32 * pSrc = (uint32*)(tinfo.pPhysicalAddress);
138
139     if( options.bUseFullTMEM )
140     {
141         Tile &tile = gRDP.tiles[tinfo.tileNo];
142
143         uint32 *pWordSrc;
144         if( tinfo.tileNo >= 0 )
145         {
146             pWordSrc = (uint32*)&g_Tmem.g_Tmem64bit[tile.dwTMem];
147
148             for (uint32 y = 0; y < tinfo.HeightToLoad; y++)
149             {
150                 uint32 * dwDst = (uint32 *)((uint8 *)dInfo.lpSurface + y*dInfo.lPitch);
151
152                 uint32 nFiddle = ( y&1 )? 0x2 : 0;
153                 int idx = tile.dwLine*4*y;
154
155                 for (uint32 x = 0; x < tinfo.WidthToLoad; x++, idx++)
156                 {
157                     uint32 w = pWordSrc[idx^nFiddle];
158                     uint8* psw = (uint8*)&w;
159                     uint8* pdw = (uint8*)&dwDst[x];
160 #ifdef HAVE_GLES0
161                     pdw[0] = psw[0];    // Red
162                     pdw[1] = psw[1];    // Green
163                     pdw[2] = psw[2];    // Blue
164 #else
165                     pdw[0] = psw[2];    // Blue
166                     pdw[1] = psw[1];    // Green
167                     pdw[2] = psw[0];    // Red
168 #endif
169                     pdw[3] = psw[3];    // Alpha
170                 }
171             }
172         }
173     }
174     else
175     {
176         if (tinfo.bSwapped)
177         {
178             for (uint32 y = 0; y < tinfo.HeightToLoad; y++)
179             {
180                 if ((y%2) == 0)
181                 {
182                     uint8 *pDst = (uint8 *)dInfo.lpSurface + y * dInfo.lPitch;
183                     uint8 *pS = (uint8 *)pSrc + (y+tinfo.TopToLoad) * tinfo.Pitch + (tinfo.LeftToLoad*4);
184
185                     for (uint32 x = 0; x < tinfo.WidthToLoad; x++)
186                     {
187 #ifdef HAVE_GLES0
188                         pDst[0] = pS[3];    // Red
189                         pDst[1] = pS[2];    // Green
190                         pDst[2] = pS[1];    // Blue
191 #else
192                         pDst[0] = pS[1];    // Blue
193                         pDst[1] = pS[2];    // Green
194                         pDst[2] = pS[3];    // Red
195 #endif
196                         pDst[3] = pS[0];    // Alpha
197                         pS+=4;
198                         pDst+=4;
199                     }
200                 }
201                 else
202                 {
203                     uint32 *pDst = (uint32 *)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch);
204                     uint8 *pS = (uint8 *)pSrc;
205                     int n;
206
207                     n = (y+tinfo.TopToLoad) * tinfo.Pitch + (tinfo.LeftToLoad*4);
208                     for (uint32 x = 0; x < tinfo.WidthToLoad; x++)
209                     {
210 #ifdef HAVE_GLES0
211                         *pDst++ = COLOR_RGBA(pS[(n+1)^0x8],
212                             pS[(n+2)^0x8],
213                             pS[(n+3)^0x8],
214                             pS[(n+0)^0x8]);
215 #else
216                         *pDst++ = COLOR_RGBA(pS[(n+3)^0x8],
217                             pS[(n+2)^0x8],
218                             pS[(n+1)^0x8],
219                             pS[(n+0)^0x8]);
220 #endif
221                         n += 4;
222                     }
223                 }
224             }
225         }
226         else
227         {
228             for (uint32 y = 0; y < tinfo.HeightToLoad; y++)
229             {
230                 uint8 *pDst = (uint8 *)dInfo.lpSurface + y * dInfo.lPitch;
231                 uint8 *pS = (uint8 *)pSrc + (y+tinfo.TopToLoad) * tinfo.Pitch + (tinfo.LeftToLoad*4);
232
233                 for (uint32 x = 0; x < tinfo.WidthToLoad; x++)
234                 {
235 #ifdef HAVE_GLES0
236                     pDst[0] = pS[3];    // Red
237                     pDst[1] = pS[2];    // Green
238                     pDst[2] = pS[1];    // Blue
239 #else
240                     pDst[0] = pS[1];    // Blue
241                     pDst[1] = pS[2];    // Green
242                     pDst[2] = pS[3];    // Red
243 #endif
244                     pDst[3] = pS[0];    // Alpha
245                     pS+=4;
246                     pDst+=4;
247                 }
248             }
249         }
250     }
251
252     pTexture->EndUpdate(&dInfo);
253     pTexture->SetOthersVariables();
254 }
255
256 // E.g. Dear Mario text
257 // Copy, Score etc
258 void ConvertIA4(CTexture *pTexture, const TxtrInfo &tinfo)
259 {
260     DrawInfo dInfo;
261     uint32 nFiddle;
262
263     uint8 * pSrc = (uint8*)(tinfo.pPhysicalAddress);
264
265 #ifdef DEBUGGER
266     if (((long long)pSrc) % 4) TRACE0("Texture src addr is not aligned to 4 bytes, check me");
267 #endif
268
269     if (!pTexture->StartUpdate(&dInfo))
270         return;
271
272     if (tinfo.bSwapped)
273     {
274         for (uint32 y = 0; y < tinfo.HeightToLoad; y++)
275         {
276             uint8 *pDst = (uint8 *)dInfo.lpSurface + y * dInfo.lPitch;
277
278             // For odd lines, swap words too
279             if ((y%2) == 0)
280                 nFiddle = 0x3;
281             else
282                 nFiddle = 0x7;
283
284
285             // This may not work if X is not even?
286             uint32 dwByteOffset = (y+tinfo.TopToLoad) * tinfo.Pitch + (tinfo.LeftToLoad/2);
287
288             if (tinfo.WidthToLoad == 1)
289             {
290                 // corner case
291                 uint8 b = pSrc[dwByteOffset ^ nFiddle];
292                 *pDst++ = ThreeToEight[(b & 0xE0) >> 5];
293                 *pDst++ = ThreeToEight[(b & 0xE0) >> 5];
294                 *pDst++ = ThreeToEight[(b & 0xE0) >> 5];
295                 *pDst++ = OneToEight[(b & 0x10) >> 4];  
296             }
297             else for (uint32 x = 0; x < tinfo.WidthToLoad; x+=2)
298             {
299                 // Do two pixels at a time
300                 uint8 b = pSrc[dwByteOffset ^ nFiddle];
301
302                 // Even
303                 *pDst++ = ThreeToEight[(b & 0xE0) >> 5];
304                 *pDst++ = ThreeToEight[(b & 0xE0) >> 5];
305                 *pDst++ = ThreeToEight[(b & 0xE0) >> 5];
306                 *pDst++ = OneToEight[(b & 0x10) >> 4];  
307                 // Odd
308                 *pDst++ = ThreeToEight[(b & 0x0E) >> 1];
309                 *pDst++ = ThreeToEight[(b & 0x0E) >> 1];
310                 *pDst++ = ThreeToEight[(b & 0x0E) >> 1];
311                 *pDst++ = OneToEight[(b & 0x01)     ];
312
313                 dwByteOffset++;
314             }
315         }
316     }
317     else
318     {
319         for (uint32 y = 0; y < tinfo.HeightToLoad; y++)
320         {
321             uint8 *pDst = (uint8 *)dInfo.lpSurface + (y * dInfo.lPitch);
322
323             // This may not work if X is not even?
324             uint32 dwByteOffset = (y+tinfo.TopToLoad) * tinfo.Pitch + (tinfo.LeftToLoad/2);
325
326             if (tinfo.WidthToLoad == 1)
327             {
328                 // corner case
329                 uint8 b = pSrc[dwByteOffset ^ 0x3];
330                 *pDst++ = ThreeToEight[(b & 0xE0) >> 5];
331                 *pDst++ = ThreeToEight[(b & 0xE0) >> 5];
332                 *pDst++ = ThreeToEight[(b & 0xE0) >> 5];
333                 *pDst++ = OneToEight[(b & 0x10) >> 4];  
334             }
335             else for (uint32 x = 0; x < tinfo.WidthToLoad; x+=2)
336             {
337                 // Do two pixels at a time
338                 uint8 b = pSrc[dwByteOffset ^ 0x3];
339
340                 // Even
341                 *pDst++ = ThreeToEight[(b & 0xE0) >> 5];
342                 *pDst++ = ThreeToEight[(b & 0xE0) >> 5];
343                 *pDst++ = ThreeToEight[(b & 0xE0) >> 5];
344                 *pDst++ = OneToEight[(b & 0x10) >> 4];  
345                 // Odd
346                 *pDst++ = ThreeToEight[(b & 0x0E) >> 1];
347                 *pDst++ = ThreeToEight[(b & 0x0E) >> 1];
348                 *pDst++ = ThreeToEight[(b & 0x0E) >> 1];
349                 *pDst++ = OneToEight[(b & 0x01)     ];
350
351                 dwByteOffset++;
352             }
353         }
354     }
355
356     pTexture->EndUpdate(&dInfo);
357     pTexture->SetOthersVariables();
358
359 }
360
361 // E.g Mario's head textures
362 void ConvertIA8(CTexture *pTexture, const TxtrInfo &tinfo)
363 {
364     DrawInfo dInfo;
365     uint32 nFiddle;
366
367     uint8 * pSrc = (uint8*)(tinfo.pPhysicalAddress);
368
369 #ifdef DEBUGGER
370     if (((long long)pSrc) % 4) TRACE0("Texture src addr is not aligned to 4 bytes, check me");
371 #endif
372
373     if (!pTexture->StartUpdate(&dInfo))
374         return;
375
376     if (tinfo.bSwapped)
377     {
378         for (uint32 y = 0; y < tinfo.HeightToLoad; y++)
379         {
380             // For odd lines, swap words too
381             if ((y%2) == 0)
382                 nFiddle = 0x3;
383             else
384                 nFiddle = 0x7;
385
386             uint8 *pDst = (uint8 *)dInfo.lpSurface + y * dInfo.lPitch;
387             // Points to current byte
388             uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + tinfo.LeftToLoad;
389
390             for (uint32 x = 0; x < tinfo.WidthToLoad; x++)
391             {
392                 uint8 b = pSrc[dwByteOffset ^ nFiddle];
393                 uint8 I = FourToEight[(b & 0xf0)>>4];
394
395                 *pDst++ = I;
396                 *pDst++ = I;
397                 *pDst++ = I;
398                 *pDst++ = FourToEight[(b & 0x0f)   ];
399
400                 dwByteOffset++;
401             }
402         }
403     }
404     else
405     {
406         register const uint8* FourToEightArray = &FourToEight[0];
407         for (uint32 y = 0; y < tinfo.HeightToLoad; y++)
408         {
409             uint8 *pDst = (uint8 *)dInfo.lpSurface + y * dInfo.lPitch;
410
411             // Points to current byte
412             uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + tinfo.LeftToLoad;
413
414             for (uint32 x = 0; x < tinfo.WidthToLoad; x++)
415             {
416                 register uint8 b = pSrc[(dwByteOffset++) ^ 0x3];
417                 uint8 I = *(FourToEightArray+(b>>4));
418
419                 *pDst++ = I;
420                 *pDst++ = I;
421                 *pDst++ = I;
422                 *pDst++ = *(FourToEightArray+(b&0xF));
423             }
424         }
425     }   
426     
427     pTexture->EndUpdate(&dInfo);
428     pTexture->SetOthersVariables();
429
430 }
431
432 // E.g. camera's clouds, shadows
433 void ConvertIA16(CTexture *pTexture, const TxtrInfo &tinfo)
434 {
435     DrawInfo dInfo;
436     uint32 nFiddle;
437
438     uint16 * pSrc = (uint16*)(tinfo.pPhysicalAddress);
439     uint8 * pByteSrc = (uint8 *)pSrc;
440
441     if (!pTexture->StartUpdate(&dInfo))
442         return;
443
444     if (tinfo.bSwapped)
445     {
446         for (uint32 y = 0; y < tinfo.HeightToLoad; y++)
447         {
448             uint8 *pDst = (uint8 *)dInfo.lpSurface + y * dInfo.lPitch;
449
450             if ((y%2) == 0)
451                 nFiddle = 0x2;
452             else
453                 nFiddle = 0x4 | 0x2;
454
455             // Points to current word
456             uint32 dwWordOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad * 2);
457
458             for (uint32 x = 0; x < tinfo.WidthToLoad; x++)
459             {
460                 uint16 w = *(uint16 *)&pByteSrc[dwWordOffset^nFiddle];
461
462                 *pDst++ = (uint8)(w >> 8);
463                 *pDst++ = (uint8)(w >> 8);
464                 *pDst++ = (uint8)(w >> 8);
465                 *pDst++ = (uint8)(w & 0xFF);
466
467                 dwWordOffset += 2;
468             }
469         }
470     }
471     else
472     {
473         for (uint32 y = 0; y < tinfo.HeightToLoad; y++)
474         {
475             uint8 *pDst = (uint8 *)dInfo.lpSurface + y * dInfo.lPitch;
476
477             // Points to current word
478             uint32 dwWordOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad * 2);
479
480             for (uint32 x = 0; x < tinfo.WidthToLoad; x++)
481             {
482                 uint16 w = *(uint16 *)&pByteSrc[dwWordOffset^0x2];
483
484                 *pDst++ = (uint8)(w >> 8);
485                 *pDst++ = (uint8)(w >> 8);
486                 *pDst++ = (uint8)(w >> 8);
487                 *pDst++ = (uint8)(w & 0xFF);
488
489                 dwWordOffset += 2;
490             }
491         }       
492     }
493
494
495     pTexture->EndUpdate(&dInfo);
496     pTexture->SetOthersVariables();
497 }
498
499
500
501 // Used by MarioKart
502 void ConvertI4(CTexture *pTexture, const TxtrInfo &tinfo)
503 {
504     DrawInfo dInfo;
505     uint32 nFiddle;
506
507     uint8 * pSrc = (uint8*)(tinfo.pPhysicalAddress);
508
509 #ifdef DEBUGGER
510     if (((long long) pSrc) % 4) TRACE0("Texture src addr is not aligned to 4 bytes, check me");
511 #endif
512
513     if (!pTexture->StartUpdate(&dInfo))
514         return;
515
516     if (tinfo.bSwapped)
517     {
518         for (uint32 y = 0; y < tinfo.HeightToLoad; y++)
519         {
520             uint8 *pDst = (uint8 *)dInfo.lpSurface + y * dInfo.lPitch;
521
522             // Might not work with non-even starting X
523             uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad / 2);
524
525             // For odd lines, swap words too
526             if( !conkerSwapHack || (y&4) == 0 )
527             {
528                 if ((y%2) == 0)
529                     nFiddle = 0x3;
530                 else
531                     nFiddle = 0x7;
532             }
533             else
534             {
535                 if ((y%2) == 1)
536                     nFiddle = 0x3;
537                 else
538                     nFiddle = 0x7;
539             }
540
541             if (tinfo.WidthToLoad == 1)
542             {
543                 // corner case
544                 uint8 b = pSrc[dwByteOffset ^ nFiddle];
545                 *pDst++ = FourToEight[(b & 0xF0)>>4];
546                 *pDst++ = FourToEight[(b & 0xF0)>>4];
547                 *pDst++ = FourToEight[(b & 0xF0)>>4];
548                 *pDst++ = FourToEight[(b & 0xF0)>>4];   
549             }
550             else for (uint32 x = 0; x < tinfo.WidthToLoad; x+=2)
551             {
552                 // two pixels at a time
553                 uint8 b = pSrc[dwByteOffset ^ nFiddle];
554
555                 // Even
556                 *pDst++ = FourToEight[(b & 0xF0)>>4];   // Other implementations seem to or in (b&0xF0)>>4
557                 *pDst++ = FourToEight[(b & 0xF0)>>4]; // why?
558                 *pDst++ = FourToEight[(b & 0xF0)>>4];
559                 *pDst++ = FourToEight[(b & 0xF0)>>4];   
560                 // Odd
561                 *pDst++ = FourToEight[(b & 0x0F)];
562                 *pDst++ = FourToEight[(b & 0x0F)];
563                 *pDst++ = FourToEight[(b & 0x0F)];
564                 *pDst++ = FourToEight[(b & 0x0F)];
565
566                 dwByteOffset++;
567             }
568         }
569
570         conkerSwapHack = false;
571     }
572     else
573     {
574         for (uint32 y = 0; y < tinfo.HeightToLoad; y++)
575         {
576             uint8 *pDst = (uint8 *)dInfo.lpSurface + y * dInfo.lPitch;
577
578             // Might not work with non-even starting X
579             uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad / 2);
580
581             if (tinfo.WidthToLoad == 1)
582             {
583                 // corner case
584                 uint8 b = pSrc[dwByteOffset ^ 0x3];
585                 *pDst++ = FourToEight[(b & 0xF0)>>4];
586                 *pDst++ = FourToEight[(b & 0xF0)>>4];
587                 *pDst++ = FourToEight[(b & 0xF0)>>4];
588                 *pDst++ = FourToEight[(b & 0xF0)>>4];   
589             }
590             else for (uint32 x = 0; x < tinfo.WidthToLoad; x+=2)
591             {
592                 // two pixels at a time
593                 uint8 b = pSrc[dwByteOffset ^ 0x3];
594
595                 // Even
596                 *pDst++ = FourToEight[(b & 0xF0)>>4];   // Other implementations seem to or in (b&0xF0)>>4
597                 *pDst++ = FourToEight[(b & 0xF0)>>4]; // why?
598                 *pDst++ = FourToEight[(b & 0xF0)>>4];
599                 *pDst++ = FourToEight[(b & 0xF0)>>4];   
600                 // Odd
601                 *pDst++ = FourToEight[(b & 0x0F)];
602                 *pDst++ = FourToEight[(b & 0x0F)];
603                 *pDst++ = FourToEight[(b & 0x0F)];
604                 *pDst++ = FourToEight[(b & 0x0F)];
605
606                 dwByteOffset++;
607             }
608         }
609     }
610
611     pTexture->EndUpdate(&dInfo);
612     pTexture->SetOthersVariables();
613 }
614
615 // Used by MarioKart
616 void ConvertI8(CTexture *pTexture, const TxtrInfo &tinfo)
617 {
618     DrawInfo dInfo;
619     uint32 nFiddle;
620
621     long long pSrc = (long long) tinfo.pPhysicalAddress;
622     if (!pTexture->StartUpdate(&dInfo))
623         return;
624
625     if (tinfo.bSwapped)
626     {
627         for (uint32 y = 0; y < tinfo.HeightToLoad; y++)
628         {
629             if ((y%2) == 0)
630                 nFiddle = 0x3;
631             else
632                 nFiddle = 0x7;
633
634             uint8 *pDst = (uint8 *)dInfo.lpSurface + y * dInfo.lPitch;
635
636             uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + tinfo.LeftToLoad;
637
638             for (uint32 x = 0; x < tinfo.WidthToLoad; x++)
639             {
640                 uint8 b = *(uint8*)((pSrc+dwByteOffset)^nFiddle);
641
642                 *pDst++ = b;
643                 *pDst++ = b;
644                 *pDst++ = b;
645                 *pDst++ = b;        // Alpha not 255?
646
647                 dwByteOffset++;
648             }
649         }
650     }
651     else
652     {
653         for (uint32 y = 0; y < tinfo.HeightToLoad; y++)
654         {
655             uint8 *pDst = (uint8 *)dInfo.lpSurface + y * dInfo.lPitch;
656
657             uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + tinfo.LeftToLoad;
658
659             for (uint32 x = 0; x < tinfo.WidthToLoad; x++)
660             {
661                 uint8 b = *(uint8*)((pSrc+dwByteOffset)^0x3);
662
663                 *pDst++ = b;
664                 *pDst++ = b;
665                 *pDst++ = b;
666                 *pDst++ = b;        // Alpha not 255?
667
668                 dwByteOffset++;
669             }
670         }
671     }
672
673     pTexture->EndUpdate(&dInfo);
674     pTexture->SetOthersVariables();
675
676 }
677
678 //*****************************************************************************
679 // Convert CI4 images. We need to switch on the palette type
680 //*****************************************************************************
681 void ConvertCI4( CTexture * p_texture, const TxtrInfo & tinfo )
682 {
683     if ( tinfo.TLutFmt == TLUT_FMT_RGBA16 )
684     {
685         ConvertCI4_RGBA16( p_texture, tinfo );  
686     }
687     else if ( tinfo.TLutFmt == TLUT_FMT_IA16 )
688     {
689         ConvertCI4_IA16( p_texture, tinfo );                    
690     }
691 }
692
693 //*****************************************************************************
694 // Convert CI8 images. We need to switch on the palette type
695 //*****************************************************************************
696 void ConvertCI8( CTexture * p_texture, const TxtrInfo & tinfo )
697 {
698     if ( tinfo.TLutFmt == TLUT_FMT_RGBA16 )
699     {
700         ConvertCI8_RGBA16( p_texture, tinfo );  
701     }
702     else if ( tinfo.TLutFmt == TLUT_FMT_IA16 )
703     {
704         ConvertCI8_IA16( p_texture, tinfo );                    
705     }
706 }
707
708 // Used by Starfox intro
709 void ConvertCI4_RGBA16(CTexture *pTexture, const TxtrInfo &tinfo)
710 {
711     DrawInfo dInfo;
712     uint32 nFiddle;
713
714     uint8 * pSrc = (uint8*)(tinfo.pPhysicalAddress);
715     uint16 * pPal = (uint16 *)tinfo.PalAddress;
716     bool bIgnoreAlpha = (tinfo.TLutFmt==TLUT_FMT_NONE);
717     
718     if (!pTexture->StartUpdate(&dInfo))
719         return;
720
721     if (tinfo.bSwapped)
722     {
723         for (uint32 y = 0; y <  tinfo.HeightToLoad; y++)
724         {
725             if ((y%2) == 0)
726                 nFiddle = 0x3;
727             else
728                 nFiddle = 0x7;
729
730             uint32 * pDst = (uint32 *)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch);
731
732             uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch);
733
734             if (tinfo.WidthToLoad == 1)
735             {
736                 // corner case
737                 uint8 b = pSrc[dwByteOffset ^ nFiddle];
738                 uint8 bhi = (b&0xf0)>>4;
739                 *pDst = Convert555ToRGBA(pPal[bhi^1]);    // Remember palette is in different endian order!
740                 if( bIgnoreAlpha )
741                 {
742                     *pDst |= 0xFF000000;
743                 }
744             }
745             else for (uint32 x = 0; x < tinfo.WidthToLoad; x+=2)
746             {
747                 // two at a time
748                 uint8 b = pSrc[dwByteOffset ^ nFiddle];
749
750                 uint8 bhi = (b&0xf0)>>4;
751                 uint8 blo = (b&0x0f);
752
753                 pDst[0] = Convert555ToRGBA(pPal[bhi^1]);    // Remember palette is in different endian order!
754                 pDst[1] = Convert555ToRGBA(pPal[blo^1]);    // Remember palette is in different endian order!
755
756                 if( bIgnoreAlpha )
757                 {
758                     pDst[0] |= 0xFF000000;
759                     pDst[1] |= 0xFF000000;
760                 }
761
762                 pDst+=2;
763
764                 dwByteOffset++;
765             }
766         }
767     }
768     else
769     {
770         for (uint32 y = 0; y <  tinfo.HeightToLoad; y++)
771         {
772             uint32 * pDst = (uint32 *)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch);
773
774             uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad / 2);
775
776             if (tinfo.WidthToLoad == 1)
777             {
778                 // corner case
779                 uint8 b = pSrc[dwByteOffset ^ 0x3];
780                 uint8 bhi = (b&0xf0)>>4;
781                 *pDst = Convert555ToRGBA(pPal[bhi^1]);    // Remember palette is in different endian order!
782                 if( bIgnoreAlpha )
783                 {
784                     *pDst |= 0xFF000000;
785                 }
786             }
787             else for (uint32 x = 0; x < tinfo.WidthToLoad; x+=2)
788             {
789                 // two at a time
790                 uint8 b = pSrc[dwByteOffset ^ 0x3];
791
792                 uint8 bhi = (b&0xf0)>>4;
793                 uint8 blo = (b&0x0f);
794
795                 pDst[0] = Convert555ToRGBA(pPal[bhi^1]);    // Remember palette is in different endian order!
796                 pDst[1] = Convert555ToRGBA(pPal[blo^1]);    // Remember palette is in different endian order!
797                 
798                 if( bIgnoreAlpha )
799                 {
800                     pDst[0] |= 0xFF000000;
801                     pDst[1] |= 0xFF000000;
802                 }
803
804                 pDst+=2;
805
806                 dwByteOffset++;
807             }
808         }
809     }
810     pTexture->EndUpdate(&dInfo);
811     pTexture->SetOthersVariables();
812 }
813
814 // Used by Starfox intro
815 void ConvertCI4_IA16(CTexture *pTexture, const TxtrInfo &tinfo)
816 {
817     DrawInfo dInfo;
818     uint32 nFiddle;
819
820     uint8 * pSrc = (uint8*)(tinfo.pPhysicalAddress);
821
822 #ifdef DEBUGGER
823     if (((long long) pSrc) % 4) TRACE0("Texture src addr is not aligned to 4 bytes, check me");
824 #endif
825
826     uint16 * pPal = (uint16 *)tinfo.PalAddress;
827     bool bIgnoreAlpha = (tinfo.TLutFmt==TLUT_FMT_UNKNOWN);
828
829     if (!pTexture->StartUpdate(&dInfo))
830         return;
831
832     if (tinfo.bSwapped)
833     {
834         for (uint32 y = 0; y <  tinfo.HeightToLoad; y++)
835         {
836             if ((y%2) == 0)
837                 nFiddle = 0x3;
838             else
839                 nFiddle = 0x7;
840
841             uint32 * pDst = (uint32 *)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch);
842
843             uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad / 2);
844
845             if (tinfo.WidthToLoad == 1)
846             {
847                 // corner case
848                 uint8 b = pSrc[dwByteOffset ^ nFiddle];
849                 uint8 bhi = (b&0xf0)>>4;
850                 *pDst = ConvertIA16ToRGBA(pPal[bhi^1]);   // Remember palette is in different endian order!
851                 if( bIgnoreAlpha )
852                     *pDst |= 0xFF000000;
853             }
854             else for (uint32 x = 0; x < tinfo.WidthToLoad; x+=2)
855             {
856                 // two at a time
857                 uint8 b = pSrc[dwByteOffset ^ nFiddle];
858
859                 uint8 bhi = (b&0xf0)>>4;
860                 uint8 blo = (b&0x0f);
861
862                 pDst[0] = ConvertIA16ToRGBA(pPal[bhi^1]);   // Remember palette is in different endian order!
863                 pDst[1] = ConvertIA16ToRGBA(pPal[blo^1]);   // Remember palette is in different endian order!
864                 
865                 if( bIgnoreAlpha )
866                 {
867                     pDst[0] |= 0xFF000000;
868                     pDst[1] |= 0xFF000000;
869                 }
870
871                 pDst+=2;
872
873                 dwByteOffset++;
874             }
875         }
876     }
877     else
878     {
879         for (uint32 y = 0; y <  tinfo.HeightToLoad; y++)
880         {
881             uint32 * pDst = (uint32 *)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch);
882
883             uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad / 2);
884
885             if (tinfo.WidthToLoad == 1)
886             {
887                 // corner case
888                 uint8 b = pSrc[dwByteOffset ^ 0x3];
889                 uint8 bhi = (b&0xf0)>>4;
890                 *pDst = ConvertIA16ToRGBA(pPal[bhi^1]);   // Remember palette is in different endian order!
891                 if( bIgnoreAlpha )
892                     *pDst |= 0xFF000000;
893             }
894             else for (uint32 x = 0; x < tinfo.WidthToLoad; x+=2)
895             {
896                 // two pixels at a time
897                 uint8 b = pSrc[dwByteOffset ^ 0x3];
898
899                 uint8 bhi = (b&0xf0)>>4;
900                 uint8 blo = (b&0x0f);
901
902                 pDst[0] = ConvertIA16ToRGBA(pPal[bhi^1]);   // Remember palette is in different endian order!
903                 pDst[1] = ConvertIA16ToRGBA(pPal[blo^1]);   // Remember palette is in different endian order!
904                 
905                 if( bIgnoreAlpha )
906                 {
907                     pDst[0] |= 0xFF000000;
908                     pDst[1] |= 0xFF000000;
909                 }
910
911                 pDst+=2;
912
913                 dwByteOffset++;
914             }
915         }
916     }
917     pTexture->EndUpdate(&dInfo);
918     pTexture->SetOthersVariables();
919 }
920
921
922 // Used by MarioKart for Cars etc
923 void ConvertCI8_RGBA16(CTexture *pTexture, const TxtrInfo &tinfo)
924 {
925     DrawInfo dInfo;
926     uint32 nFiddle;
927
928     uint8 * pSrc = (uint8*)(tinfo.pPhysicalAddress);
929
930 #ifdef DEBUGGER
931     if (((long long) pSrc) % 4) TRACE0("Texture src addr is not aligned to 4 bytes, check me");
932 #endif
933
934     uint16 * pPal = (uint16 *)tinfo.PalAddress;
935     bool bIgnoreAlpha = (tinfo.TLutFmt==TLUT_FMT_NONE);
936
937     if (!pTexture->StartUpdate(&dInfo))
938         return;
939     
940     if (tinfo.bSwapped)
941     {
942         for (uint32 y = 0; y < tinfo.HeightToLoad; y++)
943         {
944             if ((y%2) == 0)
945                 nFiddle = 0x3;
946             else
947                 nFiddle = 0x7;
948
949             uint32 *pDst = (uint32 *)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch);
950
951             uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + tinfo.LeftToLoad;
952             
953             for (uint32 x = 0; x < tinfo.WidthToLoad; x++)
954             {
955                 uint8 b = pSrc[dwByteOffset ^ nFiddle];
956
957                 *pDst++ = Convert555ToRGBA(pPal[b^1]);  // Remember palette is in different endian order!
958                 
959                 if( bIgnoreAlpha )
960                 {
961                     *(pDst-1) |= 0xFF000000;
962                 }
963
964                 dwByteOffset++;
965             }
966         }
967     }
968     else
969     {
970         for (uint32 y = 0; y < tinfo.HeightToLoad; y++)
971         {
972             uint32 *pDst = (uint32 *)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch);
973
974             int dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + tinfo.LeftToLoad;
975             
976             for (uint32 x = 0; x < tinfo.WidthToLoad; x++)
977             {
978                 uint8 b = pSrc[dwByteOffset ^ 0x3];
979
980                 *pDst++ = Convert555ToRGBA(pPal[b^1]);  // Remember palette is in different endian order!
981                 if( bIgnoreAlpha )
982                 {
983                     *(pDst-1) |= 0xFF000000;
984                 }
985
986                 dwByteOffset++;
987             }
988         }
989     }
990
991     pTexture->EndUpdate(&dInfo);
992     pTexture->SetOthersVariables();
993
994 }
995
996
997 // Used by MarioKart for Cars etc
998 void ConvertCI8_IA16(CTexture *pTexture, const TxtrInfo &tinfo)
999 {
1000     DrawInfo dInfo;
1001     uint32 nFiddle;
1002
1003     uint8 * pSrc = (uint8*)(tinfo.pPhysicalAddress);
1004
1005 #ifdef DEBUGGER
1006     if (((long long) pSrc) % 4) TRACE0("Texture src addr is not aligned to 4 bytes, check me");
1007 #endif
1008
1009     uint16 * pPal = (uint16 *)tinfo.PalAddress;
1010     bool bIgnoreAlpha = (tinfo.TLutFmt==TLUT_FMT_UNKNOWN);
1011
1012     if (!pTexture->StartUpdate(&dInfo))
1013         return;
1014
1015     if (tinfo.bSwapped)
1016     {
1017         for (uint32 y = 0; y < tinfo.HeightToLoad; y++)
1018         {
1019             if ((y%2) == 0)
1020                 nFiddle = 0x3;
1021             else
1022                 nFiddle = 0x7;
1023
1024             uint32 *pDst = (uint32 *)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch);
1025
1026             uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + tinfo.LeftToLoad;
1027             
1028             for (uint32 x = 0; x < tinfo.WidthToLoad; x++)
1029             {
1030                 uint8 b = pSrc[dwByteOffset ^ nFiddle];
1031
1032                 *pDst++ = ConvertIA16ToRGBA(pPal[b^1]); // Remember palette is in different endian order!
1033                 if( bIgnoreAlpha )
1034                 {
1035                     *(pDst-1) |= 0xFF000000;
1036                 }
1037
1038                 dwByteOffset++;
1039             }
1040         }
1041     }
1042     else
1043     {
1044         for (uint32 y = 0; y < tinfo.HeightToLoad; y++)
1045         {
1046             uint32 *pDst = (uint32 *)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch);
1047
1048             uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + tinfo.LeftToLoad;
1049             
1050             for (uint32 x = 0; x < tinfo.WidthToLoad; x++)
1051             {
1052                 uint8 b = pSrc[dwByteOffset ^ 0x3];
1053
1054                 *pDst++ = ConvertIA16ToRGBA(pPal[b^1]); // Remember palette is in different endian order!
1055                 if( bIgnoreAlpha )
1056                 {
1057                     *(pDst-1) |= 0xFF000000;
1058                 }
1059
1060                 dwByteOffset++;
1061             }
1062         }
1063     }
1064
1065     pTexture->EndUpdate(&dInfo);
1066     pTexture->SetOthersVariables();
1067 }
1068
1069 void ConvertYUV(CTexture *pTexture, const TxtrInfo &tinfo)
1070 {
1071     DrawInfo dInfo;
1072     if (!pTexture->StartUpdate(&dInfo))
1073         return;
1074
1075     uint32 x, y;
1076     uint32 nFiddle;
1077
1078     if( options.bUseFullTMEM )
1079     {
1080         Tile &tile = gRDP.tiles[tinfo.tileNo];
1081
1082         uint16 * pSrc;
1083         if( tinfo.tileNo >= 0 )
1084             pSrc = (uint16*)&g_Tmem.g_Tmem64bit[tile.dwTMem];
1085         else
1086             pSrc = (uint16*)(tinfo.pPhysicalAddress);
1087
1088         uint8 * pByteSrc = (uint8 *)pSrc;
1089         for (y = 0; y < tinfo.HeightToLoad; y++)
1090         {
1091             nFiddle = ( y&1 )? 0x4 : 0;
1092             int dwWordOffset = tinfo.tileNo>=0? tile.dwLine*8*y : ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad * 2);
1093             uint32 * dwDst = (uint32 *)((uint8 *)dInfo.lpSurface + y*dInfo.lPitch);
1094
1095             for (x = 0; x < tinfo.WidthToLoad/2; x++)
1096             {
1097                 int y0 = *(uint8*)&pByteSrc[(dwWordOffset+1)^nFiddle];
1098                 int y1 = *(uint8*)&pByteSrc[(dwWordOffset+3)^nFiddle];
1099                 int u0 = *(uint8*)&pByteSrc[(dwWordOffset  )^nFiddle];
1100                 int v0 = *(uint8*)&pByteSrc[(dwWordOffset+2)^nFiddle];
1101
1102                 dwDst[x*2+0] = ConvertYUV16ToR8G8B8(y0,u0,v0);
1103                 dwDst[x*2+1] = ConvertYUV16ToR8G8B8(y1,u0,v0);
1104
1105                 dwWordOffset += 4;
1106             }
1107         }
1108     }
1109     else
1110     {
1111         uint16 * pSrc = (uint16*)(tinfo.pPhysicalAddress);
1112         uint8 * pByteSrc = (uint8 *)pSrc;
1113
1114         if (tinfo.bSwapped)
1115         {
1116             for (y = 0; y < tinfo.HeightToLoad; y++)
1117             {
1118                 if ((y&1) == 0)
1119                     nFiddle = 0x3;
1120                 else
1121                     nFiddle = 0x7;
1122
1123                 // dwDst points to start of destination row
1124                 uint32 * dwDst = (uint32 *)((uint8 *)dInfo.lpSurface + y*dInfo.lPitch);
1125
1126                 // DWordOffset points to the current dword we're looking at
1127                 // (process 2 pixels at a time). May be a problem if we don't start on even pixel
1128                 uint32 dwWordOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad * 2);
1129
1130                 for (x = 0; x < tinfo.WidthToLoad/2; x++)
1131                 {
1132                     int y0 = *(uint8*)&pByteSrc[(dwWordOffset+2)^nFiddle];
1133                     int v0 = *(uint8*)&pByteSrc[(dwWordOffset+1)^nFiddle];
1134                     int y1 = *(uint8*)&pByteSrc[(dwWordOffset  )^nFiddle];
1135                     int u0 = *(uint8*)&pByteSrc[(dwWordOffset+3)^nFiddle];
1136
1137                     dwDst[x*2+0] = ConvertYUV16ToR8G8B8(y0,u0,v0);
1138                     dwDst[x*2+1] = ConvertYUV16ToR8G8B8(y1,u0,v0);
1139
1140                     dwWordOffset += 4;
1141                 }
1142             }
1143         }
1144         else
1145         {
1146             for (y = 0; y < tinfo.HeightToLoad; y++)
1147             {
1148                 // dwDst points to start of destination row
1149                 uint32 * dwDst = (uint32 *)((uint8 *)dInfo.lpSurface + y*dInfo.lPitch);
1150                 uint32 dwByteOffset = y * 32;
1151
1152                 for (x = 0; x < tinfo.WidthToLoad/2; x++)
1153                 {
1154                     int y0 = *(uint8*)&pByteSrc[(dwByteOffset+2)];
1155                     int v0 = *(uint8*)&pByteSrc[(dwByteOffset+1)];
1156                     int y1 = *(uint8*)&pByteSrc[(dwByteOffset  )];
1157                     int u0 = *(uint8*)&pByteSrc[(dwByteOffset+3)];
1158
1159                     dwDst[x*2+0] = ConvertYUV16ToR8G8B8(y0,u0,v0);
1160                     dwDst[x*2+1] = ConvertYUV16ToR8G8B8(y1,u0,v0);
1161
1162                     // Increment word offset to point to the next two pixels
1163                     dwByteOffset += 4;
1164                 }
1165             }
1166         }
1167     }
1168
1169     pTexture->EndUpdate(&dInfo);
1170     pTexture->SetOthersVariables();
1171 }
1172
1173 uint32 ConvertYUV16ToR8G8B8(int Y, int U, int V)
1174 {
1175     /*
1176     int R = int(g_convc0 *(Y-16) + g_convc1 * V);
1177     int G = int(g_convc0 *(Y-16) + g_convc2 * U - g_convc3 * V);
1178     int B = int(g_convc0 *(Y-16) + g_convc4 * U);
1179     */
1180
1181     Y += 80;
1182     int R = int(Y + (1.370705f * (V-128)));
1183     int G = int(Y - (0.698001f * (V-128)) - (0.337633f * (U-128)));
1184     int B = int(Y + (1.732446f * (U-128)));
1185
1186     R = R < 0 ? 0 : (R>255 ? 255 : R);
1187     G = G < 0 ? 0 : (G>255 ? 255 : G);
1188     B = B < 0 ? 0 : (B>255 ? 255 : B);
1189
1190     return COLOR_RGBA(R, G, B, 0xFF);
1191 }
1192
1193
1194 // Used by Starfox intro
1195 void Convert4b(CTexture *pTexture, const TxtrInfo &tinfo)
1196 {
1197     DrawInfo dInfo;
1198
1199     if (!pTexture->StartUpdate(&dInfo)) 
1200         return;
1201
1202     uint16 * pPal = (uint16 *)tinfo.PalAddress;
1203     bool bIgnoreAlpha = (tinfo.TLutFmt==TLUT_FMT_UNKNOWN);
1204     if( tinfo.Format <= TXT_FMT_CI ) bIgnoreAlpha = (tinfo.TLutFmt==TLUT_FMT_NONE);
1205
1206     Tile &tile = gRDP.tiles[tinfo.tileNo];
1207
1208     uint8 *pByteSrc = tinfo.tileNo >= 0 ? (uint8*)&g_Tmem.g_Tmem64bit[tile.dwTMem] : (uint8*)(tinfo.pPhysicalAddress);
1209
1210     for (uint32 y = 0; y < tinfo.HeightToLoad; y++)
1211     {
1212         uint32 nFiddle;
1213         if( tinfo.tileNo < 0 )  
1214         {
1215             if (tinfo.bSwapped)
1216             {
1217                 if ((y%2) == 0)
1218                     nFiddle = 0x3;
1219                 else
1220                     nFiddle = 0x7;
1221             }
1222             else
1223             {
1224                 nFiddle = 3;
1225             }
1226         }
1227         else
1228         {
1229             nFiddle = ( y&1 )? 0x4 : 0;
1230         }
1231
1232         uint32 * pDst = (uint32 *)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch);
1233         int idx = tinfo.tileNo>=0 ? tile.dwLine*8*y : ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad / 2);
1234
1235         if (tinfo.WidthToLoad == 1)
1236         {
1237             // corner case
1238             uint8 b = pByteSrc[idx^nFiddle];
1239             uint8 bhi = (b&0xf0)>>4;
1240             if( gRDP.otherMode.text_tlut>=2 || ( tinfo.Format != TXT_FMT_IA && tinfo.Format != TXT_FMT_I) )
1241             {
1242                 if( tinfo.TLutFmt == TLUT_FMT_IA16 )
1243                 {
1244                     if( tinfo.tileNo>=0 )
1245                         *pDst = ConvertIA16ToRGBA(g_Tmem.g_Tmem16bit[0x400+tinfo.Palette*0x40+(bhi<<2)]);
1246                     else
1247                         *pDst = ConvertIA16ToRGBA(pPal[bhi^1]);
1248                 }
1249                 else
1250                 {
1251                     if( tinfo.tileNo>=0 )
1252                         *pDst = Convert555ToRGBA(g_Tmem.g_Tmem16bit[0x400+tinfo.Palette*0x40+(bhi<<2)]);
1253                     else
1254                         *pDst = Convert555ToRGBA(pPal[bhi^1]);
1255                 }
1256             }
1257             else if( tinfo.Format == TXT_FMT_IA )
1258                 *pDst = ConvertIA4ToRGBA(b>>4);
1259             else    // if( tinfo.Format == TXT_FMT_I )
1260                 *pDst = ConvertI4ToRGBA(b>>4);
1261             if( bIgnoreAlpha )
1262                 *pDst |= 0xFF000000;
1263         }
1264         else for (uint32 x = 0; x < tinfo.WidthToLoad; x+=2, idx++)
1265         {
1266             // two pixels at a time
1267             uint8 b = pByteSrc[idx^nFiddle];
1268             uint8 bhi = (b&0xf0)>>4;
1269             uint8 blo = (b&0x0f);
1270
1271             if( gRDP.otherMode.text_tlut>=2 || ( tinfo.Format != TXT_FMT_IA && tinfo.Format != TXT_FMT_I) )
1272             {
1273                 if( tinfo.TLutFmt == TLUT_FMT_IA16 )
1274                 {
1275                     if( tinfo.tileNo>=0 )
1276                     {
1277                         pDst[0] = ConvertIA16ToRGBA(g_Tmem.g_Tmem16bit[0x400+tinfo.Palette*0x40+(bhi<<2)]);
1278                         pDst[1] = ConvertIA16ToRGBA(g_Tmem.g_Tmem16bit[0x400+tinfo.Palette*0x40+(blo<<2)]);
1279                     }
1280                     else
1281                     {
1282                         pDst[0] = ConvertIA16ToRGBA(pPal[bhi^1]);
1283                         pDst[1] = ConvertIA16ToRGBA(pPal[blo^1]);
1284                     }
1285                 }
1286                 else
1287                 {
1288                     if( tinfo.tileNo>=0 )
1289                     {
1290                         pDst[0] = Convert555ToRGBA(g_Tmem.g_Tmem16bit[0x400+tinfo.Palette*0x40+(bhi<<2)]);
1291                         pDst[1] = Convert555ToRGBA(g_Tmem.g_Tmem16bit[0x400+tinfo.Palette*0x40+(blo<<2)]);
1292                     }
1293                     else
1294                     {
1295                         pDst[0] = Convert555ToRGBA(pPal[bhi^1]);
1296                         pDst[1] = Convert555ToRGBA(pPal[blo^1]);
1297                     }
1298                 }
1299             }
1300             else if( tinfo.Format == TXT_FMT_IA )
1301             {
1302                 pDst[0] = ConvertIA4ToRGBA(b>>4);
1303                 pDst[1] = ConvertIA4ToRGBA(b&0xF);
1304             }
1305             else    // if( tinfo.Format == TXT_FMT_I )
1306             {
1307                 pDst[0] = ConvertI4ToRGBA(b>>4);
1308                 pDst[1] = ConvertI4ToRGBA(b&0xF);
1309             }
1310
1311             if( bIgnoreAlpha )
1312             {
1313                 pDst[0] |= 0xFF000000;
1314                 pDst[1] |= 0xFF000000;
1315             }
1316             pDst+=2;
1317         }
1318     }
1319
1320     pTexture->EndUpdate(&dInfo);
1321     pTexture->SetOthersVariables();
1322 }
1323
1324 void Convert8b(CTexture *pTexture, const TxtrInfo &tinfo)
1325 {
1326     DrawInfo dInfo;
1327     if (!pTexture->StartUpdate(&dInfo)) 
1328         return;
1329
1330     uint16 * pPal = (uint16 *)tinfo.PalAddress;
1331     bool bIgnoreAlpha = (tinfo.TLutFmt==TLUT_FMT_UNKNOWN);
1332     if( tinfo.Format <= TXT_FMT_CI ) bIgnoreAlpha = (tinfo.TLutFmt==TLUT_FMT_NONE);
1333
1334     Tile &tile = gRDP.tiles[tinfo.tileNo];
1335
1336     uint8 *pByteSrc;
1337     if( tinfo.tileNo >= 0 )
1338     {
1339         pByteSrc = (uint8*)&g_Tmem.g_Tmem64bit[tile.dwTMem];
1340     }
1341     else
1342     {
1343         pByteSrc = (uint8*)(tinfo.pPhysicalAddress);
1344     }
1345
1346
1347     for (uint32 y = 0; y < tinfo.HeightToLoad; y++)
1348     {
1349         uint32 * pDst = (uint32 *)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch);
1350
1351         uint32 nFiddle;
1352         if( tinfo.tileNo < 0 )  
1353         {
1354             if (tinfo.bSwapped)
1355             {
1356                 if ((y%2) == 0)
1357                     nFiddle = 0x3;
1358                 else
1359                     nFiddle = 0x7;
1360             }
1361             else
1362             {
1363                 nFiddle = 3;
1364             }
1365         }
1366         else
1367         {
1368             nFiddle = ( y&1 )? 0x4 : 0;
1369         }
1370
1371
1372         int idx = tinfo.tileNo>=0? tile.dwLine*8*y : ((y+tinfo.TopToLoad) * tinfo.Pitch) + tinfo.LeftToLoad;
1373
1374         for (uint32 x = 0; x < tinfo.WidthToLoad; x++, idx++)
1375         {
1376             uint8 b = pByteSrc[idx^nFiddle];
1377
1378             if( gRDP.otherMode.text_tlut>=2 || ( tinfo.Format != TXT_FMT_IA && tinfo.Format != TXT_FMT_I) )
1379             {
1380                 if( tinfo.TLutFmt == TLUT_FMT_IA16 )
1381                 {
1382                     if( tinfo.tileNo>=0 )
1383                         *pDst = ConvertIA16ToRGBA(g_Tmem.g_Tmem16bit[0x400+(b<<2)]);
1384                     else
1385                         *pDst = ConvertIA16ToRGBA(pPal[b^1]);
1386                 }
1387                 else
1388                 {
1389                     if( tinfo.tileNo>=0 )
1390                         *pDst = Convert555ToRGBA(g_Tmem.g_Tmem16bit[0x400+(b<<2)]);
1391                     else
1392                         *pDst = Convert555ToRGBA(pPal[b^1]);
1393                 }
1394             }
1395             else if( tinfo.Format == TXT_FMT_IA )
1396             {
1397                 uint8 I = FourToEight[(b & 0xf0)>>4];
1398                 uint8 * pByteDst = (uint8*)pDst;
1399                 pByteDst[0] = I;
1400                 pByteDst[1] = I;
1401                 pByteDst[2] = I;
1402                 pByteDst[3] = FourToEight[(b & 0x0f)   ];
1403             }
1404             else    // if( tinfo.Format == TXT_FMT_I )
1405             {
1406                 uint8 * pByteDst = (uint8*)pDst;
1407                 pByteDst[0] = b;
1408                 pByteDst[1] = b;
1409                 pByteDst[2] = b;
1410                 pByteDst[3] = b;
1411             }
1412
1413             if( bIgnoreAlpha )
1414             {
1415                 *pDst |= 0xFF000000;
1416             }
1417             pDst++;
1418         }
1419     }
1420
1421     pTexture->EndUpdate(&dInfo);
1422     pTexture->SetOthersVariables();
1423 }
1424
1425
1426 void Convert16b(CTexture *pTexture, const TxtrInfo &tinfo)
1427 {
1428     DrawInfo dInfo;
1429     if (!pTexture->StartUpdate(&dInfo)) 
1430         return;
1431
1432     Tile &tile = gRDP.tiles[tinfo.tileNo];
1433
1434     uint16 *pWordSrc;
1435     if( tinfo.tileNo >= 0 )
1436         pWordSrc = (uint16*)&g_Tmem.g_Tmem64bit[tile.dwTMem];
1437     else
1438         pWordSrc = (uint16*)(tinfo.pPhysicalAddress);
1439
1440
1441     for (uint32 y = 0; y < tinfo.HeightToLoad; y++)
1442     {
1443         uint32 * dwDst = (uint32 *)((uint8 *)dInfo.lpSurface + y*dInfo.lPitch);
1444
1445         uint32 nFiddle;
1446         if( tinfo.tileNo < 0 )  
1447         {
1448             if (tinfo.bSwapped)
1449             {
1450                 if ((y&1) == 0)
1451                     nFiddle = 0x1;
1452                 else
1453                     nFiddle = 0x3;
1454             }
1455             else
1456             {
1457                 nFiddle = 0x1;
1458             }
1459         }
1460         else
1461         {
1462             nFiddle = ( y&1 )? 0x2 : 0;
1463         }
1464
1465
1466         int idx = tinfo.tileNo>=0? tile.dwLine*4*y : (((y+tinfo.TopToLoad) * tinfo.Pitch)>>1) + tinfo.LeftToLoad;
1467
1468         for (uint32 x = 0; x < tinfo.WidthToLoad; x++, idx++)
1469         {
1470             uint16 w = pWordSrc[idx^nFiddle];
1471             uint16 w2 = tinfo.tileNo>=0? ((w>>8)|(w<<8)) : w;
1472
1473             if( tinfo.Format == TXT_FMT_RGBA )
1474             {
1475                 dwDst[x] = Convert555ToRGBA(w2);
1476             }
1477             else if( tinfo.Format == TXT_FMT_YUV )
1478             {
1479             }
1480             else if( tinfo.Format >= TXT_FMT_IA )
1481             {
1482                 uint8 * pByteDst = (uint8*)&dwDst[x];
1483                 *pByteDst++ = (uint8)(w2 >> 8);
1484                 *pByteDst++ = (uint8)(w2 >> 8);
1485                 *pByteDst++ = (uint8)(w2 >> 8);
1486                 *pByteDst++ = (uint8)(w2 & 0xFF);
1487             }
1488         }
1489     }
1490
1491     pTexture->EndUpdate(&dInfo);
1492     pTexture->SetOthersVariables();
1493 }
1494