- Main Page
- Related Pages
- Modules
- Classes
- Examples

# 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.
    }