From f48b61c65038c3a0a0dcf0892fff6bc7a8cee44c Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Tue, 30 May 2017 19:21:40 +0200 Subject: [PATCH 1/9] early implementation of geometry bank, partial replacement of math classes with glm --- Float3d.h | 7 + Ground.cpp | 18 +-- Model3d.cpp | 288 ++++++++++++++++++++++++---------------- Model3d.h | 152 +++------------------ Texture.h | 2 + VBO.cpp | 12 +- VBO.h | 22 +-- maszyna.vcxproj.filters | 6 + openglgeometrybank.cpp | 218 ++++++++++++++++++++++++++++++ openglgeometrybank.h | 122 +++++++++++++++++ renderer.cpp | 22 ++- 11 files changed, 592 insertions(+), 277 deletions(-) create mode 100644 openglgeometrybank.cpp create mode 100644 openglgeometrybank.h diff --git a/Float3d.h b/Float3d.h index 6c309357..f7217a11 100644 --- a/Float3d.h +++ b/Float3d.h @@ -263,6 +263,13 @@ inline float3 operator*(const float4x4 &m, const float3 &v) v.x * m[0][2] + v.y * m[1][2] + v.z * m[2][2] + m[3][2]); } +inline glm::vec3 operator*( const float4x4 &m, const glm::vec3 &v ) { // mnożenie wektora przez macierz + return glm::vec3( + v.x * m[ 0 ][ 0 ] + v.y * m[ 1 ][ 0 ] + v.z * m[ 2 ][ 0 ] + m[ 3 ][ 0 ], + v.x * m[ 0 ][ 1 ] + v.y * m[ 1 ][ 1 ] + v.z * m[ 2 ][ 1 ] + m[ 3 ][ 1 ], + v.x * m[ 0 ][ 2 ] + v.y * m[ 1 ][ 2 ] + v.z * m[ 2 ][ 2 ] + m[ 3 ][ 2 ] ); +} + inline float4x4 &float4x4::Rotation(double angle, float3 axis) { double c = cos(angle); diff --git a/Ground.cpp b/Ground.cpp index 4dfbaa9f..7f18da04 100644 --- a/Ground.cpp +++ b/Ground.cpp @@ -4348,7 +4348,7 @@ void TGround::TerrainWrite() // int ver=0; //caÅ‚kowita ilość wierzchoÅ‚ków int i, j, k; // indeksy w pÄ™tli TGroundNode *Current; - float8 *ver; // trójkÄ…ty + basic_vertex *ver; // trójkÄ…ty TSubModel::iInstance = 0; // pozycja w tabeli wierzchoÅ‚ków liczona narastajÄ…co for (i = 0; i < iNumRects; ++i) // pÄ™tla po wszystkich kwadratach kilometrowych for (j = 0; j < iNumRects; ++j) @@ -4395,14 +4395,14 @@ void TGround::TerrainWrite() Current->iVboPtr = -1; // bo to byÅ‚o tymczasowo używane for (k = 0; k < Current->iNumVerts; ++k) { // przepisanie współrzÄ™dnych - ver[k].Point.x = Current->Vertices[k].Point.x; - ver[k].Point.y = Current->Vertices[k].Point.y; - ver[k].Point.z = Current->Vertices[k].Point.z; - ver[k].Normal.x = Current->Vertices[k].Normal.x; - ver[k].Normal.y = Current->Vertices[k].Normal.y; - ver[k].Normal.z = Current->Vertices[k].Normal.z; - ver[k].tu = Current->Vertices[k].tu; - ver[k].tv = Current->Vertices[k].tv; + ver[k].position.x = Current->Vertices[k].Point.x; + ver[k].position.y = Current->Vertices[k].Point.y; + ver[k].position.z = Current->Vertices[k].Point.z; + ver[k].normal.x = Current->Vertices[k].Normal.x; + ver[k].normal.y = Current->Vertices[k].Normal.y; + ver[k].normal.z = Current->Vertices[k].Normal.z; + ver[k].texture.s = Current->Vertices[k].tu; + ver[k].texture.t = Current->Vertices[k].tv; } break; case GL_TRIANGLE_STRIP: // na razie nie, bo trzeba przerabiać na pojedyncze diff --git a/Model3d.cpp b/Model3d.cpp index 7eb1493f..2d9ebfdb 100644 --- a/Model3d.cpp +++ b/Model3d.cpp @@ -113,11 +113,6 @@ TSubModel::~TSubModel() delete fMatrix; // wÅ‚asny transform trzeba usunąć (zawsze jeden) delete[] Vertices; } - /* - else - {//wczytano z pliku binarnego (nie jest wÅ‚aÅ›cicielem tablic) - } - */ delete[] smLetter; // używany tylko roboczo dla TP_TEXT, do przyspieszenia // wyÅ›wietlania }; @@ -141,23 +136,23 @@ void TSubModel::NameSet(const char *n) // int TSubModel::SeekFaceNormal(DWORD *Masks, int f,DWORD dwMask,vector3 // *pt,GLVERTEX // *Vertices) -int TSubModel::SeekFaceNormal(unsigned int *Masks, int f, unsigned int dwMask, float3 *pt, - float8 *Vertices) +int TSubModel::SeekFaceNormal(unsigned int *Masks, int f, unsigned int dwMask, glm::vec3 *pt, + basic_vertex *Vertices) { // szukanie punktu stycznego // do (pt), zwraca numer // wierzchoÅ‚ka, a nie trójkÄ…ta int iNumFaces = iNumVerts / 3; // bo maska powierzchni jest jedna na trójkÄ…t // GLVERTEX *p; //roboczy wskaźnik - float8 *p; // roboczy wskaźnik + basic_vertex *p; // roboczy wskaźnik for (int i = f; i < iNumFaces; ++i) // pÄ™tla po trójkÄ…tach, od trójkÄ…ta (f) if (Masks[i] & dwMask) // jeÅ›li wspólna maska powierzchni { p = Vertices + 3 * i; - if (p->Point == *pt) + if (p->position == *pt) return 3 * i; - if ((++p)->Point == *pt) + if ((++p)->position == *pt) return 3 * i + 1; - if ((++p)->Point == *pt) + if ((++p)->position == *pt) return 3 * i + 2; } return -1; // nie znaleziono stycznego wierzchoÅ‚ka @@ -446,7 +441,7 @@ int TSubModel::Load(cParser &parser, TModel3d *Model, int Pos, bool dynamic) // Vertices=new GLVERTEX[iNumVerts]; if (iNumVerts) { - Vertices = new float8[iNumVerts]; + Vertices = new basic_vertex[iNumVerts]; iNumFaces = iNumVerts / 3; sg = new unsigned int[iNumFaces]; // maski powierzchni: 0 oznacza brak // użredniania wektorów normalnych @@ -467,21 +462,28 @@ int TSubModel::Load(cParser &parser, TModel3d *Model, int Pos, bool dynamic) // wektorów normalnych } parser.getTokens(3, false); - parser >> Vertices[i].Point.x >> Vertices[i].Point.y >> Vertices[i].Point.z; + parser + >> Vertices[i].position.x + >> Vertices[i].position.y + >> Vertices[i].position.z; if (maska == -1) { // jeÅ›li wektory normalne podane jawnie parser.getTokens(3, false); - parser >> Vertices[i].Normal.x >> Vertices[i].Normal.y >> - Vertices[i].Normal.z; + parser + >> Vertices[i].normal.x + >> Vertices[i].normal.y + >> Vertices[i].normal.z; wsp[i] = i; // wektory normalne "sÄ… już policzone" } parser.getTokens(2, false); - parser >> Vertices[i].tu >> Vertices[i].tv; + parser + >> Vertices[i].texture.s + >> Vertices[i].texture.t; if (i % 3 == 2) // jeżeli wczytano 3 punkty { - if (Vertices[i].Point == Vertices[i - 1].Point || - Vertices[i - 1].Point == Vertices[i - 2].Point || - Vertices[i - 2].Point == Vertices[i].Point) + if (Vertices[i].position == Vertices[i - 1].position + || Vertices[i - 1].position == Vertices[i - 2].position + || Vertices[i - 2].position == Vertices[i].position) { // jeżeli punkty siÄ™ nakÅ‚adajÄ… na siebie --iNumFaces; // o jeden trójkÄ…t mniej iNumVerts -= 3; // czyli o 3 wierzchoÅ‚ki @@ -491,10 +493,9 @@ int TSubModel::Load(cParser &parser, TModel3d *Model, int Pos, bool dynamic) } if (i > 0) // jeÅ›li pierwszy trójkÄ…t bÄ™dzie zdegenerowany, to // zostanie usuniÄ™ty i nie ma co sprawdzać - if (((Vertices[i].Point - Vertices[i - 1].Point).Length() > 1000.0) || - ((Vertices[i - 1].Point - Vertices[i - 2].Point).Length() > - 1000.0) || - ((Vertices[i - 2].Point - Vertices[i].Point).Length() > 1000.0)) + if ((glm::length(Vertices[i].position - Vertices[i - 1].position) > 1000.0) + || (glm::length(Vertices[i - 1].position - Vertices[i - 2].position) > 1000.0) + || (glm::length(Vertices[i - 2].position - Vertices[i].position) > 1000.0)) { // jeżeli sÄ… dalej niż 2km od siebie //Ra 15-01: // obiekt wstawiany nie powinien być wiÄ™kszy niż // 300m (trójkÄ…ty terenu w E3D mogÄ… mieć 1.5km) @@ -507,26 +508,27 @@ int TSubModel::Load(cParser &parser, TModel3d *Model, int Pos, bool dynamic) } } int i; // indeks dla trójkÄ…tów - float3 *n = new float3[iNumFaces]; // tablica wektorów normalnych dla trójkÄ…tów - for (i = 0; i < iNumFaces; i++) // pÄ™tla po trójkÄ…tach - bÄ™dzie + glm::vec3 *n = new glm::vec3[iNumFaces]; // tablica wektorów normalnych dla trójkÄ…tów + for (i = 0; i < iNumFaces; ++i) // pÄ™tla po trójkÄ…tach - bÄ™dzie // szybciej, jak wstÄ™pnie przeliczymy // normalne trójkÄ…tów - n[i] = SafeNormalize( - CrossProduct(Vertices[i * 3].Point - Vertices[i * 3 + 1].Point, - Vertices[i * 3].Point - Vertices[i * 3 + 2].Point)); + n[i] = glm::normalize( + glm::cross( + Vertices[i * 3].position - Vertices[i * 3 + 1].position, + Vertices[i * 3].position - Vertices[i * 3 + 2].position)); int v; // indeks dla wierzchoÅ‚ków int f; // numer trójkÄ…ta stycznego - float3 norm; // roboczy wektor normalny - for (v = 0; v < iNumVerts; v++) + glm::vec3 norm; // roboczy wektor normalny + for (v = 0; v < iNumVerts; ++v) { // pÄ™tla po wierzchoÅ‚kach trójkÄ…tów if (wsp[v] >= 0) // jeÅ›li już byÅ‚ liczony wektor normalny z użyciem // tego wierzchoÅ‚ka - Vertices[v].Normal = - Vertices[wsp[v]].Normal; // to wystarczy skopiować policzony wczeÅ›niej + Vertices[v].normal = + Vertices[wsp[v]].normal; // to wystarczy skopiować policzony wczeÅ›niej else { // inaczej musimy dopiero policzyć i = v / 3; // numer trójkÄ…ta - norm = float3(0, 0, 0); // liczenie zaczynamy od zera + norm = glm::vec3(); // liczenie zaczynamy od zera f = v; // zaczynamy dodawanie wektorów normalnych od wÅ‚asnego while (f >= 0) { // sumowanie z wektorem normalnym sÄ…siada (włącznie @@ -534,13 +536,13 @@ int TSubModel::Load(cParser &parser, TModel3d *Model, int Pos, bool dynamic) wsp[f] = v; // informacja, że w tym wierzchoÅ‚ku jest już policzony // wektor normalny norm += n[f / 3]; - f = SeekFaceNormal(sg, f / 3 + 1, sg[i], &Vertices[v].Point, + f = SeekFaceNormal(sg, f / 3 + 1, sg[i], &Vertices[v].position, Vertices); // i szukanie od kolejnego trójkÄ…ta } // Ra 15-01: należaÅ‚o by jeszcze uwzglÄ™dnić skalowanie wprowadzane // przez transformy, aby normalne po przeskalowaniu byÅ‚y jednostkowe - Vertices[v].Normal = - SafeNormalize(norm); // przepisanie do wierzchoÅ‚ka trójkÄ…ta + Vertices[v].normal = + glm::normalize(norm); // przepisanie do wierzchoÅ‚ka trójkÄ…ta } } delete[] wsp; @@ -561,21 +563,24 @@ int TSubModel::Load(cParser &parser, TModel3d *Model, int Pos, bool dynamic) parser.getTokens(2, false); parser >> discard >> iNumVerts; // Vertices=new GLVERTEX[iNumVerts]; - Vertices = new float8[iNumVerts]; + Vertices = new basic_vertex[iNumVerts]; int i, j; - for (i = 0; i < iNumVerts; i++) + for (i = 0; i < iNumVerts; ++i) { if (i % 3 == 0) { parser.ignoreToken(); // maska powierzchni trójkÄ…ta } parser.getTokens(5, false); - parser >> Vertices[i].Point.x >> Vertices[i].Point.y >> Vertices[i].Point.z >> - j // zakodowany kolor + parser + >> Vertices[i].position.x + >> Vertices[i].position.y + >> Vertices[i].position.z + >> j // zakodowany kolor >> discard; - Vertices[i].Normal.x = ((j) & 0xFF) / 255.0; // R - Vertices[i].Normal.y = ((j >> 8) & 0xFF) / 255.0; // G - Vertices[i].Normal.z = ((j >> 16) & 0xFF) / 255.0; // B + Vertices[i].normal.x = ((j) & 0xFF) / 255.0; // R + Vertices[i].normal.y = ((j >> 8) & 0xFF) / 255.0; // G + Vertices[i].normal.z = ((j >> 16) & 0xFF) / 255.0; // B } } // Visible=true; //siÄ™ potem wyłączy w razie potrzeby @@ -605,11 +610,9 @@ int TSubModel::TriangleAdd(TModel3d *m, texture_manager::size_type tex, int tri) s = new TSubModel(); m->AddTo(this, s); } - // s->asTexture=AnsiString(TTexturesManager::GetName(tex).c_str()); s->TextureNameSet(GfxRenderer.Texture(tex).name.c_str()); s->TextureID = tex; s->eType = GL_TRIANGLES; - // iAnimOwner=0; //roboczy wskaźnik na wierzchoÅ‚ek } if (s->iNumVerts < 0) s->iNumVerts = tri; // bo na poczÄ…tku jest -1, czyli że nie wiadomo @@ -618,7 +621,7 @@ int TSubModel::TriangleAdd(TModel3d *m, texture_manager::size_type tex, int tri) return s->iNumVerts - tri; // zwraca pozycjÄ™ tych trójkÄ…tów w submodelu }; -float8 *TSubModel::TrianglePtr(int tex, int pos, int *la, int *ld, int *ls) +basic_vertex *TSubModel::TrianglePtr(int tex, int pos, int *la, int *ld, int *ls) { // zwraca wskaźnik do wypeÅ‚nienia tabeli wierzchoÅ‚ków, używane // przy tworzeniu E3D terenu TSubModel *s = this; @@ -633,9 +636,7 @@ float8 *TSubModel::TrianglePtr(int tex, int pos, int *la, int *ld, int *ls) return NULL; // coÅ› nie tak poszÅ‚o if (!s->Vertices) { // utworznie tabeli trójkÄ…tów - s->Vertices = new float8[s->iNumVerts]; - // iVboPtr=pos; //pozycja submodelu w tabeli wierzchoÅ‚ków - // pos+=iNumVerts; //rezerwacja miejsca w tabeli + s->Vertices = new basic_vertex[s->iNumVerts]; s->iVboPtr = iInstance; // pozycja submodelu w tabeli wierzchoÅ‚ków iInstance += s->iNumVerts; // pozycja dla nastÄ™pnego } @@ -648,7 +649,6 @@ void TSubModel::DisplayLists() // każdego submodelu if (Global::bUseVBO) return; // Ra: przy VBO to siÄ™ nie przyda - // iFlags|=0x4000; //wyłączenie przeliczania wierzchoÅ‚ków, bo nie sÄ… zachowane if (eType < TP_ROTATOR) { if (iNumVerts > 0) @@ -670,9 +670,9 @@ void TSubModel::DisplayLists() glTexCoord2f(Vertices[i].tu,Vertices[i].tv); glVertex3dv(&Vertices[i].Point.x); */ - glNormal3fv(&Vertices[i].Normal.x); - glTexCoord2f(Vertices[i].tu, Vertices[i].tv); - glVertex3fv(&Vertices[i].Point.x); + glNormal3fv(glm::value_ptr(Vertices[i].normal)); + glTexCoord2fv(glm::value_ptr(Vertices[i].texture)); + glVertex3fv(glm::value_ptr(Vertices[i].position)); }; glEnd(); #endif @@ -693,10 +693,10 @@ void TSubModel::DisplayLists() uiDisplayList = glGenLists(1); glNewList(uiDisplayList, GL_COMPILE); glBegin(GL_POINTS); - for (int i = 0; i < iNumVerts; i++) + for (int i = 0; i < iNumVerts; ++i) { - glColor3f(Vertices[i].Normal.x, Vertices[i].Normal.y, Vertices[i].Normal.z); - glVertex3fv(&Vertices[i].Point.x); + glColor3fv(glm::value_ptr(Vertices[i].normal)); + glVertex3fv(glm::value_ptr(Vertices[i].position)); }; glEnd(); glEndList(); @@ -736,13 +736,13 @@ void TSubModel::InitialRotate(bool doit) if (Vertices) { for (int i = 0; i < iNumVerts; ++i) - Vertices[i].Point = (*mat) * Vertices[i].Point; + Vertices[i].position = (*mat) * Vertices[i].position; (*mat)(3)[0] = (*mat)(3)[1] = (*mat)(3)[2] = 0.0; // zerujemy przesuniÄ™cie przed obracaniem normalnych if (eType != TP_STARS) // gwiazdki majÄ… kolory zamiast normalnych, to // ich wtedy nie ruszamy for (int i = 0; i < iNumVerts; ++i) - Vertices[i].Normal = SafeNormalize((*mat) * Vertices[i].Normal); + Vertices[i].normal = glm::normalize((*mat) * Vertices[i].normal); } mat->Identity(); // jedynkowanie transformu po przeliczeniu wierzchoÅ‚ków iFlags &= ~0x8000; // transform jedynkowy @@ -756,17 +756,17 @@ void TSubModel::InitialRotate(bool doit) if (Vertices) for (int i = 0; i < iNumVerts; ++i) { - Vertices[i].Point.x = -Vertices[i].Point.x; // zmiana znaku X - t = Vertices[i].Point.y; // zamiana Y i Z - Vertices[i].Point.y = Vertices[i].Point.z; - Vertices[i].Point.z = t; + Vertices[i].position.x = -Vertices[i].position.x; // zmiana znaku X + t = Vertices[i].position.y; // zamiana Y i Z + Vertices[i].position.y = Vertices[i].position.z; + Vertices[i].position.z = t; // wektory normalne również trzeba przeksztaÅ‚cić, bo siÄ™ źle oÅ›wietlajÄ… if( eType != TP_STARS ) { // gwiazdki majÄ… kolory zamiast normalnych, to // ich wtedy nie ruszamy - Vertices[ i ].Normal.x = -Vertices[ i ].Normal.x; // zmiana znaku X - t = Vertices[ i ].Normal.y; // zamiana Y i Z - Vertices[ i ].Normal.y = Vertices[ i ].Normal.z; - Vertices[ i ].Normal.z = t; + Vertices[ i ].normal.x = -Vertices[ i ].normal.x; // zmiana znaku X + t = Vertices[ i ].normal.y; // zamiana Y i Z + Vertices[ i ].normal.y = Vertices[ i ].normal.z; + Vertices[ i ].normal.z = t; } } if (Child) @@ -1045,14 +1045,14 @@ void TSubModel::RaArrayFill(CVertNormTex *Vert) if ((eType < TP_ROTATOR) || (eType == TP_STARS)) for (int i = 0; i < iNumVerts; ++i) { - Vert[iVboPtr + i].x = Vertices[i].Point.x; - Vert[iVboPtr + i].y = Vertices[i].Point.y; - Vert[iVboPtr + i].z = Vertices[i].Point.z; - Vert[iVboPtr + i].nx = Vertices[i].Normal.x; - Vert[iVboPtr + i].ny = Vertices[i].Normal.y; - Vert[iVboPtr + i].nz = Vertices[i].Normal.z; - Vert[iVboPtr + i].u = Vertices[i].tu; - Vert[iVboPtr + i].v = Vertices[i].tv; + Vert[iVboPtr + i].x = Vertices[i].position.x; + Vert[iVboPtr + i].y = Vertices[i].position.y; + Vert[iVboPtr + i].z = Vertices[i].position.z; + Vert[iVboPtr + i].nx = Vertices[i].normal.x; + Vert[iVboPtr + i].ny = Vertices[i].normal.y; + Vert[iVboPtr + i].nz = Vertices[i].normal.z; + Vert[iVboPtr + i].u = Vertices[i].texture.s; + Vert[iVboPtr + i].v = Vertices[i].texture.t; } else if (eType == TP_FREESPOTLIGHT) Vert[iVboPtr].x = Vert[iVboPtr].y = Vert[iVboPtr].z = 0.0; @@ -1114,6 +1114,7 @@ float TSubModel::MaxY(const float4x4 &m) return 0; // tylko dla trójkÄ…tów liczymy if (iNumVerts < 1) return 0; +/* if (!Vertices) return 0; float y, @@ -1126,6 +1127,22 @@ float TSubModel::MaxY(const float4x4 &m) if (my < y) my = y; } +*/ + float my = + m[ 0 ][ 1 ] * Vertices[ 0 ].position.x + + m[ 1 ][ 1 ] * Vertices[ 0 ].position.y + + m[ 2 ][ 1 ] * Vertices[ 0 ].position.z + + m[ 3 ][ 1 ]; + float y; + for( int i = 1; i < iNumVerts; ++i ) { + y = + m[ 0 ][ 1 ] * Vertices[ i ].position.x + + m[ 1 ][ 1 ] * Vertices[ i ].position.y + + m[ 2 ][ 1 ] * Vertices[ i ].position.z + + m[ 3 ][ 1 ]; + + if( my < y ) { my = y; } + } return my; }; //--------------------------------------------------------------------------- @@ -1495,28 +1512,7 @@ void TModel3d::deserialize(std::istream &s, size_t size, bool dynamic) uint32_t size = sn_utils::ld_uint32(s) - 8; std::streampos end = s.tellg() + (std::streampos)size; - if (type == MAKE_ID4('V', 'N', 'T', '0')) - { -#ifdef EU07_USE_OLD_VERTEXBUFFER - if (m_pVNT != nullptr) -#else - if( false == m_pVNT.empty() ) -#endif - throw std::runtime_error("e3d: duplicated VNT chunk"); - - size_t vt_cnt = size / 32; - iNumVerts = (int)vt_cnt; - m_nVertexCount = (int)vt_cnt; -#ifdef EU07_USE_OLD_VERTEXBUFFER - assert( m_pVNT == nullptr ); - m_pVNT = new CVertNormTex[vt_cnt]; -#else - m_pVNT.resize( vt_cnt ); -#endif - for (size_t i = 0; i < vt_cnt; i++) - m_pVNT[i].deserialize(s); - } - else if ((type & 0x00FFFFFF) == MAKE_ID4('S', 'U', 'B', 0)) + if ((type & 0x00FFFFFF) == MAKE_ID4('S', 'U', 'B', 0)) { if (Root != nullptr) throw std::runtime_error("e3d: duplicated SUB chunk"); @@ -1532,6 +1528,66 @@ void TModel3d::deserialize(std::istream &s, size_t size, bool dynamic) Root[i].deserialize(s); } } + else if (type == MAKE_ID4('V', 'N', 'T', '0')) + { +#ifdef EU07_USE_OLD_VERTEXBUFFER + if (m_pVNT != nullptr) +#else + if( false == m_pVNT.empty() ) +#endif + throw std::runtime_error("e3d: duplicated VNT chunk"); + +/* + size_t vt_cnt = size / 32; + iNumVerts = (int)vt_cnt; + m_nVertexCount = (int)vt_cnt; +#ifdef EU07_USE_OLD_VERTEXBUFFER + assert( m_pVNT == nullptr ); + m_pVNT = new CVertNormTex[vt_cnt]; +#else + m_pVNT.resize( vt_cnt ); +#endif + for (size_t i = 0; i < vt_cnt; i++) + m_pVNT[i].deserialize(s); +*/ + + // we rely on the SUB chunk coming before the vertex data, and on the overall vertex count matching the size of data in the chunk + // geometry associated with chunks isn't stored in the order the actual chunks are listed, so we need to sort that out first + std::vector< std::pair > submodeloffsets; + submodeloffsets.reserve( iSubModelsCount ); + for( int idx = 0; idx < iSubModelsCount; ++idx ) { + auto &submodel = Root[ idx ]; + if( submodel.iNumVerts <= 0 ) { continue; } + submodeloffsets.emplace_back( submodel.tVboPtr, idx ); + } + std::sort( + submodeloffsets.begin(), + submodeloffsets.end(), + []( std::pair const &Left, std::pair const &Right ) { + return (Left.first) < (Right.first); } ); + // once sorted we can grab geometry for the chunks as they come + for( auto const &submodeloffset : submodeloffsets ) { + auto &submodel = Root[ submodeloffset.second ]; + vertex_array vertices; vertices.resize( submodel.iNumVerts ); + for( auto &vertex : vertices ) { + vertex.deserialize( s ); + } + // remap geometry type for custom type submodels + int type; + switch( submodel.eType ) { + case TP_FREESPOTLIGHT: + case TP_STARS: { + type = GL_POINTS; + break; } + default: { + type = submodel.eType; + break; + } + } + submodel.m_chunk = m_geometry->create( vertices, type ); + } + + } else if (type == MAKE_ID4('T', 'R', 'A', '0')) { if (tm != nullptr) @@ -1572,18 +1628,23 @@ void TModel3d::deserialize(std::istream &s, size_t size, bool dynamic) if (!Root) throw std::runtime_error("e3d: no submodels"); - +/* #ifdef EU07_USE_OLD_VERTEXBUFFER if (!m_pVNT) #else if(m_pVNT.empty() ) #endif throw std::runtime_error("e3d: no vertices"); - - for (size_t i = 0; (int)i < iSubModelsCount; i++) +*/ + for (size_t i = 0; (int)i < iSubModelsCount; ++i) { #ifdef EU07_USE_OLD_VERTEXBUFFER - Root[i].BinInit(Root, tm, (float8*)m_pVNT, &Textures, &Names, dynamic); + Root[i].BinInit( + Root, tm, + ( Root[i].m_chunk ? + &m_geometry->data(Root[i].m_chunk)[0] : + nullptr ), + &Textures, &Names, dynamic); #else Root[ i ].BinInit( Root, tm, (float8*)m_pVNT.data(), &Textures, &Names, dynamic ); #endif @@ -1595,7 +1656,7 @@ void TModel3d::deserialize(std::istream &s, size_t size, bool dynamic) } } -void TSubModel::BinInit(TSubModel *s, float4x4 *m, float8 *v, +void TSubModel::BinInit(TSubModel *s, float4x4 *m, basic_vertex *v, std::vector *t, std::vector *n, bool dynamic) { // ustawienie wskaźników w submodelu //m7todo: brzydko @@ -1659,9 +1720,7 @@ void TSubModel::BinInit(TSubModel *s, float4x4 *m, float8 *v, iFlags &= ~0x0200; // wczytano z pliku binarnego (nie jest wÅ‚aÅ›cicielem tablic) iVboPtr = tVboPtr; - Vertices = v + iVboPtr; - // if (!iNumVerts) eType=-1; //tymczasowo zmiana typu, żeby siÄ™ nie - // renderowaÅ‚o na siłę + Vertices = v; }; void TModel3d::LoadFromBinFile(std::string const &FileName, bool dynamic) @@ -1696,27 +1755,26 @@ void TModel3d::LoadFromTextFile(std::string const &FileName, bool dynamic) // parser.getToken(parent); parser.getTokens(1, false); // nazwa submodelu nadrzÄ™dnego bez zmieny na maÅ‚e parser >> parent; - if (parent == "") - break; + if( parent == "" ) { + break; + } SubModel = new TSubModel(); iNumVerts += SubModel->Load(parser, this, iNumVerts, dynamic); - SubModel->Parent = AddToNamed( - parent.c_str(), SubModel); // bÄ™dzie potrzebne do wyliczenia pozycji, np. pantografu - // iSubModelsCount++; + + // bÄ™dzie potrzebne do wyliczenia pozycji, np. pantografu + SubModel->Parent = AddToNamed(parent.c_str(), SubModel); + parser.getTokens(); parser >> token; } - // Ra: od wersji 334 przechylany jest caÅ‚y model, a nie tylko pierwszy - // submodel - // ale bujanie kabiny nadal używa bananów :( od 393 przywrócone, ale z - // dodatkowym warunkiem + // Ra: od wersji 334 przechylany jest caÅ‚y model, a nie tylko pierwszy submodel + // ale bujanie kabiny nadal używa bananów :( od 393 przywrócone, ale z dodatkowym warunkiem if (Global::iConvertModels & 4) { // automatyczne banany czasem psuÅ‚y przechylanie kabin... if (dynamic && Root) { if (Root->NextGet()) // jeÅ›li ma jakiekolwiek kolejne - { // dynamic musi mieć "banana", bo tylko pierwszy obiekt jest animowany, - // a nastÄ™pne nie + { // dynamic musi mieć "banana", bo tylko pierwszy obiekt jest animowany, a nastÄ™pne nie SubModel = new TSubModel(); // utworzenie pustego SubModel->ChildAdd(Root); Root = SubModel; diff --git a/Model3d.h b/Model3d.h index ae650785..06a5c985 100644 --- a/Model3d.h +++ b/Model3d.h @@ -19,82 +19,6 @@ http://mozilla.org/MPL/2.0/. using namespace Math3D; -struct GLVERTEX -{ - vector3 Point; - vector3 Normal; - float tu, tv; -}; - -class TMaterialColor -{ -public: - TMaterialColor() {}; - TMaterialColor(char V) - { - r = g = b = V; - }; - // TMaterialColor(double R, double G, double B) - TMaterialColor(char R, char G, char B) - { - r = R; - g = G; - b = B; - }; - - char r, g, b; -}; - -/* -struct TMaterial -{ -int ID; -AnsiString Name; -//McZapkie-240702: lepiej uzywac wartosci float do opisu koloru bo funkcje opengl chyba tego na ogol -uzywaja -float Ambient[4]; -float Diffuse[4]; -float Specular[4]; -float Transparency; -GLuint TextureID; -}; -*/ -/* -struct THitBoxContainer -{ -TPlane Planes[6]; -int Index; -inline void Reset() { Planes[0]= TPlane(vector3(0,0,0),0.0f); }; -inline bool Inside(vector3 Point) -{ -bool Hit= true; - -if (Planes[0].Defined()) -for (int i=0; i<6; i++) -{ -if (Planes[i].GetSide(Point)>0) -{ -Hit= false; -break; -}; - -} -else return(false); -return(Hit); -}; -}; -*/ - -/* Ra: tego nie bÄ™dziemy już używać, bo można wycisnąć wiÄ™cej -typedef enum -{smt_Unknown, //nieznany -smt_Mesh, //siatka -smt_Point, -smt_FreeSpotLight, //punkt Å›wietlny -smt_Text, //generator tekstu -smt_Stars //wiele punktów Å›wietlnych -} TSubModelType; -*/ // Ra: specjalne typy submodeli, poza tym GL_TRIANGLES itp. const int TP_ROTATOR = 256; const int TP_FREESPOTLIGHT = 257; @@ -134,6 +58,7 @@ class TSubModel //m7todo: zrobić normalnÄ… serializacjÄ™ friend class opengl_renderer; + friend class TModel3d; // temporary workaround. TODO: clean up class content/hierarchy private: int iNext; @@ -160,7 +85,6 @@ private: union { // transform, nie każdy submodel musi mieć float4x4 *fMatrix; // pojedyncza precyzja wystarcza - // matrix4x4 *dMatrix; //do testu macierz podwójnej precyzji int iMatrix; // w pliku binarnym jest numer matrycy }; int iNumVerts; // ilość wierzchoÅ‚ków (1 dla FreeSpotLight) @@ -188,21 +112,19 @@ private: TSubModel *Next; TSubModel *Child; intptr_t iVboPtr; + geometrychunk_handle m_chunk; // geometry of the submodel 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 float Opacity; // nie używane, ale wczytywane //m7todo: wywalić to - // ABu: te same zmienne, ale zdublowane dla Render i RenderAlpha, - // bo sie chrzanilo przemieszczanie obiektow. - // Ra: już siÄ™ nie chrzani float f_Angle; float3 v_RotateAxis; float3 v_Angles; public: // chwilowo float3 v_TransVector; - float8 *Vertices; // roboczy wskaźnik - wczytanie T3D do VBO + basic_vertex *Vertices; // roboczy wskaźnik - wczytanie T3D do VBO size_t iAnimOwner; // roboczy numer egzemplarza, który ustawiÅ‚ animacjÄ™ TAnimType b_aAnim; // kody animacji oddzielnie, bo zerowane public: @@ -212,14 +134,10 @@ public: smLetter; // wskaźnik na tablicÄ™ submdeli do generoania tekstu (docelowo zapisać do E3D) TSubModel *Parent; // nadrzÄ™dny, np. do wymnażania macierzy int iVisible; // roboczy stan widocznoÅ›ci - // AnsiString asTexture; //robocza nazwa tekstury do zapisania w pliku binarnym - // AnsiString asName; //robocza nazwa std::string pTexture; // robocza nazwa tekstury do zapisania w pliku binarnym std::string pName; // robocza nazwa private: - // int SeekFaceNormal(DWORD *Masks, int f,DWORD dwMask,vector3 *pt,GLVERTEX - // *Vertices); - int SeekFaceNormal(unsigned int *Masks, int f, unsigned int dwMask, float3 *pt, float8 *Vertices); + int SeekFaceNormal(unsigned int *Masks, int f, unsigned int dwMask, glm::vec3 *pt, basic_vertex *Vertices); void RaAnimation(TAnimType a); public: @@ -235,18 +153,10 @@ public: int Load(cParser &Parser, TModel3d *Model, int Pos, bool dynamic); void ChildAdd(TSubModel *SubModel); void NextAdd(TSubModel *SubModel); - TSubModel * NextGet() - { - return Next; - }; - TSubModel * ChildGet() - { - return Child; - }; + TSubModel * NextGet() { return Next; }; + TSubModel * ChildGet() { return Child; }; 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); + basic_vertex * TrianglePtr(int tex, int pos, int *la, int *ld, int *ls); void SetRotate(float3 vNewRotateAxis, float fNewAngle); void SetRotateXYZ(vector3 vNewAngles); void SetRotateXYZ(float3 vNewAngles); @@ -255,18 +165,9 @@ public: void SetRotateIK1(float3 vNewAngles); TSubModel * GetFromName(std::string const &search, bool i = true); TSubModel * GetFromName(char const *search, bool i = true); - // inline matrix4x4* GetMatrix() {return dMatrix;}; - inline float4x4 * GetMatrix() - { - return fMatrix; - }; - // matrix4x4* GetTransform() {return Matrix;}; - inline void Hide() - { - iVisible = 0; - }; + inline float4x4 * GetMatrix() { return fMatrix; }; + inline void Hide() { iVisible = 0; }; void RaArrayFill(CVertNormTex *Vert); - // void Render(); int FlagsCheck(); void WillBeAnimated() { @@ -275,7 +176,7 @@ public: }; void InitialRotate(bool doit); void DisplayLists(); - void BinInit(TSubModel *s, float4x4 *m, float8 *v, + void BinInit(TSubModel *s, float4x4 *m, basic_vertex *v, std::vector *t, std::vector *n, bool dynamic); void ReplacableSet(texture_manager::size_type const *r, int a) { @@ -285,14 +186,8 @@ public: void TextureNameSet(const char *n); void NameSet(const char *n); // Ra: funkcje do budowania terenu z E3D - int Flags() - { - return iFlags; - }; - void UnFlagNext() - { - iFlags &= 0x00FFFFFF; - }; + int Flags() { return iFlags; }; + void UnFlagNext() { iFlags &= 0x00FFFFFF; }; void ColorsSet(int *a, int *d, int *s); inline float3 Translation1Get() { @@ -323,9 +218,6 @@ class TModel3d : public CMesh friend class opengl_renderer; private: - // TMaterial *Materials; - // int MaterialsCount; //Ra: nie używane - // bool TractionPart; //Ra: nie używane TSubModel *Root; // drzewo submodeli int iFlags; // Ra: czy submodele majÄ… przezroczyste tekstury public: // Ra: tymczasowo @@ -338,16 +230,10 @@ private: std::string asBinary; // nazwa pod którÄ… zapisać model binarny std::string m_filename; public: - inline TSubModel * GetSMRoot() - { - return (Root); - }; - // double Radius; //Ra: nie używane + inline TSubModel * GetSMRoot() { return (Root); }; TModel3d(); - TModel3d(char *FileName); ~TModel3d(); TSubModel * GetFromName(const char *sName); - // TMaterial* GetMaterialFromName(char *sName); TSubModel * AddToNamed(const char *Name, TSubModel *SubModel); void AddTo(TSubModel *tmp, TSubModel *SubModel); void LoadFromTextFile(std::string const &FileName, bool dynamic); @@ -355,17 +241,9 @@ public: bool LoadFromFile(std::string const &FileName, bool dynamic); void SaveToBinFile(char const *FileName); void BreakHierarhy(); - // inline int GetSubModelsCount() { return (SubModelsCount); }; - int Flags() const - { - return iFlags; - }; + int Flags() const { return iFlags; }; void Init(); - std::string NameGet() - { -// return Root ? Root->pName : NULL; - return m_filename; - }; + std::string NameGet() { return m_filename; }; int TerrainCount(); TSubModel * TerrainSquare(int n); void TerrainRenderVBO(int n); diff --git a/Texture.h b/Texture.h index bfdd73c5..8ed8c2dc 100644 --- a/Texture.h +++ b/Texture.h @@ -62,6 +62,8 @@ private: */ }; +typedef std::size_t texture_handle; + class texture_manager { private: diff --git a/VBO.cpp b/VBO.cpp index 0de6cb14..6fdba7c0 100644 --- a/VBO.cpp +++ b/VBO.cpp @@ -49,6 +49,9 @@ CMesh::CMesh() #endif m_nVertexCount = -1; m_nVBOVertices = 0; // nie zarezerwowane + + // TODO: bind proper subtype based on the settings + m_geometry = std::make_shared(); }; CMesh::~CMesh() @@ -107,6 +110,7 @@ void CMesh::Clear() bool CMesh::StartVBO() { // poczÄ…tek rysowania elementów z VBO + if (m_nVertexCount <= 0) return false; // nie ma nic do rysowania w ten sposób glEnableClientState(GL_VERTEX_ARRAY); @@ -118,12 +122,15 @@ bool CMesh::StartVBO() glVertexPointer( 3, GL_FLOAT, sizeof(CVertNormTex), static_cast(nullptr) ); // pozycje glNormalPointer( GL_FLOAT, sizeof( CVertNormTex ), static_cast( nullptr ) + 12 ); // normalne glTexCoordPointer( 2, GL_FLOAT, sizeof( CVertNormTex ), static_cast( nullptr ) + 24 ); // wierzchoÅ‚ki + return true; // można rysować z VBO } - return true; // można rysować z VBO + + return false; }; bool CMesh::StartColorVBO() { // poczÄ…tek rysowania punktów Å›wiecÄ…cych z VBO + if (m_nVertexCount <= 0) return false; // nie ma nic do rysowania w ten sposób glEnableClientState(GL_VERTEX_ARRAY); @@ -134,8 +141,9 @@ bool CMesh::StartColorVBO() glVertexPointer( 3, GL_FLOAT, sizeof( CVertNormTex ), static_cast( nullptr ) ); // pozycje // glColorPointer(3,GL_UNSIGNED_BYTE,sizeof(CVertNormTex),((char*)NULL)+12); //kolory glColorPointer( 3, GL_FLOAT, sizeof( CVertNormTex ), static_cast( nullptr ) + 12 ); // kolory + return true; // można rysować z VBO } - return true; // można rysować z VBO + return false; }; void CMesh::EndVBO() diff --git a/VBO.h b/VBO.h index a5e4947a..63a104fc 100644 --- a/VBO.h +++ b/VBO.h @@ -7,8 +7,9 @@ obtain one at http://mozilla.org/MPL/2.0/. */ -#ifndef VBOH -#define VBOH +#pragma once + +#include "openglgeometrybank.h" #define EU07_USE_OLD_VERTEXBUFFER @@ -32,13 +33,6 @@ class CVertNormTex class CMesh { // wsparcie dla VBO public: - int m_nVertexCount; // liczba wierzchoÅ‚ków -#ifdef EU07_USE_OLD_VERTEXBUFFER - CVertNormTex *m_pVNT; -#else - std::vector m_pVNT; -#endif - unsigned int m_nVBOVertices; // numer VBO z wierzchoÅ‚kami CMesh(); ~CMesh(); void MakeArray(int n); // tworzenie tablicy z elementami VNT @@ -47,6 +41,14 @@ class CMesh bool StartVBO(); void EndVBO(); bool StartColorVBO(); -}; + int m_nVertexCount; // liczba wierzchoÅ‚ków +#ifdef EU07_USE_OLD_VERTEXBUFFER + CVertNormTex *m_pVNT; +#else + std::vector m_pVNT; #endif + unsigned int m_nVBOVertices; // numer VBO z wierzchoÅ‚kami + + std::shared_ptr m_geometry; +}; diff --git a/maszyna.vcxproj.filters b/maszyna.vcxproj.filters index 0dcd5af5..2e0bf701 100644 --- a/maszyna.vcxproj.filters +++ b/maszyna.vcxproj.filters @@ -222,6 +222,9 @@ Source Files + + Source Files + @@ -434,6 +437,9 @@ Header Files + + Header Files + diff --git a/openglgeometrybank.cpp b/openglgeometrybank.cpp new file mode 100644 index 00000000..ec25b023 --- /dev/null +++ b/openglgeometrybank.cpp @@ -0,0 +1,218 @@ +/* +This Source Code Form is subject to the +terms of the Mozilla Public License, v. +2.0. If a copy of the MPL was not +distributed with this file, You can +obtain one at +http://mozilla.org/MPL/2.0/. +*/ + +#include "stdafx.h" +#include "openglgeometrybank.h" + +#include "sn_utils.h" + +void +basic_vertex::serialize( std::ostream &s ) { + + sn_utils::ls_float32( s, position.x ); + sn_utils::ls_float32( s, position.y ); + sn_utils::ls_float32( s, position.z ); + + sn_utils::ls_float32( s, normal.x ); + sn_utils::ls_float32( s, normal.y ); + sn_utils::ls_float32( s, normal.z ); + + sn_utils::ls_float32( s, texture.x ); + sn_utils::ls_float32( s, texture.y ); +} + +void +basic_vertex::deserialize( std::istream &s ) { + + position.x = sn_utils::ld_float32( s ); + position.y = sn_utils::ld_float32( s ); + position.z = sn_utils::ld_float32( s ); + + normal.x = sn_utils::ld_float32( s ); + normal.y = sn_utils::ld_float32( s ); + normal.z = sn_utils::ld_float32( s ); + + texture.x = sn_utils::ld_float32( s ); + texture.y = sn_utils::ld_float32( s ); +} + +// generic geometry bank class, allows storage, update and drawing of geometry chunks + +// creates a new geometry chunk of specified type from supplied vertex data. returns: handle to the chunk +geometrychunk_handle +geometry_bank::create( vertex_array &Vertices, int const Datatype ) { + + if( true == Vertices.empty() ) { return NULL; } + + m_chunks.emplace_back( Vertices, Datatype ); + // NOTE: handle is effectively (index into chunk array + 1) this leaves value of 0 to serve as error/empty handle indication + return m_chunks.size(); +} + +// replaces data of specified chunk with the supplied vertex data, starting from specified offset +bool +geometry_bank::replace( vertex_array &Vertices, geometrychunk_handle const Chunk, std::size_t const Offset ) { + + if( ( Chunk == 0 ) || ( Chunk > m_chunks.size() ) ) { return false; } + + auto &chunk = m_chunks[ Chunk - 1 ]; + + if( ( Offset == 0 ) + && ( Vertices.size() == chunk.vertices.size() ) ) { + // check first if we can get away with a simple swap... + chunk.vertices.swap( Vertices ); + } + else { + // ...otherwise we need to do some legwork + // NOTE: if the offset is larger than existing size of the chunk, it'll bridge the gap with 'blank' vertices + // TBD: we could bail out with an error instead if such request occurs + chunk.vertices.resize( Offset + Vertices.size(), basic_vertex() ); + chunk.vertices.insert( std::end( chunk.vertices ), std::begin( Vertices ), std::end( Vertices ) ); + } + return true; +} + +vertex_array & +geometry_bank::data( geometrychunk_handle const Chunk ) { + + return m_chunks.at( Chunk - 1 ).vertices; +} + +// opengl vbo-based variant of the geometry bank + +GLuint opengl_vbogeometrybank::m_activebuffer{ NULL }; // buffer bound currently on the opengl end, if any + +// creates a new geometry chunk of specified type from supplied vertex data. returns: handle to the chunk +geometrychunk_handle +opengl_vbogeometrybank::create( vertex_array &Vertices, int const Datatype ) { + + auto const handle = geometry_bank::create( Vertices, Datatype ); + if( handle == NULL ) { + // if we didn't get anything, bail early + return handle; + } + // adding a chunk means we'll be (re)building the buffer, which will fill the chunk records, amongst other things + // so we don't need to initialize the values here + m_chunkrecords.emplace_back( chunk_record() ); + // kiss the existing buffer goodbye, new overall data size means we'll be making a new one + delete_buffer(); + + return handle; +} + +// replaces data of specified chunk with the supplied vertex data, starting from specified offset +bool +opengl_vbogeometrybank::replace( vertex_array &Vertices, geometrychunk_handle const Chunk, std::size_t const Offset ) { + + auto const result = geometry_bank::replace( Vertices, Chunk, Offset ); + if( false == result ) { + // if nothing happened we can bail out early + return result; + } + auto &chunkrecord = m_chunkrecords[ Chunk - 1 ]; + chunkrecord.is_good = false; + // if the overall length of the chunk didn't change we can get away with reusing the old buffer... + if( m_chunks[ Chunk - 1 ].vertices.size() != chunkrecord.size ) { + // ...but otherwise we'll need to allocate a new one + // TBD: we could keep and reuse the old buffer also if the new chunk is smaller than the old one, + // but it'd require some extra tracking and work to keep all chunks up to date; also wasting vram; may be not worth it? + delete_buffer(); + } + return result; +} + +// draws geometry stored in specified chunk +void +opengl_vbogeometrybank::draw( geometrychunk_handle const Chunk ) { + + if( m_buffer == NULL ) { + // if there's no buffer, we'll have to make one + // NOTE: this isn't exactly optimal in terms of ensuring the gfx card doesn't stall waiting for the data + // may be better to initiate upload earlier (during update phase) and trust this effort won't go to waste + if( true == m_chunks.empty() ) { return; } + + std::size_t datasize{ 0 }; + auto &chunkrecord = m_chunkrecords.begin(); + for( auto &chunk : m_chunks ) { + // fill all chunk records, based on the chunk data + chunkrecord->offset = datasize; + chunkrecord->size = chunk.vertices.size(); + datasize += chunkrecord->size; + ++chunkrecord; + } + // the odds for all created chunks to get replaced with empty ones are quite low, but the possibility does exist + if( datasize == 0 ) { return; } + // try to set up the buffer we need + ::glGenBuffers( 1, &m_buffer ); + bind_buffer(); + // NOTE: we're using static_draw since it's generally true for all we have implemented at the moment + // TODO: allow to specify usage hint at the object creation, and pass it here + ::glBufferData( + GL_ARRAY_BUFFER, + datasize * sizeof( basic_vertex ), + nullptr, + GL_STATIC_DRAW ); + m_buffercapacity = datasize; + } + // actual draw procedure starts here + // setup... + if( m_activebuffer != m_buffer ) { + bind_buffer(); + } + auto &chunkrecord = m_chunkrecords[ Chunk - 1 ]; + auto const &chunk = m_chunks[ Chunk - 1 ]; + if( false == chunkrecord.is_good ) { + // we may potentially need to upload new buffer data before we can draw it + ::glBufferSubData( + GL_ARRAY_BUFFER, + chunkrecord.offset * sizeof( basic_vertex ), + chunkrecord.size * sizeof( basic_vertex ), + chunk.vertices.data() ); + chunkrecord.is_good = true; + } + // ...render... + ::glDrawArrays( chunk.type, chunkrecord.offset, chunkrecord.size ); + // ...post-render cleanup +/* + ::glDisableClientState( GL_VERTEX_ARRAY ); + ::glDisableClientState( GL_NORMAL_ARRAY ); + ::glDisableClientState( GL_TEXTURE_COORD_ARRAY ); + ::glBindBuffer( GL_ARRAY_BUFFER, 0 ); m_activebuffer = 0; +*/ +} + +void +opengl_vbogeometrybank::bind_buffer() { + + ::glBindBuffer( GL_ARRAY_BUFFER, m_buffer ); + // TODO: allow specifying other vertex data setups + ::glVertexPointer( 3, GL_FLOAT, sizeof( basic_vertex ), static_cast( nullptr ) ); + ::glNormalPointer( GL_FLOAT, sizeof( basic_vertex ), static_cast( nullptr ) + sizeof(float) * 3 ); // normalne + ::glTexCoordPointer( 2, GL_FLOAT, sizeof( basic_vertex ), static_cast( nullptr ) + 24 ); // wierzchoÅ‚ki + // TODO: allow specifying other vertex data setups, either in the draw() parameters or during chunk or buffer creation + ::glEnableClientState( GL_VERTEX_ARRAY ); + ::glEnableClientState( GL_NORMAL_ARRAY ); + ::glEnableClientState( GL_TEXTURE_COORD_ARRAY ); + + m_activebuffer = m_buffer; +} + +void +opengl_vbogeometrybank::delete_buffer() { + + if( m_buffer != NULL ) { + + ::glDeleteBuffers( 1, &m_buffer ); + if( m_activebuffer == m_buffer ) { + m_activebuffer = NULL; + } + m_buffer = NULL; + m_buffercapacity = 0; + } +} diff --git a/openglgeometrybank.h b/openglgeometrybank.h new file mode 100644 index 00000000..91969a29 --- /dev/null +++ b/openglgeometrybank.h @@ -0,0 +1,122 @@ +/* +This Source Code Form is subject to the +terms of the Mozilla Public License, v. +2.0. If a copy of the MPL was not +distributed with this file, You can +obtain one at +http://mozilla.org/MPL/2.0/. +*/ + +#pragma once + +#include +#include +#include +#include "GL/glew.h" +#ifdef _WINDOWS +#include "GL/wglew.h" +#endif + +struct basic_vertex { + glm::vec3 position; // 3d space + glm::vec3 normal; // 3d space + glm::vec2 texture; // uv space + + void serialize( std::ostream& ); + void deserialize( std::istream& ); +}; + +typedef std::vector vertex_array; + +// generic geometry bank class, allows storage, update and drawing of geometry chunks + +typedef std::size_t geometrychunk_handle; + +class geometry_bank { + +public: +// types: + +// constructors: + +// destructor: + virtual + ~geometry_bank() { ; } + +// methods: + // creates a new geometry chunk of specified type from supplied vertex data. returns: handle to the chunk or NULL + virtual + geometrychunk_handle + create( vertex_array &Vertices, int const Datatype ); + // replaces data of specified chunk with the supplied vertex data, starting from specified offset + virtual + bool + replace( vertex_array &Vertices, geometrychunk_handle const Chunk, std::size_t const Offset = 0 ); + // draws geometry stored in specified chunk + virtual + void + draw( geometrychunk_handle const Chunk ) = 0; + // draws geometry stored in supplied list of chunks + template + void + draw( _Iterator First, _Iterator Last ) { while( First != Last ) { draw( *First ); ++First; } } + vertex_array & + data( geometrychunk_handle const Chunk ); + +protected: +// types: + struct geometry_chunk { + int type; // kind of geometry used by the chunk + vertex_array vertices; // geometry data + + geometry_chunk( vertex_array &Vertices, int const Datatype ) : + vertices( Vertices ), type( Datatype ) + {} + }; + + typedef std::vector geometrychunk_sequence; + +// members: + geometrychunk_sequence m_chunks; + +}; + +// opengl vbo-based variant of the geometry bank + +class opengl_vbogeometrybank : public geometry_bank { + +public: +// methods: + // creates a new geometry chunk of specified type from supplied vertex data. returns: handle to the chunk or NULL + geometrychunk_handle + create( vertex_array &Vertices, int const Datatype ); + // replaces data of specified chunk with the supplied vertex data, starting from specified offset + bool + replace( vertex_array &Vertices, geometrychunk_handle const Chunk, std::size_t const Offset = 0 ); + // draws geometry stored in specified chunk + void + draw( geometrychunk_handle const Chunk ); + +private: +// types: + struct chunk_record{ + std::size_t offset{ 0 }; // beginning of the chunk data as offset from the beginning of the last established buffer + std::size_t size{ 0 }; // size of the chunk in the last established buffer + bool is_good{ false }; // true if local content of the chunk matches the data on the opengl end + }; + + typedef std::vector chunkrecord_sequence; + +// methods: + void + bind_buffer(); + void + delete_buffer(); + +// members: + static GLuint m_activebuffer; // buffer bound currently on the opengl end, if any + GLuint m_buffer{ NULL }; // id of the buffer holding data on the opengl end + std::size_t m_buffercapacity{ 0 }; // total capacity of the last established buffer + chunkrecord_sequence m_chunkrecords; // helper data for all stored geometry chunks, in matching order + +}; diff --git a/renderer.cpp b/renderer.cpp index 93789019..177bbf89 100644 --- a/renderer.cpp +++ b/renderer.cpp @@ -775,11 +775,12 @@ opengl_renderer::Render( TModel3d *Model, material_data const *Material, double // TODO: unify the render code after generic buffers are in place // setup +/* if( Global::bUseVBO ) { if( false == Model->StartVBO() ) return false; } - +*/ Model->Root->ReplacableSet( ( Material != nullptr ? Material->replacable_skins : @@ -793,7 +794,7 @@ opengl_renderer::Render( TModel3d *Model, material_data const *Material, double // post-render cleanup if( Global::bUseVBO ) { - Model->EndVBO(); +// Model->EndVBO(); } return true; @@ -857,7 +858,10 @@ opengl_renderer::Render( TSubModel *Submodel ) { // main draw call. TODO: generic buffer base class, specialized for vbo, dl etc if( Global::bUseVBO ) { +/* ::glDrawArrays( Submodel->eType, Submodel->iVboPtr, Submodel->iNumVerts ); +*/ + Submodel->pRoot->m_geometry->draw( Submodel->m_chunk ); } else { ::glCallList( Submodel->uiDisplayList ); @@ -898,7 +902,10 @@ opengl_renderer::Render( TSubModel *Submodel ) { // main draw call. TODO: generic buffer base class, specialized for vbo, dl etc if( Global::bUseVBO ) { +/* ::glDrawArrays( GL_POINTS, Submodel->iVboPtr, Submodel->iNumVerts ); +*/ + Submodel->pRoot->m_geometry->draw( Submodel->m_chunk ); } else { ::glCallList( Submodel->uiDisplayList ); @@ -921,6 +928,7 @@ opengl_renderer::Render( TSubModel *Submodel ) { // main draw call. TODO: generic buffer base class, specialized for vbo, dl etc if( Global::bUseVBO ) { +/* // NOTE: we're doing manual switch to color vbo setup, because there doesn't seem to be any convenient way available atm // TODO: implement easier way to go about it ::glDisableClientState( GL_NORMAL_ARRAY ); @@ -933,6 +941,7 @@ opengl_renderer::Render( TSubModel *Submodel ) { ::glDisableClientState( GL_COLOR_ARRAY ); ::glEnableClientState( GL_NORMAL_ARRAY ); ::glEnableClientState( GL_TEXTURE_COORD_ARRAY ); +*/ } else { ::glCallList( Submodel->uiDisplayList ); @@ -1298,11 +1307,12 @@ opengl_renderer::Render_Alpha( TModel3d *Model, material_data const *Material, d // TODO: unify the render code after generic buffers are in place // setup +/* if( Global::bUseVBO ) { if( false == Model->StartVBO() ) return false; } - +*/ Model->Root->ReplacableSet( ( Material != nullptr ? Material->replacable_skins : @@ -1315,10 +1325,11 @@ opengl_renderer::Render_Alpha( TModel3d *Model, material_data const *Material, d Render_Alpha( Model->Root ); // post-render cleanup +/* if( Global::bUseVBO ) { Model->EndVBO(); } - +*/ return true; } @@ -1378,7 +1389,10 @@ opengl_renderer::Render_Alpha( TSubModel *Submodel ) { // main draw call. TODO: generic buffer base class, specialized for vbo, dl etc if( Global::bUseVBO ) { +/* ::glDrawArrays( Submodel->eType, Submodel->iVboPtr, Submodel->iNumVerts ); +*/ + Submodel->pRoot->m_geometry->draw( Submodel->m_chunk ); } else { ::glCallList( Submodel->uiDisplayList ); From 135ac514f4922fcdd65a8d93ccd021923f0aab93 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Sat, 3 Jun 2017 17:14:02 +0200 Subject: [PATCH 2/9] fix for trace route early return on full speed signal, fix for tachometers initialization --- Driver.cpp | 2 +- Ground.cpp | 8 ++++---- Train.cpp | 36 ++---------------------------------- Train.h | 22 ++++++++-------------- version.h | 2 +- 5 files changed, 16 insertions(+), 54 deletions(-) diff --git a/Driver.cpp b/Driver.cpp index 35daf905..98709cc7 100644 --- a/Driver.cpp +++ b/Driver.cpp @@ -481,7 +481,7 @@ void TController::TableTraceRoute(double fDistance, TDynamicObject *pVehicle) } // kontynuacja skanowania od ostatnio sprawdzonego toru (w ostatniej pozycji zawsze jest tor) if( ( SemNextStopIndex != -1 ) - && ( sSpeedTable[SemNextStopIndex].fVelNext < 1.0 ) ) { + && ( sSpeedTable[SemNextStopIndex].fVelNext == 0.0 ) ) { // znaleziono semafor lub tarczÄ™ lub tor z prÄ™dkoÅ›ciÄ… zero, trzeba sprawdzić czy to nadaÅ‚ semafor // jeÅ›li jest nastÄ™pny semafor to sprawdzamy czy to on nadaÅ‚ zero if( ( OrderCurrentGet() & Obey_train ) diff --git a/Ground.cpp b/Ground.cpp index 54662956..c9fb6c68 100644 --- a/Ground.cpp +++ b/Ground.cpp @@ -3169,10 +3169,10 @@ bool TGround::AddToQuery(TEvent *Event, TDynamicObject *Node) { // kolejka eventów jest posortowana wzglÄ™dem (fStartTime) Event->Activator = Node; if( ( Event->Type == tp_AddValues ) - && ( Event->fDelay == 0.0 ) ) { - // eventy AddValues trzeba wykonywać natychmiastowo, inaczej kolejka może zgubić jakieÅ› dodawanie - // Ra: kopiowanie wykonania tu jest bez sensu, lepiej by byÅ‚o wydzielić funkcjÄ™ - // wykonujÄ…cÄ… eventy i jÄ… wywoÅ‚ać + && ( Event->fDelay == 0.0 ) ) { + // eventy AddValues trzeba wykonywać natychmiastowo, inaczej kolejka może zgubić jakieÅ› dodawanie + // Ra: kopiowanie wykonania tu jest bez sensu, lepiej by byÅ‚o wydzielić funkcjÄ™ + // wykonujÄ…cÄ… eventy i jÄ… wywoÅ‚ać if( EventConditon( Event ) ) { // teraz mogÄ… być warunki do tych eventów Event->Params[ 5 ].asMemCell->UpdateValues( Event->Params[ 0 ].asText, Event->Params[ 1 ].asdouble, diff --git a/Train.cpp b/Train.cpp index 61bc9138..5a572617 100644 --- a/Train.cpp +++ b/Train.cpp @@ -4400,16 +4400,6 @@ bool TTrain::Update( double const Deltatime ) { // ustawienie zmiennych dla silnika spalinowego fEngine[1] = mvControlled->ShowEngineRotation(1); fEngine[2] = mvControlled->ShowEngineRotation(2); - // if (ggEnrot1m.SubModel) - //{ - // ggEnrot1m.UpdateValue(mvControlled->ShowEngineRotation(1)); - // ggEnrot1m.Update(); - //} - // if (ggEnrot2m.SubModel) - //{ - // ggEnrot2m.UpdateValue(mvControlled->ShowEngineRotation(2)); - // ggEnrot2m.Update(); - //} } else if (mvControlled->EngineType == DieselEngine) @@ -4417,34 +4407,12 @@ bool TTrain::Update( double const Deltatime ) fEngine[1] = mvControlled->ShowEngineRotation(1); fEngine[2] = mvControlled->ShowEngineRotation(2); fEngine[3] = mvControlled->ShowEngineRotation(3); - // if (ggEnrot1m.SubModel) - //{ - // ggEnrot1m.UpdateValue(mvControlled->ShowEngineRotation(1)); - // ggEnrot1m.Update(); - //} - // if (ggEnrot2m.SubModel) - //{ - // ggEnrot2m.UpdateValue(mvControlled->ShowEngineRotation(2)); - // ggEnrot2m.Update(); - //} - // if (ggEnrot3m.SubModel) - // if (mvControlled->Couplers[1].Connected) - // { - // ggEnrot3m.UpdateValue(mvControlled->ShowEngineRotation(3)); - // ggEnrot3m.Update(); - // } - // if (ggEngageRatio.SubModel) - //{ - // ggEngageRatio.UpdateValue(mvControlled->dizel_engage); - // ggEngageRatio.Update(); - //} if (ggMainGearStatus.SubModel) { if (mvControlled->Mains) - ggMainGearStatus.UpdateValue(1.1 - - fabs(mvControlled->dizel_automaticgearstatus)); + ggMainGearStatus.UpdateValue(1.1 - std::abs(mvControlled->dizel_automaticgearstatus)); else - ggMainGearStatus.UpdateValue(0); + ggMainGearStatus.UpdateValue(0.0); ggMainGearStatus.Update(); } if (ggIgnitionKey.SubModel) diff --git a/Train.h b/Train.h index aab20177..c4b6b574 100644 --- a/Train.h +++ b/Train.h @@ -449,23 +449,17 @@ public: // reszta może by?publiczna int CAflag; // hunter-131211: dla osobnego zbijania CA i SHP double fPoslizgTimer; - // double fShpTimer; - // double fDblClickTimer; - // ABu: Przeniesione do public. - Wiem, ze to nieladnie... - // bool CabChange(int iDirection); - // bool InitializeCab(int NewCabNo, AnsiString asFileName); TTrack *tor; int keybrakecount; // McZapkie-240302 - przyda sie do tachometru - float fTachoVelocity; - float fTachoVelocityJump; // ze skakaniem - float fTachoTimer; - float fTachoCount; - float fHVoltage; // napi?cie dla dynamicznych ga?ek - float fHCurrent[4]; // pr?dy: suma i amperomierze 1,2,3 - float fEngine[4]; // obroty te? trzeba pobra? - int iCarNo, iPowerNo, iUnitNo; // liczba pojazdow, czlonow napednych i jednostek spiÄ™tych ze - // sobÄ… + float fTachoVelocity{ 0.0f }; + float fTachoVelocityJump{ 0.0f }; // ze skakaniem + float fTachoTimer{ 0.0f }; + float fTachoCount{ 0.0f }; + float fHVoltage{ 0.0f }; // napi?cie dla dynamicznych ga?ek + float fHCurrent[ 4 ] = { 0.0f, 0.0f, 0.0f, 0.0f }; // pr?dy: suma i amperomierze 1,2,3 + float fEngine[ 4 ] = { 0.0f, 0.0f, 0.0f, 0.0f }; // obroty te? trzeba pobra? + int iCarNo, iPowerNo, iUnitNo; // liczba pojazdow, czlonow napednych i jednostek spiÄ™tych ze sobÄ… bool bDoors[20][3]; // drzwi dla wszystkich czlonow int iUnits[20]; // numer jednostki int iDoorNo[20]; // liczba drzwi diff --git a/version.h b/version.h index 005e6949..b41d9f32 100644 --- a/version.h +++ b/version.h @@ -1,5 +1,5 @@ #pragma once #define VERSION_MAJOR 17 -#define VERSION_MINOR 602 +#define VERSION_MINOR 603 #define VERSION_REVISION 0 From ba8c0dd96f1a8cb3574dfc58394d256ef3a37deb Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Sat, 3 Jun 2017 18:29:07 +0200 Subject: [PATCH 3/9] pre-merge with renderer_unification branch --- openglgeometrybank.cpp | 218 +++++++++++++++++++++++++++++++++++++++++ openglgeometrybank.h | 122 +++++++++++++++++++++++ 2 files changed, 340 insertions(+) create mode 100644 openglgeometrybank.cpp create mode 100644 openglgeometrybank.h diff --git a/openglgeometrybank.cpp b/openglgeometrybank.cpp new file mode 100644 index 00000000..ec25b023 --- /dev/null +++ b/openglgeometrybank.cpp @@ -0,0 +1,218 @@ +/* +This Source Code Form is subject to the +terms of the Mozilla Public License, v. +2.0. If a copy of the MPL was not +distributed with this file, You can +obtain one at +http://mozilla.org/MPL/2.0/. +*/ + +#include "stdafx.h" +#include "openglgeometrybank.h" + +#include "sn_utils.h" + +void +basic_vertex::serialize( std::ostream &s ) { + + sn_utils::ls_float32( s, position.x ); + sn_utils::ls_float32( s, position.y ); + sn_utils::ls_float32( s, position.z ); + + sn_utils::ls_float32( s, normal.x ); + sn_utils::ls_float32( s, normal.y ); + sn_utils::ls_float32( s, normal.z ); + + sn_utils::ls_float32( s, texture.x ); + sn_utils::ls_float32( s, texture.y ); +} + +void +basic_vertex::deserialize( std::istream &s ) { + + position.x = sn_utils::ld_float32( s ); + position.y = sn_utils::ld_float32( s ); + position.z = sn_utils::ld_float32( s ); + + normal.x = sn_utils::ld_float32( s ); + normal.y = sn_utils::ld_float32( s ); + normal.z = sn_utils::ld_float32( s ); + + texture.x = sn_utils::ld_float32( s ); + texture.y = sn_utils::ld_float32( s ); +} + +// generic geometry bank class, allows storage, update and drawing of geometry chunks + +// creates a new geometry chunk of specified type from supplied vertex data. returns: handle to the chunk +geometrychunk_handle +geometry_bank::create( vertex_array &Vertices, int const Datatype ) { + + if( true == Vertices.empty() ) { return NULL; } + + m_chunks.emplace_back( Vertices, Datatype ); + // NOTE: handle is effectively (index into chunk array + 1) this leaves value of 0 to serve as error/empty handle indication + return m_chunks.size(); +} + +// replaces data of specified chunk with the supplied vertex data, starting from specified offset +bool +geometry_bank::replace( vertex_array &Vertices, geometrychunk_handle const Chunk, std::size_t const Offset ) { + + if( ( Chunk == 0 ) || ( Chunk > m_chunks.size() ) ) { return false; } + + auto &chunk = m_chunks[ Chunk - 1 ]; + + if( ( Offset == 0 ) + && ( Vertices.size() == chunk.vertices.size() ) ) { + // check first if we can get away with a simple swap... + chunk.vertices.swap( Vertices ); + } + else { + // ...otherwise we need to do some legwork + // NOTE: if the offset is larger than existing size of the chunk, it'll bridge the gap with 'blank' vertices + // TBD: we could bail out with an error instead if such request occurs + chunk.vertices.resize( Offset + Vertices.size(), basic_vertex() ); + chunk.vertices.insert( std::end( chunk.vertices ), std::begin( Vertices ), std::end( Vertices ) ); + } + return true; +} + +vertex_array & +geometry_bank::data( geometrychunk_handle const Chunk ) { + + return m_chunks.at( Chunk - 1 ).vertices; +} + +// opengl vbo-based variant of the geometry bank + +GLuint opengl_vbogeometrybank::m_activebuffer{ NULL }; // buffer bound currently on the opengl end, if any + +// creates a new geometry chunk of specified type from supplied vertex data. returns: handle to the chunk +geometrychunk_handle +opengl_vbogeometrybank::create( vertex_array &Vertices, int const Datatype ) { + + auto const handle = geometry_bank::create( Vertices, Datatype ); + if( handle == NULL ) { + // if we didn't get anything, bail early + return handle; + } + // adding a chunk means we'll be (re)building the buffer, which will fill the chunk records, amongst other things + // so we don't need to initialize the values here + m_chunkrecords.emplace_back( chunk_record() ); + // kiss the existing buffer goodbye, new overall data size means we'll be making a new one + delete_buffer(); + + return handle; +} + +// replaces data of specified chunk with the supplied vertex data, starting from specified offset +bool +opengl_vbogeometrybank::replace( vertex_array &Vertices, geometrychunk_handle const Chunk, std::size_t const Offset ) { + + auto const result = geometry_bank::replace( Vertices, Chunk, Offset ); + if( false == result ) { + // if nothing happened we can bail out early + return result; + } + auto &chunkrecord = m_chunkrecords[ Chunk - 1 ]; + chunkrecord.is_good = false; + // if the overall length of the chunk didn't change we can get away with reusing the old buffer... + if( m_chunks[ Chunk - 1 ].vertices.size() != chunkrecord.size ) { + // ...but otherwise we'll need to allocate a new one + // TBD: we could keep and reuse the old buffer also if the new chunk is smaller than the old one, + // but it'd require some extra tracking and work to keep all chunks up to date; also wasting vram; may be not worth it? + delete_buffer(); + } + return result; +} + +// draws geometry stored in specified chunk +void +opengl_vbogeometrybank::draw( geometrychunk_handle const Chunk ) { + + if( m_buffer == NULL ) { + // if there's no buffer, we'll have to make one + // NOTE: this isn't exactly optimal in terms of ensuring the gfx card doesn't stall waiting for the data + // may be better to initiate upload earlier (during update phase) and trust this effort won't go to waste + if( true == m_chunks.empty() ) { return; } + + std::size_t datasize{ 0 }; + auto &chunkrecord = m_chunkrecords.begin(); + for( auto &chunk : m_chunks ) { + // fill all chunk records, based on the chunk data + chunkrecord->offset = datasize; + chunkrecord->size = chunk.vertices.size(); + datasize += chunkrecord->size; + ++chunkrecord; + } + // the odds for all created chunks to get replaced with empty ones are quite low, but the possibility does exist + if( datasize == 0 ) { return; } + // try to set up the buffer we need + ::glGenBuffers( 1, &m_buffer ); + bind_buffer(); + // NOTE: we're using static_draw since it's generally true for all we have implemented at the moment + // TODO: allow to specify usage hint at the object creation, and pass it here + ::glBufferData( + GL_ARRAY_BUFFER, + datasize * sizeof( basic_vertex ), + nullptr, + GL_STATIC_DRAW ); + m_buffercapacity = datasize; + } + // actual draw procedure starts here + // setup... + if( m_activebuffer != m_buffer ) { + bind_buffer(); + } + auto &chunkrecord = m_chunkrecords[ Chunk - 1 ]; + auto const &chunk = m_chunks[ Chunk - 1 ]; + if( false == chunkrecord.is_good ) { + // we may potentially need to upload new buffer data before we can draw it + ::glBufferSubData( + GL_ARRAY_BUFFER, + chunkrecord.offset * sizeof( basic_vertex ), + chunkrecord.size * sizeof( basic_vertex ), + chunk.vertices.data() ); + chunkrecord.is_good = true; + } + // ...render... + ::glDrawArrays( chunk.type, chunkrecord.offset, chunkrecord.size ); + // ...post-render cleanup +/* + ::glDisableClientState( GL_VERTEX_ARRAY ); + ::glDisableClientState( GL_NORMAL_ARRAY ); + ::glDisableClientState( GL_TEXTURE_COORD_ARRAY ); + ::glBindBuffer( GL_ARRAY_BUFFER, 0 ); m_activebuffer = 0; +*/ +} + +void +opengl_vbogeometrybank::bind_buffer() { + + ::glBindBuffer( GL_ARRAY_BUFFER, m_buffer ); + // TODO: allow specifying other vertex data setups + ::glVertexPointer( 3, GL_FLOAT, sizeof( basic_vertex ), static_cast( nullptr ) ); + ::glNormalPointer( GL_FLOAT, sizeof( basic_vertex ), static_cast( nullptr ) + sizeof(float) * 3 ); // normalne + ::glTexCoordPointer( 2, GL_FLOAT, sizeof( basic_vertex ), static_cast( nullptr ) + 24 ); // wierzchoÅ‚ki + // TODO: allow specifying other vertex data setups, either in the draw() parameters or during chunk or buffer creation + ::glEnableClientState( GL_VERTEX_ARRAY ); + ::glEnableClientState( GL_NORMAL_ARRAY ); + ::glEnableClientState( GL_TEXTURE_COORD_ARRAY ); + + m_activebuffer = m_buffer; +} + +void +opengl_vbogeometrybank::delete_buffer() { + + if( m_buffer != NULL ) { + + ::glDeleteBuffers( 1, &m_buffer ); + if( m_activebuffer == m_buffer ) { + m_activebuffer = NULL; + } + m_buffer = NULL; + m_buffercapacity = 0; + } +} diff --git a/openglgeometrybank.h b/openglgeometrybank.h new file mode 100644 index 00000000..91969a29 --- /dev/null +++ b/openglgeometrybank.h @@ -0,0 +1,122 @@ +/* +This Source Code Form is subject to the +terms of the Mozilla Public License, v. +2.0. If a copy of the MPL was not +distributed with this file, You can +obtain one at +http://mozilla.org/MPL/2.0/. +*/ + +#pragma once + +#include +#include +#include +#include "GL/glew.h" +#ifdef _WINDOWS +#include "GL/wglew.h" +#endif + +struct basic_vertex { + glm::vec3 position; // 3d space + glm::vec3 normal; // 3d space + glm::vec2 texture; // uv space + + void serialize( std::ostream& ); + void deserialize( std::istream& ); +}; + +typedef std::vector vertex_array; + +// generic geometry bank class, allows storage, update and drawing of geometry chunks + +typedef std::size_t geometrychunk_handle; + +class geometry_bank { + +public: +// types: + +// constructors: + +// destructor: + virtual + ~geometry_bank() { ; } + +// methods: + // creates a new geometry chunk of specified type from supplied vertex data. returns: handle to the chunk or NULL + virtual + geometrychunk_handle + create( vertex_array &Vertices, int const Datatype ); + // replaces data of specified chunk with the supplied vertex data, starting from specified offset + virtual + bool + replace( vertex_array &Vertices, geometrychunk_handle const Chunk, std::size_t const Offset = 0 ); + // draws geometry stored in specified chunk + virtual + void + draw( geometrychunk_handle const Chunk ) = 0; + // draws geometry stored in supplied list of chunks + template + void + draw( _Iterator First, _Iterator Last ) { while( First != Last ) { draw( *First ); ++First; } } + vertex_array & + data( geometrychunk_handle const Chunk ); + +protected: +// types: + struct geometry_chunk { + int type; // kind of geometry used by the chunk + vertex_array vertices; // geometry data + + geometry_chunk( vertex_array &Vertices, int const Datatype ) : + vertices( Vertices ), type( Datatype ) + {} + }; + + typedef std::vector geometrychunk_sequence; + +// members: + geometrychunk_sequence m_chunks; + +}; + +// opengl vbo-based variant of the geometry bank + +class opengl_vbogeometrybank : public geometry_bank { + +public: +// methods: + // creates a new geometry chunk of specified type from supplied vertex data. returns: handle to the chunk or NULL + geometrychunk_handle + create( vertex_array &Vertices, int const Datatype ); + // replaces data of specified chunk with the supplied vertex data, starting from specified offset + bool + replace( vertex_array &Vertices, geometrychunk_handle const Chunk, std::size_t const Offset = 0 ); + // draws geometry stored in specified chunk + void + draw( geometrychunk_handle const Chunk ); + +private: +// types: + struct chunk_record{ + std::size_t offset{ 0 }; // beginning of the chunk data as offset from the beginning of the last established buffer + std::size_t size{ 0 }; // size of the chunk in the last established buffer + bool is_good{ false }; // true if local content of the chunk matches the data on the opengl end + }; + + typedef std::vector chunkrecord_sequence; + +// methods: + void + bind_buffer(); + void + delete_buffer(); + +// members: + static GLuint m_activebuffer; // buffer bound currently on the opengl end, if any + GLuint m_buffer{ NULL }; // id of the buffer holding data on the opengl end + std::size_t m_buffercapacity{ 0 }; // total capacity of the last established buffer + chunkrecord_sequence m_chunkrecords; // helper data for all stored geometry chunks, in matching order + +}; From de5b245f2edb618d2cd9fba5a53e3e2ae02a8b54 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Thu, 8 Jun 2017 14:59:37 +0200 Subject: [PATCH 4/9] implemented geometry bank manager, unified traction render code --- DynObj.cpp | 2 +- DynObj.h | 2 +- Ground.cpp | 65 ++--- Ground.h | 58 ++-- McZapkie/MOVER.h | 4 +- Model3d.cpp | 177 ++++-------- Model3d.h | 21 +- Names.h | 8 +- Texture.cpp | 32 +-- Texture.h | 68 ++--- Track.h | 4 +- Traction.cpp | 625 +++++++++++------------------------------ Traction.h | 77 ++--- VBO.cpp | 4 +- VBO.h | 3 +- dumb3d.h | 4 +- openglgeometrybank.cpp | 209 +++++++++++--- openglgeometrybank.h | 172 ++++++++++-- openglmatrixstack.h | 20 +- parser.h | 8 +- renderer.cpp | 200 ++++++------- renderer.h | 113 ++++---- uilayer.h | 2 +- usefull.h | 28 +- 24 files changed, 875 insertions(+), 1031 deletions(-) diff --git a/DynObj.cpp b/DynObj.cpp index 16229e1d..9e588c3b 100644 --- a/DynObj.cpp +++ b/DynObj.cpp @@ -3992,7 +3992,7 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName, // otherwise try the basic approach int skinindex = 0; do { - texture_manager::size_type texture = GfxRenderer.GetTextureId( Global::asCurrentTexturePath + ReplacableSkin + "," + std::to_string( skinindex + 1 ), "", Global::iDynamicFiltering, true ); + texture_handle texture = GfxRenderer.GetTextureId( Global::asCurrentTexturePath + ReplacableSkin + "," + std::to_string( skinindex + 1 ), "", Global::iDynamicFiltering, true ); if( false == GfxRenderer.Texture( texture ).is_ready ) { break; } diff --git a/DynObj.h b/DynObj.h index c61254d3..9b9cd735 100644 --- a/DynObj.h +++ b/DynObj.h @@ -143,7 +143,7 @@ class TAnim struct material_data { int textures_alpha{ 0x30300030 }; // maska przezroczystoÅ›ci tekstur. default: tekstury wymienne nie majÄ… przezroczystoÅ›ci - texture_manager::size_type replacable_skins[ 5 ]; // McZapkie:zmienialne nadwozie + texture_handle replacable_skins[ 5 ]; // McZapkie:zmienialne nadwozie int multi_textures{ 0 }; //<0 tekstury wskazane wpisem, >0 tekstury z przecinkami, =0 jedna material_data() { diff --git a/Ground.cpp b/Ground.cpp index 7f18da04..62054b1d 100644 --- a/Ground.cpp +++ b/Ground.cpp @@ -380,7 +380,14 @@ void TSubRect::NodeAdd(TGroundNode *Node) // nRenderWires - lista grup renderowanych z wÅ‚asnych VBO albo DL - druty i linie // nMeshed - obiekty do pogrupowania wg tekstur - Node->m_rootposition = Math3D::vector3( m_area.center.x, m_area.center.y, m_area.center.z ) ; + Node->m_rootposition = Math3D::vector3( m_area.center.x, m_area.center.y, m_area.center.z ); + + // since ground rectangle can be empty, we're doing lazy initialization of the geometry bank, when something may actually use it + // NOTE: this method is called for both subcell and cell, but subcells get first created and passed the handle from their parent + // thus, this effectively only gets executed for the 'parent' ground cells. Not the most elegant, but for now it'll do + if( m_geometrybank == NULL ) { + m_geometrybank = GfxRenderer.Create_Bank(); + } switch (Node->iType) { @@ -756,9 +763,7 @@ void TSubRect::LoadNodes() m_nVertexCount += n->iNumVerts; break; case TP_TRACTION: - n->iVboPtr = m_nVertexCount; // nowy poczÄ…tek - n->iNumVerts = n->hvTraction->RaArrayPrepare(); // zliczenie wierzchoÅ‚ków - m_nVertexCount += n->iNumVerts; + n->hvTraction->create_geometry( m_geometrybank, n->m_rootposition ); break; } n = n->nNext2; // nastÄ™pny z sektora @@ -810,14 +815,7 @@ void TSubRect::LoadNodes() #endif } break; - case TP_TRACTION: - if( n->iNumVerts ) { // druty mogÄ… być niewidoczne...? -#ifdef EU07_USE_OLD_VERTEXBUFFER - n->hvTraction->RaArrayFill( m_pVNT + n->iVboPtr, n->m_rootposition ); -#else - n->hvTraction->RaArrayFill( m_pVNT.data() + n->iVboPtr ); -#endif - } + default: break; } n = n->nNext2; // nastÄ™pny z sektora @@ -857,22 +855,25 @@ TGroundRect::~TGroundRect() void TGroundRect::Init() { + // since ground rectangle can be empty, we're doing lazy initialization of the geometry bank, when something may actually use it + if( m_geometrybank == NULL ) { + m_geometrybank = GfxRenderer.Create_Bank(); + } pSubRects = new TSubRect[ iNumSubRects * iNumSubRects ]; float const subrectsize = 1000.0f / iNumSubRects; for( int column = 0; column < iNumSubRects; ++column ) { for( int row = 0; row < iNumSubRects; ++row ) { - auto &area = SafeGetRect(column, row)->m_area; + auto subcell = FastGetRect( column, row ); + auto &area = subcell->m_area; area.center = m_area.center - glm::vec3( 500.0f, 0.0f, 500.0f ) // 'upper left' corner of rectangle + glm::vec3( subrectsize * 0.5f, 0.0f, subrectsize * 0.5f ) // center of sub-rectangle + glm::vec3( subrectsize * column, 0.0f, subrectsize * row ); -/* - // NOTE: the actual coordinates get swapped, as they're swapped in rest of the code :x - area.center = glm::vec3( area.center.z, area.center.y, area.center.x ); -*/ area.radius = subrectsize * M_SQRT2; + // all subcells share the same geometry bank with their parent, to reduce buffer switching during render + subcell->m_geometrybank = m_geometrybank; } } }; @@ -1822,8 +1823,11 @@ void TGround::FirstInit() Current->InitNormals(); if (Current->iType != TP_DYNAMIC) { // pojazdów w ogóle nie dotyczy dodawanie do mapy - if (i == TP_EVLAUNCH ? Current->EvLaunch->IsGlobal() : false) - srGlobal.NodeAdd(Current); // dodanie do globalnego obiektu + if( ( i == TP_EVLAUNCH ) + && ( true == Current->EvLaunch->IsGlobal() ) ) { + // dodanie do globalnego obiektu + srGlobal.NodeAdd( Current ); + } else if (i == TP_TERRAIN) { // specjalne przetwarzanie terenu wczytanego z pliku E3D TGroundRect *gr; @@ -1918,8 +1922,10 @@ bool TGround::Init(std::string File) if (!LastNode->Vertices) SafeDelete(LastNode); // usuwamy nieprzezroczyste trójkÄ…ty terenu } - else if ( ( LastNode->iType == TP_TRACTION ) && ( false == Global::bLoadTraction ) ) - SafeDelete(LastNode); // usuwamy druty, jeÅ›li wyłączone + else if( ( LastNode->iType == TP_TRACTION ) + && ( false == Global::bLoadTraction ) ) { + SafeDelete( LastNode ); // usuwamy druty, jeÅ›li wyłączone + } if (LastNode) // dopiero na koniec dopisujemy do tablic if (LastNode->iType != TP_DYNAMIC) @@ -4371,11 +4377,9 @@ void TGround::TerrainWrite() m->iNumVerts += Current->iNumVerts; // zwiÄ™kszenie caÅ‚kowitej iloÅ›ci wierzchoÅ‚ków break; - case GL_TRIANGLE_STRIP: // na razie nie, bo trzeba przerabiać na pojedyncze - // trójkÄ…ty + case GL_TRIANGLE_STRIP: // na razie nie, bo trzeba przerabiać na pojedyncze trójkÄ…ty break; - case GL_TRIANGLE_FAN: // na razie nie, bo trzeba przerabiać na pojedyncze - // trójkÄ…ty + case GL_TRIANGLE_FAN: // na razie nie, bo trzeba przerabiać na pojedyncze trójkÄ…ty break; } for (Current = Rects[i][j].nRootNode; Current; Current = Current->nNext2) @@ -4383,15 +4387,10 @@ void TGround::TerrainWrite() switch (Current->iType) { // pÄ™tla po trójkÄ…tach - dopisywanie wierzchoÅ‚ków case GL_TRIANGLES: - // ver=sk->TrianglePtr(TTexturesManager::GetName(Current->TextureID).c_str(),Current->iNumVerts); // //wskaźnik na poczÄ…tek ver = sk->TrianglePtr(Current->TextureID, Current->iVboPtr, Current->Ambient, Current->Diffuse, Current->Specular); // wskaźnik na poczÄ…tek - // WriteLog("Zapis "+AnsiString(Current->iNumVerts)+" trójkÄ…tów w - // ("+AnsiString(i)+","+AnsiString(j)+") od - // "+AnsiString(Current->iVboPtr)+" dla - // "+AnsiString(Current->TextureID)); Current->iVboPtr = -1; // bo to byÅ‚o tymczasowo używane for (k = 0; k < Current->iNumVerts; ++k) { // przepisanie współrzÄ™dnych @@ -4405,11 +4404,9 @@ void TGround::TerrainWrite() ver[k].texture.t = Current->Vertices[k].tv; } break; - case GL_TRIANGLE_STRIP: // na razie nie, bo trzeba przerabiać na pojedyncze - // trójkÄ…ty + case GL_TRIANGLE_STRIP: // na razie nie, bo trzeba przerabiać na pojedyncze trójkÄ…ty break; - case GL_TRIANGLE_FAN: // na razie nie, bo trzeba przerabiać na pojedyncze - // trójkÄ…ty + case GL_TRIANGLE_FAN: // na razie nie, bo trzeba przerabiać na pojedyncze trójkÄ…ty break; } } diff --git a/Ground.h b/Ground.h index dd408880..08b6f4a7 100644 --- a/Ground.h +++ b/Ground.h @@ -11,6 +11,7 @@ http://mozilla.org/MPL/2.0/. #include #include "GL/glew.h" +#include "openglgeometrybank.h" #include "VBO.h" #include "Classes.h" #include "ResourceManager.h" @@ -141,7 +142,7 @@ public: GLuint DisplayListID; // numer siatki DisplayLists bool PROBLEND; int iVboPtr; // indeks w buforze VBO - texture_manager::size_type TextureID; // główna (jedna) tekstura obiektu + texture_handle 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; @@ -235,32 +236,38 @@ class TGroundRect : public TSubRect // Ra: 2012-02 doszÅ‚y submodele terenu friend class opengl_renderer; - private: +private: + TSubRect *pSubRects { nullptr }; int iLastDisplay; // numer klatki w której byÅ‚ ostatnio wyÅ›wietlany - TSubRect *pSubRects{ nullptr }; + void Init(); - public: - static int iFrameNumber; // numer kolejny wyÅ›wietlanej klatki - TGroundNode *nTerrain{ nullptr }; // model terenu z E3D - użyć nRootMesh? +public: virtual ~TGroundRect(); - - TSubRect * SafeGetRect(int iCol, int iRow) - { // pobranie wskaźnika do maÅ‚ego kwadratu, utworzenie jeÅ›li trzeba - if (!pSubRects) - Init(); // utworzenie maÅ‚ych kwadratów + // pobranie wskaźnika do maÅ‚ego kwadratu, utworzenie jeÅ›li trzeba + TSubRect * SafeGetRect(int iCol, int iRow) { + if( !pSubRects ) { + // utworzenie maÅ‚ych kwadratów + Init(); + } return pSubRects + iRow * iNumSubRects + iCol; // zwrócenie wÅ‚aÅ›ciwego }; - TSubRect * FastGetRect(int iCol, int iRow) - { // pobranie wskaźnika do maÅ‚ego kwadratu, bez tworzenia jeÅ›li nie ma + // pobranie wskaźnika do maÅ‚ego kwadratu, bez tworzenia jeÅ›li nie ma + TSubRect * FastGetRect(int iCol, int iRow) { return (pSubRects ? pSubRects + iRow * iNumSubRects + iCol : NULL); }; - void Optimize() - { // optymalizacja obiektów w sektorach - if (pSubRects) - for (int i = iNumSubRects * iNumSubRects - 1; i >= 0; --i) - pSubRects[i].Sort(); // optymalizacja obiektów w sektorach + // optymalizacja obiektów w sektorach + void Optimize() { + if( pSubRects ) { + for( int i = iNumSubRects * iNumSubRects - 1; i >= 0; --i ) { + // optymalizacja obiektów w sektorach + pSubRects[ i ].Sort(); + } + } }; + + static int iFrameNumber; // numer kolejny wyÅ›wietlanej klatki + TGroundNode *nTerrain { nullptr }; // model terenu z E3D - użyć nRootMesh? }; class TGround @@ -269,7 +276,6 @@ class TGround vector3 CameraDirection; // zmienna robocza przy renderowaniu int const *iRange = nullptr; // tabela widocznoÅ›ci - // TGroundNode *nRootNode; //lista wszystkich wÄ™złów TGroundNode *nRootDynamic = nullptr; // lista pojazdów TGroundRect Rects[iNumRects][iNumRects]; // mapa kwadratów kilometrowych TEvent *RootEvent = nullptr; // lista zdarzeÅ„ @@ -283,9 +289,7 @@ class TGround vector3 aRotate; bool bInitDone = false; TGroundNode *nRootOfType[TP_LAST]; // tablica grupujÄ…ca obiekty, przyspiesza szukanie - // TGroundNode *nLastOfType[TP_LAST]; //ostatnia TSubRect srGlobal; // zawiera obiekty globalne (na razie wyzwalacze czasowe) - // int tracks,tracksfar; //liczniki torów typedef std::unordered_map event_map; event_map m_eventmap; TNames m_trackmap; @@ -296,7 +300,6 @@ class TGround public: bool bDynamicRemove = false; // czy uruchomić procedurÄ™ usuwania pojazdów - TDynamicObject *LastDyn = nullptr; // ABu: paskudnie, ale na bardzo szybko moze jakos przejdzie... TGround(); ~TGround(); @@ -311,17 +314,6 @@ class TGround TTraction * FindTraction(vector3 *Point, int &iConnection, TGroundNode *Exclude); TTraction * TractionNearestFind(vector3 &p, int dir, TGroundNode *n); TGroundNode * AddGroundNode(cParser *parser); - bool AddGroundNode(double x, double z, TGroundNode *Node) - { - TSubRect *tmp = GetSubRect(x, z); - if (tmp) - { - tmp->NodeAdd(Node); - return true; - } - else - return false; - }; void UpdatePhys(double dt, int iter); // aktualizacja fizyki staÅ‚ym krokiem bool Update(double dt, int iter); // aktualizacja przesunięć zgodna z FPS void Update_Lights(); // updates scene lights array diff --git a/McZapkie/MOVER.h b/McZapkie/MOVER.h index 36df83ce..26c3ad7b 100644 --- a/McZapkie/MOVER.h +++ b/McZapkie/MOVER.h @@ -1228,9 +1228,9 @@ extract_value( std::string const &Key, std::string const &Input ) { return value; } -template +template bool -extract_value( _Type &Variable, std::string const &Key, std::string const &Input, std::string const &Default ) { +extract_value( Type_ &Variable, std::string const &Key, std::string const &Input, std::string const &Default ) { auto value = extract_value( Key, Input ); if( false == value.empty() ) { diff --git a/Model3d.cpp b/Model3d.cpp index 2d9ebfdb..3b86d474 100644 --- a/Model3d.cpp +++ b/Model3d.cpp @@ -29,7 +29,7 @@ using namespace Mtable; double TSubModel::fSquareDist = 0; size_t TSubModel::iInstance; // numer renderowanego egzemplarza obiektu -texture_manager::size_type const *TSubModel::ReplacableSkinId = NULL; +texture_handle const *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; @@ -117,20 +117,20 @@ TSubModel::~TSubModel() // wyÅ›wietlania }; -void TSubModel::TextureNameSet(const char *n) +void TSubModel::TextureNameSet(std::string const &Name) { // ustawienie nazwy submodelu, o // ile nie jest wczytany z E3D if (iFlags & 0x0200) { // tylko jeżeli submodel zosta utworzony przez new - pTexture = std::string(n); + pTexture = Name; } }; -void TSubModel::NameSet(const char *n) +void TSubModel::NameSet(std::string const &Name) { // ustawienie nazwy submodelu, o ile // nie jest wczytany z E3D if (iFlags & 0x0200) - pName = std::string(n); + pName = Name; }; // int TSubModel::SeekFaceNormal(DWORD *Masks, int f,DWORD dwMask,vector3 @@ -204,9 +204,6 @@ int TSubModel::Load(cParser &parser, TModel3d *Model, int Pos, bool dynamic) { // Ra: VBO tworzone na poziomie modelu, a nie submodeli iNumVerts = 0; iVboPtr = Pos; // pozycja w VBO - // TMaterialColorf Ambient,Diffuse,Specular; - // GLuint TextureID; - // char *extName; if (!parser.expectToken("type:")) Error("Model type parse failure!"); { @@ -224,22 +221,24 @@ int TSubModel::Load(cParser &parser, TModel3d *Model, int Pos, bool dynamic) }; parser.ignoreToken(); std::string token; - // parser.getToken(token1); //ze zmianÄ… na maÅ‚e! parser.getTokens(1, false); // nazwa submodelu bez zmieny na maÅ‚e parser >> token; - NameSet(token.c_str()); - if (dynamic) - { // dla pojazdu, blokujemy załączone submodele, które mogÄ… być - // nieobsÅ‚ugiwane - if ( (token.size() >= 3) - && (token.find("_on") + 3 == token.length())) // jeÅ›li nazwa koÅ„czy siÄ™ na "_on" - iVisible = 0; // to domyÅ›lnie wyłączyć, żeby siÄ™ nie nakÅ‚adaÅ‚o z obiektem "_off" + NameSet(token); + if (dynamic) { + // dla pojazdu, blokujemy załączone submodele, które mogÄ… być nieobsÅ‚ugiwane + if( ( token.size() >= 3 ) + && ( token.find( "_on" ) + 3 == token.length() ) ) { + // jeÅ›li nazwa koÅ„czy siÄ™ na "_on" to domyÅ›lnie wyłączyć, żeby siÄ™ nie nakÅ‚adaÅ‚o z obiektem "_off" + iVisible = 0; + } + } + else { + // dla pozostaÅ‚ych modeli blokujemy zapalone Å›wiatÅ‚a, które mogÄ… być nieobsÅ‚ugiwane + if( token.compare( 0, 8, "Light_On" ) == 0 ) { + // jeÅ›li nazwa zaczyna siÄ™ od "Light_On" to domyÅ›lnie wyłączyć, żeby siÄ™ nie nakÅ‚adaÅ‚o z obiektem "Light_Off" + iVisible = 0; + } } - else // dla pozostaÅ‚ych modeli blokujemy zapalone Å›wiatÅ‚a, które mogÄ… być - // nieobsÅ‚ugiwane - if (token.compare(0, 8, "Light_On") == 0) // jeÅ›li nazwa zaczyna siÄ™ od "Light_On" - iVisible = 0; // to domyÅ›lnie wyłączyć, żeby siÄ™ nie nakÅ‚adaÅ‚o z obiektem - // "Light_Off" if (parser.expectToken("anim:")) // Ra: ta informacja by siÄ™ przydaÅ‚a! { // rodzaj animacji @@ -590,7 +589,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, texture_manager::size_type tex, int tri) +int TSubModel::TriangleAdd(TModel3d *m, texture_handle tex, int tri) { // dodanie trójkÄ…tów do submodelu, używane // przy tworzeniu E3D terenu TSubModel *s = this; @@ -644,6 +643,7 @@ basic_vertex *TSubModel::TrianglePtr(int tex, int pos, int *la, int *ld, int *ls return s->Vertices + pos; // wskaźnik na wolne miejsce w tabeli wierzchoÅ‚ków }; +#ifdef EU07_USE_OLD_RENDERCODE void TSubModel::DisplayLists() { // utworznie po jednej skompilowanej liÅ›cie dla // każdego submodelu @@ -708,6 +708,7 @@ void TSubModel::DisplayLists() if (Next) Next->DisplayLists(); }; +#endif void TSubModel::InitialRotate(bool doit) { // konwersja ukÅ‚adu współrzÄ™dnych na zgodny ze sceneriÄ… @@ -986,11 +987,6 @@ void TSubModel::RaAnimation(TAnimType a) break; case at_Billboard: // obrót w pionie do kamery { -/* - matrix4x4 mat; // potrzebujemy współrzÄ™dne przesuniÄ™cia Å›rodka ukÅ‚adu - // współrzÄ™dnych submodelu - glGetDoublev(GL_MODELVIEW_MATRIX, mat.getArray()); // pobranie aktualnej matrycy -*/ matrix4x4 mat; mat.OpenGL_Matrix( OpenGLMatrices.data_array( GL_MODELVIEW ) ); float3 gdzie = float3(mat[3][0], mat[3][1], mat[3][2]); // poczÄ…tek ukÅ‚adu współrzÄ™dnych submodelu wzglÄ™dem kamery glLoadIdentity(); // macierz jedynkowa @@ -1090,6 +1086,7 @@ void TSubModel::ColorsSet(int *a, int *d, int *s) for (i = 0; i < 4; ++i) f4Specular[i] = s[i] / 255.0; }; + void TSubModel::ParentMatrix(float4x4 *m) { // pobranie transformacji wzglÄ™dem wstawienia modelu // jeÅ›li nie zostaÅ‚o wykonane Init() (tzn. zaraz po wczytaniu T3D), to @@ -1107,68 +1104,41 @@ void TSubModel::ParentMatrix(float4x4 *m) // dla ostatniego może być potrzebny dodatkowy obrót, jeÅ›li wczytano z T3D, a // nie obrócono jeszcze }; -float TSubModel::MaxY(const float4x4 &m) -{ // obliczenie maksymalnej wysokoÅ›ci, - // na poczÄ…tek Å›lizgu w pantografie - if (eType != 4) - return 0; // tylko dla trójkÄ…tów liczymy - if (iNumVerts < 1) - return 0; -/* - if (!Vertices) - return 0; - float y, - my = m[0][1] * Vertices[0].Point.x + m[1][1] * Vertices[0].Point.y + - m[2][1] * Vertices[0].Point.z + m[3][1]; - for (int i = 1; i < iNumVerts; ++i) - { - y = m[0][1] * Vertices[i].Point.x + m[1][1] * Vertices[i].Point.y + - m[2][1] * Vertices[i].Point.z + m[3][1]; - if (my < y) - my = y; - } -*/ - float my = - m[ 0 ][ 1 ] * Vertices[ 0 ].position.x - + m[ 1 ][ 1 ] * Vertices[ 0 ].position.y - + m[ 2 ][ 1 ] * Vertices[ 0 ].position.z - + m[ 3 ][ 1 ]; - float y; - for( int i = 1; i < iNumVerts; ++i ) { - y = - m[ 0 ][ 1 ] * Vertices[ i ].position.x - + m[ 1 ][ 1 ] * Vertices[ i ].position.y - + m[ 2 ][ 1 ] * Vertices[ i ].position.z - + m[ 3 ][ 1 ]; - if( my < y ) { my = y; } +float TSubModel::MaxY( float4x4 const &m ) +{ // obliczenie maksymalnej wysokoÅ›ci, na poczÄ…tek Å›lizgu w pantografie + if( eType != 4 ) { + // tylko dla trójkÄ…tów liczymy + return 0; } - return my; + if( m_geometry == NULL ) { + return 0; + } + + auto maxy { 0.0f }; + for( auto const &vertex : GfxRenderer.Vertices( m_geometry ) ) { + + maxy = std::max( + maxy, + m[ 0 ][ 1 ] * vertex.position.x + + m[ 1 ][ 1 ] * vertex.position.y + + m[ 2 ][ 1 ] * vertex.position.z + + m[ 3 ][ 1 ] ); + } + + return maxy; }; //--------------------------------------------------------------------------- TModel3d::TModel3d() { - // Materials=NULL; - // MaterialsCount=0; Root = NULL; iFlags = 0; iSubModelsCount = 0; iModel = NULL; // tylko jak wczytany model binarny iNumVerts = 0; // nie ma jeszcze wierzchoÅ‚ków }; -/* -TModel3d::TModel3d(char *FileName) -{ -// Root=NULL; -// Materials=NULL; -// MaterialsCount=0; -Root=NULL; -SubModelsCount=0; -iFlags=0; -LoadFromFile(FileName); -}; -*/ + TModel3d::~TModel3d() { // SafeDeleteArray(Materials); @@ -1227,18 +1197,6 @@ TSubModel *TModel3d::GetFromName(const char *sName) } }; -/* -TMaterial* TModel3d::GetMaterialFromName(char *sName) -{ -AnsiString tmp=AnsiString(sName).Trim(); -for (int i=0; i > submodeloffsets; submodeloffsets.reserve( iSubModelsCount ); - for( int idx = 0; idx < iSubModelsCount; ++idx ) { - auto &submodel = Root[ idx ]; + for( int submodelindex = 0; submodelindex < iSubModelsCount; ++submodelindex ) { + auto const &submodel = Root[ submodelindex ]; if( submodel.iNumVerts <= 0 ) { continue; } - submodeloffsets.emplace_back( submodel.tVboPtr, idx ); + submodeloffsets.emplace_back( submodel.tVboPtr, submodelindex ); } std::sort( submodeloffsets.begin(), submodeloffsets.end(), []( std::pair const &Left, std::pair const &Right ) { return (Left.first) < (Right.first); } ); - // once sorted we can grab geometry for the chunks as they come + // once sorted we can grab geometry as it comes, and assign it to the chunks it belongs to for( auto const &submodeloffset : submodeloffsets ) { auto &submodel = Root[ submodeloffset.second ]; vertex_array vertices; vertices.resize( submodel.iNumVerts ); @@ -1584,7 +1543,7 @@ void TModel3d::deserialize(std::istream &s, size_t size, bool dynamic) break; } } - submodel.m_chunk = m_geometry->create( vertices, type ); + submodel.m_geometry = GfxRenderer.Insert( vertices, m_geometrybank, type ); } } @@ -1639,12 +1598,7 @@ void TModel3d::deserialize(std::istream &s, size_t size, bool dynamic) for (size_t i = 0; (int)i < iSubModelsCount; ++i) { #ifdef EU07_USE_OLD_VERTEXBUFFER - Root[i].BinInit( - Root, tm, - ( Root[i].m_chunk ? - &m_geometry->data(Root[i].m_chunk)[0] : - nullptr ), - &Textures, &Names, dynamic); + Root[i].BinInit( Root, tm, &Textures, &Names, dynamic ); #else Root[ i ].BinInit( Root, tm, (float8*)m_pVNT.data(), &Textures, &Names, dynamic ); #endif @@ -1656,8 +1610,7 @@ void TModel3d::deserialize(std::istream &s, size_t size, bool dynamic) } } -void TSubModel::BinInit(TSubModel *s, float4x4 *m, basic_vertex *v, - std::vector *t, std::vector *n, bool dynamic) +void TSubModel::BinInit(TSubModel *s, float4x4 *m, std::vector *t, std::vector *n, bool dynamic) { // ustawienie wskaźników w submodelu //m7todo: brzydko iVisible = 1; // tymczasowo używane @@ -1720,7 +1673,6 @@ void TSubModel::BinInit(TSubModel *s, float4x4 *m, basic_vertex *v, iFlags &= ~0x0200; // wczytano z pliku binarnego (nie jest wÅ‚aÅ›cicielem tablic) iVboPtr = tVboPtr; - Vertices = v; }; void TModel3d::LoadFromBinFile(std::string const &FileName, bool dynamic) @@ -1812,15 +1764,9 @@ void TModel3d::Init() SaveToBinFile(asBinary.c_str()); // utworzy tablicÄ™ (m_pVNT) asBinary = ""; // zablokowanie powtórnego zapisu } - if (iNumVerts) +#ifdef EU07_USE_OLD_DRAW_CODE + if (iNumVerts) { -/* // NOTE: we will be applying distance factor dynamically during render, - // so we're leaving the defined ranges intact - if (Global::fDistanceFactor != - 1.0) // trochÄ™ zaoszczÄ™dzi czasu na modelach z wieloma submocelami - Root->AdjustDist(); // aktualizacja odlegÅ‚oÅ›ci faz LoD, zależnie od - // rozdzielczoÅ›ci pionowej oraz multisamplingu -*/ if (Global::bUseVBO) { #ifdef EU07_USE_OLD_VERTEXBUFFER @@ -1844,10 +1790,9 @@ void TModel3d::Init() { // przygotowanie skompilowanych siatek dla DisplayLists Root->DisplayLists(); // tworzenie skompilowanej listy dla submodelu } - // if (Root->TextureID) //o ile ma teksturÄ™ - // Root->iFlags|=0x80; //konieczność ustawienia tekstury } - } +#endif + } }; void TModel3d::BreakHierarhy() diff --git a/Model3d.h b/Model3d.h index 06a5c985..81049800 100644 --- a/Model3d.h +++ b/Model3d.h @@ -112,8 +112,8 @@ private: TSubModel *Next; TSubModel *Child; intptr_t iVboPtr; - geometrychunk_handle m_chunk; // geometry of the submodel - texture_manager::size_type TextureID; // numer tekstury, -1 wymienna, 0 brak + geometry_handle m_geometry; // geometry of the submodel + texture_handle 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 @@ -142,7 +142,7 @@ private: public: static size_t iInstance; // identyfikator egzemplarza, który aktualnie renderuje model - static texture_manager::size_type const *ReplacableSkinId; + static texture_handle const *ReplacableSkinId; static int iAlpha; // maska bitowa dla danego przebiegu static double fSquareDist; static TModel3d *pRoot; @@ -155,7 +155,7 @@ public: void NextAdd(TSubModel *SubModel); TSubModel * NextGet() { return Next; }; TSubModel * ChildGet() { return Child; }; - int TriangleAdd(TModel3d *m, texture_manager::size_type tex, int tri); + int TriangleAdd(TModel3d *m, texture_handle tex, int tri); basic_vertex * TrianglePtr(int tex, int pos, int *la, int *ld, int *ls); void SetRotate(float3 vNewRotateAxis, float fNewAngle); void SetRotateXYZ(vector3 vNewAngles); @@ -175,16 +175,17 @@ public: iFlags |= 0x4000; }; void InitialRotate(bool doit); +#ifdef EU07_USE_OLD_DRAW_CODE void DisplayLists(); - void BinInit(TSubModel *s, float4x4 *m, basic_vertex *v, - std::vector *t, std::vector *n, bool dynamic); - void ReplacableSet(texture_manager::size_type const *r, int a) +#endif + void BinInit(TSubModel *s, float4x4 *m, std::vector *t, std::vector *n, bool dynamic); + void ReplacableSet(texture_handle const *r, int a) { ReplacableSkinId = r; iAlpha = a; }; - void TextureNameSet(const char *n); - void NameSet(const char *n); + void TextureNameSet( std::string const &Name ); + void NameSet( std::string const &Name ); // Ra: funkcje do budowania terenu z E3D int Flags() { return iFlags; }; void UnFlagNext() { iFlags &= 0x00FFFFFF; }; @@ -202,7 +203,7 @@ public: return TextureID; } void ParentMatrix(float4x4 *m); - float MaxY(const float4x4 &m); + float MaxY( float4x4 const &m ); void AdjustDist(); void deserialize(std::istream&); diff --git a/Names.h b/Names.h index a4bbdf70..2a3addb6 100644 --- a/Names.h +++ b/Names.h @@ -12,7 +12,7 @@ http://mozilla.org/MPL/2.0/. #include #include -template +template class TNames { public: @@ -26,7 +26,7 @@ public: // methods: // dodanie obiektu z wskaźnikiem. updates data field if the object already exists. returns true for insertion, false for update bool - Add( int const Type, std::string const &Name, _Type Data ) { + Add( int const Type, std::string const &Name, Type_ Data ) { auto lookup = find_map( Type ).emplace( Name, Data ); if( lookup.second == false ) { @@ -40,7 +40,7 @@ public: } } // returns pointer associated with provided label, or nullptr if there's no match - _Type + Type_ Find( int const Type, std::string const &Name ) { auto const &map = find_map( Type ); @@ -51,7 +51,7 @@ public: private: // types: - typedef std::unordered_map type_map; + typedef std::unordered_map type_map; typedef std::unordered_map typemap_map; // methods: diff --git a/Texture.cpp b/Texture.cpp index 3d2c2304..ba7abbfe 100644 --- a/Texture.cpp +++ b/Texture.cpp @@ -692,13 +692,9 @@ opengl_texture::downsize( GLuint const Format ) { }; } -void -texture_manager::Init() { -} - // 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 ) { +texture_handle +texture_manager::create( std::string Filename, std::string const &Dir, int const Filter, bool const Loadnow ) { if( Filename.find( '|' ) != std::string::npos ) Filename.erase( Filename.find( '|' ) ); // po | może być nazwa kolejnej tekstury @@ -788,7 +784,7 @@ texture_manager::GetTextureId( std::string Filename, std::string const &Dir, int traits += '#'; } texture.traits = traits; - auto const textureindex = (texture_manager::size_type)m_textures.size(); + auto const textureindex = (texture_handle)m_textures.size(); m_textures.emplace_back( texture ); m_texturemappings.emplace( filename, textureindex ); @@ -796,9 +792,9 @@ texture_manager::GetTextureId( std::string Filename, std::string const &Dir, int if( true == Loadnow ) { - Texture( textureindex ).load(); + texture_manager::texture( textureindex ).load(); #ifndef EU07_DEFERRED_TEXTURE_UPLOAD - Texture( textureindex ).create(); + texture_manager::texture( textureindex ).create(); #endif } @@ -806,7 +802,7 @@ texture_manager::GetTextureId( std::string Filename, std::string const &Dir, int }; void -texture_manager::Bind( texture_manager::size_type const Id ) { +texture_manager::bind( texture_handle const Texture ) { /* // 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 @@ -818,11 +814,11 @@ texture_manager::Bind( texture_manager::size_type const Id ) { } */ // TODO: do binding in texture object, add support for other types - if( Id != 0 ) { + if( Texture != 0 ) { #ifndef EU07_DEFERRED_TEXTURE_UPLOAD // NOTE: we could bind dedicated 'error' texture here if the id isn't valid - ::glBindTexture( GL_TEXTURE_2D, Texture(Id).id ); - m_activetexture = Texture(Id).id; + ::glBindTexture( GL_TEXTURE_2D, texture(Texture).id ); + m_activetexture = texture(Texture).id; #else if( Texture( Id ).bind() == resource_state::good ) { m_activetexture = Id; @@ -842,7 +838,7 @@ texture_manager::Bind( texture_manager::size_type const Id ) { } void -texture_manager::Free() { +texture_manager::delete_textures() { for( auto const &texture : m_textures ) { // usuniÄ™cie wszyskich tekstur (bez usuwania struktury) if( ( texture.id > 0 ) @@ -854,7 +850,7 @@ texture_manager::Free() { // debug performance string std::string -texture_manager::Info() const { +texture_manager::info() const { // TODO: cache this data and update only during resource sweep std::size_t totaltexturecount{ m_textures.size() - 1 }; @@ -892,8 +888,8 @@ texture_manager::Info() const { } // 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 ) { +texture_handle +texture_manager::find_in_databank( std::string const &Texturename ) const { auto lookup = m_texturemappings.find( Texturename ); if( lookup != m_texturemappings.end() ) { @@ -910,7 +906,7 @@ texture_manager::find_in_databank( std::string const &Texturename ) { // checks whether specified file exists. std::string -texture_manager::find_on_disk( std::string const &Texturename ) { +texture_manager::find_on_disk( std::string const &Texturename ) const { { std::ifstream file( Texturename ); diff --git a/Texture.h b/Texture.h index 8ed8c2dc..8ed49627 100644 --- a/Texture.h +++ b/Texture.h @@ -62,7 +62,7 @@ private: */ }; -typedef std::size_t texture_handle; +typedef int texture_handle; class texture_manager { @@ -70,68 +70,52 @@ private: typedef std::vector opengltexture_array; public: -// typedef opengltexture_array::size_type size_type; - typedef int size_type; - texture_manager(); - ~texture_manager() { Free(); } + ~texture_manager() { delete_textures(); } - size_type - GetTextureId( std::string Filename, std::string const &Dir, int const Filter = -1, bool const Loadnow = true ); + texture_handle + create( std::string Filename, std::string const &Dir, int const Filter = -1, bool const Loadnow = true ); void - Bind( size_type const Id ); + bind( texture_handle const Texture ); opengl_texture & - Texture( size_type const Id ) { return m_textures[ Id ]; } - void - Init(); - void - Free(); + texture( texture_handle const Texture ) { return m_textures[ Texture ]; } // debug performance string std::string - Info() const; + info() const; private: - typedef std::unordered_map index_map; -/* - opengltexture_array::size_type LoadFromFile(std::string name, int filter = -1); -*/ -/* - 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 ); -*/ + typedef std::unordered_map index_map; + // checks whether specified texture is in the texture bank. returns texture id, or npos. - size_type find_in_databank( std::string const &Texturename ); + texture_handle + find_in_databank( std::string const &Texturename ) const; // 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 + std::string + find_on_disk( std::string const &Texturename ) const; + void + delete_textures(); + + static const texture_handle 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 + texture_handle m_activetexture{ 0 }; // last i.e. currently bound texture }; // reduces provided data image to half of original size, using basic 2x2 average -template +template void downsample( std::size_t const Width, std::size_t const Height, char *Imagedata ) { - _Colortype *destination = reinterpret_cast<_Colortype*>( Imagedata ); - _Colortype *sampler = reinterpret_cast<_Colortype*>( Imagedata ); + Colortype_ *destination = reinterpret_cast( Imagedata ); + Colortype_ *sampler = reinterpret_cast( Imagedata ); - _Colortype accumulator, color; + Colortype_ accumulator, color; /* _Colortype color; float component; */ - for( size_t row = 0; row < Height; row += 2, sampler += Width ) { // column movement advances us down another row - for( size_t column = 0; column < Width; column += 2, sampler += 2 ) { + for( std::size_t row = 0; row < Height; row += 2, sampler += Width ) { // column movement advances us down another row + for( std::size_t column = 0; column < Width; column += 2, sampler += 2 ) { /* // straightforward, but won't work with byte data auto color = ( @@ -158,8 +142,8 @@ downsample( std::size_t const Width, std::size_t const Height, char *Imagedata ) *destination++ = color; /* // "full" 8bit resolution - color = _Colortype(); component = 0; - for( int idx = 0; idx < sizeof( _Colortype ); ++idx ) { + color = Colortype_(); component = 0; + for( int idx = 0; idx < sizeof( Colortype_ ); ++idx ) { component = ( (*sampler)[idx] diff --git a/Track.h b/Track.h index be0f16c2..b51bb3a6 100644 --- a/Track.h +++ b/Track.h @@ -133,8 +133,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 - texture_manager::size_type TextureID1 = 0; // tekstura szyn albo nawierzchni - texture_manager::size_type TextureID2 = 0; // tekstura automatycznej podsypki albo pobocza + texture_handle TextureID1 = 0; // tekstura szyn albo nawierzchni + texture_handle TextureID2 = 0; // tekstura automatycznej podsypki albo pobocza float fTexLength = 4.0f; // dÅ‚ugość powtarzania tekstury w metrach float fTexRatio1 = 1.0f; // proporcja boków tekstury nawierzchni (żeby zaoszczÄ™dzić na rozmiarach tekstur...) float fTexRatio2 = 1.0f; // proporcja boków tekstury chodnika (żeby zaoszczÄ™dzić na rozmiarach tekstur...) diff --git a/Traction.cpp b/Traction.cpp index c7add93a..da00856e 100644 --- a/Traction.cpp +++ b/Traction.cpp @@ -18,7 +18,6 @@ http://mozilla.org/MPL/2.0/. #include "logs.h" #include "mctools.h" #include "TractionPower.h" -#include "renderer.h" //--------------------------------------------------------------------------- /* @@ -91,274 +90,32 @@ jawnie nazwÄ™ sekcji, ewentualnie nazwÄ™ zasilacza (zostanie zastÄ…piona wskazan sekcji z sÄ…siedniego przÄ™sÅ‚a). */ -TTraction::TTraction() -{ - hvNext[ 0 ] = nullptr; - hvNext[ 1 ] = nullptr; - psPower[ 0 ] = nullptr; - psPower[ 1 ] = nullptr; // na poczÄ…tku zasilanie nie podłączone - iNext[ 0 ] = 0; - iNext[ 1 ] = 0; - fResistance[ 0 ] = -1.0; - fResistance[ 1 ] = -1.0; // trzeba dopiero policzyć -} +std::size_t +TTraction::create_geometry( geometrybank_handle const &Bank, Math3D::vector3 const &Origin ) { -TTraction::~TTraction() -{ - if (!Global::bUseVBO) - glDeleteLists(uiDisplayList, 1); -} - -void TTraction::Optimize( Math3D::vector3 const &Origin ) -{ - if (Global::bUseVBO) - return; - uiDisplayList = glGenLists(1); - glNewList(uiDisplayList, GL_COMPILE); - - if (Wires != 0) - { - // Dlugosc odcinka trakcji 'Winger - double ddp = std::hypot(pPoint2.x - pPoint1.x, pPoint2.z - pPoint1.z); - if (Wires == 2) - WireOffset = 0; - // Przewoz jezdny 1 'Marcin - glBegin(GL_LINE_STRIP); - glVertex3f( - pPoint1.x - (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset - Origin.x, - pPoint1.y - Origin.y, - pPoint1.z - (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset - Origin.z); - glVertex3f( - pPoint2.x - (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset - Origin.x, - pPoint2.y - Origin.y, - pPoint2.z - (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset - Origin.z ); - glEnd(); - // Nie wiem co 'Marcin - Math3D::vector3 pt1, pt2, pt3, pt4, v1, v2; - v1 = pPoint4 - pPoint3; - v2 = pPoint2 - pPoint1; - float step = 0; - if (iNumSections > 0) - step = 1.0f / (float)iNumSections; - float f = step; - float mid = 0.5; - float t; - // Przewod nosny 'Marcin - if (Wires > 1) - { - glBegin(GL_LINE_STRIP); - glVertex3f( - pPoint3.x - Origin.x, - pPoint3.y - Origin.y, - pPoint3.z - Origin.z ); - for (int i = 0; i < iNumSections - 1; ++i) - { - pt3 = pPoint3 + v1 * f; - t = (1 - std::fabs(f - mid) * 2); - if ((Wires < 4) || ((i != 0) && (i != iNumSections - 2))) - glVertex3f( - pt3.x - Origin.x, - pt3.y - std::sqrt(t) * fHeightDifference - Origin.y, - pt3.z - Origin.z ); - f += step; - } - glVertex3f( - pPoint4.x - Origin.x, - pPoint4.y - Origin.y, - pPoint4.z - Origin.z ); - glEnd(); - } - // Drugi przewod jezdny 'Winger - if (Wires > 2) - { - glBegin(GL_LINE_STRIP); - glVertex3f( - pPoint1.x + (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset - Origin.x, - pPoint1.y - Origin.y, - pPoint1.z + (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset - Origin.z ); - glVertex3f( - pPoint2.x + (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset - Origin.x, - pPoint2.y - Origin.y, - pPoint2.z + (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset - Origin.z ); - glEnd(); - } - - f = step; - - if (Wires == 4) - { - glBegin(GL_LINE_STRIP); - glVertex3f( - pPoint3.x - Origin.x, - pPoint3.y - 0.65f * fHeightDifference - Origin.y, - pPoint3.z - Origin.z ); - for (int i = 0; i < iNumSections - 1; ++i) - { - pt3 = pPoint3 + v1 * f; - t = (1 - std::fabs(f - mid) * 2); - glVertex3f( - pt3.x - Origin.x, - pt3.y - std::sqrt( t ) * fHeightDifference - ( - ( ( i == 0 ) - || ( i == iNumSections - 2 ) ) ? - 0.25f * fHeightDifference : - 0.05 ) - - Origin.y, - pt3.z - Origin.z ); - f += step; - } - glVertex3f( - pPoint4.x - Origin.x, - pPoint4.y - 0.65f * fHeightDifference - Origin.y, - pPoint4.z - Origin.z ); - glEnd(); - } - - f = step; - - // Przewody pionowe (wieszaki) 'Marcin, poprawki na 2 przewody jezdne 'Winger - if (Wires != 1) - { - glBegin(GL_LINES); - for (int i = 0; i < iNumSections - 1; ++i) - { - float flo, flo1; - flo = (Wires == 4 ? 0.25f * fHeightDifference : 0); - flo1 = (Wires == 4 ? +0.05 : 0); - pt3 = pPoint3 + v1 * f; - pt4 = pPoint1 + v2 * f; - t = (1 - std::fabs(f - mid) * 2); - if ((i % 2) == 0) - { - glVertex3f( - pt3.x - Origin.x, - pt3.y - std::sqrt(t) * fHeightDifference - ((i == 0) || (i == iNumSections - 2) ? flo : flo1) - Origin.y, - pt3.z - Origin.z ); - glVertex3f( - pt4.x - (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset - Origin.x, - pt4.y - Origin.y, - pt4.z - (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset - Origin.z ); - } - else - { - glVertex3f( - pt3.x - Origin.x, - pt3.y - std::sqrt(t) * fHeightDifference - ((i == 0) || (i == iNumSections - 2) ? flo : flo1) - Origin.y, - pt3.z - Origin.z ); - glVertex3f( - pt4.x + (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset - Origin.x, - pt4.y - Origin.y, - pt4.z + (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset - Origin.z ); - } - if ((Wires == 4) && ((i == 1) || (i == iNumSections - 3))) - { - glVertex3f( - pt3.x - Origin.x, - pt3.y - std::sqrt(t) * fHeightDifference - 0.05 - Origin.y, - pt3.z - Origin.z ); - glVertex3f( - pt3.x - Origin.x, - pt3.y - std::sqrt(t) * fHeightDifference - Origin.y, - pt3.z - Origin.z ); - } - f += step; - } - glEnd(); - } - glEndList(); + if( m_geometry != NULL ) { + return GfxRenderer.Vertices( m_geometry ).size() / 2; } -} -/* -void TTraction::InitCenter(vector3 Angles, vector3 pOrigin) -{ - pPosition= (pPoint2+pPoint1)*0.5f; - fSquaredRadius= SquareMagnitude((pPoint2-pPoint1)*0.5f); -} */ -void TTraction::RenderDL(float mgn, Math3D::vector3 const &Origin ) // McZapkie: mgn to odleglosc od obserwatora -{ - // McZapkie: ustalanie przezroczystosci i koloru linii: - if( Wires != 0 && !TestFlag( DamageFlag, 128 ) ) // rysuj jesli sa druty i nie zerwana - { - // setup - GfxRenderer.Bind( 0 ); - if( !Global::bSmoothTraction ) { - // na liniach kiepsko wyglÄ…da - robi gradient - ::glDisable( GL_LINE_SMOOTH ); - } - float linealpha = 5000 * WireThickness / ( mgn + 1.0 ); //*WireThickness - linealpha = std::min( 1.2f, linealpha ); // zbyt grube nie sÄ… dobre - ::glLineWidth( linealpha ); - // McZapkie-261102: kolor zalezy od materialu i zasniedzenia - float - red{ 0.0f }, - green{ 0.0f }, - blue{ 0.0f }; - wire_color( red, green, blue ); - ::glColor4f( red, green, blue, linealpha ); - // draw code - if (!uiDisplayList) - Optimize( Origin ); // generowanie DL w miarÄ™ potrzeby - ::glCallList(uiDisplayList); - // cleanup - ::glLineWidth(1.0); - ::glEnable(GL_LINE_SMOOTH); - } -} + vertex_array vertices; -// przygotowanie tablic do skopiowania do VBO (zliczanie wierzchoÅ‚ków) -int TTraction::RaArrayPrepare() -{ - // jezdny - iLines = 2; - // przewod nosny - if( Wires > 1 ) { - iLines += 2 + ( - Wires < 4 ? - std::max( 0, iNumSections - 1 ) : - ( iNumSections > 2 ? - std::max( 0, iNumSections - 1 - 2 ) : - std::max( 0, iNumSections - 1 - 1 ) ) ); - } - // drugi przewod jezdny - if( Wires > 2 ) { - iLines += 2; - } - if( Wires == 4 ) { - iLines += 2 + std::max( 0, iNumSections - 1 ); - } - // przewody pionowe (wieszaki) - if( Wires > 1 ) { - iLines += 2 * ( std::max( 0, iNumSections - 1 ) ); - if( ( Wires == 4 ) - &&( iNumSections > 0 ) ) { - iLines += ( - iNumSections > 4 ? - 4 : - 2 ); - } - } - return iLines; -}; - -int TTraction::RaArrayFill(CVertNormTex *Vert, Math3D::vector3 const &Origin) -{ // wypeÅ‚nianie tablic VBO - int debugvertexcount{ 0 }; - - double ddp = std::hypot(pPoint2.x - pPoint1.x, pPoint2.z - pPoint1.z); - if (Wires == 2) + double ddp = std::hypot( pPoint2.x - pPoint1.x, pPoint2.z - pPoint1.z ); + if( Wires == 2 ) WireOffset = 0; // jezdny - Vert->x = pPoint1.x - ( pPoint2.z / ddp - pPoint1.z / ddp ) * WireOffset - Origin.x; - Vert->y = pPoint1.y - Origin.y; - Vert->z = pPoint1.z - ( -pPoint2.x / ddp + pPoint1.x / ddp ) * WireOffset - Origin.z; - ++Vert; - ++debugvertexcount; - Vert->x = pPoint2.x - ( pPoint2.z / ddp - pPoint1.z / ddp ) * WireOffset - Origin.x; - Vert->y = pPoint2.y - Origin.y; - Vert->z = pPoint2.z - ( -pPoint2.x / ddp + pPoint1.x / ddp ) * WireOffset - Origin.z; - ++Vert; - ++debugvertexcount; + basic_vertex startvertex, endvertex; + startvertex.position = + glm::vec3( + pPoint1.x - ( pPoint2.z / ddp - pPoint1.z / ddp ) * WireOffset - Origin.x, + pPoint1.y - Origin.y, + pPoint1.z - ( -pPoint2.x / ddp + pPoint1.x / ddp ) * WireOffset - Origin.z ); + endvertex.position = + glm::vec3( + pPoint2.x - ( pPoint2.z / ddp - pPoint1.z / ddp ) * WireOffset - Origin.x, + pPoint2.y - Origin.y, + pPoint2.z - ( -pPoint2.x / ddp + pPoint1.x / ddp ) * WireOffset - Origin.z ); + vertices.emplace_back( startvertex ); + vertices.emplace_back( endvertex ); // Nie wiem co 'Marcin Math3D::vector3 pt1, pt2, pt3, pt4, v1, v2; v1 = pPoint4 - pPoint3; @@ -370,201 +127,152 @@ int TTraction::RaArrayFill(CVertNormTex *Vert, Math3D::vector3 const &Origin) float mid = 0.5; float t; // Przewod nosny 'Marcin - if (Wires > 1) - { // lina noÅ›na w kawaÅ‚kach - Vert->x = pPoint3.x - Origin.x; - Vert->y = pPoint3.y - Origin.y; - Vert->z = pPoint3.z - Origin.z; - ++Vert; - ++debugvertexcount; - for (int i = 0; i < iNumSections - 1; ++i) - { + if( Wires > 1 ) { // lina noÅ›na w kawaÅ‚kach + startvertex.position = + glm::vec3( + pPoint3.x - Origin.x, + pPoint3.y - Origin.y, + pPoint3.z - Origin.z ); + for( int i = 0; i < iNumSections - 1; ++i ) { pt3 = pPoint3 + v1 * f; - t = (1 - std::fabs(f - mid) * 2); + t = ( 1 - std::fabs( f - mid ) * 2 ); if( ( Wires < 4 ) || ( ( i != 0 ) && ( i != iNumSections - 2 ) ) ) { - Vert->x = pt3.x - Origin.x; - Vert->y = pt3.y - std::sqrt( t ) * fHeightDifference - Origin.y; - Vert->z = pt3.z - Origin.z; - ++Vert; - ++debugvertexcount; + endvertex.position = + glm::vec3( + pt3.x - Origin.x, + pt3.y - std::sqrt( t ) * fHeightDifference - Origin.y, + pt3.z - Origin.z ); + vertices.emplace_back( startvertex ); + vertices.emplace_back( endvertex ); + startvertex = endvertex; } f += step; } - Vert->x = pPoint4.x - Origin.x; - Vert->y = pPoint4.y - Origin.y; - Vert->z = pPoint4.z - Origin.z; - ++Vert; - ++debugvertexcount; + endvertex.position = + glm::vec3( + pPoint4.x - Origin.x, + pPoint4.y - Origin.y, + pPoint4.z - Origin.z ); + vertices.emplace_back( startvertex ); + vertices.emplace_back( endvertex ); } // Drugi przewod jezdny 'Winger - if (Wires > 2) - { - Vert->x = pPoint1.x + (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset - Origin.x; - Vert->y = pPoint1.y - Origin.y; - Vert->z = pPoint1.z + (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset - Origin.z; - ++Vert; - ++debugvertexcount; - Vert->x = pPoint2.x + (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset - Origin.x; - Vert->y = pPoint2.y - Origin.y; - Vert->z = pPoint2.z + (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset - Origin.z; - ++Vert; - ++debugvertexcount; + if( Wires > 2 ) { + startvertex.position = + glm::vec3( + pPoint1.x + ( pPoint2.z / ddp - pPoint1.z / ddp ) * WireOffset - Origin.x, + pPoint1.y - Origin.y, + pPoint1.z + ( -pPoint2.x / ddp + pPoint1.x / ddp ) * WireOffset - Origin.z ); + endvertex.position = + glm::vec3( + pPoint2.x + ( pPoint2.z / ddp - pPoint1.z / ddp ) * WireOffset - Origin.x, + pPoint2.y - Origin.y, + pPoint2.z + ( -pPoint2.x / ddp + pPoint1.x / ddp ) * WireOffset - Origin.z ); + vertices.emplace_back( startvertex ); + vertices.emplace_back( endvertex ); } f = step; if( Wires == 4 ) { - Vert->x = pPoint3.x - Origin.x; - Vert->y = pPoint3.y - 0.65f * fHeightDifference - Origin.y; - Vert->z = pPoint3.z - Origin.z; - ++Vert; - ++debugvertexcount; + startvertex.position = + glm::vec3( + pPoint3.x - Origin.x, + pPoint3.y - 0.65f * fHeightDifference - Origin.y, + pPoint3.z - Origin.z ); for( int i = 0; i < iNumSections - 1; ++i ) { pt3 = pPoint3 + v1 * f; t = ( 1 - std::fabs( f - mid ) * 2 ); - Vert->x = pt3.x - Origin.x; - Vert->y = pt3.y - std::sqrt( t ) * fHeightDifference - ( - ( ( i == 0 ) - || ( i == iNumSections - 2 ) ) ? - 0.25f * fHeightDifference : - 0.05 ) - - Origin.y; - Vert->z = pt3.z - Origin.z; - ++Vert; - ++debugvertexcount; + endvertex.position = + glm::vec3( + pt3.x - Origin.x, + pt3.y - std::sqrt( t ) * fHeightDifference - ( + ( ( i == 0 ) + || ( i == iNumSections - 2 ) ) ? + 0.25f * fHeightDifference : + 0.05 ) + - Origin.y, + pt3.z - Origin.z ); + vertices.emplace_back( startvertex ); + vertices.emplace_back( endvertex ); + startvertex = endvertex; f += step; } - Vert->x = pPoint4.x - Origin.x; - Vert->y = pPoint4.y - 0.65f * fHeightDifference - Origin.y; - Vert->z = pPoint4.z - Origin.z; - ++Vert; - ++debugvertexcount; + endvertex.position = + glm::vec3( + pPoint4.x - Origin.x, + pPoint4.y - 0.65f * fHeightDifference - Origin.y, + pPoint4.z - Origin.z ); + vertices.emplace_back( startvertex ); + vertices.emplace_back( endvertex ); } f = step; // Przewody pionowe (wieszaki) 'Marcin, poprawki na 2 przewody jezdne 'Winger - if (Wires > 1) - { - for (int i = 0; i < iNumSections - 1; ++i) - { + if( Wires > 1 ) { + for( int i = 0; i < iNumSections - 1; ++i ) { float flo, flo1; flo = ( Wires == 4 ? 0.25f * fHeightDifference : 0 ); flo1 = ( Wires == 4 ? +0.05 : 0 ); pt3 = pPoint3 + v1 * f; pt4 = pPoint1 + v2 * f; - t = (1 - std::fabs(f - mid) * 2); + t = ( 1 - std::fabs( f - mid ) * 2 ); if( ( i % 2 ) == 0 ) { - Vert->x = pt3.x - Origin.x; - Vert->y = pt3.y - std::sqrt( t ) * fHeightDifference - ( ( i == 0 ) || ( i == iNumSections - 2 ) ? flo : flo1 ) - Origin.y; - Vert->z = pt3.z - Origin.z; - ++Vert; - ++debugvertexcount; - Vert->x = pt4.x - ( pPoint2.z / ddp - pPoint1.z / ddp ) * WireOffset - Origin.x; - Vert->y = pt4.y - Origin.y; - Vert->z = pt4.z - ( -pPoint2.x / ddp + pPoint1.x / ddp ) * WireOffset - Origin.z; - ++Vert; - ++debugvertexcount; + startvertex.position = + glm::vec3( + pt3.x - Origin.x, + pt3.y - std::sqrt( t ) * fHeightDifference - ( ( i == 0 ) || ( i == iNumSections - 2 ) ? flo : flo1 ) - Origin.y, + pt3.z - Origin.z ); + endvertex.position = + glm::vec3( + pt4.x - ( pPoint2.z / ddp - pPoint1.z / ddp ) * WireOffset - Origin.x, + pt4.y - Origin.y, + pt4.z - ( -pPoint2.x / ddp + pPoint1.x / ddp ) * WireOffset - Origin.z ); + vertices.emplace_back( startvertex ); + vertices.emplace_back( endvertex ); } else { - Vert->x = pt3.x - Origin.x; - Vert->y = pt3.y - std::sqrt( t ) * fHeightDifference - ( ( i == 0 ) || ( i == iNumSections - 2 ) ? flo : flo1 ) - Origin.y; - Vert->z = pt3.z - Origin.z; - ++Vert; - ++debugvertexcount; - Vert->x = pt4.x + ( pPoint2.z / ddp - pPoint1.z / ddp ) * WireOffset - Origin.x; - Vert->y = pt4.y - Origin.y; - Vert->z = pt4.z + ( -pPoint2.x / ddp + pPoint1.x / ddp ) * WireOffset - Origin.z; - ++Vert; - ++debugvertexcount; + startvertex.position = + glm::vec3( + pt3.x - Origin.x, + pt3.y - std::sqrt( t ) * fHeightDifference - ( ( i == 0 ) || ( i == iNumSections - 2 ) ? flo : flo1 ) - Origin.y, + pt3.z - Origin.z ); + endvertex.position = + glm::vec3( + pt4.x + ( pPoint2.z / ddp - pPoint1.z / ddp ) * WireOffset - Origin.x, + pt4.y - Origin.y, + pt4.z - ( -pPoint2.x / ddp + pPoint1.x / ddp ) * WireOffset - Origin.z ); + vertices.emplace_back( startvertex ); + vertices.emplace_back( endvertex ); } if( ( ( Wires == 4 ) && ( ( i == 1 ) || ( i == iNumSections - 3 ) ) ) ) { - Vert->x = pt3.x - Origin.x; - Vert->y = pt3.y - std::sqrt( t ) * fHeightDifference - 0.05 - Origin.y; - Vert->z = pt3.z - Origin.z; - ++Vert; - ++debugvertexcount; - Vert->x = pt3.x - Origin.x; - Vert->y = pt3.y - std::sqrt( t ) * fHeightDifference - Origin.y; - Vert->z = pt3.z - Origin.z; - ++Vert; - ++debugvertexcount; + startvertex.position = + glm::vec3( + pt3.x - Origin.x, + pt3.y - std::sqrt( t ) * fHeightDifference - 0.05 - Origin.y, + pt3.z - Origin.z ); + endvertex.position = + glm::vec3( + pt3.x - Origin.x, + pt3.y - std::sqrt( t ) * fHeightDifference - Origin.y, + pt3.z - Origin.z ); + vertices.emplace_back( startvertex ); + vertices.emplace_back( endvertex ); } f += step; } } - return debugvertexcount; -}; -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 - { - // setup - GfxRenderer.Bind(0); - if( !Global::bSmoothTraction ) { - // na liniach kiepsko wyglÄ…da - robi gradient - ::glDisable( GL_LINE_SMOOTH ); - } - float linealpha = 5000 * WireThickness / (mgn + 1.0); //*WireThickness - linealpha = std::min( 1.2f, linealpha ); // zbyt grube nie sÄ… dobre - ::glLineWidth(linealpha); - // McZapkie-261102: kolor zalezy od materialu i zasniedzenia - float - red{ 0.0f }, - green{ 0.0f }, - blue{ 0.0f }; - wire_color( red, green, blue ); - ::glColor4f(red, green, blue, linealpha); - // draw code - // jezdny - ::glDrawArrays( GL_LINE_STRIP, iPtr, 2 ); - iPtr += 2; - // przewod nosny - if( Wires > 1 ) { - auto const piececount = 2 + ( - Wires < 4 ? - std::max( 0 , iNumSections - 1 ) : - ( iNumSections > 2 ? - std::max( 0, iNumSections - 1 - 2 ) : - std::max( 0, iNumSections - 1 - 1 ) ) ); - ::glDrawArrays( GL_LINE_STRIP, iPtr, piececount ); - iPtr += piececount; - } - // drugi przewod jezdny - if( Wires > 2 ) { - ::glDrawArrays( GL_LINE_STRIP, iPtr, 2 ); - iPtr += 2; - } - if( Wires == 4 ) { - auto const piececount = 2 + std::max( 0, iNumSections - 1 ); - ::glDrawArrays( GL_LINE_STRIP, iPtr, piececount ); - iPtr += piececount; - } - // przewody pionowe (wieszaki) - if( Wires != 1 ) { - auto piececount = 2 * std::max( 0, iNumSections - 1 ); - if( ( Wires == 4 ) - && ( iNumSections > 0 ) ) { - piececount += ( - iNumSections > 4 ? - 4 : - 2 ); - } - if( piececount > 0 ) { - ::glDrawArrays( GL_LINES, iPtr, piececount ); - iPtr += piececount; - } - } - // cleanup - ::glLineWidth(1.0); - ::glEnable(GL_LINE_SMOOTH); - } -}; + auto const elementcount = vertices.size() / 2; + m_geometry = GfxRenderer.Insert( vertices, Bank, GL_LINES ); + + return elementcount; +} int TTraction::TestPoint(Math3D::vector3 *Point) { // sprawdzanie, czy przÄ™sÅ‚a można połączyć @@ -633,24 +341,10 @@ void TTraction::ResistanceCalc(int d, double r, TTractionPowerSource *ps) else ps = psPower[d ^ 1]; // zasilacz od przeciwnej strony niż idzie analiza d = iNext[d]; // kierunek -#ifdef EU07_USE_OLD_TRACTIONPOWER_CODE - if (DebugModeFlag) // tylko podczas testów - Material = 4; // pokazanie, że to przÄ™sÅ‚o ma podłączone zasilanie -#else PowerState = 4; -#endif while( ( t != nullptr ) && ( t->psPower[d] == nullptr ) ) // jeÅ›li jest jakiÅ› kolejny i nie ma ustalonego zasilacza { // ustawienie zasilacza i policzenie rezystancji zastÄ™pczej -#ifdef EU07_USE_OLD_TRACTIONPOWER_CODE - if (DebugModeFlag) // tylko podczas testów - if (t->Material != 4) // przÄ™sÅ‚a zasilajÄ…cego nie modyfikować - { - if (t->Material < 4) - t->Material = 4; // tymczasowo, aby zmieniÅ‚a kolor - t->Material |= d ? 2 : 1; // kolor zależny od strony, z której jest zasilanie - } -#else if( t->PowerState != 4 ) { // przÄ™sÅ‚a zasilajÄ…cego nie modyfikować if( t->psPowered != nullptr ) { @@ -662,7 +356,6 @@ void TTraction::ResistanceCalc(int d, double r, TTractionPowerSource *ps) t->PowerState |= d ? 2 : 1; } } -#endif t->psPower[d] = ps; // skopiowanie wskaźnika zasilacza od danej strony t->fResistance[d] = r; // wpisanie rezystancji w kierunku tego zasilacza r += t->fResistivity * Length3(t->vParametric); // doliczenie oporu kolejnego odcinka @@ -749,44 +442,45 @@ double TTraction::VoltageGet(double u, double i) return 0.0; // gdy nie podłączony wcale? }; -void -TTraction::wire_color( float &Red, float &Green, float &Blue ) const { +glm::vec3 +TTraction::wire_color() const { + glm::vec3 color; if( false == DebugModeFlag ) { switch( Material ) { // Ra: kolory podzieliÅ‚em przez 2, bo po zmianie ambient za jasne byÅ‚y // trzeba uwzglÄ™dnić kierunek Å›wiecenia SÅ‚oÅ„ca - tylko ze SÅ‚oÅ„cem widać kolor case 1: { if( TestFlag( DamageFlag, 1 ) ) { - Red = 0.00000f; - Green = 0.32549f; - Blue = 0.2882353f; // zielona miedź + color.r = 0.00000f; + color.g = 0.32549f; + color.b = 0.2882353f; // zielona miedź } else { - Red = 0.35098f; - Green = 0.22549f; - Blue = 0.1f; // czerwona miedź + color.r = 0.35098f; + color.g = 0.22549f; + color.b = 0.1f; // czerwona miedź } break; } case 2: { if( TestFlag( DamageFlag, 1 ) ) { - Red = 0.10f; - Green = 0.10f; - Blue = 0.10f; // czarne Al + color.r = 0.10f; + color.g = 0.10f; + color.b = 0.10f; // czarne Al } else { - Red = 0.25f; - Green = 0.25f; - Blue = 0.25f; // srebrne Al + color.r = 0.25f; + color.g = 0.25f; + color.b = 0.25f; // srebrne Al } break; } default: {break; } } // w zaleźnoÅ›ci od koloru swiatÅ‚a - Red *= Global::DayLight.ambient[ 0 ]; - Green *= Global::DayLight.ambient[ 1 ]; - Blue *= Global::DayLight.ambient[ 2 ]; + color.r *= Global::DayLight.ambient[ 0 ]; + color.g *= Global::DayLight.ambient[ 1 ]; + color.b *= Global::DayLight.ambient[ 2 ]; } else { // tymczasowo pokazanie zasilanych odcinków @@ -794,38 +488,39 @@ TTraction::wire_color( float &Red, float &Green, float &Blue ) const { case 1: { // czerwone z podłączonym zasilaniem 1 - Red = 1.0f; - Green = 0.0f; - Blue = 0.0f; + color.r = 1.0f; + color.g = 0.0f; + color.b = 0.0f; break; } case 2: { // zielone z podłączonym zasilaniem 2 - Red = 0.0f; - Green = 1.0f; - Blue = 0.0f; + color.r = 0.0f; + color.g = 1.0f; + color.b = 0.0f; break; } case 3: { //żółte z podłączonym zasilaniem z obu stron - Red = 1.0f; - Green = 1.0f; - Blue = 0.0f; + color.r = 1.0f; + color.g = 1.0f; + color.b = 0.0f; break; } case 4: { // niebieskie z podłączonym zasilaniem - Red = 0.5f; - Green = 0.5f; - Blue = 1.0f; + color.r = 0.5f; + color.g = 0.5f; + color.b = 1.0f; break; } default: { break; } } if( hvParallel ) { // jeÅ›li z bieżniÄ… wspólnÄ…, to dodatkowo przyciemniamy - Red *= 0.6f; - Green *= 0.6f; - Blue *= 0.6f; + color.r *= 0.6f; + color.g *= 0.6f; + color.b *= 0.6f; } } -} \ No newline at end of file + return color; +} diff --git a/Traction.h b/Traction.h index 62a635cb..80bd9607 100644 --- a/Traction.h +++ b/Traction.h @@ -11,65 +11,47 @@ http://mozilla.org/MPL/2.0/. #include #include "GL/glew.h" -#include "VBO.h" #include "dumb3d.h" +#include "openglgeometrybank.h" class TTractionPowerSource; class TTraction { // drut zasilajÄ…cy, dla wskaźników używać przedrostka "hv" - private: - // vector3 vUp,vFront,vLeft; - // matrix4x4 mMatrix; - // matryca do wyliczania pozycji drutu w zależnoÅ›ci od [X,Y,kÄ…t] w scenerii: - // - x: odlegÅ‚ość w bok (czy odbierak siÄ™ nie zsunÄ…Å‚) - // - y: przyjmuje wartość <0,1>, jeÅ›li pod drutem (wzdÅ‚uż) - // - z: wysokość bezwzglÄ™dna drutu w danym miejsu + friend class opengl_renderer; + public: // na razie - TTractionPowerSource *psPower[2]; // najbliższe zasilacze z obu kierunków - TTractionPowerSource *psPowered = nullptr; // ustawione tylko dla bezpoÅ›rednio zasilanego przÄ™sÅ‚a - TTraction *hvNext[2]; //łączenie drutów w sieć - int iNext[2]; // do którego koÅ„ca siÄ™ łączy - int iLast = 1; //że niby ostatni drut // ustawiony bit 0, jeÅ›li jest ostatnim drutem w sekcji; bit1 - przedostatni + TTractionPowerSource *psPower[ 2 ] { nullptr, nullptr }; // najbliższe zasilacze z obu kierunków + TTractionPowerSource *psPowered { nullptr }; // ustawione tylko dla bezpoÅ›rednio zasilanego przÄ™sÅ‚a + TTraction *hvNext[ 2 ] { nullptr, nullptr }; //łączenie drutów w sieć + int iNext[ 2 ] { 0, 0 }; // do którego koÅ„ca siÄ™ łączy + int iLast { 1 }; //że niby ostatni drut // ustawiony bit 0, jeÅ›li jest ostatnim drutem w sekcji; bit1 - przedostatni public: - GLuint uiDisplayList = 0; Math3D::vector3 pPoint1, pPoint2, pPoint3, pPoint4; Math3D::vector3 vParametric; // współczynniki równania parametrycznego odcinka - double fHeightDifference = 0.0; //,fMiddleHeight; - // int iCategory,iMaterial,iDamageFlag; - // float fU,fR,fMaxI,fWireThickness; - int iNumSections = 0; - int iLines = 0; // ilosc linii dla VBO - float NominalVoltage = 0.0; - float MaxCurrent = 0.0; - float fResistivity = 0.0; //[om/m], przeliczone z [om/km] - DWORD Material = 0; // 1: Cu, 2: Al - float WireThickness = 0.0; - DWORD DamageFlag = 0; // 1: zasniedziale, 128: zerwana - int Wires = 2; - float WireOffset = 0.0; + double fHeightDifference { 0.0 }; //,fMiddleHeight; + int iNumSections { 0 }; + float NominalVoltage { 0.0f }; + float MaxCurrent { 0.0f }; + float fResistivity { 0.0f }; //[om/m], przeliczone z [om/km] + DWORD Material { 0 }; // 1: Cu, 2: Al + float WireThickness { 0.0f }; + DWORD DamageFlag { 0 }; // 1: zasniedziale, 128: zerwana + int Wires { 2 }; + float WireOffset { 0.0f }; std::string asPowerSupplyName; // McZapkie: nazwa podstacji trakcyjnej - TTractionPowerSource *psSection = nullptr; // zasilacz (opcjonalnie może to być pulpit sterujÄ…cy EL2 w hali!) + TTractionPowerSource *psSection { nullptr }; // zasilacz (opcjonalnie może to być pulpit sterujÄ…cy EL2 w hali!) std::string asParallel; // nazwa przÄ™sÅ‚a, z którym może być bieżnia wspólna - TTraction *hvParallel = nullptr; // jednokierunkowa i zapÄ™tlona lista przÄ™seÅ‚ ewentualnej bieżni wspólnej - float fResistance[2]; // rezystancja zastÄ™pcza do punktu zasilania (0: przÄ™sÅ‚o zasilane, <0: do policzenia) - int iTries = 0; - int PowerState{ 0 }; // type of incoming power, if any + TTraction *hvParallel { nullptr }; // jednokierunkowa i zapÄ™tlona lista przÄ™seÅ‚ ewentualnej bieżni wspólnej + float fResistance[ 2 ] { -1.0f, -1.0f }; // rezystancja zastÄ™pcza do punktu zasilania (0: przÄ™sÅ‚o zasilane, <0: do policzenia) + int iTries { 0 }; + int PowerState { 0 }; // type of incoming power, if any + // visualization data + geometry_handle m_geometry; - void Optimize( Math3D::vector3 const &Origin ); - - TTraction(); - ~TTraction(); - - // virtual void InitCenter(vector3 Angles, vector3 pOrigin); - // virtual bool Hit(double x, double z, vector3 &hitPoint, vector3 &hitDirection) - // { return TNode::Hit(x,z,hitPoint,hitDirection); }; - // virtual bool Move(double dx, double dy, double dz) { return false; }; - // virtual void SelectedRender(); - void RenderDL(float mgn, Math3D::vector3 const &Origin ); - int RaArrayPrepare(); - int RaArrayFill( CVertNormTex *Vert, Math3D::vector3 const &Origin ); - void RenderVBO(float mgn, int iPtr); + // creates geometry data in specified geometry bank. returns: number of created elements, or NULL + // NOTE: deleting nodes doesn't currently release geometry data owned by the node. TODO: implement erasing individual geometry chunks and banks + std::size_t create_geometry( geometrybank_handle const &Bank, Math3D::vector3 const &Origin ); int TestPoint(Math3D::vector3 *Point); void Connect(int my, TTraction *with, int to); void Init(); @@ -78,6 +60,7 @@ class TTraction void PowerSet(TTractionPowerSource *ps); double VoltageGet(double u, double i); private: - void wire_color( float &Red, float &Green, float &Blue ) const; + glm::vec3 wire_color() const; }; + //--------------------------------------------------------------------------- diff --git a/VBO.cpp b/VBO.cpp index 6fdba7c0..a61e457a 100644 --- a/VBO.cpp +++ b/VBO.cpp @@ -12,6 +12,7 @@ http://mozilla.org/MPL/2.0/. #include "GL/glew.h" #include "usefull.h" #include "sn_utils.h" +#include "globals.h" //--------------------------------------------------------------------------- void CVertNormTex::deserialize(std::istream &s) @@ -49,9 +50,6 @@ CMesh::CMesh() #endif m_nVertexCount = -1; m_nVBOVertices = 0; // nie zarezerwowane - - // TODO: bind proper subtype based on the settings - m_geometry = std::make_shared(); }; CMesh::~CMesh() diff --git a/VBO.h b/VBO.h index 63a104fc..d0228bfc 100644 --- a/VBO.h +++ b/VBO.h @@ -50,5 +50,6 @@ class CMesh #endif unsigned int m_nVBOVertices; // numer VBO z wierzchoÅ‚kami - std::shared_ptr m_geometry; + geometrybank_handle m_geometrybank; + }; diff --git a/dumb3d.h b/dumb3d.h index 818306d9..3a666e4f 100644 --- a/dumb3d.h +++ b/dumb3d.h @@ -140,8 +140,8 @@ class matrix4x4 for (int x = 0; x < 4; ++x) (*this)(x)[y] = initArray[i++]; } - template - void OpenGL_Matrix(_Type const *initArray) + template + void OpenGL_Matrix(Type_ const *initArray) { int i = 0; for (int x = 0; x < 4; ++x) diff --git a/openglgeometrybank.cpp b/openglgeometrybank.cpp index ec25b023..a5fcb34f 100644 --- a/openglgeometrybank.cpp +++ b/openglgeometrybank.cpp @@ -11,6 +11,8 @@ http://mozilla.org/MPL/2.0/. #include "openglgeometrybank.h" #include "sn_utils.h" +#include "logs.h" +#include "globals.h" void basic_vertex::serialize( std::ostream &s ) { @@ -45,23 +47,27 @@ basic_vertex::deserialize( std::istream &s ) { // generic geometry bank class, allows storage, update and drawing of geometry chunks // creates a new geometry chunk of specified type from supplied vertex data. returns: handle to the chunk -geometrychunk_handle -geometry_bank::create( vertex_array &Vertices, int const Datatype ) { +geometry_handle +geometry_bank::create( vertex_array &Vertices, int const Type ) { - if( true == Vertices.empty() ) { return NULL; } + if( true == Vertices.empty() ) { return geometry_handle( 0, 0 ); } - m_chunks.emplace_back( Vertices, Datatype ); + m_chunks.emplace_back( Vertices, Type ); // NOTE: handle is effectively (index into chunk array + 1) this leaves value of 0 to serve as error/empty handle indication - return m_chunks.size(); + geometry_handle chunkhandle{ 0, m_chunks.size() }; + // template method + create_( chunkhandle ); + // all done + return chunkhandle; } // replaces data of specified chunk with the supplied vertex data, starting from specified offset bool -geometry_bank::replace( vertex_array &Vertices, geometrychunk_handle const Chunk, std::size_t const Offset ) { +geometry_bank::replace( vertex_array &Vertices, geometry_handle const &Geometry, std::size_t const Offset ) { - if( ( Chunk == 0 ) || ( Chunk > m_chunks.size() ) ) { return false; } + if( ( Geometry.chunk == 0 ) || ( Geometry.chunk > m_chunks.size() ) ) { return false; } - auto &chunk = m_chunks[ Chunk - 1 ]; + auto &chunk = geometry_bank::chunk( Geometry ); if( ( Offset == 0 ) && ( Vertices.size() == chunk.vertices.size() ) ) { @@ -75,61 +81,66 @@ geometry_bank::replace( vertex_array &Vertices, geometrychunk_handle const Chunk chunk.vertices.resize( Offset + Vertices.size(), basic_vertex() ); chunk.vertices.insert( std::end( chunk.vertices ), std::begin( Vertices ), std::end( Vertices ) ); } + // template method + replace_( Geometry ); + // all done return true; } -vertex_array & -geometry_bank::data( geometrychunk_handle const Chunk ) { +// adds supplied vertex data at the end of specified chunk +bool +geometry_bank::append( vertex_array &Vertices, geometry_handle const &Geometry ) { - return m_chunks.at( Chunk - 1 ).vertices; + if( ( Geometry.chunk == 0 ) || ( Geometry.chunk > m_chunks.size() ) ) { return false; } + + return replace( Vertices, Geometry, geometry_bank::chunk( Geometry ).vertices.size() ); +} + +// draws geometry stored in specified chunk +void +geometry_bank::draw( geometry_handle const &Geometry ) { + // template method + draw_( Geometry ); +} + +vertex_array const & +geometry_bank::vertices( geometry_handle const &Geometry ) const { + + return geometry_bank::chunk( Geometry ).vertices; } // opengl vbo-based variant of the geometry bank GLuint opengl_vbogeometrybank::m_activebuffer{ NULL }; // buffer bound currently on the opengl end, if any -// creates a new geometry chunk of specified type from supplied vertex data. returns: handle to the chunk -geometrychunk_handle -opengl_vbogeometrybank::create( vertex_array &Vertices, int const Datatype ) { - - auto const handle = geometry_bank::create( Vertices, Datatype ); - if( handle == NULL ) { - // if we didn't get anything, bail early - return handle; - } - // adding a chunk means we'll be (re)building the buffer, which will fill the chunk records, amongst other things - // so we don't need to initialize the values here +// create() subclass details +void +opengl_vbogeometrybank::create_( geometry_handle const &Geometry ) { + // adding a chunk means we'll be (re)building the buffer, which will fill the chunk records, amongst other things. + // thus we don't need to initialize the values here m_chunkrecords.emplace_back( chunk_record() ); // kiss the existing buffer goodbye, new overall data size means we'll be making a new one delete_buffer(); - - return handle; } -// replaces data of specified chunk with the supplied vertex data, starting from specified offset -bool -opengl_vbogeometrybank::replace( vertex_array &Vertices, geometrychunk_handle const Chunk, std::size_t const Offset ) { +// replace() subclass details +void +opengl_vbogeometrybank::replace_( geometry_handle const &Geometry ) { - auto const result = geometry_bank::replace( Vertices, Chunk, Offset ); - if( false == result ) { - // if nothing happened we can bail out early - return result; - } - auto &chunkrecord = m_chunkrecords[ Chunk - 1 ]; + auto &chunkrecord = m_chunkrecords[ Geometry.chunk - 1 ]; chunkrecord.is_good = false; // if the overall length of the chunk didn't change we can get away with reusing the old buffer... - if( m_chunks[ Chunk - 1 ].vertices.size() != chunkrecord.size ) { + if( geometry_bank::chunk( Geometry ).vertices.size() != chunkrecord.size ) { // ...but otherwise we'll need to allocate a new one // TBD: we could keep and reuse the old buffer also if the new chunk is smaller than the old one, // but it'd require some extra tracking and work to keep all chunks up to date; also wasting vram; may be not worth it? delete_buffer(); } - return result; } -// draws geometry stored in specified chunk +// draw() subclass details void -opengl_vbogeometrybank::draw( geometrychunk_handle const Chunk ) { +opengl_vbogeometrybank::draw_( geometry_handle const &Geometry ) { if( m_buffer == NULL ) { // if there's no buffer, we'll have to make one @@ -138,13 +149,13 @@ opengl_vbogeometrybank::draw( geometrychunk_handle const Chunk ) { if( true == m_chunks.empty() ) { return; } std::size_t datasize{ 0 }; - auto &chunkrecord = m_chunkrecords.begin(); - for( auto &chunk : m_chunks ) { - // fill all chunk records, based on the chunk data - chunkrecord->offset = datasize; - chunkrecord->size = chunk.vertices.size(); - datasize += chunkrecord->size; - ++chunkrecord; + auto chunkiterator = m_chunks.cbegin(); + for( auto &chunkrecord : m_chunkrecords ) { + // fill records for all chunks, based on the chunk data + chunkrecord.offset = datasize; + chunkrecord.size = chunkiterator->vertices.size(); + datasize += chunkrecord.size; + ++chunkiterator; } // the odds for all created chunks to get replaced with empty ones are quite low, but the possibility does exist if( datasize == 0 ) { return; } @@ -158,6 +169,12 @@ opengl_vbogeometrybank::draw( geometrychunk_handle const Chunk ) { datasize * sizeof( basic_vertex ), nullptr, GL_STATIC_DRAW ); + if( ::glGetError() == GL_OUT_OF_MEMORY ) { + // TBD: throw a bad_alloc? + ErrorLog( "openGL error: out of memory; failed to create a geometry buffer" ); + delete_buffer(); + return; + } m_buffercapacity = datasize; } // actual draw procedure starts here @@ -165,8 +182,8 @@ opengl_vbogeometrybank::draw( geometrychunk_handle const Chunk ) { if( m_activebuffer != m_buffer ) { bind_buffer(); } - auto &chunkrecord = m_chunkrecords[ Chunk - 1 ]; - auto const &chunk = m_chunks[ Chunk - 1 ]; + auto &chunkrecord = m_chunkrecords[ Geometry.chunk - 1 ]; + auto const &chunk = geometry_bank::chunk( Geometry ); if( false == chunkrecord.is_good ) { // we may potentially need to upload new buffer data before we can draw it ::glBufferSubData( @@ -216,3 +233,103 @@ opengl_vbogeometrybank::delete_buffer() { m_buffercapacity = 0; } } + +// opengl display list based variant of the geometry bank + +// create() subclass details +void +opengl_dlgeometrybank::create_( geometry_handle const &Geometry ) { + + m_chunkrecords.emplace_back( chunk_record() ); +} + +// replace() subclass details +void +opengl_dlgeometrybank::replace_( geometry_handle const &Geometry ) { + + delete_list( Geometry ); +} + +// draw() subclass details +void +opengl_dlgeometrybank::draw_( geometry_handle const &Geometry ) { + + auto &chunkrecord = m_chunkrecords[ Geometry.chunk - 1 ]; + if( chunkrecord.list == 0 ) { + // we don't have a list ready, so compile one + chunkrecord.list = ::glGenLists( 1 ); + auto const &chunk = geometry_bank::chunk( Geometry ); + ::glNewList( chunkrecord.list, GL_COMPILE ); + + ::glBegin( chunk.type ); + // TODO: add specification of chunk vertex attributes + for( auto const &vertex : chunk.vertices ) { + ::glNormal3fv( glm::value_ptr( vertex.normal ) ); + ::glTexCoord2fv( glm::value_ptr( vertex.texture ) ); + ::glVertex3fv( glm::value_ptr( vertex.position ) ); + } + ::glEnd(); + ::glEndList(); + } + // with the list done we can just play it + ::glCallList( chunkrecord.list ); +} + +void +opengl_dlgeometrybank::delete_list( geometry_handle const &Geometry ) { + // NOTE: given it's our own internal method we trust it to be called with valid parameters + auto &chunkrecord = m_chunkrecords[ Geometry.chunk - 1 ]; + ::glDeleteLists( chunkrecord.list, 1 ); + chunkrecord.list = 0; +} + +// geometry bank manager, holds collection of geometry banks + +// creates a new geometry bank. returns: handle to the bank or NULL +geometrybank_handle +geometrybank_manager::create_bank() { + + if( true == Global::bUseVBO ) { m_geometrybanks.emplace_back( std::make_shared() ); } + else { m_geometrybanks.emplace_back( std::make_shared() ); } + // NOTE: handle is effectively (index into chunk array + 1) this leaves value of 0 to serve as error/empty handle indication + return geometrybank_handle( m_geometrybanks.size(), 0 ); +} + +// creates a new geometry chunk of specified type from supplied vertex data, in specified bank. returns: handle to the chunk or NULL +geometry_handle +geometrybank_manager::create_chunk( vertex_array &Vertices, geometrybank_handle const &Geometry, int const Type ) { + + auto const newchunkhandle = bank( Geometry )->create( Vertices, Type ); + + if( newchunkhandle.chunk != 0 ) { return geometry_handle( Geometry.bank, newchunkhandle.chunk ); } + else { return geometry_handle( 0, 0 ); } +} + +// replaces data of specified chunk with the supplied vertex data, starting from specified offset +bool +geometrybank_manager::replace( vertex_array &Vertices, geometry_handle const &Geometry, std::size_t const Offset ) { + + return bank( Geometry )->replace( Vertices, Geometry, Offset ); +} + +// adds supplied vertex data at the end of specified chunk +bool +geometrybank_manager::append( vertex_array &Vertices, geometry_handle const &Geometry ) { + + return bank( Geometry )->append( Vertices, Geometry ); +} +// draws geometry stored in specified chunk +void +geometrybank_manager::draw( geometry_handle const &Geometry ) { + + if( Geometry == NULL ) { return; } + + return bank( Geometry )->draw( Geometry ); +} + +// provides direct access to vertex data of specfied chunk +vertex_array const & +geometrybank_manager::vertices( geometry_handle const &Geometry ) const { + + return bank( Geometry )->vertices( Geometry ); +} diff --git a/openglgeometrybank.h b/openglgeometrybank.h index 91969a29..a05a05ce 100644 --- a/openglgeometrybank.h +++ b/openglgeometrybank.h @@ -30,7 +30,23 @@ typedef std::vector vertex_array; // generic geometry bank class, allows storage, update and drawing of geometry chunks -typedef std::size_t geometrychunk_handle; +struct geometry_handle { +// constructors + geometry_handle() : + bank( 0 ), chunk( 0 ) + {} + geometry_handle( std::uint32_t const Bank, std::uint32_t const Chunk ) : + bank( Bank ), chunk( Chunk ) + {} +// methods + inline + operator std::uint32_t() const { + return bank << 12 | chunk; } +// members + std::uint32_t + bank : 20, // 1 mil banks + chunk : 12; // 4 k chunks per bank +}; class geometry_bank { @@ -41,27 +57,28 @@ public: // destructor: virtual - ~geometry_bank() { ; } + ~geometry_bank() {} // methods: // creates a new geometry chunk of specified type from supplied vertex data. returns: handle to the chunk or NULL - virtual - geometrychunk_handle - create( vertex_array &Vertices, int const Datatype ); + geometry_handle + create( vertex_array &Vertices, int const Type ); // replaces data of specified chunk with the supplied vertex data, starting from specified offset - virtual bool - replace( vertex_array &Vertices, geometrychunk_handle const Chunk, std::size_t const Offset = 0 ); + replace( vertex_array &Vertices, geometry_handle const &Geometry, std::size_t const Offset = 0 ); + // adds supplied vertex data at the end of specified chunk + bool + append( vertex_array &Vertices, geometry_handle const &Geometry ); // draws geometry stored in specified chunk - virtual void - draw( geometrychunk_handle const Chunk ) = 0; + draw( geometry_handle const &Geometry ); // draws geometry stored in supplied list of chunks - template + template void - draw( _Iterator First, _Iterator Last ) { while( First != Last ) { draw( *First ); ++First; } } - vertex_array & - data( geometrychunk_handle const Chunk ); + draw( Iterator_ First, Iterator_ Last ) { while( First != Last ) { draw( *First ); ++First; } } + // provides direct access to vertex data of specfied chunk + vertex_array const & + vertices( geometry_handle const &Geometry ) const; protected: // types: @@ -69,16 +86,34 @@ protected: int type; // kind of geometry used by the chunk vertex_array vertices; // geometry data - geometry_chunk( vertex_array &Vertices, int const Datatype ) : - vertices( Vertices ), type( Datatype ) + geometry_chunk( vertex_array &Vertices, int const Type ) : + vertices( Vertices ), type( Type ) {} }; typedef std::vector geometrychunk_sequence; +// methods + inline + geometry_chunk & + chunk( geometry_handle const Geometry ) { + return m_chunks[ Geometry.chunk - 1 ]; } + inline + geometry_chunk const & + chunk( geometry_handle const Geometry ) const { + return m_chunks[ Geometry.chunk - 1 ]; } + // members: geometrychunk_sequence m_chunks; +private: +// methods: + // create() subclass details + virtual void create_( geometry_handle const &Geometry ) = 0; + // replace() subclass details + virtual void replace_( geometry_handle const &Geometry ) = 0; + // draw() subclass details + virtual void draw_( geometry_handle const &Geometry ) = 0; }; // opengl vbo-based variant of the geometry bank @@ -87,15 +122,8 @@ class opengl_vbogeometrybank : public geometry_bank { public: // methods: - // creates a new geometry chunk of specified type from supplied vertex data. returns: handle to the chunk or NULL - geometrychunk_handle - create( vertex_array &Vertices, int const Datatype ); - // replaces data of specified chunk with the supplied vertex data, starting from specified offset - bool - replace( vertex_array &Vertices, geometrychunk_handle const Chunk, std::size_t const Offset = 0 ); - // draws geometry stored in specified chunk - void - draw( geometrychunk_handle const Chunk ); + ~opengl_vbogeometrybank() { + delete_buffer(); } private: // types: @@ -108,6 +136,15 @@ private: typedef std::vector chunkrecord_sequence; // methods: + // create() subclass details + void + create_( geometry_handle const &Geometry ); + // replace() subclass details + void + replace_( geometry_handle const &Geometry ); + // draw() subclass details + void + draw_( geometry_handle const &Geometry ); void bind_buffer(); void @@ -120,3 +157,90 @@ private: chunkrecord_sequence m_chunkrecords; // helper data for all stored geometry chunks, in matching order }; + +// opengl display list based variant of the geometry bank + +class opengl_dlgeometrybank : public geometry_bank { + +public: +// methods: + ~opengl_dlgeometrybank() { + for( auto &chunkrecord : m_chunkrecords ) { + ::glDeleteLists( chunkrecord.list, 1 ); } } + +private: +// types: + struct chunk_record { + GLuint list{ 0 }; // display list associated with the chunk + }; + + typedef std::vector chunkrecord_sequence; + +// methods: + // create() subclass details + void + create_( geometry_handle const &Geometry ); + // replace() subclass details + void + replace_( geometry_handle const &Geometry ); + // draw() subclass details + void + draw_( geometry_handle const &Geometry ); + void + delete_list( geometry_handle const &Geometry ); + +// members: + chunkrecord_sequence m_chunkrecords; // helper data for all stored geometry chunks, in matching order + +}; + +// geometry bank manager, holds collection of geometry banks + +typedef geometry_handle geometrybank_handle; + +class geometrybank_manager { + +public: +// methods: + // creates a new geometry bank. returns: handle to the bank or NULL + geometrybank_handle + create_bank(); + // creates a new geometry chunk of specified type from supplied vertex data, in specified bank. returns: handle to the chunk or NULL + geometry_handle + create_chunk( vertex_array &Vertices, geometrybank_handle const &Geometry, int const Type ); + // replaces data of specified chunk with the supplied vertex data, starting from specified offset + bool + replace( vertex_array &Vertices, geometry_handle const &Geometry, std::size_t const Offset = 0 ); + // adds supplied vertex data at the end of specified chunk + bool + append( vertex_array &Vertices, geometry_handle const &Geometry ); + // draws geometry stored in specified chunk + void + draw( geometry_handle const &Geometry ); + // provides direct access to vertex data of specfied chunk + vertex_array const & + vertices( geometry_handle const &Geometry ) const; + +private: +// types: + typedef std::deque< std::shared_ptr > geometrybank_sequence; + +// members: + geometrybank_sequence m_geometrybanks; + +// methods + inline + bool + valid( geometry_handle const &Geometry ) { + return ( ( Geometry.bank != 0 ) + && ( Geometry.bank <= m_geometrybanks.size() ) ); } + inline + geometrybank_sequence::value_type & + bank( geometry_handle const Geometry ) { + return m_geometrybanks[ Geometry.bank - 1 ]; } + inline + geometrybank_sequence::value_type const & + bank( geometry_handle const Geometry ) const { + return m_geometrybanks[ Geometry.bank - 1 ]; } + +}; \ No newline at end of file diff --git a/openglmatrixstack.h b/openglmatrixstack.h index 85561d0f..b57f545b 100644 --- a/openglmatrixstack.h +++ b/openglmatrixstack.h @@ -109,39 +109,39 @@ public: pop_matrix() { m_stacks[ m_mode ].pop_matrix(); } void load_identity() { m_stacks[ m_mode ].load_identity(); } - template + template void - rotate( _Type const Angle, _Type const X, _Type const Y, _Type const Z ) { + rotate( Type_ const Angle, Type_ const X, Type_ const Y, Type_ const Z ) { m_stacks[ m_mode ].rotate( static_cast(Angle) * 0.0174532925f, // deg2rad glm::vec3( static_cast(X), static_cast(Y), static_cast(Z) ) ); } - template + template void - translate( _Type const X, _Type const Y, _Type const Z ) { + translate( Type_ const X, Type_ const Y, Type_ const Z ) { m_stacks[ m_mode ].translate( glm::vec3( static_cast( X ), static_cast( Y ), static_cast( Z ) ) ); } - template + template void - multiply( _Type const *Matrix ) { + multiply( Type_ const *Matrix ) { m_stacks[ m_mode ].multiply( glm::make_mat4( Matrix ) ); } - template + template void - perspective( _Type const Fovy, _Type const Aspect, _Type const Znear, _Type const Zfar ) { + perspective( Type_ const Fovy, Type_ const Aspect, Type_ const Znear, Type_ const Zfar ) { m_stacks[ m_mode ].perspective( static_cast(Fovy) * 0.0174532925f, // deg2rad static_cast( Aspect ), static_cast( Znear ), static_cast( Zfar ) ); } - template + template void - look_at( _Type const Eyex, _Type const Eyey, _Type const Eyez, _Type const Centerx, _Type const Centery, _Type const Centerz, _Type const Upx, _Type const Upy, _Type const Upz ) { + look_at( Type_ const Eyex, Type_ const Eyey, Type_ const Eyez, Type_ const Centerx, Type_ const Centery, Type_ const Centerz, Type_ const Upx, Type_ const Upy, Type_ const Upz ) { m_stacks[ m_mode ].look_at( glm::vec3( static_cast( Eyex ), diff --git a/parser.h b/parser.h index b08d5a2b..90fdfc6d 100644 --- a/parser.h +++ b/parser.h @@ -32,9 +32,9 @@ class cParser //: public std::stringstream // destructor: virtual ~cParser(); // methods: - template + template cParser& - operator>>( _Type &Right ); + operator>>( Type_ &Right ); template <> cParser& operator>>( std::string &Right ); @@ -107,9 +107,9 @@ class cParser //: public std::stringstream std::deque tokens; }; -template +template cParser& -cParser::operator>>( _Type &Right ) { +cParser::operator>>( Type_ &Right ) { if( true == this->tokens.empty() ) { return *this; } diff --git a/renderer.cpp b/renderer.cpp index 177bbf89..95137e19 100644 --- a/renderer.cpp +++ b/renderer.cpp @@ -142,10 +142,7 @@ opengl_renderer::Render() { ::glLoadIdentity(); if( World.InitPerformed() ) { -/* - World.Camera.SetMatrix(); - m_camera.update_frustum(); -*/ + glm::dmat4 worldcamera; World.Camera.SetMatrix( worldcamera ); m_camera.update_frustum( OpenGLMatrices.data( GL_PROJECTION ), worldcamera ); @@ -182,15 +179,6 @@ opengl_renderer::Render( world_environment *Environment ) { ::glDisable( GL_DEPTH_TEST ); ::glDepthMask( GL_FALSE ); ::glPushMatrix(); -/* - ::glTranslatef( Global::pCameraPosition.x, Global::pCameraPosition.y, Global::pCameraPosition.z ); -*/ -/* - glm::mat4 worldcamera; - World.Camera.SetMatrix( worldcamera ); - glLoadIdentity(); - glMultMatrixf( glm::value_ptr( glm::mat4( glm::mat3( worldcamera ) ) ) ); -*/ // setup fog if( Global::fFogEnd > 0 ) { // fog setup @@ -300,6 +288,63 @@ opengl_renderer::Render( world_environment *Environment ) { return true; } +// geometry methods +// creates a new geometry bank. returns: handle to the bank or NULL +geometrybank_handle +opengl_renderer::Create_Bank() { + + return m_geometry.create_bank(); +} + +// creates a new geometry chunk of specified type from supplied vertex data, in specified bank. returns: handle to the chunk or NULL +geometry_handle +opengl_renderer::Insert( vertex_array &Vertices, geometrybank_handle const &Geometry, int const Type ) { + + return m_geometry.create_chunk( Vertices, Geometry, Type ); +} + +// replaces data of specified chunk with the supplied vertex data, starting from specified offset +bool +opengl_renderer::Replace( vertex_array &Vertices, geometry_handle const &Geometry, std::size_t const Offset ) { + + return m_geometry.replace( Vertices, Geometry, Offset ); +} + +// adds supplied vertex data at the end of specified chunk +bool +opengl_renderer::Append( vertex_array &Vertices, geometry_handle const &Geometry ) { + + return m_geometry.append( Vertices, Geometry ); +} + +// provides direct access to vertex data of specfied chunk +vertex_array const & +opengl_renderer::Vertices( geometry_handle const &Geometry ) const { + + return m_geometry.vertices( Geometry ); +} + +// texture methods +texture_handle +opengl_renderer::GetTextureId( std::string Filename, std::string const &Dir, int const Filter, bool const Loadnow ) { + + return m_textures.create( Filename, Dir, Filter, Loadnow ); +} + +void +opengl_renderer::Bind( texture_handle const Texture ) { + // temporary until we separate the renderer + m_textures.bind( Texture ); +} + +opengl_texture & +opengl_renderer::Texture( texture_handle const Texture ) { + + return m_textures.texture( Texture ); +} + + + bool opengl_renderer::Render( TGround *Ground ) { @@ -698,16 +743,7 @@ opengl_renderer::Render( TDynamicObject *Dynamic ) { double const squaredistance = SquareMagnitude( originoffset / Global::ZoomFactor ); Dynamic->ABuLittleUpdate( squaredistance ); // ustawianie zmiennych submodeli dla wspólnego modelu ::glPushMatrix(); -/* - if( Dynamic == Global::pUserDynamic ) { - //specjalne ustawienie, aby nie trzÄ™sÅ‚o - //tu trzeba by ustawić animacje na modelu zewnÄ™trznym - ::glLoadIdentity(); // zacząć od macierzy jedynkowej - Global::pCamera->SetCabMatrix( Dynamic->vPosition ); // specjalne ustawienie kamery - } - else - ::glTranslated( Dynamic->vPosition.x, Dynamic->vPosition.y, Dynamic->vPosition.z ); // standardowe przesuniÄ™cie wzglÄ™dem poczÄ…tku scenerii -*/ + ::glTranslated( originoffset.x, originoffset.y, originoffset.z ); ::glMultMatrixd( Dynamic->mMatrix.getArray() ); @@ -773,14 +809,7 @@ opengl_renderer::Render( TModel3d *Model, material_data const *Material, double Model->Root->fSquareDist = Squaredistance; // zmienna globalna! - // TODO: unify the render code after generic buffers are in place // setup -/* - if( Global::bUseVBO ) { - if( false == Model->StartVBO() ) - return false; - } -*/ Model->Root->ReplacableSet( ( Material != nullptr ? Material->replacable_skins : @@ -793,9 +822,6 @@ opengl_renderer::Render( TModel3d *Model, material_data const *Material, double Render( Model->Root ); // post-render cleanup - if( Global::bUseVBO ) { -// Model->EndVBO(); - } return true; } @@ -812,7 +838,6 @@ opengl_renderer::Render( TModel3d *Model, material_data const *Material, Math3D: if( Angle.z != 0.0 ) ::glRotated( Angle.z, 0.0, 0.0, 1.0 ); -// auto const result = Render( Model, Material, SquareMagnitude( Position / Global::ZoomFactor ) ); // position is effectively camera offset auto const result = Render( Model, Material, SquareMagnitude( Position ) ); // position is effectively camera offset ::glPopMatrix(); @@ -856,16 +881,8 @@ opengl_renderer::Render( TSubModel *Submodel ) { ::glMaterialfv( GL_FRONT, GL_EMISSION, Submodel->f4Diffuse ); } - // main draw call. TODO: generic buffer base class, specialized for vbo, dl etc - if( Global::bUseVBO ) { -/* - ::glDrawArrays( Submodel->eType, Submodel->iVboPtr, Submodel->iNumVerts ); -*/ - Submodel->pRoot->m_geometry->draw( Submodel->m_chunk ); - } - else { - ::glCallList( Submodel->uiDisplayList ); - } + // main draw call + m_geometry.draw( Submodel->m_geometry ); // post-draw reset if( Global::fLuminance < Submodel->fLight ) { @@ -900,16 +917,8 @@ opengl_renderer::Render( TSubModel *Submodel ) { ::glDisable( GL_LIGHTING ); ::glEnable( GL_BLEND ); - // main draw call. TODO: generic buffer base class, specialized for vbo, dl etc - if( Global::bUseVBO ) { -/* - ::glDrawArrays( GL_POINTS, Submodel->iVboPtr, Submodel->iNumVerts ); -*/ - Submodel->pRoot->m_geometry->draw( Submodel->m_chunk ); - } - else { - ::glCallList( Submodel->uiDisplayList ); - } + // main draw call + m_geometry.draw( Submodel->m_geometry ); // post-draw reset ::glPopAttrib(); @@ -926,9 +935,11 @@ opengl_renderer::Render( TSubModel *Submodel ) { Bind( 0 ); ::glDisable( GL_LIGHTING ); - // main draw call. TODO: generic buffer base class, specialized for vbo, dl etc - if( Global::bUseVBO ) { + // main draw call + // TODO: add support for colour data draw mode + m_geometry.draw( Submodel->m_geometry ); /* + if( Global::bUseVBO ) { // NOTE: we're doing manual switch to color vbo setup, because there doesn't seem to be any convenient way available atm // TODO: implement easier way to go about it ::glDisableClientState( GL_NORMAL_ARRAY ); @@ -941,12 +952,11 @@ opengl_renderer::Render( TSubModel *Submodel ) { ::glDisableClientState( GL_COLOR_ARRAY ); ::glEnableClientState( GL_NORMAL_ARRAY ); ::glEnableClientState( GL_TEXTURE_COORD_ARRAY ); -*/ } else { ::glCallList( Submodel->uiDisplayList ); } - +*/ // post-draw reset ::glPopAttrib(); } @@ -1094,18 +1104,39 @@ opengl_renderer::Render_Alpha( TGroundNode *Node ) { case TP_TRACTION: { // TODO: unify the render code after generic buffers are in place if( Node->bVisible ) { + // rysuj jesli sa druty i nie zerwana + if( ( Node->hvTraction->Wires == 0 ) + || ( true == TestFlag( Node->hvTraction->DamageFlag, 128 ) ) ) { + return false; + } // setup ::glPushMatrix(); auto const originoffset = Node->m_rootposition - Global::pCameraPosition; ::glTranslated( originoffset.x, originoffset.y, originoffset.z ); + + Bind( NULL ); + if( !Global::bSmoothTraction ) { + // na liniach kiepsko wyglÄ…da - robi gradient + ::glDisable( GL_LINE_SMOOTH ); + } + float const linealpha = static_cast( + std::min( + 1.2, + 5000 * Node->hvTraction->WireThickness / ( distancesquared + 1.0 ) ) ); // zbyt grube nie sÄ… dobre + ::glLineWidth( linealpha ); + // McZapkie-261102: kolor zalezy od materialu i zasniedzenia + auto const color { Node->hvTraction->wire_color() }; + ::glColor4f( color.r, color.g, color.b, linealpha ); + // render - if( Global::bUseVBO ) { - Node->hvTraction->RenderVBO( distancesquared, Node->iVboPtr ); - } - else { - Node->hvTraction->RenderDL( distancesquared, Node->m_rootposition ); - } + m_geometry.draw( Node->hvTraction->m_geometry ); + // post-render cleanup + ::glLineWidth( 1.0 ); + if( !Global::bSmoothTraction ) { + ::glEnable( GL_LINE_SMOOTH ); + } + ::glPopMatrix(); return true; } @@ -1233,14 +1264,7 @@ opengl_renderer::Render_Alpha( TDynamicObject *Dynamic ) { double const squaredistance = SquareMagnitude( originoffset / Global::ZoomFactor ); Dynamic->ABuLittleUpdate( squaredistance ); // ustawianie zmiennych submodeli dla wspólnego modelu ::glPushMatrix(); -/* - if( Dynamic == Global::pUserDynamic ) { // specjalne ustawienie, aby nie trzÄ™sÅ‚o - ::glLoadIdentity(); // zacząć od macierzy jedynkowej - Global::pCamera->SetCabMatrix( Dynamic->vPosition ); // specjalne ustawienie kamery - } - else - ::glTranslated( Dynamic->vPosition.x, Dynamic->vPosition.y, Dynamic->vPosition.z ); // standardowe przesuniÄ™cie wzglÄ™dem poczÄ…tku scenerii -*/ + ::glTranslated( originoffset.x, originoffset.y, originoffset.z ); ::glMultMatrixd( Dynamic->mMatrix.getArray() ); @@ -1305,18 +1329,11 @@ opengl_renderer::Render_Alpha( TModel3d *Model, material_data const *Material, d Model->Root->fSquareDist = Squaredistance; // zmienna globalna! - // TODO: unify the render code after generic buffers are in place // setup -/* - if( Global::bUseVBO ) { - if( false == Model->StartVBO() ) - return false; - } -*/ Model->Root->ReplacableSet( ( Material != nullptr ? - Material->replacable_skins : - nullptr ), + Material->replacable_skins : + nullptr ), alpha ); Model->Root->pRoot = Model; @@ -1325,11 +1342,7 @@ opengl_renderer::Render_Alpha( TModel3d *Model, material_data const *Material, d Render_Alpha( Model->Root ); // post-render cleanup -/* - if( Global::bUseVBO ) { - Model->EndVBO(); - } -*/ + return true; } @@ -1345,7 +1358,6 @@ opengl_renderer::Render_Alpha( TModel3d *Model, material_data const *Material, M if( Angle.z != 0.0 ) ::glRotated( Angle.z, 0.0, 0.0, 1.0 ); -// auto const result = Render_Alpha( Model, Material, SquareMagnitude( Position / Global::ZoomFactor ) ); // position is effectively camera offset auto const result = Render_Alpha( Model, Material, SquareMagnitude( Position ) ); // position is effectively camera offset ::glPopMatrix(); @@ -1387,16 +1399,8 @@ opengl_renderer::Render_Alpha( TSubModel *Submodel ) { ::glMaterialfv( GL_FRONT, GL_EMISSION, Submodel->f4Diffuse ); } - // main draw call. TODO: generic buffer base class, specialized for vbo, dl etc - if( Global::bUseVBO ) { -/* - ::glDrawArrays( Submodel->eType, Submodel->iVboPtr, Submodel->iNumVerts ); -*/ - Submodel->pRoot->m_geometry->draw( Submodel->m_chunk ); - } - else { - ::glCallList( Submodel->uiDisplayList ); - } + // main draw call + m_geometry.draw( Submodel->m_geometry ); // post-draw reset if( Global::fLuminance < Submodel->fLight ) { @@ -1554,7 +1558,7 @@ opengl_renderer::Update ( double const Deltatime ) { // TODO: add garbage collection and other less frequent works here if( DebugModeFlag ) - m_debuginfo = m_textures.Info(); + m_debuginfo = m_textures.info(); }; // debug performance string diff --git a/renderer.h b/renderer.h index 3cce3b05..19e31d55 100644 --- a/renderer.h +++ b/renderer.h @@ -10,6 +10,7 @@ http://mozilla.org/MPL/2.0/. #pragma once #include "GL/glew.h" +#include "openglgeometrybank.h" #include "texture.h" #include "lightarray.h" #include "dumb3d.h" @@ -120,71 +121,54 @@ public: // main draw call. returns false on error bool Render(); - bool - Render( world_environment *Environment ); - bool - Render( TGround *Ground ); - bool - Render( TGroundRect *Groundcell ); - bool - Render( TSubRect *Groundsubcell ); - bool - Render( TGroundNode *Node ); + // render sub-methods, temporarily exposed until we complete migrating render code to the renderer bool Render( TDynamicObject *Dynamic ); - bool - Render( TModel3d *Model, material_data const *Material, double const Squaredistance ); bool Render( TModel3d *Model, material_data const *Material, Math3D::vector3 const &Position, Math3D::vector3 const &Angle ); + bool + Render( TModel3d *Model, material_data const *Material, double const Squaredistance ); void Render( TSubModel *Submodel ); - void - Render( TMemCell *Memcell ); - bool - Render_Alpha( TGround *Ground ); - bool - Render_Alpha( TSubRect *Groundsubcell ); - bool - Render_Alpha( TGroundNode *Node ); bool Render_Alpha( TDynamicObject *Dynamic ); - bool - Render_Alpha( TModel3d *Model, material_data const *Material, double const Squaredistance ); bool Render_Alpha( TModel3d *Model, material_data const *Material, Math3D::vector3 const &Position, Math3D::vector3 const &Angle ); - void - Render_Alpha( TSubModel *Submodel ); + bool + Render_Alpha( TModel3d *Model, material_data const *Material, double const Squaredistance ); // maintenance jobs void - Update( double const Deltatime); - void - Update_Lights( light_array const &Lights ); - void - Disable_Lights(); - inline - bool - Visible( TDynamicObject const *Dynamic ) const { return m_camera.visible( Dynamic ); } + Update( double const Deltatime ); // debug performance string std::string const & Info() const; - - texture_manager::size_type - GetTextureId( std::string Filename, std::string const &Dir, int const Filter = -1, bool const Loadnow = true ) { - - return m_textures.GetTextureId( Filename, Dir, Filter, Loadnow ); - } - + // light methods void - Bind( texture_manager::size_type const Id ) { - // temporary until we separate the renderer - m_textures.Bind( Id ); - } - + Disable_Lights(); + // geometry methods + // NOTE: hands-on geometry management is exposed as a temporary measure; ultimately all visualization data should be generated/handled automatically by the renderer itself + // creates a new geometry bank. returns: handle to the bank or NULL + geometrybank_handle + Create_Bank(); + // creates a new geometry chunk of specified type from supplied vertex data, in specified bank. returns: handle to the chunk or NULL + geometry_handle + Insert( vertex_array &Vertices, geometrybank_handle const &Geometry, int const Type ); + // replaces data of specified chunk with the supplied vertex data, starting from specified offset + bool + Replace( vertex_array &Vertices, geometry_handle const &Geometry, std::size_t const Offset = 0 ); + // adds supplied vertex data at the end of specified chunk + bool + Append( vertex_array &Vertices, geometry_handle const &Geometry ); + // provides direct access to vertex data of specfied chunk + vertex_array const & + Vertices( geometry_handle const &Geometry ) const; + // texture methods + texture_handle + GetTextureId( std::string Filename, std::string const &Dir, int const Filter = -1, bool const Loadnow = true ); + void + Bind( texture_handle const Texture ); opengl_texture & - Texture( texture_manager::size_type const Id ) { - - return m_textures.Texture( Id ); - } + Texture( texture_handle const Texture ); // members GLenum static const sunlight{ GL_LIGHT0 }; @@ -200,20 +184,43 @@ private: // methods bool Init_caps(); - + bool + Render( world_environment *Environment ); + bool + Render( TGround *Ground ); + bool + Render( TGroundRect *Groundcell ); + bool + Render( TSubRect *Groundsubcell ); + bool + Render( TGroundNode *Node ); + void + Render( TMemCell *Memcell ); + bool + Render_Alpha( TGround *Ground ); + bool + Render_Alpha( TSubRect *Groundsubcell ); + bool + Render_Alpha( TGroundNode *Node ); + void + Render_Alpha( TSubModel *Submodel ); + void + Update_Lights( light_array const &Lights ); + // members - rendermode renderpass{ rendermode::color }; opengllight_array m_lights; + geometrybank_manager m_geometry; texture_manager m_textures; opengl_camera m_camera; + rendermode renderpass{ rendermode::color }; float m_drawrange{ 2500.0f }; // current drawing range float m_drawtime{ 1000.0f / 30.0f * 20.0f }; // start with presumed 'neutral' average of 30 fps double m_updateaccumulator{ 0.0 }; std::string m_debuginfo; GLFWwindow *m_window{ nullptr }; - texture_manager::size_type m_glaretextureid{ -1 }; - texture_manager::size_type m_suntextureid{ -1 }; - texture_manager::size_type m_moontextureid{ -1 }; + texture_handle m_glaretextureid{ -1 }; + texture_handle m_suntextureid{ -1 }; + texture_handle m_moontextureid{ -1 }; GLUquadricObj *m_quadric; // helper object for drawing debug mode scene elements }; diff --git a/uilayer.h b/uilayer.h index 8966ec8b..2fb8d30b 100644 --- a/uilayer.h +++ b/uilayer.h @@ -79,7 +79,7 @@ private: GLuint m_fontbase{ (GLuint)-1 }; // numer DL dla znaków w napisach float m_progress{ 0.0f }; // percentage of filled progres bar, to indicate lengthy operations. float m_subtaskprogress{ 0.0f }; // percentage of filled progres bar, to indicate lengthy operations. - texture_manager::size_type m_background; // path to texture used as the background. size depends on mAspect. + texture_handle m_background; // path to texture used as the background. size depends on mAspect. std::vector > m_panels; }; diff --git a/usefull.h b/usefull.h index a5c62578..e639caf4 100644 --- a/usefull.h +++ b/usefull.h @@ -24,32 +24,32 @@ http://mozilla.org/MPL/2.0/. #define MAKE_ID4(a,b,c,d) (((std::uint32_t)(d)<<24)|((std::uint32_t)(c)<<16)|((std::uint32_t)(b)<<8)|(std::uint32_t)(a)) -template -void SafeDelete( _Type &Pointer ) { +template +void SafeDelete( Type_ &Pointer ) { delete Pointer; Pointer = nullptr; } -template -void SafeDeleteArray( _Type &Pointer ) { +template +void SafeDeleteArray( Type_ &Pointer ) { delete[] Pointer; Pointer = nullptr; } -template -_Type -clamp( _Type const Value, _Type const Min, _Type const Max ) { +template +Type_ +clamp( Type_ const Value, Type_ const Min, Type_ const Max ) { - _Type value = Value; + Type_ value = Value; if( value < Min ) { value = Min; } if( value > Max ) { value = Max; } return value; } // keeps the provided value in specified range 0-Range, as if the range was circular buffer -template -_Type -clamp_circular( _Type Value, _Type const Range = static_cast<_Type>(360) ) { +template +Type_ +clamp_circular( Type_ Value, Type_ const Range = static_cast(360) ) { Value -= Range * (int)( Value / Range ); // clamp the range to 0-360 if( Value < 0.0 ) Value += Range; @@ -57,9 +57,9 @@ clamp_circular( _Type Value, _Type const Range = static_cast<_Type>(360) ) { return Value; } -template -_Type -interpolate( _Type const First, _Type const Second, float const Factor ) { +template +Type_ +interpolate( Type_ const First, Type_ const Second, float const Factor ) { return ( First * ( 1.0f - Factor ) ) + ( Second * Factor ); } From 22746bad21b43d736053ae08049da13f7a40f957 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Sat, 10 Jun 2017 22:51:51 +0200 Subject: [PATCH 5/9] partial replacement of math classes with glm --- AnimModel.cpp | 2 + AnimModel.h | 9 +- Ground.cpp | 795 +++++++++++++++++++++----------------------------- Ground.h | 93 +++--- Model3d.cpp | 97 +++--- Model3d.h | 17 +- Segment.cpp | 64 ++-- Track.cpp | 54 ++-- Traction.cpp | 16 +- Traction.h | 8 +- VBO.cpp | 6 +- VBO.h | 3 + dumb3d.h | 3 + renderer.cpp | 138 ++++----- stdafx.h | 3 + usefull.h | 9 +- 16 files changed, 603 insertions(+), 714 deletions(-) diff --git a/AnimModel.cpp b/AnimModel.cpp index 0e183997..95e45c41 100644 --- a/AnimModel.cpp +++ b/AnimModel.cpp @@ -631,11 +631,13 @@ TSubModel * TAnimModel::TerrainSquare(int n) { // pobieranie wskaźników do pierwszego submodelu return pModel ? pModel->TerrainSquare(n) : 0; }; +#ifdef EU07_USE_OLD_RENDERCODE void TAnimModel::TerrainRenderVBO(int n) { // renderowanie terenu z VBO if (pModel) pModel->TerrainRenderVBO(n); }; +#endif //--------------------------------------------------------------------------- void TAnimModel::Advanced() diff --git a/AnimModel.h b/AnimModel.h index 36fa9c48..17957f16 100644 --- a/AnimModel.h +++ b/AnimModel.h @@ -128,8 +128,11 @@ class TAnimAdvanced int SortByBone(); }; -class TAnimModel -{ // opakowanie modelu, okreÅ›lajÄ…ce stan egzemplarza +// opakowanie modelu, okreÅ›lajÄ…ce stan egzemplarza +class TAnimModel { + + friend class opengl_renderer; + private: TAnimContainer *pRoot; // pojemniki sterujÄ…ce, tylko dla aniomowanych submodeli TModel3d *pModel; @@ -173,7 +176,9 @@ class TAnimModel bool TerrainLoaded(); int TerrainCount(); TSubModel * TerrainSquare(int n); +#ifdef EU07_USE_OLD_RENDERCODE void TerrainRenderVBO(int n); +#endif void AnimationVND(void *pData, double a, double b, double c, double d); void LightSet(int n, float v); static void AnimUpdate(double dt); diff --git a/Ground.cpp b/Ground.cpp index 62054b1d..e65f414d 100644 --- a/Ground.cpp +++ b/Ground.cpp @@ -70,7 +70,9 @@ TGroundNode::TGroundNode() iType = GL_POINTS; Vertices = NULL; nNext = nNext2 = NULL; +/* pCenter = vector3(0, 0, 0); +*/ iCount = 0; // wierzchoÅ‚ków w trójkÄ…cie // iNumPts=0; //punktów w linii TextureID = 0; @@ -81,15 +83,15 @@ TGroundNode::TGroundNode() fSquareRadius = 10000 * 10000; fSquareMinRadius = 0; asName = ""; - // Color= TMaterialColor(1); - // fAngle=0; //obrót dla modelu fLineThickness=1.0; //mm dla linii +/* for (int i = 0; i < 3; i++) { Ambient[i] = Global::whiteLight[i] * 255; Diffuse[i] = Global::whiteLight[i] * 255; Specular[i] = Global::noLight[i] * 255; } +*/ nNext3 = NULL; // nie wyÅ›wietla innych iVboPtr = -1; // indeks w VBO sektora (-1: nie używa VBO) iVersion = 0; // wersja siatki @@ -155,66 +157,65 @@ void TGroundNode::Init(int n) Vertices = new TGroundVertex[iNumVerts]; } -TGroundNode::TGroundNode(TGroundNodeType t, int n) -{ // utworzenie obiektu - TGroundNode(); // domyÅ›lne ustawienia +TGroundNode::TGroundNode( TGroundNodeType t, int n ) : + TGroundNode() { + // utworzenie obiektu iNumVerts = n; - if (iNumVerts) - Vertices = new TGroundVertex[iNumVerts]; - iType = t; - switch (iType) - { // zależnie od typu - case TP_TRACK: - pTrack = new TTrack(this); - break; + if( iNumVerts ) { + Vertices = new TGroundVertex[ iNumVerts ]; + } + iType = t; + switch (iType) { + // zależnie od typu + case TP_TRACK: { + pTrack = new TTrack( this ); + break; + } + default: { + break; + } } -} - -void TGroundNode::InitCenter() -{ // obliczenie Å›rodka ciężkoÅ›ci obiektu - for (int i = 0; i < iNumVerts; i++) - pCenter += Vertices[i].Point; - pCenter /= iNumVerts; } void TGroundNode::InitNormals() { // obliczenie wektorów normalnych - vector3 v1, v2, v3, v4, v5, n1, n2, n3, n4; - int i; - float tu, tv; + glm::dvec3 v1, v2, v3, v4, v5; + glm::vec3 n1, n2, n3, n4; + glm::vec2 t1; + std::size_t i; switch (iType) { case GL_TRIANGLE_STRIP: - v1 = Vertices[0].Point - Vertices[1].Point; - v2 = Vertices[1].Point - Vertices[2].Point; - n1 = SafeNormalize(CrossProduct(v1, v2)); - if (Vertices[0].Normal == vector3(0, 0, 0)) - Vertices[0].Normal = n1; - v3 = Vertices[2].Point - Vertices[3].Point; - n2 = SafeNormalize(CrossProduct(v3, v2)); - if (Vertices[1].Normal == vector3(0, 0, 0)) - Vertices[1].Normal = (n1 + n2) * 0.5; + v1 = Vertices[0].position - Vertices[1].position; + v2 = Vertices[1].position - Vertices[2].position; + n1 = glm::normalize(glm::cross(v1, v2)); + if (Vertices[0].normal == glm::vec3()) + Vertices[0].normal = n1; + v3 = Vertices[2].position - Vertices[3].position; + n2 = glm::normalize(glm::cross(v3, v2)); + if (Vertices[1].normal == glm::vec3()) + Vertices[1].normal = (n1 + n2) * 0.5f; - for (i = 2; i < iNumVerts - 2; i += 2) + for ( i = 2; i < iNumVerts - 2; i += 2) { - v4 = Vertices[i - 1].Point - Vertices[i].Point; - v5 = Vertices[i].Point - Vertices[i + 1].Point; - n3 = SafeNormalize(CrossProduct(v3, v4)); - n4 = SafeNormalize(CrossProduct(v5, v4)); - if (Vertices[i].Normal == vector3(0, 0, 0)) - Vertices[i].Normal = (n1 + n2 + n3) / 3; - if (Vertices[i + 1].Normal == vector3(0, 0, 0)) - Vertices[i + 1].Normal = (n2 + n3 + n4) / 3; + v4 = Vertices[i - 1].position - Vertices[i].position; + v5 = Vertices[i].position - Vertices[i + 1].position; + n3 = glm::normalize(glm::cross(v3, v4)); + n4 = glm::normalize(glm::cross(v5, v4)); + if (Vertices[i].normal == glm::vec3()) + Vertices[i].normal = (n1 + n2 + n3) / 3.0f; + if (Vertices[i + 1].normal == glm::vec3()) + Vertices[i + 1].normal = (n2 + n3 + n4) / 3.0f; n1 = n3; n2 = n4; v3 = v5; } - if (Vertices[i].Normal == vector3(0, 0, 0)) - Vertices[i].Normal = (n1 + n2) / 2; + if (Vertices[i].normal == glm::vec3()) + Vertices[i].normal = (n1 + n2) / 2.0f; if (i + 1 < iNumVerts) { - if (Vertices[i + 1].Normal == vector3(0, 0, 0)) - Vertices[i + 1].Normal = n2; + if (Vertices[i + 1].normal == glm::vec3()) + Vertices[i + 1].normal = n2; } else WriteLog("odd number of vertices, normals may be wrong!"); @@ -226,36 +227,34 @@ void TGroundNode::InitNormals() case GL_TRIANGLES: for (i = 0; i < iNumVerts; i += 3) { - v1 = Vertices[i + 0].Point - Vertices[i + 1].Point; - v2 = Vertices[i + 1].Point - Vertices[i + 2].Point; - n1 = SafeNormalize(CrossProduct(v1, v2)); - if (Vertices[i + 0].Normal == vector3(0, 0, 0)) - Vertices[i + 0].Normal = (n1); - if (Vertices[i + 1].Normal == vector3(0, 0, 0)) - Vertices[i + 1].Normal = (n1); - if (Vertices[i + 2].Normal == vector3(0, 0, 0)) - Vertices[i + 2].Normal = (n1); - tu = floor(Vertices[i + 0].tu); - tv = floor(Vertices[i + 0].tv); - Vertices[i + 1].tv -= tv; - Vertices[i + 2].tv -= tv; - Vertices[i + 0].tv -= tv; - Vertices[i + 1].tu -= tu; - Vertices[i + 2].tu -= tu; - Vertices[i + 0].tu -= tu; + v1 = Vertices[i + 0].position - Vertices[i + 1].position; + v2 = Vertices[i + 1].position - Vertices[i + 2].position; + n1 = glm::normalize(glm::cross(v1, v2)); + if (Vertices[i + 0].normal == glm::vec3()) + Vertices[i + 0].normal = (n1); + if (Vertices[i + 1].normal == glm::vec3()) + Vertices[i + 1].normal = (n1); + if (Vertices[i + 2].normal == glm::vec3()) + Vertices[i + 2].normal = (n1); + t1 = glm::vec2( + std::floor( Vertices[ i + 0 ].texture.s ), + std::floor( Vertices[ i + 0 ].texture.t ) ); + Vertices[ i + 1 ].texture -= t1; + Vertices[ i + 2 ].texture -= t1; + Vertices[ i + 0 ].texture -= t1; } break; } } - +/* void TGroundNode::RaRenderVBO() { // renderowanie z domyslnego bufora VBO glColor3ub(Diffuse[0], Diffuse[1], Diffuse[2]); GfxRenderer.Bind( TextureID ); // Ustaw aktywnÄ… teksturÄ™ glDrawArrays(iType, iVboPtr, iNumVerts); // Narysuj naraz wszystkie trójkÄ…ty } - -void TGroundNode::Compile( Math3D::vector3 const &Origin, bool const Multiple ) +*/ +void TGroundNode::Compile( glm::dvec3 const &Origin, bool const Multiple ) { // tworzenie skompilowanej listy w wyÅ›wietlaniu DL if (false == Multiple) { // obsÅ‚uga pojedynczej listy @@ -272,33 +271,26 @@ void TGroundNode::Compile( Math3D::vector3 const &Origin, bool const Multiple ) { glBegin(iType); for (int i = 0; i < iNumPts; ++i) - glVertex3d( - Points[i].x - Origin.x, - Points[i].y - Origin.y, - Points[i].z - Origin.z ); + glVertex3dv( glm::value_ptr( Points[i] - Origin ) ); glEnd(); } else if (iType == GL_TRIANGLE_STRIP || iType == GL_TRIANGLE_FAN || iType == GL_TRIANGLES) { // jak nie linie, to trójkÄ…ty // TODO: eliminate these calls, they're duplicated by setup part in the unified render function #ifdef EU07_USE_OLD_RENDERCODE - glColor3ub(Diffuse[0], Diffuse[1], Diffuse[2]); + ::glColor3fv( glm::value_ptr( Diffuse ) ); GfxRenderer.Bind(TextureID); #endif glBegin(iType); for (int i = 0; i < iNumVerts; ++i) { - glNormal3dv(&Vertices[i].Normal.x); - glTexCoord2f( - Vertices[i].tu, - Vertices[i].tv); - glVertex3d( - Vertices[i].Point.x - Origin.x, - Vertices[i].Point.y - Origin.y, - Vertices[i].Point.z - Origin.z ); + glNormal3fv( glm::value_ptr( Vertices[ i ].normal ) ); + glTexCoord2fv( glm::value_ptr( Vertices[ i ].texture ) ); + glVertex3dv( glm::value_ptr( Vertices[ i ].position - Origin ) ); } glEnd(); } +/* else if (iType == TP_MESH) { // grupa ze wspólnÄ… teksturÄ… - wrzucanie do wspólnego Display List #ifdef EU07_USE_OLD_RENDERCODE @@ -318,6 +310,7 @@ void TGroundNode::Compile( Math3D::vector3 const &Origin, bool const Multiple ) n = n->nNext3; // nastÄ™pny z listy } } +*/ if (false == Multiple) if (Global::bManageNodes) glEndList(); @@ -378,9 +371,8 @@ void TSubRect::NodeAdd(TGroundNode *Node) // nRender - lista grup renderowanych z wÅ‚asnych VBO albo DL // nRenderAlpha - lista grup renderowanych z wÅ‚asnych VBO albo DL z przezroczystoÅ›ciÄ… // nRenderWires - lista grup renderowanych z wÅ‚asnych VBO albo DL - druty i linie - // nMeshed - obiekty do pogrupowania wg tekstur - Node->m_rootposition = Math3D::vector3( m_area.center.x, m_area.center.y, m_area.center.z ); + Node->m_rootposition = m_area.center; // since ground rectangle can be empty, we're doing lazy initialization of the geometry bank, when something may actually use it // NOTE: this method is called for both subcell and cell, but subcells get first created and passed the handle from their parent @@ -399,47 +391,21 @@ void TSubRect::NodeAdd(TGroundNode *Node) case TP_TRACK: // TODO: tory z cieniem (tunel, canyon) też dać bez łączenia? ++iTracks; // jeden tor wiÄ™cej Node->pTrack->RaOwnerSet(this); // do którego sektora ma zgÅ‚aszać animacjÄ™ -/* - if( ( true == Global::bUseVBO ) - || ( false == Node->pTrack->IsGroupable() ) ) { - // tory ruchome nie sÄ… grupowane przy Display Lists (wymagajÄ… odÅ›wieżania DL) - RaNodeAdd( Node ); - } - else - { // tory nieruchome mogÄ… być pogrupowane wg tekstury, przy VBO wszystkie - Node->TextureID = Node->pTrack->TextureGet(0); // pobranie tekstury do sortowania - GLuint t = Node->pTrack->TextureGet(1); - if (Node->TextureID) // jeżeli jest pierwsza - { - if (t && (Node->TextureID != t)) - { // jeÅ›li sÄ… dwie różne tekstury, dodajemy drugi obiekt dla danego toru - TGroundNode *n = new TGroundNode(); // BUG: source of a memory leak here - n->iType = TP_DUMMYTRACK; // obiekt renderujÄ…cy siatki dla tekstury - n->TextureID = t; - n->pTrack = Node->pTrack; // wskazuje na ten sam tor - n->pCenter = Node->pCenter; - n->fSquareRadius = Node->fSquareRadius; - n->fSquareMinRadius = Node->fSquareMinRadius; - n->iFlags = Node->iFlags; - n->nNext2 = nRootMesh; - nRootMesh = n; // podczepienie do listy, żeby usunąć na koÅ„cu - n->nNext3 = nMeshed; - nMeshed = n; - } - } - else - Node->TextureID = t; // jest tylko druga tekstura - if (Node->TextureID) - { - Node->nNext3 = nMeshed; - nMeshed = Node; - } // do podzielenia potem - } -*/ - // NOTE: track merge code temporarily disabled to simplify implementation of camera-centric rendering - // TODO: re-implement merge for both render paths down the road - RaNodeAdd( Node ); - + // NOTE: track merge/sort temporarily disabled to simplify unification of render code + // TODO: refactor sorting as universal part of drawing process in the renderer +#ifdef EU07_USE_OLD_RENDERCODE + if( Global::bUseVBO ) { + Node->nNext3 = nRenderRect; + nRenderRect = Node; + } // VBO: do nieprzezroczystych z sektora + else { + Node->nNext3 = nRender; + nRender = Node; + } // DL: do nieprzezroczystych +#else + Node->nNext3 = nRenderRect; + nRenderRect = Node; +#endif break; case GL_TRIANGLE_STRIP: case GL_TRIANGLE_FAN: @@ -492,8 +458,6 @@ void TSubRect::NodeAdd(TGroundNode *Node) Node->nNext3 = nRenderMixed; nRenderMixed = Node; } // do mieszanych - // Node->nNext3=nMeshed; //dopisanie do listy sortowania - // nMeshed=Node; break; #ifdef EU07_SCENERY_EDITOR case TP_MEMCELL: { @@ -512,156 +476,21 @@ void TSubRect::NodeAdd(TGroundNode *Node) ++iNodeCount; // licznik obiektów } -void TSubRect::RaNodeAdd(TGroundNode *Node) -{ // finalna kwalifikacja na listy renderowania, jeÅ›li nie obsÅ‚ugiwane grupowo - switch (Node->iType) - { - case TP_TRACK: -#ifdef EU07_USE_OLD_RENDERCODE - if (Global::bUseVBO) - { - Node->nNext3 = nRenderRect; - nRenderRect = Node; - } // VBO: do nieprzezroczystych z sektora - else - { - Node->nNext3 = nRender; - nRender = Node; - } // DL: do nieprzezroczystych -#else - Node->nNext3 = nRenderRect; - nRenderRect = Node; -#endif - break; - case GL_TRIANGLE_STRIP: - case GL_TRIANGLE_FAN: - case GL_TRIANGLES: - if (Node->iFlags & 0x20) // czy jest przezroczyste? - { - Node->nNext3 = nRenderRectAlpha; - nRenderRectAlpha = Node; - } // DL: do przezroczystych z sektora -#ifdef EU07_USE_OLD_RENDERCODE - else if (Global::bUseVBO) - { - Node->nNext3 = nRenderRect; - nRenderRect = Node; - } // VBO: do nieprzezroczystych z sektora - else - { - Node->nNext3 = nRender; - nRender = Node; - } // DL: do nieprzezroczystych wszelakich -#else - else { - Node->nNext3 = nRenderRect; - nRenderRect = Node; - } // do nieprzezroczystych z sektora -#endif - break; - case TP_MODEL: // modele zawsze wyÅ›wietlane z wÅ‚asnego VBO - if ((Node->iFlags & 0x20200020) == 0) // czy brak przezroczystoÅ›ci? - { - Node->nNext3 = nRender; - nRender = Node; - } // do nieprzezroczystych - else if ((Node->iFlags & 0x10100010) == 0) // czy brak nieprzezroczystoÅ›ci? - { - Node->nNext3 = nRenderAlpha; - nRenderAlpha = Node; - } // do przezroczystych - else // jak i take i takie, to bÄ™dzie dwa razy renderowane... - { - Node->nNext3 = nRenderMixed; - nRenderMixed = Node; - } // do mieszanych - break; - case TP_MESH: // grupa ze wspólnÄ… teksturÄ… - //{Node->nNext3=nRenderRect; nRenderRect=Node;} //do nieprzezroczystych z sektora - { - Node->nNext3 = nRender; - nRender = Node; - } // do nieprzezroczystych - break; - case TP_SUBMODEL: // submodele terenu w kwadracie kilometrowym idÄ… do nRootMesh - // WriteLog("nRootMesh was "+AnsiString(nRootMesh?"not null ":"null - // ")+IntToHex(int(this),8)); - Node->nNext3 = nRootMesh; // przy VBO musi być inaczej - nRootMesh = Node; - break; - } -} +// przygotowanie sektora do renderowania +void TSubRect::Sort() { -void TSubRect::Sort() -{ // przygotowanie sektora do renderowania - TGroundNode **n0, *n1, *n2; // wskaźniki robocze - delete[] tTracks; // usuniÄ™cie listy - tTracks = - iTracks ? new TTrack *[iTracks] : NULL; // tworzenie tabeli torów do renderowania pojazdów - if (tTracks) - { // wypeÅ‚nianie tabeli torów + assert( tTracks == nullptr ); + if( iTracks > 0 ) { + tTracks = new TTrack *[ iTracks ]; // tworzenie tabeli torów do renderowania pojazdów int i = 0; - for (n1 = nRootNode; n1; n1 = n1->nNext2) // kolejne obiekty z sektora - if (n1->iType == TP_TRACK) - tTracks[i++] = n1->pTrack; - } - // sortowanie obiektów w sektorze na listy renderowania - if (!nMeshed) - return; // nie ma nic do sortowania - bool sorted = false; - while (!sorted) - { // sortowanie bÄ…belkowe obiektów wg tekstury - sorted = true; // zakÅ‚adamy posortowanie - n0 = &nMeshed; // wskaźnik niezbÄ™dny do zamieniania obiektów - n1 = nMeshed; // lista obiektów przetwarzanych na statyczne siatki - while (n1) - { // sprawdzanie stanu posortowania obiektów i ewentualne zamiany - n2 = n1->nNext3; // kolejny z tej listy - if (n2) // jeÅ›li istnieje - if (n1->TextureID > n2->TextureID) - { // zamiana elementów miejscami - *n0 = n2; // drugi bÄ™dzie na poczÄ…tku - n1->nNext3 = n2->nNext3; // ten zza drugiego bÄ™dzie za pierwszym - n2->nNext3 = n1; // a za drugim bÄ™dzie pierwszy - sorted = false; // potrzebny kolejny przebieg - } - n0 = &(n1->nNext3); - n1 = n2; - }; - } - // wyrzucenie z listy obiektów pojedynczych (nie ma z czym ich grupować) - // nawet jak sÄ… pojedyncze, to i tak lepiej, aby byÅ‚y w jednym Display List - /* - else - {//dodanie do zwykÅ‚ej listy renderowania i usuniÄ™cie z grupowego - *n0=n2; //drugi bÄ™dzie na poczÄ…tku - RaNodeAdd(n1); //nie ma go z czym zgrupować; (n1->nNext3) zostanie nadpisane - n1=n2; //potrzebne do ustawienia (n0) + for( TGroundNode *node = nRootNode; node != nullptr; node = node->nNext2 ) { + // kolejne obiekty z sektora + if( node->iType == TP_TRACK ) { + tTracks[ i++ ] = node->pTrack; + } } - */ - //... - // przeglÄ…danie listy i tworzenie obiektów renderujÄ…cych dla danej tekstury - int t = 0; // pomocniczy kod tekstury - n1 = nMeshed; // lista obiektów przetwarzanych na statyczne siatki - while (n1) - { // dla każdej tekstury powinny istnieć co najmniej dwa obiekty, ale dla DL nie ma to znaczenia - if (t < n1->TextureID) // jeÅ›li (n1) ma innÄ… teksturÄ™ niż poprzednie - { // można zrobić obiekt renderujÄ…cy - t = n1->TextureID; - n2 = new TGroundNode(); // BUG: source of a memory leak here - n2->nNext2 = nRootMesh; - nRootMesh = n2; // podczepienie na poczÄ…tku listy - nRootMesh->iType = TP_MESH; // obiekt renderujÄ…cy siatki dla tekstury - nRootMesh->TextureID = t; - nRootMesh->nNode = n1; // pierwszy element z listy - nRootMesh->pCenter = n1->pCenter; - nRootMesh->fSquareRadius = 1e8; // widać bez ograniczeÅ„ - nRootMesh->fSquareMinRadius = 0.0; - nRootMesh->iFlags = 0x10; - RaNodeAdd(nRootMesh); // dodanie do odpowiedniej listy renderowania - } - n1 = n1->nNext3; // kolejny z tej listy - }; + } + // NOTE: actual sort procedure temporarily removed as part of render code unification } TTrack * TSubRect::FindTrack(vector3 *Point, int &iConnection, TTrack *Exclude) @@ -704,7 +533,7 @@ void TSubRect::RaAnimate() } // crude way to mark whether a vbo is bound, for the vbo render path // TODO: sort this shit out and re-arrange into something more elegant... eventually - GLuint vertexbuffer{ static_cast(-1) }; + GLuint vertexbuffer { static_cast(-1) }; if (Global::bUseVBO) { // odÅ›wieżenie VBO sektora if( GLEW_VERSION_1_5 ) { @@ -720,7 +549,7 @@ void TSubRect::RaAnimate() tTrackAnim = tTrackAnim->RaAnimate( vertexbuffer ); // przeliczenie animacji kolejnego }; -TTraction * TSubRect::FindTraction(vector3 *Point, int &iConnection, TTraction *Exclude) +TTraction * TSubRect::FindTraction(glm::dvec3 const &Point, int &iConnection, TTraction *Exclude) { // szukanie przÄ™sÅ‚a w sektorze, którego koniec jest najbliższy (*Point) TGroundNode *Current; for (Current = nRenderWires; Current; Current = Current->nNext3) @@ -772,7 +601,9 @@ void TSubRect::LoadNodes() return; // jeÅ›li nie ma obiektów do wyÅ›wietlenia z VBO, to koniec if (Global::bUseVBO) { // tylko liczenie wierzchołów, gdy nie ma VBO + MakeArray(m_nVertexCount); + n = nRootNode; int i; while (n) @@ -785,14 +616,23 @@ void TSubRect::LoadNodes() case GL_TRIANGLES: for (i = 0; i < n->iNumVerts; ++i) { // Ra: trójkÄ…ty można od razu wczytywać do takich tablic... to może poczekać - m_pVNT[n->iVboPtr + i].x = n->Vertices[i].Point.x - n->m_rootposition.x; - m_pVNT[n->iVboPtr + i].y = n->Vertices[i].Point.y - n->m_rootposition.y; - m_pVNT[n->iVboPtr + i].z = n->Vertices[i].Point.z - n->m_rootposition.z; - m_pVNT[n->iVboPtr + i].nx = n->Vertices[i].Normal.x; - m_pVNT[n->iVboPtr + i].ny = n->Vertices[i].Normal.y; - m_pVNT[n->iVboPtr + i].nz = n->Vertices[i].Normal.z; + m_pVNT[ n->iVboPtr + i ].position = n->Vertices[ i ].position - n->m_rootposition; +/* + m_pVNT[n->iVboPtr + i].x = n->Vertices[i].position.x - n->m_rootposition.x; + m_pVNT[n->iVboPtr + i].y = n->Vertices[i].position.y - n->m_rootposition.y; + m_pVNT[n->iVboPtr + i].z = n->Vertices[i].position.z - n->m_rootposition.z; +*/ + m_pVNT[ n->iVboPtr + i ].normal = n->Vertices[ i ].normal; +/* + m_pVNT[n->iVboPtr + i].nx = n->Vertices[i].normal.x; + m_pVNT[n->iVboPtr + i].ny = n->Vertices[i].normal.y; + m_pVNT[n->iVboPtr + i].nz = n->Vertices[i].normal.z; +*/ + m_pVNT[ n->iVboPtr + i ].texture = n->Vertices[ i ].texture; +/* m_pVNT[n->iVboPtr + i].u = n->Vertices[i].tu; m_pVNT[n->iVboPtr + i].v = n->Vertices[i].tv; +*/ } break; case GL_LINES: @@ -800,9 +640,13 @@ void TSubRect::LoadNodes() case GL_LINE_LOOP: for (i = 0; i < n->iNumPts; ++i) { - m_pVNT[n->iVboPtr + i].x = n->Points[i].x - n->m_rootposition.x; - m_pVNT[n->iVboPtr + i].y = n->Points[i].y - n->m_rootposition.y; - m_pVNT[n->iVboPtr + i].z = n->Points[i].z - n->m_rootposition.z; + m_pVNT[ n->iVboPtr + i ].position = ( n->Points[ i ] - n->m_rootposition ); +/* + glm::vec3( + n->Points[ i ].x - n->m_rootposition.x, + n->Points[ i ].y - n->m_rootposition.y, + n->Points[ i ].z - n->m_rootposition.z ); +*/ // miejsce w tablicach normalnych i teksturowania siÄ™ marnuje... } break; @@ -880,8 +724,6 @@ TGroundRect::Init() { //--------------------------------------------------------------------------- -std::vector TempVerts; - BYTE TempConnectionType[ 200 ]; // Ra: sprzêgi w sk³adzie; ujemne, gdy odwrotnie TGround::TGround() @@ -896,7 +738,7 @@ TGround::TGround() // set bounding area information for ground rectangles float const rectsize = 1000.0f; - glm::vec3 const worldcenter( 0.0f, 0.0f, 0.0f ); + glm::vec3 const worldcenter; for( int column = 0; column < iNumRects; ++column ) { for( int row = 0; row < iNumRects; ++row ) { auto &area = Rects[ column ][ row ].m_area; @@ -1038,12 +880,12 @@ void TGround::RaTriangleDivider(TGroundNode *node) double x1 = x0 + 1400.0; double z0 = 1000.0 * floor(0.001 * node->pCenter.z) - 200.0; double z1 = z0 + 1400.0; - if ((node->Vertices[0].Point.x >= x0) && (node->Vertices[0].Point.x <= x1) && - (node->Vertices[0].Point.z >= z0) && (node->Vertices[0].Point.z <= z1) && - (node->Vertices[1].Point.x >= x0) && (node->Vertices[1].Point.x <= x1) && - (node->Vertices[1].Point.z >= z0) && (node->Vertices[1].Point.z <= z1) && - (node->Vertices[2].Point.x >= x0) && (node->Vertices[2].Point.x <= x1) && - (node->Vertices[2].Point.z >= z0) && (node->Vertices[2].Point.z <= z1)) + if ((node->Vertices[0].position.x >= x0) && (node->Vertices[0].position.x <= x1) && + (node->Vertices[0].position.z >= z0) && (node->Vertices[0].position.z <= z1) && + (node->Vertices[1].position.x >= x0) && (node->Vertices[1].position.x <= x1) && + (node->Vertices[1].position.z >= z0) && (node->Vertices[1].position.z <= z1) && + (node->Vertices[2].position.x >= x0) && (node->Vertices[2].position.x <= x1) && + (node->Vertices[2].position.z >= z0) && (node->Vertices[2].position.z <= z1)) return; // trójkÄ…t wystajÄ…cy mniej niż 200m z kw. kilometrowego jest do przyjÄ™cia // Ra: przerobić na dzielenie na 2 trójkÄ…ty, podziaÅ‚ w przeciÄ™ciu z siatkÄ… kilometrowÄ… // Ra: i z rekurencjÄ… bÄ™dzie dzielić trzy trójkÄ…ty, jeÅ›li bÄ™dzie taka potrzeba @@ -1053,40 +895,40 @@ void TGround::RaTriangleDivider(TGroundNode *node) x1 -= 200.0; // przestawienie na siatkÄ™ z0 += 200.0; z1 -= 200.0; - mul = (node->Vertices[0].Point.x - x0) * (node->Vertices[1].Point.x - x0); // AB na wschodzie + mul = (node->Vertices[0].position.x - x0) * (node->Vertices[1].position.x - x0); // AB na wschodzie if (mul < min) min = mul, divide = 0; - mul = (node->Vertices[1].Point.x - x0) * (node->Vertices[2].Point.x - x0); // BC na wschodzie + mul = (node->Vertices[1].position.x - x0) * (node->Vertices[2].position.x - x0); // BC na wschodzie if (mul < min) min = mul, divide = 1; - mul = (node->Vertices[2].Point.x - x0) * (node->Vertices[0].Point.x - x0); // CA na wschodzie + mul = (node->Vertices[2].position.x - x0) * (node->Vertices[0].position.x - x0); // CA na wschodzie if (mul < min) min = mul, divide = 2; - mul = (node->Vertices[0].Point.x - x1) * (node->Vertices[1].Point.x - x1); // AB na zachodzie + mul = (node->Vertices[0].position.x - x1) * (node->Vertices[1].position.x - x1); // AB na zachodzie if (mul < min) min = mul, divide = 8; - mul = (node->Vertices[1].Point.x - x1) * (node->Vertices[2].Point.x - x1); // BC na zachodzie + mul = (node->Vertices[1].position.x - x1) * (node->Vertices[2].position.x - x1); // BC na zachodzie if (mul < min) min = mul, divide = 9; - mul = (node->Vertices[2].Point.x - x1) * (node->Vertices[0].Point.x - x1); // CA na zachodzie + mul = (node->Vertices[2].position.x - x1) * (node->Vertices[0].position.x - x1); // CA na zachodzie if (mul < min) min = mul, divide = 10; - mul = (node->Vertices[0].Point.z - z0) * (node->Vertices[1].Point.z - z0); // AB na poÅ‚udniu + mul = (node->Vertices[0].position.z - z0) * (node->Vertices[1].position.z - z0); // AB na poÅ‚udniu if (mul < min) min = mul, divide = 4; - mul = (node->Vertices[1].Point.z - z0) * (node->Vertices[2].Point.z - z0); // BC na poÅ‚udniu + mul = (node->Vertices[1].position.z - z0) * (node->Vertices[2].position.z - z0); // BC na poÅ‚udniu if (mul < min) min = mul, divide = 5; - mul = (node->Vertices[2].Point.z - z0) * (node->Vertices[0].Point.z - z0); // CA na poÅ‚udniu + mul = (node->Vertices[2].position.z - z0) * (node->Vertices[0].position.z - z0); // CA na poÅ‚udniu if (mul < min) min = mul, divide = 6; - mul = (node->Vertices[0].Point.z - z1) * (node->Vertices[1].Point.z - z1); // AB na północy + mul = (node->Vertices[0].position.z - z1) * (node->Vertices[1].position.z - z1); // AB na północy if (mul < min) min = mul, divide = 12; - mul = (node->Vertices[1].Point.z - z1) * (node->Vertices[2].Point.z - z1); // BC na północy + mul = (node->Vertices[1].position.z - z1) * (node->Vertices[2].position.z - z1); // BC na północy if (mul < min) min = mul, divide = 13; - mul = (node->Vertices[2].Point.z - z1) * (node->Vertices[0].Point.z - z1); // CA na północy + mul = (node->Vertices[2].position.z - z1) * (node->Vertices[0].position.z - z1); // CA na północy if (mul < min) divide = 14; // tworzymy jeden dodatkowy trójkÄ…t, dzielÄ…c jeden bok na przeciÄ™ciu siatki kilometrowej @@ -1096,19 +938,24 @@ void TGround::RaTriangleDivider(TGroundNode *node) ntri->Init(3); ntri->TextureID = node->TextureID; ntri->iFlags = node->iFlags; +/* for (int j = 0; j < 4; ++j) { ntri->Ambient[j] = node->Ambient[j]; ntri->Diffuse[j] = node->Diffuse[j]; ntri->Specular[j] = node->Specular[j]; } +*/ + ntri->Ambient = node->Ambient; + ntri->Diffuse = node->Diffuse; + ntri->Specular = node->Specular; ntri->asName = node->asName; ntri->fSquareRadius = node->fSquareRadius; ntri->fSquareMinRadius = node->fSquareMinRadius; ntri->bVisible = node->bVisible; // a sÄ… jakieÅ› niewidoczne? ntri->nNext = nRootOfType[GL_TRIANGLES]; nRootOfType[GL_TRIANGLES] = ntri; // dopisanie z przodu do listy - iNumNodes++; + ++iNumNodes; switch (divide & 3) { // podzielenie jednego z boków, powstaje wierzchoÅ‚ek D case 0: // podziaÅ‚ AB (0-1) -> ADC i DBC @@ -1143,17 +990,14 @@ void TGround::RaTriangleDivider(TGroundNode *node) break; } // przeliczenie Å›rodków ciężkoÅ›ci obu - node->pCenter = - (node->Vertices[0].Point + node->Vertices[1].Point + node->Vertices[2].Point) / 3.0; - ntri->pCenter = - (ntri->Vertices[0].Point + ntri->Vertices[1].Point + ntri->Vertices[2].Point) / 3.0; + node->pCenter = ( node->Vertices[ 0 ].position + node->Vertices[ 1 ].position + node->Vertices[ 2 ].position ) / 3.0; + ntri->pCenter = ( ntri->Vertices[ 0 ].position + ntri->Vertices[ 1 ].position + ntri->Vertices[ 2 ].position ) / 3.0; RaTriangleDivider(node); // rekurencja, bo nawet na TD raz nie wystarczy RaTriangleDivider(ntri); }; TGroundNode * TGround::AddGroundNode(cParser *parser) { // wczytanie wpisu typu "node" - // parser->LoadTraction=Global::bLoadTraction; //Ra: tu nie potrzeba powtarzać std::string str, str1, str2, str3, str4, Skin, DriverType, asNodeName; int nv, i; double tf, r, rmin, tf1, tf3; @@ -1171,7 +1015,6 @@ TGroundNode * TGround::AddGroundNode(cParser *parser) >> rmin >> asNodeName >> str; - //str = AnsiString(token.c_str()); TGroundNode *tmp = new TGroundNode(); tmp->asName = (asNodeName == "none" ? "" : asNodeName); if (r >= 0) @@ -1223,6 +1066,9 @@ TGroundNode * TGround::AddGroundNode(cParser *parser) delete tmp; return NULL; } + glm::dvec3 center; + std::vector importedvertices; + switch (tmp->iType) { case TP_TRACTION: @@ -1231,8 +1077,10 @@ TGroundNode * TGround::AddGroundNode(cParser *parser) *parser >> token; tmp->hvTraction->asPowerSupplyName = token; // nazwa zasilacza parser->getTokens(3); - *parser >> tmp->hvTraction->NominalVoltage >> tmp->hvTraction->MaxCurrent >> - tmp->hvTraction->fResistivity; + *parser + >> tmp->hvTraction->NominalVoltage + >> tmp->hvTraction->MaxCurrent + >> tmp->hvTraction->fResistivity; if (tmp->hvTraction->fResistivity == 0.01f) // tyle jest w sceneriach [om/km] tmp->hvTraction->fResistivity = 0.075f; // taka sensowniejsza wartość za // http://www.ikolej.pl/fileadmin/user_upload/Seminaria_IK/13_05_07_Prezentacja_Kruczek.pdf @@ -1254,33 +1102,38 @@ TGroundNode * TGround::AddGroundNode(cParser *parser) parser->getTokens(); *parser >> tmp->hvTraction->DamageFlag; parser->getTokens(3); - *parser >> tmp->hvTraction->pPoint1.x >> tmp->hvTraction->pPoint1.y >> - tmp->hvTraction->pPoint1.z; - tmp->hvTraction->pPoint1 += pOrigin; + *parser + >> tmp->hvTraction->pPoint1.x + >> tmp->hvTraction->pPoint1.y + >> tmp->hvTraction->pPoint1.z; + tmp->hvTraction->pPoint1 += glm::dvec3( pOrigin.x, pOrigin.y, pOrigin.z ); parser->getTokens(3); - *parser >> tmp->hvTraction->pPoint2.x >> tmp->hvTraction->pPoint2.y >> - tmp->hvTraction->pPoint2.z; - tmp->hvTraction->pPoint2 += pOrigin; + *parser + >> tmp->hvTraction->pPoint2.x + >> tmp->hvTraction->pPoint2.y + >> tmp->hvTraction->pPoint2.z; + tmp->hvTraction->pPoint2 += glm::dvec3( pOrigin.x, pOrigin.y, pOrigin.z ); parser->getTokens(3); - *parser >> tmp->hvTraction->pPoint3.x >> tmp->hvTraction->pPoint3.y >> - tmp->hvTraction->pPoint3.z; - tmp->hvTraction->pPoint3 += pOrigin; + *parser + >> tmp->hvTraction->pPoint3.x + >> tmp->hvTraction->pPoint3.y + >> tmp->hvTraction->pPoint3.z; + tmp->hvTraction->pPoint3 += glm::dvec3( pOrigin.x, pOrigin.y, pOrigin.z ); parser->getTokens(3); - *parser >> tmp->hvTraction->pPoint4.x >> tmp->hvTraction->pPoint4.y >> - tmp->hvTraction->pPoint4.z; - tmp->hvTraction->pPoint4 += pOrigin; + *parser + >> tmp->hvTraction->pPoint4.x + >> tmp->hvTraction->pPoint4.y + >> tmp->hvTraction->pPoint4.z; + tmp->hvTraction->pPoint4 += glm::dvec3( pOrigin.x, pOrigin.y, pOrigin.z ); parser->getTokens(); *parser >> tf1; tmp->hvTraction->fHeightDifference = - (tmp->hvTraction->pPoint3.y - tmp->hvTraction->pPoint1.y + tmp->hvTraction->pPoint4.y - - tmp->hvTraction->pPoint2.y) * - 0.5f - - tf1; + (tmp->hvTraction->pPoint3.y - tmp->hvTraction->pPoint1.y + tmp->hvTraction->pPoint4.y - tmp->hvTraction->pPoint2.y) * 0.5f - tf1; parser->getTokens(); *parser >> tf1; if (tf1 > 0) tmp->hvTraction->iNumSections = - (tmp->hvTraction->pPoint1 - tmp->hvTraction->pPoint2).Length() / tf1; + glm::length((tmp->hvTraction->pPoint1 - tmp->hvTraction->pPoint2)) / tf1; else tmp->hvTraction->iNumSections = 0; parser->getTokens(); @@ -1305,19 +1158,24 @@ TGroundNode * TGround::AddGroundNode(cParser *parser) tmp->hvTraction->Init(); // przeliczenie parametrów // if (Global::bLoadTraction) // tmp->hvTraction->Optimize(); //generowanie DL dla wszystkiego przy wczytywaniu? - tmp->pCenter = (tmp->hvTraction->pPoint2 + tmp->hvTraction->pPoint1) * 0.5f; - // if (!Global::bLoadTraction) SafeDelete(tmp); //Ra: tak być nie może, bo NULL to błąd + tmp->pCenter = interpolate( tmp->hvTraction->pPoint2, tmp->hvTraction->pPoint1, 0.5 ); break; case TP_TRACTIONPOWERSOURCE: parser->getTokens(3); - *parser >> tmp->pCenter.x >> tmp->pCenter.y >> tmp->pCenter.z; + *parser + >> tmp->pCenter.x + >> tmp->pCenter.y + >> tmp->pCenter.z; tmp->pCenter += pOrigin; tmp->psTractionPowerSource = new TTractionPowerSource(tmp); tmp->psTractionPowerSource->Load(parser); break; case TP_MEMCELL: parser->getTokens(3); - *parser >> tmp->pCenter.x >> tmp->pCenter.y >> tmp->pCenter.z; + *parser + >> tmp->pCenter.x + >> tmp->pCenter.y + >> tmp->pCenter.z; tmp->pCenter.RotateY(aRotate.y / 180.0 * M_PI); // Ra 2014-11: uwzglÄ™dnienie rotacji tmp->pCenter += pOrigin; tmp->MemCell = new TMemCell(&tmp->pCenter); @@ -1332,7 +1190,10 @@ TGroundNode * TGround::AddGroundNode(cParser *parser) break; case TP_EVLAUNCH: parser->getTokens(3); - *parser >> tmp->pCenter.x >> tmp->pCenter.y >> tmp->pCenter.z; + *parser + >> tmp->pCenter.x + >> tmp->pCenter.y + >> tmp->pCenter.z; tmp->pCenter.RotateY(aRotate.y / 180.0 * M_PI); // Ra 2014-11: uwzglÄ™dnienie rotacji tmp->pCenter += pOrigin; tmp->EvLaunch = new TEventLauncher(); @@ -1343,8 +1204,7 @@ TGroundNode * TGround::AddGroundNode(cParser *parser) if (Global::iWriteLogEnabled & 4) if (!tmp->asName.empty()) WriteLog(tmp->asName); - tmp->pTrack->Load(parser, pOrigin, - tmp->asName); // w nazwie może być nazwa odcinka izolowanego + tmp->pTrack->Load(parser, pOrigin, tmp->asName); // w nazwie może być nazwa odcinka izolowanego if (!tmp->asName.empty()) // jest pusta gdy "none" { // dodanie do wyszukiwarki if( false == m_trackmap.Add( TP_TRACK, tmp->asName, tmp ) ) { @@ -1352,14 +1212,18 @@ TGroundNode * TGround::AddGroundNode(cParser *parser) ErrorLog( "Duplicated track: " + tmp->asName ); // to zgÅ‚aszać duplikat } } - tmp->pCenter = (tmp->pTrack->CurrentSegment()->FastGetPoint_0() + - tmp->pTrack->CurrentSegment()->FastGetPoint(0.5) + - tmp->pTrack->CurrentSegment()->FastGetPoint_1()) / - 3.0; + tmp->pCenter = ( + tmp->pTrack->CurrentSegment()->FastGetPoint_0() + + tmp->pTrack->CurrentSegment()->FastGetPoint( 0.5 ) + + tmp->pTrack->CurrentSegment()->FastGetPoint_1() ) + / 3.0; break; case TP_SOUND: parser->getTokens(3); - *parser >> tmp->pCenter.x >> tmp->pCenter.y >> tmp->pCenter.z; + *parser + >> tmp->pCenter.x + >> tmp->pCenter.y + >> tmp->pCenter.z; tmp->pCenter.RotateY(aRotate.y / 180.0 * M_PI); // Ra 2014-11: uwzglÄ™dnienie rotacji tmp->pCenter += pOrigin; parser->getTokens(); @@ -1368,11 +1232,7 @@ TGroundNode * TGround::AddGroundNode(cParser *parser) //str = AnsiString(token.c_str()); tmp->tsStaticSound = new TTextSound(str, sqrt(tmp->fSquareRadius), tmp->pCenter.x, tmp->pCenter.y, tmp->pCenter.z, false, false, rmin); if (rmin < 0.0) - rmin = - 0.0; // przywrócenie poprawnej wartoÅ›ci, jeÅ›li sÅ‚użyÅ‚a do wyłączenia efektu Dopplera - - // tmp->pDirectSoundBuffer=TSoundsManager::GetFromName(str.c_str()); - // tmp->iState=(Parser->GetNextSymbol().LowerCase()=="loop"?DSBPLAY_LOOPING:0); + rmin = 0.0; // przywrócenie poprawnej wartoÅ›ci, jeÅ›li sÅ‚użyÅ‚a do wyłączenia efektu Dopplera parser->getTokens(); *parser >> token; break; @@ -1406,12 +1266,11 @@ TGroundNode * TGround::AddGroundNode(cParser *parser) str4 = ""; } int2 = 0; // zeruje po wykorzystaniu - // *parser >> int1; //yB: nastawy i takie tam TUTAJ!!!!! if (int1 < 0) int1 = (-int1) | ctrain_depot; // sprzÄ™g zablokowany (pojazdy nierozłączalne przy manewrach) if (tf1 != -1.0) - if (fabs(tf1) > 0.5) // maksymalna odlegÅ‚ość miÄ™dzy sprzÄ™gami - do przemyÅ›lenia + if (std::fabs(tf1) > 0.5) // maksymalna odlegÅ‚ość miÄ™dzy sprzÄ™gami - do przemyÅ›lenia int1 = 0; // likwidacja sprzÄ™gu, jeÅ›li odlegÅ‚ość zbyt duża - to powinno być // uwzglÄ™dniane w fizyce sprzÄ™gów... TempConnectionType[iTrainSetWehicleNumber] = int1; // wartość dodatnia @@ -1534,37 +1393,19 @@ TGroundNode * TGround::AddGroundNode(cParser *parser) tmp->pCenter.RotateY(aRotate.y / 180.0 * M_PI); // McZapkie-260402: model tez ma wspolrzedne wzgledne tmp->pCenter += pOrigin; - // tmp->fAngle+=aRotate.y; // /180*M_PI - /* - if (tmp->iType==TP_MODEL) - {//jeÅ›li standardowy model - */ + tmp->Model = new TAnimModel(); - tmp->Model->RaAnglesSet(aRotate.x, tf1 + aRotate.y, - aRotate.z); // dostosowanie do pochylania linii - if (tmp->Model->Load( - parser, tmp->iType == TP_TERRAIN)) // wczytanie modelu, tekstury i stanu Å›wiateÅ‚... - tmp->iFlags = - tmp->Model->Flags() | 0x200; // ustalenie, czy przezroczysty; flaga usuwania + tmp->Model->RaAnglesSet(aRotate.x, tf1 + aRotate.y, aRotate.z); // dostosowanie do pochylania linii + if( tmp->Model->Load( parser, tmp->iType == TP_TERRAIN ) ) { + // wczytanie modelu, tekstury i stanu Å›wiateÅ‚... + tmp->iFlags = tmp->Model->Flags() | 0x200; // ustalenie, czy przezroczysty; flaga usuwania + } else if (tmp->iType != TP_TERRAIN) { // model nie wczytaÅ‚ siÄ™ - ignorowanie node delete tmp; tmp = NULL; // nie może być tu return break; // nie może być tu return? } - /* - } - else if (tmp->iType==TP_TERRAIN) - {//nie potrzeba nakÅ‚adki animujÄ…cej submodele - *parser >> token; - tmp->pModel3D=TModelsManager::GetModel(token.c_str(),false); - do //Ra: z tym to trochÄ™ bez sensu jest - {parser->getTokens(); - *parser >> token; - str=AnsiString(token.c_str()); - } while (str!="endterrains"); - } - */ if (tmp->iType == TP_TERRAIN) { // jeÅ›li model jest terenem, trzeba utworzyć dodatkowe obiekty // po wczytaniu model ma już utworzone DL albo VBO @@ -1608,30 +1449,30 @@ TGroundNode * TGround::AddGroundNode(cParser *parser) { if (token.compare("ambient:") == 0) { - parser->getTokens(); - *parser >> tmp->Ambient[0]; - parser->getTokens(); - *parser >> tmp->Ambient[1]; - parser->getTokens(); - *parser >> tmp->Ambient[2]; + parser->getTokens(3); + *parser + >> tmp->Ambient.r + >> tmp->Ambient.g + >> tmp->Ambient.b; + tmp->Ambient /= 255.0f; } else if (token.compare("diffuse:") == 0) { // Ra: coÅ› jest nie tak, bo w jednej linijce nie dziaÅ‚a - parser->getTokens(); - *parser >> tmp->Diffuse[0]; - parser->getTokens(); - *parser >> tmp->Diffuse[1]; - parser->getTokens(); - *parser >> tmp->Diffuse[2]; + parser->getTokens( 3 ); + *parser + >> tmp->Diffuse.r + >> tmp->Diffuse.g + >> tmp->Diffuse.b; + tmp->Diffuse /= 255.0f; } else if (token.compare("specular:") == 0) { - parser->getTokens(); - *parser >> tmp->Specular[0]; - parser->getTokens(); - *parser >> tmp->Specular[1]; - parser->getTokens(); - *parser >> tmp->Specular[2]; + parser->getTokens( 3 ); + *parser + >> tmp->Specular.r + >> tmp->Specular.g + >> tmp->Specular.b; + tmp->Specular /= 255.0f; } else Error("Scene material failure!"); @@ -1669,47 +1510,53 @@ TGroundNode * TGround::AddGroundNode(cParser *parser) } else { - TempVerts.clear(); TGroundVertex vertex; do { parser->getTokens( 8, false ); *parser - >> vertex.Point.x - >> vertex.Point.y - >> vertex.Point.z - >> vertex.Normal.x - >> vertex.Normal.y - >> vertex.Normal.z - >> vertex.tu - >> vertex.tv; - vertex.Point.RotateZ( aRotate.z / 180 * M_PI ); - vertex.Point.RotateX( aRotate.x / 180 * M_PI ); - vertex.Point.RotateY( aRotate.y / 180 * M_PI ); - vertex.Normal.RotateZ( aRotate.z / 180 * M_PI ); - vertex.Normal.RotateX( aRotate.x / 180 * M_PI ); - vertex.Normal.RotateY( aRotate.y / 180 * M_PI ); - vertex.Point += pOrigin; - tmp->pCenter += vertex.Point; + >> vertex.position.x + >> vertex.position.y + >> vertex.position.z + >> vertex.normal.x + >> vertex.normal.y + >> vertex.normal.z + >> vertex.texture.s + >> vertex.texture.t; +/* + vertex.position.RotateZ( aRotate.z / 180 * M_PI ); + vertex.position.RotateX( aRotate.x / 180 * M_PI ); + vertex.position.RotateY( aRotate.y / 180 * M_PI ); + vertex.normal.RotateZ( aRotate.z / 180 * M_PI ); + vertex.normal.RotateX( aRotate.x / 180 * M_PI ); + vertex.normal.RotateY( aRotate.y / 180 * M_PI ); +*/ + vertex.position = glm::rotateZ( vertex.position, aRotate.z / 180 * M_PI ); + vertex.position = glm::rotateX( vertex.position, aRotate.x / 180 * M_PI ); + vertex.position = glm::rotateY( vertex.position, aRotate.y / 180 * M_PI ); + vertex.normal = glm::rotateZ( vertex.normal, static_cast( aRotate.z / 180 * M_PI ) ); + vertex.normal = glm::rotateX( vertex.normal, static_cast( aRotate.x / 180 * M_PI ) ); + vertex.normal = glm::rotateY( vertex.normal, static_cast( aRotate.y / 180 * M_PI ) ); + vertex.position += glm::dvec3( pOrigin.x, pOrigin.y, pOrigin.z ); + tmp->pCenter += vertex.position; - TempVerts.emplace_back( vertex ); + importedvertices.emplace_back( vertex ); parser->getTokens(); *parser >> token; } while (token.compare("endtri") != 0); - nv = (int)TempVerts.size(); + nv = (int)importedvertices.size(); tmp->Init(nv); // utworzenie tablicy wierzchoÅ‚ków tmp->pCenter /= (nv > 0 ? nv : 1); r = 0; for (int i = 0; i < nv; i++) { - tmp->Vertices[i] = TempVerts[i]; - tf = SquareMagnitude(tmp->Vertices[i].Point - tmp->pCenter); + tmp->Vertices[i] = importedvertices[i]; + tf = SquareMagnitude( tmp->Vertices[ i ].position - tmp->pCenter ); if (tf > r) r = tf; } - // tmp->fSquareRadius=2000*2000+r; tmp->fSquareRadius += r; RaTriangleDivider(tmp); // Ra: dzielenie trójkÄ…tów jest teraz caÅ‚kiem wydajne } // koniec wczytywania trójkÄ…tów @@ -1719,27 +1566,35 @@ TGroundNode * TGround::AddGroundNode(cParser *parser) case GL_LINE_LOOP: { parser->getTokens( 4 ); *parser - >> tmp->Diffuse[ 0 ] - >> tmp->Diffuse[ 1 ] - >> tmp->Diffuse[ 2 ] + >> tmp->Diffuse.r + >> tmp->Diffuse.g + >> tmp->Diffuse.b >> tmp->fLineThickness; - TempVerts.clear(); + tmp->Diffuse /= 255.0f; TGroundVertex vertex; i = 0; parser->getTokens(); *parser >> token; do { - vertex.Point.x = std::atof( token.c_str() ); + vertex.position.x = std::atof( token.c_str() ); parser->getTokens( 2 ); *parser - >> vertex.Point.y - >> vertex.Point.z; - vertex.Point.RotateZ( aRotate.z / 180 * M_PI ); - vertex.Point.RotateX( aRotate.x / 180 * M_PI ); - vertex.Point.RotateY( aRotate.y / 180 * M_PI ); - vertex.Point += pOrigin; - tmp->pCenter += vertex.Point; - TempVerts.emplace_back( vertex ); + >> vertex.position.y + >> vertex.position.z; +/* + vertex.position.RotateZ( aRotate.z / 180 * M_PI ); + vertex.position.RotateX( aRotate.x / 180 * M_PI ); + vertex.position.RotateY( aRotate.y / 180 * M_PI ); +*/ + vertex.position = glm::rotateZ( vertex.position, aRotate.z / 180 * M_PI ); + vertex.position = glm::rotateX( vertex.position, aRotate.x / 180 * M_PI ); + vertex.position = glm::rotateY( vertex.position, aRotate.y / 180 * M_PI ); + + vertex.position += glm::dvec3( pOrigin.x, pOrigin.y, pOrigin.z ); + + tmp->pCenter += vertex.position; + + importedvertices.emplace_back( vertex ); ++i; parser->getTokens(); @@ -1747,11 +1602,11 @@ TGroundNode * TGround::AddGroundNode(cParser *parser) } while( token.compare( "endline" ) != 0 ); nv = i; // tmp->Init(nv); - tmp->Points = new vector3[ nv ]; + tmp->Points = new glm::dvec3[ nv ]; tmp->iNumPts = nv; tmp->pCenter /= ( nv > 0 ? nv : 1 ); for( int i = 0; i < nv; i++ ) - tmp->Points[ i ] = TempVerts[ i ].Point; + tmp->Points[ i ] = importedvertices[ i ].position; break; } } @@ -1837,10 +1692,7 @@ void TGround::FirstInit() gr = GetRect( ( std::stoi( xxxzzz.substr( 0, 3 )) - 500 ) * 1000, ( std::stoi( xxxzzz.substr( 3, 3 )) - 500 ) * 1000 ); - if (Global::bUseVBO) - gr->nTerrain = Current->nNode + j; // zapamiÄ™tanie - else - gr->RaNodeAdd(&Current->nNode[j]); + gr->nTerrain = Current->nNode + j; // zapamiÄ™tanie } } else if( ( Current->iType != GL_TRIANGLES ) @@ -1852,6 +1704,10 @@ void TGround::FirstInit() } else { // dodajemy do kwadratu kilometrowego + // override visibility ranges, to ensure the content is drawn from far enough + // TODO: subclass NodeAdd() for the ground cell and specialize it, instead of this + Current->fSquareRadius = 50000.0 * 50000.0; + Current->fSquareMinRadius = 0.0; GetRect( Current->pCenter.x, Current->pCenter.z )->NodeAdd( Current ); } } @@ -2805,7 +2661,7 @@ void TGround::InitTraction() Traction = nCurrent->hvTraction; if (!Traction->hvNext[0]) // tylko jeÅ›li jeszcze nie podłączony { - tmp = FindTraction(&Traction->pPoint1, iConnection, nCurrent); + tmp = FindTraction(Traction->pPoint1, iConnection, nCurrent); switch (iConnection) { case 0: @@ -2840,7 +2696,7 @@ void TGround::InitTraction() } if (!Traction->hvNext[1]) // tylko jeÅ›li jeszcze nie podłączony { - tmp = FindTraction(&Traction->pPoint2, iConnection, nCurrent); + tmp = FindTraction(Traction->pPoint2, iConnection, nCurrent); switch (iConnection) { case 0: @@ -3085,14 +2941,14 @@ TTrack * TGround::FindTrack(vector3 Point, int &iConnection, TGroundNode *Exclud return NULL; } -TTraction * TGround::FindTraction(vector3 *Point, int &iConnection, TGroundNode *Exclude) +TTraction * TGround::FindTraction(glm::dvec3 const &Point, int &iConnection, TGroundNode *Exclude) { // wyszukiwanie innego przÄ™sÅ‚a koÅ„czÄ…cego siÄ™ w (Point) TTraction *tmp; iConnection = -1; TSubRect *sr; // najpierw szukamy w okolicznych segmentach - int c = GetColFromX(Point->x); - int r = GetRowFromZ(Point->z); + int c = GetColFromX(Point.x); + int r = GetRowFromZ(Point.z); if ((sr = FastGetSubRect(c, r)) != NULL) // wiÄ™kszość bÄ™dzie w tym samym sektorze if ((tmp = sr->FindTraction(Point, iConnection, Exclude->hvTraction)) != NULL) return tmp; @@ -3121,7 +2977,7 @@ TTraction * TGround::FindTraction(vector3 *Point, int &iConnection, TGroundNode return NULL; }; -TTraction * TGround::TractionNearestFind(vector3 &p, int dir, TGroundNode *n) +TTraction * TGround::TractionNearestFind(glm::dvec3 &p, int dir, TGroundNode *n) { // wyszukanie najbliższego do (p) przÄ™sÅ‚a o tej samej nazwie sekcji (ale innego niż podłączone) // oraz zasilanego z kierunku (dir) TGroundNode *nCurrent, *nBest = NULL; @@ -3144,7 +3000,7 @@ TTraction * TGround::TractionNearestFind(vector3 &p, int dir, TGroundNode *n) ->hvNext[0]) // ale nie jest bezpoÅ›rednio podłączonym if (nCurrent->hvTraction != n->hvTraction->hvNext[1]) if (nCurrent->hvTraction->psPower - [k = (DotProduct( + [k = (glm::dot( n->hvTraction->vParametric, nCurrent->hvTraction->vParametric) >= 0 ? dir ^ 1 : @@ -3153,10 +3009,7 @@ TTraction * TGround::TractionNearestFind(vector3 &p, int dir, TGroundNode *n) if (nCurrent->hvTraction->fResistance[k] >= 0.0) //żeby siÄ™ nie propagowaÅ‚y jakieÅ› ujemne { // znaleziony kandydat do połączenia - d = SquareMagnitude( - p - - nCurrent - ->pCenter); // kwadrat odlegÅ‚oÅ›ci Å›rodków + d = SquareMagnitude( p - nCurrent->pCenter ); // kwadrat odlegÅ‚oÅ›ci Å›rodków if (dist > d) { // zapamiÄ™tanie nowego najbliższego dist = d; // nowy rekord odlegÅ‚oÅ›ci @@ -3175,7 +3028,7 @@ TTraction * TGround::TractionNearestFind(vector3 &p, int dir, TGroundNode *n) // else // n->hvTraction->pPoint4=0.25*(nBest->pCenter+3*(zg?nBest->hvTraction->pPoint4:nBest->hvTraction->pPoint3)); } - return (nBest ? nBest->hvTraction : NULL); + return (nBest ? nBest->hvTraction : nullptr); }; bool TGround::AddToQuery(TEvent *Event, TDynamicObject *Node) @@ -3768,15 +3621,16 @@ bool TGround::GetTraction(TDynamicObject *model) double fRaParam; // parametr równania parametrycznego odcinka drutu double fVertical; // odlegÅ‚ość w pionie; musi być w zasiÄ™gu ruchu "pionowego" pantografu double fHorizontal; // odlegÅ‚ość w bok; powinna być mniejsza niż pół szerokoÅ›ci pantografu - vector3 vLeft, vUp, vFront, dwys; - vector3 pant0; - vector3 vParam; // współczynniki równania parametrycznego drutu - vector3 vStyk; // punkt przebicia drutu przez pÅ‚aszczyznÄ™ ruchu pantografu - vector3 vGdzie; // wektor poÅ‚ożenia drutu wzglÄ™dem pojazdu - vFront = model->VectorFront(); // wektor normalny dla pÅ‚aszczyzny ruchu pantografu - vUp = model->VectorUp(); // wektor pionu pudÅ‚a (pochylony od pionu na przechyÅ‚ce) - vLeft = model->VectorLeft(); // wektor odlegÅ‚oÅ›ci w bok (odchylony od poziomu na przechyÅ‚ce) - dwys = model->GetPosition(); // współrzÄ™dne Å›rodka pojazdu + glm::dvec3 vLeft, vUp, vFront, dwys; + glm::dvec3 pant0; + glm::dvec3 vParam; // współczynniki równania parametrycznego drutu + glm::dvec3 vStyk; // punkt przebicia drutu przez pÅ‚aszczyznÄ™ ruchu pantografu + glm::dvec3 vGdzie; // wektor poÅ‚ożenia drutu wzglÄ™dem pojazdu + vFront = glm::make_vec3(model->VectorFront().getArray()); // wektor normalny dla pÅ‚aszczyzny ruchu pantografu + vUp = glm::make_vec3(model->VectorUp().getArray()); // wektor pionu pudÅ‚a (pochylony od pionu na przechyÅ‚ce) + vLeft = glm::make_vec3(model->VectorLeft().getArray()); // wektor odlegÅ‚oÅ›ci w bok (odchylony od poziomu na przechyÅ‚ce) + auto const position = model->GetPosition(); // współrzÄ™dne Å›rodka pojazdu + dwys = glm::dvec3( position.x, position.y, position.z ); TAnimPant *p; // wskaźnik do obiektu danych pantografu for (int k = 0; k < model->iAnimType[ANIM_PANTS]; ++k) { // pÄ™tla po pantografach @@ -3791,11 +3645,11 @@ bool TGround::GetTraction(TDynamicObject *model) { // powtarzane aż do znalezienia odpowiedniego odcinka na liÅ›cie dwukierunkowej // obliczamy wyraz wolny równania pÅ‚aszczyzny (to miejsce nie jest odpowienie) vParam = p->hvPowerWire->vParametric; // współczynniki równania parametrycznego - fRaParam = -DotProduct(pant0, vFront); + fRaParam = -glm::dot(pant0, vFront); // podstawiamy równanie parametryczne drutu do równania pÅ‚aszczyzny pantografu // vFront.x*(t1x+t*vParam.x)+vFront.y*(t1y+t*vParam.y)+vFront.z*(t1z+t*vParam.z)+fRaDist=0; - fRaParam = -(DotProduct(p->hvPowerWire->pPoint1, vFront) + fRaParam) / - DotProduct(vParam, vFront); + fRaParam = -(glm::dot(p->hvPowerWire->pPoint1, vFront) + fRaParam) / + glm::dot(vParam, vFront); if (fRaParam < -0.001) // histereza rzÄ™du 7cm na 70m typowego przÄ™sÅ‚a daje 1 promil p->hvPowerWire = p->hvPowerWire->hvNext[0]; @@ -3821,10 +3675,10 @@ bool TGround::GetTraction(TDynamicObject *model) // el.) vGdzie = vStyk - pant0; // wektor // odlegÅ‚ość w pionie musi być w zasiÄ™gu ruchu "pionowego" pantografu - fVertical = DotProduct( + fVertical = glm::dot( vGdzie, vUp); // musi siÄ™ mieÅ›cić w przedziale ruchu pantografu // odlegÅ‚ość w bok powinna być mniejsza niż pół szerokoÅ›ci pantografu - fHorizontal = fabs(DotProduct(vGdzie, vLeft)) - + fHorizontal = std::fabs(glm::dot(vGdzie, vLeft)) - p->fWidth; // to siÄ™ musi mieÅ›cić w przedziale zależnym od // szerokoÅ›ci pantografu // jeÅ›li w pionie albo w bok jest za daleko, to dany drut jest nieużyteczny @@ -3885,10 +3739,10 @@ bool TGround::GetTraction(TDynamicObject *model) vParam = node->hvTraction ->vParametric; // współczynniki równania parametrycznego - fRaParam = -DotProduct(pant0, vFront); - fRaParam = -(DotProduct(node->hvTraction->pPoint1, vFront) + + fRaParam = -glm::dot(pant0, vFront); + fRaParam = -(glm::dot(node->hvTraction->pPoint1, vFront) + fRaParam) / - DotProduct(vParam, vFront); + glm::dot(vParam, vFront); if ((fRaParam >= -0.001) ? (fRaParam <= 1.001) : false) { // jeÅ›li tylko jest w przedziale, wyznaczyć odlegÅ‚ość wzdÅ‚uż // wektorów vUp i vLeft @@ -3897,7 +3751,7 @@ bool TGround::GetTraction(TDynamicObject *model) // drutem (dla generatora Å‚uku // el.) vGdzie = vStyk - pant0; // wektor - fVertical = DotProduct( + fVertical = glm::dot( vGdzie, vUp); // musi siÄ™ mieÅ›cić w przedziale ruchu pantografu if (fVertical >= 0.0) // jeÅ›li ponad pantografem (bo może @@ -3910,7 +3764,7 @@ bool TGround::GetTraction(TDynamicObject *model) // (bEnableTraction) aby daÅ‚o siÄ™ jeździć na // koÅ›lawych // sceneriach - fHorizontal = fabs(DotProduct(vGdzie, vLeft)) - + fHorizontal = std::fabs(glm::dot(vGdzie, vLeft)) - p->fWidth; // i do tego jeszcze // wejdzie pod Å›lizg if (fHorizontal <= 0.0) // 0.635 dla AKP-1 AKP-4E @@ -3944,7 +3798,7 @@ bool TGround::GetTraction(TDynamicObject *model) // znaleziony { fHorizontal = - fabs(DotProduct(vGdzie, vLeft)) - p->fWidth; + std::fabs(glm::dot(vGdzie, vLeft)) - p->fWidth; if (fHorizontal <= 0.0) // 0.635 dla AKP-1 AKP-4E { // to siÄ™ musi mieÅ›cić w przedziale zaleznym od // szerokoÅ›ci pantografu @@ -4394,14 +4248,19 @@ void TGround::TerrainWrite() Current->iVboPtr = -1; // bo to byÅ‚o tymczasowo używane for (k = 0; k < Current->iNumVerts; ++k) { // przepisanie współrzÄ™dnych - ver[k].position.x = Current->Vertices[k].Point.x; - ver[k].position.y = Current->Vertices[k].Point.y; - ver[k].position.z = Current->Vertices[k].Point.z; - ver[k].normal.x = Current->Vertices[k].Normal.x; - ver[k].normal.y = Current->Vertices[k].Normal.y; - ver[k].normal.z = Current->Vertices[k].Normal.z; + ver[ k ].position = Current->Vertices[ k ].position; + ver[ k ].normal = Current->Vertices[ k ].normal; + ver[ k ].texture = Current->Vertices[ k ].texture; +/* + ver[k].position.x = Current->Vertices[k].position.x; + ver[k].position.y = Current->Vertices[k].position.y; + ver[k].position.z = Current->Vertices[k].position.z; + ver[k].normal.x = Current->Vertices[k].normal.x; + ver[k].normal.y = Current->Vertices[k].normal.y; + ver[k].normal.z = Current->Vertices[k].normal.z; ver[k].texture.s = Current->Vertices[k].tu; ver[k].texture.t = Current->Vertices[k].tv; +*/ } break; case GL_TRIANGLE_STRIP: // na razie nie, bo trzeba przerabiać na pojedyncze trójkÄ…ty diff --git a/Ground.h b/Ground.h index 08b6f4a7..55b4a819 100644 --- a/Ground.h +++ b/Ground.h @@ -23,20 +23,27 @@ http://mozilla.org/MPL/2.0/. using namespace Math3D; +typedef int TGroundNodeType; // Ra: zmniejszone liczby, aby zrobić tabelkÄ™ i zoptymalizować wyszukiwanie const int TP_MODEL = 10; +/* const int TP_MESH = 11; // Ra: specjalny obiekt grupujÄ…cy siatki dla tekstury const int TP_DUMMYTRACK = 12; // Ra: zdublowanie obiektu toru dla rozdzielenia tekstur +*/ const int TP_TERRAIN = 13; // Ra: specjalny model dla terenu const int TP_DYNAMIC = 14; const int TP_SOUND = 15; const int TP_TRACK = 16; -// const int TP_GEOMETRY=17; +/* +const int TP_GEOMETRY=17; +*/ const int TP_MEMCELL = 18; const int TP_EVLAUNCH = 19; // MC const int TP_TRACTION = 20; const int TP_TRACTIONPOWERSOURCE = 21; // MC -// const int TP_ISOLATED=22; //Ra +/* +const int TP_ISOLATED=22; //Ra +*/ const int TP_SUBMODEL = 22; // Ra: submodele terenu const int TP_LAST = 25; // rozmiar tablicy @@ -64,37 +71,28 @@ struct DaneRozkaz2 }; }; -typedef int TGroundNodeType; - struct TGroundVertex { - vector3 Point; - vector3 Normal; - float tu{ 0.0f }, tv{ 0.0f }; + glm::dvec3 position; + glm::vec3 normal; + glm::vec2 texture; + void HalfSet(const TGroundVertex &v1, const TGroundVertex &v2) { // wyliczenie współrzÄ™dnych i mapowania punktu na Å›rodku odcinka v1<->v2 - Point = 0.5 * (v1.Point + v2.Point); - Normal = 0.5 * (v1.Normal + v2.Normal); - tu = 0.5 * (v1.tu + v2.tu); - tv = 0.5 * (v1.tv + v2.tv); + interpolate_( v1, v2, 0.5 ); } void SetByX(const TGroundVertex &v1, const TGroundVertex &v2, double x) { // wyliczenie współrzÄ™dnych i mapowania punktu na odcinku v1<->v2 - double i = (x - v1.Point.x) / (v2.Point.x - v1.Point.x); // parametr równania - double j = 1.0 - i; - Point = j * v1.Point + i * v2.Point; - Normal = j * v1.Normal + i * v2.Normal; - tu = j * v1.tu + i * v2.tu; - tv = j * v1.tv + i * v2.tv; + interpolate_( v1, v2, ( x - v1.position.x ) / ( v2.position.x - v1.position.x ) ); } void SetByZ(const TGroundVertex &v1, const TGroundVertex &v2, double z) { // wyliczenie współrzÄ™dnych i mapowania punktu na odcinku v1<->v2 - double i = (z - v1.Point.z) / (v2.Point.z - v1.Point.z); // parametr równania - double j = 1.0 - i; - Point = j * v1.Point + i * v2.Point; - Normal = j * v1.Normal + i * v2.Normal; - tu = j * v1.tu + i * v2.tu; - tv = j * v1.tv + i * v2.tv; + interpolate_( v1, v2, ( z - v1.position.z ) / ( v2.position.z - v1.position.z ) ); + } + void interpolate_( const TGroundVertex &v1, const TGroundVertex &v2, double factor ) { + position = interpolate( v1.position, v2.position, factor ); + normal = interpolate( v1.normal, v2.normal, static_cast( factor ) ); + texture = interpolate( v1.texture, v2.texture, static_cast( factor ) ); } }; @@ -103,8 +101,11 @@ class TGroundNode : public Resource friend class opengl_renderer; -private: public: + TGroundNode *nNext; // lista wszystkich w scenerii, ostatni na poczÄ…tku + TGroundNode *nNext2; // lista obiektów w sektorze + TGroundNode *nNext3; // lista obiektów renderowanych we wspólnym cyklu + std::string asName; // nazwa (nie zawsze ma znaczenie) TGroundNodeType iType; // typ obiektu union { // Ra: wskażniki zależne od typu - zrobić klasy dziedziczone zamiast @@ -112,7 +113,7 @@ public: TSubModel *smTerrain; // modele terenu (kwadratow kilometrowych) TAnimModel *Model; // model z animacjami TDynamicObject *DynamicObject; // pojazd - vector3 *Points; // punkty dla linii + glm::dvec3 *Points; // punkty dla linii TTrack *pTrack; // trajektoria ruchu TGroundVertex *Vertices; // wierzchoÅ‚ki dla trójkÄ…tów TMemCell *MemCell; // komórka pamiÄ™ci @@ -122,39 +123,35 @@ public: TTextSound *tsStaticSound; // dźwiÄ™k przestrzenny TGroundNode *nNode; // obiekt renderujÄ…cy grupowo ma tu wskaźnik na listÄ™ obiektów }; - std::string asName; // nazwa (nie zawsze ma znaczenie) - - vector3 pCenter; // współrzÄ™dne Å›rodka do przydzielenia sektora - vector3 m_rootposition; // position of the ground (sub)rectangle holding the node, in the 3d world + Math3D::vector3 pCenter; // współrzÄ™dne Å›rodka do przydzielenia sektora + glm::dvec3 m_rootposition; // position of the ground (sub)rectangle holding the node, in the 3d world // visualization-related data // TODO: wrap these in a struct, when cleaning objects up + double fSquareMinRadius; // kwadrat widocznoÅ›ci od + double fSquareRadius; // kwadrat widocznoÅ›ci do union { int iNumVerts; // dla trójkÄ…tów int iNumPts; // dla linii int iCount; // dla terenu }; - double fLineThickness; // McZapkie-120702: grubosc linii - double fSquareRadius; // kwadrat widocznoÅ›ci do - double fSquareMinRadius; // kwadrat widocznoÅ›ci od int iVersion; // wersja siatki (do wykonania rekompilacji) - // union ? GLuint DisplayListID; // numer siatki DisplayLists - bool PROBLEND; int iVboPtr; // indeks w buforze VBO - texture_handle 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 + texture_handle TextureID; // główna (jedna) tekstura obiektu + glm::vec3 + Ambient{ 1.0f, 1.0f, 1.0f }, + Diffuse{ 1.0f, 1.0f, 1.0f }, + Specular{ 1.0f, 1.0f, 1.0f }; // oÅ›wietlenie + double fLineThickness; // McZapkie-120702: grubosc linii + bool PROBLEND; bool bVisible; - TGroundNode *nNext; // lista wszystkich w scenerii, ostatni na poczÄ…tku - TGroundNode *nNext2; // lista obiektów w sektorze - TGroundNode *nNext3; // lista obiektów renderowanych we wspólnym cyklu TGroundNode(); TGroundNode(TGroundNodeType t, int n = 0); ~TGroundNode(); void Init(int n); - void InitCenter(); // obliczenie współrzÄ™dnych Å›rodka void InitNormals(); // bool Disable(); @@ -167,19 +164,20 @@ public: return NULL; }; - void Compile(Math3D::vector3 const &Origin, bool const Multiple = false); + void Compile(glm::dvec3 const &Origin, bool const Multiple = false); void Release(); void RenderHidden(); // obsÅ‚uga dźwiÄ™ków i wyzwalaczy zdarzeÅ„ +#ifdef EU07_USE_OLD_RENDERCODE // (McZapkie-131202) void RaRenderVBO(); // renderowanie (nieprzezroczystych) ze wspólnego VBO - +#endif }; struct bounding_area { glm::vec3 center; // mid point of the rectangle - float radius{ 0.0f }; // radius of the bounding sphere + float radius { 0.0f }; // radius of the bounding sphere }; class TSubRect : public Resource, public CMesh @@ -190,8 +188,10 @@ class TSubRect : public Resource, public CMesh TTrack **tTracks = nullptr; // tory do renderowania pojazdów protected: TTrack *tTrackAnim = nullptr; // obiekty do przeliczenia animacji +#ifdef EU07_USE_OLD_RENDERCODE TGroundNode *nRootMesh = nullptr; // obiekty renderujÄ…ce wg tekstury (wtórne, lista po nNext2) TGroundNode *nMeshed = nullptr; // lista obiektów dla których istniejÄ… obiekty renderujÄ…ce grupowo +#endif public: TGroundNode *nRootNode = nullptr; // wszystkie obiekty w sektorze, z wyjÄ…tkiem renderujÄ…cych i pojazdów (nNext2) TGroundNode *nRenderHidden = nullptr; // lista obiektów niewidocznych, "renderowanych" również z tyÅ‚u (nNext3) @@ -211,10 +211,9 @@ class TSubRect : public Resource, public CMesh virtual ~TSubRect(); virtual void Release(); // zwalnianie VBO sektora void NodeAdd(TGroundNode *Node); // dodanie obiektu do sektora na etapie rozdzielania na sektory - void RaNodeAdd(TGroundNode *Node); // dodanie obiektu do listy renderowania void Sort(); // optymalizacja obiektów w sektorze (sortowanie wg tekstur) TTrack * FindTrack(vector3 *Point, int &iConnection, TTrack *Exclude); - TTraction * FindTraction(vector3 *Point, int &iConnection, TTraction *Exclude); + TTraction * FindTraction(glm::dvec3 const &Point, int &iConnection, TTraction *Exclude); bool StartVBO(); // ustwienie VBO sektora dla (nRenderRect), (nRenderRectAlpha) i (nRenderWires) bool RaTrackAnimAdd(TTrack *t); // zgÅ‚oszenie toru do animacji void RaAnimate(); // przeliczenie animacji torów @@ -311,8 +310,8 @@ class TGround bool InitEvents(); bool InitLaunchers(); TTrack * FindTrack(vector3 Point, int &iConnection, TGroundNode *Exclude); - TTraction * FindTraction(vector3 *Point, int &iConnection, TGroundNode *Exclude); - TTraction * TractionNearestFind(vector3 &p, int dir, TGroundNode *n); + TTraction * FindTraction(glm::dvec3 const &Point, int &iConnection, TGroundNode *Exclude); + TTraction * TractionNearestFind(glm::dvec3 &p, int dir, TGroundNode *n); TGroundNode * AddGroundNode(cParser *parser); void UpdatePhys(double dt, int iter); // aktualizacja fizyki staÅ‚ym krokiem bool Update(double dt, int iter); // aktualizacja przesunięć zgodna z FPS diff --git a/Model3d.cpp b/Model3d.cpp index 3b86d474..1c5e444c 100644 --- a/Model3d.cpp +++ b/Model3d.cpp @@ -177,12 +177,19 @@ template inline void readColor(cParser &parser, ColorT *color) color[ 2 ] /= 255.0; }; -inline void readColor(cParser &parser, int &color) +inline void readColor(cParser &parser, glm::vec4 &color) { - int r, g, b, discard; + int discard; parser.getTokens(4, false); - parser >> discard >> r >> g >> b; + parser + >> discard + >> color.r + >> color.g + >> color.b; + color /= 255.0f; +/* color = r + (g << 8) + (b << 16); +*/ }; /* inline void readMatrix(cParser& parser,matrix4x4& matrix) @@ -620,7 +627,7 @@ int TSubModel::TriangleAdd(TModel3d *m, texture_handle tex, int tri) return s->iNumVerts - tri; // zwraca pozycjÄ™ tych trójkÄ…tów w submodelu }; -basic_vertex *TSubModel::TrianglePtr(int tex, int pos, int *la, int *ld, int *ls) +basic_vertex *TSubModel::TrianglePtr(int tex, int pos, glm::vec3 const &Ambient, glm::vec3 const &Diffuse, glm::vec3 const &Specular ) { // zwraca wskaźnik do wypeÅ‚nienia tabeli wierzchoÅ‚ków, używane // przy tworzeniu E3D terenu TSubModel *s = this; @@ -639,7 +646,7 @@ basic_vertex *TSubModel::TrianglePtr(int tex, int pos, int *la, int *ld, int *ls s->iVboPtr = iInstance; // pozycja submodelu w tabeli wierzchoÅ‚ków iInstance += s->iNumVerts; // pozycja dla nastÄ™pnego } - s->ColorsSet(la, ld, ls); // ustawienie kolorów Å›wiateÅ‚ + s->ColorsSet(Ambient, Diffuse, Specular); // ustawienie kolorów Å›wiateÅ‚ return s->Vertices + pos; // wskaźnik na wolne miejsce w tabeli wierzchoÅ‚ków }; @@ -1038,20 +1045,24 @@ void TSubModel::RaArrayFill(CVertNormTex *Vert) { // wypeÅ‚nianie tablic VBO if (Child) Child->RaArrayFill(Vert); - if ((eType < TP_ROTATOR) || (eType == TP_STARS)) - for (int i = 0; i < iNumVerts; ++i) - { - Vert[iVboPtr + i].x = Vertices[i].position.x; - Vert[iVboPtr + i].y = Vertices[i].position.y; - Vert[iVboPtr + i].z = Vertices[i].position.z; - Vert[iVboPtr + i].nx = Vertices[i].normal.x; - Vert[iVboPtr + i].ny = Vertices[i].normal.y; - Vert[iVboPtr + i].nz = Vertices[i].normal.z; - Vert[iVboPtr + i].u = Vertices[i].texture.s; - Vert[iVboPtr + i].v = Vertices[i].texture.t; - } - else if (eType == TP_FREESPOTLIGHT) - Vert[iVboPtr].x = Vert[iVboPtr].y = Vert[iVboPtr].z = 0.0; + if( ( eType < TP_ROTATOR ) || ( eType == TP_STARS ) ) + for( int i = 0; i < iNumVerts; ++i ) { + Vert[ iVboPtr + i ].position = Vertices[ i ].position; + Vert[ iVboPtr + i ].normal = Vertices[ i ].normal; + Vert[ iVboPtr + i ].texture = Vertices[ i ].texture; +/* + Vert[iVboPtr + i].x = Vertices[i].position.x; + Vert[iVboPtr + i].y = Vertices[i].position.y; + Vert[iVboPtr + i].z = Vertices[i].position.z; + Vert[iVboPtr + i].nx = Vertices[i].normal.x; + Vert[iVboPtr + i].ny = Vertices[i].normal.y; + Vert[iVboPtr + i].nz = Vertices[i].normal.z; + Vert[iVboPtr + i].u = Vertices[i].texture.s; + Vert[iVboPtr + i].v = Vertices[i].texture.t; +*/ + } + else if( eType == TP_FREESPOTLIGHT ) + Vert[ iVboPtr ].position = glm::vec3(); if (Next) Next->RaArrayFill(Vert); }; @@ -1073,9 +1084,13 @@ void TSubModel::AdjustDist() Next->AdjustDist(); }; -void TSubModel::ColorsSet(int *a, int *d, int *s) +void TSubModel::ColorsSet( glm::vec3 const &Ambient, glm::vec3 const &Diffuse, glm::vec3 const &Specular ) { // ustawienie kolorów dla modelu terenu - int i; + f4Ambient = glm::vec4( Ambient, 1.0f ); + f4Diffuse = glm::vec4( Diffuse, 1.0f ); + f4Specular = glm::vec4( Specular, 1.0f ); +/* + int i; if (a) for (i = 0; i < 4; ++i) f4Ambient[i] = a[i] / 255.0; @@ -1085,6 +1100,7 @@ void TSubModel::ColorsSet(int *a, int *d, int *s) if (s) for (i = 0; i < 4; ++i) f4Specular[i] = s[i] / 255.0; +*/ }; void TSubModel::ParentMatrix(float4x4 *m) @@ -1429,13 +1445,13 @@ void TSubModel::deserialize(std::istream &s) fVisible = sn_utils::ld_float32(s); fLight = sn_utils::ld_float32(s); - for (size_t i = 0; i < 4; i++) + for (size_t i = 0; i < 4; ++i) f4Ambient[i] = sn_utils::ld_float32(s); - for (size_t i = 0; i < 4; i++) + for (size_t i = 0; i < 4; ++i) f4Diffuse[i] = sn_utils::ld_float32(s); - for (size_t i = 0; i < 4; i++) + for (size_t i = 0; i < 4; ++i) f4Specular[i] = sn_utils::ld_float32(s); - for (size_t i = 0; i < 4; i++) + for (size_t i = 0; i < 4; ++i) f4Emision[i] = sn_utils::ld_float32(s); fWireSize = sn_utils::ld_float32(s); @@ -1828,28 +1844,17 @@ TSubModel *TModel3d::TerrainSquare(int n) r->UnFlagNext(); // blokowanie wyÅ›wietlania po Next głównej listy return r; }; +#ifdef EU07_USE_OLD_RENDERCODE void TModel3d::TerrainRenderVBO(int n) { // renderowanie terenu z VBO - glPushMatrix(); + ::glPushMatrix(); ::glTranslated( -Global::pCameraPosition.x, -Global::pCameraPosition.y, -Global::pCameraPosition.z ); - - // glTranslated(vPosition->x,vPosition->y,vPosition->z); - // if (vAngle->y!=0.0) glRotated(vAngle->y,0.0,1.0,0.0); - // if (vAngle->x!=0.0) glRotated(vAngle->x,1.0,0.0,0.0); - // if (vAngle->z!=0.0) glRotated(vAngle->z,0.0,0.0,1.0); - // TSubModel::fSquareDist=SquareMagnitude(*vPosition-Global::GetCameraPosition()); - // //zmienna globalna! - if (StartVBO()) - { // odwrócenie flag, aby wyÅ‚apać nieprzezroczyste - // Root->ReplacableSet(ReplacableSkinId,iAlpha^0x0F0F000F); - TSubModel *r = Root; - while (r) - { - if (r->iVisible == n) // tylko jeÅ›li ma być widoczny w danej ramce (problem dla 0==false) - GfxRenderer.Render(r); // sub kolejne (Next) siÄ™ nie wyrenderujÄ… - r = r->NextGet(); - } - EndVBO(); - } - glPopMatrix(); + TSubModel *r = Root; + while( r ) { + if( r->iVisible == n ) // tylko jeÅ›li ma być widoczny w danej ramce (problem dla 0==false) + GfxRenderer.Render( r ); // sub kolejne (Next) siÄ™ nie wyrenderujÄ… + r = r->NextGet(); + } + ::glPopMatrix(); }; +#endif \ No newline at end of file diff --git a/Model3d.h b/Model3d.h index 81049800..a78712eb 100644 --- a/Model3d.h +++ b/Model3d.h @@ -92,10 +92,11 @@ private: int iTexture; // numer nazwy tekstury, -1 wymienna, 0 brak float fVisible; // próg jasnoÅ›ci Å›wiatÅ‚a do załączenia submodelu float fLight; // próg jasnoÅ›ci Å›wiatÅ‚a do zadziaÅ‚ania selfillum - float f4Ambient[4]; - float f4Diffuse[4]; // float ze wzglÄ™du na glMaterialfv() - float f4Specular[4]; - float f4Emision[4]; + glm::vec4 + f4Ambient, + f4Diffuse, + f4Specular, + f4Emision; float fWireSize; // nie używane, ale wczytywane float fSquareMaxDist; float fSquareMinDist; @@ -156,7 +157,7 @@ public: TSubModel * NextGet() { return Next; }; TSubModel * ChildGet() { return Child; }; int TriangleAdd(TModel3d *m, texture_handle tex, int tri); - basic_vertex * TrianglePtr(int tex, int pos, int *la, int *ld, int *ls); + basic_vertex * TrianglePtr(int tex, int pos, glm::vec3 const &Ambient, glm::vec3 const &Diffuse, glm::vec3 const &Specular ); void SetRotate(float3 vNewRotateAxis, float fNewAngle); void SetRotateXYZ(vector3 vNewAngles); void SetRotateXYZ(float3 vNewAngles); @@ -189,7 +190,7 @@ public: // Ra: funkcje do budowania terenu z E3D int Flags() { return iFlags; }; void UnFlagNext() { iFlags &= 0x00FFFFFF; }; - void ColorsSet(int *a, int *d, int *s); + void ColorsSet( glm::vec3 const &Ambient, glm::vec3 const &Diffuse, glm::vec3 const &Specular ); inline float3 Translation1Get() { return fMatrix ? *(fMatrix->TranslationGet()) + v_TransVector : v_TransVector; @@ -247,7 +248,9 @@ public: std::string NameGet() { return m_filename; }; int TerrainCount(); TSubModel * TerrainSquare(int n); - void TerrainRenderVBO(int n); +#ifdef EU07_USE_OLD_RENDERCODE + void TerrainRenderVBO(int n); +#endif void deserialize(std::istream &s, size_t size, bool dynamic); }; diff --git a/Segment.cpp b/Segment.cpp index c3fdb478..a39c46b6 100644 --- a/Segment.cpp +++ b/Segment.cpp @@ -398,14 +398,14 @@ int TSegment::RenderLoft( CVertNormTex* &Output, Math3D::vector3 const &Origin, ::glVertex3f( pt.x, pt.y, pt.z ); // pt nie mamy gdzie zapamiÄ™tać? } else { - Output->x = pt.x; - Output->y = pt.y; - Output->z = pt.z; - Output->nx = norm.x; - Output->ny = norm.y; - Output->nz = norm.z; - Output->u = (jmm1 * ShapePoints[ j ].z + m1 * ShapePoints[ j + iNumShapePoints ].z) / Texturescale; - Output->v = tv1; + Output->position.x = pt.x; + Output->position.y = pt.y; + Output->position.z = pt.z; + Output->normal.x = norm.x; + Output->normal.y = norm.y; + Output->normal.z = norm.z; + Output->texture.s = (jmm1 * ShapePoints[ j ].z + m1 * ShapePoints[ j + iNumShapePoints ].z) / Texturescale; + Output->texture.t = tv1; ++Output; } ++vertexcount; @@ -431,14 +431,14 @@ int TSegment::RenderLoft( CVertNormTex* &Output, Math3D::vector3 const &Origin, ::glVertex3f( pt.x, pt.y, pt.z ); } else { - Output->x = pt.x; - Output->y = pt.y; - Output->z = pt.z; - Output->nx = norm.x; - Output->ny = norm.y; - Output->nz = norm.z; - Output->u = (jmm2 * ShapePoints[ j ].z + m2 * ShapePoints[ j + iNumShapePoints ].z) / Texturescale; - Output->v = tv2; + Output->position.x = pt.x; + Output->position.y = pt.y; + Output->position.z = pt.z; + Output->normal.x = norm.x; + Output->normal.y = norm.y; + Output->normal.z = norm.z; + Output->texture.s = (jmm2 * ShapePoints[ j ].z + m2 * ShapePoints[ j + iNumShapePoints ].z) / Texturescale; + Output->texture.t = tv2; ++Output; } ++vertexcount; @@ -468,14 +468,14 @@ int TSegment::RenderLoft( CVertNormTex* &Output, Math3D::vector3 const &Origin, ::glVertex3f( pt.x, pt.y, pt.z ); // punkt na poczÄ…tku odcinka } else { - Output->x = pt.x; - Output->y = pt.y; - Output->z = pt.z; - Output->nx = norm.x; - Output->ny = norm.y; - Output->nz = norm.z; - Output->u = ShapePoints[ j ].z / Texturescale; - Output->v = tv1; + Output->position.x = pt.x; + Output->position.y = pt.y; + Output->position.z = pt.z; + Output->normal.x = norm.x; + Output->normal.y = norm.y; + Output->normal.z = norm.z; + Output->texture.s = ShapePoints[ j ].z / Texturescale; + Output->texture.t = tv1; ++Output; } ++vertexcount; @@ -492,14 +492,14 @@ int TSegment::RenderLoft( CVertNormTex* &Output, Math3D::vector3 const &Origin, ::glVertex3f( pt.x, pt.y, pt.z ); // punkt na koÅ„cu odcinka } else { - Output->x = pt.x; - Output->y = pt.y; - Output->z = pt.z; - Output->nx = norm.x; - Output->ny = norm.y; - Output->nz = norm.z; - Output->u = ShapePoints[ j ].z / Texturescale; - Output->v = tv2; + Output->position.x = pt.x; + Output->position.y = pt.y; + Output->position.z = pt.z; + Output->normal.x = norm.x; + Output->normal.y = norm.y; + Output->normal.z = norm.z; + Output->texture.s = ShapePoints[ j ].z / Texturescale; + Output->texture.t = tv2; ++Output; } ++vertexcount; diff --git a/Track.cpp b/Track.cpp index d42a3c91..48e39a66 100644 --- a/Track.cpp +++ b/Track.cpp @@ -1091,7 +1091,7 @@ void TTrack::Compile(GLuint tex) normal2 = normal1; } - auto const origin = pMyNode->m_rootposition; + auto const origin { pMyNode->m_rootposition }; double roll1, roll2; switch (iCategoryFlag & 15) @@ -1866,7 +1866,7 @@ void TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start, int cons normal2 = normal1; } - auto const origin = pMyNode->m_rootposition; + auto const origin { pMyNode->m_rootposition }; double roll1, roll2; switch (iCategoryFlag & 15) @@ -2302,42 +2302,42 @@ void TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start, int cons if (TextureID1) { // jeÅ›li podana tekstura nawierzchni // we start with a vertex in the middle... - Vert->nx = 0.0; - Vert->ny = 1.0; - Vert->nz = 0.0; - Vert->u = 0.5; - Vert->v = 0.5; - Vert->x = oxz.x - origin.x; - Vert->y = oxz.y - origin.y; - Vert->z = oxz.z - origin.z; + Vert->normal.x = 0.0; + Vert->normal.y = 1.0; + Vert->normal.z = 0.0; + Vert->texture.s = 0.5; + Vert->texture.t = 0.5; + Vert->position.x = oxz.x - origin.x; + Vert->position.y = oxz.y - origin.y; + Vert->position.z = oxz.z - origin.z; ++Vert; // ...and add one extra vertex to close the fan... - Vert->nx = 0.0; - Vert->ny = 1.0; - Vert->nz = 0.0; + Vert->normal.x = 0.0; + Vert->normal.y = 1.0; + Vert->normal.z = 0.0; // mapowanie we współrzÄ™dnych scenerii u = ( SwitchExtension->vPoints[ 0 ].x - oxz.x + origin.x ) / fTexLength; v = ( SwitchExtension->vPoints[ 0 ].z - oxz.z + origin.z ) / ( fTexRatio1 * fTexLength ); - Vert->u = cosa0 * u + sina0 * v + 0.5; - Vert->v = -sina0 * u + cosa0 * v + 0.5; - Vert->x = SwitchExtension->vPoints[ 0 ].x; - Vert->y = SwitchExtension->vPoints[ 0 ].y; - Vert->z = SwitchExtension->vPoints[ 0 ].z; + Vert->texture.s = cosa0 * u + sina0 * v + 0.5; + Vert->texture.t = -sina0 * u + cosa0 * v + 0.5; + Vert->position.x = SwitchExtension->vPoints[ 0 ].x; + Vert->position.y = SwitchExtension->vPoints[ 0 ].y; + Vert->position.z = SwitchExtension->vPoints[ 0 ].z; ++Vert; // ...then draw the precalculated rest for (i = SwitchExtension->iPoints + SwitchExtension->iRoads - 1; i >= 0; --i) { - Vert->nx = 0.0; - Vert->ny = 1.0; - Vert->nz = 0.0; + Vert->normal.x = 0.0; + Vert->normal.y = 1.0; + Vert->normal.z = 0.0; // mapowanie we współrzÄ™dnych scenerii u = (SwitchExtension->vPoints[i].x - oxz.x + origin.x ) / fTexLength; v = (SwitchExtension->vPoints[i].z - oxz.z + origin.z ) / (fTexRatio1 * fTexLength); - Vert->u = cosa0 * u + sina0 * v + 0.5; - Vert->v = -sina0 * u + cosa0 * v + 0.5; - Vert->x = SwitchExtension->vPoints[ i ].x; - Vert->y = SwitchExtension->vPoints[ i ].y; - Vert->z = SwitchExtension->vPoints[ i ].z; + Vert->texture.s = cosa0 * u + sina0 * v + 0.5; + Vert->texture.t = -sina0 * u + cosa0 * v + 0.5; + Vert->position.x = SwitchExtension->vPoints[ i ].x; + Vert->position.y = SwitchExtension->vPoints[ i ].y; + Vert->position.z = SwitchExtension->vPoints[ i ].z; ++Vert; } } @@ -2894,7 +2894,7 @@ TTrack * TTrack::RaAnimate(GLuint const Vertexbuffer) bladesbuffer.data() ); */ auto bladevertices = bladesbuffer.data(); - auto const origin = pMyNode->m_rootposition; + auto const origin { pMyNode->m_rootposition }; if( SwitchExtension->RightSwitch ) { // nowa wersja z SPKS, ale odwrotnie lewa/prawa SwitchExtension->Segments[ 0 ]->RenderLoft( bladevertices, origin, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, SwitchExtension->fOffset2 /*, true*/ ); SwitchExtension->Segments[ 1 ]->RenderLoft( bladevertices, origin, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -fMaxOffset + SwitchExtension->fOffset1 /*, true*/ ); diff --git a/Traction.cpp b/Traction.cpp index da00856e..cb79da05 100644 --- a/Traction.cpp +++ b/Traction.cpp @@ -91,7 +91,7 @@ sekcji z sÄ…siedniego przÄ™sÅ‚a). */ std::size_t -TTraction::create_geometry( geometrybank_handle const &Bank, Math3D::vector3 const &Origin ) { +TTraction::create_geometry( geometrybank_handle const &Bank, glm::dvec3 const &Origin ) { if( m_geometry != NULL ) { return GfxRenderer.Vertices( m_geometry ).size() / 2; @@ -117,13 +117,13 @@ TTraction::create_geometry( geometrybank_handle const &Bank, Math3D::vector3 con vertices.emplace_back( startvertex ); vertices.emplace_back( endvertex ); // Nie wiem co 'Marcin - Math3D::vector3 pt1, pt2, pt3, pt4, v1, v2; + glm::dvec3 pt1, pt2, pt3, pt4, v1, v2; v1 = pPoint4 - pPoint3; v2 = pPoint2 - pPoint1; float step = 0; if( iNumSections > 0 ) step = 1.0f / (float)iNumSections; - float f = step; + double f = step; float mid = 0.5; float t; // Przewod nosny 'Marcin @@ -274,13 +274,13 @@ TTraction::create_geometry( geometrybank_handle const &Bank, Math3D::vector3 con return elementcount; } -int TTraction::TestPoint(Math3D::vector3 *Point) +int TTraction::TestPoint(glm::dvec3 const &Point) { // sprawdzanie, czy przÄ™sÅ‚a można połączyć if (!hvNext[0]) - if (pPoint1.Equal(Point)) + if( glm::all( glm::epsilonEqual( Point, pPoint1, 0.025 ) ) ) return 0; if (!hvNext[1]) - if (pPoint2.Equal(Point)) + if( glm::all( glm::epsilonEqual( Point, pPoint2, 0.025 ) ) ) return 1; return -1; }; @@ -358,7 +358,7 @@ void TTraction::ResistanceCalc(int d, double r, TTractionPowerSource *ps) } t->psPower[d] = ps; // skopiowanie wskaźnika zasilacza od danej strony t->fResistance[d] = r; // wpisanie rezystancji w kierunku tego zasilacza - r += t->fResistivity * Length3(t->vParametric); // doliczenie oporu kolejnego odcinka + r += t->fResistivity * glm::dot(t->vParametric, t->vParametric ); // doliczenie oporu kolejnego odcinka p = t; // zapamiÄ™tanie dotychczasowego t = p->hvNext[d ^ 1]; // podążanie w tÄ™ samÄ… stronÄ™ d = p->iNext[d ^ 1]; @@ -368,7 +368,7 @@ void TTraction::ResistanceCalc(int d, double r, TTractionPowerSource *ps) else { // podążanie w obu kierunkach, można by rekurencjÄ…, ale szkoda zasobów r = 0.5 * fResistivity * - Length3(vParametric); // powiedzmy, że w zasilanym przęśle jest poÅ‚owa + glm::dot(vParametric, vParametric ); // powiedzmy, że w zasilanym przęśle jest poÅ‚owa if (fResistance[0] == 0.0) ResistanceCalc(0, r); // do tyÅ‚u (w stronÄ™ Point1) if (fResistance[1] == 0.0) diff --git a/Traction.h b/Traction.h index 80bd9607..569d8f45 100644 --- a/Traction.h +++ b/Traction.h @@ -27,8 +27,8 @@ class TTraction int iNext[ 2 ] { 0, 0 }; // do którego koÅ„ca siÄ™ łączy int iLast { 1 }; //że niby ostatni drut // ustawiony bit 0, jeÅ›li jest ostatnim drutem w sekcji; bit1 - przedostatni public: - Math3D::vector3 pPoint1, pPoint2, pPoint3, pPoint4; - Math3D::vector3 vParametric; // współczynniki równania parametrycznego odcinka + glm::dvec3 pPoint1, pPoint2, pPoint3, pPoint4; + glm::dvec3 vParametric; // współczynniki równania parametrycznego odcinka double fHeightDifference { 0.0 }; //,fMiddleHeight; int iNumSections { 0 }; float NominalVoltage { 0.0f }; @@ -51,8 +51,8 @@ class TTraction // creates geometry data in specified geometry bank. returns: number of created elements, or NULL // NOTE: deleting nodes doesn't currently release geometry data owned by the node. TODO: implement erasing individual geometry chunks and banks - std::size_t create_geometry( geometrybank_handle const &Bank, Math3D::vector3 const &Origin ); - int TestPoint(Math3D::vector3 *Point); + std::size_t create_geometry( geometrybank_handle const &Bank, glm::dvec3 const &Origin ); + int TestPoint(glm::dvec3 const &Point); void Connect(int my, TTraction *with, int to); void Init(); bool WhereIs(); diff --git a/VBO.cpp b/VBO.cpp index a61e457a..d9c3a9dd 100644 --- a/VBO.cpp +++ b/VBO.cpp @@ -14,7 +14,7 @@ http://mozilla.org/MPL/2.0/. #include "sn_utils.h" #include "globals.h" //--------------------------------------------------------------------------- - +/* void CVertNormTex::deserialize(std::istream &s) { x = sn_utils::ld_float32(s); @@ -42,7 +42,7 @@ void CVertNormTex::serialize(std::ostream &s) sn_utils::ls_float32(s, u); sn_utils::ls_float32(s, v); } - +*/ CMesh::CMesh() { // utworzenie pustego obiektu #ifdef EU07_USE_OLD_VERTEXBUFFER @@ -117,7 +117,7 @@ bool CMesh::StartVBO() if (m_nVBOVertices) { glBindBuffer(GL_ARRAY_BUFFER_ARB, m_nVBOVertices); - glVertexPointer( 3, GL_FLOAT, sizeof(CVertNormTex), static_cast(nullptr) ); // pozycje + glVertexPointer( 3, GL_FLOAT, sizeof( CVertNormTex ), static_cast( nullptr ) ); // pozycje glNormalPointer( GL_FLOAT, sizeof( CVertNormTex ), static_cast( nullptr ) + 12 ); // normalne glTexCoordPointer( 2, GL_FLOAT, sizeof( CVertNormTex ), static_cast( nullptr ) + 24 ); // wierzchoÅ‚ki return true; // można rysować z VBO diff --git a/VBO.h b/VBO.h index d0228bfc..0f52b9d9 100644 --- a/VBO.h +++ b/VBO.h @@ -14,6 +14,7 @@ http://mozilla.org/MPL/2.0/. #define EU07_USE_OLD_VERTEXBUFFER //--------------------------------------------------------------------------- +/* class CVertNormTex { public: @@ -29,6 +30,8 @@ class CVertNormTex void deserialize(std::istream&); void serialize(std::ostream&); }; +*/ +typedef basic_vertex CVertNormTex; class CMesh { // wsparcie dla VBO diff --git a/dumb3d.h b/dumb3d.h index 3a666e4f..66e7fda3 100644 --- a/dumb3d.h +++ b/dumb3d.h @@ -72,6 +72,9 @@ class vector3 y = b; z = c; } + vector3( glm::dvec3 const &Vector ) : + x( Vector.x ), y( Vector.y ), z( Vector.z ) + {} // The int parameter is the number of elements to copy from initArray (3 or 4) // explicit vector3(scalar_t* initArray, int arraySize = 3) diff --git a/renderer.cpp b/renderer.cpp index 95137e19..d5ab5fa1 100644 --- a/renderer.cpp +++ b/renderer.cpp @@ -367,9 +367,9 @@ opengl_renderer::Render( TGround *Ground ) { for( int column = originx; column <= originx + segmentcount; ++column ) { for( int row = originz; row <= originz + segmentcount; ++row ) { - auto *rectangle = &Ground->Rects[ column ][ row ]; - if( m_camera.visible( rectangle->m_area ) ) { - Render( rectangle ); + auto *cell = &Ground->Rects[ column ][ row ]; + if( m_camera.visible( cell->m_area ) ) { + Render( cell ); } } } @@ -387,8 +387,8 @@ opengl_renderer::Render( TGround *Ground ) { int r = Ground->GetRowFromZ( Global::pCameraPosition.z ); TSubRect *tmp; int i, j, k; - for( j = r - n; j <= r + n; j++ ) { - for( i = c - n; i <= c + n; i++ ) { + for( j = r - n; j <= r + n; ++j ) { + for( i = c - n; i <= c + n; ++i ) { if( ( tmp = Ground->FastGetSubRect( i, j ) ) != nullptr ) { // oznaczanie aktywnych sektorów tmp->LoadNodes(); @@ -441,12 +441,29 @@ opengl_renderer::Render( TGround *Ground ) { } } while( ( i < 0 ) || ( j < 0 ) ); // sÄ… 4 przypadki, oprócz i=j=0 } +/* // dodać renderowanie terenu z E3D - jedno VBO jest używane dla caÅ‚ego modelu, chyba że jest ich wiÄ™cej if( Global::bUseVBO ) { - if( Global::pTerrainCompact ) { + if( ( Global::pTerrainCompact != nullptr ) + && ( Global::pTerrainCompact->pModel != nullptr ) ) { +#ifdef EU07_USE_OLD_RENDERCODE Global::pTerrainCompact->TerrainRenderVBO( TGroundRect::iFrameNumber ); +#endif + // TODO: remap geometry of terrain cells to allow camera-centric rendering + ::glPushMatrix(); + ::glTranslated( -Global::pCameraPosition.x, -Global::pCameraPosition.y, -Global::pCameraPosition.z ); + TSubModel *submodel = Global::pTerrainCompact->pModel->Root; + while( submodel != nullptr ) { + if( submodel->iVisible == TGroundRect::iFrameNumber ) { + // tylko jeÅ›li ma być widoczny w danej ramce (problem dla 0==false) + Render( submodel ); // sub kolejne (Next) siÄ™ nie wyrenderujÄ… + } + submodel = submodel->NextGet(); + } + ::glPopMatrix(); } } +*/ // renderowanie nieprzezroczystych for( i = 0; i < Ground->iRendered; ++i ) { Render( Ground->pRendered[ i ] ); @@ -456,43 +473,42 @@ opengl_renderer::Render( TGround *Ground ) { } // TODO: unify ground render code, until then old version is in place -#define EU07_USE_OLD_RENDERCODE bool opengl_renderer::Render( TGroundRect *Groundcell ) { - ::glPushMatrix(); - auto const &cellorigin = Groundcell->m_area.center; - // TODO: unify all math objects - auto const originoffset = Math3D::vector3( cellorigin.x, cellorigin.y, cellorigin.z ) - Global::pCameraPosition; - ::glTranslated( originoffset.x, originoffset.y, originoffset.z ); - - bool result{ false }; // will be true if we do any rendering + bool result { false }; // will be true if we do any rendering // TODO: unify render paths if( Global::bUseVBO ) { - if ( Groundcell->iLastDisplay != Groundcell->iFrameNumber) - { // tylko jezeli dany kwadrat nie byÅ‚ jeszcze renderowany + if ( Groundcell->iLastDisplay != Groundcell->iFrameNumber) { + // tylko jezeli dany kwadrat nie byÅ‚ jeszcze renderowany Groundcell->LoadNodes(); // ewentualne tworzenie siatek - if ( Groundcell->nRenderRect && Groundcell->StartVBO()) - { - for (TGroundNode *node = Groundcell->nRenderRect; node; node = node->nNext3) // nastÄ™pny tej grupy -#ifdef EU07_USE_OLD_RENDERCODE - node->RaRenderVBO(); // nieprzezroczyste trójkÄ…ty kwadratu kilometrowego -#else - Render( node ); // nieprzezroczyste trójkÄ…ty kwadratu kilometrowego -#endif + + if( ( Groundcell->nRenderRect != nullptr ) + && ( true == Groundcell->StartVBO() ) ) { + // nieprzezroczyste trójkÄ…ty kwadratu kilometrowego + for( TGroundNode *node = Groundcell->nRenderRect; node; node = node->nNext3 ) { + Render( node ); + } Groundcell->EndVBO(); - Groundcell->iLastDisplay = Groundcell->iFrameNumber; - result = true; } - if ( Groundcell->nTerrain) - Groundcell->nTerrain->smTerrain->iVisible = Groundcell->iFrameNumber; // ma siÄ™ wyÅ›wietlić w tej ramce + if( Groundcell->nTerrain ) { + + Render( Groundcell->nTerrain ); + } + Groundcell->iLastDisplay = Groundcell->iFrameNumber; // drugi raz nie potrzeba + result = true; } - ::glPopMatrix(); } else { -#ifdef EU07_USE_OLD_RENDERCODE + // display list render path + ::glPushMatrix(); + auto const &cellorigin = Groundcell->m_area.center; + // TODO: unify all math objects + auto const originoffset = Math3D::vector3( cellorigin.x, cellorigin.y, cellorigin.z ) - Global::pCameraPosition; + ::glTranslated( originoffset.x, originoffset.y, originoffset.z ); + if (Groundcell->iLastDisplay != Groundcell->iFrameNumber) { // tylko jezeli dany kwadrat nie byÅ‚ jeszcze renderowany // for (TGroundNode* node=pRender;node;node=node->pNext3) @@ -505,7 +521,7 @@ opengl_renderer::Render( TGroundRect *Groundcell ) { Groundcell->nRender->DisplayListID = glGenLists(1); glNewList( Groundcell->nRender->DisplayListID, GL_COMPILE); Groundcell->nRender->iVersion = Global::iReCompile; // aktualna wersja siatek - auto const origin = Math3D::vector3( Groundcell->m_area.center.x, Groundcell->m_area.center.y, Groundcell->m_area.center.z ); + auto const origin = glm::dvec3( Groundcell->m_area.center ); for (TGroundNode *node = Groundcell->nRender; node; node = node->nNext3) // nastÄ™pny tej grupy node->Compile(origin, true); glEndList(); @@ -515,32 +531,18 @@ opengl_renderer::Render( TGroundRect *Groundcell ) { // submodels geometry is world-centric, so at least for the time being we need to pop the stack early ::glPopMatrix(); - if( Groundcell->nRootMesh ) { - Render( Groundcell->nRootMesh ); - } + if( Groundcell->nTerrain ) { Render( Groundcell->nTerrain ); } + Groundcell->iLastDisplay = Groundcell->iFrameNumber; // drugi raz nie potrzeba result = true; } else { ::glPopMatrix(); } -#else - if( iLastDisplay != iFrameNumber ) { // tylko jezeli dany kwadrat nie byÅ‚ jeszcze renderowany - LoadNodes(); // ewentualne tworzenie siatek - if( nRenderRect ) { - for( TGroundNode *node = nRenderRect; node; node = node->nNext3 ) // nastÄ™pny tej grupy - Render( node ); // nieprzezroczyste trójkÄ…ty kwadratu kilometrowego - } - if( nRootMesh ) - Render( nRootMesh ); - iLastDisplay = iFrameNumber; - } -#endif } return result; } -#undef EU07_USE_OLD_RENDERCODE bool opengl_renderer::Render( TSubRect *Groundsubcell ) { @@ -665,11 +667,13 @@ opengl_renderer::Render( TGroundNode *Node ) { if( Node->iNumPts ) { // setup // w zaleznosci od koloru swiatla - ::glColor4ub( - static_cast( std::floor( Node->Diffuse[ 0 ] * Global::DayLight.ambient[ 0 ] ) ), - static_cast( std::floor( Node->Diffuse[ 1 ] * Global::DayLight.ambient[ 1 ] ) ), - static_cast( std::floor( Node->Diffuse[ 2 ] * Global::DayLight.ambient[ 2 ] ) ), - static_cast( std::min( 255.0, 255000 * Node->fLineThickness / ( distancesquared + 1.0 ) ) ) ); + ::glColor4fv( + glm::value_ptr( + glm::vec4( + Node->Diffuse * glm::make_vec3( Global::DayLight.ambient ), + std::min( + 1.0, + 1000.0 * Node->fLineThickness / ( distancesquared + 1.0 ) ) ) ) ); GfxRenderer.Bind( 0 ); @@ -700,10 +704,7 @@ opengl_renderer::Render( TGroundNode *Node ) { return false; } // setup - ::glColor3ub( - static_cast( Node->Diffuse[ 0 ] ), - static_cast( Node->Diffuse[ 1 ] ), - static_cast( Node->Diffuse[ 2 ] ) ); + ::glColor3fv( glm::value_ptr( Node->Diffuse ) ); Bind( Node->TextureID ); @@ -874,11 +875,11 @@ opengl_renderer::Render( TSubModel *Submodel ) { // również 0 Bind( Submodel->TextureID ); } - ::glColor3fv( Submodel->f4Diffuse ); // McZapkie-240702: zamiast ub + ::glColor3fv( glm::value_ptr(Submodel->f4Diffuse) ); // McZapkie-240702: zamiast ub // ...luminance if( Global::fLuminance < Submodel->fLight ) { // zeby swiecilo na kolorowo - ::glMaterialfv( GL_FRONT, GL_EMISSION, Submodel->f4Diffuse ); + ::glMaterialfv( GL_FRONT, GL_EMISSION, glm::value_ptr(Submodel->f4Diffuse) ); } // main draw call @@ -1184,11 +1185,13 @@ opengl_renderer::Render_Alpha( TGroundNode *Node ) { auto const originoffset = Node->m_rootposition - Global::pCameraPosition; ::glTranslated( originoffset.x, originoffset.y, originoffset.z ); // w zaleznosci od koloru swiatla - ::glColor4ub( - static_cast( std::floor( Node->Diffuse[ 0 ] * Global::DayLight.ambient[ 0 ] ) ), - static_cast( std::floor( Node->Diffuse[ 1 ] * Global::DayLight.ambient[ 1 ] ) ), - static_cast( std::floor( Node->Diffuse[ 2 ] * Global::DayLight.ambient[ 2 ] ) ), - static_cast( std::min( 255.0, 255000 * Node->fLineThickness / ( distancesquared + 1.0 ) ) ) ); + ::glColor4fv( + glm::value_ptr( + glm::vec4( + Node->Diffuse * glm::make_vec3( Global::DayLight.ambient ), + std::min( + 1.0, + 1000.0 * Node->fLineThickness / ( distancesquared + 1.0 ) ) ) ) ); GfxRenderer.Bind( 0 ); @@ -1212,10 +1215,7 @@ opengl_renderer::Render_Alpha( TGroundNode *Node ) { auto const originoffset = Node->m_rootposition - Global::pCameraPosition; ::glTranslated( originoffset.x, originoffset.y, originoffset.z ); - ::glColor3ub( - static_cast( Node->Diffuse[ 0 ] ), - static_cast( Node->Diffuse[ 1 ] ), - static_cast( Node->Diffuse[ 2 ] ) ); + ::glColor3fv( glm::value_ptr( Node->Diffuse ) ); Bind( Node->TextureID ); @@ -1392,11 +1392,11 @@ opengl_renderer::Render_Alpha( TSubModel *Submodel ) { // również 0 Bind( Submodel->TextureID ); } - ::glColor3fv( Submodel->f4Diffuse ); // McZapkie-240702: zamiast ub + ::glColor3fv( glm::value_ptr(Submodel->f4Diffuse) ); // McZapkie-240702: zamiast ub // ...luminance if( Global::fLuminance < Submodel->fLight ) { // zeby swiecilo na kolorowo - ::glMaterialfv( GL_FRONT, GL_EMISSION, Submodel->f4Diffuse ); + ::glMaterialfv( GL_FRONT, GL_EMISSION, glm::value_ptr(Submodel->f4Diffuse) ); } // main draw call diff --git a/stdafx.h b/stdafx.h index c331c425..e68efd55 100644 --- a/stdafx.h +++ b/stdafx.h @@ -85,5 +85,8 @@ #include #include #include +#include +#include +#include #include "openglmatrixstack.h" \ No newline at end of file diff --git a/usefull.h b/usefull.h index e639caf4..cd747876 100644 --- a/usefull.h +++ b/usefull.h @@ -59,9 +59,16 @@ clamp_circular( Type_ Value, Type_ const Range = static_cast(360) ) { template Type_ -interpolate( Type_ const First, Type_ const Second, float const Factor ) { +interpolate( Type_ const &First, Type_ const &Second, float const Factor ) { return ( First * ( 1.0f - Factor ) ) + ( Second * Factor ); } +template +Type_ +interpolate( Type_ const &First, Type_ const &Second, double const Factor ) { + + return ( First * ( 1.0 - Factor ) ) + ( Second * Factor ); +} + //--------------------------------------------------------------------------- From 21680a5d3017e56ac0e80da60194c503ea94577e Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Tue, 13 Jun 2017 18:13:49 +0200 Subject: [PATCH 6/9] completed unification of render paths --- Ground.cpp | 557 +++++++++++++++++----------------------- Ground.h | 47 ++-- Model3d.cpp | 43 ++-- Model3d.h | 2 +- Segment.cpp | 113 ++------- Segment.h | 70 ++--- Track.cpp | 558 ++++++++++++++++++++++++---------------- Track.h | 138 +++++----- Traction.cpp | 5 +- Traction.h | 2 +- VBO.cpp | 145 ----------- VBO.h | 43 +--- World.cpp | 40 ++- openglgeometrybank.cpp | 6 +- openglgeometrybank.h | 54 +++- parser.cpp | 12 +- parser.h | 4 +- renderer.cpp | 564 ++++++++++++++++------------------------- renderer.h | 21 +- 19 files changed, 1040 insertions(+), 1384 deletions(-) diff --git a/Ground.cpp b/Ground.cpp index e65f414d..b15c5421 100644 --- a/Ground.cpp +++ b/Ground.cpp @@ -247,82 +247,13 @@ void TGroundNode::InitNormals() } } /* -void TGroundNode::RaRenderVBO() -{ // renderowanie z domyslnego bufora VBO - glColor3ub(Diffuse[0], Diffuse[1], Diffuse[2]); - GfxRenderer.Bind( TextureID ); // Ustaw aktywnÄ… teksturÄ™ - glDrawArrays(iType, iVboPtr, iNumVerts); // Narysuj naraz wszystkie trójkÄ…ty -} -*/ -void TGroundNode::Compile( glm::dvec3 const &Origin, bool const Multiple ) -{ // tworzenie skompilowanej listy w wyÅ›wietlaniu DL - if (false == Multiple) - { // obsÅ‚uga pojedynczej listy - if (DisplayListID) - Release(); - if (Global::bManageNodes) - { - DisplayListID = glGenLists(1); - glNewList(DisplayListID, GL_COMPILE); - iVersion = Global::iReCompile; // aktualna wersja siatek (do WireFrame) - } - } - if ((iType == GL_LINES) || (iType == GL_LINE_STRIP) || (iType == GL_LINE_LOOP)) - { - glBegin(iType); - for (int i = 0; i < iNumPts; ++i) - glVertex3dv( glm::value_ptr( Points[i] - Origin ) ); - glEnd(); - } - else if (iType == GL_TRIANGLE_STRIP || iType == GL_TRIANGLE_FAN || iType == GL_TRIANGLES) - { // jak nie linie, to trójkÄ…ty - // TODO: eliminate these calls, they're duplicated by setup part in the unified render function -#ifdef EU07_USE_OLD_RENDERCODE - ::glColor3fv( glm::value_ptr( Diffuse ) ); - GfxRenderer.Bind(TextureID); -#endif - glBegin(iType); - for (int i = 0; i < iNumVerts; ++i) - { - glNormal3fv( glm::value_ptr( Vertices[ i ].normal ) ); - glTexCoord2fv( glm::value_ptr( Vertices[ i ].texture ) ); - glVertex3dv( glm::value_ptr( Vertices[ i ].position - Origin ) ); - } - glEnd(); - } -/* - else if (iType == TP_MESH) - { // grupa ze wspólnÄ… teksturÄ… - wrzucanie do wspólnego Display List -#ifdef EU07_USE_OLD_RENDERCODE - if (TextureID) - GfxRenderer.Bind(TextureID); // Ustaw aktywnÄ… teksturÄ™ -#endif - TGroundNode *n = nNode; - while (n ? n->TextureID == TextureID : false) - { // wszystkie obiekty o tej samej testurze - switch (n->iType) - { // poszczególne typy różnie siÄ™ tworzy - case TP_TRACK: - case TP_DUMMYTRACK: - n->pTrack->Compile(TextureID); // dodanie trójkÄ…tów dla podanej tekstury - break; - } - n = n->nNext3; // nastÄ™pny z listy - } - } -*/ - if (false == Multiple) - if (Global::bManageNodes) - glEndList(); -}; - void TGroundNode::Release() { if (DisplayListID) glDeleteLists(DisplayListID, 1); DisplayListID = 0; }; - +*/ void TGroundNode::RenderHidden() { // renderowanie obiektów niewidocznych double mgn = SquareMagnitude(pCenter - Global::pCameraPosition); @@ -354,8 +285,10 @@ void TGroundNode::RenderHidden() //------------------------------------------------------------------------------ TSubRect::~TSubRect() { +/* if (Global::bManageNodes) // Ra: tu siÄ™ coÅ› sypie ResourceManager::Unregister(this); // wyrejestrowanie ze sprzÄ…tacza +*/ // TODO: usunąć obiekty z listy (nRootMesh), bo sÄ… one tworzone dla sektora delete[] tTracks; } @@ -393,46 +326,22 @@ void TSubRect::NodeAdd(TGroundNode *Node) Node->pTrack->RaOwnerSet(this); // do którego sektora ma zgÅ‚aszać animacjÄ™ // NOTE: track merge/sort temporarily disabled to simplify unification of render code // TODO: refactor sorting as universal part of drawing process in the renderer -#ifdef EU07_USE_OLD_RENDERCODE - if( Global::bUseVBO ) { - Node->nNext3 = nRenderRect; - nRenderRect = Node; - } // VBO: do nieprzezroczystych z sektora - else { - Node->nNext3 = nRender; - nRender = Node; - } // DL: do nieprzezroczystych -#else Node->nNext3 = nRenderRect; nRenderRect = Node; -#endif break; case GL_TRIANGLE_STRIP: case GL_TRIANGLE_FAN: case GL_TRIANGLES: - // Node->nNext3=nMeshed; nMeshed=Node; //do podzielenia potem - if (Node->iFlags & 0x20) // czy jest przezroczyste? - { + if (Node->iFlags & 0x20) { + // do przezroczystych z sektora Node->nNext3 = nRenderRectAlpha; nRenderRectAlpha = Node; - } // DL: do przezroczystych z sektora -#ifdef EU07_USE_OLD_RENDERCODE - else if (Global::bUseVBO) - { - Node->nNext3 = nRenderRect; - nRenderRect = Node; - } // VBO: do nieprzezroczystych z sektora - else - { - Node->nNext3 = nRender; - nRender = Node; - } // DL: do nieprzezroczystych wszelakich -#else + } else { + // do nieprzezroczystych z sektora Node->nNext3 = nRenderRect; nRenderRect = Node; - } // do nieprzezroczystych z sektora -#endif + } break; case TP_TRACTION: case GL_LINES: @@ -471,9 +380,11 @@ void TSubRect::NodeAdd(TGroundNode *Node) case TP_DYNAMIC: return; // tych nie dopisujemy wcale } - Node->nNext2 = nRootNode; // dopisanie do ogólnej listy + // dopisanie do ogólnej listy + Node->nNext2 = nRootNode; nRootNode = Node; - ++iNodeCount; // licznik obiektów + // licznik obiektów + ++iNodeCount; } // przygotowanie sektora do renderowania @@ -516,8 +427,10 @@ TTrack * TSubRect::FindTrack(vector3 *Point, int &iConnection, TTrack *Exclude) bool TSubRect::RaTrackAnimAdd(TTrack *t) { // aktywacja animacji torów w VBO (zwrotnica, obrotnica) - if (m_nVertexCount < 0) - return true; // nie ma animacji, gdy nie widać + if( false == m_geometrycreated ) { + // nie ma animacji, gdy nie widać + return true; + } if (tTrackAnim) tTrackAnim->RaAnimListAdd(t); else @@ -531,22 +444,7 @@ void TSubRect::RaAnimate() // nie ma nic do animowania return; } - // crude way to mark whether a vbo is bound, for the vbo render path - // TODO: sort this shit out and re-arrange into something more elegant... eventually - GLuint vertexbuffer { static_cast(-1) }; - if (Global::bUseVBO) { - // odÅ›wieżenie VBO sektora - if( GLEW_VERSION_1_5 ) { - // modyfikacje VBO sÄ… dostÄ™pne od OpenGL 1.5 - vertexbuffer = m_nVBOVertices; - ::glBindBuffer( GL_ARRAY_BUFFER, vertexbuffer ); - } - else { - // dla OpenGL 1.4 z GL_ARB_vertex_buffer_object odÅ›wieżenie caÅ‚ego sektora - Release(); // opróżnienie VBO sektora, aby siÄ™ odÅ›wieżyÅ‚ z nowymi ustawieniami - } - } - tTrackAnim = tTrackAnim->RaAnimate( vertexbuffer ); // przeliczenie animacji kolejnego + tTrackAnim = tTrackAnim->RaAnimate(); // przeliczenie animacji kolejnego }; TTraction * TSubRect::FindTraction(glm::dvec3 const &Point, int &iConnection, TTraction *Exclude) @@ -562,126 +460,69 @@ TTraction * TSubRect::FindTraction(glm::dvec3 const &Point, int &iConnection, TT return NULL; }; -void TSubRect::LoadNodes() -{ // utworzenie siatek VBO dla wszystkich node w sektorze - if (m_nVertexCount >= 0) - return; // obiekty byÅ‚y już sprawdzone - m_nVertexCount = 0; //-1 oznacza, że nie sprawdzono listy obiektów - if (!nRootNode) +// utworzenie siatek VBO dla wszystkich node w sektorze +void TSubRect::LoadNodes() { + + if( true == m_geometrycreated ) { + // obiekty byÅ‚y już sprawdzone return; - TGroundNode *n = nRootNode; - while (n) - { - switch (n->iType) - { - case GL_TRIANGLE_STRIP: - case GL_TRIANGLE_FAN: - case GL_TRIANGLES: - n->iVboPtr = m_nVertexCount; // nowy poczÄ…tek - m_nVertexCount += n->iNumVerts; - break; - case GL_LINES: - case GL_LINE_STRIP: - case GL_LINE_LOOP: - n->iVboPtr = m_nVertexCount; // nowy poczÄ…tek - m_nVertexCount += n->iNumPts; // miejsce w tablicach normalnych i teksturowania siÄ™ zmarnuje... - break; - case TP_TRACK: - n->iVboPtr = m_nVertexCount; // nowy poczÄ…tek - n->iNumVerts = n->pTrack->RaArrayPrepare(); // zliczenie wierzchoÅ‚ków - m_nVertexCount += n->iNumVerts; - break; - case TP_TRACTION: - n->hvTraction->create_geometry( m_geometrybank, n->m_rootposition ); - break; - } - n = n->nNext2; // nastÄ™pny z sektora } - if (m_nVertexCount <= 0) - return; // jeÅ›li nie ma obiektów do wyÅ›wietlenia z VBO, to koniec - if (Global::bUseVBO) - { // tylko liczenie wierzchołów, gdy nie ma VBO + else { + // mark it done for future checks + m_geometrycreated = true; + } - MakeArray(m_nVertexCount); - - n = nRootNode; - int i; - while (n) - { - if (n->iVboPtr >= 0) - switch (n->iType) - { - case GL_TRIANGLE_STRIP: - case GL_TRIANGLE_FAN: - case GL_TRIANGLES: - for (i = 0; i < n->iNumVerts; ++i) - { // Ra: trójkÄ…ty można od razu wczytywać do takich tablic... to może poczekać - m_pVNT[ n->iVboPtr + i ].position = n->Vertices[ i ].position - n->m_rootposition; -/* - m_pVNT[n->iVboPtr + i].x = n->Vertices[i].position.x - n->m_rootposition.x; - m_pVNT[n->iVboPtr + i].y = n->Vertices[i].position.y - n->m_rootposition.y; - m_pVNT[n->iVboPtr + i].z = n->Vertices[i].position.z - n->m_rootposition.z; -*/ - m_pVNT[ n->iVboPtr + i ].normal = n->Vertices[ i ].normal; -/* - m_pVNT[n->iVboPtr + i].nx = n->Vertices[i].normal.x; - m_pVNT[n->iVboPtr + i].ny = n->Vertices[i].normal.y; - m_pVNT[n->iVboPtr + i].nz = n->Vertices[i].normal.z; -*/ - m_pVNT[ n->iVboPtr + i ].texture = n->Vertices[ i ].texture; -/* - m_pVNT[n->iVboPtr + i].u = n->Vertices[i].tu; - m_pVNT[n->iVboPtr + i].v = n->Vertices[i].tv; -*/ - } - break; - case GL_LINES: - case GL_LINE_STRIP: - case GL_LINE_LOOP: - for (i = 0; i < n->iNumPts; ++i) - { - m_pVNT[ n->iVboPtr + i ].position = ( n->Points[ i ] - n->m_rootposition ); -/* - glm::vec3( - n->Points[ i ].x - n->m_rootposition.x, - n->Points[ i ].y - n->m_rootposition.y, - n->Points[ i ].z - n->m_rootposition.z ); -*/ - // miejsce w tablicach normalnych i teksturowania siÄ™ marnuje... - } - break; - case TP_TRACK: - if( n->iNumVerts ) { // bo tory zabezpieczajÄ…ce sÄ… niewidoczne -#ifdef EU07_USE_OLD_VERTEXBUFFER - n->pTrack->RaArrayFill( m_pVNT + n->iVboPtr, m_pVNT, std::min( n->iNumVerts, m_nVertexCount - n->iVboPtr ) ); -#else - n->pTrack->RaArrayFill( m_pVNT.data() + n->iVboPtr, m_pVNT.data(), std::min( n->iNumVerts, m_nVertexCount - n->iVboPtr ) ); -#endif - } - break; - default: - break; + auto *node { nRootNode }; + while( node != nullptr ) { + switch (node->iType) { + case GL_TRIANGLES: { + vertex_array vertices; + for( std::size_t idx = 0; idx < node->iNumVerts; ++idx ) { + vertices.emplace_back( + node->Vertices[ idx ].position - node->m_rootposition, + node->Vertices[ idx ].normal, + node->Vertices[ idx ].texture ); } - n = n->nNext2; // nastÄ™pny z sektora + node->m_geometry = GfxRenderer.Insert( vertices, m_geometrybank, GL_TRIANGLES ); + SafeDeleteArray( node->Vertices ); + node->iNumVerts = 0; + break; + } + case GL_LINES: { + vertex_array vertices; + for( std::size_t idx = 0; idx < node->iNumPts; ++idx ) { + vertices.emplace_back( + node->Points[ idx ] - node->m_rootposition, + glm::vec3(), + glm::vec2() ); + } + node->m_geometry = GfxRenderer.Insert( vertices, m_geometrybank, GL_LINES ); + SafeDeleteArray( node->Vertices ); + node->iNumPts = 0; + break; + } + case TP_TRACK: + if( node->pTrack->bVisible ) { // bo tory zabezpieczajÄ…ce sÄ… niewidoczne + node->pTrack->create_geometry( m_geometrybank ); + } + break; + case TP_TRACTION: + node->hvTraction->create_geometry( m_geometrybank, node->m_rootposition ); + break; + default: { break; } } - BuildVBOs(); + node = node->nNext2; // nastÄ™pny z sektora } +/* if (Global::bManageNodes) ResourceManager::Register(this); // dodanie do automatu zwalniajÄ…cego pamięć +*/ } - -bool TSubRect::StartVBO() -{ // poczÄ…tek rysowania elementów z VBO w sektorze - SetLastUsage(Timer::GetSimulationTime()); // te z tyÅ‚u bÄ™dÄ… niepotrzebnie zwalniane - return CMesh::StartVBO(); -}; - +/* void TSubRect::Release() { // wirtualne zwolnienie zasobów przez sprzÄ…tacz albo destruktor - if (Global::bUseVBO) - CMesh::Clear(); // usuwanie buforów }; - +*/ void TSubRect::RenderSounds() { // aktualizacja dźwiÄ™ków w pojazdach sektora (sektor może nie być wyÅ›wietlany) for (int j = 0; j < iTracks; ++j) @@ -708,7 +549,7 @@ TGroundRect::Init() { float const subrectsize = 1000.0f / iNumSubRects; for( int column = 0; column < iNumSubRects; ++column ) { for( int row = 0; row < iNumSubRects; ++row ) { - auto subcell = FastGetRect( column, row ); + auto subcell = FastGetSubRect( column, row ); auto &area = subcell->m_area; area.center = m_area.center @@ -734,8 +575,9 @@ TGround::TGround() nRootOfType[ i ] = nullptr; // zerowanie tablic wyszukiwania } ::SecureZeroMemory( TempConnectionType, sizeof( TempConnectionType ) ); +/* ::SecureZeroMemory( pRendered, sizeof( pRendered ) ); - +*/ // set bounding area information for ground rectangles float const rectsize = 1000.0f; glm::vec3 const worldcenter; @@ -876,9 +718,9 @@ void TGround::RaTriangleDivider(TGroundNode *node) return; // tylko pojedyncze trójkÄ…ty if (node->iNumVerts != 3) return; // tylko gdy jeden trójkÄ…t - double x0 = 1000.0 * floor(0.001 * node->pCenter.x) - 200.0; + double x0 = 1000.0 * std::floor(0.001 * node->pCenter.x) - 200.0; double x1 = x0 + 1400.0; - double z0 = 1000.0 * floor(0.001 * node->pCenter.z) - 200.0; + double z0 = 1000.0 * std::floor(0.001 * node->pCenter.z) - 200.0; double z1 = z0 + 1400.0; if ((node->Vertices[0].position.x >= x0) && (node->Vertices[0].position.x <= x1) && (node->Vertices[0].position.z >= z0) && (node->Vertices[0].position.z <= z1) && @@ -999,7 +841,6 @@ void TGround::RaTriangleDivider(TGroundNode *node) TGroundNode * TGround::AddGroundNode(cParser *parser) { // wczytanie wpisu typu "node" std::string str, str1, str2, str3, str4, Skin, DriverType, asNodeName; - int nv, i; double tf, r, rmin, tf1, tf3; int int1; size_t int2; @@ -1415,7 +1256,7 @@ TGroundNode * TGround::AddGroundNode(cParser *parser) tmp->nNode[0].iType = TP_MODEL; // pierwszy zawiera model (dla delete) tmp->nNode[0].Model = Global::pTerrainCompact; tmp->nNode[0].iFlags = 0x200; // nie wyÅ›wietlany, ale usuwany - for (i = 1; i < tmp->iCount; ++i) + for (std::size_t i = 1; i < tmp->iCount; ++i) { // a reszta to submodele tmp->nNode[i].iType = TP_SUBMODEL; // tmp->nNode[i].smTerrain = Global::pTerrainCompact->TerrainSquare(i - 1); @@ -1498,19 +1339,20 @@ TGroundNode * TGround::AddGroundNode(cParser *parser) #endif tmp->TextureID = GfxRenderer.GetTextureId( str, szTexturePath ); tmp->iFlags = GfxRenderer.Texture(tmp->TextureID).has_alpha ? 0x220 : 0x210; // z usuwaniem - if (((tmp->iType == GL_TRIANGLES) && (tmp->iFlags & 0x10)) ? - Global::pTerrainCompact->TerrainLoaded() : - false) - { // jeÅ›li jest tekstura nieprzezroczysta, a teren zaÅ‚adowany, to pomijamy trójkÄ…ty - do - { // pomijanie trójkÄ…tów + if( (tmp->iType == GL_TRIANGLES) + && (tmp->iFlags & 0x10) + && (Global::pTerrainCompact->TerrainLoaded()) ) { + // jeÅ›li jest tekstura nieprzezroczysta, a teren zaÅ‚adowany, to pomijamy trójkÄ…ty + do { + // pomijanie trójkÄ…tów parser->getTokens(); *parser >> token; } while (token.compare("endtri") != 0); } else { - TGroundVertex vertex; + TGroundVertex vertex, vertex1, vertex2; + std::size_t vertexcount { 0 }; do { parser->getTokens( 8, false ); *parser @@ -1522,14 +1364,6 @@ TGroundNode * TGround::AddGroundNode(cParser *parser) >> vertex.normal.z >> vertex.texture.s >> vertex.texture.t; -/* - vertex.position.RotateZ( aRotate.z / 180 * M_PI ); - vertex.position.RotateX( aRotate.x / 180 * M_PI ); - vertex.position.RotateY( aRotate.y / 180 * M_PI ); - vertex.normal.RotateZ( aRotate.z / 180 * M_PI ); - vertex.normal.RotateX( aRotate.x / 180 * M_PI ); - vertex.normal.RotateY( aRotate.y / 180 * M_PI ); -*/ vertex.position = glm::rotateZ( vertex.position, aRotate.z / 180 * M_PI ); vertex.position = glm::rotateX( vertex.position, aRotate.x / 180 * M_PI ); vertex.position = glm::rotateY( vertex.position, aRotate.y / 180 * M_PI ); @@ -1538,19 +1372,52 @@ TGroundNode * TGround::AddGroundNode(cParser *parser) vertex.normal = glm::rotateY( vertex.normal, static_cast( aRotate.y / 180 * M_PI ) ); vertex.position += glm::dvec3( pOrigin.x, pOrigin.y, pOrigin.z ); tmp->pCenter += vertex.position; - - importedvertices.emplace_back( vertex ); + // convert all data to gl_triangles to allow data merge for matching nodes + switch( tmp->iType ) { + case GL_TRIANGLES: { + importedvertices.emplace_back( vertex ); + break; + } + case GL_TRIANGLE_FAN: { + if( vertexcount == 0 ) { vertex1 = vertex; } + else if( vertexcount == 1 ) { vertex2 = vertex; } + else if( vertexcount >= 2 ) { + importedvertices.emplace_back( vertex1 ); + importedvertices.emplace_back( vertex2 ); + importedvertices.emplace_back( vertex ); + vertex2 = vertex; + } + ++vertexcount; + break; + } + case GL_TRIANGLE_STRIP: { + if( vertexcount == 0 ) { vertex1 = vertex; } + else if( vertexcount == 1 ) { vertex2 = vertex; } + else if( vertexcount >= 2 ) { + importedvertices.emplace_back( vertex1 ); + importedvertices.emplace_back( vertex2 ); + importedvertices.emplace_back( vertex ); + vertex1 = vertex2; + vertex2 = vertex; + } + ++vertexcount; + break; + } + default: { break; } + } parser->getTokens(); *parser >> token; } while (token.compare("endtri") != 0); - nv = (int)importedvertices.size(); + tmp->iType = GL_TRIANGLES; + + auto const nv = importedvertices.size(); tmp->Init(nv); // utworzenie tablicy wierzchoÅ‚ków tmp->pCenter /= (nv > 0 ? nv : 1); r = 0; - for (int i = 0; i < nv; i++) + for (std::size_t i = 0; i < nv; ++i) { tmp->Vertices[i] = importedvertices[i]; tf = SquareMagnitude( tmp->Vertices[ i ].position - tmp->pCenter ); @@ -1571,8 +1438,10 @@ TGroundNode * TGround::AddGroundNode(cParser *parser) >> tmp->Diffuse.b >> tmp->fLineThickness; tmp->Diffuse /= 255.0f; - TGroundVertex vertex; - i = 0; + + TGroundVertex vertex, vertex0, vertex1; + std::size_t vertexcount{ 0 }; + parser->getTokens(); *parser >> token; do { @@ -1581,32 +1450,64 @@ TGroundNode * TGround::AddGroundNode(cParser *parser) *parser >> vertex.position.y >> vertex.position.z; -/* - vertex.position.RotateZ( aRotate.z / 180 * M_PI ); - vertex.position.RotateX( aRotate.x / 180 * M_PI ); - vertex.position.RotateY( aRotate.y / 180 * M_PI ); -*/ vertex.position = glm::rotateZ( vertex.position, aRotate.z / 180 * M_PI ); vertex.position = glm::rotateX( vertex.position, aRotate.x / 180 * M_PI ); vertex.position = glm::rotateY( vertex.position, aRotate.y / 180 * M_PI ); vertex.position += glm::dvec3( pOrigin.x, pOrigin.y, pOrigin.z ); - tmp->pCenter += vertex.position; - - importedvertices.emplace_back( vertex ); - - ++i; + // convert all data to gl_lines to allow data merge for matching nodes + switch( tmp->iType ) { + case GL_LINES: { + importedvertices.emplace_back( vertex ); + break; + } + case GL_LINE_STRIP: { + if( vertexcount > 0 ) { + importedvertices.emplace_back( vertex1 ); + importedvertices.emplace_back( vertex ); + } + vertex1 = vertex; + ++vertexcount; + break; + } + case GL_LINE_LOOP: { + if( vertexcount == 0 ) { + vertex0 = vertex; + vertex1 = vertex; + } + else { + importedvertices.emplace_back( vertex1 ); + importedvertices.emplace_back( vertex ); + } + vertex1 = vertex; + ++vertexcount; + break; + } + default: { break; } + } parser->getTokens(); *parser >> token; } while( token.compare( "endline" ) != 0 ); - nv = i; - // tmp->Init(nv); + // add closing line for the loop + if( ( tmp->iType == GL_LINE_LOOP ) + && ( vertexcount > 2 ) ) { + importedvertices.emplace_back( vertex1 ); + importedvertices.emplace_back( vertex0 ); + } + if( importedvertices.size() % 2 != 0 ) { + ErrorLog( "Lines node specified odd number of vertices, encountered in file \"" + parser->Name() + "\"" ); + importedvertices.pop_back(); + } + tmp->iType = GL_LINES; + + auto const nv = importedvertices.size(); tmp->Points = new glm::dvec3[ nv ]; tmp->iNumPts = nv; tmp->pCenter /= ( nv > 0 ? nv : 1 ); - for( int i = 0; i < nv; i++ ) + for( std::size_t i = 0; i < nv; ++i ) { tmp->Points[ i ] = importedvertices[ i ].position; + } break; } } @@ -1622,7 +1523,7 @@ TSubRect * TGround::FastGetSubRect(int iCol, int iRow) sc = iCol - bc * iNumSubRects; if ((br < 0) || (bc < 0) || (br >= iNumRects) || (bc >= iNumRects)) return NULL; - return (Rects[bc][br].FastGetRect(sc, sr)); + return (Rects[bc][br].FastGetSubRect(sc, sr)); } TSubRect * TGround::GetSubRect(int iCol, int iRow) @@ -1634,7 +1535,7 @@ TSubRect * TGround::GetSubRect(int iCol, int iRow) sc = iCol - bc * iNumSubRects; if ((br < 0) || (bc < 0) || (br >= iNumRects) || (bc >= iNumRects)) return NULL; // jeÅ›li poza mapÄ… - return (Rects[bc][br].SafeGetRect(sc, sr)); // pobranie maÅ‚ego kwadratu + return (Rects[bc][br].SafeGetSubRect(sc, sr)); // pobranie maÅ‚ego kwadratu } TEvent * TGround::FindEvent(const std::string &asEventName) @@ -1670,23 +1571,21 @@ void TGround::FirstInit() return; // Ra: żeby nie robiÅ‚o siÄ™ dwa razy bInitDone = true; WriteLog("InitNormals"); - int i, j; - for (i = 0; i < TP_LAST; ++i) - { - for (TGroundNode *Current = nRootOfType[i]; Current; Current = Current->nNext) - { + for (int type = 0; type < TP_LAST; ++type) { + for (TGroundNode *Current = nRootOfType[type]; Current != nullptr; Current = Current->nNext) { + Current->InitNormals(); if (Current->iType != TP_DYNAMIC) { // pojazdów w ogóle nie dotyczy dodawanie do mapy - if( ( i == TP_EVLAUNCH ) + if( ( type == TP_EVLAUNCH ) && ( true == Current->EvLaunch->IsGlobal() ) ) { // dodanie do globalnego obiektu srGlobal.NodeAdd( Current ); } - else if (i == TP_TERRAIN) + else if (type == TP_TERRAIN) { // specjalne przetwarzanie terenu wczytanego z pliku E3D TGroundRect *gr; - for (j = 1; j < Current->iCount; ++j) + for (int j = 1; j < Current->iCount; ++j) { // od 1 do koÅ„ca sÄ… zestawy trójkÄ…tów std::string xxxzzz = Current->nNode[j].smTerrain->pName; // pobranie nazwy gr = GetRect( @@ -1706,6 +1605,7 @@ void TGround::FirstInit() // dodajemy do kwadratu kilometrowego // override visibility ranges, to ensure the content is drawn from far enough // TODO: subclass NodeAdd() for the ground cell and specialize it, instead of this + // TODO: given their view ranges are the same, combine the geometry in single per-material nodes Current->fSquareRadius = 50000.0 * 50000.0; Current->fSquareMinRadius = 0.0; GetRect( Current->pCenter.x, Current->pCenter.z )->NodeAdd( Current ); @@ -1713,8 +1613,8 @@ void TGround::FirstInit() } } } - for (i = 0; i < iNumRects; ++i) - for (j = 0; j < iNumRects; ++j) + for (std::size_t i = 0; i < iNumRects; ++i) + for (std::size_t j = 0; j < iNumRects; ++j) Rects[i][j].Optimize(); // optymalizacja obiektów w sektorach WriteLog("InitNormals OK"); @@ -1751,7 +1651,7 @@ bool TGround::Init(std::string File) std::stack OriginStack; // stos zagnieżdżenia origin - TGroundNode *LastNode = NULL; // do użycia w trainset + TGroundNode *LastNode = nullptr; // do użycia w trainset iNumNodes = 0; token = ""; parser.getTokens(); @@ -1763,64 +1663,76 @@ bool TGround::Init(std::string File) ++processed; if( processed % 1000 == 0 ) { + glfwPollEvents(); UILayer.set_progress( parser.getProgress(), parser.getFullProgress() ); GfxRenderer.Render(); - glfwPollEvents(); } str = token; - if (str == "node") - { - LastNode = AddGroundNode(&parser); // rozpoznanie wÄ™zÅ‚a - if (LastNode) - { // jeżeli przetworzony poprawnie - if (LastNode->iType == GL_TRIANGLES) - { - if (!LastNode->Vertices) - SafeDelete(LastNode); // usuwamy nieprzezroczyste trójkÄ…ty terenu - } - else if( ( LastNode->iType == TP_TRACTION ) - && ( false == Global::bLoadTraction ) ) { - SafeDelete( LastNode ); // usuwamy druty, jeÅ›li wyłączone + if (str == "node") { + // rozpoznanie wÄ™zÅ‚a + LastNode = AddGroundNode(&parser); + if (LastNode) { + // jeżeli przetworzony poprawnie + switch( LastNode->iType ) { + // validate the new node + case GL_TRIANGLES: { + if( LastNode->Vertices == nullptr ) { + SafeDelete( LastNode ); + } + break; + } + case TP_TRACTION: { + if( false == Global::bLoadTraction ) { + // usuwamy druty, jeÅ›li wyłączone + SafeDelete( LastNode ); + } + break; + } + default: { + break; + } } - if (LastNode) // dopiero na koniec dopisujemy do tablic - if (LastNode->iType != TP_DYNAMIC) - { // jeÅ›li nie jest pojazdem - // ostatni dodany dołączamy na koÅ„cu nowego - LastNode->nNext = nRootOfType[LastNode->iType]; + if( LastNode ) { + // dopiero na koniec dopisujemy do tablic + if( LastNode->iType != TP_DYNAMIC ) { + // jeÅ›li nie jest pojazdem ostatni dodany dołączamy na koÅ„cu nowego + LastNode->nNext = nRootOfType[ LastNode->iType ]; // ustawienie nowego na poczÄ…tku listy - nRootOfType[LastNode->iType] = LastNode; - iNumNodes++; + nRootOfType[ LastNode->iType ] = LastNode; + ++iNumNodes; } - else - { // jeÅ›li jest pojazdem - // if (!bInitDone) FirstInit(); //jeÅ›li nie byÅ‚o w scenerii - if (LastNode->DynamicObject->Mechanik) // ale może być pasażer - if (LastNode->DynamicObject->Mechanik - ->Primary()) // jeÅ›li jest głównym (pasażer nie jest) - nTrainSetDriver = - LastNode; // pojazd, któremu zostanie wysÅ‚any rozkÅ‚ad + else { // jeÅ›li jest pojazdem + if( ( LastNode->DynamicObject->Mechanik != nullptr ) + && ( LastNode->DynamicObject->Mechanik->Primary() ) ) { + // jeÅ›li jest głównym (pasażer nie jest) + nTrainSetDriver = LastNode; // pojazd, któremu zostanie wysÅ‚any rozkÅ‚ad + } LastNode->nNext = nRootDynamic; nRootDynamic = LastNode; // dopisanie z przodu do listy - // if (bTrainSet && (LastNode?(LastNode->iType==TP_DYNAMIC):false)) - if (nTrainSetNode) // jeżeli istnieje wczeÅ›niejszy TP_DYNAMIC + + if( nTrainSetNode != nullptr ) { + // jeżeli istnieje wczeÅ›niejszy TP_DYNAMIC nTrainSetNode->DynamicObject->AttachPrev( LastNode->DynamicObject, - TempConnectionType[iTrainSetWehicleNumber - 2]); + TempConnectionType[ iTrainSetWehicleNumber - 2 ] ); + } nTrainSetNode = LastNode; // ostatnio wczytany - if (TempConnectionType[iTrainSetWehicleNumber - 1] == - 0) // jeÅ›li sprzÄ™g jest zerowy, to wysÅ‚ać rozkÅ‚ad do skÅ‚adu + + if( TempConnectionType[ iTrainSetWehicleNumber - 1 ] == 0 ) // jeÅ›li sprzÄ™g jest zerowy, to wysÅ‚ać rozkÅ‚ad do skÅ‚adu { // powinien też tu wchodzić, gdy pojazd bez trainset - if (nTrainSetDriver) // pojazd, któremu zostanie wysÅ‚any rozkÅ‚ad + if( nTrainSetDriver ) // pojazd, któremu zostanie wysÅ‚any rozkÅ‚ad { // wysÅ‚anie komendy "Timetable" ustawia odpowiedni tryb jazdy nTrainSetDriver->DynamicObject->Mechanik->DirectionInitial(); nTrainSetDriver->DynamicObject->Mechanik->PutCommand( - "Timetable:" + asTrainName, fTrainSetVel, 0, NULL); - nTrainSetDriver = - NULL; // a przy "endtrainset" już wtedy nie potrzeba + "Timetable:" + asTrainName, + fTrainSetVel, 0, + nullptr ); + nTrainSetDriver = nullptr; // a przy "endtrainset" już wtedy nie potrzeba } } } + } } else { @@ -1927,10 +1839,11 @@ bool TGround::Init(std::string File) RootEvent = tmp; if (!found) { // jeÅ›li nazwa wystÄ…piÅ‚a, to do kolejki i wyszukiwarki dodawany jest tylko pierwszy - if (RootEvent->Type != tp_Ignored) - if (RootEvent->asName.find( - "onstart") != std::string::npos) // event uruchamiany automatycznie po starcie - AddToQuery(RootEvent, NULL); // dodanie do kolejki + if( ( RootEvent->Type != tp_Ignored ) + && ( RootEvent->asName.find( "onstart" ) != std::string::npos ) ) { + // event uruchamiany automatycznie po starcie + AddToQuery( RootEvent, NULL ); // dodanie do kolejki + } m_eventmap.emplace( tmp->asName, tmp ); // dodanie do wyszukiwarki } } diff --git a/Ground.h b/Ground.h index 55b4a819..99f639e9 100644 --- a/Ground.h +++ b/Ground.h @@ -21,8 +21,6 @@ http://mozilla.org/MPL/2.0/. #include "Names.h" #include "lightarray.h" -using namespace Math3D; - typedef int TGroundNodeType; // Ra: zmniejszone liczby, aby zrobić tabelkÄ™ i zoptymalizować wyszukiwanie const int TP_MODEL = 10; @@ -95,8 +93,14 @@ struct TGroundVertex texture = interpolate( v1.texture, v2.texture, static_cast( factor ) ); } }; - -class TGroundNode : public Resource +/* +// ground node holding single, unique piece of 3d geometry. TBD, TODO: unify this with basic 3d model node +struct mesh_node { + std::vector vertices; + geometry_handle geometry; // geometry prepared for drawing +}; +*/ +class TGroundNode /*: public Resource*/ { // obiekt scenerii friend class opengl_renderer; @@ -138,6 +142,9 @@ public: int iVersion; // wersja siatki (do wykonania rekompilacji) GLuint DisplayListID; // numer siatki DisplayLists int iVboPtr; // indeks w buforze VBO + // NOTE: geometry handle is duplicated in (anim)model(3d), as well as in track and traction type nodes + // TODO: clean this up when node types are refactored into an inheritance/composition scheme + geometry_handle m_geometry; // geometry of the submodel int iFlags; // tryb przezroczystoÅ›ci: 0x10-nieprz.,0x20-przezroczysty,0x30-mieszany texture_handle TextureID; // główna (jedna) tekstura obiektu glm::vec3 @@ -153,25 +160,10 @@ public: ~TGroundNode(); void Init(int n); void InitNormals(); - - // bool Disable(); - inline TGroundNode * Find(const std::string &asNameToFind, TGroundNodeType iNodeType) - { // wyszukiwanie czoÅ‚gowe z typem - if ((iNodeType == iType) && (asNameToFind == asName)) - return this; - else if (nNext) - return nNext->Find(asNameToFind, iNodeType); - return NULL; - }; - - void Compile(glm::dvec3 const &Origin, bool const Multiple = false); +/* void Release(); - +*/ void RenderHidden(); // obsÅ‚uga dźwiÄ™ków i wyzwalaczy zdarzeÅ„ -#ifdef EU07_USE_OLD_RENDERCODE - // (McZapkie-131202) - void RaRenderVBO(); // renderowanie (nieprzezroczystych) ze wspólnego VBO -#endif }; struct bounding_area { @@ -180,7 +172,7 @@ struct bounding_area { float radius { 0.0f }; // radius of the bounding sphere }; -class TSubRect : public Resource, public CMesh +class TSubRect : /*public Resource,*/ public CMesh { // sektor skÅ‚adowy kwadratu kilometrowego public: bounding_area m_area; @@ -209,12 +201,13 @@ class TSubRect : public Resource, public CMesh void LoadNodes(); // utworzenie VBO sektora public: virtual ~TSubRect(); +/* virtual void Release(); // zwalnianie VBO sektora +*/ void NodeAdd(TGroundNode *Node); // dodanie obiektu do sektora na etapie rozdzielania na sektory void Sort(); // optymalizacja obiektów w sektorze (sortowanie wg tekstur) TTrack * FindTrack(vector3 *Point, int &iConnection, TTrack *Exclude); TTraction * FindTraction(glm::dvec3 const &Point, int &iConnection, TTraction *Exclude); - bool StartVBO(); // ustwienie VBO sektora dla (nRenderRect), (nRenderRectAlpha) i (nRenderWires) bool RaTrackAnimAdd(TTrack *t); // zgÅ‚oszenie toru do animacji void RaAnimate(); // przeliczenie animacji torów void RenderSounds(); // dźwiÄ™ki pojazdów z niewidocznych sektorów @@ -244,7 +237,7 @@ private: public: virtual ~TGroundRect(); // pobranie wskaźnika do maÅ‚ego kwadratu, utworzenie jeÅ›li trzeba - TSubRect * SafeGetRect(int iCol, int iRow) { + TSubRect * SafeGetSubRect(int iCol, int iRow) { if( !pSubRects ) { // utworzenie maÅ‚ych kwadratów Init(); @@ -252,7 +245,7 @@ public: return pSubRects + iRow * iNumSubRects + iCol; // zwrócenie wÅ‚aÅ›ciwego }; // pobranie wskaźnika do maÅ‚ego kwadratu, bez tworzenia jeÅ›li nie ma - TSubRect * FastGetRect(int iCol, int iRow) { + TSubRect * FastGetSubRect(int iCol, int iRow) { return (pSubRects ? pSubRects + iRow * iNumSubRects + iCol : NULL); }; // optymalizacja obiektów w sektorach @@ -282,7 +275,9 @@ class TGround *tmpEvent = nullptr, *tmp2Event = nullptr, *OldQRE = nullptr; +/* TSubRect *pRendered[1500]; // lista renderowanych sektorów +*/ int iNumNodes = 0; vector3 pOrigin; vector3 aRotate; @@ -293,6 +288,7 @@ class TGround event_map m_eventmap; TNames m_trackmap; light_array m_lights; // collection of dynamic light sources present in the scene + bool PROBLEND; private: // metody prywatne bool EventConditon(TEvent *e); @@ -351,7 +347,6 @@ class TGround private: void RaTriangleDivider(TGroundNode *node); void Navigate(std::string const &ClassName, UINT Msg, WPARAM wParam, LPARAM lParam); - bool PROBLEND; public: void WyslijEvent(const std::string &e, const std::string &d); diff --git a/Model3d.cpp b/Model3d.cpp index 1c5e444c..7f13e17f 100644 --- a/Model3d.cpp +++ b/Model3d.cpp @@ -1041,7 +1041,7 @@ void TSubModel::RaAnimation(TAnimType a) //--------------------------------------------------------------------------- -void TSubModel::RaArrayFill(CVertNormTex *Vert) +void TSubModel::RaArrayFill(basic_vertex *Vert) { // wypeÅ‚nianie tablic VBO if (Child) Child->RaArrayFill(Vert); @@ -1159,17 +1159,11 @@ TModel3d::~TModel3d() { // SafeDeleteArray(Materials); if (iFlags & 0x0200) - { // wczytany z pliku tekstowego, submodele sprzÄ…tajÄ… - // same + { // wczytany z pliku tekstowego, submodele sprzÄ…tajÄ… same SafeDelete(Root); // submodele siÄ™ usunÄ… rekurencyjnie } else { // wczytano z pliku binarnego (jest wÅ‚aÅ›cicielem tablic) -#ifdef EU07_USE_OLD_VERTEXBUFFER - m_pVNT = nullptr; // nie usuwać tego, bo wskazuje na iModel -#else - m_pVNT.clear(); -#endif Root = nullptr; delete[] iModel; // usuwamy caÅ‚y wczytany plik i to wystarczy } @@ -1344,6 +1338,9 @@ void TSubModel::serialize(std::ostream &s, void TModel3d::SaveToBinFile(char const *FileName) { + // TODO: re-implement! + return; + WriteLog("saving e3d model.."); //m7todo: można by zoptymalizować robiÄ…c unordered_map @@ -1379,18 +1376,20 @@ void TModel3d::SaveToBinFile(char const *FileName) sn_utils::ls_uint32(s, 8 + (uint32_t)transforms.size() * 64); for (size_t i = 0; i < transforms.size(); i++) transforms[i].serialize_float32(s); - +/* MakeArray(iNumVerts); #ifdef EU07_USE_OLD_VERTEXBUFFER Root->RaArrayFill(m_pVNT); #else Root->RaArrayFill( m_pVNT.data() ); #endif +*/ sn_utils::ls_uint32(s, MAKE_ID4('V', 'N', 'T', '0')); sn_utils::ls_uint32(s, 8 + iNumVerts * 32); +/* for (size_t i = 0; i < (size_t)iNumVerts; i++) m_pVNT[i].serialize(s); - +*/ if (textures.size()) { sn_utils::ls_uint32(s, MAKE_ID4('T', 'E', 'X', '0')); @@ -1470,11 +1469,6 @@ void TSubModel::deserialize(std::istream &s) void TModel3d::deserialize(std::istream &s, size_t size, bool dynamic) { -#ifdef EU07_USE_OLD_VERTEXBUFFER - m_pVNT = nullptr; -#else - m_pVNT.clear(); -#endif Root = nullptr; float4x4 *tm = nullptr; if( m_geometrybank == NULL ) { @@ -1507,19 +1501,16 @@ void TModel3d::deserialize(std::istream &s, size_t size, bool dynamic) } else if (type == MAKE_ID4('V', 'N', 'T', '0')) { -#ifdef EU07_USE_OLD_VERTEXBUFFER - if (m_pVNT != nullptr) -#else - if( false == m_pVNT.empty() ) -#endif - throw std::runtime_error("e3d: duplicated VNT chunk"); /* - size_t vt_cnt = size / 32; + if (m_pVNT != nullptr) + throw std::runtime_error("e3d: duplicated VNT chunk"); + + size_t vt_cnt = size / 32; iNumVerts = (int)vt_cnt; m_nVertexCount = (int)vt_cnt; #ifdef EU07_USE_OLD_VERTEXBUFFER assert( m_pVNT == nullptr ); - m_pVNT = new CVertNormTex[vt_cnt]; + m_pVNT = new basic_vertex[vt_cnt]; #else m_pVNT.resize( vt_cnt ); #endif @@ -1613,13 +1604,9 @@ void TModel3d::deserialize(std::istream &s, size_t size, bool dynamic) */ for (size_t i = 0; (int)i < iSubModelsCount; ++i) { -#ifdef EU07_USE_OLD_VERTEXBUFFER Root[i].BinInit( Root, tm, &Textures, &Names, dynamic ); -#else - Root[ i ].BinInit( Root, tm, (float8*)m_pVNT.data(), &Textures, &Names, dynamic ); -#endif - if (Root[i].ChildGet()) + if (Root[i].ChildGet()) Root[i].ChildGet()->Parent = &Root[i]; if (Root[i].NextGet()) Root[i].NextGet()->Parent = Root[i].Parent; diff --git a/Model3d.h b/Model3d.h index a78712eb..136bfac7 100644 --- a/Model3d.h +++ b/Model3d.h @@ -168,7 +168,7 @@ public: TSubModel * GetFromName(char const *search, bool i = true); inline float4x4 * GetMatrix() { return fMatrix; }; inline void Hide() { iVisible = 0; }; - void RaArrayFill(CVertNormTex *Vert); + void RaArrayFill(basic_vertex *Vert); int FlagsCheck(); void WillBeAnimated() { diff --git a/Segment.cpp b/Segment.cpp index a39c46b6..c74451bd 100644 --- a/Segment.cpp +++ b/Segment.cpp @@ -319,16 +319,15 @@ vector3 TSegment::FastGetPoint(double t) return (bCurve ? RaInterpolate(t) : ((1.0 - t) * Point1 + (t)*Point2)); } -int TSegment::RenderLoft( CVertNormTex* &Output, Math3D::vector3 const &Origin, const vector6 *ShapePoints, int iNumShapePoints, double fTextureLength, double Texturescale, int iSkip, int iEnd, double fOffsetX, vector3 **p, bool bRender) +bool TSegment::RenderLoft( vertex_array &Output, Math3D::vector3 const &Origin, const vector6 *ShapePoints, int iNumShapePoints, double fTextureLength, double Texturescale, int iSkip, int iEnd, double fOffsetX, vector3 **p, bool bRender) { // generowanie trójkÄ…tów dla odcinka trajektorii ruchu // standardowo tworzy triangle_strip dla prostego albo ich zestaw dla Å‚uku // po modyfikacji - dla ujemnego (iNumShapePoints) w dodatkowych polach tabeli // podany jest przekrój koÅ„cowy // podsypka toru jest robiona za pomocÄ… 6 punktów, szyna 12, drogi i rzeki na 3+2+3 - int vertexcount{ 0 }; if( !fTsBuffer ) - return vertexcount; // prowizoryczne zabezpieczenie przed wysypem - ustalić faktycznÄ… przyczynÄ™ + return false; // prowizoryczne zabezpieczenie przed wysypem - ustalić faktycznÄ… przyczynÄ™ vector3 pos1, pos2, dir, parallel1, parallel2, pt, norm; double s, step, fOffset, tv1, tv2, t, fEnd; @@ -378,11 +377,6 @@ int TSegment::RenderLoft( CVertNormTex* &Output, Math3D::vector3 const &Origin, dir = FastGetDirection( t, fOffset ); // nowy wektor kierunku parallel2 = Normalize( vector3( -dir.z, 0.0, dir.x ) ); // wektor poprzeczny - if( Output == nullptr ) { - // immediate mode - ::glBegin( GL_TRIANGLE_STRIP ); - } - if( trapez ) { for( int j = 0; j < iNumShapePoints; ++j ) { pt = parallel1 * ( jmm1 * ( ShapePoints[ j ].x - fOffsetX ) + m1 * ShapePoints[ j + iNumShapePoints ].x ) + pos1; @@ -390,25 +384,12 @@ int TSegment::RenderLoft( CVertNormTex* &Output, Math3D::vector3 const &Origin, pt -= Origin; norm = ( jmm1 * ShapePoints[ j ].n.x + m1 * ShapePoints[ j + iNumShapePoints ].n.x ) * parallel1; norm.y += jmm1 * ShapePoints[ j ].n.y + m1 * ShapePoints[ j + iNumShapePoints ].n.y; - if( bRender ) { // skrzyżowania podczas łączenia siatek mogÄ… nie renderować poboczy, ale potrzebować punktów - if( Output == nullptr ) { - // immediate mode - ::glNormal3f( norm.x, norm.y, norm.z ); - ::glTexCoord2f( (jmm1 * ShapePoints[ j ].z + m1 * ShapePoints[ j + iNumShapePoints ].z) / Texturescale, tv1 ); - ::glVertex3f( pt.x, pt.y, pt.z ); // pt nie mamy gdzie zapamiÄ™tać? - } - else { - Output->position.x = pt.x; - Output->position.y = pt.y; - Output->position.z = pt.z; - Output->normal.x = norm.x; - Output->normal.y = norm.y; - Output->normal.z = norm.z; - Output->texture.s = (jmm1 * ShapePoints[ j ].z + m1 * ShapePoints[ j + iNumShapePoints ].z) / Texturescale; - Output->texture.t = tv1; - ++Output; - } - ++vertexcount; + if( bRender ) { + // skrzyżowania podczas łączenia siatek mogÄ… nie renderować poboczy, ale potrzebować punktów + Output.emplace_back( + glm::vec3 { pt.x, pt.y, pt.z }, + glm::vec3 { norm.x, norm.y, norm.z }, + glm::vec2 { ( jmm1 * ShapePoints[ j ].z + m1 * ShapePoints[ j + iNumShapePoints ].z ) / Texturescale, tv1 } ); } if( p ) // jeÅ›li jest wskaźnik do tablicy if( *p ) @@ -423,25 +404,12 @@ int TSegment::RenderLoft( CVertNormTex* &Output, Math3D::vector3 const &Origin, pt -= Origin; norm = ( jmm1 * ShapePoints[ j ].n.x + m1 * ShapePoints[ j + iNumShapePoints ].n.x ) * parallel2; norm.y += jmm1 * ShapePoints[ j ].n.y + m1 * ShapePoints[ j + iNumShapePoints ].n.y; - if( bRender ) { // skrzyżowania podczas łączenia siatek mogÄ… nie renderować poboczy, ale potrzebować punktów - if( Output == nullptr ) { - // immediate mode - ::glNormal3f( norm.x, norm.y, norm.z ); - ::glTexCoord2f( (jmm2 * ShapePoints[ j ].z + m2 * ShapePoints[ j + iNumShapePoints ].z) / Texturescale, tv2 ); - ::glVertex3f( pt.x, pt.y, pt.z ); - } - else { - Output->position.x = pt.x; - Output->position.y = pt.y; - Output->position.z = pt.z; - Output->normal.x = norm.x; - Output->normal.y = norm.y; - Output->normal.z = norm.z; - Output->texture.s = (jmm2 * ShapePoints[ j ].z + m2 * ShapePoints[ j + iNumShapePoints ].z) / Texturescale; - Output->texture.t = tv2; - ++Output; - } - ++vertexcount; + if( bRender ) { + // skrzyżowania podczas łączenia siatek mogÄ… nie renderować poboczy, ale potrzebować punktów + Output.emplace_back( + glm::vec3 { pt.x, pt.y, pt.z }, + glm::vec3 { norm.x, norm.y, norm.z }, + glm::vec2 { ( jmm2 * ShapePoints[ j ].z + m2 * ShapePoints[ j + iNumShapePoints ].z ) / Texturescale, tv2 } ); } if( p ) // jeÅ›li jest wskaźnik do tablicy if( *p ) @@ -461,61 +429,30 @@ int TSegment::RenderLoft( CVertNormTex* &Output, Math3D::vector3 const &Origin, pt -= Origin; norm = ShapePoints[ j ].n.x * parallel1; norm.y += ShapePoints[ j ].n.y; - if( Output == nullptr ) { - // immediate mode - ::glNormal3f( norm.x, norm.y, norm.z ); - ::glTexCoord2f( ShapePoints[ j ].z / Texturescale, tv1 ); - ::glVertex3f( pt.x, pt.y, pt.z ); // punkt na poczÄ…tku odcinka - } - else { - Output->position.x = pt.x; - Output->position.y = pt.y; - Output->position.z = pt.z; - Output->normal.x = norm.x; - Output->normal.y = norm.y; - Output->normal.z = norm.z; - Output->texture.s = ShapePoints[ j ].z / Texturescale; - Output->texture.t = tv1; - ++Output; - } - ++vertexcount; + + Output.emplace_back( + glm::vec3 { pt.x, pt.y, pt.z }, + glm::vec3 { norm.x, norm.y, norm.z }, + glm::vec2 { ShapePoints[ j ].z / Texturescale, tv1 } ); pt = parallel2 * ShapePoints[ j ].x + pos2; pt.y += ShapePoints[ j ].y; pt -= Origin; norm = ShapePoints[ j ].n.x * parallel2; norm.y += ShapePoints[ j ].n.y; - if( Output == nullptr ) { - // immediate mode - ::glNormal3f( norm.x, norm.y, norm.z ); - ::glTexCoord2f( ShapePoints[ j ].z / Texturescale, tv2 ); - ::glVertex3f( pt.x, pt.y, pt.z ); // punkt na koÅ„cu odcinka - } - else { - Output->position.x = pt.x; - Output->position.y = pt.y; - Output->position.z = pt.z; - Output->normal.x = norm.x; - Output->normal.y = norm.y; - Output->normal.z = norm.z; - Output->texture.s = ShapePoints[ j ].z / Texturescale; - Output->texture.t = tv2; - ++Output; - } - ++vertexcount; + + Output.emplace_back( + glm::vec3 { pt.x, pt.y, pt.z }, + glm::vec3 { norm.x, norm.y, norm.z }, + glm::vec2 { ShapePoints[ j ].z / Texturescale, tv2 } ); } } } - if( Output == nullptr ) { - // immediate mode - glEnd(); - } pos1 = pos2; parallel1 = parallel2; tv1 = tv2; } - - return vertexcount; + return true; }; void TSegment::Render() diff --git a/Segment.h b/Segment.h index 25a9875f..90d0a6a8 100644 --- a/Segment.h +++ b/Segment.h @@ -9,8 +9,10 @@ http://mozilla.org/MPL/2.0/. #ifndef SegmentH #define SegmentH - +/* #include "VBO.h" +*/ +#include "openglgeometrybank.h" #include "dumb3d.h" #include "Classes.h" #include "usefull.h" @@ -74,51 +76,35 @@ class TSegment bool bCurve = false; TSegment(TTrack *owner); ~TSegment(); - bool Init(vector3 NewPoint1, vector3 NewPoint2, double fNewStep, double fNewRoll1 = 0, - double fNewRoll2 = 0); + bool Init(vector3 NewPoint1, vector3 NewPoint2, double fNewStep, double fNewRoll1 = 0, double fNewRoll2 = 0); bool Init(vector3 &NewPoint1, vector3 NewCPointOut, vector3 NewCPointIn, vector3 &NewPoint2, double fNewStep, double fNewRoll1 = 0, double fNewRoll2 = 0, bool bIsCurve = true); inline double ComputeLength(); // McZapkie-150503 - inline vector3 GetDirection1() - { - return bCurve ? CPointOut - Point1 : CPointOut; - }; - inline vector3 GetDirection2() - { - return bCurve ? CPointIn - Point2 : CPointIn; - }; + inline vector3 GetDirection1() { + return bCurve ? CPointOut - Point1 : CPointOut; }; + inline vector3 GetDirection2() { + return bCurve ? CPointIn - Point2 : CPointIn; }; vector3 GetDirection(double fDistance); - vector3 GetDirection() - { - return CPointOut; - }; + vector3 GetDirection() { + return CPointOut; }; vector3 FastGetDirection(double fDistance, double fOffset); vector3 GetPoint(double fDistance); void RaPositionGet(double fDistance, vector3 &p, vector3 &a); vector3 FastGetPoint(double t); - inline vector3 FastGetPoint_0() - { - return Point1; - }; - inline vector3 FastGetPoint_1() - { - return Point2; - }; - inline double GetRoll(double const Distance) - { - return interpolate( fRoll1, fRoll2, Distance / fLength ); - } - void GetRolls(double &r1, double &r2) - { // pobranie przechyÅ‚ek (do generowania trójkÄ…tów) + inline vector3 FastGetPoint_0() { + return Point1; }; + inline vector3 FastGetPoint_1() { + return Point2; }; + inline double GetRoll(double const Distance) { + return interpolate( fRoll1, fRoll2, Distance / fLength ); } + void GetRolls(double &r1, double &r2) { + // pobranie przechyÅ‚ek (do generowania trójkÄ…tów) r1 = fRoll1; - r2 = fRoll2; - } - int RenderLoft( CVertNormTex* &Output, Math3D::vector3 const &Origin, vector6 const *ShapePoints, int iNumShapePoints, double fTextureLength, double Texturescale = 1.0, int iSkip = 0, int iEnd = 0, double fOffsetX = 0.0, vector3 **p = nullptr, bool bRender = true); + r2 = fRoll2; } + bool RenderLoft( vertex_array &Output, Math3D::vector3 const &Origin, vector6 const *ShapePoints, int iNumShapePoints, double fTextureLength, double Texturescale = 1.0, int iSkip = 0, int iEnd = 0, double fOffsetX = 0.0, vector3 **p = nullptr, bool bRender = true); void Render(); - inline double GetLength() - { - return fLength; - }; + inline double GetLength() { + return fLength; }; void MoveMe(vector3 pPosition) { Point1 += pPosition; @@ -129,14 +115,10 @@ class TSegment CPointOut += pPosition; } } - int RaSegCount() - { - return fTsBuffer ? iSegCount : 1; - }; - void AngleSet(int i, double a) - { - fAngle[i] = a; - }; + int RaSegCount() { + return fTsBuffer ? iSegCount : 1; }; + void AngleSet(int i, double a) { + fAngle[i] = a; }; }; //--------------------------------------------------------------------------- diff --git a/Track.cpp b/Track.cpp index 48e39a66..67ffdc63 100644 --- a/Track.cpp +++ b/Track.cpp @@ -177,7 +177,6 @@ void TTrack::Init() case tt_Cross: // tylko dla skrzyżowania dróg SwitchExtension = std::make_shared( this, 6 ); // 6 po³¹czeñ SwitchExtension->vPoints = nullptr; // brak tablicy punktów - SwitchExtension->iPoints = 0; SwitchExtension->bPoints = false; // tablica punktów nie wypeÅ‚niona SwitchExtension->iRoads = 4; // domyÅ›lnie 4 break; @@ -203,7 +202,9 @@ TTrack * TTrack::Create400m(int what, double dx) TSubRect *r = Global::pGround->GetSubRect(tmp->pCenter.x, tmp->pCenter.z); r->NodeAdd(tmp); // dodanie toru do segmentu r->Sort(); //żeby wyÅ›wietlaÅ‚ tabor z dodanego toru +/* r->Release(); // usuniÄ™cie skompilowanych zasobów +*/ return trk; }; @@ -313,7 +314,9 @@ TTrack * TTrack::NullCreate(int dir) if (tmp2) r->NodeAdd(tmp2); // drugiego też r->Sort(); //żeby wyÅ›wietlaÅ‚ tabor z dodanego toru +/* r->Release(); // usuniÄ™cie skompilowanych zasobów +*/ return trk; }; @@ -989,22 +992,6 @@ bool TTrack::AddDynamicObject(TDynamicObject *Dynamic) return true; }; -void TTrack::MoveMe(vector3 pPosition) -{ // to nie jest używane - if (SwitchExtension) - { - SwitchExtension->Segments[0]->MoveMe(1 * pPosition); - SwitchExtension->Segments[1]->MoveMe(1 * pPosition); - SwitchExtension->Segments[2]->MoveMe(3 * pPosition); // Ra: 3 razy? - SwitchExtension->Segments[3]->MoveMe(4 * pPosition); - } - else - { - Segment->MoveMe(pPosition); - }; - ResourceManager::Unregister(this); -}; - const int numPts = 4; const int nnumPts = 12; @@ -1039,10 +1026,10 @@ const vector6 iglica[nnumPts] = // iglica - vextor3(x,y,mapowanie tekstury) vector6(-0.040, -0.180, 1.00, -1.000, 0.000, 0.000) // 1mm wiÄ™cej, żeby nie nachodziÅ‚y tekstury? }; - +/* void TTrack::Compile(GLuint tex) { - CVertNormTex *immediate{ nullptr }; + basic_vertex *immediate{ nullptr }; // generowanie treÅ›ci dla Display Lists - model proceduralny if (!tex) @@ -1656,14 +1643,16 @@ void TTrack::Compile(GLuint tex) if (Global::bManageNodes) glEndList(); }; - +*/ void TTrack::Release() { +/* if (DisplayListID) glDeleteLists(DisplayListID, 1); DisplayListID = 0; +*/ }; - +/* void TTrack::Render() { if (bVisible) // Ra: tory sÄ… renderowane sektorami i nie ma sensu każdorazowo liczyć odlegÅ‚oÅ›ci @@ -1682,7 +1671,7 @@ void TTrack::Render() Release(); // zwrotnica w trakcie animacji do odrysowania } }; - +*/ bool TTrack::CheckDynamicObject(TDynamicObject *Dynamic) { // sprawdzenie, czy pojazd jest przypisany do toru for( auto dynamic : Dynamics ) { @@ -1774,7 +1763,7 @@ void TTrack::RaAssign(TGroundNode *gn, TAnimModel *am, TEvent *done, TEvent *joi am->GetContainer(NULL)->EventAssign(done); // zdarzenie zakoÅ„czenia animacji } }; - +/* int TTrack::RaArrayPrepare() { // przygotowanie tablic do skopiowania do VBO (zliczanie wierzchoÅ‚ków) if (bVisible) // o ile w ogóle widać @@ -1803,16 +1792,6 @@ int TTrack::RaArrayPrepare() + SwitchExtension->Segments[ 4 ]->RaSegCount() + SwitchExtension->Segments[ 5 ]->RaSegCount(); } -/* - if (fTexHeight1 >= 0) { - // normalne pobocze, na razie siÄ™ skÅ‚ada z - return ( ( TextureID1 ? SwitchExtension->iPoints + SwitchExtension->iRoads + 2 : 0 ) + ( TextureID2 ? SwitchExtension->iPoints * 12 : 0 ) ); - } - else { - // jeÅ›li fTexHeight1<0, to sÄ… chodniki i może któregoÅ› nie być - return ( ( TextureID1 ? SwitchExtension->iPoints + SwitchExtension->iRoads + 2 : 0 ) + ( TextureID2 ? SwitchExtension->iPoints * 6 : 0 ) ); - } -*/ // each sub-segment covers only one side of the road, so it has points for single sideroad, if any return ( ( TextureID1 ? SwitchExtension->iPoints + SwitchExtension->iRoads + 2 : 0 ) + ( TextureID2 ? SwitchExtension->iPoints * 6 : 0 ) ); } @@ -1829,28 +1808,28 @@ int TTrack::RaArrayPrepare() } return 0; }; - -void TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start, int const Vertexcount) -{ // wypeÅ‚nianie tablic VBO +*/ +// wypeÅ‚nianie tablic VBO +void TTrack::create_geometry( geometrybank_handle const &Bank ) { // Ra: trzeba rozdzielić szyny od podsypki, aby móc grupować wg tekstur - double fHTW = 0.5 * fabs(fTrackWidth); - double side = fabs(fTexWidth); // szerokść podsypki na zewnÄ…trz szyny albo pobocza - double slop = fabs(fTexSlope); // brzeg zewnÄ™trzny - double rozp = fHTW + side + slop; // brzeg zewnÄ™trzny - double hypot1 = hypot(slop, fTexHeight1); // rozmiar pochylenia do liczenia normalnych + double const fHTW = 0.5 * std::fabs(fTrackWidth); + double const side = std::fabs(fTexWidth); // szerokść podsypki na zewnÄ…trz szyny albo pobocza + double const slop = std::fabs(fTexSlope); // brzeg zewnÄ™trzny + double const rozp = fHTW + side + slop; // brzeg zewnÄ™trzny + double hypot1 = std::hypot(slop, fTexHeight1); // rozmiar pochylenia do liczenia normalnych if (hypot1 == 0.0) hypot1 = 1.0; - vector3 normal1 = vector3(fTexSlope / hypot1, fTexHeight1 / hypot1, 0.0); // wektor normalny + vector3 normal1 { fTexSlope / hypot1, fTexHeight1 / hypot1, 0.0 }; // wektor normalny double fHTW2, side2, slop2, rozp2, fTexHeight2, hypot2; vector3 normal2; if (iTrapezoid & 2) // ten bit oznacza, że istnieje odpowiednie pNext { // Ra: jest OK - fHTW2 = 0.5 * fabs(trNext->fTrackWidth); // poÅ‚owa rozstawu/nawierzchni - side2 = fabs(trNext->fTexWidth); - slop2 = fabs(trNext->fTexSlope); // nie jest używane później + fHTW2 = 0.5 * std::fabs(trNext->fTrackWidth); // poÅ‚owa rozstawu/nawierzchni + side2 = std::fabs(trNext->fTexWidth); + slop2 = std::fabs(trNext->fTexSlope); // nie jest używane później rozp2 = fHTW2 + side2 + slop2; fTexHeight2 = trNext->fTexHeight1; - hypot2 = hypot(slop2, fTexHeight2); + hypot2 = std::hypot(slop2, fTexHeight2); if (hypot2 == 0.0) hypot2 = 1.0; normal2 = vector3(trNext->fTexSlope / hypot2, fTexHeight2 / hypot2, 0.0); @@ -1877,37 +1856,48 @@ void TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start, int cons Segment->GetRolls(roll1, roll2); else roll1 = roll2 = 0.0; // dla zwrotnic - double sin1 = sin(roll1), cos1 = cos(roll1), sin2 = sin(roll2), cos2 = cos(roll2); + double sin1 = std::sin(roll1), cos1 = std::cos(roll1), sin2 = std::sin(roll2), cos2 = std::cos(roll2); // zwykla szyna: //Ra: czemu główki sÄ… asymetryczne na wysokoÅ›ci 0.140? vector6 rpts1[24], rpts2[24], rpts3[24], rpts4[24]; int i; for (i = 0; i < 12; ++i) { - rpts1[i] = vector6((fHTW + szyna[i].x) * cos1 + szyna[i].y * sin1, - -(fHTW + szyna[i].x) * sin1 + szyna[i].y * cos1, szyna[i].z, - +szyna[i].n.x * cos1 + szyna[i].n.y * sin1, - -szyna[i].n.x * sin1 + szyna[i].n.y * cos1, 0.0); - rpts2[11 - i] = vector6((-fHTW - szyna[i].x) * cos1 + szyna[i].y * sin1, - -(-fHTW - szyna[i].x) * sin1 + szyna[i].y * cos1, szyna[i].z, - -szyna[i].n.x * cos1 + szyna[i].n.y * sin1, - +szyna[i].n.x * sin1 + szyna[i].n.y * cos1, 0.0); + rpts1[i] = vector6( + (fHTW + szyna[i].x) * cos1 + szyna[i].y * sin1, + -(fHTW + szyna[i].x) * sin1 + szyna[i].y * cos1, + szyna[i].z, + szyna[i].n.x * cos1 + szyna[i].n.y * sin1, + -szyna[i].n.x * sin1 + szyna[i].n.y * cos1, + 0.0); + rpts2[11 - i] = vector6( + (-fHTW - szyna[i].x) * cos1 + szyna[i].y * sin1, + -(-fHTW - szyna[i].x) * sin1 + szyna[i].y * cos1, + szyna[i].z, + -szyna[i].n.x * cos1 + szyna[i].n.y * sin1, + szyna[i].n.x * sin1 + szyna[i].n.y * cos1, + 0.0); } if (iTrapezoid) // trapez albo przechyÅ‚ki, to oddzielne punkty na koÅ„cu for (i = 0; i < 12; ++i) { - rpts1[12 + i] = vector6((fHTW2 + szyna[i].x) * cos2 + szyna[i].y * sin2, - -(fHTW2 + szyna[i].x) * sin2 + szyna[i].y * cos2, - szyna[i].z, +szyna[i].n.x * cos2 + szyna[i].n.y * sin2, - -szyna[i].n.x * sin2 + szyna[i].n.y * cos2, 0.0); - rpts2[23 - i] = vector6((-fHTW2 - szyna[i].x) * cos2 + szyna[i].y * sin2, - -(-fHTW2 - szyna[i].x) * sin2 + szyna[i].y * cos2, - szyna[i].z, -szyna[i].n.x * cos2 + szyna[i].n.y * sin2, - +szyna[i].n.x * sin2 + szyna[i].n.y * cos2, 0.0); + rpts1[12 + i] = vector6( + (fHTW2 + szyna[i].x) * cos2 + szyna[i].y * sin2, + -(fHTW2 + szyna[i].x) * sin2 + szyna[i].y * cos2, + szyna[i].z, + szyna[i].n.x * cos2 + szyna[i].n.y * sin2, + -szyna[i].n.x * sin2 + szyna[i].n.y * cos2, + 0.0); + rpts2[23 - i] = vector6( + (-fHTW2 - szyna[i].x) * cos2 + szyna[i].y * sin2, + -(-fHTW2 - szyna[i].x) * sin2 + szyna[i].y * cos2, + szyna[i].z, + -szyna[i].n.x * cos2 + szyna[i].n.y * sin2, + szyna[i].n.x * sin2 + szyna[i].n.y * cos2, + 0.0); } switch (eType) // dalej zależnie od typu { case tt_Table: // obrotnica jak zwykÅ‚y tor, tylko animacja dochodzi - SwitchExtension->iLeftVBO = Vert - Start; // indeks toru obrotnicy case tt_Normal: if (TextureID2) { // podsypka z podkÅ‚adami jest tylko dla zwykÅ‚ego toru @@ -1969,12 +1959,33 @@ void TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start, int cons bpts1[3] = vector6(-rozp, -fTexHeight1 - 0.18, 0.5 + map12, -normal1.x, -normal1.y, 0.0); // prawy skos } } - Segment->RenderLoft(Vert, origin, bpts1, iTrapezoid ? -4 : 4, fTexLength); + vertex_array vertices; + Segment->RenderLoft(vertices, origin, bpts1, iTrapezoid ? -4 : 4, fTexLength); + if( ( Bank == 0 ) && ( false == Geometry2.empty() ) ) { + // special variant, replace existing data for a turntable track + GfxRenderer.Replace( vertices, Geometry2[ 0 ] ); + } + else { + Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); + } } if (TextureID1) { // szyny - generujemy dwie, najwyżej rysować siÄ™ bÄ™dzie jednÄ… - Segment->RenderLoft(Vert, origin, rpts1, iTrapezoid ? -nnumPts : nnumPts, fTexLength); - Segment->RenderLoft(Vert, origin, rpts2, iTrapezoid ? -nnumPts : nnumPts, fTexLength); + vertex_array vertices; + if( ( Bank == 0 ) && ( false == Geometry1.empty() ) ) { + Segment->RenderLoft( vertices, origin, rpts1, iTrapezoid ? -nnumPts : nnumPts, fTexLength ); + GfxRenderer.Replace( vertices, Geometry1[ 0 ] ); + vertices.clear(); // reuse the scratchpad + Segment->RenderLoft( vertices, origin, rpts2, iTrapezoid ? -nnumPts : nnumPts, fTexLength ); + GfxRenderer.Replace( vertices, Geometry1[ 1 ] ); + } + else { + Segment->RenderLoft( vertices, origin, rpts1, iTrapezoid ? -nnumPts : nnumPts, fTexLength ); + Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); + vertices.clear(); // reuse the scratchpad + Segment->RenderLoft( vertices, origin, rpts2, iTrapezoid ? -nnumPts : nnumPts, fTexLength ); + Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); + } } break; case tt_Switch: // dla zwrotnicy dwa razy szyny @@ -1984,47 +1995,85 @@ void TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start, int cons for (i = 0; i < 12; ++i) { rpts3[i] = - vector6(+(fHTW + iglica[i].x) * cos1 + iglica[i].y * sin1, - -(+fHTW + iglica[i].x) * sin1 + iglica[i].y * cos1, iglica[i].z); + vector6( + +( fHTW + iglica[i].x) * cos1 + iglica[i].y * sin1, + -(+fHTW + iglica[i].x) * sin1 + iglica[i].y * cos1, + iglica[i].z); rpts3[i + 12] = - vector6(+(fHTW2 + szyna[i].x) * cos2 + szyna[i].y * sin2, - -(+fHTW2 + szyna[i].x) * sin2 + iglica[i].y * cos2, szyna[i].z); + vector6( + +( fHTW2 + szyna[i].x) * cos2 + szyna[i].y * sin2, + -(+fHTW2 + szyna[i].x) * sin2 + iglica[i].y * cos2, + szyna[i].z); rpts4[11 - i] = - vector6((-fHTW - iglica[i].x) * cos1 + iglica[i].y * sin1, - -(-fHTW - iglica[i].x) * sin1 + iglica[i].y * cos1, iglica[i].z); + vector6( + (-fHTW - iglica[i].x) * cos1 + iglica[i].y * sin1, + -(-fHTW - iglica[i].x) * sin1 + iglica[i].y * cos1, + iglica[i].z); rpts4[23 - i] = - vector6((-fHTW2 - szyna[i].x) * cos2 + szyna[i].y * sin2, - -(-fHTW2 - szyna[i].x) * sin2 + iglica[i].y * cos2, szyna[i].z); + vector6( + (-fHTW2 - szyna[i].x) * cos2 + szyna[i].y * sin2, + -(-fHTW2 - szyna[i].x) * sin2 + iglica[i].y * cos2, + szyna[i].z); } + // TODO, TBD: change all track geometry to triangles, to allow packing data in less, larger buffers if (SwitchExtension->RightSwitch) { // nowa wersja z SPKS, ale odwrotnie lewa/prawa + vertex_array vertices; if( TextureID1 ) { - SwitchExtension->Segments[ 0 ]->RenderLoft( Vert, origin, rpts2, nnumPts, fTexLength ); - SwitchExtension->Segments[ 0 ]->RenderLoft( Vert, origin, rpts1, nnumPts, fTexLength, 1.0, 2 ); - - SwitchExtension->iLeftVBO = Vert - Start; // indeks lewej iglicy - SwitchExtension->Segments[ 0 ]->RenderLoft( Vert, origin, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, SwitchExtension->fOffset2 ); + // fixed parts + SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, origin, rpts2, nnumPts, fTexLength ); + Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); + vertices.clear(); + SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, origin, rpts1, nnumPts, fTexLength, 1.0, 2 ); + Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); + vertices.clear(); + // left blade + SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, origin, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, SwitchExtension->fOffset2 ); + Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); + vertices.clear(); } if( TextureID2 ) { - SwitchExtension->iRightVBO = Vert - Start; // indeks prawej iglicy - SwitchExtension->Segments[ 1 ]->RenderLoft( Vert, origin, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -fMaxOffset + SwitchExtension->fOffset1 ); - SwitchExtension->Segments[ 1 ]->RenderLoft( Vert, origin, rpts2, nnumPts, fTexLength, 1.0, 2 ); - SwitchExtension->Segments[ 1 ]->RenderLoft( Vert, origin, rpts1, nnumPts, fTexLength ); + // fixed parts + SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, origin, rpts1, nnumPts, fTexLength ); + Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); + vertices.clear(); + SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, origin, rpts2, nnumPts, fTexLength, 1.0, 2 ); + Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); + vertices.clear(); + // right blade + SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, origin, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -fMaxOffset + SwitchExtension->fOffset1 ); + Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); + vertices.clear(); } } else { // lewa dziaÅ‚a lepiej niż prawa + vertex_array vertices; if( TextureID1 ) { - SwitchExtension->Segments[ 0 ]->RenderLoft( Vert, origin, rpts1, nnumPts, fTexLength ); // lewa szyna normalna caÅ‚a - SwitchExtension->Segments[ 0 ]->RenderLoft( Vert, origin, rpts2, nnumPts, fTexLength, 1.0, 2 ); // prawa szyna za iglicÄ… - SwitchExtension->iLeftVBO = Vert - Start; // indeks lewej iglicy - SwitchExtension->Segments[ 0 ]->RenderLoft( Vert, origin, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -SwitchExtension->fOffset2 ); // prawa iglica + // fixed parts + SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, origin, rpts1, nnumPts, fTexLength ); // lewa szyna normalna caÅ‚a + Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); + vertices.clear(); + SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, origin, rpts2, nnumPts, fTexLength, 1.0, 2 ); // prawa szyna za iglicÄ… + Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); + vertices.clear(); + // right blade + SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, origin, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -SwitchExtension->fOffset2 ); + Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); + vertices.clear(); } if( TextureID2 ) { - SwitchExtension->iRightVBO = Vert - Start; // indeks prawej iglicy - SwitchExtension->Segments[ 1 ]->RenderLoft( Vert, origin, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, fMaxOffset - SwitchExtension->fOffset1 ); // lewa iglica - SwitchExtension->Segments[ 1 ]->RenderLoft( Vert, origin, rpts1, nnumPts, fTexLength, 1.0, 2 ); // lewa szyna za iglicÄ… - SwitchExtension->Segments[ 1 ]->RenderLoft( Vert, origin, rpts2, nnumPts, fTexLength ); // prawa szyna normalnie caÅ‚a + // fixed parts + SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, origin, rpts2, nnumPts, fTexLength ); // prawa szyna normalnie caÅ‚a + Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); + vertices.clear(); + SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, origin, rpts1, nnumPts, fTexLength, 1.0, 2 ); // lewa szyna za iglicÄ… + Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); + vertices.clear(); + // left blade + SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, origin, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, fMaxOffset - SwitchExtension->fOffset1 ); + Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); + vertices.clear(); } } } @@ -2059,7 +2108,9 @@ void TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start, int cons } if (TextureID1) // jeÅ›li podana byÅ‚a tekstura, generujemy trójkÄ…ty { // tworzenie trójkÄ…tów nawierzchni szosy - Segment->RenderLoft(Vert, origin, bpts1, iTrapezoid ? -2 : 2, fTexLength); + vertex_array vertices; + Segment->RenderLoft(vertices, origin, bpts1, iTrapezoid ? -2 : 2, fTexLength); + Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); } if (TextureID2) { // pobocze drogi - poziome przy przechyÅ‚ce (a może krawężnik i chodnik zrobić jak w Midtown Madness 2?) @@ -2136,22 +2187,31 @@ void TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start, int cons rpts2[5] = vector6(bpts1[3].x - side2, bpts1[3].y + h2l, 0.484375 - map2l); // lewy brzeg lewego chodnika } } + vertex_array vertices; if( iTrapezoid ) // trapez albo przechyÅ‚ki { // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony // odcinka if( ( fTexHeight1 >= 0.0 ) || ( slop != 0.0 ) ) { - Segment->RenderLoft( Vert, origin, rpts1, -3, fTexLength ); // tylko jeÅ›li jest z prawej + Segment->RenderLoft( vertices, origin, rpts1, -3, fTexLength ); // tylko jeÅ›li jest z prawej + Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); + vertices.clear(); } if( ( fTexHeight1 >= 0.0 ) || ( side != 0.0 ) ) { - Segment->RenderLoft( Vert, origin, rpts2, -3, fTexLength ); // tylko jeÅ›li jest z lewej + Segment->RenderLoft( vertices, origin, rpts2, -3, fTexLength ); // tylko jeÅ›li jest z lewej + Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); + vertices.clear(); } } else { // pobocza zwykÅ‚e, brak przechyÅ‚ki if( ( fTexHeight1 >= 0.0 ) || ( slop != 0.0 ) ) { - Segment->RenderLoft( Vert, origin, rpts1, 3, fTexLength ); + Segment->RenderLoft( vertices, origin, rpts1, 3, fTexLength ); + Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); + vertices.clear(); } if( ( fTexHeight1 >= 0.0 ) || ( side != 0.0 ) ) { - Segment->RenderLoft( Vert, origin, rpts2, 3, fTexLength ); + Segment->RenderLoft( vertices, origin, rpts2, 3, fTexLength ); + Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); + vertices.clear(); } } } @@ -2182,12 +2242,25 @@ void TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start, int cons p[3] = SwitchExtension->Segments[1]->FastGetPoint_0(); // Point4 - przy trzech drogach pokrywa siÄ™ z Point1 // 2014-07: na poczÄ…tek rysować brzegi jak dla Å‚uków // punkty brzegu nawierzchni uzyskujemy podczas renderowania boków (bez sensu, ale najszybciej byÅ‚o zrobić) - int i; // ile punktów (może byc różna ilość punktów miÄ™dzy drogami) + int pointcount; + if( SwitchExtension->iRoads == 3 ) { + // mogÄ… być tylko 3 drogi zamiast 4 + pointcount = + SwitchExtension->Segments[ 0 ]->RaSegCount() + + SwitchExtension->Segments[ 1 ]->RaSegCount() + + SwitchExtension->Segments[ 2 ]->RaSegCount(); + } + else { + pointcount = + SwitchExtension->Segments[ 2 ]->RaSegCount() + + SwitchExtension->Segments[ 3 ]->RaSegCount() + + SwitchExtension->Segments[ 4 ]->RaSegCount() + + SwitchExtension->Segments[ 5 ]->RaSegCount(); + } if (!SwitchExtension->vPoints) { // jeÅ›li tablica punktów nie jest jeszcze utworzona, zliczamy punkty i tworzymy jÄ… - // points were already counted during preparation stage // we'll need to add couple extra points for the complete fan we'll build - SwitchExtension->vPoints = new vector3[SwitchExtension->iPoints + SwitchExtension->iRoads]; + SwitchExtension->vPoints = new vector3[pointcount + SwitchExtension->iRoads]; } vector3 *b = SwitchExtension->bPoints ? @@ -2272,22 +2345,50 @@ void TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start, int cons } } bool render = ( TextureID2 != 0 ); // renderować nie trzeba, ale trzeba wyznaczyć punkty brzegowe nawierzchni - // if (iTrapezoid) //trapez albo przechyÅ‚ki + vertex_array vertices; if (SwitchExtension->iRoads == 4) { // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony odcinka if( ( fTexHeight1 >= 0.0 ) || ( side != 0.0 ) ) { - SwitchExtension->Segments[ 2 ]->RenderLoft( Vert, origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render ); - SwitchExtension->Segments[ 3 ]->RenderLoft( Vert, origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render ); - SwitchExtension->Segments[ 4 ]->RenderLoft( Vert, origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render ); - SwitchExtension->Segments[ 5 ]->RenderLoft( Vert, origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render ); + SwitchExtension->Segments[ 2 ]->RenderLoft( vertices, origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render ); + if( true == render ) { + Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); + vertices.clear(); + } + SwitchExtension->Segments[ 3 ]->RenderLoft( vertices, origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render ); + if( true == render ) { + Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); + vertices.clear(); + } + SwitchExtension->Segments[ 4 ]->RenderLoft( vertices, origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render ); + if( true == render ) { + Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); + vertices.clear(); + } + SwitchExtension->Segments[ 5 ]->RenderLoft( vertices, origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render ); + if( true == render ) { + Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); + vertices.clear(); + } } } else { // punkt 3 pokrywa siÄ™ z punktem 1, jak w zwrotnicy; połączenie 1->2 nie musi być prostoliniowe if( ( fTexHeight1 >= 0.0 ) || ( side != 0.0 ) ) { - SwitchExtension->Segments[ 2 ]->RenderLoft( Vert, origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render ); // z P2 do P4 - SwitchExtension->Segments[ 1 ]->RenderLoft( Vert, origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render ); // z P4 do P3=P1 (odwrócony) - SwitchExtension->Segments[ 0 ]->RenderLoft( Vert, origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render ); // z P1 do P2 + SwitchExtension->Segments[ 2 ]->RenderLoft( vertices, origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render ); // z P2 do P4 + if( true == render ) { + Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); + vertices.clear(); + } + SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render ); // z P4 do P3=P1 (odwrócony) + if( true == render ) { + Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); + vertices.clear(); + } + SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render ); // z P1 do P2 + if( true == render ) { + Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); + vertices.clear(); + } } } } @@ -2299,47 +2400,47 @@ void TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start, int cons SwitchExtension->bPoints = true; // tablica punktów zostaÅ‚a wypeÅ‚niona } - if (TextureID1) { + if( TextureID1 ) { + vertex_array vertices; // jeÅ›li podana tekstura nawierzchni // we start with a vertex in the middle... - Vert->normal.x = 0.0; - Vert->normal.y = 1.0; - Vert->normal.z = 0.0; - Vert->texture.s = 0.5; - Vert->texture.t = 0.5; - Vert->position.x = oxz.x - origin.x; - Vert->position.y = oxz.y - origin.y; - Vert->position.z = oxz.z - origin.z; - ++Vert; + vertices.emplace_back( + glm::vec3{ + oxz.x - origin.x, + oxz.y - origin.y, + oxz.z - origin.z }, + glm::vec3{ 0.0f, 1.0f, 0.0f }, + glm::vec2{ 0.5f, 0.5f } ); // ...and add one extra vertex to close the fan... - Vert->normal.x = 0.0; - Vert->normal.y = 1.0; - Vert->normal.z = 0.0; - // mapowanie we współrzÄ™dnych scenerii u = ( SwitchExtension->vPoints[ 0 ].x - oxz.x + origin.x ) / fTexLength; v = ( SwitchExtension->vPoints[ 0 ].z - oxz.z + origin.z ) / ( fTexRatio1 * fTexLength ); - Vert->texture.s = cosa0 * u + sina0 * v + 0.5; - Vert->texture.t = -sina0 * u + cosa0 * v + 0.5; - Vert->position.x = SwitchExtension->vPoints[ 0 ].x; - Vert->position.y = SwitchExtension->vPoints[ 0 ].y; - Vert->position.z = SwitchExtension->vPoints[ 0 ].z; - ++Vert; - // ...then draw the precalculated rest - for (i = SwitchExtension->iPoints + SwitchExtension->iRoads - 1; i >= 0; --i) - { - Vert->normal.x = 0.0; - Vert->normal.y = 1.0; - Vert->normal.z = 0.0; + vertices.emplace_back( + glm::vec3 { + SwitchExtension->vPoints[ 0 ].x, + SwitchExtension->vPoints[ 0 ].y, + SwitchExtension->vPoints[ 0 ].z }, + glm::vec3{ 0.0f, 1.0f, 0.0f }, // mapowanie we współrzÄ™dnych scenerii - u = (SwitchExtension->vPoints[i].x - oxz.x + origin.x ) / fTexLength; - v = (SwitchExtension->vPoints[i].z - oxz.z + origin.z ) / (fTexRatio1 * fTexLength); - Vert->texture.s = cosa0 * u + sina0 * v + 0.5; - Vert->texture.t = -sina0 * u + cosa0 * v + 0.5; - Vert->position.x = SwitchExtension->vPoints[ i ].x; - Vert->position.y = SwitchExtension->vPoints[ i ].y; - Vert->position.z = SwitchExtension->vPoints[ i ].z; - ++Vert; + glm::vec2{ + cosa0 * u + sina0 * v + 0.5, + -sina0 * u + cosa0 * v + 0.5 } ); + // ...then draw the precalculated rest + for (int i = pointcount + SwitchExtension->iRoads - 1; i >= 0; --i) { + // mapowanie we współrzÄ™dnych scenerii + u = ( SwitchExtension->vPoints[ i ].x - oxz.x + origin.x ) / fTexLength; + v = ( SwitchExtension->vPoints[ i ].z - oxz.z + origin.z ) / ( fTexRatio1 * fTexLength ); + vertices.emplace_back( + glm::vec3 { + SwitchExtension->vPoints[ i ].x, + SwitchExtension->vPoints[ i ].y, + SwitchExtension->vPoints[ i ].z }, + glm::vec3{ 0.0f, 1.0f, 0.0f }, + // mapowanie we współrzÄ™dnych scenerii + glm::vec2{ + cosa0 * u + sina0 * v + 0.5, + -sina0 * u + cosa0 * v + 0.5 } ); } + Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_FAN ) ); } break; } // tt_cross @@ -2378,11 +2479,13 @@ void TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start, int cons } if (TextureID1) // jeÅ›li podana byÅ‚a tekstura, generujemy trójkÄ…ty { // tworzenie trójkÄ…tów nawierzchni szosy - Segment->RenderLoft(Vert, origin, bpts1, iTrapezoid ? -2 : 2, fTexLength); + vertex_array vertices; + Segment->RenderLoft(vertices, origin, bpts1, iTrapezoid ? -2 : 2, fTexLength); + Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); } if (TextureID2) - { // pobocze drogi - poziome przy przechyÅ‚ce (a może krawężnik i chodnik zrobić jak w - // Midtown Madness 2?) + { // pobocze drogi - poziome przy przechyÅ‚ce (a może krawężnik i chodnik zrobić jak w Midtown Madness 2?) + vertex_array vertices; vector6 rpts1[6], rpts2[6]; // współrzÄ™dne przekroju i mapowania dla prawej i lewej strony rpts1[0] = vector6(rozp, -fTexHeight1, 0.0); // lewy brzeg podstawy @@ -2400,13 +2503,21 @@ void TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start, int cons rpts2[3] = vector6(bpts1[3].x, bpts1[3].y, 1.0); rpts2[4] = vector6(bpts1[3].x - side2, bpts1[3].y, 0.5); rpts2[5] = vector6(-rozp2, -fTexHeight2, 0.0); // prawy brzeg prawego pobocza - Segment->RenderLoft(Vert, origin, rpts1, -3, fTexLength); - Segment->RenderLoft(Vert, origin, rpts2, -3, fTexLength); + Segment->RenderLoft(vertices, origin, rpts1, -3, fTexLength); + Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); + vertices.clear(); + Segment->RenderLoft(vertices, origin, rpts2, -3, fTexLength); + Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); + vertices.clear(); } else { // pobocza zwykÅ‚e, brak przechyÅ‚ki - Segment->RenderLoft(Vert, origin, rpts1, 3, fTexLength); - Segment->RenderLoft(Vert, origin, rpts2, 3, fTexLength); + Segment->RenderLoft(vertices, origin, rpts1, 3, fTexLength); + Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); + vertices.clear(); + Segment->RenderLoft(vertices, origin, rpts2, 3, fTexLength); + Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); + vertices.clear(); } } } @@ -2415,10 +2526,9 @@ void TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start, int cons } return; }; - +/* void TTrack::RaRenderVBO( int iPtr ) { // renderowanie z użyciem VBO - // Ra 2014-07: trzeba wymienić GL_TRIANGLE_STRIP na GL_TRIANGLES i renderować trójkÄ…ty sektora - // dla kolejnych tekstur! + // Ra 2014-07: trzeba wymienić GL_TRIANGLE_STRIP na GL_TRIANGLES i renderować trójkÄ…ty sektora dla kolejnych tekstur! EnvironmentSet(); int seg; switch( iCategoryFlag & 15 ) { @@ -2568,7 +2678,7 @@ void TTrack::RaRenderVBO( int iPtr ) { // renderowanie z użyciem VBO } EnvironmentReset(); }; - +*/ void TTrack::EnvironmentSet() { // ustawienie zmienionego Å›wiatÅ‚a glColor3f(1.0f, 1.0f, 1.0f); // Ra: potrzebne to? @@ -2822,11 +2932,11 @@ void TTrack::RaAnimListAdd(TTrack *t) } }; -TTrack * TTrack::RaAnimate(GLuint const Vertexbuffer) +TTrack * TTrack::RaAnimate() { // wykonanie rekurencyjne animacji, wywoÅ‚ywane przed wyÅ›wietleniem sektora // zwraca wskaźnik toru wymagajÄ…cego dalszej animacji if( SwitchExtension->pNextAnim ) - SwitchExtension->pNextAnim = SwitchExtension->pNextAnim->RaAnimate( Vertexbuffer ); + SwitchExtension->pNextAnim = SwitchExtension->pNextAnim->RaAnimate(); bool m = true; // animacja trwa if (eType == tt_Switch) // dla zwrotnicy tylko szyny { @@ -2855,77 +2965,85 @@ TTrack * TTrack::RaAnimate(GLuint const Vertexbuffer) m = false; // koniec animacji } } - if( ( Global::bUseVBO ) - && ( Vertexbuffer != -1 ) ) - { // dla OpenGL 1.4 odÅ›wieży siÄ™ caÅ‚y sektor, w późniejszych poprawiamy fragment - if (GLEW_VERSION_1_5) // dla OpenGL 1.4 to siÄ™ nie wykona poprawnie - if (TextureID1) // Ra: !!!! tu jest do poprawienia - { // iglice liczone tylko dla zwrotnic - vector6 rpts3[24], rpts4[24]; - double fHTW = 0.5 * fabs(fTrackWidth); - double fHTW2 = fHTW; // Ra: na razie niech tak bÄ™dzie - double cos1 = 1.0, sin1 = 0.0, cos2 = 1.0, sin2 = 0.0; // Ra: ... - for( int i = 0; i < 12; ++i ) { + // skip the geometry update if no geometry for this track was generated yet + if( ( ( TextureID1 != 0 ) + || ( TextureID2 != 0 ) ) + && ( ( false == Geometry1.empty() ) + || ( false == Geometry2.empty() ) ) ) { + // iglice liczone tylko dla zwrotnic + double fHTW = 0.5 * fabs( fTrackWidth ); + double fHTW2 = fHTW; // Ra: na razie niech tak bÄ™dzie + double cos1 = 1.0, sin1 = 0.0, cos2 = 1.0, sin2 = 0.0; // Ra: ... + vector6 rpts3[ 24 ], rpts4[ 24 ]; + for (int i = 0; i < 12; ++i) + { + rpts3[i] = + vector6( + +( fHTW + iglica[i].x) * cos1 + iglica[i].y * sin1, + -(+fHTW + iglica[i].x) * sin1 + iglica[i].y * cos1, + iglica[i].z); + rpts3[i + 12] = + vector6( + +( fHTW2 + szyna[i].x) * cos2 + szyna[i].y * sin2, + -(+fHTW2 + szyna[i].x) * sin2 + iglica[i].y * cos2, + szyna[i].z); + rpts4[11 - i] = + vector6( + (-fHTW - iglica[i].x) * cos1 + iglica[i].y * sin1, + -(-fHTW - iglica[i].x) * sin1 + iglica[i].y * cos1, + iglica[i].z); + rpts4[23 - i] = + vector6( + (-fHTW2 - szyna[i].x) * cos2 + szyna[i].y * sin2, + -(-fHTW2 - szyna[i].x) * sin2 + iglica[i].y * cos2, + szyna[i].z); + } - rpts3[ i ] = - vector6( +( fHTW + iglica[ i ].x ) * cos1 + iglica[ i ].y * sin1, - -( +fHTW + iglica[ i ].x ) * sin1 + iglica[ i ].y * cos1, iglica[ i ].z ); - rpts3[ i + 12 ] = - vector6( +( fHTW2 + szyna[ i ].x ) * cos2 + szyna[ i ].y * sin2, - -( +fHTW2 + szyna[ i ].x ) * sin2 + iglica[ i ].y * cos2, szyna[ i ].z ); - rpts4[ 11 - i ] = - vector6( ( -fHTW - iglica[ i ].x ) * cos1 + iglica[ i ].y * sin1, - -( -fHTW - iglica[ i ].x ) * sin1 + iglica[ i ].y * cos1, iglica[ i ].z ); - rpts4[ 23 - i ] = - vector6( ( -fHTW2 - szyna[ i ].x ) * cos2 + szyna[ i ].y * sin2, - -( -fHTW2 - szyna[ i ].x ) * sin2 + iglica[ i ].y * cos2, szyna[ i ].z ); - } - // NOTE: performance-wise it'd make much more sense to keep the most recent shape cached as part of switch extension, - // and only send updates when/if they take place, instead of the current back-and-forth - // TODO: implement optimized version + auto const origin { pMyNode->m_rootposition }; + vertex_array vertices; - // fetch current blade geometry - std::vector bladesbuffer; bladesbuffer.resize( 2 * 2 * 24 ); // 2 blades, 2 segments each -/* - ::glGetBufferSubData( - GL_ARRAY_BUFFER, - SwitchExtension->iLeftVBO * sizeof( CVertNormTex ), - bladesbuffer.size() * sizeof( CVertNormTex ), - bladesbuffer.data() ); -*/ - auto bladevertices = bladesbuffer.data(); - auto const origin { pMyNode->m_rootposition }; - if( SwitchExtension->RightSwitch ) { // nowa wersja z SPKS, ale odwrotnie lewa/prawa - SwitchExtension->Segments[ 0 ]->RenderLoft( bladevertices, origin, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, SwitchExtension->fOffset2 /*, true*/ ); - SwitchExtension->Segments[ 1 ]->RenderLoft( bladevertices, origin, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -fMaxOffset + SwitchExtension->fOffset1 /*, true*/ ); - } - else { - SwitchExtension->Segments[ 0 ]->RenderLoft( bladevertices, origin, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -SwitchExtension->fOffset2 /*, true*/ ); // prawa iglica - SwitchExtension->Segments[ 1 ]->RenderLoft( bladevertices, origin, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, fMaxOffset - SwitchExtension->fOffset1 /*, true*/ ); // lewa iglica - } - // push back updated geometry - ::glBufferSubData( - GL_ARRAY_BUFFER, - SwitchExtension->iLeftVBO * sizeof( CVertNormTex ), - bladesbuffer.size() * sizeof( CVertNormTex ), - bladesbuffer.data() ); + if (SwitchExtension->RightSwitch) + { // nowa wersja z SPKS, ale odwrotnie lewa/prawa + vertex_array vertices; + if( TextureID1 ) { + // left blade + SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, origin, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, SwitchExtension->fOffset2 ); + GfxRenderer.Replace( vertices, Geometry1[ 2 ] ); + vertices.clear(); } + if( TextureID2 ) { + // right blade + SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, origin, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -fMaxOffset + SwitchExtension->fOffset1 ); + GfxRenderer.Replace( vertices, Geometry2[ 2 ] ); + vertices.clear(); + } + } + else { // lewa dziaÅ‚a lepiej niż prawa + vertex_array vertices; + if( TextureID1 ) { + // right blade + SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, origin, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -SwitchExtension->fOffset2 ); + GfxRenderer.Replace( vertices, Geometry1[ 2 ] ); + vertices.clear(); + } + if( TextureID2 ) { + // left blade + SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, origin, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, fMaxOffset - SwitchExtension->fOffset1 ); + GfxRenderer.Replace( vertices, Geometry2[ 2 ] ); + vertices.clear(); + } + } } - else // gdy Display List - Release(); // niszczenie skompilowanej listy, aby siÄ™ wygenerowaÅ‚a nowa } - else if (eType == tt_Table) // dla obrotnicy - szyny i podsypka - { + else if (eType == tt_Table) { + // dla obrotnicy - szyny i podsypka if (SwitchExtension->pModel && SwitchExtension->CurrentIndex) // 0=zablokowana siÄ™ nie animuje { // trzeba każdorazowo porównywać z kÄ…tem modelu - // SwitchExtension->fOffset1=SwitchExtension->pAnim?SwitchExtension->pAnim->AngleGet():0.0; // //pobranie kÄ…ta z modelu TAnimContainer *ac = SwitchExtension->pModel ? SwitchExtension->pModel->GetContainer(NULL) : NULL; // pobranie głównego submodelu - // if (ac) ac->EventAssign(SwitchExtension->evMinus); //event zakoÅ„czenia animacji, - // trochÄ™ bez sensu tutaj if (ac) if ((ac->AngleGet() != SwitchExtension->fOffset) || !(ac->TransGet() == @@ -2947,22 +3065,26 @@ TTrack * TTrack::RaAnimate(GLuint const Vertexbuffer) dynamic->Move( 0.000001 ); } // kÄ…ty +/* if (Global::bUseVBO) { // dla OpenGL 1.4 odÅ›wieży siÄ™ caÅ‚y sektor, w późniejszych poprawiamy fragment // aktualizacja pojazdów na torze if (GLEW_VERSION_1_5) // dla OpenGL 1.4 to siÄ™ nie wykona poprawnie { int size = RaArrayPrepare(); // wielkość tabeli potrzebna dla tej obrotnicy - CVertNormTex *Vert = new CVertNormTex[size]; // bufor roboczy - // CVertNormTex *v=Vert; //zmieniane przez + basic_vertex *Vert = new basic_vertex[size]; // bufor roboczy + // basic_vertex *v=Vert; //zmieniane przez RaArrayFill(Vert, Vert - SwitchExtension->iLeftVBO, size); // iLeftVBO powinno zostać niezmienione ::glBufferSubData( - GL_ARRAY_BUFFER, SwitchExtension->iLeftVBO * sizeof(CVertNormTex), - size * sizeof(CVertNormTex), Vert); // wysÅ‚anie fragmentu bufora VBO + GL_ARRAY_BUFFER, SwitchExtension->iLeftVBO * sizeof(basic_vertex), + size * sizeof(basic_vertex), Vert); // wysÅ‚anie fragmentu bufora VBO } } else // gdy Display List Release(); // niszczenie skompilowanej listy, aby siÄ™ wygenerowaÅ‚a nowa +*/ + // NOTE: passing empty handle is a bit of a hack here. could be refactored into something more elegant + create_geometry( geometrybank_handle() ); } // animacja trwa nadal } else diff --git a/Track.h b/Track.h index b51bb3a6..8ded71b5 100644 --- a/Track.h +++ b/Track.h @@ -15,8 +15,6 @@ http://mozilla.org/MPL/2.0/. #include "Segment.h" #include "Texture.h" -class TEvent; - typedef enum { tt_Unknown, @@ -39,6 +37,7 @@ typedef enum } TEnvironmentType; // Ra: opracować alternatywny system cieni/Å›wiateÅ‚ z definiowaniem koloru oÅ›wietlenia w halach +class TEvent; class TTrack; class TGroundNode; class TSubRect; @@ -77,10 +76,10 @@ class TSwitchExtension }; struct { // zmienne dla skrzyżowania - vector3 *vPoints; // tablica wierzchoÅ‚ków nawierzchni, generowana przez pobocze - int iPoints; // liczba faktycznie użytych wierzchoÅ‚ków nawierzchni - bool bPoints; // czy utworzone? int iRoads; // ile dróg siÄ™ spotyka? + vector3 *vPoints; // tablica wierzchoÅ‚ków nawierzchni, generowana przez pobocze +// int iPoints; // liczba faktycznie użytych wierzchoÅ‚ków nawierzchni + bool bPoints; // czy utworzone? }; }; bool bMovement = false; // czy w trakcie animacji @@ -108,46 +107,48 @@ class TIsolated TIsolated(); TIsolated(const std::string &n, TIsolated *i); ~TIsolated(); - static TIsolated * Find( - const std::string &n); // znalezienie obiektu albo utworzenie nowego + static TIsolated * Find(const std::string &n); // znalezienie obiektu albo utworzenie nowego void Modify(int i, TDynamicObject *o); // dodanie lub odjÄ™cie osi - bool Busy() - { - return (iAxles > 0); - }; - static TIsolated * Root() - { - return (pRoot); - }; - TIsolated * Next() - { - return (pNext); - }; + bool Busy() { + return (iAxles > 0); }; + static TIsolated * Root() { + return (pRoot); }; + TIsolated * Next() { + return (pNext); }; }; -class TTrack : public Resource -{ // trajektoria ruchu - opakowanie - private: +// trajektoria ruchu - opakowanie +class TTrack : public Resource { + + friend class opengl_renderer; + +private: + TGroundNode * pMyNode = nullptr; // Ra: proteza, żeby tor znaÅ‚ swojÄ… nazwÄ™ TODO: odziedziczyć TTrack z TGroundNode + TIsolated * pIsolated = nullptr; // obwód izolowany obsÅ‚ugujÄ…cy zajÄ™cia/zwolnienia grupy torów std::shared_ptr SwitchExtension; // dodatkowe dane do toru, który jest zwrotnicÄ… std::shared_ptr Segment; - TTrack *trNext = nullptr; // odcinek od strony punktu 2 - to powinno być w segmencie - TTrack *trPrev = nullptr; // odcinek od strony punktu 1 + 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 - texture_handle TextureID1 = 0; // tekstura szyn albo nawierzchni - texture_handle TextureID2 = 0; // tekstura automatycznej podsypki albo pobocza + int iTrapezoid = 0; // 0-standard, 1-przechyÅ‚ka, 2-trapez, 3-oba + double fRadiusTable[ 2 ]; // dwa promienie, drugi dla zwrotnicy float fTexLength = 4.0f; // dÅ‚ugość powtarzania tekstury w metrach float fTexRatio1 = 1.0f; // proporcja boków tekstury nawierzchni (żeby zaoszczÄ™dzić na rozmiarach tekstur...) float fTexRatio2 = 1.0f; // proporcja boków tekstury chodnika (żeby zaoszczÄ™dzić na rozmiarach tekstur...) float fTexHeight1 = 0.6f; // wysokość brzegu wzglÄ™dem trajektorii float fTexWidth = 0.9f; // szerokość boku float fTexSlope = 0.9f; - double fRadiusTable[ 2 ]; // dwa promienie, drugi dla zwrotnicy - int iTrapezoid = 0; // 0-standard, 1-przechyÅ‚ka, 2-trapez, 3-oba +/* GLuint DisplayListID = 0; - TIsolated *pIsolated = nullptr; // obwód izolowany obsÅ‚ugujÄ…cy zajÄ™cia/zwolnienia grupy torów - TGroundNode * - pMyNode = nullptr; // Ra: proteza, żeby tor znaÅ‚ swojÄ… nazwÄ™ TODO: odziedziczyć TTrack z TGroundNode - public: +*/ + texture_handle TextureID1 = 0; // tekstura szyn albo nawierzchni + texture_handle TextureID2 = 0; // tekstura automatycznej podsypki albo pobocza + typedef std::vector geometryhandle_sequence; + geometryhandle_sequence Geometry1; // geometry chunks textured with texture 1 + geometryhandle_sequence Geometry2; // geometry chunks textured with texture 2 + +public: typedef std::deque dynamics_sequence; dynamics_sequence Dynamics; int iEvents = 0; // Ra: flaga informujÄ…ca o obecnoÅ›ci eventów @@ -193,39 +194,30 @@ class TTrack : public Resource void Init(); static TTrack * Create400m(int what, double dx); TTrack * NullCreate(int dir); - inline bool IsEmpty() - { - return Dynamics.empty(); - }; + inline bool IsEmpty() { + return Dynamics.empty(); }; void ConnectPrevPrev(TTrack *pNewPrev, int typ); void ConnectPrevNext(TTrack *pNewPrev, int typ); void ConnectNextPrev(TTrack *pNewNext, int typ); void ConnectNextNext(TTrack *pNewNext, int typ); - inline double Length() - { - return Segment->GetLength(); - }; - inline std::shared_ptr CurrentSegment() - { - return Segment; - }; - inline TTrack * CurrentNext() - { - return (trNext); - }; - inline TTrack * CurrentPrev() - { - return (trPrev); - }; + inline double Length() { + return Segment->GetLength(); }; + inline std::shared_ptr CurrentSegment() { + return Segment; }; + inline TTrack * CurrentNext() { + return (trNext); }; + inline TTrack * CurrentPrev() { + return (trPrev); }; TTrack * Neightbour(int s, double &d); bool SetConnections(int i); bool Switch(int i, double t = -1.0, double d = -1.0); bool SwitchForced(int i, TDynamicObject *o); int CrossSegment(int from, int into); - inline int GetSwitchState() - { - return (SwitchExtension ? SwitchExtension->CurrentIndex : -1); - }; + inline int GetSwitchState() { + return ( + SwitchExtension ? + SwitchExtension->CurrentIndex : + -1); }; void Load(cParser *parser, vector3 pOrigin, std::string name); bool AssignEvents(TEvent *NewEvent0, TEvent *NewEvent1, TEvent *NewEvent2); bool AssignallEvents(TEvent *NewEvent0, TEvent *NewEvent1, TEvent *NewEvent2); @@ -233,44 +225,42 @@ class TTrack : public Resource bool CheckDynamicObject(TDynamicObject *Dynamic); bool AddDynamicObject(TDynamicObject *Dynamic); bool RemoveDynamicObject(TDynamicObject *Dynamic); - void MoveMe(vector3 pPosition); void Release(); +/* void Compile(GLuint tex = 0); - void Render(); // renderowanie z Display Lists int RaArrayPrepare(); // zliczanie rozmiaru dla VBO sektroa - void RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start, int const Vertexcount); // wypeÅ‚nianie VBO +*/ + void create_geometry(geometrybank_handle const &Bank); // wypeÅ‚nianie VBO +/* void RaRenderVBO(int iPtr); // renderowanie z VBO sektora +*/ void RenderDyn(); // renderowanie nieprzezroczystych pojazdów (oba tryby) void RenderDynAlpha(); // renderowanie przezroczystych pojazdów (oba tryby) - void RenderDynSounds(); // odtwarzanie dźwiÄ™ków pojazdów jest niezależne od ich - // wyÅ›wietlania + void RenderDynSounds(); // odtwarzanie dźwiÄ™ków pojazdów jest niezależne od ich wyÅ›wietlania - void RaOwnerSet(TSubRect *o) - { + void RaOwnerSet(TSubRect *o) { if (SwitchExtension) - SwitchExtension->pOwner = o; - }; + SwitchExtension->pOwner = o; }; bool InMovement(); // czy w trakcie animacji? void RaAssign(TGroundNode *gn, TAnimContainer *ac); void RaAssign(TGroundNode *gn, TAnimModel *am, TEvent *done, TEvent *joined); void RaAnimListAdd(TTrack *t); - TTrack * RaAnimate(GLuint const Vertexbuffer = -1); + TTrack * RaAnimate(); void RadioStop(); - void AxleCounter(int i, TDynamicObject *o) - { + void AxleCounter(int i, TDynamicObject *o) { if (pIsolated) - pIsolated->Modify(i, o); - }; // dodanie lub odjÄ™cie osi + pIsolated->Modify(i, o); }; // dodanie lub odjÄ™cie osi std::string IsolatedName(); bool IsolatedEventsAssign(TEvent *busy, TEvent *free); double WidthTotal(); - GLuint TextureGet(int i) - { - return i ? TextureID1 : TextureID2; - }; + GLuint TextureGet(int i) { + return ( + i ? + TextureID1 : + TextureID2 ); }; bool IsGroupable(); int TestPoint(vector3 *Point); void MovedUp1(double dh); diff --git a/Traction.cpp b/Traction.cpp index cb79da05..0b6028fb 100644 --- a/Traction.cpp +++ b/Traction.cpp @@ -358,7 +358,7 @@ void TTraction::ResistanceCalc(int d, double r, TTractionPowerSource *ps) } t->psPower[d] = ps; // skopiowanie wskaźnika zasilacza od danej strony t->fResistance[d] = r; // wpisanie rezystancji w kierunku tego zasilacza - r += t->fResistivity * glm::dot(t->vParametric, t->vParametric ); // doliczenie oporu kolejnego odcinka + r += t->fResistivity * glm::length(t->vParametric); // doliczenie oporu kolejnego odcinka p = t; // zapamiÄ™tanie dotychczasowego t = p->hvNext[d ^ 1]; // podążanie w tÄ™ samÄ… stronÄ™ d = p->iNext[d ^ 1]; @@ -367,8 +367,7 @@ void TTraction::ResistanceCalc(int d, double r, TTractionPowerSource *ps) } else { // podążanie w obu kierunkach, można by rekurencjÄ…, ale szkoda zasobów - r = 0.5 * fResistivity * - glm::dot(vParametric, vParametric ); // powiedzmy, że w zasilanym przęśle jest poÅ‚owa + r = 0.5 * fResistivity * glm::length(vParametric); // powiedzmy, że w zasilanym przęśle jest poÅ‚owa if (fResistance[0] == 0.0) ResistanceCalc(0, r); // do tyÅ‚u (w stronÄ™ Point1) if (fResistance[1] == 0.0) diff --git a/Traction.h b/Traction.h index 569d8f45..49304a30 100644 --- a/Traction.h +++ b/Traction.h @@ -56,7 +56,7 @@ class TTraction void Connect(int my, TTraction *with, int to); void Init(); bool WhereIs(); - void ResistanceCalc(int d = -1, double r = 0, TTractionPowerSource *ps = NULL); + void ResistanceCalc(int d = -1, double r = 0, TTractionPowerSource *ps = nullptr); void PowerSet(TTractionPowerSource *ps); double VoltageGet(double u, double i); private: diff --git a/VBO.cpp b/VBO.cpp index d9c3a9dd..be4ea20a 100644 --- a/VBO.cpp +++ b/VBO.cpp @@ -9,148 +9,3 @@ http://mozilla.org/MPL/2.0/. #include "stdafx.h" #include "VBO.h" -#include "GL/glew.h" -#include "usefull.h" -#include "sn_utils.h" -#include "globals.h" -//--------------------------------------------------------------------------- -/* -void CVertNormTex::deserialize(std::istream &s) -{ - x = sn_utils::ld_float32(s); - y = sn_utils::ld_float32(s); - z = sn_utils::ld_float32(s); - - nx = sn_utils::ld_float32(s); - ny = sn_utils::ld_float32(s); - nz = sn_utils::ld_float32(s); - - u = sn_utils::ld_float32(s); - v = sn_utils::ld_float32(s); -} - -void CVertNormTex::serialize(std::ostream &s) -{ - sn_utils::ls_float32(s, x); - sn_utils::ls_float32(s, y); - sn_utils::ls_float32(s, z); - - sn_utils::ls_float32(s, nx); - sn_utils::ls_float32(s, ny); - sn_utils::ls_float32(s, nz); - - sn_utils::ls_float32(s, u); - sn_utils::ls_float32(s, v); -} -*/ -CMesh::CMesh() -{ // utworzenie pustego obiektu -#ifdef EU07_USE_OLD_VERTEXBUFFER - m_pVNT = nullptr; -#endif - m_nVertexCount = -1; - m_nVBOVertices = 0; // nie zarezerwowane -}; - -CMesh::~CMesh() -{ // usuwanie obiektu - Clear(); // zwolnienie zasobów -}; - -void CMesh::MakeArray(int n) -{ // tworzenie tablic - m_nVertexCount = n; -#ifdef EU07_USE_OLD_VERTEXBUFFER - assert( m_pVNT == nullptr ); - m_pVNT = new CVertNormTex[m_nVertexCount]; // przydzielenie pamiÄ™ci dla tablicy -#else - m_pVNT.clear(); - m_pVNT.resize( m_nVertexCount ); -#endif -}; - -void CMesh::BuildVBOs(bool del) -{ // tworzenie VBO i kasowanie już niepotrzebnych tablic - // pobierz numer VBO oraz ustaw go jako aktywny - glGenBuffers(1, &m_nVBOVertices); // pobierz numer - glBindBuffer(GL_ARRAY_BUFFER, m_nVBOVertices); // ustaw bufor jako aktualny -#ifdef EU07_USE_OLD_VERTEXBUFFER - glBufferData(GL_ARRAY_BUFFER, m_nVertexCount * sizeof(CVertNormTex), m_pVNT, GL_STATIC_DRAW); -#else - glBufferData( GL_ARRAY_BUFFER, m_nVertexCount * sizeof( CVertNormTex ), m_pVNT.data(), GL_STATIC_DRAW ); -#endif - // WriteLog("Assigned VBO number "+AnsiString(m_nVBOVertices)+", vertices: - // "+AnsiString(m_nVertexCount)); -#ifdef EU07_USE_OLD_VERTEXBUFFER - if (del) - SafeDeleteArray(m_pVNT); // wierzchoÅ‚ki już siÄ™ nie przydadzÄ… -#else - m_pVNT.clear(); -#endif -}; - -void CMesh::Clear() -{ // niewirtualne zwolnienie zasobów przez sprzÄ…tacz albo destruktor - // inna nazwa, żeby nie mieszaÅ‚o siÄ™ z funkcjÄ… wirtualnÄ… sprzÄ…tacza - if (m_nVBOVertices) // jeÅ›li byÅ‚o coÅ› rezerwowane - { - glDeleteBuffers(1, &m_nVBOVertices); // Free The Memory - // WriteLog("Released VBO number "+AnsiString(m_nVBOVertices)); - } - m_nVBOVertices = 0; - m_nVertexCount = -1; // do ponownego zliczenia -#ifdef EU07_USE_OLD_VERTEXBUFFER - SafeDeleteArray(m_pVNT); // usuwanie tablic, gdy byÅ‚y użyte do Vertex Array -#else - m_pVNT.clear(); -#endif -}; - -bool CMesh::StartVBO() -{ // poczÄ…tek rysowania elementów z VBO - - if (m_nVertexCount <= 0) - return false; // nie ma nic do rysowania w ten sposób - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_NORMAL_ARRAY); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - if (m_nVBOVertices) - { - glBindBuffer(GL_ARRAY_BUFFER_ARB, m_nVBOVertices); - glVertexPointer( 3, GL_FLOAT, sizeof( CVertNormTex ), static_cast( nullptr ) ); // pozycje - glNormalPointer( GL_FLOAT, sizeof( CVertNormTex ), static_cast( nullptr ) + 12 ); // normalne - glTexCoordPointer( 2, GL_FLOAT, sizeof( CVertNormTex ), static_cast( nullptr ) + 24 ); // wierzchoÅ‚ki - return true; // można rysować z VBO - } - - return false; -}; - -bool CMesh::StartColorVBO() -{ // poczÄ…tek rysowania punktów Å›wiecÄ…cych z VBO - - if (m_nVertexCount <= 0) - return false; // nie ma nic do rysowania w ten sposób - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_COLOR_ARRAY); - if (m_nVBOVertices) - { - glBindBuffer(GL_ARRAY_BUFFER, m_nVBOVertices); - glVertexPointer( 3, GL_FLOAT, sizeof( CVertNormTex ), static_cast( nullptr ) ); // pozycje - // glColorPointer(3,GL_UNSIGNED_BYTE,sizeof(CVertNormTex),((char*)NULL)+12); //kolory - glColorPointer( 3, GL_FLOAT, sizeof( CVertNormTex ), static_cast( nullptr ) + 12 ); // kolory - return true; // można rysować z VBO - } - return false; -}; - -void CMesh::EndVBO() -{ // koniec użycia VBO - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_NORMAL_ARRAY); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - glDisableClientState(GL_COLOR_ARRAY); - // glBindBuffer(GL_ARRAY_BUFFER,0); //takie coÅ› psuje, mimo iż polecali użyć - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); // Ra: to na przyszÅ‚ość -}; diff --git a/VBO.h b/VBO.h index 0f52b9d9..99a3fac7 100644 --- a/VBO.h +++ b/VBO.h @@ -11,48 +11,9 @@ http://mozilla.org/MPL/2.0/. #include "openglgeometrybank.h" -#define EU07_USE_OLD_VERTEXBUFFER - -//--------------------------------------------------------------------------- -/* -class CVertNormTex +class CMesh { public: - float x = 0.0; // X wierzchoÅ‚ka - float y = 0.0; // Y wierzchoÅ‚ka - float z = 0.0; // Z wierzchoÅ‚ka - float nx = 0.0; // X wektora normalnego - float ny = 0.0; // Y wektora normalnego - float nz = 0.0; // Z wektora normalnego - float u = 0.0; // U mapowania - float v = 0.0; // V mapowania - - void deserialize(std::istream&); - void serialize(std::ostream&); -}; -*/ -typedef basic_vertex CVertNormTex; - -class CMesh -{ // wsparcie dla VBO - public: - CMesh(); - ~CMesh(); - void MakeArray(int n); // tworzenie tablicy z elementami VNT - void BuildVBOs(bool del = true); // zamiana tablic na VBO - void Clear(); // zwolnienie zasobów - bool StartVBO(); - void EndVBO(); - bool StartColorVBO(); - - int m_nVertexCount; // liczba wierzchoÅ‚ków -#ifdef EU07_USE_OLD_VERTEXBUFFER - CVertNormTex *m_pVNT; -#else - std::vector m_pVNT; -#endif - unsigned int m_nVBOVertices; // numer VBO z wierzchoÅ‚kami - geometrybank_handle m_geometrybank; - + bool m_geometrycreated { false }; }; diff --git a/World.cpp b/World.cpp index dc3c4968..1723253d 100644 --- a/World.cpp +++ b/World.cpp @@ -1267,7 +1267,7 @@ TWorld::Render_Cab() { } TDynamicObject *dynamic = Train->Dynamic(); - TSubModel::iInstance = reinterpret_cast( dynamic ); + TSubModel::iInstance = reinterpret_cast( dynamic ); if( ( true == FreeFlyModeFlag ) || ( false == dynamic->bDisplayCab ) @@ -1275,8 +1275,6 @@ TWorld::Render_Cab() { // ABu: Rendering kabiny jako ostatniej, zeby bylo widac przez szyby, tylko w widoku ze srodka return; } - - ::glEnable( GL_LIGHTING ); // po renderowaniu drutów może być to wyłączone. TODO: have the wires render take care of its own shit /* glPushMatrix(); vector3 pos = dynamic->GetPosition(); // wszpółrzÄ™dne pojazdu z kabinÄ… @@ -1651,7 +1649,7 @@ TWorld::Update_UI() { } case( GLFW_KEY_F8 ) : { - + // gfx renderer data uitextline1 = "Draw range x " + to_string( Global::fDistanceFactor, 1 ) + "; FPS: " + to_string( Timer::GetFPS(), 2 ); @@ -1659,28 +1657,16 @@ TWorld::Update_UI() { uitextline1 += " (slowmotion " + to_string( Global::iSlowMotion ) + ")"; } uitextline1 += - ", sectors: " + to_string( Ground.iRendered ) - + "/" + to_string( Global::iSegmentsRendered ) + ", sectors: " + std::to_string( GfxRenderer.m_drawcount ) + + "/" + std::to_string( Global::iSegmentsRendered ) + "; FoV: " + to_string( Global::FieldOfView / Global::ZoomFactor, 1 ); - break; - } - - case( GLFW_KEY_F9 ) : { - // informacja o wersji, sposobie wyÅ›wietlania i błędach OpenGL - uitextline1 = "MaSzyna " + Global::asVersion; // informacja o wersji - if( Global::iMultiplayer ) { - uitextline1 += " (multiplayer mode is active)"; - } - uitextline2 = - std::string("Rendering mode: ") + std::string( "Rendering mode: " ) + ( Global::bUseVBO ? "VBO" : "Display Lists" ) - + ". " - + GfxRenderer.Info(); - + + ". "; // dump last opengl error, if any GLenum glerror = ::glGetError(); if( glerror != GL_NO_ERROR ) { @@ -1689,10 +1675,22 @@ TWorld::Update_UI() { Global::LastGLError = std::to_string( glerror ) + " (" + glerrorstring + ")"; } if( false == Global::LastGLError.empty() ) { - uitextline3 = + uitextline2 += "Last openGL error: " + Global::LastGLError; } + // renderer stats + uitextline3 = GfxRenderer.Info(); + + break; + } + + case( GLFW_KEY_F9 ) : { + // informacja o wersji + uitextline1 = "MaSzyna " + Global::asVersion; // informacja o wersji + if( Global::iMultiplayer ) { + uitextline1 += " (multiplayer mode is active)"; + } break; } diff --git a/openglgeometrybank.cpp b/openglgeometrybank.cpp index a5fcb34f..f75906b1 100644 --- a/openglgeometrybank.cpp +++ b/openglgeometrybank.cpp @@ -48,13 +48,13 @@ basic_vertex::deserialize( std::istream &s ) { // creates a new geometry chunk of specified type from supplied vertex data. returns: handle to the chunk geometry_handle -geometry_bank::create( vertex_array &Vertices, int const Type ) { +geometry_bank::create( vertex_array &Vertices, unsigned int const Type, unsigned int const Streams ) { if( true == Vertices.empty() ) { return geometry_handle( 0, 0 ); } - m_chunks.emplace_back( Vertices, Type ); + m_chunks.emplace_back( Vertices, Type, Streams ); // NOTE: handle is effectively (index into chunk array + 1) this leaves value of 0 to serve as error/empty handle indication - geometry_handle chunkhandle{ 0, m_chunks.size() }; + geometry_handle chunkhandle { 0, static_cast(m_chunks.size()) }; // template method create_( chunkhandle ); // all done diff --git a/openglgeometrybank.h b/openglgeometrybank.h index a05a05ce..6974a47f 100644 --- a/openglgeometrybank.h +++ b/openglgeometrybank.h @@ -18,14 +18,30 @@ http://mozilla.org/MPL/2.0/. #endif struct basic_vertex { + glm::vec3 position; // 3d space glm::vec3 normal; // 3d space glm::vec2 texture; // uv space + basic_vertex() = default; + basic_vertex( glm::vec3 const&Position, glm::vec3 const &Normal, glm::vec2 const &Texture ) : + position( Position ), normal( Normal ), texture( Texture ) + {} void serialize( std::ostream& ); void deserialize( std::istream& ); }; +// data streams carried in a vertex +enum stream { + position = 0x1, + normal = 0x2, + color = 0x4, // currently normal and colour streams are stored in the same slot, and mutually exclusive + texture = 0x8 +}; + +unsigned int const basic_streams { stream::position | stream::normal | stream::texture }; +unsigned int const color_streams{ stream::position | stream::color | stream::texture }; + typedef std::vector vertex_array; // generic geometry bank class, allows storage, update and drawing of geometry chunks @@ -40,12 +56,20 @@ struct geometry_handle { {} // methods inline - operator std::uint32_t() const { - return bank << 12 | chunk; } + operator std::uint64_t() const { +/* + return bank << 14 | chunk; } +*/ + return bank << 32 | chunk; } + // members +/* std::uint32_t - bank : 20, // 1 mil banks - chunk : 12; // 4 k chunks per bank + bank : 18, // 250k banks + chunk : 14; // 16k chunks per bank +*/ + std::uint32_t bank; + std::uint32_t chunk; }; class geometry_bank { @@ -62,7 +86,7 @@ public: // methods: // creates a new geometry chunk of specified type from supplied vertex data. returns: handle to the chunk or NULL geometry_handle - create( vertex_array &Vertices, int const Type ); + create( vertex_array &Vertices, unsigned int const Type, unsigned int const Streams = stream::position | stream::normal | stream::texture ); // replaces data of specified chunk with the supplied vertex data, starting from specified offset bool replace( vertex_array &Vertices, geometry_handle const &Geometry, std::size_t const Offset = 0 ); @@ -83,11 +107,12 @@ public: protected: // types: struct geometry_chunk { - int type; // kind of geometry used by the chunk + unsigned int streams; // data streams carried by vertices + unsigned int type; // kind of geometry used by the chunk vertex_array vertices; // geometry data - geometry_chunk( vertex_array &Vertices, int const Type ) : - vertices( Vertices ), type( Type ) + geometry_chunk( vertex_array &Vertices, unsigned int const Type, unsigned int const Streams ) : + vertices( Vertices ), type( Type ), streams( Streams ) {} }; @@ -121,9 +146,14 @@ private: class opengl_vbogeometrybank : public geometry_bank { public: -// methods: +// destructor ~opengl_vbogeometrybank() { delete_buffer(); } +// methods: + static + void + reset() { + m_activebuffer = 0; } private: // types: @@ -217,6 +247,12 @@ public: // draws geometry stored in specified chunk void draw( geometry_handle const &Geometry ); + template + void + draw( Iterator_ First, Iterator_ Last ) { + while( First != Last ) { + draw( *First ); + ++First; } } // provides direct access to vertex data of specfied chunk vertex_array const & vertices( geometry_handle const &Geometry ) const; diff --git a/parser.cpp b/parser.cpp index a9171bd3..4b71b7cd 100644 --- a/parser.cpp +++ b/parser.cpp @@ -30,6 +30,9 @@ cParser::cParser( std::string const &Stream, buffertype const Type, std::string // mComments.insert(commentmap::value_type("--","\n")); //Ra: to chyba nie używane // store to calculate sub-sequent includes from relative path mPath = Path; + if( Type == buffertype::buffer_FILE ) { + mFile = Stream; + } // reset pointers and attach proper type of buffer switch (Type) { @@ -263,8 +266,15 @@ std::size_t cParser::count() { return count - 1; } - void cParser::addCommentStyle( std::string const &Commentstart, std::string const &Commentend ) { mComments.insert( commentmap::value_type(Commentstart, Commentend) ); } + +// returns name of currently open file, or empty string for text type stream +std::string +cParser::Name() { + + if( mIncludeParser ) { return mIncludeParser->Name(); } + else { return mPath + mFile; } +} diff --git a/parser.h b/parser.h index 90fdfc6d..1212fcc5 100644 --- a/parser.h +++ b/parser.h @@ -85,19 +85,21 @@ class cParser //: public std::stringstream static std::size_t countTokens( std::string const &Stream, std::string Path = "" ); // add custom definition of text which should be ignored when retrieving tokens void addCommentStyle( std::string const &Commentstart, std::string const &Commentend ); + // returns name of currently open file, or empty string for text type stream + std::string Name(); private: // methods: std::string readToken(bool ToLower = true, const char *Break = "\n\r\t ;"); std::string readQuotes( char const Quote = '\"' ); std::string readComment( std::string const &Break = "\n\r\t ;" ); -// std::string trtest; bool findQuotes( std::string &String ); bool trimComments( std::string &String ); std::size_t count(); // members: bool LoadTraction; // load traction? std::istream *mStream; // relevant kind of buffer is attached on creation. + std::string mFile; // name of the open file, if any std::string mPath; // path to open stream, for relative path lookups. std::streamoff mSize; // size of open stream, for progress report. typedef std::map commentmap; diff --git a/renderer.cpp b/renderer.cpp index d5ab5fa1..242d29ae 100644 --- a/renderer.cpp +++ b/renderer.cpp @@ -39,7 +39,8 @@ opengl_camera::visible( TDynamicObject const *Dynamic ) const { static_cast( Dynamic->MoverParameters->Dim.L ), static_cast( Dynamic->MoverParameters->Dim.H ), static_cast( Dynamic->MoverParameters->Dim.W ) ); - float const radius = glm::length( diagonal ) * 0.5f; + // we're giving vehicles some extra padding, to allow for things like shared bogeys extending past the main body + float const radius = glm::length( diagonal ) * 0.65f; return ( m_frustum.sphere_inside( Dynamic->GetPosition(), radius ) > 0.0f ); } @@ -47,10 +48,7 @@ opengl_camera::visible( TDynamicObject const *Dynamic ) const { bool opengl_renderer::Init( GLFWwindow *Window ) { - if( false == Init_caps() ) { - - return false; - } + if( false == Init_caps() ) { return false; } m_window = Window; @@ -111,11 +109,21 @@ opengl_renderer::Init( GLFWwindow *Window ) { } // preload some common textures WriteLog( "Loading common gfx data..." ); - m_glaretextureid = GetTextureId( "fx\\lightglare", szTexturePath ); - m_suntextureid = GetTextureId( "fx\\sun", szTexturePath ); - m_moontextureid = GetTextureId( "fx\\moon", szTexturePath ); + m_glaretexture = GetTextureId( "fx\\lightglare", szTexturePath ); + m_suntexture = GetTextureId( "fx\\sun", szTexturePath ); + m_moontexture = GetTextureId( "fx\\moon", szTexturePath ); WriteLog( "...gfx data pre-loading done" ); - + // prepare basic geometry chunks + auto const geometrybank = m_geometry.create_bank(); + float const size = 2.5f; + m_billboardgeometry = m_geometry.create_chunk( + vertex_array{ + { { -size, size, 0.0f }, glm::vec3(), { 1.0f, 1.0f } }, + { { size, size, 0.0f }, glm::vec3(), { 0.0f, 1.0f } }, + { { -size, -size, 0.0f }, glm::vec3(), { 1.0f, 0.0f } }, + { { size, -size, 0.0f }, glm::vec3(), { 0.0f, 0.0f } } }, + geometrybank, + GL_TRIANGLE_STRIP ); // prepare debug mode objects m_quadric = gluNewQuadric(); gluQuadricNormals( m_quadric, GLU_FLAT ); @@ -157,6 +165,7 @@ opengl_renderer::Render() { // accumulate last 20 frames worth of render time (cap at 1000 fps to prevent calculations going awry) m_drawtime = std::max( 20.0f, 0.95f * m_drawtime + std::chrono::duration_cast( ( std::chrono::steady_clock::now() - timestart ) ).count()); + m_drawcount = m_drawqueue.size(); } UILayer.render(); @@ -189,6 +198,10 @@ opengl_renderer::Render( world_environment *Environment ) { else { ::glDisable( GL_FOG ); } Environment->m_skydome.Render(); + if( true == Global::bUseVBO ) { + // skydome uses a custom vbo which could potentially confuse the main geometry system. hardly elegant but, eh + opengl_vbogeometrybank::reset(); + } Environment->m_stars.render(); float const duskfactor = 1.0f - clamp( std::abs( Environment->m_sun.getAngle() ), 0.0f, 12.0f ) / 12.0f; @@ -213,7 +226,7 @@ opengl_renderer::Render( world_environment *Environment ) { auto const &modelview = OpenGLMatrices.data( GL_MODELVIEW ); // sun { - Bind( m_suntextureid ); + Bind( m_suntexture ); ::glColor4f( suncolor.x, suncolor.y, suncolor.z, 1.0f ); auto const sunvector = Environment->m_sun.getDirection(); auto const sunposition = modelview * glm::vec4( sunvector.x, sunvector.y, sunvector.z, 1.0f ); @@ -234,7 +247,7 @@ opengl_renderer::Render( world_environment *Environment ) { } // moon { - Bind( m_moontextureid ); + Bind( m_moontexture ); float3 mooncolor( 255.0f / 255.0f, 242.0f / 255.0f, 231.0f / 255.0f ); ::glColor4f( mooncolor.x, mooncolor.y, mooncolor.z, static_cast( 1.0 - Global::fLuminance * 0.5 ) ); @@ -412,7 +425,8 @@ opengl_renderer::Render( TGround *Ground ) { Global::FieldOfView / Global::ZoomFactor * std::max( 1.0f, (float)Global::ScreenWidth ) / std::max( 1.0f, (float)Global::ScreenHeight ) ) ); - Ground->iRendered = 0; // ilość renderowanych sektorów + m_drawqueue.clear(); + Math3D::vector3 direction; for( k = 0; k < Global::iSegmentsRendered; ++k ) // sektory w kolejnoÅ›ci odlegÅ‚oÅ›ci { // przerobione na użycie SectorOrder @@ -436,37 +450,14 @@ opengl_renderer::Render( TGround *Ground ) { if( ( tmp = Ground->FastGetSubRect( i + c, j + r ) ) != nullptr ) { if( tmp->iNodeCount ) { // o ile sÄ… jakieÅ› obiekty, bo po co puste sektory przelatywać - Ground->pRendered[ Ground->iRendered++ ] = tmp; // tworzenie listy sektorów do renderowania + m_drawqueue.emplace_back( tmp ); } } } while( ( i < 0 ) || ( j < 0 ) ); // sÄ… 4 przypadki, oprócz i=j=0 } -/* - // dodać renderowanie terenu z E3D - jedno VBO jest używane dla caÅ‚ego modelu, chyba że jest ich wiÄ™cej - if( Global::bUseVBO ) { - if( ( Global::pTerrainCompact != nullptr ) - && ( Global::pTerrainCompact->pModel != nullptr ) ) { -#ifdef EU07_USE_OLD_RENDERCODE - Global::pTerrainCompact->TerrainRenderVBO( TGroundRect::iFrameNumber ); -#endif - // TODO: remap geometry of terrain cells to allow camera-centric rendering - ::glPushMatrix(); - ::glTranslated( -Global::pCameraPosition.x, -Global::pCameraPosition.y, -Global::pCameraPosition.z ); - TSubModel *submodel = Global::pTerrainCompact->pModel->Root; - while( submodel != nullptr ) { - if( submodel->iVisible == TGroundRect::iFrameNumber ) { - // tylko jeÅ›li ma być widoczny w danej ramce (problem dla 0==false) - Render( submodel ); // sub kolejne (Next) siÄ™ nie wyrenderujÄ… - } - submodel = submodel->NextGet(); - } - ::glPopMatrix(); - } - } -*/ - // renderowanie nieprzezroczystych - for( i = 0; i < Ground->iRendered; ++i ) { - Render( Ground->pRendered[ i ] ); + + for( auto subcell : m_drawqueue ) { + Render( subcell ); } // regular render takes care of all solid geometry present in the scene, thus we can launch alpha parts render here return Render_Alpha( Ground ); @@ -478,69 +469,23 @@ opengl_renderer::Render( TGroundRect *Groundcell ) { bool result { false }; // will be true if we do any rendering - // TODO: unify render paths - if( Global::bUseVBO ) { + if( Groundcell->iLastDisplay != Groundcell->iFrameNumber ) { + // tylko jezeli dany kwadrat nie byÅ‚ jeszcze renderowany + Groundcell->LoadNodes(); // ewentualne tworzenie siatek - if ( Groundcell->iLastDisplay != Groundcell->iFrameNumber) { - // tylko jezeli dany kwadrat nie byÅ‚ jeszcze renderowany - Groundcell->LoadNodes(); // ewentualne tworzenie siatek - - if( ( Groundcell->nRenderRect != nullptr ) - && ( true == Groundcell->StartVBO() ) ) { - // nieprzezroczyste trójkÄ…ty kwadratu kilometrowego - for( TGroundNode *node = Groundcell->nRenderRect; node; node = node->nNext3 ) { - Render( node ); - } - Groundcell->EndVBO(); + if( Groundcell->nRenderRect != nullptr ) { + // nieprzezroczyste trójkÄ…ty kwadratu kilometrowego + for( TGroundNode *node = Groundcell->nRenderRect; node != nullptr; node = node->nNext3 ) { + Render( node ); } - if( Groundcell->nTerrain ) { - - Render( Groundcell->nTerrain ); - } - Groundcell->iLastDisplay = Groundcell->iFrameNumber; // drugi raz nie potrzeba - result = true; } + if( Groundcell->nTerrain ) { + + Render( Groundcell->nTerrain ); + } + Groundcell->iLastDisplay = Groundcell->iFrameNumber; // drugi raz nie potrzeba + result = true; } - else { - // display list render path - ::glPushMatrix(); - auto const &cellorigin = Groundcell->m_area.center; - // TODO: unify all math objects - auto const originoffset = Math3D::vector3( cellorigin.x, cellorigin.y, cellorigin.z ) - Global::pCameraPosition; - ::glTranslated( originoffset.x, originoffset.y, originoffset.z ); - - if (Groundcell->iLastDisplay != Groundcell->iFrameNumber) - { // tylko jezeli dany kwadrat nie byÅ‚ jeszcze renderowany - // for (TGroundNode* node=pRender;node;node=node->pNext3) - // node->Render(); //nieprzezroczyste trójkÄ…ty kwadratu kilometrowego - if ( Groundcell->nRender) - { //łączenie trójkÄ…tów w jednÄ… listÄ™ - trochÄ™ wioska - if (!Groundcell->nRender->DisplayListID || ( Groundcell->nRender->iVersion != Global::iReCompile)) - { // jeżeli nie skompilowany, kompilujemy wszystkie trójkÄ…ty w jeden - Groundcell->nRender->fSquareRadius = 5000.0 * 5000.0; // aby agregat nigdy nie znikaÅ‚ - Groundcell->nRender->DisplayListID = glGenLists(1); - glNewList( Groundcell->nRender->DisplayListID, GL_COMPILE); - Groundcell->nRender->iVersion = Global::iReCompile; // aktualna wersja siatek - auto const origin = glm::dvec3( Groundcell->m_area.center ); - for (TGroundNode *node = Groundcell->nRender; node; node = node->nNext3) // nastÄ™pny tej grupy - node->Compile(origin, true); - glEndList(); - } - Render( Groundcell->nRender ); // nieprzezroczyste trójkÄ…ty kwadratu kilometrowego - } - // submodels geometry is world-centric, so at least for the time being we need to pop the stack early - ::glPopMatrix(); - - if( Groundcell->nTerrain ) { Render( Groundcell->nTerrain ); } - - Groundcell->iLastDisplay = Groundcell->iFrameNumber; // drugi raz nie potrzeba - result = true; - } - else { - ::glPopMatrix(); - } - } - return result; } @@ -551,32 +496,21 @@ opengl_renderer::Render( TSubRect *Groundsubcell ) { TGroundNode *node; // nieprzezroczyste obiekty terenu - if( Global::bUseVBO ) { - // vbo render path - if( Groundsubcell->StartVBO() ) { - for( node = Groundsubcell->nRenderRect; node; node = node->nNext3 ) { - if( node->iVboPtr >= 0 ) { - Render( node ); - } - } - Groundsubcell->EndVBO(); - } - } - else { - // display list render path - for( node = Groundsubcell->nRenderRect; node; node = node->nNext3 ) { - Render( node ); // nieprzezroczyste obiekty terenu - } + for( node = Groundsubcell->nRenderRect; node != nullptr; node = node->nNext3 ) { + Render( node ); } // nieprzezroczyste obiekty (oprócz pojazdów) - for( node = Groundsubcell->nRender; node; node = node->nNext3 ) + for( node = Groundsubcell->nRender; node != nullptr; node = node->nNext3 ) { Render( node ); + } // nieprzezroczyste z mieszanych modeli - for( node = Groundsubcell->nRenderMixed; node; node = node->nNext3 ) + for( node = Groundsubcell->nRenderMixed; node != nullptr; node = node->nNext3 ) { Render( node ); + } // nieprzezroczyste fragmenty pojazdów na torach - for( int j = 0; j < Groundsubcell->iTracks; ++j ) + for( int j = 0; j < Groundsubcell->iTracks; ++j ) { Groundsubcell->tTracks[ j ]->RenderDyn(); + } #ifdef EU07_SCENERY_EDITOR // memcells if( DebugModeFlag ) { @@ -590,9 +524,9 @@ opengl_renderer::Render( TSubRect *Groundsubcell ) { bool opengl_renderer::Render( TGroundNode *Node ) { - +/* Node->SetLastUsage( Timer::GetSimulationTime() ); - +*/ switch (Node->iType) { // obiekty renderowane niezależnie od odlegÅ‚oÅ›ci case TP_SUBMODEL: @@ -611,96 +545,58 @@ opengl_renderer::Render( TGroundNode *Node ) { return false; } - switch (Node->iType) - { - case TP_TRACK: { + switch (Node->iType) { - if( Global::bUseVBO && ( Node->iNumVerts <= 0 ) ) { - return false; - } + case TP_TRACK: { // setup ::glPushMatrix(); auto const originoffset = Node->m_rootposition - Global::pCameraPosition; ::glTranslated( originoffset.x, originoffset.y, originoffset.z ); - - // TODO: unify the render code after generic buffers are in place - if( Global::bUseVBO ) { - // vbo render path - Node->pTrack->RaRenderVBO( Node->iVboPtr ); - } - else { - // display list render path - Node->pTrack->Render(); - } + // render + Render( Node->pTrack ); // post-render cleanup ::glPopMatrix(); return true; } + case TP_MODEL: { Node->Model->Render( Node->pCenter - Global::pCameraPosition ); return true; } - case TP_MEMCELL: { - GfxRenderer.Render( Node->MemCell ); - return true; - } - } - // TODO: sprawdzic czy jest potrzebny warunek fLineThickness < 0 - if( ( Node->iFlags & 0x10 ) - || ( Node->fLineThickness < 0 ) ) { - // TODO: unify the render code after generic buffers are in place - if( false == Global::bUseVBO ) { - // additional setup for display lists - if( ( Node->DisplayListID == 0 ) - || ( Node->iVersion != Global::iReCompile ) ) { // Ra: wymuszenie rekompilacji - Node->Compile(Node->m_rootposition); - if( Global::bManageNodes ) - ResourceManager::Register( Node ); - }; - } - - if( ( Node->iType == GL_LINES ) - || ( Node->iType == GL_LINE_STRIP ) - || ( Node->iType == GL_LINE_LOOP ) ) { - // wszelkie linie sÄ… rysowane na samym koÅ„cu - if( Node->iNumPts ) { - // setup - // w zaleznosci od koloru swiatla - ::glColor4fv( - glm::value_ptr( - glm::vec4( - Node->Diffuse * glm::make_vec3( Global::DayLight.ambient ), - std::min( - 1.0, - 1000.0 * Node->fLineThickness / ( distancesquared + 1.0 ) ) ) ) ); - - GfxRenderer.Bind( 0 ); - - // render - // TODO: unify the render code after generic buffers are in place - if( Global::bUseVBO ) { - ::glPushMatrix(); - auto const originoffset = Node->m_rootposition - Global::pCameraPosition; - ::glTranslated( originoffset.x, originoffset.y, originoffset.z ); - ::glDrawArrays( Node->iType, Node->iVboPtr, Node->iNumPts ); - ::glPopMatrix(); - } - else { - ::glCallList( Node->DisplayListID ); - } - // post-render cleanup - return true; - } - else { + case GL_LINES: { + if( ( Node->m_geometry == NULL ) + || ( Node->fLineThickness > 0.0 ) ) { return false; } + // setup + // w zaleznosci od koloru swiatla + ::glColor4fv( + glm::value_ptr( + glm::vec4( + Node->Diffuse * glm::make_vec3( Global::DayLight.ambient ), + std::min( + 1.0, + 1000.0 * Node->fLineThickness / ( distancesquared + 1.0 ) ) ) ) ); + + GfxRenderer.Bind( 0 ); + + ::glPushMatrix(); + auto const originoffset = Node->m_rootposition - Global::pCameraPosition; + ::glTranslated( originoffset.x, originoffset.y, originoffset.z ); + + // render + m_geometry.draw( Node->m_geometry ); + + // post-render cleanup + ::glPopMatrix(); + + return true; } - else { - // GL_TRIANGLE etc - if( ( Global::bUseVBO ? - Node->iVboPtr < 0 : - Node->DisplayListID == 0 ) ) { + + case GL_TRIANGLES: { + if( ( Node->m_geometry == NULL ) + || ( ( Node->iFlags & 0x10 ) == 0 ) ) { return false; } // setup @@ -708,23 +604,25 @@ opengl_renderer::Render( TGroundNode *Node ) { Bind( Node->TextureID ); + ::glPushMatrix(); + auto const originoffset = Node->m_rootposition - Global::pCameraPosition; + ::glTranslated( originoffset.x, originoffset.y, originoffset.z ); + // render - // TODO: unify the render code after generic buffers are in place - if( Global::bUseVBO ) { - // vbo render path - ::glPushMatrix(); - auto const originoffset = Node->m_rootposition - Global::pCameraPosition; - ::glTranslated( originoffset.x, originoffset.y, originoffset.z ); - ::glDrawArrays( Node->iType, Node->iVboPtr, Node->iNumVerts ); - ::glPopMatrix(); - } - else { - // display list render path - ::glCallList( Node->DisplayListID ); - } + m_geometry.draw( Node->m_geometry ); + // post-render cleanup + ::glPopMatrix(); + return true; } + + case TP_MEMCELL: { + Render( Node->MemCell ); + return true; + } + + default: { break; } } // in theory we shouldn't ever get here but, eh return false; @@ -946,7 +844,7 @@ opengl_renderer::Render( TSubModel *Submodel ) { ::glDisableClientState( GL_NORMAL_ARRAY ); ::glDisableClientState( GL_TEXTURE_COORD_ARRAY ); ::glEnableClientState( GL_COLOR_ARRAY ); - ::glColorPointer( 3, GL_FLOAT, sizeof( CVertNormTex ), static_cast( nullptr ) + 12 ); // kolory + ::glColorPointer( 3, GL_FLOAT, sizeof( basic_vertex ), static_cast( nullptr ) + 12 ); // kolory ::glDrawArrays( GL_POINTS, Submodel->iVboPtr, Submodel->iNumVerts ); @@ -978,6 +876,28 @@ opengl_renderer::Render( TSubModel *Submodel ) { Render( Submodel->Next ); // dalsze rekurencyjnie } +void +opengl_renderer::Render( TTrack *Track ) { + + if( ( Track->TextureID1 == 0 ) + && ( Track->TextureID2 == 0 ) ) { + return; + } + + Track->EnvironmentSet(); + + if( Track->TextureID1 != 0 ) { + Bind( Track->TextureID1 ); + m_geometry.draw( std::begin( Track->Geometry1 ), std::end( Track->Geometry1 ) ); + } + if( Track->TextureID2 != 0 ) { + Bind( Track->TextureID2 ); + m_geometry.draw( std::begin( Track->Geometry2 ), std::end( Track->Geometry2 ) ); + } + + Track->EnvironmentReset(); +} + void opengl_renderer::Render( TMemCell *Memcell ) { @@ -999,7 +919,6 @@ opengl_renderer::Render( TMemCell *Memcell ) { bool opengl_renderer::Render_Alpha( TGround *Ground ) { - // legacy version of the code: ::glEnable( GL_BLEND ); ::glAlphaFunc( GL_GREATER, 0.04f ); // im mniejsza wartość, tym wiÄ™ksza ramka, domyÅ›lnie 0.1f ::glColor4f( 1.0f, 1.0f, 1.0f, 1.0f ); @@ -1007,54 +926,30 @@ opengl_renderer::Render_Alpha( TGround *Ground ) { TGroundNode *node; TSubRect *tmp; // Ra: renderowanie progresywne - zależne od FPS oraz kierunku patrzenia - for( int i = Ground->iRendered - 1; i >= 0; --i ) // od najdalszych - { // przezroczyste trójkÄ…ty w oddzielnym cyklu przed modelami - tmp = Ground->pRendered[ i ]; - if( Global::bUseVBO ) { - // vbo render path - if( tmp->StartVBO() ) { - for( node = tmp->nRenderRectAlpha; node; node = node->nNext3 ) { - if( node->iVboPtr >= 0 ) { - Render_Alpha( node ); - } - } - tmp->EndVBO(); - } - } - else { - // display list render path - for( node = tmp->nRenderRectAlpha; node; node = node->nNext3 ) { - Render_Alpha( node ); - } + for( auto subcell = std::rbegin( m_drawqueue ); subcell != std::rend( m_drawqueue ); ++subcell ) { + // przezroczyste trójkÄ…ty w oddzielnym cyklu przed modelami + tmp = *subcell; + for( node = tmp->nRenderRectAlpha; node; node = node->nNext3 ) { + Render_Alpha( node ); } } - for( int i = Ground->iRendered - 1; i >= 0; --i ) // od najdalszych + for( auto subcell = std::rbegin( m_drawqueue ); subcell != std::rend( m_drawqueue ); ++subcell ) { // renderowanie przezroczystych modeli oraz pojazdów - Render_Alpha( Ground->pRendered[ i ] ); + Render_Alpha( *subcell ); } ::glDisable( GL_LIGHTING ); // linie nie powinny Å›wiecić - for( int i = Ground->iRendered - 1; i >= 0; --i ) // od najdalszych - { // druty na koÅ„cu, żeby siÄ™ nie robiÅ‚y biaÅ‚e plamy na tle lasu - tmp = Ground->pRendered[ i ]; - if( Global::bUseVBO ) { - // vbo render path - if( tmp->StartVBO() ) { - for( node = tmp->nRenderWires; node; node = node->nNext3 ) { - Render_Alpha( node ); - } - tmp->EndVBO(); - } - } - else { - // display list render path - for( node = tmp->nRenderWires; node; node = node->nNext3 ) { - Render_Alpha( node ); // druty - } + for( auto subcell = std::rbegin( m_drawqueue ); subcell != std::rend( m_drawqueue ); ++subcell ) { + // druty na koÅ„cu, żeby siÄ™ nie robiÅ‚y biaÅ‚e plamy na tle lasu + tmp = *subcell; + for( node = tmp->nRenderWires; node; node = node->nNext3 ) { + Render_Alpha( node ); } } + ::glEnable( GL_LIGHTING ); + return true; } @@ -1091,9 +986,9 @@ opengl_renderer::Render_Alpha( TGroundNode *Node ) { // pozniej sprawdzamy czy jest wlaczony PROBLEND dla aktualnie renderowanego noda TRIANGLE, // wlasciwie dla kazdego node'a // i jezeli tak to odpowiedni GL_GREATER w przeciwnym wypadku standardowy 0.04 - +/* Node->SetLastUsage( Timer::GetSimulationTime() ); - +*/ double const distancesquared = SquareMagnitude( ( Node->pCenter - Global::pCameraPosition ) / Global::ZoomFactor ); if( ( distancesquared > ( Node->fSquareRadius * Global::fDistanceFactor ) ) || ( distancesquared < ( Node->fSquareMinRadius / Global::fDistanceFactor ) ) ) { @@ -1103,7 +998,6 @@ opengl_renderer::Render_Alpha( TGroundNode *Node ) { switch (Node->iType) { case TP_TRACTION: { - // TODO: unify the render code after generic buffers are in place if( Node->bVisible ) { // rysuj jesli sa druty i nie zerwana if( ( Node->hvTraction->Wires == 0 ) @@ -1111,11 +1005,6 @@ opengl_renderer::Render_Alpha( TGroundNode *Node ) { return false; } // setup - ::glPushMatrix(); - auto const originoffset = Node->m_rootposition - Global::pCameraPosition; - ::glTranslated( originoffset.x, originoffset.y, originoffset.z ); - - Bind( NULL ); if( !Global::bSmoothTraction ) { // na liniach kiepsko wyglÄ…da - robi gradient ::glDisable( GL_LINE_SMOOTH ); @@ -1129,16 +1018,23 @@ opengl_renderer::Render_Alpha( TGroundNode *Node ) { auto const color { Node->hvTraction->wire_color() }; ::glColor4f( color.r, color.g, color.b, linealpha ); + Bind( NULL ); + + ::glPushMatrix(); + auto const originoffset = Node->m_rootposition - Global::pCameraPosition; + ::glTranslated( originoffset.x, originoffset.y, originoffset.z ); + // render m_geometry.draw( Node->hvTraction->m_geometry ); // post-render cleanup + ::glPopMatrix(); + ::glLineWidth( 1.0 ); if( !Global::bSmoothTraction ) { ::glEnable( GL_LINE_SMOOTH ); } - ::glPopMatrix(); return true; } else { @@ -1149,102 +1045,75 @@ opengl_renderer::Render_Alpha( TGroundNode *Node ) { Node->Model->RenderAlpha( Node->pCenter - Global::pCameraPosition ); return true; } - } - // TODO: sprawdzic czy jest potrzebny warunek fLineThickness < 0 - if( ( Node->iNumVerts && ( Node->iFlags & 0x20 ) ) - || ( Node->iNumPts && ( Node->fLineThickness > 0 ) ) ) { - -#ifdef _PROBLEND - if( ( Node->PROBLEND ) ) // sprawdza, czy w nazwie nie ma @ //Q: 13122011 - Szociu: 27012012 - { - ::glDisable( GL_BLEND ); - ::glAlphaFunc( GL_GREATER, 0.50f ); // im mniejsza wartość, tym wiÄ™ksza ramka, domyÅ›lnie 0.1f - }; -#endif - // TODO: unify the render code after generic buffers are in place - if( false == Global::bUseVBO ) { - // additional setup for display lists - if( ( Node->DisplayListID == 0 ) - || ( Node->iVersion != Global::iReCompile ) ) { // Ra: wymuszenie rekompilacji - Node->Compile(Node->m_rootposition); - if( Global::bManageNodes ) - ResourceManager::Register( Node ); - }; - } - - bool result( false ); - - if( ( Node->iType == GL_LINES ) - || ( Node->iType == GL_LINE_STRIP ) - || ( Node->iType == GL_LINE_LOOP ) ) { - // wszelkie linie sÄ… rysowane na samym koÅ„cu - if( Node->iNumPts ) { - // setup - ::glPushMatrix(); - auto const originoffset = Node->m_rootposition - Global::pCameraPosition; - ::glTranslated( originoffset.x, originoffset.y, originoffset.z ); - // w zaleznosci od koloru swiatla - ::glColor4fv( - glm::value_ptr( - glm::vec4( - Node->Diffuse * glm::make_vec3( Global::DayLight.ambient ), - std::min( - 1.0, - 1000.0 * Node->fLineThickness / ( distancesquared + 1.0 ) ) ) ) ); - - GfxRenderer.Bind( 0 ); - - // render - // TODO: unify the render code after generic buffers are in place - if( Global::bUseVBO ) { - ::glDrawArrays( Node->iType, Node->iVboPtr, Node->iNumPts ); - } - else { - ::glCallList( Node->DisplayListID ); - } - // post-render cleanup - ::glPopMatrix(); - result = true; + case GL_LINES: { + if( ( Node->m_geometry == NULL ) + || ( Node->fLineThickness < 0.0 ) ) { + return false; } - } - else { - // GL_TRIANGLE etc // setup + // w zaleznosci od koloru swiatla + ::glColor4fv( + glm::value_ptr( + glm::vec4( + Node->Diffuse * glm::make_vec3( Global::DayLight.ambient ), + std::min( + 1.0, + 1000.0 * Node->fLineThickness / ( distancesquared + 1.0 ) ) ) ) ); + + GfxRenderer.Bind( 0 ); + ::glPushMatrix(); auto const originoffset = Node->m_rootposition - Global::pCameraPosition; ::glTranslated( originoffset.x, originoffset.y, originoffset.z ); + // render + m_geometry.draw( Node->m_geometry ); + + // post-render cleanup + ::glPopMatrix(); + + return true; + } + + case GL_TRIANGLES: { + if( ( Node->m_geometry == NULL ) + || ( ( Node->iFlags & 0x20 ) == 0 ) ) { + return false; + } + // setup +#ifdef _PROBLEND + if( ( Node->PROBLEND ) ) // sprawdza, czy w nazwie nie ma @ //Q: 13122011 - Szociu: 27012012 + { + ::glDisable( GL_BLEND ); + ::glAlphaFunc( GL_GREATER, 0.50f ); // im mniejsza wartość, tym wiÄ™ksza ramka, domyÅ›lnie 0.1f + }; +#endif ::glColor3fv( glm::value_ptr( Node->Diffuse ) ); Bind( Node->TextureID ); + ::glPushMatrix(); + auto const originoffset = Node->m_rootposition - Global::pCameraPosition; + ::glTranslated( originoffset.x, originoffset.y, originoffset.z ); + // render - // TODO: unify the render code after generic buffers are in place - if( Global::bUseVBO ) { - // vbo render path - if( Node->iVboPtr >= 0 ) { - ::glDrawArrays( Node->iType, Node->iVboPtr, Node->iNumVerts ); - result = true; - } - } - else { - // display list render path - ::glCallList( Node->DisplayListID ); - result = true; - } + m_geometry.draw( Node->m_geometry ); + // post-render cleanup ::glPopMatrix(); - } #ifdef _PROBLEND - if( ( Node->PROBLEND ) ) // sprawdza, czy w nazwie nie ma @ //Q: 13122011 - Szociu: 27012012 - { - ::glEnable( GL_BLEND ); - ::glAlphaFunc( GL_GREATER, 0.04f ); - } + if( ( Node->PROBLEND ) ) // sprawdza, czy w nazwie nie ma @ //Q: 13122011 - Szociu: 27012012 + { + ::glEnable( GL_BLEND ); + ::glAlphaFunc( GL_GREATER, 0.04f ); + } #endif - return result; + return true; + } + + default: { break; } } // in theory we shouldn't ever get here but, eh return false; @@ -1253,10 +1122,7 @@ opengl_renderer::Render_Alpha( TGroundNode *Node ) { bool opengl_renderer::Render_Alpha( TDynamicObject *Dynamic ) { - if( false == Dynamic->renderme ) { - - return false; - } + if( false == Dynamic->renderme ) { return false; } // setup TSubModel::iInstance = ( size_t )this; //żeby nie robić cudzych animacji @@ -1426,10 +1292,10 @@ opengl_renderer::Render_Alpha( TSubModel *Submodel ) { glarelevel = std::max( 0.0f, glarelevel - static_cast(Global::fLuminance) ); if( glarelevel > 0.0f ) { - + // setup ::glPushAttrib( GL_ENABLE_BIT | GL_CURRENT_BIT | GL_COLOR_BUFFER_BIT ); - Bind( m_glaretextureid ); + Bind( m_glaretexture ); ::glColor4f( Submodel->f4Diffuse[ 0 ], Submodel->f4Diffuse[ 1 ], Submodel->f4Diffuse[ 2 ], glarelevel ); ::glDisable( GL_LIGHTING ); ::glBlendFunc( GL_SRC_ALPHA, GL_ONE ); @@ -1437,15 +1303,10 @@ opengl_renderer::Render_Alpha( TSubModel *Submodel ) { ::glPushMatrix(); ::glLoadIdentity(); // macierz jedynkowa ::glTranslatef( lightcenter.x, lightcenter.y, lightcenter.z ); // poczÄ…tek ukÅ‚adu zostaje bez zmian - ::glRotated( atan2( lightcenter.x, lightcenter.z ) * 180.0 / M_PI, 0.0, 1.0, 0.0 ); // jedynie obracamy w pionie o kÄ…t + ::glRotated( std::atan2( lightcenter.x, lightcenter.z ) * 180.0 / M_PI, 0.0, 1.0, 0.0 ); // jedynie obracamy w pionie o kÄ…t - // TODO: turn the drawing instructions into a compiled call / array - ::glBegin( GL_TRIANGLE_STRIP ); - float const size = 2.5f; - ::glTexCoord2f( 1.0f, 1.0f ); ::glVertex3f( -size, size, 0.0f ); - ::glTexCoord2f( 0.0f, 1.0f ); ::glVertex3f( size, size, 0.0f ); - ::glTexCoord2f( 1.0f, 0.0f ); ::glVertex3f( -size, -size, 0.0f ); - ::glTexCoord2f( 0.0f, 0.0f ); ::glVertex3f( size, -size, 0.0f ); + // main draw call + m_geometry.draw( m_billboardgeometry ); /* // NOTE: we could do simply... vec3 vertexPosition_worldspace = @@ -1454,8 +1315,7 @@ opengl_renderer::Render_Alpha( TSubModel *Submodel ) { + CameraUp_worldspace * squareVertices.y * BillboardSize.y; // ...etc instead IF we had easy access to camera's forward and right vectors. TODO: check if Camera matrix is accessible */ - ::glEnd(); - + // post-render cleanup ::glPopMatrix(); ::glPopAttrib(); } @@ -1557,8 +1417,12 @@ opengl_renderer::Update ( double const Deltatime ) { } // TODO: add garbage collection and other less frequent works here - if( DebugModeFlag ) + if( true == DebugModeFlag ) { m_debuginfo = m_textures.info(); + } + else { + m_debuginfo.clear(); + } }; // debug performance string diff --git a/renderer.h b/renderer.h index 19e31d55..a1420e25 100644 --- a/renderer.h +++ b/renderer.h @@ -172,6 +172,7 @@ public: // members GLenum static const sunlight{ GL_LIGHT0 }; + std::size_t m_drawcount { 0 }; private: // types @@ -194,6 +195,8 @@ private: Render( TSubRect *Groundsubcell ); bool Render( TGroundNode *Node ); + void + Render( TTrack *Track ); void Render( TMemCell *Memcell ); bool @@ -212,16 +215,18 @@ private: geometrybank_manager m_geometry; texture_manager m_textures; opengl_camera m_camera; - rendermode renderpass{ rendermode::color }; - float m_drawrange{ 2500.0f }; // current drawing range - float m_drawtime{ 1000.0f / 30.0f * 20.0f }; // start with presumed 'neutral' average of 30 fps - double m_updateaccumulator{ 0.0 }; + rendermode renderpass { rendermode::color }; + float m_drawrange { 2500.0f }; // current drawing range + float m_drawtime { 1000.0f / 30.0f * 20.0f }; // start with presumed 'neutral' average of 30 fps + double m_updateaccumulator { 0.0 }; std::string m_debuginfo; - GLFWwindow *m_window{ nullptr }; - texture_handle m_glaretextureid{ -1 }; - texture_handle m_suntextureid{ -1 }; - texture_handle m_moontextureid{ -1 }; + GLFWwindow *m_window { nullptr }; + texture_handle m_glaretexture { -1 }; + texture_handle m_suntexture { -1 }; + texture_handle m_moontexture { -1 }; + geometry_handle m_billboardgeometry { 0, 0 }; GLUquadricObj *m_quadric; // helper object for drawing debug mode scene elements + std::vector< TSubRect* > m_drawqueue; // list of subcells to be drawn in current render pass }; From d87848ef9b59d98dc460aa0907fa6eb80cd7da08 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Tue, 13 Jun 2017 20:04:31 +0200 Subject: [PATCH 7/9] post-merge cleanup --- Ground.cpp | 85 ++---- Ground.h | 4 +- Model3d.cpp | 20 +- Track.cpp | 670 ------------------------------------------- Track.h | 6 +- openglgeometrybank.h | 3 +- version.h | 2 +- 7 files changed, 28 insertions(+), 762 deletions(-) diff --git a/Ground.cpp b/Ground.cpp index 218b218f..bff36c80 100644 --- a/Ground.cpp +++ b/Ground.cpp @@ -70,31 +70,17 @@ TGroundNode::TGroundNode() iType = GL_POINTS; Vertices = NULL; nNext = nNext2 = NULL; -/* - pCenter = vector3(0, 0, 0); -*/ iCount = 0; // wierzchoÅ‚ków w trójkÄ…cie // iNumPts=0; //punktów w linii TextureID = 0; iFlags = 0; // tryb przezroczystoÅ›ci nie zbadany - DisplayListID = 0; Pointer = NULL; // zerowanie wskaźnika kontekstowego bVisible = false; // czy widoczny fSquareRadius = 10000 * 10000; fSquareMinRadius = 0; asName = ""; fLineThickness=1.0; //mm dla linii -/* - for (int i = 0; i < 3; i++) - { - Ambient[i] = Global::whiteLight[i] * 255; - Diffuse[i] = Global::whiteLight[i] * 255; - Specular[i] = Global::noLight[i] * 255; - } -*/ nNext3 = NULL; // nie wyÅ›wietla innych - iVboPtr = -1; // indeks w VBO sektora (-1: nie używa VBO) - iVersion = 0; // wersja siatki } TGroundNode::~TGroundNode() @@ -182,7 +168,7 @@ void TGroundNode::InitNormals() glm::dvec3 v1, v2, v3, v4, v5; glm::vec3 n1, n2, n3, n4; glm::vec2 t1; - std::size_t i; + int i; switch (iType) { case GL_TRIANGLE_STRIP: @@ -246,14 +232,7 @@ void TGroundNode::InitNormals() break; } } -/* -void TGroundNode::Release() -{ - if (DisplayListID) - glDeleteLists(DisplayListID, 1); - DisplayListID = 0; -}; -*/ + void TGroundNode::RenderHidden() { // renderowanie obiektów niewidocznych double mgn = SquareMagnitude(pCenter - Global::pCameraPosition); @@ -285,10 +264,6 @@ void TGroundNode::RenderHidden() //------------------------------------------------------------------------------ TSubRect::~TSubRect() { -/* - if (Global::bManageNodes) // Ra: tu siÄ™ coÅ› sypie - ResourceManager::Unregister(this); // wyrejestrowanie ze sprzÄ…tacza -*/ // TODO: usunąć obiekty z listy (nRootMesh), bo sÄ… one tworzone dla sektora delete[] tTracks; } @@ -477,7 +452,7 @@ void TSubRect::LoadNodes() { switch (node->iType) { case GL_TRIANGLES: { vertex_array vertices; - for( std::size_t idx = 0; idx < node->iNumVerts; ++idx ) { + for( int idx = 0; idx < node->iNumVerts; ++idx ) { vertices.emplace_back( node->Vertices[ idx ].position - node->m_rootposition, node->Vertices[ idx ].normal, @@ -490,7 +465,7 @@ void TSubRect::LoadNodes() { } case GL_LINES: { vertex_array vertices; - for( std::size_t idx = 0; idx < node->iNumPts; ++idx ) { + for( int idx = 0; idx < node->iNumPts; ++idx ) { vertices.emplace_back( node->Points[ idx ] - node->m_rootposition, glm::vec3(), @@ -513,16 +488,8 @@ void TSubRect::LoadNodes() { } node = node->nNext2; // nastÄ™pny z sektora } -/* - if (Global::bManageNodes) - ResourceManager::Register(this); // dodanie do automatu zwalniajÄ…cego pamięć -*/ } -/* -void TSubRect::Release() -{ // wirtualne zwolnienie zasobów przez sprzÄ…tacz albo destruktor -}; -*/ + void TSubRect::RenderSounds() { // aktualizacja dźwiÄ™ków w pojazdach sektora (sektor może nie być wyÅ›wietlany) for (int j = 0; j < iTracks; ++j) @@ -575,9 +542,6 @@ TGround::TGround() nRootOfType[ i ] = nullptr; // zerowanie tablic wyszukiwania } ::SecureZeroMemory( TempConnectionType, sizeof( TempConnectionType ) ); -/* - ::SecureZeroMemory( pRendered, sizeof( pRendered ) ); -*/ // set bounding area information for ground rectangles float const rectsize = 1000.0f; glm::vec3 const worldcenter; @@ -780,14 +744,6 @@ void TGround::RaTriangleDivider(TGroundNode *node) ntri->Init(3); ntri->TextureID = node->TextureID; ntri->iFlags = node->iFlags; -/* - for (int j = 0; j < 4; ++j) - { - ntri->Ambient[j] = node->Ambient[j]; - ntri->Diffuse[j] = node->Diffuse[j]; - ntri->Specular[j] = node->Specular[j]; - } -*/ ntri->Ambient = node->Ambient; ntri->Diffuse = node->Diffuse; ntri->Specular = node->Specular; @@ -1256,7 +1212,7 @@ TGroundNode * TGround::AddGroundNode(cParser *parser) tmp->nNode[0].iType = TP_MODEL; // pierwszy zawiera model (dla delete) tmp->nNode[0].Model = Global::pTerrainCompact; tmp->nNode[0].iFlags = 0x200; // nie wyÅ›wietlany, ale usuwany - for (std::size_t i = 1; i < tmp->iCount; ++i) + for (int i = 1; i < tmp->iCount; ++i) { // a reszta to submodele tmp->nNode[i].iType = TP_SUBMODEL; // tmp->nNode[i].smTerrain = Global::pTerrainCompact->TerrainSquare(i - 1); @@ -2073,7 +2029,7 @@ bool TGround::Init(std::string File) bool TGround::InitEvents() { //łączenie eventów z pozostaÅ‚ymi obiektami TGroundNode *tmp, *trk; - char buff[255]; + char buff[ 255 ]; std::string cellastext; int i; for (TEvent *Current = RootEvent; Current; Current = Current->evNext2) { @@ -2166,19 +2122,16 @@ bool TGround::InitEvents() else ErrorLog("Bad copyvalues: event \"" + Current->asName + "\" cannot find memcell \"" + Current->asNodeName + "\""); - strcpy( - buff, - Current->Params[9].asText); // skopiowanie nazwy drugiej komórki do bufora roboczego + cellastext = Current->Params[ 9 ].asText; SafeDeleteArray(Current->Params[9].asText); // usuniÄ™cie nazwy komórki - tmp = FindGroundNode(buff, TP_MEMCELL); // komórka źódÅ‚owa - if (tmp) - { + tmp = FindGroundNode( cellastext, TP_MEMCELL); // komórka źódÅ‚owa + if (tmp != nullptr ) { Current->Params[8].nGroundNode = tmp; Current->Params[9].asMemCell = tmp->MemCell; // komórka źródÅ‚owa } else ErrorLog("Bad copyvalues: event \"" + Current->asName + - "\" cannot find memcell \"" + buff + "\""); + "\" cannot find memcell \"" + cellastext + "\""); break; case tp_Animation: // animacja modelu tmp = FindGroundNode(Current->asNodeName, TP_MODEL); // egzemplarza modelu do animowania @@ -4024,13 +3977,17 @@ void TGround::DynamicRemove(TDynamicObject *dyn) }; //--------------------------------------------------------------------------- + void TGround::TerrainRead(std::string const &f){ // Ra: wczytanie trójkÄ…tów terenu z pliku E3D }; //--------------------------------------------------------------------------- + void TGround::TerrainWrite() { // Ra: zapisywanie trójkÄ…tów terenu do pliku E3D + // TODO: re-implement +/* if (Global::pTerrainCompact->TerrainLoaded()) return; // jeÅ›li zostaÅ‚o wczytane, to nie ma co dalej robić if (Global::asTerrainModel.empty()) @@ -4092,16 +4049,6 @@ void TGround::TerrainWrite() ver[ k ].position = Current->Vertices[ k ].position; ver[ k ].normal = Current->Vertices[ k ].normal; ver[ k ].texture = Current->Vertices[ k ].texture; -/* - ver[k].position.x = Current->Vertices[k].position.x; - ver[k].position.y = Current->Vertices[k].position.y; - ver[k].position.z = Current->Vertices[k].position.z; - ver[k].normal.x = Current->Vertices[k].normal.x; - ver[k].normal.y = Current->Vertices[k].normal.y; - ver[k].normal.z = Current->Vertices[k].normal.z; - ver[k].texture.s = Current->Vertices[k].tu; - ver[k].texture.t = Current->Vertices[k].tv; -*/ } break; case GL_TRIANGLE_STRIP: // na razie nie, bo trzeba przerabiać na pojedyncze trójkÄ…ty @@ -4111,7 +4058,9 @@ void TGround::TerrainWrite() } } m->SaveToBinFile(strdup(("models\\" + Global::asTerrainModel).c_str())); +*/ }; + //--------------------------------------------------------------------------- void TGround::TrackBusyList() diff --git a/Ground.h b/Ground.h index 966555a8..c3773de0 100644 --- a/Ground.h +++ b/Ground.h @@ -139,9 +139,6 @@ public: int iNumPts; // dla linii int iCount; // dla terenu }; - int iVersion; // wersja siatki (do wykonania rekompilacji) - GLuint DisplayListID; // numer siatki DisplayLists - int iVboPtr; // indeks w buforze VBO // NOTE: geometry handle is duplicated in (anim)model(3d), as well as in track and traction type nodes // TODO: clean this up when node types are refactored into an inheritance/composition scheme geometry_handle m_geometry; // geometry of the submodel @@ -273,6 +270,7 @@ class TGround TEvent *RootEvent = nullptr; // lista zdarzeÅ„ TEvent *QueryRootEvent = nullptr, *tmpEvent = nullptr; +/* TSubRect *pRendered[1500]; // lista renderowanych sektorów */ int iNumNodes = 0; diff --git a/Model3d.cpp b/Model3d.cpp index 7f13e17f..40db9adf 100644 --- a/Model3d.cpp +++ b/Model3d.cpp @@ -187,18 +187,8 @@ inline void readColor(cParser &parser, glm::vec4 &color) >> color.g >> color.b; color /= 255.0f; -/* - color = r + (g << 8) + (b << 16); -*/ }; -/* -inline void readMatrix(cParser& parser,matrix4x4& matrix) -{//Ra: wczytanie transforma -for (int x=0;x<=3;x++) //wiersze -for (int y=0;y<=3;y++) //kolumny -parser.getToken(matrix(x)[y]); -}; -*/ + inline void readMatrix(cParser &parser, float4x4 &matrix) { // Ra: wczytanie transforma parser.getTokens(16, false); @@ -597,8 +587,7 @@ int TSubModel::Load(cParser &parser, TModel3d *Model, int Pos, bool dynamic) }; int TSubModel::TriangleAdd(TModel3d *m, texture_handle tex, int tri) -{ // dodanie trójkÄ…tów do submodelu, używane - // przy tworzeniu E3D terenu +{ // dodanie trójkÄ…tów do submodelu, używane przy tworzeniu E3D terenu TSubModel *s = this; while (s ? (s->TextureID != tex) : false) { // szukanie submodelu o danej teksturze @@ -616,7 +605,7 @@ int TSubModel::TriangleAdd(TModel3d *m, texture_handle tex, int tri) s = new TSubModel(); m->AddTo(this, s); } - s->TextureNameSet(GfxRenderer.Texture(tex).name.c_str()); + s->TextureNameSet(GfxRenderer.Texture(tex).name); s->TextureID = tex; s->eType = GL_TRIANGLES; } @@ -628,8 +617,7 @@ int TSubModel::TriangleAdd(TModel3d *m, texture_handle tex, int tri) }; basic_vertex *TSubModel::TrianglePtr(int tex, int pos, glm::vec3 const &Ambient, glm::vec3 const &Diffuse, glm::vec3 const &Specular ) -{ // zwraca wskaźnik do wypeÅ‚nienia tabeli wierzchoÅ‚ków, używane - // przy tworzeniu E3D terenu +{ // zwraca wskaźnik do wypeÅ‚nienia tabeli wierzchoÅ‚ków, używane przy tworzeniu E3D terenu TSubModel *s = this; while (s ? s->TextureID != tex : false) { // szukanie submodelu o danej teksturze diff --git a/Track.cpp b/Track.cpp index 67ffdc63..2f58097d 100644 --- a/Track.cpp +++ b/Track.cpp @@ -202,9 +202,6 @@ TTrack * TTrack::Create400m(int what, double dx) TSubRect *r = Global::pGround->GetSubRect(tmp->pCenter.x, tmp->pCenter.z); r->NodeAdd(tmp); // dodanie toru do segmentu r->Sort(); //żeby wyÅ›wietlaÅ‚ tabor z dodanego toru -/* - r->Release(); // usuniÄ™cie skompilowanych zasobów -*/ return trk; }; @@ -314,9 +311,6 @@ TTrack * TTrack::NullCreate(int dir) if (tmp2) r->NodeAdd(tmp2); // drugiego też r->Sort(); //żeby wyÅ›wietlaÅ‚ tabor z dodanego toru -/* - r->Release(); // usuniÄ™cie skompilowanych zasobów -*/ return trk; }; @@ -1026,652 +1020,7 @@ const vector6 iglica[nnumPts] = // iglica - vextor3(x,y,mapowanie tekstury) vector6(-0.040, -0.180, 1.00, -1.000, 0.000, 0.000) // 1mm wiÄ™cej, żeby nie nachodziÅ‚y tekstury? }; -/* -void TTrack::Compile(GLuint tex) -{ - basic_vertex *immediate{ nullptr }; - - // generowanie treÅ›ci dla Display Lists - model proceduralny - if (!tex) - { // jeÅ›li nie podana tekstura, to każdy tor ma wlasne DL - if (DisplayListID) - Release(); // zwolnienie zasobów w celu ponownego utworzenia - if (Global::bManageNodes) - { - DisplayListID = glGenLists(1); // otwarcie nowej listy - glNewList(DisplayListID, GL_COMPILE); - }; - } - glColor3f(1.0f, 1.0f, 1.0f); // to tutaj potrzebne? - // Ra: nie zmieniamy oÅ›wietlenia przy kompilowaniu, ponieważ ono siÄ™ zmienia w czasie! - // trochÄ™ podliczonych zmiennych, co siÄ™ potem przydadzÄ… - double fHTW = 0.5 * fabs(fTrackWidth); // poÅ‚owa szerokoÅ›ci - double side = fabs(fTexWidth); // szerokść podsypki na zewnÄ…trz szyny albo pobocza - double slop = fabs(fTexSlope); // szerokość pochylenia - double rozp = fHTW + side + slop; // brzeg zewnÄ™trzny - double hypot1 = hypot(slop, fTexHeight1); // rozmiar pochylenia do liczenia normalnych - if (hypot1 == 0.0) - hypot1 = 1.0; - vector3 normal1 = vector3(fTexSlope / hypot1, fTexHeight1 / hypot1, 0.0); // wektor normalny - double fHTW2, side2, slop2, rozp2, fTexHeight2, hypot2; - vector3 normal2; - if (iTrapezoid & 2) // ten bit oznacza, że istnieje odpowiednie pNext - { // Ra: jest OK - fHTW2 = 0.5 * fabs(trNext->fTrackWidth); // poÅ‚owa rozstawu/nawierzchni - side2 = fabs(trNext->fTexWidth); - slop2 = fabs(trNext->fTexSlope); - rozp2 = fHTW2 + side2 + slop2; // szerokość podstawy - fTexHeight2 = trNext->fTexHeight1; - hypot2 = hypot(slop2, fTexHeight2); - if (hypot2 == 0.0) - hypot2 = 1.0; - normal2 = vector3(trNext->fTexSlope / hypot2, fTexHeight2 / hypot2, 0.0); - } - else // gdy nie ma nastÄ™pnego albo jest nieodpowiednim koÅ„cem podpiÄ™ty - { - fHTW2 = fHTW; - side2 = side; - slop2 = slop; - rozp2 = rozp; - fTexHeight2 = fTexHeight1; - hypot2 = hypot1; - normal2 = normal1; - } - auto const origin { pMyNode->m_rootposition }; - - double roll1, roll2; - switch (iCategoryFlag & 15) - { - case 1: // tor - { - Segment->GetRolls(roll1, roll2); - double sin1 = sin(roll1), cos1 = cos(roll1), sin2 = sin(roll2), cos2 = cos(roll2); - // zwykla szyna: //Ra: czemu główki sÄ… asymetryczne na wysokoÅ›ci 0.140? - vector6 rpts1[24], rpts2[24], rpts3[24], rpts4[24]; - int i; - for (i = 0; i < 12; ++i) - { - rpts1[i] = - vector6( - (fHTW + szyna[i].x) * cos1 + szyna[i].y * sin1, - -(fHTW + szyna[i].x) * sin1 + szyna[i].y * cos1, - szyna[i].z, - +szyna[i].n.x * cos1 + szyna[i].n.y * sin1, - -szyna[i].n.x * sin1 + szyna[i].n.y * cos1, - 0.0); - rpts2[11 - i] = - vector6( - (-fHTW - szyna[i].x) * cos1 + szyna[i].y * sin1, - -(-fHTW - szyna[i].x) * sin1 + szyna[i].y * cos1, - szyna[i].z, - -szyna[i].n.x * cos1 + szyna[i].n.y * sin1, - +szyna[i].n.x * sin1 + szyna[i].n.y * cos1, - 0.0); - } - if (iTrapezoid) // jak trapez albo przechyÅ‚ki, to oddzielne punkty na koÅ„cu - for (i = 0; i < 12; ++i) - { - rpts1[12 + i] = - vector6( - (fHTW2 + szyna[i].x) * cos2 + szyna[i].y * sin2, - -(fHTW2 + szyna[i].x) * sin2 + szyna[i].y * cos2, - szyna[i].z, - +szyna[i].n.x * cos2 + szyna[i].n.y * sin2, - -szyna[i].n.x * sin2 + szyna[i].n.y * cos2, - 0.0); - rpts2[23 - i] = - vector6( - (-fHTW2 - szyna[i].x) * cos2 + szyna[i].y * sin2, - -(-fHTW2 - szyna[i].x) * sin2 + szyna[i].y * cos2, - szyna[i].z, - -szyna[i].n.x * cos2 + szyna[i].n.y * sin2, - +szyna[i].n.x * sin2 + szyna[i].n.y * cos2, - 0.0); - } - switch (eType) // dalej zależnie od typu - { - case tt_Table: // obrotnica jak zwykÅ‚y tor, animacja wykonywana w RaAnimate(), tutaj tylko - // regeneracja siatek - case tt_Normal: - if (TextureID2) - if (tex ? TextureID2 == tex : true) // jeÅ›li pasuje do grupy (tex) - { // podsypka z podkÅ‚adami jest tylko dla zwykÅ‚ego toru - vector6 bpts1[8]; // punkty głównej pÅ‚aszczyzny nie przydajÄ… siÄ™ do robienia boków - if (fTexLength == 4.0) // jeÅ›li stare mapowanie na profil 0.2 0.5 1.1 (również 6-9-9/noil) - { // stare mapowanie z różnÄ… gÄ™stoÅ›ciÄ… pikseli i oddzielnymi teksturami na każdy - // profil - if (iTrapezoid) // trapez albo przechyÅ‚ki - { // podsypka z podkladami trapezowata - // ewentualnie poprawić mapowanie, żeby Å›rodek mapowaÅ‚ siÄ™ na 1.435/4.671 ((0.3464,0.6536) - // bo siÄ™ tekstury podsypki rozjeżdżajÄ… po zmianie proporcji profilu - bpts1[0] = vector6(rozp, -fTexHeight1 - 0.18, 0.00, normal1.x, -normal1.y, 0.0); // lewy brzeg - bpts1[1] = vector6((fHTW + side) * cos1, -(fHTW + side) * sin1 - 0.18, 0.33, 0.0, 1.0, 0.0); // krawÄ™dź zaÅ‚amania - bpts1[2] = vector6(-bpts1[1].x, +(fHTW + side) * sin1 - 0.18, 0.67, -normal1.x, -normal1.y, 0.0); // prawy brzeg poczÄ…tku symetrycznie - bpts1[3] = vector6(-rozp, -fTexHeight1 - 0.18, 1.00, -normal1.x, -normal1.y, 0.0); // prawy skos - // przekrój koÅ„cowy - bpts1[4] = vector6(rozp2, -fTexHeight2 - 0.18, 0.00, normal2.x, -normal2.y, 0.0); // lewy brzeg - bpts1[5] = vector6((fHTW2 + side2) * cos2, -(fHTW2 + side2) * sin2 - 0.18, 0.33, 0.0, 1.0, 0.0); // krawÄ™dź zaÅ‚amania - bpts1[6] = vector6(-bpts1[5].x, +(fHTW2 + side2) * sin2 - 0.18, 0.67, 0.0, 1.0, 0.0); // prawy brzeg poczÄ…tku symetrycznie - bpts1[7] = vector6(-rozp2, -fTexHeight2 - 0.18, 1.00, -normal2.x, -normal2.y, 0.0); // prawy skos - } - else - { - bpts1[0] = vector6(rozp, -fTexHeight1 - 0.18, 0.0, +normal1.x, -normal1.y, 0.0); // lewy brzeg - bpts1[1] = vector6(fHTW + side, -0.18, 0.33, +normal1.x, -normal1.y, 0.0); // krawÄ™dź zaÅ‚amania - bpts1[2] = vector6(-fHTW - side, -0.18, 0.67, -normal1.x, -normal1.y, 0.0); // druga - bpts1[3] = vector6(-rozp, -fTexHeight1 - 0.18, 1.0, -normal1.x, -normal1.y, 0.0); // prawy skos - } - } - else - { // mapowanie proporcjonalne do powierzchni, rozmiar w poprzek okreÅ›la fTexLength - double max = fTexRatio2 * fTexLength; // szerokość proporcjonalna do dÅ‚ugoÅ›ci - double map11 = ( - max > 0.0 ? - (fHTW + side) / max : - 0.25 ); // zaÅ‚amanie od strony 1 - double map12 = ( - max > 0.0 ? - (fHTW + side + hypot1) / max : - 0.5 ); // brzeg od strony 1 - if (iTrapezoid) // trapez albo przechyÅ‚ki - { // podsypka z podkladami trapezowata - double map21 = ( - max > 0.0 ? - (fHTW2 + side2) / max : - 0.25 ); // zaÅ‚amanie od strony 2 - double map22 = ( - max > 0.0 ? - (fHTW2 + side2 + hypot2) / max : - 0.5 ); // brzeg od strony 2 - // ewentualnie poprawić mapowanie, żeby Å›rodek mapowaÅ‚ siÄ™ na 1.435/4.671 ((0.3464,0.6536) - // bo siÄ™ tekstury podsypki rozjeżdżajÄ… po zmianie proporcji profilu - bpts1[0] = vector6(rozp, -fTexHeight1 - 0.18, 0.5 - map12, normal1.x, -normal1.y, 0.0); // lewy brzeg - bpts1[1] = vector6((fHTW + side) * cos1, -(fHTW + side) * sin1 - 0.18, 0.5 - map11, 0.0, 1.0, 0.0); // krawÄ™dź zaÅ‚amania - bpts1[2] = vector6(-bpts1[1].x, +(fHTW + side) * sin1 - 0.18, 0.5 + map11, 0.0, 1.0, 0.0); // prawy brzeg poczÄ…tku symetrycznie - bpts1[3] = vector6(-rozp, -fTexHeight1 - 0.18, 0.5 + map12, -normal1.x, -normal1.y, 0.0); // prawy skos - // przekrój koÅ„cowy - bpts1[4] = vector6(rozp2, -fTexHeight2 - 0.18, 0.5 - map22, normal2.x, -normal2.y, 0.0); // lewy brzeg - bpts1[5] = vector6((fHTW2 + side2) * cos2, -(fHTW2 + side2) * sin2 - 0.18, 0.5 - map21, 0.0, 1.0, 0.0); // krawÄ™dź zaÅ‚amania - bpts1[6] = vector6(-bpts1[5].x, +(fHTW2 + side2) * sin2 - 0.18, 0.5 + map21, 0.0, 1.0, 0.0); // prawy brzeg poczÄ…tku symetrycznie - bpts1[7] = vector6(-rozp2, -fTexHeight2 - 0.18, 0.5 + map22, -normal2.x, -normal2.y, 0.0); // prawy skos - } - else - { - bpts1[0] = vector6(rozp, -fTexHeight1 - 0.18, 0.5 - map12, +normal1.x, -normal1.y, 0.0); // lewy brzeg - bpts1[1] = vector6(fHTW + side, -0.18, 0.5 - map11, +normal1.x, -normal1.y, 0.0); // krawÄ™dź zaÅ‚amania - bpts1[2] = vector6(-fHTW - side, -0.18, 0.5 + map11, -normal1.x, -normal1.y, 0.0); // druga - bpts1[3] = vector6(-rozp, -fTexHeight1 - 0.18, 0.5 + map12, -normal1.x, -normal1.y, 0.0); // prawy skos - } - } - if (!tex) - GfxRenderer.Bind( TextureID2 ); - Segment->RenderLoft( immediate, origin, bpts1, iTrapezoid ? -4 : 4, fTexLength); - } - if (TextureID1) - if (tex ? TextureID1 == tex : true) // jeÅ›li pasuje do grupy (tex) - { // szyny - if (!tex) - GfxRenderer.Bind( TextureID1 ); - Segment->RenderLoft( immediate, origin, rpts1, iTrapezoid ? -nnumPts : nnumPts, fTexLength); - Segment->RenderLoft( immediate, origin, rpts2, iTrapezoid ? -nnumPts : nnumPts, fTexLength); - } - break; - case tt_Switch: // dla zwrotnicy dwa razy szyny - if (TextureID1 || TextureID2) // zwrotnice nie sÄ… grupowane, aby proÅ›ciej byÅ‚o je animować - { // iglice liczone tylko dla zwrotnic - // Ra: TODO: oddzielna animacja każdej iglicy, opór na docisku - vector6 rpts3[24], rpts4[24]; - for (i = 0; i < 12; ++i) - { - rpts3[i] = - vector6(+(fHTW + iglica[i].x) * cos1 + iglica[i].y * sin1, - -(+fHTW + iglica[i].x) * sin1 + iglica[i].y * cos1, iglica[i].z); - rpts3[i + 12] = - vector6(+(fHTW2 + szyna[i].x) * cos2 + szyna[i].y * sin2, - -(+fHTW2 + szyna[i].x) * sin2 + iglica[i].y * cos2, szyna[i].z); - rpts4[11 - i] = - vector6((-fHTW - iglica[i].x) * cos1 + iglica[i].y * sin1, - -(-fHTW - iglica[i].x) * sin1 + iglica[i].y * cos1, iglica[i].z); - rpts4[23 - i] = - vector6((-fHTW2 - szyna[i].x) * cos2 + szyna[i].y * sin2, - -(-fHTW2 - szyna[i].x) * sin2 + iglica[i].y * cos2, szyna[i].z); - } - // McZapkie-130302 - poprawione rysowanie szyn - if (SwitchExtension->RightSwitch) - { // zwrotnica prawa - if( TextureID1 ) { - GfxRenderer.Bind( TextureID1 ); - SwitchExtension->Segments[ 0 ]->RenderLoft( immediate, origin, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, SwitchExtension->fOffset2 ); // prawa iglica - SwitchExtension->Segments[ 0 ]->RenderLoft( immediate, origin, rpts1, nnumPts, fTexLength, 1.0, 2 ); // prawa szyna za iglicÄ… - SwitchExtension->Segments[ 0 ]->RenderLoft( immediate, origin, rpts2, nnumPts, fTexLength ); // lewa szyna normalnie caÅ‚a - } - if( TextureID2 ) { - GfxRenderer.Bind( TextureID2 ); - SwitchExtension->Segments[ 1 ]->RenderLoft( immediate, origin, rpts1, nnumPts, fTexLength ); // prawa szyna normalna caÅ‚a - SwitchExtension->Segments[ 1 ]->RenderLoft( immediate, origin, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -fMaxOffset + SwitchExtension->fOffset1 ); // lewa iglica - SwitchExtension->Segments[ 1 ]->RenderLoft( immediate, origin, rpts2, nnumPts, fTexLength, 1.0, 2 ); // lewa szyna za iglicÄ… - } - } - else - { // lewa kiedyÅ› dziaÅ‚aÅ‚a lepiej niż prawa - if( TextureID1 ) { - GfxRenderer.Bind( TextureID1 ); - SwitchExtension->Segments[ 0 ]->RenderLoft( immediate, origin, rpts1, nnumPts, fTexLength ); // prawa szyna normalna caÅ‚a - SwitchExtension->Segments[ 0 ]->RenderLoft( immediate, origin, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -SwitchExtension->fOffset2 ); // lewa iglica - SwitchExtension->Segments[ 0 ]->RenderLoft( immediate, origin, rpts2, nnumPts, fTexLength, 1.0, 2 ); // lewa szyna za iglicÄ… - } - if( TextureID2 ) { - // nie wiadomo, czy OpenGL to optymalizuje - GfxRenderer.Bind( TextureID2 ); - SwitchExtension->Segments[ 1 ]->RenderLoft( immediate, origin, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, fMaxOffset - SwitchExtension->fOffset1 ); // prawa iglica - SwitchExtension->Segments[ 1 ]->RenderLoft( immediate, origin, rpts1, nnumPts, fTexLength, 1.0, 2 ); // prawa szyna za iglicÄ… - SwitchExtension->Segments[ 1 ]->RenderLoft( immediate, origin, rpts2, nnumPts, fTexLength ); // lewa szyna normalnie caÅ‚a - } - } - } - break; - } - } // koniec obsÅ‚ugi torów - break; - case 2: // McZapkie-260302 - droga - rendering - // McZapkie:240702-zmieniony zakres widzialnosci - switch (eType) // dalej zależnie od typu - { - case tt_Normal: // drogi proste, bo skrzyżowania osobno - { - vector6 bpts1[4]; // punkty głównej pÅ‚aszczyzny przydajÄ… siÄ™ do robienia boków - if (TextureID1 || TextureID2) // punkty siÄ™ przydadzÄ…, nawet jeÅ›li nawierzchni nie ma - { // double max=2.0*(fHTW>fHTW2?fHTW:fHTW2); //z szerszej strony jest 100% - double max = fTexRatio1 * fTexLength; // test: szerokość proporcjonalna do dÅ‚ugoÅ›ci - double map1 = max > 0.0 ? fHTW / max : 0.5; // obciÄ™cie tekstury od strony 1 - double map2 = max > 0.0 ? fHTW2 / max : 0.5; // obciÄ™cie tekstury od strony 2 - if (iTrapezoid) // trapez albo przechyÅ‚ki - { // nawierzchnia trapezowata - Segment->GetRolls(roll1, roll2); - bpts1[0] = vector6(fHTW * cos(roll1), -fHTW * sin(roll1), 0.5 - map1, sin(roll1), cos(roll1), 0.0); // lewy brzeg poczÄ…tku - bpts1[1] = vector6(-bpts1[0].x, -bpts1[0].y, 0.5 + map1, -sin(roll1), cos(roll1), 0.0); // prawy brzeg poczÄ…tku symetrycznie - bpts1[2] = vector6(fHTW2 * cos(roll2), -fHTW2 * sin(roll2), 0.5 - map2, sin(roll2), cos(roll2), 0.0); // lewy brzeg koÅ„ca - bpts1[3] = vector6(-bpts1[2].x, -bpts1[2].y, 0.5 + map2, -sin(roll2), cos(roll2), 0.0); // prawy brzeg poczÄ…tku symetrycznie - } - else - { - bpts1[0] = vector6(fHTW, 0.0, 0.5 - map1, 0.0, 1.0, 0.0); - bpts1[1] = vector6(-fHTW, 0.0, 0.5 + map1, 0.0, 1.0, 0.0); - } - } - if (TextureID1) // jeÅ›li podana byÅ‚a tekstura, generujemy trójkÄ…ty - if (tex ? TextureID1 == tex : true) // jeÅ›li pasuje do grupy (tex) - { // tworzenie trójkÄ…tów nawierzchni szosy - if (!tex) - GfxRenderer.Bind( TextureID1 ); - Segment->RenderLoft( immediate, origin, bpts1, iTrapezoid ? -2 : 2, fTexLength); - } - if (TextureID2) - if (tex ? TextureID2 == tex : true) // jeÅ›li pasuje do grupy (tex) - { // pobocze drogi - poziome przy przechyÅ‚ce (a może krawężnik i chodnik zrobić jak w Midtown Madness 2?) - if (!tex) - GfxRenderer.Bind( TextureID2 ); - vector6 - rpts1[6], - rpts2[6]; // współrzÄ™dne przekroju i mapowania dla prawej i lewej strony - if (fTexHeight1 >= 0.0) - { // standardowo: od zewnÄ…trz pochylenie, a od wewnÄ…trz poziomo - rpts1[0] = vector6(rozp, -fTexHeight1, 0.0); // lewy brzeg podstawy - rpts1[1] = vector6(bpts1[0].x + side, bpts1[0].y, 0.5); // lewa krawÄ™dź zaÅ‚amania - rpts1[2] = vector6(bpts1[0].x, bpts1[0].y, 1.0); // lewy brzeg pobocza (mapowanie może być inne - rpts2[0] = vector6(bpts1[1].x, bpts1[1].y, 1.0); // prawy brzeg pobocza - rpts2[1] = vector6(bpts1[1].x - side, bpts1[1].y, 0.5); // prawa krawÄ™dź zaÅ‚amania - rpts2[2] = vector6(-rozp, -fTexHeight1, 0.0); // prawy brzeg podstawy - if (iTrapezoid) // trapez albo przechyÅ‚ki - { // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony odcinka - rpts1[3] = vector6(rozp2, -fTexHeight2, 0.0); // lewy brzeg lewego pobocza - rpts1[4] = vector6(bpts1[2].x + side2, bpts1[2].y, 0.5); // krawÄ™dź zaÅ‚amania - rpts1[5] = vector6(bpts1[2].x, bpts1[2].y, 1.0); // brzeg pobocza - rpts2[3] = vector6(bpts1[3].x, bpts1[3].y, 1.0); - rpts2[4] = vector6(bpts1[3].x - side2, bpts1[3].y, 0.5); - rpts2[5] = vector6(-rozp2, -fTexHeight2, 0.0); // prawy brzeg prawego pobocza - } - } - else - { // wersja dla chodnika: skos 1:3.75, każdy chodnik innej szerokoÅ›ci - // mapowanie propocjonalne do szerokoÅ›ci chodnika - // krawężnik jest mapowany od 31/64 do 32/64 lewy i od 32/64 do 33/64 prawy - double d = -fTexHeight1 / 3.75; // krawężnik o wysokoÅ›ci 150mm jest pochylony 40mm - double max = fTexRatio2 * fTexLength; // test: szerokość proporcjonalna do dÅ‚ugoÅ›ci - double map1l = ( - max > 0.0 ? - side / max : - 0.484375 ); // obciÄ™cie tekstury od lewej strony punktu 1 - double map1r = ( - max > 0.0 ? - slop / max : - 0.484375 ); // obciÄ™cie tekstury od prawej strony punktu 1 - double h1r = ( - slop > d ? - -fTexHeight1 : - 0 ); - double h1l = ( - side > d ? - -fTexHeight1 : - 0 ); - rpts1[ 0 ] = vector6( bpts1[ 0 ].x + slop, bpts1[ 0 ].y + h1r, 0.515625 + map1r ); // prawy brzeg prawego chodnika - rpts1[ 1 ] = vector6( bpts1[ 0 ].x + d, bpts1[ 0 ].y + h1r, 0.515625 ); // prawy krawężnik u góry - rpts1[ 2 ] = vector6( bpts1[ 0 ].x, bpts1[ 0 ].y, 0.515625 - d / 2.56 ); // prawy krawężnik u doÅ‚u - rpts2[ 0 ] = vector6( bpts1[ 1 ].x, bpts1[ 1 ].y, 0.484375 + d / 2.56 ); // lewy krawężnik u doÅ‚u - rpts2[ 1 ] = vector6( bpts1[ 1 ].x - d, bpts1[ 1 ].y + h1l, 0.484375 ); // lewy krawężnik u góry - rpts2[ 2 ] = vector6( bpts1[ 1 ].x - side, bpts1[ 1 ].y + h1l, 0.484375 - map1l ); // lewy brzeg lewego chodnika - if (iTrapezoid) // trapez albo przechyÅ‚ki - { // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony odcinka - slop2 = ( - fabs( ( iTrapezoid & 2 ) ? - slop2 : - slop ) ); // szerokość chodnika po prawej - double map2l = ( - max > 0.0 ? - side2 / max : - 0.484375 ); // obciÄ™cie tekstury od lewej strony punktu 2 - double map2r = ( - max > 0.0 ? - slop2 / max : - 0.484375 ); // obciÄ™cie tekstury od prawej strony punktu 2 - double h2r = ( slop2 > d ) ? -fTexHeight2 : 0; - double h2l = ( side2 > d ) ? -fTexHeight2 : 0; - rpts1[ 3 ] = vector6( bpts1[ 2 ].x + slop2, bpts1[ 2 ].y + h2r, 0.515625 + map2r ); // prawy brzeg prawego chodnika - rpts1[ 4 ] = vector6( bpts1[ 2 ].x + d, bpts1[ 2 ].y + h2r, 0.515625 ); // prawy krawężnik u góry - rpts1[ 5 ] = vector6( bpts1[ 2 ].x, bpts1[ 2 ].y, 0.515625 - d / 2.56 ); // prawy krawężnik u doÅ‚u - rpts2[ 3 ] = vector6( bpts1[ 3 ].x, bpts1[ 3 ].y, 0.484375 + d / 2.56 ); // lewy krawężnik u doÅ‚u - rpts2[ 4 ] = vector6( bpts1[ 3 ].x - d, bpts1[ 3 ].y + h2l, 0.484375 ); // lewy krawężnik u góry - rpts2[ 5 ] = vector6( bpts1[ 3 ].x - side2, bpts1[ 3 ].y + h2l, 0.484375 - map2l ); // lewy brzeg lewego chodnika - } - } - if (iTrapezoid) // trapez albo przechyÅ‚ki - { // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony - // odcinka - if ((fTexHeight1 >= 0.0) ? true : (slop != 0.0)) - Segment->RenderLoft( immediate, origin, rpts1, -3, fTexLength); // tylko jeÅ›li jest z prawej - if ((fTexHeight1 >= 0.0) ? true : (side != 0.0)) - Segment->RenderLoft( immediate, origin, rpts2, -3, fTexLength); // tylko jeÅ›li jest z lewej - } - else - { // pobocza zwykÅ‚e, brak przechyÅ‚ki - if ((fTexHeight1 >= 0.0) ? true : (slop != 0.0)) - Segment->RenderLoft( immediate, origin, rpts1, 3, fTexLength); - if ((fTexHeight1 >= 0.0) ? true : (side != 0.0)) - Segment->RenderLoft( immediate, origin, rpts2, 3, fTexLength); - } - } - break; - } - case tt_Cross: // skrzyżowanie dróg rysujemy inaczej - { // ustalenie współrzÄ™dnych Å›rodka - przeciÄ™cie Point1-Point2 z CV4-Point4 - double a[4]; // kÄ…ty osi ulic wchodzÄ…cych - vector3 p[4]; // punkty siÄ™ przydadzÄ… do obliczeÅ„ - // na razie poÅ‚owa odlegÅ‚oÅ›ci pomiÄ™dzy Point1 i Point2, potem siÄ™ dopracuje - a[0] = a[1] = 0.5; // parametr do poszukiwania przeciÄ™cia Å‚uków - // modyfikować a[0] i a[1] tak, aby trafić na przeciÄ™cie odcinka 34 - p[0] = SwitchExtension->Segments[0]->FastGetPoint(a[0]); // współrzÄ™dne Å›rodka pierwszego odcinka - p[1] = SwitchExtension->Segments[1]->FastGetPoint(a[1]); //-//- drugiego - // p[2]=p[1]-p[0]; //jeÅ›li różne od zera, przeliczyć a[0] i a[1] i wyznaczyć nowe punkty - vector3 oxz = p[0]; // punkt mapowania Å›rodka tekstury skrzyżowania - p[0] = SwitchExtension->Segments[0]->GetDirection1(); // Point1 - pobranie wektorów kontrolnych - p[1] = SwitchExtension->Segments[1]->GetDirection2(); // Point3 (bo zamienione) - p[2] = SwitchExtension->Segments[0]->GetDirection2(); // Point2 - p[3] = SwitchExtension->Segments[1]->GetDirection1(); // Point4 (bo zamienione) - a[0] = atan2(-p[0].x, p[0].z); // kÄ…ty stycznych osi dróg - a[1] = atan2(-p[1].x, p[1].z); - a[2] = atan2(-p[2].x, p[2].z); - a[3] = atan2(-p[3].x, p[3].z); - p[0] = SwitchExtension->Segments[0]->FastGetPoint_0(); // Point1 - pobranie współrzÄ™dnych koÅ„ców - p[1] = SwitchExtension->Segments[1]->FastGetPoint_1(); // Point3 - p[2] = SwitchExtension->Segments[0]->FastGetPoint_1(); // Point2 - p[3] = SwitchExtension->Segments[1]->FastGetPoint_0(); // Point4 - przy trzech drogach pokrywa siÄ™ z Point1 - // 2014-07: na poczÄ…tek rysować brzegi jak dla Å‚uków - // punkty brzegu nawierzchni uzyskujemy podczas renderowania boków (bez sensu, ale najszybciej byÅ‚o zrobić) - int i; // ile punktów (może byc różna ilość punktów miÄ™dzy drogami) - if (!SwitchExtension->vPoints) - { // jeÅ›li tablica punktów nie jest jeszcze utworzona, zliczamy punkty i tworzymy jÄ… - if( SwitchExtension->iRoads == 3 ) { - // mogÄ… być tylko 3 drogi zamiast 4 - SwitchExtension->iPoints = - SwitchExtension->Segments[ 0 ]->RaSegCount() - + SwitchExtension->Segments[ 1 ]->RaSegCount() - + SwitchExtension->Segments[ 2 ]->RaSegCount(); - } - else { - SwitchExtension->iPoints = - SwitchExtension->Segments[ 2 ]->RaSegCount() - + SwitchExtension->Segments[ 3 ]->RaSegCount() - + SwitchExtension->Segments[ 4 ]->RaSegCount() - + SwitchExtension->Segments[ 5 ]->RaSegCount(); - } - // tablica utworzona z zapasem, ale nie wypeÅ‚niona współrzÄ™dnymi - SwitchExtension->vPoints = new vector3[ SwitchExtension->iPoints + SwitchExtension->iRoads ]; - } - vector3 *b = - SwitchExtension->bPoints ? - nullptr : - SwitchExtension->vPoints; // zmienna robocza, NULL gdy tablica punktów już jest wypeÅ‚niona - vector6 bpts1[4]; // punkty głównej pÅ‚aszczyzny przydajÄ… siÄ™ do robienia boków - if (TextureID1 || TextureID2) // punkty siÄ™ przydadzÄ…, nawet jeÅ›li nawierzchni nie ma - { // double max=2.0*(fHTW>fHTW2?fHTW:fHTW2); //z szerszej strony jest 100% - double max = fTexRatio1 * fTexLength; // test: szerokość proporcjonalna do dÅ‚ugoÅ›ci - double map1 = max > 0.0 ? fHTW / max : 0.5; // obciÄ™cie tekstury od strony 1 - double map2 = max > 0.0 ? fHTW2 / max : 0.5; // obciÄ™cie tekstury od strony 2 - // if (iTrapezoid) //trapez albo przechyÅ‚ki - { // nawierzchnia trapezowata - Segment->GetRolls(roll1, roll2); - bpts1[0] = vector6(fHTW * cos(roll1), -fHTW * sin(roll1), 0.5 - map1, sin(roll1), cos(roll1), 0.0); // lewy brzeg poczÄ…tku - bpts1[1] = vector6(-bpts1[0].x, -bpts1[0].y, 0.5 + map1, -sin(roll1), cos(roll1), 0.0); // prawy brzeg poczÄ…tku symetrycznie - bpts1[2] = vector6(fHTW2 * cos(roll2), -fHTW2 * sin(roll2), 0.5 - map2, sin(roll2), cos(roll2), 0.0); // lewy brzeg koÅ„ca - bpts1[3] = vector6(-bpts1[2].x, -bpts1[2].y, 0.5 + map2, -sin(roll2), cos(roll2), 0.0); // prawy brzeg poczÄ…tku symetrycznie - } - } - // najpierw renderowanie poboczy i zapamiÄ™tywanie punktów - // problem ze skrzyżowaniami jest taki, że teren chce siÄ™ pogrupować wg tekstur, ale zaczyna od nawierzchni - // sama nawierzchnia nie wypeÅ‚ni tablicy punktów, bo potrzebne sÄ… pobocza - // ale pobocza renderujÄ… siÄ™ później, wiÄ™c nawierzchnia nie zaÅ‚apuje siÄ™ na renderowanie w swoim czasie - { // pobocze drogi - poziome przy przechyÅ‚ce (a może krawężnik i chodnik zrobić jak w Midtown Madness 2?) - if (TextureID2) - if (!tex) - GfxRenderer.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 sÄ…siednich dróg - if (fTexHeight1 >= 0.0) - { // standardowo: od zewnÄ…trz pochylenie, a od wewnÄ…trz poziomo - rpts1[0] = vector6(rozp, -fTexHeight1, 0.0); // lewy brzeg podstawy - rpts1[1] = vector6(bpts1[0].x + side, bpts1[0].y, 0.5); // lewa krawÄ™dź zaÅ‚amania - rpts1[2] = vector6(bpts1[0].x, bpts1[0].y, 1.0); // lewy brzeg pobocza (mapowanie może być inne - rpts2[0] = vector6(bpts1[1].x, bpts1[1].y, 1.0); // prawy brzeg pobocza - rpts2[1] = vector6(bpts1[1].x - side, bpts1[1].y, 0.5); // prawa krawÄ™dź zaÅ‚amania - rpts2[2] = vector6(-rozp, -fTexHeight1, 0.0); // prawy brzeg podstawy - // if (iTrapezoid) //trapez albo przechyÅ‚ki - { // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony odcinka - rpts1[3] = vector6(rozp2, -fTexHeight2, 0.0); // lewy brzeg lewego pobocza - rpts1[4] = vector6(bpts1[2].x + side2, bpts1[2].y, 0.5); // krawÄ™dź zaÅ‚amania - rpts1[5] = vector6(bpts1[2].x, bpts1[2].y, 1.0); // brzeg pobocza - rpts2[3] = vector6(bpts1[3].x, bpts1[3].y, 1.0); - rpts2[4] = vector6(bpts1[3].x - side2, bpts1[3].y, 0.5); - rpts2[5] = vector6(-rozp2, -fTexHeight2, 0.0); // prawy brzeg prawego pobocza - } - } - else - { // wersja dla chodnika: skos 1:3.75, każdy chodnik innej szerokoÅ›ci - // mapowanie propocjonalne do szerokoÅ›ci chodnika - // krawężnik jest mapowany od 31/64 do 32/64 lewy i od 32/64 do 33/64 prawy - double d = -fTexHeight1 / 3.75; // krawężnik o wysokoÅ›ci 150mm jest pochylony 40mm - double max = fTexRatio2 * fTexLength; // test: szerokość proporcjonalna do dÅ‚ugoÅ›ci - double map1l = max > 0.0 ? - side / max : - 0.484375; // obciÄ™cie tekstury od lewej strony punktu 1 - double map1r = max > 0.0 ? - slop / max : - 0.484375; // obciÄ™cie tekstury od prawej strony punktu 1 - rpts1[0] = vector6(bpts1[0].x + slop, bpts1[0].y - fTexHeight1, 0.515625 + map1r); // prawy brzeg prawego chodnika - rpts1[1] = vector6(bpts1[0].x + d, bpts1[0].y - fTexHeight1, 0.515625); // prawy krawężnik u góry - rpts1[2] = vector6(bpts1[0].x, bpts1[0].y, 0.515625 - d / 2.56); // prawy krawężnik u doÅ‚u - rpts2[0] = vector6(bpts1[1].x, bpts1[1].y, 0.484375 + d / 2.56); // lewy krawężnik u doÅ‚u - rpts2[1] = vector6(bpts1[1].x - d, bpts1[1].y - fTexHeight1, 0.484375); // lewy krawężnik u góry - rpts2[2] = vector6(bpts1[1].x - side, bpts1[1].y - fTexHeight1, 0.484375 - map1l); // lewy brzeg lewego chodnika - // if (iTrapezoid) //trapez albo przechyÅ‚ki - { // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony odcinka - slop2 = fabs((iTrapezoid & 2) ? slop2 : slop); // szerokość chodnika po prawej - double map2l = max > 0.0 ? - side2 / max : - 0.484375; // obciÄ™cie tekstury od lewej strony punktu 2 - double map2r = max > 0.0 ? - slop2 / max : - 0.484375; // obciÄ™cie tekstury od prawej strony punktu 2 - rpts1[3] = vector6(bpts1[2].x + slop2, bpts1[2].y - fTexHeight2, 0.515625 + map2r); // prawy brzeg prawego chodnika - rpts1[4] = vector6(bpts1[2].x + d, bpts1[2].y - fTexHeight2, 0.515625); // prawy krawężnik u góry - rpts1[5] = vector6(bpts1[2].x, bpts1[2].y, 0.515625 - d / 2.56); // prawy krawężnik u doÅ‚u - rpts2[3] = vector6(bpts1[3].x, bpts1[3].y, 0.484375 + d / 2.56); // lewy krawężnik u doÅ‚u - rpts2[4] = vector6(bpts1[3].x - d, bpts1[3].y - fTexHeight2, 0.484375); // lewy krawężnik u góry - rpts2[5] = vector6(bpts1[3].x - side2, bpts1[3].y - fTexHeight2, 0.484375 - map2l); // lewy brzeg lewego chodnika - } - } - bool render = ( - TextureID2 ? ( - tex ? - TextureID2 == tex : - true ) : - false ); // renderować nie trzeba, ale trzeba wyznaczyć punkty brzegowe nawierzchni - // if (iTrapezoid) //trapez albo przechyÅ‚ki - if (SwitchExtension->iRoads == 4) - { // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony odcinka - if( ( fTexHeight1 >= 0.0 ) || ( side != 0.0 ) ) { - SwitchExtension->Segments[ 2 ]->RenderLoft( immediate, origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render ); - SwitchExtension->Segments[ 3 ]->RenderLoft( immediate, origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render ); - SwitchExtension->Segments[ 4 ]->RenderLoft( immediate, origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render ); - SwitchExtension->Segments[ 5 ]->RenderLoft( immediate, origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render ); - } - } - else - // to bÄ™dzie ewentualnie dla prostego na skrzyżowaniu trzech dróg - { // punkt 3 pokrywa siÄ™ z punktem 1, jak w zwrotnicy; połączenie 1->2 nie musi być prostoliniowe - if( ( fTexHeight1 >= 0.0 ) || ( side != 0.0 ) ) { - SwitchExtension->Segments[ 2 ]->RenderLoft( immediate, origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render ); // z P2 do P4 - SwitchExtension->Segments[ 1 ]->RenderLoft( immediate, origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render ); // z P4 do P3=P1 (odwrócony) - SwitchExtension->Segments[ 0 ]->RenderLoft( immediate, origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render ); // z P1 do P2 - } - } - } - // renderowanie nawierzchni na koÅ„cu - double sina0 = sin(a[0]), cosa0 = cos(a[0]); - double u, v; - if( ( false == SwitchExtension->bPoints ) // jeÅ›li tablica nie wypeÅ‚niona - && ( b != nullptr ) ) { - SwitchExtension->bPoints = true; // tablica punktów zostaÅ‚a wypeÅ‚niona - } - - if (TextureID1) // jeÅ›li podana tekstura nawierzchni - if ( (tex == TextureID1) || (tex == 0) ) // jeÅ›li pasuje do grupy (tex) - { - if (!tex) - GfxRenderer.Bind( TextureID1 ); - glBegin(GL_TRIANGLE_FAN); // takie kółeczko bÄ™dzie - // we start with a vertex in the middle... - glNormal3f(0, 1, 0); - glTexCoord2f(0.5, 0.5); //Å›rodek tekstury na Å›rodku skrzyżowania - glVertex3f( - oxz.x - origin.x, - oxz.y - origin.y, - oxz.z - origin.z ); - // ...and add one extra vertex to close the fan... - glNormal3f( 0, 1, 0 ); - // mapowanie we współrzÄ™dnych scenerii - u = ( SwitchExtension->vPoints[ 0 ].x - oxz.x + origin.x ) / fTexLength; - v = ( SwitchExtension->vPoints[ 0 ].z - oxz.z + origin.z ) / ( fTexRatio1 * fTexLength ); - glTexCoord2f( - cosa0 * u + sina0 * v + 0.5, - -sina0 * u + cosa0 * v + 0.5 ); - glVertex3f( - SwitchExtension->vPoints[ 0 ].x, - SwitchExtension->vPoints[ 0 ].y, - SwitchExtension->vPoints[ 0 ].z ); - - for ( i = SwitchExtension->iPoints + SwitchExtension->iRoads - 1; i >= 0; --i ) - { - glNormal3f(0, 1, 0); - // mapowanie we współrzÄ™dnych scenerii - u = (SwitchExtension->vPoints[i].x - oxz.x + origin.x) / fTexLength; - v = (SwitchExtension->vPoints[i].z - oxz.z + origin.z) / (fTexRatio1 * fTexLength); - glTexCoord2f( - cosa0 * u + sina0 * v + 0.5, - -sina0 * u + cosa0 * v + 0.5); - glVertex3f( - SwitchExtension->vPoints[i].x, - SwitchExtension->vPoints[i].y, - SwitchExtension->vPoints[i].z); - } - glEnd(); - } - break; - } - } - break; - case 4: // McZapkie-260302 - rzeka- rendering - // Ra: rzeki na razie bez zmian, przechyÅ‚ki na pewno nie majÄ… - // Ra: przemyÅ›leć wyrównanie u góry trawÄ… do czworoboku - vector6 bpts1[numPts] = {vector6(fHTW, 0.0, 0.0), vector6(fHTW, 0.2, 0.33), - vector6(-fHTW, 0.0, 0.67), vector6(-fHTW, 0.0, 1.0)}; - // Ra: dziwnie ten ksztaÅ‚t wyglÄ…da - if (TextureID1) - if (tex ? TextureID1 == tex : true) // jeÅ›li pasuje do grupy (tex) - { - if (!tex) - GfxRenderer.Bind( TextureID1 ); - Segment->RenderLoft( immediate, origin, bpts1, numPts, fTexLength); - } - if (TextureID2) - if (tex ? TextureID2 == tex : true) // jeÅ›li pasuje do grupy (tex) - { // brzegi rzeki prawie jak pobocze derogi, tylko inny znak ma wysokość - // znak jest zmieniany przy wczytywaniu, wiÄ™c tu musi byc minus fTexHeight - vector6 rpts1[3] = {vector6(rozp, -fTexHeight1, 0.0), - vector6(fHTW + side, 0.0, 0.5), vector6(fHTW, 0.0, 1.0)}; - 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) - GfxRenderer.Bind( TextureID2 ); // brzeg rzeki - Segment->RenderLoft( immediate, origin, rpts1, 3, fTexLength ); - Segment->RenderLoft( immediate, origin, rpts2, 3, fTexLength ); - } - break; - } - if (!tex) - if (Global::bManageNodes) - glEndList(); -}; -*/ -void TTrack::Release() -{ -/* - if (DisplayListID) - glDeleteLists(DisplayListID, 1); - DisplayListID = 0; -*/ -}; -/* -void TTrack::Render() -{ - if (bVisible) // Ra: tory sÄ… renderowane sektorami i nie ma sensu każdorazowo liczyć odlegÅ‚oÅ›ci - { - if (!DisplayListID) - { - Compile(); - if (Global::bManageNodes) - ResourceManager::Register(this); - }; - SetLastUsage(Timer::GetSimulationTime()); - EnvironmentSet(); // oÅ›wietlenie nie może być skompilowane, bo może siÄ™ zmieniać z czasem - glCallList(DisplayListID); - EnvironmentReset(); // ustawienie oÅ›wietlenia na zwykÅ‚e - if (InMovement()) - Release(); // zwrotnica w trakcie animacji do odrysowania - } -}; -*/ bool TTrack::CheckDynamicObject(TDynamicObject *Dynamic) { // sprawdzenie, czy pojazd jest przypisany do toru for( auto dynamic : Dynamics ) { @@ -3064,25 +2413,6 @@ TTrack * TTrack::RaAnimate() // minimalny ruch, aby przeliczyć pozycjÄ™ dynamic->Move( 0.000001 ); } - // kÄ…ty -/* - if (Global::bUseVBO) - { // dla OpenGL 1.4 odÅ›wieży siÄ™ caÅ‚y sektor, w późniejszych poprawiamy fragment - // aktualizacja pojazdów na torze - if (GLEW_VERSION_1_5) // dla OpenGL 1.4 to siÄ™ nie wykona poprawnie - { - int size = RaArrayPrepare(); // wielkość tabeli potrzebna dla tej obrotnicy - basic_vertex *Vert = new basic_vertex[size]; // bufor roboczy - // basic_vertex *v=Vert; //zmieniane przez - RaArrayFill(Vert, Vert - SwitchExtension->iLeftVBO, size); // iLeftVBO powinno zostać niezmienione - ::glBufferSubData( - GL_ARRAY_BUFFER, SwitchExtension->iLeftVBO * sizeof(basic_vertex), - size * sizeof(basic_vertex), Vert); // wysÅ‚anie fragmentu bufora VBO - } - } - else // gdy Display List - Release(); // niszczenie skompilowanej listy, aby siÄ™ wygenerowaÅ‚a nowa -*/ // NOTE: passing empty handle is a bit of a hack here. could be refactored into something more elegant create_geometry( geometrybank_handle() ); } // animacja trwa nadal diff --git a/Track.h b/Track.h index 8ded71b5..f7bf31e6 100644 --- a/Track.h +++ b/Track.h @@ -118,7 +118,7 @@ class TIsolated }; // trajektoria ruchu - opakowanie -class TTrack : public Resource { +class TTrack /*: public Resource*/ { friend class opengl_renderer; @@ -225,9 +225,9 @@ public: bool CheckDynamicObject(TDynamicObject *Dynamic); bool AddDynamicObject(TDynamicObject *Dynamic); bool RemoveDynamicObject(TDynamicObject *Dynamic); - - void Release(); /* + void Release(); + void Compile(GLuint tex = 0); void Render(); // renderowanie z Display Lists int RaArrayPrepare(); // zliczanie rozmiaru dla VBO sektroa diff --git a/openglgeometrybank.h b/openglgeometrybank.h index 6974a47f..4a41a51e 100644 --- a/openglgeometrybank.h +++ b/openglgeometrybank.h @@ -60,7 +60,8 @@ struct geometry_handle { /* return bank << 14 | chunk; } */ - return bank << 32 | chunk; } + return ( std::uint64_t { bank } << 32 | chunk ); + } // members /* diff --git a/version.h b/version.h index b41d9f32..b34c61ee 100644 --- a/version.h +++ b/version.h @@ -1,5 +1,5 @@ #pragma once #define VERSION_MAJOR 17 -#define VERSION_MINOR 603 +#define VERSION_MINOR 613 #define VERSION_REVISION 0 From 0d805e8ba2a57c9cc634d646deed5b06d84acf77 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Wed, 14 Jun 2017 21:02:38 +0200 Subject: [PATCH 8/9] support for vertex data streams selection, t3d model loading fixes --- Model3d.cpp | 379 +++++++++++++++++++++-------------------- Model3d.h | 19 ++- Texture.cpp | 11 +- Track.cpp | 201 +--------------------- openglgeometrybank.cpp | 90 +++++++--- openglgeometrybank.h | 41 +++-- renderer.cpp | 25 +-- 7 files changed, 307 insertions(+), 459 deletions(-) diff --git a/Model3d.cpp b/Model3d.cpp index 40db9adf..ab655643 100644 --- a/Model3d.cpp +++ b/Model3d.cpp @@ -51,10 +51,14 @@ TSubModel::TSubModel() void TSubModel::FirstInit() { eType = TP_ROTATOR; +/* Vertices = NULL; uiDisplayList = 0; +*/ iNumVerts = -1; // do sprawdzenia +/* iVboPtr = -1; +*/ fLight = -1.0; //Å›wietcenie wyłączone v_RotateAxis = float3(0, 0, 0); v_TransVector = float3(0, 0, 0); @@ -103,15 +107,19 @@ void TSubModel::FirstInit() TSubModel::~TSubModel() { +/* if (uiDisplayList) glDeleteLists(uiDisplayList, 1); +*/ if (iFlags & 0x0200) { // wczytany z pliku tekstowego musi sam posprzÄ…tać // SafeDeleteArray(Indices); SafeDelete(Next); SafeDelete(Child); delete fMatrix; // wÅ‚asny transform trzeba usunąć (zawsze jeden) +/* delete[] Vertices; +*/ } delete[] smLetter; // używany tylko roboczo dla TP_TEXT, do przyspieszenia // wyÅ›wietlania @@ -136,25 +144,20 @@ void TSubModel::NameSet(std::string const &Name) // int TSubModel::SeekFaceNormal(DWORD *Masks, int f,DWORD dwMask,vector3 // *pt,GLVERTEX // *Vertices) -int TSubModel::SeekFaceNormal(unsigned int *Masks, int f, unsigned int dwMask, glm::vec3 *pt, - basic_vertex *Vertices) -{ // szukanie punktu stycznego - // do (pt), zwraca numer - // wierzchoÅ‚ka, a nie trójkÄ…ta - int iNumFaces = iNumVerts / 3; // bo maska powierzchni jest jedna na trójkÄ…t - // GLVERTEX *p; //roboczy wskaźnik - basic_vertex *p; // roboczy wskaźnik - for (int i = f; i < iNumFaces; ++i) // pÄ™tla po trójkÄ…tach, od trójkÄ…ta (f) - if (Masks[i] & dwMask) // jeÅ›li wspólna maska powierzchni - { - p = Vertices + 3 * i; - if (p->position == *pt) - return 3 * i; - if ((++p)->position == *pt) - return 3 * i + 1; - if ((++p)->position == *pt) - return 3 * i + 2; - } +int TSubModel::SeekFaceNormal(std::vector const &Masks, int const Startface, unsigned int const Mask, glm::vec3 const &Position, vertex_array const &Vertices) +{ // szukanie punktu stycznego do (pt), zwraca numer wierzchoÅ‚ka, a nie trójkÄ…ta + int facecount = iNumVerts / 3; // bo maska powierzchni jest jedna na trójkÄ…t + for( int faceidx = Startface; faceidx < facecount; ++faceidx ) { + // pÄ™tla po trójkÄ…tach, od trójkÄ…ta (f) + if( Masks[ faceidx ] & Mask ) { + // jeÅ›li wspólna maska powierzchni + for( int vertexidx = 0; vertexidx < 2; ++vertexidx ) { + if( Vertices[ 3 * faceidx + vertexidx ].position == Position ) { + return 3 * faceidx + vertexidx; + } + } + } + } return -1; // nie znaleziono stycznego wierzchoÅ‚ka } @@ -197,10 +200,12 @@ inline void readMatrix(cParser &parser, float4x4 &matrix) parser >> matrix(x)[y]; }; -int TSubModel::Load(cParser &parser, TModel3d *Model, int Pos, bool dynamic) +int TSubModel::Load( cParser &parser, TModel3d *Model, /*int Pos,*/ bool dynamic) { // Ra: VBO tworzone na poziomie modelu, a nie submodeli iNumVerts = 0; +/* iVboPtr = Pos; // pozycja w VBO +*/ if (!parser.expectToken("type:")) Error("Model type parse failure!"); { @@ -329,13 +334,18 @@ int TSubModel::Load(cParser &parser, TModel3d *Model, int Pos, bool dynamic) { std::string discard; parser.getTokens(5, false); - parser >> discard >> bWire >> discard >> fWireSize >> discard; - Opacity = readIntAsDouble(parser, - 100.0f); // wymagane jest 0 dla szyb, 100 idzie w nieprzezroczyste + parser + >> discard >> bWire + >> discard >> fWireSize + >> discard; + // wymagane jest 0 dla szyb, 100 idzie w nieprzezroczyste + Opacity = readIntAsDouble(parser, 100.0f); if (Opacity > 1.0f) Opacity *= 0.01f; // w 2013 byÅ‚ błąd i aby go obejść, trzeba byÅ‚o wpisać 10000.0 +/* if ((Global::iConvertModels & 1) == 0) // dla zgodnoÅ›ci wstecz Opacity = 0.0; // wszystko idzie w przezroczyste albo zależnie od tekstury +*/ if (!parser.expectToken("map:")) Error("Model map parse failure!"); std::string texture = parser.getToken(); @@ -371,20 +381,19 @@ int TSubModel::Load(cParser &parser, TModel3d *Model, int Pos, bool dynamic) } else { // jeÅ›li tylko nazwa pliku, to dawać bieżącÄ… Å›cieżkÄ™ do tekstur - // asTexture=AnsiString(texture.c_str()); //zapamiÄ™tanie nazwy tekstury TextureNameSet(texture.c_str()); - if (texture.find_first_of("/\\") == texture.npos) - texture.insert(0, Global::asCurrentTexturePath.c_str()); + if( texture.find_first_of( "/\\" ) == texture.npos ) { + texture.insert( 0, Global::asCurrentTexturePath.c_str() ); + } TextureID = GfxRenderer.GetTextureId( texture, szTexturePath ); - // TexAlpha=TTexturesManager::GetAlpha(TextureID); - // iFlags|=TexAlpha?0x20:0x10; //0x10-nieprzezroczysta, 0x20-przezroczysta - iFlags |= - ( GfxRenderer.Texture(TextureID).has_alpha ? - 0x20 : - 0x10 ); // 0x10-nieprzezroczysta, 0x20-przezroczysta // renderowanie w cyklu przezroczystych tylko jeÅ›li: // 1. Opacity=0 (przejÅ›ciowo <1, czy tam <100) oraz // 2. tekstura ma przezroczystość + iFlags |= + ( ( ( Opacity < 1.0 ) + && ( GfxRenderer.Texture(TextureID).has_alpha ) ) ? + 0x20 : + 0x10 ); // 0x10-nieprzezroczysta, 0x20-przezroczysta }; } else @@ -407,8 +416,6 @@ int TSubModel::Load(cParser &parser, TModel3d *Model, int Pos, bool dynamic) readMatrix(parser, *fMatrix); // wczytanie transform if (!fMatrix->IdentityIs()) iFlags |= 0x8000; // transform niejedynkowy - trzeba go przechować - int iNumFaces; // ilość trójkÄ…tów - unsigned int *sg; // maski przynależnoÅ›ci trójkÄ…tów do powierzchni if (eType < TP_ROTATOR) { // wczytywanie wierzchoÅ‚ków parser.getTokens(2, false); @@ -423,11 +430,11 @@ int TSubModel::Load(cParser &parser, TModel3d *Model, int Pos, bool dynamic) { // jeÅ›li pierwszy znak jest gwiazdkÄ…, poszukać // submodelu o nazwie bez tej gwiazdki i wziąć z // niego wierzchoÅ‚ki - Error("Verticles reference not yet supported!"); + Error("Vertices reference not yet supported!"); } else { // normalna lista wierzchoÅ‚ków - iNumVerts = atoi(token.c_str()); + iNumVerts = std::atoi(token.c_str()); if (iNumVerts % 3) { iNumVerts = 0; @@ -435,27 +442,31 @@ int TSubModel::Load(cParser &parser, TModel3d *Model, int Pos, bool dynamic) return 0; } // Vertices=new GLVERTEX[iNumVerts]; - if (iNumVerts) - { + if (iNumVerts) { +/* Vertices = new basic_vertex[iNumVerts]; - iNumFaces = iNumVerts / 3; - sg = new unsigned int[iNumFaces]; // maski powierzchni: 0 oznacza brak - // użredniania wektorów normalnych - int *wsp = new int[iNumVerts]; // z którego wierzchoÅ‚ka kopiować wektor - // normalny +*/ + Vertices.resize( iNumVerts ); + int facecount = iNumVerts / 3; +/* + unsigned int *sg; // maski przynależnoÅ›ci trójkÄ…tów do powierzchni + sg = new unsigned int[iNumFaces]; // maski powierzchni: 0 oznacza brak użredniania wektorów normalnych + int *wsp = new int[iNumVerts]; // z którego wierzchoÅ‚ka kopiować wektor normalny +*/ + std::vector sg; sg.resize( facecount ); // maski przynależnoÅ›ci trójkÄ…tów do powierzchni + std::vector wsp; wsp.resize( iNumVerts );// z którego wierzchoÅ‚ka kopiować wektor normalny int maska = 0; - for (int i = 0; i < iNumVerts; i++) - { // Ra: z konwersjÄ… na ukÅ‚ad scenerii - bÄ™dzie wydajniejsze - // wyÅ›wietlanie + for (int i = 0; i < iNumVerts; ++i) { + // Ra: z konwersjÄ… na ukÅ‚ad scenerii - bÄ™dzie wydajniejsze wyÅ›wietlanie wsp[i] = -1; // wektory normalne nie sÄ… policzone dla tego wierzchoÅ‚ka - if ((i % 3) == 0) - { // jeÅ›li bÄ™dzie maska -1, to dalej bÄ™dÄ… - // wierzchoÅ‚ki z wektorami normalnymi, podanymi - // jawnie + if ((i % 3) == 0) { + // jeÅ›li bÄ™dzie maska -1, to dalej bÄ™dÄ… wierzchoÅ‚ki z wektorami normalnymi, podanymi jawnie maska = parser.getToken(false); // maska powierzchni trójkÄ…ta - sg[i / 3] = (maska == -1) ? 0 : maska; // dla maski -1 bÄ™dzie 0, - // czyli nie ma wspólnych - // wektorów normalnych + // dla maski -1 bÄ™dzie 0, czyli nie ma wspólnych wektorów normalnych + sg[i / 3] = ( + ( maska == -1 ) ? + 0 : + maska ); } parser.getTokens(3, false); parser @@ -475,80 +486,77 @@ int TSubModel::Load(cParser &parser, TModel3d *Model, int Pos, bool dynamic) parser >> Vertices[i].texture.s >> Vertices[i].texture.t; - if (i % 3 == 2) // jeżeli wczytano 3 punkty - { - if (Vertices[i].position == Vertices[i - 1].position + if (i % 3 == 2) { + // jeżeli wczytano 3 punkty + if (Vertices[i ].position == Vertices[i - 1].position || Vertices[i - 1].position == Vertices[i - 2].position - || Vertices[i - 2].position == Vertices[i].position) + || Vertices[i - 2].position == Vertices[i ].position) { // jeżeli punkty siÄ™ nakÅ‚adajÄ… na siebie - --iNumFaces; // o jeden trójkÄ…t mniej + --facecount; // o jeden trójkÄ…t mniej iNumVerts -= 3; // czyli o 3 wierzchoÅ‚ki i -= 3; // wczytanie kolejnego w to miejsce - WriteLog(std::string("Degenerated triangle ignored in: \"") + pName + - "\", verticle " + std::to_string(i)); + WriteLog("Degenerated triangle ignored in: \"" + pName + "\", verticle " + std::to_string(i)); } - if (i > 0) // jeÅ›li pierwszy trójkÄ…t bÄ™dzie zdegenerowany, to - // zostanie usuniÄ™ty i nie ma co sprawdzać - if ((glm::length(Vertices[i].position - Vertices[i - 1].position) > 1000.0) - || (glm::length(Vertices[i - 1].position - Vertices[i - 2].position) > 1000.0) - || (glm::length(Vertices[i - 2].position - Vertices[i].position) > 1000.0)) - { // jeżeli sÄ… dalej niż 2km od siebie //Ra 15-01: - // obiekt wstawiany nie powinien być wiÄ™kszy niż - // 300m (trójkÄ…ty terenu w E3D mogÄ… mieć 1.5km) - --iNumFaces; // o jeden trójkÄ…t mniej + if (i > 0) { + // jeÅ›li pierwszy trójkÄ…t bÄ™dzie zdegenerowany, to zostanie usuniÄ™ty i nie ma co sprawdzać + if ((glm::length(Vertices[i ].position - Vertices[i - 1].position) > 1000.0) + || (glm::length(Vertices[i - 1].position - Vertices[i - 2].position) > 1000.0) + || (glm::length(Vertices[i - 2].position - Vertices[i ].position) > 1000.0)) { + // jeżeli sÄ… dalej niż 2km od siebie //Ra 15-01: + // obiekt wstawiany nie powinien być wiÄ™kszy niż 300m (trójkÄ…ty terenu w E3D mogÄ… mieć 1.5km) + --facecount; // o jeden trójkÄ…t mniej iNumVerts -= 3; // czyli o 3 wierzchoÅ‚ki i -= 3; // wczytanie kolejnego w to miejsce - WriteLog(std::string("Too large triangle ignored in: \"") + pName + - "\""); + WriteLog( "Too large triangle ignored in: \"" + pName + "\"" ); } + } } } - int i; // indeks dla trójkÄ…tów +/* glm::vec3 *n = new glm::vec3[iNumFaces]; // tablica wektorów normalnych dla trójkÄ…tów - for (i = 0; i < iNumFaces; ++i) // pÄ™tla po trójkÄ…tach - bÄ™dzie - // szybciej, jak wstÄ™pnie przeliczymy - // normalne trójkÄ…tów - n[i] = glm::normalize( - glm::cross( - Vertices[i * 3].position - Vertices[i * 3 + 1].position, - Vertices[i * 3].position - Vertices[i * 3 + 2].position)); - int v; // indeks dla wierzchoÅ‚ków - int f; // numer trójkÄ…ta stycznego - glm::vec3 norm; // roboczy wektor normalny - for (v = 0; v < iNumVerts; ++v) - { // pÄ™tla po wierzchoÅ‚kach trójkÄ…tów - if (wsp[v] >= 0) // jeÅ›li już byÅ‚ liczony wektor normalny z użyciem - // tego wierzchoÅ‚ka - Vertices[v].normal = - Vertices[wsp[v]].normal; // to wystarczy skopiować policzony wczeÅ›niej - else - { // inaczej musimy dopiero policzyć - i = v / 3; // numer trójkÄ…ta - norm = glm::vec3(); // liczenie zaczynamy od zera - f = v; // zaczynamy dodawanie wektorów normalnych od wÅ‚asnego - while (f >= 0) - { // sumowanie z wektorem normalnym sÄ…siada (włącznie - // ze sobÄ…) - wsp[f] = v; // informacja, że w tym wierzchoÅ‚ku jest już policzony - // wektor normalny - norm += n[f / 3]; - f = SeekFaceNormal(sg, f / 3 + 1, sg[i], &Vertices[v].position, - Vertices); // i szukanie od kolejnego trójkÄ…ta +*/ + std::vector facenormals; + for( int i = 0; i < facecount; ++i ) { + // pÄ™tla po trójkÄ…tach - bÄ™dzie szybciej, jak wstÄ™pnie przeliczymy normalne trójkÄ…tów + facenormals.emplace_back( + glm::normalize( + glm::cross( + Vertices[ i * 3 ].position - Vertices[ i * 3 + 1 ].position, + Vertices[ i * 3 ].position - Vertices[ i * 3 + 2 ].position ) ) ); + } + glm::vec3 vertexnormal; // roboczy wektor normalny + for (int vertexidx = 0; vertexidx < iNumVerts; ++vertexidx) { + // pÄ™tla po wierzchoÅ‚kach trójkÄ…tów + if( wsp[ vertexidx ] >= 0 ) { + // jeÅ›li już byÅ‚ liczony wektor normalny z użyciem tego wierzchoÅ‚ka to wystarczy skopiować policzony wczeÅ›niej + Vertices[ vertexidx ].normal = Vertices[ wsp[ vertexidx ] ].normal; + } + else { + // inaczej musimy dopiero policzyć + auto const faceidx = vertexidx / 3; // numer trójkÄ…ta + vertexnormal = glm::vec3(); // liczenie zaczynamy od zera + auto adjacenvertextidx = vertexidx; // zaczynamy dodawanie wektorów normalnych od wÅ‚asnego + while (adjacenvertextidx >= 0) { + // sumowanie z wektorem normalnym sÄ…siada (włącznie ze sobÄ…) + wsp[adjacenvertextidx] = vertexidx; // informacja, że w tym wierzchoÅ‚ku jest już policzony wektor normalny + vertexnormal += facenormals[adjacenvertextidx / 3]; + // i szukanie od kolejnego trójkÄ…ta + adjacenvertextidx = SeekFaceNormal(sg, adjacenvertextidx / 3 + 1, sg[faceidx], Vertices[vertexidx].position, Vertices); } - // Ra 15-01: należaÅ‚o by jeszcze uwzglÄ™dnić skalowanie wprowadzane - // przez transformy, aby normalne po przeskalowaniu byÅ‚y jednostkowe - Vertices[v].normal = - glm::normalize(norm); // przepisanie do wierzchoÅ‚ka trójkÄ…ta + // Ra 15-01: należaÅ‚o by jeszcze uwzglÄ™dnić skalowanie wprowadzane przez transformy, aby normalne po przeskalowaniu byÅ‚y jednostkowe + Vertices[vertexidx].normal = glm::normalize(vertexnormal); // przepisanie do wierzchoÅ‚ka trójkÄ…ta } } +/* delete[] wsp; delete[] n; delete[] sg; +*/ } else // gdy brak wierzchoÅ‚ków { eType = TP_ROTATOR; // submodel pomocniczy, ma tylko macierz przeksztaÅ‚cenia - iVboPtr = iNumVerts = 0; // dla formalnoÅ›ci + /*iVboPtr =*/ iNumVerts = 0; // dla formalnoÅ›ci } } // obsÅ‚uga submodelu z wÅ‚asnÄ… listÄ… wierzchoÅ‚ków } @@ -558,9 +566,13 @@ int TSubModel::Load(cParser &parser, TModel3d *Model, int Pos, bool dynamic) std::string discard; parser.getTokens(2, false); parser >> discard >> iNumVerts; +/* // Vertices=new GLVERTEX[iNumVerts]; Vertices = new basic_vertex[iNumVerts]; - int i, j; +*/ + Vertices.resize( iNumVerts ); + int i; + unsigned int color; for (i = 0; i < iNumVerts; ++i) { if (i % 3 == 0) @@ -572,13 +584,17 @@ int TSubModel::Load(cParser &parser, TModel3d *Model, int Pos, bool dynamic) >> Vertices[i].position.x >> Vertices[i].position.y >> Vertices[i].position.z - >> j // zakodowany kolor + >> color // zakodowany kolor >> discard; - Vertices[i].normal.x = ((j) & 0xFF) / 255.0; // R - Vertices[i].normal.y = ((j >> 8) & 0xFF) / 255.0; // G - Vertices[i].normal.z = ((j >> 16) & 0xFF) / 255.0; // B + Vertices[i].normal.x = ((color) & 0xff) / 255.0f; // R + Vertices[i].normal.y = ((color >> 8) & 0xff) / 255.0f; // G + Vertices[i].normal.z = ((color >> 16) & 0xff) / 255.0f; // B } } + else if( eType == TP_FREESPOTLIGHT ) { + // single light points only have single data point, duh + Vertices.emplace_back(); + } // Visible=true; //siÄ™ potem wyłączy w razie potrzeby // iFlags|=0x0200; //wczytano z pliku tekstowego (jest wÅ‚aÅ›cicielem tablic) if (iNumVerts < 1) @@ -615,9 +631,10 @@ int TSubModel::TriangleAdd(TModel3d *m, texture_handle tex, int tri) s->iNumVerts += tri; // aktualizacja iloÅ›ci wierzchoÅ‚ków return s->iNumVerts - tri; // zwraca pozycjÄ™ tych trójkÄ…tów w submodelu }; - +/* basic_vertex *TSubModel::TrianglePtr(int tex, int pos, glm::vec3 const &Ambient, glm::vec3 const &Diffuse, glm::vec3 const &Specular ) { // zwraca wskaźnik do wypeÅ‚nienia tabeli wierzchoÅ‚ków, używane przy tworzeniu E3D terenu + TSubModel *s = this; while (s ? s->TextureID != tex : false) { // szukanie submodelu o danej teksturze @@ -637,7 +654,7 @@ basic_vertex *TSubModel::TrianglePtr(int tex, int pos, glm::vec3 const &Ambient, s->ColorsSet(Ambient, Diffuse, Specular); // ustawienie kolorów Å›wiateÅ‚ return s->Vertices + pos; // wskaźnik na wolne miejsce w tabeli wierzchoÅ‚ków }; - +*/ #ifdef EU07_USE_OLD_RENDERCODE void TSubModel::DisplayLists() { // utworznie po jednej skompilowanej liÅ›cie dla @@ -709,10 +726,10 @@ void TSubModel::InitialRotate(bool doit) { // konwersja ukÅ‚adu współrzÄ™dnych na zgodny ze sceneriÄ… if (iFlags & 0xC000) // jeÅ›li jest animacja albo niejednostkowy transform { // niejednostkowy transform jest mnożony i wystarczy zabawy - if (doit) - { // obrót lewostronny - if (!fMatrix) // macierzy może nie być w dodanym "bananie" - { + if (doit) { + // obrót lewostronny + if (!fMatrix) { + // macierzy może nie być w dodanym "bananie" fMatrix = new float4x4(); // tworzy macierz o przypadkowej zawartoÅ›ci fMatrix->Identity(); // a zaczynamy obracanie od jednostkowej } @@ -729,16 +746,18 @@ void TSubModel::InitialRotate(bool doit) { // jak nie ma potomnych, można wymnożyć przez transform i wyjedynkować // go float4x4 *mat = GetMatrix(); // transform submodelu - if (Vertices) - { - for (int i = 0; i < iNumVerts; ++i) - Vertices[i].position = (*mat) * Vertices[i].position; - (*mat)(3)[0] = (*mat)(3)[1] = (*mat)(3)[2] = - 0.0; // zerujemy przesuniÄ™cie przed obracaniem normalnych - if (eType != TP_STARS) // gwiazdki majÄ… kolory zamiast normalnych, to - // ich wtedy nie ruszamy - for (int i = 0; i < iNumVerts; ++i) - Vertices[i].normal = glm::normalize((*mat) * Vertices[i].normal); + if( false == Vertices.empty() ) { + for( auto &vertex : Vertices ) { + vertex.position = (*mat) * vertex.position; + } + // zerujemy przesuniÄ™cie przed obracaniem normalnych + (*mat)(3)[0] = (*mat)(3)[1] = (*mat)(3)[2] = 0.0; + if( eType != TP_STARS ) { + // gwiazdki majÄ… kolory zamiast normalnych, to ich wtedy nie ruszamy + for( auto &vertex : Vertices ) { + vertex.normal = glm::normalize( ( *mat ) * vertex.normal ); + } + } } mat->Identity(); // jedynkowanie transformu po przeliczeniu wierzchoÅ‚ków iFlags &= ~0x8000; // transform jedynkowy @@ -748,23 +767,26 @@ void TSubModel::InitialRotate(bool doit) if (doit) { // jeÅ›li jest jednostkowy transform, to przeliczamy // wierzchoÅ‚ki, a mnożenie podajemy dalej - double t; - if (Vertices) - for (int i = 0; i < iNumVerts; ++i) - { - Vertices[i].position.x = -Vertices[i].position.x; // zmiana znaku X - t = Vertices[i].position.y; // zamiana Y i Z - Vertices[i].position.y = Vertices[i].position.z; - Vertices[i].position.z = t; + float swapcopy; +// if( false == Vertices.empty() ) { +/* + for( auto &vertex : Vertices ) { +*/ + for( int idx = 0; idx < iNumVerts; ++idx ) { + Vertices[idx].position.x = -Vertices[idx].position.x; // zmiana znaku X + swapcopy = Vertices[idx].position.y; // zamiana Y i Z + Vertices[idx].position.y = Vertices[idx].position.z; + Vertices[idx].position.z = swapcopy; // wektory normalne również trzeba przeksztaÅ‚cić, bo siÄ™ źle oÅ›wietlajÄ… if( eType != TP_STARS ) { // gwiazdki majÄ… kolory zamiast normalnych, to // ich wtedy nie ruszamy - Vertices[ i ].normal.x = -Vertices[ i ].normal.x; // zmiana znaku X - t = Vertices[ i ].normal.y; // zamiana Y i Z - Vertices[ i ].normal.y = Vertices[ i ].normal.z; - Vertices[ i ].normal.z = t; + Vertices[idx].normal.x = -Vertices[idx].normal.x; // zmiana znaku X + swapcopy = Vertices[idx].normal.y; // zamiana Y i Z + Vertices[idx].normal.y = Vertices[idx].normal.z; + Vertices[idx].normal.z = swapcopy; } } + // } if (Child) Child->InitialRotate(doit); // potomne ewentualnie obrócimy } @@ -1028,7 +1050,7 @@ void TSubModel::RaAnimation(TAnimType a) }; //--------------------------------------------------------------------------- - +/* void TSubModel::RaArrayFill(basic_vertex *Vert) { // wypeÅ‚nianie tablic VBO if (Child) @@ -1038,22 +1060,31 @@ void TSubModel::RaArrayFill(basic_vertex *Vert) Vert[ iVboPtr + i ].position = Vertices[ i ].position; Vert[ iVboPtr + i ].normal = Vertices[ i ].normal; Vert[ iVboPtr + i ].texture = Vertices[ i ].texture; -/* - Vert[iVboPtr + i].x = Vertices[i].position.x; - Vert[iVboPtr + i].y = Vertices[i].position.y; - Vert[iVboPtr + i].z = Vertices[i].position.z; - Vert[iVboPtr + i].nx = Vertices[i].normal.x; - Vert[iVboPtr + i].ny = Vertices[i].normal.y; - Vert[iVboPtr + i].nz = Vertices[i].normal.z; - Vert[iVboPtr + i].u = Vertices[i].texture.s; - Vert[iVboPtr + i].v = Vertices[i].texture.t; -*/ } else if( eType == TP_FREESPOTLIGHT ) Vert[ iVboPtr ].position = glm::vec3(); if (Next) Next->RaArrayFill(Vert); }; +*/ +void +TSubModel::create_geometry( geometrybank_handle const &Bank ) { + + if( Child ) + Child->create_geometry( Bank ); + + if( false == Vertices.empty() ) { + // conveniently all relevant custom node types use GL_POINTS, or we'd have to determine the type on individual basis + auto type = ( + eType < TP_ROTATOR ? + eType : + GL_POINTS ); + m_geometry = GfxRenderer.Insert( Vertices, Bank, type ); + } + + if( Next ) + Next->create_geometry( Bank ); +} // NOTE: leftover from static distance factor adjustment. // TODO: get rid of it, once we have the dynamic adjustment code in place @@ -1285,9 +1316,10 @@ void TSubModel::serialize(std::ostream &s, sn_utils::ls_int32(s, iFlags); sn_utils::ls_int32(s, (int32_t)get_container_pos(transforms, *fMatrix)); - +/* sn_utils::ls_int32(s, iNumVerts); sn_utils::ls_int32(s, (int)iVboPtr); +*/ if (TextureID <= 0) sn_utils::ls_int32(s, TextureID); else @@ -1324,7 +1356,7 @@ void TSubModel::serialize(std::ostream &s, s.put(0); } -void TModel3d::SaveToBinFile(char const *FileName) +void TModel3d::SaveToBinFile(std::string const &FileName) { // TODO: re-implement! return; @@ -1637,10 +1669,12 @@ void TSubModel::BinInit(TSubModel *s, float4x4 *m, std::vector *t, if (pTexture.find_last_of("/\\") == std::string::npos) pTexture.insert(0, Global::asCurrentTexturePath); TextureID = GfxRenderer.GetTextureId(pTexture, szTexturePath); +/* iFlags |= ( GfxRenderer.Texture( TextureID ).has_alpha ? 0x20 : 0x10 ); // 0x10-nieprzezroczysta, 0x20-przezroczysta +*/ } else TextureID = iTexture; @@ -1662,8 +1696,9 @@ void TSubModel::BinInit(TSubModel *s, float4x4 *m, std::vector *t, } iFlags &= ~0x0200; // wczytano z pliku binarnego (nie jest wÅ‚aÅ›cicielem tablic) - +/* iVboPtr = tVboPtr; +*/ }; void TModel3d::LoadFromBinFile(std::string const &FileName, bool dynamic) @@ -1702,7 +1737,7 @@ void TModel3d::LoadFromTextFile(std::string const &FileName, bool dynamic) break; } SubModel = new TSubModel(); - iNumVerts += SubModel->Load(parser, this, iNumVerts, dynamic); + iNumVerts += SubModel->Load(parser, this, /*iNumVerts,*/ dynamic); // bÄ™dzie potrzebne do wyliczenia pozycji, np. pantografu SubModel->Parent = AddToNamed(parent.c_str(), SubModel); @@ -1752,37 +1787,15 @@ void TModel3d::Init() if (false == asBinary.empty()) // jeÅ›li jest podana nazwa { if (Global::iConvertModels) // i włączony zapis - SaveToBinFile(asBinary.c_str()); // utworzy tablicÄ™ (m_pVNT) + SaveToBinFile( asBinary ); // utworzy tablicÄ™ (m_pVNT) asBinary = ""; // zablokowanie powtórnego zapisu } -#ifdef EU07_USE_OLD_DRAW_CODE - if (iNumVerts) - { - if (Global::bUseVBO) - { -#ifdef EU07_USE_OLD_VERTEXBUFFER - if (!m_pVNT) // jeÅ›li nie ma jeszcze tablicy (wczytano z pliku tekstowego) -#else - if( m_pVNT.empty() ) -#endif - { // tworzenie tymczasowej tablicy z wierzchoÅ‚kami caÅ‚ego modelu - MakeArray(iNumVerts); // tworzenie tablic dla VBO -#ifdef EU07_USE_OLD_VERTEXBUFFER - Root->RaArrayFill(m_pVNT); // wypeÅ‚nianie tablicy -#else - Root->RaArrayFill( m_pVNT.data() ); // wypeÅ‚nianie tablicy -#endif - BuildVBOs(); // tworzenie VBO i usuwanie tablicy z pamiÄ™ci - } - else - BuildVBOs(false); // tworzenie VBO bez usuwania tablicy z pamiÄ™ci - } - else - { // przygotowanie skompilowanych siatek dla DisplayLists - Root->DisplayLists(); // tworzenie skompilowanej listy dla submodelu - } - } -#endif + if (iNumVerts) { + if( m_geometrybank == NULL ) { + m_geometrybank = GfxRenderer.Create_Bank(); + } + Root->create_geometry( m_geometrybank ); + } } }; diff --git a/Model3d.h b/Model3d.h index 136bfac7..90df8eaa 100644 --- a/Model3d.h +++ b/Model3d.h @@ -112,12 +112,15 @@ private: TSubModel *Next; TSubModel *Child; +/* intptr_t iVboPtr; +*/ geometry_handle m_geometry; // geometry of the submodel texture_handle 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 +*/ float Opacity; // nie używane, ale wczytywane //m7todo: wywalić to float f_Angle; float3 v_RotateAxis; @@ -125,7 +128,10 @@ private: public: // chwilowo float3 v_TransVector; +/* basic_vertex *Vertices; // roboczy wskaźnik - wczytanie T3D do VBO +*/ + vertex_array Vertices; size_t iAnimOwner; // roboczy numer egzemplarza, który ustawiÅ‚ animacjÄ™ TAnimType b_aAnim; // kody animacji oddzielnie, bo zerowane public: @@ -138,7 +144,7 @@ public: std::string pTexture; // robocza nazwa tekstury do zapisania w pliku binarnym std::string pName; // robocza nazwa private: - int SeekFaceNormal(unsigned int *Masks, int f, unsigned int dwMask, glm::vec3 *pt, basic_vertex *Vertices); + int SeekFaceNormal( std::vector const &Masks, int const Startface, unsigned int const Mask, glm::vec3 const &Position, vertex_array const &Vertices ); void RaAnimation(TAnimType a); public: @@ -151,13 +157,15 @@ public: TSubModel(); ~TSubModel(); void FirstInit(); - int Load(cParser &Parser, TModel3d *Model, int Pos, bool dynamic); + int Load(cParser &Parser, TModel3d *Model, /*int Pos,*/ bool dynamic); void ChildAdd(TSubModel *SubModel); void NextAdd(TSubModel *SubModel); TSubModel * NextGet() { return Next; }; TSubModel * ChildGet() { return Child; }; int TriangleAdd(TModel3d *m, texture_handle tex, int tri); +/* basic_vertex * TrianglePtr(int tex, int pos, glm::vec3 const &Ambient, glm::vec3 const &Diffuse, glm::vec3 const &Specular ); +*/ void SetRotate(float3 vNewRotateAxis, float fNewAngle); void SetRotateXYZ(vector3 vNewAngles); void SetRotateXYZ(float3 vNewAngles); @@ -168,7 +176,10 @@ public: TSubModel * GetFromName(char const *search, bool i = true); inline float4x4 * GetMatrix() { return fMatrix; }; inline void Hide() { iVisible = 0; }; +/* void RaArrayFill(basic_vertex *Vert); +*/ + void create_geometry( geometrybank_handle const &Bank ); int FlagsCheck(); void WillBeAnimated() { @@ -241,7 +252,7 @@ public: void LoadFromTextFile(std::string const &FileName, bool dynamic); void LoadFromBinFile(std::string const &FileName, bool dynamic); bool LoadFromFile(std::string const &FileName, bool dynamic); - void SaveToBinFile(char const *FileName); + void SaveToBinFile(std::string const &FileName); void BreakHierarhy(); int Flags() const { return iFlags; }; void Init(); diff --git a/Texture.cpp b/Texture.cpp index ba7abbfe..9856a152 100644 --- a/Texture.cpp +++ b/Texture.cpp @@ -795,6 +795,8 @@ texture_manager::create( std::string Filename, std::string const &Dir, int const texture_manager::texture( textureindex ).load(); #ifndef EU07_DEFERRED_TEXTURE_UPLOAD texture_manager::texture( textureindex ).create(); + // texture creation binds a different texture, force a re-bind on next use + m_activetexture = 0; #endif } @@ -803,16 +805,11 @@ texture_manager::create( std::string Filename, std::string const &Dir, int const void texture_manager::bind( texture_handle const Texture ) { -/* - // 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 ) { + + if( Texture == m_activetexture ) { // don't bind again what's already active return; } -*/ // TODO: do binding in texture object, add support for other types if( Texture != 0 ) { #ifndef EU07_DEFERRED_TEXTURE_UPLOAD diff --git a/Track.cpp b/Track.cpp index 2f58097d..5386a839 100644 --- a/Track.cpp +++ b/Track.cpp @@ -1112,52 +1112,7 @@ void TTrack::RaAssign(TGroundNode *gn, TAnimModel *am, TEvent *done, TEvent *joi am->GetContainer(NULL)->EventAssign(done); // zdarzenie zakoÅ„czenia animacji } }; -/* -int TTrack::RaArrayPrepare() -{ // przygotowanie tablic do skopiowania do VBO (zliczanie wierzchoÅ‚ków) - if (bVisible) // o ile w ogóle widać - switch (iCategoryFlag & 15) - { - case 1: // tor - if (eType == tt_Switch) // dla zwrotnicy tylko szyny - return 48 * ((TextureID1 ? SwitchExtension->Segments[0]->RaSegCount() : 0) + - (TextureID2 ? SwitchExtension->Segments[1]->RaSegCount() : 0)); - else // dla toru podsypka plus szyny - return (Segment->RaSegCount()) * ((TextureID1 ? 48 : 0) + (TextureID2 ? 8 : 0)); - case 2: // droga - if (eType == tt_Cross) // tylko dla skrzyżowania dróg - { // specjalny sposób obliczania liczby wierzchoÅ‚ków w skrzyżowaniu - if( SwitchExtension->iRoads == 3 ) { - // mogÄ… być tylko 3 drogi zamiast 4 - SwitchExtension->iPoints = - SwitchExtension->Segments[ 0 ]->RaSegCount() - + SwitchExtension->Segments[ 1 ]->RaSegCount() - + SwitchExtension->Segments[ 2 ]->RaSegCount(); - } - else { - SwitchExtension->iPoints = - SwitchExtension->Segments[ 2 ]->RaSegCount() - + SwitchExtension->Segments[ 3 ]->RaSegCount() - + SwitchExtension->Segments[ 4 ]->RaSegCount() - + SwitchExtension->Segments[ 5 ]->RaSegCount(); - } - // each sub-segment covers only one side of the road, so it has points for single sideroad, if any - return ( ( TextureID1 ? SwitchExtension->iPoints + SwitchExtension->iRoads + 2 : 0 ) + ( TextureID2 ? SwitchExtension->iPoints * 6 : 0 ) ); - } - else // standardowo dla zwykÅ‚ej drogi - if (fTexHeight1 >= 0) // jeÅ›li fTexHeight1<0, to sÄ… chodniki i może któregoÅ› nie być - return ( Segment->RaSegCount()) * - ((TextureID1 ? 4 : 0) + (TextureID2 ? 12 : 0)); // może nie być poziomego! - else - return (Segment->RaSegCount()) * - ((TextureID1 ? 4 : 0) + - (TextureID2 ? (fTexWidth != 0.0 ? 6 : 0) + (fTexSlope != 0.0 ? 6 : 0) : 0)); - case 4: // rzeki do przemyÅ›lenia - return (Segment->RaSegCount()) * ((TextureID1 ? 4 : 0) + (TextureID2 ? 12 : 0)); - } - return 0; -}; -*/ + // wypeÅ‚nianie tablic VBO void TTrack::create_geometry( geometrybank_handle const &Bank ) { // Ra: trzeba rozdzielić szyny od podsypki, aby móc grupować wg tekstur @@ -1875,159 +1830,7 @@ void TTrack::create_geometry( geometrybank_handle const &Bank ) { } return; }; -/* -void TTrack::RaRenderVBO( int iPtr ) { // renderowanie z użyciem VBO - // Ra 2014-07: trzeba wymienić GL_TRIANGLE_STRIP na GL_TRIANGLES i renderować trójkÄ…ty sektora dla kolejnych tekstur! - EnvironmentSet(); - int seg; - switch( iCategoryFlag & 15 ) { - case 1: { - // tor - if( eType == tt_Switch ) // dla zwrotnicy tylko szyny - { - int const bladesegmentcount = 2; - if( TextureID1 ) { - if( ( seg = SwitchExtension->Segments[ 0 ]->RaSegCount() ) > 0 ) { - GfxRenderer.Bind( TextureID1 ); // szyny + - ::glDrawArrays( GL_TRIANGLE_STRIP, iPtr, 24 * seg ); - iPtr += 24 * seg; - ::glDrawArrays( GL_TRIANGLE_STRIP, iPtr, 24 * ( seg - bladesegmentcount ) ); - // NOTE: due to way blades bend need to render each segment separately, or some unwanted edges may show - iPtr += 24 * ( seg - bladesegmentcount ); - for( int i = 0; i < bladesegmentcount; ++i ) { - ::glDrawArrays( GL_TRIANGLE_STRIP, iPtr, 24 ); - iPtr += 24; - } - } - } - if( TextureID2 ) { - if( ( seg = SwitchExtension->Segments[ 1 ]->RaSegCount() ) > 0 ) { - GfxRenderer.Bind( TextureID2 ); - // NOTE: due to way blades bend need to render each segment separately, or some unwanted edges may show - for( int i = 0; i < bladesegmentcount; ++i ) { - ::glDrawArrays( GL_TRIANGLE_STRIP, iPtr, 24 ); - iPtr += 24; - } - ::glDrawArrays( GL_TRIANGLE_STRIP, iPtr, 24 * ( seg - bladesegmentcount ) ); - iPtr += 24 * ( seg - bladesegmentcount ); - ::glDrawArrays( GL_TRIANGLE_STRIP, iPtr, 24 * seg ); - iPtr += 24 * seg; - } - } - } - else // dla toru podsypka plus szyny - { - if( ( seg = Segment->RaSegCount() ) > 0 ) { - if( TextureID2 ) { - GfxRenderer.Bind( TextureID2 ); // podsypka - glDrawArrays( GL_TRIANGLE_STRIP, iPtr, 8 * seg ); - iPtr += 8 * seg; // pominiÄ™cie podsypki - } - if( TextureID1 ) { - GfxRenderer.Bind( TextureID1 ); // szyny - glDrawArrays( GL_TRIANGLE_STRIP, iPtr, 24 * seg ); - iPtr += 24 * seg; // pominiÄ™cie lewej szyny - glDrawArrays( GL_TRIANGLE_STRIP, iPtr, 24 * seg ); - iPtr += 24 * seg; - } - } - } - break; - } - case 2: { - // droga - switch( eType ) { - case tt_Normal: { - if( ( seg = Segment->RaSegCount() ) > 0 ) { - if( TextureID1 ) { - GfxRenderer.Bind( TextureID1 ); // nawierzchnia - ::glDrawArrays( GL_TRIANGLE_STRIP, iPtr, 4 * seg ); - iPtr += 4 * seg; - } - if( TextureID2 ) { - GfxRenderer.Bind( TextureID2 ); // pobocze - if( fTexHeight1 >= 0.0 ) { // normalna droga z poboczem - ::glDrawArrays( GL_TRIANGLE_STRIP, iPtr, 6 * seg ); - iPtr += 6 * seg; // pominiÄ™cie lewego pobocza - ::glDrawArrays( GL_TRIANGLE_STRIP, iPtr, 6 * seg ); - iPtr += 6 * seg; - } - else { // z chodnikami o różnych szerokociach - if( fTexWidth != 0.0 ) { - ::glDrawArrays( GL_TRIANGLE_STRIP, iPtr, 6 * seg ); - iPtr += 6 * seg; // pominiÄ™cie lewego pobocza - } - if( fTexSlope != 0.0 ) { - ::glDrawArrays( GL_TRIANGLE_STRIP, iPtr, 6 * seg ); - iPtr += 6 * seg; - } - } - } - } - break; - } - case tt_Cross: { - if( (seg = SwitchExtension->iPoints) > 0 ) { - if( TextureID2 ) { - // sidewalks - GfxRenderer.Bind( TextureID2 ); - if( fTexHeight1 != 0.0 ) { - if( SwitchExtension->iRoads == 4 ) { - ::glDrawArrays( GL_TRIANGLE_STRIP, iPtr, 6 * SwitchExtension->Segments[ 2 ]->RaSegCount() ); - iPtr += 6 * SwitchExtension->Segments[ 2 ]->RaSegCount(); - ::glDrawArrays( GL_TRIANGLE_STRIP, iPtr, 6 * SwitchExtension->Segments[ 3 ]->RaSegCount() ); - iPtr += 6 * SwitchExtension->Segments[ 3 ]->RaSegCount(); - ::glDrawArrays( GL_TRIANGLE_STRIP, iPtr, 6 * SwitchExtension->Segments[ 4 ]->RaSegCount() ); - iPtr += 6 * SwitchExtension->Segments[ 4 ]->RaSegCount(); - ::glDrawArrays( GL_TRIANGLE_STRIP, iPtr, 6 * SwitchExtension->Segments[ 5 ]->RaSegCount() ); - iPtr += 6 * SwitchExtension->Segments[ 5 ]->RaSegCount(); - } - else { - // presumed 3 roads otherwise, as we only support 3 & 4 road crossings - ::glDrawArrays( GL_TRIANGLE_STRIP, iPtr, 6 * SwitchExtension->Segments[ 2 ]->RaSegCount() ); - iPtr += 6 * SwitchExtension->Segments[ 2 ]->RaSegCount(); - ::glDrawArrays( GL_TRIANGLE_STRIP, iPtr, 6 * SwitchExtension->Segments[ 1 ]->RaSegCount() ); - iPtr += 6 * SwitchExtension->Segments[ 1 ]->RaSegCount(); - ::glDrawArrays( GL_TRIANGLE_STRIP, iPtr, 6 * SwitchExtension->Segments[ 0 ]->RaSegCount() ); - iPtr += 6 * SwitchExtension->Segments[ 0 ]->RaSegCount(); - } - } - } - if( TextureID1 ) { - // roads - GfxRenderer.Bind( TextureID1 ); - ::glDrawArrays( GL_TRIANGLE_FAN, iPtr, SwitchExtension->iPoints + SwitchExtension->iRoads + 2 ); - iPtr += SwitchExtension->iPoints; - } - } - break; - } - default: { break; } - } //switch etype - break; - } - case 4: { - // rzeki - jeszcze do przemyÅ›lenia - if( ( seg = Segment->RaSegCount() ) > 0 ) { - if( TextureID1 ) { - GfxRenderer.Bind( TextureID1 ); // nawierzchnia - glDrawArrays( GL_TRIANGLE_STRIP, iPtr, 4 * seg ); - iPtr += 4 * seg; - } - if( TextureID2 ) { - GfxRenderer.Bind( TextureID2 ); // pobocze - glDrawArrays( GL_TRIANGLE_STRIP, iPtr, 6 * seg ); - iPtr += 6 * seg; // pominiÄ™cie lewego pobocza - glDrawArrays( GL_TRIANGLE_STRIP, iPtr, 6 * seg ); - iPtr += 6 * seg; - } - } - break; - } - } - EnvironmentReset(); -}; -*/ + void TTrack::EnvironmentSet() { // ustawienie zmienionego Å›wiatÅ‚a glColor3f(1.0f, 1.0f, 1.0f); // Ra: potrzebne to? diff --git a/openglgeometrybank.cpp b/openglgeometrybank.cpp index f75906b1..2f18a7c5 100644 --- a/openglgeometrybank.cpp +++ b/openglgeometrybank.cpp @@ -48,11 +48,11 @@ basic_vertex::deserialize( std::istream &s ) { // creates a new geometry chunk of specified type from supplied vertex data. returns: handle to the chunk geometry_handle -geometry_bank::create( vertex_array &Vertices, unsigned int const Type, unsigned int const Streams ) { +geometry_bank::create( vertex_array &Vertices, unsigned int const Type ) { if( true == Vertices.empty() ) { return geometry_handle( 0, 0 ); } - m_chunks.emplace_back( Vertices, Type, Streams ); + m_chunks.emplace_back( Vertices, Type ); // NOTE: handle is effectively (index into chunk array + 1) this leaves value of 0 to serve as error/empty handle indication geometry_handle chunkhandle { 0, static_cast(m_chunks.size()) }; // template method @@ -98,9 +98,9 @@ geometry_bank::append( vertex_array &Vertices, geometry_handle const &Geometry ) // draws geometry stored in specified chunk void -geometry_bank::draw( geometry_handle const &Geometry ) { +geometry_bank::draw( geometry_handle const &Geometry, unsigned int const Streams ) { // template method - draw_( Geometry ); + draw_( Geometry, Streams ); } vertex_array const & @@ -111,7 +111,8 @@ geometry_bank::vertices( geometry_handle const &Geometry ) const { // opengl vbo-based variant of the geometry bank -GLuint opengl_vbogeometrybank::m_activebuffer{ NULL }; // buffer bound currently on the opengl end, if any +GLuint opengl_vbogeometrybank::m_activebuffer { NULL }; // buffer bound currently on the opengl end, if any +unsigned int opengl_vbogeometrybank::m_activestreams { stream::none }; // currently enabled data type pointers // create() subclass details void @@ -140,7 +141,7 @@ opengl_vbogeometrybank::replace_( geometry_handle const &Geometry ) { // draw() subclass details void -opengl_vbogeometrybank::draw_( geometry_handle const &Geometry ) { +opengl_vbogeometrybank::draw_( geometry_handle const &Geometry, unsigned int const Streams ) { if( m_buffer == NULL ) { // if there's no buffer, we'll have to make one @@ -152,6 +153,7 @@ opengl_vbogeometrybank::draw_( geometry_handle const &Geometry ) { auto chunkiterator = m_chunks.cbegin(); for( auto &chunkrecord : m_chunkrecords ) { // fill records for all chunks, based on the chunk data + chunkrecord.is_good = false; // if we're re-creating buffer, chunks might've been uploaded in the old one chunkrecord.offset = datasize; chunkrecord.size = chunkiterator->vertices.size(); datasize += chunkrecord.size; @@ -193,6 +195,9 @@ opengl_vbogeometrybank::draw_( geometry_handle const &Geometry ) { chunk.vertices.data() ); chunkrecord.is_good = true; } + if( m_activestreams != Streams ) { + bind_streams( Streams ); + } // ...render... ::glDrawArrays( chunk.type, chunkrecord.offset, chunkrecord.size ); // ...post-render cleanup @@ -208,16 +213,8 @@ void opengl_vbogeometrybank::bind_buffer() { ::glBindBuffer( GL_ARRAY_BUFFER, m_buffer ); - // TODO: allow specifying other vertex data setups - ::glVertexPointer( 3, GL_FLOAT, sizeof( basic_vertex ), static_cast( nullptr ) ); - ::glNormalPointer( GL_FLOAT, sizeof( basic_vertex ), static_cast( nullptr ) + sizeof(float) * 3 ); // normalne - ::glTexCoordPointer( 2, GL_FLOAT, sizeof( basic_vertex ), static_cast( nullptr ) + 24 ); // wierzchoÅ‚ki - // TODO: allow specifying other vertex data setups, either in the draw() parameters or during chunk or buffer creation - ::glEnableClientState( GL_VERTEX_ARRAY ); - ::glEnableClientState( GL_NORMAL_ARRAY ); - ::glEnableClientState( GL_TEXTURE_COORD_ARRAY ); - m_activebuffer = m_buffer; + m_activestreams = stream::none; } void @@ -231,9 +228,47 @@ opengl_vbogeometrybank::delete_buffer() { } m_buffer = NULL; m_buffercapacity = 0; + // NOTE: since we've deleted the buffer all chunks it held were rendered invalid as well + // instead of clearing their state here we're delaying it until new buffer is created to avoid looping through chunk records twice } } +void +opengl_vbogeometrybank::bind_streams( unsigned int const Streams ) { + + if( Streams & stream::position ) { + ::glVertexPointer( 3, GL_FLOAT, sizeof( basic_vertex ), static_cast( nullptr ) ); + ::glEnableClientState( GL_VERTEX_ARRAY ); + } + else { + ::glDisableClientState( GL_VERTEX_ARRAY ); + } + // NOTE: normal and color streams share the data, making them effectively mutually exclusive + if( Streams & stream::normal ) { + ::glNormalPointer( GL_FLOAT, sizeof( basic_vertex ), static_cast( nullptr ) + sizeof( float ) * 3 ); + ::glEnableClientState( GL_NORMAL_ARRAY ); + } + else { + ::glDisableClientState( GL_NORMAL_ARRAY ); + } + if( Streams & stream::color ) { + ::glColorPointer( 3, GL_FLOAT, sizeof( basic_vertex ), static_cast( nullptr ) + sizeof( float ) * 3 ); + ::glEnableClientState( GL_COLOR_ARRAY ); + } + else { + ::glDisableClientState( GL_COLOR_ARRAY ); + } + if( Streams & stream::texture ) { + ::glTexCoordPointer( 2, GL_FLOAT, sizeof( basic_vertex ), static_cast( nullptr ) + 24 ); + ::glEnableClientState( GL_TEXTURE_COORD_ARRAY ); + } + else { + ::glDisableClientState( GL_TEXTURE_COORD_ARRAY ); + } + + m_activestreams = Streams; +} + // opengl display list based variant of the geometry bank // create() subclass details @@ -252,21 +287,25 @@ opengl_dlgeometrybank::replace_( geometry_handle const &Geometry ) { // draw() subclass details void -opengl_dlgeometrybank::draw_( geometry_handle const &Geometry ) { +opengl_dlgeometrybank::draw_( geometry_handle const &Geometry, unsigned int const Streams ) { auto &chunkrecord = m_chunkrecords[ Geometry.chunk - 1 ]; + if( chunkrecord.streams != Streams ) { + delete_list( Geometry ); + } if( chunkrecord.list == 0 ) { // we don't have a list ready, so compile one + chunkrecord.streams = Streams; chunkrecord.list = ::glGenLists( 1 ); auto const &chunk = geometry_bank::chunk( Geometry ); ::glNewList( chunkrecord.list, GL_COMPILE ); ::glBegin( chunk.type ); - // TODO: add specification of chunk vertex attributes for( auto const &vertex : chunk.vertices ) { - ::glNormal3fv( glm::value_ptr( vertex.normal ) ); - ::glTexCoord2fv( glm::value_ptr( vertex.texture ) ); - ::glVertex3fv( glm::value_ptr( vertex.position ) ); + if( Streams & stream::normal ) { ::glNormal3fv( glm::value_ptr( vertex.normal ) ); } + else if( Streams & stream::color ) { ::glColor3fv( glm::value_ptr( vertex.normal ) ); } + if( Streams & stream::texture ) { ::glTexCoord2fv( glm::value_ptr( vertex.texture ) ); } + if( Streams & stream::position ) { ::glVertex3fv( glm::value_ptr( vertex.position ) ); } } ::glEnd(); ::glEndList(); @@ -279,8 +318,11 @@ void opengl_dlgeometrybank::delete_list( geometry_handle const &Geometry ) { // NOTE: given it's our own internal method we trust it to be called with valid parameters auto &chunkrecord = m_chunkrecords[ Geometry.chunk - 1 ]; - ::glDeleteLists( chunkrecord.list, 1 ); - chunkrecord.list = 0; + if( chunkrecord.list != 0 ) { + ::glDeleteLists( chunkrecord.list, 1 ); + chunkrecord.list = 0; + } + chunkrecord.streams = stream::none; } // geometry bank manager, holds collection of geometry banks @@ -320,11 +362,11 @@ geometrybank_manager::append( vertex_array &Vertices, geometry_handle const &Geo } // draws geometry stored in specified chunk void -geometrybank_manager::draw( geometry_handle const &Geometry ) { +geometrybank_manager::draw( geometry_handle const &Geometry, unsigned int const Streams ) { if( Geometry == NULL ) { return; } - return bank( Geometry )->draw( Geometry ); + return bank( Geometry )->draw( Geometry, Streams ); } // provides direct access to vertex data of specfied chunk diff --git a/openglgeometrybank.h b/openglgeometrybank.h index 4a41a51e..a6868a2f 100644 --- a/openglgeometrybank.h +++ b/openglgeometrybank.h @@ -33,10 +33,11 @@ struct basic_vertex { // data streams carried in a vertex enum stream { + none = 0x0, position = 0x1, - normal = 0x2, - color = 0x4, // currently normal and colour streams are stored in the same slot, and mutually exclusive - texture = 0x8 + normal = 0x2, + color = 0x4, // currently normal and colour streams are stored in the same slot, and mutually exclusive + texture = 0x8 }; unsigned int const basic_streams { stream::position | stream::normal | stream::texture }; @@ -87,7 +88,7 @@ public: // methods: // creates a new geometry chunk of specified type from supplied vertex data. returns: handle to the chunk or NULL geometry_handle - create( vertex_array &Vertices, unsigned int const Type, unsigned int const Streams = stream::position | stream::normal | stream::texture ); + create( vertex_array &Vertices, unsigned int const Type ); // replaces data of specified chunk with the supplied vertex data, starting from specified offset bool replace( vertex_array &Vertices, geometry_handle const &Geometry, std::size_t const Offset = 0 ); @@ -96,11 +97,11 @@ public: append( vertex_array &Vertices, geometry_handle const &Geometry ); // draws geometry stored in specified chunk void - draw( geometry_handle const &Geometry ); + draw( geometry_handle const &Geometry, unsigned int const Streams = basic_streams ); // draws geometry stored in supplied list of chunks template void - draw( Iterator_ First, Iterator_ Last ) { while( First != Last ) { draw( *First ); ++First; } } + draw( Iterator_ First, Iterator_ Last, unsigned int const Streams = basic_streams ) { while( First != Last ) { draw( *First, Streams ); ++First; } } // provides direct access to vertex data of specfied chunk vertex_array const & vertices( geometry_handle const &Geometry ) const; @@ -108,12 +109,11 @@ public: protected: // types: struct geometry_chunk { - unsigned int streams; // data streams carried by vertices unsigned int type; // kind of geometry used by the chunk vertex_array vertices; // geometry data - geometry_chunk( vertex_array &Vertices, unsigned int const Type, unsigned int const Streams ) : - vertices( Vertices ), type( Type ), streams( Streams ) + geometry_chunk( vertex_array &Vertices, unsigned int const Type ) : + vertices( Vertices ), type( Type ) {} }; @@ -139,7 +139,7 @@ private: // replace() subclass details virtual void replace_( geometry_handle const &Geometry ) = 0; // draw() subclass details - virtual void draw_( geometry_handle const &Geometry ) = 0; + virtual void draw_( geometry_handle const &Geometry, unsigned int const Streams ) = 0; }; // opengl vbo-based variant of the geometry bank @@ -154,7 +154,8 @@ public: static void reset() { - m_activebuffer = 0; } + m_activebuffer = 0; + m_activestreams = stream::none; } private: // types: @@ -175,15 +176,18 @@ private: replace_( geometry_handle const &Geometry ); // draw() subclass details void - draw_( geometry_handle const &Geometry ); + draw_( geometry_handle const &Geometry, unsigned int const Streams ); void bind_buffer(); void delete_buffer(); + void + bind_streams( unsigned int const Streams ); // members: static GLuint m_activebuffer; // buffer bound currently on the opengl end, if any - GLuint m_buffer{ NULL }; // id of the buffer holding data on the opengl end + static unsigned int m_activestreams; + GLuint m_buffer { NULL }; // id of the buffer holding data on the opengl end std::size_t m_buffercapacity{ 0 }; // total capacity of the last established buffer chunkrecord_sequence m_chunkrecords; // helper data for all stored geometry chunks, in matching order @@ -202,7 +206,8 @@ public: private: // types: struct chunk_record { - GLuint list{ 0 }; // display list associated with the chunk + GLuint list { 0 }; // display list associated with the chunk + unsigned int streams { 0 }; // stream combination used to generate the display list }; typedef std::vector chunkrecord_sequence; @@ -216,7 +221,7 @@ private: replace_( geometry_handle const &Geometry ); // draw() subclass details void - draw_( geometry_handle const &Geometry ); + draw_( geometry_handle const &Geometry, unsigned int const Streams ); void delete_list( geometry_handle const &Geometry ); @@ -247,12 +252,12 @@ public: append( vertex_array &Vertices, geometry_handle const &Geometry ); // draws geometry stored in specified chunk void - draw( geometry_handle const &Geometry ); + draw( geometry_handle const &Geometry, unsigned int const Streams = basic_streams ); template void - draw( Iterator_ First, Iterator_ Last ) { + draw( Iterator_ First, Iterator_ Last, unsigned int const Streams = basic_streams ) { while( First != Last ) { - draw( *First ); + draw( *First, Streams ); ++First; } } // provides direct access to vertex data of specfied chunk vertex_array const & diff --git a/renderer.cpp b/renderer.cpp index 242d29ae..f7970509 100644 --- a/renderer.cpp +++ b/renderer.cpp @@ -157,7 +157,6 @@ opengl_renderer::Render() { // frustum tests are performed in 'world space' but after we set up frustum // we no longer need camera translation, only rotation ::glMultMatrixd( glm::value_ptr( glm::dmat4( glm::dmat3( worldcamera )))); - Render( &World.Environment ); Render( &World.Ground ); @@ -835,27 +834,8 @@ opengl_renderer::Render( TSubModel *Submodel ) { ::glDisable( GL_LIGHTING ); // main draw call - // TODO: add support for colour data draw mode - m_geometry.draw( Submodel->m_geometry ); -/* - if( Global::bUseVBO ) { - // NOTE: we're doing manual switch to color vbo setup, because there doesn't seem to be any convenient way available atm - // TODO: implement easier way to go about it - ::glDisableClientState( GL_NORMAL_ARRAY ); - ::glDisableClientState( GL_TEXTURE_COORD_ARRAY ); - ::glEnableClientState( GL_COLOR_ARRAY ); - ::glColorPointer( 3, GL_FLOAT, sizeof( basic_vertex ), static_cast( nullptr ) + 12 ); // kolory + m_geometry.draw( Submodel->m_geometry, color_streams ); - ::glDrawArrays( GL_POINTS, Submodel->iVboPtr, Submodel->iNumVerts ); - - ::glDisableClientState( GL_COLOR_ARRAY ); - ::glEnableClientState( GL_NORMAL_ARRAY ); - ::glEnableClientState( GL_TEXTURE_COORD_ARRAY ); - } - else { - ::glCallList( Submodel->uiDisplayList ); - } -*/ // post-draw reset ::glPopAttrib(); } @@ -986,9 +966,6 @@ opengl_renderer::Render_Alpha( TGroundNode *Node ) { // pozniej sprawdzamy czy jest wlaczony PROBLEND dla aktualnie renderowanego noda TRIANGLE, // wlasciwie dla kazdego node'a // i jezeli tak to odpowiedni GL_GREATER w przeciwnym wypadku standardowy 0.04 -/* - Node->SetLastUsage( Timer::GetSimulationTime() ); -*/ double const distancesquared = SquareMagnitude( ( Node->pCenter - Global::pCameraPosition ) / Global::ZoomFactor ); if( ( distancesquared > ( Node->fSquareRadius * Global::fDistanceFactor ) ) || ( distancesquared < ( Node->fSquareMinRadius / Global::fDistanceFactor ) ) ) { From 34a899239f75ce501a263129c136d7205d295470 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Sun, 18 Jun 2017 01:16:28 +0200 Subject: [PATCH 9/9] build 170617. frustum based ground sector culling, fully view range based draw range limit, support for line width parameter for lines --- Ground.cpp | 30 ++--- Ground.h | 2 - Model3d.cpp | 244 ++++++++++++++++------------------------- Model3d.h | 110 +++++++++---------- PyInt.cpp | 2 +- World.cpp | 10 +- openglgeometrybank.cpp | 2 +- openglgeometrybank.h | 10 +- renderer.cpp | 181 +++++++++++------------------- renderer.h | 4 +- version.h | 2 +- 11 files changed, 240 insertions(+), 357 deletions(-) diff --git a/Ground.cpp b/Ground.cpp index bff36c80..76666103 100644 --- a/Ground.cpp +++ b/Ground.cpp @@ -39,7 +39,6 @@ http://mozilla.org/MPL/2.0/. #include "world.h" #include "uilayer.h" -#define _PROBLEND 1 //--------------------------------------------------------------------------- extern "C" @@ -1283,18 +1282,16 @@ TGroundNode * TGround::AddGroundNode(cParser *parser) *parser >> token; } str = token; -#ifdef _PROBLEND - // 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('@') != std::string::npos) // sprawdza, czy w nazwie tekstury jest znak "@" - { - PROBLEND = false; // jeÅ›li jest, wyswietla po staremu - tmp->PROBLEND = false; - } -#endif tmp->TextureID = GfxRenderer.GetTextureId( str, szTexturePath ); - tmp->iFlags = GfxRenderer.Texture(tmp->TextureID).has_alpha ? 0x220 : 0x210; // z usuwaniem + + tmp->iFlags |= 200; // z usuwaniem + // remainder of legacy 'problend' system -- geometry assigned a texture with '@' in its name is treated as translucent, opaque otherwise + tmp->iFlags |= ( + ( ( str.find( '@' ) != std::string::npos ) + && ( true == GfxRenderer.Texture( tmp->TextureID ).has_alpha ) ) ? + 0x20 : + 0x10 ); + if( (tmp->iType == GL_TRIANGLES) && (tmp->iFlags & 0x10) && (Global::pTerrainCompact->TerrainLoaded()) ) { @@ -1327,7 +1324,6 @@ TGroundNode * TGround::AddGroundNode(cParser *parser) vertex.normal = glm::rotateX( vertex.normal, static_cast( aRotate.x / 180 * M_PI ) ); vertex.normal = glm::rotateY( vertex.normal, static_cast( aRotate.y / 180 * M_PI ) ); vertex.position += glm::dvec3( pOrigin.x, pOrigin.y, pOrigin.z ); - tmp->pCenter += vertex.position; // convert all data to gl_triangles to allow data merge for matching nodes switch( tmp->iType ) { case GL_TRIANGLES: { @@ -1370,6 +1366,10 @@ TGroundNode * TGround::AddGroundNode(cParser *parser) auto const nv = importedvertices.size(); tmp->Init(nv); // utworzenie tablicy wierzchoÅ‚ków + + for( std::size_t i = 0; i < nv; ++i ) { + tmp->pCenter += importedvertices[ i ].position; + } tmp->pCenter /= (nv > 0 ? nv : 1); r = 0; @@ -1411,7 +1411,6 @@ TGroundNode * TGround::AddGroundNode(cParser *parser) vertex.position = glm::rotateY( vertex.position, aRotate.y / 180 * M_PI ); vertex.position += glm::dvec3( pOrigin.x, pOrigin.y, pOrigin.z ); - tmp->pCenter += vertex.position; // convert all data to gl_lines to allow data merge for matching nodes switch( tmp->iType ) { case GL_LINES: { @@ -1460,10 +1459,11 @@ TGroundNode * TGround::AddGroundNode(cParser *parser) auto const nv = importedvertices.size(); tmp->Points = new glm::dvec3[ nv ]; tmp->iNumPts = nv; - tmp->pCenter /= ( nv > 0 ? nv : 1 ); for( std::size_t i = 0; i < nv; ++i ) { tmp->Points[ i ] = importedvertices[ i ].position; + tmp->pCenter += importedvertices[ i ].position; } + tmp->pCenter /= ( nv > 0 ? nv : 1 ); break; } } diff --git a/Ground.h b/Ground.h index c3773de0..4edf8976 100644 --- a/Ground.h +++ b/Ground.h @@ -149,7 +149,6 @@ public: Diffuse{ 1.0f, 1.0f, 1.0f }, Specular{ 1.0f, 1.0f, 1.0f }; // oÅ›wietlenie double fLineThickness; // McZapkie-120702: grubosc linii - bool PROBLEND; bool bVisible; TGroundNode(); @@ -283,7 +282,6 @@ class TGround event_map m_eventmap; TNames m_trackmap; light_array m_lights; // collection of dynamic light sources present in the scene - bool PROBLEND; private: // metody prywatne bool EventConditon(TEvent *e); diff --git a/Model3d.cpp b/Model3d.cpp index ab655643..e7617e06 100644 --- a/Model3d.cpp +++ b/Model3d.cpp @@ -42,69 +42,6 @@ std::string *TSubModel::pasText; // 0x3F3F003F - wszystkie wymienne tekstury używane w danym cyklu // Ale w TModel3d okerÅ›la przezroczystość tekstur wymiennych! -TSubModel::TSubModel() -{ - ::SecureZeroMemory(this, sizeof(TSubModel)); // istotne przy zapisywaniu wersji binarnej - FirstInit(); -}; - -void TSubModel::FirstInit() -{ - eType = TP_ROTATOR; -/* - Vertices = NULL; - uiDisplayList = 0; -*/ - iNumVerts = -1; // do sprawdzenia -/* - iVboPtr = -1; -*/ - fLight = -1.0; //Å›wietcenie wyłączone - v_RotateAxis = float3(0, 0, 0); - v_TransVector = float3(0, 0, 0); - f_Angle = 0; - b_Anim = at_None; - b_aAnim = at_None; - fVisible = 0.0; // zawsze widoczne - iVisible = 1; - fMatrix = NULL; // to samo co iMatrix=0; - Next = NULL; - Child = NULL; - TextureID = 0; - // TexAlpha=false; - iFlags = 0x0200; // bit 9=1: submodel zostaÅ‚ utworzony a nie ustawiony na - // wczytany plik - // TexHash=false; - // Hits=NULL; - // CollisionPts=NULL; - // CollisionPtsCount=0; - Opacity = 0.0f; // przy wczytywaniu modeli byÅ‚o dzielone przez 100... - bWire = false; - fWireSize = 0; - fNearAttenStart = 40; - fNearAttenEnd = 80; - bUseNearAtten = false; - iFarAttenDecay = 0; - fFarDecayRadius = 100.0f; - fCosFalloffAngle = 0.5f; // 120°? - fCosHotspotAngle = 0.3f; // 145°? - fCosViewAngle = 0; - fSquareMaxDist = 10000 * 10000; // 10km - fSquareMinDist = 0; - iName = -1; // brak nazwy - iTexture = 0; // brak tekstury - // asName=""; - // asTexture=""; - pName = ""; - pTexture = ""; - f4Ambient[0] = f4Ambient[1] = f4Ambient[2] = f4Ambient[3] = 1.0; //{1,1,1,1}; - f4Diffuse[0] = f4Diffuse[1] = f4Diffuse[2] = f4Diffuse[3] = 1.0; //{1,1,1,1}; - f4Specular[0] = f4Specular[1] = f4Specular[2] = 0.0; - f4Specular[3] = 1.0; //{0,0,0,1}; - f4Emision[0] = f4Emision[1] = f4Emision[2] = f4Emision[3] = 1.0; - smLetter = NULL; // używany tylko roboczo dla TP_TEXT, do przyspieszenia wyÅ›wietlania -}; - TSubModel::~TSubModel() { /* @@ -141,9 +78,6 @@ void TSubModel::NameSet(std::string const &Name) pName = Name; }; -// int TSubModel::SeekFaceNormal(DWORD *Masks, int f,DWORD dwMask,vector3 -// *pt,GLVERTEX -// *Vertices) int TSubModel::SeekFaceNormal(std::vector const &Masks, int const Startface, unsigned int const Mask, glm::vec3 const &Position, vertex_array const &Vertices) { // szukanie punktu stycznego do (pt), zwraca numer wierzchoÅ‚ka, a nie trójkÄ…ta int facecount = iNumVerts / 3; // bo maska powierzchni jest jedna na trójkÄ…t @@ -518,11 +452,14 @@ int TSubModel::Load( cParser &parser, TModel3d *Model, /*int Pos,*/ bool dynamic std::vector facenormals; for( int i = 0; i < facecount; ++i ) { // pÄ™tla po trójkÄ…tach - bÄ™dzie szybciej, jak wstÄ™pnie przeliczymy normalne trójkÄ…tów + auto facenormal = + glm::cross( + Vertices[ i * 3 ].position - Vertices[ i * 3 + 1 ].position, + Vertices[ i * 3 ].position - Vertices[ i * 3 + 2 ].position ); facenormals.emplace_back( - glm::normalize( - glm::cross( - Vertices[ i * 3 ].position - Vertices[ i * 3 + 1 ].position, - Vertices[ i * 3 ].position - Vertices[ i * 3 + 2 ].position ) ) ); + glm::length( facenormal ) > 0.0f ? + glm::normalize( facenormal ) : + glm::vec3() ); } glm::vec3 vertexnormal; // roboczy wektor normalny for (int vertexidx = 0; vertexidx < iNumVerts; ++vertexidx) { @@ -544,7 +481,10 @@ int TSubModel::Load( cParser &parser, TModel3d *Model, /*int Pos,*/ bool dynamic adjacenvertextidx = SeekFaceNormal(sg, adjacenvertextidx / 3 + 1, sg[faceidx], Vertices[vertexidx].position, Vertices); } // Ra 15-01: należaÅ‚o by jeszcze uwzglÄ™dnić skalowanie wprowadzane przez transformy, aby normalne po przeskalowaniu byÅ‚y jednostkowe - Vertices[vertexidx].normal = glm::normalize(vertexnormal); // przepisanie do wierzchoÅ‚ka trójkÄ…ta + Vertices[ vertexidx ].normal = ( + glm::length( vertexnormal ) > 0.0f ? + glm::normalize( vertexnormal ) : + glm::vec3() ); // przepisanie do wierzchoÅ‚ka trójkÄ…ta } } /* @@ -755,7 +695,10 @@ void TSubModel::InitialRotate(bool doit) if( eType != TP_STARS ) { // gwiazdki majÄ… kolory zamiast normalnych, to ich wtedy nie ruszamy for( auto &vertex : Vertices ) { - vertex.normal = glm::normalize( ( *mat ) * vertex.normal ); + vertex.normal = ( + glm::length( vertex.normal ) > 0.0f ? + glm::normalize( ( *mat ) * vertex.normal ) : + glm::vec3() ); } } } @@ -772,18 +715,18 @@ void TSubModel::InitialRotate(bool doit) /* for( auto &vertex : Vertices ) { */ - for( int idx = 0; idx < iNumVerts; ++idx ) { - Vertices[idx].position.x = -Vertices[idx].position.x; // zmiana znaku X - swapcopy = Vertices[idx].position.y; // zamiana Y i Z - Vertices[idx].position.y = Vertices[idx].position.z; - Vertices[idx].position.z = swapcopy; + for( auto &vertex : Vertices ) { + vertex.position.x = -vertex.position.x; // zmiana znaku X + swapcopy = vertex.position.y; // zamiana Y i Z + vertex.position.y = vertex.position.z; + vertex.position.z = swapcopy; // wektory normalne również trzeba przeksztaÅ‚cić, bo siÄ™ źle oÅ›wietlajÄ… if( eType != TP_STARS ) { // gwiazdki majÄ… kolory zamiast normalnych, to // ich wtedy nie ruszamy - Vertices[idx].normal.x = -Vertices[idx].normal.x; // zmiana znaku X - swapcopy = Vertices[idx].normal.y; // zamiana Y i Z - Vertices[idx].normal.y = Vertices[idx].normal.z; - Vertices[idx].normal.z = swapcopy; + vertex.normal.x = -vertex.normal.x; // zmiana znaku X + swapcopy = vertex.normal.y; // zamiana Y i Z + vertex.normal.y = vertex.normal.z; + vertex.normal.z = swapcopy; } } // } @@ -1050,30 +993,34 @@ void TSubModel::RaAnimation(TAnimType a) }; //--------------------------------------------------------------------------- -/* -void TSubModel::RaArrayFill(basic_vertex *Vert) -{ // wypeÅ‚nianie tablic VBO - if (Child) - Child->RaArrayFill(Vert); - if( ( eType < TP_ROTATOR ) || ( eType == TP_STARS ) ) - for( int i = 0; i < iNumVerts; ++i ) { - Vert[ iVboPtr + i ].position = Vertices[ i ].position; - Vert[ iVboPtr + i ].normal = Vertices[ i ].normal; - Vert[ iVboPtr + i ].texture = Vertices[ i ].texture; + +void TSubModel::serialize_geometry( std::ostream &Output ) { + + if( Child ) { + Child->serialize_geometry( Output ); + } + if( m_geometry != NULL ) { + for( auto const &vertex : GfxRenderer.Vertices( m_geometry ) ) { + vertex.serialize( Output ); } - else if( eType == TP_FREESPOTLIGHT ) - Vert[ iVboPtr ].position = glm::vec3(); - if (Next) - Next->RaArrayFill(Vert); + } + if( Next ) { + Next->serialize_geometry( Output ); + } }; -*/ + void -TSubModel::create_geometry( geometrybank_handle const &Bank ) { +TSubModel::create_geometry( std::size_t &Dataoffset, geometrybank_handle const &Bank ) { + + // data offset is used to determine data offset of each submodel into single shared geometry bank + // (the offsets are part of legacy system which we now need to work around for backward compatibility) if( Child ) - Child->create_geometry( Bank ); + Child->create_geometry( Dataoffset, Bank ); if( false == Vertices.empty() ) { + tVboPtr = static_cast( Dataoffset ); + Dataoffset += Vertices.size(); // conveniently all relevant custom node types use GL_POINTS, or we'd have to determine the type on individual basis auto type = ( eType < TP_ROTATOR ? @@ -1083,7 +1030,7 @@ TSubModel::create_geometry( geometrybank_handle const &Bank ) { } if( Next ) - Next->create_geometry( Bank ); + Next->create_geometry( Dataoffset, Bank ); } // NOTE: leftover from static distance factor adjustment. @@ -1140,25 +1087,34 @@ void TSubModel::ParentMatrix(float4x4 *m) // nie obrócono jeszcze }; -float TSubModel::MaxY( float4x4 const &m ) -{ // obliczenie maksymalnej wysokoÅ›ci, na poczÄ…tek Å›lizgu w pantografie - if( eType != 4 ) { - // tylko dla trójkÄ…tów liczymy - return 0; - } - if( m_geometry == NULL ) { - return 0; - } +// obliczenie maksymalnej wysokoÅ›ci, na poczÄ…tek Å›lizgu w pantografie +float TSubModel::MaxY( float4x4 const &m ) { + // tylko dla trójkÄ…tów liczymy + if( eType != 4 ) { return 0; } auto maxy { 0.0f }; - for( auto const &vertex : GfxRenderer.Vertices( m_geometry ) ) { + // binary and text models invoke this function at different stages, either after or before geometry data was sent to the geometry manager + if( m_geometry != NULL ) { - maxy = std::max( - maxy, - m[ 0 ][ 1 ] * vertex.position.x - + m[ 1 ][ 1 ] * vertex.position.y - + m[ 2 ][ 1 ] * vertex.position.z - + m[ 3 ][ 1 ] ); + for( auto const &vertex : GfxRenderer.Vertices( m_geometry ) ) { + maxy = std::max( + maxy, + m[ 0 ][ 1 ] * vertex.position.x + + m[ 1 ][ 1 ] * vertex.position.y + + m[ 2 ][ 1 ] * vertex.position.z + + m[ 3 ][ 1 ] ); + } + } + else if( false == Vertices.empty() ) { + + for( auto const &vertex : Vertices ) { + maxy = std::max( + maxy, + m[ 0 ][ 1 ] * vertex.position.x + + m[ 1 ][ 1 ] * vertex.position.y + + m[ 2 ][ 1 ] * vertex.position.z + + m[ 3 ][ 1 ] ); + } } return maxy; @@ -1316,10 +1272,10 @@ void TSubModel::serialize(std::ostream &s, sn_utils::ls_int32(s, iFlags); sn_utils::ls_int32(s, (int32_t)get_container_pos(transforms, *fMatrix)); -/* + sn_utils::ls_int32(s, iNumVerts); - sn_utils::ls_int32(s, (int)iVboPtr); -*/ + sn_utils::ls_int32(s, tVboPtr); + if (TextureID <= 0) sn_utils::ls_int32(s, TextureID); else @@ -1358,9 +1314,6 @@ void TSubModel::serialize(std::ostream &s, void TModel3d::SaveToBinFile(std::string const &FileName) { - // TODO: re-implement! - return; - WriteLog("saving e3d model.."); //m7todo: można by zoptymalizować robiÄ…c unordered_map @@ -1396,20 +1349,11 @@ void TModel3d::SaveToBinFile(std::string const &FileName) sn_utils::ls_uint32(s, 8 + (uint32_t)transforms.size() * 64); for (size_t i = 0; i < transforms.size(); i++) transforms[i].serialize_float32(s); -/* - MakeArray(iNumVerts); -#ifdef EU07_USE_OLD_VERTEXBUFFER - Root->RaArrayFill(m_pVNT); -#else - Root->RaArrayFill( m_pVNT.data() ); -#endif -*/ - sn_utils::ls_uint32(s, MAKE_ID4('V', 'N', 'T', '0')); + + sn_utils::ls_uint32(s, MAKE_ID4('V', 'N', 'T', '0')); sn_utils::ls_uint32(s, 8 + iNumVerts * 32); -/* - for (size_t i = 0; i < (size_t)iNumVerts; i++) - m_pVNT[i].serialize(s); -*/ + Root->serialize_geometry( s ); + if (textures.size()) { sn_utils::ls_uint32(s, MAKE_ID4('T', 'E', 'X', '0')); @@ -1555,6 +1499,7 @@ void TModel3d::deserialize(std::istream &s, size_t size, bool dynamic) for( auto const &submodeloffset : submodeloffsets ) { auto &submodel = Root[ submodeloffset.second ]; vertex_array vertices; vertices.resize( submodel.iNumVerts ); + iNumVerts += submodel.iNumVerts; for( auto &vertex : vertices ) { vertex.deserialize( s ); } @@ -1669,12 +1614,13 @@ void TSubModel::BinInit(TSubModel *s, float4x4 *m, std::vector *t, if (pTexture.find_last_of("/\\") == std::string::npos) pTexture.insert(0, Global::asCurrentTexturePath); TextureID = GfxRenderer.GetTextureId(pTexture, szTexturePath); -/* - iFlags |= - ( GfxRenderer.Texture( TextureID ).has_alpha ? - 0x20 : - 0x10 ); // 0x10-nieprzezroczysta, 0x20-przezroczysta -*/ + if( ( iFlags & 0x30 ) == 0 ) { + // texture-alpha based fallback if for some reason we don't have opacity flag set yet + iFlags |= + ( GfxRenderer.Texture( TextureID ).has_alpha ? + 0x20 : + 0x10 ); // 0x10-nieprzezroczysta, 0x20-przezroczysta + } } else TextureID = iTexture; @@ -1688,10 +1634,10 @@ void TSubModel::BinInit(TSubModel *s, float4x4 *m, std::vector *t, iFlags |= 0x20; } // intercept and fix hotspot values if specified in degrees and not directly - if( fCosFalloffAngle > 1.0 ) { + if( fCosFalloffAngle > 1.0f ) { fCosFalloffAngle = std::cos( DegToRad( 0.5f * fCosFalloffAngle ) ); } - if( fCosHotspotAngle > 1.0 ) { + if( fCosHotspotAngle > 1.0f ) { fCosHotspotAngle = std::cos( DegToRad( 0.5f * fCosHotspotAngle ) ); } @@ -1784,17 +1730,17 @@ void TModel3d::Init() Root->InitialRotate(true); // argumet okreÅ›la, czy wykonać pierwotny obrót } iFlags |= Root->FlagsCheck() | 0x8000; // flagi caÅ‚ego modelu - if (false == asBinary.empty()) // jeÅ›li jest podana nazwa - { - if (Global::iConvertModels) // i włączony zapis - SaveToBinFile( asBinary ); // utworzy tablicÄ™ (m_pVNT) - asBinary = ""; // zablokowanie powtórnego zapisu - } if (iNumVerts) { if( m_geometrybank == NULL ) { m_geometrybank = GfxRenderer.Create_Bank(); } - Root->create_geometry( m_geometrybank ); + std::size_t dataoffset = 0; + Root->create_geometry( dataoffset, m_geometrybank ); + } + if( ( Global::iConvertModels > 0 ) + && ( false == asBinary.empty() ) ) { + SaveToBinFile( asBinary ); + asBinary = ""; // zablokowanie powtórnego zapisu } } }; diff --git a/Model3d.h b/Model3d.h index 90df8eaa..fab31e2e 100644 --- a/Model3d.h +++ b/Model3d.h @@ -7,8 +7,7 @@ obtain one at http://mozilla.org/MPL/2.0/. */ -#ifndef Model3dH -#define Model3dH +#pragma once #include "GL/glew.h" #include "Parser.h" @@ -51,8 +50,6 @@ enum TAnimType // rodzaj animacji at_Undefined = 0x800000FF // animacja chwilowo nieokreÅ›lona }; -class TModel3d; - class TSubModel { // klasa submodelu - pojedyncza siatka, punkt Å›wietlny albo grupa punktów //m7todo: zrobić normalnÄ… serializacjÄ™ @@ -61,15 +58,16 @@ class TSubModel friend class TModel3d; // temporary workaround. TODO: clean up class content/hierarchy private: - int iNext; - int iChild; - int eType; // Ra: modele binarne dajÄ… wiÄ™cej możliwoÅ›ci niż mesh zÅ‚ożony z trójkÄ…tów - int iName; // numer Å‚aÅ„cucha z nazwÄ… submodelu, albo -1 gdy anonimowy + int iNext{ NULL }; + int iChild{ NULL }; + int eType{ TP_ROTATOR }; // Ra: modele binarne dajÄ… wiÄ™cej możliwoÅ›ci niż mesh zÅ‚ożony z trójkÄ…tów + int iName{ -1 }; // numer Å‚aÅ„cucha z nazwÄ… submodelu, albo -1 gdy anonimowy public: // chwilowo - TAnimType b_Anim; + TAnimType b_Anim{ at_None }; private: - int iFlags; // flagi informacyjne: + int iFlags{ 0x0200 }; // bit 9=1: submodel zostaÅ‚ utworzony a nie ustawiony na wczytany plik + // flagi informacyjne: // bit 0: =1 faza rysowania zależy od wymiennej tekstury 0 // bit 1: =1 faza rysowania zależy od wymiennej tekstury 1 // bit 2: =1 faza rysowania zależy od wymiennej tekstury 2 @@ -84,63 +82,62 @@ private: // bit 15: =1 wymagane przechowanie macierzy (transform niejedynkowy) union { // transform, nie każdy submodel musi mieć - float4x4 *fMatrix; // pojedyncza precyzja wystarcza + float4x4 *fMatrix = nullptr; // pojedyncza precyzja wystarcza int iMatrix; // w pliku binarnym jest numer matrycy }; - int iNumVerts; // ilość wierzchoÅ‚ków (1 dla FreeSpotLight) + int iNumVerts{ -1 }; // ilość wierzchoÅ‚ków (1 dla FreeSpotLight) int tVboPtr; // poczÄ…tek na liÅ›cie wierzchoÅ‚ków albo indeksów - int iTexture; // numer nazwy tekstury, -1 wymienna, 0 brak - float fVisible; // próg jasnoÅ›ci Å›wiatÅ‚a do załączenia submodelu - float fLight; // próg jasnoÅ›ci Å›wiatÅ‚a do zadziaÅ‚ania selfillum + int iTexture{ 0 }; // numer nazwy tekstury, -1 wymienna, 0 brak + float fVisible{ 0.0f }; // próg jasnoÅ›ci Å›wiatÅ‚a do załączenia submodelu + float fLight{ -1.0f }; // próg jasnoÅ›ci Å›wiatÅ‚a do zadziaÅ‚ania selfillum glm::vec4 - f4Ambient, - f4Diffuse, - f4Specular, - f4Emision; - float fWireSize; // nie używane, ale wczytywane - float fSquareMaxDist; - float fSquareMinDist; + f4Ambient{ 1.0f,1.0f,1.0f,1.0f }, + f4Diffuse{ 1.0f,1.0f,1.0f,1.0f }, + f4Specular{ 0.0f,0.0f,0.0f,1.0f }, + f4Emision{ 1.0f,1.0f,1.0f,1.0f }; + float fWireSize{ 0.0f }; // nie używane, ale wczytywane + float fSquareMaxDist{ 10000.0f * 10000.0f }; + float fSquareMinDist{ 0.0f }; // McZapkie-050702: parametry dla swiatla: - float fNearAttenStart; - float fNearAttenEnd; - bool bUseNearAtten; // te 3 zmienne okreslaja rysowanie aureoli wokol zrodla swiatla - int iFarAttenDecay; // ta zmienna okresla typ zaniku natezenia swiatla (0:brak, 1,2: potega 1/R) - float fFarDecayRadius; // normalizacja j.w. - float fCosFalloffAngle; // cosinus kÄ…ta stożka pod którym widać Å›wiatÅ‚o - float fCosHotspotAngle; // cosinus kÄ…ta stożka pod którym widać aureolÄ™ i zwiÄ™kszone natężenie Å›wiatÅ‚a - float fCosViewAngle; // cos kata pod jakim sie teraz patrzy + float fNearAttenStart{ 40.0f }; + float fNearAttenEnd{ 80.0f }; + bool bUseNearAtten{ false }; // te 3 zmienne okreslaja rysowanie aureoli wokol zrodla swiatla + int iFarAttenDecay{ 0 }; // ta zmienna okresla typ zaniku natezenia swiatla (0:brak, 1,2: potega 1/R) + float fFarDecayRadius{ 100.0f }; // normalizacja j.w. + float fCosFalloffAngle{ 0.5f }; // cosinus kÄ…ta stożka pod którym widać Å›wiatÅ‚o + float fCosHotspotAngle{ 0.3f }; // cosinus kÄ…ta stożka pod którym widać aureolÄ™ i zwiÄ™kszone natężenie Å›wiatÅ‚a + float fCosViewAngle{ 0.0f }; // cos kata pod jakim sie teraz patrzy - TSubModel *Next; - TSubModel *Child; + TSubModel *Next{ nullptr }; + TSubModel *Child{ nullptr }; /* intptr_t iVboPtr; */ - geometry_handle m_geometry; // geometry of the submodel - texture_handle TextureID; // numer tekstury, -1 wymienna, 0 brak - bool bWire; // nie używane, ale wczytywane + geometry_handle m_geometry{ NULL, NULL }; // geometry of the submodel + texture_handle TextureID{ NULL }; // numer tekstury, -1 wymienna, 0 brak + bool bWire{ false }; // nie używane, ale wczytywane /* GLuint uiDisplayList; // roboczy numer listy wyÅ›wietlania */ - float Opacity; // nie używane, ale wczytywane //m7todo: wywalić to - float f_Angle; - float3 v_RotateAxis; - float3 v_Angles; + float Opacity{ 1.0f }; + float f_Angle{ 0.0f }; + float3 v_RotateAxis{ 0.0f, 0.0f, 0.0f }; + float3 v_Angles { 0.0f, 0.0f, 0.0f }; public: // chwilowo - float3 v_TransVector; + float3 v_TransVector{ 0.0f, 0.0f, 0.0f }; /* basic_vertex *Vertices; // roboczy wskaźnik - wczytanie T3D do VBO */ vertex_array Vertices; - size_t iAnimOwner; // roboczy numer egzemplarza, który ustawiÅ‚ animacjÄ™ - TAnimType b_aAnim; // kody animacji oddzielnie, bo zerowane + size_t iAnimOwner{ NULL }; // roboczy numer egzemplarza, który ustawiÅ‚ animacjÄ™ + TAnimType b_aAnim{ at_None }; // kody animacji oddzielnie, bo zerowane public: - float4x4 *mAnimMatrix; // macierz do animacji kwaternionowych (należy do AnimContainer) + float4x4 *mAnimMatrix{ nullptr }; // macierz do animacji kwaternionowych (należy do AnimContainer) public: - TSubModel ** - smLetter; // wskaźnik na tablicÄ™ submdeli do generoania tekstu (docelowo zapisać do E3D) - TSubModel *Parent; // nadrzÄ™dny, np. do wymnażania macierzy - int iVisible; // roboczy stan widocznoÅ›ci + TSubModel **smLetter{ nullptr }; // wskaźnik na tablicÄ™ submdeli do generoania tekstu (docelowo zapisać do E3D) + TSubModel *Parent{ nullptr }; // nadrzÄ™dny, np. do wymnażania macierzy + int iVisible{ 1 }; // roboczy stan widocznoÅ›ci std::string pTexture; // robocza nazwa tekstury do zapisania w pliku binarnym std::string pName; // robocza nazwa private: @@ -154,9 +151,7 @@ public: static double fSquareDist; static TModel3d *pRoot; static std::string *pasText; // tekst dla wyÅ›wietlacza (!!!! do przemyÅ›lenia) - TSubModel(); ~TSubModel(); - void FirstInit(); int Load(cParser &Parser, TModel3d *Model, /*int Pos,*/ bool dynamic); void ChildAdd(TSubModel *SubModel); void NextAdd(TSubModel *SubModel); @@ -176,10 +171,8 @@ public: TSubModel * GetFromName(char const *search, bool i = true); inline float4x4 * GetMatrix() { return fMatrix; }; inline void Hide() { iVisible = 0; }; -/* - void RaArrayFill(basic_vertex *Vert); -*/ - void create_geometry( geometrybank_handle const &Bank ); + + void create_geometry( std::size_t &Dataoffset, geometrybank_handle const &Bank ); int FlagsCheck(); void WillBeAnimated() { @@ -187,9 +180,6 @@ public: iFlags |= 0x4000; }; void InitialRotate(bool doit); -#ifdef EU07_USE_OLD_DRAW_CODE - void DisplayLists(); -#endif void BinInit(TSubModel *s, float4x4 *m, std::vector *t, std::vector *n, bool dynamic); void ReplacableSet(texture_handle const *r, int a) { @@ -219,11 +209,13 @@ public: void AdjustDist(); void deserialize(std::istream&); - void TSubModel::serialize(std::ostream&, + void serialize(std::ostream&, std::vector&, std::vector&, std::vector&, std::vector&); + void serialize_geometry( std::ostream &Output ); + }; class TModel3d : public CMesh @@ -259,11 +251,7 @@ public: std::string NameGet() { return m_filename; }; int TerrainCount(); TSubModel * TerrainSquare(int n); -#ifdef EU07_USE_OLD_RENDERCODE - void TerrainRenderVBO(int n); -#endif void deserialize(std::istream &s, size_t size, bool dynamic); }; //--------------------------------------------------------------------------- -#endif diff --git a/PyInt.cpp b/PyInt.cpp index 84fd7847..c55e371f 100644 --- a/PyInt.cpp +++ b/PyInt.cpp @@ -292,7 +292,7 @@ void TPythonScreenRenderer::updateTexture() WriteLog(buff); #endif // _PY_INT_MORE_LOG glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - glBindTexture(GL_TEXTURE_2D, _textureId); + GfxRenderer.Bind(_textureId); // setup texture parameters if( GLEW_VERSION_1_4 ) { diff --git a/World.cpp b/World.cpp index 1723253d..f6e53a81 100644 --- a/World.cpp +++ b/World.cpp @@ -1651,15 +1651,13 @@ TWorld::Update_UI() { case( GLFW_KEY_F8 ) : { // gfx renderer data uitextline1 = - "Draw range x " + to_string( Global::fDistanceFactor, 1 ) - + "; FPS: " + to_string( Timer::GetFPS(), 2 ); + "FoV: " + to_string( Global::FieldOfView / Global::ZoomFactor, 1 ) + + ", Draw range x " + to_string( Global::fDistanceFactor, 1 ) + + "; sectors: " + std::to_string( GfxRenderer.m_drawcount ) + + ", FPS: " + to_string( Timer::GetFPS(), 2 ); if( Global::iSlowMotion ) { uitextline1 += " (slowmotion " + to_string( Global::iSlowMotion ) + ")"; } - uitextline1 += - ", sectors: " + std::to_string( GfxRenderer.m_drawcount ) - + "/" + std::to_string( Global::iSegmentsRendered ) - + "; FoV: " + to_string( Global::FieldOfView / Global::ZoomFactor, 1 ); uitextline2 = std::string( "Rendering mode: " ) diff --git a/openglgeometrybank.cpp b/openglgeometrybank.cpp index 2f18a7c5..5c9fe8b0 100644 --- a/openglgeometrybank.cpp +++ b/openglgeometrybank.cpp @@ -15,7 +15,7 @@ http://mozilla.org/MPL/2.0/. #include "globals.h" void -basic_vertex::serialize( std::ostream &s ) { +basic_vertex::serialize( std::ostream &s ) const { sn_utils::ls_float32( s, position.x ); sn_utils::ls_float32( s, position.y ); diff --git a/openglgeometrybank.h b/openglgeometrybank.h index a6868a2f..0b174566 100644 --- a/openglgeometrybank.h +++ b/openglgeometrybank.h @@ -27,7 +27,7 @@ struct basic_vertex { basic_vertex( glm::vec3 const&Position, glm::vec3 const &Normal, glm::vec2 const &Texture ) : position( Position ), normal( Normal ), texture( Texture ) {} - void serialize( std::ostream& ); + void serialize( std::ostream& ) const; void deserialize( std::istream& ); }; @@ -111,10 +111,12 @@ protected: struct geometry_chunk { unsigned int type; // kind of geometry used by the chunk vertex_array vertices; // geometry data - + // NOTE: constructor doesn't copy provided vertex data, but moves it geometry_chunk( vertex_array &Vertices, unsigned int const Type ) : - vertices( Vertices ), type( Type ) - {} + type( Type ) + { + vertices.swap( Vertices ); + } }; typedef std::vector geometrychunk_sequence; diff --git a/renderer.cpp b/renderer.cpp index f7970509..27167c1e 100644 --- a/renderer.cpp +++ b/renderer.cpp @@ -368,7 +368,14 @@ opengl_renderer::Render( TGround *Ground ) { ++TGroundRect::iFrameNumber; // zwiÄ™szenie licznika ramek (do usuwniania nadanimacji) Update_Lights( Ground->m_lights ); -/* + + m_drawqueue.clear(); + + // rednerowanie globalnych (nie za czÄ™sto?) + for( TGroundNode *node = Ground->srGlobal.nRenderHidden; node; node = node->nNext3 ) { + node->RenderHidden(); + } + glm::vec3 const cameraposition( Global::pCameraPosition.x, Global::pCameraPosition.y, Global::pCameraPosition.z ); int const camerax = static_cast( std::floor( cameraposition.x / 1000.0f ) + iNumRects / 2 ); int const cameraz = static_cast( std::floor( cameraposition.z / 1000.0f ) + iNumRects / 2 ); @@ -380,89 +387,40 @@ opengl_renderer::Render( TGround *Ground ) { for( int row = originz; row <= originz + segmentcount; ++row ) { auto *cell = &Ground->Rects[ column ][ row ]; + + for( int subcellcolumn = 0; subcellcolumn < iNumSubRects; ++subcellcolumn ) { + for( int subcellrow = 0; subcellrow < iNumSubRects; ++subcellrow ) { + auto subcell = cell->FastGetSubRect( subcellcolumn, subcellrow ); + if( subcell == nullptr ) { continue; } + // renderowanie obiektów aktywnych a niewidocznych + for( auto node = subcell->nRenderHidden; node; node = node->nNext3 ) { + node->RenderHidden(); + } + // jeszcze dźwiÄ™ki pojazdów by siÄ™ przydaÅ‚y, również niewidocznych + subcell->RenderSounds(); + } + } + if( m_camera.visible( cell->m_area ) ) { Render( cell ); } } } -*/ - Ground->CameraDirection.x = std::sin( Global::pCameraRotation ); // wektor kierunkowy - Ground->CameraDirection.z = std::cos( Global::pCameraRotation ); - TGroundNode *node; - // rednerowanie globalnych (nie za czÄ™sto?) - for( node = Ground->srGlobal.nRenderHidden; node; node = node->nNext3 ) { - node->RenderHidden(); + + // draw queue was filled while rendering content of ground cells. now sort the nodes based on their distance to viewer... + std::sort( + std::begin( m_drawqueue ), + std::end( m_drawqueue ), + []( distancesubcell_pair const &Left, distancesubcell_pair const &Right ) { + return ( Left.first ) < ( Right.first ); } ); + // ...then render the opaque content of the visible subcells. + for( auto subcellpair : m_drawqueue ) { + Render( subcellpair.second ); } - // renderowanie czoÅ‚gowe dla obiektów aktywnych a niewidocznych - int n = 2 * iNumSubRects; //(2*==2km) promieÅ„ wyÅ›wietlanej mapy w sektorach - int c = Ground->GetColFromX( Global::pCameraPosition.x ); - int r = Ground->GetRowFromZ( Global::pCameraPosition.z ); - TSubRect *tmp; - int i, j, k; - for( j = r - n; j <= r + n; ++j ) { - for( i = c - n; i <= c + n; ++i ) { - if( ( tmp = Ground->FastGetSubRect( i, j ) ) != nullptr ) { - // oznaczanie aktywnych sektorów - tmp->LoadNodes(); - - for( node = tmp->nRenderHidden; node; node = node->nNext3 ) { - node->RenderHidden(); - } - // jeszcze dźwiÄ™ki pojazdów by siÄ™ przydaÅ‚y, również niewidocznych - tmp->RenderSounds(); - } - } - } - // renderowanie progresywne - zależne od FPS oraz kierunku patrzenia - // pre-calculate camera view span - double const fieldofviewcosine = - std::cos( - std::max( - // vertical... - Global::FieldOfView / Global::ZoomFactor, - // ...or horizontal, whichever is bigger - Global::FieldOfView / Global::ZoomFactor - * std::max( 1.0f, (float)Global::ScreenWidth ) / std::max( 1.0f, (float)Global::ScreenHeight ) ) ); - - m_drawqueue.clear(); - - Math3D::vector3 direction; - for( k = 0; k < Global::iSegmentsRendered; ++k ) // sektory w kolejnoÅ›ci odlegÅ‚oÅ›ci - { // przerobione na użycie SectorOrder - i = SectorOrder[ k ].x; // na starcie oba >=0 - j = SectorOrder[ k ].y; - do { - // pierwszy przebieg: j<=0, i>=0; drugi: j>=0, i<=0; trzeci: j<=0, i<=0 czwarty: j>=0, i>=0; - if( j <= 0 ) - i = -i; - j = -j; // i oraz j musi być zmienione wczeÅ›niej, żeby continue dziaÅ‚aÅ‚o - direction = Math3D::vector3( i, 0, j ); // wektor od kamery do danego sektora - if( Math3D::LengthSquared3( direction ) > 5 ) // te blisko sÄ… zawsze wyÅ›wietlane - { - direction = Math3D::SafeNormalize( direction ); // normalizacja - if( Ground->CameraDirection.x * direction.x + Ground->CameraDirection.z * direction.z < 0.5 ) - continue; // pomijanie sektorów poza kÄ…tem patrzenia - } - // kwadrat kilometrowy nie zawsze, bo szkoda FPS - Render( &Ground->Rects[ ( i + c ) / iNumSubRects ][ ( j + r ) / iNumSubRects ] ); - - if( ( tmp = Ground->FastGetSubRect( i + c, j + r ) ) != nullptr ) { - if( tmp->iNodeCount ) { - // o ile sÄ… jakieÅ› obiekty, bo po co puste sektory przelatywać - m_drawqueue.emplace_back( tmp ); - } - } - } while( ( i < 0 ) || ( j < 0 ) ); // sÄ… 4 przypadki, oprócz i=j=0 - } - - for( auto subcell : m_drawqueue ) { - Render( subcell ); - } - // regular render takes care of all solid geometry present in the scene, thus we can launch alpha parts render here + // now hand the control over to the renderer of translucent parts, it'll do the rest return Render_Alpha( Ground ); } -// TODO: unify ground render code, until then old version is in place bool opengl_renderer::Render( TGroundRect *Groundcell ) { @@ -484,6 +442,19 @@ opengl_renderer::Render( TGroundRect *Groundcell ) { } Groundcell->iLastDisplay = Groundcell->iFrameNumber; // drugi raz nie potrzeba result = true; + + // add the subcells of the cell to the draw queue + if( Groundcell->pSubRects != nullptr ) { + for( std::size_t subcellindex = 0; subcellindex < iNumSubRects * iNumSubRects; ++subcellindex ) { + auto subcell = Groundcell->pSubRects + subcellindex; + if( subcell->iNodeCount ) { + // o ile sÄ… jakieÅ› obiekty, bo po co puste sektory przelatywać + m_drawqueue.emplace_back( + ( Global::pCameraPosition - glm::dvec3( subcell->m_area.center ) ).LengthSquared(), + subcell ); + } + } + } } return result; } @@ -491,6 +462,9 @@ opengl_renderer::Render( TGroundRect *Groundcell ) { bool opengl_renderer::Render( TSubRect *Groundsubcell ) { + // oznaczanie aktywnych sektorów + Groundsubcell->LoadNodes(); + Groundsubcell->RaAnimate(); // przeliczenia animacji torów w sektorze TGroundNode *node; @@ -906,23 +880,23 @@ opengl_renderer::Render_Alpha( TGround *Ground ) { TGroundNode *node; TSubRect *tmp; // Ra: renderowanie progresywne - zależne od FPS oraz kierunku patrzenia - for( auto subcell = std::rbegin( m_drawqueue ); subcell != std::rend( m_drawqueue ); ++subcell ) { + for( auto subcellpair = std::rbegin( m_drawqueue ); subcellpair != std::rend( m_drawqueue ); ++subcellpair ) { // przezroczyste trójkÄ…ty w oddzielnym cyklu przed modelami - tmp = *subcell; + tmp = subcellpair->second; for( node = tmp->nRenderRectAlpha; node; node = node->nNext3 ) { Render_Alpha( node ); } } - for( auto subcell = std::rbegin( m_drawqueue ); subcell != std::rend( m_drawqueue ); ++subcell ) + for( auto subcellpair = std::rbegin( m_drawqueue ); subcellpair != std::rend( m_drawqueue ); ++subcellpair ) { // renderowanie przezroczystych modeli oraz pojazdów - Render_Alpha( *subcell ); + Render_Alpha( subcellpair->second ); } ::glDisable( GL_LIGHTING ); // linie nie powinny Å›wiecić - for( auto subcell = std::rbegin( m_drawqueue ); subcell != std::rend( m_drawqueue ); ++subcell ) { + for( auto subcellpair = std::rbegin( m_drawqueue ); subcellpair != std::rend( m_drawqueue ); ++subcellpair ) { // druty na koÅ„cu, żeby siÄ™ nie robiÅ‚y biaÅ‚e plamy na tle lasu - tmp = *subcell; + tmp = subcellpair->second; for( node = tmp->nRenderWires; node; node = node->nNext3 ) { Render_Alpha( node ); } @@ -947,25 +921,9 @@ opengl_renderer::Render_Alpha( TSubRect *Groundsubcell ) { return true; } -// NOTE: legacy render system switch -#define _PROBLEND - bool opengl_renderer::Render_Alpha( TGroundNode *Node ) { - // SPOSOB NA POZBYCIE SIE RAMKI DOOKOLA TEXTURY ALPHA DLA OBIEKTOW ZAGNIEZDZONYCH W SCN JAKO - // NODE - - // W GROUND.H dajemy do klasy TGroundNode zmienna bool PROBLEND to samo robimy w klasie TGround - // nastepnie podczas wczytywania textury dla TRIANGLES w TGround::AddGroundNode - // sprawdzamy czy w nazwie jest @ i wg tego - // ustawiamy PROBLEND na true dla wlasnie wczytywanego trojkata (kazdy trojkat jest osobnym - // nodem) - // nastepnie podczas renderowania w bool TGroundNode::RenderAlpha() - // na poczatku ustawiamy standardowe GL_GREATER = 0.04 - // pozniej sprawdzamy czy jest wlaczony PROBLEND dla aktualnie renderowanego noda TRIANGLE, - // wlasciwie dla kazdego node'a - // i jezeli tak to odpowiedni GL_GREATER w przeciwnym wypadku standardowy 0.04 double const distancesquared = SquareMagnitude( ( Node->pCenter - Global::pCameraPosition ) / Global::ZoomFactor ); if( ( distancesquared > ( Node->fSquareRadius * Global::fDistanceFactor ) ) || ( distancesquared < ( Node->fSquareMinRadius / Global::fDistanceFactor ) ) ) { @@ -1029,14 +987,15 @@ opengl_renderer::Render_Alpha( TGroundNode *Node ) { return false; } // setup - // w zaleznosci od koloru swiatla + auto const linewidth = clamp( 100.0 * Node->fLineThickness / ( distancesquared + 1.0 ), 1.0, 10.0 ); ::glColor4fv( glm::value_ptr( glm::vec4( - Node->Diffuse * glm::make_vec3( Global::DayLight.ambient ), - std::min( - 1.0, - 1000.0 * Node->fLineThickness / ( distancesquared + 1.0 ) ) ) ) ); + Node->Diffuse * glm::make_vec3( Global::DayLight.ambient ), // w zaleznosci od koloru swiatla + std::min( 1.0, linewidth ) ) ) ); + if( linewidth > 1.0 ) { + ::glLineWidth( static_cast(linewidth) ); + } GfxRenderer.Bind( 0 ); @@ -1048,6 +1007,10 @@ opengl_renderer::Render_Alpha( TGroundNode *Node ) { m_geometry.draw( Node->m_geometry ); // post-render cleanup + if( linewidth > 1.0 ) { + ::glLineWidth( 1.0f ); + } + ::glPopMatrix(); return true; @@ -1059,13 +1022,6 @@ opengl_renderer::Render_Alpha( TGroundNode *Node ) { return false; } // setup -#ifdef _PROBLEND - if( ( Node->PROBLEND ) ) // sprawdza, czy w nazwie nie ma @ //Q: 13122011 - Szociu: 27012012 - { - ::glDisable( GL_BLEND ); - ::glAlphaFunc( GL_GREATER, 0.50f ); // im mniejsza wartość, tym wiÄ™ksza ramka, domyÅ›lnie 0.1f - }; -#endif ::glColor3fv( glm::value_ptr( Node->Diffuse ) ); Bind( Node->TextureID ); @@ -1080,13 +1036,6 @@ opengl_renderer::Render_Alpha( TGroundNode *Node ) { // post-render cleanup ::glPopMatrix(); -#ifdef _PROBLEND - if( ( Node->PROBLEND ) ) // sprawdza, czy w nazwie nie ma @ //Q: 13122011 - Szociu: 27012012 - { - ::glEnable( GL_BLEND ); - ::glAlphaFunc( GL_GREATER, 0.04f ); - } -#endif return true; } diff --git a/renderer.h b/renderer.h index a1420e25..43332c5b 100644 --- a/renderer.h +++ b/renderer.h @@ -182,6 +182,8 @@ private: typedef std::vector opengllight_array; + typedef std::pair< double, TSubRect * > distancesubcell_pair; + // methods bool Init_caps(); @@ -226,7 +228,7 @@ private: texture_handle m_moontexture { -1 }; geometry_handle m_billboardgeometry { 0, 0 }; GLUquadricObj *m_quadric; // helper object for drawing debug mode scene elements - std::vector< TSubRect* > m_drawqueue; // list of subcells to be drawn in current render pass + std::vector m_drawqueue; // list of subcells to be drawn in current render pass }; diff --git a/version.h b/version.h index b34c61ee..252fa070 100644 --- a/version.h +++ b/version.h @@ -1,5 +1,5 @@ #pragma once #define VERSION_MAJOR 17 -#define VERSION_MINOR 613 +#define VERSION_MINOR 617 #define VERSION_REVISION 0