#include "include/TextureManager/SalmonTexture.h" #include "include/Utils/Utils.h" #include "include/Engine.h" #include "boost/gil/gil_all.hpp" #include "boost/gil/extension/numeric/sampler.hpp" #include "boost/gil/extension/numeric/resample.hpp" #include "boost/assign.hpp" namespace SE { TTextureListClass::TTextureListClass() { using namespace boost::assign; using namespace std; CreateFunctionMap[".bmp"] = boost::bind(&TTextureListClass::CreateTexDataFromBmp24, this, _1, _2); CreateFunctionMap[".bmp32"] = boost::bind(&TTextureListClass::CreateTexDataFromBmp32, this, _1, _2); CreateFunctionMap[".png"] = boost::bind(&TTextureListClass::CreateTexDataFromPng, this, _1, _2); CreateFunctionMap[".tga"] = boost::bind(&TTextureListClass::CreateTexDataFromTga, this, _1, _2); AddFunctionMap["bmp24"] = boost::bind(&TTextureListClass::AddTextureBmp24Data, this, _1); AddFunctionMap["bmp32"] = boost::bind(&TTextureListClass::AddTextureBmp32Data, this, _1); } TTextureListClass::~TTextureListClass() { Clear(); *Console<<"ResourceManager::TexList deleting"; } void TTextureListClass::Clear() { PerformInMainThreadAsync(boost::bind(&TTextureListClass::InnerClear, this)); } void TTextureListClass::InnerClear() { AssertIfInMainThread(); if (TexMap.size() != 0) { BOOST_FOREACH(auto& i, TexMap) { glDeleteTextures(1,&(i.second.TexID)); } TexMap.clear(); *Console<<"ResourceManager::TexList cleared"; } } void TTextureListClass::Serialize(boost::property_tree::ptree& propertyTree) { BOOST_FOREACH(boost::property_tree::ptree::value_type &v, propertyTree.get_child("Textures")) { std::string fileName = v.second.get("FileName"); std::string texName = v.second.get("TexName", ""); AddTexture(fileName, texName); } } void TTextureListClass::NormalizeTexData(TTextureData& texData) { using namespace boost::gil; if (IsPower2(texData.Width) && IsPower2(texData.Height)) { return; } cardinal newWidth = GetGreaterPower2(texData.Width); cardinal newHeight = GetGreaterPower2(texData.Height); if (!strcmp(texData.Format, "bmp32")) { boost::shared_array newData(new char [newWidth * newHeight * 4]); rgba8_view_t oldView = interleaved_view(texData.Width, texData.Height, reinterpret_cast(texData.Data.get()), texData.DataSize / texData.Height); rgba8_image_t newImage(newWidth, newHeight); resize_view(oldView, view(newImage), bilinear_sampler()); texData.Data = newData; texData.Width = newWidth; texData.Height = newHeight; texData.DataSize = newWidth * newHeight * 4; oldView = interleaved_view(texData.Width, texData.Height, reinterpret_cast(texData.Data.get()), texData.DataSize / texData.Height); copy_pixels(view(newImage), oldView); } else if (!strcmp(texData.Format, "bmp24")) { boost::shared_array newData(new char [newWidth * newHeight * 3]); rgb8_view_t oldView = interleaved_view(texData.Width, texData.Height, reinterpret_cast(texData.Data.get()), texData.DataSize / texData.Height); rgb8_image_t newImage(newWidth, newHeight); resize_view(oldView, view(newImage), bilinear_sampler()); texData.Data = newData; texData.Width = newWidth; texData.Height = newHeight; texData.DataSize = newWidth * newHeight * 3; oldView = interleaved_view(texData.Width, texData.Height, reinterpret_cast(texData.Data.get()), texData.DataSize / texData.Height); copy_pixels(view(newImage), oldView); } else { throw ErrorToLog("TTextureListClass::NormalizeTexData Format unsupported: "+std::string(texData.Format)); } } bool TTextureListClass::CreateTexDataFromBmp24(const std::string& filename, TTextureData& texData) { cardinal fileSize; boost::shared_array fileArr = CreateMemFromFile(filename, fileSize); if (fileSize<22) throw ErrorFileNotCorrect(filename); //This refers to BITMAPV5HEADER strcpy(texData.Format, "bmp24"); texData.Width = *reinterpret_cast(&fileArr[18]); texData.Height = *reinterpret_cast(&fileArr[22]); texData.DataSize = texData.Height * texData.Width * 3; texData.Data = boost::shared_array(new char [texData.DataSize]); cardinal pos = *reinterpret_cast(&fileArr[10]); cardinal x = 0; for (cardinal i=0; ifileSize) throw ErrorFileTooShort(filename); x = (i * texData.Height + j) + (i * texData.Height + j) + (i * texData.Height + j); texData.Data[x + 2] = fileArr[pos++]; texData.Data[x + 1] = fileArr[pos++]; texData.Data[x + 0] = fileArr[pos++]; } return true; } bool TTextureListClass::CreateTexDataFromBmp32(const std::string& filename, TTextureData& texData) { cardinal fileSize; boost::shared_array fileArr = CreateMemFromFile(filename, fileSize); if (fileSize<22) throw ErrorFileNotCorrect(filename); //Meaning BITMAPV5HEADER strcpy(texData.Format, "bmp32"); texData.Width = *reinterpret_cast(&fileArr[18]); texData.Height = *reinterpret_cast(&fileArr[22]); texData.DataSize = texData.Height * texData.Width * 4; texData.Data = boost::shared_array(new char [texData.DataSize]); cardinal pos = *reinterpret_cast(&fileArr[10]); cardinal x = 0; for (cardinal i=0; ifileSize) throw ErrorFileTooShort(filename); x = (i * texData.Height + j) * 4; texData.Data[x + 2] = fileArr[pos++]; texData.Data[x + 1] = fileArr[pos++]; texData.Data[x + 0] = fileArr[pos++]; texData.Data[x + 3] = fileArr[pos++]; } //delete [] fileArr; return true; } bool TTextureListClass::CreateTexDataFromTga(const std::string& filename, TTextureData& texData) { cardinal fileSize; boost::shared_array fileArr = CreateMemFromFile(filename, fileSize); if (fileSize < 22) throw ErrorFileNotCorrect(filename); texData.Width = *reinterpret_cast(&fileArr[12]); texData.Height = *reinterpret_cast(&fileArr[14]); char textLength = fileArr[0]; char dataType = fileArr[2]; char bitsPerPixel = fileArr[16]; if (bitsPerPixel == 24) { texData.DataSize = texData.Height * texData.Width * 3; texData.Data = boost::shared_array(new char [texData.DataSize]); strcpy(texData.Format, "bmp24"); } else if (bitsPerPixel == 32) { texData.DataSize = texData.Height * texData.Width * 4; texData.Data = boost::shared_array(new char [texData.DataSize]); strcpy(texData.Format, "bmp32"); } else throw ErrorFileNotCorrect(filename); int bytesPerPixel = bitsPerPixel / 8; unsigned char blockInfo; char whatItIs; unsigned int numPixels; cardinal n = 0; int filePos = textLength + 18; if (dataType == 2) { for(cardinal n = 0; n < texData.Height * texData.Width; n++) { texData.Data[n*bytesPerPixel + 2] = fileArr[filePos++]; texData.Data[n*bytesPerPixel + 1] = fileArr[filePos++]; texData.Data[n*bytesPerPixel + 0] = fileArr[filePos++]; if (bitsPerPixel == 32) { texData.Data[n*bytesPerPixel + 3] = fileArr[filePos++]; } } } else if (dataType == 10) { throw ErrorToLog("RLE-compressed TGA is not supported yet: "+filename); while (n < texData.Height * texData.Width) { blockInfo = fileArr[filePos++]; whatItIs = blockInfo & 128; numPixels = blockInfo & 127; if (whatItIs) { for (cardinal i=0; i fileArr = CreateMemFromFile(filename, fileSize); if (fileSize < 22) throw ErrorFileNotCorrect(filename); TPngDataStruct s = read_png_file(fileArr, fileSize); texData.Width = s.Width; texData.Height = s.Height; cardinal bytesPerPixel; if (s.ColorType == PNG_COLOR_TYPE_RGB) { strcpy(texData.Format, "bmp24"); bytesPerPixel = 3; } else if (s.ColorType == PNG_COLOR_TYPE_RGBA) { strcpy(texData.Format, "bmp32"); bytesPerPixel = 4; } texData.DataSize = texData.Height * texData.Width * bytesPerPixel; texData.Data = boost::shared_array(new char [texData.DataSize]); cardinal x; for (cardinal i=0; iPathToResources + fileName; boost::function f = boost::bind(&TTextureListClass::AddTextureDirectly, this, fullFileName, texName); return PerformInMainThread(f); } cardinal TTextureListClass::AddTextureFromUserdata(const std::string& fileName, std::string texName) { if (!IsFileExistsInUserData(fileName)) { throw ErrorToLog("File not found in userdata: "+fileName); } std::string fullFileName = GetFilePathUserData(fileName); boost::function f = boost::bind(&TTextureListClass::AddTextureDirectly, this, fullFileName, texName); return PerformInMainThread(f); } cardinal TTextureListClass::AddCubemapTexture(std::string filename[6]) { AssertIfInMainThread(); filename[0] = ResourceManager->PathToResources + filename[0]; filename[1] = ResourceManager->PathToResources + filename[1]; filename[2] = ResourceManager->PathToResources + filename[2]; filename[3] = ResourceManager->PathToResources + filename[3]; filename[4] = ResourceManager->PathToResources + filename[4]; filename[5] = ResourceManager->PathToResources + filename[5]; std::string texname = GetFileName(filename[0]); std::string texext; cardinal TexID; int i; if (TexMap.count(texname) == 0) { TTextureData texData[6]; for (i = 0; i < 6; i++) { texext = GetFileExt(filename[i]); *Console<<"Going to add texture: "+filename[i]; if (texext == ".bmp") { if (!CreateTexDataFromBmp24(filename[i],texData[i])) { *Console<<"ResourceManager::TexList ERROR - TEXTURE LOAD FAILED: "+texname; return 0; } } else { *Console<<"ResourceManager::TexList ERROR - FORMAT NOT SUPPORTED: "+texext; return 0; } } //All textures have been inserted into texData[6], lets add them TexID = AddCubemapTextureBmp24Data(texData); //for (int j = 0; j < 6; j++) delete [] texData[j].Data; if (TexID != 0) { TexMap[texname].RefCount = 1; TexMap[texname].TexID = TexID; *Console<<"ResourceManager::TexList texture added succesfuly: "+texname; return TexID; } else { *Console<<"ResourceManager::TexList ERROR - TEXTURE ADD TO OPENGL FAILED: "+texname; return 0; } } else { ++TexMap[texname].RefCount; *Console<<"ResourceManager::TexList Texture reference added: "+texname; return TexMap[texname].TexID; } } cardinal TTextureListClass::AddEmptyTexture(const std::string& texName,cardinal width,cardinal height) { AssertIfInMainThread(); cardinal texID; if (TexMap.count(texName) == 0) { glGenTextures(1, &texID); glBindTexture(GL_TEXTURE_2D, texID); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); #ifdef TARGET_WIN32 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL); #endif #ifndef TARGET_WIN32 //TARGET_ANDROID or TARGET_IOS glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); #endif } else { TexMap[texName].RefCount++; texID = TexMap[texName].TexID; } return texID; } cardinal TTextureListClass::AddEmptyCubemapTexture(const std::string& texName,cardinal width,cardinal height) { AssertIfInMainThread(); cardinal texID; if (TexMap.count(texName) == 0) { glGenTextures(1, &texID); glBindTexture(GL_TEXTURE_CUBE_MAP, texID); #ifdef TARGET_WIN32 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X+0, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL); glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X+1, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL); glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X+2, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL); glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X+3, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL); glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X+4, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL); glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X+5, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL); #endif #ifndef TARGET_WIN32 //TARGET_IOS or TARGET_ANDROID glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X+0, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X+1, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X+2, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X+3, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X+4, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X+5, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); #endif } else { TexMap[texName].RefCount++; texID = TexMap[texName].TexID; } return texID; } cardinal TTextureListClass::AddDepthTexture(const std::string& texName,cardinal width,cardinal height) { AssertIfInMainThread(); #ifdef TARGET_WIN32 cardinal texID; if (TexMap.count(texName) == 0) { glGenTextures(1, &texID); glBindTexture(GL_TEXTURE_2D, texID); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32, width, height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL); } else { TexMap[texName].RefCount++; texID = TexMap[texName].TexID; } return texID; #endif #ifdef TARGET_ANDROID throw ErrorToLog("Trying to create depth texture on Android!!!"); return 0; #endif #ifdef TARGET_IOS throw ErrorToLog("Trying to create depth texture on iOS!!!"); return 0; #endif } void TTextureListClass::DeleteTexture(const std::string& texName) { AssertIfInMainThread(); if (TexMap.count(texName) != 0) { --TexMap[texName].RefCount; if (TexMap[texName].RefCount == 0) { glDeleteTextures(1,&(TexMap[texName].TexID)); TexMap.erase(texName); *Console<<"ResourceManager::TexList texture "+texName+" deleted"; } else *Console<<"ResourceManager::TexList texture "+texName+" reference deleted"; } } void TTextureListClass::DeleteTexture(cardinal texID) { AssertIfInMainThread(); TTextureMap::iterator i = TexMap.begin(); while (i != TexMap.end()) { if (i->second.TexID == texID) { (i->second.RefCount)--; if (i->second.RefCount == 0) { glDeleteTextures(1,&(i->second.TexID)); *Console << "ResourceManager::TexList texture " + (i->first) + " deleted"; TexMap.erase(i); } else *Console<<"ResourceManager::TexList texture "+(i->first)+" reference deleted"; i = TexMap.end(); //to go out of loop } else { ++i; } } } void TTextureListClass::PrintTextureList() { TTextureMap::iterator i; Console->PrintImmediate("======= Texture List =========="); for (i = TexMap.begin(); i != TexMap.end(); ++i) { Console->PrintImmediate("ID="+tostr(i->second.TexID) + " " + i->first +" Ref="+tostr(i->second.RefCount)); } } void TTextureListClass::BindFunctions() { //*Console<<"Bind functions in TTextureListClass\n"; ResourceManager->ScriptManager.AddFunction("ptl", TScriptInfo("PrintTextureList"), *this, &TTextureListClass::PrintTextureList); } void TTextureListClass::SaveTexDataToPlainBmpToUserData(const std::string& fileName, TTextureData texData) { std::string fullFileName = GetFilePathUserData(fileName); FILE * pFile; pFile = fopen (fullFileName.c_str(), "wb"); if (pFile == NULL) { throw ErrorToLog("pFile == NULL in TTextureListClass::SaveTexDataToPlainBmp"); } char DummyBuffer[10]; fwrite (DummyBuffer, 1, 10, pFile); //0 -> 10 int rgbDataOffset = 26; fwrite (&rgbDataOffset, 4, 1, pFile); //10 -> 14 fwrite (DummyBuffer, 1, 4, pFile); //14 -> 18 fwrite (&(texData.Width), 4, 1, pFile); //18 -> 22 fwrite (&(texData.Height), 4, 1, pFile); //22 -> 26 cardinal x = 0; for (cardinal i = 0; i < texData.Width; i++) { for(cardinal j = 0; j < texData.Height; j++) { x = (i * texData.Height + j) + (i * texData.Height + j) + (i * texData.Height + j); fwrite (&(texData.Data[x + 2]), 1, 1, pFile); fwrite (&(texData.Data[x + 1]), 1, 1, pFile); fwrite (&(texData.Data[x + 0]), 1, 1, pFile); } } fclose (pFile); } } //namespace SE