Files
firestorm/Gameleap/code/mw4/Tools/Max43DSPlugins/Proxies/CoalesceTextures.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

409 lines
12 KiB
C++

#include "ProxyHeaders.hpp"
typedef int (*LPERROR_CALLBACKFN)(char *,bool);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
CoalesceTexturesProcess::CoalesceTexturesProcess(
Stuff::NotationFile *megatexture_file,
const char *megatexture_list,
bool bSuppress,
void* fcn
) :
Process(NULL,bSuppress,fcn),
megatextureFile(megatexture_file)
{
if (megatexture_list)
{
megatextureList = MakeMegatextureChain(megatexture_list);
Register_Object(megatextureList);
Check_Object(megatextureFile);
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
CoalesceTexturesProcess::CoalesceTexturesProcess(
Stuff::NotationFile *megatexture_file,
const char *megatexture_list,
Stuff::NotationFile *config_file,
bool bSuppress,
void* fcn
):
Process(config_file,bSuppress,fcn),
megatextureFile(megatexture_file)
{
if (megatexture_list)
{
megatextureList = MakeMegatextureChain(megatexture_list);
Register_Object(megatextureList);
Check_Object(megatextureFile);
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
CoalesceTexturesProcess::~CoalesceTexturesProcess()
{
if (megatextureList)
{
MStringChainIterator iterator(megatextureList);
iterator.DeletePlugs();
Unregister_Object(megatextureList);
delete megatextureList;
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MStringChain*
CoalesceTexturesProcess::MakeMegatextureChain(const char* list)
{
Check_Pointer(list);
//
//--------------------------------------------
// If the string is empty, don't make anything
//--------------------------------------------
//
MStringChain *chain = NULL;
const char* begin = list;
do
{
//
//-------------------------------------------------------------------
// If we can't find a comma, the remainder of the string is the token
//-------------------------------------------------------------------
//
const char* end = strchr(begin, ',');
MString token = begin;
if (!end)
begin = NULL;
//
//------------------------------------------------------
// Otherwise, clip the token to where we found the comma
//------------------------------------------------------
//
else
{
int len = end - begin;
token[len] = '\0';
begin = end;
while (*begin == ',')
++begin;
if (!*begin)
begin = NULL;
}
//
//----------------------------
// Put this token in the chain
//----------------------------
//
if (!chain)
chain = new MStringChain(NULL);
PlugOf<MString> *plug = new PlugOf<MString>(token);
Register_Object(plug);
chain->Add(plug);
//
//----------------------------------
// Skip to the next token until done
//----------------------------------
//
} while (begin);
return chain;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
PolygonMeshProxy::CoalesceTextures(CoalesceTexturesProcess *process)
{
Check_Object(this);
Check_Object(process);
//
//------------------------------------------------------------
// Make sure that the process says its OK to check the texture
//------------------------------------------------------------
//
process->CoalesceTexturesCallback(this);
if (!process->continueProcess)
return;
//
//--------------------------------------
// See if this will be a trivial process
//--------------------------------------
//
if (!process->megatextureList)
return;
Check_Object(process->megatextureFile);
Check_Object(process->megatextureFile);
//
//------------------------------------------------------------------------
// Get the state arrays for this mesh and make sure that they have already
// been split
//------------------------------------------------------------------------
//
DynamicArrayOf<PolygonProxy*> polygons;
unsigned polygon_count = UsePolygonArray(&polygons);
if (!polygon_count)
return;
DynamicArrayOf<MultiState*> states;
DynamicArrayOf<unsigned> index;
DynamicArrayOf<unsigned> count;
#if defined(_ARMOR)
unsigned unique_states =
#endif
UseMultiStateArray(&states, &index, &count, polygons);
Verify(unique_states==1 && count[0]==polygon_count);
//
//----------------------------------------------------------------------
// If this mesh is not textured, we can just return. Otherwise, get the
// texture name
//----------------------------------------------------------------------
//
Check_Object(states[0]);
unsigned state_count = states[0]->GetLength();
for(unsigned state_loop=0;state_loop<state_count;++state_loop)
{
TextureProxy *texture = (*states[0])[state_loop]->UseTextureProxy();
if (!texture)
{
Unwind_1:
DetachArrayReferences(&states);
DetachArrayReferences(&polygons);
return;
#undef UNWIND
#define UNWIND() goto Unwind_1
}
MString name;
texture->GetName(&name);
Vector2DOf<int> texture_size;
texture->GetImageSize(&texture_size);
texture->DetachReference();
//
//------------------------------------------------------------------------
// Look through each of the listed megatextures to try and find where this
// texture should be rerouted
//------------------------------------------------------------------------
//
MStringChainIterator megatextures(process->megatextureList);
PlugOf<MString> *string;
Vector2DOf<Scalar> offset;
offset.x = offset.y = 0.0f;
const char* mega_name = NULL;
while ((string = megatextures.ReadAndNext()) != NULL)
{
mega_name = string->GetItem();
Check_Pointer(mega_name);
const char *offset_string;
Page *page = process->megatextureFile->FindPage(mega_name);
if (page)
{
if (page->GetEntry(name, &offset_string))
{
Check_Pointer(offset_string);
#if defined(_ARMOR)
int count =
#endif
sscanf(offset_string, "%f %f", &offset.x, &offset.y);
Verify(count == 2);
break;
}
}
// Look for alias
page = process->megatextureFile->FindPage(name);
if (page)
{
const char *alias_name;
if (page->GetEntry("alias",&alias_name))
{
page = process->megatextureFile->FindPage(alias_name);
if (page)
{
if (page->GetEntry(name, &offset_string))
{
Check_Pointer(offset_string);
#if defined(_ARMOR)
int count =
#endif
sscanf(offset_string, "%f %f", &offset.x, &offset.y);
Verify(count == 2);
break;
}
}
}
}
}
//
//-----------------------------------------------------------------------
// If no megatexture has this texture in its entries, this texture should
// be left alone
//-----------------------------------------------------------------------
//
if (!string)
UNWIND();
//
//-----------------------------------------------------------------------
// Now, get the megatexture from the library. If it isn't already there,
// an empty one will be created
//-----------------------------------------------------------------------
//
SceneProxy *scene = GetSceneProxy();
Check_Object(scene);
StateLibrary *state_library = scene->GetStateLibrary();
Check_Object(state_library);
TextureLibrary *textures = state_library->GetTextureLibrary();
Check_Object(textures);
TextureProxy *mega_texture = textures->UseTextureProxy(mega_name);
//
//----------------------------------------
// Read the size from the megatexture page
//----------------------------------------
//
const char* size_string;
Page *page = process->megatextureFile->GetPage(mega_name);
Check_Object(page);
page->GetEntry("PageSize", &size_string);
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 == 2);
//
//---------------------------------------------
// Compute the new scale and offset for our uvs
//---------------------------------------------
//
Vector2DOf<Scalar>
pixel_size(1.0f/mega_size.x, 1.0f/mega_size.y),
pixel_count(
static_cast<Scalar>(texture_size.x),
static_cast<Scalar>(texture_size.y)
);
//
//--------------------------------------------------------------------
// Get the array of vertices, then go through each one and set the UVs
// according to the coalesced values
//--------------------------------------------------------------------
//
DynamicArrayOf<VertexProxy*> vertices;
unsigned vertex_count = UseVertexArray(&vertices);
for (unsigned i=0; i<vertex_count; ++i)
{
Check_Object(vertices[i]);
DynamicArrayOf<Vector2DOf<Scalar> > uv;
vertices[i]->GetUVs(&uv);
uv[state_loop].x = (uv[state_loop].x*pixel_count.x + offset.x) * pixel_size.x;
uv[state_loop].y = (uv[state_loop].y*pixel_count.y + offset.y) * pixel_size.y;
vertices[i]->SetUVs(uv);
// If uv are wrapped for more than 4 pixels
if (uv[state_loop].x < -4.0/texture_size.x || uv[state_loop].x > 1+4.0/texture_size.x ||
uv[state_loop].y < -4.0/texture_size.y || uv[state_loop].y > 1+4.0/texture_size.y )
{
if (process->errorfn)
{
char buffer[200];
sprintf(buffer, "CoalesceTextures: %s has UV's wrapped (%f %f)!", (char*)name, uv[state_loop].x, uv[state_loop].y);
LPERROR_CALLBACKFN fcn = (LPERROR_CALLBACKFN)process->errorfn;
fcn(buffer,process->suppress);
}
}
}
DetachArrayReferences(&vertices);
//
//--------------------------------------------------------------------
// Now change the states of the polygons so that they point at the new
// megatextures
//--------------------------------------------------------------------
//
(*states[0])[state_loop]->SetToMatchTextureProxy(mega_texture);
//
//---------
// Clean up
//---------
//
mega_texture->DetachReference();
DetachArrayReferences(&polygons);
}
SetToMatchMultiState(states[0]);
DetachArrayReferences(&states);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
SceneProxy::CoalesceTextures(CoalesceTexturesProcess *process)
{
Check_Object(this);
Check_Object(process);
//
//---------------------------------------
// Make sure that the process says its OK
//---------------------------------------
//
process->CoalesceTexturesCallback(this);
if (!process->continueProcess)
return;
//
//--------------------------------------
// See if this will be a trivial process
//--------------------------------------
//
if (!process->megatextureList)
return;
//
//------------------------------------------------------------------
// Coalesce the children. At this point, they must all be flattened
//------------------------------------------------------------------
//
unsigned child_count = GetChildCount();
ChildProxy *child = UseFirstChildProxy();
for (unsigned i=0; i<child_count; ++i)
{
Check_Object(child);
ChildProxy *next = child->UseNextSiblingProxy();
PolygonMeshProxy *mesh = Cast_Object(PolygonMeshProxy*, child);
mesh->CoalesceTextures(process);
child->DetachReference();
child = next;
if (!process->continueProcess)
{
if (child)
child->DetachReference();
break;
}
}
//
//-------------------------------------------
// Make sure to discard any remaining proxies
//-------------------------------------------
//
if (child)
child->DetachReference();
}