~ubuntu-branches/ubuntu/trusty/mupen64plus-video-rice/trusty

« back to all changes in this revision

Viewing changes to .pc/divide_by_zero.patch/src/TextureFilters.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Sven Eckelmann
  • Date: 2011-07-24 14:24:45 UTC
  • Revision ID: james.westby@ubuntu.com-20110724142445-uczh2xgij7tkx2rt
Tags: 1.99.4-3
* Upload to unstable
* debian/rules:
  - Mark all targets as phony
  - Force PIC using Makefile option
  - Remove unintended optimization flags
* debian/patches:
  - Remove default-optimisations.patch, hurd_os.patch
  - Add rewrite_makefile.patch, Rewrite Makefile to fix flags and linking
  - Add png_truecolor_conversation.patch, Convert 8-bit png to truecolor when
    needed
  - Add divide_by_zero.patch, Fix random crash due to divide-by-zero error
  - Add undefined_functions.patch, Add header for undefined min/max/memcpy
  - Add portable_movsxl.patch, Replace movsxl with more portable mnemonic
    movslq
  - Add infinit_loop.patch, Fix double infinit loop in GetValidTmemInfoIndex
  - Add wom_corruption.patch, Remove write-only member variables m_bClampS and
    m_bClampT
  - Add z_coordinate_lines.patch, Fix z coordinate in 3d line rendering
  - Add mipmapping.patch, Synchronize MipMapping options in Arachnoid and Rice
* Depend on pkg-config in debian/control for new Makefile

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
#include "m64p_plugin.h"
 
23
#include "typedefs.h"
 
24
#include "ConvertImage.h"
 
25
#include "DeviceBuilder.h"
 
26
#include "TextureFilters.h"
 
27
#include "Render.h"
 
28
#include "Video.h"
 
29
 
 
30
#include "liblinux/BMGLibPNG.h"
 
31
#include "liblinux/BMGDLL.h"
 
32
#include <sys/types.h>
 
33
 
 
34
/************************************************************************/
 
35
/* 2X filters                                                           */
 
36
/************************************************************************/
 
37
// Basic 2x R8G8B8A8 filter with interpolation
 
38
 
 
39
void Texture2x_32( DrawInfo &srcInfo, DrawInfo &destInfo)
 
40
{
 
41
    uint32 *pDst1, *pDst2;
 
42
    uint32 *pSrc, *pSrc2;
 
43
    uint32 nWidth = srcInfo.dwWidth;
 
44
    uint32 nHeight = srcInfo.dwHeight;
 
45
 
 
46
    uint32 b1;
 
47
    uint32 g1;
 
48
    uint32 r1;
 
49
    uint32 a1;
 
50
    uint32 b2 = 0;
 
51
    uint32 g2 = 0;
 
52
    uint32 r2 = 0;
 
53
    uint32 a2 = 0;
 
54
    uint32 b3 = 0;
 
55
    uint32 g3 = 0;
 
56
    uint32 r3 = 0;
 
57
    uint32 a3 = 0;
 
58
    uint32 b4 = 0;
 
59
    uint32 g4 = 0;
 
60
    uint32 r4 = 0;
 
61
    uint32 a4 = 0;
 
62
 
 
63
 
 
64
    for (uint32 ySrc = 0; ySrc < nHeight; ySrc++)
 
65
    {
 
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);
 
70
 
 
71
        for (uint32 xSrc = 0; xSrc < nWidth; xSrc++)
 
72
        {
 
73
            b1 = (pSrc[xSrc]>>0)&0xFF;
 
74
            g1 = (pSrc[xSrc]>>8)&0xFF;
 
75
            r1 = (pSrc[xSrc]>>16)&0xFF;
 
76
            a1 = (pSrc[xSrc]>>24)&0xFF;
 
77
 
 
78
            if( xSrc<nWidth-1 )
 
79
            {
 
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;
 
84
            }
 
85
 
 
86
            if( ySrc<nHeight-1 )
 
87
            {
 
88
                b3 = (pSrc2[xSrc]>>0)&0xFF;
 
89
                g3 = (pSrc2[xSrc]>>8)&0xFF;
 
90
                r3 = (pSrc2[xSrc]>>16)&0xFF;
 
91
                a3 = (pSrc2[xSrc]>>24)&0xFF;
 
92
                if( xSrc<nWidth-1 )
 
93
                {
 
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;
 
98
                }
 
99
            }
 
100
 
 
101
 
 
102
            // Pixel 1
 
103
            pDst1[xSrc*2] = pSrc[xSrc];
 
104
 
 
105
            // Pixel 2
 
106
            if( xSrc<nWidth-1 )
 
107
            {
 
108
                pDst1[xSrc*2+1] = DWORD_MAKE((r1+r2)/2, (g1+g2)/2, (b1+b2)/2, (a1+a2)/2);
 
109
            }
 
110
            else
 
111
                pDst1[xSrc*2+1] = pSrc[xSrc];
 
112
 
 
113
 
 
114
            // Pixel 3
 
115
            if( ySrc<nHeight-1 )
 
116
            {
 
117
                pDst2[xSrc*2] = DWORD_MAKE((r1+r3)/2, (g1+g3)/2, (b1+b3)/2, (a1+a3)/2);
 
118
            }
 
119
            else
 
120
                pDst2[xSrc*2] = pSrc[xSrc];
 
121
 
 
122
            // Pixel 4
 
123
            if( xSrc<nWidth-1 )
 
124
            {
 
125
                if( ySrc<nHeight-1 )
 
126
                {
 
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);
 
128
                }
 
129
                else
 
130
                {
 
131
                    pDst2[xSrc*2+1] = DWORD_MAKE((r1+r2)/2, (g1+g2)/2, (b1+b2)/2, (a1+a2)/2);
 
132
                }
 
133
            }
 
134
            else
 
135
            {
 
136
                if( ySrc<nHeight-1 )
 
137
                {
 
138
                    pDst2[xSrc*2+1] = DWORD_MAKE((r1+r3)/2, (g1+g3)/2, (b1+b3)/2, (a1+a3)/2);
 
139
                }
 
140
                else
 
141
                    pDst2[xSrc*2+1] = pSrc[xSrc];
 
142
            }
 
143
        }
 
144
    }
 
145
}
 
146
 
 
147
// Basic 2x R4G4B4A4 filter with interpolation
 
148
void Texture2x_16( DrawInfo &srcInfo, DrawInfo &destInfo )
 
149
{
 
150
    uint16 *pDst1, *pDst2;
 
151
    uint16 *pSrc, *pSrc2;
 
152
    uint32 nWidth = srcInfo.dwWidth;
 
153
    uint32 nHeight = srcInfo.dwHeight;
 
154
 
 
155
    uint16 b1;
 
156
    uint16 g1;
 
157
    uint16 r1;
 
158
    uint16 a1;
 
159
    uint16 b2 = 0;
 
160
    uint16 g2 = 0;
 
161
    uint16 r2 = 0;
 
162
    uint16 a2 = 0;
 
163
    uint16 b3 = 0;
 
164
    uint16 g3 = 0;
 
165
    uint16 r3 = 0;
 
166
    uint16 a3 = 0;
 
167
    uint16 b4 = 0;
 
168
    uint16 g4 = 0;
 
169
    uint16 r4 = 0;
 
170
    uint16 a4 = 0;
 
171
 
 
172
    for (uint16 ySrc = 0; ySrc < nHeight; ySrc++)
 
173
    {
 
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);
 
178
 
 
179
        for (uint16 xSrc = 0; xSrc < nWidth; xSrc++)
 
180
        {
 
181
            b1 = (pSrc[xSrc]>> 0)&0xF;
 
182
            g1 = (pSrc[xSrc]>> 4)&0xF;
 
183
            r1 = (pSrc[xSrc]>> 8)&0xF;
 
184
            a1 = (pSrc[xSrc]>>12)&0xF;
 
185
 
 
186
            if( xSrc<nWidth-1 )
 
187
            {
 
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;
 
192
            }
 
193
 
 
194
            if( ySrc<nHeight-1 )
 
195
            {
 
196
                b3 = (pSrc2[xSrc]>> 0)&0xF;
 
197
                g3 = (pSrc2[xSrc]>> 4)&0xF;
 
198
                r3 = (pSrc2[xSrc]>> 8)&0xF;
 
199
                a3 = (pSrc2[xSrc]>>12)&0xF;
 
200
                if( xSrc<nWidth-1 )
 
201
                {
 
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;
 
206
                }
 
207
            }
 
208
 
 
209
            // Pixel 1
 
210
            pDst1[xSrc*2] = pSrc[xSrc];
 
211
 
 
212
            // Pixel 2
 
213
            if( xSrc<nWidth-1 )
 
214
            {
 
215
                pDst1[xSrc*2+1] = WORD_MAKE((r1+r2)/2, (g1+g2)/2, (b1+b2)/2, (a1+a2)/2);
 
216
            }
 
217
            else
 
218
                pDst1[xSrc*2+1] = pSrc[xSrc];
 
219
 
 
220
 
 
221
            // Pixel 3
 
222
            if( ySrc<nHeight-1 )
 
223
            {
 
224
                pDst2[xSrc*2] = WORD_MAKE((r1+r3)/2, (g1+g3)/2, (b1+b3)/2, (a1+a3)/2);
 
225
            }
 
226
            else
 
227
                pDst2[xSrc*2] = pSrc[xSrc];
 
228
 
 
229
            // Pixel 4
 
230
            if( xSrc<nWidth-1 )
 
231
            {
 
232
                if( ySrc<nHeight-1 )
 
233
                {
 
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);
 
235
                }
 
236
                else
 
237
                {
 
238
                    pDst2[xSrc*2+1] = WORD_MAKE((r1+r2)/2, (g1+g2)/2, (b1+b2)/2, (a1+a2)/2);
 
239
                }
 
240
            }
 
241
            else
 
242
            {
 
243
                if( ySrc<nHeight-1 )
 
244
                {
 
245
                    pDst2[xSrc*2+1] = WORD_MAKE((r1+r3)/2, (g1+g3)/2, (b1+b3)/2, (a1+a3)/2);
 
246
                }
 
247
                else
 
248
                    pDst2[xSrc*2+1] = pSrc[xSrc];
 
249
            }
 
250
        }
 
251
    }
 
252
}
 
253
 
 
254
/************************************************************************/
 
255
/* Sharpen filters                                                      */
 
256
/************************************************************************/
 
257
void SharpenFilter_32(uint32 *pdata, uint32 width, uint32 height, uint32 pitch, uint32 filter)
 
258
{
 
259
    uint32 len=height*pitch;
 
260
    uint32 *pcopy = new uint32[len];
 
261
 
 
262
    if( !pcopy )    return;
 
263
 
 
264
    memcpy(pcopy, pdata, len<<2);
 
265
 
 
266
    uint32 mul1, mul2, mul3, shift4;
 
267
    switch( filter )
 
268
    {
 
269
        case TEXTURE_SHARPEN_MORE_ENHANCEMENT:
 
270
            mul1=1;
 
271
            mul2=8;
 
272
            mul3=12;
 
273
            shift4=2;
 
274
            break;
 
275
        case TEXTURE_SHARPEN_ENHANCEMENT:
 
276
        default:
 
277
            mul1=1;
 
278
            mul2=8;
 
279
            mul3=16;
 
280
            shift4=3;
 
281
            break;
 
282
    }
 
283
 
 
284
    uint32 x,y,z;
 
285
    uint32 *src1, *src2, *src3, *dest;
 
286
    uint32 val[4];
 
287
    uint32 t1,t2,t3,t4,t5,t6,t7,t8,t9;
 
288
 
 
289
    for( y=1; y<height-1; y++)
 
290
    {
 
291
        dest = pdata+y*pitch;
 
292
        src1 = pcopy+(y-1)*pitch;
 
293
        src2 = src1 + pitch;
 
294
        src3 = src2 + pitch;
 
295
        for( x=1; x<width-1; x++)
 
296
        {
 
297
            for( z=0; z<4; z++ )
 
298
            {
 
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);
 
308
                val[z]=t5;
 
309
                if( (t5*mul2) > (t1+t3+t7+t9+t2+t4+t6+t8)*mul1 )
 
310
                {
 
311
                    val[z]= min((((t5*mul3) - (t1+t3+t7+t9+t2+t4+t6+t8)*mul1)>>shift4),0xFF);
 
312
                }
 
313
            }
 
314
            dest[x] = val[0]|(val[1]<<8)|(val[2]<<16)|(val[3]<<24);
 
315
        }
 
316
    }
 
317
    delete [] pcopy;
 
318
}
 
319
 
 
320
void SharpenFilter_16(uint16 *pdata, uint32 width, uint32 height, uint32 pitch, uint32 filter)
 
321
{
 
322
    //return;   // Sharpen does not make sense for 16 bits
 
323
 
 
324
    uint32 len=height*pitch;
 
325
    uint16 *pcopy = new uint16[len];
 
326
 
 
327
    if( !pcopy )    return;
 
328
 
 
329
    memcpy(pcopy, pdata, len<<1);
 
330
 
 
331
    uint16 mul1, mul2, mul3, shift4;
 
332
    switch( filter )
 
333
    {
 
334
        case TEXTURE_SHARPEN_MORE_ENHANCEMENT:
 
335
            mul1=1;
 
336
            mul2=8;
 
337
            mul3=12;
 
338
            shift4=2;
 
339
            break;
 
340
        case TEXTURE_SHARPEN_ENHANCEMENT:
 
341
        default:
 
342
            mul1=1;
 
343
            mul2=8;
 
344
            mul3=16;
 
345
            shift4=3;
 
346
            break;
 
347
    }
 
348
 
 
349
    uint32 x,y,z;
 
350
    uint16 *src1, *src2, *src3, *dest;
 
351
    uint16 val[4];
 
352
    uint16 t1,t2,t3,t4,t5,t6,t7,t8,t9;
 
353
 
 
354
    for( y=1; y<height-1; y++)
 
355
    {
 
356
        dest = pdata+y*pitch;
 
357
        src1 = pcopy+(y-1)*pitch;
 
358
        src2 = src1 + pitch;
 
359
        src3 = src2 + pitch;
 
360
        for( x=1; x<width-1; x++)
 
361
        {
 
362
            for( z=0; z<4; z++ )
 
363
            {
 
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;
 
374
                val[z]=t5;
 
375
                if( (t5*mul2) > (t1+t3+t7+t9+t2+t4+t6+t8)*mul1 )
 
376
                {
 
377
                    val[z] = (((t5*mul3) - (t1+t3+t7+t9+t2+t4+t6+t8)*mul1)>>shift4);
 
378
                    val[z]= min(val[z],0xF);
 
379
                }
 
380
            }
 
381
            dest[x] = val[0]|(val[1]<<4)|(val[2]<<8)|(val[3]<<12);
 
382
        }
 
383
    }
 
384
    delete [] pcopy;
 
385
}
 
386
 
 
387
/************************************************************************/
 
388
/* Smooth filters                                                       */
 
389
/************************************************************************/
 
390
void SmoothFilter_32(uint32 *pdata, uint32 width, uint32 height, uint32 pitch, uint32 filter)
 
391
{
 
392
    uint32 len=height*pitch;
 
393
    uint32 *pcopy = new uint32[len];
 
394
 
 
395
    if( !pcopy )    return;
 
396
 
 
397
    memcpy(pcopy, pdata, len<<2);
 
398
 
 
399
    uint32 mul1, mul2, mul3, shift4;
 
400
    switch( filter )
 
401
    {
 
402
        case TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_1:
 
403
            mul1=1;
 
404
            mul2=2;
 
405
            mul3=4;
 
406
            shift4=4;
 
407
            break;
 
408
        case TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_2:
 
409
            mul1=1;
 
410
            mul2=1;
 
411
            mul3=8;
 
412
            shift4=4;
 
413
            break;
 
414
        case TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_3:
 
415
            mul1=1;
 
416
            mul2=1;
 
417
            mul3=2;
 
418
            shift4=2;
 
419
            break;
 
420
        case TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_4:
 
421
        default:
 
422
            mul1=1;
 
423
            mul2=1;
 
424
            mul3=6;
 
425
            shift4=3;
 
426
            break;
 
427
    }
 
428
 
 
429
    uint32 x,y,z;
 
430
    uint32 *src1, *src2, *src3, *dest;
 
431
    uint32 val[4];
 
432
    uint32 t1,t2,t3,t4,t5,t6,t7,t8,t9;
 
433
 
 
434
    if( filter == TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_3 || filter == TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_4 )
 
435
    {
 
436
        for( y=1; y<height-1; y+=2)
 
437
        {
 
438
            dest = pdata+y*pitch;
 
439
            src1 = pcopy+(y-1)*pitch;
 
440
            src2 = src1 + pitch;
 
441
            src3 = src2 + pitch;
 
442
            for( x=0; x<width; x++)
 
443
            {
 
444
                for( z=0; z<4; z++ )
 
445
                {
 
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;
 
450
                }
 
451
                dest[x] = val[0]|(val[1]<<8)|(val[2]<<16)|(val[3]<<24);
 
452
            }
 
453
        }
 
454
    }
 
455
    else
 
456
    {
 
457
        for( y=0; y<height; y++)
 
458
        {
 
459
            dest = pdata+y*pitch;
 
460
            if( y>0 )
 
461
            {
 
462
                src1 = pcopy+(y-1)*pitch;
 
463
                src2 = src1 + pitch;
 
464
            }
 
465
            else
 
466
            {
 
467
                src1 = src2 = pcopy;
 
468
            }
 
469
 
 
470
            src3 = src2;
 
471
            if( y<height-1) src3 += pitch;
 
472
 
 
473
            for( x=1; x<width-1; x++)
 
474
            {
 
475
                for( z=0; z<4; z++ )
 
476
                {
 
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;
 
487
                }
 
488
                dest[x] = val[0]|(val[1]<<8)|(val[2]<<16)|(val[3]<<24);
 
489
            }
 
490
        }
 
491
    }
 
492
    delete [] pcopy;
 
493
}
 
494
 
 
495
void SmoothFilter_16(uint16 *pdata, uint32 width, uint32 height, uint32 pitch, uint32 filter)
 
496
{
 
497
    uint32 len=height*pitch;
 
498
    uint16 *pcopy = new uint16[len];
 
499
 
 
500
    if( !pcopy )    return;
 
501
 
 
502
    memcpy(pcopy, pdata, len<<1);
 
503
 
 
504
    uint16 mul1, mul2, mul3, shift4;
 
505
    switch( filter )
 
506
    {
 
507
        case TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_1:
 
508
            mul1=1;
 
509
            mul2=2;
 
510
            mul3=4;
 
511
            shift4=4;
 
512
            break;
 
513
        case TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_2:
 
514
            mul1=1;
 
515
            mul2=1;
 
516
            mul3=8;
 
517
            shift4=4;
 
518
            break;
 
519
        case TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_3:
 
520
            mul1=1;
 
521
            mul2=1;
 
522
            mul3=2;
 
523
            shift4=2;
 
524
            break;
 
525
        case TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_4:
 
526
        default:
 
527
            mul1=1;
 
528
            mul2=1;
 
529
            mul3=6;
 
530
            shift4=3;
 
531
            break;
 
532
    }
 
533
 
 
534
    uint32 x,y,z;
 
535
    uint16 *src1, *src2, *src3, *dest;
 
536
    uint16 val[4];
 
537
    uint16 t1,t2,t3,t4,t5,t6,t7,t8,t9;
 
538
 
 
539
    if( filter == TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_3 || filter == TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_4 )
 
540
    {
 
541
        for( y=1; y<height-1; y+=2)
 
542
        {
 
543
            dest = pdata+y*pitch;
 
544
            src1 = pcopy+(y-1)*pitch;
 
545
            src2 = src1 + pitch;
 
546
            src3 = src2 + pitch;
 
547
            for( x=0; x<width; x++)
 
548
            {
 
549
                for( z=0; z<4; z++ )
 
550
                {
 
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;
 
556
                }
 
557
                dest[x] = val[0]|(val[1]<<4)|(val[2]<<8)|(val[3]<<12);
 
558
            }
 
559
        }
 
560
    }
 
561
    else
 
562
    {
 
563
        for( y=0; y<height; y++)
 
564
        {
 
565
            dest = pdata+y*pitch;
 
566
            if( y>0 )
 
567
            {
 
568
                src1 = pcopy+(y-1)*pitch;
 
569
                src2 = src1 + pitch;
 
570
            }
 
571
            else
 
572
            {
 
573
                src1 = src2 = pcopy;
 
574
            }
 
575
 
 
576
            src3 = src2;
 
577
            if( y<height-1) src3 += pitch;
 
578
 
 
579
            for( x=1; x<width-1; x++)
 
580
            {
 
581
                for( z=0; z<4; z++ )
 
582
                {
 
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;
 
594
                }
 
595
                dest[x] = val[0]|(val[1]<<4)|(val[2]<<8)|(val[3]<<12);
 
596
            }
 
597
        }
 
598
    }
 
599
    delete [] pcopy;
 
600
}
 
601
 
 
602
 
 
603
void EnhanceTexture(TxtrCacheEntry *pEntry)
 
604
{
 
605
    if( pEntry->dwEnhancementFlag == options.textureEnhancement )
 
606
    {
 
607
        // The texture has already been enhanced
 
608
        return;
 
609
    }
 
610
    else if( options.textureEnhancement == TEXTURE_NO_ENHANCEMENT )
 
611
    {
 
612
        SAFE_DELETE(pEntry->pEnhancedTexture);
 
613
        pEntry->dwEnhancementFlag = TEXTURE_NO_ENHANCEMENT;
 
614
        return;
 
615
    }
 
616
 
 
617
    if( status.primitiveType != PRIM_TEXTRECT && options.bTexRectOnly )
 
618
    {
 
619
        return;
 
620
    }
 
621
 
 
622
    DrawInfo srcInfo;   
 
623
    if( pEntry->pTexture->StartUpdate(&srcInfo) == false )
 
624
    {
 
625
        SAFE_DELETE(pEntry->pEnhancedTexture);
 
626
        return;
 
627
    }
 
628
 
 
629
    uint32 realwidth = srcInfo.dwWidth;
 
630
    uint32 realheight = srcInfo.dwHeight;
 
631
    uint32 nWidth = srcInfo.dwCreatedWidth;
 
632
    uint32 nHeight = srcInfo.dwCreatedHeight;
 
633
 
 
634
    if( options.textureEnhancement == TEXTURE_SHARPEN_ENHANCEMENT || options.textureEnhancement == TEXTURE_SHARPEN_MORE_ENHANCEMENT )
 
635
    {
 
636
        if( pEntry->pTexture->GetPixelSize() == 4 )
 
637
            SharpenFilter_32((uint32*)srcInfo.lpSurface, nWidth, nHeight, nWidth, options.textureEnhancement);
 
638
        else
 
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);
 
643
        return;
 
644
    }
 
645
 
 
646
    pEntry->dwEnhancementFlag = options.textureEnhancement;
 
647
    if( options.bSmallTextureOnly )
 
648
    {
 
649
        if( nWidth + nHeight > 256 )
 
650
        {
 
651
            pEntry->pTexture->EndUpdate(&srcInfo);
 
652
            SAFE_DELETE(pEntry->pEnhancedTexture);
 
653
            pEntry->dwEnhancementFlag = TEXTURE_NO_ENHANCEMENT;
 
654
            return;
 
655
        }
 
656
    }
 
657
 
 
658
 
 
659
    CTexture* pSurfaceHandler = NULL;
 
660
    if( options.textureEnhancement == TEXTURE_HQ4X_ENHANCEMENT )
 
661
    {
 
662
        if( nWidth + nHeight > 1024/4 )
 
663
        {
 
664
            // Don't enhance for large textures
 
665
            pEntry->pTexture->EndUpdate(&srcInfo);
 
666
            SAFE_DELETE(pEntry->pEnhancedTexture);
 
667
            pEntry->dwEnhancementFlag = TEXTURE_NO_ENHANCEMENT;
 
668
            return;
 
669
        }
 
670
        pSurfaceHandler = CDeviceBuilder::GetBuilder()->CreateTexture(nWidth*4, nHeight*4);
 
671
    }
 
672
    else
 
673
    {
 
674
        if( nWidth + nHeight > 1024/2 )
 
675
        {
 
676
            // Don't enhance for large textures
 
677
            pEntry->pTexture->EndUpdate(&srcInfo);
 
678
            SAFE_DELETE(pEntry->pEnhancedTexture);
 
679
            pEntry->dwEnhancementFlag = TEXTURE_NO_ENHANCEMENT;
 
680
            return;
 
681
        }
 
682
        pSurfaceHandler = CDeviceBuilder::GetBuilder()->CreateTexture(nWidth*2, nHeight*2);
 
683
    }
 
684
    DrawInfo destInfo;
 
685
    if(pSurfaceHandler)
 
686
    {
 
687
        if(pSurfaceHandler->StartUpdate(&destInfo))
 
688
        {
 
689
            if( options.textureEnhancement == TEXTURE_2XSAI_ENHANCEMENT )
 
690
            {
 
691
                if( pEntry->pTexture->GetPixelSize() == 4 )
 
692
                    Super2xSaI_32((uint32*)(srcInfo.lpSurface),(uint32*)(destInfo.lpSurface), nWidth, realheight, nWidth);
 
693
                else
 
694
                    Super2xSaI_16((uint16*)(srcInfo.lpSurface),(uint16*)(destInfo.lpSurface), nWidth, realheight, nWidth);
 
695
            }
 
696
            else if( options.textureEnhancement == TEXTURE_HQ2X_ENHANCEMENT )
 
697
            {
 
698
                if( pEntry->pTexture->GetPixelSize() == 4 )
 
699
                {
 
700
                    hq2x_init(32);
 
701
                    hq2x_32((uint8*)(srcInfo.lpSurface), srcInfo.lPitch, (uint8*)(destInfo.lpSurface), destInfo.lPitch, nWidth, realheight);
 
702
                }
 
703
                else
 
704
                {
 
705
                    hq2x_init(16);
 
706
                    hq2x_16((uint8*)(srcInfo.lpSurface), srcInfo.lPitch, (uint8*)(destInfo.lpSurface), destInfo.lPitch, nWidth, realheight);
 
707
                }
 
708
            }
 
709
            else if( options.textureEnhancement == TEXTURE_LQ2X_ENHANCEMENT )
 
710
            {
 
711
                if( pEntry->pTexture->GetPixelSize() == 4 )
 
712
                {
 
713
                    hq2x_init(32);
 
714
                    lq2x_32((uint8*)(srcInfo.lpSurface), srcInfo.lPitch, (uint8*)(destInfo.lpSurface), destInfo.lPitch, nWidth, realheight);
 
715
                }
 
716
                else
 
717
                {
 
718
                    hq2x_init(16);
 
719
                    lq2x_16((uint8*)(srcInfo.lpSurface), srcInfo.lPitch, (uint8*)(destInfo.lpSurface), destInfo.lPitch, nWidth, realheight);
 
720
                }
 
721
            }
 
722
            else if( options.textureEnhancement == TEXTURE_HQ4X_ENHANCEMENT )
 
723
            {
 
724
                if( pEntry->pTexture->GetPixelSize() == 4 )
 
725
                {
 
726
                    hq4x_InitLUTs();
 
727
                    hq4x_32((uint8*)(srcInfo.lpSurface), (uint8*)(destInfo.lpSurface), realwidth, realheight, nWidth, destInfo.lPitch);
 
728
                }
 
729
                else
 
730
                {
 
731
                    hq4x_InitLUTs();
 
732
                    hq4x_16((uint8*)(srcInfo.lpSurface), (uint8*)(destInfo.lpSurface), realwidth, realheight, nWidth, destInfo.lPitch);
 
733
                }
 
734
            }
 
735
            else 
 
736
            {
 
737
                if( pEntry->pTexture->GetPixelSize() == 4 )
 
738
                    Texture2x_32( srcInfo, destInfo);
 
739
                else
 
740
                    Texture2x_16( srcInfo, destInfo);
 
741
            }
 
742
 
 
743
            if( options.textureEnhancementControl >= TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_1 )
 
744
            {
 
745
                if( options.textureEnhancement != TEXTURE_HQ4X_ENHANCEMENT )
 
746
                {
 
747
                    if( pEntry->pTexture->GetPixelSize() == 4 )
 
748
                        SmoothFilter_32((uint32*)destInfo.lpSurface, realwidth<<1, realheight<<1, nWidth<<1, options.textureEnhancementControl);
 
749
                    else
 
750
                        SmoothFilter_16((uint16*)destInfo.lpSurface, realwidth<<1, realheight<<1, nWidth<<1, options.textureEnhancementControl);
 
751
                }
 
752
                else
 
753
                {
 
754
                    if( pEntry->pTexture->GetPixelSize() == 4 )
 
755
                        SmoothFilter_32((uint32*)destInfo.lpSurface, realwidth<<2, realheight<<2, nWidth<<2, options.textureEnhancementControl);
 
756
                    else
 
757
                        SmoothFilter_16((uint16*)destInfo.lpSurface, realwidth<<2, realheight<<2, nWidth<<2, options.textureEnhancementControl);
 
758
                }
 
759
            }
 
760
 
 
761
            pSurfaceHandler->EndUpdate(&destInfo);  
 
762
        }
 
763
    
 
764
        pSurfaceHandler->SetOthersVariables();
 
765
        pSurfaceHandler->m_bIsEnhancedTexture = true;
 
766
    }
 
767
 
 
768
    pEntry->pTexture->EndUpdate(&srcInfo);
 
769
 
 
770
    pEntry->pEnhancedTexture = pSurfaceHandler;
 
771
}
 
772
 
 
773
 
 
774
/************************************************************************/
 
775
/*                                                                      */
 
776
/************************************************************************/
 
777
void MirrorEmulator_DrawLine(DrawInfo& destInfo, DrawInfo& srcInfo, uint32 *pSource, uint32 *pDest, uint32 nWidth, BOOL bFlipLeftRight)
 
778
{
 
779
    if(!bFlipLeftRight)
 
780
    {
 
781
        memcpy(pDest, pSource, nWidth * 4);
 
782
    }
 
783
    else
 
784
    {
 
785
        uint32 *pMaxDest = pDest + nWidth;
 
786
        pSource += nWidth - 1;
 
787
        for(; pDest < pMaxDest; pDest++, pSource--)
 
788
        {
 
789
            *pDest = *pSource;
 
790
        }
 
791
    }
 
792
}
 
793
 
 
794
 
 
795
void MirrorEmulator_Draw(DrawInfo& destInfo, DrawInfo& srcInfo, uint32 nDestX, uint32 nDestY, BOOL bFlipLeftRight, BOOL bFlipUpDown)
 
796
{
 
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);
 
800
    if(!bFlipUpDown)
 
801
    {
 
802
        for(; pDest < pMaxDest; pDest += destInfo.lPitch, pSource += srcInfo.lPitch)
 
803
        {
 
804
            MirrorEmulator_DrawLine(destInfo, srcInfo, (uint32*)pSource, (uint32*)pDest, srcInfo.dwWidth, bFlipLeftRight);
 
805
        }
 
806
    }
 
807
    else
 
808
    {
 
809
        pSource += (srcInfo.lPitch * (srcInfo.dwHeight - 1));
 
810
        for(; pDest < pMaxDest; pDest += destInfo.lPitch, pSource -= srcInfo.lPitch)
 
811
        {
 
812
            MirrorEmulator_DrawLine(destInfo, srcInfo, (uint32*)pSource, (uint32*)pDest, srcInfo.dwWidth, bFlipLeftRight);
 
813
        }
 
814
    }
 
815
}
 
816
 
 
817
void MirrorTexture(uint32 dwTile, TxtrCacheEntry *pEntry)
 
818
{
 
819
    if( ((gRDP.tiles[dwTile].bMirrorS) || (gRDP.tiles[dwTile].bMirrorT)) && CGraphicsContext::Get()->m_supportTextureMirror == false )
 
820
    {
 
821
        if(pEntry->pEnhancedTexture)
 
822
        {
 
823
            return;
 
824
        }
 
825
        else
 
826
        {
 
827
            CTexture* pSurfaceHandler = NULL;
 
828
 
 
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;
 
832
            
 
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
 
835
 
 
836
            // But again, check me
 
837
 
 
838
            //if( pEntry->pTexture->m_bScaledS == false || pEntry->pTexture->m_bScaledT == false)
 
839
            //{
 
840
            //  pEntry->pTexture->ScaleImageToSurface();
 
841
            //}
 
842
 
 
843
            DrawInfo srcInfo;   
 
844
            if( pEntry->pTexture->StartUpdate(&srcInfo) )
 
845
            {
 
846
                uint32 nWidth = srcInfo.dwWidth;
 
847
                uint32 nHeight = srcInfo.dwHeight;
 
848
 
 
849
                pSurfaceHandler = CDeviceBuilder::GetBuilder()->CreateTexture(nWidth * nXTimes, nHeight * nYTimes);
 
850
                if( pSurfaceHandler )
 
851
                {
 
852
                    DrawInfo destInfo;
 
853
                    if( pSurfaceHandler->StartUpdate(&destInfo) )
 
854
                    {
 
855
                        for(uint32 nY = 0; nY < nYTimes; nY++)
 
856
                        {
 
857
                            for(uint32 nX = 0; nX < nXTimes; nX++)
 
858
                            {
 
859
                                MirrorEmulator_Draw(destInfo, srcInfo, nWidth * nX, nHeight * nY, nX & 0x1, nY & 0x1);
 
860
                            }
 
861
                        }
 
862
 
 
863
                        pSurfaceHandler->EndUpdate(&destInfo);
 
864
                    }
 
865
                
 
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();
 
869
                }
 
870
 
 
871
                pEntry->pTexture->EndUpdate(&srcInfo);  
 
872
                pEntry->dwEnhancementFlag = TEXTURE_MIRRORED;
 
873
            }
 
874
 
 
875
 
 
876
            pEntry->pEnhancedTexture = pSurfaceHandler;
 
877
        }
 
878
    }
 
879
}
 
880
 
 
881
enum TextureType
 
882
{
 
883
    NO_TEXTURE,
 
884
 RGB_PNG,
 
885
 COLOR_INDEXED_BMP,
 
886
 RGB_WITH_ALPHA_TOGETHER_PNG,
 
887
 RGBA_PNG_FOR_CI,
 
888
 RGBA_PNG_FOR_ALL_CI,
 
889
};
 
890
typedef struct {
 
891
    int width;
 
892
    int height;
 
893
    int fmt;
 
894
    int siz;
 
895
    int crc32;
 
896
    int pal_crc32;
 
897
    char *foldername;
 
898
    //char name[40];
 
899
    char RGBNameTail[23];
 
900
    char AlphaNameTail[20];
 
901
    TextureType type;
 
902
    bool        bSeparatedAlpha;
 
903
} ExtTxtrInfo;
 
904
 
 
905
CSortedList<uint64,ExtTxtrInfo> gTxtrDumpInfos;
 
906
CSortedList<uint64,ExtTxtrInfo> gHiresTxtrInfos;
 
907
 
 
908
extern char * right(const char * src, int nchars);
 
909
 
 
910
#define SURFFMT_P8 41
 
911
 
 
912
int GetImageInfoFromFile(char* pSrcFile, IMAGE_INFO *pSrcInfo)
 
913
{
 
914
    unsigned char sig[8];
 
915
    FILE *f;
 
916
 
 
917
    f = fopen(pSrcFile, "rb");
 
918
    if (f == NULL)
 
919
    {
 
920
      DebugMessage(M64MSG_ERROR, "GetImageInfoFromFile() error: couldn't open file '%s'", pSrcFile);
 
921
      return 1;
 
922
    }
 
923
    if (fread(sig, 1, 8, f) != 8)
 
924
    {
 
925
      DebugMessage(M64MSG_ERROR, "GetImageInfoFromFile() error: couldn't read first 8 bytes of file '%s'", pSrcFile);
 
926
      return 1;
 
927
    }
 
928
    fclose(f);
 
929
 
 
930
    if(sig[0] == 'B' && sig[1] == 'M') // BMP
 
931
    {
 
932
        struct BMGImageStruct img;
 
933
        memset(&img, 0, sizeof(BMGImageStruct));
 
934
        BMG_Error code = ReadBMP(pSrcFile, &img);
 
935
        if( code == BMG_OK )
 
936
        {
 
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
 
946
            FreeBMGImage(&img);
 
947
            return 0;
 
948
        }
 
949
        DebugMessage(M64MSG_ERROR, "Couldn't read BMP file '%s'; error = %i", pSrcFile, code);
 
950
        return 1;
 
951
    }
 
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
 
954
    {
 
955
        struct BMGImageStruct img;
 
956
        memset(&img, 0, sizeof(BMGImageStruct));
 
957
        BMG_Error code = ReadPNG(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 PNG file '%s'; error = %i", pSrcFile, code);
 
973
        return 1;
 
974
    }
 
975
 
 
976
    DebugMessage(M64MSG_ERROR, "GetImageInfoFromFile : unknown file format (%s)", pSrcFile);
 
977
    return 1;
 
978
}
 
979
 
 
980
BOOL PathFileExists(char* pszPath)
 
981
{
 
982
    FILE *f;
 
983
    f = fopen(pszPath, "rb");
 
984
    if(f != NULL)
 
985
    {
 
986
        fclose(f);
 
987
        return TRUE;
 
988
    }
 
989
    return FALSE;
 
990
}
 
991
 
 
992
void FindAllTexturesFromFolder(char *foldername, CSortedList<uint64,ExtTxtrInfo> &infos, bool extraCheck, bool bRecursive)
 
993
{
 
994
    if (!osal_is_directory(foldername))
 
995
        return;
 
996
 
 
997
    char texturefilename[PATH_MAX];
 
998
    IMAGE_INFO  imgInfo;
 
999
    IMAGE_INFO  imgInfo2;
 
1000
 
 
1001
    void *dir;
 
1002
    dir = osal_search_dir_open(foldername);
 
1003
    const char *foundfilename;
 
1004
 
 
1005
    int crc, palcrc32;
 
1006
    unsigned int fmt, siz;
 
1007
    char crcstr[16], crcstr2[16];
 
1008
 
 
1009
    do
 
1010
    {
 
1011
        foundfilename = osal_search_dir_read_next(dir);
 
1012
        if (foundfilename == NULL) break;
 
1013
        if (foundfilename[0] == '.' ) continue;
 
1014
 
 
1015
        strcpy(texturefilename, foldername);
 
1016
        strcat(texturefilename, foundfilename);
 
1017
 
 
1018
        /* handle recursion into sub-directories */
 
1019
        if (osal_is_directory(texturefilename) && bRecursive )
 
1020
        {
 
1021
            strcat(texturefilename, OSAL_DIR_SEPARATOR_STR);
 
1022
            FindAllTexturesFromFolder(texturefilename, infos, extraCheck, bRecursive);
 
1023
            continue;
 
1024
        }
 
1025
        /* if filename doesn't match the ROM's name, skip it */
 
1026
        if( strstr(foundfilename,(const char*)g_curRomInfo.szGameName) == 0 )
 
1027
            continue;
 
1028
 
 
1029
        TextureType type = NO_TEXTURE;
 
1030
        bool bSeparatedAlpha = false;
 
1031
 
 
1032
        if( strcasecmp(right(foundfilename,7), "_ci.bmp") == 0 )
 
1033
        {
 
1034
            if( GetImageInfoFromFile(texturefilename, &imgInfo) != 0)
 
1035
            {
 
1036
                DebugMessage(M64MSG_WARNING, "Cannot get image info for file: %s", foundfilename);
 
1037
                continue;
 
1038
            }
 
1039
 
 
1040
            if( imgInfo.Format == SURFFMT_P8 )
 
1041
                type = COLOR_INDEXED_BMP;
 
1042
            else
 
1043
                continue;
 
1044
        }
 
1045
        else if( strcasecmp(right(foundfilename,13), "_ciByRGBA.png") == 0 )
 
1046
        {
 
1047
            if( GetImageInfoFromFile(texturefilename, &imgInfo) != 0 )
 
1048
            {
 
1049
                DebugMessage(M64MSG_WARNING, "Cannot get image info for file: %s", foundfilename);
 
1050
                continue;
 
1051
            }
 
1052
 
 
1053
            if( imgInfo.Format == SURFFMT_A8R8G8B8 )
 
1054
                type = RGBA_PNG_FOR_CI;
 
1055
            else
 
1056
                continue;
 
1057
        }
 
1058
        else if( strcasecmp(right(foundfilename,16), "_allciByRGBA.png") == 0 )
 
1059
        {
 
1060
            if( GetImageInfoFromFile(texturefilename, &imgInfo) != 0 )
 
1061
            {
 
1062
                DebugMessage(M64MSG_WARNING, "Cannot get image info for file: %s", foundfilename);
 
1063
                continue;
 
1064
            }
 
1065
            if( imgInfo.Format == SURFFMT_A8R8G8B8 )
 
1066
                type = RGBA_PNG_FOR_ALL_CI;
 
1067
            else
 
1068
                continue;
 
1069
        }
 
1070
        else if( strcasecmp(right(foundfilename,8), "_rgb.png") == 0 )
 
1071
        {
 
1072
            if( GetImageInfoFromFile(texturefilename, &imgInfo) != 0 )
 
1073
            {
 
1074
                DebugMessage(M64MSG_WARNING, "Cannot get image info for file: %s", foundfilename);
 
1075
                continue;
 
1076
            }
 
1077
 
 
1078
            type = RGB_PNG;
 
1079
 
 
1080
            char filename2[PATH_MAX];
 
1081
            strcpy(filename2,texturefilename);
 
1082
            strcpy(filename2+strlen(filename2)-8,"_a.png");
 
1083
            if( PathFileExists(filename2) )
 
1084
            {
 
1085
                if( GetImageInfoFromFile(filename2, &imgInfo2) != 0 )
 
1086
                {
 
1087
                    DebugMessage(M64MSG_WARNING, "Cannot get image info for file: %s", filename2);
 
1088
                    continue;
 
1089
                }
 
1090
                
 
1091
                if( extraCheck && (imgInfo2.Width != imgInfo.Width || imgInfo2.Height != imgInfo.Height) )
 
1092
                {
 
1093
                    DebugMessage(M64MSG_WARNING, "RGB and alpha texture size mismatch: %s", filename2);
 
1094
                    continue;
 
1095
                }
 
1096
 
 
1097
                bSeparatedAlpha = true;
 
1098
            }
 
1099
        }
 
1100
        else if( strcasecmp(right(foundfilename,8), "_all.png") == 0 )
 
1101
        {
 
1102
            if( GetImageInfoFromFile(texturefilename, &imgInfo) != 0 )
 
1103
            {
 
1104
                DebugMessage(M64MSG_WARNING, "Cannot get image info for file: %s", foundfilename);
 
1105
                continue;
 
1106
            }
 
1107
 
 
1108
            type = RGB_WITH_ALPHA_TOGETHER_PNG;
 
1109
        }
 
1110
    
 
1111
        if( type != NO_TEXTURE )
 
1112
        {
 
1113
            /* Try to read image information here.
 
1114
 
 
1115
            (CASTLEVANIA2)(#58E2333F)(#2#0#)(D7A5C6D 9)_ciByRGBA.png
 
1116
            (------1-----)(----2----)(3)(4)(----5-----)_ciByRGBA.png
 
1117
 
 
1118
            1. Internal ROM name
 
1119
            2. The DRAM CRC
 
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)
 
1122
            5. The PAL CRC
 
1123
            */
 
1124
            strcpy(texturefilename, foundfilename);
 
1125
 
 
1126
            char *ptr = strchr(texturefilename,'#');
 
1127
            *ptr++ = 0;
 
1128
            if( type == RGBA_PNG_FOR_CI )
 
1129
            {
 
1130
                sscanf(ptr,"%8c#%d#%d#%8c", crcstr, &fmt, &siz,crcstr2);
 
1131
                crcstr2[8] = 0;
 
1132
                palcrc32 = strtoul(crcstr2,NULL,16);
 
1133
            }
 
1134
            else
 
1135
            {
 
1136
                sscanf(ptr,"%8c#%d#%d", crcstr, &fmt, &siz);
 
1137
                palcrc32 = 0xFFFFFFFF;
 
1138
            }
 
1139
            crcstr[8]=0;
 
1140
            crc = strtoul(crcstr,NULL,16);
 
1141
 
 
1142
            int foundIdx = -1;
 
1143
            for( int k=0; k<infos.size(); k++)
 
1144
            {
 
1145
                if( infos[k].crc32 == crc && infos[k].pal_crc32 == palcrc32 )
 
1146
                {
 
1147
                    foundIdx = k;
 
1148
                    break;
 
1149
                }
 
1150
            }
 
1151
 
 
1152
            if( foundIdx < 0 || type != infos[foundIdx].type)
 
1153
            {
 
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);
 
1160
                newinfo.fmt = fmt;
 
1161
                newinfo.siz = siz;
 
1162
                newinfo.crc32 = crc;
 
1163
                newinfo.pal_crc32 = palcrc32;
 
1164
                newinfo.type = type;
 
1165
                newinfo.bSeparatedAlpha = bSeparatedAlpha;
 
1166
 
 
1167
                newinfo.RGBNameTail[0] = newinfo.AlphaNameTail[0] = 0;
 
1168
 
 
1169
                switch ( type )
 
1170
                {
 
1171
                    case RGB_PNG:
 
1172
                        strcpy(newinfo.RGBNameTail, "_rgb.png");
 
1173
                        strcpy(newinfo.AlphaNameTail, "_a.png");
 
1174
                        break;
 
1175
                    case COLOR_INDEXED_BMP:
 
1176
                        strcpy(newinfo.RGBNameTail, "_ci.bmp");
 
1177
                        break;
 
1178
                    case RGBA_PNG_FOR_CI:
 
1179
                        strcpy(newinfo.RGBNameTail, right(ptr,22));
 
1180
                        break;
 
1181
                    case RGBA_PNG_FOR_ALL_CI:
 
1182
                        strcpy(newinfo.RGBNameTail, "_allciByRGBA.png");
 
1183
                        break;
 
1184
                    default:
 
1185
                        strcpy(newinfo.RGBNameTail, "_all.png");
 
1186
                        break;
 
1187
                }
 
1188
 
 
1189
                uint64 crc64 = newinfo.crc32;
 
1190
                crc64 <<= 32;
 
1191
                crc64 |= (newinfo.pal_crc32&0xFFFFFF00)|(newinfo.fmt<<4)|newinfo.siz;
 
1192
                infos.add(crc64,newinfo);
 
1193
            }
 
1194
        }
 
1195
    } while(foundfilename != NULL);
 
1196
 
 
1197
    osal_search_dir_close(dir);
 
1198
}
 
1199
 
 
1200
bool CheckAndCreateFolder(const char* pathname)
 
1201
{
 
1202
    if( !PathFileExists((char*)pathname) )
 
1203
    {
 
1204
        if (osal_mkdirp(pathname, 0700) != 0)
 
1205
        {
 
1206
            DebugMessage(M64MSG_WARNING, "Can not create new folder: %s", pathname);
 
1207
            return false;
 
1208
        }
 
1209
    }
 
1210
 
 
1211
    return true;
 
1212
}
 
1213
 
 
1214
 
 
1215
// Texture dumping filenaming
 
1216
// GameName_FrameCount_CRC_Fmt_Siz.bmp
 
1217
// File format:     BMP
 
1218
// GameName:        N64 game internal name
 
1219
// CRC:             32 bit, 8 hex digits
 
1220
// Fmt:             0 - 4
 
1221
// Siz:             0 - 3
 
1222
 
 
1223
const char *subfolders[] = {
 
1224
    "png_all",
 
1225
    "png_by_rgb_a",
 
1226
    "ci_bmp",
 
1227
    "ci_bmp_with_pal_crc",
 
1228
    "ci_by_png",
 
1229
};
 
1230
 
 
1231
void FindAllDumpedTextures(void)
 
1232
{
 
1233
    char    foldername[PATH_MAX + 64];
 
1234
    strncpy(foldername, ConfigGetUserDataPath(), PATH_MAX);
 
1235
    foldername[PATH_MAX] = 0;
 
1236
 
 
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);
 
1240
 
 
1241
    CheckAndCreateFolder(foldername);
 
1242
 
 
1243
    strcat(foldername,(const char*)g_curRomInfo.szGameName);
 
1244
    strcat(foldername, OSAL_DIR_SEPARATOR_STR);
 
1245
 
 
1246
    gTxtrDumpInfos.clear();
 
1247
    if( !PathFileExists(foldername) )
 
1248
    {
 
1249
        CheckAndCreateFolder(foldername);
 
1250
        char    foldername2[PATH_MAX];
 
1251
        for( int i=0; i<5; i++)
 
1252
        {
 
1253
            strcpy(foldername2,foldername);
 
1254
            strcat(foldername2,subfolders[i]);
 
1255
            CheckAndCreateFolder(foldername2);
 
1256
        }
 
1257
        return;
 
1258
    }
 
1259
    else
 
1260
    {
 
1261
        gTxtrDumpInfos.clear();
 
1262
        FindAllTexturesFromFolder(foldername,gTxtrDumpInfos, false, true);
 
1263
 
 
1264
        char    foldername2[PATH_MAX];
 
1265
        for( int i=0; i<5; i++)
 
1266
        {
 
1267
            strcpy(foldername2,foldername);
 
1268
            strcat(foldername2,subfolders[i]);
 
1269
            CheckAndCreateFolder(foldername2);
 
1270
        }
 
1271
    }
 
1272
}
 
1273
 
 
1274
 
 
1275
void FindAllHiResTextures(void)
 
1276
{
 
1277
    char    foldername[PATH_MAX + 64];
 
1278
    strncpy(foldername, ConfigGetUserDataPath(), PATH_MAX);
 
1279
    foldername[PATH_MAX] = 0;
 
1280
 
 
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);
 
1285
 
 
1286
    strcat(foldername,(const char*)g_curRomInfo.szGameName);
 
1287
    strcat(foldername, OSAL_DIR_SEPARATOR_STR);
 
1288
    gHiresTxtrInfos.clear();
 
1289
    if (!osal_is_directory(foldername))
 
1290
    {
 
1291
        DebugMessage(M64MSG_WARNING, "Couldn't open hi-res texture directory: %s", foldername);
 
1292
        return;
 
1293
    }
 
1294
    else
 
1295
    {
 
1296
        FindAllTexturesFromFolder(foldername,gHiresTxtrInfos, true, true);
 
1297
    }
 
1298
}
 
1299
 
 
1300
void CloseHiresTextures(void)
 
1301
{
 
1302
    for( int i=0; i<gHiresTxtrInfos.size(); i++)
 
1303
    {
 
1304
        if( gHiresTxtrInfos[i].foldername )
 
1305
            delete [] gHiresTxtrInfos[i].foldername;
 
1306
    }
 
1307
 
 
1308
    gHiresTxtrInfos.clear();
 
1309
}
 
1310
 
 
1311
void CloseTextureDump(void)
 
1312
{
 
1313
    for( int i=0; i<gTxtrDumpInfos.size(); i++)
 
1314
    {
 
1315
        if( gTxtrDumpInfos[i].foldername )  
 
1316
            delete [] gTxtrDumpInfos[i].foldername;
 
1317
    }
 
1318
 
 
1319
    gTxtrDumpInfos.clear();
 
1320
}
 
1321
 
 
1322
void CloseExternalTextures(void)
 
1323
{
 
1324
    CloseHiresTextures();
 
1325
    CloseTextureDump();
 
1326
}
 
1327
 
 
1328
void InitHiresTextures(void)
 
1329
{
 
1330
if( options.bLoadHiResTextures )
 
1331
    {
 
1332
    DebugMessage(M64MSG_INFO, "Texture loading option is enabled. Finding all hires textures");
 
1333
    FindAllHiResTextures();
 
1334
    }
 
1335
}
 
1336
 
 
1337
void InitTextureDump(void)
 
1338
{
 
1339
if( options.bDumpTexturesToFiles )
 
1340
    {
 
1341
    DebugMessage(M64MSG_INFO, "Texture dump option is enabled. Finding all dumpped textures");
 
1342
    FindAllDumpedTextures();
 
1343
    }
 
1344
}
 
1345
void InitExternalTextures(void)
 
1346
{
 
1347
    DebugMessage(M64MSG_VERBOSE, "InitExternalTextures");
 
1348
    CloseExternalTextures();
 
1349
    InitHiresTextures();
 
1350
    InitTextureDump();
 
1351
}
 
1352
 
 
1353
/*
 
1354
ExtTxtrInfo.height ExtTxtrInfo.width are ints.
 
1355
TxtrInfo.HeightToLoad TxtrInfo.WidthToLoad (ti of TxtrCacheEntry 
 
1356
is of type TxtrInfo) are uint32.
 
1357
*/
 
1358
int FindScaleFactor(const ExtTxtrInfo &info, TxtrCacheEntry &entry)
 
1359
{
 
1360
    int scaleShift = 0;
 
1361
 
 
1362
    // find the smallest power of 2 which is greater than or equal to the ratio of the hi-res texture's
 
1363
    // dimensions to the original (N64) texture dimensions
 
1364
    while (info.height > (int) entry.ti.HeightToLoad * (1 << scaleShift) && info.width > (int) entry.ti.WidthToLoad * (1 << scaleShift))
 
1365
    {
 
1366
        scaleShift++;
 
1367
    }
 
1368
    // if the ratio of the 2 textures' dimensions is an even power of 2, then the hi-res texture is allowed
 
1369
    if (info.height == (int) entry.ti.HeightToLoad * (1 << scaleShift) && info.width == (int) entry.ti.WidthToLoad * (1 << scaleShift))
 
1370
    {
 
1371
        // found appropriate scale shift, return it
 
1372
        return scaleShift;
 
1373
    }
 
1374
 
 
1375
    // the dimensions of the hires replacement are not power of 2 of the original texture
 
1376
    return -1;
 
1377
}
 
1378
 
 
1379
int CheckTextureInfos( CSortedList<uint64,ExtTxtrInfo> &infos, TxtrCacheEntry &entry, int &indexa, int &scaleShift, bool bForDump = false)
 
1380
{
 
1381
    if(entry.ti.WidthToCreate/entry.ti.WidthToLoad > 2 || entry.ti.HeightToCreate/entry.ti.HeightToLoad > 2 )
 
1382
    {
 
1383
        //DebugMessage(M64MSG_WARNING, "Hires texture does not support extreme texture replication");
 
1384
        return -1;
 
1385
    }
 
1386
 
 
1387
    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
 
 
1389
    uint64 crc64a = entry.dwCRC;
 
1390
    crc64a <<= 32;
 
1391
    uint64 crc64b = crc64a;
 
1392
    crc64a |= (0xFFFFFF00|(entry.ti.Format<<4)|entry.ti.Size);
 
1393
    crc64b |= ((entry.dwPalCRC&0xFFFFFF00)|(entry.ti.Format<<4)|entry.ti.Size);
 
1394
 
 
1395
    int infosize = infos.size();
 
1396
    int indexb=-1;
 
1397
    indexa = infos.find(crc64a);        // For CI without pal CRC, and for RGBA_PNG_FOR_ALL_CI
 
1398
    if( bCI )   
 
1399
        indexb = infos.find(crc64b);    // For CI or PNG with pal CRC
 
1400
 
 
1401
    if( indexa >= infosize )    indexa = -1;
 
1402
    if( indexb >= infosize )    indexb = -1;
 
1403
 
 
1404
    scaleShift = -1;
 
1405
 
 
1406
    if( indexb >= 0 )
 
1407
    {
 
1408
        scaleShift = FindScaleFactor(infos[indexb], entry);
 
1409
        if( scaleShift >= 0 )
 
1410
            return indexb;
 
1411
    }
 
1412
 
 
1413
    if( bForDump && bCI && indexb < 0)
 
1414
        return -1;
 
1415
 
 
1416
    if( indexa >= 0 )   scaleShift = FindScaleFactor(infos[indexa], entry);
 
1417
 
 
1418
    if( scaleShift >= 0 )
 
1419
        return indexa;
 
1420
    else
 
1421
        return -1;
 
1422
}
 
1423
 
 
1424
bool SaveCITextureToFile(TxtrCacheEntry &entry, char *filename, bool bShow, bool bWhole);
 
1425
 
 
1426
void DumpCachedTexture( TxtrCacheEntry &entry )
 
1427
{
 
1428
    char cSep = '/';
 
1429
 
 
1430
    CTexture *pSrcTexture = entry.pTexture;
 
1431
    if( pSrcTexture )
 
1432
    {
 
1433
        // Check the vector table
 
1434
        int ciidx, scaleShift;
 
1435
        if( CheckTextureInfos(gTxtrDumpInfos,entry,ciidx,scaleShift,true) >= 0 )
 
1436
            return;     // This texture has been dumpped
 
1437
 
 
1438
        char filename1[PATH_MAX + 64];
 
1439
        char filename2[PATH_MAX + 64];
 
1440
        char filename3[PATH_MAX + 64];
 
1441
        char gamefolder[PATH_MAX + 64];
 
1442
        strncpy(gamefolder, ConfigGetUserDataPath(), PATH_MAX);
 
1443
        gamefolder[PATH_MAX] = 0;
 
1444
        
 
1445
        strcat(gamefolder,"texture_dump" OSAL_DIR_SEPARATOR_STR);
 
1446
        strcat(gamefolder,(const char*)g_curRomInfo.szGameName);
 
1447
        strcat(gamefolder, OSAL_DIR_SEPARATOR_STR);
 
1448
 
 
1449
        //sprintf(filename1+strlen(filename1), "%08X#%d#%d", entry.dwCRC, entry.ti.Format, entry.ti.Size);
 
1450
        sprintf(filename1, "%s%s#%08X#%d#%d", gamefolder, g_curRomInfo.szGameName, entry.dwCRC, entry.ti.Format, entry.ti.Size);
 
1451
 
 
1452
        if( (gRDP.otherMode.text_tlut>=2 || entry.ti.Format == TXT_FMT_CI || entry.ti.Format == TXT_FMT_RGBA) && entry.ti.Size <= TXT_SIZE_8b )
 
1453
        {
 
1454
            if( ciidx < 0 )
 
1455
            {
 
1456
                sprintf(filename1, "%sci_bmp%c%s#%08X#%d#%d_ci", gamefolder, cSep, g_curRomInfo.szGameName, entry.dwCRC, entry.ti.Format, entry.ti.Size);
 
1457
                SaveCITextureToFile(entry, filename1, false, false);
 
1458
            }
 
1459
 
 
1460
            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);
 
1461
            SaveCITextureToFile(entry, filename1, false, false);
 
1462
 
 
1463
            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);
 
1464
            CRender::g_pRender->SaveTextureToFile(*pSrcTexture, filename1, TXT_RGBA, false, false, entry.ti.WidthToLoad, entry.ti.HeightToLoad);
 
1465
        }
 
1466
        else
 
1467
        {
 
1468
            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);
 
1469
            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);
 
1470
            sprintf(filename3, "%spng_all%c%s#%08X#%d#%d_all", gamefolder, cSep, g_curRomInfo.szGameName, entry.dwCRC, entry.ti.Format, entry.ti.Size);
 
1471
 
 
1472
 
 
1473
            CRender::g_pRender->SaveTextureToFile(*pSrcTexture, filename1, TXT_RGB, false, false, entry.ti.WidthToLoad, entry.ti.HeightToLoad);
 
1474
            CRender::g_pRender->SaveTextureToFile(*pSrcTexture, filename3, TXT_RGBA, false, false, entry.ti.WidthToLoad, entry.ti.HeightToLoad);
 
1475
            if( entry.ti.Format != TXT_FMT_I )
 
1476
            {
 
1477
                DrawInfo srcInfo;   
 
1478
                uint32 aFF = 0xFF;
 
1479
                if( pSrcTexture->StartUpdate(&srcInfo) )
 
1480
                {
 
1481
                    // Copy RGB to buffer
 
1482
                    for( int i=entry.ti.HeightToLoad-1; i>=0; i--)
 
1483
                    {
 
1484
                        unsigned char *pSrc = (unsigned char*)srcInfo.lpSurface+srcInfo.lPitch * i;
 
1485
                        for( uint32 j=0; j<entry.ti.WidthToLoad; j++)
 
1486
                        {
 
1487
                            aFF &= pSrc[3];
 
1488
                            pSrc += 4;
 
1489
                        }
 
1490
                    }
 
1491
                    pSrcTexture->EndUpdate(&srcInfo);
 
1492
                }
 
1493
 
 
1494
                if( aFF != 0xFF)
 
1495
                    CRender::g_pRender->SaveTextureToFile(*pSrcTexture, filename2, TXT_ALPHA, false, false);
 
1496
            }       
 
1497
        }
 
1498
 
 
1499
        ExtTxtrInfo newinfo;
 
1500
        newinfo.width = entry.ti.WidthToLoad;
 
1501
        newinfo.height = entry.ti.HeightToLoad;
 
1502
        //strcpy(newinfo.name,g_curRomInfo.szGameName);
 
1503
        newinfo.fmt = entry.ti.Format;
 
1504
        newinfo.siz = entry.ti.Size;
 
1505
        newinfo.crc32 = entry.dwCRC;
 
1506
 
 
1507
        newinfo.pal_crc32 = entry.dwPalCRC;
 
1508
        newinfo.foldername = NULL;
 
1509
        newinfo.RGBNameTail[0] = newinfo.AlphaNameTail[0] = 0;
 
1510
 
 
1511
        uint64 crc64 = newinfo.crc32;
 
1512
        crc64 <<= 32;
 
1513
        crc64 |= (newinfo.pal_crc32&0xFFFFFF00)|(newinfo.fmt<<4)|newinfo.siz;
 
1514
        gTxtrDumpInfos.add(crc64,newinfo);
 
1515
 
 
1516
    }
 
1517
}
 
1518
 
 
1519
bool LoadRGBBufferFromPNGFile(char *filename, unsigned char **pbuf, int &width, int &height, int bits_per_pixel = 24 )
 
1520
{
 
1521
    struct BMGImageStruct img;
 
1522
    memset(&img, 0, sizeof(BMGImageStruct));
 
1523
    if (!PathFileExists(filename))
 
1524
    {
 
1525
        DebugMessage(M64MSG_ERROR, "File at '%s' doesn't exist in LoadRGBBufferFromPNGFile!", filename);
 
1526
        return false;
 
1527
    }
 
1528
 
 
1529
    BMG_Error code = ReadPNG( filename, &img );
 
1530
    if( code == BMG_OK )
 
1531
    {
 
1532
        *pbuf = NULL;
 
1533
 
 
1534
        *pbuf = new unsigned char[img.width*img.height*bits_per_pixel/8];
 
1535
        if (*pbuf == NULL)
 
1536
        {
 
1537
            DebugMessage(M64MSG_ERROR, "new[] returned NULL for image width=%i height=%i bpp=%i", img.width, img.height, bits_per_pixel);
 
1538
            return false;
 
1539
        }
 
1540
        if (img.bits_per_pixel == bits_per_pixel)
 
1541
        {
 
1542
            memcpy(*pbuf, img.bits, img.width*img.height*bits_per_pixel/8);
 
1543
        }
 
1544
        else if (img.bits_per_pixel == 24 && bits_per_pixel == 32)
 
1545
        {
 
1546
            unsigned char *pSrc = img.bits;
 
1547
            unsigned char *pDst = *pbuf;
 
1548
            for (int i = 0; i < (int)(img.width*img.height); i++)
 
1549
            {
 
1550
                *pDst++ = *pSrc++;
 
1551
                *pDst++ = *pSrc++;
 
1552
                *pDst++ = *pSrc++;
 
1553
                *pDst++ = 0;
 
1554
            }
 
1555
        }
 
1556
        else if (img.bits_per_pixel == 32 && bits_per_pixel == 24)
 
1557
        {
 
1558
            unsigned char *pSrc = img.bits;
 
1559
            unsigned char *pDst = *pbuf;
 
1560
            for (int i = 0; i < (int)(img.width*img.height); i++)
 
1561
            {
 
1562
                *pDst++ = *pSrc++;
 
1563
                *pDst++ = *pSrc++;
 
1564
                *pDst++ = *pSrc++;
 
1565
                pSrc++;
 
1566
            }
 
1567
        }
 
1568
        else if (img.bits_per_pixel == 8 && (bits_per_pixel == 24 || bits_per_pixel == 32))
 
1569
        {
 
1570
            // do palette lookup and convert 8bpp to 24/32bpp
 
1571
            int destBytePP = bits_per_pixel / 8;
 
1572
            int paletteBytePP = img.bytes_per_palette_entry;
 
1573
            unsigned char *pSrc = img.bits;
 
1574
            unsigned char *pDst = *pbuf;
 
1575
            // clear the destination image data (just to clear alpha if bpp=32)
 
1576
            memset(*pbuf, 0, img.width*img.height*destBytePP);
 
1577
            for (int i = 0; i < (int)(img.width*img.height); i++)
 
1578
            {
 
1579
                unsigned char clridx = *pSrc++;
 
1580
                unsigned char *palcolor = img.palette + clridx * paletteBytePP;
 
1581
                pDst[0] = palcolor[2]; // red
 
1582
                pDst[1] = palcolor[1]; // green
 
1583
                pDst[2] = palcolor[0]; // blue
 
1584
                pDst += destBytePP;
 
1585
            }
 
1586
        }
 
1587
        else
 
1588
        {
 
1589
            DebugMessage(M64MSG_ERROR, "PNG file '%s' is %i bpp but texture is %i bpp.", filename, img.bits_per_pixel, bits_per_pixel);
 
1590
            delete [] *pbuf;
 
1591
            *pbuf = NULL;
 
1592
        }
 
1593
 
 
1594
        width = img.width;
 
1595
        height = img.height;
 
1596
        FreeBMGImage(&img);
 
1597
 
 
1598
        return true;
 
1599
    }
 
1600
    else
 
1601
    {
 
1602
        DebugMessage(M64MSG_ERROR, "ReadPNG() returned error for '%s' in LoadRGBBufferFromPNGFile!", filename);
 
1603
        *pbuf = NULL;
 
1604
        return false;
 
1605
    }
 
1606
}
 
1607
 
 
1608
bool LoadRGBABufferFromColorIndexedFile(char *filename, TxtrCacheEntry &entry, unsigned char **pbuf, int &width, int &height)
 
1609
{
 
1610
    BITMAPFILEHEADER fileHeader;
 
1611
    BITMAPINFOHEADER infoHeader;
 
1612
 
 
1613
    FILE *f;
 
1614
    f = fopen(filename, "rb");
 
1615
    if(f != NULL)
 
1616
    {
 
1617
        if (fread(&fileHeader, sizeof(BITMAPFILEHEADER), 1, f) != 1 ||
 
1618
            fread(&infoHeader, sizeof(BITMAPINFOHEADER), 1, f) != 1)
 
1619
        {
 
1620
            DebugMessage(M64MSG_ERROR, "Couldn't read BMP headers in file '%s'", filename);
 
1621
            return false;
 
1622
        }
 
1623
 
 
1624
        if( infoHeader.biBitCount != 4 && infoHeader.biBitCount != 8 )
 
1625
        {
 
1626
            fclose(f);
 
1627
            DebugMessage(M64MSG_ERROR, "Unsupported BMP file format: %s", filename);
 
1628
            *pbuf = NULL;
 
1629
            return false;
 
1630
        }
 
1631
 
 
1632
        int tablesize = infoHeader.biBitCount == 4 ? 16 : 256;
 
1633
        uint32 *pTable = new uint32[tablesize];
 
1634
        if (fread(pTable, tablesize*4, 1, f) != 1)
 
1635
        {
 
1636
            DebugMessage(M64MSG_ERROR, "Couldn't read BMP palette in file '%s'", filename);
 
1637
            delete [] pTable;
 
1638
            return false;
 
1639
        }
 
1640
 
 
1641
        // Create the pallette table
 
1642
        uint16 * pPal = (uint16 *)entry.ti.PalAddress;
 
1643
        if( entry.ti.Size == TXT_SIZE_4b )
 
1644
        {
 
1645
            // 4-bit table
 
1646
            for( int i=0; i<16; i++ )
 
1647
            {
 
1648
                pTable[i] = entry.ti.TLutFmt == TLUT_FMT_RGBA16 ? Convert555ToRGBA(pPal[i^1]) : ConvertIA16ToRGBA(pPal[i^1]);
 
1649
            }
 
1650
        }
 
1651
        else
 
1652
        {
 
1653
            // 8-bit table
 
1654
            for( int i=0; i<256; i++ )
 
1655
            {
 
1656
                pTable[i] = entry.ti.TLutFmt == TLUT_FMT_RGBA16 ? Convert555ToRGBA(pPal[i^1]) : ConvertIA16ToRGBA(pPal[i^1]);
 
1657
            }
 
1658
        }
 
1659
 
 
1660
        *pbuf = new unsigned char[infoHeader.biWidth*infoHeader.biHeight*4];
 
1661
        if( *pbuf )
 
1662
        {
 
1663
            unsigned char *colorIdxBuf = new unsigned char[infoHeader.biSizeImage];
 
1664
            if( colorIdxBuf )
 
1665
            {
 
1666
                if (fread(colorIdxBuf, infoHeader.biSizeImage, 1, f) != 1)
 
1667
                {
 
1668
                    DebugMessage(M64MSG_ERROR, "Couldn't read BMP image data in file '%s'", filename);
 
1669
                }
 
1670
 
 
1671
                width = infoHeader.biWidth;
 
1672
                height = infoHeader.biHeight;
 
1673
 
 
1674
                // Converting pallette texture to RGBA texture
 
1675
                int idx = 0;
 
1676
                uint32 *pbuf2 = (uint32*) *pbuf;
 
1677
 
 
1678
                for( int i=height-1; i>=0; i--)
 
1679
                {
 
1680
                    for( int j=0; j<width; j++)
 
1681
                    {
 
1682
                        if( entry.ti.Size == TXT_SIZE_4b )
 
1683
                        {
 
1684
                            // 4 bits
 
1685
                            if( idx%2 )
 
1686
                            {
 
1687
                                // 1
 
1688
                                *pbuf2++ = pTable[colorIdxBuf[(idx++)>>1]&0xF];
 
1689
                            }
 
1690
                            else
 
1691
                            {
 
1692
                                // 0
 
1693
                                *pbuf2++ = pTable[(colorIdxBuf[(idx++)>>1]>>4)&0xF];
 
1694
                            }
 
1695
                        }
 
1696
                        else
 
1697
                        {
 
1698
                            // 8 bits
 
1699
                            *pbuf2++ = pTable[colorIdxBuf[idx++]];
 
1700
                        }
 
1701
                    }
 
1702
                    if( entry.ti.Size == TXT_SIZE_4b )
 
1703
                    {
 
1704
                        if( idx%8 ) idx = (idx/8+1)*8;
 
1705
                    }
 
1706
                    else
 
1707
                    {
 
1708
                        if( idx%4 ) idx = (idx/4+1)*4;
 
1709
                    }
 
1710
                }
 
1711
 
 
1712
                delete [] colorIdxBuf;
 
1713
            }
 
1714
            else
 
1715
            {
 
1716
                TRACE0("Out of memory");
 
1717
            }
 
1718
 
 
1719
            delete [] pTable;
 
1720
            return true;
 
1721
        }
 
1722
        else
 
1723
        {
 
1724
            fclose(f);
 
1725
            delete [] pTable;
 
1726
            return false;
 
1727
        }
 
1728
    }
 
1729
    else
 
1730
    {
 
1731
        // Do something
 
1732
        TRACE1("Fail to open file %s", filename);
 
1733
        *pbuf = NULL;
 
1734
        return false;
 
1735
    }
 
1736
}
 
1737
 
 
1738
bool LoadRGBBufferFromBMPFile(char *filename, unsigned char **pbuf, int &width, int &height)
 
1739
{
 
1740
    BITMAPFILEHEADER fileHeader;
 
1741
    BITMAPINFOHEADER infoHeader;
 
1742
 
 
1743
    FILE *f;
 
1744
    f = fopen(filename, "rb");
 
1745
    if(f != NULL)
 
1746
    {
 
1747
        if (fread(&fileHeader, sizeof(BITMAPFILEHEADER), 1, f) != 1 ||
 
1748
            fread(&infoHeader, sizeof(BITMAPINFOHEADER), 1, f) != 1)
 
1749
        {
 
1750
            DebugMessage(M64MSG_ERROR, "Couldn't read BMP headers in file '%s'", filename);
 
1751
            return false;
 
1752
        }
 
1753
 
 
1754
        if( infoHeader.biBitCount != 24 )
 
1755
        {
 
1756
            fclose(f);
 
1757
            DebugMessage(M64MSG_ERROR, "Unsupported BMP file 16 bits format: %s", filename);
 
1758
            *pbuf = NULL;
 
1759
            return false;
 
1760
        }
 
1761
 
 
1762
        *pbuf = new unsigned char[infoHeader.biWidth*infoHeader.biHeight*3];
 
1763
        if( *pbuf )
 
1764
        {
 
1765
            if (fread(*pbuf, infoHeader.biWidth*infoHeader.biHeight*3, 1, f) != 1)
 
1766
                DebugMessage(M64MSG_ERROR, "Couldn't read RGB BMP image data in file '%s'", filename);
 
1767
            fclose(f);
 
1768
            width = infoHeader.biWidth;
 
1769
            height = infoHeader.biHeight;
 
1770
            return true;
 
1771
        }
 
1772
        else
 
1773
        {
 
1774
            fclose(f);
 
1775
            return false;
 
1776
        }
 
1777
    }
 
1778
    else
 
1779
    {
 
1780
        // Do something
 
1781
        DebugMessage(M64MSG_WARNING, "Fail to open file %s", filename);
 
1782
        *pbuf = NULL;
 
1783
        return false;
 
1784
    }
 
1785
}
 
1786
 
 
1787
void LoadHiresTexture( TxtrCacheEntry &entry )
 
1788
{
 
1789
    if( entry.bExternalTxtrChecked )
 
1790
        return;
 
1791
 
 
1792
    if( entry.pEnhancedTexture )
 
1793
    {
 
1794
        SAFE_DELETE(entry.pEnhancedTexture);
 
1795
    }
 
1796
 
 
1797
    int ciidx, scaleShift;
 
1798
    int idx = CheckTextureInfos(gHiresTxtrInfos,entry,ciidx,scaleShift,false);
 
1799
    if( idx < 0 )
 
1800
    {
 
1801
        entry.bExternalTxtrChecked = true;
 
1802
        return;
 
1803
    }
 
1804
 
 
1805
    // Load the bitmap file
 
1806
    char filename_rgb[PATH_MAX];
 
1807
    char filename_a[PATH_MAX];
 
1808
 
 
1809
    strcpy(filename_rgb, gHiresTxtrInfos[idx].foldername);
 
1810
 
 
1811
    sprintf(filename_rgb+strlen(filename_rgb), "%s#%08X#%d#%d", g_curRomInfo.szGameName, entry.dwCRC, entry.ti.Format, entry.ti.Size);
 
1812
    strcpy(filename_a,filename_rgb);
 
1813
    strcat(filename_rgb,gHiresTxtrInfos[idx].RGBNameTail);
 
1814
    strcat(filename_a,gHiresTxtrInfos[idx].AlphaNameTail);
 
1815
 
 
1816
    // Load BMP image to buffer_rbg
 
1817
    unsigned char *buf_rgba = NULL;
 
1818
    unsigned char *buf_a = NULL;
 
1819
    int width, height;
 
1820
 
 
1821
    bool bResRGBA=false, bResA=false;
 
1822
    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 );
 
1823
 
 
1824
    switch( gHiresTxtrInfos[idx].type )
 
1825
    {
 
1826
        case RGB_PNG:
 
1827
            if( bCI )   
 
1828
                return;
 
1829
            else
 
1830
            {
 
1831
                bResRGBA = LoadRGBBufferFromPNGFile(filename_rgb, &buf_rgba, width, height);
 
1832
                if( bResRGBA && gHiresTxtrInfos[idx].bSeparatedAlpha )
 
1833
                    bResA = LoadRGBBufferFromPNGFile(filename_a, &buf_a, width, height);
 
1834
            }
 
1835
            break;
 
1836
        case COLOR_INDEXED_BMP:
 
1837
            if( bCI )   
 
1838
                bResRGBA = LoadRGBABufferFromColorIndexedFile(filename_rgb, entry, &buf_rgba, width, height);
 
1839
            else
 
1840
                return;
 
1841
            break;
 
1842
        case RGBA_PNG_FOR_CI:
 
1843
        case RGBA_PNG_FOR_ALL_CI:
 
1844
            if( bCI )   
 
1845
                bResRGBA = LoadRGBBufferFromPNGFile(filename_rgb, &buf_rgba, width, height, 32);
 
1846
            else
 
1847
                return;
 
1848
            break;
 
1849
        case RGB_WITH_ALPHA_TOGETHER_PNG:
 
1850
            if( bCI )   
 
1851
                return;
 
1852
            else
 
1853
                bResRGBA = LoadRGBBufferFromPNGFile(filename_rgb, &buf_rgba, width, height, 32);
 
1854
            break;
 
1855
        default:
 
1856
            return;
 
1857
    }
 
1858
 
 
1859
    if( !bResRGBA )
 
1860
    {
 
1861
        DebugMessage(M64MSG_ERROR, "RGBBuffer creation failed for file '%s'.", filename_rgb);
 
1862
        return;
 
1863
    }
 
1864
    else if( gHiresTxtrInfos[idx].bSeparatedAlpha && !bResA )
 
1865
    {
 
1866
        DebugMessage(M64MSG_ERROR, "Alpha buffer creation failed for file '%s'.", filename_a);
 
1867
        delete [] buf_rgba;
 
1868
        return;
 
1869
    }
 
1870
 
 
1871
    // calculate the texture size magnification by comparing the N64 texture size and the hi-res texture size
 
1872
    int scalex = width / (int)entry.ti.WidthToLoad;
 
1873
    int scaley = height / (int)entry.ti.HeightToLoad;
 
1874
    int mirrorx = 1;
 
1875
    int mirrory = 1;
 
1876
    if (entry.ti.WidthToCreate/entry.ti.WidthToLoad == 2) mirrorx = 2;
 
1877
    if (entry.ti.HeightToCreate/entry.ti.HeightToLoad == 2) mirrory = 2;
 
1878
    entry.pEnhancedTexture = CDeviceBuilder::GetBuilder()->CreateTexture(entry.ti.WidthToCreate*scalex*mirrorx, entry.ti.HeightToCreate*scaley*mirrory);
 
1879
    DrawInfo info;
 
1880
 
 
1881
    if( entry.pEnhancedTexture && entry.pEnhancedTexture->StartUpdate(&info) )
 
1882
    {
 
1883
 
 
1884
        if( gHiresTxtrInfos[idx].type == RGB_PNG )
 
1885
        {
 
1886
            unsigned char *pRGB = buf_rgba;
 
1887
            unsigned char *pA = buf_a;
 
1888
 
 
1889
            if (info.lPitch < width * 4)
 
1890
                DebugMessage(M64MSG_ERROR, "Texture pitch %i less than width %i times 4", info.lPitch, width);
 
1891
            if (height > info.dwHeight)
 
1892
                DebugMessage(M64MSG_ERROR, "Texture source height %i greater than destination height %i", height, info.dwHeight);
 
1893
 
 
1894
            // Update the texture by using the buffer
 
1895
            for( int i=height-1; i>=0; i--)
 
1896
            {
 
1897
                unsigned char* pdst = (unsigned char*)info.lpSurface + i*info.lPitch;
 
1898
                for( int j=0; j<width; j++)
 
1899
                {
 
1900
                    *pdst++ = *pRGB++;      // R
 
1901
                    *pdst++ = *pRGB++;      // G
 
1902
                    *pdst++ = *pRGB++;      // B
 
1903
 
 
1904
                    if( gHiresTxtrInfos[idx].bSeparatedAlpha )
 
1905
                    {
 
1906
                        *pdst++ = *pA;
 
1907
                        pA += 3;
 
1908
                    }
 
1909
                    else if( entry.ti.Format == TXT_FMT_I )
 
1910
                    {
 
1911
                        *pdst++ = pRGB[-1];
 
1912
                    }
 
1913
                    else
 
1914
                    {
 
1915
                        *pdst++ = 0xFF;
 
1916
                    }
 
1917
                }
 
1918
            }
 
1919
        }
 
1920
        else
 
1921
        {
 
1922
            // Update the texture by using the buffer
 
1923
            uint32 *pRGB = (uint32*)buf_rgba;
 
1924
            for( int i=height-1; i>=0; i--)
 
1925
            {
 
1926
                uint32 *pdst = (uint32*)((unsigned char*)info.lpSurface + i*info.lPitch);
 
1927
                for( int j=0; j<width; j++)
 
1928
                {
 
1929
                    *pdst++ = *pRGB++;      // RGBA
 
1930
                }
 
1931
            }
 
1932
        }
 
1933
 
 
1934
        if (mirrorx == 2)
 
1935
        {
 
1936
            //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);
 
1937
            gTextureManager.Mirror(info.lpSurface, width, entry.ti.maskS+scaleShift, width*2, width*2, height, S_FLAG, 4 );
 
1938
        }
 
1939
 
 
1940
        if (mirrory == 2)
 
1941
        {
 
1942
            //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);
 
1943
            gTextureManager.Mirror(info.lpSurface, height, entry.ti.maskT+scaleShift, height*2, entry.pEnhancedTexture->m_dwCreatedTextureWidth, height, T_FLAG, 4 );
 
1944
        }
 
1945
 
 
1946
        if( entry.ti.WidthToCreate*scalex*mirrorx < entry.pEnhancedTexture->m_dwCreatedTextureWidth )
 
1947
        {
 
1948
            // Clamp
 
1949
            gTextureManager.Clamp(info.lpSurface, width, entry.pEnhancedTexture->m_dwCreatedTextureWidth, entry.pEnhancedTexture->m_dwCreatedTextureWidth, height, S_FLAG, 4 );
 
1950
        }
 
1951
        if( entry.ti.HeightToCreate*scaley*mirrory < entry.pEnhancedTexture->m_dwCreatedTextureHeight )
 
1952
        {
 
1953
            // Clamp
 
1954
            gTextureManager.Clamp(info.lpSurface, height, entry.pEnhancedTexture->m_dwCreatedTextureHeight, entry.pEnhancedTexture->m_dwCreatedTextureWidth, height, T_FLAG, 4 );
 
1955
        }
 
1956
 
 
1957
        entry.pEnhancedTexture->EndUpdate(&info);
 
1958
        entry.pEnhancedTexture->SetOthersVariables();
 
1959
        entry.pEnhancedTexture->m_bIsEnhancedTexture = true;
 
1960
        entry.dwEnhancementFlag = TEXTURE_EXTERNAL;
 
1961
 
 
1962
        DebugMessage(M64MSG_VERBOSE, "Loaded hi-res texture: %s", filename_rgb);
 
1963
    }
 
1964
    else
 
1965
    {
 
1966
        DebugMessage(M64MSG_ERROR, "New texture creation failed.");
 
1967
        TRACE0("Cannot create a new texture");
 
1968
    }
 
1969
 
 
1970
    if( buf_rgba )
 
1971
    {
 
1972
        delete [] buf_rgba;
 
1973
    }
 
1974
 
 
1975
    if( buf_a )
 
1976
    {
 
1977
        delete [] buf_a;
 
1978
    }
 
1979
}
 
1980