Rice GLES2 (from mupen64plus-ae) plugin. Compile but doesn't works well on the OpenPa...
[mupen64plus-pandora.git] / source / gles2rice / src / TextureFilters.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 "osal_files.h"
21
22 #define M64P_PLUGIN_PROTOTYPES 1
23 #include "m64p_plugin.h"
24 #include "typedefs.h"
25 #include "ConvertImage.h"
26 #include "DeviceBuilder.h"
27 #include "TextureFilters.h"
28 #include "Render.h"
29 #include "Video.h"
30
31 #include "liblinux/BMGLibPNG.h"
32 #include "liblinux/BMGDLL.h"
33 #include <sys/types.h>
34 #include <algorithm>
35
36 #ifdef min
37 #undef min
38 #endif
39
40 /************************************************************************/
41 /* 2X filters                                                           */
42 /************************************************************************/
43 // Basic 2x R8G8B8A8 filter with interpolation
44
45 void Texture2x_32( DrawInfo &srcInfo, DrawInfo &destInfo)
46 {
47     uint32 *pDst1, *pDst2;
48     uint32 *pSrc, *pSrc2;
49     uint32 nWidth = srcInfo.dwWidth;
50     uint32 nHeight = srcInfo.dwHeight;
51
52     uint32 b1;
53     uint32 g1;
54     uint32 r1;
55     uint32 a1;
56     uint32 b2 = 0;
57     uint32 g2 = 0;
58     uint32 r2 = 0;
59     uint32 a2 = 0;
60     uint32 b3 = 0;
61     uint32 g3 = 0;
62     uint32 r3 = 0;
63     uint32 a3 = 0;
64     uint32 b4 = 0;
65     uint32 g4 = 0;
66     uint32 r4 = 0;
67     uint32 a4 = 0;
68
69
70     for (uint32 ySrc = 0; ySrc < nHeight; ySrc++)
71     {
72         pSrc = (uint32*)(((uint8*)srcInfo.lpSurface)+ySrc*srcInfo.lPitch);
73         pSrc2 = (uint32*)(((uint8*)srcInfo.lpSurface)+(ySrc+1)*srcInfo.lPitch);
74         pDst1 = (uint32*)(((uint8*)destInfo.lpSurface)+(ySrc*2)*destInfo.lPitch);
75         pDst2 = (uint32*)(((uint8*)destInfo.lpSurface)+(ySrc*2+1)*destInfo.lPitch);
76
77         for (uint32 xSrc = 0; xSrc < nWidth; xSrc++)
78         {
79             b1 = (pSrc[xSrc]>>0)&0xFF;
80             g1 = (pSrc[xSrc]>>8)&0xFF;
81             r1 = (pSrc[xSrc]>>16)&0xFF;
82             a1 = (pSrc[xSrc]>>24)&0xFF;
83
84             if( xSrc<nWidth-1 )
85             {
86                 b2 = (pSrc[xSrc+1]>>0)&0xFF;
87                 g2 = (pSrc[xSrc+1]>>8)&0xFF;
88                 r2 = (pSrc[xSrc+1]>>16)&0xFF;
89                 a2 = (pSrc[xSrc+1]>>24)&0xFF;
90             }
91
92             if( ySrc<nHeight-1 )
93             {
94                 b3 = (pSrc2[xSrc]>>0)&0xFF;
95                 g3 = (pSrc2[xSrc]>>8)&0xFF;
96                 r3 = (pSrc2[xSrc]>>16)&0xFF;
97                 a3 = (pSrc2[xSrc]>>24)&0xFF;
98                 if( xSrc<nWidth-1 )
99                 {
100                     b4 = (pSrc2[xSrc+1]>>0)&0xFF;
101                     g4 = (pSrc2[xSrc+1]>>8)&0xFF;
102                     r4 = (pSrc2[xSrc+1]>>16)&0xFF;
103                     a4 = (pSrc2[xSrc+1]>>24)&0xFF;
104                 }
105             }
106
107
108             // Pixel 1
109             pDst1[xSrc*2] = pSrc[xSrc];
110
111             // Pixel 2
112             if( xSrc<nWidth-1 )
113             {
114                 pDst1[xSrc*2+1] = DWORD_MAKE((r1+r2)/2, (g1+g2)/2, (b1+b2)/2, (a1+a2)/2);
115             }
116             else
117                 pDst1[xSrc*2+1] = pSrc[xSrc];
118
119
120             // Pixel 3
121             if( ySrc<nHeight-1 )
122             {
123                 pDst2[xSrc*2] = DWORD_MAKE((r1+r3)/2, (g1+g3)/2, (b1+b3)/2, (a1+a3)/2);
124             }
125             else
126                 pDst2[xSrc*2] = pSrc[xSrc];
127
128             // Pixel 4
129             if( xSrc<nWidth-1 )
130             {
131                 if( ySrc<nHeight-1 )
132                 {
133                     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);
134                 }
135                 else
136                 {
137                     pDst2[xSrc*2+1] = DWORD_MAKE((r1+r2)/2, (g1+g2)/2, (b1+b2)/2, (a1+a2)/2);
138                 }
139             }
140             else
141             {
142                 if( ySrc<nHeight-1 )
143                 {
144                     pDst2[xSrc*2+1] = DWORD_MAKE((r1+r3)/2, (g1+g3)/2, (b1+b3)/2, (a1+a3)/2);
145                 }
146                 else
147                     pDst2[xSrc*2+1] = pSrc[xSrc];
148             }
149         }
150     }
151 }
152
153 // Basic 2x R4G4B4A4 filter with interpolation
154 void Texture2x_16( DrawInfo &srcInfo, DrawInfo &destInfo )
155 {
156     uint16 *pDst1, *pDst2;
157     uint16 *pSrc, *pSrc2;
158     uint32 nWidth = srcInfo.dwWidth;
159     uint32 nHeight = srcInfo.dwHeight;
160
161     uint16 b1;
162     uint16 g1;
163     uint16 r1;
164     uint16 a1;
165     uint16 b2 = 0;
166     uint16 g2 = 0;
167     uint16 r2 = 0;
168     uint16 a2 = 0;
169     uint16 b3 = 0;
170     uint16 g3 = 0;
171     uint16 r3 = 0;
172     uint16 a3 = 0;
173     uint16 b4 = 0;
174     uint16 g4 = 0;
175     uint16 r4 = 0;
176     uint16 a4 = 0;
177
178     for (uint16 ySrc = 0; ySrc < nHeight; ySrc++)
179     {
180         pSrc = (uint16*)(((uint8*)srcInfo.lpSurface)+ySrc*srcInfo.lPitch);
181         pSrc2 = (uint16*)(((uint8*)srcInfo.lpSurface)+(ySrc+1)*srcInfo.lPitch);
182         pDst1 = (uint16*)(((uint8*)destInfo.lpSurface)+(ySrc*2)*destInfo.lPitch);
183         pDst2 = (uint16*)(((uint8*)destInfo.lpSurface)+(ySrc*2+1)*destInfo.lPitch);
184
185         for (uint16 xSrc = 0; xSrc < nWidth; xSrc++)
186         {
187             b1 = (pSrc[xSrc]>> 0)&0xF;
188             g1 = (pSrc[xSrc]>> 4)&0xF;
189             r1 = (pSrc[xSrc]>> 8)&0xF;
190             a1 = (pSrc[xSrc]>>12)&0xF;
191
192             if( xSrc<nWidth-1 )
193             {
194                 b2 = (pSrc[xSrc+1]>> 0)&0xF;
195                 g2 = (pSrc[xSrc+1]>> 4)&0xF;
196                 r2 = (pSrc[xSrc+1]>> 8)&0xF;
197                 a2 = (pSrc[xSrc+1]>>12)&0xF;
198             }
199
200             if( ySrc<nHeight-1 )
201             {
202                 b3 = (pSrc2[xSrc]>> 0)&0xF;
203                 g3 = (pSrc2[xSrc]>> 4)&0xF;
204                 r3 = (pSrc2[xSrc]>> 8)&0xF;
205                 a3 = (pSrc2[xSrc]>>12)&0xF;
206                 if( xSrc<nWidth-1 )
207                 {
208                     b4 = (pSrc2[xSrc+1]>> 0)&0xF;
209                     g4 = (pSrc2[xSrc+1]>> 4)&0xF;
210                     r4 = (pSrc2[xSrc+1]>> 8)&0xF;
211                     a4 = (pSrc2[xSrc+1]>>12)&0xF;
212                 }
213             }
214
215             // Pixel 1
216             pDst1[xSrc*2] = pSrc[xSrc];
217
218             // Pixel 2
219             if( xSrc<nWidth-1 )
220             {
221                 pDst1[xSrc*2+1] = WORD_MAKE((r1+r2)/2, (g1+g2)/2, (b1+b2)/2, (a1+a2)/2);
222             }
223             else
224                 pDst1[xSrc*2+1] = pSrc[xSrc];
225
226
227             // Pixel 3
228             if( ySrc<nHeight-1 )
229             {
230                 pDst2[xSrc*2] = WORD_MAKE((r1+r3)/2, (g1+g3)/2, (b1+b3)/2, (a1+a3)/2);
231             }
232             else
233                 pDst2[xSrc*2] = pSrc[xSrc];
234
235             // Pixel 4
236             if( xSrc<nWidth-1 )
237             {
238                 if( ySrc<nHeight-1 )
239                 {
240                     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);
241                 }
242                 else
243                 {
244                     pDst2[xSrc*2+1] = WORD_MAKE((r1+r2)/2, (g1+g2)/2, (b1+b2)/2, (a1+a2)/2);
245                 }
246             }
247             else
248             {
249                 if( ySrc<nHeight-1 )
250                 {
251                     pDst2[xSrc*2+1] = WORD_MAKE((r1+r3)/2, (g1+g3)/2, (b1+b3)/2, (a1+a3)/2);
252                 }
253                 else
254                     pDst2[xSrc*2+1] = pSrc[xSrc];
255             }
256         }
257     }
258 }
259
260 /************************************************************************/
261 /* Sharpen filters                                                      */
262 /************************************************************************/
263 void SharpenFilter_32(uint32 *pdata, uint32 width, uint32 height, uint32 pitch, uint32 filter)
264 {
265     uint32 len=height*pitch;
266     uint32 *pcopy = new uint32[len];
267
268     if( !pcopy )    return;
269
270     memcpy(pcopy, pdata, len<<2);
271
272     uint32 mul1, mul2, mul3, shift4;
273     switch( filter )
274     {
275         case TEXTURE_SHARPEN_MORE_ENHANCEMENT:
276             mul1=1;
277             mul2=8;
278             mul3=12;
279             shift4=2;
280             break;
281         case TEXTURE_SHARPEN_ENHANCEMENT:
282         default:
283             mul1=1;
284             mul2=8;
285             mul3=16;
286             shift4=3;
287             break;
288     }
289
290     uint32 x,y,z;
291     uint32 *src1, *src2, *src3, *dest;
292     uint32 val[4];
293     uint32 t1,t2,t3,t4,t5,t6,t7,t8,t9;
294
295     for( y=1; y<height-1; y++)
296     {
297         dest = pdata+y*pitch;
298         src1 = pcopy+(y-1)*pitch;
299         src2 = src1 + pitch;
300         src3 = src2 + pitch;
301         for( x=1; x<width-1; x++)
302         {
303             for( z=0; z<4; z++ )
304             {
305                 t1 = *((uint8*)(src1+x-1)+z);
306                 t2 = *((uint8*)(src1+x  )+z);
307                 t3 = *((uint8*)(src1+x+1)+z);
308                 t4 = *((uint8*)(src2+x-1)+z);
309                 t5 = *((uint8*)(src2+x  )+z);
310                 t6 = *((uint8*)(src2+x+1)+z);
311                 t7 = *((uint8*)(src3+x-1)+z);
312                 t8 = *((uint8*)(src3+x  )+z);
313                 t9 = *((uint8*)(src3+x+1)+z);
314                 val[z]=t5;
315                 if( (t5*mul2) > (t1+t3+t7+t9+t2+t4+t6+t8)*mul1 )
316                 {
317                     val[z]= std::min((((t5*mul3) - (t1+t3+t7+t9+t2+t4+t6+t8)*mul1)>>shift4),0xFFU);
318                 }
319             }
320             dest[x] = val[0]|(val[1]<<8)|(val[2]<<16)|(val[3]<<24);
321         }
322     }
323     delete [] pcopy;
324 }
325
326 void SharpenFilter_16(uint16 *pdata, uint32 width, uint32 height, uint32 pitch, uint32 filter)
327 {
328     //return;   // Sharpen does not make sense for 16 bits
329
330     uint32 len=height*pitch;
331     uint16 *pcopy = new uint16[len];
332
333     if( !pcopy )    return;
334
335     memcpy(pcopy, pdata, len<<1);
336
337     uint16 mul1, mul2, mul3, shift4;
338     switch( filter )
339     {
340         case TEXTURE_SHARPEN_MORE_ENHANCEMENT:
341             mul1=1;
342             mul2=8;
343             mul3=12;
344             shift4=2;
345             break;
346         case TEXTURE_SHARPEN_ENHANCEMENT:
347         default:
348             mul1=1;
349             mul2=8;
350             mul3=16;
351             shift4=3;
352             break;
353     }
354
355     uint32 x,y,z;
356     uint16 *src1, *src2, *src3, *dest;
357     uint16 val[4];
358     uint16 t1,t2,t3,t4,t5,t6,t7,t8,t9;
359
360     for( y=1; y<height-1; y++)
361     {
362         dest = pdata+y*pitch;
363         src1 = pcopy+(y-1)*pitch;
364         src2 = src1 + pitch;
365         src3 = src2 + pitch;
366         for( x=1; x<width-1; x++)
367         {
368             for( z=0; z<4; z++ )
369             {
370                 uint32 shift = (z%1)?4:0;
371                 t1 = (*((uint8*)(src1+x-1)+(z>>1)))>>shift;
372                 t2 = (*((uint8*)(src1+x  )+(z>>1)))>>shift;
373                 t3 = (*((uint8*)(src1+x+1)+(z>>1)))>>shift;
374                 t4 = (*((uint8*)(src2+x-1)+(z>>1)))>>shift;
375                 t5 = (*((uint8*)(src2+x  )+(z>>1)))>>shift;
376                 t6 = (*((uint8*)(src2+x+1)+(z>>1)))>>shift;
377                 t7 = (*((uint8*)(src3+x-1)+(z>>1)))>>shift;
378                 t8 = (*((uint8*)(src3+x  )+(z>>1)))>>shift;
379                 t9 = (*((uint8*)(src3+x+1)+(z>>1)))>>shift;
380                 val[z]=t5;
381                 if( (t5*mul2) > (t1+t3+t7+t9+t2+t4+t6+t8)*mul1 )
382                 {
383                     val[z] = (((t5*mul3) - (t1+t3+t7+t9+t2+t4+t6+t8)*mul1)>>shift4);
384                     val[z]= std::min(val[z],(unsigned short)0xFU);
385                 }
386             }
387             dest[x] = val[0]|(val[1]<<4)|(val[2]<<8)|(val[3]<<12);
388         }
389     }
390     delete [] pcopy;
391 }
392
393 /************************************************************************/
394 /* Smooth filters                                                       */
395 /************************************************************************/
396 void SmoothFilter_32(uint32 *pdata, uint32 width, uint32 height, uint32 pitch, uint32 filter)
397 {
398     uint32 len=height*pitch;
399     uint32 *pcopy = new uint32[len];
400
401     if( !pcopy )    return;
402
403     memcpy(pcopy, pdata, len<<2);
404
405     uint32 mul1, mul2, mul3, shift4;
406     switch( filter )
407     {
408         case TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_1:
409             mul1=1;
410             mul2=2;
411             mul3=4;
412             shift4=4;
413             break;
414         case TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_2:
415             mul1=1;
416             mul2=1;
417             mul3=8;
418             shift4=4;
419             break;
420         case TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_3:
421             mul1=1;
422             mul2=1;
423             mul3=2;
424             shift4=2;
425             break;
426         case TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_4:
427         default:
428             mul1=1;
429             mul2=1;
430             mul3=6;
431             shift4=3;
432             break;
433     }
434
435     uint32 x,y,z;
436     uint32 *src1, *src2, *src3, *dest;
437     uint32 val[4];
438     uint32 t1,t2,t3,t4,t5,t6,t7,t8,t9;
439
440     if( filter == TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_3 || filter == TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_4 )
441     {
442         for( y=1; y<height-1; y+=2)
443         {
444             dest = pdata+y*pitch;
445             src1 = pcopy+(y-1)*pitch;
446             src2 = src1 + pitch;
447             src3 = src2 + pitch;
448             for( x=0; x<width; x++)
449             {
450                 for( z=0; z<4; z++ )
451                 {
452                     t2 = *((uint8*)(src1+x  )+z);
453                     t5 = *((uint8*)(src2+x  )+z);
454                     t8 = *((uint8*)(src3+x  )+z);
455                     val[z] = ((t2+t8)*mul2+(t5*mul3))>>shift4;
456                 }
457                 dest[x] = val[0]|(val[1]<<8)|(val[2]<<16)|(val[3]<<24);
458             }
459         }
460     }
461     else
462     {
463         for( y=0; y<height; y++)
464         {
465             dest = pdata+y*pitch;
466             if( y>0 )
467             {
468                 src1 = pcopy+(y-1)*pitch;
469                 src2 = src1 + pitch;
470             }
471             else
472             {
473                 src1 = src2 = pcopy;
474             }
475
476             src3 = src2;
477             if( y<height-1) src3 += pitch;
478
479             for( x=1; x<width-1; x++)
480             {
481                 for( z=0; z<4; z++ )
482                 {
483                     t1 = *((uint8*)(src1+x-1)+z);
484                     t2 = *((uint8*)(src1+x  )+z);
485                     t3 = *((uint8*)(src1+x+1)+z);
486                     t4 = *((uint8*)(src2+x-1)+z);
487                     t5 = *((uint8*)(src2+x  )+z);
488                     t6 = *((uint8*)(src2+x+1)+z);
489                     t7 = *((uint8*)(src3+x-1)+z);
490                     t8 = *((uint8*)(src3+x  )+z);
491                     t9 = *((uint8*)(src3+x+1)+z);
492                     val[z] = ((t1+t3+t7+t9)*mul1+((t2+t4+t6+t8)*mul2)+(t5*mul3))>>shift4;
493                 }
494                 dest[x] = val[0]|(val[1]<<8)|(val[2]<<16)|(val[3]<<24);
495             }
496         }
497     }
498     delete [] pcopy;
499 }
500
501 void SmoothFilter_16(uint16 *pdata, uint32 width, uint32 height, uint32 pitch, uint32 filter)
502 {
503     uint32 len=height*pitch;
504     uint16 *pcopy = new uint16[len];
505
506     if( !pcopy )
507         return;
508
509     memcpy(pcopy, pdata, len<<1);
510
511     uint16 mul1, mul2, mul3, shift4;
512     switch( filter )
513     {
514         case TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_1:
515             mul1=1;
516             mul2=2;
517             mul3=4;
518             shift4=4;
519             break;
520         case TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_2:
521             mul1=1;
522             mul2=1;
523             mul3=8;
524             shift4=4;
525             break;
526         case TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_3:
527             mul1=1;
528             mul2=1;
529             mul3=2;
530             shift4=2;
531             break;
532         case TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_4:
533         default:
534             mul1=1;
535             mul2=1;
536             mul3=6;
537             shift4=3;
538             break;
539     }
540
541     uint32 x,y,z;
542     uint16 *src1, *src2, *src3, *dest;
543     uint16 val[4];
544     uint16 t1,t2,t3,t4,t5,t6,t7,t8,t9;
545
546     if( filter == TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_3 || filter == TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_4 )
547     {
548         for( y=1; y<height-1; y+=2)
549         {
550             dest = pdata+y*pitch;
551             src1 = pcopy+(y-1)*pitch;
552             src2 = src1 + pitch;
553             src3 = src2 + pitch;
554             for( x=0; x<width; x++)
555             {
556                 for( z=0; z<4; z++ )
557                 {
558                     uint32 shift = (z&1)?4:0;
559                     t2 = (*((uint8*)(src1+x  )+(z>>1)))>>shift;
560                     t5 = (*((uint8*)(src2+x  )+(z>>1)))>>shift;
561                     t8 = (*((uint8*)(src3+x  )+(z>>1)))>>shift;
562                     val[z] = ((t2+t8)*mul2+(t5*mul3))>>shift4;
563                 }
564                 dest[x] = val[0]|(val[1]<<4)|(val[2]<<8)|(val[3]<<12);
565             }
566         }
567     }
568     else
569     {
570         for( y=0; y<height; y++)
571         {
572             dest = pdata+y*pitch;
573             if( y>0 )
574             {
575                 src1 = pcopy+(y-1)*pitch;
576                 src2 = src1 + pitch;
577             }
578             else
579             {
580                 src1 = src2 = pcopy;
581             }
582
583             src3 = src2;
584             if( y<height-1) src3 += pitch;
585
586             for( x=1; x<width-1; x++)
587             {
588                 for( z=0; z<4; z++ )
589                 {
590                     uint32 shift = (z&1)?4:0;
591                     t1 = (*((uint8*)(src1+x-1)+(z>>1)))>>shift;
592                     t2 = (*((uint8*)(src1+x  )+(z>>1)))>>shift;
593                     t3 = (*((uint8*)(src1+x+1)+(z>>1)))>>shift;
594                     t4 = (*((uint8*)(src2+x-1)+(z>>1)))>>shift;
595                     t5 = (*((uint8*)(src2+x  )+(z>>1)))>>shift;
596                     t6 = (*((uint8*)(src2+x+1)+(z>>1)))>>shift;
597                     t7 = (*((uint8*)(src3+x-1)+(z>>1)))>>shift;
598                     t8 = (*((uint8*)(src3+x  )+(z>>1)))>>shift;
599                     t9 = (*((uint8*)(src3+x+1)+(z>>1)))>>shift;
600                     val[z] = ((t1+t3+t7+t9)*mul1+((t2+t4+t6+t8)*mul2)+(t5*mul3))>>shift4;
601                 }
602                 dest[x] = val[0]|(val[1]<<4)|(val[2]<<8)|(val[3]<<12);
603             }
604         }
605     }
606     delete [] pcopy;
607 }
608
609
610 void EnhanceTexture(TxtrCacheEntry *pEntry)
611 {
612     if( pEntry->dwEnhancementFlag == options.textureEnhancement )
613     {
614         // The texture has already been enhanced
615         return;
616     }
617     else if( options.textureEnhancement == TEXTURE_NO_ENHANCEMENT )
618     {
619         //Texture enhancement has being turned off
620         //Delete any allocated memory for the enhanced texture
621         SAFE_DELETE(pEntry->pEnhancedTexture);
622         //Set the enhancement flag so the texture wont be processed again
623         pEntry->dwEnhancementFlag = TEXTURE_NO_ENHANCEMENT;
624         return;
625     }
626
627     if( status.primitiveType != PRIM_TEXTRECT && options.bTexRectOnly )
628     {
629         return;
630     }
631
632     DrawInfo srcInfo;   
633     //Start the draw update
634     if( pEntry->pTexture->StartUpdate(&srcInfo) == false )
635     {
636         //If we get here we were unable to start the draw update
637         //Delete any allocated memory for the enhanced texture
638         SAFE_DELETE(pEntry->pEnhancedTexture);
639         return;
640     }
641
642     uint32 realwidth = srcInfo.dwWidth;
643     uint32 realheight = srcInfo.dwHeight;
644     uint32 nWidth = srcInfo.dwCreatedWidth;
645     uint32 nHeight = srcInfo.dwCreatedHeight;
646     
647     //Sharpen option is enabled, sharpen the texture
648     if( options.textureEnhancement == TEXTURE_SHARPEN_ENHANCEMENT || options.textureEnhancement == TEXTURE_SHARPEN_MORE_ENHANCEMENT )
649     {
650         if( pEntry->pTexture->GetPixelSize() == 4 )
651             SharpenFilter_32((uint32*)srcInfo.lpSurface, nWidth, nHeight, nWidth, options.textureEnhancement);
652         else
653             SharpenFilter_16((uint16*)srcInfo.lpSurface, nWidth, nHeight, nWidth, options.textureEnhancement);
654         pEntry->dwEnhancementFlag = options.textureEnhancement;
655         //End the draw update
656         pEntry->pTexture->EndUpdate(&srcInfo);
657         //Delete any allocated memory for the enhanced texture
658         SAFE_DELETE(pEntry->pEnhancedTexture);
659         return;
660     }
661
662     pEntry->dwEnhancementFlag = options.textureEnhancement;
663     if( options.bSmallTextureOnly )
664     {
665         if( nWidth + nHeight > 256 )
666         {
667             //End the draw update
668             pEntry->pTexture->EndUpdate(&srcInfo);
669             //Delete any data allocated for the enhanced texture
670             SAFE_DELETE(pEntry->pEnhancedTexture);
671             //Set the enhancement flag so the texture wont be processed again
672             pEntry->dwEnhancementFlag = TEXTURE_NO_ENHANCEMENT;
673             return;
674         }
675     }
676
677
678     CTexture* pSurfaceHandler = NULL;
679     if( options.textureEnhancement == TEXTURE_HQ4X_ENHANCEMENT )
680     {
681         if( nWidth + nHeight > 1024/4 )
682         {
683             // Don't enhance for large textures
684             pEntry->pTexture->EndUpdate(&srcInfo);
685             SAFE_DELETE(pEntry->pEnhancedTexture);
686             pEntry->dwEnhancementFlag = TEXTURE_NO_ENHANCEMENT;
687             return;
688         }
689         pSurfaceHandler = CDeviceBuilder::GetBuilder()->CreateTexture(nWidth*4, nHeight*4);
690     }
691     else
692     {
693         if( nWidth + nHeight > 1024/2 )
694         {
695             // Don't enhance for large textures
696             pEntry->pTexture->EndUpdate(&srcInfo);
697             SAFE_DELETE(pEntry->pEnhancedTexture);
698             pEntry->dwEnhancementFlag = TEXTURE_NO_ENHANCEMENT;
699             return;
700         }
701         pSurfaceHandler = CDeviceBuilder::GetBuilder()->CreateTexture(nWidth*2, nHeight*2);
702     }
703     DrawInfo destInfo;
704     if(pSurfaceHandler)
705     {
706         if(pSurfaceHandler->StartUpdate(&destInfo))
707         {
708             if( options.textureEnhancement == TEXTURE_2XSAI_ENHANCEMENT )
709             {
710                 if( pEntry->pTexture->GetPixelSize() == 4 )
711                     Super2xSaI_32((uint32*)(srcInfo.lpSurface),(uint32*)(destInfo.lpSurface), nWidth, realheight, nWidth);
712                 else
713                     Super2xSaI_16((uint16*)(srcInfo.lpSurface),(uint16*)(destInfo.lpSurface), nWidth, realheight, nWidth);
714             }
715             else if( options.textureEnhancement == TEXTURE_HQ2X_ENHANCEMENT )
716             {
717                 if( pEntry->pTexture->GetPixelSize() == 4 )
718                 {
719                     hq2x_init(32);
720                     hq2x_32((uint8*)(srcInfo.lpSurface), srcInfo.lPitch, (uint8*)(destInfo.lpSurface), destInfo.lPitch, nWidth, realheight);
721                 }
722                 else
723                 {
724                     hq2x_init(16);
725                     hq2x_16((uint8*)(srcInfo.lpSurface), srcInfo.lPitch, (uint8*)(destInfo.lpSurface), destInfo.lPitch, nWidth, realheight);
726                 }
727             }
728             else if( options.textureEnhancement == TEXTURE_LQ2X_ENHANCEMENT )
729             {
730                 if( pEntry->pTexture->GetPixelSize() == 4 )
731                 {
732                     hq2x_init(32);
733                     lq2x_32((uint8*)(srcInfo.lpSurface), srcInfo.lPitch, (uint8*)(destInfo.lpSurface), destInfo.lPitch, nWidth, realheight);
734                 }
735                 else
736                 {
737                     hq2x_init(16);
738                     lq2x_16((uint8*)(srcInfo.lpSurface), srcInfo.lPitch, (uint8*)(destInfo.lpSurface), destInfo.lPitch, nWidth, realheight);
739                 }
740             }
741             else if( options.textureEnhancement == TEXTURE_HQ4X_ENHANCEMENT )
742             {
743                 if( pEntry->pTexture->GetPixelSize() == 4 )
744                 {
745                     hq4x_InitLUTs();
746                     hq4x_32((uint8*)(srcInfo.lpSurface), (uint8*)(destInfo.lpSurface), realwidth, realheight, nWidth, destInfo.lPitch);
747                 }
748                 else
749                 {
750                     hq4x_InitLUTs();
751                     hq4x_16((uint8*)(srcInfo.lpSurface), (uint8*)(destInfo.lpSurface), realwidth, realheight, nWidth, destInfo.lPitch);
752                 }
753             }
754             else 
755             {
756                 if( pEntry->pTexture->GetPixelSize() == 4 )
757                     Texture2x_32( srcInfo, destInfo);
758                 else
759                     Texture2x_16( srcInfo, destInfo);
760             }
761
762             if( options.textureEnhancementControl >= TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_1 )
763             {
764                 if( options.textureEnhancement != TEXTURE_HQ4X_ENHANCEMENT )
765                 {
766                     if( pEntry->pTexture->GetPixelSize() == 4 )
767                         SmoothFilter_32((uint32*)destInfo.lpSurface, realwidth<<1, realheight<<1, nWidth<<1, options.textureEnhancementControl);
768                     else
769                         SmoothFilter_16((uint16*)destInfo.lpSurface, realwidth<<1, realheight<<1, nWidth<<1, options.textureEnhancementControl);
770                 }
771                 else
772                 {
773                     if( pEntry->pTexture->GetPixelSize() == 4 )
774                         SmoothFilter_32((uint32*)destInfo.lpSurface, realwidth<<2, realheight<<2, nWidth<<2, options.textureEnhancementControl);
775                     else
776                         SmoothFilter_16((uint16*)destInfo.lpSurface, realwidth<<2, realheight<<2, nWidth<<2, options.textureEnhancementControl);
777                 }
778             }
779
780             pSurfaceHandler->EndUpdate(&destInfo);  
781         }
782     
783         pSurfaceHandler->SetOthersVariables();
784         pSurfaceHandler->m_bIsEnhancedTexture = true;
785     }
786
787     pEntry->pTexture->EndUpdate(&srcInfo);
788
789     pEntry->pEnhancedTexture = pSurfaceHandler;
790 }
791
792
793 /************************************************************************/
794 /*                                                                      */
795 /************************************************************************/
796 void MirrorEmulator_DrawLine(DrawInfo& destInfo, DrawInfo& srcInfo, uint32 *pSource, uint32 *pDest, uint32 nWidth, BOOL bFlipLeftRight)
797 {
798     if(!bFlipLeftRight)
799     {
800         memcpy(pDest, pSource, nWidth * 4);
801     }
802     else
803     {
804         uint32 *pMaxDest = pDest + nWidth;
805         pSource += nWidth - 1;
806         for(; pDest < pMaxDest; pDest++, pSource--)
807         {
808             *pDest = *pSource;
809         }
810     }
811 }
812
813
814 void MirrorEmulator_Draw(DrawInfo& destInfo, DrawInfo& srcInfo, uint32 nDestX, uint32 nDestY, BOOL bFlipLeftRight, BOOL bFlipUpDown)
815 {
816     uint8 *pDest = (uint8 *) destInfo.lpSurface + (destInfo.lPitch * nDestY) + (4 * nDestX);
817     uint8 *pMaxDest = pDest + (destInfo.lPitch * srcInfo.dwHeight);
818     uint8 *pSource = (uint8 *)(srcInfo.lpSurface);
819     if(!bFlipUpDown)
820     {
821         for(; pDest < pMaxDest; pDest += destInfo.lPitch, pSource += srcInfo.lPitch)
822         {
823             MirrorEmulator_DrawLine(destInfo, srcInfo, (uint32*)pSource, (uint32*)pDest, srcInfo.dwWidth, bFlipLeftRight);
824         }
825     }
826     else
827     {
828         pSource += (srcInfo.lPitch * (srcInfo.dwHeight - 1));
829         for(; pDest < pMaxDest; pDest += destInfo.lPitch, pSource -= srcInfo.lPitch)
830         {
831             MirrorEmulator_DrawLine(destInfo, srcInfo, (uint32*)pSource, (uint32*)pDest, srcInfo.dwWidth, bFlipLeftRight);
832         }
833     }
834 }
835
836 void MirrorTexture(uint32 dwTile, TxtrCacheEntry *pEntry)
837 {
838     if( ((gRDP.tiles[dwTile].bMirrorS) || (gRDP.tiles[dwTile].bMirrorT)) && CGraphicsContext::Get()->m_supportTextureMirror == false )
839     {
840         if(pEntry->pEnhancedTexture)
841         {
842             return;
843         }
844         else
845         {
846             CTexture* pSurfaceHandler = NULL;
847
848             // FIXME: Compute the correct values. 2/2 seems to always work correctly in Mario64
849             uint32 nXTimes = gRDP.tiles[dwTile].bMirrorS ? 2 : 1;
850             uint32 nYTimes = gRDP.tiles[dwTile].bMirrorT ? 2 : 1;
851             
852             // For any texture need to use mirror, we should not need to rescale it
853             // because texture need to be mirrored must with MaskS and MaskT
854
855             // But again, check me
856
857             //if( pEntry->pTexture->m_bScaledS == false || pEntry->pTexture->m_bScaledT == false)
858             //{
859             //  pEntry->pTexture->ScaleImageToSurface();
860             //}
861
862             DrawInfo srcInfo;   
863             if( pEntry->pTexture->StartUpdate(&srcInfo) )
864             {
865                 uint32 nWidth = srcInfo.dwWidth;
866                 uint32 nHeight = srcInfo.dwHeight;
867
868                 pSurfaceHandler = CDeviceBuilder::GetBuilder()->CreateTexture(nWidth * nXTimes, nHeight * nYTimes);
869                 if( pSurfaceHandler )
870                 {
871                     DrawInfo destInfo;
872                     if( pSurfaceHandler->StartUpdate(&destInfo) )
873                     {
874                         for(uint32 nY = 0; nY < nYTimes; nY++)
875                         {
876                             for(uint32 nX = 0; nX < nXTimes; nX++)
877                             {
878                                 MirrorEmulator_Draw(destInfo, srcInfo, nWidth * nX, nHeight * nY, nX & 0x1, nY & 0x1);
879                             }
880                         }
881
882                         pSurfaceHandler->EndUpdate(&destInfo);
883                     }
884                 
885                     // FIXME: There should be a flag to tell that it is a mirrored texture handler
886                     // not the original texture handlers, so all texture coordinate should be divided by 2
887                     pSurfaceHandler->SetOthersVariables();
888                 }
889
890                 pEntry->pTexture->EndUpdate(&srcInfo);  
891                 pEntry->dwEnhancementFlag = TEXTURE_MIRRORED;
892             }
893
894
895             pEntry->pEnhancedTexture = pSurfaceHandler;
896         }
897     }
898 }
899 /****
900  All code bellow, CLEAN ME
901 ****/
902
903 enum TextureType
904 {
905     NO_TEXTURE,
906  RGB_PNG,
907  COLOR_INDEXED_BMP,
908  RGB_WITH_ALPHA_TOGETHER_PNG,
909  RGBA_PNG_FOR_CI,
910  RGBA_PNG_FOR_ALL_CI,
911 };
912 typedef struct {
913     unsigned int width;
914     unsigned int height;
915     int fmt;
916     int siz;
917     int crc32;
918     int pal_crc32;
919     char *foldername;
920     char *filename;
921     char *filename_a;
922     //char name[40];
923     TextureType type;
924     bool        bSeparatedAlpha;
925 } ExtTxtrInfo;
926
927 CSortedList<uint64,ExtTxtrInfo> gTxtrDumpInfos;
928 CSortedList<uint64,ExtTxtrInfo> gHiresTxtrInfos;
929
930 extern char * right(const char * src, int nchars);
931
932 #define SURFFMT_P8 41
933
934 int GetImageInfoFromFile(char* pSrcFile, IMAGE_INFO *pSrcInfo)
935 {
936     unsigned char sig[8];
937     FILE *f;
938
939     f = fopen(pSrcFile, "rb");
940     if (f == NULL)
941     {
942       DebugMessage(M64MSG_ERROR, "GetImageInfoFromFile() error: couldn't open file '%s'", pSrcFile);
943       return 1;
944     }
945     if (fread(sig, 1, 8, f) != 8)
946     {
947       DebugMessage(M64MSG_ERROR, "GetImageInfoFromFile() error: couldn't read first 8 bytes of file '%s'", pSrcFile);
948       fclose(f);
949       return 1;
950     }
951     fclose(f);
952
953     if(sig[0] == 'B' && sig[1] == 'M') // BMP
954     {
955         struct BMGImageStruct img;
956         memset(&img, 0, sizeof(BMGImageStruct));
957         BMG_Error code = ReadBMP(pSrcFile, &img);
958         if( code == BMG_OK )
959         {
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
969             FreeBMGImage(&img);
970             return 0;
971         }
972         DebugMessage(M64MSG_ERROR, "Couldn't read BMP file '%s'; error = %i", pSrcFile, code);
973         return 1;
974     }
975     else if(sig[0] == 137 && sig[1] == 'P' && sig[2] == 'N' && sig[3] == 'G' && sig[4] == '\r' && sig[5] == '\n' &&
976                sig[6] == 26 && sig[7] == '\n') // PNG
977     {
978         struct BMGImageStruct img;
979         memset(&img, 0, sizeof(BMGImageStruct));
980         BMG_Error code = ReadPNGInfo(pSrcFile, &img);
981         if( code == BMG_OK )
982         {
983             pSrcInfo->Width = img.width;
984             pSrcInfo->Height = img.height;
985             pSrcInfo->Depth = img.bits_per_pixel;
986             pSrcInfo->MipLevels = 1;
987             if(img.bits_per_pixel == 32)
988                 pSrcInfo->Format = SURFFMT_A8R8G8B8;
989             else if(img.bits_per_pixel == 8)
990                 pSrcInfo->Format = SURFFMT_P8;
991             // Resource and File Format ignored
992             FreeBMGImage(&img);
993             return 0;
994         }
995         DebugMessage(M64MSG_ERROR, "Couldn't read PNG file '%s'; error = %i", pSrcFile, code);
996         return 1;
997     }
998
999     DebugMessage(M64MSG_ERROR, "GetImageInfoFromFile : unknown file format (%s)", pSrcFile);
1000     return 1;
1001 }
1002
1003 BOOL PathFileExists(char* pszPath)
1004 {
1005     FILE *f;
1006     f = fopen(pszPath, "rb");
1007     if(f != NULL)
1008     {
1009         fclose(f);
1010         return TRUE;
1011     }
1012     return FALSE;
1013 }
1014
1015 /********************************************************************************************************************
1016  * Truncates the current list with information about hires textures and scans the hires folder for hires textures and
1017  * creates a list with records of properties of the hires textures.
1018  * parameter:
1019  * foldername: the folder that should be scaned for valid hires textures.
1020  * infos: a pointer that will point to the list containing the records with the infos about the found hires textures.
1021  *        In case of enabled caching, these records will also contain the actual textures.
1022  * extraCheck: ?
1023  * bRecursive: flag that indicates if also subfolders should be scanned for hires textures
1024  * bCacheTextures: flag that indicates if the identified hires textures should also be cached
1025  * bMainFolder: indicates if the folder is the main folder that will be scanned. That way, texture counting does not
1026  *              start at 1 each time a subfolder is accessed. (microdev: I know that is not important but it really
1027  *              bugged me ;-))
1028  * return:
1029  * infos: the list with the records of the identified hires textures. Be aware that these records also contains the
1030  *        actual textures if caching is enabled.
1031  ********************************************************************************************************************/
1032 void FindAllTexturesFromFolder(char *foldername, CSortedList<uint64,ExtTxtrInfo> &infos, bool extraCheck, bool bRecursive)
1033 {
1034     // check if folder actually exists
1035     if (!osal_is_directory(foldername))
1036         return;
1037
1038     // the path of the texture
1039     char texturefilename[PATH_MAX];
1040     //
1041     IMAGE_INFO  imgInfo;
1042     //
1043     IMAGE_INFO  imgInfo2;
1044
1045     void *dir;
1046     dir = osal_search_dir_open(foldername);
1047     const char *foundfilename;
1048
1049     int crc, palcrc32;
1050     unsigned int fmt, siz;
1051     char crcstr[16], crcstr2[16];
1052
1053     do
1054     {
1055         foundfilename = osal_search_dir_read_next(dir);
1056
1057         // The array is empty,  break the current operation
1058         if (foundfilename == NULL)
1059             break;
1060         // The current file is a hidden one
1061         if (foundfilename[0] == '.' )
1062             // These files we don't need
1063             continue;
1064
1065         // Get the folder name
1066         strcpy(texturefilename, foldername);
1067         // And append the file name
1068         strcat(texturefilename, foundfilename);
1069
1070         // Check if the current file is a directory and if recursive scanning is enabled
1071         if (osal_is_directory(texturefilename) && bRecursive )
1072         {
1073             // Add file-separator
1074             strcat(texturefilename, OSAL_DIR_SEPARATOR_STR);
1075             // Scan detected folder for hires textures (recursive call)
1076             FindAllTexturesFromFolder(texturefilename, infos, extraCheck, bRecursive);
1077             continue;
1078         }
1079         // well, the current file is actually no file (probably a directory & recursive scanning is not enabled)
1080         if( strstr(foundfilename,(const char*)g_curRomInfo.szGameName) == 0 )
1081             // go on with the next one
1082             continue;
1083
1084         TextureType type = NO_TEXTURE;
1085         bool bSeparatedAlpha = false;
1086
1087         // Detect the texture type by it's extention
1088         // microdev: this is not the smartest way. Should be done by header analysis if possible
1089         if( strcasecmp(right(foundfilename,7), "_ci.bmp") == 0 )
1090         {
1091             // Identify type
1092             if( GetImageInfoFromFile(texturefilename, &imgInfo) != 0)
1093             {
1094                 DebugMessage(M64MSG_WARNING, "Cannot get image info for file: %s", foundfilename);
1095                 continue;
1096             }
1097
1098             if( imgInfo.Format == SURFFMT_P8 )
1099                 // and store it to the record
1100                 type = COLOR_INDEXED_BMP;
1101             else
1102                 // Type is not supported, go on with the next one
1103                 continue;
1104         }
1105         // Detect the texture type by its extention
1106         else if( strcasecmp(right(foundfilename,13), "_ciByRGBA.png") == 0 )
1107         {
1108             // Identify type
1109             if( GetImageInfoFromFile(texturefilename, &imgInfo) != 0 )
1110             {
1111                 DebugMessage(M64MSG_WARNING, "Cannot get image info for file: %s", foundfilename);
1112                 continue;
1113             }
1114
1115             if( imgInfo.Format == SURFFMT_A8R8G8B8 )
1116                 // and store it to the record
1117                 type = RGBA_PNG_FOR_CI;
1118             else
1119                 // Type is not supported, go on with the next one
1120                 continue;
1121         }
1122         // Detect the texture type by its extention
1123         else if( strcasecmp(right(foundfilename,16), "_allciByRGBA.png") == 0 )
1124         {
1125             // Identify type
1126             if( GetImageInfoFromFile(texturefilename, &imgInfo) != 0 )
1127             {
1128                 DebugMessage(M64MSG_WARNING, "Cannot get image info for file: %s", foundfilename);
1129                 continue;
1130             }
1131             if( imgInfo.Format == SURFFMT_A8R8G8B8 )
1132                 // and store it to the record
1133                 type = RGBA_PNG_FOR_ALL_CI;
1134             else
1135                 // Type not supported, go on with next one
1136                 continue;
1137         }
1138         // Detect the texture type by its extention
1139         else if( strcasecmp(right(foundfilename,8), "_rgb.png") == 0 )
1140         {
1141             // Identify type
1142             if( GetImageInfoFromFile(texturefilename, &imgInfo) != 0 )
1143             {
1144                 DebugMessage(M64MSG_WARNING, "Cannot get image info for file: %s", foundfilename);
1145                 continue;
1146             }
1147
1148             // Store type to the record
1149             type = RGB_PNG;
1150
1151             char filename2[PATH_MAX];
1152             // Assemble the file name for the separate alpha channel file
1153             strcpy(filename2,texturefilename);
1154             strcpy(filename2+strlen(filename2)-8,"_a.png");
1155             // Check if the file actually exists
1156             if( PathFileExists(filename2) )
1157             {
1158                 // Check if the file with this name is actually a texture (well an alpha channel one)
1159                 if( GetImageInfoFromFile(filename2, &imgInfo2) != 0 )
1160                 {
1161                     // Nope, it isn't. => Go on with the next file
1162                     DebugMessage(M64MSG_WARNING, "Cannot get image info for file: %s", filename2);
1163                     continue;
1164                 }
1165                 
1166                 // Yes it is a texture file. Check if the size of the alpha channel is the same as the one of the texture
1167                 if( extraCheck && (imgInfo2.Width != imgInfo.Width || imgInfo2.Height != imgInfo.Height) )
1168                 {
1169                     // Nope, it isn't => go on with next file
1170                     DebugMessage(M64MSG_WARNING, "RGB and alpha texture size mismatch: %s", filename2);
1171                     continue;
1172                 }
1173
1174                 bSeparatedAlpha = true;
1175             }
1176         }
1177         // Detect the texture type by its extention
1178         else if( strcasecmp(right(foundfilename,8), "_all.png") == 0 )
1179         {
1180             // Check if texture is of expected type
1181             if( GetImageInfoFromFile(texturefilename, &imgInfo) != 0 )
1182             {
1183                 DebugMessage(M64MSG_WARNING, "Cannot get image info for file: %s", foundfilename);
1184                 // Nope, continue with next file
1185                 continue;
1186             }
1187
1188             // Indicate file type
1189             type = RGB_WITH_ALPHA_TOGETHER_PNG;
1190         }
1191     
1192         // If a known texture format has been detected...
1193         if( type != NO_TEXTURE )
1194         {
1195         /*
1196             Try to read image information here.
1197
1198             (CASTLEVANIA2)#(58E2333F)#(2)#(0)#(D7A5C6D9)_ciByRGBA.png
1199             (------1-----)#(---2----)#(3)#(4)#(---5----)_ciByRGBA.png
1200  
1201             1. Internal ROM name
1202             2. The DRAM CRC
1203             3. The image pixel size (8b=0, 16b=1, 24b=2, 32b=3)
1204             4. The texture format (RGBA=0, YUV=1, CI=2, IA=3, I=4)
1205             5. The palette CRC
1206
1207             <internal Rom name>#<DRAM CRC>#<24bit>#<RGBA>#<PAL CRC>_ciByRGBA.png
1208             */
1209
1210             // Get the actual file name
1211             strcpy(texturefilename, foundfilename);
1212             // Place the pointer before the DRAM-CRC (first occurrence of '#')
1213             char *ptr = strchr(texturefilename,'#');
1214             // Terminate the string ('0' means end of string - or in this case begin of string)
1215             *ptr++ = 0;
1216             if( type == RGBA_PNG_FOR_CI )
1217             {
1218                 // Extract the information from the file name; information is:
1219                 // <DRAM(or texture)-CRC><texture type><texture format><PAL(or palette)-CRC>
1220                 sscanf(ptr,"%8c#%d#%d#%8c", crcstr, &fmt, &siz,crcstr2);
1221                 // Terminate the ascii represntation of the palette crc
1222                 crcstr2[8] = 0;
1223                 // Transform the ascii presentation of the hex value to an unsigned integer
1224                 palcrc32 = strtoul(crcstr2,NULL,16);
1225             }
1226             else
1227             {
1228                 // Extract the information from the file name - this file does not have a palette crc; information is:
1229                 // <DRAM(or texture)-CRC><texture type><texture format>
1230                 // o gosh, commenting source code is really boring - but necessary!! Thus do it! (and don't use drugs ;-))
1231                 sscanf(ptr,"%8c#%d#%d", crcstr, &fmt, &siz);
1232                 // Use dummy for palette crc - that way each texture can be handled in a heterogeneous way
1233                 palcrc32 = 0xFFFFFFFF;
1234             }
1235             // Terminate the ascii represntation of the texture crc
1236             crcstr[8]=0;
1237             // Transform the ascii presentation of the hex value to an unsigned integer
1238             crc = strtoul(crcstr,NULL,16);
1239             // For the detection of an existing item
1240
1241             int foundIdx = -1;
1242             for( int k=0; k<infos.size(); k++)
1243             {
1244                 // Check if texture already exists in the list
1245                 // microdev: that's why I somehow love documenting code: that makes the implementation of a WIP folder check
1246                 // fucking easy :-)
1247                 if( infos[k].crc32 == crc && infos[k].pal_crc32 == palcrc32 )
1248                 {
1249                     // Indeeed, the texture already exists
1250                     // microdev: MAYBE ADD CODE TO MOVE IT TO A 'DUBLICATE' FOLDER TO EASE WORK OF RETEXTURERS
1251                     foundIdx = k;
1252                     break;
1253                 }
1254             }
1255
1256             if( foundIdx < 0 || type != infos[foundIdx].type)
1257             {
1258                 // Create a new entry
1259                 ExtTxtrInfo newinfo;
1260                 // Store the width
1261                 newinfo.width = imgInfo.Width;
1262                 // Store the height
1263                 newinfo.height = imgInfo.Height;
1264                 // Store the name of the folder it has been found in
1265                 //strcpy(newinfo.name,g_curRomInfo.szGameName);
1266                 newinfo.foldername = new char[strlen(foldername)+1];
1267                 strcpy(newinfo.foldername,foldername);
1268                 // store the filename
1269                 newinfo.filename = strdup(foundfilename);
1270                 newinfo.filename_a = NULL;
1271                 // Store the format
1272                 newinfo.fmt = fmt;
1273                 // Store the size (bit-size, not texture size)
1274                 newinfo.siz = siz;
1275                 // Store DRAM (texture) CRC
1276                 newinfo.crc32 = crc;
1277                 // Store PAL (palette) CRC (the actual one, or the dummy value ('FFFFFFFF'))
1278                 newinfo.pal_crc32 = palcrc32;
1279                 // Store the texture type
1280                 newinfo.type = type;
1281                 //Indicate if there is a separate alpha file that has to be loaded
1282                 newinfo.bSeparatedAlpha = bSeparatedAlpha;
1283                 if (bSeparatedAlpha) {
1284                     char filename2[PATH_MAX];
1285                     strcpy(filename2, foundfilename);
1286                     strcpy(filename2+strlen(filename2)-8,"_a.png");
1287                     newinfo.filename_a = strdup(filename2);
1288                 }
1289                 // Generate the key for the record describing the hires texture.
1290                 // This key is used to find it back in the list
1291                 // The key format is: <DRAM(texture)-CRC-8byte><PAL(palette)-CRC-6byte(2bytes have been truncated to have space for format and size)><format-1byte><size-1byte>
1292                 uint64 crc64 = newinfo.crc32;
1293                 crc64 <<= 32;
1294                 if (options.bLoadHiResCRCOnly)
1295                     crc64 |= newinfo.pal_crc32&0xFFFFFFFF;
1296                 else
1297                     crc64 |= (newinfo.pal_crc32&0xFFFFFF00)|(newinfo.fmt<<4)|newinfo.siz;
1298                 // Add the new record to the list
1299                 infos.add(crc64,newinfo);
1300             }
1301         }
1302     } while(foundfilename != NULL);
1303
1304     osal_search_dir_close(dir);
1305 }
1306 /********************************************************************************************************************
1307  * Checks if a folder is actually existant. If not, it tries to create this folder
1308  * parameter:
1309  * pathname: the name of the folder that should be checked or created if not existant
1310  * return:
1311  * return value: flag that indicates true if the folder is existant or could be created. If none was the case,
1312  *               false will be returned
1313  ********************************************************************************************************************/
1314
1315 bool CheckAndCreateFolder(const char* pathname)
1316 {
1317     // Check if provided folder already exists
1318     if( !PathFileExists((char*)pathname) )
1319     {
1320         // It didn't. Try creating it.
1321         if (osal_mkdirp(pathname, 0700) != 0)
1322         {
1323             // It didn't work (probably insufficient permissions or read-only media) ==> return false
1324             DebugMessage(M64MSG_WARNING, "Can not create new folder: %s", pathname);
1325             return false;
1326         }
1327     }
1328     // success
1329
1330     return true;
1331 }
1332 // microdev: THIS HAS TO BE CLEANED UP...
1333
1334
1335 // Texture dumping filenaming
1336 // GameName_FrameCount_CRC_Fmt_Siz.bmp
1337 // File format:     BMP
1338 // GameName:        N64 game internal name
1339 // CRC:             32 bit, 8 hex digits
1340 // Fmt:             0 - 4
1341 // Siz:             0 - 3
1342
1343 const char *subfolders[] = {
1344     "png_all",
1345     "png_by_rgb_a",
1346     "ci_bmp",
1347     "ci_bmp_with_pal_crc",
1348     "ci_by_png",
1349 };
1350
1351 void FindAllDumpedTextures(void)
1352 {
1353     char    foldername[PATH_MAX + 64];
1354     strncpy(foldername, ConfigGetUserDataPath(), PATH_MAX);
1355     foldername[PATH_MAX] = 0;
1356
1357     if (foldername[strlen(foldername) - 1] != OSAL_DIR_SEPARATOR_CHAR)
1358         strcat(foldername, OSAL_DIR_SEPARATOR_STR);
1359     strcat(foldername,"texture_dump" OSAL_DIR_SEPARATOR_STR);
1360
1361     CheckAndCreateFolder(foldername);
1362
1363     strcat(foldername,(const char*)g_curRomInfo.szGameName);
1364     strcat(foldername, OSAL_DIR_SEPARATOR_STR);
1365
1366     gTxtrDumpInfos.clear();
1367     if( !PathFileExists(foldername) )
1368     {
1369         CheckAndCreateFolder(foldername);
1370         char    foldername2[PATH_MAX];
1371         for( int i=0; i<5; i++)
1372         {
1373             strcpy(foldername2,foldername);
1374             strcat(foldername2,subfolders[i]);
1375             CheckAndCreateFolder(foldername2);
1376         }
1377         return;
1378     }
1379     else
1380     {
1381         gTxtrDumpInfos.clear();
1382         FindAllTexturesFromFolder(foldername,gTxtrDumpInfos, false, true);
1383
1384         char    foldername2[PATH_MAX];
1385         for( int i=0; i<5; i++)
1386         {
1387             strcpy(foldername2,foldername);
1388             strcat(foldername2,subfolders[i]);
1389             CheckAndCreateFolder(foldername2);
1390         }
1391     }
1392 }
1393
1394 /********************************************************************************************************************
1395  * Truncates the current list with information about hires textures and scans the hires folder for hires textures and
1396  * creates a list with records of properties of the hires textures.
1397  * parameter:
1398  * none
1399  * return:
1400  * none
1401  ********************************************************************************************************************/
1402 void FindAllHiResTextures(void)
1403 {
1404     char    foldername[PATH_MAX + 64];
1405     strncpy(foldername, ConfigGetUserDataPath(), PATH_MAX);
1406     foldername[PATH_MAX] = 0;
1407
1408     // Assure that a backslash exists at the end (should be handled by GetPluginDir())
1409     if(foldername[strlen(foldername) - 1] != OSAL_DIR_SEPARATOR_CHAR)
1410         strcat(foldername, OSAL_DIR_SEPARATOR_STR);
1411     // Add the relative path to the hires folder
1412     strcat(foldername,"hires_texture" OSAL_DIR_SEPARATOR_STR);
1413     // It does not exist? => Create it
1414     CheckAndCreateFolder(foldername);
1415
1416     // Add the path to a sub-folder corresponding to the rom name
1417     // HOOK IN: PACK SELECT
1418     strcat(foldername,(const char*)g_curRomInfo.szGameName);
1419     strcat(foldername, OSAL_DIR_SEPARATOR_STR);
1420     // Truncate the current list with the hires texture info
1421     gHiresTxtrInfos.clear();
1422     if (!osal_is_directory(foldername))
1423     {
1424         DebugMessage(M64MSG_WARNING, "Couldn't open hi-res texture directory: %s", foldername);
1425         return;
1426     }
1427     else
1428     {
1429         // Find all hires textures and also cache them if configured to do so
1430         FindAllTexturesFromFolder(foldername,gHiresTxtrInfos, true, true);
1431     }
1432 }
1433
1434 void CloseHiresTextures(void)
1435 {
1436     for( int i=0; i<gHiresTxtrInfos.size(); i++)
1437     {
1438         if( gHiresTxtrInfos[i].foldername )
1439             delete [] gHiresTxtrInfos[i].foldername;
1440         if( gHiresTxtrInfos[i].filename )
1441             delete [] gHiresTxtrInfos[i].filename;
1442         if( gHiresTxtrInfos[i].filename_a )
1443             delete [] gHiresTxtrInfos[i].filename_a;
1444     }
1445
1446     gHiresTxtrInfos.clear();
1447 }
1448
1449 void CloseTextureDump(void)
1450 {
1451     for( int i=0; i<gTxtrDumpInfos.size(); i++)
1452     {
1453         if( gTxtrDumpInfos[i].foldername )  
1454             delete [] gTxtrDumpInfos[i].foldername;
1455         if( gTxtrDumpInfos[i].filename )
1456             delete [] gTxtrDumpInfos[i].filename;
1457         if( gTxtrDumpInfos[i].filename_a )
1458             delete [] gTxtrDumpInfos[i].filename_a;
1459     }
1460
1461     gTxtrDumpInfos.clear();
1462 }
1463
1464 void CloseExternalTextures(void)
1465 {
1466     CloseHiresTextures();
1467     CloseTextureDump();
1468 }
1469
1470 /********************************************************************************************************************
1471  * Scans the hires folder for hires textures and creates a list with records of properties of the hires textures.
1472  * in case of enabled hires caching also the actual hires textures will be added to the record. Before textures will
1473  * be loaded, existing list of texture information will be truncated.
1474  * parameter:
1475  * bWIPFolder: Indicates if all textures should be inited or just the WIP folder. Just the content of the WIP folder
1476  *             will be reloaded if a savestate has been loaded or if there has been a switch between window and full-
1477  *             screen mode. (Not implemented yet)
1478  * return:
1479  * none
1480  ********************************************************************************************************************/
1481 void InitHiresTextures(void)
1482 {
1483     if( options.bLoadHiResTextures )
1484     {
1485         DebugMessage(M64MSG_INFO, "Texture loading option is enabled. Finding all hires textures");
1486         FindAllHiResTextures();
1487     }
1488 }
1489
1490 void InitTextureDump(void)
1491 {
1492     if( options.bDumpTexturesToFiles )
1493     {
1494         DebugMessage(M64MSG_INFO, "Texture dump option is enabled. Finding all dumpped textures");
1495         FindAllDumpedTextures();
1496     }
1497 }
1498
1499 /********************************************************************************************************************
1500  * Inits the hires textures. For doing so, all hires textures info & the cached textures (for dumping and the hires ones)
1501  * are deleted. Afterwards they are reloaded from file system. This only takes place if a new rom has been loaded.
1502  * parameter:
1503  * none
1504  * return:
1505  * none
1506  ********************************************************************************************************************/
1507 void InitExternalTextures(void)
1508 {
1509     DebugMessage(M64MSG_VERBOSE, "InitExternalTextures");
1510     // remove all hires & dump textures from cache
1511     CloseExternalTextures();
1512     // reload and recache hires textures
1513     InitHiresTextures();
1514     // prepare list of already dumped textures (for avoiding to redump them). Available hires textures will
1515     // also be excluded from dumping
1516     InitTextureDump();
1517 }
1518
1519 /********************************************************************************************************************
1520  * Determines the scale factor for resizing the original texture to the hires replacement. The scale factor is a left
1521  * shift. That means scale factor 1 = size(original texture)*2= size(hires texture),
1522  * factor 2 = size(original texture)*4= size(hires texture), etc. (I'm not yet sure why it has to be 2^x. Most probably
1523  * because of block size. Has to be further determined.
1524  * parameter:
1525  * info: the record describing the external texture
1526  * entry: the original texture in the texture cache
1527  * return:
1528  * info.scaleShift: the value for left shift the original texture size to the corresponding hires texture size
1529  * return value: the value for left shift the original texture size to the corresponding hires texture size.
1530  *               The function returns -1 if the dimensions of the hires texture are not a power of two of the
1531  *               original texture.
1532  ********************************************************************************************************************/
1533 int FindScaleFactor(const ExtTxtrInfo &info, TxtrCacheEntry &entry)
1534 {
1535     // init scale shift
1536     int scaleShift = 0;
1537     // check if the original texture dimensions (x and y) scaled with the current shift is still smaller or of the same size as the hires one
1538     while(info.height >= entry.ti.HeightToLoad*(1<<scaleShift)  && info.width >= entry.ti.WidthToLoad*(1<<scaleShift))
1539     {
1540         // check if the original texture dimensions (x and y)scaled with the current shift have the same size as the hires one
1541         if(info.height == entry.ti.HeightToLoad*(1<<scaleShift)  && info.width == entry.ti.WidthToLoad*(1<<scaleShift))
1542             // found appropriate scale shift, return it
1543             return scaleShift;
1544
1545         scaleShift++;
1546     }
1547
1548     // original texture dimensions (x or y or both) scaled with the last scale shift have become larger than the dimensions
1549     // of the hires texture. That means the dimensions of the hires replacement are not power of 2 of the original texture.
1550     // Therefore indicate a crop shift (or -1 when the hires_texture was smaller from the beginning)
1551     scaleShift -= 1;
1552     return scaleShift;
1553 }
1554
1555
1556 /********************************************************************************************************************
1557  * Checks if a hires replacement for a texture is available.
1558  * parameter:
1559  * infos: The list of external textures
1560  * entry: the original texture in the texture cache
1561  * return:
1562  * indexa: returns the index in "infos" where a hires replacement for a texture without
1563  *         palette crc or a RGBA_PNG_FOR_ALL_CI texture has been found
1564  * return value: the index in "infos" where the corresponding hires texture has been found
1565  ********************************************************************************************************************/
1566 int CheckTextureInfos( CSortedList<uint64,ExtTxtrInfo> &infos, TxtrCacheEntry &entry, int &indexa, int &scaleShift, bool bForDump = false)
1567 {
1568     if ((entry.ti.WidthToLoad  != 0 && entry.ti.WidthToCreate  / entry.ti.WidthToLoad  > 2) ||
1569         (entry.ti.HeightToLoad != 0 && entry.ti.HeightToCreate / entry.ti.HeightToLoad > 2 ))
1570     {
1571         //DebugMessage(M64MSG_WARNING, "Hires texture does not support extreme texture replication");
1572         return -1;
1573     }
1574     // determine if texture is a color-indexed (CI) texture
1575
1576     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;
1577     // generate two alternative ids
1578
1579     uint64 crc64a = entry.dwCRC;
1580     crc64a <<= 32;
1581     uint64 crc64b = crc64a;
1582     if (options.bLoadHiResCRCOnly) {
1583         crc64a |= (0xFFFFFFFF);
1584         crc64b |= (entry.dwPalCRC&0xFFFFFFFF);
1585     } else {
1586         crc64a |= (0xFFFFFF00|(entry.ti.Format<<4)|entry.ti.Size);
1587         crc64b |= ((entry.dwPalCRC&0xFFFFFF00)|(entry.ti.Format<<4)|entry.ti.Size);
1588     }
1589
1590     // infos is the list containing the references to the detected external textures
1591     // get the number of items contained in this list
1592     int infosize = infos.size();
1593     int indexb=-1;
1594     // try to identify the external texture that
1595     // corresponds to the original texture
1596     indexa = infos.find(crc64a);        // For CI without pal CRC, and for RGBA_PNG_FOR_ALL_CI
1597     if( bCI )   
1598         // and also for textures with separate alpha channel
1599         indexb = infos.find(crc64b);    // For CI or PNG with pal CRC
1600
1601     // did not found the ext. text.
1602     if( indexa >= infosize )
1603         indexa = -1;
1604     // did not found the ext. text. w/ sep. alpha channel
1605     if( indexb >= infosize )
1606         indexb = -1;
1607
1608     scaleShift = -1;
1609
1610     // found texture with sep. alpha channel
1611
1612     if( indexb >= 0 )
1613     {
1614         // determine the factor for scaling
1615         scaleShift = FindScaleFactor(infos[indexb], entry);
1616         // ok. the scale factor is supported. A valid replacement has been found
1617         if( scaleShift >= 0 )
1618             return indexb;
1619     }
1620     // if texture is 4bit, should be dumped and there is no match in the list of external textures
1621
1622     if( bForDump && bCI && indexb < 0)
1623         // than return that there is no replacement & therefore texture can be dumped (microdev: not sure about that...)
1624         return -1;
1625
1626     // texture has no separate alpha channel, try to find it in the ext. text. list
1627     if( indexa >= 0 )
1628         scaleShift = FindScaleFactor(infos[indexa], entry);
1629     // ok. the scale factor is supported. A valid replacement has been found
1630     // this is a texture without ext. alpha channel
1631
1632     if( scaleShift >= 0 )
1633         return indexa;
1634     // no luck at all. there is no valid replacement
1635     else
1636         return -1;
1637 }
1638
1639 bool SaveCITextureToFile(TxtrCacheEntry &entry, char *filename, bool bShow, bool bWhole);
1640
1641 void DumpCachedTexture( TxtrCacheEntry &entry )
1642 {
1643     char cSep = '/';
1644
1645     CTexture *pSrcTexture = entry.pTexture;
1646     if( pSrcTexture )
1647     {
1648         // Check the vector table
1649         int ciidx, scaleShift;
1650         if( CheckTextureInfos(gTxtrDumpInfos,entry,ciidx,scaleShift,true) >= 0 )
1651             return;     // This texture has been dumpped
1652
1653         char filename1[PATH_MAX + 64];
1654         char filename2[PATH_MAX + 64];
1655         char filename3[PATH_MAX + 64];
1656         char gamefolder[PATH_MAX + 64];
1657         strncpy(gamefolder, ConfigGetUserDataPath(), PATH_MAX);
1658         gamefolder[PATH_MAX] = 0;
1659         
1660         strcat(gamefolder,"texture_dump" OSAL_DIR_SEPARATOR_STR);
1661         strcat(gamefolder,(const char*)g_curRomInfo.szGameName);
1662         strcat(gamefolder, OSAL_DIR_SEPARATOR_STR);
1663
1664         //sprintf(filename1+strlen(filename1), "%08X#%d#%d", entry.dwCRC, entry.ti.Format, entry.ti.Size);
1665         sprintf(filename1, "%s%s#%08X#%d#%d", gamefolder, g_curRomInfo.szGameName, entry.dwCRC, entry.ti.Format, entry.ti.Size);
1666
1667         if( (gRDP.otherMode.text_tlut>=2 || entry.ti.Format == TXT_FMT_CI || entry.ti.Format == TXT_FMT_RGBA) && entry.ti.Size <= TXT_SIZE_8b )
1668         {
1669             if( ciidx < 0 )
1670             {
1671                 sprintf(filename1, "%sci_bmp%c%s#%08X#%d#%d_ci", gamefolder, cSep, g_curRomInfo.szGameName, entry.dwCRC, entry.ti.Format, entry.ti.Size);
1672                 SaveCITextureToFile(entry, filename1, false, false);
1673             }
1674
1675             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);
1676             SaveCITextureToFile(entry, filename1, false, false);
1677
1678             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);
1679             CRender::g_pRender->SaveTextureToFile(*pSrcTexture, filename1, TXT_RGBA, false, false, entry.ti.WidthToLoad, entry.ti.HeightToLoad);
1680         }
1681         else
1682         {
1683             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);
1684             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);
1685             sprintf(filename3, "%spng_all%c%s#%08X#%d#%d_all", gamefolder, cSep, g_curRomInfo.szGameName, entry.dwCRC, entry.ti.Format, entry.ti.Size);
1686
1687
1688             CRender::g_pRender->SaveTextureToFile(*pSrcTexture, filename1, TXT_RGB, false, false, entry.ti.WidthToLoad, entry.ti.HeightToLoad);
1689             CRender::g_pRender->SaveTextureToFile(*pSrcTexture, filename3, TXT_RGBA, false, false, entry.ti.WidthToLoad, entry.ti.HeightToLoad);
1690             if( entry.ti.Format != TXT_FMT_I )
1691             {
1692                 DrawInfo srcInfo;   
1693                 uint32 aFF = 0xFF;
1694                 if( pSrcTexture->StartUpdate(&srcInfo) )
1695                 {
1696                     // Copy RGB to buffer
1697                     for( int i=entry.ti.HeightToLoad-1; i>=0; i--)
1698                     {
1699                         unsigned char *pSrc = (unsigned char*)srcInfo.lpSurface+srcInfo.lPitch * i;
1700                         for( uint32 j=0; j<entry.ti.WidthToLoad; j++)
1701                         {
1702                             aFF &= pSrc[3];
1703                             pSrc += 4;
1704                         }
1705                     }
1706                     pSrcTexture->EndUpdate(&srcInfo);
1707                 }
1708
1709                 if( aFF != 0xFF)
1710                     CRender::g_pRender->SaveTextureToFile(*pSrcTexture, filename2, TXT_ALPHA, false, false);
1711             }       
1712         }
1713
1714         ExtTxtrInfo newinfo;
1715         newinfo.width = entry.ti.WidthToLoad;
1716         newinfo.height = entry.ti.HeightToLoad;
1717         //strcpy(newinfo.name,g_curRomInfo.szGameName);
1718         newinfo.fmt = entry.ti.Format;
1719         newinfo.siz = entry.ti.Size;
1720         newinfo.crc32 = entry.dwCRC;
1721
1722         newinfo.pal_crc32 = entry.dwPalCRC;
1723         newinfo.foldername = NULL;
1724         newinfo.filename = NULL;
1725         newinfo.filename_a = NULL;
1726         newinfo.type = NO_TEXTURE;
1727         newinfo.bSeparatedAlpha = false;
1728
1729         uint64 crc64 = newinfo.crc32;
1730         crc64 <<= 32;
1731         if (options.bLoadHiResCRCOnly)
1732             crc64 |= newinfo.pal_crc32&0xFFFFFFFF;
1733         else
1734             crc64 |= (newinfo.pal_crc32&0xFFFFFF00)|(newinfo.fmt<<4)|newinfo.siz;
1735         gTxtrDumpInfos.add(crc64,newinfo);
1736
1737     }
1738 }
1739
1740 bool LoadRGBBufferFromPNGFile(char *filename, unsigned char **pbuf, int &width, int &height, int bits_per_pixel = 24 )
1741 {
1742     struct BMGImageStruct img;
1743     memset(&img, 0, sizeof(BMGImageStruct));
1744     if (!PathFileExists(filename))
1745     {
1746         DebugMessage(M64MSG_ERROR, "File at '%s' doesn't exist in LoadRGBBufferFromPNGFile!", filename);
1747         return false;
1748     }
1749
1750     BMG_Error code = ReadPNG( filename, &img );
1751     if( code == BMG_OK )
1752     {
1753         *pbuf = NULL;
1754
1755         *pbuf = new unsigned char[img.width*img.height*bits_per_pixel/8];
1756         if (*pbuf == NULL)
1757         {
1758             DebugMessage(M64MSG_ERROR, "new[] returned NULL for image width=%i height=%i bpp=%i", img.width, img.height, bits_per_pixel);
1759             return false;
1760         }
1761         if (img.bits_per_pixel == bits_per_pixel)
1762         {
1763             memcpy(*pbuf, img.bits, img.width*img.height*bits_per_pixel/8);
1764         }
1765         else if (img.bits_per_pixel == 24 && bits_per_pixel == 32)
1766         {
1767             unsigned char *pSrc = img.bits;
1768             unsigned char *pDst = *pbuf;
1769             for (int i = 0; i < (int)(img.width*img.height); i++)
1770             {
1771                 *pDst++ = *pSrc++;
1772                 *pDst++ = *pSrc++;
1773                 *pDst++ = *pSrc++;
1774                 *pDst++ = 0;
1775             }
1776         }
1777         // loaded image has alpha, needed image has to be without alpha channel
1778         else if (img.bits_per_pixel == 32 && bits_per_pixel == 24)
1779         {
1780             // pointer to source image data
1781             unsigned char *pSrc = img.bits;
1782             // buffer for destination image
1783             unsigned char *pDst = *pbuf;
1784             // copy data of the loaded image to the buffer by skipping the alpha byte
1785             for (int i = 0; i < (int)(img.width*img.height); i++)
1786             {
1787                 // copy R
1788                 *pDst++ = *pSrc++;
1789                 // copy G
1790                 *pDst++ = *pSrc++;
1791                 // copy B
1792                 *pDst++ = *pSrc++;
1793                 // skip the alpha byte of the loaded image
1794                 pSrc++;
1795             }
1796         }
1797         else if (img.bits_per_pixel == 8 && (bits_per_pixel == 24 || bits_per_pixel == 32))
1798         {
1799             // do palette lookup and convert 8bpp to 24/32bpp
1800             int destBytePP = bits_per_pixel / 8;
1801             int paletteBytePP = img.bytes_per_palette_entry;
1802             unsigned char *pSrc = img.bits;
1803             unsigned char *pDst = *pbuf;
1804             // clear the destination image data (just to clear alpha if bpp=32)
1805             memset(*pbuf, 0, img.width*img.height*destBytePP);
1806             for (int i = 0; i < (int)(img.width*img.height); i++)
1807             {
1808                 unsigned char clridx = *pSrc++;
1809                 unsigned char *palcolor = img.palette + clridx * paletteBytePP;
1810                 pDst[0] = palcolor[2]; // red
1811                 pDst[1] = palcolor[1]; // green
1812                 pDst[2] = palcolor[0]; // blue
1813                 pDst += destBytePP;
1814             }
1815         }
1816         else
1817         {
1818             DebugMessage(M64MSG_ERROR, "PNG file '%s' is %i bpp but texture is %i bpp.", filename, img.bits_per_pixel, bits_per_pixel);
1819             delete [] *pbuf;
1820             *pbuf = NULL;
1821         }
1822
1823         width = img.width;
1824         height = img.height;
1825         FreeBMGImage(&img);
1826
1827         return true;
1828     }
1829     else
1830     {
1831         DebugMessage(M64MSG_ERROR, "ReadPNG() returned error for '%s' in LoadRGBBufferFromPNGFile!", filename);
1832         *pbuf = NULL;
1833         return false;
1834     }
1835 }
1836
1837 bool LoadRGBABufferFromColorIndexedFile(char *filename, TxtrCacheEntry &entry, unsigned char **pbuf, int &width, int &height)
1838 {
1839     BITMAPFILEHEADER fileHeader;
1840     BITMAPINFOHEADER infoHeader;
1841
1842     FILE *f;
1843     f = fopen(filename, "rb");
1844     if(f != NULL)
1845     {
1846         if (fread(&fileHeader, sizeof(BITMAPFILEHEADER), 1, f) != 1 ||
1847             fread(&infoHeader, sizeof(BITMAPINFOHEADER), 1, f) != 1)
1848         {
1849             DebugMessage(M64MSG_ERROR, "Couldn't read BMP headers in file '%s'", filename);
1850             return false;
1851         }
1852
1853         if( infoHeader.biBitCount != 4 && infoHeader.biBitCount != 8 )
1854         {
1855             fclose(f);
1856             DebugMessage(M64MSG_ERROR, "Unsupported BMP file format: %s", filename);
1857             *pbuf = NULL;
1858             return false;
1859         }
1860
1861         int tablesize = infoHeader.biBitCount == 4 ? 16 : 256;
1862         uint32 *pTable = new uint32[tablesize];
1863         if (fread(pTable, tablesize*4, 1, f) != 1)
1864         {
1865             DebugMessage(M64MSG_ERROR, "Couldn't read BMP palette in file '%s'", filename);
1866             delete [] pTable;
1867             return false;
1868         }
1869
1870         // Create the pallette table
1871         uint16 * pPal = (uint16 *)entry.ti.PalAddress;
1872         if( entry.ti.Size == TXT_SIZE_4b )
1873         {
1874             // 4-bit table
1875             for( int i=0; i<16; i++ )
1876             {
1877                 pTable[i] = entry.ti.TLutFmt == TLUT_FMT_RGBA16 ? Convert555ToRGBA(pPal[i^1]) : ConvertIA16ToRGBA(pPal[i^1]);
1878             }
1879         }
1880         else
1881         {
1882             // 8-bit table
1883             for( int i=0; i<256; i++ )
1884             {
1885                 pTable[i] = entry.ti.TLutFmt == TLUT_FMT_RGBA16 ? Convert555ToRGBA(pPal[i^1]) : ConvertIA16ToRGBA(pPal[i^1]);
1886             }
1887         }
1888
1889         *pbuf = new unsigned char[infoHeader.biWidth*infoHeader.biHeight*4];
1890         if( *pbuf )
1891         {
1892             unsigned char *colorIdxBuf = new unsigned char[infoHeader.biSizeImage];
1893             if( colorIdxBuf )
1894             {
1895                 if (fread(colorIdxBuf, infoHeader.biSizeImage, 1, f) != 1)
1896                 {
1897                     DebugMessage(M64MSG_ERROR, "Couldn't read BMP image data in file '%s'", filename);
1898                 }
1899
1900                 width = infoHeader.biWidth;
1901                 height = infoHeader.biHeight;
1902
1903                 // Converting pallette texture to RGBA texture
1904                 int idx = 0;
1905                 uint32 *pbuf2 = (uint32*) *pbuf;
1906
1907                 for( int i=height-1; i>=0; i--)
1908                 {
1909                     for( int j=0; j<width; j++)
1910                     {
1911                         if( entry.ti.Size == TXT_SIZE_4b )
1912                         {
1913                             // 4 bits
1914                             if( idx%2 )
1915                             {
1916                                 // 1
1917                                 *pbuf2++ = pTable[colorIdxBuf[(idx++)>>1]&0xF];
1918                             }
1919                             else
1920                             {
1921                                 // 0
1922                                 *pbuf2++ = pTable[(colorIdxBuf[(idx++)>>1]>>4)&0xF];
1923                             }
1924                         }
1925                         else
1926                         {
1927                             // 8 bits
1928                             *pbuf2++ = pTable[colorIdxBuf[idx++]];
1929                         }
1930                     }
1931                     if( entry.ti.Size == TXT_SIZE_4b )
1932                     {
1933                         if( idx%8 ) idx = (idx/8+1)*8;
1934                     }
1935                     else
1936                     {
1937                         if( idx%4 ) idx = (idx/4+1)*4;
1938                     }
1939                 }
1940
1941                 delete [] colorIdxBuf;
1942             }
1943             else
1944             {
1945                 TRACE0("Out of memory");
1946             }
1947
1948             delete [] pTable;
1949             return true;
1950         }
1951         else
1952         {
1953             fclose(f);
1954             delete [] pTable;
1955             return false;
1956         }
1957     }
1958     else
1959     {
1960         // Do something
1961         TRACE1("Fail to open file %s", filename);
1962         *pbuf = NULL;
1963         return false;
1964     }
1965 }
1966
1967 bool LoadRGBBufferFromBMPFile(char *filename, unsigned char **pbuf, int &width, int &height)
1968 {
1969     BITMAPFILEHEADER fileHeader;
1970     BITMAPINFOHEADER infoHeader;
1971
1972     FILE *f;
1973     f = fopen(filename, "rb");
1974     if(f != NULL)
1975     {
1976         if (fread(&fileHeader, sizeof(BITMAPFILEHEADER), 1, f) != 1 ||
1977             fread(&infoHeader, sizeof(BITMAPINFOHEADER), 1, f) != 1)
1978         {
1979             DebugMessage(M64MSG_ERROR, "Couldn't read BMP headers in file '%s'", filename);
1980             return false;
1981         }
1982
1983         if( infoHeader.biBitCount != 24 )
1984         {
1985             fclose(f);
1986             DebugMessage(M64MSG_ERROR, "Unsupported BMP file 16 bits format: %s", filename);
1987             *pbuf = NULL;
1988             return false;
1989         }
1990
1991         *pbuf = new unsigned char[infoHeader.biWidth*infoHeader.biHeight*3];
1992         if( *pbuf )
1993         {
1994             if (fread(*pbuf, infoHeader.biWidth*infoHeader.biHeight*3, 1, f) != 1)
1995                 DebugMessage(M64MSG_ERROR, "Couldn't read RGB BMP image data in file '%s'", filename);
1996             fclose(f);
1997             width = infoHeader.biWidth;
1998             height = infoHeader.biHeight;
1999             return true;
2000         }
2001         else
2002         {
2003             fclose(f);
2004             return false;
2005         }
2006     }
2007     else
2008     {
2009         // Do something
2010         DebugMessage(M64MSG_WARNING, "Fail to open file %s", filename);
2011         *pbuf = NULL;
2012         return false;
2013     }
2014 }
2015
2016 /*******************************************************
2017  * Loads the hires equivaltent of a texture
2018  * parameter:
2019  * TxtrCacheEntry: The original texture in the texture cache
2020  * return:
2021  * none
2022  *******************************************************/
2023 void LoadHiresTexture( TxtrCacheEntry &entry )
2024 {
2025     // check if the external texture has already been loaded
2026     if( entry.bExternalTxtrChecked )
2027         return;
2028     // there is already an enhanced texture (e.g. a filtered one)
2029
2030     if( entry.pEnhancedTexture )
2031     {
2032         // delete it from memory before loading the external one
2033         SAFE_DELETE(entry.pEnhancedTexture);
2034     }
2035
2036     int ciidx, scaleShift;
2037     // search the index of the appropriate hires replacement texture
2038     // in the list containing the infos of the external textures
2039     // ciidx is not needed here (just needed for dumping)
2040     int idx = CheckTextureInfos(gHiresTxtrInfos,entry,ciidx,scaleShift,false);
2041     if( idx < 0 )
2042     {
2043         // there is no hires replacement => indicate that
2044         entry.bExternalTxtrChecked = true;
2045         return;
2046     }
2047
2048     // Load the bitmap file
2049     char filename_rgb[PATH_MAX];
2050     char filename_a[PATH_MAX];
2051
2052     strcpy(filename_rgb, gHiresTxtrInfos[idx].foldername);
2053     strcat(filename_rgb, gHiresTxtrInfos[idx].filename);
2054
2055     if (gHiresTxtrInfos[idx].filename_a) {
2056         strcpy(filename_a, gHiresTxtrInfos[idx].foldername);
2057         strcat(filename_a, gHiresTxtrInfos[idx].filename_a);
2058     } else {
2059         strcpy(filename_a, "");
2060     }
2061
2062     // Load BMP image to buffer_rbg
2063     unsigned char *buf_rgba = NULL;
2064     unsigned char *buf_a = NULL;
2065     int width, height;
2066
2067     bool bResRGBA=false, bResA=false;
2068     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 );
2069
2070     switch( gHiresTxtrInfos[idx].type )
2071     {
2072         case RGB_PNG:
2073             if( bCI )   
2074                 return;
2075             else
2076             {
2077                 bResRGBA = LoadRGBBufferFromPNGFile(filename_rgb, &buf_rgba, width, height);
2078                 if( bResRGBA && gHiresTxtrInfos[idx].bSeparatedAlpha )
2079                     bResA = LoadRGBBufferFromPNGFile(filename_a, &buf_a, width, height);
2080             }
2081             break;
2082         case COLOR_INDEXED_BMP:
2083             if( bCI )   
2084                 bResRGBA = LoadRGBABufferFromColorIndexedFile(filename_rgb, entry, &buf_rgba, width, height);
2085             else
2086                 return;
2087             break;
2088         case RGBA_PNG_FOR_CI:
2089         case RGBA_PNG_FOR_ALL_CI:
2090             if( bCI )   
2091                 bResRGBA = LoadRGBBufferFromPNGFile(filename_rgb, &buf_rgba, width, height, 32);
2092             else
2093                 return;
2094             break;
2095         case RGB_WITH_ALPHA_TOGETHER_PNG:
2096             if( bCI )   
2097                 return;
2098             else
2099                 bResRGBA = LoadRGBBufferFromPNGFile(filename_rgb, &buf_rgba, width, height, 32);
2100             break;
2101         default:
2102             return;
2103     }
2104
2105     if( !bResRGBA || !buf_rgba )
2106     {
2107         DebugMessage(M64MSG_ERROR, "RGBBuffer creation failed for file '%s'.", filename_rgb);
2108         return;
2109     }
2110     // check if the alpha channel has been loaded if the texture has a separate alpha channel
2111     else if( gHiresTxtrInfos[idx].bSeparatedAlpha && !bResA )
2112     {
2113         DebugMessage(M64MSG_ERROR, "Alpha buffer creation failed for file '%s'.", filename_a);
2114         delete [] buf_rgba;
2115         return;
2116     }
2117
2118     // calculate the texture size magnification by comparing the N64 texture size and the hi-res texture size
2119     int scale = 1 << scaleShift;
2120     int mirrorx = 1;
2121     int mirrory = 1;
2122     int input_height_shift = height - entry.ti.HeightToLoad * scale;
2123     int input_pitch_a = width;
2124     int input_pitch_rgb = width;
2125     width = entry.ti.WidthToLoad * scale;
2126     height = entry.ti.HeightToLoad * scale;
2127     if (entry.ti.WidthToCreate/entry.ti.WidthToLoad == 2) mirrorx = 2;
2128     if (entry.ti.HeightToCreate/entry.ti.HeightToLoad == 2) mirrory = 2;
2129     entry.pEnhancedTexture = CDeviceBuilder::GetBuilder()->CreateTexture(entry.ti.WidthToCreate*scale, entry.ti.HeightToCreate*scale);
2130     DrawInfo info;
2131     
2132     if( entry.pEnhancedTexture && entry.pEnhancedTexture->StartUpdate(&info) )
2133     {
2134
2135         if( gHiresTxtrInfos[idx].type == RGB_PNG )
2136         {
2137             input_pitch_rgb *= 3;
2138             input_pitch_a *= 3;
2139
2140             if (info.lPitch < width * 4)
2141                 DebugMessage(M64MSG_ERROR, "Texture pitch %i less than width %i times 4", info.lPitch, width);
2142             if (height > info.dwHeight)
2143                 DebugMessage(M64MSG_ERROR, "Texture source height %i greater than destination height %i", height, info.dwHeight);
2144
2145             // Update the texture by using the buffer
2146             for( int i=0; i<height; i++)
2147             {
2148                 unsigned char *pRGB = buf_rgba + (input_height_shift + i) * input_pitch_rgb;
2149                 unsigned char *pA = buf_a + (input_height_shift + i) * input_pitch_a;
2150                 unsigned char* pdst = (unsigned char*)info.lpSurface + (height - i - 1)*info.lPitch;
2151                 for( int j=0; j<width; j++)
2152                 {
2153                     *pdst++ = *pRGB++;      // R
2154                     *pdst++ = *pRGB++;      // G
2155                     *pdst++ = *pRGB++;      // B
2156
2157                     if( gHiresTxtrInfos[idx].bSeparatedAlpha )
2158                     {
2159                         *pdst++ = *pA;
2160                         pA += 3;
2161                     }
2162                     else if( entry.ti.Format == TXT_FMT_I )
2163                     {
2164                         *pdst++ = pRGB[-1];
2165                     }
2166                     else
2167                     {
2168                         *pdst++ = 0xFF;
2169                     }
2170                 }
2171             }
2172         }
2173         else
2174         {
2175             input_pitch_rgb *= 4;
2176
2177             // Update the texture by using the buffer
2178             for( int i=height-1; i>=0; i--)
2179             {
2180                 uint32 *pRGB = (uint32*)(buf_rgba + (input_height_shift + i) * input_pitch_rgb);
2181                 uint32 *pdst = (uint32*)((unsigned char*)info.lpSurface + (height - i - 1)*info.lPitch);
2182                 for( int j=0; j<width; j++)
2183                 {
2184                     *pdst++ = *pRGB++;      // RGBA
2185                 }
2186             }
2187         }
2188
2189         if (mirrorx == 2)
2190         {
2191             //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, scale, scale, mirrorx, mirrory, width, height, entry.ti.maskS+scaleShift);
2192             gTextureManager.Mirror(info.lpSurface, width, entry.ti.maskS+scaleShift, width*2, width*2, height, S_FLAG, 4 );
2193         }
2194
2195         if (mirrory == 2)
2196         {
2197             //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, scale, scale, mirrorx, mirrory, width, height, entry.ti.maskT+scaleShift);
2198             gTextureManager.Mirror(info.lpSurface, height, entry.ti.maskT+scaleShift, height*2, entry.pEnhancedTexture->m_dwCreatedTextureWidth, height, T_FLAG, 4 );
2199         }
2200
2201         if( entry.ti.WidthToCreate*scale < entry.pEnhancedTexture->m_dwCreatedTextureWidth )
2202         {
2203             // Clamp
2204             gTextureManager.Clamp(info.lpSurface, width, entry.pEnhancedTexture->m_dwCreatedTextureWidth, entry.pEnhancedTexture->m_dwCreatedTextureWidth, height, S_FLAG, 4 );
2205         }
2206         if( entry.ti.HeightToCreate*scale < entry.pEnhancedTexture->m_dwCreatedTextureHeight )
2207         {
2208             // Clamp
2209             gTextureManager.Clamp(info.lpSurface, height, entry.pEnhancedTexture->m_dwCreatedTextureHeight, entry.pEnhancedTexture->m_dwCreatedTextureWidth, height, T_FLAG, 4 );
2210         }
2211
2212         entry.pEnhancedTexture->EndUpdate(&info);
2213         entry.pEnhancedTexture->SetOthersVariables();
2214         entry.pEnhancedTexture->m_bIsEnhancedTexture = true;
2215         entry.dwEnhancementFlag = TEXTURE_EXTERNAL;
2216
2217         DebugMessage(M64MSG_VERBOSE, "Loaded hi-res texture: %s", filename_rgb);
2218     }
2219     else
2220     {
2221         DebugMessage(M64MSG_ERROR, "New texture creation failed.");
2222         TRACE0("Cannot create a new texture");
2223     }
2224
2225     if( buf_rgba )
2226     {
2227         delete [] buf_rgba;
2228     }
2229
2230     if( buf_a )
2231     {
2232         delete [] buf_a;
2233     }
2234 }
2235