//----------------------------------------------------------------------------- // Torque Game Engine // Copyright (C) GarageGames.com, Inc. //----------------------------------------------------------------------------- #include "interior/interiorLMManager.h" #include "dgl/gTexManager.h" #include "dgl/gBitmap.h" #include "platform/platformGL.h" #include "interior/interiorRes.h" #include "interior/interiorInstance.h" #include "interior/interior.h" #include "sceneGraph/sceneLighting.h" //------------------------------------------------------------------------------ // Globals InteriorLMManager gInteriorLMManager; //------------------------------------------------------------------------------ namespace { void interiorLMTextureCallback(const U32 eventCode, void * userData) { AssertFatal(&gInteriorLMManager == reinterpret_cast(userData), "Bunk ptr!"); gInteriorLMManager.processTextureEvent(eventCode); } // '__lm_.png' const char * getTextureName(Interior * interior, U32 instance, U32 lightmap) { static char buffer[256]; dSprintf(buffer, sizeof(buffer), "%p_%d_lm_%d.png", interior, instance, lightmap); return(buffer); } } //------------------------------------------------------------------------------ U32 InteriorLMManager::smTextureCallbackKey = U32(-1); // D3D vertex buffers for Interiors are in here so they get dumped/reallocated // along with the lightmaps on the texture events S32 InteriorLMManager::smMTVertexBuffer = -1; S32 InteriorLMManager::smFTVertexBuffer = -1; S32 InteriorLMManager::smFMTVertexBuffer = -1; InteriorLMManager::InteriorLMManager() { } InteriorLMManager::~InteriorLMManager() { for(U32 i = 0; i < mInteriors.size(); i++) removeInterior(LM_HANDLE(i)); } //------------------------------------------------------------------------------ void InteriorLMManager::init() { smTextureCallbackKey = TextureManager::registerEventCallback(interiorLMTextureCallback, &gInteriorLMManager); } void InteriorLMManager::destroy() { if(smTextureCallbackKey != U32(-1)) { TextureManager::unregisterEventCallback(smTextureCallbackKey); smTextureCallbackKey = U32(-1); } if (smMTVertexBuffer != -1) { if (dglDoesSupportVertexBuffer()) glFreeVertexBufferEXT(smMTVertexBuffer); else AssertFatal(false,"Vertex buffer should have already been freed!"); smMTVertexBuffer = -1; } if (smFTVertexBuffer != -1) { if (dglDoesSupportVertexBuffer()) glFreeVertexBufferEXT(smFTVertexBuffer); else AssertFatal(false,"Vertex buffer should have already been freed!"); smFTVertexBuffer = -1; } if (smFMTVertexBuffer != -1) { if (dglDoesSupportVertexBuffer()) glFreeVertexBufferEXT(smFMTVertexBuffer); else AssertFatal(false,"Vertex buffer should have already been freed!"); smFMTVertexBuffer = -1; } } void InteriorLMManager::processTextureEvent(U32 eventCode) { switch(eventCode) { case TextureManager::BeginZombification: purgeGLTextures(); if (smMTVertexBuffer != -1) { if (dglDoesSupportVertexBuffer()) glFreeVertexBufferEXT(smMTVertexBuffer); else AssertFatal(false,"Vertex buffer should have already been freed!"); smMTVertexBuffer = -1; } if (smFTVertexBuffer != -1) { if (dglDoesSupportVertexBuffer()) glFreeVertexBufferEXT(smFTVertexBuffer); else AssertFatal(false,"Vertex buffer should have already been freed!"); smFTVertexBuffer = -1; } if (smFMTVertexBuffer != -1) { if (dglDoesSupportVertexBuffer()) glFreeVertexBufferEXT(smFMTVertexBuffer); else AssertFatal(false,"Vertex buffer should have already been freed!"); smFMTVertexBuffer = -1; } break; case TextureManager::CacheResurrected: // relighting the scene will take care of things for us if(mInteriors.size()) SceneLighting::lightScene(0, SceneLighting::LoadOnly); break; } } //------------------------------------------------------------------------------ void InteriorLMManager::addInterior(LM_HANDLE & interiorHandle, U32 numLightmaps, Interior * interior) { interiorHandle = mInteriors.size(); mInteriors.increment(); mInteriors.last() = new InteriorLMInfo; mInteriors.last()->mInterior = interior; mInteriors.last()->mHandlePtr = &interiorHandle; mInteriors.last()->mNumLightmaps = numLightmaps; // create base instance addInstance(interiorHandle, mInteriors.last()->mBaseInstanceHandle, 0); AssertFatal(mInteriors.last()->mBaseInstanceHandle == LM_HANDLE(0), "InteriorLMManager::addInterior: invalid base instance handle"); // steal the lightmaps from the interior Vector& texHandles = getHandles(interiorHandle, 0); for(U32 i = 0; i < interior->mLightmaps.size(); i++) { AssertFatal(interior->mLightmaps[i], "InteriorLMManager::addInterior: interior missing lightmap"); texHandles[i] = new TextureHandle(getTextureName(interior, 0, i), interior->mLightmaps[i], BitmapNoDownloadTexture); } interior->mLightmaps.clear(); } void InteriorLMManager::removeInterior(LM_HANDLE interiorHandle) { AssertFatal(interiorHandle < mInteriors.size(), "InteriorLMManager::removeInterior: invalid interior handle"); AssertFatal(mInteriors[interiorHandle]->mInstances.size() == 1, "InteriorLMManager::removeInterior: cannot remove base interior"); // remove base instance removeInstance(interiorHandle, 0); *mInteriors[interiorHandle]->mHandlePtr = LM_HANDLE(-1); delete mInteriors[interiorHandle]; // last one? otherwise move it if((mInteriors.size()-1) != interiorHandle) { mInteriors[interiorHandle] = mInteriors.last(); *(mInteriors[interiorHandle]->mHandlePtr) = interiorHandle; } mInteriors.decrement(); } //------------------------------------------------------------------------------ void InteriorLMManager::addInstance(LM_HANDLE interiorHandle, LM_HANDLE & instanceHandle, InteriorInstance * instance) { AssertFatal(interiorHandle < mInteriors.size(), "InteriorLMManager::addInstance: invalid interior handle"); AssertFatal(interiorHandle == *(mInteriors[interiorHandle]->mHandlePtr), "InteriorLMManager::addInstance: invalid handle value"); InteriorLMInfo * interiorInfo = mInteriors[interiorHandle]; // create the instance info and fill InstanceLMInfo * instanceInfo = new InstanceLMInfo; instanceInfo->mInstance = instance; instanceInfo->mHandlePtr = &instanceHandle; instanceHandle = interiorInfo->mInstances.size(); interiorInfo->mInstances.push_back(instanceInfo); // create/clear list instanceInfo->mLightmapHandles.setSize(interiorInfo->mNumLightmaps); dMemset(instanceInfo->mLightmapHandles.address(), 0, sizeof(TextureHandle*) * instanceInfo->mLightmapHandles.size()); } void InteriorLMManager::removeInstance(LM_HANDLE interiorHandle, LM_HANDLE instanceHandle) { AssertFatal(interiorHandle < mInteriors.size(), "InteriorLMManager::removeInstance: invalid interior handle"); AssertFatal(instanceHandle < mInteriors[interiorHandle]->mInstances.size(), "InteriorLMManager::removeInstance: invalid instance handle"); AssertFatal(!(instanceHandle == mInteriors[interiorHandle]->mBaseInstanceHandle && mInteriors[interiorHandle]->mInstances.size() > 1), "InteriorLMManager::removeInstance: invalid base instance"); InteriorLMInfo * itrInfo = mInteriors[interiorHandle]; // kill it InstanceLMInfo * instInfo = itrInfo->mInstances[instanceHandle]; for(U32 i = 0; i < instInfo->mLightmapHandles.size(); i++) delete instInfo->mLightmapHandles[i]; // reset on last instance removal only (multi detailed shapes share the same instance handle) if(itrInfo->mInstances.size() == 1) *instInfo->mHandlePtr = LM_HANDLE(-1); delete instInfo; // last one? otherwise move it if((itrInfo->mInstances.size()-1) != instanceHandle) { itrInfo->mInstances[instanceHandle] = itrInfo->mInstances.last(); *(itrInfo->mInstances[instanceHandle]->mHandlePtr) = instanceHandle; } itrInfo->mInstances.decrement(); } void InteriorLMManager::useBaseTextures(LM_HANDLE interiorHandle, LM_HANDLE instanceHandle) { AssertFatal(interiorHandle < mInteriors.size(), "InteriorLMManager::useBaseTextures: invalid interior handle"); AssertFatal(interiorHandle == *(mInteriors[interiorHandle]->mHandlePtr), "InteriorLMManager::useBaseTextures: invalid handle value"); // Make sure the base light maps are loaded loadBaseLightmaps(interiorHandle,instanceHandle); // Install base lightmaps for this instance... Vector& baseHandles = getHandles(interiorHandle, 0); Vector& texHandles = getHandles(interiorHandle, instanceHandle); for(U32 i = 0; i < baseHandles.size(); i++) texHandles[i] = new TextureHandle(*baseHandles[i]); } //------------------------------------------------------------------------------ void InteriorLMManager::destroyBitmaps() { for(S32 i = mInteriors.size() - 1; i >= 0; i--) { InteriorLMInfo * interiorInfo = mInteriors[i]; for(S32 j = interiorInfo->mInstances.size() - 1; j >= 0; j--) { InstanceLMInfo * instanceInfo = interiorInfo->mInstances[j]; for(S32 k = instanceInfo->mLightmapHandles.size() - 1; k >= 0; k--) { if(!instanceInfo->mLightmapHandles[k]) continue; TextureObject * texObj = *instanceInfo->mLightmapHandles[k]; if(!texObj || !texObj->bitmap) continue; // don't remove 'keep' bitmaps if(!interiorInfo->mInterior->mLightmapKeep[k]) { delete texObj->bitmap; texObj->bitmap = 0; } } } } } void InteriorLMManager::destroyTextures() { for(S32 i = mInteriors.size() - 1; i >= 0; i--) { InteriorLMInfo * interiorInfo = mInteriors[i]; for(S32 j = interiorInfo->mInstances.size() - 1; j >= 0; j--) { InstanceLMInfo * instanceInfo = interiorInfo->mInstances[j]; for(S32 k = interiorInfo->mNumLightmaps - 1; k >= 0; k--) { // will want to remove the vector here eventually... so don't clear delete instanceInfo->mLightmapHandles[k]; instanceInfo->mLightmapHandles[k] = 0; } } } } void InteriorLMManager::purgeGLTextures() { Vector purgeList(4096); for(S32 i = mInteriors.size() - 1; i >= 0; i--) { InteriorLMInfo * interiorInfo = mInteriors[i]; for(S32 j = interiorInfo->mInstances.size() - 1; j >= 0; j--) { InstanceLMInfo * instanceInfo = interiorInfo->mInstances[j]; for(S32 k = instanceInfo->mLightmapHandles.size() - 1; k >= 0; k--) { if(!instanceInfo->mLightmapHandles[k]) continue; TextureObject * texObj = *instanceInfo->mLightmapHandles[k]; if(!texObj || !texObj->texGLName) continue; #ifdef TORQUE_GATHER_METRICS AssertFatal(texObj->textureSpace <= TextureManager::smTextureSpaceLoaded, "Doh!"); TextureManager::smTextureSpaceLoaded -= texObj->textureSpace; texObj->textureSpace = 0; #endif purgeList.push_back(texObj->texGLName); texObj->texGLName = 0; } } } glDeleteTextures(purgeList.size(), purgeList.address()); } void InteriorLMManager::downloadGLTextures() { for(S32 i = mInteriors.size() - 1; i >= 0; i--) downloadGLTextures(i); } void InteriorLMManager::downloadGLTextures(LM_HANDLE interiorHandle) { AssertFatal(interiorHandle < mInteriors.size(), "InteriorLMManager::downloadGLTextures: invalid interior handle"); InteriorLMInfo * interiorInfo = mInteriors[interiorHandle]; // The bit vector is used to keep track of which lightmap sets need // to be loaded from the shared "base" instance. Every instance // can have it's own lightmap set due to mission lighting. BitVector needTexture; needTexture.setSize(interiorInfo->mNumLightmaps); needTexture.clear(); for(S32 j = interiorInfo->mInstances.size() - 1; j >= 0; j--) { InstanceLMInfo * instanceInfo = interiorInfo->mInstances[j]; for(S32 k = instanceInfo->mLightmapHandles.size() - 1; k >= 0; k--) { // All instances can share the base instances static lightmaps. // Test here to see if we need to load those lightmaps. if ((j == 0) && !needTexture.test(k)) continue; if (!instanceInfo->mLightmapHandles[k]) { needTexture.set(k); continue; } TextureObject * texObj = *instanceInfo->mLightmapHandles[k]; if (!texObj || !texObj->bitmap) { needTexture.set(k); continue; } // Make sure this one is not already loaded. if (texObj->texGLName) continue; // Go ahead and download this set to GL #ifdef TORQUE_GATHER_METRICS texObj->textureSpace = texObj->downloadedWidth * texObj->downloadedHeight; TextureManager::smTextureSpaceLoaded += texObj->textureSpace; #endif TextureManager::createGLName(texObj->bitmap, texObj->clamp, 0, texObj->type, texObj); } } } bool InteriorLMManager::loadBaseLightmaps(LM_HANDLE interiorHandle, LM_HANDLE instanceHandle) { AssertFatal(interiorHandle < mInteriors.size(), "InteriorLMManager::loadBaseLightmaps: invalid interior handle"); AssertFatal(instanceHandle < mInteriors[interiorHandle]->mInstances.size(), "InteriorLMManager::loadBaseLightmaps: invalid instance handle"); // must use a valid instance handle if(!instanceHandle) return(false); InteriorLMInfo * interiorInfo = mInteriors[interiorHandle]; if(!interiorInfo->mNumLightmaps) return(false); InstanceLMInfo * baseInstanceInfo = interiorInfo->mInstances[0]; // already loaded? (if any bitmap is present, then assumed that all will be) TextureHandle * texture = baseInstanceInfo->mLightmapHandles[0]; if(texture && texture->getBitmap()) return(true); InstanceLMInfo * instanceInfo = interiorInfo->mInstances[instanceHandle]; Resource & interiorRes = instanceInfo->mInstance->getResource(); if(!bool(interiorRes)) return(false); GBitmap *** pBitmaps = 0; if(!instanceInfo->mInstance->readLightmaps(&pBitmaps)) return(false); for(U32 i = 0; i < interiorRes->getNumDetailLevels(); i++) { Interior * interior = interiorRes->getDetailLevel(i); AssertFatal(interior, "InteriorLMManager::loadBaseLightmaps: invalid detail level in resource"); AssertFatal(interior->getLMHandle() != LM_HANDLE(-1), "InteriorLMManager::loadBaseLightmaps: interior not added to manager"); AssertFatal(interior->getLMHandle() < mInteriors.size(), "InteriorLMManager::loadBaseLightmaps: invalid interior"); InteriorLMInfo * interiorInfo = mInteriors[interior->getLMHandle()]; InstanceLMInfo * baseInstanceInfo = interiorInfo->mInstances[0]; for(U32 j = 0; j < interiorInfo->mNumLightmaps; j++) { AssertFatal(pBitmaps[i][j], "InteriorLMManager::loadBaseLightmaps: invalid bitmap"); if (baseInstanceInfo->mLightmapHandles[j]) { TextureObject * texObj = *baseInstanceInfo->mLightmapHandles[j]; texObj->bitmap = pBitmaps[i][j]; } else baseInstanceInfo->mLightmapHandles[j] = new TextureHandle(getTextureName(interior, 0, j), pBitmaps[i][j], BitmapNoDownloadTexture); } delete [] pBitmaps[i]; } delete [] pBitmaps; return(true); } //------------------------------------------------------------------------------ TextureHandle * InteriorLMManager::getHandle(LM_HANDLE interiorHandle, LM_HANDLE instanceHandle, U32 index) { AssertFatal(interiorHandle < mInteriors.size(), "InteriorLMManager::getHandle: invalid interior handle"); AssertFatal(instanceHandle < mInteriors[interiorHandle]->mInstances.size(), "InteriorLMManager::getHandle: invalid instance handle"); AssertFatal(index < mInteriors[interiorHandle]->mNumLightmaps, "InteriorLMManager::getHandle: invalid texture index"); // valid? if not, then get base lightmap handle if(!mInteriors[interiorHandle]->mInstances[instanceHandle]->mLightmapHandles[index]) { AssertFatal(mInteriors[interiorHandle]->mInstances[0]->mLightmapHandles[index], "InteriorLMManager::getHandle: invalid base texture handle"); return(mInteriors[interiorHandle]->mInstances[0]->mLightmapHandles[index]); } return(mInteriors[interiorHandle]->mInstances[instanceHandle]->mLightmapHandles[index]); } GBitmap * InteriorLMManager::getBitmap(LM_HANDLE interiorHandle, LM_HANDLE instanceHandle, U32 index) { AssertFatal(interiorHandle < mInteriors.size(), "InteriorLMManager::getBitmap: invalid interior handle"); AssertFatal(instanceHandle < mInteriors[interiorHandle]->mInstances.size(), "InteriorLMManager::getBitmap: invalid instance handle"); AssertFatal(index < mInteriors[interiorHandle]->mNumLightmaps, "InteriorLMManager::getBitmap: invalid texture index"); if(!mInteriors[interiorHandle]->mInstances[instanceHandle]->mLightmapHandles[index]) { AssertFatal(mInteriors[interiorHandle]->mInstances[0]->mLightmapHandles[index], "InteriorLMManager::getBitmap: invalid base texture handle"); return(mInteriors[interiorHandle]->mInstances[0]->mLightmapHandles[index]->getBitmap()); } return(mInteriors[interiorHandle]->mInstances[instanceHandle]->mLightmapHandles[index]->getBitmap()); } Vector & InteriorLMManager::getHandles(LM_HANDLE interiorHandle, LM_HANDLE instanceHandle) { AssertFatal(interiorHandle < mInteriors.size(), "InteriorLMManager::getHandles: invalid interior handle"); AssertFatal(instanceHandle < mInteriors[interiorHandle]->mInstances.size(), "InteriorLMManager::getHandles: invalid instance handle"); return(mInteriors[interiorHandle]->mInstances[instanceHandle]->mLightmapHandles); } //------------------------------------------------------------------------------ U32 InteriorLMManager::getNumLightmaps(LM_HANDLE interiorHandle) { AssertFatal(interiorHandle < mInteriors.size(), "InteriorLMManager::getNumLightmaps: invalid interior handle"); return(mInteriors[interiorHandle]->mNumLightmaps); } //------------------------------------------------------------------------------ void InteriorLMManager::deleteLightmap(LM_HANDLE interiorHandle, LM_HANDLE instanceHandle, U32 index) { AssertFatal(interiorHandle < mInteriors.size(), "InteriorLMManager::deleteLightmap: invalid interior handle"); AssertFatal(instanceHandle < mInteriors[interiorHandle]->mInstances.size(), "InteriorLMManager::deleteLightmap: invalid instance handle"); AssertFatal(index < mInteriors[interiorHandle]->mNumLightmaps, "InteriorLMManager::deleteLightmap: invalid texture index"); delete mInteriors[interiorHandle]->mInstances[instanceHandle]->mLightmapHandles[index]; mInteriors[interiorHandle]->mInstances[instanceHandle]->mLightmapHandles[index] = 0; } void InteriorLMManager::clearLightmaps(LM_HANDLE interiorHandle, LM_HANDLE instanceHandle) { AssertFatal(interiorHandle < mInteriors.size(), "InteriorLMManager::clearLightmaps: invalid interior handle"); AssertFatal(instanceHandle < mInteriors[interiorHandle]->mInstances.size(), "InteriorLMManager::clearLightmaps: invalid instance handle"); for(U32 i = 0; i < mInteriors[interiorHandle]->mNumLightmaps; i++) { delete mInteriors[interiorHandle]->mInstances[instanceHandle]->mLightmapHandles[i]; mInteriors[interiorHandle]->mInstances[instanceHandle]->mLightmapHandles[i] = 0; } } //------------------------------------------------------------------------------ TextureHandle * InteriorLMManager::duplicateBaseLightmap(LM_HANDLE interiorHandle, LM_HANDLE instanceHandle, U32 index) { AssertFatal(interiorHandle < mInteriors.size(), "InteriorLMManager::duplicateBaseLightmap: invalid interior handle"); AssertFatal(instanceHandle < mInteriors[interiorHandle]->mInstances.size(), "InteriorLMManager::duplicateBaseLightmap: invalid instance handle"); AssertFatal(index < mInteriors[interiorHandle]->mNumLightmaps, "InteriorLMManager::duplicateBaseLightmap: invalid texture index"); // already exists? TextureHandle * texHandle = mInteriors[interiorHandle]->mInstances[instanceHandle]->mLightmapHandles[index]; if(texHandle && static_cast(*texHandle)->bitmap) return(texHandle); AssertFatal(mInteriors[interiorHandle]->mInstances[0]->mLightmapHandles[index], "InteriorLMManager::duplicateBaseLightmap: invalid base handle"); // copy it GBitmap * src = mInteriors[interiorHandle]->mInstances[0]->mLightmapHandles[index]->getBitmap(); GBitmap * dest = new GBitmap(*src); // don't want this texture to be downloaded yet (SceneLighting will take care of that) TextureHandle * tHandle = new TextureHandle(getTextureName(mInteriors[interiorHandle]->mInterior, instanceHandle, index), dest, BitmapNoDownloadTexture); mInteriors[interiorHandle]->mInstances[instanceHandle]->mLightmapHandles[index] = tHandle; return(tHandle); } S32 InteriorLMManager::getVertexBuffer(S32 format) { switch (format) { case GL_V12MTVFMT_EXT: { if (smMTVertexBuffer != -1) return smMTVertexBuffer; smMTVertexBuffer = glAllocateVertexBufferEXT(512,GL_V12MTVFMT_EXT,false); return smMTVertexBuffer; } case GL_V12FTVFMT_EXT: { if (smFTVertexBuffer != -1) return smFTVertexBuffer; smFTVertexBuffer = glAllocateVertexBufferEXT(512,GL_V12FTVFMT_EXT,false); return smFTVertexBuffer; } case GL_V12FMTVFMT_EXT: { if (smFMTVertexBuffer != -1) return smFMTVertexBuffer; smFMTVertexBuffer = glAllocateVertexBufferEXT(512,GL_V12FMTVFMT_EXT,false); return smFMTVertexBuffer; } } AssertFatal(false,"InteriorLMManager::getVertexBuffer() What? We should never get here!!!"); return -1; }