#include "cgfxTextureCache.h"
#include "cgfxFindImage.h"
#include "cgfxProfile.h"
#include <maya/MHardwareRenderer.h>
#include <maya/MFileObject.h>
#include <maya/MGLFunctionTable.h>
#include "nv_dds.h"
#include <map>
namespace {
bool textureInitPowerOfTwo(unsigned int val, unsigned int & retval)
{
unsigned int res = 0;
if (val)
{
val <<= 1;
unsigned int low = 3;
res = 1;
while (val > low)
{
low <<= 1;
res <<= 1;
}
}
retval = res;
return (res == (val>>1)) ? 1 : 0;
}
)
{
if (texFileName.
length() == 0) {
}
MString path = cgfxFindFile(texFileName);
{
path = cgfxFindFile(effectFile.
path() + texFileName);
}
return path;
}
bool allocateAndReadTexture(
cgfxAttrDef::cgfxAttrType attrType,
GLuint& textureId
)
{
if ( 0 == gGLFT )
GLuint val;
gGLFT->
glGenTextures(1, &val);
textureId = val;
nv_dds::CDDSImage image;
{
switch (attrType)
{
case cgfxAttrDef::kAttrTypeEnvTexture:
case cgfxAttrDef::kAttrTypeCubeTexture:
case cgfxAttrDef::kAttrTypeNormalizationTexture:
image.load(path.
asChar(),
false);
break;
default:
image.load(
cgfxProfile::getTexCoordOrientation() == cgfxProfile::TEXCOORD_OPENGL);
break;
}
}
static unsigned char whitePixel[ 4] = { 255, 255, 255, 255};
bool imageLoaded = false;
switch (attrType)
{
case cgfxAttrDef::kAttrTypeColor1DTexture:
gGLFT->
glBindTexture(GL_TEXTURE_1D,textureId);
if( image.is_valid())
{
GL_TEXTURE_1D, GL_GENERATE_MIPMAP_SGIS, image.get_num_mipmaps() == 0);
image.upload_texture1D();
imageLoaded = true;
}
else
{
GL_TEXTURE_1D, 0, GL_RGBA, 1, 0,
GL_RGBA, GL_UNSIGNED_BYTE, whitePixel);
}
break;
case cgfxAttrDef::kAttrTypeColor2DTexture:
case cgfxAttrDef::kAttrTypeNormalTexture:
case cgfxAttrDef::kAttrTypeBumpTexture:
#if !defined(WIN32) && !defined(LINUX)
case cgfxAttrDef::kAttrTypeColor2DRectTexture:
#endif
gGLFT->glBindTexture(GL_TEXTURE_2D,textureId);
if( image.is_valid())
{
gGLFT->glTexParameteri(
GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, image.get_num_mipmaps() == 0);
image.upload_texture2D();
imageLoaded = true;
}
else
{
{
unsigned int width, height;
{
if (cgfxProfile::getTexCoordOrientation() ==
cgfxProfile::TEXCOORD_DIRECTX)
{
}
{
if (width > 2 && height > 2)
{
unsigned int p2Width, p2Height;
bool widthPowerOfTwo = textureInitPowerOfTwo(width, p2Width);
bool heightPowerOfTwo = textureInitPowerOfTwo(height, p2Height);
if(!widthPowerOfTwo || !heightPowerOfTwo)
{
width = p2Width;
height = p2Height;
img.
resize( p2Width, p2Height,
false );
}
}
gGLFT->glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, true);
GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
GL_RGBA, GL_UNSIGNED_BYTE, img.
pixels());
imageLoaded = true;
}
}
}
}
if (!imageLoaded) {
gGLFT->glTexImage2D(
GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0,
GL_RGBA, GL_UNSIGNED_BYTE, whitePixel);
}
break;
case cgfxAttrDef::kAttrTypeEnvTexture:
case cgfxAttrDef::kAttrTypeCubeTexture:
case cgfxAttrDef::kAttrTypeNormalizationTexture:
{
gGLFT->glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, textureId);
if( image.is_valid()) {
gGLFT->glTexParameteri(
GL_TEXTURE_CUBE_MAP_ARB, GL_GENERATE_MIPMAP_SGIS,
image.get_num_mipmaps() == 0);
for (int n = 0; n < 6; ++n)
{
GLenum target = GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB+n;
image.upload_texture2D(image.is_cubemap() ? n : 0, target);
}
imageLoaded = true;
}
else {
for (int n = 0; n < 6; ++n)
{
GLenum target = GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB+n;
gGLFT->glTexImage2D(
target, 0, GL_RGBA, 1, 1, 0,
GL_RGBA, GL_UNSIGNED_BYTE, whitePixel);
}
}
break;
}
case cgfxAttrDef::kAttrTypeColor3DTexture:
gGLFT->glBindTexture(GL_TEXTURE_3D,textureId);
if( image.is_valid())
{
image.upload_texture3D();
imageLoaded = true;
}
else {
GL_TEXTURE_3D, 0, GL_RGBA, 1, 1, 1, 0,
GL_RGBA, GL_UNSIGNED_BYTE, whitePixel);
}
break;
#if defined(WIN32) || defined(LINUX)
case cgfxAttrDef::kAttrTypeColor2DRectTexture:
gGLFT->glBindTexture(GL_TEXTURE_RECTANGLE_NV, textureId);
if( image.is_valid())
{
image.upload_textureRectangle();
imageLoaded = true;
}
else
{
gGLFT->glTexImage2D(
GL_TEXTURE_RECTANGLE_NV, 0, GL_RGBA, 1, 1, 0,
GL_RGBA, GL_UNSIGNED_BYTE, whitePixel);
}
break;
#endif
default:
assert(false);
}
return imageLoaded;
}
struct EntryKey
{
EntryKey(
const std::string& textureFilePath,
const std::string& shaderFxFile,
const std::string& attrName,
cgfxAttrDef::cgfxAttrType attrType
)
: fTextureFilePath(textureFilePath),
fShaderFxFile(shaderFxFile),
fAttrName(attrName),
fAttrType(attrType)
{}
EntryKey(const EntryKey& rhs)
: fTextureFilePath(rhs.fTextureFilePath),
fShaderFxFile(rhs.fShaderFxFile),
fAttrName(rhs. fAttrName),
fAttrType(rhs.fAttrType)
{}
const std::string fTextureFilePath;
const std::string fShaderFxFile;
const std::string fAttrName;
const cgfxAttrDef::cgfxAttrType fAttrType;
private:
const EntryKey& operator=(const EntryKey& rhs);
};
struct EntryKeyLessThan
{
bool operator()(const EntryKey& lhs, const EntryKey& rhs) const
{
if (lhs.fTextureFilePath < rhs.fTextureFilePath) {
return true;
}
if (lhs.fTextureFilePath > rhs.fTextureFilePath) {
return false;
}
if (lhs.fShaderFxFile < rhs.fShaderFxFile) {
return true;
}
if (lhs.fShaderFxFile > rhs.fShaderFxFile) {
return false;
}
if (lhs.fAttrName < rhs.fAttrName) {
return true;
}
if (lhs.fAttrName > rhs.fAttrName) {
return false;
}
if (lhs.fAttrType < rhs.fAttrType) {
return true;
}
return false;
}
};
}
class cgfxTextureCache::Imp : public cgfxTextureCache
{
public:
static Imp* sTheTextureCache;
Imp();
~Imp() override;
cgfxRCPtr<cgfxTextureCacheEntry> getTexture(
cgfxAttrDef::cgfxAttrType attrType
) override;
void dump() const override
{
fprintf(stderr, "*** Dumping texture cache ***\n");
const Map::const_iterator end = fEntries.end();
for (Map::const_iterator it = fEntries.begin(); it != end; ++it) {
fprintf(stderr, " entry = 0x%p, refCount = %d\n",
it->second.operator->(),
it->second->getRefCount());
fprintf(stderr, " tex file = \"%s\"\n",
it->first.fTextureFilePath.c_str());
fprintf(stderr, " fx file = \"%s\"\n",
it->first.fShaderFxFile.c_str());
fprintf(stderr, " attrName = %s, attrType = %s\n\n",
it->first.fAttrName.c_str(),
cgfxAttrDef::typeName(it->first.fAttrType));
}
}
static void flushEntry(const EntryKey& key)
{
sTheTextureCache->fEntries.erase(key);
}
private:
typedef std::map<EntryKey, cgfxRCPtr<cgfxTextureCacheEntry>, EntryKeyLessThan> Map;
Map fEntries;
};
cgfxTextureCache::Imp* cgfxTextureCache::Imp::sTheTextureCache = 0;
cgfxTextureCache::Imp::Imp()
{}
cgfxTextureCache::Imp::~Imp()
{}
cgfxRCPtr<cgfxTextureCacheEntry> cgfxTextureCache::Imp::getTexture(
cgfxAttrDef::cgfxAttrType attrType
)
{
computeTextureFilePath(texFileName, shaderFxFile).
asChar();
EntryKey key(textureFilePath.
asChar(), shaderFxFile.
asChar(), attrName.
asChar(), attrType);
const Map::const_iterator entryIt = fEntries.find(key);
if (entryIt != fEntries.end()) {
return entryIt->second;
}
GLuint textureId;
bool valid = allocateAndReadTexture(
textureFilePath, textureNode, attrType, textureId);
cgfxRCPtr<cgfxTextureCacheEntry> entry(
new cgfxTextureCacheEntry(
key.fTextureFilePath, key.fShaderFxFile, key.fAttrName, key.fAttrType,
textureId, valid));
fEntries.insert(std::make_pair(key,entry));
return entry;
}
cgfxTextureCacheEntry::~cgfxTextureCacheEntry()
{
glDeleteTextures(1, &fTextureId);
fTextureId = 0;
}
void cgfxTextureCacheEntry::markAsStaled()
{
fStaled = true;
addRef();
cgfxTextureCache::Imp::flushEntry(
EntryKey(fTextureFilePath, fShaderFxFile, fAttrName, fAttrType));
release();
}
void cgfxTextureCacheEntry::addRef()
{
++fRefCount;
};
void cgfxTextureCacheEntry::release()
{
-- fRefCount;
if (fRefCount == 1) {
cgfxTextureCache::Imp::flushEntry(
EntryKey(fTextureFilePath, fShaderFxFile, fAttrName, fAttrType));
}
else if (fRefCount == 0) {
delete this;
}
}
void cgfxTextureCache::initialize()
{
Imp::sTheTextureCache = new cgfxTextureCache::Imp;
}
void cgfxTextureCache::uninitialize()
{
delete Imp::sTheTextureCache;
Imp::sTheTextureCache = 0;
}
cgfxTextureCache& cgfxTextureCache::instance()
{
return *Imp::sTheTextureCache;
}
cgfxTextureCache::cgfxTextureCache()
{}
cgfxTextureCache::~cgfxTextureCache()
{}