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