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.
20
#include "osal_files.h"
22
#include "m64p_plugin.h"
24
#include "ConvertImage.h"
25
#include "DeviceBuilder.h"
26
#include "TextureFilters.h"
30
#include "liblinux/BMGLibPNG.h"
31
#include "liblinux/BMGDLL.h"
32
#include <sys/types.h>
34
/************************************************************************/
36
/************************************************************************/
37
// Basic 2x R8G8B8A8 filter with interpolation
39
void Texture2x_32( DrawInfo &srcInfo, DrawInfo &destInfo)
41
uint32 *pDst1, *pDst2;
43
uint32 nWidth = srcInfo.dwWidth;
44
uint32 nHeight = srcInfo.dwHeight;
64
for (uint32 ySrc = 0; ySrc < nHeight; ySrc++)
66
pSrc = (uint32*)(((uint8*)srcInfo.lpSurface)+ySrc*srcInfo.lPitch);
67
pSrc2 = (uint32*)(((uint8*)srcInfo.lpSurface)+(ySrc+1)*srcInfo.lPitch);
68
pDst1 = (uint32*)(((uint8*)destInfo.lpSurface)+(ySrc*2)*destInfo.lPitch);
69
pDst2 = (uint32*)(((uint8*)destInfo.lpSurface)+(ySrc*2+1)*destInfo.lPitch);
71
for (uint32 xSrc = 0; xSrc < nWidth; xSrc++)
73
b1 = (pSrc[xSrc]>>0)&0xFF;
74
g1 = (pSrc[xSrc]>>8)&0xFF;
75
r1 = (pSrc[xSrc]>>16)&0xFF;
76
a1 = (pSrc[xSrc]>>24)&0xFF;
80
b2 = (pSrc[xSrc+1]>>0)&0xFF;
81
g2 = (pSrc[xSrc+1]>>8)&0xFF;
82
r2 = (pSrc[xSrc+1]>>16)&0xFF;
83
a2 = (pSrc[xSrc+1]>>24)&0xFF;
88
b3 = (pSrc2[xSrc]>>0)&0xFF;
89
g3 = (pSrc2[xSrc]>>8)&0xFF;
90
r3 = (pSrc2[xSrc]>>16)&0xFF;
91
a3 = (pSrc2[xSrc]>>24)&0xFF;
94
b4 = (pSrc2[xSrc+1]>>0)&0xFF;
95
g4 = (pSrc2[xSrc+1]>>8)&0xFF;
96
r4 = (pSrc2[xSrc+1]>>16)&0xFF;
97
a4 = (pSrc2[xSrc+1]>>24)&0xFF;
103
pDst1[xSrc*2] = pSrc[xSrc];
108
pDst1[xSrc*2+1] = DWORD_MAKE((r1+r2)/2, (g1+g2)/2, (b1+b2)/2, (a1+a2)/2);
111
pDst1[xSrc*2+1] = pSrc[xSrc];
117
pDst2[xSrc*2] = DWORD_MAKE((r1+r3)/2, (g1+g3)/2, (b1+b3)/2, (a1+a3)/2);
120
pDst2[xSrc*2] = pSrc[xSrc];
127
pDst2[xSrc*2+1] = DWORD_MAKE((r1+r2+r3+r4)/4, (g1+g2+g3+g4)/4, (b1+b2+b3+b4)/4, (a1+a2+a3+a4)/4);
131
pDst2[xSrc*2+1] = DWORD_MAKE((r1+r2)/2, (g1+g2)/2, (b1+b2)/2, (a1+a2)/2);
138
pDst2[xSrc*2+1] = DWORD_MAKE((r1+r3)/2, (g1+g3)/2, (b1+b3)/2, (a1+a3)/2);
141
pDst2[xSrc*2+1] = pSrc[xSrc];
147
// Basic 2x R4G4B4A4 filter with interpolation
148
void Texture2x_16( DrawInfo &srcInfo, DrawInfo &destInfo )
150
uint16 *pDst1, *pDst2;
151
uint16 *pSrc, *pSrc2;
152
uint32 nWidth = srcInfo.dwWidth;
153
uint32 nHeight = srcInfo.dwHeight;
172
for (uint16 ySrc = 0; ySrc < nHeight; ySrc++)
174
pSrc = (uint16*)(((uint8*)srcInfo.lpSurface)+ySrc*srcInfo.lPitch);
175
pSrc2 = (uint16*)(((uint8*)srcInfo.lpSurface)+(ySrc+1)*srcInfo.lPitch);
176
pDst1 = (uint16*)(((uint8*)destInfo.lpSurface)+(ySrc*2)*destInfo.lPitch);
177
pDst2 = (uint16*)(((uint8*)destInfo.lpSurface)+(ySrc*2+1)*destInfo.lPitch);
179
for (uint16 xSrc = 0; xSrc < nWidth; xSrc++)
181
b1 = (pSrc[xSrc]>> 0)&0xF;
182
g1 = (pSrc[xSrc]>> 4)&0xF;
183
r1 = (pSrc[xSrc]>> 8)&0xF;
184
a1 = (pSrc[xSrc]>>12)&0xF;
188
b2 = (pSrc[xSrc+1]>> 0)&0xF;
189
g2 = (pSrc[xSrc+1]>> 4)&0xF;
190
r2 = (pSrc[xSrc+1]>> 8)&0xF;
191
a2 = (pSrc[xSrc+1]>>12)&0xF;
196
b3 = (pSrc2[xSrc]>> 0)&0xF;
197
g3 = (pSrc2[xSrc]>> 4)&0xF;
198
r3 = (pSrc2[xSrc]>> 8)&0xF;
199
a3 = (pSrc2[xSrc]>>12)&0xF;
202
b4 = (pSrc2[xSrc+1]>> 0)&0xF;
203
g4 = (pSrc2[xSrc+1]>> 4)&0xF;
204
r4 = (pSrc2[xSrc+1]>> 8)&0xF;
205
a4 = (pSrc2[xSrc+1]>>12)&0xF;
210
pDst1[xSrc*2] = pSrc[xSrc];
215
pDst1[xSrc*2+1] = WORD_MAKE((r1+r2)/2, (g1+g2)/2, (b1+b2)/2, (a1+a2)/2);
218
pDst1[xSrc*2+1] = pSrc[xSrc];
224
pDst2[xSrc*2] = WORD_MAKE((r1+r3)/2, (g1+g3)/2, (b1+b3)/2, (a1+a3)/2);
227
pDst2[xSrc*2] = pSrc[xSrc];
234
pDst2[xSrc*2+1] = WORD_MAKE((r1+r2+r3+r4)/4, (g1+g2+g3+g4)/4, (b1+b2+b3+b4)/4, (a1+a2+a3+a4)/4);
238
pDst2[xSrc*2+1] = WORD_MAKE((r1+r2)/2, (g1+g2)/2, (b1+b2)/2, (a1+a2)/2);
245
pDst2[xSrc*2+1] = WORD_MAKE((r1+r3)/2, (g1+g3)/2, (b1+b3)/2, (a1+a3)/2);
248
pDst2[xSrc*2+1] = pSrc[xSrc];
254
/************************************************************************/
255
/* Sharpen filters */
256
/************************************************************************/
257
void SharpenFilter_32(uint32 *pdata, uint32 width, uint32 height, uint32 pitch, uint32 filter)
259
uint32 len=height*pitch;
260
uint32 *pcopy = new uint32[len];
264
memcpy(pcopy, pdata, len<<2);
266
uint32 mul1, mul2, mul3, shift4;
269
case TEXTURE_SHARPEN_MORE_ENHANCEMENT:
275
case TEXTURE_SHARPEN_ENHANCEMENT:
285
uint32 *src1, *src2, *src3, *dest;
287
uint32 t1,t2,t3,t4,t5,t6,t7,t8,t9;
289
for( y=1; y<height-1; y++)
291
dest = pdata+y*pitch;
292
src1 = pcopy+(y-1)*pitch;
295
for( x=1; x<width-1; x++)
299
t1 = *((uint8*)(src1+x-1)+z);
300
t2 = *((uint8*)(src1+x )+z);
301
t3 = *((uint8*)(src1+x+1)+z);
302
t4 = *((uint8*)(src2+x-1)+z);
303
t5 = *((uint8*)(src2+x )+z);
304
t6 = *((uint8*)(src2+x+1)+z);
305
t7 = *((uint8*)(src3+x-1)+z);
306
t8 = *((uint8*)(src3+x )+z);
307
t9 = *((uint8*)(src3+x+1)+z);
309
if( (t5*mul2) > (t1+t3+t7+t9+t2+t4+t6+t8)*mul1 )
311
val[z]= min((((t5*mul3) - (t1+t3+t7+t9+t2+t4+t6+t8)*mul1)>>shift4),0xFF);
314
dest[x] = val[0]|(val[1]<<8)|(val[2]<<16)|(val[3]<<24);
320
void SharpenFilter_16(uint16 *pdata, uint32 width, uint32 height, uint32 pitch, uint32 filter)
322
//return; // Sharpen does not make sense for 16 bits
324
uint32 len=height*pitch;
325
uint16 *pcopy = new uint16[len];
329
memcpy(pcopy, pdata, len<<1);
331
uint16 mul1, mul2, mul3, shift4;
334
case TEXTURE_SHARPEN_MORE_ENHANCEMENT:
340
case TEXTURE_SHARPEN_ENHANCEMENT:
350
uint16 *src1, *src2, *src3, *dest;
352
uint16 t1,t2,t3,t4,t5,t6,t7,t8,t9;
354
for( y=1; y<height-1; y++)
356
dest = pdata+y*pitch;
357
src1 = pcopy+(y-1)*pitch;
360
for( x=1; x<width-1; x++)
364
uint32 shift = (z%1)?4:0;
365
t1 = (*((uint8*)(src1+x-1)+(z>>1)))>>shift;
366
t2 = (*((uint8*)(src1+x )+(z>>1)))>>shift;
367
t3 = (*((uint8*)(src1+x+1)+(z>>1)))>>shift;
368
t4 = (*((uint8*)(src2+x-1)+(z>>1)))>>shift;
369
t5 = (*((uint8*)(src2+x )+(z>>1)))>>shift;
370
t6 = (*((uint8*)(src2+x+1)+(z>>1)))>>shift;
371
t7 = (*((uint8*)(src3+x-1)+(z>>1)))>>shift;
372
t8 = (*((uint8*)(src3+x )+(z>>1)))>>shift;
373
t9 = (*((uint8*)(src3+x+1)+(z>>1)))>>shift;
375
if( (t5*mul2) > (t1+t3+t7+t9+t2+t4+t6+t8)*mul1 )
377
val[z] = (((t5*mul3) - (t1+t3+t7+t9+t2+t4+t6+t8)*mul1)>>shift4);
378
val[z]= min(val[z],0xF);
381
dest[x] = val[0]|(val[1]<<4)|(val[2]<<8)|(val[3]<<12);
387
/************************************************************************/
389
/************************************************************************/
390
void SmoothFilter_32(uint32 *pdata, uint32 width, uint32 height, uint32 pitch, uint32 filter)
392
uint32 len=height*pitch;
393
uint32 *pcopy = new uint32[len];
397
memcpy(pcopy, pdata, len<<2);
399
uint32 mul1, mul2, mul3, shift4;
402
case TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_1:
408
case TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_2:
414
case TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_3:
420
case TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_4:
430
uint32 *src1, *src2, *src3, *dest;
432
uint32 t1,t2,t3,t4,t5,t6,t7,t8,t9;
434
if( filter == TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_3 || filter == TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_4 )
436
for( y=1; y<height-1; y+=2)
438
dest = pdata+y*pitch;
439
src1 = pcopy+(y-1)*pitch;
442
for( x=0; x<width; x++)
446
t2 = *((uint8*)(src1+x )+z);
447
t5 = *((uint8*)(src2+x )+z);
448
t8 = *((uint8*)(src3+x )+z);
449
val[z] = ((t2+t8)*mul2+(t5*mul3))>>shift4;
451
dest[x] = val[0]|(val[1]<<8)|(val[2]<<16)|(val[3]<<24);
457
for( y=0; y<height; y++)
459
dest = pdata+y*pitch;
462
src1 = pcopy+(y-1)*pitch;
471
if( y<height-1) src3 += pitch;
473
for( x=1; x<width-1; x++)
477
t1 = *((uint8*)(src1+x-1)+z);
478
t2 = *((uint8*)(src1+x )+z);
479
t3 = *((uint8*)(src1+x+1)+z);
480
t4 = *((uint8*)(src2+x-1)+z);
481
t5 = *((uint8*)(src2+x )+z);
482
t6 = *((uint8*)(src2+x+1)+z);
483
t7 = *((uint8*)(src3+x-1)+z);
484
t8 = *((uint8*)(src3+x )+z);
485
t9 = *((uint8*)(src3+x+1)+z);
486
val[z] = ((t1+t3+t7+t9)*mul1+((t2+t4+t6+t8)*mul2)+(t5*mul3))>>shift4;
488
dest[x] = val[0]|(val[1]<<8)|(val[2]<<16)|(val[3]<<24);
495
void SmoothFilter_16(uint16 *pdata, uint32 width, uint32 height, uint32 pitch, uint32 filter)
497
uint32 len=height*pitch;
498
uint16 *pcopy = new uint16[len];
502
memcpy(pcopy, pdata, len<<1);
504
uint16 mul1, mul2, mul3, shift4;
507
case TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_1:
513
case TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_2:
519
case TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_3:
525
case TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_4:
535
uint16 *src1, *src2, *src3, *dest;
537
uint16 t1,t2,t3,t4,t5,t6,t7,t8,t9;
539
if( filter == TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_3 || filter == TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_4 )
541
for( y=1; y<height-1; y+=2)
543
dest = pdata+y*pitch;
544
src1 = pcopy+(y-1)*pitch;
547
for( x=0; x<width; x++)
551
uint32 shift = (z&1)?4:0;
552
t2 = (*((uint8*)(src1+x )+(z>>1)))>>shift;
553
t5 = (*((uint8*)(src2+x )+(z>>1)))>>shift;
554
t8 = (*((uint8*)(src3+x )+(z>>1)))>>shift;
555
val[z] = ((t2+t8)*mul2+(t5*mul3))>>shift4;
557
dest[x] = val[0]|(val[1]<<4)|(val[2]<<8)|(val[3]<<12);
563
for( y=0; y<height; y++)
565
dest = pdata+y*pitch;
568
src1 = pcopy+(y-1)*pitch;
577
if( y<height-1) src3 += pitch;
579
for( x=1; x<width-1; x++)
583
uint32 shift = (z&1)?4:0;
584
t1 = (*((uint8*)(src1+x-1)+(z>>1)))>>shift;
585
t2 = (*((uint8*)(src1+x )+(z>>1)))>>shift;
586
t3 = (*((uint8*)(src1+x+1)+(z>>1)))>>shift;
587
t4 = (*((uint8*)(src2+x-1)+(z>>1)))>>shift;
588
t5 = (*((uint8*)(src2+x )+(z>>1)))>>shift;
589
t6 = (*((uint8*)(src2+x+1)+(z>>1)))>>shift;
590
t7 = (*((uint8*)(src3+x-1)+(z>>1)))>>shift;
591
t8 = (*((uint8*)(src3+x )+(z>>1)))>>shift;
592
t9 = (*((uint8*)(src3+x+1)+(z>>1)))>>shift;
593
val[z] = ((t1+t3+t7+t9)*mul1+((t2+t4+t6+t8)*mul2)+(t5*mul3))>>shift4;
595
dest[x] = val[0]|(val[1]<<4)|(val[2]<<8)|(val[3]<<12);
603
void EnhanceTexture(TxtrCacheEntry *pEntry)
605
if( pEntry->dwEnhancementFlag == options.textureEnhancement )
607
// The texture has already been enhanced
610
else if( options.textureEnhancement == TEXTURE_NO_ENHANCEMENT )
612
SAFE_DELETE(pEntry->pEnhancedTexture);
613
pEntry->dwEnhancementFlag = TEXTURE_NO_ENHANCEMENT;
617
if( status.primitiveType != PRIM_TEXTRECT && options.bTexRectOnly )
623
if( pEntry->pTexture->StartUpdate(&srcInfo) == false )
625
SAFE_DELETE(pEntry->pEnhancedTexture);
629
uint32 realwidth = srcInfo.dwWidth;
630
uint32 realheight = srcInfo.dwHeight;
631
uint32 nWidth = srcInfo.dwCreatedWidth;
632
uint32 nHeight = srcInfo.dwCreatedHeight;
634
if( options.textureEnhancement == TEXTURE_SHARPEN_ENHANCEMENT || options.textureEnhancement == TEXTURE_SHARPEN_MORE_ENHANCEMENT )
636
if( pEntry->pTexture->GetPixelSize() == 4 )
637
SharpenFilter_32((uint32*)srcInfo.lpSurface, nWidth, nHeight, nWidth, options.textureEnhancement);
639
SharpenFilter_16((uint16*)srcInfo.lpSurface, nWidth, nHeight, nWidth, options.textureEnhancement);
640
pEntry->dwEnhancementFlag = options.textureEnhancement;
641
pEntry->pTexture->EndUpdate(&srcInfo);
642
SAFE_DELETE(pEntry->pEnhancedTexture);
646
pEntry->dwEnhancementFlag = options.textureEnhancement;
647
if( options.bSmallTextureOnly )
649
if( nWidth + nHeight > 256 )
651
pEntry->pTexture->EndUpdate(&srcInfo);
652
SAFE_DELETE(pEntry->pEnhancedTexture);
653
pEntry->dwEnhancementFlag = TEXTURE_NO_ENHANCEMENT;
659
CTexture* pSurfaceHandler = NULL;
660
if( options.textureEnhancement == TEXTURE_HQ4X_ENHANCEMENT )
662
if( nWidth + nHeight > 1024/4 )
664
// Don't enhance for large textures
665
pEntry->pTexture->EndUpdate(&srcInfo);
666
SAFE_DELETE(pEntry->pEnhancedTexture);
667
pEntry->dwEnhancementFlag = TEXTURE_NO_ENHANCEMENT;
670
pSurfaceHandler = CDeviceBuilder::GetBuilder()->CreateTexture(nWidth*4, nHeight*4);
674
if( nWidth + nHeight > 1024/2 )
676
// Don't enhance for large textures
677
pEntry->pTexture->EndUpdate(&srcInfo);
678
SAFE_DELETE(pEntry->pEnhancedTexture);
679
pEntry->dwEnhancementFlag = TEXTURE_NO_ENHANCEMENT;
682
pSurfaceHandler = CDeviceBuilder::GetBuilder()->CreateTexture(nWidth*2, nHeight*2);
687
if(pSurfaceHandler->StartUpdate(&destInfo))
689
if( options.textureEnhancement == TEXTURE_2XSAI_ENHANCEMENT )
691
if( pEntry->pTexture->GetPixelSize() == 4 )
692
Super2xSaI_32((uint32*)(srcInfo.lpSurface),(uint32*)(destInfo.lpSurface), nWidth, realheight, nWidth);
694
Super2xSaI_16((uint16*)(srcInfo.lpSurface),(uint16*)(destInfo.lpSurface), nWidth, realheight, nWidth);
696
else if( options.textureEnhancement == TEXTURE_HQ2X_ENHANCEMENT )
698
if( pEntry->pTexture->GetPixelSize() == 4 )
701
hq2x_32((uint8*)(srcInfo.lpSurface), srcInfo.lPitch, (uint8*)(destInfo.lpSurface), destInfo.lPitch, nWidth, realheight);
706
hq2x_16((uint8*)(srcInfo.lpSurface), srcInfo.lPitch, (uint8*)(destInfo.lpSurface), destInfo.lPitch, nWidth, realheight);
709
else if( options.textureEnhancement == TEXTURE_LQ2X_ENHANCEMENT )
711
if( pEntry->pTexture->GetPixelSize() == 4 )
714
lq2x_32((uint8*)(srcInfo.lpSurface), srcInfo.lPitch, (uint8*)(destInfo.lpSurface), destInfo.lPitch, nWidth, realheight);
719
lq2x_16((uint8*)(srcInfo.lpSurface), srcInfo.lPitch, (uint8*)(destInfo.lpSurface), destInfo.lPitch, nWidth, realheight);
722
else if( options.textureEnhancement == TEXTURE_HQ4X_ENHANCEMENT )
724
if( pEntry->pTexture->GetPixelSize() == 4 )
727
hq4x_32((uint8*)(srcInfo.lpSurface), (uint8*)(destInfo.lpSurface), realwidth, realheight, nWidth, destInfo.lPitch);
732
hq4x_16((uint8*)(srcInfo.lpSurface), (uint8*)(destInfo.lpSurface), realwidth, realheight, nWidth, destInfo.lPitch);
737
if( pEntry->pTexture->GetPixelSize() == 4 )
738
Texture2x_32( srcInfo, destInfo);
740
Texture2x_16( srcInfo, destInfo);
743
if( options.textureEnhancementControl >= TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_1 )
745
if( options.textureEnhancement != TEXTURE_HQ4X_ENHANCEMENT )
747
if( pEntry->pTexture->GetPixelSize() == 4 )
748
SmoothFilter_32((uint32*)destInfo.lpSurface, realwidth<<1, realheight<<1, nWidth<<1, options.textureEnhancementControl);
750
SmoothFilter_16((uint16*)destInfo.lpSurface, realwidth<<1, realheight<<1, nWidth<<1, options.textureEnhancementControl);
754
if( pEntry->pTexture->GetPixelSize() == 4 )
755
SmoothFilter_32((uint32*)destInfo.lpSurface, realwidth<<2, realheight<<2, nWidth<<2, options.textureEnhancementControl);
757
SmoothFilter_16((uint16*)destInfo.lpSurface, realwidth<<2, realheight<<2, nWidth<<2, options.textureEnhancementControl);
761
pSurfaceHandler->EndUpdate(&destInfo);
764
pSurfaceHandler->SetOthersVariables();
765
pSurfaceHandler->m_bIsEnhancedTexture = true;
768
pEntry->pTexture->EndUpdate(&srcInfo);
770
pEntry->pEnhancedTexture = pSurfaceHandler;
774
/************************************************************************/
776
/************************************************************************/
777
void MirrorEmulator_DrawLine(DrawInfo& destInfo, DrawInfo& srcInfo, uint32 *pSource, uint32 *pDest, uint32 nWidth, BOOL bFlipLeftRight)
781
memcpy(pDest, pSource, nWidth * 4);
785
uint32 *pMaxDest = pDest + nWidth;
786
pSource += nWidth - 1;
787
for(; pDest < pMaxDest; pDest++, pSource--)
795
void MirrorEmulator_Draw(DrawInfo& destInfo, DrawInfo& srcInfo, uint32 nDestX, uint32 nDestY, BOOL bFlipLeftRight, BOOL bFlipUpDown)
797
uint8 *pDest = (uint8 *) destInfo.lpSurface + (destInfo.lPitch * nDestY) + (4 * nDestX);
798
uint8 *pMaxDest = pDest + (destInfo.lPitch * srcInfo.dwHeight);
799
uint8 *pSource = (uint8 *)(srcInfo.lpSurface);
802
for(; pDest < pMaxDest; pDest += destInfo.lPitch, pSource += srcInfo.lPitch)
804
MirrorEmulator_DrawLine(destInfo, srcInfo, (uint32*)pSource, (uint32*)pDest, srcInfo.dwWidth, bFlipLeftRight);
809
pSource += (srcInfo.lPitch * (srcInfo.dwHeight - 1));
810
for(; pDest < pMaxDest; pDest += destInfo.lPitch, pSource -= srcInfo.lPitch)
812
MirrorEmulator_DrawLine(destInfo, srcInfo, (uint32*)pSource, (uint32*)pDest, srcInfo.dwWidth, bFlipLeftRight);
817
void MirrorTexture(uint32 dwTile, TxtrCacheEntry *pEntry)
819
if( ((gRDP.tiles[dwTile].bMirrorS) || (gRDP.tiles[dwTile].bMirrorT)) && CGraphicsContext::Get()->m_supportTextureMirror == false )
821
if(pEntry->pEnhancedTexture)
827
CTexture* pSurfaceHandler = NULL;
829
// FIXME: Compute the correct values. 2/2 seems to always work correctly in Mario64
830
uint32 nXTimes = gRDP.tiles[dwTile].bMirrorS ? 2 : 1;
831
uint32 nYTimes = gRDP.tiles[dwTile].bMirrorT ? 2 : 1;
833
// For any texture need to use mirror, we should not need to rescale it
834
// because texture need to be mirrored must with MaskS and MaskT
836
// But again, check me
838
//if( pEntry->pTexture->m_bScaledS == false || pEntry->pTexture->m_bScaledT == false)
840
// pEntry->pTexture->ScaleImageToSurface();
844
if( pEntry->pTexture->StartUpdate(&srcInfo) )
846
uint32 nWidth = srcInfo.dwWidth;
847
uint32 nHeight = srcInfo.dwHeight;
849
pSurfaceHandler = CDeviceBuilder::GetBuilder()->CreateTexture(nWidth * nXTimes, nHeight * nYTimes);
850
if( pSurfaceHandler )
853
if( pSurfaceHandler->StartUpdate(&destInfo) )
855
for(uint32 nY = 0; nY < nYTimes; nY++)
857
for(uint32 nX = 0; nX < nXTimes; nX++)
859
MirrorEmulator_Draw(destInfo, srcInfo, nWidth * nX, nHeight * nY, nX & 0x1, nY & 0x1);
863
pSurfaceHandler->EndUpdate(&destInfo);
866
// fix me, there should be a flag to tell that it is a mirrored texture handler
867
// not the original texture handlers, so all texture coordinate should be divided by 2
868
pSurfaceHandler->SetOthersVariables();
871
pEntry->pTexture->EndUpdate(&srcInfo);
872
pEntry->dwEnhancementFlag = TEXTURE_MIRRORED;
876
pEntry->pEnhancedTexture = pSurfaceHandler;
886
RGB_WITH_ALPHA_TOGETHER_PNG,
899
char RGBNameTail[23];
900
char AlphaNameTail[20];
902
bool bSeparatedAlpha;
905
CSortedList<uint64,ExtTxtrInfo> gTxtrDumpInfos;
906
CSortedList<uint64,ExtTxtrInfo> gHiresTxtrInfos;
908
extern char * right(const char * src, int nchars);
910
#define SURFFMT_P8 41
912
int GetImageInfoFromFile(char* pSrcFile, IMAGE_INFO *pSrcInfo)
914
unsigned char sig[8];
917
f = fopen(pSrcFile, "rb");
920
DebugMessage(M64MSG_ERROR, "GetImageInfoFromFile() error: couldn't open file '%s'", pSrcFile);
923
if (fread(sig, 1, 8, f) != 8)
925
DebugMessage(M64MSG_ERROR, "GetImageInfoFromFile() error: couldn't read first 8 bytes of file '%s'", pSrcFile);
930
if(sig[0] == 'B' && sig[1] == 'M') // BMP
932
struct BMGImageStruct img;
933
memset(&img, 0, sizeof(BMGImageStruct));
934
BMG_Error code = ReadBMP(pSrcFile, &img);
937
pSrcInfo->Width = img.width;
938
pSrcInfo->Height = img.height;
939
pSrcInfo->Depth = img.bits_per_pixel;
940
pSrcInfo->MipLevels = 1;
941
if(img.bits_per_pixel == 32)
942
pSrcInfo->Format = SURFFMT_A8R8G8B8;
943
else if(img.bits_per_pixel == 8)
944
pSrcInfo->Format = SURFFMT_P8;
945
// Resource and File Format ignored
949
DebugMessage(M64MSG_ERROR, "Couldn't read BMP file '%s'; error = %i", pSrcFile, code);
952
else if(sig[0] == 137 && sig[1] == 'P' && sig[2] == 'N' && sig[3] == 'G' && sig[4] == '\r' && sig[5] == '\n' &&
953
sig[6] == 26 && sig[7] == '\n') // PNG
955
struct BMGImageStruct img;
956
memset(&img, 0, sizeof(BMGImageStruct));
957
BMG_Error code = ReadPNG(pSrcFile, &img);
960
pSrcInfo->Width = img.width;
961
pSrcInfo->Height = img.height;
962
pSrcInfo->Depth = img.bits_per_pixel;
963
pSrcInfo->MipLevels = 1;
964
if(img.bits_per_pixel == 32)
965
pSrcInfo->Format = SURFFMT_A8R8G8B8;
966
else if(img.bits_per_pixel == 8)
967
pSrcInfo->Format = SURFFMT_P8;
968
// Resource and File Format ignored
972
DebugMessage(M64MSG_ERROR, "Couldn't read PNG file '%s'; error = %i", pSrcFile, code);
976
DebugMessage(M64MSG_ERROR, "GetImageInfoFromFile : unknown file format (%s)", pSrcFile);
980
BOOL PathFileExists(char* pszPath)
983
f = fopen(pszPath, "rb");
992
void FindAllTexturesFromFolder(char *foldername, CSortedList<uint64,ExtTxtrInfo> &infos, bool extraCheck, bool bRecursive)
994
if (!osal_is_directory(foldername))
997
char texturefilename[PATH_MAX];
1002
dir = osal_search_dir_open(foldername);
1003
const char *foundfilename;
1006
unsigned int fmt, siz;
1007
char crcstr[16], crcstr2[16];
1011
foundfilename = osal_search_dir_read_next(dir);
1012
if (foundfilename == NULL) break;
1013
if (foundfilename[0] == '.' ) continue;
1015
strcpy(texturefilename, foldername);
1016
strcat(texturefilename, foundfilename);
1018
/* handle recursion into sub-directories */
1019
if (osal_is_directory(texturefilename) && bRecursive )
1021
strcat(texturefilename, OSAL_DIR_SEPARATOR_STR);
1022
FindAllTexturesFromFolder(texturefilename, infos, extraCheck, bRecursive);
1025
/* if filename doesn't match the ROM's name, skip it */
1026
if( strstr(foundfilename,(const char*)g_curRomInfo.szGameName) == 0 )
1029
TextureType type = NO_TEXTURE;
1030
bool bSeparatedAlpha = false;
1032
if( strcasecmp(right(foundfilename,7), "_ci.bmp") == 0 )
1034
if( GetImageInfoFromFile(texturefilename, &imgInfo) != 0)
1036
DebugMessage(M64MSG_WARNING, "Cannot get image info for file: %s", foundfilename);
1040
if( imgInfo.Format == SURFFMT_P8 )
1041
type = COLOR_INDEXED_BMP;
1045
else if( strcasecmp(right(foundfilename,13), "_ciByRGBA.png") == 0 )
1047
if( GetImageInfoFromFile(texturefilename, &imgInfo) != 0 )
1049
DebugMessage(M64MSG_WARNING, "Cannot get image info for file: %s", foundfilename);
1053
if( imgInfo.Format == SURFFMT_A8R8G8B8 )
1054
type = RGBA_PNG_FOR_CI;
1058
else if( strcasecmp(right(foundfilename,16), "_allciByRGBA.png") == 0 )
1060
if( GetImageInfoFromFile(texturefilename, &imgInfo) != 0 )
1062
DebugMessage(M64MSG_WARNING, "Cannot get image info for file: %s", foundfilename);
1065
if( imgInfo.Format == SURFFMT_A8R8G8B8 )
1066
type = RGBA_PNG_FOR_ALL_CI;
1070
else if( strcasecmp(right(foundfilename,8), "_rgb.png") == 0 )
1072
if( GetImageInfoFromFile(texturefilename, &imgInfo) != 0 )
1074
DebugMessage(M64MSG_WARNING, "Cannot get image info for file: %s", foundfilename);
1080
char filename2[PATH_MAX];
1081
strcpy(filename2,texturefilename);
1082
strcpy(filename2+strlen(filename2)-8,"_a.png");
1083
if( PathFileExists(filename2) )
1085
if( GetImageInfoFromFile(filename2, &imgInfo2) != 0 )
1087
DebugMessage(M64MSG_WARNING, "Cannot get image info for file: %s", filename2);
1091
if( extraCheck && (imgInfo2.Width != imgInfo.Width || imgInfo2.Height != imgInfo.Height) )
1093
DebugMessage(M64MSG_WARNING, "RGB and alpha texture size mismatch: %s", filename2);
1097
bSeparatedAlpha = true;
1100
else if( strcasecmp(right(foundfilename,8), "_all.png") == 0 )
1102
if( GetImageInfoFromFile(texturefilename, &imgInfo) != 0 )
1104
DebugMessage(M64MSG_WARNING, "Cannot get image info for file: %s", foundfilename);
1108
type = RGB_WITH_ALPHA_TOGETHER_PNG;
1111
if( type != NO_TEXTURE )
1113
/* Try to read image information here.
1115
(CASTLEVANIA2)(#58E2333F)(#2#0#)(D7A5C6D 9)_ciByRGBA.png
1116
(------1-----)(----2----)(3)(4)(----5-----)_ciByRGBA.png
1118
1. Internal ROM name
1120
3. The image pixel size (8b=0, 16b=1, 24b=2, 32b=3)
1121
4. The texture format (RGBA=0, YUV=1, CI=2, IA=3, I=4)
1124
strcpy(texturefilename, foundfilename);
1126
char *ptr = strchr(texturefilename,'#');
1128
if( type == RGBA_PNG_FOR_CI )
1130
sscanf(ptr,"%8c#%d#%d#%8c", crcstr, &fmt, &siz,crcstr2);
1132
palcrc32 = strtoul(crcstr2,NULL,16);
1136
sscanf(ptr,"%8c#%d#%d", crcstr, &fmt, &siz);
1137
palcrc32 = 0xFFFFFFFF;
1140
crc = strtoul(crcstr,NULL,16);
1143
for( int k=0; k<infos.size(); k++)
1145
if( infos[k].crc32 == crc && infos[k].pal_crc32 == palcrc32 )
1152
if( foundIdx < 0 || type != infos[foundIdx].type)
1154
ExtTxtrInfo newinfo;
1155
newinfo.width = imgInfo.Width;
1156
newinfo.height = imgInfo.Height;
1157
//strcpy(newinfo.name,g_curRomInfo.szGameName);
1158
newinfo.foldername = new char[strlen(foldername)+1];
1159
strcpy(newinfo.foldername,foldername);
1162
newinfo.crc32 = crc;
1163
newinfo.pal_crc32 = palcrc32;
1164
newinfo.type = type;
1165
newinfo.bSeparatedAlpha = bSeparatedAlpha;
1167
newinfo.RGBNameTail[0] = newinfo.AlphaNameTail[0] = 0;
1172
strcpy(newinfo.RGBNameTail, "_rgb.png");
1173
strcpy(newinfo.AlphaNameTail, "_a.png");
1175
case COLOR_INDEXED_BMP:
1176
strcpy(newinfo.RGBNameTail, "_ci.bmp");
1178
case RGBA_PNG_FOR_CI:
1179
strcpy(newinfo.RGBNameTail, right(ptr,22));
1181
case RGBA_PNG_FOR_ALL_CI:
1182
strcpy(newinfo.RGBNameTail, "_allciByRGBA.png");
1185
strcpy(newinfo.RGBNameTail, "_all.png");
1189
uint64 crc64 = newinfo.crc32;
1191
crc64 |= (newinfo.pal_crc32&0xFFFFFF00)|(newinfo.fmt<<4)|newinfo.siz;
1192
infos.add(crc64,newinfo);
1195
} while(foundfilename != NULL);
1197
osal_search_dir_close(dir);
1200
bool CheckAndCreateFolder(const char* pathname)
1202
if( !PathFileExists((char*)pathname) )
1204
if (osal_mkdirp(pathname, 0700) != 0)
1206
DebugMessage(M64MSG_WARNING, "Can not create new folder: %s", pathname);
1215
// Texture dumping filenaming
1216
// GameName_FrameCount_CRC_Fmt_Siz.bmp
1218
// GameName: N64 game internal name
1219
// CRC: 32 bit, 8 hex digits
1223
const char *subfolders[] = {
1227
"ci_bmp_with_pal_crc",
1231
void FindAllDumpedTextures(void)
1233
char foldername[PATH_MAX + 64];
1234
strncpy(foldername, ConfigGetUserDataPath(), PATH_MAX);
1235
foldername[PATH_MAX] = 0;
1237
if (foldername[strlen(foldername) - 1] != OSAL_DIR_SEPARATOR_CHAR)
1238
strcat(foldername, OSAL_DIR_SEPARATOR_STR);
1239
strcat(foldername,"texture_dump" OSAL_DIR_SEPARATOR_STR);
1241
CheckAndCreateFolder(foldername);
1243
strcat(foldername,(const char*)g_curRomInfo.szGameName);
1244
strcat(foldername, OSAL_DIR_SEPARATOR_STR);
1246
gTxtrDumpInfos.clear();
1247
if( !PathFileExists(foldername) )
1249
CheckAndCreateFolder(foldername);
1250
char foldername2[PATH_MAX];
1251
for( int i=0; i<5; i++)
1253
strcpy(foldername2,foldername);
1254
strcat(foldername2,subfolders[i]);
1255
CheckAndCreateFolder(foldername2);
1261
gTxtrDumpInfos.clear();
1262
FindAllTexturesFromFolder(foldername,gTxtrDumpInfos, false, true);
1264
char foldername2[PATH_MAX];
1265
for( int i=0; i<5; i++)
1267
strcpy(foldername2,foldername);
1268
strcat(foldername2,subfolders[i]);
1269
CheckAndCreateFolder(foldername2);
1275
void FindAllHiResTextures(void)
1277
char foldername[PATH_MAX + 64];
1278
strncpy(foldername, ConfigGetUserDataPath(), PATH_MAX);
1279
foldername[PATH_MAX] = 0;
1281
if(foldername[strlen(foldername) - 1] != OSAL_DIR_SEPARATOR_CHAR)
1282
strcat(foldername, OSAL_DIR_SEPARATOR_STR);
1283
strcat(foldername,"hires_texture" OSAL_DIR_SEPARATOR_STR);
1284
CheckAndCreateFolder(foldername);
1286
strcat(foldername,(const char*)g_curRomInfo.szGameName);
1287
strcat(foldername, OSAL_DIR_SEPARATOR_STR);
1288
gHiresTxtrInfos.clear();
1289
if (!osal_is_directory(foldername))
1295
FindAllTexturesFromFolder(foldername,gHiresTxtrInfos, true, true);
1299
void CloseHiresTextures(void)
1301
for( int i=0; i<gHiresTxtrInfos.size(); i++)
1303
if( gHiresTxtrInfos[i].foldername )
1304
delete [] gHiresTxtrInfos[i].foldername;
1307
gHiresTxtrInfos.clear();
1310
void CloseTextureDump(void)
1312
for( int i=0; i<gTxtrDumpInfos.size(); i++)
1314
if( gTxtrDumpInfos[i].foldername )
1315
delete [] gTxtrDumpInfos[i].foldername;
1318
gTxtrDumpInfos.clear();
1321
void CloseExternalTextures(void)
1323
CloseHiresTextures();
1327
void InitHiresTextures(void)
1329
if( options.bLoadHiResTextures )
1331
DebugMessage(M64MSG_INFO, "Texture loading option is enabled. Finding all hires textures");
1332
FindAllHiResTextures();
1336
void InitTextureDump(void)
1338
if( options.bDumpTexturesToFiles )
1340
DebugMessage(M64MSG_INFO, "Texture dump option is enabled. Finding all dumpped textures");
1341
FindAllDumpedTextures();
1344
void InitExternalTextures(void)
1346
DebugMessage(M64MSG_VERBOSE, "InitExternalTextures");
1347
CloseExternalTextures();
1348
InitHiresTextures();
1353
ExtTxtrInfo.height ExtTxtrInfo.width are ints.
1354
TxtrInfo.HeightToLoad TxtrInfo.WidthToLoad (ti of TxtrCacheEntry
1355
is of type TxtrInfo) are uint32.
1357
int FindScaleFactor(const ExtTxtrInfo &info, TxtrCacheEntry &entry)
1361
// find the smallest power of 2 which is greater than or equal to the ratio of the hi-res texture's
1362
// dimensions to the original (N64) texture dimensions
1363
while (info.height > (int) entry.ti.HeightToLoad * (1 << scaleShift) && info.width > (int) entry.ti.WidthToLoad * (1 << scaleShift))
1367
// if the ratio of the 2 textures' dimensions is an even power of 2, then the hi-res texture is allowed
1368
if (info.height == (int) entry.ti.HeightToLoad * (1 << scaleShift) && info.width == (int) entry.ti.WidthToLoad * (1 << scaleShift))
1370
// found appropriate scale shift, return it
1374
// the dimensions of the hires replacement are not power of 2 of the original texture
1378
int CheckTextureInfos( CSortedList<uint64,ExtTxtrInfo> &infos, TxtrCacheEntry &entry, int &indexa, int &scaleShift, bool bForDump = false)
1380
if(entry.ti.WidthToCreate/entry.ti.WidthToLoad > 2 || entry.ti.HeightToCreate/entry.ti.HeightToLoad > 2 )
1382
//DebugMessage(M64MSG_WARNING, "Hires texture does not support extreme texture replication");
1386
bool bCI = (gRDP.otherMode.text_tlut>=2 || entry.ti.Format == TXT_FMT_CI || entry.ti.Format == TXT_FMT_RGBA) && entry.ti.Size <= TXT_SIZE_8b;
1388
uint64 crc64a = entry.dwCRC;
1390
uint64 crc64b = crc64a;
1391
crc64a |= (0xFFFFFF00|(entry.ti.Format<<4)|entry.ti.Size);
1392
crc64b |= ((entry.dwPalCRC&0xFFFFFF00)|(entry.ti.Format<<4)|entry.ti.Size);
1394
int infosize = infos.size();
1396
indexa = infos.find(crc64a); // For CI without pal CRC, and for RGBA_PNG_FOR_ALL_CI
1398
indexb = infos.find(crc64b); // For CI or PNG with pal CRC
1400
if( indexa >= infosize ) indexa = -1;
1401
if( indexb >= infosize ) indexb = -1;
1407
scaleShift = FindScaleFactor(infos[indexb], entry);
1408
if( scaleShift >= 0 )
1412
if( bForDump && bCI && indexb < 0)
1415
if( indexa >= 0 ) scaleShift = FindScaleFactor(infos[indexa], entry);
1417
if( scaleShift >= 0 )
1423
bool SaveCITextureToFile(TxtrCacheEntry &entry, char *filename, bool bShow, bool bWhole);
1425
void DumpCachedTexture( TxtrCacheEntry &entry )
1429
CTexture *pSrcTexture = entry.pTexture;
1432
// Check the vector table
1433
int ciidx, scaleShift;
1434
if( CheckTextureInfos(gTxtrDumpInfos,entry,ciidx,scaleShift,true) >= 0 )
1435
return; // This texture has been dumpped
1437
char filename1[PATH_MAX + 64];
1438
char filename2[PATH_MAX + 64];
1439
char filename3[PATH_MAX + 64];
1440
char gamefolder[PATH_MAX + 64];
1441
strncpy(gamefolder, ConfigGetUserDataPath(), PATH_MAX);
1442
gamefolder[PATH_MAX] = 0;
1444
strcat(gamefolder,"texture_dump" OSAL_DIR_SEPARATOR_STR);
1445
strcat(gamefolder,(const char*)g_curRomInfo.szGameName);
1446
strcat(gamefolder, OSAL_DIR_SEPARATOR_STR);
1448
//sprintf(filename1+strlen(filename1), "%08X#%d#%d", entry.dwCRC, entry.ti.Format, entry.ti.Size);
1449
sprintf(filename1, "%s%s#%08X#%d#%d", gamefolder, g_curRomInfo.szGameName, entry.dwCRC, entry.ti.Format, entry.ti.Size);
1451
if( (gRDP.otherMode.text_tlut>=2 || entry.ti.Format == TXT_FMT_CI || entry.ti.Format == TXT_FMT_RGBA) && entry.ti.Size <= TXT_SIZE_8b )
1455
sprintf(filename1, "%sci_bmp%c%s#%08X#%d#%d_ci", gamefolder, cSep, g_curRomInfo.szGameName, entry.dwCRC, entry.ti.Format, entry.ti.Size);
1456
SaveCITextureToFile(entry, filename1, false, false);
1459
sprintf(filename1, "%sci_bmp_with_pal_crc%c%s#%08X#%d#%d#%08X_ci", gamefolder, cSep, g_curRomInfo.szGameName, entry.dwCRC, entry.ti.Format, entry.ti.Size,entry.dwPalCRC);
1460
SaveCITextureToFile(entry, filename1, false, false);
1462
sprintf(filename1, "%sci_by_png%c%s#%08X#%d#%d#%08X_ciByRGBA", gamefolder, cSep, g_curRomInfo.szGameName, entry.dwCRC, entry.ti.Format, entry.ti.Size,entry.dwPalCRC);
1463
CRender::g_pRender->SaveTextureToFile(*pSrcTexture, filename1, TXT_RGBA, false, false, entry.ti.WidthToLoad, entry.ti.HeightToLoad);
1467
sprintf(filename1, "%spng_by_rgb_a%c%s#%08X#%d#%d_rgb", gamefolder, cSep, g_curRomInfo.szGameName, entry.dwCRC, entry.ti.Format, entry.ti.Size);
1468
sprintf(filename2, "%spng_by_rgb_a%c%s#%08X#%d#%d_a", gamefolder, cSep, g_curRomInfo.szGameName, entry.dwCRC, entry.ti.Format, entry.ti.Size);
1469
sprintf(filename3, "%spng_all%c%s#%08X#%d#%d_all", gamefolder, cSep, g_curRomInfo.szGameName, entry.dwCRC, entry.ti.Format, entry.ti.Size);
1472
CRender::g_pRender->SaveTextureToFile(*pSrcTexture, filename1, TXT_RGB, false, false, entry.ti.WidthToLoad, entry.ti.HeightToLoad);
1473
CRender::g_pRender->SaveTextureToFile(*pSrcTexture, filename3, TXT_RGBA, false, false, entry.ti.WidthToLoad, entry.ti.HeightToLoad);
1474
if( entry.ti.Format != TXT_FMT_I )
1478
if( pSrcTexture->StartUpdate(&srcInfo) )
1480
// Copy RGB to buffer
1481
for( int i=entry.ti.HeightToLoad-1; i>=0; i--)
1483
unsigned char *pSrc = (unsigned char*)srcInfo.lpSurface+srcInfo.lPitch * i;
1484
for( uint32 j=0; j<entry.ti.WidthToLoad; j++)
1490
pSrcTexture->EndUpdate(&srcInfo);
1494
CRender::g_pRender->SaveTextureToFile(*pSrcTexture, filename2, TXT_ALPHA, false, false);
1498
ExtTxtrInfo newinfo;
1499
newinfo.width = entry.ti.WidthToLoad;
1500
newinfo.height = entry.ti.HeightToLoad;
1501
//strcpy(newinfo.name,g_curRomInfo.szGameName);
1502
newinfo.fmt = entry.ti.Format;
1503
newinfo.siz = entry.ti.Size;
1504
newinfo.crc32 = entry.dwCRC;
1506
newinfo.pal_crc32 = entry.dwPalCRC;
1507
newinfo.foldername = NULL;
1508
newinfo.RGBNameTail[0] = newinfo.AlphaNameTail[0] = 0;
1510
uint64 crc64 = newinfo.crc32;
1512
crc64 |= (newinfo.pal_crc32&0xFFFFFF00)|(newinfo.fmt<<4)|newinfo.siz;
1513
gTxtrDumpInfos.add(crc64,newinfo);
1518
bool LoadRGBBufferFromPNGFile(char *filename, unsigned char **pbuf, int &width, int &height, int bits_per_pixel = 24 )
1520
struct BMGImageStruct img;
1521
memset(&img, 0, sizeof(BMGImageStruct));
1522
if (!PathFileExists(filename))
1524
DebugMessage(M64MSG_ERROR, "File at '%s' doesn't exist in LoadRGBBufferFromPNGFile!", filename);
1528
BMG_Error code = ReadPNG( filename, &img );
1529
if( code == BMG_OK )
1533
*pbuf = new unsigned char[img.width*img.height*bits_per_pixel/8];
1536
DebugMessage(M64MSG_ERROR, "new[] returned NULL for image width=%i height=%i bpp=%i", img.width, img.height, bits_per_pixel);
1539
if (img.bits_per_pixel == bits_per_pixel)
1541
memcpy(*pbuf, img.bits, img.width*img.height*bits_per_pixel/8);
1543
else if (img.bits_per_pixel == 24 && bits_per_pixel == 32)
1545
unsigned char *pSrc = img.bits;
1546
unsigned char *pDst = *pbuf;
1547
for (int i = 0; i < (int)(img.width*img.height); i++)
1555
else if (img.bits_per_pixel == 32 && bits_per_pixel == 24)
1557
unsigned char *pSrc = img.bits;
1558
unsigned char *pDst = *pbuf;
1559
for (int i = 0; i < (int)(img.width*img.height); i++)
1569
DebugMessage(M64MSG_ERROR, "PNG file is %i bpp but texture is %i bpp.", img.bits_per_pixel, bits_per_pixel);
1575
height = img.height;
1582
DebugMessage(M64MSG_ERROR, "ReadPNG() returned error in LoadRGBBufferFromPNGFile!");
1588
bool LoadRGBABufferFromColorIndexedFile(char *filename, TxtrCacheEntry &entry, unsigned char **pbuf, int &width, int &height)
1590
BITMAPFILEHEADER fileHeader;
1591
BITMAPINFOHEADER infoHeader;
1594
f = fopen(filename, "rb");
1597
if (fread(&fileHeader, sizeof(BITMAPFILEHEADER), 1, f) != 1 ||
1598
fread(&infoHeader, sizeof(BITMAPINFOHEADER), 1, f) != 1)
1600
DebugMessage(M64MSG_ERROR, "Couldn't read BMP headers in file '%s'", filename);
1604
if( infoHeader.biBitCount != 4 && infoHeader.biBitCount != 8 )
1607
DebugMessage(M64MSG_ERROR, "Unsupported BMP file format: %s", filename);
1612
int tablesize = infoHeader.biBitCount == 4 ? 16 : 256;
1613
uint32 *pTable = new uint32[tablesize];
1614
if (fread(pTable, tablesize*4, 1, f) != 1)
1616
DebugMessage(M64MSG_ERROR, "Couldn't read BMP palette in file '%s'", filename);
1621
// Create the pallette table
1622
uint16 * pPal = (uint16 *)entry.ti.PalAddress;
1623
if( entry.ti.Size == TXT_SIZE_4b )
1626
for( int i=0; i<16; i++ )
1628
pTable[i] = entry.ti.TLutFmt == TLUT_FMT_RGBA16 ? Convert555ToRGBA(pPal[i^1]) : ConvertIA16ToRGBA(pPal[i^1]);
1634
for( int i=0; i<256; i++ )
1636
pTable[i] = entry.ti.TLutFmt == TLUT_FMT_RGBA16 ? Convert555ToRGBA(pPal[i^1]) : ConvertIA16ToRGBA(pPal[i^1]);
1640
*pbuf = new unsigned char[infoHeader.biWidth*infoHeader.biHeight*4];
1643
unsigned char *colorIdxBuf = new unsigned char[infoHeader.biSizeImage];
1646
if (fread(colorIdxBuf, infoHeader.biSizeImage, 1, f) != 1)
1648
DebugMessage(M64MSG_ERROR, "Couldn't read BMP image data in file '%s'", filename);
1651
width = infoHeader.biWidth;
1652
height = infoHeader.biHeight;
1654
// Converting pallette texture to RGBA texture
1656
uint32 *pbuf2 = (uint32*) *pbuf;
1658
for( int i=height-1; i>=0; i--)
1660
for( int j=0; j<width; j++)
1662
if( entry.ti.Size == TXT_SIZE_4b )
1668
*pbuf2++ = pTable[colorIdxBuf[(idx++)>>1]&0xF];
1673
*pbuf2++ = pTable[(colorIdxBuf[(idx++)>>1]>>4)&0xF];
1679
*pbuf2++ = pTable[colorIdxBuf[idx++]];
1682
if( entry.ti.Size == TXT_SIZE_4b )
1684
if( idx%8 ) idx = (idx/8+1)*8;
1688
if( idx%4 ) idx = (idx/4+1)*4;
1692
delete [] colorIdxBuf;
1696
TRACE0("Out of memory");
1712
TRACE1("Fail to open file %s", filename);
1718
bool LoadRGBBufferFromBMPFile(char *filename, unsigned char **pbuf, int &width, int &height)
1720
BITMAPFILEHEADER fileHeader;
1721
BITMAPINFOHEADER infoHeader;
1724
f = fopen(filename, "rb");
1727
if (fread(&fileHeader, sizeof(BITMAPFILEHEADER), 1, f) != 1 ||
1728
fread(&infoHeader, sizeof(BITMAPINFOHEADER), 1, f) != 1)
1730
DebugMessage(M64MSG_ERROR, "Couldn't read BMP headers in file '%s'", filename);
1734
if( infoHeader.biBitCount != 24 )
1737
DebugMessage(M64MSG_ERROR, "Unsupported BMP file 16 bits format: %s", filename);
1742
*pbuf = new unsigned char[infoHeader.biWidth*infoHeader.biHeight*3];
1745
if (fread(*pbuf, infoHeader.biWidth*infoHeader.biHeight*3, 1, f) != 1)
1746
DebugMessage(M64MSG_ERROR, "Couldn't read RGB BMP image data in file '%s'", filename);
1748
width = infoHeader.biWidth;
1749
height = infoHeader.biHeight;
1761
DebugMessage(M64MSG_WARNING, "Fail to open file %s", filename);
1767
void LoadHiresTexture( TxtrCacheEntry &entry )
1769
if( entry.bExternalTxtrChecked )
1772
if( entry.pEnhancedTexture )
1774
SAFE_DELETE(entry.pEnhancedTexture);
1777
int ciidx, scaleShift;
1778
int idx = CheckTextureInfos(gHiresTxtrInfos,entry,ciidx,scaleShift,false);
1781
entry.bExternalTxtrChecked = true;
1785
// Load the bitmap file
1786
char filename_rgb[PATH_MAX];
1787
char filename_a[PATH_MAX];
1789
strcpy(filename_rgb, gHiresTxtrInfos[idx].foldername);
1791
sprintf(filename_rgb+strlen(filename_rgb), "%s#%08X#%d#%d", g_curRomInfo.szGameName, entry.dwCRC, entry.ti.Format, entry.ti.Size);
1792
strcpy(filename_a,filename_rgb);
1793
strcat(filename_rgb,gHiresTxtrInfos[idx].RGBNameTail);
1794
strcat(filename_a,gHiresTxtrInfos[idx].AlphaNameTail);
1796
// Load BMP image to buffer_rbg
1797
unsigned char *buf_rgba = NULL;
1798
unsigned char *buf_a = NULL;
1801
bool bResRGBA=false, bResA=false;
1802
bool bCI = ((gRDP.otherMode.text_tlut>=2 || entry.ti.Format == TXT_FMT_CI || entry.ti.Format == TXT_FMT_RGBA) && entry.ti.Size <= TXT_SIZE_8b );
1804
switch( gHiresTxtrInfos[idx].type )
1811
bResRGBA = LoadRGBBufferFromPNGFile(filename_rgb, &buf_rgba, width, height);
1812
if( bResRGBA && gHiresTxtrInfos[idx].bSeparatedAlpha )
1813
bResA = LoadRGBBufferFromPNGFile(filename_a, &buf_a, width, height);
1816
case COLOR_INDEXED_BMP:
1818
bResRGBA = LoadRGBABufferFromColorIndexedFile(filename_rgb, entry, &buf_rgba, width, height);
1822
case RGBA_PNG_FOR_CI:
1823
case RGBA_PNG_FOR_ALL_CI:
1825
bResRGBA = LoadRGBBufferFromPNGFile(filename_rgb, &buf_rgba, width, height, 32);
1829
case RGB_WITH_ALPHA_TOGETHER_PNG:
1833
bResRGBA = LoadRGBBufferFromPNGFile(filename_rgb, &buf_rgba, width, height, 32);
1841
DebugMessage(M64MSG_ERROR, "RGBBuffer creation failed for file '%s'.", filename_rgb);
1844
else if( gHiresTxtrInfos[idx].bSeparatedAlpha && !bResA )
1846
DebugMessage(M64MSG_ERROR, "Alpha buffer creation failed for file '%s'.", filename_a);
1851
// calculate the texture size magnification by comparing the N64 texture size and the hi-res texture size
1852
int scalex = width / (int)entry.ti.WidthToCreate;
1853
int scaley = height / (int)entry.ti.HeightToCreate;
1856
if (entry.ti.WidthToCreate/entry.ti.WidthToLoad == 2) mirrorx = 2;
1857
if (entry.ti.HeightToCreate/entry.ti.HeightToLoad == 2) mirrory = 2;
1858
entry.pEnhancedTexture = CDeviceBuilder::GetBuilder()->CreateTexture(entry.ti.WidthToCreate*scalex*mirrorx, entry.ti.HeightToCreate*scaley*mirrory);
1861
if( entry.pEnhancedTexture && entry.pEnhancedTexture->StartUpdate(&info) )
1864
if( gHiresTxtrInfos[idx].type == RGB_PNG )
1866
unsigned char *pRGB = buf_rgba;
1867
unsigned char *pA = buf_a;
1869
if (info.lPitch < width * 4)
1870
DebugMessage(M64MSG_ERROR, "Texture pitch %i less than width %i times 4", info.lPitch, width);
1871
if (height > info.dwHeight)
1872
DebugMessage(M64MSG_ERROR, "Texture source height %i greater than destination height %i", height, info.dwHeight);
1874
// Update the texture by using the buffer
1875
for( int i=height-1; i>=0; i--)
1877
unsigned char* pdst = (unsigned char*)info.lpSurface + i*info.lPitch;
1878
for( int j=0; j<width; j++)
1880
*pdst++ = *pRGB++; // R
1881
*pdst++ = *pRGB++; // G
1882
*pdst++ = *pRGB++; // B
1884
if( gHiresTxtrInfos[idx].bSeparatedAlpha )
1889
else if( entry.ti.Format == TXT_FMT_I )
1902
// Update the texture by using the buffer
1903
uint32 *pRGB = (uint32*)buf_rgba;
1904
for( int i=height-1; i>=0; i--)
1906
uint32 *pdst = (uint32*)((unsigned char*)info.lpSurface + i*info.lPitch);
1907
for( int j=0; j<width; j++)
1909
*pdst++ = *pRGB++; // RGBA
1916
//printf("Mirror: ToCreate: (%d,%d) ToLoad: (%d,%d) Scale: (%i,%i) Mirror: (%i,%i) Size: (%i,%i) Mask: %i\n", entry.ti.WidthToCreate, entry.ti.HeightToCreate, entry.ti.WidthToLoad, entry.ti.HeightToLoad, scalex, scaley, mirrorx, mirrory, width, height, entry.ti.maskS+scaleShift);
1917
gTextureManager.Mirror(info.lpSurface, width, entry.ti.maskS+scaleShift, width*2, width*2, height, S_FLAG, 4 );
1922
//printf("Mirror: ToCreate: (%d,%d) ToLoad: (%d,%d) Scale: (%i,%i) Mirror: (%i,%i) Size: (%i,%i) Mask: %i\n", entry.ti.WidthToCreate, entry.ti.HeightToCreate, entry.ti.WidthToLoad, entry.ti.HeightToLoad, scalex, scaley, mirrorx, mirrory, width, height, entry.ti.maskT+scaleShift);
1923
gTextureManager.Mirror(info.lpSurface, height, entry.ti.maskT+scaleShift, height*2, entry.pEnhancedTexture->m_dwCreatedTextureWidth, height, T_FLAG, 4 );
1926
if( entry.ti.WidthToCreate*scalex*mirrorx < entry.pEnhancedTexture->m_dwCreatedTextureWidth )
1929
gTextureManager.Clamp(info.lpSurface, width, entry.pEnhancedTexture->m_dwCreatedTextureWidth, entry.pEnhancedTexture->m_dwCreatedTextureWidth, height, S_FLAG, 4 );
1931
if( entry.ti.HeightToCreate*scaley*mirrory < entry.pEnhancedTexture->m_dwCreatedTextureHeight )
1934
gTextureManager.Clamp(info.lpSurface, height, entry.pEnhancedTexture->m_dwCreatedTextureHeight, entry.pEnhancedTexture->m_dwCreatedTextureWidth, height, T_FLAG, 4 );
1937
entry.pEnhancedTexture->EndUpdate(&info);
1938
entry.pEnhancedTexture->SetOthersVariables();
1939
entry.pEnhancedTexture->m_bIsEnhancedTexture = true;
1940
entry.dwEnhancementFlag = TEXTURE_EXTERNAL;
1942
DebugMessage(M64MSG_VERBOSE, "Loaded hi-res texture: %s", filename_rgb);
1946
DebugMessage(M64MSG_ERROR, "New texture creation failed.");
1947
TRACE0("Cannot create a new texture");