hwDecalBumpShader_NV20/MTextureCache.cpp
 
 
 
hwDecalBumpShader_NV20/MTextureCache.cpp
//-
// ==========================================================================
// Copyright (C) 1995 - 2006 Autodesk, Inc. and/or its licensors.  All 
// rights reserved.
//
// The coded instructions, statements, computer programs, and/or related 
// material (collectively the "Data") in these files contain unpublished 
// information proprietary to Autodesk, Inc. ("Autodesk") and/or its 
// licensors, which is protected by U.S. and Canadian federal copyright 
// law and by international treaties.
//
// The Data is provided for use exclusively by You. You have the right 
// to use, modify, and incorporate this Data into other products for 
// purposes authorized by the Autodesk software license agreement, 
// without fee.
//
// The copyright notices in the Software and this entire statement, 
// including the above license grant, this restriction and the 
// following disclaimer, must be included in all copies of the 
// Software, in whole or in part, and all derivative works of 
// the Software, unless such copies or derivative works are solely 
// in the form of machine-executable object code generated by a 
// source language processor.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND. 
// AUTODESK DOES NOT MAKE AND HEREBY DISCLAIMS ANY EXPRESS OR IMPLIED 
// WARRANTIES INCLUDING, BUT NOT LIMITED TO, THE WARRANTIES OF 
// NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR 
// PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE, OR 
// TRADE PRACTICE. IN NO EVENT WILL AUTODESK AND/OR ITS LICENSORS 
// BE LIABLE FOR ANY LOST REVENUES, DATA, OR PROFITS, OR SPECIAL, 
// DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES, EVEN IF AUTODESK 
// AND/OR ITS LICENSORS HAS BEEN ADVISED OF THE POSSIBILITY 
// OR PROBABILITY OF SUCH DAMAGES.
//
// ==========================================================================
//+

// MTextureCache.cpp

// DESCRIPTION: Texture cache, used to temporarily store textures.
//                              Eventually, we'll likely expose the actual Maya
//                              texture cache to plug-ins to improve memory utilization
//                              and performance.
//
// PS: Thanks to sbrew@lucasarts.com for contributing several fixes 
// to this class! ;-)
//

#include <maya/MPlug.h>
#include "MTextureCache.h"
#include "NodeMonitor.h"

// Initialize the singleton instance, and the refcount is originally 0.
MTextureCache* MTextureCache::m_instance = NULL;
/*static*/ int MTextureCache::refcount = 0;

MTextureCacheElement::~MTextureCacheElement()
{ 
        if (m_texture) 
        {
                delete m_texture;
                m_texture = NULL;
        }
}


MTextureCache::~MTextureCache()
{
        if (m_textureTable.empty())
                return;

        // Delete all texture cache elements.
        //
        string_to_cacheElement_map::iterator p = m_textureTable.begin();
        for ( ; p != m_textureTable.end(); ++p)
        {
                delete p->second;
        }
}

// Return a reference to the texture. Need to dereference by calling "release".
MTexture* MTextureCache::texture(MObject textureObj, 
                         MTexture::Type type /* = MTexture::RGBA */, 
                         bool mipmapped /* = true */,
                         GLenum target /* = GL_TEXTURE_2D */)
{
        // Get the name of the texture object.
        MString textureName = getNameFromObj(textureObj);
        
        // If this isn't a file texture node, or if it has no valid name, 
        // return NULL.
        if (!textureObj.hasFn(MFn::kFileTexture) ||
                textureName == "")
                return NULL;

        // Check if we already have a texCacheElement assigned to the given texture name.
        MTextureCacheElement *texCacheElement = 
                m_textureTable[textureName.asChar()];
        bool newTexture = !texCacheElement;
        bool textureDirty = texCacheElement && texCacheElement->fMonitor.dirty();

        if (textureDirty)
        {
                texCacheElement->fMonitor.stopWatching();
                delete texCacheElement->m_texture;
                texCacheElement->m_texture = NULL;
        }

        if (newTexture)
        {
                texCacheElement = new MTextureCacheElement;

                texCacheElement->fMonitor.setManager(this);
                
                // Add it to the map.
                m_textureTable[textureName.asChar()] = texCacheElement;
        }

        if (textureDirty || newTexture)
        {
                // Get the filename of the file texture node.
                MString textureFilename;
                MFnDependencyNode textureNode(textureObj);
                MPlug filenamePlug( textureObj, 
                        textureNode.attribute(MString("fileTextureName")) );
                filenamePlug.getValue(textureFilename);
                
                // Create the MTexture
                texCacheElement->m_texture = new MTexture;

                // Monitor the given texture node for "dirty" or "rename" messages.
                texCacheElement->fMonitor.watch(textureObj);

                // Attempt to load the texture from disk and bind it in the OpenGL driver. 
                if (texCacheElement->m_texture->load(textureFilename, 
                                                                type, mipmapped, target) == false)
                {
                        // An error occured. Most likely, it was impossible to 
                        // open the given filename.
                        // Clean up and return NULL.
                        delete texCacheElement;
                        texCacheElement = NULL;
                        m_textureTable.erase(textureName.asChar());
                        return NULL;
                }
        }

        // Update the last updated timestamp.
        texCacheElement->lastAccessedTimestamp = m_currentTimestamp;

        return texCacheElement->texture();
}

// Returns true if the texture was found and bound; 
// returns false otherwise.
bool MTextureCache::bind(MObject textureObj, 
                                                 MTexture::Type type /* = MTexture::RGBA */, 
                                                 bool mipmapped /* = true */,
                                                 GLenum target /* = GL_TEXTURE_2D */)
{
        // Get a reference to the texture, allocating it if necessary.
        MTexture* pTex = texture(textureObj, type, mipmapped, target);

        if (pTex)
        {
                // bind the texture.
                pTex->bind();
        
                return true;
        }
        
        return false;
}

void MTextureCache::onNodeRenamed(MObject& node, MString oldName, MString newName)
{
        // Remove the texture from the cache.
        MTextureCacheElement *texCacheElement = m_textureTable[oldName.asChar()];
        delete texCacheElement->m_texture;
        texCacheElement->m_texture = NULL;
}

void MTextureCache::incrementTimestamp(unsigned int increment /* =  1 */)
{
        m_currentTimestamp += increment;
        
        // Optionally, go through all textures and get rid of each of them that
        // is too old.
}