mirror of
https://github.com/blawar/GLideN64.git
synced 2024-07-02 09:03:37 +00:00
GLideNHQ: Introduce TxHiResNoCache
This commit is contained in:
parent
b78df0b002
commit
4a9e1260ce
|
@ -126,7 +126,9 @@
|
||||||
<ClCompile Include="..\..\src\GLideNHQ\TxDbg.cpp" />
|
<ClCompile Include="..\..\src\GLideNHQ\TxDbg.cpp" />
|
||||||
<ClCompile Include="..\..\src\GLideNHQ\TxFilter.cpp" />
|
<ClCompile Include="..\..\src\GLideNHQ\TxFilter.cpp" />
|
||||||
<ClCompile Include="..\..\src\GLideNHQ\TxFilterExport.cpp" />
|
<ClCompile Include="..\..\src\GLideNHQ\TxFilterExport.cpp" />
|
||||||
|
<ClCompile Include="..\..\src\GLideNHQ\TxHiResLoader.cpp" />
|
||||||
<ClCompile Include="..\..\src\GLideNHQ\TxHiResCache.cpp" />
|
<ClCompile Include="..\..\src\GLideNHQ\TxHiResCache.cpp" />
|
||||||
|
<ClCompile Include="..\..\src\GLideNHQ\TxHiResNoCache.cpp" />
|
||||||
<ClCompile Include="..\..\src\GLideNHQ\TxImage.cpp" />
|
<ClCompile Include="..\..\src\GLideNHQ\TxImage.cpp" />
|
||||||
<ClCompile Include="..\..\src\GLideNHQ\TxQuantize.cpp" />
|
<ClCompile Include="..\..\src\GLideNHQ\TxQuantize.cpp" />
|
||||||
<ClCompile Include="..\..\src\GLideNHQ\TxReSample.cpp" />
|
<ClCompile Include="..\..\src\GLideNHQ\TxReSample.cpp" />
|
||||||
|
|
|
@ -22,9 +22,15 @@
|
||||||
<ClCompile Include="..\..\src\GLideNHQ\TxFilterExport.cpp">
|
<ClCompile Include="..\..\src\GLideNHQ\TxFilterExport.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\GLideNHQ\TxHiResLoader.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\src\GLideNHQ\TxHiResCache.cpp">
|
<ClCompile Include="..\..\src\GLideNHQ\TxHiResCache.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\GLideNHQ\TxHiResNoCache.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\src\GLideNHQ\TxImage.cpp">
|
<ClCompile Include="..\..\src\GLideNHQ\TxImage.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
|
|
@ -102,6 +102,7 @@ void Config::resetToDefaults()
|
||||||
|
|
||||||
textureFilter.txEnhancedTextureFileStorage = 0;
|
textureFilter.txEnhancedTextureFileStorage = 0;
|
||||||
textureFilter.txHiresTextureFileStorage = 0;
|
textureFilter.txHiresTextureFileStorage = 0;
|
||||||
|
textureFilter.txNoTextureFileStorage = 0;
|
||||||
|
|
||||||
api().GetUserDataPath(textureFilter.txPath);
|
api().GetUserDataPath(textureFilter.txPath);
|
||||||
gln_wcscat(textureFilter.txPath, wst("/hires_texture"));
|
gln_wcscat(textureFilter.txPath, wst("/hires_texture"));
|
||||||
|
|
|
@ -175,6 +175,7 @@ struct Config
|
||||||
|
|
||||||
u32 txEnhancedTextureFileStorage; // Use file storage instead of memory cache for enhanced textures.
|
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 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 txPath[PLUGIN_PATH_SIZE]; // Path to texture packs
|
||||||
wchar_t txCachePath[PLUGIN_PATH_SIZE]; // Path to store texture cache, that is .htc files
|
wchar_t txCachePath[PLUGIN_PATH_SIZE]; // Path to store texture cache, that is .htc files
|
||||||
|
|
|
@ -12,7 +12,9 @@ set(GLideNHQ_SOURCES
|
||||||
TxDbg.cpp
|
TxDbg.cpp
|
||||||
TxFilter.cpp
|
TxFilter.cpp
|
||||||
TxFilterExport.cpp
|
TxFilterExport.cpp
|
||||||
|
TxHiResLoader.cpp
|
||||||
TxHiResCache.cpp
|
TxHiResCache.cpp
|
||||||
|
TxHiResNoCache.cpp
|
||||||
TxImage.cpp
|
TxImage.cpp
|
||||||
TxQuantize.cpp
|
TxQuantize.cpp
|
||||||
TxReSample.cpp
|
TxReSample.cpp
|
||||||
|
|
|
@ -93,6 +93,7 @@ typedef unsigned char boolean;
|
||||||
#define JABO_HIRESTEXTURES 0x00030000
|
#define JABO_HIRESTEXTURES 0x00030000
|
||||||
|
|
||||||
#define FILE_CACHE_MASK 0x00300000
|
#define FILE_CACHE_MASK 0x00300000
|
||||||
|
#define FILE_NOTEXCACHE 0x08500000
|
||||||
#define FILE_TEXCACHE 0x00100000
|
#define FILE_TEXCACHE 0x00100000
|
||||||
#define FILE_HIRESTEXCACHE 0x00200000
|
#define FILE_HIRESTEXCACHE 0x00200000
|
||||||
#define GZ_TEXCACHE 0x00400000
|
#define GZ_TEXCACHE 0x00400000
|
||||||
|
|
|
@ -38,8 +38,8 @@
|
||||||
|
|
||||||
void TxFilter::clear()
|
void TxFilter::clear()
|
||||||
{
|
{
|
||||||
/* clear hires texture cache */
|
/* clear hires texture loader */
|
||||||
delete _txHiResCache;
|
delete _txHiResLoader;
|
||||||
|
|
||||||
/* clear texture cache */
|
/* clear texture cache */
|
||||||
delete _txTexCache;
|
delete _txTexCache;
|
||||||
|
@ -71,7 +71,7 @@ TxFilter::TxFilter(int maxwidth,
|
||||||
, _tex2(nullptr)
|
, _tex2(nullptr)
|
||||||
, _txQuantize(nullptr)
|
, _txQuantize(nullptr)
|
||||||
, _txTexCache(nullptr)
|
, _txTexCache(nullptr)
|
||||||
, _txHiResCache(nullptr)
|
, _txHiResLoader(nullptr)
|
||||||
, _txImage(nullptr)
|
, _txImage(nullptr)
|
||||||
{
|
{
|
||||||
/* HACKALERT: the emulator misbehaves and sometimes forgets to shutdown */
|
/* HACKALERT: the emulator misbehaves and sometimes forgets to shutdown */
|
||||||
|
@ -150,9 +150,17 @@ TxFilter::TxFilter(int maxwidth,
|
||||||
|
|
||||||
/* hires texture */
|
/* hires texture */
|
||||||
#if 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;
|
_options &= ~HIRESTEXTURES_MASK;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -479,7 +487,7 @@ TxFilter::hirestex(uint64 g64crc, uint64 r_crc64, uint16 *palette, GHQTexInfo *i
|
||||||
#if HIRES_TEXTURE
|
#if HIRES_TEXTURE
|
||||||
/* check if we have it in hires memory cache. */
|
/* check if we have it in hires memory cache. */
|
||||||
if ((_options & HIRESTEXTURES_MASK) && r_crc64) {
|
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);
|
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
|
/* 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 */
|
return 1; /* yep, got it */
|
||||||
}
|
}
|
||||||
if (_txHiResCache->get((r_crc64 >> 32), info) ||
|
if (_txHiResLoader->get((r_crc64 >> 32), info) ||
|
||||||
_txHiResCache->get((r_crc64 & 0xffffffff), 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);
|
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
|
/* 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);
|
setTextureFormat(format, info);
|
||||||
|
|
||||||
/* XXX: add to hires texture cache!!! */
|
/* 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));
|
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"));
|
DBG_INFO(80, wst("Reload hires textures from texture pack.\n"));
|
||||||
|
|
||||||
if (_txHiResCache->load(0) && !_txHiResCache->empty()) {
|
if (_txHiResLoader->reload()) {
|
||||||
_options |= HIRESTEXTURES_MASK;
|
_options |= HIRESTEXTURES_MASK;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -655,6 +663,6 @@ TxFilter::dumpcache()
|
||||||
|
|
||||||
/* hires texture */
|
/* hires texture */
|
||||||
#if HIRES_TEXTURE
|
#if HIRES_TEXTURE
|
||||||
_txHiResCache->dump();
|
_txHiResLoader->dump();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,8 @@
|
||||||
#include "TxInternal.h"
|
#include "TxInternal.h"
|
||||||
#include "TxQuantize.h"
|
#include "TxQuantize.h"
|
||||||
#include "TxHiResCache.h"
|
#include "TxHiResCache.h"
|
||||||
|
#include "TxHiResNoCache.h"
|
||||||
|
#include "TxHiResLoader.h"
|
||||||
#include "TxTexCache.h"
|
#include "TxTexCache.h"
|
||||||
#include "TxUtil.h"
|
#include "TxUtil.h"
|
||||||
#include "TxImage.h"
|
#include "TxImage.h"
|
||||||
|
@ -47,7 +49,7 @@ private:
|
||||||
tx_wstring _dumpPath;
|
tx_wstring _dumpPath;
|
||||||
TxQuantize *_txQuantize;
|
TxQuantize *_txQuantize;
|
||||||
TxTexCache *_txTexCache;
|
TxTexCache *_txTexCache;
|
||||||
TxHiResCache *_txHiResCache;
|
TxHiResLoader *_txHiResLoader;
|
||||||
TxImage *_txImage;
|
TxImage *_txImage;
|
||||||
boolean _initialized;
|
boolean _initialized;
|
||||||
void clear();
|
void clear();
|
||||||
|
|
|
@ -28,17 +28,10 @@
|
||||||
#pragma warning(disable: 4786)
|
#pragma warning(disable: 4786)
|
||||||
#endif
|
#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 "TxHiResCache.h"
|
||||||
#include "TxDbg.h"
|
#include "TxDbg.h"
|
||||||
#include <osal_files.h>
|
#include <osal_files.h>
|
||||||
|
#include <osal_keys.h>
|
||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
@ -59,16 +52,10 @@ TxHiResCache::TxHiResCache(int maxwidth,
|
||||||
const wchar_t *ident,
|
const wchar_t *ident,
|
||||||
dispInfoFuncExt callback)
|
dispInfoFuncExt callback)
|
||||||
: TxCache((options & ~(GZ_TEXCACHE | FILE_TEXCACHE)), 0, cachePath, ident, callback)
|
: TxCache((options & ~(GZ_TEXCACHE | FILE_TEXCACHE)), 0, cachePath, ident, callback)
|
||||||
, _maxwidth(maxwidth)
|
, TxHiResLoader(maxwidth, maxheight, maxbpp, options)
|
||||||
, _maxheight(maxheight)
|
|
||||||
, _maxbpp(maxbpp)
|
|
||||||
, _abortLoad(false)
|
, _abortLoad(false)
|
||||||
, _cacheDumped(false)
|
, _cacheDumped(false)
|
||||||
, _txImage(new TxImage())
|
|
||||||
, _txQuantize(new TxQuantize())
|
|
||||||
, _txReSample(new TxReSample())
|
|
||||||
{
|
{
|
||||||
|
|
||||||
if (texPackPath)
|
if (texPackPath)
|
||||||
_texPackPath.assign(texPackPath);
|
_texPackPath.assign(texPackPath);
|
||||||
|
|
||||||
|
@ -125,7 +112,7 @@ boolean TxHiResCache::_HiResTexPackPathExists() const
|
||||||
return osal_path_existsW(dir_path.c_str());
|
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())
|
if (_texPackPath.empty() || _ident.empty())
|
||||||
return false;
|
return false;
|
||||||
|
@ -151,7 +138,7 @@ bool TxHiResCache::load(boolean replace) /* 0 : reload, 1 : replace partial */
|
||||||
dir_path += OSAL_DIR_SEPARATOR_STR;
|
dir_path += OSAL_DIR_SEPARATOR_STR;
|
||||||
dir_path += _ident;
|
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 (res == resError) {
|
||||||
if (_callback) (*_callback)(wst("Texture pack load failed. Clear hiresolution texture cache.\n"));
|
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"));
|
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;
|
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("-----\n"));
|
||||||
DBG_INFO(80, wst("path: %ls\n"), dir_path);
|
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;
|
tx_wstring texturefilename;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
osal_keys_update_state();
|
||||||
if (KBHIT(0x1B)) {
|
if (osal_is_key_pressed(KEY_Escape, 0x0001)) {
|
||||||
_abortLoad = true;
|
_abortLoad = true;
|
||||||
if (_callback) (*_callback)(wst("Aborted loading hiresolution texture!\n"));
|
if (_callback) (*_callback)(wst("Aborted loading hiresolution texture!\n"));
|
||||||
INFO(80, wst("Error: 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(".")))
|
if (wccmp(foundfilename, wst(".")))
|
||||||
// These files we don't need
|
// These files we don't need
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
texturefilename.assign(dir_path);
|
texturefilename.assign(dir_path);
|
||||||
texturefilename += OSAL_DIR_SEPARATOR_STR;
|
texturefilename += OSAL_DIR_SEPARATOR_STR;
|
||||||
texturefilename += foundfilename;
|
texturefilename += foundfilename;
|
||||||
|
|
||||||
/* recursive read into sub-directory */
|
/* recursive read into sub-directory */
|
||||||
if (osal_is_directory(texturefilename.c_str())) {
|
if (osal_is_directory(texturefilename.c_str())) {
|
||||||
result = loadHiResTextures(texturefilename.c_str(), replace);
|
result = _loadHiResTextures(texturefilename.c_str(), replace);
|
||||||
if (result == resOk)
|
if (result == resOk)
|
||||||
continue;
|
continue;
|
||||||
else
|
else
|
||||||
|
@ -229,103 +222,25 @@ TxHiResCache::LoadResult TxHiResCache::loadHiResTextures(const wchar_t * dir_pat
|
||||||
int width = 0, height = 0;
|
int width = 0, height = 0;
|
||||||
ColorFormat format = graphics::internalcolorFormat::NOCOLOR;
|
ColorFormat format = graphics::internalcolorFormat::NOCOLOR;
|
||||||
uint8 *tex = nullptr;
|
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
|
/* Rice hi-res textures: begin
|
||||||
*/
|
*/
|
||||||
uint32 chksum = 0, fmt = 0, siz = 0, palchksum = 0;
|
uint32 chksum = 0, fmt = 0, siz = 0, palchksum = 0, length = 0;
|
||||||
bool hasWildcard = false;
|
char fname[MAX_PATH];
|
||||||
char *pfname = nullptr, fname[MAX_PATH];
|
char ident[MAX_PATH];
|
||||||
std::string ident;
|
|
||||||
FILE *fp = nullptr;
|
FILE *fp = nullptr;
|
||||||
|
|
||||||
wcstombs(fname, _ident.c_str(), MAX_PATH);
|
wcstombs(ident, _ident.c_str(), MAX_PATH);
|
||||||
/* XXX case sensitivity fiasco!
|
wcstombs(fname, foundfilename, MAX_PATH);
|
||||||
* files must use _a, _rgb, _all, _allciByRGBA, _ciByRGBA, _ci
|
|
||||||
* and file extensions must be in lower case letters! */
|
/* lowercase on windows */
|
||||||
#ifdef OS_WINDOWS
|
CORRECTFILENAME(ident);
|
||||||
{
|
CORRECTFILENAME(fname);
|
||||||
unsigned int i;
|
|
||||||
for (i = 0; i < strlen(fname); i++) fname[i] = tolower(fname[i]);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
ident.assign(fname);
|
|
||||||
|
|
||||||
/* read in Rice's file naming convention */
|
/* read in Rice's file naming convention */
|
||||||
#define CRCFMTSIZ_LEN 13
|
length = checkFileName(ident, fname, &chksum, &palchksum, &fmt, &siz);
|
||||||
#define CRCWILDCARD_LEN 15
|
if (length == 0) {
|
||||||
#define PALCRC_LEN 9
|
/* invalid file name, skip it */
|
||||||
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"));
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -339,424 +254,22 @@ TxHiResCache::LoadResult TxHiResCache::loadHiResTextures(const wchar_t * dir_pat
|
||||||
if (isCached(chksum64)) {
|
if (isCached(chksum64)) {
|
||||||
#if !DEBUG
|
#if !DEBUG
|
||||||
INFO(80, wst("-----\n"));
|
INFO(80, wst("-----\n"));
|
||||||
INFO(80, wst("path: %ls\n"), dir_path.string().c_str());
|
INFO(80, wst("file: %s\n"), fname);
|
||||||
INFO(80, wst("file: %ls\n"), it->path().leaf().c_str());
|
|
||||||
#endif
|
#endif
|
||||||
INFO(80, wst("Error: already cached! duplicate texture!\n"));
|
INFO(80, wst("Error: already cached! duplicate texture!\n"));
|
||||||
continue;
|
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);
|
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. */
|
/* load it into hires texture cache. */
|
||||||
{
|
|
||||||
uint64 chksum64 = (uint64)palchksum;
|
uint64 chksum64 = (uint64)palchksum;
|
||||||
if (chksum) {
|
if (chksum) {
|
||||||
chksum64 <<= 32;
|
chksum64 <<= 32;
|
||||||
|
@ -792,12 +305,27 @@ TxHiResCache::LoadResult TxHiResCache::loadHiResTextures(const wchar_t * dir_pat
|
||||||
result = resError;
|
result = resError;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
} while (foundfilename != nullptr);
|
} while (foundfilename != nullptr);
|
||||||
|
|
||||||
osal_search_dir_close(dir);
|
osal_search_dir_close(dir);
|
||||||
|
|
||||||
CHDIR(curpath);
|
CHDIR(curpath);
|
||||||
|
|
||||||
return result;
|
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);
|
||||||
|
}
|
||||||
|
|
|
@ -24,38 +24,29 @@
|
||||||
#ifndef __TXHIRESCACHE_H__
|
#ifndef __TXHIRESCACHE_H__
|
||||||
#define __TXHIRESCACHE_H__
|
#define __TXHIRESCACHE_H__
|
||||||
|
|
||||||
/* support hires textures
|
|
||||||
* 0: disable
|
|
||||||
* 1: enable
|
|
||||||
*/
|
|
||||||
#define HIRES_TEXTURE 1
|
|
||||||
|
|
||||||
#include "TxCache.h"
|
#include "TxCache.h"
|
||||||
#include "TxQuantize.h"
|
#include "TxQuantize.h"
|
||||||
#include "TxImage.h"
|
#include "TxImage.h"
|
||||||
#include "TxReSample.h"
|
#include "TxReSample.h"
|
||||||
|
#include "TxHiResLoader.h"
|
||||||
|
|
||||||
class TxHiResCache : public TxCache
|
class TxHiResCache : public TxCache, public TxHiResLoader
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
int _maxwidth;
|
|
||||||
int _maxheight;
|
|
||||||
int _maxbpp;
|
|
||||||
bool _abortLoad;
|
bool _abortLoad;
|
||||||
bool _cacheDumped;
|
bool _cacheDumped;
|
||||||
std::unique_ptr<TxImage> _txImage;
|
|
||||||
std::unique_ptr<TxQuantize> _txQuantize;
|
|
||||||
std::unique_ptr<TxReSample> _txReSample;
|
|
||||||
tx_wstring _texPackPath;
|
tx_wstring _texPackPath;
|
||||||
enum LoadResult {
|
enum LoadResult {
|
||||||
resOk,
|
resOk,
|
||||||
resNotFound,
|
resNotFound,
|
||||||
resError
|
resError
|
||||||
};
|
};
|
||||||
LoadResult loadHiResTextures(const wchar_t * dir_path, boolean replace);
|
LoadResult _loadHiResTextures(const wchar_t * dir_path, boolean replace);
|
||||||
boolean _HiResTexPackPathExists() const;
|
boolean _HiResTexPackPathExists() const;
|
||||||
tx_wstring _getFileName() const override;
|
tx_wstring _getFileName() const override;
|
||||||
int _getConfig() const override;
|
int _getConfig() const override;
|
||||||
|
bool _load(boolean replace);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
~TxHiResCache();
|
~TxHiResCache();
|
||||||
|
@ -67,8 +58,11 @@ public:
|
||||||
const wchar_t *texPackPath,
|
const wchar_t *texPackPath,
|
||||||
const wchar_t *ident,
|
const wchar_t *ident,
|
||||||
dispInfoFuncExt callback);
|
dispInfoFuncExt callback);
|
||||||
bool load(boolean replace);
|
bool empty() const override;
|
||||||
void dump();
|
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__ */
|
#endif /* __TXHIRESCACHE_H__ */
|
||||||
|
|
585
src/GLideNHQ/TxHiResLoader.cpp
Normal file
585
src/GLideNHQ/TxHiResLoader.cpp
Normal file
|
@ -0,0 +1,585 @@
|
||||||
|
#include "TxHiResLoader.h"
|
||||||
|
#include "TxDbg.h"
|
||||||
|
#include "TxDbg.h"
|
||||||
|
#include "Ext_TxFilter.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <osal_files.h>
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
}
|
||||||
|
|
50
src/GLideNHQ/TxHiResLoader.h
Normal file
50
src/GLideNHQ/TxHiResLoader.h
Normal file
|
@ -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> _txImage;
|
||||||
|
std::unique_ptr<TxQuantize> _txQuantize;
|
||||||
|
std::unique_ptr<TxReSample> _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 */
|
225
src/GLideNHQ/TxHiResNoCache.cpp
Normal file
225
src/GLideNHQ/TxHiResNoCache.cpp
Normal file
|
@ -0,0 +1,225 @@
|
||||||
|
#include "TxHiResNoCache.h"
|
||||||
|
|
||||||
|
#include "TxDbg.h"
|
||||||
|
#include "Ext_TxFilter.h"
|
||||||
|
#include <osal_files.h>
|
||||||
|
|
||||||
|
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<uint64, GHQTexInfo>::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<uint64, fileIndexEntry_t>::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;
|
||||||
|
}
|
||||||
|
|
45
src/GLideNHQ/TxHiResNoCache.h
Normal file
45
src/GLideNHQ/TxHiResNoCache.h
Normal file
|
@ -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<uint64, fileIndexEntry_t> _filesIndex;
|
||||||
|
std::map<uint64, GHQTexInfo> _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 */
|
|
@ -29,12 +29,6 @@
|
||||||
|
|
||||||
#include <Graphics/Parameters.h>
|
#include <Graphics/Parameters.h>
|
||||||
|
|
||||||
#ifdef WIN32
|
|
||||||
#define KBHIT(key) ((GetAsyncKeyState(key) & 0x8001) == 0x8001)
|
|
||||||
#else
|
|
||||||
#define KBHIT(key) (0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef graphics::InternalColorFormatParam ColorFormat;
|
typedef graphics::InternalColorFormatParam ColorFormat;
|
||||||
|
|
||||||
/* in-memory zlib texture compression */
|
/* in-memory zlib texture compression */
|
||||||
|
|
|
@ -340,6 +340,7 @@ void ConfigDialog::_init(bool reInit, bool blockCustomSettings)
|
||||||
ui->saveTextureCacheCheckBox->setChecked(config.textureFilter.txSaveCache != 0);
|
ui->saveTextureCacheCheckBox->setChecked(config.textureFilter.txSaveCache != 0);
|
||||||
ui->enhancedTexFileStorageCheckBox->setChecked(config.textureFilter.txEnhancedTextureFileStorage != 0);
|
ui->enhancedTexFileStorageCheckBox->setChecked(config.textureFilter.txEnhancedTextureFileStorage != 0);
|
||||||
ui->hiresTexFileStorageCheckBox->setChecked(config.textureFilter.txHiresTextureFileStorage != 0);
|
ui->hiresTexFileStorageCheckBox->setChecked(config.textureFilter.txHiresTextureFileStorage != 0);
|
||||||
|
ui->noTexFileStorageCheckBox->setChecked(config.textureFilter.txNoTextureFileStorage != 0);
|
||||||
|
|
||||||
ui->texPackPathLineEdit->setText(QString::fromWCharArray(config.textureFilter.txPath));
|
ui->texPackPathLineEdit->setText(QString::fromWCharArray(config.textureFilter.txPath));
|
||||||
ui->texCachePathLineEdit->setText(QString::fromWCharArray(config.textureFilter.txCachePath));
|
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.txSaveCache = ui->saveTextureCacheCheckBox->isChecked() ? 1 : 0;
|
||||||
config.textureFilter.txEnhancedTextureFileStorage = ui->enhancedTexFileStorageCheckBox->isChecked() ? 1 : 0;
|
config.textureFilter.txEnhancedTextureFileStorage = ui->enhancedTexFileStorageCheckBox->isChecked() ? 1 : 0;
|
||||||
config.textureFilter.txHiresTextureFileStorage = ui->hiresTexFileStorageCheckBox->isChecked() ? 1 : 0;
|
config.textureFilter.txHiresTextureFileStorage = ui->hiresTexFileStorageCheckBox->isChecked() ? 1 : 0;
|
||||||
|
config.textureFilter.txNoTextureFileStorage = ui->noTexFileStorageCheckBox->isChecked() ? 1 : 0;
|
||||||
|
|
||||||
QDir txPath(ui->texPackPathLineEdit->text());
|
QDir txPath(ui->texPackPathLineEdit->text());
|
||||||
if (!txPath.exists() &&
|
if (!txPath.exists() &&
|
||||||
|
@ -853,6 +855,11 @@ void ConfigDialog::on_texDumpPathButton_clicked()
|
||||||
ui->texDumpPathLineEdit->setText(directory);
|
ui->texDumpPathLineEdit->setText(directory);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ConfigDialog::on_noTexFileStorageCheckBox_toggled(bool checked)
|
||||||
|
{
|
||||||
|
ui->hiresTexFileStorageCheckBox->setEnabled(!checked);
|
||||||
|
}
|
||||||
|
|
||||||
void ConfigDialog::on_windowedResolutionComboBox_currentIndexChanged(int index)
|
void ConfigDialog::on_windowedResolutionComboBox_currentIndexChanged(int index)
|
||||||
{
|
{
|
||||||
if (index < numWindowedModes)
|
if (index < numWindowedModes)
|
||||||
|
|
|
@ -74,6 +74,8 @@ private slots:
|
||||||
|
|
||||||
void on_texDumpPathButton_clicked();
|
void on_texDumpPathButton_clicked();
|
||||||
|
|
||||||
|
void on_noTexFileStorageCheckBox_toggled(bool checked);
|
||||||
|
|
||||||
void on_profilesComboBox_currentIndexChanged(const QString &arg1);
|
void on_profilesComboBox_currentIndexChanged(const QString &arg1);
|
||||||
|
|
||||||
void on_settingsDestProfileRadioButton_toggled(bool checked);
|
void on_settingsDestProfileRadioButton_toggled(bool checked);
|
||||||
|
|
|
@ -102,6 +102,7 @@ void _loadSettings(QSettings & settings)
|
||||||
config.textureFilter.txSaveCache = settings.value("txSaveCache", config.textureFilter.txSaveCache).toInt();
|
config.textureFilter.txSaveCache = settings.value("txSaveCache", config.textureFilter.txSaveCache).toInt();
|
||||||
config.textureFilter.txEnhancedTextureFileStorage = settings.value("txEnhancedTextureFileStorage", config.textureFilter.txEnhancedTextureFileStorage).toInt();
|
config.textureFilter.txEnhancedTextureFileStorage = settings.value("txEnhancedTextureFileStorage", config.textureFilter.txEnhancedTextureFileStorage).toInt();
|
||||||
config.textureFilter.txHiresTextureFileStorage = settings.value("txHiresTextureFileStorage", config.textureFilter.txHiresTextureFileStorage).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);
|
QString txPath = QString::fromWCharArray(config.textureFilter.txPath);
|
||||||
config.textureFilter.txPath[settings.value("txPath", txPath).toString().toWCharArray(config.textureFilter.txPath)] = L'\0';
|
config.textureFilter.txPath[settings.value("txPath", txPath).toString().toWCharArray(config.textureFilter.txPath)] = L'\0';
|
||||||
QString txCachePath = QString::fromWCharArray(config.textureFilter.txCachePath);
|
QString txCachePath = QString::fromWCharArray(config.textureFilter.txCachePath);
|
||||||
|
@ -289,6 +290,7 @@ void writeSettings(const QString & _strIniFolder)
|
||||||
settings.setValue("txSaveCache", config.textureFilter.txSaveCache);
|
settings.setValue("txSaveCache", config.textureFilter.txSaveCache);
|
||||||
settings.setValue("txEnhancedTextureFileStorage", config.textureFilter.txEnhancedTextureFileStorage);
|
settings.setValue("txEnhancedTextureFileStorage", config.textureFilter.txEnhancedTextureFileStorage);
|
||||||
settings.setValue("txHiresTextureFileStorage", config.textureFilter.txHiresTextureFileStorage);
|
settings.setValue("txHiresTextureFileStorage", config.textureFilter.txHiresTextureFileStorage);
|
||||||
|
settings.setValue("txNoTextureFileStorage", config.textureFilter.txNoTextureFileStorage);
|
||||||
settings.setValue("txPath", QString::fromWCharArray(config.textureFilter.txPath));
|
settings.setValue("txPath", QString::fromWCharArray(config.textureFilter.txPath));
|
||||||
settings.setValue("txCachePath", QString::fromWCharArray(config.textureFilter.txCachePath));
|
settings.setValue("txCachePath", QString::fromWCharArray(config.textureFilter.txCachePath));
|
||||||
settings.setValue("txDumpPath", QString::fromWCharArray(config.textureFilter.txDumpPath));
|
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, txCacheSize);
|
||||||
WriteCustomSetting(textureFilter, txEnhancedTextureFileStorage);
|
WriteCustomSetting(textureFilter, txEnhancedTextureFileStorage);
|
||||||
WriteCustomSetting(textureFilter, txHiresTextureFileStorage);
|
WriteCustomSetting(textureFilter, txHiresTextureFileStorage);
|
||||||
|
WriteCustomSetting(textureFilter, txNoTextureFileStorage);
|
||||||
WriteCustomSetting(textureFilter, txHiresEnable);
|
WriteCustomSetting(textureFilter, txHiresEnable);
|
||||||
WriteCustomSetting(textureFilter, txHiresFullAlphaChannel);
|
WriteCustomSetting(textureFilter, txHiresFullAlphaChannel);
|
||||||
WriteCustomSetting(textureFilter, txHresAltCRC);
|
WriteCustomSetting(textureFilter, txHresAltCRC);
|
||||||
|
|
|
@ -2659,6 +2659,13 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="noTexFileStorageCheckBox">
|
||||||
|
<property name="text">
|
||||||
|
<string>Use no file storage or cache (causes worse stutter, not recommended for playing games)</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
|
|
|
@ -63,6 +63,8 @@ u32 TextureFilterHandler::_getConfigOptions() const
|
||||||
options |= FILE_TEXCACHE;
|
options |= FILE_TEXCACHE;
|
||||||
if (config.textureFilter.txHiresTextureFileStorage)
|
if (config.textureFilter.txHiresTextureFileStorage)
|
||||||
options |= FILE_HIRESTEXCACHE;
|
options |= FILE_HIRESTEXCACHE;
|
||||||
|
if (config.textureFilter.txNoTextureFileStorage)
|
||||||
|
options |= FILE_NOTEXCACHE;
|
||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -198,6 +198,8 @@ void PluginAPI::RomClosed()
|
||||||
|
|
||||||
int PluginAPI::RomOpen()
|
int PluginAPI::RomOpen()
|
||||||
{
|
{
|
||||||
|
osal_keys_init();
|
||||||
|
|
||||||
LOG(LOG_APIFUNC, "RomOpen");
|
LOG(LOG_APIFUNC, "RomOpen");
|
||||||
#ifdef RSPTHREAD
|
#ifdef RSPTHREAD
|
||||||
m_pluginThreadMtx.lock();
|
m_pluginThreadMtx.lock();
|
||||||
|
@ -212,7 +214,6 @@ int PluginAPI::RomOpen()
|
||||||
if (!dwnd().start())
|
if (!dwnd().start())
|
||||||
return 0;
|
return 0;
|
||||||
#endif
|
#endif
|
||||||
osal_keys_init();
|
|
||||||
|
|
||||||
m_bRomOpen = true;
|
m_bRomOpen = true;
|
||||||
|
|
||||||
|
|
|
@ -255,6 +255,8 @@ bool Config_SetDefault()
|
||||||
assert(res == M64ERR_SUCCESS);
|
assert(res == M64ERR_SUCCESS);
|
||||||
res = ConfigSetDefaultBool(g_configVideoGliden64, "txHiresTextureFileStorage", config.textureFilter.txHiresTextureFileStorage, "Use file storage instead of memory cache for HD textures.");
|
res = ConfigSetDefaultBool(g_configVideoGliden64, "txHiresTextureFileStorage", config.textureFilter.txHiresTextureFileStorage, "Use file storage instead of memory cache for HD textures.");
|
||||||
assert(res == M64ERR_SUCCESS);
|
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
|
// Convert to multibyte
|
||||||
char txPath[PLUGIN_PATH_SIZE * 2];
|
char txPath[PLUGIN_PATH_SIZE * 2];
|
||||||
wcstombs(txPath, config.textureFilter.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);
|
if (result == M64ERR_SUCCESS) config.textureFilter.txEnhancedTextureFileStorage = atoi(value);
|
||||||
result = ConfigExternalGetParameter(fileHandle, sectionName, "textureFilter\\txHiresTextureFileStorage", value, sizeof(value));
|
result = ConfigExternalGetParameter(fileHandle, sectionName, "textureFilter\\txHiresTextureFileStorage", value, sizeof(value));
|
||||||
if (result == M64ERR_SUCCESS) config.textureFilter.txHiresTextureFileStorage = atoi(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);
|
ConfigExternalClose(fileHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -553,6 +557,7 @@ void Config_LoadConfig()
|
||||||
config.textureFilter.txSaveCache = ConfigGetParamBool(g_configVideoGliden64, "txSaveCache");
|
config.textureFilter.txSaveCache = ConfigGetParamBool(g_configVideoGliden64, "txSaveCache");
|
||||||
config.textureFilter.txEnhancedTextureFileStorage = ConfigGetParamBool(g_configVideoGliden64, "txEnhancedTextureFileStorage");
|
config.textureFilter.txEnhancedTextureFileStorage = ConfigGetParamBool(g_configVideoGliden64, "txEnhancedTextureFileStorage");
|
||||||
config.textureFilter.txHiresTextureFileStorage = ConfigGetParamBool(g_configVideoGliden64, "txHiresTextureFileStorage");
|
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.txPath, ConfigGetParamString(g_configVideoGliden64, "txPath"), PLUGIN_PATH_SIZE);
|
||||||
::mbstowcs(config.textureFilter.txCachePath, ConfigGetParamString(g_configVideoGliden64, "txCachePath"), 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);
|
::mbstowcs(config.textureFilter.txDumpPath, ConfigGetParamString(g_configVideoGliden64, "txDumpPath"), PLUGIN_PATH_SIZE);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user