From 22245a880164e0aad31de7f78a213e833581b33e Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Sat, 11 Feb 2017 21:02:21 +0100 Subject: [PATCH 1/5] introduced opengl texture object --- AnimModel.cpp | 16 ++- AnimModel.h | 3 +- DynObj.cpp | 48 ++++---- DynObj.h | 2 +- Globals.cpp | 12 +- Globals.h | 6 +- Ground.cpp | 6 +- Ground.h | 3 +- Model3d.cpp | 14 +-- Model3d.h | 5 +- Texture.cpp | 296 ++++++++++++++++++++++++-------------------------- Texture.h | 93 ++++++++-------- Track.cpp | 8 +- Track.h | 5 +- World.cpp | 14 +-- World.h | 2 +- stdafx.h | 1 + 17 files changed, 272 insertions(+), 262 deletions(-) diff --git a/AnimModel.cpp b/AnimModel.cpp index 54e0d2b6..1c6814f8 100644 --- a/AnimModel.cpp +++ b/AnimModel.cpp @@ -449,12 +449,16 @@ bool TAnimModel::Init(std::string const &asName, std::string const &asReplacable asText = asReplacableTexture.substr(1, asReplacableTexture.length() - 1); // zapamiętanie tekstu else if (asReplacableTexture != "none") ReplacableSkinId[1] = - TTexturesManager::GetTextureID(NULL, NULL, asReplacableTexture.c_str()); - if (TTexturesManager::GetAlpha(ReplacableSkinId[1])) - iTexAlpha = - 0x31310031; // tekstura z kanałem alfa - nie renderować w cyklu nieprzezroczystych - else - iTexAlpha = 0x30300030; // tekstura nieprzezroczysta - nie renderować w cyklu + TTexturesManager.GetTextureId( asReplacableTexture, "" ); + if( ( ReplacableSkinId[ 1 ] != 0 ) + && ( TTexturesManager.Texture( ReplacableSkinId[ 1 ] ).has_alpha ) ) { + // tekstura z kanałem alfa - nie renderować w cyklu nieprzezroczystych + iTexAlpha = 0x31310031; + } + else{ + // tekstura nieprzezroczysta - nie renderować w cyklu + iTexAlpha = 0x30300030; + } // przezroczystych return (Init(TModelsManager::GetModel(asName.c_str()))); } diff --git a/AnimModel.h b/AnimModel.h index 8ceebcda..bc688a5d 100644 --- a/AnimModel.h +++ b/AnimModel.h @@ -16,6 +16,7 @@ http://mozilla.org/MPL/2.0/. #define AnimModelH #include "Model3d.h" +#include "Texture.h" const int iMaxNumLights = 8; @@ -148,7 +149,7 @@ class TAnimModel void RaAnimate(); // przeliczenie animacji egzemplarza void RaPrepare(); // ustawienie animacji egzemplarza na wzorcu public: - GLuint ReplacableSkinId[5]; // McZapkie-020802: zmienialne skory + texture_manager::size_type ReplacableSkinId[5]; // McZapkie-020802: zmienialne skory static TAnimContainer *acAnimList; // lista animacji z eventem, które muszą być przeliczane // również bez wyświetlania TAnimModel(); diff --git a/DynObj.cpp b/DynObj.cpp index 7c4618e0..2af42063 100644 --- a/DynObj.cpp +++ b/DynObj.cpp @@ -4417,7 +4417,7 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName, Global::asCurrentTexturePath + ReplacableSkin; // skory tez z dynamic/... std::string x = TextureTest(Global::asCurrentTexturePath + "nowhere"); // na razie prymitywnie if (!x.empty()) - ReplacableSkinID[4] = TTexturesManager::GetTextureID(NULL, NULL, Global::asCurrentTexturePath + "nowhere", 9); + ReplacableSkinID[4] = TTexturesManager.GetTextureId( Global::asCurrentTexturePath + "nowhere", "", 9); /* if ((i = ReplacableSkin.Pos("|")) > 0) // replacable dzielone { @@ -4480,24 +4480,22 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName, */ if (iMultiTex > 0) { // jeśli model ma 4 tekstury - ReplacableSkinID[1] = TTexturesManager::GetTextureID( - NULL, NULL, ReplacableSkin + ",1", Global::iDynamicFiltering); + ReplacableSkinID[1] = TTexturesManager.GetTextureId( + ReplacableSkin + ",1", "", Global::iDynamicFiltering); if (ReplacableSkinID[1]) { // pierwsza z zestawu znaleziona - ReplacableSkinID[2] = TTexturesManager::GetTextureID( - NULL, NULL, ReplacableSkin + ",2", Global::iDynamicFiltering); + ReplacableSkinID[2] = TTexturesManager.GetTextureId( + ReplacableSkin + ",2", "", Global::iDynamicFiltering); if (ReplacableSkinID[2]) { iMultiTex = 2; // już są dwie - ReplacableSkinID[3] = TTexturesManager::GetTextureID( - NULL, NULL, ReplacableSkin + ",3", - Global::iDynamicFiltering); + ReplacableSkinID[3] = TTexturesManager.GetTextureId( + ReplacableSkin + ",3", "", Global::iDynamicFiltering); if (ReplacableSkinID[3]) { iMultiTex = 3; // a teraz nawet trzy - ReplacableSkinID[4] = TTexturesManager::GetTextureID( - NULL, NULL, ReplacableSkin + ",4", - Global::iDynamicFiltering); + ReplacableSkinID[4] = TTexturesManager.GetTextureId( + ReplacableSkin + ",4", "", Global::iDynamicFiltering); if (ReplacableSkinID[4]) iMultiTex = 4; // jak są cztery, to blokujemy podmianę tekstury // rozkładem @@ -4507,14 +4505,14 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName, else { // zestaw nie zadziałał, próbujemy normanie iMultiTex = 0; - ReplacableSkinID[1] = TTexturesManager::GetTextureID( - NULL, NULL, ReplacableSkin, Global::iDynamicFiltering); + ReplacableSkinID[1] = TTexturesManager.GetTextureId( + ReplacableSkin, "", Global::iDynamicFiltering); } } else - ReplacableSkinID[1] = TTexturesManager::GetTextureID( - NULL, NULL, ReplacableSkin, Global::iDynamicFiltering); - if (TTexturesManager::GetAlpha(ReplacableSkinID[1])) + ReplacableSkinID[1] = TTexturesManager.GetTextureId( + ReplacableSkin, "", Global::iDynamicFiltering); + if (TTexturesManager.Texture(ReplacableSkinID[1]).has_alpha) iAlpha = 0x31310031; // tekstura -1 z kanałem alfa - nie renderować w cyklu // nieprzezroczystych else @@ -4522,21 +4520,22 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName, // renderować w // cyklu przezroczystych if (ReplacableSkinID[2]) - if (TTexturesManager::GetAlpha(ReplacableSkinID[2])) + if (TTexturesManager.Texture(ReplacableSkinID[2]).has_alpha) iAlpha |= 0x02020002; // tekstura -2 z kanałem alfa - nie renderować // w cyklu // nieprzezroczystych if (ReplacableSkinID[3]) - if (TTexturesManager::GetAlpha(ReplacableSkinID[3])) + if (TTexturesManager.Texture(ReplacableSkinID[3]).has_alpha) iAlpha |= 0x04040004; // tekstura -3 z kanałem alfa - nie renderować // w cyklu // nieprzezroczystych if (ReplacableSkinID[4]) - if (TTexturesManager::GetAlpha(ReplacableSkinID[4])) + if (TTexturesManager.Texture(ReplacableSkinID[4]).has_alpha) iAlpha |= 0x08080008; // tekstura -4 z kanałem alfa - nie renderować // w cyklu // nieprzezroczystych } +/* // Winger 040304 - ladowanie przedsionkow dla EZT if (MoverParameters->TrainType == dt_EZT) { @@ -4544,6 +4543,7 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName, asModel = BaseDir + asModel; mdPrzedsionek = TModelsManager::GetModel(asModel, true); } +*/ if (!MoverParameters->LoadAccepted.empty()) // if (MoverParameters->LoadAccepted!=AnsiString("")); // && // MoverParameters->LoadType!=AnsiString("passengers")) @@ -5849,13 +5849,13 @@ void TDynamicObject::DestinationSet(std::string to, std::string numer) std::string x = TextureTest(asBaseDir + numer + "@" + MoverParameters->TypeName); if (!x.empty()) { - ReplacableSkinID[4] = TTexturesManager::GetTextureID( NULL, NULL, x, 9); // rozmywania 0,1,4,5 nie nadają się + ReplacableSkinID[4] = TTexturesManager.GetTextureId( x, "", 9); // rozmywania 0,1,4,5 nie nadają się return; } x = TextureTest(asBaseDir + numer ); if (!x.empty()) { - ReplacableSkinID[4] = TTexturesManager::GetTextureID( NULL, NULL, x, 9); // rozmywania 0,1,4,5 nie nadają się + ReplacableSkinID[4] = TTexturesManager.GetTextureId( x, "", 9); // rozmywania 0,1,4,5 nie nadają się return; } if (to.empty()) @@ -5863,17 +5863,17 @@ void TDynamicObject::DestinationSet(std::string to, std::string numer) x = TextureTest(asBaseDir + to + "@" + MoverParameters->TypeName); // w pierwszej kolejności z nazwą FIZ/MMD if (!x.empty()) { - ReplacableSkinID[4] = TTexturesManager::GetTextureID( NULL, NULL, x, 9); // rozmywania 0,1,4,5 nie nadają się + ReplacableSkinID[4] = TTexturesManager.GetTextureId( x, "", 9); // rozmywania 0,1,4,5 nie nadają się return; } x = TextureTest(asBaseDir + to); // na razie prymitywnie if (!x.empty()) - ReplacableSkinID[4] = TTexturesManager::GetTextureID( NULL, NULL, x, 9); // rozmywania 0,1,4,5 nie nadają się + ReplacableSkinID[4] = TTexturesManager.GetTextureId( x, "", 9); // rozmywania 0,1,4,5 nie nadają się else { x = TextureTest(asBaseDir + "nowhere"); // jak nie znalazł dedykowanej, to niech daje nowhere if (!x.empty()) - ReplacableSkinID[4] = TTexturesManager::GetTextureID(NULL, NULL, x, 9); + ReplacableSkinID[4] = TTexturesManager.GetTextureId( x, "", 9); } // Ra 2015-01: żeby zalogować błąd, trzeba by mieć pewność, że model używa // tekstury nr 4 diff --git a/DynObj.h b/DynObj.h index e49ff803..56f31d02 100644 --- a/DynObj.h +++ b/DynObj.h @@ -395,7 +395,7 @@ private: int iCabs; // maski bitowe modeli kabin TTrack *MyTrack; // McZapkie-030303: tor na ktorym stoi, ABu std::string asBaseDir; - GLuint ReplacableSkinID[5]; // McZapkie:zmienialne nadwozie + texture_manager::size_type ReplacableSkinID[5]; // McZapkie:zmienialne nadwozie int iAlpha; // maska przezroczystości tekstur int iMultiTex; //<0 tekstury wskazane wpisem, >0 tekstury z przecinkami, =0 jedna int iOverheadMask; // maska przydzielana przez AI pojazdom posiadającym pantograf, aby wymuszały diff --git a/Globals.cpp b/Globals.cpp index 397f0a6d..1780eee5 100644 --- a/Globals.cpp +++ b/Globals.cpp @@ -60,8 +60,8 @@ int Global::iScreenMode[12] = {0, 0, 0, 0, 0, 0, double Global::fSunDeclination = 0.0; // deklinacja Słońca double Global::fTimeAngleDeg = 0.0; // godzina w postaci kąta float Global::fClockAngleDeg[6]; // kąty obrotu cylindrów dla zegara cyfrowego -char *Global::szTexturesTGA[4] = {"tga", "dds", "tex", "bmp"}; // lista tekstur od TGA -char *Global::szTexturesDDS[4] = {"dds", "tga", "tex", "bmp"}; // lista tekstur od DDS +std::string Global::szTexturesTGA = ".tga"; // lista tekstur od TGA +std::string Global::szTexturesDDS = ".dds"; // lista tekstur od DDS int Global::iKeyLast = 0; // ostatnio naciśnięty klawisz w celu logowania GLuint Global::iTextureId = 0; // ostatnio użyta tekstura 2D int Global::iPause = 0x10; // globalna pauza ruchu @@ -135,7 +135,7 @@ int Global::iDynamicFiltering = 5; // domyślne rozmywanie tekstur pojazdów bool Global::bUseVBO = false; // czy jest VBO w karcie graficznej (czy użyć) GLint Global::iMaxTextureSize = 16384; // maksymalny rozmiar tekstury bool Global::bSmoothTraction = false; // wygładzanie drutów starym sposobem -char **Global::szDefaultExt = Global::szTexturesDDS; // domyślnie od DDS +std::string Global::szDefaultExt = Global::szTexturesDDS; // domyślnie od DDS int Global::iMultisampling = 2; // tryb antyaliasingu: 0=brak,1=2px,2=4px,3=8px,4=16px bool Global::bGlutFont = false; // czy tekst generowany przez GLUT32.DLL int Global::iConvertModels = 7; // tworzenie plików binarnych, +2-optymalizacja transformów @@ -422,6 +422,12 @@ void Global::ConfigParse(cParser &Parser) // domyślnie od TGA Global::szDefaultExt = Global::szTexturesTGA; } + else { + Global::szDefaultExt = + ( token[ 0 ] == '.' ? + token : + "." + token ); + } } else if (token == "newaircouplers") { diff --git a/Globals.h b/Globals.h index 38f18281..c50f5d83 100644 --- a/Globals.h +++ b/Globals.h @@ -184,7 +184,7 @@ class Global static double fFogStart; static double fFogEnd; static TGround *pGround; - static char **szDefaultExt; + static std::string szDefaultExt; static std::string SceneryFile; static char CreatorName1[20]; static char CreatorName2[20]; @@ -258,8 +258,8 @@ class Global static double fTimeAngleDeg; // godzina w postaci kąta static float fClockAngleDeg[6]; // kąty obrotu cylindrów dla zegara cyfrowego static double fLatitudeDeg; // szerokość geograficzna - static char *szTexturesTGA[4]; // lista tekstur od TGA - static char *szTexturesDDS[4]; // lista tekstur od DDS + static std::string szTexturesTGA; // lista tekstur od TGA + static std::string szTexturesDDS; // lista tekstur od DDS static int iMultisampling; // tryb antyaliasingu: 0=brak,1=2px,2=4px,3=8px,4=16px static bool bGlutFont; // tekst generowany przez GLUT static int iKeyLast; // ostatnio naciśnięty klawisz w celu logowania diff --git a/Ground.cpp b/Ground.cpp index 39f74e65..69df2d6e 100644 --- a/Ground.cpp +++ b/Ground.cpp @@ -2103,14 +2103,14 @@ TGroundNode * TGround::AddGroundNode(cParser *parser) // PROBLEND Q: 13122011 - Szociu: 27012012 PROBLEND = true; // domyslnie uruchomione nowe wyświetlanie tmp->PROBLEND = true; // odwolanie do tgroundnode, bo rendering jest w tej klasie - if (str.find("@") != string::npos) // sprawdza, czy w nazwie tekstury jest znak "@" + if (str.find('@') != string::npos) // sprawdza, czy w nazwie tekstury jest znak "@" { PROBLEND = false; // jeśli jest, wyswietla po staremu tmp->PROBLEND = false; } #endif - tmp->TextureID = TTexturesManager::GetTextureID(szTexturePath, szSceneryPath, str.c_str()); - tmp->iFlags = TTexturesManager::GetAlpha(tmp->TextureID) ? 0x220 : 0x210; // z usuwaniem + tmp->TextureID = TTexturesManager.GetTextureId( str, szTexturePath ); + tmp->iFlags = TTexturesManager.Texture(tmp->TextureID).has_alpha ? 0x220 : 0x210; // z usuwaniem if (((tmp->iType == GL_TRIANGLES) && (tmp->iFlags & 0x10)) ? Global::pTerrainCompact->TerrainLoaded() : false) diff --git a/Ground.h b/Ground.h index 099eff67..b78023d6 100644 --- a/Ground.h +++ b/Ground.h @@ -14,6 +14,7 @@ http://mozilla.org/MPL/2.0/. #include "VBO.h" #include "Classes.h" #include "ResourceManager.h" +#include "Texture.h" #include "dumb3d.h" #include "Names.h" @@ -141,7 +142,7 @@ class TGroundNode : public Resource GLuint DisplayListID; // numer siatki DisplayLists bool PROBLEND; int iVboPtr; // indeks w buforze VBO - GLuint TextureID; // główna (jedna) tekstura obiektu + texture_manager::size_type TextureID; // główna (jedna) tekstura obiektu int iFlags; // tryb przezroczystości: 0x10-nieprz.,0x20-przezroczysty,0x30-mieszany int Ambient[4], Diffuse[4], Specular[4]; // oświetlenie bool bVisible; diff --git a/Model3d.cpp b/Model3d.cpp index f70dd091..59f9bbbc 100644 --- a/Model3d.cpp +++ b/Model3d.cpp @@ -411,13 +411,12 @@ int TSubModel::Load(cParser &parser, TModel3d *Model, int Pos, bool dynamic) TextureNameSet(texture.c_str()); if (texture.find_first_of("/\\") == texture.npos) texture.insert(0, Global::asCurrentTexturePath.c_str()); - TextureID = TTexturesManager::GetTextureID( - szTexturePath, const_cast(Global::asCurrentTexturePath.c_str()), texture); + TextureID = TTexturesManager.GetTextureId( texture, szTexturePath ); // TexAlpha=TTexturesManager::GetAlpha(TextureID); // iFlags|=TexAlpha?0x20:0x10; //0x10-nieprzezroczysta, 0x20-przezroczysta if (Opacity < 1.0) // przezroczystość z tekstury brana tylko dla Opacity // 0! - iFlags |= TTexturesManager::GetAlpha(TextureID) ? + iFlags |= TTexturesManager.Texture(TextureID).has_alpha ? 0x20 : 0x10; // 0x10-nieprzezroczysta, 0x20-przezroczysta else @@ -616,7 +615,7 @@ int TSubModel::Load(cParser &parser, TModel3d *Model, int Pos, bool dynamic) return iNumVerts; // do określenia wielkości VBO }; -int TSubModel::TriangleAdd(TModel3d *m, int tex, int tri) +int TSubModel::TriangleAdd(TModel3d *m, texture_manager::size_type tex, int tri) { // dodanie trójkątów do submodelu, używane // przy tworzeniu E3D terenu TSubModel *s = this; @@ -637,7 +636,7 @@ int TSubModel::TriangleAdd(TModel3d *m, int tex, int tri) m->AddTo(this, s); } // s->asTexture=AnsiString(TTexturesManager::GetName(tex).c_str()); - s->TextureNameSet(TTexturesManager::GetName(tex).c_str()); + s->TextureNameSet(TTexturesManager.Texture(tex).name.c_str()); s->TextureID = tex; s->eType = GL_TRIANGLES; // iAnimOwner=0; //roboczy wskaźnik na wierzchołek @@ -1625,15 +1624,14 @@ void TSubModel::BinInit(TSubModel *s, float4x4 *m, float8 *v, TStringPack *t, TS std::string tex = pTexture; if (tex.find_last_of("/\\") == std::string::npos) tex.insert(0, Global::asCurrentTexturePath); - TextureID = TTexturesManager::GetTextureID( - szTexturePath, const_cast(Global::asCurrentTexturePath.c_str()), tex); + TextureID = TTexturesManager.GetTextureId( tex, szTexturePath ); // TexAlpha=TTexturesManager::GetAlpha(TextureID); //zmienna robocza // ustawienie cyklu przezroczyste/nieprzezroczyste zależnie od własności // stałej tekstury // iFlags=(iFlags&~0x30)|(TTexturesManager::GetAlpha(TextureID)?0x20:0x10); // //0x10-nieprzezroczysta, 0x20-przezroczysta if (Opacity < 1.0) // przezroczystość z tekstury brana tylko dla Opacity 0! - iFlags |= TTexturesManager::GetAlpha(TextureID) ? + iFlags |= TTexturesManager.Texture(TextureID).has_alpha ? 0x20 : 0x10; // 0x10-nieprzezroczysta, 0x20-przezroczysta else diff --git a/Model3d.h b/Model3d.h index 0653673b..c6adc688 100644 --- a/Model3d.h +++ b/Model3d.h @@ -15,6 +15,7 @@ http://mozilla.org/MPL/2.0/. #include "dumb3d.h" #include "Float3d.h" #include "VBO.h" +#include "Texture.h" using namespace Math3D; @@ -215,7 +216,7 @@ class TSubModel // światła float fCosViewAngle; // cos kata pod jakim sie teraz patrzy // Ra: dalej są zmienne robocze, można je przestawiać z zachowaniem rozmiaru klasy - int TextureID; // numer tekstury, -1 wymienna, 0 brak + texture_manager::size_type TextureID; // numer tekstury, -1 wymienna, 0 brak bool bWire; // nie używane, ale wczytywane // short TexAlpha; //Ra: nie używane już GLuint uiDisplayList; // roboczy numer listy wyświetlania @@ -271,7 +272,7 @@ class TSubModel { return Child; }; - int TriangleAdd(TModel3d *m, int tex, int tri); + int TriangleAdd(TModel3d *m, texture_manager::size_type tex, int tri); float8 * TrianglePtr(int tex, int pos, int *la, int *ld, int *ls); // float8* TrianglePtr(const char *tex,int tri); // void SetRotate(vector3 vNewRotateAxis,float fNewAngle); diff --git a/Texture.cpp b/Texture.cpp index e16d85c8..1ad3622a 100644 --- a/Texture.cpp +++ b/Texture.cpp @@ -26,11 +26,20 @@ http://mozilla.org/MPL/2.0/. #include "Usefull.h" #include "TextureDDS.h" +texture_manager TTexturesManager; + +/* TTexturesManager::Alphas TTexturesManager::_alphas; TTexturesManager::Names TTexturesManager::_names; +*/ +void +texture_manager::Init() { -void TTexturesManager::Init(){}; + // since index 0 is used to indicate no texture, we put a blank entry in the first texture slot + m_textures.emplace_back( opengl_texture() ); +} +/* TTexturesManager::Names::iterator TTexturesManager::LoadFromFile(std::string fileName, int filter) { @@ -81,7 +90,8 @@ TTexturesManager::Names::iterator TTexturesManager::LoadFromFile(std::string fil // WriteLog("OK"); //Ra: "OK" nie potrzeba, samo "Failed" wystarczy return ret.first; }; - +*/ +/* struct ReplaceSlash { const char operator()(const char input) @@ -89,159 +99,137 @@ struct ReplaceSlash return input == '/' ? '\\' : input; } }; +*/ +// ustalenie numeru tekstury, wczytanie jeśli nie jeszcze takiej nie było +texture_manager::size_type +texture_manager::GetTextureId( std::string Filename, std::string const &Dir, int const Filter ) { -GLuint TTexturesManager::GetTextureID(char *dir, char *where, std::string fileName, int filter) -{ // ustalenie numeru tekstury, wczytanie jeśli nie jeszcze takiej nie było - /* - // Ra: niby tak jest lepiej, ale działa gorzej, więc przywrócone jest oryginalne - //najpierw szukamy w katalogu, z którego wywoływana jest tekstura, potem z wyższego - //Ra: przerobić na wyszukiwanie w drzewie nazw, do którego zapisywać np. rozmiary, - przezroczystość - //Ra: ustalać, które tekstury można wczytać już w trakcie symulacji - size_t pos=fileName.find(':'); //szukamy dwukropka - if (pos!=std::string::npos) //po dwukropku mogą być podane dodatkowe informacje - fileName=fileName.substr(0,pos); //niebędące nazwą tekstury - std::transform(fileName.begin(),fileName.end(),fileName.begin(),ReplaceSlash()); //zamiana "/" - na "\" - //jeśli bieżaca ścieżka do tekstur nie została dodana to dodajemy domyślną - //if (fileName.find('\\')==std::string::npos) //bz sensu - // fileName.insert(0,szDefaultTexturePath); - //najpierw szukamy w podanym katalogu, potem w domyślnym - Names::iterator iter; - std::ifstream file; - if ((fileName.find('.')==fileName.npos)?true:(fileName.rfind('.')second; //znalezione! - if (dir) - {//może we wskazanym katalogu? - test=fileName; - test.insert(0,dir); //jeszcze próba z dodatkową ścieżką - test.append(Global::szDefaultExt[i]); //dodanie jednego z kilku rozszerzeń - iter=_names.find(test); //czy mamy już w magazynie? - if (iter!=_names.end()) - return iter->second; //znalezione! - } - //} - //for (int i=0;i<4;++i) - //{//w magazynie nie ma, to sprawdzamy na dysku - test=fileName; - if (where) test.insert(0,where); //ścieżka obiektu wywołującego - test.append(Global::szDefaultExt[i]); //dodanie jednego z kilku rozszerzeń - file.open(test.c_str()); - if (!file.is_open()) - {test=fileName; - if (dir) test.insert(0,dir); //próba z dodatkową ścieżką - test.append(Global::szDefaultExt[i]); //dodanie jednego z kilku rozszerzeń - file.open(test.c_str()); - } - if (file.is_open()) - {//jak znaleziony, to plik zostaje otwarty - fileName=test; //zapamiętanie znalezionego rozszerzenia - break; //wyjście z pętli na etapie danego rozszerzenia - } - } - } - else - {//gdy jest kropka, to rozszerzenie jest jawne - std::string test; //zmienna robocza - //najpierw szukamy w magazynie - test=fileName; - if (where) test.insert(0,where); //ścieżka obiektu wywołującego - iter=_names.find(test); //czy mamy już w magazynie? - if (iter!=_names.end()) - return iter->second; //znalezione! - test=fileName; - if (dir) test.insert(0,dir); //jeszcze próba z dodatkową ścieżką - iter=_names.find(test); //czy mamy już w magazynie? - if (iter!=_names.end()) - return iter->second; //znalezione! - //w magazynie nie ma, to sprawdzamy na dysku - test=fileName; - if (where) test.insert(0,where); //ścieżka obiektu wywołującego - file.open(test.c_str()); - if (!file.is_open()) - {//jak znaleziony, to plik zostaje otwarty - test=fileName; - if (dir) test.insert(0,dir); //próba z dodatkową ścieżką - file.open(test.c_str()); - if (file.is_open()) - fileName=test; //ustalenie nowej nazwy - } - } - if (file.is_open()) - {//plik pozostaje otwarty, gdy znaleziono na dysku - file.close(); //można już zamknąć - iter=LoadFromFile(fileName,filter); //doda się do magazynu i zwróci swoją pozycję - } - */ - size_t pos = fileName.find(':'); // szukamy dwukropka - if (pos != std::string::npos) // po dwukropku mogą być podane dodatkowe informacje - fileName = fileName.substr(0, pos); // niebędące nazwą tekstury - pos = fileName.find('|'); // szukamy separatora tekstur - if (pos != std::string::npos) // po | może być nazwa kolejnej tekstury - fileName = fileName.substr(0, pos); // i trzeba to obciąć - std::transform(fileName.begin(), fileName.end(), fileName.begin(), ReplaceSlash()); - // jeśli bieżaca ścieżka do tekstur nie została dodana to dodajemy domyślną - if (fileName.find('\\') == std::string::npos) - fileName.insert(0, szTexturePath); - Names::iterator iter; - if (fileName.find('.') == std::string::npos) - { // Ra: wypróbowanie rozszerzeń po kolei, zaczynając od domyślnego - fileName.append("."); // kropka będze na pewno, resztę trzeba próbować - std::string test; // zmienna robocza - for (int i = 0; i < 4; ++i) - { // najpierw szukamy w magazynie - test = fileName; - test.append(Global::szDefaultExt[i]); - iter = _names.find(fileName); // czy mamy już w magazynie? - if (iter != _names.end()) - return iter->second; // znalezione! - test.insert(0, szTexturePath); // jeszcze próba z dodatkową ścieżką - iter = _names.find(fileName); // czy mamy już w magazynie? - if (iter != _names.end()) - return iter->second; // znalezione! - } - for (int i = 0; i < 4; ++i) - { // w magazynie nie ma, to sprawdzamy na dysku - test = fileName; - test.append(Global::szDefaultExt[i]); - std::ifstream file(test.c_str()); - if (!file.is_open()) - { - test.insert(0, szTexturePath); - file.open(test.c_str()); + if( Filename.find( ':' ) != std::string::npos ) + Filename.erase( Filename.find( ':' ) ); // po dwukropku mogą być podane dodatkowe informacje niebędące nazwą tekstury + if( Filename.find( '|' ) != std::string::npos ) + Filename.erase( Filename.find( '|' ) ); // po | może być nazwa kolejnej tekstury + for( char &c : Filename ) { + // change forward slashes to windows ones. NOTE: probably not strictly necessary, but eh + c = ( c == '/' ? '\\' : c ); + } +/* + std::transform( + Filename.begin(), Filename.end(), + Filename.begin(), + []( char Char ){ return Char == '/' ? '\\' : Char; } ); +*/ + if( Filename.find( '\\' ) == std::string::npos ) { + // jeśli bieżaca ścieżka do tekstur nie została dodana to dodajemy domyślną + Filename = szTexturePath + Filename; + } + + std::vector extensions{ { ".dds" }, { ".tga" }, { ".bmp" }, { ".ext" } }; + + // try to locate requested texture in the databank + auto lookup = find_in_databank( Filename + Global::szDefaultExt ); + if( lookup != npos ) { + // start with the default extension... + return lookup; + } + else { + // ...then try recognized file extensions other than default + for( auto const &extension : extensions ) { + + if( extension == Global::szDefaultExt ) { + // we already tried this one + continue; } - if (file.is_open()) - { - fileName.append(Global::szDefaultExt[i]); // dopisanie znalezionego - file.close(); - break; // wyjście z pętli na etapie danego rozszerzenia + lookup = find_in_databank( Filename + extension ); + if( lookup != npos ) { + + return lookup; } } } - iter = _names.find(fileName); // czy mamy już w magazynie - if (iter == _names.end()) - iter = LoadFromFile(fileName, filter); - return (iter != _names.end() ? iter->second : 0); + // if we don't have the texture in the databank, check if it's on disk + std::string filename = find_on_disk( Filename + Global::szDefaultExt ); + if( true == filename.empty() ) { + // if the default lookup fails, try other known extensions + for( auto const &extension : extensions ) { + + if( extension == Global::szDefaultExt ) { + // we already tried this one + continue; + } + filename = find_on_disk( Filename + extension ); + if( false == filename.empty() ) { + // we found something, don't bother with others + break; + } + } + } + + if( true == filename.empty() ) { + // there's nothing matching in the databank nor on the disk, report failure + return npos; + } + + opengl_texture texture; + texture.name = filename; + m_textures.emplace_back( texture ); + auto const textureindex = m_textures.size() - 1; + m_texturemappings.emplace( filename, textureindex ); + + WriteLog( "Created texture object for file \"" + filename + "\"" ); + + return textureindex; }; +// checks whether specified texture is in the texture bank. returns texture id, or npos. +texture_manager::size_type +texture_manager::find_in_databank( std::string const &Texturename ) { + + auto lookup = m_texturemappings.find( Texturename ); + if( lookup != m_texturemappings.end() ) { + return lookup->second; + } + // jeszcze próba z dodatkową ścieżką + lookup = m_texturemappings.find( szTexturePath + Texturename ); + + return ( + lookup != m_texturemappings.end() ? + lookup->second : + npos ); +} + +// checks whether specified file exists. +std::string +texture_manager::find_on_disk( std::string const &Texturename ) { + + { + std::ifstream file( Texturename ); + if( true == file.is_open() ) { + // success + return Texturename; + } + + } + // if we fail make a last ditch attempt in the default textures directory + { + std::ifstream file( szTexturePath + Texturename ); + if( true == file.is_open() ) { + // success + return szTexturePath + Texturename; + } + + } + // no results either way, report failure + return ""; +} + +/* bool TTexturesManager::GetAlpha(GLuint id) { // atrybut przezroczystości dla tekstury o podanym numerze (id) Alphas::iterator iter = _alphas.find(id); return (iter != _alphas.end() ? iter->second : false); } - +*/ +/* TTexturesManager::AlphaValue TTexturesManager::LoadBMP(std::string const &fileName) { @@ -797,6 +785,8 @@ TTexturesManager::AlphaValue TTexturesManager::LoadDDS(std::string fileName, int return std::make_pair(id, data.components == 4); }; +*/ +/* void TTexturesManager::SetFiltering(int filter) { if (filter < 4) // rozmycie przy powiększeniu @@ -910,17 +900,16 @@ GLuint TTexturesManager::CreateTexture(GLubyte *buff, GLint bpp, int width, int return ID; } - -void TTexturesManager::Free() -{ // usunięcie wszyskich tekstur (bez usuwania struktury) - // for (Names::iterator iter = _names.begin(); iter != _names.end(); iter++) - if( false == _names.empty() ) { - for( auto const &texture : _names ) { - glDeleteTextures( 1, &texture.second ); - } - } +*/ +void +texture_manager::Free() +{ + for( auto const &texture : m_textures ) { + // usunięcie wszyskich tekstur (bez usuwania struktury) + glDeleteTextures( 1, &texture.id ); + } } - +/* std::string TTexturesManager::GetName(GLuint id) { // pobranie nazwy tekstury for( auto const &pair : _names ) { @@ -928,3 +917,4 @@ std::string TTexturesManager::GetName(GLuint id) } return ""; }; +*/ \ No newline at end of file diff --git a/Texture.h b/Texture.h index 8810d537..6d058f8f 100644 --- a/Texture.h +++ b/Texture.h @@ -12,49 +12,56 @@ http://mozilla.org/MPL/2.0/. #include #include "opengl/glew.h" +struct opengl_texture { + + GLuint id{ -1 }; // associated GL resource + bool has_alpha{ false }; // indicates the texture has alpha channel + bool is_ready{ false }; // indicates the texture was processed and is ready for use + std::string name; // name of the texture source file + std::vector data; // texture data + /*std::atomic*/ bool is_loaded{ false }; // indicates the texture data was loaded and can be processed + /*std::atomic*/ bool is_good{ false }; // indicates the texture data was retrieved without errors +}; + +class texture_manager { + +private: + typedef std::vector opengltexture_array; + +public: + typedef opengltexture_array::size_type size_type; + + ~texture_manager() { Free(); } + + size_type GetTextureId( std::string Filename, std::string const &Dir, int const Filter = -1 ); + opengl_texture &Texture( size_type const Id ) { return m_textures.at( Id ); } + void Init(); + void Free(); + +private: + typedef std::unordered_map index_map; /* -//Ra: miejsce umieszczenia tego jest deczko bezsensowne -void glDebug() -{//logowanie błędów OpenGL - GLenum err; - if (Global::iErorrCounter==326) //tu wpisz o 1 mniej niz wartość, przy której się wyłożyło - Global::iErorrCounter=Global::iErorrCounter+0; //do zastawiania pułapki przed błędnym kodem - while ((err=glGetError())!=GL_NO_ERROR) //dalej jest pułapka po wykonaniu błędnego kodu - WriteLog("OpenGL error found: "+AnsiString(err)+", step:"+AnsiString(Global::iErorrCounter)); - ++Global::iErorrCounter; -}; + opengltexture_array::size_type LoadFromFile(std::string name, int filter = -1); */ - -class TTexturesManager -{ - public: - static void Init(); - static void Free(); - - static GLuint GetTextureID(char *dir, char *where, std::string name, int filter = -1); - static bool GetAlpha(GLuint ID); // McZapkie-141203: czy tekstura ma polprzeroczystosc - static std::string GetName(GLuint id); - - private: - typedef std::pair AlphaValue; - - typedef std::map Names; - typedef std::map Alphas; - - static Names::iterator LoadFromFile(std::string name, int filter = -1); - - static AlphaValue LoadBMP(std::string const &fileName); - static AlphaValue LoadTEX(std::string fileName); - static AlphaValue LoadTGA(std::string fileName, int filter = -1); - static AlphaValue LoadDDS(std::string fileName, int filter = -1); - - static void SetFiltering(int filter); - static void SetFiltering(bool alpha, bool hash); - static GLuint CreateTexture(GLubyte *buff, GLint bpp, int width, int height, bool bHasAlpha, - bool bHash, bool bDollar = true, int filter = -1); - - static Names _names; - static Alphas _alphas; - // std::list Textures; +/* + bool LoadBMP( std::string const &fileName); + bool LoadTEX( std::string fileName ); + bool LoadTGA( std::string fileName, int filter = -1 ); + bool LoadDDS( std::string fileName, int filter = -1 ); +*/ + // checks whether specified texture is in the texture bank. returns texture id, or npos. + size_type find_in_databank( std::string const &Texturename ); + // checks whether specified file exists. returns name of the located file, or empty string. + std::string find_on_disk( std::string const &Texturename ); +/* + void SetFiltering(int filter); + void SetFiltering(bool alpha, bool hash); + GLuint CreateTexture(GLubyte *buff, GLint bpp, int width, int height, bool bHasAlpha, + bool bHash, bool bDollar = true, int filter = -1); +*/ + static const size_type npos{ 0 }; // should be -1, but the rest of the code uses -1 for something else + opengltexture_array m_textures; + index_map m_texturemappings; }; -//--------------------------------------------------------------------------- + +extern texture_manager TTexturesManager; \ No newline at end of file diff --git a/Track.cpp b/Track.cpp index 7386b98e..fd32a2ad 100644 --- a/Track.cpp +++ b/Track.cpp @@ -508,8 +508,8 @@ void TTrack::Load(cParser *parser, vector3 pOrigin, std::string name) parser->getTokens(); *parser >> token; str = token; // railtex - TextureID1 = (str == "none" ? 0 : TTexturesManager::GetTextureID( - szTexturePath, szSceneryPath, str, + TextureID1 = (str == "none" ? 0 : TTexturesManager.GetTextureId( + str, szTexturePath, (iCategoryFlag & 1) ? Global::iRailProFiltering : Global::iBallastFiltering)); parser->getTokens(); @@ -519,8 +519,8 @@ void TTrack::Load(cParser *parser, vector3 pOrigin, std::string name) parser->getTokens(); *parser >> token; str = token; // sub || railtex - TextureID2 = (str == "none" ? 0 : TTexturesManager::GetTextureID( - szTexturePath, szSceneryPath, str, + TextureID2 = (str == "none" ? 0 : TTexturesManager.GetTextureId( + str, szTexturePath, (eType == tt_Normal) ? Global::iBallastFiltering : Global::iRailProFiltering)); parser->getTokens(3); diff --git a/Track.h b/Track.h index 6382f0f0..0d3d9e5e 100644 --- a/Track.h +++ b/Track.h @@ -13,6 +13,7 @@ http://mozilla.org/MPL/2.0/. #include "opengl/glew.h" #include "ResourceManager.h" #include "Segment.h" +#include "Texture.h" class TEvent; @@ -136,8 +137,8 @@ class TTrack : public Resource TTrack *trNext = nullptr; // odcinek od strony punktu 2 - to powinno być w segmencie TTrack *trPrev = nullptr; // odcinek od strony punktu 1 // McZapkie-070402: dodalem zmienne opisujace rozmiary tekstur - GLuint TextureID1 = 0; // tekstura szyn albo nawierzchni - GLuint TextureID2 = 0; // tekstura automatycznej podsypki albo pobocza + texture_manager::size_type TextureID1 = 0; // tekstura szyn albo nawierzchni + texture_manager::size_type TextureID2 = 0; // tekstura automatycznej podsypki albo pobocza float fTexLength = 4.0; // długość powtarzania tekstury w metrach float fTexRatio1 = 1.0; // proporcja boków tekstury nawierzchni (żeby zaoszczędzić na rozmiarach tekstur...) float fTexRatio2 = 1.0; // proporcja boków tekstury chodnika (żeby zaoszczędzić na rozmiarach tekstur...) diff --git a/World.cpp b/World.cpp index 6ebe9161..9cfa8762 100644 --- a/World.cpp +++ b/World.cpp @@ -71,7 +71,7 @@ TWorld::~TWorld() // Ground.Free(); //Ra: usunięcie obiektów przed usunięciem dźwięków - sypie się TSoundsManager::Free(); TModelsManager::Free(); - TTexturesManager::Free(); +// TTexturesManager.Free(); glDeleteLists(base, 96); if (hinstGLUT32) FreeLibrary(hinstGLUT32); @@ -479,8 +479,7 @@ bool TWorld::Init(HWND NhWnd, HDC hDC) glDisable(GL_DEPTH_TEST); // Disables depth testing glColor3f(3.0f, 3.0f, 3.0f); - GLuint logo; - logo = TTexturesManager::GetTextureID(szTexturePath, szSceneryPath, "logo", 6); + auto logo = TTexturesManager.GetTextureId( "logo", szTexturePath, 6 ); glBindTexture(GL_TEXTURE_2D, logo); // Select our texture glBegin(GL_QUADS); // Drawing using triangles @@ -527,8 +526,9 @@ bool TWorld::Init(HWND NhWnd, HDC hDC) glPrint("Tekstury / Textures..."); } SwapBuffers(hDC); // Swap Buffers (Double Buffering) - - TTexturesManager::Init(); +/* + TTexturesManager.Init(); +*/ WriteLog("Textures init OK"); if (Global::detonatoryOK) { @@ -663,9 +663,9 @@ bool TWorld::Init(HWND NhWnd, HDC hDC) // glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); //{Texture blends with object // background} if (Global::bOldSmudge == true) - light = TTexturesManager::GetTextureID(szTexturePath, szSceneryPath, "smuga.tga"); + light = TTexturesManager.GetTextureId( "smuga.tga", szTexturePath ); else - light = TTexturesManager::GetTextureID(szTexturePath, szSceneryPath, "smuga2.tga"); + light = TTexturesManager.GetTextureId( "smuga2.tga", szTexturePath ); // Camera.Reset(); Timer::ResetTimers(); WriteLog( "Load time: " + diff --git a/World.h b/World.h index 7868971c..f710a515 100644 --- a/World.h +++ b/World.h @@ -51,7 +51,7 @@ class TWorld TDynamicObject *pDynamicNearest; bool Paused; GLuint base; // numer DL dla znaków w napisach - GLuint light; // numer tekstury dla smugi + texture_manager::size_type light; // numer tekstury dla smugi TSky Clouds; TEvent *KeyEvents[10]; // eventy wyzwalane z klawiaury TMoverParameters *mvControlled; // wskaźnik na człon silnikowy, do wyświetlania jego parametrów diff --git a/stdafx.h b/stdafx.h index 22d52bd3..d4c1225e 100644 --- a/stdafx.h +++ b/stdafx.h @@ -54,6 +54,7 @@ #include #include #include +#include #include #include #include From a8ece11c2755e051bab662e00f47fc998a789cfd Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Sun, 12 Feb 2017 20:06:05 +0100 Subject: [PATCH 2/5] removed direct texture binding. binding is now done through texture manager --- AnimModel.cpp | 4 +- DynObj.cpp | 32 +++--- Ground.cpp | 12 +-- Model3d.cpp | 52 +++++----- Model3d.h | 28 ++--- PyInt.cpp | 2 +- Segment.cpp | 2 +- Texture.cpp | 276 ++++++++++++++++++++++++++++++++++++++++++++++++-- Texture.h | 38 ++++++- Track.cpp | 48 ++++----- Traction.cpp | 5 +- World.cpp | 14 +-- 12 files changed, 398 insertions(+), 115 deletions(-) diff --git a/AnimModel.cpp b/AnimModel.cpp index 1c6814f8..f19210f3 100644 --- a/AnimModel.cpp +++ b/AnimModel.cpp @@ -449,9 +449,9 @@ bool TAnimModel::Init(std::string const &asName, std::string const &asReplacable asText = asReplacableTexture.substr(1, asReplacableTexture.length() - 1); // zapamiętanie tekstu else if (asReplacableTexture != "none") ReplacableSkinId[1] = - TTexturesManager.GetTextureId( asReplacableTexture, "" ); + TextureManager.GetTextureId( asReplacableTexture, "" ); if( ( ReplacableSkinId[ 1 ] != 0 ) - && ( TTexturesManager.Texture( ReplacableSkinId[ 1 ] ).has_alpha ) ) { + && ( TextureManager.Texture( ReplacableSkinId[ 1 ] ).has_alpha ) ) { // tekstura z kanałem alfa - nie renderować w cyklu nieprzezroczystych iTexAlpha = 0x31310031; } diff --git a/DynObj.cpp b/DynObj.cpp index 2af42063..c42b47ac 100644 --- a/DynObj.cpp +++ b/DynObj.cpp @@ -4417,7 +4417,7 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName, Global::asCurrentTexturePath + ReplacableSkin; // skory tez z dynamic/... std::string x = TextureTest(Global::asCurrentTexturePath + "nowhere"); // na razie prymitywnie if (!x.empty()) - ReplacableSkinID[4] = TTexturesManager.GetTextureId( Global::asCurrentTexturePath + "nowhere", "", 9); + ReplacableSkinID[4] = TextureManager.GetTextureId( Global::asCurrentTexturePath + "nowhere", "", 9); /* if ((i = ReplacableSkin.Pos("|")) > 0) // replacable dzielone { @@ -4480,21 +4480,21 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName, */ if (iMultiTex > 0) { // jeśli model ma 4 tekstury - ReplacableSkinID[1] = TTexturesManager.GetTextureId( + ReplacableSkinID[1] = TextureManager.GetTextureId( ReplacableSkin + ",1", "", Global::iDynamicFiltering); if (ReplacableSkinID[1]) { // pierwsza z zestawu znaleziona - ReplacableSkinID[2] = TTexturesManager.GetTextureId( + ReplacableSkinID[2] = TextureManager.GetTextureId( ReplacableSkin + ",2", "", Global::iDynamicFiltering); if (ReplacableSkinID[2]) { iMultiTex = 2; // już są dwie - ReplacableSkinID[3] = TTexturesManager.GetTextureId( + ReplacableSkinID[3] = TextureManager.GetTextureId( ReplacableSkin + ",3", "", Global::iDynamicFiltering); if (ReplacableSkinID[3]) { iMultiTex = 3; // a teraz nawet trzy - ReplacableSkinID[4] = TTexturesManager.GetTextureId( + ReplacableSkinID[4] = TextureManager.GetTextureId( ReplacableSkin + ",4", "", Global::iDynamicFiltering); if (ReplacableSkinID[4]) iMultiTex = 4; // jak są cztery, to blokujemy podmianę tekstury @@ -4505,14 +4505,14 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName, else { // zestaw nie zadziałał, próbujemy normanie iMultiTex = 0; - ReplacableSkinID[1] = TTexturesManager.GetTextureId( + ReplacableSkinID[1] = TextureManager.GetTextureId( ReplacableSkin, "", Global::iDynamicFiltering); } } else - ReplacableSkinID[1] = TTexturesManager.GetTextureId( + ReplacableSkinID[1] = TextureManager.GetTextureId( ReplacableSkin, "", Global::iDynamicFiltering); - if (TTexturesManager.Texture(ReplacableSkinID[1]).has_alpha) + if (TextureManager.Texture(ReplacableSkinID[1]).has_alpha) iAlpha = 0x31310031; // tekstura -1 z kanałem alfa - nie renderować w cyklu // nieprzezroczystych else @@ -4520,17 +4520,17 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName, // renderować w // cyklu przezroczystych if (ReplacableSkinID[2]) - if (TTexturesManager.Texture(ReplacableSkinID[2]).has_alpha) + if (TextureManager.Texture(ReplacableSkinID[2]).has_alpha) iAlpha |= 0x02020002; // tekstura -2 z kanałem alfa - nie renderować // w cyklu // nieprzezroczystych if (ReplacableSkinID[3]) - if (TTexturesManager.Texture(ReplacableSkinID[3]).has_alpha) + if (TextureManager.Texture(ReplacableSkinID[3]).has_alpha) iAlpha |= 0x04040004; // tekstura -3 z kanałem alfa - nie renderować // w cyklu // nieprzezroczystych if (ReplacableSkinID[4]) - if (TTexturesManager.Texture(ReplacableSkinID[4]).has_alpha) + if (TextureManager.Texture(ReplacableSkinID[4]).has_alpha) iAlpha |= 0x08080008; // tekstura -4 z kanałem alfa - nie renderować // w cyklu // nieprzezroczystych @@ -5849,13 +5849,13 @@ void TDynamicObject::DestinationSet(std::string to, std::string numer) std::string x = TextureTest(asBaseDir + numer + "@" + MoverParameters->TypeName); if (!x.empty()) { - ReplacableSkinID[4] = TTexturesManager.GetTextureId( x, "", 9); // rozmywania 0,1,4,5 nie nadają się + ReplacableSkinID[4] = TextureManager.GetTextureId( x, "", 9); // rozmywania 0,1,4,5 nie nadają się return; } x = TextureTest(asBaseDir + numer ); if (!x.empty()) { - ReplacableSkinID[4] = TTexturesManager.GetTextureId( x, "", 9); // rozmywania 0,1,4,5 nie nadają się + ReplacableSkinID[4] = TextureManager.GetTextureId( x, "", 9); // rozmywania 0,1,4,5 nie nadają się return; } if (to.empty()) @@ -5863,17 +5863,17 @@ void TDynamicObject::DestinationSet(std::string to, std::string numer) x = TextureTest(asBaseDir + to + "@" + MoverParameters->TypeName); // w pierwszej kolejności z nazwą FIZ/MMD if (!x.empty()) { - ReplacableSkinID[4] = TTexturesManager.GetTextureId( x, "", 9); // rozmywania 0,1,4,5 nie nadają się + ReplacableSkinID[4] = TextureManager.GetTextureId( x, "", 9); // rozmywania 0,1,4,5 nie nadają się return; } x = TextureTest(asBaseDir + to); // na razie prymitywnie if (!x.empty()) - ReplacableSkinID[4] = TTexturesManager.GetTextureId( x, "", 9); // rozmywania 0,1,4,5 nie nadają się + ReplacableSkinID[4] = TextureManager.GetTextureId( x, "", 9); // rozmywania 0,1,4,5 nie nadają się else { x = TextureTest(asBaseDir + "nowhere"); // jak nie znalazł dedykowanej, to niech daje nowhere if (!x.empty()) - ReplacableSkinID[4] = TTexturesManager.GetTextureId( x, "", 9); + ReplacableSkinID[4] = TextureManager.GetTextureId( x, "", 9); } // Ra 2015-01: żeby zalogować błąd, trzeba by mieć pewność, że model używa // tekstury nr 4 diff --git a/Ground.cpp b/Ground.cpp index 69df2d6e..b1d55d3c 100644 --- a/Ground.cpp +++ b/Ground.cpp @@ -276,7 +276,7 @@ void TGroundNode::RaRenderVBO() { // renderowanie z domyslnego bufora VBO glColor3ub(Diffuse[0], Diffuse[1], Diffuse[2]); if (TextureID) - glBindTexture(GL_TEXTURE_2D, TextureID); // Ustaw aktywną teksturę + TextureManager.Bind(TextureID); // Ustaw aktywną teksturę glDrawArrays(iType, iVboPtr, iNumVerts); // Narysuj naraz wszystkie trójkąty } @@ -445,7 +445,7 @@ void TGroundNode::Compile(bool many) #ifdef USE_VERTEX_ARRAYS glVertexPointer(3, GL_DOUBLE, sizeof(vector3), &Points[0].x); #endif - glBindTexture(GL_TEXTURE_2D, 0); + TextureManager.Bind(0); #ifdef USE_VERTEX_ARRAYS glDrawArrays(iType, 0, iNumPts); #else @@ -466,7 +466,7 @@ void TGroundNode::Compile(bool many) glTexCoordPointer(2, GL_FLOAT, sizeof(TGroundVertex), &tri->Vertices[0].tu); #endif glColor3ub(tri->Diffuse[0], tri->Diffuse[1], tri->Diffuse[2]); - glBindTexture(GL_TEXTURE_2D, Global::bWireFrame ? 0 : tri->TextureID); + TextureManager.Bind(Global::bWireFrame ? 0 : tri->TextureID); #ifdef USE_VERTEX_ARRAYS glDrawArrays(Global::bWireFrame ? GL_LINE_LOOP : tri->iType, 0, tri->iNumVerts); #else @@ -494,7 +494,7 @@ void TGroundNode::Compile(bool many) else if (iType == TP_MESH) { // grupa ze wspólną teksturą - wrzucanie do wspólnego Display List if (TextureID) - glBindTexture(GL_TEXTURE_2D, TextureID); // Ustaw aktywną teksturę + TextureManager.Bind(TextureID); // Ustaw aktywną teksturę TGroundNode *n = nNode; while (n ? n->TextureID == TextureID : false) { // wszystkie obiekty o tej samej testurze @@ -2109,8 +2109,8 @@ TGroundNode * TGround::AddGroundNode(cParser *parser) tmp->PROBLEND = false; } #endif - tmp->TextureID = TTexturesManager.GetTextureId( str, szTexturePath ); - tmp->iFlags = TTexturesManager.Texture(tmp->TextureID).has_alpha ? 0x220 : 0x210; // z usuwaniem + tmp->TextureID = TextureManager.GetTextureId( str, szTexturePath ); + tmp->iFlags = TextureManager.Texture(tmp->TextureID).has_alpha ? 0x220 : 0x210; // z usuwaniem if (((tmp->iType == GL_TRIANGLES) && (tmp->iFlags & 0x10)) ? Global::pTerrainCompact->TerrainLoaded() : false) diff --git a/Model3d.cpp b/Model3d.cpp index 59f9bbbc..4071db89 100644 --- a/Model3d.cpp +++ b/Model3d.cpp @@ -28,7 +28,7 @@ using namespace Mtable; double TSubModel::fSquareDist = 0; int TSubModel::iInstance; // numer renderowanego egzemplarza obiektu -GLuint *TSubModel::ReplacableSkinId = NULL; +texture_manager::size_type *TSubModel::ReplacableSkinId = NULL; int TSubModel::iAlpha = 0x30300030; // maska do testowania flag tekstur wymiennych TModel3d *TSubModel::pRoot; // Ra: tymczasowo wskaźnik na model widoczny z submodelu std::string *TSubModel::pasText; @@ -411,12 +411,12 @@ int TSubModel::Load(cParser &parser, TModel3d *Model, int Pos, bool dynamic) TextureNameSet(texture.c_str()); if (texture.find_first_of("/\\") == texture.npos) texture.insert(0, Global::asCurrentTexturePath.c_str()); - TextureID = TTexturesManager.GetTextureId( texture, szTexturePath ); + TextureID = TextureManager.GetTextureId( texture, szTexturePath ); // TexAlpha=TTexturesManager::GetAlpha(TextureID); // iFlags|=TexAlpha?0x20:0x10; //0x10-nieprzezroczysta, 0x20-przezroczysta if (Opacity < 1.0) // przezroczystość z tekstury brana tylko dla Opacity // 0! - iFlags |= TTexturesManager.Texture(TextureID).has_alpha ? + iFlags |= TextureManager.Texture(TextureID).has_alpha ? 0x20 : 0x10; // 0x10-nieprzezroczysta, 0x20-przezroczysta else @@ -636,7 +636,7 @@ int TSubModel::TriangleAdd(TModel3d *m, texture_manager::size_type tex, int tri) m->AddTo(this, s); } // s->asTexture=AnsiString(TTexturesManager::GetName(tex).c_str()); - s->TextureNameSet(TTexturesManager.Texture(tex).name.c_str()); + s->TextureNameSet(TextureManager.Texture(tex).name.c_str()); s->TextureID = tex; s->eType = GL_TRIANGLES; // iAnimOwner=0; //roboczy wskaźnik na wierzchołek @@ -714,7 +714,7 @@ void TSubModel::DisplayLists() { uiDisplayList = glGenLists(1); glNewList(uiDisplayList, GL_COMPILE); - glBindTexture(GL_TEXTURE_2D, 0); + TextureManager.Bind(0); // if (eType==smt_FreeSpotLight) // { // if (iFarAttenDecay==0) @@ -737,7 +737,7 @@ void TSubModel::DisplayLists() { // punkty świecące dookólnie uiDisplayList = glGenLists(1); glNewList(uiDisplayList, GL_COMPILE); - glBindTexture(GL_TEXTURE_2D, 0); // tekstury nie ma + TextureManager.Bind(0); // tekstury nie ma glColorMaterial(GL_FRONT, GL_EMISSION); glDisable(GL_LIGHTING); // Tolaris-030603: bo mu punkty swiecace sie blendowaly glBegin(GL_POINTS); @@ -1100,11 +1100,11 @@ void TSubModel::RenderDL() { if (TextureID < 0) // && (ReplacableSkinId!=0)) { // zmienialne skóry - glBindTexture(GL_TEXTURE_2D, ReplacableSkinId[-TextureID]); + TextureManager.Bind(ReplacableSkinId[-TextureID]); // TexAlpha=!(iAlpha&1); //zmiana tylko w przypadku wymienej tekstury } else - glBindTexture(GL_TEXTURE_2D, TextureID); // również 0 + TextureManager.Bind(TextureID); // również 0 if (Global::fLuminance < fLight) { glMaterialfv(GL_FRONT, GL_EMISSION, f4Diffuse); // zeby swiecilo na kolorowo @@ -1197,11 +1197,11 @@ void TSubModel::RenderAlphaDL() { if (TextureID < 0) // && (ReplacableSkinId!=0)) { // zmienialne skóry - glBindTexture(GL_TEXTURE_2D, ReplacableSkinId[-TextureID]); + TextureManager.Bind(ReplacableSkinId[-TextureID]); // TexAlpha=iAlpha&1; //zmiana tylko w przypadku wymienej tekstury } else - glBindTexture(GL_TEXTURE_2D, TextureID); // również 0 + TextureManager.Bind(TextureID); // również 0 if (Global::fLuminance < fLight) { glMaterialfv(GL_FRONT, GL_EMISSION, f4Diffuse); // zeby swiecilo na kolorowo @@ -1278,11 +1278,11 @@ void TSubModel::RenderVBO() { if (TextureID < 0) // && (ReplacableSkinId!=0)) { // zmienialne skóry - glBindTexture(GL_TEXTURE_2D, ReplacableSkinId[-TextureID]); + TextureManager.Bind(ReplacableSkinId[-TextureID]); // TexAlpha=!(iAlpha&1); //zmiana tylko w przypadku wymienej tekstury } else - glBindTexture(GL_TEXTURE_2D, TextureID); // również 0 + TextureManager.Bind(TextureID); // również 0 glColor3fv(f4Diffuse); // McZapkie-240702: zamiast ub // glMaterialfv(GL_FRONT,GL_AMBIENT_AND_DIFFUSE,f4Diffuse); //to samo, // co glColor @@ -1349,7 +1349,7 @@ void TSubModel::RenderVBO() Distdimm=1; */ - glBindTexture(GL_TEXTURE_2D, 0); // nie teksturować + TextureManager.Bind(0); // nie teksturować // glColor3f(f4Diffuse[0],f4Diffuse[1],f4Diffuse[2]); // glColorMaterial(GL_FRONT,GL_EMISSION); float color[4] = {f4Diffuse[0] * Distdimm, f4Diffuse[1] * Distdimm, @@ -1378,7 +1378,7 @@ void TSubModel::RenderVBO() if (pRoot->StartColorVBO()) { // wyświetlanie kolorowych punktów zamiast // trójkątów - glBindTexture(GL_TEXTURE_2D, 0); // tekstury nie ma + TextureManager.Bind(0); // tekstury nie ma glColorMaterial(GL_FRONT, GL_EMISSION); glDisable(GL_LIGHTING); // Tolaris-030603: bo mu punkty swiecace sie // blendowaly @@ -1452,11 +1452,11 @@ void TSubModel::RenderAlphaVBO() { if (TextureID < 0) // && (ReplacableSkinId!=0)) { // zmienialne skory - glBindTexture(GL_TEXTURE_2D, ReplacableSkinId[-TextureID]); + TextureManager.Bind(ReplacableSkinId[-TextureID]); // TexAlpha=iAlpha&1; //zmiana tylko w przypadku wymienej tekstury } else - glBindTexture(GL_TEXTURE_2D, TextureID); // również 0 + TextureManager.Bind(TextureID); // również 0 if (Global::fLuminance < fLight) { glMaterialfv(GL_FRONT, GL_EMISSION, f4Diffuse); // zeby swiecilo na kolorowo @@ -1624,14 +1624,14 @@ void TSubModel::BinInit(TSubModel *s, float4x4 *m, float8 *v, TStringPack *t, TS std::string tex = pTexture; if (tex.find_last_of("/\\") == std::string::npos) tex.insert(0, Global::asCurrentTexturePath); - TextureID = TTexturesManager.GetTextureId( tex, szTexturePath ); + TextureID = TextureManager.GetTextureId( tex, szTexturePath ); // TexAlpha=TTexturesManager::GetAlpha(TextureID); //zmienna robocza // ustawienie cyklu przezroczyste/nieprzezroczyste zależnie od własności // stałej tekstury // iFlags=(iFlags&~0x30)|(TTexturesManager::GetAlpha(TextureID)?0x20:0x10); // //0x10-nieprzezroczysta, 0x20-przezroczysta if (Opacity < 1.0) // przezroczystość z tekstury brana tylko dla Opacity 0! - iFlags |= TTexturesManager.Texture(TextureID).has_alpha ? + iFlags |= TextureManager.Texture(TextureID).has_alpha ? 0x20 : 0x10; // 0x10-nieprzezroczysta, 0x20-przezroczysta else @@ -2175,7 +2175,7 @@ ReplacableSkinId,int iAlpha) }; */ -void TModel3d::Render(double fSquareDistance, GLuint *ReplacableSkinId, int iAlpha) +void TModel3d::Render(double fSquareDistance, texture_manager::size_type *ReplacableSkinId, int iAlpha) { iAlpha ^= 0x0F0F000F; // odwrócenie flag tekstur, aby wyłapać nieprzezroczyste if (iAlpha & iFlags & 0x1F1F001F) // czy w ogóle jest co robić w tym cyklu? @@ -2186,7 +2186,7 @@ void TModel3d::Render(double fSquareDistance, GLuint *ReplacableSkinId, int iAlp } }; -void TModel3d::RenderAlpha(double fSquareDistance, GLuint *ReplacableSkinId, int iAlpha) +void TModel3d::RenderAlpha(double fSquareDistance, texture_manager::size_type *ReplacableSkinId, int iAlpha) { if (iAlpha & iFlags & 0x2F2F002F) { @@ -2230,7 +2230,7 @@ globalna! }; */ -void TModel3d::RaRender(double fSquareDistance, GLuint *ReplacableSkinId, int iAlpha) +void TModel3d::RaRender( double fSquareDistance, texture_manager::size_type *ReplacableSkinId, int iAlpha ) { // renderowanie specjalne, np. kabiny iAlpha ^= 0x0F0F000F; // odwrócenie flag tekstur, aby wyłapać nieprzezroczyste if (iAlpha & iFlags & 0x1F1F001F) // czy w ogóle jest co robić w tym cyklu? @@ -2246,7 +2246,7 @@ void TModel3d::RaRender(double fSquareDistance, GLuint *ReplacableSkinId, int iA } }; -void TModel3d::RaRenderAlpha(double fSquareDistance, GLuint *ReplacableSkinId, int iAlpha) +void TModel3d::RaRenderAlpha(double fSquareDistance, texture_manager::size_type *ReplacableSkinId, int iAlpha) { // renderowanie specjalne, np. kabiny if (iAlpha & iFlags & 0x2F2F002F) // czy w ogóle jest co robić w tym cyklu? { @@ -2284,7 +2284,7 @@ globalna! // 2011-03-16 cztery nowe funkcje renderowania z możliwością pochylania obiektów //----------------------------------------------------------------------------- -void TModel3d::Render(vector3 *vPosition, vector3 *vAngle, GLuint *ReplacableSkinId, int iAlpha) +void TModel3d::Render(vector3 *vPosition, vector3 *vAngle, texture_manager::size_type *ReplacableSkinId, int iAlpha) { // nieprzezroczyste, Display List glPushMatrix(); glTranslated(vPosition->x, vPosition->y, vPosition->z); @@ -2301,7 +2301,7 @@ void TModel3d::Render(vector3 *vPosition, vector3 *vAngle, GLuint *ReplacableSki Root->RenderDL(); glPopMatrix(); }; -void TModel3d::RenderAlpha(vector3 *vPosition, vector3 *vAngle, GLuint *ReplacableSkinId, +void TModel3d::RenderAlpha(vector3 *vPosition, vector3 *vAngle, texture_manager::size_type *ReplacableSkinId, int iAlpha) { // przezroczyste, Display List glPushMatrix(); @@ -2318,7 +2318,7 @@ void TModel3d::RenderAlpha(vector3 *vPosition, vector3 *vAngle, GLuint *Replacab Root->RenderAlphaDL(); glPopMatrix(); }; -void TModel3d::RaRender(vector3 *vPosition, vector3 *vAngle, GLuint *ReplacableSkinId, int iAlpha) +void TModel3d::RaRender( vector3 *vPosition, vector3 *vAngle, texture_manager::size_type *ReplacableSkinId, int iAlpha ) { // nieprzezroczyste, VBO glPushMatrix(); glTranslated(vPosition->x, vPosition->y, vPosition->z); @@ -2338,7 +2338,7 @@ void TModel3d::RaRender(vector3 *vPosition, vector3 *vAngle, GLuint *ReplacableS } glPopMatrix(); }; -void TModel3d::RaRenderAlpha(vector3 *vPosition, vector3 *vAngle, GLuint *ReplacableSkinId, +void TModel3d::RaRenderAlpha(vector3 *vPosition, vector3 *vAngle, texture_manager::size_type *ReplacableSkinId, int iAlpha) { // przezroczyste, VBO glPushMatrix(); diff --git a/Model3d.h b/Model3d.h index c6adc688..9f1cb3e0 100644 --- a/Model3d.h +++ b/Model3d.h @@ -253,7 +253,7 @@ class TSubModel public: static int iInstance; // identyfikator egzemplarza, który aktualnie renderuje model - static GLuint *ReplacableSkinId; + static texture_manager::size_type *ReplacableSkinId; static int iAlpha; // maska bitowa dla danego przebiegu static double fSquareDist; static TModel3d *pRoot; @@ -312,7 +312,7 @@ class TSubModel void InfoSet(TSubModelInfo *info); void BinInit(TSubModel *s, float4x4 *m, float8 *v, TStringPack *t, TStringPack *n = NULL, bool dynamic = false); - void ReplacableSet(GLuint *r, int a) + void ReplacableSet(texture_manager::size_type *r, int a) { ReplacableSkinId = r; iAlpha = a; @@ -410,29 +410,29 @@ class TModel3d : public CMesh void SaveToBinFile(char const *FileName); void BreakHierarhy(); // renderowanie specjalne - void Render(double fSquareDistance, GLuint *ReplacableSkinId = NULL, int iAlpha = 0x30300030); - void RenderAlpha(double fSquareDistance, GLuint *ReplacableSkinId = NULL, + void Render(double fSquareDistance, texture_manager::size_type *ReplacableSkinId = NULL, int iAlpha = 0x30300030); + void RenderAlpha(double fSquareDistance, texture_manager::size_type *ReplacableSkinId = NULL, int iAlpha = 0x30300030); - void RaRender(double fSquareDistance, GLuint *ReplacableSkinId = NULL, int iAlpha = 0x30300030); - void RaRenderAlpha(double fSquareDistance, GLuint *ReplacableSkinId = NULL, + void RaRender(double fSquareDistance, texture_manager::size_type *ReplacableSkinId = NULL, int iAlpha = 0x30300030); + void RaRenderAlpha(double fSquareDistance, texture_manager::size_type *ReplacableSkinId = NULL, int iAlpha = 0x30300030); // jeden kąt obrotu - void Render(vector3 pPosition, double fAngle = 0, GLuint *ReplacableSkinId = NULL, + void Render(vector3 pPosition, double fAngle = 0, texture_manager::size_type *ReplacableSkinId = NULL, int iAlpha = 0x30300030); - void RenderAlpha(vector3 pPosition, double fAngle = 0, GLuint *ReplacableSkinId = NULL, + void RenderAlpha(vector3 pPosition, double fAngle = 0, texture_manager::size_type *ReplacableSkinId = NULL, int iAlpha = 0x30300030); - void RaRender(vector3 pPosition, double fAngle = 0, GLuint *ReplacableSkinId = NULL, + void RaRender(vector3 pPosition, double fAngle = 0, texture_manager::size_type *ReplacableSkinId = NULL, int iAlpha = 0x30300030); - void RaRenderAlpha(vector3 pPosition, double fAngle = 0, GLuint *ReplacableSkinId = NULL, + void RaRenderAlpha(vector3 pPosition, double fAngle = 0, texture_manager::size_type *ReplacableSkinId = NULL, int iAlpha = 0x30300030); // trzy kąty obrotu - void Render(vector3 *vPosition, vector3 *vAngle, GLuint *ReplacableSkinId = NULL, + void Render( vector3 *vPosition, vector3 *vAngle, texture_manager::size_type *ReplacableSkinId = NULL, int iAlpha = 0x30300030); - void RenderAlpha(vector3 *vPosition, vector3 *vAngle, GLuint *ReplacableSkinId = NULL, + void RenderAlpha( vector3 *vPosition, vector3 *vAngle, texture_manager::size_type *ReplacableSkinId = NULL, int iAlpha = 0x30300030); - void RaRender(vector3 *vPosition, vector3 *vAngle, GLuint *ReplacableSkinId = NULL, + void RaRender( vector3 *vPosition, vector3 *vAngle, texture_manager::size_type *ReplacableSkinId = NULL, int iAlpha = 0x30300030); - void RaRenderAlpha(vector3 *vPosition, vector3 *vAngle, GLuint *ReplacableSkinId = NULL, + void RaRenderAlpha( vector3 *vPosition, vector3 *vAngle, texture_manager::size_type *ReplacableSkinId = NULL, int iAlpha = 0x30300030); // inline int GetSubModelsCount() { return (SubModelsCount); }; int Flags() diff --git a/PyInt.cpp b/PyInt.cpp index 190a9737..73c40a05 100644 --- a/PyInt.cpp +++ b/PyInt.cpp @@ -447,7 +447,7 @@ void TPythonScreens::init(cParser &parser, TModel3d *model, std::string const &n free(pyClassName); return; // nie ma takiego sub modelu w danej kabinie pomijamy } - int textureId = subModel->GetTextureId(); + int textureId = TextureManager.Texture(subModel->GetTextureId()).id; if (textureId <= 0) { sprintf(buff, "Python Screen: invalid texture id %d - Ignoring screen", textureId); diff --git a/Segment.cpp b/Segment.cpp index 5a9772ec..daaf7356 100644 --- a/Segment.cpp +++ b/Segment.cpp @@ -641,7 +641,7 @@ void TSegment::RenderSwitchRail(const vector6 *ShapePoints1, const vector6 *Shap void TSegment::Render() { vector3 pt; - glBindTexture(GL_TEXTURE_2D, 0); + TextureManager.Bind(0); int i; if (bCurve) { diff --git a/Texture.cpp b/Texture.cpp index 1ad3622a..8893ce24 100644 --- a/Texture.cpp +++ b/Texture.cpp @@ -26,19 +26,248 @@ http://mozilla.org/MPL/2.0/. #include "Usefull.h" #include "TextureDDS.h" -texture_manager TTexturesManager; +texture_manager TextureManager; -/* -TTexturesManager::Alphas TTexturesManager::_alphas; -TTexturesManager::Names TTexturesManager::_names; -*/ -void -texture_manager::Init() { +texture_manager::texture_manager() { // since index 0 is used to indicate no texture, we put a blank entry in the first texture slot m_textures.emplace_back( opengl_texture() ); } +// loads texture data from specified file +// TODO: wrap it in a workitem class, for the job system deferred loading +void +opengl_texture::load() { + + if( name.size() < 3 ) { goto fail; } + + WriteLog( "Loading texture data from \"" + name + "\"" ); + + data_state = resource_state::loading; + { + std::string const extension = name.substr( name.size() - 3, 3 ); + + if( extension == "dds" ) { load_DDS(); } +/* + else if( extension == "tga" ) { load_TGA(); } + else if( extension == "tex" ) { load_TEX(); } + else if( extension == "bmp" ) { load_BMP(); } +*/ + else { goto fail; } + } + + // data state will be set by called loader, so we're all done here + if( data_state == resource_state::good ) { + + return; + } + +fail: + data_state = resource_state::failed; + ErrorLog( "Failed to load texture \"" + name + "\"" ); + return; +} + +void +opengl_texture::load_DDS() { + + std::ifstream file( name, std::ios::binary | std::ios::ate ); file.unsetf( std::ios::skipws ); + std::size_t filesize = static_cast(file.tellg()); // ios::ate already positioned us at the end of the file + file.seekg( 0, std::ios::beg ); // rewind the caret afterwards + + char filecode[5]; + file.read(filecode, 4); + filesize -= 4; + filecode[4] = 0; + + if( filecode != std::string( "DDS " ) ) + { + data_state = resource_state::failed; + return; + } + + DDSURFACEDESC2 ddsd; + file.read((char *)&ddsd, sizeof(ddsd)); + filesize -= sizeof( ddsd ); + + // + // This .dds loader supports the loading of compressed formats DXT1, DXT3 + // and DXT5. + // + + switch (ddsd.ddpfPixelFormat.dwFourCC) + { + case FOURCC_DXT1: + // DXT1's compression ratio is 8:1 + data_format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; + break; + + case FOURCC_DXT3: + // DXT3's compression ratio is 4:1 + data_format = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; + break; + + case FOURCC_DXT5: + // DXT5's compression ratio is 4:1 + data_format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; + break; + + default: + data_state = resource_state::failed; + return; + } + + data_width = ddsd.dwWidth; + data_height = ddsd.dwHeight; + data_mapcount = 1;// ddsd.dwMipMapCount; + + int blockSize = ( data_format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT ? 8 : 16 ); + int offset = 0; + + while( ( data_width > Global::iMaxTextureSize ) || ( data_height > Global::iMaxTextureSize ) ) { + // pomijanie zbyt dużych mipmap, jeśli wymagane jest ograniczenie rozmiaru + offset += ( ( data_width + 3 ) / 4 ) * ( ( data_height + 3 ) / 4 ) * blockSize; + data_width /= 2; + data_height /= 2; + --data_mapcount; + }; + + if( data_mapcount <= 0 ) { + // there's a chance we've discarded the provided mipmap(s) as too large + WriteLog( "Texture \"" + name + "\" has no mipmaps which can fit currently set texture size limits." ); + data_state = resource_state::failed; + return; + } + + int datasize = filesize - offset; +// int datasize = ( ( data_width + 3 ) / 4 ) * ( ( data_height + 3 ) / 4 ) * blockSize; +/* + // calculate size of accepted data + // NOTE: this is a fallback, as we should be able to just move the file caret by calculated offset and read the rest + int datasize = 0; + int mapcount = data_mapcount, + width = data_width, + height = data_height; + while( mapcount ) { + + datasize += ( ( width + 3 ) / 4 ) * ( ( height + 3 ) / 4 ) * blockSize; + width = std::max( width / 2, 4 ); + height = std::max( height / 2, 4 ); + --mapcount; + } +*/ + // reserve space and load texture data + data.resize( datasize ); + if( offset != 0 ) { + // skip data for mipmaps we don't need + file.seekg( offset, std::ios_base::cur ); + filesize -= offset; + } + file.read((char *)&data[0], datasize); + filesize -= datasize; + + data_components = + ( ddsd.ddpfPixelFormat.dwFourCC == FOURCC_DXT1 ? + GL_RGB : + GL_RGBA ); + + data_state = resource_state::good; + + return; +} + +void +opengl_texture::create() { + + if( data_state != resource_state::good ) { + // don't bother until we have useful texture data + return; + } + + glGenTextures( 1, &id ); + glBindTexture( GL_TEXTURE_2D, id ); + + // TODO: set wrapping according to supplied parameters + glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT ); + glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT ); + + set_filtering(); + + if( GLEW_VERSION_1_4 ) { + + if( data_mapcount == 1 ) { + // fill missing mipmaps if needed + glTexParameteri( GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE ); + } + // upload texture data + // TBD, TODO: handle mipmaps other than base manually, or let the card take care of it? + int dataoffset = 0, + datasize = 0, + datawidth = data_width, + dataheight = data_height; + for( int maplevel = 0; maplevel < data_mapcount; ++maplevel ) { + + if( ( data_format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT ) + || ( data_format == GL_COMPRESSED_RGBA_S3TC_DXT3_EXT ) + || ( data_format == GL_COMPRESSED_RGBA_S3TC_DXT5_EXT ) ) { + // compressed dds formats + if( false == Global::bDecompressDDS ) { + // let the openGL handle this + int const datablocksize = + ( data_format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT ? + 8 : + 16 ); + + datasize = ( ( std::max(datawidth, 4) + 3 ) / 4 ) * ( ( std::max(dataheight, 4) + 3 ) / 4 ) * datablocksize; + + glCompressedTexImage2D( + GL_TEXTURE_2D, maplevel, + data_format, datawidth, dataheight, 0, datasize, + (GLubyte *)&data[0] + dataoffset ); + + dataoffset += datasize; + datawidth = std::max( datawidth / 2, 1 ); + dataheight = std::max( dataheight / 2, 1 ); + } + } + } + } + + is_ready = true; + has_alpha = ( + data_components == GL_RGBA ? + true : + false ); + + data.resize( 0 ); // TBD, TODO: keep the texture data if we start doing some gpu data cleaning down the road + data_state = resource_state::none; +} + +void +opengl_texture::set_filtering() { + + bool hash = ( name.find( '#' ) != std::string::npos ); + + if( GLEW_VERSION_1_4 ) { + + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR ); + + if( true == hash ) { + // #: sharpen more + glTexEnvf( GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, -2.0 ); + } + else { + // regular texture sharpening + glTexEnvf( GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, -1.0 ); + } + } +} + +void +texture_manager::Init() { +} + /* TTexturesManager::Names::iterator TTexturesManager::LoadFromFile(std::string fileName, int filter) { @@ -100,9 +329,9 @@ struct ReplaceSlash } }; */ -// ustalenie numeru tekstury, wczytanie jeśli nie jeszcze takiej nie było +// ustalenie numeru tekstury, wczytanie jeśli jeszcze takiej nie było texture_manager::size_type -texture_manager::GetTextureId( std::string Filename, std::string const &Dir, int const Filter ) { +texture_manager::GetTextureId( std::string Filename, std::string const &Dir, int const Filter, bool const Loadnow ) { if( Filename.find( ':' ) != std::string::npos ) Filename.erase( Filename.find( ':' ) ); // po dwukropku mogą być podane dodatkowe informacje niebędące nazwą tekstury @@ -112,6 +341,8 @@ texture_manager::GetTextureId( std::string Filename, std::string const &Dir, int // change forward slashes to windows ones. NOTE: probably not strictly necessary, but eh c = ( c == '/' ? '\\' : c ); } + if( Filename.rfind('.')!= std::string::npos ) + Filename.erase( Filename.find( '.' ) ); // trim extension if there's one /* std::transform( Filename.begin(), Filename.end(), @@ -171,15 +402,38 @@ texture_manager::GetTextureId( std::string Filename, std::string const &Dir, int opengl_texture texture; texture.name = filename; + texture.attributes = std::to_string( Filter ); // temporary. TODO, TBD: check how it's used and possibly get rid of it + auto const textureindex = m_textures.size(); m_textures.emplace_back( texture ); - auto const textureindex = m_textures.size() - 1; m_texturemappings.emplace( filename, textureindex ); - WriteLog( "Created texture object for file \"" + filename + "\"" ); + WriteLog( "Created texture object for \"" + filename + "\"" ); + + if( true == Loadnow ) { + + Texture( textureindex ).load(); + Texture( textureindex ).create(); + } return textureindex; }; +void +texture_manager::Bind( texture_manager::size_type const Id ) { + + // TODO: keep track of what's currently bound and don't do it twice + // TODO: do binding in texture object, add support for other types + if( Id != 0 ) { + + auto const &texture = Texture( Id ); + if( true == texture.is_ready ) { + glBindTexture( GL_TEXTURE_2D, texture.id ); + return; + } + } + + glBindTexture( GL_TEXTURE_2D, 0 ); +} // checks whether specified texture is in the texture bank. returns texture id, or npos. texture_manager::size_type texture_manager::find_in_databank( std::string const &Texturename ) { diff --git a/Texture.h b/Texture.h index 6d058f8f..e6082728 100644 --- a/Texture.h +++ b/Texture.h @@ -12,15 +12,40 @@ http://mozilla.org/MPL/2.0/. #include #include "opengl/glew.h" +enum resource_state { + none, + loading, + good, + failed +}; + struct opengl_texture { GLuint id{ -1 }; // associated GL resource bool has_alpha{ false }; // indicates the texture has alpha channel bool is_ready{ false }; // indicates the texture was processed and is ready for use + std::string attributes; // requested texture attributes: wrapping modes etc std::string name; // name of the texture source file std::vector data; // texture data - /*std::atomic*/ bool is_loaded{ false }; // indicates the texture data was loaded and can be processed - /*std::atomic*/ bool is_good{ false }; // indicates the texture data was retrieved without errors + resource_state data_state{ none }; // current state of texture data + int data_width{ 0 }, + data_height{ 0 }, + data_mapcount{ 0 }; + GLuint data_format{ 0 }, + data_components{ 0 }; +/* + std::atomic is_loaded{ false }; // indicates the texture data was loaded and can be processed + std::atomic is_good{ false }; // indicates the texture data was retrieved without errors +*/ + void load(); + void create(); + +private: +// void load_BMP(); + void load_DDS(); +// void load_TEX(); +// void load_TGA(); + void set_filtering(); }; class texture_manager { @@ -29,11 +54,14 @@ private: typedef std::vector opengltexture_array; public: - typedef opengltexture_array::size_type size_type; +// typedef opengltexture_array::size_type size_type; + typedef int size_type; + texture_manager(); ~texture_manager() { Free(); } - size_type GetTextureId( std::string Filename, std::string const &Dir, int const Filter = -1 ); + size_type GetTextureId( std::string Filename, std::string const &Dir, int const Filter = -1, bool const Loadnow = true ); + void Bind( size_type const Id ); opengl_texture &Texture( size_type const Id ) { return m_textures.at( Id ); } void Init(); void Free(); @@ -64,4 +92,4 @@ private: index_map m_texturemappings; }; -extern texture_manager TTexturesManager; \ No newline at end of file +extern texture_manager TextureManager; \ No newline at end of file diff --git a/Track.cpp b/Track.cpp index fd32a2ad..d36b4016 100644 --- a/Track.cpp +++ b/Track.cpp @@ -508,7 +508,7 @@ void TTrack::Load(cParser *parser, vector3 pOrigin, std::string name) parser->getTokens(); *parser >> token; str = token; // railtex - TextureID1 = (str == "none" ? 0 : TTexturesManager.GetTextureId( + TextureID1 = (str == "none" ? 0 : TextureManager.GetTextureId( str, szTexturePath, (iCategoryFlag & 1) ? Global::iRailProFiltering : Global::iBallastFiltering)); @@ -519,7 +519,7 @@ void TTrack::Load(cParser *parser, vector3 pOrigin, std::string name) parser->getTokens(); *parser >> token; str = token; // sub || railtex - TextureID2 = (str == "none" ? 0 : TTexturesManager.GetTextureId( + TextureID2 = (str == "none" ? 0 : TextureManager.GetTextureId( str, szTexturePath, (eType == tt_Normal) ? Global::iBallastFiltering : Global::iRailProFiltering)); @@ -579,12 +579,12 @@ void TTrack::Load(cParser *parser, vector3 pOrigin, std::string name) if (TextureID1 && fTexLength) { // dla drogi trzeba ustalić proporcje boków nawierzchni float w, h; - glBindTexture(GL_TEXTURE_2D, TextureID1); + TextureManager.Bind(TextureID1); glGetTexLevelParameterfv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &w); glGetTexLevelParameterfv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &h); if (h != 0.0) fTexRatio1 = w / h; // proporcja boków - glBindTexture(GL_TEXTURE_2D, TextureID2); + TextureManager.Bind(TextureID2); glGetTexLevelParameterfv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &w); glGetTexLevelParameterfv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &h); if (h != 0.0) @@ -1299,14 +1299,14 @@ void TTrack::Compile(GLuint tex) } } if (!tex) - glBindTexture(GL_TEXTURE_2D, TextureID2); + TextureManager.Bind( TextureID2 ); Segment->RenderLoft(bpts1, iTrapezoid ? -4 : 4, fTexLength); } if (TextureID1) if (tex ? TextureID1 == tex : true) // jeśli pasuje do grupy (tex) { // szyny if (!tex) - glBindTexture(GL_TEXTURE_2D, TextureID1); + TextureManager.Bind( TextureID1 ); Segment->RenderLoft(rpts1, iTrapezoid ? -nnumPts : nnumPts, fTexLength); Segment->RenderLoft(rpts2, iTrapezoid ? -nnumPts : nnumPts, fTexLength); } @@ -1345,7 +1345,7 @@ void TTrack::Compile(GLuint tex) // McZapkie-130302 - poprawione rysowanie szyn if (SwitchExtension->RightSwitch) { // zwrotnica prawa - glBindTexture(GL_TEXTURE_2D, TextureID1); + TextureManager.Bind( TextureID1 ); SwitchExtension->Segments[0]->RenderLoft(rpts1, nnumPts, fTexLength, 2); // prawa szyna za iglicą SwitchExtension->Segments[0]->RenderSwitchRail( @@ -1354,7 +1354,7 @@ void TTrack::Compile(GLuint tex) SwitchExtension->Segments[0]->RenderLoft( rpts2, nnumPts, fTexLength); // lewa szyna normalnie cała if (TextureID2 != TextureID1) // nie wiadomo, czy OpenGL to optymalizuje - glBindTexture(GL_TEXTURE_2D, TextureID2); + TextureManager.Bind( TextureID2 ); SwitchExtension->Segments[1]->RenderLoft( rpts1, nnumPts, fTexLength); // prawa szyna normalna cała SwitchExtension->Segments[1]->RenderLoft(rpts2, nnumPts, fTexLength, @@ -1365,7 +1365,7 @@ void TTrack::Compile(GLuint tex) } else { // lewa kiedyś działała lepiej niż prawa - glBindTexture(GL_TEXTURE_2D, TextureID1); + TextureManager.Bind( TextureID1 ); SwitchExtension->Segments[0]->RenderLoft( rpts1, nnumPts, fTexLength); // prawa szyna normalna cała SwitchExtension->Segments[0]->RenderLoft(rpts2, nnumPts, fTexLength, @@ -1374,7 +1374,7 @@ void TTrack::Compile(GLuint tex) rpts2, rpts4, nnumPts, fTexLength, 2, -SwitchExtension->fOffset2); // lewa iglica if (TextureID2 != TextureID1) // nie wiadomo, czy OpenGL to optymalizuje - glBindTexture(GL_TEXTURE_2D, TextureID2); + TextureManager.Bind( TextureID2 ); SwitchExtension->Segments[1]->RenderLoft(rpts1, nnumPts, fTexLength, 2); // prawa szyna za iglicą SwitchExtension->Segments[1]->RenderSwitchRail( @@ -1422,7 +1422,7 @@ void TTrack::Compile(GLuint tex) if (tex ? TextureID1 == tex : true) // jeśli pasuje do grupy (tex) { // tworzenie trójkątów nawierzchni szosy if (!tex) - glBindTexture(GL_TEXTURE_2D, TextureID1); + TextureManager.Bind( TextureID1 ); Segment->RenderLoft(bpts1, iTrapezoid ? -2 : 2, fTexLength); } if (TextureID2) @@ -1430,7 +1430,7 @@ void TTrack::Compile(GLuint tex) { // pobocze drogi - poziome przy przechyłce (a może krawężnik i chodnik zrobić jak // w Midtown Madness 2?) if (!tex) - glBindTexture(GL_TEXTURE_2D, TextureID2); + TextureManager.Bind( TextureID2 ); vector6 rpts1[6], rpts2[6]; // współrzędne przekroju i mapowania dla prawej i lewej strony if (fTexHeight1 >= 0.0) @@ -1610,7 +1610,7 @@ void TTrack::Compile(GLuint tex) // Midtown Madness 2?) if (TextureID2) if (!tex) - glBindTexture(GL_TEXTURE_2D, TextureID2); + TextureManager.Bind( TextureID2 ); vector6 rpts1[6], rpts2[6]; // współrzędne przekroju i mapowania dla prawej i lewej strony // Ra 2014-07: trzeba to przerobić na pętlę i pobierać profile (przynajmniej 2..4) z @@ -1755,7 +1755,7 @@ void TTrack::Compile(GLuint tex) if (tex ? TextureID1 == tex : true) // jeśli pasuje do grupy (tex) { if (!tex) - glBindTexture(GL_TEXTURE_2D, TextureID1); + TextureManager.Bind( TextureID1 ); glBegin(GL_TRIANGLE_FAN); // takie kółeczko będzie glNormal3f(0, 1, 0); glTexCoord2f(0.5, 0.5); //środek tekstury na środku skrzyżowania @@ -1787,7 +1787,7 @@ void TTrack::Compile(GLuint tex) if (tex ? TextureID1 == tex : true) // jeśli pasuje do grupy (tex) { if (!tex) - glBindTexture(GL_TEXTURE_2D, TextureID1); + TextureManager.Bind( TextureID1 ); Segment->RenderLoft(bpts1, numPts, fTexLength); } if (TextureID2) @@ -1799,7 +1799,7 @@ void TTrack::Compile(GLuint tex) vector6 rpts2[3] = {vector6(-fHTW, 0.0, 1.0), vector6(-fHTW - side, 0.0, 0.5), vector6(-rozp, -fTexHeight1, 0.0)}; // Ra: po kiego 0.1? if (!tex) - glBindTexture(GL_TEXTURE_2D, TextureID2); // brzeg rzeki + TextureManager.Bind( TextureID2 ); // brzeg rzeki Segment->RenderLoft(rpts1, 3, fTexLength); Segment->RenderLoft(rpts2, 3, fTexLength); } @@ -2473,7 +2473,7 @@ void TTrack::RaRenderVBO(int iPtr) if (TextureID1) if ((seg = SwitchExtension->Segments[0]->RaSegCount()) > 0) { - glBindTexture(GL_TEXTURE_2D, TextureID1); // szyny + + TextureManager.Bind( TextureID1 ); // szyny + for (i = 0; i < seg; ++i) glDrawArrays(GL_TRIANGLE_STRIP, iPtr + 24 * i, 24); iPtr += 24 * seg; // pominięcie lewej szyny @@ -2484,7 +2484,7 @@ void TTrack::RaRenderVBO(int iPtr) if (TextureID2) if ((seg = SwitchExtension->Segments[1]->RaSegCount()) > 0) { - glBindTexture(GL_TEXTURE_2D, TextureID2); // szyny - + TextureManager.Bind( TextureID2 ); // szyny - for (i = 0; i < seg; ++i) glDrawArrays(GL_TRIANGLE_STRIP, iPtr + 24 * i, 24); iPtr += 24 * seg; // pominięcie lewej szyny @@ -2498,14 +2498,14 @@ void TTrack::RaRenderVBO(int iPtr) { if (TextureID2) { - glBindTexture(GL_TEXTURE_2D, TextureID2); // podsypka + TextureManager.Bind( TextureID2 ); // podsypka for (i = 0; i < seg; ++i) glDrawArrays(GL_TRIANGLE_STRIP, iPtr + 8 * i, 8); iPtr += 8 * seg; // pominięcie podsypki } if (TextureID1) { - glBindTexture(GL_TEXTURE_2D, TextureID1); // szyny + TextureManager.Bind( TextureID1 ); // szyny for (i = 0; i < seg; ++i) glDrawArrays(GL_TRIANGLE_STRIP, iPtr + 24 * i, 24); iPtr += 24 * seg; // pominięcie lewej szyny @@ -2520,7 +2520,7 @@ void TTrack::RaRenderVBO(int iPtr) { if (TextureID1) { - glBindTexture(GL_TEXTURE_2D, TextureID1); // nawierzchnia + TextureManager.Bind( TextureID1 ); // nawierzchnia for (i = 0; i < seg; ++i) { glDrawArrays(GL_TRIANGLE_STRIP, iPtr, 4); @@ -2529,7 +2529,7 @@ void TTrack::RaRenderVBO(int iPtr) } if (TextureID2) { - glBindTexture(GL_TEXTURE_2D, TextureID2); // pobocze + TextureManager.Bind( TextureID2 ); // pobocze if (fTexHeight1 >= 0.0) { // normalna droga z poboczem for (i = 0; i < seg; ++i) @@ -2558,7 +2558,7 @@ void TTrack::RaRenderVBO(int iPtr) { if (TextureID1) { - glBindTexture(GL_TEXTURE_2D, TextureID1); // nawierzchnia + TextureManager.Bind( TextureID1 ); // nawierzchnia for (i = 0; i < seg; ++i) { glDrawArrays(GL_TRIANGLE_STRIP, iPtr, 4); @@ -2567,7 +2567,7 @@ void TTrack::RaRenderVBO(int iPtr) } if (TextureID2) { - glBindTexture(GL_TEXTURE_2D, TextureID2); // pobocze + TextureManager.Bind( TextureID2 ); // pobocze for (i = 0; i < seg; ++i) glDrawArrays(GL_TRIANGLE_STRIP, iPtr + 6 * i, 6); iPtr += 6 * seg; // pominięcie lewego pobocza diff --git a/Traction.cpp b/Traction.cpp index 5b836c6f..c9a2bdf2 100644 --- a/Traction.cpp +++ b/Traction.cpp @@ -18,6 +18,7 @@ http://mozilla.org/MPL/2.0/. #include "logs.h" #include "mctools.h" #include "TractionPower.h" +#include "Texture.h" //--------------------------------------------------------------------------- /* @@ -115,7 +116,7 @@ void TTraction::Optimize() uiDisplayList = glGenLists(1); glNewList(uiDisplayList, GL_COMPILE); - glBindTexture(GL_TEXTURE_2D, 0); + TextureManager.Bind(0); // glColor3ub(0,0,0); McZapkie: to do render // glPushMatrix(); @@ -462,7 +463,7 @@ void TTraction::RenderVBO(float mgn, int iPtr) { // renderowanie z użyciem VBO if (Wires != 0 && !TestFlag(DamageFlag, 128)) // rysuj jesli sa druty i nie zerwana { - glBindTexture(GL_TEXTURE_2D, 0); + TextureManager.Bind(0); glDisable(GL_LIGHTING); // aby nie używało wektorów normalnych do kolorowania glColor4f(0, 0, 0, 1); // jak nieznany kolor to czarne nieprzezroczyste if (!Global::bSmoothTraction) diff --git a/World.cpp b/World.cpp index 9cfa8762..b58e21f9 100644 --- a/World.cpp +++ b/World.cpp @@ -479,8 +479,8 @@ bool TWorld::Init(HWND NhWnd, HDC hDC) glDisable(GL_DEPTH_TEST); // Disables depth testing glColor3f(3.0f, 3.0f, 3.0f); - auto logo = TTexturesManager.GetTextureId( "logo", szTexturePath, 6 ); - glBindTexture(GL_TEXTURE_2D, logo); // Select our texture + auto logo = TextureManager.GetTextureId( "logo", szTexturePath, 6 ); + TextureManager.Bind(logo); // Select our texture glBegin(GL_QUADS); // Drawing using triangles glTexCoord2f(0.0f, 0.0f); @@ -663,9 +663,9 @@ bool TWorld::Init(HWND NhWnd, HDC hDC) // glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); //{Texture blends with object // background} if (Global::bOldSmudge == true) - light = TTexturesManager.GetTextureId( "smuga.tga", szTexturePath ); + light = TextureManager.GetTextureId( "smuga.tga", szTexturePath ); else - light = TTexturesManager.GetTextureId( "smuga2.tga", szTexturePath ); + light = TextureManager.GetTextureId( "smuga2.tga", szTexturePath ); // Camera.Reset(); Timer::ResetTimers(); WriteLog( "Load time: " + @@ -1584,7 +1584,7 @@ TWorld::Render_Cab() { glDisable( GL_LIGHTING ); glDisable( GL_FOG ); glColor4f( 1.0f, 1.0f, 1.0f, 1.0f ); - glBindTexture( GL_TEXTURE_2D, light ); // Select our texture + TextureManager.Bind( light ); // Select our texture glBegin( GL_QUADS ); float fSmudge = dynamic->MoverParameters->DimHalf.y + 7; // gdzie zaczynać smugę @@ -1623,7 +1623,7 @@ TWorld::Render_Cab() { glDisable( GL_LIGHTING ); glDisable( GL_FOG ); //glColor4f(0.15f, 0.15f, 0.15f, 0.25f); - glBindTexture( GL_TEXTURE_2D, light ); // Select our texture + TextureManager.Bind( light ); // Select our texture //float ddl = (0.15*Global::diffuseDayLight[0]+0.295*Global::diffuseDayLight[1]+0.055*Global::diffuseDayLight[2]); //0.24:0 glBegin( GL_QUADS ); float fSmudge = dynamic->MoverParameters->DimHalf.y + 7; // gdzie zaczynać smugę @@ -1922,7 +1922,7 @@ TWorld::Render_UI() { SetWindowText( hWnd, Controlled->MoverParameters->Name.c_str() ); else SetWindowText( hWnd, Global::SceneryFile.c_str() ); // nazwa scenerii - glBindTexture( GL_TEXTURE_2D, 0 ); + TextureManager.Bind( 0 ); glColor4f( 1.0f, 0.0f, 0.0f, 1.0f ); glLoadIdentity(); glTranslatef( 0.0f, 0.0f, -0.50f ); From 1b2b3b06e7fda4ee725f4bd1dbe90af008883eef Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Sun, 12 Feb 2017 23:28:30 +0100 Subject: [PATCH 3/5] converted remaining image loaders --- Texture.cpp | 786 ++++++++++++++++++---------------------------------- Texture.h | 6 +- 2 files changed, 275 insertions(+), 517 deletions(-) diff --git a/Texture.cpp b/Texture.cpp index 8893ce24..70dd9441 100644 --- a/Texture.cpp +++ b/Texture.cpp @@ -48,11 +48,9 @@ opengl_texture::load() { std::string const extension = name.substr( name.size() - 3, 3 ); if( extension == "dds" ) { load_DDS(); } -/* else if( extension == "tga" ) { load_TGA(); } - else if( extension == "tex" ) { load_TEX(); } else if( extension == "bmp" ) { load_BMP(); } -*/ + else if( extension == "tex" ) { load_TEX(); } else { goto fail; } } @@ -68,6 +66,64 @@ fail: return; } +void +opengl_texture::load_BMP() { + + std::ifstream file( name, std::ios::binary ); file.unsetf( std::ios::skipws ); + + BITMAPFILEHEADER header; + + file.read( (char *)&header, sizeof( BITMAPFILEHEADER ) ); + if( file.eof() ) { + + data_state = resource_state::failed; + return; + } + + // Read in bitmap information structure + BITMAPINFO info; + unsigned int infosize = header.bfOffBits - sizeof( BITMAPFILEHEADER ); + if( infosize > sizeof( info ) ) { + WriteLog( "Warning - BMP header is larger than expected, possible format difference." ); + } + file.read( (char *)&info, std::min( infosize, sizeof( info ) ) ); + + data_width = info.bmiHeader.biWidth; + data_height = info.bmiHeader.biHeight; + + if( info.bmiHeader.biCompression != BI_RGB ) { + + ErrorLog( "Compressed BMP textures aren't supported." ); + data_state = resource_state::failed; + return; + } + + unsigned long datasize = info.bmiHeader.biSizeImage; + if( 0 == datasize ) { + // calculate missing info + datasize = ( data_width * info.bmiHeader.biBitCount + 7 ) / 8 * data_height; + } + + data.resize( datasize ); + file.read( &data[0], datasize ); + + // fill remaining data info + if( info.bmiHeader.biBitCount == 32 ) { + + data_format = GL_BGRA; + data_components = GL_RGBA; + } + else { + + data_format = GL_BGR; + data_components = GL_RGB; + } + data_mapcount = 1; + data_state = resource_state::good; + + return; +} + void opengl_texture::load_DDS() { @@ -138,9 +194,11 @@ opengl_texture::load_DDS() { data_state = resource_state::failed; return; } - +/* + // this approach loads only the first mipmap and relies on graphics card to fill the rest + int datasize = ( ( data_width + 3 ) / 4 ) * ( ( data_height + 3 ) / 4 ) * blockSize; +*/ int datasize = filesize - offset; -// int datasize = ( ( data_width + 3 ) / 4 ) * ( ( data_height + 3 ) / 4 ) * blockSize; /* // calculate size of accepted data // NOTE: this is a fallback, as we should be able to just move the file caret by calculated offset and read the rest @@ -176,6 +234,193 @@ opengl_texture::load_DDS() { return; } +void +opengl_texture::load_TEX() { + + std::ifstream file( name, std::ios::binary ); file.unsetf( std::ios::skipws ); + + char head[ 5 ]; + file.read( head, 4 ); + head[ 4 ] = 0; + + bool hasalpha; + if( std::string( "RGB " ) == head ) { + hasalpha = false; + } + else if( std::string( "RGBA" ) == head ) { + hasalpha = true; + } + else { + ErrorLog( "Unrecognized TEX texture sub-format: " + std::string(head) ); + data_state = resource_state::failed; + return; + }; + + file.read( (char *)&data_width, sizeof( int ) ); + file.read( (char *)&data_height, sizeof( int ) ); + + std::size_t datasize = data_width * data_height * ( hasalpha ? 4 : 3 ); + + data.resize( datasize ); + file.read( reinterpret_cast( &data[0] ), datasize ); + + // fill remaining data info + if( true == hasalpha ) { + + data_format = GL_BGRA; + data_components = GL_RGBA; + } + else { + + data_format = GL_BGR; + data_components = GL_RGB; + } + data_mapcount = 1; + data_state = resource_state::good; + + return; +} + +void +opengl_texture::load_TGA() { + + std::ifstream file( name, std::ios::binary ); file.unsetf( std::ios::skipws ); + + // Read the header of the TGA, compare it with the known headers for compressed and uncompressed TGAs + unsigned char tgaheader[ 18 ]; + file.read( (char *)tgaheader, sizeof( unsigned char ) * 18 ); + + while( tgaheader[ 0 ] > 0 ) { + --tgaheader[ 0 ]; + + unsigned char temp; + file.read( (char *)&temp, sizeof( unsigned char ) ); + } + + data_width = tgaheader[ 13 ] * 256 + tgaheader[ 12 ]; + data_height = tgaheader[ 15 ] * 256 + tgaheader[ 14 ]; + int const bytesperpixel = tgaheader[ 16 ] / 8; + + // check whether width, height an BitsPerPixel are valid + if( ( data_width <= 0 ) + || ( data_height <= 0 ) + || ( ( bytesperpixel != 1 ) && ( bytesperpixel != 3 ) && ( bytesperpixel != 4 ) ) ) { + + data_state = resource_state::failed; + return; + } + + // allocate the data buffer + int const datasize = data_width * data_height * 4; + data.resize( datasize ); + + // call the appropriate loader-routine + if( tgaheader[ 2 ] == 2 ) { + // uncompressed TGA + if( bytesperpixel == 4 ) { + // read the data directly + file.read( reinterpret_cast( &data[ 0 ] ), datasize ); + } + else { + // rgb or greyscale image, expand to bgra + unsigned char buffer[ 4 ] = { 255, 255, 255, 255 }; // alpha channel will be white + + unsigned int *datapointer = (unsigned int*)&data[ 0 ]; + unsigned int *bufferpointer = (unsigned int*)&buffer[ 0 ]; + + int const pixelcount = data_width * data_height; + + for( int i = 0; i < pixelcount; ++i ) { + file.read( (char *)buffer, sizeof( unsigned char ) ); + if( bytesperpixel == 1 ) { + // expand greyscale data + buffer[ 1 ] = buffer[ 0 ]; + buffer[ 2 ] = buffer[ 0 ]; + } + // copy all four values in one operation + ( *datapointer ) = ( *bufferpointer ); + ++datapointer; + } + } + } + else if( tgaheader[ 2 ] == 10 ) { + // compressed TGA + int currentpixel = 0; + int currentbyte = 0; + + unsigned char buffer[ 4 ] = { 255, 255, 255, 255 }; + const int pixelcount = data_width * data_height; + + unsigned int *datapointer = (unsigned int *)&data[ 0 ]; + unsigned int *bufferpointer = (unsigned int *)&buffer[ 0 ]; + + do { + unsigned char chunkheader = 0; + + file.read( (char *)&chunkheader, sizeof( unsigned char ) ); + + if( chunkheader < 128 ) { + // if the header is < 128, it means it is the number of RAW color packets minus 1 + // that follow the header + // add 1 to get number of following color values + ++chunkheader; + // read RAW color values + for( int i = 0; i < (int)chunkheader; ++i ) { + + file.read( (char *)&buffer[ 0 ], bytesperpixel ); + + if( bytesperpixel == 1 ) { + // expand greyscale data + buffer[ 1 ] = buffer[ 0 ]; + buffer[ 2 ] = buffer[ 0 ]; + } + // copy all four values in one operation + ( *datapointer ) = ( *bufferpointer ); + + ++datapointer; + ++currentpixel; + } + } + else { + // chunkheader > 128 RLE data, next color reapeated (chunkheader - 127) times + chunkheader -= 127; // Subteact 127 to get rid of the ID bit + // read the current color + file.read( (char *)&buffer[ 0 ], bytesperpixel ); + + if( bytesperpixel == 1 ) { + // expand greyscale data + buffer[ 1 ] = buffer[ 0 ]; + buffer[ 2 ] = buffer[ 0 ]; + } + // copy the color into the image data as many times as dictated + for( int i = 0; i < (int)chunkheader; ++i ) { + + ( *datapointer ) = ( *buffer ); + ++datapointer; + ++currentpixel; + } + } + + } while( currentpixel < pixelcount ); + } + else { + // unrecognized TGA sub-type + data_state = resource_state::failed; + return; + } + + // fill remaining data info + data_mapcount = 1; + data_format = GL_BGRA; + data_components = + ( bytesperpixel == 4 ? + GL_RGBA : + GL_RGB ); + data_state = resource_state::good; + + return; +} + void opengl_texture::create() { @@ -200,7 +445,6 @@ opengl_texture::create() { glTexParameteri( GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE ); } // upload texture data - // TBD, TODO: handle mipmaps other than base manually, or let the card take care of it? int dataoffset = 0, datasize = 0, datawidth = data_width, @@ -211,24 +455,28 @@ opengl_texture::create() { || ( data_format == GL_COMPRESSED_RGBA_S3TC_DXT3_EXT ) || ( data_format == GL_COMPRESSED_RGBA_S3TC_DXT5_EXT ) ) { // compressed dds formats - if( false == Global::bDecompressDDS ) { - // let the openGL handle this - int const datablocksize = - ( data_format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT ? - 8 : - 16 ); + int const datablocksize = + ( data_format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT ? + 8 : + 16 ); - datasize = ( ( std::max(datawidth, 4) + 3 ) / 4 ) * ( ( std::max(dataheight, 4) + 3 ) / 4 ) * datablocksize; + datasize = ( ( std::max(datawidth, 4) + 3 ) / 4 ) * ( ( std::max(dataheight, 4) + 3 ) / 4 ) * datablocksize; - glCompressedTexImage2D( - GL_TEXTURE_2D, maplevel, - data_format, datawidth, dataheight, 0, datasize, - (GLubyte *)&data[0] + dataoffset ); + glCompressedTexImage2D( + GL_TEXTURE_2D, maplevel, data_format, + datawidth, dataheight, 0, + datasize, (GLubyte *)&data[0] + dataoffset ); - dataoffset += datasize; - datawidth = std::max( datawidth / 2, 1 ); - dataheight = std::max( dataheight / 2, 1 ); - } + dataoffset += datasize; + datawidth = std::max( datawidth / 2, 4 ); + dataheight = std::max( dataheight / 2, 4 ); + } + else{ + // uncompressed texture data + glTexImage2D( + GL_TEXTURE_2D, 0, GL_RGBA8, + data_width, data_height, 0, + data_format, GL_UNSIGNED_BYTE, (GLubyte *)&data[0] ); } } } @@ -268,67 +516,6 @@ void texture_manager::Init() { } -/* -TTexturesManager::Names::iterator TTexturesManager::LoadFromFile(std::string fileName, int filter) -{ - - std::string message("Loading - texture: "); - - std::string realFileName(fileName); - std::ifstream file(fileName.c_str()); - // Ra: niby bez tego jest lepiej, ale działa gorzej, więc przywrócone jest oryginalne - if (!file.is_open()) - realFileName.insert(0, szTexturePath); - else - file.close(); - - // char* cFileName = const_cast(fileName.c_str()); - - message += realFileName; - WriteLog(message.c_str()); // Ra: chybaa miało być z komunikatem z przodu, a nie tylko nazwa - - size_t pos = fileName.rfind('.'); - std::string ext(fileName, pos + 1, std::string::npos); - - AlphaValue texinfo; - - if( ext == "dds" ) - texinfo = LoadDDS( realFileName, filter ); - else if( ext == "tga" ) - texinfo = LoadTGA(realFileName, filter); - else if (ext == "tex") - texinfo = LoadTEX(realFileName); - else if (ext == "bmp") - texinfo = LoadBMP(realFileName); - - _alphas.insert( - texinfo); // zapamiętanie stanu przezroczystości tekstury - można by tylko przezroczyste - std::pair ret = _names.insert(std::make_pair(fileName, texinfo.first)); - - if (!texinfo.first) - { - WriteLog("Failed"); - ErrorLog("Missed texture: " + realFileName); - return _names.end(); - }; - - _alphas.insert(texinfo); - ret = _names.insert( - std::make_pair(fileName, texinfo.first)); // dodanie tekstury do magazynu (spisu nazw) - - // WriteLog("OK"); //Ra: "OK" nie potrzeba, samo "Failed" wystarczy - return ret.first; -}; -*/ -/* -struct ReplaceSlash -{ - const char operator()(const char input) - { - return input == '/' ? '\\' : input; - } -}; -*/ // ustalenie numeru tekstury, wczytanie jeśli jeszcze takiej nie było texture_manager::size_type texture_manager::GetTextureId( std::string Filename, std::string const &Dir, int const Filter, bool const Loadnow ) { @@ -336,13 +523,13 @@ texture_manager::GetTextureId( std::string Filename, std::string const &Dir, int if( Filename.find( ':' ) != std::string::npos ) Filename.erase( Filename.find( ':' ) ); // po dwukropku mogą być podane dodatkowe informacje niebędące nazwą tekstury if( Filename.find( '|' ) != std::string::npos ) - Filename.erase( Filename.find( '|' ) ); // po | może być nazwa kolejnej tekstury + Filename.erase( Filename.find( '|' ) ); // po | może być nazwa kolejnej tekstury + if( Filename.rfind( '.' ) != std::string::npos ) + Filename.erase( Filename.rfind( '.' ) ); // trim extension if there's one for( char &c : Filename ) { // change forward slashes to windows ones. NOTE: probably not strictly necessary, but eh c = ( c == '/' ? '\\' : c ); } - if( Filename.rfind('.')!= std::string::npos ) - Filename.erase( Filename.find( '.' ) ); // trim extension if there's one /* std::transform( Filename.begin(), Filename.end(), @@ -461,7 +648,6 @@ texture_manager::find_on_disk( std::string const &Texturename ) { // success return Texturename; } - } // if we fail make a last ditch attempt in the default textures directory { @@ -470,431 +656,12 @@ texture_manager::find_on_disk( std::string const &Texturename ) { // success return szTexturePath + Texturename; } - } // no results either way, report failure return ""; } /* -bool TTexturesManager::GetAlpha(GLuint id) -{ // atrybut przezroczystości dla tekstury o podanym numerze (id) - Alphas::iterator iter = _alphas.find(id); - return (iter != _alphas.end() ? iter->second : false); -} -*/ -/* -TTexturesManager::AlphaValue TTexturesManager::LoadBMP(std::string const &fileName) -{ - - AlphaValue fail(0, false); - std::ifstream file(fileName, std::ios::binary); - - if (!file.is_open()) - { - // file.close(); - return fail; - }; - - BITMAPFILEHEADER header; - - file.read((char *)&header, sizeof(BITMAPFILEHEADER)); - if (file.eof()) - { - return fail; - } - - // Read in bitmap information structure - BITMAPINFO info; - unsigned int infoSize = header.bfOffBits - sizeof(BITMAPFILEHEADER); - if( infoSize > sizeof( info ) ) { - WriteLog( "Warning - BMP header is larger than expected, possible format difference." ); - } - file.read((char *)&info, std::min(infoSize, sizeof(info))); - - if (file.eof()) - { - return fail; - }; - - GLuint width = info.bmiHeader.biWidth; - GLuint height = info.bmiHeader.biHeight; - bool hasalpha = ( info.bmiHeader.biBitCount == 32 ); - - if( info.bmiHeader.biCompression != BI_RGB ) { - ErrorLog( "Compressed BMP textures aren't supported." ); - return fail; - } - - unsigned long bitSize = info.bmiHeader.biSizeImage; - if (!bitSize) - bitSize = (width * info.bmiHeader.biBitCount + 7) / 8 * height; - - std::shared_ptr data( new GLubyte[ bitSize ], std::default_delete() ); - file.read((char *)data.get(), bitSize); - - if (file.eof()) - { - return fail; - }; - - GLuint id; - glGenTextures(1, &id); - glBindTexture(GL_TEXTURE_2D, id); - 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_MAG_FILTER, GL_LINEAR ); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR ); - if( GLEW_VERSION_1_4 ) { - glTexParameteri( GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE ); - } - // This is specific to the binary format of the data read in. - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); - glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); - glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); - -// glTexImage2D(GL_TEXTURE_2D, 0, 3, width, height, 0, GL_BGR_EXT, GL_UNSIGNED_BYTE, data.get()); - glTexImage2D( - GL_TEXTURE_2D, - 0, - GL_RGBA8, - width, - height, - 0, - hasalpha ? GL_BGRA : GL_BGR, - GL_UNSIGNED_BYTE, - data.get() ); - - return std::make_pair(id, hasalpha); -}; - -TTexturesManager::AlphaValue TTexturesManager::LoadTGA(std::string fileName, int filter) -{ - AlphaValue fail(0, false); - int writeback = -1; //-1 plik jest OK, >=0 - od którego bajtu zapisać poprawiony plik - GLubyte TGACompheader[] = {0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // uncompressed TGA header - GLubyte TGAcompare[12]; // used to compare TGA header - GLubyte header[6]; // first 6 useful bytes from the header - std::fstream file(fileName.c_str(), std::ios::binary | std::ios::in); - file.read((char *)TGAcompare, sizeof(TGAcompare)); - file.read((char *)header, sizeof(header)); - // std::cout << file.tellg() << std::endl; - if (file.eof()) - { - file.close(); - return fail; - }; - bool compressed = (memcmp(TGACompheader, TGAcompare, sizeof(TGACompheader)) == 0); - GLint width = header[1] * 256 + header[0]; // determine the TGA width (highbyte*256+lowbyte) - GLint height = header[3] * 256 + header[2]; // determine the TGA height (highbyte*256+lowbyte) - // check if width, height and bpp is correct - if (!width || !height || (header[4] != 24 && header[4] != 32)) - { - WriteLog("Bad texture: " + fileName + " has wrong header or bits per pixel"); - file.close(); - return fail; - }; - { // sprawdzenie prawidłowości rozmiarów - int i, j; - for (i = width, j = 0; i; i >>= 1) - if (i & 1) - ++j; - if (j == 1) - for (i = height, j = 0; i; i >>= 1) - if (i & 1) - ++j; - if (j != 1) - WriteLog("Bad texture: " + fileName + " is " + std::to_string(width) + "×" + std::to_string(height) ); - } - GLuint bpp = header[4]; // grab the TGA's bits per pixel (24 or 32) - GLuint bytesPerPixel = bpp / 8; // divide by 8 to get the bytes per pixel - GLuint imageSize = - width * height * bytesPerPixel; // calculate the memory required for the TGA data - GLubyte *imageData = new GLubyte[imageSize]; // reserve memory to hold the TGA data - if (!compressed) - { // WriteLog("Not compressed."); - file.read(reinterpret_cast(imageData), imageSize); - if (file.eof()) - { - delete[] imageData; - file.close(); - return fail; - }; - } - else - { // skompresowany plik TGA - GLuint filesize; // current byte - GLuint colorbuffer[1]; // Storage for 1 pixel - file.seekg(0, std::ios::end); // na koniec - filesize = (int)file.tellg() - 18; // rozmiar bez nagłówka - file.seekg(18, std::ios::beg); // ponownie za nagłówkiem - GLubyte *copyto = imageData; // gdzie wstawiać w buforze - GLubyte *copyend = imageData + imageSize; // za ostatnim bajtem bufora - GLubyte *copyfrom = imageData + imageSize - filesize; // gdzie jest początek - int chunkheader = 0; // Ra: będziemy wczytywać najmłodszy bajt - if (filesize < imageSize) // jeśli po kompresji jest mniejszy niż przed - { // Ra: nowe wczytywanie skompresowanych: czytamy całe od razu, dekompresja w pamięci - GLuint copybytes; - file.read(reinterpret_cast(copyfrom), filesize); // wczytanie reszty po nagłówku - // najpierw trzeba ustalić, ile skopiowanych pikseli jest na samym końcu - copyto = copyfrom; // roboczo przelatujemy wczytane dane - copybytes = 0; // licznik bajtów obrazka - while (copybytes < imageSize) - { - chunkheader = (unsigned char)*copyto; // jeden bajt, pozostałe zawsze zerowe - copyto += 1 + bytesPerPixel; // bajt licznika oraz jeden piksel jest zawsze - copybytes += (1 + (chunkheader & 127)) * bytesPerPixel; // ilość pikseli - if (chunkheader < 128) // jeśli kopiowanie, pikseli jest więcej - copyto += (chunkheader)*bytesPerPixel; // rozmiar kopiowanego obszaru (bez - // jednego piksela) - } - if (copybytes > imageSize) - { // nie ma prawa być większe - WriteLog("Compression error"); - delete[] imageData; - file.close(); - return fail; - } - // na końcu mogą być śmieci - int extraend = copyend - copyto; // długość śmieci na końcu - if (extraend > 0) - { // przesuwamy bufor do końca obszaru dekompresji - WriteLog("Extra bytes: " + std::to_string(extraend)); - memmove(copyfrom + extraend, copyfrom, filesize - extraend); - copyfrom += extraend; - file.close(); - filesize -= extraend; // to chyba nie ma znaczenia - if (Global::iModifyTGA & 2) // flaga obcinania śmieci - { // najlepiej by było obciąć plik, ale fstream tego nie potrafi - int handle; - for( unsigned int i = 0; i < fileName.length(); ++i ) { - if( fileName[ i ] == '/' ) { fileName[ i ] = '\\'; } // bo to Windows } - } - WriteLog("Truncating extra bytes"); - // NOTE: this posix code is unsafe, and being deprecated in visual c - // TODO: replace with something up to date - handle = open(fileName.c_str(), O_RDWR | O_BINARY); - chsize(handle, 18 + filesize); // obcięcie śmieci - close(handle); - extraend = 0; // skoro obcięty, to się już nie liczy - } - file.open(fileName.c_str(), std::ios::binary | std::ios::in); - } - if (chunkheader < 128) // jeśli ostatnie piksele są kopiowane - copyend -= (1 + chunkheader) * - bytesPerPixel; // bajty kopiowane na końcu nie podlegające dekompresji - else - copyend -= bytesPerPixel; // ostatni piksel i tak się nie zmieni - copyto = imageData; // teraz będzie wypełnianie od początku obszaru - while (copyto < copyend) - { - chunkheader = (unsigned char)*copyfrom; // jeden bajt, pozostałe zawsze zerowe - if (copyto > copyfrom) - { // jeśli piksele mają być kopiowane, to możliwe jest przesunięcie ich o 1 bajt, na - // miejsce licznika - filesize = (imageData + imageSize - copyto) / - bytesPerPixel; // ile pikseli pozostało do końca - // WriteLog("Decompression buffer overflow at pixel - // "+AnsiString((copyto-imageData)/bytesPerPixel)+"+"+AnsiString(filesize)); - // pozycję w pliku trzeba by zapamietać i po wczytaniu reszty pikseli starą - // metodą - // zapisać od niej dane od (copyto), poprzedzone bajtem o wartości (filesize-1) - writeback = imageData + imageSize + extraend - - copyfrom; // ile bajtów skompresowanych zostało do końca - copyfrom = copyto; // adres piksela do zapisania - file.seekg(-writeback, std::ios::end); // odległość od końca (ujemna) - if ((filesize > 128) || - !(Global::iModifyTGA & 4)) // gdy za dużo pikseli albo wyłączone - writeback = -1; // zapis możliwe jeśli ilość problematycznych pikseli nie - // przekaracza 128 - break; // bufor się zatkał, dalej w ten sposób się nie da - } - if (chunkheader < 128) - { // dla nagłówka < 128 mamy podane ile pikseli przekopiować minus 1 - copybytes = (++chunkheader) * bytesPerPixel; // rozmiar kopiowanego obszaru - memcpy(copyto, ++copyfrom, copybytes); // skopiowanie tylu bajtów - copyto += copybytes; - copyfrom += copybytes; - } - else - { // chunkheader > 128 RLE data, next color reapeated chunkheader - 127 times - chunkheader -= 127; - // copy the color into the image data as many times as dictated - if (bytesPerPixel == 4) - { // przy czterech bajtach powinno być szybsze używanie int - __int32 *ptr = (__int32 *)(copyto); // wskaźnik na int - __int32 bgra = *((__int32 *)++copyfrom); // kolor wypełniający (4 bajty) - for (int counter = 0; counter < chunkheader; counter++) - *ptr++ = bgra; - copyto = reinterpret_cast(ptr); // rzutowanie, żeby nie dodawać - copyfrom += 4; - } - else - { - colorbuffer[0] = *((int *)(++copyfrom)); // pobranie koloru (3 bajty) - for (int counter = 0; counter < chunkheader; counter++) - { // by the header - memcpy(copyto, colorbuffer, 3); - copyto += 3; - } - copyfrom += 3; - } - } - } // while (copyto(copyto), chunkheader * bytesPerPixel); - copyto += chunkheader * bytesPerPixel; - } - else - { // chunkheader>128 RLE data, next color reapeated (chunkheader-127) times - chunkheader -= 127; - file.read((char *)colorbuffer, bytesPerPixel); - // copy the color into the image data as many times as dictated - if (bytesPerPixel == 4) - { // przy czterech bajtach powinno być szybsze używanie int - __int32 *ptr = (__int32 *)(copyto), bgra = *((__int32 *)colorbuffer); - for (int counter = 0; counter < chunkheader; counter++) - *ptr++ = bgra; - copyto = reinterpret_cast(ptr); // rzutowanie, żeby nie dodawać - } - else - for (int counter = 0; counter < chunkheader; counter++) - { // by the header - memcpy(copyto, colorbuffer, bytesPerPixel); - copyto += bytesPerPixel; - } - } - } // while (copyto= 0) - { // zapisanie pliku - file.close(); // tamten zamykamy, bo był tylko do odczytu - if (writeback) - { // zapisanie samej końcówki pliku, która utrudnia dekompresję w buforze - WriteLog("Rewriting end of file..."); - chunkheader = filesize - 1; // licznik jest o 1 mniejszy - file.open(fileName.c_str(), std::ios::binary | std::ios::out | std::ios::in); - file.seekg(-writeback, std::ios::end); // odległość od końca (ujemna) - file.write((char *)&chunkheader, 1); // zapisanie licznika - file.write(reinterpret_cast(copyfrom), filesize * bytesPerPixel); // piksele bez kompresji - } - else - { // zapisywanie całości pliku, będzie krótszy, więc trzeba usunąć go w całości - WriteLog("Writing uncompressed file..."); - TGAcompare[2] = 2; // bez kompresji - file.open(fileName.c_str(), std::ios::binary | std::ios::out | std::ios::trunc); - file.write((char *)TGAcompare, sizeof(TGAcompare)); - file.write((char *)header, sizeof(header)); - file.write(reinterpret_cast(imageData), imageSize); - } - } - }; - file.close(); // plik zamykamy dopiero na samym końcu - bool alpha = (bpp == 32); - bool hash = (fileName.find('#') != std::string::npos); // true gdy w nazwie jest "#" - bool dollar = (fileName.find('$') == std::string::npos); // true gdy w nazwie nie ma "$" - size_t pos = fileName.rfind('%'); // ostatni % w nazwie - if (pos != std::string::npos) - if (pos < fileName.size()) - { - filter = (int)fileName[pos + 1] - '0'; // zamiana cyfry za % na liczbę - if ((filter < 0) || (filter > 10)) - filter = -1; // jeśli nie jest cyfrą - } - if (!alpha && !hash && dollar && (filter < 0)) - filter = Global::iDefaultFiltering; // dotyczy tekstur TGA bez kanału alfa - // ewentualne przeskalowanie tekstury do dopuszczalnego rozumiaru - GLint w = width, h = height; - if (width > Global::iMaxTextureSize) - width = Global::iMaxTextureSize; // ogranizczenie wielkości - if (height > Global::iMaxTextureSize) - height = Global::iMaxTextureSize; - if ((w != width) || (h != height)) - { // przeskalowanie tekstury, żeby się nie wyświetlała jako biała - GLubyte *imgData = new GLubyte[width * height * bytesPerPixel]; // nowy rozmiar - gluScaleImage(bytesPerPixel == 3 ? GL_RGB : GL_RGBA, w, h, GL_UNSIGNED_BYTE, imageData, - width, height, GL_UNSIGNED_BYTE, imgData); - delete[] imageData; // usunięcie starego - imageData = imgData; - } - GLuint id = CreateTexture(imageData, (alpha ? GL_BGRA : GL_BGR), width, height, alpha, hash, - dollar, filter); - delete[] imageData; - ++Global::iTextures; - return std::make_pair(id, alpha); -}; - -TTexturesManager::AlphaValue TTexturesManager::LoadTEX(std::string fileName) -{ - - AlphaValue fail(0, false); - - std::ifstream file(fileName.c_str(), std::ios::binary); - - char head[5]; - file.read(head, 4); - head[4] = 0; - - bool alpha; - - if (std::string("RGB ") == head) - { - alpha = false; - } - else if (std::string("RGBA") == head) - { - alpha = true; - } - else - { - std::string message("Unrecognized texture format: "); - message += head; - Error(message.c_str()); - return fail; - }; - - GLuint width; - GLuint height; - - file.read((char *)&width, sizeof(int)); - file.read((char *)&height, sizeof(int)); - - GLuint bpp = alpha ? 4 : 3; - GLuint size = width * height * bpp; - - GLubyte *data = new GLubyte[size]; - file.read(reinterpret_cast(data), size); - - bool hash = (fileName.find('#') != std::string::npos); - - GLuint id = CreateTexture(data, (alpha ? GL_RGBA : GL_RGB), width, height, alpha, hash); - delete[] data; - - return std::make_pair(id, alpha); -}; - TTexturesManager::AlphaValue TTexturesManager::LoadDDS(std::string fileName, int filter) { @@ -1163,12 +930,3 @@ texture_manager::Free() glDeleteTextures( 1, &texture.id ); } } -/* -std::string TTexturesManager::GetName(GLuint id) -{ // pobranie nazwy tekstury - for( auto const &pair : _names ) { - if( pair.second == id ) { return pair.first; } - } - return ""; -}; -*/ \ No newline at end of file diff --git a/Texture.h b/Texture.h index e6082728..f975216c 100644 --- a/Texture.h +++ b/Texture.h @@ -41,10 +41,10 @@ struct opengl_texture { void create(); private: -// void load_BMP(); + void load_BMP(); void load_DDS(); -// void load_TEX(); -// void load_TGA(); + void load_TEX(); + void load_TGA(); void set_filtering(); }; From 6ed00729fca61d9961e85009a0f63ee2a0db2496 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Mon, 13 Feb 2017 15:55:55 +0100 Subject: [PATCH 4/5] recognition of basic texture traits --- Texture.cpp | 85 ++++++++++++++++++++++++++++++++++++++--------------- Texture.h | 3 +- 2 files changed, 64 insertions(+), 24 deletions(-) diff --git a/Texture.cpp b/Texture.cpp index 70dd9441..234b1109 100644 --- a/Texture.cpp +++ b/Texture.cpp @@ -359,13 +359,9 @@ opengl_texture::load_TGA() { file.read( (char *)&chunkheader, sizeof( unsigned char ) ); - if( chunkheader < 128 ) { - // if the header is < 128, it means it is the number of RAW color packets minus 1 - // that follow the header - // add 1 to get number of following color values - ++chunkheader; - // read RAW color values - for( int i = 0; i < (int)chunkheader; ++i ) { + if( (chunkheader & 0x80 ) == 0 ) { + // if the high bit is not set, it means it is the number of RAW color packets, plus 1 + for( int i = 0; i <= chunkheader; ++i ) { file.read( (char *)&buffer[ 0 ], bytesperpixel ); @@ -382,8 +378,8 @@ opengl_texture::load_TGA() { } } else { - // chunkheader > 128 RLE data, next color reapeated (chunkheader - 127) times - chunkheader -= 127; // Subteact 127 to get rid of the ID bit + // rle chunk, the color supplied afterwards is reapeated header + 1 times (not including the highest bit) + chunkheader &= ~0x80; // read the current color file.read( (char *)&buffer[ 0 ], bytesperpixel ); @@ -393,9 +389,9 @@ opengl_texture::load_TGA() { buffer[ 2 ] = buffer[ 0 ]; } // copy the color into the image data as many times as dictated - for( int i = 0; i < (int)chunkheader; ++i ) { + for( int i = 0; i <= chunkheader; ++i ) { - ( *datapointer ) = ( *buffer ); + ( *datapointer ) = ( *bufferpointer ); ++datapointer; ++currentpixel; } @@ -432,9 +428,21 @@ opengl_texture::create() { glGenTextures( 1, &id ); glBindTexture( GL_TEXTURE_2D, id ); + // analyze specified texture traits + bool wraps{ true }; + bool wrapt{ true }; + for( auto const &trait : traits ) { + + switch( trait ) { + + case 's': { wraps = false; break; } + case 't': { wrapt = false; break; } + } + } + // TODO: set wrapping according to supplied parameters - glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT ); - glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, ( wraps == true ? GL_REPEAT : GL_CLAMP_TO_EDGE ) ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, ( wrapt == true ? GL_REPEAT : GL_CLAMP_TO_EDGE ) ); set_filtering(); @@ -457,8 +465,8 @@ opengl_texture::create() { // compressed dds formats int const datablocksize = ( data_format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT ? - 8 : - 16 ); + 8 : + 16 ); datasize = ( ( std::max(datawidth, 4) + 3 ) / 4 ) * ( ( std::max(dataheight, 4) + 3 ) / 4 ) * datablocksize; @@ -484,8 +492,8 @@ opengl_texture::create() { is_ready = true; has_alpha = ( data_components == GL_RGBA ? - true : - false ); + true : + false ); data.resize( 0 ); // TBD, TODO: keep the texture data if we start doing some gpu data cleaning down the road data_state = resource_state::none; @@ -494,14 +502,21 @@ opengl_texture::create() { void opengl_texture::set_filtering() { - bool hash = ( name.find( '#' ) != std::string::npos ); + bool sharpen{ false }; + for( auto const &trait : traits ) { + + switch( trait ) { + + case '#': { sharpen = true; break; } + } + } if( GLEW_VERSION_1_4 ) { glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR ); - if( true == hash ) { + if( true == sharpen ) { // #: sharpen more glTexEnvf( GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, -2.0 ); } @@ -520,12 +535,21 @@ texture_manager::Init() { texture_manager::size_type texture_manager::GetTextureId( std::string Filename, std::string const &Dir, int const Filter, bool const Loadnow ) { - if( Filename.find( ':' ) != std::string::npos ) - Filename.erase( Filename.find( ':' ) ); // po dwukropku mogą być podane dodatkowe informacje niebędące nazwą tekstury if( Filename.find( '|' ) != std::string::npos ) Filename.erase( Filename.find( '|' ) ); // po | może być nazwa kolejnej tekstury + + std::string traits; + auto const traitpos = Filename.find( ':' ); + if( traitpos != std::string::npos ) { + // po dwukropku mogą być podane dodatkowe informacje niebędące nazwą tekstury + if( Filename.size() > traitpos + 1 ) + traits = Filename.substr( traitpos + 1 ); + Filename.erase( traitpos ); + } + if( Filename.rfind( '.' ) != std::string::npos ) Filename.erase( Filename.rfind( '.' ) ); // trim extension if there's one + for( char &c : Filename ) { // change forward slashes to windows ones. NOTE: probably not strictly necessary, but eh c = ( c == '/' ? '\\' : c ); @@ -589,7 +613,15 @@ texture_manager::GetTextureId( std::string Filename, std::string const &Dir, int opengl_texture texture; texture.name = filename; - texture.attributes = std::to_string( Filter ); // temporary. TODO, TBD: check how it's used and possibly get rid of it + if( ( Filter > 0 ) && ( Filter < 10 ) ) { + // temporary. TODO, TBD: check how it's used and possibly get rid of it + traits += std::to_string( Filter ); + } + if( Filename.find('#') !=std::string::npos ) { + // temporary code for legacy assets -- textures with names beginning with # are to be sharpened + traits += '#'; + } + texture.traits = traits; auto const textureindex = m_textures.size(); m_textures.emplace_back( texture ); m_texturemappings.emplace( filename, textureindex ); @@ -608,18 +640,25 @@ texture_manager::GetTextureId( std::string Filename, std::string const &Dir, int void texture_manager::Bind( texture_manager::size_type const Id ) { - // TODO: keep track of what's currently bound and don't do it twice + if( Id == m_activetexture ) { + // don't bind again what's already active + return; + } // TODO: do binding in texture object, add support for other types if( Id != 0 ) { auto const &texture = Texture( Id ); if( true == texture.is_ready ) { glBindTexture( GL_TEXTURE_2D, texture.id ); + m_activetexture = Id; return; } } glBindTexture( GL_TEXTURE_2D, 0 ); + m_activetexture = 0; + + return; } // checks whether specified texture is in the texture bank. returns texture id, or npos. texture_manager::size_type diff --git a/Texture.h b/Texture.h index 99f7eff5..89b34eb1 100644 --- a/Texture.h +++ b/Texture.h @@ -28,7 +28,7 @@ struct opengl_texture { GLuint id{ -1 }; // associated GL resource bool has_alpha{ false }; // indicates the texture has alpha channel bool is_ready{ false }; // indicates the texture was processed and is ready for use - std::string attributes; // requested texture attributes: wrapping modes etc + std::string traits; // requested texture attributes: wrapping modes etc std::string name; // name of the texture source file private: @@ -95,6 +95,7 @@ private: static const size_type npos{ 0 }; // should be -1, but the rest of the code uses -1 for something else opengltexture_array m_textures; index_map m_texturemappings; + size_type m_activetexture{ 0 }; // last i.e. currently bound texture }; extern texture_manager TextureManager; \ No newline at end of file From a362d10fb0739d3a89c521b3caa2a1b7b4d6b898 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Mon, 13 Feb 2017 22:06:26 +0100 Subject: [PATCH 5/5] texture-related render code bumped to openGL 1.4; disabled texture switching optimization until other parts of the render code are reviewed. --- EU07.cpp | 7 + Texture.cpp | 420 ++++++++++++---------------------------------------- Texture.h | 4 +- 3 files changed, 105 insertions(+), 326 deletions(-) diff --git a/EU07.cpp b/EU07.cpp index 367afaa8..3a071cd3 100644 --- a/EU07.cpp +++ b/EU07.cpp @@ -63,6 +63,13 @@ int InitGL(GLvoid) // All Setup For OpenGL Goes Here // _clear87(); // _control87(MCW_EM, MCW_EM); glewInit(); + + if( !GLEW_VERSION_1_4 ) { + // experimental: require at least openGL 1.4 + Error( "This application requires openGL version 1.4 (or better)" ); + return 0; + } + // hunter-271211: przeniesione // AllocConsole(); // SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_GREEN); diff --git a/Texture.cpp b/Texture.cpp index 234b1109..9e509d20 100644 --- a/Texture.cpp +++ b/Texture.cpp @@ -267,12 +267,12 @@ opengl_texture::load_TEX() { // fill remaining data info if( true == hasalpha ) { - data_format = GL_BGRA; + data_format = GL_RGBA; data_components = GL_RGBA; } else { - data_format = GL_BGR; + data_format = GL_RGB; data_components = GL_RGB; } data_mapcount = 1; @@ -425,8 +425,8 @@ opengl_texture::create() { return; } - glGenTextures( 1, &id ); - glBindTexture( GL_TEXTURE_2D, id ); + ::glGenTextures( 1, &id ); + ::glBindTexture( GL_TEXTURE_2D, id ); // analyze specified texture traits bool wraps{ true }; @@ -440,52 +440,48 @@ opengl_texture::create() { } } - // TODO: set wrapping according to supplied parameters - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, ( wraps == true ? GL_REPEAT : GL_CLAMP_TO_EDGE ) ); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, ( wrapt == true ? GL_REPEAT : GL_CLAMP_TO_EDGE ) ); + ::glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, ( wraps == true ? GL_REPEAT : GL_CLAMP_TO_EDGE ) ); + ::glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, ( wrapt == true ? GL_REPEAT : GL_CLAMP_TO_EDGE ) ); set_filtering(); - if( GLEW_VERSION_1_4 ) { + if( data_mapcount == 1 ) { + // fill missing mipmaps if needed + ::glTexParameteri( GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE ); + } + // upload texture data + int dataoffset = 0, + datasize = 0, + datawidth = data_width, + dataheight = data_height; + for( int maplevel = 0; maplevel < data_mapcount; ++maplevel ) { - if( data_mapcount == 1 ) { - // fill missing mipmaps if needed - glTexParameteri( GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE ); + if( ( data_format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT ) + || ( data_format == GL_COMPRESSED_RGBA_S3TC_DXT3_EXT ) + || ( data_format == GL_COMPRESSED_RGBA_S3TC_DXT5_EXT ) ) { + // compressed dds formats + int const datablocksize = + ( data_format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT ? + 8 : + 16 ); + + datasize = ( ( std::max(datawidth, 4) + 3 ) / 4 ) * ( ( std::max(dataheight, 4) + 3 ) / 4 ) * datablocksize; + + ::glCompressedTexImage2D( + GL_TEXTURE_2D, maplevel, data_format, + datawidth, dataheight, 0, + datasize, (GLubyte *)&data[0] + dataoffset ); + + dataoffset += datasize; + datawidth = std::max( datawidth / 2, 4 ); + dataheight = std::max( dataheight / 2, 4 ); } - // upload texture data - int dataoffset = 0, - datasize = 0, - datawidth = data_width, - dataheight = data_height; - for( int maplevel = 0; maplevel < data_mapcount; ++maplevel ) { - - if( ( data_format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT ) - || ( data_format == GL_COMPRESSED_RGBA_S3TC_DXT3_EXT ) - || ( data_format == GL_COMPRESSED_RGBA_S3TC_DXT5_EXT ) ) { - // compressed dds formats - int const datablocksize = - ( data_format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT ? - 8 : - 16 ); - - datasize = ( ( std::max(datawidth, 4) + 3 ) / 4 ) * ( ( std::max(dataheight, 4) + 3 ) / 4 ) * datablocksize; - - glCompressedTexImage2D( - GL_TEXTURE_2D, maplevel, data_format, - datawidth, dataheight, 0, - datasize, (GLubyte *)&data[0] + dataoffset ); - - dataoffset += datasize; - datawidth = std::max( datawidth / 2, 4 ); - dataheight = std::max( dataheight / 2, 4 ); - } - else{ - // uncompressed texture data - glTexImage2D( - GL_TEXTURE_2D, 0, GL_RGBA8, - data_width, data_height, 0, - data_format, GL_UNSIGNED_BYTE, (GLubyte *)&data[0] ); - } + else{ + // uncompressed texture data + ::glTexImage2D( + GL_TEXTURE_2D, 0, GL_RGBA8, + data_width, data_height, 0, + data_format, GL_UNSIGNED_BYTE, (GLubyte *)&data[0] ); } } @@ -502,28 +498,60 @@ opengl_texture::create() { void opengl_texture::set_filtering() { + // default texture mode + ::glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + ::glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR ); + bool sharpen{ false }; for( auto const &trait : traits ) { switch( trait ) { case '#': { sharpen = true; break; } +/* + // legacy filter modes. TODO, TBD: get rid of them? + // let's just turn them off and see if anyone notices. + case '4': { + // najbliższy z tekstury + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); + break; + } + case '5': { + //średnia z tekstury + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + break; + } + case '6': { + // najbliższy z mipmapy + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST ); + break; + } + case '7': { + //średnia z mipmapy + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST ); + break; + } + case '8': { + // najbliższy z dwóch mipmap + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR ); + break; + } + case '9': { + //średnia z dwóch mipmap + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR ); + break; + } +*/ } } - if( GLEW_VERSION_1_4 ) { - - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR ); - - if( true == sharpen ) { - // #: sharpen more - glTexEnvf( GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, -2.0 ); - } - else { - // regular texture sharpening - glTexEnvf( GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, -1.0 ); - } + if( true == sharpen ) { + // #: sharpen more + ::glTexEnvf( GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, -2.0 ); + } + else { + // regular texture sharpening + ::glTexEnvf( GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, -1.0 ); } } @@ -615,7 +643,7 @@ texture_manager::GetTextureId( std::string Filename, std::string const &Dir, int texture.name = filename; if( ( Filter > 0 ) && ( Filter < 10 ) ) { // temporary. TODO, TBD: check how it's used and possibly get rid of it - traits += std::to_string( Filter ); + traits += std::to_string( ( Filter < 4 ? Filter + 4 : Filter ) ); } if( Filename.find('#') !=std::string::npos ) { // temporary code for legacy assets -- textures with names beginning with # are to be sharpened @@ -639,23 +667,28 @@ texture_manager::GetTextureId( std::string Filename, std::string const &Dir, int void texture_manager::Bind( texture_manager::size_type const Id ) { - +/* + // NOTE: this optimization disabled for the time being, until the render code is reviewed + // having it active would lead to some terrain and spline chunks receiving wrong + // (the most recent?) texture, instead of the proper one. It'd also affect negatively + // light point rendering. if( Id == m_activetexture ) { // don't bind again what's already active return; } +*/ // TODO: do binding in texture object, add support for other types if( Id != 0 ) { auto const &texture = Texture( Id ); if( true == texture.is_ready ) { - glBindTexture( GL_TEXTURE_2D, texture.id ); + ::glBindTexture( GL_TEXTURE_2D, texture.id ); m_activetexture = Id; return; } } - glBindTexture( GL_TEXTURE_2D, 0 ); + ::glBindTexture( GL_TEXTURE_2D, 0 ); m_activetexture = 0; return; @@ -700,272 +733,11 @@ texture_manager::find_on_disk( std::string const &Texturename ) { return ""; } -/* -TTexturesManager::AlphaValue TTexturesManager::LoadDDS(std::string fileName, int filter) -{ - - AlphaValue fail(0, false); - - std::ifstream file(fileName.c_str(), std::ios::binary); - - char filecode[5]; - file.read(filecode, 4); - filecode[4] = 0; - - if (std::string("DDS ") != filecode) - { - file.close(); - return fail; - }; - - DDSURFACEDESC2 ddsd; - file.read((char *)&ddsd, sizeof(ddsd)); - - DDS_IMAGE_DATA data; - - // - // This .dds loader supports the loading of compressed formats DXT1, DXT3 - // and DXT5. - // - - GLuint factor; - - switch (ddsd.ddpfPixelFormat.dwFourCC) - { - case FOURCC_DXT1: - // DXT1's compression ratio is 8:1 - data.format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; - factor = 2; - break; - - case FOURCC_DXT3: - // DXT3's compression ratio is 4:1 - data.format = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; - factor = 4; - break; - - case FOURCC_DXT5: - // DXT5's compression ratio is 4:1 - data.format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; - factor = 4; - break; - - default: - file.close(); - return fail; - } - - GLuint bufferSize = (ddsd.dwMipMapCount > 1 ? ddsd.dwLinearSize * factor : ddsd.dwLinearSize); - - data.pixels = new GLubyte[bufferSize]; - file.read((char *)data.pixels, bufferSize); - - file.close(); - - data.width = ddsd.dwWidth; - data.height = ddsd.dwHeight; - data.numMipMaps = ddsd.dwMipMapCount; - { // sprawdzenie prawidłowości rozmiarów - int i, j; - for (i = data.width, j = 0; i; i >>= 1) - if (i & 1) - ++j; - if (j == 1) - for (i = data.height, j = 0; i; i >>= 1) - if (i & 1) - ++j; - if (j != 1) - WriteLog( "Bad texture: " + fileName + " is " + std::to_string(data.width) + "×" + std::to_string(data.height) ); - } - - if (ddsd.ddpfPixelFormat.dwFourCC == FOURCC_DXT1) - data.components = 3; - else - data.components = 4; - - data.blockSize = (data.format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT ? 8 : 16); - - GLuint id; - glGenTextures(1, &id); - glBindTexture(GL_TEXTURE_2D, id); - if (filter >= 0) - SetFiltering(filter); // cyfra po % w nazwie - else - // SetFiltering(bHasAlpha&&bDollar,bHash); //znaki #, $ i kanał alfa w nazwie - SetFiltering(data.components == 4, fileName.find('#') != std::string::npos); - - GLuint offset = 0; - int firstMipMap = 0; - - while ((data.width > Global::iMaxTextureSize) || (data.height > Global::iMaxTextureSize)) - { // pomijanie zbyt dużych mipmap, jeśli wymagane jest ograniczenie rozmiaru - offset += ((data.width + 3) / 4) * ((data.height + 3) / 4) * data.blockSize; - data.width /= 2; - data.height /= 2; - firstMipMap++; - }; - - for (int i = 0; i < data.numMipMaps - firstMipMap; i++) - { // wczytanie kolejnych poziomów mipmap - if (!data.width) - data.width = 1; - if (!data.height) - data.height = 1; - GLuint size = ((data.width + 3) / 4) * ((data.height + 3) / 4) * data.blockSize; - if (Global::bDecompressDDS) - { // programowa dekompresja DDS - // if (i==1) //should be i==0 but then problem with "glBindTexture()" - { - GLuint decomp_size = data.width * data.height * 4; - GLubyte *output = new GLubyte[decomp_size]; - DecompressDXT(data, data.pixels + offset, output); - glTexImage2D( GL_TEXTURE_2D, i, GL_RGBA8, data.width, data.height, 0, GL_RGBA, - GL_UNSIGNED_BYTE, output); - delete[] output; - } - } - else // przetwarzanie DDS przez OpenGL (istnieje odpowiednie rozszerzenie) - glCompressedTexImage2D(GL_TEXTURE_2D, i, data.format, data.width, data.height, 0, size, - data.pixels + offset); - offset += size; - // Half the image size for the next mip-map level... - data.width /= 2; - data.height /= 2; - }; - - if( ( data.numMipMaps == 1 ) - && ( GLEW_VERSION_1_4 ) ) { - // generate missing mipmaps for the updated render path - // TODO, TBD: skip this for UI images - glGenerateMipmap( GL_TEXTURE_2D ); - WriteLog( "Warning - generating missing mipmaps for " + fileName ); - } - - delete[] data.pixels; - return std::make_pair(id, data.components == 4); -}; - -*/ -/* -void TTexturesManager::SetFiltering(int filter) -{ - if (filter < 4) // rozmycie przy powiększeniu - { // brak rozmycia z bliska - tych jest 4: 0..3, aby nie było przeskoku - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - filter += 4; - } - else - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - switch (filter) // rozmycie przy oddaleniu - { - case 4: // najbliższy z tekstury - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - break; - case 5: //średnia z tekstury - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - break; - case 6: // najbliższy z mipmapy - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST); - break; - case 7: //średnia z mipmapy - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); - break; - case 8: // najbliższy z dwóch mipmap - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR); - break; - case 9: //średnia z dwóch mipmap - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - break; - } -}; - -void TTexturesManager::SetFiltering(bool alpha, bool hash) -{ - - if( GLEW_VERSION_1_4 ) { - - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR ); - - if( true == hash ) { - // #: sharpen more - glTexEnvf( GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, -2.0 ); - } - else { - // regular texture sharpening - glTexEnvf( GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, -1.0 ); - } - } - else { - // legacy version, for ancient systems - if( alpha || hash ) { - if( alpha ) // przezroczystosc: nie wlaczac mipmapingu - { - if( hash ) // #: calkowity brak filtracji - pikseloza - { - glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); - glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); - } - else { - glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); - glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); - } - } - else // filtruj ale bez dalekich mipmap - robi artefakty - { - glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); - glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); - } - } - else // $: filtruj wszystko - brzydko się zlewa - { - glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); - glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR ); - } - } -}; - -/////////////////////////////////////////////////////////////////////////////// -GLuint TTexturesManager::CreateTexture(GLubyte *buff, GLint bpp, int width, int height, bool bHasAlpha, - bool bHash, bool bDollar, int filter) -{ // Ra: używane tylko dla TGA i TEX - // Ra: dodana obsługa GL_BGR oraz GL_BGRA dla TGA - szybciej się wczytuje - GLuint ID; - glGenTextures(1, &ID); - glBindTexture(GL_TEXTURE_2D, ID); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - if (filter >= 0) - SetFiltering(filter); // cyfra po % w nazwie - else - SetFiltering(bHasAlpha && bDollar, bHash); // znaki #, $ i kanał alfa w nazwie - - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); - glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); - glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); - - if( GLEW_VERSION_1_4 ) { - - glTexParameteri( GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE ); - glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, bpp, GL_UNSIGNED_BYTE, buff ); - } - else { - // legacy version, for ancient systems - if( bHasAlpha || bHash || ( filter == 0 ) ) - glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, bpp, GL_UNSIGNED_BYTE, buff ); - else - gluBuild2DMipmaps( GL_TEXTURE_2D, GL_RGB, width, height, bpp, GL_UNSIGNED_BYTE, buff ); - } - - return ID; -} -*/ void texture_manager::Free() { for( auto const &texture : m_textures ) { // usunięcie wszyskich tekstur (bez usuwania struktury) - glDeleteTextures( 1, &texture.id ); + ::glDeleteTextures( 1, &texture.id ); } } diff --git a/Texture.h b/Texture.h index 89b34eb1..168bdfe1 100644 --- a/Texture.h +++ b/Texture.h @@ -12,7 +12,7 @@ http://mozilla.org/MPL/2.0/. #include #include "opengl/glew.h" -enum resource_state { +enum class resource_state { none, loading, good, @@ -41,7 +41,7 @@ private: // members std::vector data; // texture data - resource_state data_state{ none }; // current state of texture data + resource_state data_state{ resource_state::none }; // current state of texture data int data_width{ 0 }, data_height{ 0 }, data_mapcount{ 0 };