diff --git a/projects/msvc/libGLideNHQ.vcxproj b/projects/msvc/libGLideNHQ.vcxproj
index 2166cb09..7ca533c7 100644
--- a/projects/msvc/libGLideNHQ.vcxproj
+++ b/projects/msvc/libGLideNHQ.vcxproj
@@ -126,7 +126,9 @@
+
+
diff --git a/projects/msvc/libGLideNHQ.vcxproj.filters b/projects/msvc/libGLideNHQ.vcxproj.filters
index c8484e32..e98cb16a 100644
--- a/projects/msvc/libGLideNHQ.vcxproj.filters
+++ b/projects/msvc/libGLideNHQ.vcxproj.filters
@@ -22,9 +22,15 @@
Source Files
+
+ Source Files
+
Source Files
+
+ Source Files
+
Source Files
diff --git a/src/Config.cpp b/src/Config.cpp
index c6f72295..bdc68473 100644
--- a/src/Config.cpp
+++ b/src/Config.cpp
@@ -102,6 +102,7 @@ void Config::resetToDefaults()
textureFilter.txEnhancedTextureFileStorage = 0;
textureFilter.txHiresTextureFileStorage = 0;
+ textureFilter.txNoTextureFileStorage = 0;
api().GetUserDataPath(textureFilter.txPath);
gln_wcscat(textureFilter.txPath, wst("/hires_texture"));
diff --git a/src/Config.h b/src/Config.h
index ddb762fd..4b0b5e05 100644
--- a/src/Config.h
+++ b/src/Config.h
@@ -175,6 +175,7 @@ struct Config
u32 txEnhancedTextureFileStorage; // Use file storage instead of memory cache for enhanced textures.
u32 txHiresTextureFileStorage; // Use file storage instead of memory cache for hires textures.
+ u32 txNoTextureFileStorage; // Use no file storage or cache for hires textures.
wchar_t txPath[PLUGIN_PATH_SIZE]; // Path to texture packs
wchar_t txCachePath[PLUGIN_PATH_SIZE]; // Path to store texture cache, that is .htc files
diff --git a/src/GLideNHQ/CMakeLists.txt b/src/GLideNHQ/CMakeLists.txt
index 6f8562bf..1e98896d 100644
--- a/src/GLideNHQ/CMakeLists.txt
+++ b/src/GLideNHQ/CMakeLists.txt
@@ -12,7 +12,9 @@ set(GLideNHQ_SOURCES
TxDbg.cpp
TxFilter.cpp
TxFilterExport.cpp
+ TxHiResLoader.cpp
TxHiResCache.cpp
+ TxHiResNoCache.cpp
TxImage.cpp
TxQuantize.cpp
TxReSample.cpp
diff --git a/src/GLideNHQ/Ext_TxFilter.h b/src/GLideNHQ/Ext_TxFilter.h
index 7185637d..439ae9b7 100644
--- a/src/GLideNHQ/Ext_TxFilter.h
+++ b/src/GLideNHQ/Ext_TxFilter.h
@@ -93,6 +93,7 @@ typedef unsigned char boolean;
#define JABO_HIRESTEXTURES 0x00030000
#define FILE_CACHE_MASK 0x00300000
+#define FILE_NOTEXCACHE 0x08500000
#define FILE_TEXCACHE 0x00100000
#define FILE_HIRESTEXCACHE 0x00200000
#define GZ_TEXCACHE 0x00400000
diff --git a/src/GLideNHQ/TxFilter.cpp b/src/GLideNHQ/TxFilter.cpp
index 6ef69086..e266d1e9 100644
--- a/src/GLideNHQ/TxFilter.cpp
+++ b/src/GLideNHQ/TxFilter.cpp
@@ -38,8 +38,8 @@
void TxFilter::clear()
{
- /* clear hires texture cache */
- delete _txHiResCache;
+ /* clear hires texture loader */
+ delete _txHiResLoader;
/* clear texture cache */
delete _txTexCache;
@@ -71,7 +71,7 @@ TxFilter::TxFilter(int maxwidth,
, _tex2(nullptr)
, _txQuantize(nullptr)
, _txTexCache(nullptr)
- , _txHiResCache(nullptr)
+ , _txHiResLoader(nullptr)
, _txImage(nullptr)
{
/* HACKALERT: the emulator misbehaves and sometimes forgets to shutdown */
@@ -150,9 +150,17 @@ TxFilter::TxFilter(int maxwidth,
/* hires texture */
#if HIRES_TEXTURE
- _txHiResCache = new TxHiResCache(_maxwidth, _maxheight, _maxbpp, _options, texCachePath, texPackPath, _ident.c_str(), callback);
+ if ((_options & FILE_NOTEXCACHE) == FILE_NOTEXCACHE) {
+ wchar_t fullTexPackPath[MAX_PATH];
+ wcscpy(fullTexPackPath, texPackPath);
+ wcscat(fullTexPackPath, OSAL_DIR_SEPARATOR_STR);
+ wcscat(fullTexPackPath, ident);
+ _txHiResLoader = new TxHiResNoCache(_maxwidth, _maxheight, _maxbpp, _options, texCachePath, texPackPath, fullTexPackPath, _ident.c_str(), callback);
+ } else {
+ _txHiResLoader = new TxHiResCache(_maxwidth, _maxheight, _maxbpp, _options, texCachePath, texPackPath, _ident.c_str(), callback);
+ }
- if (_txHiResCache->empty())
+ if (_txHiResLoader->empty())
_options &= ~HIRESTEXTURES_MASK;
#endif
@@ -479,7 +487,7 @@ TxFilter::hirestex(uint64 g64crc, uint64 r_crc64, uint16 *palette, GHQTexInfo *i
#if HIRES_TEXTURE
/* check if we have it in hires memory cache. */
if ((_options & HIRESTEXTURES_MASK) && r_crc64) {
- if (_txHiResCache->get(r_crc64, info)) {
+ if (_txHiResLoader->get(r_crc64, info)) {
DBG_INFO(80, wst("hires hit: %d x %d gfmt:%x\n"), info->width, info->height, info->format);
/* TODO: Enable emulation for special N64 combiner modes. There are few ways
@@ -506,8 +514,8 @@ TxFilter::hirestex(uint64 g64crc, uint64 r_crc64, uint16 *palette, GHQTexInfo *i
return 1; /* yep, got it */
}
- if (_txHiResCache->get((r_crc64 >> 32), info) ||
- _txHiResCache->get((r_crc64 & 0xffffffff), info)) {
+ if (_txHiResLoader->get((r_crc64 >> 32), info) ||
+ _txHiResLoader->get((r_crc64 & 0xffffffff), info)) {
DBG_INFO(80, wst("hires hit: %d x %d gfmt:%x\n"), info->width, info->height, info->format);
/* for true CI textures, we use the passed in palette to convert to
@@ -543,7 +551,7 @@ TxFilter::hirestex(uint64 g64crc, uint64 r_crc64, uint16 *palette, GHQTexInfo *i
setTextureFormat(format, info);
/* XXX: add to hires texture cache!!! */
- _txHiResCache->add(r_crc64, info);
+ _txHiResLoader->add(r_crc64, info);
DBG_INFO(80, wst("COLOR_INDEX8 loaded as gfmt:%x!\n"), u32(format));
}
@@ -639,7 +647,7 @@ TxFilter::reloadhirestex()
{
DBG_INFO(80, wst("Reload hires textures from texture pack.\n"));
- if (_txHiResCache->load(0) && !_txHiResCache->empty()) {
+ if (_txHiResLoader->reload()) {
_options |= HIRESTEXTURES_MASK;
return 1;
}
@@ -655,6 +663,6 @@ TxFilter::dumpcache()
/* hires texture */
#if HIRES_TEXTURE
- _txHiResCache->dump();
+ _txHiResLoader->dump();
#endif
}
diff --git a/src/GLideNHQ/TxFilter.h b/src/GLideNHQ/TxFilter.h
index f3e24bf1..a331c697 100644
--- a/src/GLideNHQ/TxFilter.h
+++ b/src/GLideNHQ/TxFilter.h
@@ -27,6 +27,8 @@
#include "TxInternal.h"
#include "TxQuantize.h"
#include "TxHiResCache.h"
+#include "TxHiResNoCache.h"
+#include "TxHiResLoader.h"
#include "TxTexCache.h"
#include "TxUtil.h"
#include "TxImage.h"
@@ -47,7 +49,7 @@ private:
tx_wstring _dumpPath;
TxQuantize *_txQuantize;
TxTexCache *_txTexCache;
- TxHiResCache *_txHiResCache;
+ TxHiResLoader *_txHiResLoader;
TxImage *_txImage;
boolean _initialized;
void clear();
diff --git a/src/GLideNHQ/TxHiResCache.cpp b/src/GLideNHQ/TxHiResCache.cpp
index 47022dd9..9669b099 100644
--- a/src/GLideNHQ/TxHiResCache.cpp
+++ b/src/GLideNHQ/TxHiResCache.cpp
@@ -28,17 +28,10 @@
#pragma warning(disable: 4786)
#endif
-/* use power of 2 texture size
- * (0:disable, 1:enable, 2:3dfx) */
-#define POW2_TEXTURES 0
-
-/* use aggressive format assumption for quantization
- * (0:disable, 1:enable, 2:extreme) */
-#define AGGRESSIVE_QUANTIZATION 1
-
#include "TxHiResCache.h"
#include "TxDbg.h"
#include
+#include
#include
#include
#include
@@ -59,16 +52,10 @@ TxHiResCache::TxHiResCache(int maxwidth,
const wchar_t *ident,
dispInfoFuncExt callback)
: TxCache((options & ~(GZ_TEXCACHE | FILE_TEXCACHE)), 0, cachePath, ident, callback)
- , _maxwidth(maxwidth)
- , _maxheight(maxheight)
- , _maxbpp(maxbpp)
+ , TxHiResLoader(maxwidth, maxheight, maxbpp, options)
, _abortLoad(false)
, _cacheDumped(false)
- , _txImage(new TxImage())
- , _txQuantize(new TxQuantize())
- , _txReSample(new TxReSample())
{
-
if (texPackPath)
_texPackPath.assign(texPackPath);
@@ -125,7 +112,7 @@ boolean TxHiResCache::_HiResTexPackPathExists() const
return osal_path_existsW(dir_path.c_str());
}
-bool TxHiResCache::load(boolean replace) /* 0 : reload, 1 : replace partial */
+bool TxHiResCache::_load(boolean replace) /* 0 : reload, 1 : replace partial */
{
if (_texPackPath.empty() || _ident.empty())
return false;
@@ -151,7 +138,7 @@ bool TxHiResCache::load(boolean replace) /* 0 : reload, 1 : replace partial */
dir_path += OSAL_DIR_SEPARATOR_STR;
dir_path += _ident;
- const LoadResult res = loadHiResTextures(dir_path.c_str(), replace);
+ const LoadResult res = _loadHiResTextures(dir_path.c_str(), replace);
if (res == resError) {
if (_callback) (*_callback)(wst("Texture pack load failed. Clear hiresolution texture cache.\n"));
INFO(80, wst("Texture pack load failed. Clear hiresolution texture cache.\n"));
@@ -162,7 +149,12 @@ bool TxHiResCache::load(boolean replace) /* 0 : reload, 1 : replace partial */
return false;
}
-TxHiResCache::LoadResult TxHiResCache::loadHiResTextures(const wchar_t * dir_path, boolean replace)
+bool TxHiResCache::reload()
+{
+ return _load(0) && !TxCache::empty();
+}
+
+TxHiResCache::LoadResult TxHiResCache::_loadHiResTextures(const wchar_t * dir_path, boolean replace)
{
DBG_INFO(80, wst("-----\n"));
DBG_INFO(80, wst("path: %ls\n"), dir_path);
@@ -193,8 +185,8 @@ TxHiResCache::LoadResult TxHiResCache::loadHiResTextures(const wchar_t * dir_pat
tx_wstring texturefilename;
do {
-
- if (KBHIT(0x1B)) {
+ osal_keys_update_state();
+ if (osal_is_key_pressed(KEY_Escape, 0x0001)) {
_abortLoad = true;
if (_callback) (*_callback)(wst("Aborted loading hiresolution texture!\n"));
INFO(80, wst("Error: aborted loading hiresolution texture!\n"));
@@ -210,13 +202,14 @@ TxHiResCache::LoadResult TxHiResCache::loadHiResTextures(const wchar_t * dir_pat
if (wccmp(foundfilename, wst(".")))
// These files we don't need
continue;
+
texturefilename.assign(dir_path);
texturefilename += OSAL_DIR_SEPARATOR_STR;
texturefilename += foundfilename;
/* recursive read into sub-directory */
if (osal_is_directory(texturefilename.c_str())) {
- result = loadHiResTextures(texturefilename.c_str(), replace);
+ result = _loadHiResTextures(texturefilename.c_str(), replace);
if (result == resOk)
continue;
else
@@ -229,103 +222,25 @@ TxHiResCache::LoadResult TxHiResCache::loadHiResTextures(const wchar_t * dir_pat
int width = 0, height = 0;
ColorFormat format = graphics::internalcolorFormat::NOCOLOR;
uint8 *tex = nullptr;
- int tmpwidth = 0, tmpheight = 0;
- ColorFormat tmpformat = graphics::internalcolorFormat::NOCOLOR;
- uint8 *tmptex = nullptr;
- ColorFormat destformat = graphics::internalcolorFormat::NOCOLOR;
/* Rice hi-res textures: begin
*/
- uint32 chksum = 0, fmt = 0, siz = 0, palchksum = 0;
- bool hasWildcard = false;
- char *pfname = nullptr, fname[MAX_PATH];
- std::string ident;
+ uint32 chksum = 0, fmt = 0, siz = 0, palchksum = 0, length = 0;
+ char fname[MAX_PATH];
+ char ident[MAX_PATH];
FILE *fp = nullptr;
- wcstombs(fname, _ident.c_str(), MAX_PATH);
- /* XXX case sensitivity fiasco!
- * files must use _a, _rgb, _all, _allciByRGBA, _ciByRGBA, _ci
- * and file extensions must be in lower case letters! */
-#ifdef OS_WINDOWS
- {
- unsigned int i;
- for (i = 0; i < strlen(fname); i++) fname[i] = tolower(fname[i]);
- }
-#endif
- ident.assign(fname);
+ wcstombs(ident, _ident.c_str(), MAX_PATH);
+ wcstombs(fname, foundfilename, MAX_PATH);
+
+ /* lowercase on windows */
+ CORRECTFILENAME(ident);
+ CORRECTFILENAME(fname);
/* read in Rice's file naming convention */
-#define CRCFMTSIZ_LEN 13
-#define CRCWILDCARD_LEN 15
-#define PALCRC_LEN 9
- wcstombs(fname, foundfilename, MAX_PATH);
- /* XXX case sensitivity fiasco!
- * files must use _a, _rgb, _all, _allciByRGBA, _ciByRGBA, _ci
- * and file extensions must be in lower case letters! */
-#ifdef OS_WINDOWS
- {
- unsigned int i;
- for (i = 0; i < strlen(fname); i++) fname[i] = tolower(fname[i]);
- }
-#endif
- pfname = fname + strlen(fname) - 4;
- if (!(pfname == strstr(fname, ".png") ||
- pfname == strstr(fname, ".bmp") ||
- pfname == strstr(fname, ".dds"))) {
-#if !DEBUG
- INFO(80, wst("-----\n"));
- INFO(80, wst("path: %ls\n"), dir_path.string().c_str());
- INFO(80, wst("file: %ls\n"), it->path().leaf().c_str());
-#endif
- INFO(80, wst("Error: not png or bmp or dds!\n"));
- continue;
- }
- pfname = strstr(fname, ident.c_str());
- if (pfname != fname) pfname = 0;
- if (pfname) {
- uint32_t length = 0;
- const char* strName = pfname + ident.size();
-
- /* wildcard support */
- if (strchr(strName, '$')) {
- if (sscanf(strName, "#%08X#%01X#%01X#$", &chksum, &fmt, &siz) == 3) {
- length = CRCWILDCARD_LEN;
- } else if (sscanf(strName, "#$#%01X#%01X#%08X", &fmt, &siz, &palchksum) == 3) {
- length = CRCWILDCARD_LEN;
- }
-
- hasWildcard = (length != 0);
- } else {
- if (sscanf(strName, "#%08X#%01X#%01X#%08X", &chksum, &fmt, &siz, &palchksum) == 4) {
- length = CRCFMTSIZ_LEN + PALCRC_LEN;
- } else if (sscanf(strName, "#%08X#%01X#%01X", &chksum, &fmt, &siz) == 3) {
- length = CRCFMTSIZ_LEN;
- }
- }
-
- if (length) {
- pfname += (ident.size() + length);
- } else {
- pfname = 0;
- }
- }
-
- if (!pfname) {
-#if !DEBUG
- INFO(80, wst("-----\n"));
- INFO(80, wst("path: %ls\n", dir_path));
- INFO(80, wst("file: %ls\n", foundfilename));
-#endif
- INFO(80, wst("Error: not Rice texture naming convention!\n"));
- continue;
- }
- if (!chksum && !hasWildcard) {
-#if !DEBUG
- INFO(80, wst("-----\n"));
- INFO(80, wst("path: %ls\n"), dir_path.string().c_str());
- INFO(80, wst("file: %ls\n"), it->path().leaf().c_str());
-#endif
- INFO(80, wst("Error: crc32 = 0!\n"));
+ length = checkFileName(ident, fname, &chksum, &palchksum, &fmt, &siz);
+ if (length == 0) {
+ /* invalid file name, skip it */
continue;
}
@@ -339,424 +254,22 @@ TxHiResCache::LoadResult TxHiResCache::loadHiResTextures(const wchar_t * dir_pat
if (isCached(chksum64)) {
#if !DEBUG
INFO(80, wst("-----\n"));
- INFO(80, wst("path: %ls\n"), dir_path.string().c_str());
- INFO(80, wst("file: %ls\n"), it->path().leaf().c_str());
+ INFO(80, wst("file: %s\n"), fname);
#endif
INFO(80, wst("Error: already cached! duplicate texture!\n"));
continue;
}
}
+ tex = loadFileInfoTex(fname, siz, &width, &height, fmt, &format);
+ if (tex == nullptr) {
+ /* failed to load file into tex data, skip it */
+ continue;
+ }
+
DBG_INFO(80, wst("rom: %ls chksum:%08X %08X fmt:%x size:%x\n"), _ident.c_str(), chksum, palchksum, fmt, siz);
- /* 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");
- if (!osal_path_existsA(fname)) {
- strcpy(pfname, "_rgb.bmp");
- if (!osal_path_existsA(fname)) {
-#if !DEBUG
- INFO(80, wst("-----\n"));
- INFO(80, wst("path: %ls\n"), dir_path.string().c_str());
- INFO(80, wst("file: %ls\n"), it->path().leaf().c_str());
-#endif
- INFO(80, wst("Error: missing _rgb.*! _a.* must be paired with _rgb.*!\n"));
- continue;
- }
- }
- /* _a.png */
- strcpy(pfname, "_a.png");
- if ((fp = fopen(fname, "rb")) != nullptr) {
- tmptex = _txImage->readPNG(fp, &tmpwidth, &tmpheight, &tmpformat);
- fclose(fp);
- }
- if (!tmptex) {
- /* _a.bmp */
- strcpy(pfname, "_a.bmp");
- if ((fp = fopen(fname, "rb")) != nullptr) {
- tmptex = _txImage->readBMP(fp, &tmpwidth, &tmpheight, &tmpformat);
- fclose(fp);
- }
- }
- /* _rgb.png */
- strcpy(pfname, "_rgb.png");
- if ((fp = fopen(fname, "rb")) != nullptr) {
- tex = _txImage->readPNG(fp, &width, &height, &format);
- fclose(fp);
- }
- if (!tex) {
- /* _rgb.bmp */
- strcpy(pfname, "_rgb.bmp");
- if ((fp = fopen(fname, "rb")) != nullptr) {
- 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 ||
- format != graphics::internalcolorFormat::RGBA8 || tmpformat != graphics::internalcolorFormat::RGBA8) {
-#if !DEBUG
- INFO(80, wst("-----\n"));
- INFO(80, wst("path: %ls\n"), dir_path.string().c_str());
- INFO(80, wst("file: %ls\n"), it->path().leaf().c_str());
-#endif
- if (!tex) {
- INFO(80, wst("Error: missing _rgb.*!\n"));
- }
- else if (width != tmpwidth || height != tmpheight) {
- INFO(80, wst("Error: _rgb.* and _a.* have mismatched width or height!\n"));
- }
- else if (format != graphics::internalcolorFormat::RGBA8 || tmpformat != graphics::internalcolorFormat::RGBA8) {
- INFO(80, wst("Error: _rgb.* or _a.* not in 32bit color!\n"));
- }
- if (tex) free(tex);
- free(tmptex);
- tex = nullptr;
- tmptex = nullptr;
- continue;
- }
- }
- /* make adjustments */
- if (tex) {
- if (tmptex) {
- /* merge (A)RGB and A comp */
- DBG_INFO(80, wst("merge (A)RGB and A comp\n"));
- int i;
- for (i = 0; i < height * width; i++) {
-#if 1
- /* use R comp for alpha. this is what Rice uses. sigh... */
- ((uint32*)tex)[i] &= 0x00ffffff;
- ((uint32*)tex)[i] |= ((((uint32*)tmptex)[i] & 0xff) << 24);
-#endif
-#if 0
- /* use libpng style grayscale conversion */
- uint32 texel = ((uint32*)tmptex)[i];
- uint32 acomp = (((texel >> 16) & 0xff) * 6969 +
- ((texel >> 8) & 0xff) * 23434 +
- ((texel ) & 0xff) * 2365) / 32768;
- ((uint32*)tex)[i] = (acomp << 24) | (((uint32*)tex)[i] & 0x00ffffff);
-#endif
-#if 0
- /* use the standard NTSC gray scale conversion */
- uint32 texel = ((uint32*)tmptex)[i];
- uint32 acomp = (((texel >> 16) & 0xff) * 299 +
- ((texel >> 8) & 0xff) * 587 +
- ((texel ) & 0xff) * 114) / 1000;
- ((uint32*)tex)[i] = (acomp << 24) | (((uint32*)tex)[i] & 0x00ffffff);
-#endif
- }
- free(tmptex);
- tmptex = nullptr;
- }
- else {
- /* clobber A comp. never a question of alpha. only RGB used. */
-#if !DEBUG
- INFO(80, wst("-----\n"));
- INFO(80, wst("path: %ls\n"), dir_path.string().c_str());
- INFO(80, wst("file: %ls\n"), it->path().leaf().c_str());
-#endif
- INFO(80, wst("Warning: missing _a.*! only using _rgb.*. treat as opaque texture.\n"));
- 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
- */
- if (pfname == strstr(fname, "_all.png") ||
- pfname == strstr(fname, "_all.dds") ||
-#ifdef OS_WINDOWS
- pfname == strstr(fname, "_allcibyrgba.png") ||
- pfname == strstr(fname, "_allcibyrgba.dds") ||
- pfname == strstr(fname, "_cibyrgba.png") ||
- pfname == strstr(fname, "_cibyrgba.dds") ||
-#else
- pfname == strstr(fname, "_allciByRGBA.png") ||
- pfname == strstr(fname, "_allciByRGBA.dds") ||
- pfname == strstr(fname, "_ciByRGBA.png") ||
- pfname == strstr(fname, "_ciByRGBA.dds") ||
-#endif
- pfname == strstr(fname, "_ci.bmp")) {
- if ((fp = fopen(fname, "rb")) != nullptr) {
- if (strstr(fname, ".png"))
- tex = _txImage->readPNG(fp, &width, &height, &format);
- else
- tex = _txImage->readBMP(fp, &width, &height, &format);
- fclose(fp);
- }
- }
-
- /* if we do not have a texture at this point we are screwed */
- if (!tex) {
-#if !DEBUG
- INFO(80, wst("-----\n"));
- INFO(80, wst("path: %ls\n"), dir_path.string().c_str());
- INFO(80, wst("file: %ls\n"), it->path().leaf().c_str());
-#endif
- INFO(80, wst("Error: load failed!\n"));
- continue;
- }
- DBG_INFO(80, wst("read in as %d x %d gfmt:%x\n"), tmpwidth, tmpheight, tmpformat);
-
- /* check if size and format are OK */
- if (!(format == graphics::internalcolorFormat::RGBA8 || format == graphics::internalcolorFormat::COLOR_INDEX8) ||
- (width * height) < 4) { /* TxQuantize requirement: width * height must be 4 or larger. */
- free(tex);
- tex = nullptr;
-#if !DEBUG
- INFO(80, wst("-----\n"));
- INFO(80, wst("path: %ls\n"), dir_path.string().c_str());
- INFO(80, wst("file: %ls\n"), it->path().leaf().c_str());
-#endif
- INFO(80, wst("Error: not width * height > 4 or 8bit palette color or 32bpp or dxt1 or dxt3 or dxt5!\n"));
- continue;
- }
-
- /* analyze and determine best format to quantize */
- if (format == graphics::internalcolorFormat::RGBA8) {
- int i;
- int alphabits = 0;
- int fullalpha = 0;
- boolean intensity = 1;
-
- if (!(getOptions() & 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) {
- DBG_INFO(80, wst("Remove black, white, etc borders along the alpha edges.\n"));
- /* round A comp */
- for (i = 0; i < height * width; i++) {
- uint32 texel = ((uint32*)tex)[i];
- ((uint32*)tex)[i] = ((texel & 0xff000000) == 0xff000000 ? 0xff000000 : 0) |
- (texel & 0x00ffffff);
- }
- /* 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) {
- b += ((tmptexel[k] & 0x00ff0000) >> 16);
- g += ((tmptexel[k] & 0x0000ff00) >> 8);
- r += ((tmptexel[k] & 0x000000ff));
- numtexel++;
- }
- }
- if (numtexel) {
- ((uint32*)tex)[i * width + j] = ((b / numtexel) << 16) |
- ((g / numtexel) << 8) |
- ((r / numtexel));
- }
- else {
- ((uint32*)tex)[i * width + j] = texel & 0x00ffffff;
- }
- }
- }
- }
- }
- }
-
- /* simple analysis of texture */
- for (i = 0; i < height * width; i++) {
- uint32 texel = ((uint32*)tex)[i];
- if (alphabits != 8) {
-#if AGGRESSIVE_QUANTIZATION
- if ((texel & 0xff000000) < 0x00000003) {
- alphabits = 1;
- fullalpha++;
- } else if ((texel & 0xff000000) < 0xfe000000) {
- alphabits = 8;
- }
-#else
- if ((texel & 0xff000000) == 0x00000000) {
- alphabits = 1;
- fullalpha++;
- } else if ((texel & 0xff000000) != 0xff000000) {
- alphabits = 8;
- }
-#endif
- }
- if (intensity) {
- int rcomp = (texel >> 16) & 0xff;
- int gcomp = (texel >> 8) & 0xff;
- int bcomp = (texel)& 0xff;
-#if AGGRESSIVE_QUANTIZATION
- if (abs(rcomp - gcomp) > 8 || abs(rcomp - bcomp) > 8 || abs(gcomp - bcomp) > 8)
- intensity = 0;
-#else
- if (rcomp != gcomp || rcomp != bcomp || gcomp != bcomp) intensity = 0;
-#endif
- }
- if (!intensity && alphabits == 8)
- break;
- }
- DBG_INFO(80, wst("required alpha bits:%d zero acomp texels:%d rgb as intensity:%d\n"), alphabits, fullalpha, intensity);
-
- /* preparations based on above analysis */
- if (_maxbpp < 32 || getOptions() & FORCE16BPP_HIRESTEX) {
- if (alphabits == 0)
- destformat = graphics::internalcolorFormat::RGB8;
- else if (alphabits == 1)
- destformat = graphics::internalcolorFormat::RGB5_A1;
- else
- destformat = graphics::internalcolorFormat::RGBA8;
- }
- else {
- destformat = graphics::internalcolorFormat::RGBA8;
- }
- if (fmt == 4 && alphabits == 0) {
- destformat = graphics::internalcolorFormat::RGBA8;
- /* 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) +
- ((texel)& 0xff)) / 3;
- ((uint32*)tex)[i] = (icomp << 24) | (texel & 0x00ffffff);
- }
- }
-
- DBG_INFO(80, wst("best gfmt:%x\n"), u32(destformat));
- }
- /*
- * Rice hi-res textures: end */
-
-
- /* XXX: only RGBA8888 for now. comeback to this later... */
- if (format == graphics::internalcolorFormat::RGBA8) {
-
- /* minification */
- if (width > _maxwidth || height > _maxheight) {
- int ratio = 1;
- if (width / _maxwidth > height / _maxheight) {
- ratio = (int)ceil((double)width / _maxwidth);
- }
- else {
- ratio = (int)ceil((double)height / _maxheight);
- }
- if (!_txReSample->minify(&tex, &width, &height, ratio)) {
- free(tex);
- tex = nullptr;
- DBG_INFO(80, wst("Error: minification failed!\n"));
- continue;
- }
- }
-
-#if POW2_TEXTURES
-#if (POW2_TEXTURES == 2)
- /* 3dfx Glide3x aspect ratio (8:1 - 1:8) */
- if (!_txReSample->nextPow2(&tex, &width , &height, 32, 1)) {
-#else
- /* normal pow2 expansion */
- if (!_txReSample->nextPow2(&tex, &width , &height, 32, 0)) {
-#endif
- free(tex);
- tex = nullptr;
- DBG_INFO(80, wst("Error: aspect ratio adjustment failed!\n"));
- continue;
- }
-#endif
-
- /* quantize */
- {
- tmptex = (uint8 *)malloc(TxUtil::sizeofTx(width, height, destformat));
- if (tmptex == nullptr) {
- free(tex);
- tex = nullptr;
- result = resError;
- break;
- }
- if (destformat == graphics::internalcolorFormat::RGBA8 ||
- destformat == graphics::internalcolorFormat::RGBA4) {
- if (_maxbpp < 32 || getOptions() & FORCE16BPP_HIRESTEX)
- destformat = graphics::internalcolorFormat::RGBA4;
- }
- else if (destformat == graphics::internalcolorFormat::RGB5_A1) {
- if (_maxbpp < 32 || getOptions() & FORCE16BPP_HIRESTEX)
- destformat = graphics::internalcolorFormat::RGB5_A1;
- }
- if (_txQuantize->quantize(tex, tmptex, width, height, graphics::internalcolorFormat::RGBA8, destformat, 0)) {
- format = destformat;
- free(tex);
- tex = tmptex;
- }
- else
- free(tmptex);
- tmptex = nullptr;
- }
- }
-
-
- /* last minute validations */
- if (!tex || (!chksum && !hasWildcard) || !width || !height || format == graphics::internalcolorFormat::NOCOLOR || width > _maxwidth || height > _maxheight) {
-#if !DEBUG
- INFO(80, wst("-----\n"));
- INFO(80, wst("path: %ls\n"), dir_path.string().c_str());
- INFO(80, wst("file: %ls\n"), it->path().leaf().c_str());
-#endif
- if (tex) {
- free(tex);
- tex = nullptr;
- INFO(80, wst("Error: bad format or size! %d x %d gfmt:%x\n"), width, height, u32(format));
- }
- else {
- INFO(80, wst("Error: load failed!!\n"));
- }
- continue;
- }
-
/* load it into hires texture cache. */
- {
uint64 chksum64 = (uint64)palchksum;
if (chksum) {
chksum64 <<= 32;
@@ -792,12 +305,27 @@ TxHiResCache::LoadResult TxHiResCache::loadHiResTextures(const wchar_t * dir_pat
result = resError;
break;
}
- }
} while (foundfilename != nullptr);
+
osal_search_dir_close(dir);
CHDIR(curpath);
return result;
}
+
+bool TxHiResCache::empty() const
+{
+ return TxCache::empty();
+}
+
+bool TxHiResCache::add(Checksum checksum, GHQTexInfo *info, int dataSize)
+{
+ return TxCache::add(checksum, info, dataSize);
+}
+
+bool TxHiResCache::get(Checksum checksum, GHQTexInfo *info)
+{
+ return TxCache::get(checksum, info);
+}
diff --git a/src/GLideNHQ/TxHiResCache.h b/src/GLideNHQ/TxHiResCache.h
index 1326ce9a..41b884ee 100644
--- a/src/GLideNHQ/TxHiResCache.h
+++ b/src/GLideNHQ/TxHiResCache.h
@@ -24,38 +24,29 @@
#ifndef __TXHIRESCACHE_H__
#define __TXHIRESCACHE_H__
-/* support hires textures
- * 0: disable
- * 1: enable
- */
-#define HIRES_TEXTURE 1
-
#include "TxCache.h"
#include "TxQuantize.h"
#include "TxImage.h"
#include "TxReSample.h"
+#include "TxHiResLoader.h"
-class TxHiResCache : public TxCache
+class TxHiResCache : public TxCache, public TxHiResLoader
{
private:
- int _maxwidth;
- int _maxheight;
- int _maxbpp;
bool _abortLoad;
bool _cacheDumped;
- std::unique_ptr _txImage;
- std::unique_ptr _txQuantize;
- std::unique_ptr _txReSample;
+
tx_wstring _texPackPath;
enum LoadResult {
resOk,
resNotFound,
resError
};
- LoadResult loadHiResTextures(const wchar_t * dir_path, boolean replace);
+ LoadResult _loadHiResTextures(const wchar_t * dir_path, boolean replace);
boolean _HiResTexPackPathExists() const;
tx_wstring _getFileName() const override;
int _getConfig() const override;
+ bool _load(boolean replace);
public:
~TxHiResCache();
@@ -67,8 +58,11 @@ public:
const wchar_t *texPackPath,
const wchar_t *ident,
dispInfoFuncExt callback);
- bool load(boolean replace);
- void dump();
+ bool empty() const override;
+ bool add(Checksum checksum, GHQTexInfo *info, int dataSize = 0) override;
+ bool get(Checksum checksum, GHQTexInfo *info) override;
+ bool reload() override;
+ void dump() override;
};
#endif /* __TXHIRESCACHE_H__ */
diff --git a/src/GLideNHQ/TxHiResLoader.cpp b/src/GLideNHQ/TxHiResLoader.cpp
new file mode 100644
index 00000000..17b21515
--- /dev/null
+++ b/src/GLideNHQ/TxHiResLoader.cpp
@@ -0,0 +1,585 @@
+#include "TxHiResLoader.h"
+#include "TxDbg.h"
+#include "TxDbg.h"
+#include "Ext_TxFilter.h"
+
+#include
+#include
+#include
+
+/* use power of 2 texture size
+ * (0:disable, 1:enable, 2:3dfx) */
+#define POW2_TEXTURES 0
+
+/* use aggressive format assumption for quantization
+ * (0:disable, 1:enable, 2:extreme) */
+#define AGGRESSIVE_QUANTIZATION 1
+
+TxHiResLoader::TxHiResLoader(int maxwidth,
+ int maxheight,
+ int maxbpp,
+ int options)
+ : _txImage(new TxImage())
+ , _txQuantize(new TxQuantize())
+ , _txReSample(new TxReSample())
+ , _maxwidth(maxwidth)
+ , _maxheight(maxheight)
+ , _maxbpp(maxbpp)
+ , _options(options)
+{
+
+}
+
+uint32_t TxHiResLoader::checkFileName(char* ident, char* filename,
+ uint32_t* pChksum, uint32_t* pPalchksum,
+ uint32_t* pFmt, uint32_t* pSiz)
+{
+#define CRCFMTSIZ_LEN 13
+#define CRCWILDCARD_LEN 15
+#define PALCRC_LEN 9
+
+ const char* strName;
+ const char* pfilename;
+ uint32_t length = 0, filename_type = 0;
+ bool hasWildcard = false;
+ const char supported_ends[][20] = {
+ "all.png",
+ "all.dds",
+#ifdef OS_WINDOWS
+ "allcibyrgba.png",
+ "allcibyrgba.dds",
+ "cibyrgba.png",
+ "cibyrgba.dds",
+#else
+ "allciByRGBA.png",
+ "allciByRGBA.dds",
+ "ciByRGBA.png",
+ "ciByRGBA.dds",
+#endif
+ "rgb.png",
+ "rgb.bmp",
+ "a.png",
+ "a.bmp"
+ };
+
+ pfilename = filename + strlen(filename) - 4;
+
+ if (strcmp(pfilename, ".png") &&
+ strcmp(pfilename, ".bmp") &&
+ strcmp(pfilename, ".dds")) {
+#if !DEBUG
+ INFO(80, wst("-----\n"));
+ INFO(80, wst("file: %s\n"), filename);
+#endif
+ INFO(80, wst("Error: not png or bmp or dds!\n"));
+ return 0;
+ }
+
+ /* make sure filename contains ident */
+ pfilename = strstr(filename, ident);
+ if (!pfilename) {
+ return 0;
+ }
+
+ strName = pfilename + strlen(ident);
+
+ /* wildcard support */
+ if (strchr(strName, '$')) {
+ if (sscanf(strName, "#%08X#%01X#%01X#$", pChksum, pFmt, pSiz) == 3) {
+ filename_type = 1;
+ length = CRCWILDCARD_LEN;
+ } else if (sscanf(strName, "#$#%01X#%01X#%08X", pFmt, pSiz, pPalchksum) == 3) {
+ filename_type = 2;
+ length = CRCWILDCARD_LEN;
+ }
+
+ hasWildcard = (length != 0);
+ } else {
+ if (sscanf(strName, "#%08X#%01X#%01X#%08X", pChksum, pFmt, pSiz, pPalchksum) == 4) {
+ filename_type = 3;
+ length = CRCFMTSIZ_LEN + PALCRC_LEN;
+ } else if (sscanf(strName, "#%08X#%01X#%01X", pChksum, pFmt, pSiz) == 3) {
+ filename_type = 4;
+ length = CRCFMTSIZ_LEN;
+ }
+ }
+
+ /* try to re-create string and match it */
+ bool supportedFilename = false;
+ char test_filename[MAX_PATH];
+ for (int i = 0; length && i < (sizeof(supported_ends) / sizeof(supported_ends[0])); i++) {
+ char* end = (char*)supported_ends[i];
+
+ switch (filename_type)
+ {
+ default:
+ case 1:
+ sprintf(test_filename, "%s#%08X#%01X#%01X#$_%s", ident, *pChksum, *pFmt, *pSiz, end);
+ break;
+ case 2:
+ sprintf(test_filename, "%s#$#%01X#%01X#%08X_%s", ident, *pFmt, *pSiz, *pPalchksum, end);
+ break;
+ case 3:
+ sprintf(test_filename, "%s#%08X#%01X#%01X#%08X_%s", ident, *pChksum, *pFmt, *pSiz, *pPalchksum, end);
+ break;
+ case 4:
+ sprintf(test_filename, "%s#%08X#%01X#%01X_%s", ident, *pChksum, *pFmt, *pSiz, end);
+ break;
+ }
+
+ /* lowercase on windows */
+ CORRECTFILENAME(test_filename);
+
+ /* when it matches, break */
+ if (strcmp(test_filename, filename) == 0) {
+ supportedFilename = true;
+ break;
+ }
+ }
+
+ if (!supportedFilename || !length) {
+#if !DEBUG
+ INFO(80, wst("-----\n"));
+ INFO(80, wst("file: %s\n", filename));
+#endif
+ INFO(80, wst("Error: not Rice texture naming convention!\n"));
+ return 0;
+ }
+
+ if (!*pChksum && !hasWildcard) {
+#if !DEBUG
+ INFO(80, wst("-----\n"));
+ INFO(80, wst("file: %s\n"), filename);
+#endif
+ INFO(80, wst("Error: crc32 = 0!\n"));
+ return 0;
+ }
+
+ return length;
+}
+
+uint8_t* TxHiResLoader::loadFileInfoTex(char* fname,
+ int siz, int* pWidth, int* pHeight,
+ uint32_t fmt,
+ ColorFormat* pFormat)
+{
+ /* 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
+ */
+
+ uint8_t* tex = nullptr;
+ uint8_t* tmptex = nullptr;
+ int tmpwidth = 0, tmpheight = 0;
+ int width = 0, height = 0;
+ FILE* fp = nullptr;
+
+ ColorFormat tmpformat = graphics::internalcolorFormat::NOCOLOR;
+ ColorFormat destformat = graphics::internalcolorFormat::NOCOLOR;
+ ColorFormat format = graphics::internalcolorFormat::NOCOLOR;
+
+ char* pfname;
+
+ /*
+ * read in _rgb.* and _a.*
+ */
+ if ((pfname = strstr(fname, "_rgb.")) ||
+ (pfname = strstr(fname, "_a."))) {
+ strcpy(pfname, "_rgb.png");
+ if (!osal_path_existsA(fname)) {
+ strcpy(pfname, "_rgb.bmp");
+ if (!osal_path_existsA(fname)) {
+#if !DEBUG
+ INFO(80, wst("-----\n"));
+ INFO(80, wst("file: %s\n"), fname);
+#endif
+ INFO(80, wst("Error: missing _rgb.*! _a.* must be paired with _rgb.*!\n"));
+ return nullptr;;
+ }
+ }
+ /* _a.png */
+ strcpy(pfname, "_a.png");
+ if ((fp = fopen(fname, "rb")) != nullptr) {
+ tmptex = _txImage->readPNG(fp, &tmpwidth, &tmpheight, &tmpformat);
+ fclose(fp);
+ }
+ if (!tmptex) {
+ /* _a.bmp */
+ strcpy(pfname, "_a.bmp");
+ if ((fp = fopen(fname, "rb")) != nullptr) {
+ tmptex = _txImage->readBMP(fp, &tmpwidth, &tmpheight, &tmpformat);
+ fclose(fp);
+ }
+ }
+ /* _rgb.png */
+ strcpy(pfname, "_rgb.png");
+ if ((fp = fopen(fname, "rb")) != nullptr) {
+ tex = _txImage->readPNG(fp, &width, &height, &format);
+ fclose(fp);
+ }
+ if (!tex) {
+ /* _rgb.bmp */
+ strcpy(pfname, "_rgb.bmp");
+ if ((fp = fopen(fname, "rb")) != nullptr) {
+ 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 ||
+ format != graphics::internalcolorFormat::RGBA8 || tmpformat != graphics::internalcolorFormat::RGBA8) {
+#if !DEBUG
+ INFO(80, wst("-----\n"));
+ INFO(80, wst("file: %s\n"), fname);
+#endif
+ if (!tex) {
+ INFO(80, wst("Error: missing _rgb.*!\n"));
+ }
+ else if (width != tmpwidth || height != tmpheight) {
+ INFO(80, wst("Error: _rgb.* and _a.* have mismatched width or height!\n"));
+ }
+ else if (format != graphics::internalcolorFormat::RGBA8 || tmpformat != graphics::internalcolorFormat::RGBA8) {
+ INFO(80, wst("Error: _rgb.* or _a.* not in 32bit color!\n"));
+ }
+ if (tex) free(tex);
+ free(tmptex);
+ tex = nullptr;
+ tmptex = nullptr;
+ return nullptr;
+ }
+ }
+ /* make adjustments */
+ if (tex) {
+ if (tmptex) {
+ /* merge (A)RGB and A comp */
+ DBG_INFO(80, wst("merge (A)RGB and A comp\n"));
+ int i;
+ for (i = 0; i < height * width; i++) {
+#if 1
+ /* use R comp for alpha. this is what Rice uses. sigh... */
+ ((uint32*)tex)[i] &= 0x00ffffff;
+ ((uint32*)tex)[i] |= ((((uint32*)tmptex)[i] & 0xff) << 24);
+#endif
+#if 0
+ /* use libpng style grayscale conversion */
+ uint32 texel = ((uint32*)tmptex)[i];
+ uint32 acomp = (((texel >> 16) & 0xff) * 6969 +
+ ((texel >> 8) & 0xff) * 23434 +
+ ((texel ) & 0xff) * 2365) / 32768;
+ ((uint32*)tex)[i] = (acomp << 24) | (((uint32*)tex)[i] & 0x00ffffff);
+#endif
+#if 0
+ /* use the standard NTSC gray scale conversion */
+ uint32 texel = ((uint32*)tmptex)[i];
+ uint32 acomp = (((texel >> 16) & 0xff) * 299 +
+ ((texel >> 8) & 0xff) * 587 +
+ ((texel ) & 0xff) * 114) / 1000;
+ ((uint32*)tex)[i] = (acomp << 24) | (((uint32*)tex)[i] & 0x00ffffff);
+#endif
+ }
+ free(tmptex);
+ tmptex = nullptr;
+ }
+ else {
+ /* clobber A comp. never a question of alpha. only RGB used. */
+#if !DEBUG
+ INFO(80, wst("-----\n"));
+ INFO(80, wst("file: %ls\n"), fname);
+#endif
+ INFO(80, wst("Warning: missing _a.*! only using _rgb.*. treat as opaque texture.\n"));
+ 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
+ */
+ if (strstr(fname, "_all.png") ||
+ strstr(fname, "_all.dds") ||
+#ifdef OS_WINDOWS
+ strstr(fname, "_allcibyrgba.png") ||
+ strstr(fname, "_allcibyrgba.dds") ||
+ strstr(fname, "_cibyrgba.png") ||
+ strstr(fname, "_cibyrgba.dds") ||
+#else
+ strstr(fname, "_allciByRGBA.png") ||
+ strstr(fname, "_allciByRGBA.dds") ||
+ strstr(fname, "_ciByRGBA.png") ||
+ strstr(fname, "_ciByRGBA.dds") ||
+#endif
+ strstr(fname, "_ci.bmp")) {
+
+ if ((fp = fopen(fname, "rb")) != nullptr) {
+ if (strstr(fname, ".png"))
+ tex = _txImage->readPNG(fp, &width, &height, &format);
+ else
+ tex = _txImage->readBMP(fp, &width, &height, &format);
+
+ fclose(fp);
+ }
+ }
+
+ /* if we do not have a texture at this point we are screwed */
+ if (!tex) {
+#if !DEBUG
+ INFO(80, wst("-----\n"));
+ INFO(80, wst("file: %s\n"), fname);
+#endif
+ INFO(80, wst("Error: load failed!\n"));
+ return nullptr;
+ }
+ DBG_INFO(80, wst("read in as %d x %d gfmt:%x\n"), tmpwidth, tmpheight, tmpformat);
+
+ /* check if size and format are OK */
+ if (!(format == graphics::internalcolorFormat::RGBA8 || format == graphics::internalcolorFormat::COLOR_INDEX8) ||
+ (width * height) < 4) { /* TxQuantize requirement: width * height must be 4 or larger. */
+ free(tex);
+ tex = nullptr;
+#if !DEBUG
+ INFO(80, wst("-----\n"));
+ INFO(80, wst("file: %ls\n"), fname);
+#endif
+ INFO(80, wst("Error: not width * height > 4 or 8bit palette color or 32bpp or dxt1 or dxt3 or dxt5!\n"));
+ return nullptr;
+ }
+
+ /* analyze and determine best format to quantize */
+ if (format == graphics::internalcolorFormat::RGBA8) {
+ int i;
+ int alphabits = 0;
+ int fullalpha = 0;
+ boolean intensity = 1;
+
+ 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) {
+ DBG_INFO(80, wst("Remove black, white, etc borders along the alpha edges.\n"));
+ /* round A comp */
+ for (i = 0; i < height * width; i++) {
+ uint32 texel = ((uint32*)tex)[i];
+ ((uint32*)tex)[i] = ((texel & 0xff000000) == 0xff000000 ? 0xff000000 : 0) |
+ (texel & 0x00ffffff);
+ }
+ /* 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) {
+ b += ((tmptexel[k] & 0x00ff0000) >> 16);
+ g += ((tmptexel[k] & 0x0000ff00) >> 8);
+ r += ((tmptexel[k] & 0x000000ff));
+ numtexel++;
+ }
+ }
+ if (numtexel) {
+ ((uint32*)tex)[i * width + j] = ((b / numtexel) << 16) |
+ ((g / numtexel) << 8) |
+ ((r / numtexel));
+ }
+ else {
+ ((uint32*)tex)[i * width + j] = texel & 0x00ffffff;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* simple analysis of texture */
+ for (i = 0; i < height * width; i++) {
+ uint32 texel = ((uint32*)tex)[i];
+ if (alphabits != 8) {
+#if AGGRESSIVE_QUANTIZATION
+ if ((texel & 0xff000000) < 0x00000003) {
+ alphabits = 1;
+ fullalpha++;
+ } else if ((texel & 0xff000000) < 0xfe000000) {
+ alphabits = 8;
+ }
+#else
+ if ((texel & 0xff000000) == 0x00000000) {
+ alphabits = 1;
+ fullalpha++;
+ } else if ((texel & 0xff000000) != 0xff000000) {
+ alphabits = 8;
+ }
+#endif
+ }
+ if (intensity) {
+ int rcomp = (texel >> 16) & 0xff;
+ int gcomp = (texel >> 8) & 0xff;
+ int bcomp = (texel)& 0xff;
+#if AGGRESSIVE_QUANTIZATION
+ if (abs(rcomp - gcomp) > 8 || abs(rcomp - bcomp) > 8 || abs(gcomp - bcomp) > 8)
+ intensity = 0;
+#else
+ if (rcomp != gcomp || rcomp != bcomp || gcomp != bcomp) intensity = 0;
+#endif
+ }
+ if (!intensity && alphabits == 8)
+ break;
+ }
+ DBG_INFO(80, wst("required alpha bits:%d zero acomp texels:%d rgb as intensity:%d\n"), alphabits, fullalpha, intensity);
+
+ /* preparations based on above analysis */
+ if (_maxbpp < 32 || _options & FORCE16BPP_HIRESTEX) {
+ if (alphabits == 0)
+ destformat = graphics::internalcolorFormat::RGB8;
+ else if (alphabits == 1)
+ destformat = graphics::internalcolorFormat::RGB5_A1;
+ else
+ destformat = graphics::internalcolorFormat::RGBA8;
+ }
+ else {
+ destformat = graphics::internalcolorFormat::RGBA8;
+ }
+ if (fmt == 4 && alphabits == 0) {
+ destformat = graphics::internalcolorFormat::RGBA8;
+ /* 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) +
+ ((texel)& 0xff)) / 3;
+ ((uint32*)tex)[i] = (icomp << 24) | (texel & 0x00ffffff);
+ }
+ }
+
+ DBG_INFO(80, wst("best gfmt:%x\n"), u32(destformat));
+ }
+ /*
+ * Rice hi-res textures: end */
+
+
+ /* XXX: only RGBA8888 for now. comeback to this later... */
+ if (format == graphics::internalcolorFormat::RGBA8) {
+
+ /* minification */
+ if (width > _maxwidth || height > _maxheight) {
+ int ratio = 1;
+ if (width / _maxwidth > height / _maxheight) {
+ ratio = (int)ceil((double)width / _maxwidth);
+ }
+ else {
+ ratio = (int)ceil((double)height / _maxheight);
+ }
+ if (!_txReSample->minify(&tex, &width, &height, ratio)) {
+ free(tex);
+ tex = nullptr;
+ DBG_INFO(80, wst("Error: minification failed!\n"));
+ return nullptr;
+ }
+ }
+
+#if POW2_TEXTURES
+#if (POW2_TEXTURES == 2)
+ /* 3dfx Glide3x aspect ratio (8:1 - 1:8) */
+ if (!_txReSample->nextPow2(&tex, &width , &height, 32, 1)) {
+#else
+ /* normal pow2 expansion */
+ if (!_txReSample->nextPow2(&tex, &width , &height, 32, 0)) {
+#endif
+ free(tex);
+ tex = nullptr;
+ DBG_INFO(80, wst("Error: aspect ratio adjustment failed!\n"));
+ return nullptr;
+ }
+#endif
+
+ /* quantize */
+ {
+ tmptex = (uint8 *)malloc(TxUtil::sizeofTx(width, height, destformat));
+ if (tmptex == nullptr) {
+ free(tex);
+ tex = nullptr;
+ return nullptr;
+ }
+ if (destformat == graphics::internalcolorFormat::RGBA8 ||
+ destformat == graphics::internalcolorFormat::RGBA4) {
+ if (_maxbpp < 32 || _options & FORCE16BPP_HIRESTEX)
+ destformat = graphics::internalcolorFormat::RGBA4;
+ }
+ else if (destformat == graphics::internalcolorFormat::RGB5_A1) {
+ if (_maxbpp < 32 || _options & FORCE16BPP_HIRESTEX)
+ destformat = graphics::internalcolorFormat::RGB5_A1;
+ }
+ if (_txQuantize->quantize(tex, tmptex, width, height, graphics::internalcolorFormat::RGBA8, destformat, 0)) {
+ format = destformat;
+ free(tex);
+ tex = tmptex;
+ }
+ else
+ free(tmptex);
+ tmptex = nullptr;
+ }
+ }
+
+
+ /* last minute validations */
+ if (!tex || !width || !height || format == graphics::internalcolorFormat::NOCOLOR || width > _maxwidth || height > _maxheight) {
+#if !DEBUG
+ INFO(80, wst("-----\n"));
+ INFO(80, wst("file: %s\n"), fname);
+#endif
+ if (tex) {
+ free(tex);
+ tex = nullptr;
+ INFO(80, wst("Error: bad format or size! %d x %d gfmt:%x\n"), width, height, u32(format));
+ }
+ else {
+ INFO(80, wst("Error: load failed!!\n"));
+ }
+ return nullptr;
+ }
+
+ *pWidth = width;
+ *pHeight = height;
+ *pFormat = format;
+
+ return tex;
+}
+
diff --git a/src/GLideNHQ/TxHiResLoader.h b/src/GLideNHQ/TxHiResLoader.h
new file mode 100644
index 00000000..98c72f19
--- /dev/null
+++ b/src/GLideNHQ/TxHiResLoader.h
@@ -0,0 +1,50 @@
+#ifndef TXHIRESLOADER_H
+#define TXHIRESLOADER_H
+
+/* support hires textures
+ * 0: disable
+ * 1: enable
+ */
+#define HIRES_TEXTURE 1
+
+#ifdef OS_WINDOWS
+#define CORRECTFILENAME(str) for (uint32 i = 0; i < strlen(str); i++) str[i] = tolower(str[i])
+#else
+#define CORRECTFILENAME(str)
+#endif /* OS_WINDOWS */
+
+#include "TxCache.h"
+#include "TxQuantize.h"
+#include "TxImage.h"
+#include "TxReSample.h"
+
+class TxHiResLoader
+{
+protected:
+ uint32_t checkFileName(char* ident, char* fname, uint32_t* pChksum, uint32_t* pPalchksum, uint32_t* pFmt, uint32_t* pSiz);
+ uint8_t* loadFileInfoTex(char* fname, int siz, int* pWidth, int* pHeight, uint32_t fmt, ColorFormat* pFormat);
+
+ std::unique_ptr _txImage;
+ std::unique_ptr _txQuantize;
+ std::unique_ptr _txReSample;
+
+ int _maxwidth;
+ int _maxheight;
+ int _maxbpp;
+ int _options;
+
+public:
+ TxHiResLoader(int maxwidth,
+ int maxheight,
+ int maxbpp,
+ int options);
+ virtual ~TxHiResLoader(){}
+
+ virtual bool empty() const = 0;
+ virtual bool add(Checksum checksum, GHQTexInfo *info, int dataSize = 0) = 0;
+ virtual bool get(Checksum checksum, GHQTexInfo *info) = 0;
+ virtual bool reload() = 0;
+ virtual void dump() = 0;
+};
+
+#endif /* TXHIRESLOADER_H */
diff --git a/src/GLideNHQ/TxHiResNoCache.cpp b/src/GLideNHQ/TxHiResNoCache.cpp
new file mode 100644
index 00000000..351c835d
--- /dev/null
+++ b/src/GLideNHQ/TxHiResNoCache.cpp
@@ -0,0 +1,225 @@
+#include "TxHiResNoCache.h"
+
+#include "TxDbg.h"
+#include "Ext_TxFilter.h"
+#include
+
+TxHiResNoCache::TxHiResNoCache(int maxwidth,
+ int maxheight,
+ int maxbpp,
+ int options,
+ const wchar_t *cachePath,
+ const wchar_t *texPackPath,
+ const wchar_t *fullTexPath,
+ const wchar_t *ident,
+ dispInfoFuncExt callback)
+ : TxHiResLoader(maxwidth, maxheight, maxbpp, options)
+ , _fullTexPath(fullTexPath)
+ , _ident(ident)
+ , _callback(callback)
+{
+ /* store this for _createFileIndexInDir */
+ wcstombs(_identc, _ident.c_str(), MAX_PATH);
+
+ /* lowercase on windows */
+ CORRECTFILENAME(_identc);
+
+ _createFileIndex(false);
+}
+
+TxHiResNoCache::~TxHiResNoCache()
+{
+ _clear();
+}
+
+void TxHiResNoCache::_clear()
+{
+ /* free loaded textures */
+ for (auto texMap : _loadedTex) {
+ free(texMap.second.data);
+ }
+
+ /* clear all lists */
+ _loadedTex.clear();
+ _filesIndex.clear();
+}
+
+bool TxHiResNoCache::empty() const
+{
+ return _filesIndex.empty();
+}
+
+bool TxHiResNoCache::get(Checksum checksum, GHQTexInfo *info)
+{
+ if (!checksum) {
+ return false;
+ }
+
+
+#ifdef DEBUG
+ uint32 chksum = checksum._checksum & 0xffffffff;
+ uint32 palchksum = checksum._checksum >> 32;
+#endif
+
+ /* loop over each file from the index and try to match it with checksum */
+ auto indexEntry = _filesIndex.find(checksum);
+ if (indexEntry == _filesIndex.end()) {
+ DBG_INFO(80, wst("TxNoCache::get: chksum:%08X %08X not found\n"), chksum, palchksum);
+ return false;
+ }
+
+ fileIndexEntry_t& entry = indexEntry->second;
+
+ /* make sure to not load the same texture twice */
+ auto loadedTexMap = _loadedTex.find(checksum);
+ if (loadedTexMap != _loadedTex.end()) {
+ DBG_INFO(80, wst("TxNoCache::get: cached chksum:%08X %08X found\n"), chksum, palchksum);
+ *info = loadedTexMap->second;
+ return true;
+ }
+
+ DBG_INFO(80, wst("TxNoCache::get: loading chksum:%08X %08X\n"), chksum, palchksum);
+
+ /* change current dir to directory */
+#ifdef OS_WINDOWS
+ wchar_t curpath[MAX_PATH];
+ GETCWD(MAX_PATH, curpath);
+ CHDIR(entry.directory.c_str());
+#else
+ char curpath[MAX_PATH];
+ char cbuf[MAX_PATH];
+ wcstombs(cbuf, entry.directory.c_str(), MAX_PATH);
+ GETCWD(MAX_PATH, curpath);
+ CHDIR(cbuf);
+#endif
+
+ /* load texture */
+ int width = 0, height = 0;
+ ColorFormat format;
+ uint8_t* tex = TxHiResLoader::loadFileInfoTex(entry.fname, entry.siz, &width, &height, entry.fmt, &format);
+
+ /* restore directory */
+ CHDIR(curpath);
+
+ if (tex == nullptr) {
+ /* failed to load texture, so return false */
+ DBG_INFO(80, wst("TxNoCache::get: failed to load chksum:%08X %08X\n"), chksum, palchksum);
+ return false;
+ }
+
+ DBG_INFO(80, wst("TxNoCache::get: loaded chksum:%08X %08X\n"), chksum, palchksum);
+
+ info->data = tex;
+ info->width = width;
+ info->height = height;
+ info->is_hires_tex = 1;
+ setTextureFormat(format, info);
+
+ /* add to loaded textures */
+ _loadedTex.insert(std::map::value_type(checksum, *info));
+ return true;
+}
+
+bool TxHiResNoCache::reload()
+{
+ _clear();
+ return _createFileIndex(true);
+}
+
+bool TxHiResNoCache::_createFileIndex(bool update)
+{
+ /* don't display anything during an update,
+ * it causes flicker on i.e an ssd
+ */
+ if (!update && _callback) {
+ _callback(L"CREATING FILE INDEX. PLEASE WAIT...");
+ }
+
+ _createFileIndexInDir(_fullTexPath, update);
+
+ return true;
+}
+
+bool TxHiResNoCache::_createFileIndexInDir(tx_wstring directory, bool update)
+{
+ /* find it on disk */
+ if (!osal_path_existsW(directory.c_str())) {
+ return false;
+ }
+
+ void *dir = osal_search_dir_open(directory.c_str());
+ const wchar_t *foundfilename;
+ tx_wstring texturefilename;
+ bool result = true;
+
+ do {
+ foundfilename = osal_search_dir_read_next(dir);
+ if (foundfilename == nullptr) {
+ /* no more files/directories */
+ break;
+ }
+
+ /* skip hidden files */
+ if (wccmp(foundfilename, wst("."))) {
+ continue;
+ }
+
+ texturefilename.assign(directory);
+ texturefilename += OSAL_DIR_SEPARATOR_STR;
+ texturefilename += foundfilename;
+
+ /* recursive read into sub-directory */
+ if (osal_is_directory(texturefilename.c_str())) {
+ result = _createFileIndexInDir(texturefilename.c_str(), update);
+ if (result) {
+ continue;
+ } else {
+ break;
+ }
+ }
+
+ uint64 chksum64 = 0;
+ uint32 chksum = 0, palchksum = 0, length = 0;
+ fileIndexEntry_t entry;
+ entry.fmt = entry.siz = 0;
+ bool ret = false;
+
+ wcstombs(entry.fname, foundfilename, MAX_PATH);
+
+ /* lowercase on windows */
+ CORRECTFILENAME(entry.fname);
+
+ /* read in Rice's file naming convention */
+ length = TxHiResLoader::checkFileName(_identc, entry.fname, &chksum, &palchksum, &entry.fmt, &entry.siz);
+ if (length == 0) {
+ /* invalid file name, skip it */
+ continue;
+ }
+
+ entry.directory = directory;
+
+ chksum64 = (uint64)palchksum;
+ if (chksum) {
+ chksum64 <<= 32;
+ chksum64 |= (uint64)chksum;
+ }
+
+ /* try to add entry to file index */
+ ret = _filesIndex.insert(std::map::value_type(chksum64, entry)).second;
+ if (!ret) {
+ /* technically we should probably fail here,
+ * however HTS & HTC both don't fail when there are duplicates,
+ * so to maintain backwards compatability, we won't either
+ */
+ DBG_INFO(80, wst("TxNoCache::_createFileIndexInDir: failed to add cksum:%08X %08X file:%ls\n"), chksum, palchksum, texturefilename.c_str());
+ } else {
+ DBG_INFO(80, wst("TxNoCache::_createFileIndexInDir: added cksum:%08X %08X file:%ls\n"), chksum, palchksum, texturefilename.c_str());
+ }
+
+ } while (foundfilename != nullptr);
+
+ osal_search_dir_close(dir);
+
+ return result;
+}
+
diff --git a/src/GLideNHQ/TxHiResNoCache.h b/src/GLideNHQ/TxHiResNoCache.h
new file mode 100644
index 00000000..8baeabd4
--- /dev/null
+++ b/src/GLideNHQ/TxHiResNoCache.h
@@ -0,0 +1,45 @@
+#ifndef TXHIRESNOCACHE_H
+#define TXHIRESNOCACHE_H
+
+#include "TxHiResLoader.h"
+
+class TxHiResNoCache : public TxHiResLoader
+{
+ private:
+ bool _createFileIndex(bool update);
+ bool _createFileIndexInDir(tx_wstring directory, bool update);
+ void _clear();
+
+ struct fileIndexEntry_t
+ {
+ char fname[MAX_PATH];
+ tx_wstring directory;
+ uint32 siz;
+ uint32 fmt;
+ };
+
+ tx_wstring _fullTexPath;
+ tx_wstring _ident;
+ char _identc[MAX_PATH];
+ std::map _filesIndex;
+ std::map _loadedTex;
+ dispInfoFuncExt _callback;
+ public:
+ ~TxHiResNoCache();
+ TxHiResNoCache(int maxwidth,
+ int maxheight,
+ int maxbpp,
+ int options,
+ const wchar_t *cachePath,
+ const wchar_t *texPackPath,
+ const wchar_t *fullTexPath,
+ const wchar_t *ident,
+ dispInfoFuncExt callback);
+ bool empty() const override;
+ bool add(Checksum checksum, GHQTexInfo *info, int dataSize = 0) override { return false; }
+ bool get(Checksum checksum, GHQTexInfo *info) override;
+ bool reload() override;
+ void dump() override { };
+};
+
+#endif /* TXHIRESNOCACHE_H */
diff --git a/src/GLideNHQ/TxInternal.h b/src/GLideNHQ/TxInternal.h
index 7a387aa5..f70509cf 100644
--- a/src/GLideNHQ/TxInternal.h
+++ b/src/GLideNHQ/TxInternal.h
@@ -29,12 +29,6 @@
#include
-#ifdef WIN32
-#define KBHIT(key) ((GetAsyncKeyState(key) & 0x8001) == 0x8001)
-#else
-#define KBHIT(key) (0)
-#endif
-
typedef graphics::InternalColorFormatParam ColorFormat;
/* in-memory zlib texture compression */
diff --git a/src/GLideNUI/ConfigDialog.cpp b/src/GLideNUI/ConfigDialog.cpp
index 99548a98..ee5d040e 100644
--- a/src/GLideNUI/ConfigDialog.cpp
+++ b/src/GLideNUI/ConfigDialog.cpp
@@ -340,6 +340,7 @@ void ConfigDialog::_init(bool reInit, bool blockCustomSettings)
ui->saveTextureCacheCheckBox->setChecked(config.textureFilter.txSaveCache != 0);
ui->enhancedTexFileStorageCheckBox->setChecked(config.textureFilter.txEnhancedTextureFileStorage != 0);
ui->hiresTexFileStorageCheckBox->setChecked(config.textureFilter.txHiresTextureFileStorage != 0);
+ ui->noTexFileStorageCheckBox->setChecked(config.textureFilter.txNoTextureFileStorage != 0);
ui->texPackPathLineEdit->setText(QString::fromWCharArray(config.textureFilter.txPath));
ui->texCachePathLineEdit->setText(QString::fromWCharArray(config.textureFilter.txCachePath));
@@ -644,6 +645,7 @@ void ConfigDialog::accept(bool justSave) {
config.textureFilter.txSaveCache = ui->saveTextureCacheCheckBox->isChecked() ? 1 : 0;
config.textureFilter.txEnhancedTextureFileStorage = ui->enhancedTexFileStorageCheckBox->isChecked() ? 1 : 0;
config.textureFilter.txHiresTextureFileStorage = ui->hiresTexFileStorageCheckBox->isChecked() ? 1 : 0;
+ config.textureFilter.txNoTextureFileStorage = ui->noTexFileStorageCheckBox->isChecked() ? 1 : 0;
QDir txPath(ui->texPackPathLineEdit->text());
if (!txPath.exists() &&
@@ -853,6 +855,11 @@ void ConfigDialog::on_texDumpPathButton_clicked()
ui->texDumpPathLineEdit->setText(directory);
}
+void ConfigDialog::on_noTexFileStorageCheckBox_toggled(bool checked)
+{
+ ui->hiresTexFileStorageCheckBox->setEnabled(!checked);
+}
+
void ConfigDialog::on_windowedResolutionComboBox_currentIndexChanged(int index)
{
if (index < numWindowedModes)
diff --git a/src/GLideNUI/ConfigDialog.h b/src/GLideNUI/ConfigDialog.h
index 77f83adf..a85c0c77 100644
--- a/src/GLideNUI/ConfigDialog.h
+++ b/src/GLideNUI/ConfigDialog.h
@@ -74,6 +74,8 @@ private slots:
void on_texDumpPathButton_clicked();
+ void on_noTexFileStorageCheckBox_toggled(bool checked);
+
void on_profilesComboBox_currentIndexChanged(const QString &arg1);
void on_settingsDestProfileRadioButton_toggled(bool checked);
diff --git a/src/GLideNUI/Settings.cpp b/src/GLideNUI/Settings.cpp
index 1a9c36e6..b374fa66 100644
--- a/src/GLideNUI/Settings.cpp
+++ b/src/GLideNUI/Settings.cpp
@@ -102,6 +102,7 @@ void _loadSettings(QSettings & settings)
config.textureFilter.txSaveCache = settings.value("txSaveCache", config.textureFilter.txSaveCache).toInt();
config.textureFilter.txEnhancedTextureFileStorage = settings.value("txEnhancedTextureFileStorage", config.textureFilter.txEnhancedTextureFileStorage).toInt();
config.textureFilter.txHiresTextureFileStorage = settings.value("txHiresTextureFileStorage", config.textureFilter.txHiresTextureFileStorage).toInt();
+ config.textureFilter.txNoTextureFileStorage = settings.value("txNoTextureFileStorage", config.textureFilter.txNoTextureFileStorage).toInt();
QString txPath = QString::fromWCharArray(config.textureFilter.txPath);
config.textureFilter.txPath[settings.value("txPath", txPath).toString().toWCharArray(config.textureFilter.txPath)] = L'\0';
QString txCachePath = QString::fromWCharArray(config.textureFilter.txCachePath);
@@ -289,6 +290,7 @@ void writeSettings(const QString & _strIniFolder)
settings.setValue("txSaveCache", config.textureFilter.txSaveCache);
settings.setValue("txEnhancedTextureFileStorage", config.textureFilter.txEnhancedTextureFileStorage);
settings.setValue("txHiresTextureFileStorage", config.textureFilter.txHiresTextureFileStorage);
+ settings.setValue("txNoTextureFileStorage", config.textureFilter.txNoTextureFileStorage);
settings.setValue("txPath", QString::fromWCharArray(config.textureFilter.txPath));
settings.setValue("txCachePath", QString::fromWCharArray(config.textureFilter.txCachePath));
settings.setValue("txDumpPath", QString::fromWCharArray(config.textureFilter.txDumpPath));
@@ -484,6 +486,7 @@ void saveCustomRomSettings(const QString & _strIniFolder, const char * _strRomNa
WriteCustomSetting(textureFilter, txCacheSize);
WriteCustomSetting(textureFilter, txEnhancedTextureFileStorage);
WriteCustomSetting(textureFilter, txHiresTextureFileStorage);
+ WriteCustomSetting(textureFilter, txNoTextureFileStorage);
WriteCustomSetting(textureFilter, txHiresEnable);
WriteCustomSetting(textureFilter, txHiresFullAlphaChannel);
WriteCustomSetting(textureFilter, txHresAltCRC);
diff --git a/src/GLideNUI/configDialog.ui b/src/GLideNUI/configDialog.ui
index bf9a0e4d..b0b50476 100644
--- a/src/GLideNUI/configDialog.ui
+++ b/src/GLideNUI/configDialog.ui
@@ -2659,6 +2659,13 @@
+ -
+
+
+ Use no file storage or cache (causes worse stutter, not recommended for playing games)
+
+
+
diff --git a/src/TextureFilterHandler.cpp b/src/TextureFilterHandler.cpp
index c97b5673..a06e54f8 100644
--- a/src/TextureFilterHandler.cpp
+++ b/src/TextureFilterHandler.cpp
@@ -63,6 +63,8 @@ u32 TextureFilterHandler::_getConfigOptions() const
options |= FILE_TEXCACHE;
if (config.textureFilter.txHiresTextureFileStorage)
options |= FILE_HIRESTEXCACHE;
+ if (config.textureFilter.txNoTextureFileStorage)
+ options |= FILE_NOTEXCACHE;
return options;
}
diff --git a/src/common/CommonAPIImpl_common.cpp b/src/common/CommonAPIImpl_common.cpp
index 70f3eee9..8e4f6728 100644
--- a/src/common/CommonAPIImpl_common.cpp
+++ b/src/common/CommonAPIImpl_common.cpp
@@ -198,6 +198,8 @@ void PluginAPI::RomClosed()
int PluginAPI::RomOpen()
{
+ osal_keys_init();
+
LOG(LOG_APIFUNC, "RomOpen");
#ifdef RSPTHREAD
m_pluginThreadMtx.lock();
@@ -212,7 +214,6 @@ int PluginAPI::RomOpen()
if (!dwnd().start())
return 0;
#endif
- osal_keys_init();
m_bRomOpen = true;
diff --git a/src/mupenplus/Config_mupenplus.cpp b/src/mupenplus/Config_mupenplus.cpp
index 30ae6b48..b497fd17 100644
--- a/src/mupenplus/Config_mupenplus.cpp
+++ b/src/mupenplus/Config_mupenplus.cpp
@@ -255,6 +255,8 @@ bool Config_SetDefault()
assert(res == M64ERR_SUCCESS);
res = ConfigSetDefaultBool(g_configVideoGliden64, "txHiresTextureFileStorage", config.textureFilter.txHiresTextureFileStorage, "Use file storage instead of memory cache for HD textures.");
assert(res == M64ERR_SUCCESS);
+ res = ConfigSetDefaultBool(g_configVideoGliden64, "txNoTextureFileStorage", config.textureFilter.txNoTextureFileStorage, "Use no file storage or cache for HD textures.");
+ assert(res == M64ERR_SUCCESS);
// Convert to multibyte
char txPath[PLUGIN_PATH_SIZE * 2];
wcstombs(txPath, config.textureFilter.txPath, PLUGIN_PATH_SIZE * 2);
@@ -465,6 +467,8 @@ void Config_LoadCustomConfig()
if (result == M64ERR_SUCCESS) config.textureFilter.txEnhancedTextureFileStorage = atoi(value);
result = ConfigExternalGetParameter(fileHandle, sectionName, "textureFilter\\txHiresTextureFileStorage", value, sizeof(value));
if (result == M64ERR_SUCCESS) config.textureFilter.txHiresTextureFileStorage = atoi(value);
+ result = ConfigExternalGetParameter(fileHandle, sectionName, "textureFilter\\txNoTextureFileStorage", value, sizeof(value));
+ if (result == M64ERR_SUCCESS) config.textureFilter.txNoTextureFileStorage = atoi(value);
ConfigExternalClose(fileHandle);
}
@@ -553,6 +557,7 @@ void Config_LoadConfig()
config.textureFilter.txSaveCache = ConfigGetParamBool(g_configVideoGliden64, "txSaveCache");
config.textureFilter.txEnhancedTextureFileStorage = ConfigGetParamBool(g_configVideoGliden64, "txEnhancedTextureFileStorage");
config.textureFilter.txHiresTextureFileStorage = ConfigGetParamBool(g_configVideoGliden64, "txHiresTextureFileStorage");
+ config.textureFilter.txNoTextureFileStorage = ConfigGetParamBool(g_configVideoGliden64, "txNoTextureFileStorage");
::mbstowcs(config.textureFilter.txPath, ConfigGetParamString(g_configVideoGliden64, "txPath"), PLUGIN_PATH_SIZE);
::mbstowcs(config.textureFilter.txCachePath, ConfigGetParamString(g_configVideoGliden64, "txCachePath"), PLUGIN_PATH_SIZE);
::mbstowcs(config.textureFilter.txDumpPath, ConfigGetParamString(g_configVideoGliden64, "txDumpPath"), PLUGIN_PATH_SIZE);