/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
/*
* Copyright (C) 2006-2010 - Frictional Games
*
* This file is part of HPL1 Engine.
*/
#include "hpl1/engine/resources/TextureManager.h"
#include "hpl1/debug.h"
#include "hpl1/engine/graphics/Graphics.h"
#include "hpl1/engine/graphics/LowLevelGraphics.h"
#include "hpl1/engine/graphics/Texture.h"
#include "hpl1/engine/graphics/bitmap2D.h"
#include "hpl1/engine/resources/FileSearcher.h"
#include "hpl1/engine/resources/Resources.h"
#include "hpl1/engine/resources/low_level_resources.h"
#include "hpl1/engine/system/String.h"
#include "hpl1/engine/system/low_level_system.h"
namespace hpl {
//////////////////////////////////////////////////////////////////////////
// CONSTRUCTORS
//////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------
cTextureManager::cTextureManager(cGraphics *apGraphics, cResources *apResources)
: iResourceManager(apResources->GetFileSearcher(), apResources->GetLowLevel(),
apResources->GetLowLevelSystem()) {
mpGraphics = apGraphics;
mpResources = apResources;
mpLowLevelResources->getSupportedImageFormats(mlstFileFormats);
mvCubeSideSuffixes.push_back("_pos_x");
mvCubeSideSuffixes.push_back("_neg_x");
mvCubeSideSuffixes.push_back("_pos_y");
mvCubeSideSuffixes.push_back("_neg_y");
mvCubeSideSuffixes.push_back("_pos_z");
mvCubeSideSuffixes.push_back("_neg_z");
}
cTextureManager::~cTextureManager() {
STLMapDeleteAll(m_mapAttenuationTextures);
DestroyAll();
Log(" Destroyed all textures\n");
}
//-----------------------------------------------------------------------
//////////////////////////////////////////////////////////////////////////
// PUBLIC METHODS
//////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------
iTexture *cTextureManager::Create1D(const tString &asName, bool abUseMipMaps, bool abCompress,
eTextureType aType, unsigned int alTextureSizeLevel) {
return CreateFlatTexture(asName, abUseMipMaps, abCompress, aType, eTextureTarget_1D, alTextureSizeLevel);
}
//-----------------------------------------------------------------------
iTexture *cTextureManager::Create2D(const tString &asName, bool abUseMipMaps, bool abCompress,
eTextureType aType, unsigned int alTextureSizeLevel, eTextureTarget aTarget) {
return CreateFlatTexture(asName, abUseMipMaps, abCompress, aType, aTarget, alTextureSizeLevel);
}
//-----------------------------------------------------------------------
iTexture *cTextureManager::CreateAnim2D(const tString &asName, bool abUseMipMaps, bool abCompress,
eTextureType aType, unsigned int alTextureSizeLevel) {
BeginLoad(asName);
iTexture *pTexture = static_cast(GetByName(asName));
if (pTexture == NULL) {
tString sFileExt = cString::GetFileExt(asName);
tString sFileName = cString::SetFileExt(cString::GetFileName(asName), "");
tStringVec mvFileNames;
tString sTest = sFileName + "01." + sFileExt;
int lNum = 2;
tStringVec vPaths;
while (true) {
tString sPath = mpFileSearcher->GetFilePath(sTest);
if (sPath == "") {
break;
} else {
vPaths.push_back(sPath);
if (lNum < 10)
sTest = sFileName + "0" + cString::ToString(lNum) + "." + sFileExt;
else
sTest = sFileName + cString::ToString(lNum) + "." + sFileExt;
++lNum;
}
}
if (vPaths.empty()) {
Error("No textures found for animation %s\n", asName.c_str());
Error("Couldn't texture '%s'\n", asName.c_str());
EndLoad();
return NULL;
}
tBitmap2DVec vBitmaps;
for (size_t i = 0; i < vPaths.size(); ++i) {
Bitmap2D *pBmp = mpResources->GetLowLevel()->loadBitmap2D(vPaths[i]);
if (pBmp == NULL) {
Error("Couldn't load bitmap '%s'!\n", vPaths[i].c_str());
for (int j = 0; j < (int)vBitmaps.size(); j++)
hplDelete(vBitmaps[j]);
EndLoad();
return NULL;
}
vBitmaps.push_back(pBmp);
}
// Create the animated texture
pTexture = mpGraphics->GetLowLevel()->CreateTexture(asName, abUseMipMaps, aType,
eTextureTarget_2D);
pTexture->SetSizeLevel(alTextureSizeLevel);
if (pTexture->CreateAnimFromBitmapVec(&vBitmaps) == false) {
Error("Couldn't create animated texture '%s'!\n", asName.c_str());
hplDelete(pTexture);
for (int j = 0; j < (int)vBitmaps.size(); j++)
hplDelete(vBitmaps[j]);
EndLoad();
return NULL;
}
// Bitmaps no longer needed.
for (int j = 0; j < (int)vBitmaps.size(); j++)
hplDelete(vBitmaps[j]);
AddResource(pTexture);
}
if (pTexture)
pTexture->IncUserCount();
else
Error("Couldn't texture '%s'\n", asName.c_str());
EndLoad();
return pTexture;
}
//-----------------------------------------------------------------------
iTexture *cTextureManager::CreateCubeMap(const tString &asPathName, bool abUseMipMaps,
bool abCompress, eTextureType aType,
unsigned int alTextureSizeLevel) {
tString sName = cString::SetFileExt(asPathName, "");
iTexture *pTexture = static_cast(GetByName(sName));
BeginLoad(asPathName);
if (pTexture == NULL) {
// See if files for all faces exist
tStringVec vPaths;
tString sPath = "";
for (int i = 0; i < 6; i++) {
for (tStringListIt it = mlstFileFormats.begin(); it != mlstFileFormats.end(); ++it) {
tString sNewName = sName + mvCubeSideSuffixes[i] + "." + *it;
sPath = mpFileSearcher->GetFilePath(sNewName);
if (sPath != "")
break;
}
if (sPath == "") {
tString sNewName = sName + mvCubeSideSuffixes[i];
Error("Couldn't find %d-face '%s', for cubemap '%s'\n", i, sNewName.c_str(), sName.c_str());
return NULL;
}
vPaths.push_back(sPath);
}
// Load bitmaps for all faces
tBitmap2DVec vBitmaps;
for (int i = 0; i < 6; i++) {
Bitmap2D *pBmp = mpResources->GetLowLevel()->loadBitmap2D(vPaths[i]);
if (pBmp == NULL) {
Error("Couldn't load bitmap '%s'!\n", vPaths[i].c_str());
for (int j = 0; j < (int)vBitmaps.size(); j++)
hplDelete(vBitmaps[j]);
EndLoad();
return NULL;
}
vBitmaps.push_back(pBmp);
}
// Create the cubemap
pTexture = mpGraphics->GetLowLevel()->CreateTexture(sName, abUseMipMaps, aType,
eTextureTarget_CubeMap);
pTexture->SetSizeLevel(alTextureSizeLevel);
if (pTexture->CreateCubeFromBitmapVec(&vBitmaps) == false) {
Error("Couldn't create cubemap '%s'!\n", sName.c_str());
hplDelete(pTexture);
for (int j = 0; j < (int)vBitmaps.size(); j++)
hplDelete(vBitmaps[j]);
EndLoad();
return NULL;
}
// Bitmaps no longer needed.
for (int j = 0; j < (int)vBitmaps.size(); j++)
hplDelete(vBitmaps[j]);
AddResource(pTexture);
}
pTexture->IncUserCount();
EndLoad();
return pTexture;
}
//-----------------------------------------------------------------------
iResourceBase *cTextureManager::Create(const tString &asName) {
return Create2D(asName, true);
}
//-----------------------------------------------------------------------
void cTextureManager::Unload(iResourceBase *apResource) {
}
//-----------------------------------------------------------------------
void cTextureManager::Destroy(iResourceBase *apResource) {
apResource->DecUserCount();
if (apResource->HasUsers() == false) {
RemoveResource(apResource);
// Log("Deleting1 '%s'-%d\n",apResource->GetName().c_str() ,apResource);
// Log("Deleting2 '%s'-%d\n",apResource->GetName().c_str() ,(iTexture*)apResource);
// Log("Deleting1 %d\n",apResource);
// Log("Deleting2 %d\n",(iTexture*)apResource);
hplDelete(apResource);
}
}
//-----------------------------------------------------------------------
void cTextureManager::Update(float afTimeStep) {
tResourceHandleMapIt it = m_mapHandleResources.begin();
for (; it != m_mapHandleResources.end(); ++it) {
iResourceBase *pBase = it->second;
iTexture *pTexture = static_cast(pBase);
pTexture->Update(afTimeStep);
}
}
//-----------------------------------------------------------------------
iTexture *cTextureManager::CreateAttenuation(const tString &asFallOffName) {
tString sName = cString::ToLowerCase(asFallOffName);
tTextureAttenuationMapIt it = m_mapAttenuationTextures.find(sName);
if (it != m_mapAttenuationTextures.end())
return it->second;
tString sPath = "";
if (cString::GetFileExt(asFallOffName) != "") {
sPath = mpFileSearcher->GetFilePath(asFallOffName);
} else {
for (tStringListIt it2 = mlstFileFormats.begin(); it2 != mlstFileFormats.end(); ++it2) {
tString sFileName = cString::SetFileExt(asFallOffName, *it2);
sPath = mpFileSearcher->GetFilePath(sFileName);
if (sPath != "")
break;
}
}
if (sPath == "") {
Log("Couldn't find falloff map file '%s'\n", asFallOffName.c_str());
return NULL;
}
Bitmap2D *pBmp = mpResources->GetLowLevel()->loadBitmap2D(sPath);
if (pBmp == NULL) {
Log("Couldn't load bitmap '%s'\n", asFallOffName.c_str());
return NULL;
}
int lBmpChannels = pBmp->getNumChannels();
int lWidth = pBmp->getWidth();
const unsigned char *pPixels = static_cast(pBmp->getRawData());
iTexture *pTexture = mpGraphics->GetLowLevel()->CreateTexture("Attenuation", false, eTextureType_Normal, eTextureTarget_3D);
int lSize = 16;
int lAttChannels = 2;
cVector3f vCentre = ((float)lSize) / 2.0f;
float fMaxDist = ((float)lSize) / 2.0f; // radius of sphere
Common::Array vAttenMap;
vAttenMap.resize(lSize * lSize * lSize * lAttChannels);
// Log("CREATTING ATTENUTAION MAP\n");
for (int z = 0; z < lSize; ++z)
for (int y = 0; y < lSize; ++y)
for (int x = 0; x < lSize; ++x) {
cVector3f vPos((float)x, (float)y, (float)z);
vPos = vPos - vCentre;
float fDist = vPos.Length();
if (fDist > fMaxDist)
fDist = fMaxDist;
float fNormDist = fDist / fMaxDist;
// unsigned char val = 255 - (unsigned char)(fNormDist * 255.0f);
int lTexPos = (int)(fNormDist * (float)lWidth);
if (lTexPos >= lWidth)
lTexPos = lWidth - 1;
unsigned char val = pPixels[lTexPos * lBmpChannels];
for (int i = 0; i < lAttChannels; ++i) {
vAttenMap[z * lSize * lSize * lAttChannels + y * lSize * lAttChannels + x * lAttChannels + i] = val;
}
}
pTexture->CreateFromArray(&vAttenMap[0], lAttChannels, cVector3l(16, 16, 16));
pTexture->SetWrapS(eTextureWrap_ClampToBorder);
pTexture->SetWrapT(eTextureWrap_ClampToBorder);
pTexture->SetWrapR(eTextureWrap_ClampToBorder);
hplDelete(pBmp);
m_mapAttenuationTextures.insert(tTextureAttenuationMap::value_type(sName, pTexture));
return pTexture;
}
//-----------------------------------------------------------------------
//////////////////////////////////////////////////////////////////////////
// PRIVATE METHODS
//////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------
iTexture *cTextureManager::CreateFlatTexture(const tString &asName, bool abUseMipMaps,
bool abCompress, eTextureType aType, eTextureTarget aTarget,
unsigned int alTextureSizeLevel) {
tString sPath;
BeginLoad(asName);
Common::ScopedPtr pTexture(FindTexture2D(asName, sPath));
if (!pTexture && sPath != "") {
// Load the bitmaps
Common::ScopedPtr bmp(mpLowLevelResources->loadBitmap2D(sPath));
if (!bmp) {
Hpl1::logError(Hpl1::kDebugResourceLoading, "Texturemanager Couldn't load bitmap '%s'\n", sPath.c_str());
EndLoad();
return nullptr;
}
// Create the texture and load from bitmap
pTexture.reset(mpGraphics->GetLowLevel()->CreateTexture(asName, abUseMipMaps, aType,
aTarget));
if (!pTexture) {
EndLoad();
return nullptr;
}
pTexture->SetSizeLevel(alTextureSizeLevel);
if (!pTexture->CreateFromBitmap(bmp.get())) {
EndLoad();
return nullptr;
}
AddResource(pTexture.get());
}
if (pTexture)
pTexture->IncUserCount();
else
Hpl1::logError(Hpl1::kDebugResourceLoading, "texture '%s' is invalid\n", asName.c_str());
EndLoad();
return pTexture.release();
}
//-----------------------------------------------------------------------
iTexture *cTextureManager::FindTexture2D(const tString &asName, tString &asFilePath) {
iTexture *pTexture = NULL;
if (cString::GetFileExt(asName) == "") {
for (tStringListIt it = mlstFileFormats.begin(); it != mlstFileFormats.end(); ++it) {
tString sNewName = cString::SetFileExt(asName, *it);
pTexture = static_cast(FindLoadedResource(sNewName, asFilePath));
if ((pTexture == NULL && asFilePath != "") || pTexture != NULL)
break;
}
} else {
pTexture = static_cast(FindLoadedResource(asName, asFilePath));
}
return pTexture;
}
//-----------------------------------------------------------------------
} // namespace hpl