Files
Cyd 2b8ca921cb Initial full mirror of c:\VWE (source + assets + toolchain + outputs) via Git LFS
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.
2026-06-24 21:28:16 -05:00

563 lines
13 KiB
C++

#include "ProxyHeaders.hpp"
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
BuildMegatexturesProcess::BuildMegatexturesProcess(NotationFile *mega_file):
megaFile(mega_file)
{
Check_Pointer(this);
Check_Object(megaFile);
Check_Object(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
BuildMegatexturesProcess::BuildMegatexturesProcess(
NotationFile *config_file,
NotationFile *mega_file
):
Process(config_file),
megaFile(mega_file)
{
Check_Pointer(this);
Check_Object(config_file);
Check_Object(megaFile);
Check_Object(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
BuildMegatexturesProcess::ProcessCallback(
int error,
const char* megatexture,
const char* texture
)
{
Check_Object(this);
Check_Pointer(megatexture);
switch (error)
{
case BadPageSize:
PAUSE(("[%s] has a bad PageSize!", megatexture));
break;
case BadTextureLine:
Check_Pointer(texture);
PAUSE(("[%s] has a bad Texture= specification!", megatexture));
break;
case SizesDontMatch:
Check_Pointer(texture);
PAUSE(("[%s]%s does not match its stated size!", megatexture, texture));
break;
case BadTexture:
Check_Pointer(texture);
PAUSE(("[%s]%s is a bad texture!", megatexture, texture));
break;
case TextureDoesntFit:
Check_Pointer(texture);
PAUSE(("[%s]%s doesn't fit!", megatexture, texture));
break;
case TextureOverlap:
Check_Pointer(texture);
PAUSE(("[%s]%s overlaps a previous texture!", megatexture, texture));
break;
case EmptyMegatexture:
PAUSE(("[%s] is empty!", megatexture));
break;
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
TextureProxy::BuildMegatextures(BuildMegatexturesProcess *process)
{
Check_Object(this);
Check_Object(process);
//
//--------------------------
// Get the mega texture data
//--------------------------
//
NotationFile *mega_file = process->megaFile;
Check_Object(mega_file);
MString mega_name;
GetName(&mega_name);
Check_Object(&mega_name);
Vector2DOf<int> mega_size;
GetImageSize(&mega_size);
Verify(
mega_size.x >= 16 && mega_size.x <= 512
&& mega_size.y >= 16 && mega_size.y <= 512
&& mega_size.x == (mega_size.x & -mega_size.x)
&& mega_size.y == (mega_size.y & -mega_size.y)
);
TextureLibrary *library = GetTextureLibrary();
Check_Object(library);
//
//-----------------------------------------------------------------
// Create the megatexture proxy and clear it out to invisible black
//-----------------------------------------------------------------
//
unsigned channel_size = mega_size.x*mega_size.y;
DynamicArrayOf<BYTE>
red(channel_size),
green(channel_size),
blue(channel_size),
alpha(channel_size);
memset(red.GetData(), 0, channel_size);
memset(green.GetData(), 0, channel_size);
memset(blue.GetData(), 0, channel_size);
memset(alpha.GetData(), 0, channel_size);
DynamicArrayOf<bool>
used(false, channel_size);
//
//----------------------------------------------------------------------
// Now start stepping through the entries for the page and skip the page
// size entry
//----------------------------------------------------------------------
//
bool alpha_used = false;
int texture_count = 0;
ChainOf<Note*> *textures = NULL;
Note *entry = NULL;
unsigned errors = 0;
Page *mega_page = mega_file->FindPage(mega_name);
if (mega_page)
{
textures = mega_page->MakeNoteChain("Texture");
Check_Object(textures);
Page::NoteIterator texture_itr(textures);
while ((entry = texture_itr.ReadAndNext()) != NULL)
{
Check_Object(entry);
//
//--------------------------------------------
// Extract the texture data from the tron file
//--------------------------------------------
//
const char* data;
entry->GetEntry(&data);
Check_Pointer(data);
Vector2DOf<int> offset, size(0,0);
char texture_name[80];
int param_count =
sscanf(
data,
"%s %d %d %d %d",
texture_name,
&offset.x,
&offset.y,
&size.x,
&size.y
);
if (param_count != 5 || !strlen(texture_name))
{
process->ProcessCallback(
BuildMegatexturesProcess::BadTextureLine,
mega_name,
texture_name
);
if (!process->continueProcess)
{
Unwind_1:
Check_Object(textures);
delete textures;
return;
#undef UNWIND
#define UNWIND() goto Unwind_1
}
else
{
++errors;
continue;
}
}
//
//--------------------------
// Do the status check again
//--------------------------
//
process->ProcessCallback(
BuildMegatexturesProcess::StatusCheck,
mega_name,
texture_name
);
if (!process->continueProcess)
UNWIND();
//
//-----------------------------------------------------------------
// We now have a texture name, so get the actual texture proxy from
// the library
//-----------------------------------------------------------------
//
TextureProxy *texture = library->UseTextureProxy(texture_name);
Check_Object(texture);
//
//---------------------------
// Make sure the size is good
//---------------------------
//
Vector2DOf<int> texture_size;
texture->GetImageSize(&texture_size);
if (!texture_size.x && !texture_size.y)
{
process->ProcessCallback(
BuildMegatexturesProcess::BadTexture,
mega_name,
texture_name
);
if (!process->continueProcess)
{
Unwind_2:
texture->DetachReference();
UNWIND();
#undef UNWIND
#define UNWIND() goto Unwind_2
}
else
{
texture->DetachReference();
++errors;
continue;
}
}
//
//-----------------------------------------------
// Make sure the size matches what is in the file
//-----------------------------------------------
//
if (size != texture_size)
{
process->ProcessCallback(
BuildMegatexturesProcess::SizesDontMatch,
mega_name,
texture_name
);
if (!process->continueProcess)
UNWIND();
else
{
texture->DetachReference();
++errors;
continue;
}
}
++texture_count;
//
//--------------------------------------------------------------
// Figure out where this texture wishes to be in the megatexture
//--------------------------------------------------------------
//
if (
offset.x < 0 || offset.x+size.x > mega_size.x
|| offset.y < 0 || offset.y+size.y > mega_size.y
)
{
process->ProcessCallback(
BuildMegatexturesProcess::TextureDoesntFit,
mega_name,
texture_name
);
if (!process->continueProcess)
UNWIND();
else
{
++errors;
texture->DetachReference();
continue;
}
}
//
//-----------------------
// Get the texture depths
//-----------------------
//
unsigned
red_depth,
green_depth,
blue_depth,
alpha_depth;
texture->GetChannelDepth(
&red_depth,
&green_depth,
&blue_depth,
&alpha_depth
);
if (alpha_depth)
alpha_used = true;
//
//---------------------
// Get the texture data
//---------------------
//
DynamicArrayOf<BYTE>
r,
g,
b,
a;
if (alpha_depth)
texture->GetChannels(&r, &g, &b, &a);
else
{
texture->GetChannels(&r, &g, &b, NULL);
alpha_depth = 0;
}
//
//-------------------------
// Copy the data row by row
//-------------------------
//
Vector2DOf<int> source(0,0);
for (source.y=0; source.y<size.y; ++source.y)
{
Vector2DOf<int> dest;
dest.Add(offset, source);
unsigned source_pixel = texture->GetPixelIndex(source);
unsigned dest_pixel = GetPixelIndex(dest);
//
//--------------------
// Look for an overlap
//--------------------
//
void *overlap = memchr(&used[dest_pixel], true, size.x);
if (overlap)
{
process->ProcessCallback(
BuildMegatexturesProcess::TextureOverlap,
mega_name,
texture_name
);
if (!process->continueProcess)
UNWIND();
else
{
++errors;
source.y = size.y;
continue;
}
}
memset(&used[dest_pixel], true, size.x);
//
//---------------------
// Copy the row of data
//---------------------
//
Mem_Copy(
&red[dest_pixel],
&r[source_pixel],
size.x,
red.GetLength() - dest_pixel
);
Mem_Copy(
&green[dest_pixel],
&g[source_pixel],
size.x,
green.GetLength() - dest_pixel
);
Mem_Copy(
&blue[dest_pixel],
&b[source_pixel],
size.x,
blue.GetLength() - dest_pixel
);
//
//----------------------------------------------------------------
// Copy the alpha data if enabled, otherwise just set it to opaque
//----------------------------------------------------------------
//
if (alpha_depth)
{
Mem_Copy(
&alpha[dest_pixel],
&a[source_pixel],
size.x,
alpha.GetLength() - dest_pixel
);
}
else
memset(&alpha[dest_pixel], static_cast<BYTE>(255), size.x);
}
//
//---------------------
// Clean up the texture
//---------------------
//
texture->DetachReference();
}
}
//
//-------------------------------------------------
// Tell the application if the megatexture is empty
//-------------------------------------------------
//
if (!texture_count)
{
process->ProcessCallback(
BuildMegatexturesProcess::EmptyMegatexture,
mega_name,
NULL
);
if (!process->continueProcess)
{
Check_Object(textures);
delete textures;
}
}
//
//---------------------------------------------------------------------
// If we didn't have any errors and aren't empty, copy the texture into
// the texture library
//---------------------------------------------------------------------
//
else if (!errors)
{
SetChannels(
&red,
&green,
&blue,
(alpha_used) ? &alpha : NULL
);
TextureProxy *proxy = library->UseMatchingTextureProxy(this);
Check_Object(proxy);
Verify(IsEqualTo(proxy));
proxy->DetachReference();
}
//
//---------
// Clean up
//---------
//
Check_Object(textures);
delete textures;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
TextureLibrary::BuildMegatextures(BuildMegatexturesProcess *process)
{
Check_Object(this);
Check_Object(process);
//
//------------------------------------------------------------------------
// Get the page list from the mega file and process each page after making
// sure the app says it's OK
//------------------------------------------------------------------------
//
NotationFile *mega_file = process->megaFile;
Check_Object(mega_file);
NotationFile::PageIterator *pages = mega_file->MakePageIterator();
Check_Object(pages);
Page *page;
while ((page = pages->ReadAndNext()) != NULL)
{
Check_Object(page);
const char* mega_name = page->GetName();
Check_Pointer(mega_name);
process->ProcessCallback(
BuildMegatexturesProcess::StatusCheck,
mega_name,
NULL
);
if (!process->continueProcess)
{
Unwind_1:
Check_Object(pages);
delete pages;
return;
#undef UNWIND
#define UNWIND() goto Unwind_1
}
//
//----------------------------------------------------------------------
// For each page, get a list of all the entries. If the page is missing
// its PageSize page, it is a final uncoalesced texture, so skip it
//----------------------------------------------------------------------
//
const char* size_string;
if (!page->GetEntry("PageSize", &size_string))
continue;
//
//------------------------------
// Make sure the page size is OK
//------------------------------
//
Vector2DOf<int> mega_size;
#if defined(_ARMOR)
int param_count =
#endif
sscanf(size_string, "%d %d", &mega_size.x, &mega_size.y);
Verify(param_count);
if (
mega_size.x < 16 || mega_size.x > 512
|| mega_size.y < 16 || mega_size.y > 512
|| mega_size.x != (mega_size.x & -mega_size.x)
|| mega_size.y != (mega_size.y & -mega_size.y)
)
{
process->ProcessCallback(
BuildMegatexturesProcess::BadPageSize,
mega_name,
NULL
);
if (!process->continueProcess)
UNWIND();
else
continue;
}
//
//---------------------------------------------------
// Create the megatexture proxy run the process on it
//---------------------------------------------------
//
TextureProxy *mega_texture =
TextureProxy::MakeProxy(mega_name, mega_size, this);
Check_Object(mega_texture);
mega_texture->BuildMegatextures(process);
mega_texture->DetachReference();
if (!process->continueProcess)
UNWIND();
}
//
//-----------------------
// Clean up the page list
//-----------------------
//
Check_Object(pages);
delete pages;
}