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 | |
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 | } |