Complete disaster-recovery snapshot: engine/game source, game data assets, VC6 toolchain + DX SDKs, build outputs, deployed game, and _UNUSED archive. Large binaries in Git LFS; text preserved byte-for-byte (core.autocrlf=false, no eol attributes). See RECOVERY.md for the one-clone rebuild procedure.
467 lines
13 KiB
C++
467 lines
13 KiB
C++
#include "AdeptHeaders.hpp"
|
|
|
|
#include "ResourceImagePool.hpp"
|
|
#include "Application.hpp"
|
|
#include "Tool.hpp"
|
|
#include "VideoRenderer.hpp"
|
|
#include <Compost\Compost.hpp>
|
|
#include <MLR\GOSImage.hpp>
|
|
|
|
using MidLevelRenderer::GOSImage;
|
|
|
|
#define SUPPORT_TGA
|
|
#define SUPPORT_PNG
|
|
|
|
#if 1
|
|
#define TEXTURE_LOAD(string) LOG_BLOCK("Texture Load::" string)
|
|
#else
|
|
#define TEXTURE_LOAD(string)
|
|
#endif
|
|
|
|
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Compost::FetchTextureData(Compost::Feature_Texture *tex, int index, int type)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Compost::FetchTextureData(Compost::Feature_Texture *tex, const char *name, int type)
|
|
{
|
|
Verify(gos_GetCurrentHeap() == Heap);
|
|
MString fname(name);
|
|
fname += ".bid";
|
|
|
|
fname.ToLower();
|
|
|
|
FileStream hFile(fname);
|
|
int size = tex->RecalculateSize();
|
|
tex->data = new BYTE [size];
|
|
tex->dataSize = size;
|
|
|
|
if(size != hFile.GetBytesRemaining())
|
|
{
|
|
STOP(("Length of BID-file %s incorrect", name));
|
|
}
|
|
|
|
hFile.ReadBytes(tex->data, size);
|
|
|
|
return;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Compost::DestroyTextureData(Compost::Feature_Texture *tex)
|
|
{
|
|
delete [] tex->data;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
DWORD ResourceImagePool::FindTexture(
|
|
const char* tex_name,
|
|
int hint
|
|
)
|
|
{
|
|
Check_Pointer(tex_name);
|
|
TEXTURE_LOAD("Find Texture");
|
|
|
|
//
|
|
//----------------------------------------------
|
|
// Put the texture directory on the texture name
|
|
//----------------------------------------------
|
|
//
|
|
MString file_name = "content\\textures\\";
|
|
file_name += tex_name;
|
|
file_name += ".tga";
|
|
|
|
//
|
|
//---------------------------------------------
|
|
// Loop through testing for each extension type
|
|
//---------------------------------------------
|
|
//
|
|
#if defined(SUPPORT_PNG)
|
|
char* ext_pointer = static_cast<char*>(file_name) + file_name.GetLength()-3;
|
|
do
|
|
{
|
|
#endif
|
|
//
|
|
//-------------------------------------------------------------------
|
|
// If we can find a texture matching the name, check to see if it has
|
|
// explicit mipmaps. If so, we need to secretly reroute to a texture
|
|
// given by the bias
|
|
//-------------------------------------------------------------------
|
|
//
|
|
bool exists;
|
|
{
|
|
Resource texture_stream(file_name);
|
|
exists = texture_stream.DoesResourceExist();
|
|
}
|
|
if (exists)
|
|
{
|
|
int hint_flags;
|
|
Resource hint_stream(MString(file_name)+"{hint}");
|
|
Verify(hint_stream.DoesResourceExist());
|
|
hint_stream.LoadData();
|
|
hint_stream >> hint_flags;
|
|
if (Environment.bitDepth == 32)
|
|
hint_flags |= gosHint_Try32bpp;
|
|
hint_stream.UnloadData();
|
|
if (hint_flags & gosHint_UserMipMaps)
|
|
{
|
|
int bias = hint_flags >> 24;
|
|
bias = VideoRenderer::s_MipBias + bias;
|
|
Min_Clamp(bias, 0);
|
|
int len = strlen(file_name)-5;
|
|
file_name[len] = static_cast<char>(file_name[len] + bias);
|
|
Max_Clamp(file_name[len], '5');
|
|
}
|
|
char format = static_cast<char>(hint_flags>>16);
|
|
hint_flags &= 0xffff;
|
|
DWORD texture_handle =
|
|
gos_NewTextureFromFile(
|
|
static_cast<gos_TextureFormat>(format),
|
|
file_name,
|
|
hint_flags|hint
|
|
);
|
|
|
|
//
|
|
//--------------------------------------------
|
|
// If we want this in video memory, preload it
|
|
//--------------------------------------------
|
|
//
|
|
if ((hint_flags & (gosHint_AGPMemory|gosHint_VideoMemory)) == gosHint_VideoMemory)
|
|
gos_PreloadTexture(texture_handle);
|
|
return texture_handle;
|
|
}
|
|
|
|
//
|
|
//--------------------------------------------------------------------
|
|
// We couldn't find the resource, so try the actual file. If the hint
|
|
// says to use explicit mipmaps, bump the number by the bias
|
|
//--------------------------------------------------------------------
|
|
//
|
|
else
|
|
{
|
|
if (hint & gosHint_UserMipMaps)
|
|
{
|
|
int len = strlen(file_name)-5;
|
|
Verify(file_name[len] == '0');
|
|
file_name[len] =
|
|
static_cast<char>(file_name[len] + VideoRenderer::s_MipBias);
|
|
}
|
|
|
|
//
|
|
//-----------------------------
|
|
// See if the file can be found
|
|
//-----------------------------
|
|
//
|
|
if (gos_DoesFileExist(file_name))
|
|
{
|
|
#ifdef LAB_ONLY
|
|
PAUSE(("[%s] is NOT in resources but found on disc.", tex_name));
|
|
#endif
|
|
if (FileStream::IsRedirected)
|
|
{
|
|
FileStream::IsRedirected = false;
|
|
return
|
|
gos_NewTextureFromFile(
|
|
gos_Texture_Detect,
|
|
FileStream::RedirectedName,
|
|
hint
|
|
);
|
|
}
|
|
else
|
|
{
|
|
return
|
|
gos_NewTextureFromFile(
|
|
gos_Texture_Detect,
|
|
file_name,
|
|
hint
|
|
);
|
|
}
|
|
}
|
|
#ifdef LAB_ONLY
|
|
else
|
|
{
|
|
PAUSE(("[%s] is NOT in resources and NOT on disc.", tex_name));
|
|
}
|
|
#endif
|
|
|
|
Verify(!FileStream::IsRedirected);
|
|
}
|
|
|
|
//
|
|
//----------------------------------------------------------------
|
|
// Stop the loop if the png doesn't exist or if we found our image
|
|
//----------------------------------------------------------------
|
|
//
|
|
#if defined(SUPPORT_PNG)
|
|
if (ext_pointer[0]=='p')
|
|
break;
|
|
|
|
//
|
|
//---------------------------
|
|
// roll to the next extension
|
|
//---------------------------
|
|
//
|
|
ext_pointer[0]='p';
|
|
ext_pointer[1]='n';
|
|
ext_pointer[2]='g';
|
|
Verify(!ext_pointer[3]);
|
|
} while (true);
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
bool
|
|
ResourceImagePool::LoadImageGOS(GOSImage *image, int hint)
|
|
{
|
|
//
|
|
//----------------------------------------
|
|
// If the image is already loaded, we done
|
|
//----------------------------------------
|
|
//
|
|
TEXTURE_LOAD("Load Image");
|
|
if ( (image->flags & GOSImage::Loaded) != 0)
|
|
return true;
|
|
|
|
//
|
|
//-----------------------------------------------------------------
|
|
// if the image name starts with an underscore, it requires special
|
|
// treatment. Two underscores mean no skin, so just remove the
|
|
// first underscore
|
|
//-----------------------------------------------------------------
|
|
//
|
|
const char* tex_name = image->imageName;
|
|
if (tex_name[1] == g_SkinSignal)
|
|
{
|
|
if (*tex_name == g_SkinSignal)
|
|
++tex_name;
|
|
|
|
//
|
|
//-------------------------------------------------------------------
|
|
// If we get here, then we must synthesize this new texture rather
|
|
// than using something directly from the resources. We will have to
|
|
// open up both the specified file and a skin file and mix them
|
|
//-------------------------------------------------------------------
|
|
//
|
|
else
|
|
{
|
|
TEXTURE_LOAD("Load Image::Composite Skin");
|
|
static char skin[7] = "skin 0";
|
|
skin[4] = *tex_name;
|
|
|
|
//
|
|
//---------------------------------------------------------------
|
|
// We've got the names of both textures now, next we need to have
|
|
// gos open them up for us
|
|
//---------------------------------------------------------------
|
|
//
|
|
DWORD skin_handle = FindTexture(skin, gosHint_DisableMipmap|gosHint_DontShrink);
|
|
if(skin_handle==0)
|
|
{
|
|
STOP((0, "Skin: %s not found !", skin));
|
|
}
|
|
DWORD detail_handle = FindTexture(tex_name+1, gosHint_DisableMipmap|gosHint_DontShrink);
|
|
if(detail_handle==0)
|
|
{
|
|
STOP((0, "Skindetail: %s not found !", tex_name+1));
|
|
}
|
|
image->imageHandle = SkinThis(tex_name, gos_Texture_Solid, skin_handle, detail_handle);
|
|
|
|
gos_DestroyTexture(detail_handle);
|
|
gos_DestroyTexture(skin_handle);
|
|
image->flags |= (image->imageHandle ? GOSImage::Loaded : 0);
|
|
return ( (image->flags & GOSImage::Loaded) != 0);
|
|
}
|
|
}
|
|
|
|
//
|
|
//--------------------------
|
|
// Just open the texture now
|
|
//--------------------------
|
|
//
|
|
image->imageHandle = FindTexture(tex_name, hint|gosHint_ReloadFromDisk);
|
|
|
|
//
|
|
//----------------------------------
|
|
// See if the image loaded correctly
|
|
//----------------------------------
|
|
//
|
|
image->flags |= (image->imageHandle ? GOSImage::Loaded : 0);
|
|
return ( (image->flags & GOSImage::Loaded) != 0);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
ResourceImagePool::BuildTexturePool(NotationFile *hint_file)
|
|
{
|
|
//
|
|
//-------------------------------
|
|
// Open up the texture build file
|
|
//-------------------------------
|
|
//
|
|
Check_Object(Tool::Instance);
|
|
NotationFile::PageIterator *pages = hint_file->MakePageIterator();
|
|
Register_Object(pages);
|
|
|
|
//
|
|
//---------------------------------------------------------
|
|
// Go through the textures file and add each listed texture
|
|
//---------------------------------------------------------
|
|
//
|
|
Check_Object(Tool::Instance);
|
|
Page *page;
|
|
Verify(!Resource::ParentFileDependencies);
|
|
while ((page = pages->ReadAndNext()) != NULL)
|
|
{
|
|
Check_Object(page);
|
|
const char* texture = page->GetName();
|
|
if (!texture)
|
|
continue;
|
|
Check_Pointer(texture);
|
|
|
|
//
|
|
//------------------------------------------------------------
|
|
// See if the resource file is aliased, if so replace the name
|
|
//------------------------------------------------------------
|
|
//
|
|
page->GetEntry("alias", &texture);
|
|
|
|
//
|
|
//--------------------------------------------
|
|
// If we don't resourcify the texture, move on
|
|
//--------------------------------------------
|
|
//
|
|
bool resourcify = true;
|
|
page->GetEntry("resourcify", &resourcify);
|
|
if (!resourcify)
|
|
continue;
|
|
|
|
//
|
|
//------------------------------------------------
|
|
// See if we can open up a resource with this name
|
|
//------------------------------------------------
|
|
//
|
|
MString file_name = "content\\textures\\";
|
|
file_name += texture;
|
|
file_name += ".tga";
|
|
|
|
//
|
|
//--------------------------
|
|
// Find the file on the path
|
|
//--------------------------
|
|
//
|
|
Verify(!FileStream::IsRedirected);
|
|
|
|
#ifdef LAB_ONLY
|
|
strcpy(MWGameInfo::g_LastFileOpenRequest, "BuildTexturePool: ");
|
|
strcpy(MWGameInfo::g_LastFileOpenRequest + 20, file_name);
|
|
#endif
|
|
|
|
|
|
if (!gos_DoesFileExist(file_name))
|
|
{
|
|
#if defined(SUPPORT_PNG)
|
|
Verify(!FileStream::IsRedirected);
|
|
char *extension = (char*)file_name + file_name.GetLength()-3;
|
|
extension[0] = 'p';
|
|
extension[1] = 'n';
|
|
extension[2] = 'g';
|
|
Verify(!extension[3]);
|
|
if (!gos_DoesFileExist(file_name))
|
|
#endif
|
|
file_name = "content\\textures\\01AACA1.tga"; /* [editor degraded-mode] substitute placeholder for missing texture instead of fatal STOP, so downstream gets a valid handle (was: STOP("Texture %s could not be found!")) */
|
|
}
|
|
|
|
//
|
|
//--------------------------------------------------------
|
|
// If not, or it's not up to date, put it in the resources
|
|
//--------------------------------------------------------
|
|
//
|
|
Resource resource((FileStream::IsRedirected)?FileStream::RedirectedName:file_name);
|
|
FileStream::IsRedirected = false;
|
|
if (!resource.DoesResourceExist() || !resource.IsResourceUpToDate())
|
|
{
|
|
|
|
//
|
|
//--------------------
|
|
// Read the hint flags
|
|
//--------------------
|
|
//
|
|
int hints = ReadHint(page) & ~gosHint_ReloadFromDisk;
|
|
|
|
//
|
|
//-------------------
|
|
// Read in the format
|
|
//-------------------
|
|
//
|
|
const char* format;
|
|
if (page->GetEntry("format", &format))
|
|
{
|
|
if (!strcmp(format, "solid"))
|
|
hints |= static_cast<BYTE>(gos_Texture_Solid) << 16;
|
|
else if (!strcmp(format, "keyed"))
|
|
hints |= static_cast<BYTE>(gos_Texture_Keyed) << 16;
|
|
else if (!strcmp(format, "alpha"))
|
|
hints |= static_cast<BYTE>(gos_Texture_Alpha) << 16;
|
|
else if (!strcmp(format, "bump"))
|
|
hints |= static_cast<BYTE>(gos_Texture_Bump) << 16;
|
|
else if (!strcmp(format, "normal"))
|
|
hints |= static_cast<BYTE>(gos_Texture_Normal) << 16;
|
|
else
|
|
hints |= static_cast<BYTE>(gos_Texture_Detect) << 16;
|
|
}
|
|
else
|
|
hints |= static_cast<BYTE>(gos_Texture_Detect) << 16;
|
|
|
|
//
|
|
//--------------------------------------------------
|
|
// Look to see if we want a one level mip-bias delay
|
|
//--------------------------------------------------
|
|
//
|
|
int bias=0;
|
|
page->GetEntry("bias", &bias);
|
|
Clamp(bias, -5, 5);
|
|
hints |= bias << 24;
|
|
|
|
//
|
|
//---------------------------------
|
|
// Open the file as a memory stream
|
|
//---------------------------------
|
|
//
|
|
FileStream texture_file(file_name);
|
|
FileDependencies texture_dependencies;
|
|
texture_dependencies.AddDependency(&texture_file);
|
|
texture_dependencies.AddDependencies(hint_file->GetFileDependencies());
|
|
resource.Save(&texture_file, &texture_dependencies);
|
|
|
|
//
|
|
//---------------------------------
|
|
// Open the file as a memory stream
|
|
//---------------------------------
|
|
//
|
|
MString hint_name = resource.GetName();
|
|
hint_name += "{hint}";
|
|
Resource hint(hint_name);
|
|
MemoryStream hint_stream(&hints, sizeof(hints));
|
|
hint.Save(&hint_stream, hint_file->GetFileDependencies());
|
|
}
|
|
}
|
|
|
|
Unregister_Object(pages);
|
|
delete pages;
|
|
}
|
|
|