2 Copyright (C) 2003 Rice1964
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.
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.
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.
21 #include "ConvertImage.h"
22 #include "RenderBase.h"
24 ConvertFunction gConvertFunctions_FullTMEM[ 8 ][ 4 ] =
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 } // ?
36 ConvertFunction gConvertFunctions[ 8 ][ 4 ] =
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 } // ?
49 ConvertFunction gConvertTlutFunctions[ 8 ][ 4 ] =
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 } // ?
62 extern bool conkerSwapHack;
64 void ConvertRGBA16(CTexture *pTexture, const TxtrInfo &tinfo)
68 // Copy of the base pointer
69 uint16 * pSrc = (uint16*)(tinfo.pPhysicalAddress);
71 uint8 * pByteSrc = (uint8 *)pSrc;
72 if (!pTexture->StartUpdate(&dInfo))
79 for (uint32 y = 0; y < tinfo.HeightToLoad; y++)
86 // dwDst points to start of destination row
87 uint32 * dwDst = (uint32 *)((uint8 *)dInfo.lpSurface + y*dInfo.lPitch);
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);
93 for (uint32 x = 0; x < tinfo.WidthToLoad; x++)
95 uint16 w = *(uint16 *)&pByteSrc[dwWordOffset ^ nFiddle];
97 dwDst[x] = Convert555ToRGBA(w);
99 // Increment word offset to point to the next two pixels
106 for (uint32 y = 0; y < tinfo.HeightToLoad; y++)
108 // dwDst points to start of destination row
109 uint32 * dwDst = (uint32 *)((uint8 *)dInfo.lpSurface + y*dInfo.lPitch);
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);
115 for (uint32 x = 0; x < tinfo.WidthToLoad; x++)
117 uint16 w = *(uint16 *)&pByteSrc[dwWordOffset ^ 0x2];
119 dwDst[x] = Convert555ToRGBA(w);
121 // Increment word offset to point to the next two pixels
127 pTexture->EndUpdate(&dInfo);
128 pTexture->SetOthersVariables();
131 void ConvertRGBA32(CTexture *pTexture, const TxtrInfo &tinfo)
134 if (!pTexture->StartUpdate(&dInfo))
137 uint32 * pSrc = (uint32*)(tinfo.pPhysicalAddress);
139 if( options.bUseFullTMEM )
141 Tile &tile = gRDP.tiles[tinfo.tileNo];
144 if( tinfo.tileNo >= 0 )
146 pWordSrc = (uint32*)&g_Tmem.g_Tmem64bit[tile.dwTMem];
148 for (uint32 y = 0; y < tinfo.HeightToLoad; y++)
150 uint32 * dwDst = (uint32 *)((uint8 *)dInfo.lpSurface + y*dInfo.lPitch);
152 uint32 nFiddle = ( y&1 )? 0x2 : 0;
153 int idx = tile.dwLine*4*y;
155 for (uint32 x = 0; x < tinfo.WidthToLoad; x++, idx++)
157 uint32 w = pWordSrc[idx^nFiddle];
158 uint8* psw = (uint8*)&w;
159 uint8* pdw = (uint8*)&dwDst[x];
161 pdw[0] = psw[0]; // Red
162 pdw[1] = psw[1]; // Green
163 pdw[2] = psw[2]; // Blue
165 pdw[0] = psw[2]; // Blue
166 pdw[1] = psw[1]; // Green
167 pdw[2] = psw[0]; // Red
169 pdw[3] = psw[3]; // Alpha
178 for (uint32 y = 0; y < tinfo.HeightToLoad; y++)
182 uint8 *pDst = (uint8 *)dInfo.lpSurface + y * dInfo.lPitch;
183 uint8 *pS = (uint8 *)pSrc + (y+tinfo.TopToLoad) * tinfo.Pitch + (tinfo.LeftToLoad*4);
185 for (uint32 x = 0; x < tinfo.WidthToLoad; x++)
188 pDst[0] = pS[3]; // Red
189 pDst[1] = pS[2]; // Green
190 pDst[2] = pS[1]; // Blue
192 pDst[0] = pS[1]; // Blue
193 pDst[1] = pS[2]; // Green
194 pDst[2] = pS[3]; // Red
196 pDst[3] = pS[0]; // Alpha
203 uint32 *pDst = (uint32 *)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch);
204 uint8 *pS = (uint8 *)pSrc;
207 n = (y+tinfo.TopToLoad) * tinfo.Pitch + (tinfo.LeftToLoad*4);
208 for (uint32 x = 0; x < tinfo.WidthToLoad; x++)
211 *pDst++ = COLOR_RGBA(pS[(n+1)^0x8],
216 *pDst++ = COLOR_RGBA(pS[(n+3)^0x8],
228 for (uint32 y = 0; y < tinfo.HeightToLoad; y++)
230 uint8 *pDst = (uint8 *)dInfo.lpSurface + y * dInfo.lPitch;
231 uint8 *pS = (uint8 *)pSrc + (y+tinfo.TopToLoad) * tinfo.Pitch + (tinfo.LeftToLoad*4);
233 for (uint32 x = 0; x < tinfo.WidthToLoad; x++)
236 pDst[0] = pS[3]; // Red
237 pDst[1] = pS[2]; // Green
238 pDst[2] = pS[1]; // Blue
240 pDst[0] = pS[1]; // Blue
241 pDst[1] = pS[2]; // Green
242 pDst[2] = pS[3]; // Red
244 pDst[3] = pS[0]; // Alpha
252 pTexture->EndUpdate(&dInfo);
253 pTexture->SetOthersVariables();
256 // E.g. Dear Mario text
258 void ConvertIA4(CTexture *pTexture, const TxtrInfo &tinfo)
263 uint8 * pSrc = (uint8*)(tinfo.pPhysicalAddress);
266 if (((long long)pSrc) % 4) TRACE0("Texture src addr is not aligned to 4 bytes, check me");
269 if (!pTexture->StartUpdate(&dInfo))
274 for (uint32 y = 0; y < tinfo.HeightToLoad; y++)
276 uint8 *pDst = (uint8 *)dInfo.lpSurface + y * dInfo.lPitch;
278 // For odd lines, swap words too
285 // This may not work if X is not even?
286 uint32 dwByteOffset = (y+tinfo.TopToLoad) * tinfo.Pitch + (tinfo.LeftToLoad/2);
288 if (tinfo.WidthToLoad == 1)
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];
297 else for (uint32 x = 0; x < tinfo.WidthToLoad; x+=2)
299 // Do two pixels at a time
300 uint8 b = pSrc[dwByteOffset ^ nFiddle];
303 *pDst++ = ThreeToEight[(b & 0xE0) >> 5];
304 *pDst++ = ThreeToEight[(b & 0xE0) >> 5];
305 *pDst++ = ThreeToEight[(b & 0xE0) >> 5];
306 *pDst++ = OneToEight[(b & 0x10) >> 4];
308 *pDst++ = ThreeToEight[(b & 0x0E) >> 1];
309 *pDst++ = ThreeToEight[(b & 0x0E) >> 1];
310 *pDst++ = ThreeToEight[(b & 0x0E) >> 1];
311 *pDst++ = OneToEight[(b & 0x01) ];
319 for (uint32 y = 0; y < tinfo.HeightToLoad; y++)
321 uint8 *pDst = (uint8 *)dInfo.lpSurface + (y * dInfo.lPitch);
323 // This may not work if X is not even?
324 uint32 dwByteOffset = (y+tinfo.TopToLoad) * tinfo.Pitch + (tinfo.LeftToLoad/2);
326 if (tinfo.WidthToLoad == 1)
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];
335 else for (uint32 x = 0; x < tinfo.WidthToLoad; x+=2)
337 // Do two pixels at a time
338 uint8 b = pSrc[dwByteOffset ^ 0x3];
341 *pDst++ = ThreeToEight[(b & 0xE0) >> 5];
342 *pDst++ = ThreeToEight[(b & 0xE0) >> 5];
343 *pDst++ = ThreeToEight[(b & 0xE0) >> 5];
344 *pDst++ = OneToEight[(b & 0x10) >> 4];
346 *pDst++ = ThreeToEight[(b & 0x0E) >> 1];
347 *pDst++ = ThreeToEight[(b & 0x0E) >> 1];
348 *pDst++ = ThreeToEight[(b & 0x0E) >> 1];
349 *pDst++ = OneToEight[(b & 0x01) ];
356 pTexture->EndUpdate(&dInfo);
357 pTexture->SetOthersVariables();
361 // E.g Mario's head textures
362 void ConvertIA8(CTexture *pTexture, const TxtrInfo &tinfo)
367 uint8 * pSrc = (uint8*)(tinfo.pPhysicalAddress);
370 if (((long long)pSrc) % 4) TRACE0("Texture src addr is not aligned to 4 bytes, check me");
373 if (!pTexture->StartUpdate(&dInfo))
378 for (uint32 y = 0; y < tinfo.HeightToLoad; y++)
380 // For odd lines, swap words too
386 uint8 *pDst = (uint8 *)dInfo.lpSurface + y * dInfo.lPitch;
387 // Points to current byte
388 uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + tinfo.LeftToLoad;
390 for (uint32 x = 0; x < tinfo.WidthToLoad; x++)
392 uint8 b = pSrc[dwByteOffset ^ nFiddle];
393 uint8 I = FourToEight[(b & 0xf0)>>4];
398 *pDst++ = FourToEight[(b & 0x0f) ];
406 register const uint8* FourToEightArray = &FourToEight[0];
407 for (uint32 y = 0; y < tinfo.HeightToLoad; y++)
409 uint8 *pDst = (uint8 *)dInfo.lpSurface + y * dInfo.lPitch;
411 // Points to current byte
412 uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + tinfo.LeftToLoad;
414 for (uint32 x = 0; x < tinfo.WidthToLoad; x++)
416 register uint8 b = pSrc[(dwByteOffset++) ^ 0x3];
417 uint8 I = *(FourToEightArray+(b>>4));
422 *pDst++ = *(FourToEightArray+(b&0xF));
427 pTexture->EndUpdate(&dInfo);
428 pTexture->SetOthersVariables();
432 // E.g. camera's clouds, shadows
433 void ConvertIA16(CTexture *pTexture, const TxtrInfo &tinfo)
438 uint16 * pSrc = (uint16*)(tinfo.pPhysicalAddress);
439 uint8 * pByteSrc = (uint8 *)pSrc;
441 if (!pTexture->StartUpdate(&dInfo))
446 for (uint32 y = 0; y < tinfo.HeightToLoad; y++)
448 uint8 *pDst = (uint8 *)dInfo.lpSurface + y * dInfo.lPitch;
455 // Points to current word
456 uint32 dwWordOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad * 2);
458 for (uint32 x = 0; x < tinfo.WidthToLoad; x++)
460 uint16 w = *(uint16 *)&pByteSrc[dwWordOffset^nFiddle];
462 *pDst++ = (uint8)(w >> 8);
463 *pDst++ = (uint8)(w >> 8);
464 *pDst++ = (uint8)(w >> 8);
465 *pDst++ = (uint8)(w & 0xFF);
473 for (uint32 y = 0; y < tinfo.HeightToLoad; y++)
475 uint8 *pDst = (uint8 *)dInfo.lpSurface + y * dInfo.lPitch;
477 // Points to current word
478 uint32 dwWordOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad * 2);
480 for (uint32 x = 0; x < tinfo.WidthToLoad; x++)
482 uint16 w = *(uint16 *)&pByteSrc[dwWordOffset^0x2];
484 *pDst++ = (uint8)(w >> 8);
485 *pDst++ = (uint8)(w >> 8);
486 *pDst++ = (uint8)(w >> 8);
487 *pDst++ = (uint8)(w & 0xFF);
495 pTexture->EndUpdate(&dInfo);
496 pTexture->SetOthersVariables();
502 void ConvertI4(CTexture *pTexture, const TxtrInfo &tinfo)
507 uint8 * pSrc = (uint8*)(tinfo.pPhysicalAddress);
510 if (((long long) pSrc) % 4) TRACE0("Texture src addr is not aligned to 4 bytes, check me");
513 if (!pTexture->StartUpdate(&dInfo))
518 for (uint32 y = 0; y < tinfo.HeightToLoad; y++)
520 uint8 *pDst = (uint8 *)dInfo.lpSurface + y * dInfo.lPitch;
522 // Might not work with non-even starting X
523 uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad / 2);
525 // For odd lines, swap words too
526 if( !conkerSwapHack || (y&4) == 0 )
541 if (tinfo.WidthToLoad == 1)
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];
550 else for (uint32 x = 0; x < tinfo.WidthToLoad; x+=2)
552 // two pixels at a time
553 uint8 b = pSrc[dwByteOffset ^ nFiddle];
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];
561 *pDst++ = FourToEight[(b & 0x0F)];
562 *pDst++ = FourToEight[(b & 0x0F)];
563 *pDst++ = FourToEight[(b & 0x0F)];
564 *pDst++ = FourToEight[(b & 0x0F)];
570 conkerSwapHack = false;
574 for (uint32 y = 0; y < tinfo.HeightToLoad; y++)
576 uint8 *pDst = (uint8 *)dInfo.lpSurface + y * dInfo.lPitch;
578 // Might not work with non-even starting X
579 uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad / 2);
581 if (tinfo.WidthToLoad == 1)
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];
590 else for (uint32 x = 0; x < tinfo.WidthToLoad; x+=2)
592 // two pixels at a time
593 uint8 b = pSrc[dwByteOffset ^ 0x3];
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];
601 *pDst++ = FourToEight[(b & 0x0F)];
602 *pDst++ = FourToEight[(b & 0x0F)];
603 *pDst++ = FourToEight[(b & 0x0F)];
604 *pDst++ = FourToEight[(b & 0x0F)];
611 pTexture->EndUpdate(&dInfo);
612 pTexture->SetOthersVariables();
616 void ConvertI8(CTexture *pTexture, const TxtrInfo &tinfo)
621 long long pSrc = (long long) tinfo.pPhysicalAddress;
622 if (!pTexture->StartUpdate(&dInfo))
627 for (uint32 y = 0; y < tinfo.HeightToLoad; y++)
634 uint8 *pDst = (uint8 *)dInfo.lpSurface + y * dInfo.lPitch;
636 uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + tinfo.LeftToLoad;
638 for (uint32 x = 0; x < tinfo.WidthToLoad; x++)
640 uint8 b = *(uint8*)((pSrc+dwByteOffset)^nFiddle);
645 *pDst++ = b; // Alpha not 255?
653 for (uint32 y = 0; y < tinfo.HeightToLoad; y++)
655 uint8 *pDst = (uint8 *)dInfo.lpSurface + y * dInfo.lPitch;
657 uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + tinfo.LeftToLoad;
659 for (uint32 x = 0; x < tinfo.WidthToLoad; x++)
661 uint8 b = *(uint8*)((pSrc+dwByteOffset)^0x3);
666 *pDst++ = b; // Alpha not 255?
673 pTexture->EndUpdate(&dInfo);
674 pTexture->SetOthersVariables();
678 //*****************************************************************************
679 // Convert CI4 images. We need to switch on the palette type
680 //*****************************************************************************
681 void ConvertCI4( CTexture * p_texture, const TxtrInfo & tinfo )
683 if ( tinfo.TLutFmt == TLUT_FMT_RGBA16 )
685 ConvertCI4_RGBA16( p_texture, tinfo );
687 else if ( tinfo.TLutFmt == TLUT_FMT_IA16 )
689 ConvertCI4_IA16( p_texture, tinfo );
693 //*****************************************************************************
694 // Convert CI8 images. We need to switch on the palette type
695 //*****************************************************************************
696 void ConvertCI8( CTexture * p_texture, const TxtrInfo & tinfo )
698 if ( tinfo.TLutFmt == TLUT_FMT_RGBA16 )
700 ConvertCI8_RGBA16( p_texture, tinfo );
702 else if ( tinfo.TLutFmt == TLUT_FMT_IA16 )
704 ConvertCI8_IA16( p_texture, tinfo );
708 // Used by Starfox intro
709 void ConvertCI4_RGBA16(CTexture *pTexture, const TxtrInfo &tinfo)
714 uint8 * pSrc = (uint8*)(tinfo.pPhysicalAddress);
715 uint16 * pPal = (uint16 *)tinfo.PalAddress;
716 bool bIgnoreAlpha = (tinfo.TLutFmt==TLUT_FMT_NONE);
718 if (!pTexture->StartUpdate(&dInfo))
723 for (uint32 y = 0; y < tinfo.HeightToLoad; y++)
730 uint32 * pDst = (uint32 *)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch);
732 uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch);
734 if (tinfo.WidthToLoad == 1)
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!
745 else for (uint32 x = 0; x < tinfo.WidthToLoad; x+=2)
748 uint8 b = pSrc[dwByteOffset ^ nFiddle];
750 uint8 bhi = (b&0xf0)>>4;
751 uint8 blo = (b&0x0f);
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!
758 pDst[0] |= 0xFF000000;
759 pDst[1] |= 0xFF000000;
770 for (uint32 y = 0; y < tinfo.HeightToLoad; y++)
772 uint32 * pDst = (uint32 *)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch);
774 uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad / 2);
776 if (tinfo.WidthToLoad == 1)
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!
787 else for (uint32 x = 0; x < tinfo.WidthToLoad; x+=2)
790 uint8 b = pSrc[dwByteOffset ^ 0x3];
792 uint8 bhi = (b&0xf0)>>4;
793 uint8 blo = (b&0x0f);
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!
800 pDst[0] |= 0xFF000000;
801 pDst[1] |= 0xFF000000;
810 pTexture->EndUpdate(&dInfo);
811 pTexture->SetOthersVariables();
814 // Used by Starfox intro
815 void ConvertCI4_IA16(CTexture *pTexture, const TxtrInfo &tinfo)
820 uint8 * pSrc = (uint8*)(tinfo.pPhysicalAddress);
823 if (((long long) pSrc) % 4) TRACE0("Texture src addr is not aligned to 4 bytes, check me");
826 uint16 * pPal = (uint16 *)tinfo.PalAddress;
827 bool bIgnoreAlpha = (tinfo.TLutFmt==TLUT_FMT_UNKNOWN);
829 if (!pTexture->StartUpdate(&dInfo))
834 for (uint32 y = 0; y < tinfo.HeightToLoad; y++)
841 uint32 * pDst = (uint32 *)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch);
843 uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad / 2);
845 if (tinfo.WidthToLoad == 1)
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!
854 else for (uint32 x = 0; x < tinfo.WidthToLoad; x+=2)
857 uint8 b = pSrc[dwByteOffset ^ nFiddle];
859 uint8 bhi = (b&0xf0)>>4;
860 uint8 blo = (b&0x0f);
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!
867 pDst[0] |= 0xFF000000;
868 pDst[1] |= 0xFF000000;
879 for (uint32 y = 0; y < tinfo.HeightToLoad; y++)
881 uint32 * pDst = (uint32 *)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch);
883 uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad / 2);
885 if (tinfo.WidthToLoad == 1)
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!
894 else for (uint32 x = 0; x < tinfo.WidthToLoad; x+=2)
896 // two pixels at a time
897 uint8 b = pSrc[dwByteOffset ^ 0x3];
899 uint8 bhi = (b&0xf0)>>4;
900 uint8 blo = (b&0x0f);
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!
907 pDst[0] |= 0xFF000000;
908 pDst[1] |= 0xFF000000;
917 pTexture->EndUpdate(&dInfo);
918 pTexture->SetOthersVariables();
922 // Used by MarioKart for Cars etc
923 void ConvertCI8_RGBA16(CTexture *pTexture, const TxtrInfo &tinfo)
928 uint8 * pSrc = (uint8*)(tinfo.pPhysicalAddress);
931 if (((long long) pSrc) % 4) TRACE0("Texture src addr is not aligned to 4 bytes, check me");
934 uint16 * pPal = (uint16 *)tinfo.PalAddress;
935 bool bIgnoreAlpha = (tinfo.TLutFmt==TLUT_FMT_NONE);
937 if (!pTexture->StartUpdate(&dInfo))
942 for (uint32 y = 0; y < tinfo.HeightToLoad; y++)
949 uint32 *pDst = (uint32 *)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch);
951 uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + tinfo.LeftToLoad;
953 for (uint32 x = 0; x < tinfo.WidthToLoad; x++)
955 uint8 b = pSrc[dwByteOffset ^ nFiddle];
957 *pDst++ = Convert555ToRGBA(pPal[b^1]); // Remember palette is in different endian order!
961 *(pDst-1) |= 0xFF000000;
970 for (uint32 y = 0; y < tinfo.HeightToLoad; y++)
972 uint32 *pDst = (uint32 *)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch);
974 int dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + tinfo.LeftToLoad;
976 for (uint32 x = 0; x < tinfo.WidthToLoad; x++)
978 uint8 b = pSrc[dwByteOffset ^ 0x3];
980 *pDst++ = Convert555ToRGBA(pPal[b^1]); // Remember palette is in different endian order!
983 *(pDst-1) |= 0xFF000000;
991 pTexture->EndUpdate(&dInfo);
992 pTexture->SetOthersVariables();
997 // Used by MarioKart for Cars etc
998 void ConvertCI8_IA16(CTexture *pTexture, const TxtrInfo &tinfo)
1003 uint8 * pSrc = (uint8*)(tinfo.pPhysicalAddress);
1006 if (((long long) pSrc) % 4) TRACE0("Texture src addr is not aligned to 4 bytes, check me");
1009 uint16 * pPal = (uint16 *)tinfo.PalAddress;
1010 bool bIgnoreAlpha = (tinfo.TLutFmt==TLUT_FMT_UNKNOWN);
1012 if (!pTexture->StartUpdate(&dInfo))
1017 for (uint32 y = 0; y < tinfo.HeightToLoad; y++)
1024 uint32 *pDst = (uint32 *)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch);
1026 uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + tinfo.LeftToLoad;
1028 for (uint32 x = 0; x < tinfo.WidthToLoad; x++)
1030 uint8 b = pSrc[dwByteOffset ^ nFiddle];
1032 *pDst++ = ConvertIA16ToRGBA(pPal[b^1]); // Remember palette is in different endian order!
1035 *(pDst-1) |= 0xFF000000;
1044 for (uint32 y = 0; y < tinfo.HeightToLoad; y++)
1046 uint32 *pDst = (uint32 *)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch);
1048 uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + tinfo.LeftToLoad;
1050 for (uint32 x = 0; x < tinfo.WidthToLoad; x++)
1052 uint8 b = pSrc[dwByteOffset ^ 0x3];
1054 *pDst++ = ConvertIA16ToRGBA(pPal[b^1]); // Remember palette is in different endian order!
1057 *(pDst-1) |= 0xFF000000;
1065 pTexture->EndUpdate(&dInfo);
1066 pTexture->SetOthersVariables();
1069 void ConvertYUV(CTexture *pTexture, const TxtrInfo &tinfo)
1072 if (!pTexture->StartUpdate(&dInfo))
1078 if( options.bUseFullTMEM )
1080 Tile &tile = gRDP.tiles[tinfo.tileNo];
1083 if( tinfo.tileNo >= 0 )
1084 pSrc = (uint16*)&g_Tmem.g_Tmem64bit[tile.dwTMem];
1086 pSrc = (uint16*)(tinfo.pPhysicalAddress);
1088 uint8 * pByteSrc = (uint8 *)pSrc;
1089 for (y = 0; y < tinfo.HeightToLoad; y++)
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);
1095 for (x = 0; x < tinfo.WidthToLoad/2; x++)
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];
1102 dwDst[x*2+0] = ConvertYUV16ToR8G8B8(y0,u0,v0);
1103 dwDst[x*2+1] = ConvertYUV16ToR8G8B8(y1,u0,v0);
1111 uint16 * pSrc = (uint16*)(tinfo.pPhysicalAddress);
1112 uint8 * pByteSrc = (uint8 *)pSrc;
1116 for (y = 0; y < tinfo.HeightToLoad; y++)
1123 // dwDst points to start of destination row
1124 uint32 * dwDst = (uint32 *)((uint8 *)dInfo.lpSurface + y*dInfo.lPitch);
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);
1130 for (x = 0; x < tinfo.WidthToLoad/2; x++)
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];
1137 dwDst[x*2+0] = ConvertYUV16ToR8G8B8(y0,u0,v0);
1138 dwDst[x*2+1] = ConvertYUV16ToR8G8B8(y1,u0,v0);
1146 for (y = 0; y < tinfo.HeightToLoad; y++)
1148 // dwDst points to start of destination row
1149 uint32 * dwDst = (uint32 *)((uint8 *)dInfo.lpSurface + y*dInfo.lPitch);
1150 uint32 dwByteOffset = y * 32;
1152 for (x = 0; x < tinfo.WidthToLoad/2; x++)
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)];
1159 dwDst[x*2+0] = ConvertYUV16ToR8G8B8(y0,u0,v0);
1160 dwDst[x*2+1] = ConvertYUV16ToR8G8B8(y1,u0,v0);
1162 // Increment word offset to point to the next two pixels
1169 pTexture->EndUpdate(&dInfo);
1170 pTexture->SetOthersVariables();
1173 uint32 ConvertYUV16ToR8G8B8(int Y, int U, int V)
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);
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)));
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);
1190 return COLOR_RGBA(R, G, B, 0xFF);
1194 // Used by Starfox intro
1195 void Convert4b(CTexture *pTexture, const TxtrInfo &tinfo)
1199 if (!pTexture->StartUpdate(&dInfo))
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);
1206 Tile &tile = gRDP.tiles[tinfo.tileNo];
1208 uint8 *pByteSrc = tinfo.tileNo >= 0 ? (uint8*)&g_Tmem.g_Tmem64bit[tile.dwTMem] : (uint8*)(tinfo.pPhysicalAddress);
1210 for (uint32 y = 0; y < tinfo.HeightToLoad; y++)
1213 if( tinfo.tileNo < 0 )
1229 nFiddle = ( y&1 )? 0x4 : 0;
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);
1235 if (tinfo.WidthToLoad == 1)
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) )
1242 if( tinfo.TLutFmt == TLUT_FMT_IA16 )
1244 if( tinfo.tileNo>=0 )
1245 *pDst = ConvertIA16ToRGBA(g_Tmem.g_Tmem16bit[0x400+tinfo.Palette*0x40+(bhi<<2)]);
1247 *pDst = ConvertIA16ToRGBA(pPal[bhi^1]);
1251 if( tinfo.tileNo>=0 )
1252 *pDst = Convert555ToRGBA(g_Tmem.g_Tmem16bit[0x400+tinfo.Palette*0x40+(bhi<<2)]);
1254 *pDst = Convert555ToRGBA(pPal[bhi^1]);
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);
1262 *pDst |= 0xFF000000;
1264 else for (uint32 x = 0; x < tinfo.WidthToLoad; x+=2, idx++)
1266 // two pixels at a time
1267 uint8 b = pByteSrc[idx^nFiddle];
1268 uint8 bhi = (b&0xf0)>>4;
1269 uint8 blo = (b&0x0f);
1271 if( gRDP.otherMode.text_tlut>=2 || ( tinfo.Format != TXT_FMT_IA && tinfo.Format != TXT_FMT_I) )
1273 if( tinfo.TLutFmt == TLUT_FMT_IA16 )
1275 if( tinfo.tileNo>=0 )
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)]);
1282 pDst[0] = ConvertIA16ToRGBA(pPal[bhi^1]);
1283 pDst[1] = ConvertIA16ToRGBA(pPal[blo^1]);
1288 if( tinfo.tileNo>=0 )
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)]);
1295 pDst[0] = Convert555ToRGBA(pPal[bhi^1]);
1296 pDst[1] = Convert555ToRGBA(pPal[blo^1]);
1300 else if( tinfo.Format == TXT_FMT_IA )
1302 pDst[0] = ConvertIA4ToRGBA(b>>4);
1303 pDst[1] = ConvertIA4ToRGBA(b&0xF);
1305 else // if( tinfo.Format == TXT_FMT_I )
1307 pDst[0] = ConvertI4ToRGBA(b>>4);
1308 pDst[1] = ConvertI4ToRGBA(b&0xF);
1313 pDst[0] |= 0xFF000000;
1314 pDst[1] |= 0xFF000000;
1320 pTexture->EndUpdate(&dInfo);
1321 pTexture->SetOthersVariables();
1324 void Convert8b(CTexture *pTexture, const TxtrInfo &tinfo)
1327 if (!pTexture->StartUpdate(&dInfo))
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);
1334 Tile &tile = gRDP.tiles[tinfo.tileNo];
1337 if( tinfo.tileNo >= 0 )
1339 pByteSrc = (uint8*)&g_Tmem.g_Tmem64bit[tile.dwTMem];
1343 pByteSrc = (uint8*)(tinfo.pPhysicalAddress);
1347 for (uint32 y = 0; y < tinfo.HeightToLoad; y++)
1349 uint32 * pDst = (uint32 *)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch);
1352 if( tinfo.tileNo < 0 )
1368 nFiddle = ( y&1 )? 0x4 : 0;
1372 int idx = tinfo.tileNo>=0? tile.dwLine*8*y : ((y+tinfo.TopToLoad) * tinfo.Pitch) + tinfo.LeftToLoad;
1374 for (uint32 x = 0; x < tinfo.WidthToLoad; x++, idx++)
1376 uint8 b = pByteSrc[idx^nFiddle];
1378 if( gRDP.otherMode.text_tlut>=2 || ( tinfo.Format != TXT_FMT_IA && tinfo.Format != TXT_FMT_I) )
1380 if( tinfo.TLutFmt == TLUT_FMT_IA16 )
1382 if( tinfo.tileNo>=0 )
1383 *pDst = ConvertIA16ToRGBA(g_Tmem.g_Tmem16bit[0x400+(b<<2)]);
1385 *pDst = ConvertIA16ToRGBA(pPal[b^1]);
1389 if( tinfo.tileNo>=0 )
1390 *pDst = Convert555ToRGBA(g_Tmem.g_Tmem16bit[0x400+(b<<2)]);
1392 *pDst = Convert555ToRGBA(pPal[b^1]);
1395 else if( tinfo.Format == TXT_FMT_IA )
1397 uint8 I = FourToEight[(b & 0xf0)>>4];
1398 uint8 * pByteDst = (uint8*)pDst;
1402 pByteDst[3] = FourToEight[(b & 0x0f) ];
1404 else // if( tinfo.Format == TXT_FMT_I )
1406 uint8 * pByteDst = (uint8*)pDst;
1415 *pDst |= 0xFF000000;
1421 pTexture->EndUpdate(&dInfo);
1422 pTexture->SetOthersVariables();
1426 void Convert16b(CTexture *pTexture, const TxtrInfo &tinfo)
1429 if (!pTexture->StartUpdate(&dInfo))
1432 Tile &tile = gRDP.tiles[tinfo.tileNo];
1435 if( tinfo.tileNo >= 0 )
1436 pWordSrc = (uint16*)&g_Tmem.g_Tmem64bit[tile.dwTMem];
1438 pWordSrc = (uint16*)(tinfo.pPhysicalAddress);
1441 for (uint32 y = 0; y < tinfo.HeightToLoad; y++)
1443 uint32 * dwDst = (uint32 *)((uint8 *)dInfo.lpSurface + y*dInfo.lPitch);
1446 if( tinfo.tileNo < 0 )
1462 nFiddle = ( y&1 )? 0x2 : 0;
1466 int idx = tinfo.tileNo>=0? tile.dwLine*4*y : (((y+tinfo.TopToLoad) * tinfo.Pitch)>>1) + tinfo.LeftToLoad;
1468 for (uint32 x = 0; x < tinfo.WidthToLoad; x++, idx++)
1470 uint16 w = pWordSrc[idx^nFiddle];
1471 uint16 w2 = tinfo.tileNo>=0? ((w>>8)|(w<<8)) : w;
1473 if( tinfo.Format == TXT_FMT_RGBA )
1475 dwDst[x] = Convert555ToRGBA(w2);
1477 else if( tinfo.Format == TXT_FMT_YUV )
1480 else if( tinfo.Format >= TXT_FMT_IA )
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);
1491 pTexture->EndUpdate(&dInfo);
1492 pTexture->SetOthersVariables();