#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 *plug = new PlugOf(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 polygons; unsigned polygon_count = UsePolygonArray(&polygons); if (!polygon_count) return; DynamicArrayOf states; DynamicArrayOf index; DynamicArrayOf 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_loopUseTextureProxy(); if (!texture) { Unwind_1: DetachArrayReferences(&states); DetachArrayReferences(&polygons); return; #undef UNWIND #define UNWIND() goto Unwind_1 } MString name; texture->GetName(&name); Vector2DOf 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 *string; Vector2DOf 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 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 pixel_size(1.0f/mega_size.x, 1.0f/mega_size.y), pixel_count( static_cast(texture_size.x), static_cast(texture_size.y) ); // //-------------------------------------------------------------------- // Get the array of vertices, then go through each one and set the UVs // according to the coalesced values //-------------------------------------------------------------------- // DynamicArrayOf vertices; unsigned vertex_count = UseVertexArray(&vertices); for (unsigned i=0; i > 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; iUseNextSiblingProxy(); 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(); }