ALL: Huge upstream synch + PerRom DelaySI & CountPerOp parameters
[mupen64plus-pandora.git] / source / gles2glide64 / src / GlideHQ / TxFilter.cpp
CommitLineData
98e75f2d 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"
2d262872 31#ifndef NO_FILTER_THREAD
98e75f2d 32#include <functional>
33#include <thread>
2d262872 34#endif
35#if defined(__MINGW32__)
36#define swprintf _snwprintf
37#endif
98e75f2d 38
39void 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
61TxFilter::~TxFilter()
62{
63 clear();
64}
65
66TxFilter::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
171boolean
172TxFilter::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
474boolean
475TxFilter::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
609uint64
610TxFilter::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
618boolean
619TxFilter::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
684boolean
685TxFilter::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}