16
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-07-19 06:29: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]);
}
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);

View File

@@ -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

View File

@@ -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<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'))
{
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<std::string> *t, std::vector<std::string> *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;

152
Model3d.h
View File

@@ -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<std::string> *t, std::vector<std::string> *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);

View File

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

12
VBO.cpp
View File

@@ -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<opengl_vbogeometrybank>();
};
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<char *>(nullptr) ); // pozycje
glNormalPointer( GL_FLOAT, sizeof( CVertNormTex ), static_cast<char *>( nullptr ) + 12 ); // normalne
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()
{ // 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<char *>( nullptr ) ); // pozycje
// glColorPointer(3,GL_UNSIGNED_BYTE,sizeof(CVertNormTex),((char*)NULL)+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()

22
VBO.h
View File

@@ -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<CVertNormTex> 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<CVertNormTex> m_pVNT;
#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">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="openglgeometrybank.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Globals.h">
@@ -434,6 +437,9 @@
<ClInclude Include="version.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="openglgeometrybank.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<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
// 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 );