Skip to content

Commit b838c65

Browse files
authored
feat(filesystem): Recover 481 higher resolution textures in Zero Hour by re-prioritizing textures by size (#1484)
1 parent cb57c1b commit b838c65

File tree

5 files changed

+235
-92
lines changed

5 files changed

+235
-92
lines changed

Core/GameEngine/Include/Common/GameDefines.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,12 @@
7373
#define ENABLE_FILESYSTEM_EXISTENCE_CACHE (1)
7474
#endif
7575

76+
// Enable prioritization of textures by size. This will improve the texture quality of 481 textures in Zero Hour
77+
// by using the larger resolution textures from Generals. Content wise these textures are identical.
78+
#ifndef PRIORITIZE_TEXTURES_BY_SIZE
79+
#define PRIORITIZE_TEXTURES_BY_SIZE (1)
80+
#endif
81+
7682
// Enable obsolete code. This mainly refers to code that existed in Generals but was removed in GeneralsMD.
7783
// Disable and remove this when Generals and GeneralsMD are merged.
7884
#if RTS_GENERALS

Generals/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DFileSystem.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
#define __W3DFILESYSTEM_H_
4141

4242
#include "WWLib/ffactory.h"
43+
#include "Common/ArchiveFileSystem.h"
4344
#include "Common/file.h"
4445

4546
//-------------------------------------------------------------------------------------------------
@@ -93,6 +94,11 @@ class W3DFileSystem : public FileFactoryClass {
9394

9495
virtual FileClass * Get_File( char const *filename );
9596
virtual void Return_File( FileClass *file );
97+
98+
private:
99+
100+
static void reprioritizeTexturesBySize();
101+
static void reprioritizeTexturesBySize(ArchivedDirectoryInfo& dirInfo);
96102
};
97103

98104
extern W3DFileSystem *TheW3DFileSystem;

Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DFileSystem.cpp

Lines changed: 108 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -40,17 +40,19 @@
4040
// for now we maintain old legacy files
4141
// #define MAINTAIN_LEGACY_FILES
4242

43+
#include "Common/ArchiveFile.h"
4344
#include "Common/Debug.h"
4445
#include "Common/file.h"
4546
#include "Common/FileSystem.h"
4647
#include "Common/GlobalData.h"
4748
#include "Common/MapObject.h"
4849
#include "Common/Registry.h"
4950
#include "W3DDevice/GameClient/W3DFileSystem.h"
50-
// DEFINES ////////////////////////////////////////////////////////////////////////////////////////
5151

5252
#include <io.h>
5353

54+
// DEFINES ////////////////////////////////////////////////////////////////////////////////////////
55+
5456
//-------------------------------------------------------------------------------------------------
5557
/** Game file access. At present this allows us to access test assets, assets from
5658
* legacy GDI assets, and the current flat directory access for textures, models etc */
@@ -71,9 +73,9 @@ typedef enum
7173
GameFileClass::GameFileClass( char const *filename )
7274
{
7375

74-
m_fileExists = FALSE;
7576
m_theFile = NULL;
76-
m_filePath[ 0 ] = 0;
77+
m_fileExists = FALSE;
78+
m_filePath[0] = 0;
7779
m_filename[0] = 0;
7880

7981
if( filename )
@@ -119,6 +121,24 @@ inline static Bool isImageFileType( GameFileType fileType )
119121
return (fileType == FILE_TYPE_TGA || fileType == FILE_TYPE_DDS);
120122
}
121123

124+
//-------------------------------------------------------------------------------------------------
125+
//-------------------------------------------------------------------------------------------------
126+
static GameFileType getFileType( char const *filename )
127+
{
128+
if (char const *extension = strrchr( filename, '.' ))
129+
{
130+
// test the extension to recognize a few key file types
131+
if( stricmp( extension, ".w3d" ) == 0 )
132+
return FILE_TYPE_W3D;
133+
else if( stricmp( extension, ".tga" ) == 0 )
134+
return FILE_TYPE_TGA;
135+
else if( stricmp( extension, ".dds" ) == 0 )
136+
return FILE_TYPE_DDS;
137+
}
138+
139+
return FILE_TYPE_COMPLETELY_UNKNOWN; // MBL FILE_TYPE_UNKNOWN change due to compile error
140+
}
141+
122142
//-------------------------------------------------------------------------------------------------
123143
/** Sets the file name, and finds the GDI asset if present. */
124144
//-------------------------------------------------------------------------------------------------
@@ -131,41 +151,7 @@ char const * GameFileClass::Set_Name( char const *filename )
131151
// save the filename
132152
strlcpy( m_filename, filename, _MAX_PATH );
133153

134-
char name[_MAX_PATH];
135-
const Int EXT_LEN = 32;
136-
char extension[EXT_LEN];
137-
extension[0] = 0;
138-
strcpy(name, filename);
139-
Int i = strlen(name);
140-
i--;
141-
Int extLen = 1;
142-
while(i>0 && extLen < EXT_LEN) {
143-
if (name[i] == '.') {
144-
strcpy(extension, name+i);
145-
name[i] = 0;
146-
break;
147-
}
148-
i--;
149-
extLen++;
150-
}
151-
Int j = 0;
152-
// Strip out spaces.
153-
for (i=0; name[i]; i++) {
154-
if (name[i] != ' ') {
155-
name[j] = name[i];
156-
j++;
157-
}
158-
}
159-
name[j] = 0;
160-
161-
// test the extension to recognize a few key file types
162-
GameFileType fileType = FILE_TYPE_COMPLETELY_UNKNOWN; // MBL FILE_TYPE_UNKNOWN change due to compile error
163-
if( stricmp( extension, ".w3d" ) == 0 )
164-
fileType = FILE_TYPE_W3D;
165-
else if( stricmp( extension, ".tga" ) == 0 )
166-
fileType = FILE_TYPE_TGA;
167-
else if( stricmp( extension, ".dds" ) == 0 )
168-
fileType = FILE_TYPE_DDS;
154+
GameFileType fileType = getFileType(filename);
169155

170156
// all .w3d files are in W3D_DIR_PATH, all .tga files are in TGA_DIR_PATH
171157
if( fileType == FILE_TYPE_W3D )
@@ -250,7 +236,7 @@ char const * GameFileClass::Set_Name( char const *filename )
250236
strlcat(m_filePath, filename, ARRAY_SIZE(m_filePath));
251237

252238
}
253-
if( isImageFileType(fileType) )
239+
else if( isImageFileType(fileType) )
254240
{
255241
sprintf(m_filePath,USER_TGA_DIR_PATH, TheGlobalData->getPath_UserData().str());
256242
//strcpy( m_filePath, USER_TGA_DIR_PATH );
@@ -264,10 +250,10 @@ char const * GameFileClass::Set_Name( char const *filename )
264250
}
265251

266252

267-
// We Need to be able to "temporarily copy over the map preview for whichever directory it came from
253+
// We need to be able to temporarily copy over the map preview for whichever directory it came from
268254
if( m_fileExists == FALSE && TheGlobalData)
269255
{
270-
if( fileType == FILE_TYPE_TGA ) // just TGA, since we don't dds previews
256+
if( fileType == FILE_TYPE_TGA ) // just TGA, since we don't do dds previews
271257
{
272258
sprintf(m_filePath,MAP_PREVIEW_DIR_PATH, TheGlobalData->getPath_UserData().str());
273259
//strcpy( m_filePath, USER_TGA_DIR_PATH );
@@ -343,11 +329,9 @@ int GameFileClass::Open(int rights)
343329
return(false);
344330
}
345331

346-
// just open up the file in m_filePath
347332
m_theFile = TheFileSystem->openFile( m_filePath, File::READ | File::BINARY );
348333

349334
return (m_theFile != NULL);
350-
351335
}
352336

353337
//-------------------------------------------------------------------------------------------------
@@ -418,12 +402,16 @@ void GameFileClass::Close(void)
418402
extern W3DFileSystem *TheW3DFileSystem = NULL;
419403

420404
//-------------------------------------------------------------------------------------------------
421-
/** Constructor. Creating an instance of this class overrices the default
405+
/** Constructor. Creating an instance of this class overrides the default
422406
W3D file factory. */
423407
//-------------------------------------------------------------------------------------------------
424408
W3DFileSystem::W3DFileSystem(void)
425409
{
426410
_TheFileFactory = this; // override the w3d file factory.
411+
412+
#if RTS_ZEROHOUR && PRIORITIZE_TEXTURES_BY_SIZE
413+
reprioritizeTexturesBySize();
414+
#endif
427415
}
428416

429417
//-------------------------------------------------------------------------------------------------
@@ -451,3 +439,79 @@ void W3DFileSystem::Return_File( FileClass *file )
451439
delete file;
452440
}
453441

442+
//-------------------------------------------------------------------------------------------------
443+
//-------------------------------------------------------------------------------------------------
444+
void W3DFileSystem::reprioritizeTexturesBySize()
445+
{
446+
ArchivedDirectoryInfo* dirInfo = TheArchiveFileSystem->friend_getArchivedDirectoryInfo(TGA_DIR_PATH);
447+
if (dirInfo != NULL)
448+
{
449+
reprioritizeTexturesBySize(*dirInfo);
450+
}
451+
}
452+
453+
//-------------------------------------------------------------------------------------------------
454+
// TheSuperHackers @info This function moves the largest texture of its name to the front of the
455+
// directory info. The algorithm only prioritizes the first item in the multimap, because this is
456+
// what we currently need:
457+
// Before: A(256kb) B(128kb) C(512kb)
458+
// After: C(512kb) B(128kb) A(256kb)
459+
//
460+
// Catered to specific game archives only. This ensures that user created archives are not included
461+
// for the re-prioritization of textures.
462+
//-------------------------------------------------------------------------------------------------
463+
void W3DFileSystem::reprioritizeTexturesBySize(ArchivedDirectoryInfo& dirInfo)
464+
{
465+
const char* const superiorArchive = "Textures.big";
466+
const char* const inferiorArchive = "TexturesZH.big";
467+
468+
ArchivedFileLocationMap::iterator it0;
469+
ArchivedFileLocationMap::iterator it1 = dirInfo.m_files.begin();
470+
ArchivedFileLocationMap::iterator end = dirInfo.m_files.end();
471+
472+
if (it1 != end)
473+
{
474+
it0 = it1;
475+
++it1;
476+
}
477+
478+
for (; it1 != end; ++it1)
479+
{
480+
const AsciiString& file0 = it0->first;
481+
const AsciiString& file1 = it1->first;
482+
483+
if (file0 == file1)
484+
{
485+
GameFileType type = getFileType(file0.str());
486+
if (isImageFileType(type))
487+
{
488+
ArchiveFile* archive0 = it0->second;
489+
ArchiveFile* archive1 = it1->second;
490+
FileInfo info0;
491+
FileInfo info1;
492+
AsciiString filepath(dirInfo.m_path);
493+
filepath.concat(file0);
494+
495+
if (archive0->getFileInfo(filepath, &info0) && archive1->getFileInfo(filepath, &info1))
496+
{
497+
if (info0.size() < info1.size()
498+
&& archive0->getName().endsWithNoCase(inferiorArchive)
499+
&& archive1->getName().endsWithNoCase(superiorArchive))
500+
{
501+
std::swap(it0->second, it1->second);
502+
503+
#if ENABLE_FILESYSTEM_LOGGING
504+
DEBUG_LOG(("W3DFileSystem::reprioritizeTexturesBySize - prioritize %s(%ukb) from %s over %s(%ukb) from %s",
505+
file1.str(), UnsignedInt(info1.size() / 1024), archive1->getName().str(),
506+
file0.str(), UnsignedInt(info0.size() / 1024), archive0->getName().str()));
507+
#endif
508+
}
509+
}
510+
}
511+
}
512+
else
513+
{
514+
it0 = it1;
515+
}
516+
}
517+
}

GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DFileSystem.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
#define __W3DFILESYSTEM_H_
4141

4242
#include "WWLib/ffactory.h"
43+
#include "Common/ArchiveFileSystem.h"
4344
#include "Common/file.h"
4445

4546
//-------------------------------------------------------------------------------------------------
@@ -93,6 +94,11 @@ class W3DFileSystem : public FileFactoryClass {
9394

9495
virtual FileClass * Get_File( char const *filename );
9596
virtual void Return_File( FileClass *file );
97+
98+
private:
99+
100+
static void reprioritizeTexturesBySize();
101+
static void reprioritizeTexturesBySize(ArchivedDirectoryInfo& dirInfo);
96102
};
97103

98104
extern W3DFileSystem *TheW3DFileSystem;

0 commit comments

Comments
 (0)