//--------------------------------------------------------------------- // // // This class will manage the texture memory provided by GOS // GOS gives me a maximum of 256 256x256 pixel texture pages. // I want GOS to think I only use 256x256 textures. This class // will insure that GOS believes that completely and provided // smaller texture surfaces out of the main surface if necessary // as well as returning the necessary UVs to get to the other surface. // //---------------------------------------------------------------------------// // Copyright (C) Microsoft Corporation. All rights reserved. // //===========================================================================// #ifndef TXMMGR_H #include "txmmgr.h" #endif #ifndef TGAINFO_H #include "tgainfo.h" #endif #ifndef FILE_H #include "file.h" #endif #ifndef TIMING_H #include "timing.h" #endif #ifndef CAMERA_H #include "camera.h" #endif #ifndef LZ_H #include "lz.h" #endif #ifndef CIDENT_H #include "cident.h" #endif #ifndef PATHS_H #include "paths.h" #endif #include #include #include //--------------------------------------------------------------------------- // static globals MC_TextureManager *mcTextureManager = NULL; gos_VERTEXManager *MC_TextureManager::gvManager = NULL; MemoryPtr MC_TextureManager::lzBuffer1 = NULL; MemoryPtr MC_TextureManager::lzBuffer2 = NULL; int MC_TextureManager::iBufferRefCount = 0; bool MLRVertexLimitReached = false; extern bool useFog; DWORD actualTextureSize = 0; DWORD compressedTextureSize = 0; #define MAX_SENDDOWN 10002 //------------------------------------------------------ // Frees up gos_VERTEX manager memory void MC_TextureManager::freeVertices (void) { if (gvManager) { gvManager->destroy(); delete gvManager; gvManager = NULL; } } //------------------------------------------------------ // Creates gos_VERTEX Manager and allocates RAM. Will not allocate if already done! void MC_TextureManager::startVertices (long maxVertices) { if (gvManager == NULL) { gvManager = new gos_VERTEXManager; gvManager->init(maxVertices); gvManager->reset(); } } //---------------------------------------------------------------------- // Class MC_TextureManager void MC_TextureManager::start (void) { init(); //------------------------------------------ // Create nodes from systemHeap. long nodeRAM = MC_MAXTEXTURES * sizeof(MC_TextureNode); masterTextureNodes = (MC_TextureNode *)systemHeap->Malloc(nodeRAM); gosASSERT(masterTextureNodes != NULL); for (long i=0;iMalloc(nodeRAM); gosASSERT(masterVertexNodes != NULL); memset(masterVertexNodes,0,nodeRAM); textureCacheHeap = new UserHeap; textureCacheHeap->init(TEXTURE_CACHE_SIZE,"TXMCache"); textureCacheHeap->setMallocFatals(false); textureStringHeap = new UserHeap; textureStringHeap->init(512000,"TXMString"); if (!textureManagerInstrumented) { StatisticFormat( "" ); StatisticFormat( "MechCommander 2 Texture Manager" ); StatisticFormat( "===============================" ); StatisticFormat( "" ); AddStatistic("Handles Used","Handles",gos_DWORD, &(currentUsedTextures), Stat_Total); AddStatistic("Cache Misses","",gos_DWORD, &(totalCacheMisses), Stat_Total); StatisticFormat( "" ); StatisticFormat( "" ); textureManagerInstrumented = true; } indexArray = (WORD *)systemHeap->Malloc(sizeof(WORD) * MC_MAXFACES); for (i=0;iFree(masterTextureNodes); masterTextureNodes = NULL; systemHeap->Free(masterVertexNodes); masterVertexNodes = NULL; delete textureCacheHeap; textureCacheHeap = NULL; delete textureStringHeap; textureStringHeap = NULL; } //---------------------------------------------------------------------- MC_TextureManager::~MC_TextureManager (void) { MC_TextureManager::iBufferRefCount--; if (0 == MC_TextureManager::iBufferRefCount) { if (lzBuffer1) { gosASSERT(lzBuffer2 != NULL); if (textureCacheHeap) { textureCacheHeap->Free(lzBuffer1); textureCacheHeap->Free(lzBuffer2); } lzBuffer1 = NULL; lzBuffer2 = NULL; } } destroy(); } //---------------------------------------------------------------------- void MC_TextureManager::flush (bool justTextures) { if (masterTextureNodes) { //----------------------------------------------------- // Traverses list of texture nodes and frees each one. long usedCount = 0; for (long i=0;iMalloc(effectsSize); effectFile.read(effectsData,effectsSize); effectFile.close(); effectStream = new Stuff::MemoryStream(effectsData,effectsSize); gosFX::EffectLibrary::Instance->Load(effectStream); gosFX::LightManager::Instance = new gosFX::LightManager(); gos_PopCurrentHeap(); systemHeap->Free(effectsData); } //---------------------------------------------------------------------- void MC_TextureManager::removeTextureNode (DWORD textureNode) { if (textureNode != 0xffffffff) { //----------------------------------------------------------- masterTextureNodes[textureNode].destroy(); if (masterTextureNodes[textureNode].textureData) { textureCacheHeap->Free(masterTextureNodes[textureNode].textureData); masterTextureNodes[textureNode].textureData = NULL; if (masterTextureNodes[textureNode].nodeName) { textureStringHeap->Free(masterTextureNodes[textureNode].nodeName); masterTextureNodes[textureNode].nodeName = NULL; } } } } //---------------------------------------------------------------------- void MC_TextureManager::removeTexture (DWORD gosHandle) { //----------------------------------------------------------- for (long i=0;iFree(masterTextureNodes[i].textureData); masterTextureNodes[i].textureData = NULL; if (masterTextureNodes[i].nodeName) { textureStringHeap->Free(masterTextureNodes[i].nodeName); masterTextureNodes[i].nodeName = NULL; } } } } #define cache_Threshold 150 //---------------------------------------------------------------------- bool MC_TextureManager::flushCache (void) { bool cacheNotFull = false; totalCacheMisses++; currentUsedTextures = 0; //Count ACTUAL number of textures being used. // ALSO can't count on turn being right. Logistics does not update unless simple Camera is up!! for (long i=0;ifogColor; //----------------------------------------------------- // FOG time. Set Render state to FOG on! if (useFog) { gos_SetRenderState( gos_State_Fog, (int)&fogColor); } else { gos_SetRenderState( gos_State_Fog, 0); } for (long i=0;i MAX_SENDDOWN) { gos_SetRenderState( gos_State_Texture, masterTextureNodes[masterVertexNodes[i].textureIndex].get_gosTextureHandle()); //Must divide up vertices into batches of 10,000 each to send down. // Somewhere around 20000 to 30000 it really gets screwy!!! long currentVertices = 0; while (currentVertices < totalVertices) { gos_VERTEX *v = masterVertexNodes[i].vertices + currentVertices; long tVertices = totalVertices - currentVertices; if (tVertices > MAX_SENDDOWN) tVertices = MAX_SENDDOWN; gos_RenderIndexedArray(v, tVertices, indexArray, tVertices ); currentVertices += tVertices; } } //Reset the list to zero length to avoid drawing more then once! //Also comes in handy if gameLogic is not called. masterVertexNodes[i].currentVertex = masterVertexNodes[i].vertices; } } if (Environment.Renderer == 3) { //Do NOT draw the water as transparent in software gos_SetRenderState( gos_State_TextureAddress, gos_TextureWrap ); } else { gos_SetRenderState( gos_State_AlphaMode, gos_Alpha_AlphaInvAlpha); gos_SetRenderState( gos_State_AlphaTest, 1); gos_SetRenderState( gos_State_TextureAddress, gos_TextureWrap ); } for (i=0;i MAX_SENDDOWN) { gos_SetRenderState( gos_State_Texture, masterTextureNodes[masterVertexNodes[i].textureIndex].get_gosTextureHandle()); //Must divide up vertices into batches of 10,000 each to send down. // Somewhere around 20000 to 30000 it really gets screwy!!! long currentVertices = 0; while (currentVertices < totalVertices) { gos_VERTEX *v = masterVertexNodes[i].vertices + currentVertices; long tVertices = totalVertices - currentVertices; if (tVertices > MAX_SENDDOWN) tVertices = MAX_SENDDOWN; gos_RenderIndexedArray(v, tVertices, indexArray, tVertices ); currentVertices += tVertices; } } //Reset the list to zero length to avoid drawing more then once! //Also comes in handy if gameLogic is not called. masterVertexNodes[i].currentVertex = masterVertexNodes[i].vertices; } } if (Environment.Renderer == 3) { gos_SetRenderState( gos_State_AlphaMode, gos_Alpha_AlphaInvAlpha); gos_SetRenderState( gos_State_AlphaTest, 1); gos_SetRenderState( gos_State_ShadeMode, gos_ShadeFlat); } gos_SetRenderState( gos_State_TextureAddress, gos_TextureClamp ); gos_SetRenderState( gos_State_ZWrite, 0); gos_SetRenderState( gos_State_ShadeMode, gos_ShadeFlat); //Draw the Craters after the detail textures on the terrain. There should never be anything here in the OLD universe. // DO NOT draw craters or footprints in software if (Environment.Renderer != 3) { for (i=0;i MAX_SENDDOWN) { gos_SetRenderState( gos_State_Texture, masterTextureNodes[masterVertexNodes[i].textureIndex].get_gosTextureHandle()); //Must divide up vertices into batches of 10,000 each to send down. // Somewhere around 20000 to 30000 it really gets screwy!!! long currentVertices = 0; while (currentVertices < totalVertices) { gos_VERTEX *v = masterVertexNodes[i].vertices + currentVertices; long tVertices = totalVertices - currentVertices; if (tVertices > MAX_SENDDOWN) tVertices = MAX_SENDDOWN; gos_RenderIndexedArray(v, tVertices, indexArray, tVertices ); currentVertices += tVertices; } } //Reset the list to zero length to avoid drawing more then once! //Also comes in handy if gameLogic is not called. masterVertexNodes[i].currentVertex = masterVertexNodes[i].vertices; } } } if (Environment.Renderer != 3) { gos_SetRenderState( gos_State_ShadeMode, gos_ShadeGouraud); gos_SetRenderState( gos_State_ZWrite, 1); } //Draw the Overlays after the detail textures on the terrain. There should never be anything here in the OLD universe. for (i=0;i MAX_SENDDOWN) { gos_SetRenderState( gos_State_Texture, masterTextureNodes[masterVertexNodes[i].textureIndex].get_gosTextureHandle()); //Must divide up vertices into batches of 10,000 each to send down. // Somewhere around 20000 to 30000 it really gets screwy!!! long currentVertices = 0; while (currentVertices < totalVertices) { gos_VERTEX *v = masterVertexNodes[i].vertices + currentVertices; long tVertices = totalVertices - currentVertices; if (tVertices > MAX_SENDDOWN) tVertices = MAX_SENDDOWN; gos_RenderIndexedArray(v, tVertices, indexArray, tVertices ); currentVertices += tVertices; } } //Reset the list to zero length to avoid drawing more then once! //Also comes in handy if gameLogic is not called. masterVertexNodes[i].currentVertex = masterVertexNodes[i].vertices; } } if (Environment.Renderer == 3) { gos_SetRenderState( gos_State_TextureAddress, gos_TextureWrap ); gos_SetRenderState( gos_State_ShadeMode, gos_ShadeFlat); gos_SetRenderState( gos_State_ZWrite, 1); gos_SetRenderState( gos_State_ZCompare, 2); } else { gos_SetRenderState( gos_State_TextureAddress, gos_TextureWrap ); gos_SetRenderState( gos_State_ShadeMode, gos_ShadeFlat); gos_SetRenderState( gos_State_MonoEnable, 1); gos_SetRenderState( gos_State_Perspective, 0); gos_SetRenderState( gos_State_Specular, 1); gos_SetRenderState( gos_State_ZWrite, 1); gos_SetRenderState( gos_State_ZCompare, 2); } //NEVER draw shadows in Software. if (Environment.Renderer != 3) { for (i=0;i MAX_SENDDOWN) { gos_SetRenderState( gos_State_Texture, masterTextureNodes[masterVertexNodes[i].textureIndex].get_gosTextureHandle()); //Must divide up vertices into batches of 10,000 each to send down. // Somewhere around 20000 to 30000 it really gets screwy!!! long currentVertices = 0; while (currentVertices < totalVertices) { gos_VERTEX *v = masterVertexNodes[i].vertices + currentVertices; long tVertices = totalVertices - currentVertices; if (tVertices > MAX_SENDDOWN) tVertices = MAX_SENDDOWN; gos_RenderIndexedArray(v, tVertices, indexArray, tVertices ); currentVertices += tVertices; } } //Reset the list to zero length to avoid drawing more then once! //Also comes in handy if gameLogic is not called. masterVertexNodes[i].currentVertex = masterVertexNodes[i].vertices; } } } gos_SetRenderState( gos_State_ZCompare, 1); if (Environment.Renderer != 3) { gos_SetRenderState( gos_State_ShadeMode, gos_ShadeGouraud); gos_SetRenderState( gos_State_ZWrite, 1); } for (i=0;i MAX_SENDDOWN) { gos_SetRenderState( gos_State_Texture, masterTextureNodes[masterVertexNodes[i].textureIndex].get_gosTextureHandle()); //Must divide up vertices into batches of 10,000 each to send down. // Somewhere around 20000 to 30000 it really gets screwy!!! long currentVertices = 0; while (currentVertices < totalVertices) { gos_VERTEX *v = masterVertexNodes[i].vertices + currentVertices; long tVertices = totalVertices - currentVertices; if (tVertices > MAX_SENDDOWN) tVertices = MAX_SENDDOWN; gos_RenderIndexedArray(v, tVertices, indexArray, tVertices ); currentVertices += tVertices; } } //Reset the list to zero length to avoid drawing more then once! //Also comes in handy if gameLogic is not called. masterVertexNodes[i].currentVertex = masterVertexNodes[i].vertices; } } if (Environment.Renderer == 3) { gos_SetRenderState( gos_State_ShadeMode, gos_ShadeGouraud); gos_SetRenderState( gos_State_ZCompare, 1); gos_SetRenderState( gos_State_Fog, 0); gos_SetRenderState( gos_State_AlphaMode, gos_Alpha_OneOne); gos_SetRenderState( gos_State_TextureMapBlend, gos_BlendModulateAlpha); gos_SetRenderState( gos_State_ZWrite, 0); gos_SetRenderState( gos_State_MonoEnable, 1); } else { gos_SetRenderState( gos_State_ShadeMode, gos_ShadeGouraud); gos_SetRenderState( gos_State_Perspective, 1); gos_SetRenderState( gos_State_ZCompare, 1); gos_SetRenderState( gos_State_Fog, 0); gos_SetRenderState( gos_State_Specular, 0); gos_SetRenderState( gos_State_AlphaMode, gos_Alpha_OneOne); gos_SetRenderState( gos_State_TextureMapBlend, gos_BlendModulateAlpha); gos_SetRenderState( gos_State_ZWrite, 0); gos_SetRenderState( gos_State_MonoEnable, 0); } for (i=0;i MAX_SENDDOWN) { gos_SetRenderState( gos_State_Texture, masterTextureNodes[masterVertexNodes[i].textureIndex].get_gosTextureHandle()); //Must divide up vertices into batches of 10,000 each to send down. // Somewhere around 20000 to 30000 it really gets screwy!!! long currentVertices = 0; while (currentVertices < totalVertices) { gos_VERTEX *v = masterVertexNodes[i].vertices + currentVertices; long tVertices = totalVertices - currentVertices; if (tVertices > MAX_SENDDOWN) tVertices = MAX_SENDDOWN; gos_RenderIndexedArray(v, tVertices, indexArray, tVertices ); currentVertices += tVertices; } } //Reset the list to zero length to avoid drawing more then once! //Also comes in handy if gameLogic is not called. masterVertexNodes[i].currentVertex = masterVertexNodes[i].vertices; } } gos_SetRenderState( gos_State_ZWrite, 1); for (i=0;i MAX_SENDDOWN) { gos_SetRenderState( gos_State_Texture, masterTextureNodes[masterVertexNodes[i].textureIndex].get_gosTextureHandle()); //Must divide up vertices into batches of 10,000 each to send down. // Somewhere around 20000 to 30000 it really gets screwy!!! long currentVertices = 0; while (currentVertices < totalVertices) { gos_VERTEX *v = masterVertexNodes[i].vertices + currentVertices; long tVertices = totalVertices - currentVertices; if (tVertices > MAX_SENDDOWN) tVertices = MAX_SENDDOWN; gos_RenderIndexedArray(v, tVertices, indexArray, tVertices ); currentVertices += tVertices; } } //Reset the list to zero length to avoid drawing more then once! //Also comes in handy if gameLogic is not called. masterVertexNodes[i].currentVertex = masterVertexNodes[i].vertices; } } gos_SetRenderState( gos_State_ZWrite, 0); gos_SetRenderState( gos_State_ZCompare, 0); gos_SetRenderState( gos_State_Perspective, 1); gos_SetRenderState( gos_State_AlphaMode, gos_Alpha_AlphaInvAlpha); gos_SetRenderState( gos_State_AlphaTest, 1); for (i=0;i MAX_SENDDOWN) { gos_SetRenderState( gos_State_Texture, masterTextureNodes[masterVertexNodes[i].textureIndex].get_gosTextureHandle()); //Must divide up vertices into batches of 10,000 each to send down. // Somewhere around 20000 to 30000 it really gets screwy!!! long currentVertices = 0; while (currentVertices < totalVertices) { gos_VERTEX *v = masterVertexNodes[i].vertices + currentVertices; long tVertices = totalVertices - currentVertices; if (tVertices > MAX_SENDDOWN) tVertices = MAX_SENDDOWN; gos_RenderIndexedArray(v, tVertices, indexArray, tVertices ); currentVertices += tVertices; } } //Reset the list to zero length to avoid drawing more then once! //Also comes in handy if gameLogic is not called. masterVertexNodes[i].currentVertex = masterVertexNodes[i].vertices; } } gos_SetRenderState( gos_State_Filter, gos_FilterNone); for (i=0;i MAX_SENDDOWN) { gos_SetRenderState( gos_State_Texture, masterTextureNodes[masterVertexNodes[i].textureIndex].get_gosTextureHandle()); //Must divide up vertices into batches of 10,000 each to send down. // Somewhere around 20000 to 30000 it really gets screwy!!! long currentVertices = 0; while (currentVertices < totalVertices) { gos_VERTEX *v = masterVertexNodes[i].vertices + currentVertices; long tVertices = totalVertices - currentVertices; if (tVertices > MAX_SENDDOWN) tVertices = MAX_SENDDOWN; gos_RenderIndexedArray(v, tVertices, indexArray, tVertices ); currentVertices += tVertices; } } //Reset the list to zero length to avoid drawing more then once! //Also comes in handy if gameLogic is not called. masterVertexNodes[i].currentVertex = masterVertexNodes[i].vertices; } } //Must turn zCompare back on for FXs gos_SetRenderState( gos_State_ZCompare, 1 ); } //---------------------------------------------------------------------- DWORD MC_TextureManager::update (void) { DWORD numTexturesFreed = 0; currentUsedTextures = 0; for (long i=0;iMalloc(MAX_LZ_BUFFER_SIZE); gosASSERT(lzBuffer1 != NULL); lzBuffer2 = (MemoryPtr)textureCacheHeap->Malloc(MAX_LZ_BUFFER_SIZE); gosASSERT(lzBuffer2 != NULL); } actualTextureSize += txmSize; DWORD txmCompressSize = LZCompress(lzBuffer2,(MemoryPtr)data,txmSize); compressedTextureSize += txmCompressSize; //------------------------------------------------------- // Create a block of cache memory to hold this texture. if (!masterTextureNodes[i].textureData ) masterTextureNodes[i].textureData = (DWORD *)textureCacheHeap->Malloc(txmCompressSize); //No More RAM. Do not display this texture anymore. if (masterTextureNodes[i].textureData == NULL) masterTextureNodes[i].gosTextureHandle = 0; else { memcpy(masterTextureNodes[i].textureData,lzBuffer2,txmCompressSize); masterTextureNodes[i].lzCompSize = txmCompressSize; } //------------------ return(i); } //---------------------------------------------------------------------- DWORD MC_TextureManager::textureInstanceExists (const char *textureFullPathName, gos_TextureFormat key, DWORD hints, DWORD uniqueInstance, DWORD nFlush) { long i=0; //-------------------------------------- // Is this texture already Loaded? for (i=0;iMalloc(strlen(textureFullPathName) + 1); gosASSERT(masterTextureNodes[i].nodeName != NULL); strcpy(masterTextureNodes[i].nodeName,textureFullPathName); masterTextureNodes[i].numUsers = 1; masterTextureNodes[i].key = key; masterTextureNodes[i].hints = hints; masterTextureNodes[i].uniqueInstance = uniqueInstance; masterTextureNodes[i].neverFLUSH = nFlush; //---------------------------------------------------------------------------------------------- // Store 0xf0000000 & fileSize in width so that cache knows to create new texture from memory. // This way, we never need to know anything about the texture AND we can store PMGs // in memory instead of TGAs which use WAY less RAM! File textureFile; #ifdef _DEBUG long textureFileOpenResult = #endif textureFile.open(textureFullPathName); gosASSERT(textureFileOpenResult == NO_ERR); long txmSize = textureFile.fileSize(); if (!lzBuffer1) { lzBuffer1 = (MemoryPtr)textureCacheHeap->Malloc(MAX_LZ_BUFFER_SIZE); gosASSERT(lzBuffer1 != NULL); lzBuffer2 = (MemoryPtr)textureCacheHeap->Malloc(MAX_LZ_BUFFER_SIZE); gosASSERT(lzBuffer2 != NULL); } //Try reading the RAW data out of the fastFile. // If it succeeds, we just saved a complete compress, decompress and two memcpys!! // long result = textureFile.readRAW(masterTextureNodes[i].textureData,textureCacheHeap); if (!result) { textureFile.read(lzBuffer1,txmSize); textureFile.close(); actualTextureSize += txmSize; DWORD txmCompressSize = LZCompress(lzBuffer2,lzBuffer1,txmSize); compressedTextureSize += txmCompressSize; masterTextureNodes[i].textureData = (DWORD *)textureCacheHeap->Malloc(txmCompressSize); if (masterTextureNodes[i].textureData == NULL) masterTextureNodes[i].gosTextureHandle = 0; else memcpy(masterTextureNodes[i].textureData,lzBuffer2,txmCompressSize); masterTextureNodes[i].lzCompSize = txmCompressSize; } else { masterTextureNodes[i].lzCompSize = result; } masterTextureNodes[i].width = 0xf0000000 + txmSize; //------------------- return(i); } //---------------------------------------------------------------------- long MC_TextureManager::saveTexture (DWORD textureIndex, const char *textureFullPathName) { if ((MC_MAXTEXTURES <= textureIndex) || (NULL == masterTextureNodes[textureIndex].textureData)) { return (~NO_ERR); } File textureFile; long textureFileOpenResult = textureFile.create(textureFullPathName); if (NO_ERR != textureFileOpenResult) { textureFile.close(); return textureFileOpenResult; } { if (masterTextureNodes[textureIndex].width == 0) { textureFile.close(); return (~NO_ERR); //These faces have no texture!! } { //------------------------------------------ // Badboys are now LZ Compressed in texture cache. long origSize = LZDecomp(MC_TextureManager::lzBuffer2,(MemoryPtr)masterTextureNodes[textureIndex].textureData,masterTextureNodes[textureIndex].lzCompSize); if (origSize != (masterTextureNodes[textureIndex].width & 0x0fffffff)) STOP(("Decompressed to different size from original! Txm:%s Width:%d DecompSize:%d",masterTextureNodes[textureIndex].nodeName,(masterTextureNodes[textureIndex].width & 0x0fffffff),origSize)); if (origSize >= MAX_LZ_BUFFER_SIZE) STOP(("Texture TOO large: %s",masterTextureNodes[textureIndex].nodeName)); textureFile.write(MC_TextureManager::lzBuffer2, origSize); } textureFile.close(); } return NO_ERR; } DWORD MC_TextureManager::copyTexture( DWORD texNodeID ) { gosASSERT( texNodeID < MC_MAXTEXTURES ); if ( masterTextureNodes[texNodeID].gosTextureHandle != -1 ) { masterTextureNodes[texNodeID].numUsers++; return texNodeID; } else { STOP(( "tried to copy an invalid texture" )); } return -1; } //---------------------------------------------------------------------- // MC_TextureNode DWORD MC_TextureNode::get_gosTextureHandle (void) //If texture is not in VidRAM, cache a texture out and cache this one in. { if (gosTextureHandle == 0xffffffff) { //Somehow this texture is bad. Probably we are using a handle which got purged between missions. // Just send back, NO TEXTURE and we should be able to debug from there because the tri will have no texture!! return 0x0; } if (gosTextureHandle != CACHED_OUT_HANDLE) { lastUsed = turn; return gosTextureHandle; } else { if ((mcTextureManager->currentUsedTextures >= MAX_MC2_GOS_TEXTURES) && !mcTextureManager->flushCache()) return 0x0; //No texture! if (width == 0) return 0; //These faces have no texture!! if (!textureData) return 0x0; //No Texture. Cache is out of RAM!! if (width > 0xf0000000) { //------------------------------------------ // Cache this badboy IN. // Badboys are now LZ Compressed in texture cache. // Uncompress, then memcpy. long origSize = LZDecomp(MC_TextureManager::lzBuffer2,(MemoryPtr)textureData,lzCompSize); if (origSize != (width & 0x0fffffff)) STOP(("Decompressed to different size from original! Txm:%s Width:%d DecompSize:%d",nodeName,(width & 0x0fffffff),origSize)); if (origSize >= MAX_LZ_BUFFER_SIZE) STOP(("Texture TOO large: %s",nodeName)); gosTextureHandle = gos_NewTextureFromMemory(key,nodeName,MC_TextureManager::lzBuffer2,(width & 0x0fffffff),hints); mcTextureManager->currentUsedTextures++; lastUsed = turn; return gosTextureHandle; } else { gosTextureHandle = gos_NewEmptyTexture(key,nodeName,width,hints); mcTextureManager->currentUsedTextures++; //------------------------------------------ // Cache this badboy IN. TEXTUREPTR pTextureData; gos_LockTexture(gosTextureHandle, 0, 0, &pTextureData); //------------------------------------------------------- // Create a block of cache memory to hold this texture. DWORD txmSize = pTextureData.Height * pTextureData.Height * sizeof(DWORD); gosASSERT(textureData); LZDecomp(MC_TextureManager::lzBuffer2,(MemoryPtr)textureData,lzCompSize); memcpy(pTextureData.pTexture,MC_TextureManager::lzBuffer2,txmSize); //------------------------ // Unlock the texture gos_UnLockTexture(gosTextureHandle); lastUsed = turn; return gosTextureHandle; } } } //---------------------------------------------------------------------- void MC_TextureNode::destroy (void) { if ((gosTextureHandle != CACHED_OUT_HANDLE) && (gosTextureHandle != 0xffffffff) && (gosTextureHandle != 0x0)) { gos_DestroyTexture(gosTextureHandle); } mcTextureManager->textureStringHeap->Free(nodeName); mcTextureManager->textureCacheHeap->Free(textureData); init(); } //----------------------------------------------------------------------