#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 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 cells(mega_size.x>>4, mega_size.y>>4); DynamicArrayOf used(false, cells.x*cells.y); // //------------------------------------------------- // Tell the application if the megatexture is empty //------------------------------------------------- // Page *texture_page = mega_file->FindPage(mega_name); ChainOf *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 > offsets(texture_count), sizes(texture_count); DynamicArrayOf 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 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; indexProcessCallback( ArrangeMegatexturesProcess::NotEnoughRoom, mega_name, texture_name ); if (!process->continueProcess) UNWIND(); else { ++errors; continue; } } // //-------------------- // Mark the used cells //-------------------- // int x,y; for (y=0; y>= 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(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 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> 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 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; }