cgfxFindImage.cpp

//
// Copyright (C) 2002-2003 NVIDIA 
// 
// File: cgfxFindImage.cpp

//-
// ==========================================================================
// Copyright 1995,2006,2008 Autodesk, Inc. All rights reserved.
//
// Use of this software is subject to the terms of the Autodesk
// license agreement provided at the time of installation or download,
// or which otherwise accompanies this software in either electronic
// or hard copy form.
// ==========================================================================
//+

#include "cgfxShaderCommon.h"
#include "cgfxFindImage.h"

#include <maya/MStringArray.h>
#include <maya/MGlobal.h>
#include <maya/MFileObject.h>

#include <sys/types.h>
#include <sys/stat.h>

#ifdef _WIN32
#else
#   include <string.h>
#   define  MAX_PATH 1024
#endif

MString cgfxFindFile(const MString& name, const MString &searchpath)
{
    struct stat statBuf;
    char path[MAX_PATH];

    const char * psearchpath = searchpath.asChar();

    OutputDebugString("File = ");
    OutputDebugString(name.asChar());
    OutputDebugString("\n");

#ifdef _WIN32
    const bool fullyQualified = name.index('/') == 0 || name.index('\\') == 0 || name.index(':') == 1;
#else
    const bool fullyQualified = name.index('/') == 0 || name.index('\\') == 0;
#endif

    // First we check if it is a fully qualified path...
    if (fullyQualified && stat(name.asChar(), &statBuf) != -1) {
        OutputDebugString("Returning fully qualified: ");
        OutputDebugString(name.asChar());
        OutputDebugString("\n");

        return name;
    }
    else {
        // Strip out any leading '/' at this point since the file has
        // not been found using a fully qualified path.
        MString resolvedName;
        if(name.index('/') == 0 || name.index('\\') == 0)
            resolvedName = name.substring(1, name.length() - 1);
        else
            resolvedName = name;
        
        while (psearchpath < searchpath.asChar() + searchpath.length())
        {
            const char * endpath = strchr(psearchpath,';');
            if (endpath)
            {
                strncpy(path,psearchpath, endpath - psearchpath);
                path[endpath - psearchpath] = '\0';
            }
            else
            {
                strcpy(path,psearchpath);
            }
                
            psearchpath += strlen(path)+1;

            bool fullPath = (path[0] == '/' ||
                             path[0] == '\\');

            if (strlen(path) > 2)
            {
                fullPath = fullPath ||
                           (path[1] == ':' &&
                            (path[2] == '/' ||
                             path[2] == '\\'));
            }

            // Add the path and the filename together to get the full path
            MString file;
            if(path[strlen(path) - 1] != '/')
                file = MString(path) + "/" + resolvedName;
            else
                file = MString(path) + resolvedName;

            OutputDebugString("Try File = ");
            OutputDebugString(file.asChar());
            OutputDebugString("\n");

            if (stat(file.asChar(), &statBuf) != -1) {
                OutputDebugString("Returning: ");
                OutputDebugString(file.asChar());
                OutputDebugString("\n");
    
                return file;
            }
        }

        OutputDebugString("Not found!\n");
    
        return MString();
    }
}

MString cgfxFindFile(const MString& name, bool projectRelative)
{
    // Our result
    MString fileName;

    // Do we have an image to look for?
    if (name.length() > 0)
    {
        // Build a list of places we'll look for textures
        MString texturePath;

        // Add the standard Maya project paths
        MString workspace;
        MStatus status = MGlobal::executeCommand(MString("workspace -q -rd;"),
                                        workspace);
        if ( status == MS::kSuccess)
        {
            texturePath += workspace;
            texturePath += ";";
            texturePath += workspace;
            texturePath += "/textures;";
            texturePath += workspace;
            texturePath += "/images;";
            texturePath += workspace;
            texturePath += "/sourceimages";
        }

        // Finally, see if any CgFX environment variable paths are set
        char * cgfxPath = getenv("CGFX_TEXTURE_PATH");
        if (cgfxPath)
        {
            if (texturePath.length() > 0) {
                texturePath += ";";
            }
            texturePath += cgfxPath;
        }
        else
        {
            char * cgfxRoot = getenv("CGFX_ROOT");
            if (cgfxRoot)
            {
                if (texturePath.length() > 0) {
                    texturePath += ";";
                }
                texturePath += cgfxRoot;
                texturePath += "/textures/2D;";
                texturePath += cgfxRoot;
                texturePath += "/textures/cubemaps;";
                texturePath += cgfxRoot;
                texturePath += "/textures/3D;";
                texturePath += cgfxRoot;
                texturePath += "/textures/rectangles;";
                texturePath += cgfxRoot;
                texturePath += "/CgFX_Textures;";
                texturePath += cgfxRoot;
                texturePath += "/CgFX";
            }
        }

        OutputDebugString("CgFX texture path is: ");
        OutputDebugString(texturePath.asChar());
        OutputDebugString("\n");

        fileName = cgfxFindFile(name, texturePath);

        int hasFile = fileName.length() > 0;

        if (hasFile == 0)
        {
            // lets extract the filename and try it again...
            int idx = name.rindex('/');
            if (idx == -1)
                idx = name.rindex('\\');
            if (idx != -1)
            {
                MString filename = name.substring(idx+1,name.length()-1);
                fileName = cgfxFindFile(filename, texturePath);
                hasFile = fileName.length() > 0;
            }
        }
            
        // If we found the file and the user wants project relative, try
        // to strip the project directory off the front of our result
        if( hasFile && projectRelative)
        {
            if( fileName.length() > workspace.length() && 
                workspace.length() > 0 &&
                fileName.substring( 0, workspace.length() - 1) == workspace)
                // Strip the project path off the front INCLUDING the
                // separating '/' (otherwise we'd create an absolute path)
                fileName = fileName.substring( workspace.length(), fileName.length() - 1);
        }

        if (hasFile == 0)
            OutputDebugString("Error: file not found.\n");
    }
    return fileName;
}

void    
cgfxGetFxIncludePath( const MString &fxFile, MStringArray &pathOptions )
{
    // Append the path of the cgfx file as a possible include search path
    //
    MString option;
    if (fxFile.length())
    {
        MFileObject fobject;
        fobject.setRawFullName( fxFile );
        option = MString("-I") + fobject.resolvedPath();        
        pathOptions.append( option );
    }

    // Add in "standard" cgfx search for cgfx files as a possible include
    // search path
    //
    char * cgfxRoot = getenv("CGFX_ROOT");
    if (cgfxRoot)
    {
        option = MString("-I") + MString(cgfxRoot);
        pathOptions.append( option );
        option = MString("-I") + MString(cgfxRoot) + MString("/CgFX");
        pathOptions.append( option );
    }

    // Add in Maya's Cg directory
    char * mayaLocation = getenv("MAYA_LOCATION");
    if (mayaLocation)
    {
        MString mayaCgLocation(MString(mayaLocation) + MString("/bin/Cg/"));
        option = MString("-I") + mayaCgLocation;
        pathOptions.append( option );
    }
}