📄 gtexmanager.cc
字号:
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#include "platform/platformAssert.h"
#include "platform/platformGL.h"
#include "platform/platform.h"
#include "core/tVector.h"
#include "core/resManager.h"
#include "dgl/gBitmap.h"
#include "dgl/gPalette.h"
#include "dgl/gTexManager.h"
#include "console/console.h"
#include "console/consoleInternal.h"
#include "console/consoleTypes.h"
#include "dgl/gChunkedTexManager.h"
//------------------------------------------------------------------------------
bool gDGLRender = true;
bool sgResurrect = false;
bool sgForcePalettedTexture = false;
bool sgForce16BitTexture = false;
#define ENABLE_HOLDING 1
#ifdef TORQUE_GATHER_METRICS
U32 TextureManager::smTextureSpaceLoaded = 0;
U32 TextureManager::smTextureCacheMisses = 0;
#endif
bool TextureManager::smUseSmallTextures = false;
bool TextureManager::smIsZombie = false;
bool TextureManager::smTextureManagerActive = false;
//--------------------------------------------------------------------------
//-------------------------------------- Texture detailing control variables
// 0: Highest
// 1: ...
// 2: ...
// 3: Lowest
namespace {
struct Forced16BitMapping
{
GLenum wanted;
GLenum forced;
bool end;
};
Forced16BitMapping sg16BitMappings[] =
{
{ GL_RGB, GL_RGB5, false },
{ GL_RGBA, GL_RGBA4, false },
{ 0, 0, true }
};
U32 sgTextureDetailLevel = 0;
U32 sgSkyTextureDetailLevel = 0;
U32 sgInteriorTextureDetailLevel = 0;
bool sgAllowTexCompression = false;
GLenum sgCompressionHint = GL_FASTEST;
F32 sgTextureAnisotropy = 0.0; // default aniso, when available. not sure why prefs.cs isn't setting.
bool sgDisableSubImage = false;
bool sgTextureTrilinear = false;
// valid texture extensions
#define EXT_ARRAY_SIZE 6
static const char* extArray[EXT_ARRAY_SIZE] = { "", ".jpg", ".png", ".gif", ".bmp", "" };
static const char* extArray_8[EXT_ARRAY_SIZE] = { "", ".bm8", ".bmp", ".jpg", ".png", ".gif" };
ConsoleFunctionGroupBegin( OpenGLTex, "Functions controlling OpenGL parameters.");
ConsoleFunction(setOpenGLMipReduction, void, 2, 2, "( n ) Sets mipmap reduction level, n ranges from 0-5.")
{
argc;
S32 val = dAtoi(argv[1]);
if (val < 0)
val = 0;
else if (val > 5)
val = 5;
sgTextureDetailLevel = val;
}
ConsoleFunction(setOpenGLSkyMipReduction, void, 2, 2, "setOpenGLSkyMipReduction(0-5);")
{
argc;
S32 val = dAtoi(argv[1]);
if (val < 0)
val = 0;
else if (val > 5)
val = 5;
sgSkyTextureDetailLevel = val;
}
ConsoleFunction(setOpenGLInteriorMipReduction, void, 2, 2, "setOpenGLInteriorMipReduction(0-5);")
{
argc;
S32 val = dAtoi(argv[1]);
if (val < 0)
val = 0;
else if (val > 5)
val = 5;
sgInteriorTextureDetailLevel = val;
}
ConsoleFunction(setOpenGLTextureCompressionHint, void, 2, 2, "setTextureCompressionHint(GL_DONT_CARE|GL_FASTEST|GL_NICEST);")
{
argc;
GLenum newHint = GL_DONT_CARE;
const char* newString = "GL_DONT_CARE";
if (!dStricmp(argv[1], "GL_FASTEST"))
{
newHint = GL_FASTEST;
newString = "GL_FASTEST";
}
else if (!dStricmp(argv[1], "GL_NICEST"))
{
newHint = GL_NICEST;
newString = "GL_NICEST";
}
sgCompressionHint = newHint;
if (dglDoesSupportTextureCompression())
glHint(GL_TEXTURE_COMPRESSION_HINT_ARB, sgCompressionHint);
}
ConsoleFunction(setOpenGLAnisotropy, void, 2, 2, "setOpenGLAnisotropy(0-1);")
{
argc;
F32 val = dAtof(argv[1]);
if (val < 0.0)
val = 0.0;
if (val > dglGetMaxAnisotropy())
val = dglGetMaxAnisotropy();
sgTextureAnisotropy = val;
if(dglDoesSupportTexAnisotropy())
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, sgTextureAnisotropy * dglGetMaxAnisotropy());
}
ConsoleFunctionGroupEnd( OpenGLTex );
} // namespace {}
//--------------------------------------
struct TextureDictionary
{
static TextureObject **smTable;
static TextureObject *smTOList;
static U32 smHashTableSize;
static void create();
static void preDestroy();
static void destroy();
static void insert(TextureObject *object);
static TextureObject *find(StringTableEntry name, TextureHandleType type, bool clamp);
static void remove(TextureObject *object);
static S32 clearHolds();
};
TextureObject **TextureDictionary::smTable = NULL;
TextureObject *TextureDictionary::smTOList = NULL;
U32 TextureDictionary::smHashTableSize = 0;
//--------------------------------------
void TextureDictionary::create()
{
smTOList = NULL;
smHashTableSize = 1023;
smTable = new TextureObject *[smHashTableSize];
for(U32 i = 0; i < smHashTableSize; i++)
smTable[i] = NULL;
Con::addVariable("$pref::OpenGL::force16BitTexture", TypeBool, &sgForce16BitTexture);
Con::addVariable("$pref::OpenGL::forcePalettedTexture", TypeBool, &sgForcePalettedTexture);
Con::addVariable("$pref::OpenGL::allowCompression", TypeBool, &sgAllowTexCompression);
Con::addVariable("$pref::OpenGL::disableSubImage", TypeBool, &sgDisableSubImage);
Con::addVariable("$pref::OpenGL::textureTrilinear", TypeBool, &sgTextureTrilinear);
Con::addVariable("$pref::OpenGL::textureAnisotropy", TypeF32, &sgTextureAnisotropy);
}
//--------------------------------------
TextureObject *TextureDictionary::find(StringTableEntry name, TextureHandleType type, bool clamp)
{
U32 key = HashPointer(name) % smHashTableSize;
TextureObject *walk = smTable[key];
for(; walk; walk = walk->hashNext)
if(walk->texFileName == name && walk->type == type && walk->clamp == clamp)
break;
return walk;
}
//--------------------------------------
void TextureDictionary::remove(TextureObject *object)
{
if(object->next)
object->next->prev = object->prev;
if(object->prev)
object->prev->next = object->next;
else
smTOList = object->next;
if(!object->texFileName)
return;
U32 key = HashPointer(object->texFileName) % smHashTableSize;
TextureObject **walk = &smTable[key];
while(*walk)
{
if(*walk == object)
{
*walk = object->hashNext;
break;
}
walk = &((*walk)->hashNext);
}
}
//--------------------------------------
void TextureDictionary::insert(TextureObject *object)
{
object->next = smTOList;
object->prev = NULL;
if(smTOList)
smTOList->prev = object;
smTOList = object;
if(object->texFileName)
{
U32 key = HashPointer(object->texFileName) % smHashTableSize;
object->hashNext = smTable[key];
smTable[key] = object;
}
}
//--------------------------------------
void TextureDictionary::preDestroy()
{
// This is a horrid hack, but it will have to do for now. (DMM, aided
// and abetted by MF.)
TextureObject* walk = smTOList;
while (walk)
{
if((gDGLRender || sgResurrect) && walk->texGLName)
glDeleteTextures(1, (const GLuint*)&walk->texGLName);
if((gDGLRender || sgResurrect) && walk->smallTexGLName)
glDeleteTextures(1, (const GLuint*)&walk->smallTexGLName);
delete walk->bitmap;
walk->texGLName = 0;
walk->smallTexGLName = 0;
walk->bitmap = NULL;
walk = walk->next;
}
}
//--------------------------------------
void TextureDictionary::destroy()
{
// This is a horrid hack, but it will have to do for now. (DMM, aided
// and abetted by MF.)
while(smTOList)
TextureManager::freeTexture(smTOList);
delete[] smTable;
}
//--------------------------------------
S32 TextureDictionary::clearHolds()
{
Vector<TextureObject *> holds;
// Find held textures to delete. Clear holding flag too so they're free
// to go away.
for (TextureObject * walk = smTOList; walk; walk = walk->next)
{
if (walk->holding)
{
if (!walk->refCount)
holds.push_back(walk);
else
walk->holding = false;
}
}
// Remove them-
for (S32 i = 0; i < holds.size(); i++)
TextureManager::freeTexture(holds[i]);
return holds.size();
}
ConsoleFunction(clearTextureHolds, S32, 1, 1, "clearTextureHolds();")
{
argc; argv;
return TextureDictionary::clearHolds();
}
//--------------------------------------------------------------------------
//--------------------------------------
//
struct EventCallbackEntry
{
TextureEventCallback callback;
void * userData;
U32 key;
};
static U32 sgCurrCallbackKey = 0;
static Vector<EventCallbackEntry> sgEventCallbacks(__FILE__, __LINE__);
U32 TextureManager::registerEventCallback(TextureEventCallback callback, void *userData)
{
sgEventCallbacks.increment();
sgEventCallbacks.last().callback = callback;
sgEventCallbacks.last().userData = userData;
sgEventCallbacks.last().key = sgCurrCallbackKey++;
return sgEventCallbacks.last().key;
}
void TextureManager::unregisterEventCallback(const U32 callbackKey)
{
for (S32 i = 0; i < sgEventCallbacks.size(); i++)
if (sgEventCallbacks[i].key == callbackKey) {
sgEventCallbacks.erase(i);
return;
}
}
void TextureManager::postTextureEvent(const U32 eventCode)
{
for (S32 i = 0; i < sgEventCallbacks.size(); i++)
(sgEventCallbacks[i].callback)(eventCode, sgEventCallbacks[i].userData);
}
void TextureManager::create()
{
AssertISV(!smTextureManagerActive, "TextureManager::create - already created!");
TextureDictionary::create();
smTextureManagerActive = true;
}
void TextureManager::preDestroy()
{
AssertISV(smTextureManagerActive, "TextureManager::preDestroy - nothing to destroy!");
TextureDictionary::preDestroy();
}
void TextureManager::destroy()
{
AssertISV(smTextureManagerActive, "TextureManager::destroy - nothing to destroy!");
TextureDictionary::destroy();
AssertFatal(sgEventCallbacks.size() == 0,
"Error, some object didn't unregister it's texture event callback function!");
smTextureManagerActive = false;
}
//--------------------------------------
void TextureManager::makeZombie()
{
if (smIsZombie == true)
return;
smIsZombie = true;
postTextureEvent(BeginZombification);
ChunkedTextureManager::makeZombie();
// Publish flush event?
Vector<GLuint> deleteNames(4096);
TextureObject* probe = TextureDictionary::smTOList;
while (probe)
{
AssertFatal(probe->type != TerrainTexture, "Error, all the terrain textureobjects should be gone by now!");
if (probe->type == BitmapNoDownloadTexture)
{
probe = probe->next;
continue;
}
if (probe->texGLName != 0)
deleteNames.push_back(probe->texGLName);
if (probe->smallTexGLName != 0)
deleteNames.push_back(probe->smallTexGLName);
#ifdef TORQUE_GATHER_METRICS
AssertFatal(probe->textureSpace <= smTextureSpaceLoaded, "Error, that shouldn't happen!");
smTextureSpaceLoaded -= probe->textureSpace;
probe->textureSpace = 0;
#endif
probe->texGLName = 0;
probe->smallTexGLName = 0;
probe = probe->next;
}
glDeleteTextures(deleteNames.size(), deleteNames.address());
}
void TextureManager::resurrect()
{
if (smIsZombie == false)
return;
smIsZombie = false;
sgResurrect = true;
// Get rid of any chunked textures created while the app was inactive
ChunkedTextureManager::makeZombie();
// Reload textures...
TextureObject* probe = TextureDictionary::smTOList;
while (probe)
{
// reload texture...
AssertFatal(probe->type != TerrainTexture, "Error, all the terrain textureobjects should be gone by now!");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -