Files
firestorm/Gameleap/code/mw4/Libraries/Proxies/ArrangeMegatextures.cpp
T
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

539 lines
13 KiB
C++

#include "ProxyHeaders.hpp"
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ArrangeMegatexturesProcess::ArrangeMegatexturesProcess(NotationFile *mega_file):
megaFile(mega_file)
{
Check_Pointer(this);
Check_Object(megaFile);
Check_Object(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ArrangeMegatexturesProcess::ArrangeMegatexturesProcess(
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
ArrangeMegatexturesProcess::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 BadTexture:
Check_Pointer(texture);
PAUSE(("[%s]%s is a bad texture!", megatexture, texture));
break;
case NotEnoughRoom:
Check_Pointer(texture);
PAUSE(("[%s] doesn't have enough room to hold %s!", megatexture, texture));
break;
case EmptyMegatexture:
PAUSE(("[%s] is empty!", megatexture));
break;
}
}
const int Offsets[32]=
{
0, 1, 4, 5,
16, 17, 20, 21,
64, 65, 68, 69,
80, 81, 84, 85,
256, 257, 260, 261,
272, 273, 276, 277,
320, 321, 324, 325,
336, 337, 340, 341
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
TextureProxy::ArrangeMegatextures(ArrangeMegatexturesProcess *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)
&& mega_size.x == mega_size.y
);
TextureLibrary *library = GetTextureLibrary();
Check_Object(library);
//
//-------------------------------
// Create the various size arrays
//-------------------------------
//
Vector2DOf<int> cells(mega_size.x>>4, mega_size.y>>4);
DynamicArrayOf<bool> used(false, cells.x*cells.y);
//
//-------------------------------------------------
// Tell the application if the megatexture is empty
//-------------------------------------------------
//
Page *texture_page = mega_file->FindPage(mega_name);
ChainOf<Note*> *textures = NULL;
int texture_count = 0;
if (texture_page)
{
textures = texture_page->MakeNoteChain("Texture");
Register_Object(textures);
Page::NoteIterator texture_itr(textures);
texture_count = texture_itr.GetSize();
}
if (!texture_count)
{
process->ProcessCallback(
ArrangeMegatexturesProcess::EmptyMegatexture,
mega_name,
NULL
);
if (!process->continueProcess)
{
Unwind_1:
if (textures)
{
Unregister_Object(textures);
delete textures;
}
return;
#undef UNWIND
#define UNWIND() goto Unwind_1
}
}
//
//----------------------------------------------------------------------
// Now start stepping through the entries for the page and skip the page
// size entry
//----------------------------------------------------------------------
//
DynamicArrayOf<Vector2DOf<int> >
offsets(texture_count),
sizes(texture_count);
DynamicArrayOf<TextureProxy*>
proxies(texture_count);
int errors = 0;
texture_count = -1;
Page::NoteIterator texture_itr(textures);
Note *entry;
while ((entry = texture_itr.ReadAndNext()) != NULL)
{
Check_Object(entry);
++texture_count;
Verify(texture_count >= 0);
//
//--------------------------------------------
// Extract the texture data from the tron file
//--------------------------------------------
//
const char* data;
entry->GetEntry(&data);
Check_Pointer(data);
char texture_name[80];
int param_count = sscanf(data, "%s", texture_name);
if (param_count != 1 || !strlen(texture_name))
{
process->ProcessCallback(
ArrangeMegatexturesProcess::BadTextureLine,
mega_name,
texture_name
);
if (!process->continueProcess)
UNWIND();
else
{
++errors;
continue;
}
}
//
//--------------------------
// Do the status check again
//--------------------------
//
process->ProcessCallback(
ArrangeMegatexturesProcess::StatusCheck,
mega_name,
texture_name
);
if (!process->continueProcess)
UNWIND();
//
//-----------------------------------------------------------------
// We now have a texture name, so get the actual texture proxy from
// the library
//-----------------------------------------------------------------
//
proxies[texture_count] = library->UseTextureProxy(texture_name);
Check_Object(proxies[texture_count]);
//
//---------------------------
// Make sure the size is good
//---------------------------
//
proxies[texture_count]->GetImageSize(&sizes[texture_count]);
if (!sizes[texture_count].x && !sizes[texture_count].y)
{
process->ProcessCallback(
ArrangeMegatexturesProcess::BadTexture,
mega_name,
texture_name
);
if (!process->continueProcess)
{
Unwind_2:
for (int i=0; i<=texture_count; ++i)
proxies[i]->DetachReference();
UNWIND();
#undef UNWIND
#define UNWIND() goto Unwind_2
}
else
{
++errors;
continue;
}
}
Verify(
sizes[texture_count].x >= 16 && sizes[texture_count].x <= 512
&& sizes[texture_count].y >= 16 && sizes[texture_count].y <= 512
&& sizes[texture_count].x == (sizes[texture_count].x & -sizes[texture_count].x)
&& sizes[texture_count].y == (sizes[texture_count].y & -sizes[texture_count].y)
);
//
//------------------------------------------------------------------------
// Find the parameters for the search, which is based upon an interleaving
// scheme using a bit-wise mix of the x and y index values
//------------------------------------------------------------------------
//
Vector2DOf<int>
units(sizes[texture_count].x>>4, sizes[texture_count].y>>4);
Verify(units.x>0 && units.y>0);
int
increment,
run,
scale;
if (units.x < units.y)
{
run = units.y / units.x;
scale = units.x*units.x;
increment = scale * run*run;
}
else
{
run = units.x / units.y;
scale = units.y*units.y;
increment = scale * run*run;
scale *= 2;
}
//
//--------------------------------------------------------------------
// We search the array associated with the step, looking for the first
// empty slot that matches
//--------------------------------------------------------------------
//
int index;
int i;
for (index=0; index<used.GetLength(); index += increment)
{
for (i=0; i<run; ++i)
{
int sub_index = scale*Offsets[i];
if (!used[index + sub_index])
{
index += sub_index;
break;
}
}
if (i!=run)
break;
}
//
//-----------------------------------------------------
// If we don't find any empty slots, do the error thing
//-----------------------------------------------------
//
if (index == used.GetLength())
{
process->ProcessCallback(
ArrangeMegatexturesProcess::NotEnoughRoom,
mega_name,
texture_name
);
if (!process->continueProcess)
UNWIND();
else
{
++errors;
continue;
}
}
//
//--------------------
// Mark the used cells
//--------------------
//
int x,y;
for (y=0; y<units.y; ++y)
for (x=0; x<units.x; ++x)
{
Verify(!used[index + Offsets[y]*2 + Offsets[x]]);
used[index + Offsets[y]*2 + Offsets[x]] = true;
}
//
//----------------------------------------
// Extract the x,y location from the index
//----------------------------------------
//
int mask=1;
x = y = 0;
while (index)
{
if (index&1)
x |= mask;
index >>= 1;
if (index&1)
y |= mask;
index >>= 1;
mask <<= 1;
}
offsets[texture_count].x = x<<4;
offsets[texture_count].y = y<<4;
}
#undef UNWIND
#define UNWIND() goto Unwind_1
//
//------------------------------------------------------------------------
// If we don't have any errors, go ahead and save our data back out to the
// notation file. We first will have to erase the old texture entries
//------------------------------------------------------------------------
//
if (!errors)
{
Note* dummy;
texture_itr.First();
while ((dummy = texture_itr.ReadAndNext()) != NULL)
texture_page->DeleteNote(dummy->GetName());
int i;
for (i=0; i<=texture_count; ++i)
{
char buffer[80];
MString texture_name;
Check_Object(proxies[i]);
proxies[i]->GetName(&texture_name);
sprintf(
buffer,
"%s %d %d %d %d",
static_cast<const char*>(texture_name),
offsets[i].x,
offsets[i].y,
sizes[i].x,
sizes[i].y
);
texture_page->AppendEntry("Texture", buffer);
}
//
//-----------------------------------------------
// Now tell the debug stream about the space left
//-----------------------------------------------
//
DynamicArrayOf<int> room(5);
int total=0;
for (i=0; i<5; ++i)
{
total <<= 2;
int shift = 8 - 2*i;
int range = 4 << (2*i);
int count=0;
for (int j=0; j<range; ++j)
if (!used[j<<shift])
++count;
room[i] = count - total;
total = count;
}
if (total)
{
SPEW(("ArrangeMegatextures", "\n[%s] has room for:", mega_name));
for (i=0; i<5; ++i)
{
if (room[i])
SPEW((
"ArrangeMegatextures",
"\t%d %dx%d textures",
room[i],
256 >> i,
256 >> i
));
}
}
}
//
//---------
// Clean up
//---------
//
for (int i=0; i<=texture_count; ++i)
proxies[i]->DetachReference();
UNWIND();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
TextureLibrary::ArrangeMegatextures(ArrangeMegatexturesProcess *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();
Register_Object(pages);
Page *page;
while ((page = pages->ReadAndNext()) != NULL)
{
const char* mega_name = page->GetName();
Check_Pointer(mega_name);
process->ProcessCallback(
ArrangeMegatexturesProcess::StatusCheck,
mega_name,
NULL
);
if (!process->continueProcess)
break;
//
//----------------------------------------------------------------------
// 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(
ArrangeMegatexturesProcess::BadPageSize,
mega_name,
NULL
);
if (!process->continueProcess)
break;
else
continue;
}
//
//---------------------------------------------------
// Create the megatexture proxy run the process on it
//---------------------------------------------------
//
TextureProxy *mega_texture =
TextureProxy::MakeProxy(mega_name, mega_size, this);
Register_Object(mega_texture);
mega_texture->ArrangeMegatextures(process);
mega_texture->DetachReference();
//
//---------
// Clean up
//---------
//
if (!process->continueProcess)
break;
}
//
//-----------------------
// Clean up the page list
//-----------------------
//
Unregister_Object(pages);
delete pages;
}