2017-04-26 10:23:36 +00:00
|
|
|
/***************************************************************************
|
|
|
|
* *
|
|
|
|
* Project64-video - A Nintendo 64 gfx plugin. *
|
|
|
|
* http://www.pj64-emu.com/ *
|
|
|
|
* Copyright (C) 2017 Project64. All rights reserved. *
|
|
|
|
* Copyright (C) 2003-2009 Sergey 'Gonetz' Lipski *
|
|
|
|
* Copyright (C) 2007 Hiroshi Morii *
|
|
|
|
* Copyright (C) 2003 Rice1964 *
|
|
|
|
* *
|
|
|
|
* License: *
|
|
|
|
* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
|
|
|
|
* version 2 of the License, or (at your option) any later version. *
|
|
|
|
* *
|
|
|
|
****************************************************************************/
|
2013-04-17 10:30:38 +00:00
|
|
|
|
2015-10-13 23:01:07 +00:00
|
|
|
#ifdef _WIN32
|
2013-04-17 10:30:38 +00:00
|
|
|
#pragma warning(disable: 4786)
|
|
|
|
#endif
|
|
|
|
|
2016-02-04 17:35:02 +00:00
|
|
|
/* dump processed hirestextures to disk
|
2013-04-17 10:30:38 +00:00
|
|
|
* (0:disable, 1:enable) */
|
|
|
|
#define DUMP_CACHE 1
|
|
|
|
|
2017-04-26 10:23:36 +00:00
|
|
|
/* handle oversized textures by
|
|
|
|
* 0: minification
|
|
|
|
* 1: Glide64 style tiling
|
|
|
|
*/
|
2013-04-17 10:30:38 +00:00
|
|
|
#define TEXTURE_TILING 1
|
|
|
|
|
2017-04-26 10:23:36 +00:00
|
|
|
/* use power of 2 texture size
|
|
|
|
* (0:disable, 1:enable, 2:3dfx) */
|
2013-04-17 10:30:38 +00:00
|
|
|
#define POW2_TEXTURES 2
|
|
|
|
|
|
|
|
#if TEXTURE_TILING
|
|
|
|
#undef POW2_TEXTURES
|
|
|
|
#define POW2_TEXTURES 2
|
|
|
|
#endif
|
|
|
|
|
2017-04-26 10:23:36 +00:00
|
|
|
/* hack to reduce texture footprint to achieve
|
|
|
|
* better performace on midrange gfx cards.
|
|
|
|
* (0:disable, 1:enable) */
|
2013-04-17 10:30:38 +00:00
|
|
|
#define REDUCE_TEXTURE_FOOTPRINT 0
|
|
|
|
|
2017-04-26 10:23:36 +00:00
|
|
|
/* use aggressive format assumption for quantization
|
|
|
|
* (0:disable, 1:enable, 2:extreme) */
|
2013-04-17 10:30:38 +00:00
|
|
|
#define AGGRESSIVE_QUANTIZATION 1
|
|
|
|
|
|
|
|
#include "TxHiResCache.h"
|
|
|
|
#include "TxDbg.h"
|
|
|
|
#include <zlib/zlib.h>
|
|
|
|
#include <string>
|
2016-01-20 06:09:05 +00:00
|
|
|
#include <Common/path.h>
|
|
|
|
#include <Common/StdString.h>
|
2017-05-17 10:34:55 +00:00
|
|
|
#include <Project64-video/Renderer/types.h>
|
2016-02-10 07:02:20 +00:00
|
|
|
#ifdef _WIN32
|
2015-10-25 11:10:54 +00:00
|
|
|
#include <io.h>
|
2016-02-10 07:02:20 +00:00
|
|
|
#endif
|
2013-04-17 10:30:38 +00:00
|
|
|
|
|
|
|
TxHiResCache::~TxHiResCache()
|
|
|
|
{
|
|
|
|
#if DUMP_CACHE
|
2016-02-10 07:02:20 +00:00
|
|
|
if ((_options & DUMP_HIRESTEXCACHE) && !_haveCache && !_abortLoad)
|
|
|
|
{
|
2016-02-04 17:35:02 +00:00
|
|
|
/* dump cache to disk */
|
2016-02-10 07:02:20 +00:00
|
|
|
std::string filename = _ident + "_HIRESTEXTURES.dat";
|
2013-04-17 10:30:38 +00:00
|
|
|
|
2016-02-10 07:02:20 +00:00
|
|
|
CPath cachepath(_path.c_str(), "");
|
2016-08-21 21:42:33 +00:00
|
|
|
cachepath.AppendDirectory("Cache");
|
2016-02-04 17:35:02 +00:00
|
|
|
int config = _options & (HIRESTEXTURES_MASK | COMPRESS_HIRESTEX | COMPRESSION_MASK | TILE_HIRESTEX | FORCE16BPP_HIRESTEX | GZ_HIRESTEXCACHE | LET_TEXARTISTS_FLY);
|
2013-04-17 10:30:38 +00:00
|
|
|
|
2016-02-10 07:02:20 +00:00
|
|
|
TxCache::save(cachepath, filename.c_str(), config);
|
2016-02-04 17:35:02 +00:00
|
|
|
}
|
2013-04-17 10:30:38 +00:00
|
|
|
#endif
|
|
|
|
|
2016-02-04 17:35:02 +00:00
|
|
|
delete _txImage;
|
|
|
|
delete _txQuantize;
|
|
|
|
delete _txReSample;
|
2013-04-17 10:30:38 +00:00
|
|
|
}
|
|
|
|
|
2016-02-10 07:02:20 +00:00
|
|
|
TxHiResCache::TxHiResCache(int maxwidth, int maxheight, int maxbpp, int options, const char *path, const char *ident, dispInfoFuncExt callback) :
|
2017-04-26 10:23:36 +00:00
|
|
|
TxCache((options & ~GZ_TEXCACHE), 0, path, ident, callback)
|
2013-04-17 10:30:38 +00:00
|
|
|
{
|
2016-02-04 17:35:02 +00:00
|
|
|
_txImage = new TxImage();
|
|
|
|
_txQuantize = new TxQuantize();
|
|
|
|
_txReSample = new TxReSample();
|
|
|
|
|
|
|
|
_maxwidth = maxwidth;
|
|
|
|
_maxheight = maxheight;
|
|
|
|
_maxbpp = maxbpp;
|
|
|
|
_abortLoad = 0;
|
|
|
|
_haveCache = 0;
|
|
|
|
|
|
|
|
/* assert local options */
|
|
|
|
if (!(_options & COMPRESS_HIRESTEX))
|
2016-02-10 07:02:20 +00:00
|
|
|
{
|
2016-02-04 17:35:02 +00:00
|
|
|
_options &= ~COMPRESSION_MASK;
|
2016-02-10 07:02:20 +00:00
|
|
|
}
|
|
|
|
if (_path.empty() || _ident.empty())
|
|
|
|
{
|
2016-02-04 17:35:02 +00:00
|
|
|
_options &= ~DUMP_HIRESTEXCACHE;
|
|
|
|
return;
|
|
|
|
}
|
2013-04-17 10:30:38 +00:00
|
|
|
|
|
|
|
#if DUMP_CACHE
|
2016-02-04 17:35:02 +00:00
|
|
|
/* read in hires texture cache */
|
2016-02-10 07:02:20 +00:00
|
|
|
if (_options & DUMP_HIRESTEXCACHE)
|
|
|
|
{
|
2016-02-04 17:35:02 +00:00
|
|
|
/* find it on disk */
|
2016-02-10 07:02:20 +00:00
|
|
|
std::string filename = _ident + "_HIRESTEXTURES.dat";
|
|
|
|
CPath cachepath(_path.c_str(), "");
|
2016-08-21 21:42:33 +00:00
|
|
|
cachepath.AppendDirectory("Cache");
|
2016-02-04 17:35:02 +00:00
|
|
|
int config = _options & (HIRESTEXTURES_MASK | COMPRESS_HIRESTEX | COMPRESSION_MASK | TILE_HIRESTEX | FORCE16BPP_HIRESTEX | GZ_HIRESTEXCACHE | LET_TEXARTISTS_FLY);
|
|
|
|
|
2016-02-10 07:02:20 +00:00
|
|
|
_haveCache = TxCache::load(cachepath, filename.c_str(), config);
|
2016-02-04 17:35:02 +00:00
|
|
|
}
|
2013-04-17 10:30:38 +00:00
|
|
|
#endif
|
|
|
|
|
2016-02-04 17:35:02 +00:00
|
|
|
/* read in hires textures */
|
|
|
|
if (!_haveCache) TxHiResCache::load(0);
|
2013-04-17 10:30:38 +00:00
|
|
|
}
|
|
|
|
|
2017-04-26 10:23:36 +00:00
|
|
|
bool
|
2013-04-17 10:30:38 +00:00
|
|
|
TxHiResCache::empty()
|
|
|
|
{
|
2016-02-04 17:35:02 +00:00
|
|
|
return _cache.empty();
|
2013-04-17 10:30:38 +00:00
|
|
|
}
|
|
|
|
|
2017-04-26 10:23:36 +00:00
|
|
|
bool
|
|
|
|
TxHiResCache::load(bool replace) /* 0 : reload, 1 : replace partial */
|
2013-04-17 10:30:38 +00:00
|
|
|
{
|
2016-02-10 07:02:20 +00:00
|
|
|
if (!_path.empty() && !_ident.empty())
|
|
|
|
{
|
2016-02-04 17:35:02 +00:00
|
|
|
if (!replace) TxCache::clear();
|
2013-04-17 10:30:38 +00:00
|
|
|
|
2016-02-10 07:02:20 +00:00
|
|
|
CPath dir_path(_path.c_str(), "");
|
2016-02-04 17:35:02 +00:00
|
|
|
|
2016-02-10 07:02:20 +00:00
|
|
|
switch (_options & HIRESTEXTURES_MASK)
|
|
|
|
{
|
2016-02-04 17:35:02 +00:00
|
|
|
case RICE_HIRESTEXTURES:
|
2016-03-10 11:14:33 +00:00
|
|
|
INFO(80, "-----\n");
|
|
|
|
INFO(80, "using Rice hires texture format...\n");
|
|
|
|
INFO(80, " must be one of the following;\n");
|
|
|
|
INFO(80, " 1) *_rgb.png + *_a.png\n");
|
|
|
|
INFO(80, " 2) *_all.png\n");
|
|
|
|
INFO(80, " 3) *_ciByRGBA.png\n");
|
|
|
|
INFO(80, " 4) *_allciByRGBA.png\n");
|
|
|
|
INFO(80, " 5) *_ci.bmp\n");
|
|
|
|
INFO(80, " usage of only 2) and 3) highly recommended!\n");
|
|
|
|
INFO(80, " folder names must be in US-ASCII characters!\n");
|
2016-02-04 17:35:02 +00:00
|
|
|
|
2016-02-10 07:02:20 +00:00
|
|
|
dir_path.AppendDirectory(_ident.c_str());
|
2016-02-04 17:35:02 +00:00
|
|
|
loadHiResTextures(dir_path, replace);
|
|
|
|
break;
|
|
|
|
}
|
2013-04-17 10:30:38 +00:00
|
|
|
|
2016-02-04 17:35:02 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
2013-04-17 10:30:38 +00:00
|
|
|
}
|
|
|
|
|
2017-04-26 10:23:36 +00:00
|
|
|
bool TxHiResCache::loadHiResTextures(const char * dir_path, bool replace)
|
2013-04-17 10:30:38 +00:00
|
|
|
{
|
2016-02-10 07:02:20 +00:00
|
|
|
#ifdef _WIN32
|
2016-03-10 11:14:33 +00:00
|
|
|
DBG_INFO(80, "-----\n");
|
|
|
|
DBG_INFO(80, "path: %s\n", stdstr(dir_path).ToUTF16().c_str());
|
2016-02-04 17:35:02 +00:00
|
|
|
|
|
|
|
CPath TextureDir(dir_path, "");
|
|
|
|
|
|
|
|
/* find it on disk */
|
|
|
|
if (!TextureDir.DirectoryExists())
|
|
|
|
{
|
2016-03-10 11:14:33 +00:00
|
|
|
INFO(80, "Error: path not found!\n");
|
2016-02-04 17:35:02 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* recursive read into sub-directory */
|
2016-04-12 07:53:40 +00:00
|
|
|
TextureDir.SetNameExtension("*");
|
|
|
|
if (TextureDir.FindFirst(CPath::FIND_ATTRIBUTE_SUBDIR))
|
2016-02-04 17:35:02 +00:00
|
|
|
{
|
|
|
|
do
|
|
|
|
{
|
|
|
|
loadHiResTextures(TextureDir, replace);
|
|
|
|
} while (TextureDir.FindNext());
|
|
|
|
}
|
|
|
|
|
|
|
|
TextureDir.SetNameExtension("*.*");
|
|
|
|
if (TextureDir.FindFirst())
|
|
|
|
{
|
|
|
|
do
|
|
|
|
{
|
|
|
|
if (_abortLoad) break;
|
|
|
|
|
2016-03-10 11:14:33 +00:00
|
|
|
DBG_INFO(80, "-----\n");
|
|
|
|
DBG_INFO(80, "file: %ls\n", stdstr(TextureDir.GetNameExtension().c_str()).ToUTF16().c_str());
|
2016-02-04 17:35:02 +00:00
|
|
|
|
|
|
|
int width = 0, height = 0;
|
|
|
|
uint16 format = 0;
|
|
|
|
uint8 *tex = NULL;
|
|
|
|
int tmpwidth = 0, tmpheight = 0;
|
|
|
|
uint16 tmpformat = 0;
|
|
|
|
uint8 *tmptex = NULL;
|
|
|
|
int untiled_width = 0, untiled_height = 0;
|
|
|
|
uint16 destformat = 0;
|
|
|
|
|
|
|
|
/* Rice hi-res textures: begin
|
|
|
|
*/
|
|
|
|
uint32 chksum = 0, fmt = 0, siz = 0, palchksum = 0;
|
2017-04-26 10:23:36 +00:00
|
|
|
char *pfname = NULL, fname[260];
|
2016-02-04 17:35:02 +00:00
|
|
|
std::string ident;
|
|
|
|
FILE *fp = NULL;
|
|
|
|
|
2016-02-10 07:02:20 +00:00
|
|
|
strcpy(fname, _ident.c_str());
|
2016-02-04 17:35:02 +00:00
|
|
|
/* XXX case sensitivity fiasco!
|
|
|
|
* files must use _a, _rgb, _all, _allciByRGBA, _ciByRGBA, _ci
|
|
|
|
* and file extensions must be in lower case letters! */
|
2015-10-13 23:01:07 +00:00
|
|
|
#ifdef _WIN32
|
2016-02-04 17:35:02 +00:00
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
for (i = 0; i < strlen(fname); i++) fname[i] = (char)tolower(fname[i]);
|
|
|
|
}
|
2015-10-13 23:01:07 +00:00
|
|
|
#endif
|
2016-02-04 17:35:02 +00:00
|
|
|
ident.assign(fname);
|
|
|
|
|
|
|
|
/* read in Rice's file naming convention */
|
|
|
|
#define CRCFMTSIZ_LEN 13
|
|
|
|
#define PALCRC_LEN 9
|
2017-04-26 10:23:36 +00:00
|
|
|
wcstombs(fname, stdstr(TextureDir.GetNameExtension()).ToUTF16().c_str(), 260);
|
2016-02-04 17:35:02 +00:00
|
|
|
/* XXX case sensitivity fiasco!
|
|
|
|
* files must use _a, _rgb, _all, _allciByRGBA, _ciByRGBA, _ci
|
|
|
|
* and file extensions must be in lower case letters! */
|
2015-10-13 23:01:07 +00:00
|
|
|
#ifdef _WIN32
|
2016-02-04 17:35:02 +00:00
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
for (i = 0; i < strlen(fname); i++) fname[i] = (char)tolower(fname[i]);
|
|
|
|
}
|
2015-10-13 23:01:07 +00:00
|
|
|
#endif
|
2016-02-04 17:35:02 +00:00
|
|
|
pfname = fname + strlen(fname) - 4;
|
|
|
|
if (!(pfname == strstr(fname, ".png") ||
|
|
|
|
pfname == strstr(fname, ".bmp") ||
|
|
|
|
pfname == strstr(fname, ".dds")))
|
|
|
|
{
|
2013-04-17 10:30:38 +00:00
|
|
|
#if !DEBUG
|
2016-03-10 11:14:33 +00:00
|
|
|
INFO(80, "-----\n");
|
|
|
|
INFO(80, "path: %ls\n", stdstr(dir_path).ToUTF16().c_str());
|
|
|
|
INFO(80, "file: %ls\n", TextureDir.GetNameExtension().ToUTF16().c_str());
|
2013-04-17 10:30:38 +00:00
|
|
|
#endif
|
2016-03-10 11:14:33 +00:00
|
|
|
INFO(80, "Error: not png or bmp or dds!\n");
|
2016-02-04 17:35:02 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
pfname = strstr(fname, ident.c_str());
|
|
|
|
if (pfname != fname) pfname = 0;
|
|
|
|
if (pfname) {
|
|
|
|
if (sscanf(pfname + ident.size(), "#%08X#%01X#%01X#%08X", &chksum, &fmt, &siz, &palchksum) == 4)
|
|
|
|
pfname += (ident.size() + CRCFMTSIZ_LEN + PALCRC_LEN);
|
|
|
|
else if (sscanf(pfname + ident.size(), "#%08X#%01X#%01X", &chksum, &fmt, &siz) == 3)
|
|
|
|
pfname += (ident.size() + CRCFMTSIZ_LEN);
|
|
|
|
else
|
|
|
|
pfname = 0;
|
|
|
|
}
|
|
|
|
if (!pfname) {
|
|
|
|
#if !DEBUG
|
2016-03-10 11:14:33 +00:00
|
|
|
INFO(80, "-----\n");
|
|
|
|
INFO(80, "path: %ls\n", stdstr(dir_path).ToUTF16().c_str());
|
|
|
|
INFO(80, "file: %ls\n", TextureDir.GetNameExtension().ToUTF16().c_str());
|
2016-02-04 17:35:02 +00:00
|
|
|
#endif
|
2016-03-10 11:14:33 +00:00
|
|
|
INFO(80, "Error: not Rice texture naming convention!\n");
|
2016-02-04 17:35:02 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (!chksum) {
|
|
|
|
#if !DEBUG
|
2016-03-10 11:14:33 +00:00
|
|
|
INFO(80, "-----\n");
|
|
|
|
INFO(80, "path: %ls\n", stdstr(dir_path).ToUTF16().c_str());
|
|
|
|
INFO(80, "file: %ls\n", TextureDir.GetNameExtension().ToUTF16().c_str());
|
2016-02-04 17:35:02 +00:00
|
|
|
#endif
|
2016-03-10 11:14:33 +00:00
|
|
|
INFO(80, "Error: crc32 = 0!\n");
|
2016-02-04 17:35:02 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* check if we already have it in hires texture cache */
|
|
|
|
if (!replace) {
|
2017-04-26 10:23:36 +00:00
|
|
|
uint64_t chksum64 = (uint64_t)palchksum;
|
2016-02-04 17:35:02 +00:00
|
|
|
chksum64 <<= 32;
|
2017-04-26 10:23:36 +00:00
|
|
|
chksum64 |= (uint64_t)chksum;
|
2016-02-04 17:35:02 +00:00
|
|
|
if (TxCache::is_cached(chksum64)) {
|
|
|
|
#if !DEBUG
|
2016-03-10 11:14:33 +00:00
|
|
|
INFO(80, "-----\n");
|
|
|
|
INFO(80, "path: %ls\n", stdstr(dir_path).ToUTF16().c_str());
|
|
|
|
INFO(80, "file: %ls\n", TextureDir.GetNameExtension().ToUTF16().c_str());
|
2016-02-04 17:35:02 +00:00
|
|
|
#endif
|
2016-03-10 11:14:33 +00:00
|
|
|
INFO(80, "Error: already cached! duplicate texture!\n");
|
2016-02-04 17:35:02 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-10 11:14:33 +00:00
|
|
|
DBG_INFO(80, "rom: %ls chksum:%08X %08X fmt:%x size:%x\n", _ident.c_str(), chksum, palchksum, fmt, siz);
|
2016-02-04 17:35:02 +00:00
|
|
|
|
|
|
|
/* Deal with the wackiness some texture packs utilize Rice format.
|
|
|
|
* Read in the following order: _a.* + _rgb.*, _all.png _ciByRGBA.png,
|
|
|
|
* _allciByRGBA.png, and _ci.bmp. PNG are prefered over BMP.
|
|
|
|
*
|
|
|
|
* For some reason there are texture packs that include them all. Some
|
|
|
|
* even have RGB textures named as _all.* and ARGB textures named as
|
|
|
|
* _rgb.*... Someone pleeeez write a GOOD guideline for the texture
|
|
|
|
* designers!!!
|
|
|
|
*
|
|
|
|
* We allow hires textures to have higher bpp than the N64 originals.
|
|
|
|
*/
|
|
|
|
/* N64 formats
|
|
|
|
* Format: 0 - RGBA, 1 - YUV, 2 - CI, 3 - IA, 4 - I
|
|
|
|
* Size: 0 - 4bit, 1 - 8bit, 2 - 16bit, 3 - 32 bit
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* read in _rgb.* and _a.*
|
|
|
|
*/
|
|
|
|
if (pfname == strstr(fname, "_rgb.") || pfname == strstr(fname, "_a.")) {
|
|
|
|
strcpy(pfname, "_rgb.png");
|
|
|
|
CPath TargetFile(dir_path, fname);
|
|
|
|
if (!TargetFile.Exists())
|
|
|
|
{
|
|
|
|
strcpy(pfname, "_rgb.bmp");
|
|
|
|
TargetFile = CPath(dir_path, fname);
|
|
|
|
if (!TargetFile.Exists())
|
|
|
|
{
|
|
|
|
#if !DEBUG
|
2016-03-10 11:14:33 +00:00
|
|
|
INFO(80, "-----\n");
|
|
|
|
INFO(80, "path: %ls\n", stdstr(dir_path).ToUTF16().c_str());
|
|
|
|
INFO(80, "file: %ls\n", TextureDir.GetNameExtension().ToUTF16().c_str());
|
2016-02-04 17:35:02 +00:00
|
|
|
#endif
|
2016-03-10 11:14:33 +00:00
|
|
|
INFO(80, "Error: missing _rgb.*! _a.* must be paired with _rgb.*!\n");
|
2016-02-04 17:35:02 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* _a.png */
|
|
|
|
strcpy(pfname, "_a.png");
|
|
|
|
TargetFile = CPath(dir_path, fname);
|
|
|
|
if ((fp = fopen(TargetFile, "rb")) != NULL) {
|
|
|
|
tmptex = _txImage->readPNG(fp, &tmpwidth, &tmpheight, &tmpformat);
|
|
|
|
fclose(fp);
|
|
|
|
}
|
|
|
|
if (!tmptex) {
|
|
|
|
/* _a.bmp */
|
|
|
|
strcpy(pfname, "_a.bmp");
|
|
|
|
TargetFile = CPath(dir_path, fname);
|
|
|
|
if ((fp = fopen(TargetFile, "rb")) != NULL) {
|
|
|
|
tmptex = _txImage->readBMP(fp, &tmpwidth, &tmpheight, &tmpformat);
|
|
|
|
fclose(fp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* _rgb.png */
|
|
|
|
strcpy(pfname, "_rgb.png");
|
|
|
|
TargetFile = CPath(dir_path, fname);
|
|
|
|
if ((fp = fopen(TargetFile, "rb")) != NULL) {
|
|
|
|
tex = _txImage->readPNG(fp, &width, &height, &format);
|
|
|
|
fclose(fp);
|
|
|
|
}
|
|
|
|
if (!tex) {
|
|
|
|
/* _rgb.bmp */
|
|
|
|
strcpy(pfname, "_rgb.bmp");
|
|
|
|
TargetFile = CPath(dir_path, fname);
|
|
|
|
if ((fp = fopen(TargetFile, "rb")) != NULL) {
|
|
|
|
tex = _txImage->readBMP(fp, &width, &height, &format);
|
|
|
|
fclose(fp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (tmptex) {
|
|
|
|
/* check if _rgb.* and _a.* have matching size and format. */
|
|
|
|
if (!tex || width != tmpwidth || height != tmpheight ||
|
2017-05-17 10:34:55 +00:00
|
|
|
format != GFX_TEXFMT_ARGB_8888 || tmpformat != GFX_TEXFMT_ARGB_8888) {
|
2016-02-04 17:35:02 +00:00
|
|
|
#if !DEBUG
|
2016-03-10 11:14:33 +00:00
|
|
|
INFO(80, "-----\n");
|
|
|
|
INFO(80, "path: %ls\n", stdstr(dir_path).ToUTF16().c_str());
|
|
|
|
INFO(80, "file: %ls\n", TextureDir.GetNameExtension().ToUTF16().c_str());
|
2016-02-04 17:35:02 +00:00
|
|
|
#endif
|
|
|
|
if (!tex) {
|
2016-03-10 11:14:33 +00:00
|
|
|
INFO(80, "Error: missing _rgb.*!\n");
|
2016-02-04 17:35:02 +00:00
|
|
|
}
|
|
|
|
else if (width != tmpwidth || height != tmpheight) {
|
2016-03-10 11:14:33 +00:00
|
|
|
INFO(80, "Error: _rgb.* and _a.* have mismatched width or height!\n");
|
2016-02-04 17:35:02 +00:00
|
|
|
}
|
2017-05-17 10:34:55 +00:00
|
|
|
else if (format != GFX_TEXFMT_ARGB_8888 || tmpformat != GFX_TEXFMT_ARGB_8888) {
|
2016-03-10 11:14:33 +00:00
|
|
|
INFO(80, "Error: _rgb.* or _a.* not in 32bit color!\n");
|
2016-02-04 17:35:02 +00:00
|
|
|
}
|
|
|
|
if (tex) free(tex);
|
|
|
|
if (tmptex) free(tmptex);
|
|
|
|
tex = NULL;
|
|
|
|
tmptex = NULL;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* make adjustments */
|
|
|
|
if (tex) {
|
|
|
|
if (tmptex) {
|
|
|
|
/* merge (A)RGB and A comp */
|
2016-03-10 11:14:33 +00:00
|
|
|
DBG_INFO(80, "merge (A)RGB and A comp\n");
|
2016-02-04 17:35:02 +00:00
|
|
|
int i;
|
|
|
|
for (i = 0; i < height * width; i++) {
|
2013-04-17 10:30:38 +00:00
|
|
|
#if 1
|
2016-02-04 17:35:02 +00:00
|
|
|
/* use R comp for alpha. this is what Rice uses. sigh... */
|
|
|
|
((uint32*)tex)[i] &= 0x00ffffff;
|
|
|
|
((uint32*)tex)[i] |= ((((uint32*)tmptex)[i] & 0x00ff0000) << 8);
|
2013-04-17 10:30:38 +00:00
|
|
|
#endif
|
|
|
|
#if 0
|
2016-02-04 17:35:02 +00:00
|
|
|
/* use libpng style grayscale conversion */
|
|
|
|
uint32 texel = ((uint32*)tmptex)[i];
|
|
|
|
uint32 acomp = (((texel >> 16) & 0xff) * 6969 +
|
2016-02-10 07:02:20 +00:00
|
|
|
((texel >> 8) & 0xff) * 23434 +
|
2017-04-26 10:23:36 +00:00
|
|
|
((texel) & 0xff) * 2365) / 32768;
|
2016-02-04 17:35:02 +00:00
|
|
|
((uint32*)tex)[i] = (acomp << 24) | (((uint32*)tex)[i] & 0x00ffffff);
|
2013-04-17 10:30:38 +00:00
|
|
|
#endif
|
|
|
|
#if 0
|
2016-02-04 17:35:02 +00:00
|
|
|
/* use the standard NTSC gray scale conversion */
|
|
|
|
uint32 texel = ((uint32*)tmptex)[i];
|
|
|
|
uint32 acomp = (((texel >> 16) & 0xff) * 299 +
|
2016-02-10 07:02:20 +00:00
|
|
|
((texel >> 8) & 0xff) * 587 +
|
2017-04-26 10:23:36 +00:00
|
|
|
((texel) & 0xff) * 114) / 1000;
|
2016-02-04 17:35:02 +00:00
|
|
|
((uint32*)tex)[i] = (acomp << 24) | (((uint32*)tex)[i] & 0x00ffffff);
|
2013-04-17 10:30:38 +00:00
|
|
|
#endif
|
2016-02-04 17:35:02 +00:00
|
|
|
}
|
|
|
|
free(tmptex);
|
|
|
|
tmptex = NULL;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* clobber A comp. never a question of alpha. only RGB used. */
|
2013-04-17 10:30:38 +00:00
|
|
|
#if !DEBUG
|
2016-03-10 11:14:33 +00:00
|
|
|
INFO(80, "-----\n");
|
|
|
|
INFO(80, "path: %ls\n", stdstr(dir_path).ToUTF16().c_str());
|
|
|
|
INFO(80, "file: %ls\n", TextureDir.GetNameExtension().ToUTF16().c_str());
|
2013-04-17 10:30:38 +00:00
|
|
|
#endif
|
2016-03-10 11:14:33 +00:00
|
|
|
INFO(80, "Warning: missing _a.*! only using _rgb.*. treat as opaque texture.\n");
|
2016-02-04 17:35:02 +00:00
|
|
|
int i;
|
|
|
|
for (i = 0; i < height * width; i++) {
|
|
|
|
((uint32*)tex)[i] |= 0xff000000;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
|
|
|
|
/*
|
|
|
|
* read in _all.png, _all.dds, _allciByRGBA.png, _allciByRGBA.dds
|
|
|
|
* _ciByRGBA.png, _ciByRGBA.dds, _ci.bmp
|
|
|
|
*/
|
2017-04-26 10:23:36 +00:00
|
|
|
if (pfname == strstr(fname, "_all.png") ||
|
|
|
|
pfname == strstr(fname, "_all.dds") ||
|
2015-10-13 23:01:07 +00:00
|
|
|
#ifdef _WIN32
|
2017-04-26 10:23:36 +00:00
|
|
|
pfname == strstr(fname, "_allcibyrgba.png") ||
|
|
|
|
pfname == strstr(fname, "_allcibyrgba.dds") ||
|
|
|
|
pfname == strstr(fname, "_cibyrgba.png") ||
|
|
|
|
pfname == strstr(fname, "_cibyrgba.dds") ||
|
2013-04-17 10:30:38 +00:00
|
|
|
#else
|
2017-04-26 10:23:36 +00:00
|
|
|
pfname == strstr(fname, "_allciByRGBA.png") ||
|
|
|
|
pfname == strstr(fname, "_allciByRGBA.dds") ||
|
|
|
|
pfname == strstr(fname, "_ciByRGBA.png") ||
|
|
|
|
pfname == strstr(fname, "_ciByRGBA.dds") ||
|
2013-04-17 10:30:38 +00:00
|
|
|
#endif
|
2017-04-26 10:23:36 +00:00
|
|
|
pfname == strstr(fname, "_ci.bmp")) {
|
|
|
|
CPath TargetFile(dir_path, fname);
|
|
|
|
if ((fp = fopen(TargetFile, "rb")) != NULL) {
|
|
|
|
if (strstr(fname, ".png")) tex = _txImage->readPNG(fp, &width, &height, &format);
|
|
|
|
else if (strstr(fname, ".dds")) tex = _txImage->readDDS(fp, &width, &height, &format);
|
|
|
|
else tex = _txImage->readBMP(fp, &width, &height, &format);
|
|
|
|
fclose(fp);
|
|
|
|
}
|
|
|
|
/* XXX: auto-adjustment of dxt dds textures unsupported for now */
|
|
|
|
if (tex && strstr(fname, ".dds")) {
|
|
|
|
const float aspectratio = (width > height) ? (float)width / (float)height : (float)height / (float)width;
|
|
|
|
if (!(aspectratio == 1.0 ||
|
|
|
|
aspectratio == 2.0 ||
|
|
|
|
aspectratio == 4.0 ||
|
|
|
|
aspectratio == 8.0)) {
|
|
|
|
free(tex);
|
|
|
|
tex = NULL;
|
2013-04-17 10:30:38 +00:00
|
|
|
#if !DEBUG
|
2017-04-26 10:23:36 +00:00
|
|
|
INFO(80, "-----\n");
|
|
|
|
INFO(80, "path: %ls\n", stdstr(dir_path).ToUTF16().c_str());
|
|
|
|
INFO(80, "file: %ls\n", TextureDir.GetNameExtension().ToUTF16().c_str());
|
2013-04-17 10:30:38 +00:00
|
|
|
#endif
|
2017-04-26 10:23:36 +00:00
|
|
|
INFO(80, "Error: W:H aspect ratio range not 8:1 - 1:8!\n");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (width != _txReSample->nextPow2(width) ||
|
|
|
|
height != _txReSample->nextPow2(height)) {
|
|
|
|
free(tex);
|
|
|
|
tex = NULL;
|
2013-04-17 10:30:38 +00:00
|
|
|
#if !DEBUG
|
2017-04-26 10:23:36 +00:00
|
|
|
INFO(80, "-----\n");
|
|
|
|
INFO(80, "path: %ls\n", stdstr(dir_path).ToUTF16().c_str());
|
|
|
|
INFO(80, "file: %ls\n", TextureDir.GetNameExtension().ToUTF16().c_str());
|
2013-04-17 10:30:38 +00:00
|
|
|
#endif
|
2017-04-26 10:23:36 +00:00
|
|
|
INFO(80, "Error: not power of 2 size!\n");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-02-04 17:35:02 +00:00
|
|
|
|
|
|
|
/* if we do not have a texture at this point we are screwed */
|
|
|
|
if (!tex) {
|
2013-04-17 10:30:38 +00:00
|
|
|
#if !DEBUG
|
2016-03-10 11:14:33 +00:00
|
|
|
INFO(80, "-----\n");
|
|
|
|
INFO(80, "path: %ls\n", stdstr(dir_path).ToUTF16().c_str());
|
|
|
|
INFO(80, "file: %ls\n", TextureDir.GetNameExtension().ToUTF16().c_str());
|
2013-04-17 10:30:38 +00:00
|
|
|
#endif
|
2016-03-10 11:14:33 +00:00
|
|
|
INFO(80, "Error: load failed!\n");
|
2016-02-04 17:35:02 +00:00
|
|
|
continue;
|
|
|
|
}
|
2016-03-10 11:14:33 +00:00
|
|
|
DBG_INFO(80, "read in as %d x %d gfmt:%x\n", tmpwidth, tmpheight, tmpformat);
|
2016-02-04 17:35:02 +00:00
|
|
|
|
|
|
|
/* check if size and format are OK */
|
2017-05-17 10:34:55 +00:00
|
|
|
if (!(format == GFX_TEXFMT_ARGB_8888 ||
|
|
|
|
format == GFX_TEXFMT_P_8 ||
|
|
|
|
format == GFX_TEXFMT_ARGB_CMP_DXT1 ||
|
|
|
|
format == GFX_TEXFMT_ARGB_CMP_DXT3 ||
|
|
|
|
format == GFX_TEXFMT_ARGB_CMP_DXT5) ||
|
2016-02-04 17:35:02 +00:00
|
|
|
(width * height) < 4) { /* TxQuantize requirement: width * height must be 4 or larger. */
|
|
|
|
free(tex);
|
|
|
|
tex = NULL;
|
2013-04-17 10:30:38 +00:00
|
|
|
#if !DEBUG
|
2016-03-10 11:14:33 +00:00
|
|
|
INFO(80, "-----\n");
|
|
|
|
INFO(80, "path: %ls\n", stdstr(dir_path).ToUTF16().c_str());
|
|
|
|
INFO(80, "file: %ls\n", TextureDir.GetNameExtension().ToUTF16().c_str());
|
2013-04-17 10:30:38 +00:00
|
|
|
#endif
|
2016-03-10 11:14:33 +00:00
|
|
|
INFO(80, "Error: not width * height > 4 or 8bit palette color or 32bpp or dxt1 or dxt3 or dxt5!\n");
|
2016-02-04 17:35:02 +00:00
|
|
|
continue;
|
|
|
|
}
|
2013-04-17 10:30:38 +00:00
|
|
|
|
2016-02-04 17:35:02 +00:00
|
|
|
/* analyze and determine best format to quantize */
|
2017-05-17 10:34:55 +00:00
|
|
|
if (format == GFX_TEXFMT_ARGB_8888) {
|
2016-02-04 17:35:02 +00:00
|
|
|
int i;
|
|
|
|
int alphabits = 0;
|
|
|
|
int fullalpha = 0;
|
2017-04-26 10:23:36 +00:00
|
|
|
bool intensity = 1;
|
2016-02-04 17:35:02 +00:00
|
|
|
|
|
|
|
if (!(_options & LET_TEXARTISTS_FLY)) {
|
|
|
|
/* HACK ALERT! */
|
|
|
|
/* Account for Rice's weirdness with fmt:0 siz:2 textures.
|
|
|
|
* Although the conditions are relaxed with other formats,
|
|
|
|
* the D3D RGBA5551 surface is used for this format in certain
|
|
|
|
* cases. See Nintemod's SuperMario64 life gauge and power
|
|
|
|
* meter. The same goes for fmt:2 textures. See Mollymutt's
|
|
|
|
* PaperMario text. */
|
|
|
|
if ((fmt == 0 && siz == 2) || fmt == 2) {
|
2016-03-10 11:14:33 +00:00
|
|
|
DBG_INFO(80, "Remove black, white, etc borders along the alpha edges.\n");
|
2016-02-04 17:35:02 +00:00
|
|
|
/* round A comp */
|
|
|
|
for (i = 0; i < height * width; i++) {
|
|
|
|
uint32 texel = ((uint32*)tex)[i];
|
|
|
|
((uint32*)tex)[i] = ((texel & 0xff000000) == 0xff000000 ? 0xff000000 : 0) |
|
2013-04-17 10:30:38 +00:00
|
|
|
(texel & 0x00ffffff);
|
2016-02-04 17:35:02 +00:00
|
|
|
}
|
|
|
|
/* Substitute texel color with the average of the surrounding
|
|
|
|
* opaque texels. This removes borders regardless of hardware
|
|
|
|
* texture filtering (bilinear, etc). */
|
|
|
|
int j;
|
|
|
|
for (i = 0; i < height; i++) {
|
|
|
|
for (j = 0; j < width; j++) {
|
|
|
|
uint32 texel = ((uint32*)tex)[i * width + j];
|
|
|
|
if ((texel & 0xff000000) != 0xff000000) {
|
|
|
|
uint32 tmptexel[8];
|
|
|
|
uint32 k, numtexel, r, g, b;
|
|
|
|
numtexel = r = g = b = 0;
|
|
|
|
memset(&tmptexel, 0, sizeof(tmptexel));
|
|
|
|
if (i > 0) {
|
|
|
|
tmptexel[0] = ((uint32*)tex)[(i - 1) * width + j]; /* north */
|
|
|
|
if (j > 0) tmptexel[1] = ((uint32*)tex)[(i - 1) * width + j - 1]; /* north-west */
|
|
|
|
if (j < width - 1) tmptexel[2] = ((uint32*)tex)[(i - 1) * width + j + 1]; /* north-east */
|
|
|
|
}
|
|
|
|
if (i < height - 1) {
|
|
|
|
tmptexel[3] = ((uint32*)tex)[(i + 1) * width + j]; /* south */
|
|
|
|
if (j > 0) tmptexel[4] = ((uint32*)tex)[(i + 1) * width + j - 1]; /* south-west */
|
|
|
|
if (j < width - 1) tmptexel[5] = ((uint32*)tex)[(i + 1) * width + j + 1]; /* south-east */
|
|
|
|
}
|
|
|
|
if (j > 0) tmptexel[6] = ((uint32*)tex)[i * width + j - 1]; /* west */
|
|
|
|
if (j < width - 1) tmptexel[7] = ((uint32*)tex)[i * width + j + 1]; /* east */
|
|
|
|
for (k = 0; k < 8; k++) {
|
|
|
|
if ((tmptexel[k] & 0xff000000) == 0xff000000) {
|
|
|
|
r += ((tmptexel[k] & 0x00ff0000) >> 16);
|
|
|
|
g += ((tmptexel[k] & 0x0000ff00) >> 8);
|
|
|
|
b += ((tmptexel[k] & 0x000000ff));
|
|
|
|
numtexel++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (numtexel) {
|
|
|
|
((uint32*)tex)[i * width + j] = ((r / numtexel) << 16) |
|
|
|
|
((g / numtexel) << 8) |
|
|
|
|
((b / numtexel));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
((uint32*)tex)[i * width + j] = texel & 0x00ffffff;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-04-17 10:30:38 +00:00
|
|
|
}
|
|
|
|
|
2016-02-04 17:35:02 +00:00
|
|
|
/* simple analysis of texture */
|
|
|
|
for (i = 0; i < height * width; i++) {
|
|
|
|
uint32 texel = ((uint32*)tex)[i];
|
|
|
|
if (alphabits != 8) {
|
2013-04-17 10:30:38 +00:00
|
|
|
#if AGGRESSIVE_QUANTIZATION
|
2016-02-04 17:35:02 +00:00
|
|
|
if ((texel & 0xff000000) < 0x00000003) {
|
|
|
|
alphabits = 1;
|
|
|
|
fullalpha++;
|
|
|
|
}
|
|
|
|
else if ((texel & 0xff000000) < 0xfe000000) {
|
|
|
|
alphabits = 8;
|
|
|
|
}
|
2013-04-17 10:30:38 +00:00
|
|
|
#else
|
2016-02-04 17:35:02 +00:00
|
|
|
if ((texel & 0xff000000) == 0x00000000) {
|
|
|
|
alphabits = 1;
|
|
|
|
fullalpha++;
|
|
|
|
}
|
|
|
|
else if ((texel & 0xff000000) != 0xff000000) {
|
|
|
|
alphabits = 8;
|
|
|
|
}
|
2013-04-17 10:30:38 +00:00
|
|
|
#endif
|
2016-02-04 17:35:02 +00:00
|
|
|
}
|
|
|
|
if (intensity) {
|
|
|
|
int rcomp = (texel >> 16) & 0xff;
|
|
|
|
int gcomp = (texel >> 8) & 0xff;
|
2017-04-26 10:23:36 +00:00
|
|
|
int bcomp = (texel) & 0xff;
|
2013-04-17 10:30:38 +00:00
|
|
|
#if AGGRESSIVE_QUANTIZATION
|
2016-02-04 17:35:02 +00:00
|
|
|
if (abs(rcomp - gcomp) > 8 || abs(rcomp - bcomp) > 8 || abs(gcomp - bcomp) > 8) intensity = 0;
|
2013-04-17 10:30:38 +00:00
|
|
|
#else
|
2016-02-04 17:35:02 +00:00
|
|
|
if (rcomp != gcomp || rcomp != bcomp || gcomp != bcomp) intensity = 0;
|
2013-04-17 10:30:38 +00:00
|
|
|
#endif
|
2016-02-04 17:35:02 +00:00
|
|
|
}
|
|
|
|
if (!intensity && alphabits == 8) break;
|
|
|
|
}
|
2016-03-10 11:14:33 +00:00
|
|
|
DBG_INFO(80, "required alpha bits:%d zero acomp texels:%d rgb as intensity:%d\n", alphabits, fullalpha, intensity);
|
2013-04-17 10:30:38 +00:00
|
|
|
|
2016-02-04 17:35:02 +00:00
|
|
|
/* preparations based on above analysis */
|
2013-04-17 10:30:38 +00:00
|
|
|
#if !REDUCE_TEXTURE_FOOTPRINT
|
2016-02-04 17:35:02 +00:00
|
|
|
if (_maxbpp < 32 || _options & (FORCE16BPP_HIRESTEX | COMPRESSION_MASK)) {
|
2013-04-17 10:30:38 +00:00
|
|
|
#endif
|
2017-05-17 10:34:55 +00:00
|
|
|
if (alphabits == 0) destformat = GFX_TEXFMT_RGB_565;
|
|
|
|
else if (alphabits == 1) destformat = GFX_TEXFMT_ARGB_1555;
|
|
|
|
else destformat = GFX_TEXFMT_ARGB_8888;
|
2013-04-17 10:30:38 +00:00
|
|
|
#if !REDUCE_TEXTURE_FOOTPRINT
|
2016-02-04 17:35:02 +00:00
|
|
|
}
|
|
|
|
else {
|
2017-05-17 10:34:55 +00:00
|
|
|
destformat = GFX_TEXFMT_ARGB_8888;
|
2016-02-04 17:35:02 +00:00
|
|
|
}
|
2013-04-17 10:30:38 +00:00
|
|
|
#endif
|
2016-02-04 17:35:02 +00:00
|
|
|
if (fmt == 4 && alphabits == 0) {
|
2017-05-17 10:34:55 +00:00
|
|
|
destformat = GFX_TEXFMT_ARGB_8888;
|
2016-02-04 17:35:02 +00:00
|
|
|
/* Rice I format; I = (R + G + B) / 3 */
|
|
|
|
for (i = 0; i < height * width; i++) {
|
|
|
|
uint32 texel = ((uint32*)tex)[i];
|
|
|
|
uint32 icomp = (((texel >> 16) & 0xff) +
|
|
|
|
((texel >> 8) & 0xff) +
|
2017-04-26 10:23:36 +00:00
|
|
|
((texel) & 0xff)) / 3;
|
2016-02-04 17:35:02 +00:00
|
|
|
((uint32*)tex)[i] = (icomp << 24) | (texel & 0x00ffffff);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (intensity) {
|
|
|
|
if (alphabits == 0) {
|
2017-05-17 10:34:55 +00:00
|
|
|
if (fmt == 4) destformat = GFX_TEXFMT_ALPHA_8;
|
|
|
|
else destformat = GFX_TEXFMT_INTENSITY_8;
|
2016-02-04 17:35:02 +00:00
|
|
|
}
|
|
|
|
else {
|
2017-05-17 10:34:55 +00:00
|
|
|
destformat = GFX_TEXFMT_ALPHA_INTENSITY_88;
|
2016-02-04 17:35:02 +00:00
|
|
|
}
|
|
|
|
}
|
2013-04-17 10:30:38 +00:00
|
|
|
|
2016-03-10 11:14:33 +00:00
|
|
|
DBG_INFO(80, "best gfmt:%x\n", destformat);
|
2016-02-04 17:35:02 +00:00
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Rice hi-res textures: end */
|
2013-04-17 10:30:38 +00:00
|
|
|
|
2017-04-26 10:23:36 +00:00
|
|
|
/* XXX: only ARGB8888 for now. comeback to this later... */
|
2017-05-17 10:34:55 +00:00
|
|
|
if (format == GFX_TEXFMT_ARGB_8888) {
|
2013-04-17 10:30:38 +00:00
|
|
|
#if TEXTURE_TILING
|
2017-08-20 22:20:19 +00:00
|
|
|
/* minification */
|
2017-04-26 10:23:36 +00:00
|
|
|
{
|
|
|
|
int ratio = 1;
|
|
|
|
|
|
|
|
/* minification to enable glide64 style texture tiling */
|
|
|
|
/* determine the minification ratio to tile the texture into 256x256 size */
|
|
|
|
if ((_options & TILE_HIRESTEX) && _maxwidth >= 256 && _maxheight >= 256) {
|
|
|
|
DBG_INFO(80, "determine minification ratio to tile\n");
|
|
|
|
tmpwidth = width;
|
|
|
|
tmpheight = height;
|
|
|
|
if (height > 256) {
|
|
|
|
ratio = ((height - 1) >> 8) + 1;
|
|
|
|
tmpwidth = width / ratio;
|
|
|
|
tmpheight = height / ratio;
|
|
|
|
DBG_INFO(80, "height > 256, minification ratio:%d %d x %d -> %d x %d\n",
|
|
|
|
ratio, width, height, tmpwidth, tmpheight);
|
|
|
|
}
|
|
|
|
if (tmpwidth > 256 && (((tmpwidth - 1) >> 8) + 1) * tmpheight > 256) {
|
|
|
|
ratio *= ((((((tmpwidth - 1) >> 8) + 1) * tmpheight) - 1) >> 8) + 1;
|
|
|
|
DBG_INFO(80, "width > 256, minification ratio:%d %d x %d -> %d x %d\n",
|
|
|
|
ratio, width, height, width / ratio, height / ratio);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* normal minification to fit max texture size */
|
|
|
|
if (width > _maxwidth || height > _maxheight) {
|
|
|
|
DBG_INFO(80, "determine minification ratio to fit max texture size\n");
|
|
|
|
tmpwidth = width;
|
|
|
|
tmpheight = height;
|
|
|
|
while (tmpwidth > _maxwidth) {
|
|
|
|
tmpheight >>= 1;
|
|
|
|
tmpwidth >>= 1;
|
|
|
|
ratio <<= 1;
|
|
|
|
}
|
|
|
|
while (tmpheight > _maxheight) {
|
|
|
|
tmpheight >>= 1;
|
|
|
|
tmpwidth >>= 1;
|
|
|
|
ratio <<= 1;
|
|
|
|
}
|
|
|
|
DBG_INFO(80, "minification ratio:%d %d x %d -> %d x %d\n",
|
|
|
|
ratio, width, height, tmpwidth, tmpheight);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ratio > 1) {
|
|
|
|
if (!_txReSample->minify(&tex, &width, &height, ratio)) {
|
|
|
|
free(tex);
|
|
|
|
tex = NULL;
|
|
|
|
DBG_INFO(80, "Error: minification failed!\n");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* tiling */
|
|
|
|
if ((_options & TILE_HIRESTEX) && _maxwidth >= 256 && _maxheight >= 256) {
|
|
|
|
bool usetile = 0;
|
|
|
|
|
|
|
|
/* to tile or not to tile, that is the question */
|
|
|
|
if (width > 256 && height <= 128 && (((width - 1) >> 8) + 1) * height <= 256) {
|
|
|
|
if (width > _maxwidth) usetile = 1;
|
|
|
|
else {
|
|
|
|
/* tile if the tiled texture memory footprint is smaller */
|
|
|
|
int tilewidth = 256;
|
|
|
|
int tileheight = _txReSample->nextPow2((((width - 1) >> 8) + 1) * height);
|
|
|
|
tmpwidth = width;
|
|
|
|
tmpheight = height;
|
|
|
|
|
|
|
|
/* 3dfx Glide3 tmpheight, W:H aspect ratio range (8:1 - 1:8) */
|
|
|
|
if (tilewidth > (tileheight << 3)) tileheight = tilewidth >> 3;
|
|
|
|
|
|
|
|
/* HACKALERT: see TxReSample::pow2(); */
|
|
|
|
if (tmpwidth > 64) tmpwidth -= 4;
|
|
|
|
else if (tmpwidth > 16) tmpwidth -= 2;
|
|
|
|
else if (tmpwidth > 4) tmpwidth -= 1;
|
|
|
|
|
|
|
|
if (tmpheight > 64) tmpheight -= 4;
|
|
|
|
else if (tmpheight > 16) tmpheight -= 2;
|
|
|
|
else if (tmpheight > 4) tmpheight -= 1;
|
|
|
|
|
|
|
|
tmpwidth = _txReSample->nextPow2(tmpwidth);
|
|
|
|
tmpheight = _txReSample->nextPow2(tmpheight);
|
|
|
|
|
|
|
|
/* 3dfx Glide3 tmpheight, W:H aspect ratio range (8:1 - 1:8) */
|
|
|
|
if (tmpwidth > tmpheight) {
|
|
|
|
if (tmpwidth > (tmpheight << 3)) tmpheight = tmpwidth >> 3;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (tmpheight > (tmpwidth << 3)) tmpwidth = tmpheight >> 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
usetile = (tilewidth * tileheight < tmpwidth * tmpheight);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* tile it! do the actual tiling into 256x256 size */
|
|
|
|
if (usetile) {
|
|
|
|
DBG_INFO(80, "Glide64 style texture tiling\n");
|
|
|
|
|
|
|
|
int x, y, z, ratio, offset;
|
|
|
|
offset = 0;
|
|
|
|
ratio = ((width - 1) >> 8) + 1;
|
|
|
|
tmptex = (uint8 *)malloc(_txUtil->sizeofTx(256, height * ratio, format));
|
|
|
|
if (tmptex) {
|
|
|
|
for (x = 0; x < ratio; x++) {
|
|
|
|
for (y = 0; y < height; y++) {
|
|
|
|
if (x < ratio - 1) {
|
|
|
|
memcpy(&tmptex[offset << 2], &tex[(x * 256 + y * width) << 2], 256 << 2);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
for (z = 0; z < width - 256 * (ratio - 1); z++) {
|
|
|
|
((uint32*)tmptex)[offset + z] = ((uint32*)tex)[x * 256 + y * width + z];
|
|
|
|
}
|
|
|
|
for (; z < 256; z++) {
|
|
|
|
((uint32*)tmptex)[offset + z] = ((uint32*)tmptex)[offset + z - 1];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
offset += 256;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
free(tex);
|
|
|
|
tex = tmptex;
|
|
|
|
untiled_width = width;
|
|
|
|
untiled_height = height;
|
|
|
|
width = 256;
|
|
|
|
height *= ratio;
|
|
|
|
DBG_INFO(80, "Tiled: %d x %d -> %d x %d\n", untiled_width, untiled_height, width, height);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-04-17 10:30:38 +00:00
|
|
|
|
|
|
|
#else /* TEXTURE_TILING */
|
|
|
|
|
2016-02-04 17:35:02 +00:00
|
|
|
/* minification */
|
|
|
|
if (width > _maxwidth || height > _maxheight) {
|
|
|
|
int ratio = 1;
|
|
|
|
if (width / _maxwidth > height / _maxheight) {
|
|
|
|
ratio = (int)ceil((double)width / _maxwidth);
|
2017-04-26 10:23:36 +00:00
|
|
|
}
|
|
|
|
else {
|
2016-02-04 17:35:02 +00:00
|
|
|
ratio = (int)ceil((double)height / _maxheight);
|
|
|
|
}
|
|
|
|
if (!_txReSample->minify(&tex, &width, &height, ratio)) {
|
|
|
|
free(tex);
|
|
|
|
tex = NULL;
|
2016-03-10 11:14:33 +00:00
|
|
|
DBG_INFO(80, "Error: minification failed!\n");
|
2016-02-04 17:35:02 +00:00
|
|
|
continue;
|
2016-02-10 07:02:20 +00:00
|
|
|
}
|
|
|
|
}
|
2013-04-17 10:30:38 +00:00
|
|
|
|
|
|
|
#endif /* TEXTURE_TILING */
|
|
|
|
|
2016-02-04 17:35:02 +00:00
|
|
|
/* texture compression */
|
|
|
|
if ((_options & COMPRESSION_MASK) &&
|
|
|
|
(width >= 64 && height >= 64) /* Texture compression is not suitable for low pixel coarse detail
|
|
|
|
* textures. The assumption here is that textures larger than 64x64
|
|
|
|
* have enough detail to produce decent quality when compressed. The
|
|
|
|
* down side is that narrow stripped textures that the N64 often use
|
|
|
|
* for large background textures are also ignored. It would be more
|
|
|
|
* reasonable if decisions are made based on fourier-transform
|
|
|
|
* spectrum or RMS error.
|
|
|
|
*
|
|
|
|
* NOTE: texture size must be checked before expanding to pow2 size.
|
|
|
|
*/
|
2017-04-26 10:23:36 +00:00
|
|
|
) {
|
2016-02-04 17:35:02 +00:00
|
|
|
int dataSize = 0;
|
|
|
|
int compressionType = _options & COMPRESSION_MASK;
|
2013-04-17 10:30:38 +00:00
|
|
|
|
|
|
|
#if POW2_TEXTURES
|
|
|
|
#if (POW2_TEXTURES == 2)
|
2016-02-04 17:35:02 +00:00
|
|
|
/* 3dfx Glide3x aspect ratio (8:1 - 1:8) */
|
|
|
|
if (!_txReSample->nextPow2(&tex, &width, &height, 32, 1)) {
|
2013-04-17 10:30:38 +00:00
|
|
|
#else
|
2016-02-04 17:35:02 +00:00
|
|
|
/* normal pow2 expansion */
|
|
|
|
if (!_txReSample->nextPow2(&tex, &width, &height, 32, 0)) {
|
2013-04-17 10:30:38 +00:00
|
|
|
#endif
|
2016-02-04 17:35:02 +00:00
|
|
|
free(tex);
|
|
|
|
tex = NULL;
|
2016-03-10 11:14:33 +00:00
|
|
|
DBG_INFO(80, "Error: aspect ratio adjustment failed!\n");
|
2016-02-04 17:35:02 +00:00
|
|
|
continue;
|
|
|
|
}
|
2013-04-17 10:30:38 +00:00
|
|
|
#endif
|
|
|
|
|
2016-02-04 17:35:02 +00:00
|
|
|
switch (_options & COMPRESSION_MASK) {
|
|
|
|
case S3TC_COMPRESSION:
|
|
|
|
switch (destformat) {
|
2017-05-17 10:34:55 +00:00
|
|
|
case GFX_TEXFMT_ARGB_8888:
|
2013-04-17 10:30:38 +00:00
|
|
|
#if GLIDE64_DXTN
|
2017-05-17 10:34:55 +00:00
|
|
|
case GFX_TEXFMT_ARGB_1555: /* for ARGB1555 use DXT5 instead of DXT1 */
|
2013-04-17 10:30:38 +00:00
|
|
|
#endif
|
2017-05-17 10:34:55 +00:00
|
|
|
case GFX_TEXFMT_ALPHA_INTENSITY_88:
|
2016-02-04 17:35:02 +00:00
|
|
|
dataSize = width * height;
|
|
|
|
break;
|
2013-04-17 10:30:38 +00:00
|
|
|
#if !GLIDE64_DXTN
|
2017-05-17 10:34:55 +00:00
|
|
|
case GFX_TEXFMT_ARGB_1555:
|
2013-04-17 10:30:38 +00:00
|
|
|
#endif
|
2017-05-17 10:34:55 +00:00
|
|
|
case GFX_TEXFMT_RGB_565:
|
|
|
|
case GFX_TEXFMT_INTENSITY_8:
|
2016-02-04 17:35:02 +00:00
|
|
|
dataSize = (width * height) >> 1;
|
|
|
|
break;
|
2017-05-17 10:34:55 +00:00
|
|
|
case GFX_TEXFMT_ALPHA_8: /* no size benefit with dxtn */
|
2016-02-04 17:35:02 +00:00
|
|
|
;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case FXT1_COMPRESSION:
|
|
|
|
switch (destformat) {
|
2017-05-17 10:34:55 +00:00
|
|
|
case GFX_TEXFMT_ARGB_1555:
|
|
|
|
case GFX_TEXFMT_RGB_565:
|
|
|
|
case GFX_TEXFMT_INTENSITY_8:
|
2016-02-04 17:35:02 +00:00
|
|
|
dataSize = (width * height) >> 1;
|
|
|
|
break;
|
|
|
|
/* XXX: textures that use 8bit alpha channel look bad with the current
|
|
|
|
* fxt1 library, so we substitute it with dxtn for now. afaik all gfx
|
|
|
|
* cards that support fxt1 also support dxtn. (3dfx and Intel) */
|
2017-05-17 10:34:55 +00:00
|
|
|
case GFX_TEXFMT_ALPHA_INTENSITY_88:
|
|
|
|
case GFX_TEXFMT_ARGB_8888:
|
2016-02-04 17:35:02 +00:00
|
|
|
compressionType = S3TC_COMPRESSION;
|
|
|
|
dataSize = width * height;
|
|
|
|
break;
|
2017-05-17 10:34:55 +00:00
|
|
|
case GFX_TEXFMT_ALPHA_8: /* no size benefit with dxtn */
|
2016-02-04 17:35:02 +00:00
|
|
|
;
|
|
|
|
}
|
2017-08-20 22:20:19 +00:00
|
|
|
}
|
2016-02-04 17:35:02 +00:00
|
|
|
/* compress it! */
|
|
|
|
if (dataSize) {
|
2013-04-17 10:30:38 +00:00
|
|
|
#if 0 /* TEST: dither before compression for better results with gradients */
|
2016-02-04 17:35:02 +00:00
|
|
|
tmptex = (uint8 *)malloc(_txUtil->sizeofTx(width, height, destformat));
|
|
|
|
if (tmptex) {
|
2017-05-17 10:34:55 +00:00
|
|
|
if (_txQuantize->quantize(tex, tmptex, width, height, GFX_TEXFMT_ARGB_8888, destformat, 0))
|
|
|
|
_txQuantize->quantize(tmptex, tex, width, height, destformat, GFX_TEXFMT_ARGB_8888, 0);
|
2016-02-04 17:35:02 +00:00
|
|
|
free(tmptex);
|
|
|
|
}
|
2013-04-17 10:30:38 +00:00
|
|
|
#endif
|
2016-02-04 17:35:02 +00:00
|
|
|
tmptex = (uint8 *)malloc(dataSize);
|
|
|
|
if (tmptex) {
|
|
|
|
if (_txQuantize->compress(tex, tmptex,
|
|
|
|
width, height, destformat,
|
|
|
|
&tmpwidth, &tmpheight, &tmpformat,
|
|
|
|
compressionType)) {
|
|
|
|
free(tex);
|
|
|
|
tex = tmptex;
|
|
|
|
width = tmpwidth;
|
|
|
|
height = tmpheight;
|
|
|
|
format = destformat = tmpformat;
|
2017-08-20 22:20:19 +00:00
|
|
|
}
|
2016-02-04 17:35:02 +00:00
|
|
|
else {
|
|
|
|
free(tmptex);
|
|
|
|
}
|
|
|
|
}
|
2017-08-20 22:20:19 +00:00
|
|
|
}
|
|
|
|
}
|
2016-02-04 17:35:02 +00:00
|
|
|
else {
|
2013-04-17 10:30:38 +00:00
|
|
|
#if POW2_TEXTURES
|
|
|
|
#if (POW2_TEXTURES == 2)
|
2016-02-04 17:35:02 +00:00
|
|
|
/* 3dfx Glide3x aspect ratio (8:1 - 1:8) */
|
|
|
|
if (!_txReSample->nextPow2(&tex, &width, &height, 32, 1)) {
|
2013-04-17 10:30:38 +00:00
|
|
|
#else
|
2016-02-04 17:35:02 +00:00
|
|
|
/* normal pow2 expansion */
|
|
|
|
if (!_txReSample->nextPow2(&tex, &width, &height, 32, 0)) {
|
2013-04-17 10:30:38 +00:00
|
|
|
#endif
|
2016-02-04 17:35:02 +00:00
|
|
|
free(tex);
|
|
|
|
tex = NULL;
|
2016-03-10 11:14:33 +00:00
|
|
|
DBG_INFO(80, "Error: aspect ratio adjustment failed!\n");
|
2016-02-04 17:35:02 +00:00
|
|
|
continue;
|
|
|
|
}
|
2013-04-17 10:30:38 +00:00
|
|
|
#endif
|
2017-08-20 22:20:19 +00:00
|
|
|
}
|
2013-04-17 10:30:38 +00:00
|
|
|
|
2016-02-04 17:35:02 +00:00
|
|
|
/* quantize */
|
2017-04-26 10:23:36 +00:00
|
|
|
{
|
|
|
|
tmptex = (uint8 *)malloc(_txUtil->sizeofTx(width, height, destformat));
|
|
|
|
if (tmptex) {
|
|
|
|
switch (destformat) {
|
2017-05-17 10:34:55 +00:00
|
|
|
case GFX_TEXFMT_ARGB_8888:
|
|
|
|
case GFX_TEXFMT_ARGB_4444:
|
2013-04-17 10:30:38 +00:00
|
|
|
#if !REDUCE_TEXTURE_FOOTPRINT
|
2017-04-26 10:23:36 +00:00
|
|
|
if (_maxbpp < 32 || _options & FORCE16BPP_HIRESTEX)
|
2013-04-17 10:30:38 +00:00
|
|
|
#endif
|
2017-05-17 10:34:55 +00:00
|
|
|
destformat = GFX_TEXFMT_ARGB_4444;
|
2017-04-26 10:23:36 +00:00
|
|
|
break;
|
2017-05-17 10:34:55 +00:00
|
|
|
case GFX_TEXFMT_ARGB_1555:
|
2013-04-17 10:30:38 +00:00
|
|
|
#if !REDUCE_TEXTURE_FOOTPRINT
|
2017-04-26 10:23:36 +00:00
|
|
|
if (_maxbpp < 32 || _options & FORCE16BPP_HIRESTEX)
|
2013-04-17 10:30:38 +00:00
|
|
|
#endif
|
2017-05-17 10:34:55 +00:00
|
|
|
destformat = GFX_TEXFMT_ARGB_1555;
|
2017-04-26 10:23:36 +00:00
|
|
|
break;
|
2017-05-17 10:34:55 +00:00
|
|
|
case GFX_TEXFMT_RGB_565:
|
2013-04-17 10:30:38 +00:00
|
|
|
#if !REDUCE_TEXTURE_FOOTPRINT
|
2017-04-26 10:23:36 +00:00
|
|
|
if (_maxbpp < 32 || _options & FORCE16BPP_HIRESTEX)
|
2013-04-17 10:30:38 +00:00
|
|
|
#endif
|
2017-05-17 10:34:55 +00:00
|
|
|
destformat = GFX_TEXFMT_RGB_565;
|
2017-04-26 10:23:36 +00:00
|
|
|
break;
|
2017-05-17 10:34:55 +00:00
|
|
|
case GFX_TEXFMT_ALPHA_INTENSITY_88:
|
|
|
|
case GFX_TEXFMT_ALPHA_INTENSITY_44:
|
2013-04-17 10:30:38 +00:00
|
|
|
#if !REDUCE_TEXTURE_FOOTPRINT
|
2017-05-17 10:34:55 +00:00
|
|
|
destformat = GFX_TEXFMT_ALPHA_INTENSITY_88;
|
2013-04-17 10:30:38 +00:00
|
|
|
#else
|
2017-05-17 10:34:55 +00:00
|
|
|
destformat = GFX_TEXFMT_ALPHA_INTENSITY_44;
|
2013-04-17 10:30:38 +00:00
|
|
|
#endif
|
2017-04-26 10:23:36 +00:00
|
|
|
break;
|
2017-05-17 10:34:55 +00:00
|
|
|
case GFX_TEXFMT_ALPHA_8:
|
|
|
|
destformat = GFX_TEXFMT_ALPHA_8; /* yes, this is correct. ALPHA_8 instead of INTENSITY_8 */
|
2017-04-26 10:23:36 +00:00
|
|
|
break;
|
2017-05-17 10:34:55 +00:00
|
|
|
case GFX_TEXFMT_INTENSITY_8:
|
|
|
|
destformat = GFX_TEXFMT_INTENSITY_8;
|
2017-04-26 10:23:36 +00:00
|
|
|
}
|
2017-05-17 10:34:55 +00:00
|
|
|
if (_txQuantize->quantize(tex, tmptex, width, height, GFX_TEXFMT_ARGB_8888, destformat, 0)) {
|
2017-04-26 10:23:36 +00:00
|
|
|
format = destformat;
|
|
|
|
free(tex);
|
|
|
|
tex = tmptex;
|
|
|
|
}
|
2017-08-20 22:20:19 +00:00
|
|
|
}
|
2017-04-26 10:23:36 +00:00
|
|
|
}
|
|
|
|
}
|
2013-04-17 10:30:38 +00:00
|
|
|
|
2016-02-04 17:35:02 +00:00
|
|
|
/* last minute validations */
|
|
|
|
if (!tex || !chksum || !width || !height || !format || width > _maxwidth || height > _maxheight) {
|
2013-04-17 10:30:38 +00:00
|
|
|
#if !DEBUG
|
2016-03-10 11:14:33 +00:00
|
|
|
INFO(80, "-----\n");
|
|
|
|
INFO(80, "path: %ls\n", stdstr(dir_path).ToUTF16().c_str());
|
|
|
|
INFO(80, "file: %ls\n", TextureDir.GetNameExtension().ToUTF16().c_str());
|
2013-04-17 10:30:38 +00:00
|
|
|
#endif
|
2016-02-04 17:35:02 +00:00
|
|
|
if (tex) {
|
|
|
|
free(tex);
|
|
|
|
tex = NULL;
|
2016-03-10 11:14:33 +00:00
|
|
|
INFO(80, "Error: bad format or size! %d x %d gfmt:%x\n", width, height, format);
|
2016-02-04 17:35:02 +00:00
|
|
|
}
|
|
|
|
else {
|
2016-03-10 11:14:33 +00:00
|
|
|
INFO(80, "Error: load failed!!\n");
|
2016-02-04 17:35:02 +00:00
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
2013-04-17 10:30:38 +00:00
|
|
|
|
2016-02-04 17:35:02 +00:00
|
|
|
/* load it into hires texture cache. */
|
2016-02-10 07:02:20 +00:00
|
|
|
{
|
2017-04-26 10:23:36 +00:00
|
|
|
uint64_t chksum64 = (uint64_t)palchksum;
|
2016-02-10 07:02:20 +00:00
|
|
|
chksum64 <<= 32;
|
2017-04-26 10:23:36 +00:00
|
|
|
chksum64 |= (uint64_t)chksum;
|
2016-02-10 07:02:20 +00:00
|
|
|
|
|
|
|
GHQTexInfo tmpInfo;
|
|
|
|
memset(&tmpInfo, 0, sizeof(GHQTexInfo));
|
|
|
|
|
|
|
|
tmpInfo.data = tex;
|
|
|
|
tmpInfo.width = width;
|
|
|
|
tmpInfo.height = height;
|
|
|
|
tmpInfo.format = format;
|
|
|
|
tmpInfo.largeLodLog2 = _txUtil->grLodLog2(width, height);
|
|
|
|
tmpInfo.smallLodLog2 = tmpInfo.largeLodLog2;
|
|
|
|
tmpInfo.aspectRatioLog2 = _txUtil->grAspectRatioLog2(width, height);
|
|
|
|
tmpInfo.is_hires_tex = 1;
|
2013-04-17 10:30:38 +00:00
|
|
|
|
|
|
|
#if TEXTURE_TILING
|
2016-02-10 07:02:20 +00:00
|
|
|
/* Glide64 style texture tiling. */
|
2017-04-26 10:23:36 +00:00
|
|
|
if (untiled_width && untiled_height)
|
|
|
|
{
|
2016-02-10 07:02:20 +00:00
|
|
|
tmpInfo.tiles = ((untiled_width - 1) >> 8) + 1;
|
|
|
|
tmpInfo.untiled_width = untiled_width;
|
|
|
|
tmpInfo.untiled_height = untiled_height;
|
|
|
|
}
|
2013-04-17 10:30:38 +00:00
|
|
|
#endif
|
|
|
|
|
2016-02-10 07:02:20 +00:00
|
|
|
/* remove redundant in cache */
|
2017-04-26 10:23:36 +00:00
|
|
|
if (replace && TxCache::del(chksum64))
|
|
|
|
{
|
2016-03-10 11:14:33 +00:00
|
|
|
DBG_INFO(80, "removed duplicate old cache.\n");
|
2016-02-10 07:02:20 +00:00
|
|
|
}
|
2013-04-17 10:30:38 +00:00
|
|
|
|
2016-02-10 07:02:20 +00:00
|
|
|
/* add to cache */
|
2017-04-26 10:23:36 +00:00
|
|
|
if (TxCache::add(chksum64, &tmpInfo))
|
|
|
|
{
|
2016-02-10 07:02:20 +00:00
|
|
|
/* Callback to display hires texture info.
|
|
|
|
* Gonetz <gonetz(at)ngs.ru> */
|
2017-04-26 10:23:36 +00:00
|
|
|
if (_callback)
|
|
|
|
{
|
|
|
|
wchar_t tmpbuf[260];
|
|
|
|
mbstowcs(tmpbuf, fname, 260);
|
2016-03-10 11:14:33 +00:00
|
|
|
(*_callback)("[%d] total mem:%.2fmb - %ls\n", _cache.size(), (float)_totalSize / 1000000, tmpbuf);
|
2016-02-10 07:02:20 +00:00
|
|
|
}
|
2016-03-10 11:14:33 +00:00
|
|
|
DBG_INFO(80, "texture loaded!\n");
|
2016-02-10 07:02:20 +00:00
|
|
|
}
|
|
|
|
free(tex);
|
2016-02-04 17:35:02 +00:00
|
|
|
}
|
2017-08-20 22:20:19 +00:00
|
|
|
} while (TextureDir.FindNext());
|
|
|
|
}
|
2016-02-10 07:02:20 +00:00
|
|
|
#endif
|
2016-02-04 17:35:02 +00:00
|
|
|
return 1;
|
2017-08-20 22:20:19 +00:00
|
|
|
}
|