ALL: Huge upstream synch + PerRom DelaySI & CountPerOp parameters
[mupen64plus-pandora.git] / source / gles2glide64 / src / GlideHQ / TxFilter.cpp
1 /*
2  * Texture Filtering
3  * Version:  1.0
4  *
5  * Copyright (C) 2007  Hiroshi Morii   All Rights Reserved.
6  * Email koolsmoky(at)users.sourceforge.net
7  * Web   http://www.3dfxzone.it/koolsmoky
8  *
9  * this is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2, or (at your option)
12  * any later version.
13  *
14  * this is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with GNU Make; see the file COPYING.  If not, write to
21  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
22  */
23
24 #ifdef __MSC__
25 #pragma warning(disable: 4786)
26 #endif
27
28 #include "TxFilter.h"
29 #include "TextureFilters.h"
30 #include "TxDbg.h"
31 #ifndef NO_FILTER_THREAD
32 #include <functional>
33 #include <thread>
34 #endif
35 #if defined(__MINGW32__)
36 #define swprintf _snwprintf
37 #endif
38
39 void TxFilter::clear()
40 {
41   /* clear hires texture cache */
42   delete _txHiResCache;
43   _txHiResCache = NULL;
44
45   /* clear texture cache */
46   delete _txTexCache;
47   _txTexCache = NULL;
48
49   /* free memory */
50   TxMemBuf::getInstance()->shutdown();
51
52   /* clear other stuff */
53   delete _txImage;
54   _txImage = NULL;
55   delete _txQuantize;
56   _txQuantize = NULL;
57   delete _txUtil;
58   _txUtil = NULL;
59 }
60
61 TxFilter::~TxFilter()
62 {
63   clear();
64 }
65
66 TxFilter::TxFilter(int maxwidth, int maxheight, int maxbpp, int options,
67                    int cachesize, wchar_t *datapath, wchar_t *cachepath,
68                    wchar_t *ident, dispInfoFuncExt callback) :
69   _numcore(1), _tex1(NULL), _tex2(NULL), _maxwidth(0), _maxheight(0),
70   _maxbpp(0), _options(0), _cacheSize(0), _ident(), _datapath(), _cachepath(),
71   _txQuantize(NULL), _txTexCache(NULL), _txHiResCache(NULL), _txUtil(NULL),
72   _txImage(NULL), _initialized(false)
73 {
74   clear(); /* gcc does not allow the destructor to be called */
75
76   /* shamelessness :P this first call to the debug output message creates
77    * a file in the executable directory. */
78   INFO(0, L"------------------------------------------------------------------\n");
79 #ifdef GHQCHK
80   INFO(0, L" GlideHQ Hires Texture Checker 1.02.00.%d\n", 0);
81 #else
82   INFO(0, L" GlideHQ version 1.02.00.%d\n", 0);
83 #endif
84   INFO(0, L" Copyright (C) 2010  Hiroshi Morii   All Rights Reserved\n");
85   INFO(0, L"    email   : koolsmoky(at)users.sourceforge.net\n");
86   INFO(0, L"    website : http://www.3dfxzone.it/koolsmoky\n");
87   INFO(0, L"\n");
88   INFO(0, L" Glide64 official website : http://glide64.emuxhaven.net\n");
89   INFO(0, L"------------------------------------------------------------------\n");
90
91   _options = options;
92
93   _txImage      = new TxImage();
94   _txQuantize   = new TxQuantize();
95   _txUtil       = new TxUtil();
96
97   /* get number of CPU cores. */
98   _numcore = _txUtil->getNumberofProcessors();
99
100   _initialized = 0;
101
102   _tex1 = NULL;
103   _tex2 = NULL;
104
105   /* XXX: anything larger than 1024 * 1024 is overkill */
106   _maxwidth  = maxwidth  > 1024 ? 1024 : maxwidth;
107   _maxheight = maxheight > 1024 ? 1024 : maxheight;
108   _maxbpp    = maxbpp;
109
110   _cacheSize = cachesize;
111
112   /* TODO: validate options and do overrides here*/
113
114   /* save path name */
115   if (datapath)
116     _datapath.assign(datapath);
117   if (cachepath)
118     _cachepath.assign(cachepath);
119
120   /* save ROM name */
121   if (ident && wcscmp(ident, L"DEFAULT") != 0)
122     _ident.assign(ident);
123
124   /* check for dxtn extensions */
125   if (!TxLoadLib::getInstance()->getdxtCompressTexFuncExt())
126     _options &= ~S3TC_COMPRESSION;
127
128   if (!TxLoadLib::getInstance()->getfxtCompressTexFuncExt())
129     _options &= ~FXT1_COMPRESSION;
130
131   switch (options & COMPRESSION_MASK) {
132   case FXT1_COMPRESSION:
133   case S3TC_COMPRESSION:
134     break;
135   case NCC_COMPRESSION:
136   default:
137     _options &= ~COMPRESSION_MASK;
138   }
139
140   if (TxMemBuf::getInstance()->init(_maxwidth, _maxheight)) {
141     if (!_tex1)
142       _tex1 = TxMemBuf::getInstance()->get(0);
143
144     if (!_tex2)
145       _tex2 = TxMemBuf::getInstance()->get(1);
146   }
147
148 #if !_16BPP_HACK
149   /* initialize hq4x filter */
150   hq4x_init();
151 #endif
152
153   /* initialize texture cache in bytes. 128Mb will do nicely in most cases */
154   _txTexCache = new TxTexCache(_options, _cacheSize, _datapath.c_str(), _cachepath.c_str(), _ident.c_str(), callback);
155
156   /* hires texture */
157 #if HIRES_TEXTURE
158   _txHiResCache = new TxHiResCache(_maxwidth, _maxheight, _maxbpp, _options, _datapath.c_str(), _cachepath.c_str(), _ident.c_str(), callback);
159
160   if (_txHiResCache->empty())
161     _options &= ~HIRESTEXTURES_MASK;
162 #endif
163
164   if (!(_options & COMPRESS_TEX))
165     _options &= ~COMPRESSION_MASK;
166
167   if (_tex1 && _tex2)
168       _initialized = 1;
169 }
170
171 boolean
172 TxFilter::filter(uint8 *src, int srcwidth, int srcheight, uint16 srcformat, uint64 g64crc, GHQTexInfo *info)
173 {
174   uint8 *texture = src;
175   uint8 *tmptex = _tex1;
176   uint16 destformat = srcformat;
177
178   /* We need to be initialized first! */
179   if (!_initialized) return 0;
180
181   /* find cached textures */
182   if (_cacheSize) {
183
184     /* calculate checksum of source texture */
185     if (!g64crc)
186       g64crc = (uint64)(_txUtil->checksumTx(texture, srcwidth, srcheight, srcformat));
187
188     DBG_INFO(80, L"filter: crc:%08X %08X %d x %d gfmt:%x\n",
189              (uint32)(g64crc >> 32), (uint32)(g64crc & 0xffffffff), srcwidth, srcheight, srcformat);
190
191 #if 0 /* use hirestex to retrieve cached textures. */
192     /* check if we have it in cache */
193     if (!(g64crc & 0xffffffff00000000) && /* we reach here only when there is no hires texture for this crc */
194         _txTexCache->get(g64crc, info)) {
195       DBG_INFO(80, L"cache hit: %d x %d gfmt:%x\n", info->width, info->height, info->format);
196       return 1; /* yep, we've got it */
197     }
198 #endif
199   }
200
201   /* Leave small textures alone because filtering makes little difference.
202    * Moreover, some filters require at least 4 * 4 to work.
203    * Bypass _options to do ARGB8888->16bpp if _maxbpp=16 or forced color reduction.
204    */
205   if ((srcwidth >= 4 && srcheight >= 4) &&
206       ((_options & (FILTER_MASK|ENHANCEMENT_MASK|COMPRESSION_MASK)) ||
207        (srcformat == GR_TEXFMT_ARGB_8888 && (_maxbpp < 32 || _options & FORCE16BPP_TEX)))) {
208
209 #if !_16BPP_HACK
210     /* convert textures to a format that the compressor accepts (ARGB8888) */
211     if (_options & COMPRESSION_MASK) {
212 #endif
213       if (srcformat != GR_TEXFMT_ARGB_8888) {
214         if (!_txQuantize->quantize(texture, tmptex, srcwidth, srcheight, srcformat, GR_TEXFMT_ARGB_8888)) {
215           DBG_INFO(80, L"Error: unsupported format! gfmt:%x\n", srcformat);
216           return 0;
217         }
218         texture = tmptex;
219         destformat = GR_TEXFMT_ARGB_8888;
220       }
221 #if !_16BPP_HACK
222     }
223 #endif
224
225     switch (destformat) {
226     case GR_TEXFMT_ARGB_8888:
227
228       /*
229        * prepare texture enhancements (x2, x4 scalers)
230        */
231       int scale_shift = 0, num_filters = 0;
232       uint32 filter = 0;
233
234       if ((_options & ENHANCEMENT_MASK) == HQ4X_ENHANCEMENT) {
235         if (srcwidth  <= (_maxwidth >> 2) && srcheight <= (_maxheight >> 2)) {
236           filter |= HQ4X_ENHANCEMENT;
237           scale_shift = 2;
238           num_filters++;
239         } else if (srcwidth  <= (_maxwidth >> 1) && srcheight <= (_maxheight >> 1)) {
240           filter |= HQ2X_ENHANCEMENT;
241           scale_shift = 1;
242           num_filters++;
243         }
244       } else if (_options & ENHANCEMENT_MASK) {
245         if (srcwidth  <= (_maxwidth >> 1) && srcheight <= (_maxheight >> 1)) {
246           filter |= (_options & ENHANCEMENT_MASK);
247           scale_shift = 1;
248           num_filters++;
249         }
250       }
251
252       /*
253        * prepare texture filters
254        */
255       if (_options & (SMOOTH_FILTER_MASK|SHARP_FILTER_MASK)) {
256         filter |= (_options & (SMOOTH_FILTER_MASK|SHARP_FILTER_MASK));
257         num_filters++;
258       }
259
260       /*
261        * execute texture enhancements and filters
262        */
263       while (num_filters > 0) {
264
265         tmptex = (texture == _tex1) ? _tex2 : _tex1;
266
267         uint8 *_texture = texture;
268         uint8 *_tmptex  = tmptex;
269
270 #if !defined(NO_FILTER_THREAD)
271         unsigned int numcore = _numcore;
272         unsigned int blkrow = 0;
273         while (numcore > 1 && blkrow == 0) {
274           blkrow = (srcheight >> 2) / numcore;
275           numcore--;
276         }
277         if (blkrow > 0 && numcore > 1) {
278           std::thread *thrd[MAX_NUMCORE];
279           unsigned int i;
280           int blkheight = blkrow << 2;
281           unsigned int srcStride = (srcwidth * blkheight) << 2;
282           unsigned int destStride = srcStride << scale_shift << scale_shift;
283           for (i = 0; i < numcore - 1; i++) {
284             thrd[i] = new std::thread(std::bind(filter_8888,
285                                                 (uint32*)_texture,
286                                                 srcwidth,
287                                                 blkheight,
288                                                 (uint32*)_tmptex,
289                                                 filter));
290             _texture += srcStride;
291             _tmptex  += destStride;
292           }
293           thrd[i] = new std::thread(std::bind(filter_8888,
294                                               (uint32*)_texture,
295                                               srcwidth,
296                                               srcheight - blkheight * i,
297                                               (uint32*)_tmptex,
298                                               filter));
299           for (i = 0; i < numcore; i++) {
300             thrd[i]->join();
301             delete thrd[i];
302           }
303         } else {
304           filter_8888((uint32*)_texture, srcwidth, srcheight, (uint32*)_tmptex, filter);
305         }
306 #else
307         filter_8888((uint32*)_texture, srcwidth, srcheight, (uint32*)_tmptex, filter);
308 #endif
309
310         if (filter & ENHANCEMENT_MASK) {
311           srcwidth  <<= scale_shift;
312           srcheight <<= scale_shift;
313           filter &= ~ENHANCEMENT_MASK;
314           scale_shift = 0;
315         }
316
317         texture = tmptex;
318         num_filters--;
319       }
320
321       /*
322        * texture compression
323        */
324       /* ignored if we only have texture compression option on.
325        * only done when texture enhancer is used. see constructor. */
326       if ((_options & COMPRESSION_MASK) &&
327           (srcwidth >= 64 && srcheight >= 64) /* Texture compression is not suitable for low pixel coarse detail
328                                                * textures. The assumption here is that textures larger than 64x64
329                                                * have enough detail to produce decent quality when compressed. The
330                                                * down side is that narrow stripped textures that the N64 often use
331                                                * for large background textures are also ignored. It would be more
332                                                * reasonable if decisions are made based on fourier-transform
333                                                * spectrum or RMS error.
334                                                */
335           ) {
336         int compressionType = _options & COMPRESSION_MASK;
337         int tmpwidth, tmpheight;
338         uint16 tmpformat;
339         /* XXX: textures that use 8bit alpha channel look bad with the current
340          * fxt1 library, so we substitute it with dxtn for now. afaik all gfx
341          * cards that support fxt1 also support dxtn. (3dfx and Intel) */
342         if ((destformat == GR_TEXFMT_ALPHA_INTENSITY_88) ||
343             (destformat == GR_TEXFMT_ARGB_8888) ||
344             (destformat == GR_TEXFMT_ALPHA_8)) {
345           compressionType = S3TC_COMPRESSION;
346         }
347         tmptex = (texture == _tex1) ? _tex2 : _tex1;
348         if (_txQuantize->compress(texture, tmptex,
349                                   srcwidth, srcheight, srcformat,
350                                   &tmpwidth, &tmpheight, &tmpformat,
351                                   compressionType)) {
352           srcwidth = tmpwidth;
353           srcheight = tmpheight;
354           destformat = tmpformat;
355           texture = tmptex;
356         }
357       }
358
359
360       /*
361        * texture (re)conversions
362        */
363       if (destformat == GR_TEXFMT_ARGB_8888) {
364         if (srcformat == GR_TEXFMT_ARGB_8888 && (_maxbpp < 32 || _options & FORCE16BPP_TEX)) srcformat = GR_TEXFMT_ARGB_4444;
365         if (srcformat != GR_TEXFMT_ARGB_8888) {
366           tmptex = (texture == _tex1) ? _tex2 : _tex1;
367           if (!_txQuantize->quantize(texture, tmptex, srcwidth, srcheight, GR_TEXFMT_ARGB_8888, srcformat)) {
368             DBG_INFO(80, L"Error: unsupported format! gfmt:%x\n", srcformat);
369             return 0;
370           }
371           texture = tmptex;
372           destformat = srcformat;
373         }
374       }
375
376       break;
377 #if !_16BPP_HACK
378     case GR_TEXFMT_ARGB_4444:
379
380       int scale_shift = 0;
381       tmptex = (texture == _tex1) ? _tex2 : _tex1;
382
383       switch (_options & ENHANCEMENT_MASK) {
384       case HQ4X_ENHANCEMENT:
385         if (srcwidth <= (_maxwidth >> 2) && srcheight <= (_maxheight >> 2)) {
386           hq4x_4444((uint8*)texture, (uint8*)tmptex, srcwidth, srcheight, srcwidth, srcwidth * 4 * 2);
387           scale_shift = 2;
388         }/* else if (srcwidth <= (_maxwidth >> 1) && srcheight <= (_maxheight >> 1)) {
389           hq2x_16((uint8*)texture, srcwidth * 2, (uint8*)tmptex, srcwidth * 2 * 2, srcwidth, srcheight);
390           scale_shift = 1;
391         }*/
392         break;
393       case HQ2X_ENHANCEMENT:
394         if (srcwidth <= (_maxwidth >> 1) && srcheight <= (_maxheight >> 1)) {
395           hq2x_16((uint8*)texture, srcwidth * 2, (uint8*)tmptex, srcwidth * 2 * 2, srcwidth, srcheight);
396           scale_shift = 1;
397         }
398         break;
399       case HQ2XS_ENHANCEMENT:
400         if (srcwidth <= (_maxwidth >> 1) && srcheight <= (_maxheight >> 1)) {
401           hq2xS_16((uint8*)texture, srcwidth * 2, (uint8*)tmptex, srcwidth * 2 * 2, srcwidth, srcheight);
402           scale_shift = 1;
403         }
404         break;
405       case LQ2X_ENHANCEMENT:
406         if (srcwidth  <= (_maxwidth >> 1) && srcheight <= (_maxheight >> 1)) {
407           lq2x_16((uint8*)texture, srcwidth * 2, (uint8*)tmptex, srcwidth * 2 * 2, srcwidth, srcheight);
408           scale_shift = 1;
409         }
410         break;
411       case LQ2XS_ENHANCEMENT:
412         if (srcwidth  <= (_maxwidth >> 1) && srcheight <= (_maxheight >> 1)) {
413           lq2xS_16((uint8*)texture, srcwidth * 2, (uint8*)tmptex, srcwidth * 2 * 2, srcwidth, srcheight);
414           scale_shift = 1;
415         }
416         break;
417       case X2SAI_ENHANCEMENT:
418         if (srcwidth  <= (_maxwidth >> 1) && srcheight <= (_maxheight >> 1)) {
419           Super2xSaI_4444((uint16*)texture, (uint16*)tmptex, srcwidth, srcheight, srcwidth);
420           scale_shift = 1;
421         }
422         break;
423       case X2_ENHANCEMENT:
424         if (srcwidth  <= (_maxwidth >> 1) && srcheight <= (_maxheight >> 1)) {
425           Texture2x_16((uint8*)texture, srcwidth * 2, (uint8*)tmptex, srcwidth * 2 * 2, srcwidth, srcheight);
426           scale_shift = 1;
427         }
428       }
429       if (scale_shift) {
430         srcwidth <<= scale_shift;
431         srcheight <<= scale_shift;
432         texture = tmptex;
433       }
434
435       if (_options & SMOOTH_FILTER_MASK) {
436         tmptex = (texture == _tex1) ? _tex2 : _tex1;
437         SmoothFilter_4444((uint16*)texture, srcwidth, srcheight, (uint16*)tmptex, (_options & SMOOTH_FILTER_MASK));
438         texture = tmptex;
439       } else if (_options & SHARP_FILTER_MASK) {
440         tmptex = (texture == _tex1) ? _tex2 : _tex1;
441         SharpFilter_4444((uint16*)texture, srcwidth, srcheight, (uint16*)tmptex, (_options & SHARP_FILTER_MASK));
442         texture = tmptex;
443       }
444
445       break;
446     case GR_TEXFMT_ARGB_1555:
447       break;
448     case GR_TEXFMT_RGB_565:
449       break;
450     case GR_TEXFMT_ALPHA_8:
451       break;
452 #endif /* _16BPP_HACK */
453     }
454   }
455
456   /* fill in the texture info. */
457   info->data = texture;
458   info->width  = srcwidth;
459   info->height = srcheight;
460   info->format = destformat;
461   info->smallLodLog2 = _txUtil->grLodLog2(srcwidth, srcheight);
462   info->largeLodLog2 = info->smallLodLog2;
463   info->aspectRatioLog2 = _txUtil->grAspectRatioLog2(srcwidth, srcheight);
464   info->is_hires_tex = 0;
465
466   /* cache the texture. */
467   if (_cacheSize) _txTexCache->add(g64crc, info);
468
469   DBG_INFO(80, L"filtered texture: %d x %d gfmt:%x\n", info->width, info->height, info->format);
470
471   return 1;
472 }
473
474 boolean
475 TxFilter::hirestex(uint64 g64crc, uint64 r_crc64, uint16 *palette, GHQTexInfo *info)
476 {
477   /* NOTE: Rice CRC32 sometimes return the same value for different textures.
478    * As a workaround, Glide64 CRC32 is used for the key for NON-hires
479    * texture cache.
480    *
481    * r_crc64 = hi:palette low:texture
482    *           (separate crc. doesn't necessary have to be rice crc)
483    * g64crc  = texture + palette glide64 crc32
484    *           (can be any other crc if robust)
485    */
486
487   DBG_INFO(80, L"hirestex: r_crc64:%08X %08X, g64crc:%08X %08X\n",
488            (uint32)(r_crc64 >> 32), (uint32)(r_crc64 & 0xffffffff),
489            (uint32)(g64crc >> 32), (uint32)(g64crc & 0xffffffff));
490
491 #if HIRES_TEXTURE
492   /* check if we have it in hires memory cache. */
493   if ((_options & HIRESTEXTURES_MASK) && r_crc64) {
494     if (_txHiResCache->get(r_crc64, info)) {
495       DBG_INFO(80, L"hires hit: %d x %d gfmt:%x\n", info->width, info->height, info->format);
496
497       /* TODO: Enable emulation for special N64 combiner modes. There are few ways
498        * to get this done. Also applies for CI textures below.
499        *
500        * Solution 1. Load the hiresolution textures in ARGB8888 (or A8, IA88) format
501        * to cache. When a cache is hit, then we take the modes passed in from Glide64
502        * (also TODO) and apply the modification. Then we do color reduction or format
503        * conversion or compression if desired and stuff it into the non-hires texture
504        * cache.
505        *
506        * Solution 2. When a cache is hit and if the combiner modes are present,
507        * convert the texture to ARGB4444 and pass it back to Glide64 to process.
508        * If a texture is compressed, it needs to be decompressed first. Then add
509        * the processed texture to the non-hires texture cache.
510        *
511        * Solution 3. Hybrid of the above 2. Load the textures in ARGB8888 (A8, IA88)
512        * format. Convert the texture to ARGB4444 and pass it back to Glide64 when
513        * the combiner modes are present. Get the processed texture back from Glide64
514        * and compress if desired and add it to the non-hires texture cache.
515        *
516        * Solution 4. Take the easy way out and forget about this whole thing.
517        */
518
519       return 1; /* yep, got it */
520     }
521     if (_txHiResCache->get((r_crc64 & 0xffffffff), info)) {
522       DBG_INFO(80, L"hires hit: %d x %d gfmt:%x\n", info->width, info->height, info->format);
523
524       /* for true CI textures, we use the passed in palette to convert to
525        * ARGB1555 and add it to memory cache.
526        *
527        * NOTE: we do this AFTER all other texture cache searches because
528        * only a few texture packs actually use true CI textures.
529        *
530        * NOTE: the pre-converted palette from Glide64 is in RGBA5551 format.
531        * A comp comes before RGB comp.
532        */
533       if (palette && info->format == GR_TEXFMT_P_8) {
534         DBG_INFO(80, L"found GR_TEXFMT_P_8 format. Need conversion!!\n");
535
536         int width = info->width;
537         int height = info->height;
538         uint16 format = info->format;
539         /* XXX: avoid collision with zlib compression buffer in TxHiResTexture::get */
540         uint8 *texture = info->data;
541         uint8 *tmptex = (texture == _tex1) ? _tex2 : _tex1;
542
543         /* use palette and convert to 16bit format */
544         _txQuantize->P8_16BPP((uint32*)texture, (uint32*)tmptex, info->width, info->height, (uint32*)palette);
545         texture = tmptex;
546         format = GR_TEXFMT_ARGB_1555;
547
548 #if 1
549         /* XXX: compressed if memory cache compression is ON */
550         if (_options & COMPRESSION_MASK) {
551           tmptex = (texture == _tex1) ? _tex2 : _tex1;
552           if (_txQuantize->quantize(texture, tmptex, info->width, info->height, format, GR_TEXFMT_ARGB_8888)) {
553             texture = tmptex;
554             format = GR_TEXFMT_ARGB_8888;
555           }
556           if (format == GR_TEXFMT_ARGB_8888) {
557             tmptex = (texture == _tex1) ? _tex2 : _tex1;
558             if (_txQuantize->compress(texture, tmptex,
559                                       info->width, info->height, GR_TEXFMT_ARGB_1555,
560                                       &width, &height, &format,
561                                       _options & COMPRESSION_MASK)) {
562               texture = tmptex;
563             } else {
564               /*if (!_txQuantize->quantize(texture, tmptex, info->width, info->height, GR_TEXFMT_ARGB_8888, GR_TEXFMT_ARGB_1555)) {
565                 DBG_INFO(80, L"Error: unsupported format! gfmt:%x\n", format);
566                 return 0;
567               }*/
568               texture = tmptex;
569               format = GR_TEXFMT_ARGB_1555;
570             }
571           }
572         }
573 #endif
574
575         /* fill in the required info to return */
576         info->data = texture;
577         info->width = width;
578         info->height = height;
579         info->format = format;
580         info->smallLodLog2 = _txUtil->grLodLog2(width, height);
581         info->largeLodLog2 = info->smallLodLog2;
582         info->aspectRatioLog2 = _txUtil->grAspectRatioLog2(width, height);
583         info->is_hires_tex = 1;
584
585         /* XXX: add to hires texture cache!!! */
586         _txHiResCache->add(r_crc64, info);
587
588         DBG_INFO(80, L"GR_TEXFMT_P_8 loaded as gfmt:%x!\n", format);
589       }
590
591       return 1;
592     }
593   }
594 #endif
595
596   /* check if we have it in memory cache */
597   if (_cacheSize && g64crc) {
598     if (_txTexCache->get(g64crc, info)) {
599       DBG_INFO(80, L"cache hit: %d x %d gfmt:%x\n", info->width, info->height, info->format);
600       return 1; /* yep, we've got it */
601     }
602   }
603
604   DBG_INFO(80, L"no cache hits.\n");
605
606   return 0;
607 }
608
609 uint64
610 TxFilter::checksum64(uint8 *src, int width, int height, int size, int rowStride, uint8 *palette)
611 {
612   if (_options & (HIRESTEXTURES_MASK|DUMP_TEX))
613     return _txUtil->checksum64(src, width, height, size, rowStride, palette);
614
615   return 0;
616 }
617
618 boolean
619 TxFilter::dmptx(uint8 *src, int width, int height, int rowStridePixel, uint16 gfmt, uint16 n64fmt, uint64 r_crc64)
620 {
621   if (!_initialized)
622     return 0;
623
624   if (!(_options & DUMP_TEX))
625     return 0;
626
627 #ifdef DUMP_CACHE
628   DBG_INFO(80, L"gfmt = %02x n64fmt = %02x\n", gfmt, n64fmt);
629   DBG_INFO(80, L"hirestex: r_crc64:%08X %08X\n",
630            (uint32)(r_crc64 >> 32), (uint32)(r_crc64 & 0xffffffff));
631
632   if (!_txQuantize->quantize(src, _tex1, rowStridePixel, height, (gfmt & 0x00ff), GR_TEXFMT_ARGB_8888))
633     return 0;
634
635   src = _tex1;
636
637   if (!_datapath.empty() && !_ident.empty()) {
638     /* dump it to disk */
639     FILE *fp = NULL;
640     std::wstring tmpbuf;
641     wchar_t texid[36];
642
643     /* create directories */
644     tmpbuf.assign(_datapath + L"/texture_dump");
645     if (!boost::filesystem::exists(tmpbuf) &&
646         !boost::filesystem::create_directory(tmpbuf))
647       return 0;
648
649     tmpbuf.append(L"/" + _ident);
650     if (!boost::filesystem::exists(tmpbuf) &&
651         !boost::filesystem::create_directory(tmpbuf))
652       return 0;
653
654     tmpbuf.append(L"/GlideHQ");
655     if (!boost::filesystem::exists(tmpbuf) &&
656         !boost::filesystem::create_directory(tmpbuf))
657       return 0;
658
659     if ((n64fmt >> 8) == 0x2) {
660       swprintf(texid, 36, L"%08X#%01X#%01X#%08X", (uint32)(r_crc64 & 0xffffffff), (uint32)(n64fmt >> 8), (uint32)(n64fmt & 0xf), (uint32)(r_crc64 >> 32));
661       tmpbuf.append(L"/" + _ident + L"#" + texid + L"_ciByRGBA.png");
662     } else {
663       swprintf(texid, 36, L"%08X#%01X#%01X",  (uint32)(r_crc64 & 0xffffffff), (uint32)(n64fmt >> 8), (uint32)(n64fmt & 0xf));
664       tmpbuf.append(L"/" + _ident + L"#" + texid + L"_all.png");
665     }
666
667 #ifdef WIN32
668     if ((fp = _wfopen(tmpbuf.c_str(), L"wb")) != NULL) {
669 #else
670     char cbuf[MAX_PATH];
671     wcstombs(cbuf, tmpbuf.c_str(), MAX_PATH);
672     if ((fp = fopen(cbuf, "wb")) != NULL) {
673 #endif
674       _txImage->writePNG(src, fp, width, height, (rowStridePixel << 2), 0x0003, 0);
675       fclose(fp);
676       return 1;
677     }
678   }
679 #endif
680
681   return 0;
682 }
683
684 boolean
685 TxFilter::reloadhirestex()
686 {
687   DBG_INFO(80, L"Reload hires textures from texture pack.\n");
688
689   if (_txHiResCache->load(0)) {
690     if (_txHiResCache->empty()) _options &= ~HIRESTEXTURES_MASK;
691     else _options |= HIRESTEXTURES_MASK;
692
693     return 1;
694   }
695
696   return 0;
697 }