16
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-07-22 09:19:18 +02:00

early implementation of geometry bank, partial replacement of math classes with glm

This commit is contained in:
tmj-fstate
2017-05-30 19:21:40 +02:00
parent d2a9f7080e
commit f48b61c650
11 changed files with 592 additions and 277 deletions

View File

@@ -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]); 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) inline float4x4 &float4x4::Rotation(double angle, float3 axis)
{ {
double c = cos(angle); double c = cos(angle);

View File

@@ -4348,7 +4348,7 @@ void TGround::TerrainWrite()
// int ver=0; //całkowita ilość wierzchołków // int ver=0; //całkowita ilość wierzchołków
int i, j, k; // indeksy w pętli int i, j, k; // indeksy w pętli
TGroundNode *Current; 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 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 (i = 0; i < iNumRects; ++i) // pętla po wszystkich kwadratach kilometrowych
for (j = 0; j < iNumRects; ++j) for (j = 0; j < iNumRects; ++j)
@@ -4395,14 +4395,14 @@ void TGround::TerrainWrite()
Current->iVboPtr = -1; // bo to było tymczasowo używane Current->iVboPtr = -1; // bo to było tymczasowo używane
for (k = 0; k < Current->iNumVerts; ++k) for (k = 0; k < Current->iNumVerts; ++k)
{ // przepisanie współrzędnych { // przepisanie współrzędnych
ver[k].Point.x = Current->Vertices[k].Point.x; ver[k].position.x = Current->Vertices[k].Point.x;
ver[k].Point.y = Current->Vertices[k].Point.y; ver[k].position.y = Current->Vertices[k].Point.y;
ver[k].Point.z = Current->Vertices[k].Point.z; ver[k].position.z = Current->Vertices[k].Point.z;
ver[k].Normal.x = Current->Vertices[k].Normal.x; ver[k].normal.x = Current->Vertices[k].Normal.x;
ver[k].Normal.y = Current->Vertices[k].Normal.y; ver[k].normal.y = Current->Vertices[k].Normal.y;
ver[k].Normal.z = Current->Vertices[k].Normal.z; ver[k].normal.z = Current->Vertices[k].Normal.z;
ver[k].tu = Current->Vertices[k].tu; ver[k].texture.s = Current->Vertices[k].tu;
ver[k].tv = Current->Vertices[k].tv; ver[k].texture.t = Current->Vertices[k].tv;
} }
break; break;
case GL_TRIANGLE_STRIP: // na razie nie, bo trzeba przerabiać na pojedyncze case GL_TRIANGLE_STRIP: // na razie nie, bo trzeba przerabiać na pojedyncze

View File

@@ -113,11 +113,6 @@ TSubModel::~TSubModel()
delete fMatrix; // własny transform trzeba usunąć (zawsze jeden) delete fMatrix; // własny transform trzeba usunąć (zawsze jeden)
delete[] Vertices; delete[] Vertices;
} }
/*
else
{//wczytano z pliku binarnego (nie jest właścicielem tablic)
}
*/
delete[] smLetter; // używany tylko roboczo dla TP_TEXT, do przyspieszenia delete[] smLetter; // używany tylko roboczo dla TP_TEXT, do przyspieszenia
// wyświetlania // wyświetlania
}; };
@@ -141,23 +136,23 @@ void TSubModel::NameSet(const char *n)
// int TSubModel::SeekFaceNormal(DWORD *Masks, int f,DWORD dwMask,vector3 // int TSubModel::SeekFaceNormal(DWORD *Masks, int f,DWORD dwMask,vector3
// *pt,GLVERTEX // *pt,GLVERTEX
// *Vertices) // *Vertices)
int TSubModel::SeekFaceNormal(unsigned int *Masks, int f, unsigned int dwMask, float3 *pt, int TSubModel::SeekFaceNormal(unsigned int *Masks, int f, unsigned int dwMask, glm::vec3 *pt,
float8 *Vertices) basic_vertex *Vertices)
{ // szukanie punktu stycznego { // szukanie punktu stycznego
// do (pt), zwraca numer // do (pt), zwraca numer
// wierzchołka, a nie trójkąta // wierzchołka, a nie trójkąta
int iNumFaces = iNumVerts / 3; // bo maska powierzchni jest jedna na trójkąt int iNumFaces = iNumVerts / 3; // bo maska powierzchni jest jedna na trójkąt
// GLVERTEX *p; //roboczy wskaźnik // 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) 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 if (Masks[i] & dwMask) // jeśli wspólna maska powierzchni
{ {
p = Vertices + 3 * i; p = Vertices + 3 * i;
if (p->Point == *pt) if (p->position == *pt)
return 3 * i; return 3 * i;
if ((++p)->Point == *pt) if ((++p)->position == *pt)
return 3 * i + 1; return 3 * i + 1;
if ((++p)->Point == *pt) if ((++p)->position == *pt)
return 3 * i + 2; return 3 * i + 2;
} }
return -1; // nie znaleziono stycznego wierzchołka 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]; // Vertices=new GLVERTEX[iNumVerts];
if (iNumVerts) if (iNumVerts)
{ {
Vertices = new float8[iNumVerts]; Vertices = new basic_vertex[iNumVerts];
iNumFaces = iNumVerts / 3; iNumFaces = iNumVerts / 3;
sg = new unsigned int[iNumFaces]; // maski powierzchni: 0 oznacza brak sg = new unsigned int[iNumFaces]; // maski powierzchni: 0 oznacza brak
// użredniania wektorów normalnych // użredniania wektorów normalnych
@@ -467,21 +462,28 @@ int TSubModel::Load(cParser &parser, TModel3d *Model, int Pos, bool dynamic)
// wektorów normalnych // wektorów normalnych
} }
parser.getTokens(3, false); 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) if (maska == -1)
{ // jeśli wektory normalne podane jawnie { // jeśli wektory normalne podane jawnie
parser.getTokens(3, false); parser.getTokens(3, false);
parser >> Vertices[i].Normal.x >> Vertices[i].Normal.y >> parser
Vertices[i].Normal.z; >> Vertices[i].normal.x
>> Vertices[i].normal.y
>> Vertices[i].normal.z;
wsp[i] = i; // wektory normalne "są już policzone" wsp[i] = i; // wektory normalne "są już policzone"
} }
parser.getTokens(2, false); 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 (i % 3 == 2) // jeżeli wczytano 3 punkty
{ {
if (Vertices[i].Point == Vertices[i - 1].Point || if (Vertices[i].position == Vertices[i - 1].position
Vertices[i - 1].Point == Vertices[i - 2].Point || || Vertices[i - 1].position == Vertices[i - 2].position
Vertices[i - 2].Point == Vertices[i].Point) || Vertices[i - 2].position == Vertices[i].position)
{ // jeżeli punkty się nakładają na siebie { // jeżeli punkty się nakładają na siebie
--iNumFaces; // o jeden trójkąt mniej --iNumFaces; // o jeden trójkąt mniej
iNumVerts -= 3; // czyli o 3 wierzchołki 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 if (i > 0) // jeśli pierwszy trójkąt będzie zdegenerowany, to
// zostanie usunięty i nie ma co sprawdzać // zostanie usunięty i nie ma co sprawdzać
if (((Vertices[i].Point - Vertices[i - 1].Point).Length() > 1000.0) || if ((glm::length(Vertices[i].position - Vertices[i - 1].position) > 1000.0)
((Vertices[i - 1].Point - Vertices[i - 2].Point).Length() > || (glm::length(Vertices[i - 1].position - Vertices[i - 2].position) > 1000.0)
1000.0) || || (glm::length(Vertices[i - 2].position - Vertices[i].position) > 1000.0))
((Vertices[i - 2].Point - Vertices[i].Point).Length() > 1000.0))
{ // jeżeli są dalej niż 2km od siebie //Ra 15-01: { // jeżeli są dalej niż 2km od siebie //Ra 15-01:
// obiekt wstawiany nie powinien być większy niż // obiekt wstawiany nie powinien być większy niż
// 300m (trójkąty terenu w E3D mogą mieć 1.5km) // 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 int i; // indeks dla trójkątów
float3 *n = new float3[iNumFaces]; // tablica wektorów normalnych 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 for (i = 0; i < iNumFaces; ++i) // pętla po trójkątach - będzie
// szybciej, jak wstępnie przeliczymy // szybciej, jak wstępnie przeliczymy
// normalne trójkątów // normalne trójkątów
n[i] = SafeNormalize( n[i] = glm::normalize(
CrossProduct(Vertices[i * 3].Point - Vertices[i * 3 + 1].Point, glm::cross(
Vertices[i * 3].Point - Vertices[i * 3 + 2].Point)); 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 v; // indeks dla wierzchołków
int f; // numer trójkąta stycznego int f; // numer trójkąta stycznego
float3 norm; // roboczy wektor normalny glm::vec3 norm; // roboczy wektor normalny
for (v = 0; v < iNumVerts; v++) for (v = 0; v < iNumVerts; ++v)
{ // pętla po wierzchołkach trójkątów { // pętla po wierzchołkach trójkątów
if (wsp[v] >= 0) // jeśli już był liczony wektor normalny z użyciem if (wsp[v] >= 0) // jeśli już był liczony wektor normalny z użyciem
// tego wierzchołka // tego wierzchołka
Vertices[v].Normal = Vertices[v].normal =
Vertices[wsp[v]].Normal; // to wystarczy skopiować policzony wcześniej Vertices[wsp[v]].normal; // to wystarczy skopiować policzony wcześniej
else else
{ // inaczej musimy dopiero policzyć { // inaczej musimy dopiero policzyć
i = v / 3; // numer trójkąta 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 f = v; // zaczynamy dodawanie wektorów normalnych od własnego
while (f >= 0) while (f >= 0)
{ // sumowanie z wektorem normalnym sąsiada (włącznie { // 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 wsp[f] = v; // informacja, że w tym wierzchołku jest już policzony
// wektor normalny // wektor normalny
norm += n[f / 3]; 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 Vertices); // i szukanie od kolejnego trójkąta
} }
// Ra 15-01: należało by jeszcze uwzględnić skalowanie wprowadzane // Ra 15-01: należało by jeszcze uwzględnić skalowanie wprowadzane
// przez transformy, aby normalne po przeskalowaniu były jednostkowe // przez transformy, aby normalne po przeskalowaniu były jednostkowe
Vertices[v].Normal = Vertices[v].normal =
SafeNormalize(norm); // przepisanie do wierzchołka trójkąta glm::normalize(norm); // przepisanie do wierzchołka trójkąta
} }
} }
delete[] wsp; delete[] wsp;
@@ -561,21 +563,24 @@ int TSubModel::Load(cParser &parser, TModel3d *Model, int Pos, bool dynamic)
parser.getTokens(2, false); parser.getTokens(2, false);
parser >> discard >> iNumVerts; parser >> discard >> iNumVerts;
// Vertices=new GLVERTEX[iNumVerts]; // Vertices=new GLVERTEX[iNumVerts];
Vertices = new float8[iNumVerts]; Vertices = new basic_vertex[iNumVerts];
int i, j; int i, j;
for (i = 0; i < iNumVerts; i++) for (i = 0; i < iNumVerts; ++i)
{ {
if (i % 3 == 0) if (i % 3 == 0)
{ {
parser.ignoreToken(); // maska powierzchni trójkąta parser.ignoreToken(); // maska powierzchni trójkąta
} }
parser.getTokens(5, false); parser.getTokens(5, false);
parser >> Vertices[i].Point.x >> Vertices[i].Point.y >> Vertices[i].Point.z >> parser
j // zakodowany kolor >> Vertices[i].position.x
>> Vertices[i].position.y
>> Vertices[i].position.z
>> j // zakodowany kolor
>> discard; >> discard;
Vertices[i].Normal.x = ((j) & 0xFF) / 255.0; // R Vertices[i].normal.x = ((j) & 0xFF) / 255.0; // R
Vertices[i].Normal.y = ((j >> 8) & 0xFF) / 255.0; // G Vertices[i].normal.y = ((j >> 8) & 0xFF) / 255.0; // G
Vertices[i].Normal.z = ((j >> 16) & 0xFF) / 255.0; // B Vertices[i].normal.z = ((j >> 16) & 0xFF) / 255.0; // B
} }
} }
// Visible=true; //się potem wyłączy w razie potrzeby // 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(); s = new TSubModel();
m->AddTo(this, s); m->AddTo(this, s);
} }
// s->asTexture=AnsiString(TTexturesManager::GetName(tex).c_str());
s->TextureNameSet(GfxRenderer.Texture(tex).name.c_str()); s->TextureNameSet(GfxRenderer.Texture(tex).name.c_str());
s->TextureID = tex; s->TextureID = tex;
s->eType = GL_TRIANGLES; s->eType = GL_TRIANGLES;
// iAnimOwner=0; //roboczy wskaźnik na wierzchołek
} }
if (s->iNumVerts < 0) if (s->iNumVerts < 0)
s->iNumVerts = tri; // bo na początku jest -1, czyli że nie wiadomo 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 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 { // zwraca wskaźnik do wypełnienia tabeli wierzchołków, używane
// przy tworzeniu E3D terenu // przy tworzeniu E3D terenu
TSubModel *s = this; 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 return NULL; // coś nie tak poszło
if (!s->Vertices) if (!s->Vertices)
{ // utworznie tabeli trójkątów { // utworznie tabeli trójkątów
s->Vertices = new float8[s->iNumVerts]; s->Vertices = new basic_vertex[s->iNumVerts];
// iVboPtr=pos; //pozycja submodelu w tabeli wierzchołków
// pos+=iNumVerts; //rezerwacja miejsca w tabeli
s->iVboPtr = iInstance; // pozycja submodelu w tabeli wierzchołków s->iVboPtr = iInstance; // pozycja submodelu w tabeli wierzchołków
iInstance += s->iNumVerts; // pozycja dla następnego iInstance += s->iNumVerts; // pozycja dla następnego
} }
@@ -648,7 +649,6 @@ void TSubModel::DisplayLists()
// każdego submodelu // każdego submodelu
if (Global::bUseVBO) if (Global::bUseVBO)
return; // Ra: przy VBO to się nie przyda 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 (eType < TP_ROTATOR)
{ {
if (iNumVerts > 0) if (iNumVerts > 0)
@@ -670,9 +670,9 @@ void TSubModel::DisplayLists()
glTexCoord2f(Vertices[i].tu,Vertices[i].tv); glTexCoord2f(Vertices[i].tu,Vertices[i].tv);
glVertex3dv(&Vertices[i].Point.x); glVertex3dv(&Vertices[i].Point.x);
*/ */
glNormal3fv(&Vertices[i].Normal.x); glNormal3fv(glm::value_ptr(Vertices[i].normal));
glTexCoord2f(Vertices[i].tu, Vertices[i].tv); glTexCoord2fv(glm::value_ptr(Vertices[i].texture));
glVertex3fv(&Vertices[i].Point.x); glVertex3fv(glm::value_ptr(Vertices[i].position));
}; };
glEnd(); glEnd();
#endif #endif
@@ -693,10 +693,10 @@ void TSubModel::DisplayLists()
uiDisplayList = glGenLists(1); uiDisplayList = glGenLists(1);
glNewList(uiDisplayList, GL_COMPILE); glNewList(uiDisplayList, GL_COMPILE);
glBegin(GL_POINTS); 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); glColor3fv(glm::value_ptr(Vertices[i].normal));
glVertex3fv(&Vertices[i].Point.x); glVertex3fv(glm::value_ptr(Vertices[i].position));
}; };
glEnd(); glEnd();
glEndList(); glEndList();
@@ -736,13 +736,13 @@ void TSubModel::InitialRotate(bool doit)
if (Vertices) if (Vertices)
{ {
for (int i = 0; i < iNumVerts; ++i) 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] = (*mat)(3)[0] = (*mat)(3)[1] = (*mat)(3)[2] =
0.0; // zerujemy przesunięcie przed obracaniem normalnych 0.0; // zerujemy przesunięcie przed obracaniem normalnych
if (eType != TP_STARS) // gwiazdki mają kolory zamiast normalnych, to if (eType != TP_STARS) // gwiazdki mają kolory zamiast normalnych, to
// ich wtedy nie ruszamy // ich wtedy nie ruszamy
for (int i = 0; i < iNumVerts; ++i) 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 mat->Identity(); // jedynkowanie transformu po przeliczeniu wierzchołków
iFlags &= ~0x8000; // transform jedynkowy iFlags &= ~0x8000; // transform jedynkowy
@@ -756,17 +756,17 @@ void TSubModel::InitialRotate(bool doit)
if (Vertices) if (Vertices)
for (int i = 0; i < iNumVerts; ++i) for (int i = 0; i < iNumVerts; ++i)
{ {
Vertices[i].Point.x = -Vertices[i].Point.x; // zmiana znaku X Vertices[i].position.x = -Vertices[i].position.x; // zmiana znaku X
t = Vertices[i].Point.y; // zamiana Y i Z t = Vertices[i].position.y; // zamiana Y i Z
Vertices[i].Point.y = Vertices[i].Point.z; Vertices[i].position.y = Vertices[i].position.z;
Vertices[i].Point.z = t; Vertices[i].position.z = t;
// wektory normalne również trzeba przekształcić, bo się źle oświetlają // wektory normalne również trzeba przekształcić, bo się źle oświetlają
if( eType != TP_STARS ) { if( eType != TP_STARS ) {
// gwiazdki mają kolory zamiast normalnych, to // ich wtedy nie ruszamy // gwiazdki mają kolory zamiast normalnych, to // ich wtedy nie ruszamy
Vertices[ i ].Normal.x = -Vertices[ i ].Normal.x; // zmiana znaku X Vertices[ i ].normal.x = -Vertices[ i ].normal.x; // zmiana znaku X
t = Vertices[ i ].Normal.y; // zamiana Y i Z t = Vertices[ i ].normal.y; // zamiana Y i Z
Vertices[ i ].Normal.y = Vertices[ i ].Normal.z; Vertices[ i ].normal.y = Vertices[ i ].normal.z;
Vertices[ i ].Normal.z = t; Vertices[ i ].normal.z = t;
} }
} }
if (Child) if (Child)
@@ -1045,14 +1045,14 @@ void TSubModel::RaArrayFill(CVertNormTex *Vert)
if ((eType < TP_ROTATOR) || (eType == TP_STARS)) if ((eType < TP_ROTATOR) || (eType == TP_STARS))
for (int i = 0; i < iNumVerts; ++i) for (int i = 0; i < iNumVerts; ++i)
{ {
Vert[iVboPtr + i].x = Vertices[i].Point.x; Vert[iVboPtr + i].x = Vertices[i].position.x;
Vert[iVboPtr + i].y = Vertices[i].Point.y; Vert[iVboPtr + i].y = Vertices[i].position.y;
Vert[iVboPtr + i].z = Vertices[i].Point.z; Vert[iVboPtr + i].z = Vertices[i].position.z;
Vert[iVboPtr + i].nx = Vertices[i].Normal.x; Vert[iVboPtr + i].nx = Vertices[i].normal.x;
Vert[iVboPtr + i].ny = Vertices[i].Normal.y; Vert[iVboPtr + i].ny = Vertices[i].normal.y;
Vert[iVboPtr + i].nz = Vertices[i].Normal.z; Vert[iVboPtr + i].nz = Vertices[i].normal.z;
Vert[iVboPtr + i].u = Vertices[i].tu; Vert[iVboPtr + i].u = Vertices[i].texture.s;
Vert[iVboPtr + i].v = Vertices[i].tv; Vert[iVboPtr + i].v = Vertices[i].texture.t;
} }
else if (eType == TP_FREESPOTLIGHT) else if (eType == TP_FREESPOTLIGHT)
Vert[iVboPtr].x = Vert[iVboPtr].y = Vert[iVboPtr].z = 0.0; 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 return 0; // tylko dla trójkątów liczymy
if (iNumVerts < 1) if (iNumVerts < 1)
return 0; return 0;
/*
if (!Vertices) if (!Vertices)
return 0; return 0;
float y, float y,
@@ -1126,6 +1127,22 @@ float TSubModel::MaxY(const float4x4 &m)
if (my < y) if (my < y)
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; 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; uint32_t size = sn_utils::ld_uint32(s) - 8;
std::streampos end = s.tellg() + (std::streampos)size; std::streampos end = s.tellg() + (std::streampos)size;
if (type == MAKE_ID4('V', 'N', 'T', '0')) if ((type & 0x00FFFFFF) == MAKE_ID4('S', 'U', 'B', 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 (Root != nullptr) if (Root != nullptr)
throw std::runtime_error("e3d: duplicated SUB chunk"); 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); 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<int, int> > 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<int, int> const &Left, std::pair<int, int> 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')) else if (type == MAKE_ID4('T', 'R', 'A', '0'))
{ {
if (tm != nullptr) if (tm != nullptr)
@@ -1572,18 +1628,23 @@ void TModel3d::deserialize(std::istream &s, size_t size, bool dynamic)
if (!Root) if (!Root)
throw std::runtime_error("e3d: no submodels"); throw std::runtime_error("e3d: no submodels");
/*
#ifdef EU07_USE_OLD_VERTEXBUFFER #ifdef EU07_USE_OLD_VERTEXBUFFER
if (!m_pVNT) if (!m_pVNT)
#else #else
if(m_pVNT.empty() ) if(m_pVNT.empty() )
#endif #endif
throw std::runtime_error("e3d: no vertices"); 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 #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 #else
Root[ i ].BinInit( Root, tm, (float8*)m_pVNT.data(), &Textures, &Names, dynamic ); Root[ i ].BinInit( Root, tm, (float8*)m_pVNT.data(), &Textures, &Names, dynamic );
#endif #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<std::string> *t, std::vector<std::string> *n, bool dynamic) std::vector<std::string> *t, std::vector<std::string> *n, bool dynamic)
{ // ustawienie wskaźników w submodelu { // ustawienie wskaźników w submodelu
//m7todo: brzydko //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) iFlags &= ~0x0200; // wczytano z pliku binarnego (nie jest właścicielem tablic)
iVboPtr = tVboPtr; iVboPtr = tVboPtr;
Vertices = v + iVboPtr; Vertices = v;
// if (!iNumVerts) eType=-1; //tymczasowo zmiana typu, żeby się nie
// renderowało na siłę
}; };
void TModel3d::LoadFromBinFile(std::string const &FileName, bool dynamic) 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.getToken(parent);
parser.getTokens(1, false); // nazwa submodelu nadrzędnego bez zmieny na małe parser.getTokens(1, false); // nazwa submodelu nadrzędnego bez zmieny na małe
parser >> parent; parser >> parent;
if (parent == "") if( parent == "" ) {
break; break;
}
SubModel = new TSubModel(); SubModel = new TSubModel();
iNumVerts += SubModel->Load(parser, this, iNumVerts, dynamic); iNumVerts += SubModel->Load(parser, this, iNumVerts, dynamic);
SubModel->Parent = AddToNamed(
parent.c_str(), SubModel); // będzie potrzebne do wyliczenia pozycji, np. pantografu // będzie potrzebne do wyliczenia pozycji, np. pantografu
// iSubModelsCount++; SubModel->Parent = AddToNamed(parent.c_str(), SubModel);
parser.getTokens(); parser.getTokens();
parser >> token; parser >> token;
} }
// Ra: od wersji 334 przechylany jest cały model, a nie tylko pierwszy // Ra: od wersji 334 przechylany jest cały model, a nie tylko pierwszy submodel
// submodel // ale bujanie kabiny nadal używa bananów :( od 393 przywrócone, ale z dodatkowym warunkiem
// ale bujanie kabiny nadal używa bananów :( od 393 przywrócone, ale z
// dodatkowym warunkiem
if (Global::iConvertModels & 4) if (Global::iConvertModels & 4)
{ // automatyczne banany czasem psuły przechylanie kabin... { // automatyczne banany czasem psuły przechylanie kabin...
if (dynamic && Root) if (dynamic && Root)
{ {
if (Root->NextGet()) // jeśli ma jakiekolwiek kolejne if (Root->NextGet()) // jeśli ma jakiekolwiek kolejne
{ // dynamic musi mieć "banana", bo tylko pierwszy obiekt jest animowany, { // dynamic musi mieć "banana", bo tylko pierwszy obiekt jest animowany, a następne nie
// a następne nie
SubModel = new TSubModel(); // utworzenie pustego SubModel = new TSubModel(); // utworzenie pustego
SubModel->ChildAdd(Root); SubModel->ChildAdd(Root);
Root = SubModel; Root = SubModel;

152
Model3d.h
View File

@@ -19,82 +19,6 @@ http://mozilla.org/MPL/2.0/.
using namespace Math3D; 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. // Ra: specjalne typy submodeli, poza tym GL_TRIANGLES itp.
const int TP_ROTATOR = 256; const int TP_ROTATOR = 256;
const int TP_FREESPOTLIGHT = 257; const int TP_FREESPOTLIGHT = 257;
@@ -134,6 +58,7 @@ class TSubModel
//m7todo: zrobić normalną serializację //m7todo: zrobić normalną serializację
friend class opengl_renderer; friend class opengl_renderer;
friend class TModel3d; // temporary workaround. TODO: clean up class content/hierarchy
private: private:
int iNext; int iNext;
@@ -160,7 +85,6 @@ private:
union union
{ // transform, nie każdy submodel musi mieć { // transform, nie każdy submodel musi mieć
float4x4 *fMatrix; // pojedyncza precyzja wystarcza float4x4 *fMatrix; // pojedyncza precyzja wystarcza
// matrix4x4 *dMatrix; //do testu macierz podwójnej precyzji
int iMatrix; // w pliku binarnym jest numer matrycy int iMatrix; // w pliku binarnym jest numer matrycy
}; };
int iNumVerts; // ilość wierzchołków (1 dla FreeSpotLight) int iNumVerts; // ilość wierzchołków (1 dla FreeSpotLight)
@@ -188,21 +112,19 @@ private:
TSubModel *Next; TSubModel *Next;
TSubModel *Child; TSubModel *Child;
intptr_t iVboPtr; intptr_t iVboPtr;
geometrychunk_handle m_chunk; // geometry of the submodel
texture_manager::size_type TextureID; // numer tekstury, -1 wymienna, 0 brak texture_manager::size_type TextureID; // numer tekstury, -1 wymienna, 0 brak
bool bWire; // nie używane, ale wczytywane bool bWire; // nie używane, ale wczytywane
// short TexAlpha; //Ra: nie używane już // short TexAlpha; //Ra: nie używane już
GLuint uiDisplayList; // roboczy numer listy wyświetlania GLuint uiDisplayList; // roboczy numer listy wyświetlania
float Opacity; // nie używane, ale wczytywane //m7todo: wywalić to 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; float f_Angle;
float3 v_RotateAxis; float3 v_RotateAxis;
float3 v_Angles; float3 v_Angles;
public: // chwilowo public: // chwilowo
float3 v_TransVector; 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ę size_t iAnimOwner; // roboczy numer egzemplarza, który ustawił animację
TAnimType b_aAnim; // kody animacji oddzielnie, bo zerowane TAnimType b_aAnim; // kody animacji oddzielnie, bo zerowane
public: public:
@@ -212,14 +134,10 @@ public:
smLetter; // wskaźnik na tablicę submdeli do generoania tekstu (docelowo zapisać do E3D) smLetter; // wskaźnik na tablicę submdeli do generoania tekstu (docelowo zapisać do E3D)
TSubModel *Parent; // nadrzędny, np. do wymnażania macierzy TSubModel *Parent; // nadrzędny, np. do wymnażania macierzy
int iVisible; // roboczy stan widoczności 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 pTexture; // robocza nazwa tekstury do zapisania w pliku binarnym
std::string pName; // robocza nazwa std::string pName; // robocza nazwa
private: private:
// int SeekFaceNormal(DWORD *Masks, int f,DWORD dwMask,vector3 *pt,GLVERTEX int SeekFaceNormal(unsigned int *Masks, int f, unsigned int dwMask, glm::vec3 *pt, basic_vertex *Vertices);
// *Vertices);
int SeekFaceNormal(unsigned int *Masks, int f, unsigned int dwMask, float3 *pt, float8 *Vertices);
void RaAnimation(TAnimType a); void RaAnimation(TAnimType a);
public: public:
@@ -235,18 +153,10 @@ public:
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 ChildAdd(TSubModel *SubModel);
void NextAdd(TSubModel *SubModel); void NextAdd(TSubModel *SubModel);
TSubModel * NextGet() TSubModel * NextGet() { return Next; };
{ TSubModel * ChildGet() { return Child; };
return Next;
};
TSubModel * ChildGet()
{
return Child;
};
int TriangleAdd(TModel3d *m, texture_manager::size_type tex, int tri); int TriangleAdd(TModel3d *m, texture_manager::size_type tex, int tri);
float8 * TrianglePtr(int tex, int pos, int *la, int *ld, int *ls); basic_vertex * TrianglePtr(int tex, int pos, int *la, int *ld, int *ls);
// float8* TrianglePtr(const char *tex,int tri);
// void SetRotate(vector3 vNewRotateAxis,float fNewAngle);
void SetRotate(float3 vNewRotateAxis, float fNewAngle); void SetRotate(float3 vNewRotateAxis, float fNewAngle);
void SetRotateXYZ(vector3 vNewAngles); void SetRotateXYZ(vector3 vNewAngles);
void SetRotateXYZ(float3 vNewAngles); void SetRotateXYZ(float3 vNewAngles);
@@ -255,18 +165,9 @@ public:
void SetRotateIK1(float3 vNewAngles); void SetRotateIK1(float3 vNewAngles);
TSubModel * GetFromName(std::string const &search, bool i = true); TSubModel * GetFromName(std::string const &search, bool i = true);
TSubModel * GetFromName(char const *search, bool i = true); TSubModel * GetFromName(char const *search, bool i = true);
// inline matrix4x4* GetMatrix() {return dMatrix;}; inline float4x4 * GetMatrix() { return fMatrix; };
inline float4x4 * GetMatrix() inline void Hide() { iVisible = 0; };
{
return fMatrix;
};
// matrix4x4* GetTransform() {return Matrix;};
inline void Hide()
{
iVisible = 0;
};
void RaArrayFill(CVertNormTex *Vert); void RaArrayFill(CVertNormTex *Vert);
// void Render();
int FlagsCheck(); int FlagsCheck();
void WillBeAnimated() void WillBeAnimated()
{ {
@@ -275,7 +176,7 @@ public:
}; };
void InitialRotate(bool doit); void InitialRotate(bool doit);
void DisplayLists(); void DisplayLists();
void BinInit(TSubModel *s, float4x4 *m, float8 *v, void BinInit(TSubModel *s, float4x4 *m, basic_vertex *v,
std::vector<std::string> *t, std::vector<std::string> *n, bool dynamic); std::vector<std::string> *t, std::vector<std::string> *n, bool dynamic);
void ReplacableSet(texture_manager::size_type const *r, int a) void ReplacableSet(texture_manager::size_type const *r, int a)
{ {
@@ -285,14 +186,8 @@ public:
void TextureNameSet(const char *n); void TextureNameSet(const char *n);
void NameSet(const char *n); void NameSet(const char *n);
// Ra: funkcje do budowania terenu z E3D // Ra: funkcje do budowania terenu z E3D
int Flags() int Flags() { return iFlags; };
{ void UnFlagNext() { iFlags &= 0x00FFFFFF; };
return iFlags;
};
void UnFlagNext()
{
iFlags &= 0x00FFFFFF;
};
void ColorsSet(int *a, int *d, int *s); void ColorsSet(int *a, int *d, int *s);
inline float3 Translation1Get() inline float3 Translation1Get()
{ {
@@ -323,9 +218,6 @@ class TModel3d : public CMesh
friend class opengl_renderer; friend class opengl_renderer;
private: private:
// TMaterial *Materials;
// int MaterialsCount; //Ra: nie używane
// bool TractionPart; //Ra: nie używane
TSubModel *Root; // drzewo submodeli TSubModel *Root; // drzewo submodeli
int iFlags; // Ra: czy submodele mają przezroczyste tekstury int iFlags; // Ra: czy submodele mają przezroczyste tekstury
public: // Ra: tymczasowo public: // Ra: tymczasowo
@@ -338,16 +230,10 @@ private:
std::string asBinary; // nazwa pod którą zapisać model binarny std::string asBinary; // nazwa pod którą zapisać model binarny
std::string m_filename; std::string m_filename;
public: public:
inline TSubModel * GetSMRoot() inline TSubModel * GetSMRoot() { return (Root); };
{
return (Root);
};
// double Radius; //Ra: nie używane
TModel3d(); TModel3d();
TModel3d(char *FileName);
~TModel3d(); ~TModel3d();
TSubModel * GetFromName(const char *sName); TSubModel * GetFromName(const char *sName);
// TMaterial* GetMaterialFromName(char *sName);
TSubModel * AddToNamed(const char *Name, TSubModel *SubModel); TSubModel * AddToNamed(const char *Name, TSubModel *SubModel);
void AddTo(TSubModel *tmp, TSubModel *SubModel); void AddTo(TSubModel *tmp, TSubModel *SubModel);
void LoadFromTextFile(std::string const &FileName, bool dynamic); void LoadFromTextFile(std::string const &FileName, bool dynamic);
@@ -355,17 +241,9 @@ public:
bool LoadFromFile(std::string const &FileName, bool dynamic); bool LoadFromFile(std::string const &FileName, bool dynamic);
void SaveToBinFile(char const *FileName); void SaveToBinFile(char const *FileName);
void BreakHierarhy(); void BreakHierarhy();
// inline int GetSubModelsCount() { return (SubModelsCount); }; int Flags() const { return iFlags; };
int Flags() const
{
return iFlags;
};
void Init(); void Init();
std::string NameGet() std::string NameGet() { return m_filename; };
{
// return Root ? Root->pName : NULL;
return m_filename;
};
int TerrainCount(); int TerrainCount();
TSubModel * TerrainSquare(int n); TSubModel * TerrainSquare(int n);
void TerrainRenderVBO(int n); void TerrainRenderVBO(int n);

View File

@@ -62,6 +62,8 @@ private:
*/ */
}; };
typedef std::size_t texture_handle;
class texture_manager { class texture_manager {
private: private:

12
VBO.cpp
View File

@@ -49,6 +49,9 @@ CMesh::CMesh()
#endif #endif
m_nVertexCount = -1; m_nVertexCount = -1;
m_nVBOVertices = 0; // nie zarezerwowane m_nVBOVertices = 0; // nie zarezerwowane
// TODO: bind proper subtype based on the settings
m_geometry = std::make_shared<opengl_vbogeometrybank>();
}; };
CMesh::~CMesh() CMesh::~CMesh()
@@ -107,6 +110,7 @@ void CMesh::Clear()
bool CMesh::StartVBO() bool CMesh::StartVBO()
{ // początek rysowania elementów z VBO { // początek rysowania elementów z VBO
if (m_nVertexCount <= 0) if (m_nVertexCount <= 0)
return false; // nie ma nic do rysowania w ten sposób return false; // nie ma nic do rysowania w ten sposób
glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_VERTEX_ARRAY);
@@ -118,12 +122,15 @@ bool CMesh::StartVBO()
glVertexPointer( 3, GL_FLOAT, sizeof(CVertNormTex), static_cast<char *>(nullptr) ); // pozycje glVertexPointer( 3, GL_FLOAT, sizeof(CVertNormTex), static_cast<char *>(nullptr) ); // pozycje
glNormalPointer( GL_FLOAT, sizeof( CVertNormTex ), static_cast<char *>( nullptr ) + 12 ); // normalne glNormalPointer( GL_FLOAT, sizeof( CVertNormTex ), static_cast<char *>( nullptr ) + 12 ); // normalne
glTexCoordPointer( 2, GL_FLOAT, sizeof( CVertNormTex ), static_cast<char *>( nullptr ) + 24 ); // wierzchołki glTexCoordPointer( 2, GL_FLOAT, sizeof( CVertNormTex ), static_cast<char *>( nullptr ) + 24 ); // wierzchołki
return true; // można rysować z VBO
} }
return true; // można rysować z VBO
return false;
}; };
bool CMesh::StartColorVBO() bool CMesh::StartColorVBO()
{ // początek rysowania punktów świecących z VBO { // początek rysowania punktów świecących z VBO
if (m_nVertexCount <= 0) if (m_nVertexCount <= 0)
return false; // nie ma nic do rysowania w ten sposób return false; // nie ma nic do rysowania w ten sposób
glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_VERTEX_ARRAY);
@@ -134,8 +141,9 @@ bool CMesh::StartColorVBO()
glVertexPointer( 3, GL_FLOAT, sizeof( CVertNormTex ), static_cast<char *>( nullptr ) ); // pozycje glVertexPointer( 3, GL_FLOAT, sizeof( CVertNormTex ), static_cast<char *>( nullptr ) ); // pozycje
// glColorPointer(3,GL_UNSIGNED_BYTE,sizeof(CVertNormTex),((char*)NULL)+12); //kolory // glColorPointer(3,GL_UNSIGNED_BYTE,sizeof(CVertNormTex),((char*)NULL)+12); //kolory
glColorPointer( 3, GL_FLOAT, sizeof( CVertNormTex ), static_cast<char *>( nullptr ) + 12 ); // kolory glColorPointer( 3, GL_FLOAT, sizeof( CVertNormTex ), static_cast<char *>( nullptr ) + 12 ); // kolory
return true; // można rysować z VBO
} }
return true; // można rysować z VBO return false;
}; };
void CMesh::EndVBO() void CMesh::EndVBO()

22
VBO.h
View File

@@ -7,8 +7,9 @@ obtain one at
http://mozilla.org/MPL/2.0/. http://mozilla.org/MPL/2.0/.
*/ */
#ifndef VBOH #pragma once
#define VBOH
#include "openglgeometrybank.h"
#define EU07_USE_OLD_VERTEXBUFFER #define EU07_USE_OLD_VERTEXBUFFER
@@ -32,13 +33,6 @@ class CVertNormTex
class CMesh class CMesh
{ // wsparcie dla VBO { // wsparcie dla VBO
public: public:
int m_nVertexCount; // liczba wierzchołków
#ifdef EU07_USE_OLD_VERTEXBUFFER
CVertNormTex *m_pVNT;
#else
std::vector<CVertNormTex> m_pVNT;
#endif
unsigned int m_nVBOVertices; // numer VBO z wierzchołkami
CMesh(); CMesh();
~CMesh(); ~CMesh();
void MakeArray(int n); // tworzenie tablicy z elementami VNT void MakeArray(int n); // tworzenie tablicy z elementami VNT
@@ -47,6 +41,14 @@ class CMesh
bool StartVBO(); bool StartVBO();
void EndVBO(); void EndVBO();
bool StartColorVBO(); bool StartColorVBO();
};
int m_nVertexCount; // liczba wierzchołków
#ifdef EU07_USE_OLD_VERTEXBUFFER
CVertNormTex *m_pVNT;
#else
std::vector<CVertNormTex> m_pVNT;
#endif #endif
unsigned int m_nVBOVertices; // numer VBO z wierzchołkami
std::shared_ptr<geometry_bank> m_geometry;
};

View File

@@ -222,6 +222,9 @@
<ClCompile Include="command.cpp"> <ClCompile Include="command.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="openglgeometrybank.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="Globals.h"> <ClInclude Include="Globals.h">
@@ -434,6 +437,9 @@
<ClInclude Include="version.h"> <ClInclude Include="version.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="openglgeometrybank.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ResourceCompile Include="maszyna.rc"> <ResourceCompile Include="maszyna.rc">

218
openglgeometrybank.cpp Normal file
View File

@@ -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<char *>( nullptr ) );
::glNormalPointer( GL_FLOAT, sizeof( basic_vertex ), static_cast<char *>( nullptr ) + sizeof(float) * 3 ); // normalne
::glTexCoordPointer( 2, GL_FLOAT, sizeof( basic_vertex ), static_cast<char *>( 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;
}
}

122
openglgeometrybank.h Normal file
View File

@@ -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 <vector>
#include <glm/glm.hpp>
#include <glm/gtc/type_ptr.hpp>
#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<basic_vertex> 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 <typename _Iterator>
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<geometry_chunk> 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<chunk_record> 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
};

View File

@@ -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 // TODO: unify the render code after generic buffers are in place
// setup // setup
/*
if( Global::bUseVBO ) { if( Global::bUseVBO ) {
if( false == Model->StartVBO() ) if( false == Model->StartVBO() )
return false; return false;
} }
*/
Model->Root->ReplacableSet( Model->Root->ReplacableSet(
( Material != nullptr ? ( Material != nullptr ?
Material->replacable_skins : Material->replacable_skins :
@@ -793,7 +794,7 @@ opengl_renderer::Render( TModel3d *Model, material_data const *Material, double
// post-render cleanup // post-render cleanup
if( Global::bUseVBO ) { if( Global::bUseVBO ) {
Model->EndVBO(); // Model->EndVBO();
} }
return true; return true;
@@ -857,7 +858,10 @@ opengl_renderer::Render( TSubModel *Submodel ) {
// main draw call. TODO: generic buffer base class, specialized for vbo, dl etc // main draw call. TODO: generic buffer base class, specialized for vbo, dl etc
if( Global::bUseVBO ) { if( Global::bUseVBO ) {
/*
::glDrawArrays( Submodel->eType, Submodel->iVboPtr, Submodel->iNumVerts ); ::glDrawArrays( Submodel->eType, Submodel->iVboPtr, Submodel->iNumVerts );
*/
Submodel->pRoot->m_geometry->draw( Submodel->m_chunk );
} }
else { else {
::glCallList( Submodel->uiDisplayList ); ::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 // main draw call. TODO: generic buffer base class, specialized for vbo, dl etc
if( Global::bUseVBO ) { if( Global::bUseVBO ) {
/*
::glDrawArrays( GL_POINTS, Submodel->iVboPtr, Submodel->iNumVerts ); ::glDrawArrays( GL_POINTS, Submodel->iVboPtr, Submodel->iNumVerts );
*/
Submodel->pRoot->m_geometry->draw( Submodel->m_chunk );
} }
else { else {
::glCallList( Submodel->uiDisplayList ); ::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 // main draw call. TODO: generic buffer base class, specialized for vbo, dl etc
if( Global::bUseVBO ) { 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 // 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 // TODO: implement easier way to go about it
::glDisableClientState( GL_NORMAL_ARRAY ); ::glDisableClientState( GL_NORMAL_ARRAY );
@@ -933,6 +941,7 @@ opengl_renderer::Render( TSubModel *Submodel ) {
::glDisableClientState( GL_COLOR_ARRAY ); ::glDisableClientState( GL_COLOR_ARRAY );
::glEnableClientState( GL_NORMAL_ARRAY ); ::glEnableClientState( GL_NORMAL_ARRAY );
::glEnableClientState( GL_TEXTURE_COORD_ARRAY ); ::glEnableClientState( GL_TEXTURE_COORD_ARRAY );
*/
} }
else { else {
::glCallList( Submodel->uiDisplayList ); ::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 // TODO: unify the render code after generic buffers are in place
// setup // setup
/*
if( Global::bUseVBO ) { if( Global::bUseVBO ) {
if( false == Model->StartVBO() ) if( false == Model->StartVBO() )
return false; return false;
} }
*/
Model->Root->ReplacableSet( Model->Root->ReplacableSet(
( Material != nullptr ? ( Material != nullptr ?
Material->replacable_skins : Material->replacable_skins :
@@ -1315,10 +1325,11 @@ opengl_renderer::Render_Alpha( TModel3d *Model, material_data const *Material, d
Render_Alpha( Model->Root ); Render_Alpha( Model->Root );
// post-render cleanup // post-render cleanup
/*
if( Global::bUseVBO ) { if( Global::bUseVBO ) {
Model->EndVBO(); Model->EndVBO();
} }
*/
return true; 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 // main draw call. TODO: generic buffer base class, specialized for vbo, dl etc
if( Global::bUseVBO ) { if( Global::bUseVBO ) {
/*
::glDrawArrays( Submodel->eType, Submodel->iVboPtr, Submodel->iNumVerts ); ::glDrawArrays( Submodel->eType, Submodel->iVboPtr, Submodel->iNumVerts );
*/
Submodel->pRoot->m_geometry->draw( Submodel->m_chunk );
} }
else { else {
::glCallList( Submodel->uiDisplayList ); ::glCallList( Submodel->uiDisplayList );