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

completed unification of render paths

This commit is contained in:
tmj-fstate
2017-06-13 18:13:49 +02:00
parent 22746bad21
commit 21680a5d30
19 changed files with 1040 additions and 1384 deletions

View File

@@ -247,82 +247,13 @@ void TGroundNode::InitNormals()
}
}
/*
void TGroundNode::RaRenderVBO()
{ // renderowanie z domyslnego bufora VBO
glColor3ub(Diffuse[0], Diffuse[1], Diffuse[2]);
GfxRenderer.Bind( TextureID ); // Ustaw aktywną teksturę
glDrawArrays(iType, iVboPtr, iNumVerts); // Narysuj naraz wszystkie trójkąty
}
*/
void TGroundNode::Compile( glm::dvec3 const &Origin, bool const Multiple )
{ // tworzenie skompilowanej listy w wyświetlaniu DL
if (false == Multiple)
{ // obsługa pojedynczej listy
if (DisplayListID)
Release();
if (Global::bManageNodes)
{
DisplayListID = glGenLists(1);
glNewList(DisplayListID, GL_COMPILE);
iVersion = Global::iReCompile; // aktualna wersja siatek (do WireFrame)
}
}
if ((iType == GL_LINES) || (iType == GL_LINE_STRIP) || (iType == GL_LINE_LOOP))
{
glBegin(iType);
for (int i = 0; i < iNumPts; ++i)
glVertex3dv( glm::value_ptr( Points[i] - Origin ) );
glEnd();
}
else if (iType == GL_TRIANGLE_STRIP || iType == GL_TRIANGLE_FAN || iType == GL_TRIANGLES)
{ // jak nie linie, to trójkąty
// TODO: eliminate these calls, they're duplicated by setup part in the unified render function
#ifdef EU07_USE_OLD_RENDERCODE
::glColor3fv( glm::value_ptr( Diffuse ) );
GfxRenderer.Bind(TextureID);
#endif
glBegin(iType);
for (int i = 0; i < iNumVerts; ++i)
{
glNormal3fv( glm::value_ptr( Vertices[ i ].normal ) );
glTexCoord2fv( glm::value_ptr( Vertices[ i ].texture ) );
glVertex3dv( glm::value_ptr( Vertices[ i ].position - Origin ) );
}
glEnd();
}
/*
else if (iType == TP_MESH)
{ // grupa ze wspólną teksturą - wrzucanie do wspólnego Display List
#ifdef EU07_USE_OLD_RENDERCODE
if (TextureID)
GfxRenderer.Bind(TextureID); // Ustaw aktywną teksturę
#endif
TGroundNode *n = nNode;
while (n ? n->TextureID == TextureID : false)
{ // wszystkie obiekty o tej samej testurze
switch (n->iType)
{ // poszczególne typy różnie się tworzy
case TP_TRACK:
case TP_DUMMYTRACK:
n->pTrack->Compile(TextureID); // dodanie trójkątów dla podanej tekstury
break;
}
n = n->nNext3; // następny z listy
}
}
*/
if (false == Multiple)
if (Global::bManageNodes)
glEndList();
};
void TGroundNode::Release()
{
if (DisplayListID)
glDeleteLists(DisplayListID, 1);
DisplayListID = 0;
};
*/
void TGroundNode::RenderHidden()
{ // renderowanie obiektów niewidocznych
double mgn = SquareMagnitude(pCenter - Global::pCameraPosition);
@@ -354,8 +285,10 @@ void TGroundNode::RenderHidden()
//------------------------------------------------------------------------------
TSubRect::~TSubRect()
{
/*
if (Global::bManageNodes) // Ra: tu się coś sypie
ResourceManager::Unregister(this); // wyrejestrowanie ze sprzątacza
*/
// TODO: usunąć obiekty z listy (nRootMesh), bo są one tworzone dla sektora
delete[] tTracks;
}
@@ -393,46 +326,22 @@ void TSubRect::NodeAdd(TGroundNode *Node)
Node->pTrack->RaOwnerSet(this); // do którego sektora ma zgłaszać animację
// NOTE: track merge/sort temporarily disabled to simplify unification of render code
// TODO: refactor sorting as universal part of drawing process in the renderer
#ifdef EU07_USE_OLD_RENDERCODE
if( Global::bUseVBO ) {
Node->nNext3 = nRenderRect;
nRenderRect = Node;
} // VBO: do nieprzezroczystych z sektora
else {
Node->nNext3 = nRender;
nRender = Node;
} // DL: do nieprzezroczystych
#else
Node->nNext3 = nRenderRect;
nRenderRect = Node;
#endif
break;
case GL_TRIANGLE_STRIP:
case GL_TRIANGLE_FAN:
case GL_TRIANGLES:
// Node->nNext3=nMeshed; nMeshed=Node; //do podzielenia potem
if (Node->iFlags & 0x20) // czy jest przezroczyste?
{
if (Node->iFlags & 0x20) {
// do przezroczystych z sektora
Node->nNext3 = nRenderRectAlpha;
nRenderRectAlpha = Node;
} // DL: do przezroczystych z sektora
#ifdef EU07_USE_OLD_RENDERCODE
else if (Global::bUseVBO)
{
Node->nNext3 = nRenderRect;
nRenderRect = Node;
} // VBO: do nieprzezroczystych z sektora
else
{
Node->nNext3 = nRender;
nRender = Node;
} // DL: do nieprzezroczystych wszelakich
#else
}
else {
// do nieprzezroczystych z sektora
Node->nNext3 = nRenderRect;
nRenderRect = Node;
} // do nieprzezroczystych z sektora
#endif
}
break;
case TP_TRACTION:
case GL_LINES:
@@ -471,9 +380,11 @@ void TSubRect::NodeAdd(TGroundNode *Node)
case TP_DYNAMIC:
return; // tych nie dopisujemy wcale
}
Node->nNext2 = nRootNode; // dopisanie do ogólnej listy
// dopisanie do ogólnej listy
Node->nNext2 = nRootNode;
nRootNode = Node;
++iNodeCount; // licznik obiektów
// licznik obiektów
++iNodeCount;
}
// przygotowanie sektora do renderowania
@@ -516,8 +427,10 @@ TTrack * TSubRect::FindTrack(vector3 *Point, int &iConnection, TTrack *Exclude)
bool TSubRect::RaTrackAnimAdd(TTrack *t)
{ // aktywacja animacji torów w VBO (zwrotnica, obrotnica)
if (m_nVertexCount < 0)
return true; // nie ma animacji, gdy nie widać
if( false == m_geometrycreated ) {
// nie ma animacji, gdy nie widać
return true;
}
if (tTrackAnim)
tTrackAnim->RaAnimListAdd(t);
else
@@ -531,22 +444,7 @@ void TSubRect::RaAnimate()
// nie ma nic do animowania
return;
}
// crude way to mark whether a vbo is bound, for the vbo render path
// TODO: sort this shit out and re-arrange into something more elegant... eventually
GLuint vertexbuffer { static_cast<GLuint>(-1) };
if (Global::bUseVBO) {
// odświeżenie VBO sektora
if( GLEW_VERSION_1_5 ) {
// modyfikacje VBO są dostępne od OpenGL 1.5
vertexbuffer = m_nVBOVertices;
::glBindBuffer( GL_ARRAY_BUFFER, vertexbuffer );
}
else {
// dla OpenGL 1.4 z GL_ARB_vertex_buffer_object odświeżenie całego sektora
Release(); // opróżnienie VBO sektora, aby się odświeżył z nowymi ustawieniami
}
}
tTrackAnim = tTrackAnim->RaAnimate( vertexbuffer ); // przeliczenie animacji kolejnego
tTrackAnim = tTrackAnim->RaAnimate(); // przeliczenie animacji kolejnego
};
TTraction * TSubRect::FindTraction(glm::dvec3 const &Point, int &iConnection, TTraction *Exclude)
@@ -562,126 +460,69 @@ TTraction * TSubRect::FindTraction(glm::dvec3 const &Point, int &iConnection, TT
return NULL;
};
void TSubRect::LoadNodes()
{ // utworzenie siatek VBO dla wszystkich node w sektorze
if (m_nVertexCount >= 0)
return; // obiekty były już sprawdzone
m_nVertexCount = 0; //-1 oznacza, że nie sprawdzono listy obiektów
if (!nRootNode)
// utworzenie siatek VBO dla wszystkich node w sektorze
void TSubRect::LoadNodes() {
if( true == m_geometrycreated ) {
// obiekty były już sprawdzone
return;
TGroundNode *n = nRootNode;
while (n)
{
switch (n->iType)
{
case GL_TRIANGLE_STRIP:
case GL_TRIANGLE_FAN:
case GL_TRIANGLES:
n->iVboPtr = m_nVertexCount; // nowy początek
m_nVertexCount += n->iNumVerts;
break;
case GL_LINES:
case GL_LINE_STRIP:
case GL_LINE_LOOP:
n->iVboPtr = m_nVertexCount; // nowy początek
m_nVertexCount += n->iNumPts; // miejsce w tablicach normalnych i teksturowania się zmarnuje...
break;
case TP_TRACK:
n->iVboPtr = m_nVertexCount; // nowy początek
n->iNumVerts = n->pTrack->RaArrayPrepare(); // zliczenie wierzchołków
m_nVertexCount += n->iNumVerts;
break;
case TP_TRACTION:
n->hvTraction->create_geometry( m_geometrybank, n->m_rootposition );
break;
}
n = n->nNext2; // następny z sektora
}
if (m_nVertexCount <= 0)
return; // jeśli nie ma obiektów do wyświetlenia z VBO, to koniec
if (Global::bUseVBO)
{ // tylko liczenie wierzchołów, gdy nie ma VBO
else {
// mark it done for future checks
m_geometrycreated = true;
}
MakeArray(m_nVertexCount);
n = nRootNode;
int i;
while (n)
{
if (n->iVboPtr >= 0)
switch (n->iType)
{
case GL_TRIANGLE_STRIP:
case GL_TRIANGLE_FAN:
case GL_TRIANGLES:
for (i = 0; i < n->iNumVerts; ++i)
{ // Ra: trójkąty można od razu wczytywać do takich tablic... to może poczekać
m_pVNT[ n->iVboPtr + i ].position = n->Vertices[ i ].position - n->m_rootposition;
/*
m_pVNT[n->iVboPtr + i].x = n->Vertices[i].position.x - n->m_rootposition.x;
m_pVNT[n->iVboPtr + i].y = n->Vertices[i].position.y - n->m_rootposition.y;
m_pVNT[n->iVboPtr + i].z = n->Vertices[i].position.z - n->m_rootposition.z;
*/
m_pVNT[ n->iVboPtr + i ].normal = n->Vertices[ i ].normal;
/*
m_pVNT[n->iVboPtr + i].nx = n->Vertices[i].normal.x;
m_pVNT[n->iVboPtr + i].ny = n->Vertices[i].normal.y;
m_pVNT[n->iVboPtr + i].nz = n->Vertices[i].normal.z;
*/
m_pVNT[ n->iVboPtr + i ].texture = n->Vertices[ i ].texture;
/*
m_pVNT[n->iVboPtr + i].u = n->Vertices[i].tu;
m_pVNT[n->iVboPtr + i].v = n->Vertices[i].tv;
*/
}
break;
case GL_LINES:
case GL_LINE_STRIP:
case GL_LINE_LOOP:
for (i = 0; i < n->iNumPts; ++i)
{
m_pVNT[ n->iVboPtr + i ].position = ( n->Points[ i ] - n->m_rootposition );
/*
glm::vec3(
n->Points[ i ].x - n->m_rootposition.x,
n->Points[ i ].y - n->m_rootposition.y,
n->Points[ i ].z - n->m_rootposition.z );
*/
// miejsce w tablicach normalnych i teksturowania się marnuje...
}
break;
case TP_TRACK:
if( n->iNumVerts ) { // bo tory zabezpieczające są niewidoczne
#ifdef EU07_USE_OLD_VERTEXBUFFER
n->pTrack->RaArrayFill( m_pVNT + n->iVboPtr, m_pVNT, std::min( n->iNumVerts, m_nVertexCount - n->iVboPtr ) );
#else
n->pTrack->RaArrayFill( m_pVNT.data() + n->iVboPtr, m_pVNT.data(), std::min( n->iNumVerts, m_nVertexCount - n->iVboPtr ) );
#endif
}
break;
default:
break;
auto *node { nRootNode };
while( node != nullptr ) {
switch (node->iType) {
case GL_TRIANGLES: {
vertex_array vertices;
for( std::size_t idx = 0; idx < node->iNumVerts; ++idx ) {
vertices.emplace_back(
node->Vertices[ idx ].position - node->m_rootposition,
node->Vertices[ idx ].normal,
node->Vertices[ idx ].texture );
}
n = n->nNext2; // następny z sektora
node->m_geometry = GfxRenderer.Insert( vertices, m_geometrybank, GL_TRIANGLES );
SafeDeleteArray( node->Vertices );
node->iNumVerts = 0;
break;
}
case GL_LINES: {
vertex_array vertices;
for( std::size_t idx = 0; idx < node->iNumPts; ++idx ) {
vertices.emplace_back(
node->Points[ idx ] - node->m_rootposition,
glm::vec3(),
glm::vec2() );
}
node->m_geometry = GfxRenderer.Insert( vertices, m_geometrybank, GL_LINES );
SafeDeleteArray( node->Vertices );
node->iNumPts = 0;
break;
}
case TP_TRACK:
if( node->pTrack->bVisible ) { // bo tory zabezpieczające są niewidoczne
node->pTrack->create_geometry( m_geometrybank );
}
break;
case TP_TRACTION:
node->hvTraction->create_geometry( m_geometrybank, node->m_rootposition );
break;
default: { break; }
}
BuildVBOs();
node = node->nNext2; // następny z sektora
}
/*
if (Global::bManageNodes)
ResourceManager::Register(this); // dodanie do automatu zwalniającego pamięć
*/
}
bool TSubRect::StartVBO()
{ // początek rysowania elementów z VBO w sektorze
SetLastUsage(Timer::GetSimulationTime()); // te z tyłu będą niepotrzebnie zwalniane
return CMesh::StartVBO();
};
/*
void TSubRect::Release()
{ // wirtualne zwolnienie zasobów przez sprzątacz albo destruktor
if (Global::bUseVBO)
CMesh::Clear(); // usuwanie buforów
};
*/
void TSubRect::RenderSounds()
{ // aktualizacja dźwięków w pojazdach sektora (sektor może nie być wyświetlany)
for (int j = 0; j < iTracks; ++j)
@@ -708,7 +549,7 @@ TGroundRect::Init() {
float const subrectsize = 1000.0f / iNumSubRects;
for( int column = 0; column < iNumSubRects; ++column ) {
for( int row = 0; row < iNumSubRects; ++row ) {
auto subcell = FastGetRect( column, row );
auto subcell = FastGetSubRect( column, row );
auto &area = subcell->m_area;
area.center =
m_area.center
@@ -734,8 +575,9 @@ TGround::TGround()
nRootOfType[ i ] = nullptr; // zerowanie tablic wyszukiwania
}
::SecureZeroMemory( TempConnectionType, sizeof( TempConnectionType ) );
/*
::SecureZeroMemory( pRendered, sizeof( pRendered ) );
*/
// set bounding area information for ground rectangles
float const rectsize = 1000.0f;
glm::vec3 const worldcenter;
@@ -876,9 +718,9 @@ void TGround::RaTriangleDivider(TGroundNode *node)
return; // tylko pojedyncze trójkąty
if (node->iNumVerts != 3)
return; // tylko gdy jeden trójkąt
double x0 = 1000.0 * floor(0.001 * node->pCenter.x) - 200.0;
double x0 = 1000.0 * std::floor(0.001 * node->pCenter.x) - 200.0;
double x1 = x0 + 1400.0;
double z0 = 1000.0 * floor(0.001 * node->pCenter.z) - 200.0;
double z0 = 1000.0 * std::floor(0.001 * node->pCenter.z) - 200.0;
double z1 = z0 + 1400.0;
if ((node->Vertices[0].position.x >= x0) && (node->Vertices[0].position.x <= x1) &&
(node->Vertices[0].position.z >= z0) && (node->Vertices[0].position.z <= z1) &&
@@ -999,7 +841,6 @@ void TGround::RaTriangleDivider(TGroundNode *node)
TGroundNode * TGround::AddGroundNode(cParser *parser)
{ // wczytanie wpisu typu "node"
std::string str, str1, str2, str3, str4, Skin, DriverType, asNodeName;
int nv, i;
double tf, r, rmin, tf1, tf3;
int int1;
size_t int2;
@@ -1415,7 +1256,7 @@ TGroundNode * TGround::AddGroundNode(cParser *parser)
tmp->nNode[0].iType = TP_MODEL; // pierwszy zawiera model (dla delete)
tmp->nNode[0].Model = Global::pTerrainCompact;
tmp->nNode[0].iFlags = 0x200; // nie wyświetlany, ale usuwany
for (i = 1; i < tmp->iCount; ++i)
for (std::size_t i = 1; i < tmp->iCount; ++i)
{ // a reszta to submodele
tmp->nNode[i].iType = TP_SUBMODEL; //
tmp->nNode[i].smTerrain = Global::pTerrainCompact->TerrainSquare(i - 1);
@@ -1498,19 +1339,20 @@ TGroundNode * TGround::AddGroundNode(cParser *parser)
#endif
tmp->TextureID = GfxRenderer.GetTextureId( str, szTexturePath );
tmp->iFlags = GfxRenderer.Texture(tmp->TextureID).has_alpha ? 0x220 : 0x210; // z usuwaniem
if (((tmp->iType == GL_TRIANGLES) && (tmp->iFlags & 0x10)) ?
Global::pTerrainCompact->TerrainLoaded() :
false)
{ // jeśli jest tekstura nieprzezroczysta, a teren załadowany, to pomijamy trójkąty
do
{ // pomijanie trójkątów
if( (tmp->iType == GL_TRIANGLES)
&& (tmp->iFlags & 0x10)
&& (Global::pTerrainCompact->TerrainLoaded()) ) {
// jeśli jest tekstura nieprzezroczysta, a teren załadowany, to pomijamy trójkąty
do {
// pomijanie trójkątów
parser->getTokens();
*parser >> token;
} while (token.compare("endtri") != 0);
}
else
{
TGroundVertex vertex;
TGroundVertex vertex, vertex1, vertex2;
std::size_t vertexcount { 0 };
do {
parser->getTokens( 8, false );
*parser
@@ -1522,14 +1364,6 @@ TGroundNode * TGround::AddGroundNode(cParser *parser)
>> vertex.normal.z
>> vertex.texture.s
>> vertex.texture.t;
/*
vertex.position.RotateZ( aRotate.z / 180 * M_PI );
vertex.position.RotateX( aRotate.x / 180 * M_PI );
vertex.position.RotateY( aRotate.y / 180 * M_PI );
vertex.normal.RotateZ( aRotate.z / 180 * M_PI );
vertex.normal.RotateX( aRotate.x / 180 * M_PI );
vertex.normal.RotateY( aRotate.y / 180 * M_PI );
*/
vertex.position = glm::rotateZ( vertex.position, aRotate.z / 180 * M_PI );
vertex.position = glm::rotateX( vertex.position, aRotate.x / 180 * M_PI );
vertex.position = glm::rotateY( vertex.position, aRotate.y / 180 * M_PI );
@@ -1538,19 +1372,52 @@ TGroundNode * TGround::AddGroundNode(cParser *parser)
vertex.normal = glm::rotateY( vertex.normal, static_cast<float>( aRotate.y / 180 * M_PI ) );
vertex.position += glm::dvec3( pOrigin.x, pOrigin.y, pOrigin.z );
tmp->pCenter += vertex.position;
importedvertices.emplace_back( vertex );
// convert all data to gl_triangles to allow data merge for matching nodes
switch( tmp->iType ) {
case GL_TRIANGLES: {
importedvertices.emplace_back( vertex );
break;
}
case GL_TRIANGLE_FAN: {
if( vertexcount == 0 ) { vertex1 = vertex; }
else if( vertexcount == 1 ) { vertex2 = vertex; }
else if( vertexcount >= 2 ) {
importedvertices.emplace_back( vertex1 );
importedvertices.emplace_back( vertex2 );
importedvertices.emplace_back( vertex );
vertex2 = vertex;
}
++vertexcount;
break;
}
case GL_TRIANGLE_STRIP: {
if( vertexcount == 0 ) { vertex1 = vertex; }
else if( vertexcount == 1 ) { vertex2 = vertex; }
else if( vertexcount >= 2 ) {
importedvertices.emplace_back( vertex1 );
importedvertices.emplace_back( vertex2 );
importedvertices.emplace_back( vertex );
vertex1 = vertex2;
vertex2 = vertex;
}
++vertexcount;
break;
}
default: { break; }
}
parser->getTokens();
*parser >> token;
} while (token.compare("endtri") != 0);
nv = (int)importedvertices.size();
tmp->iType = GL_TRIANGLES;
auto const nv = importedvertices.size();
tmp->Init(nv); // utworzenie tablicy wierzchołków
tmp->pCenter /= (nv > 0 ? nv : 1);
r = 0;
for (int i = 0; i < nv; i++)
for (std::size_t i = 0; i < nv; ++i)
{
tmp->Vertices[i] = importedvertices[i];
tf = SquareMagnitude( tmp->Vertices[ i ].position - tmp->pCenter );
@@ -1571,8 +1438,10 @@ TGroundNode * TGround::AddGroundNode(cParser *parser)
>> tmp->Diffuse.b
>> tmp->fLineThickness;
tmp->Diffuse /= 255.0f;
TGroundVertex vertex;
i = 0;
TGroundVertex vertex, vertex0, vertex1;
std::size_t vertexcount{ 0 };
parser->getTokens();
*parser >> token;
do {
@@ -1581,32 +1450,64 @@ TGroundNode * TGround::AddGroundNode(cParser *parser)
*parser
>> vertex.position.y
>> vertex.position.z;
/*
vertex.position.RotateZ( aRotate.z / 180 * M_PI );
vertex.position.RotateX( aRotate.x / 180 * M_PI );
vertex.position.RotateY( aRotate.y / 180 * M_PI );
*/
vertex.position = glm::rotateZ( vertex.position, aRotate.z / 180 * M_PI );
vertex.position = glm::rotateX( vertex.position, aRotate.x / 180 * M_PI );
vertex.position = glm::rotateY( vertex.position, aRotate.y / 180 * M_PI );
vertex.position += glm::dvec3( pOrigin.x, pOrigin.y, pOrigin.z );
tmp->pCenter += vertex.position;
importedvertices.emplace_back( vertex );
++i;
// convert all data to gl_lines to allow data merge for matching nodes
switch( tmp->iType ) {
case GL_LINES: {
importedvertices.emplace_back( vertex );
break;
}
case GL_LINE_STRIP: {
if( vertexcount > 0 ) {
importedvertices.emplace_back( vertex1 );
importedvertices.emplace_back( vertex );
}
vertex1 = vertex;
++vertexcount;
break;
}
case GL_LINE_LOOP: {
if( vertexcount == 0 ) {
vertex0 = vertex;
vertex1 = vertex;
}
else {
importedvertices.emplace_back( vertex1 );
importedvertices.emplace_back( vertex );
}
vertex1 = vertex;
++vertexcount;
break;
}
default: { break; }
}
parser->getTokens();
*parser >> token;
} while( token.compare( "endline" ) != 0 );
nv = i;
// tmp->Init(nv);
// add closing line for the loop
if( ( tmp->iType == GL_LINE_LOOP )
&& ( vertexcount > 2 ) ) {
importedvertices.emplace_back( vertex1 );
importedvertices.emplace_back( vertex0 );
}
if( importedvertices.size() % 2 != 0 ) {
ErrorLog( "Lines node specified odd number of vertices, encountered in file \"" + parser->Name() + "\"" );
importedvertices.pop_back();
}
tmp->iType = GL_LINES;
auto const nv = importedvertices.size();
tmp->Points = new glm::dvec3[ nv ];
tmp->iNumPts = nv;
tmp->pCenter /= ( nv > 0 ? nv : 1 );
for( int i = 0; i < nv; i++ )
for( std::size_t i = 0; i < nv; ++i ) {
tmp->Points[ i ] = importedvertices[ i ].position;
}
break;
}
}
@@ -1622,7 +1523,7 @@ TSubRect * TGround::FastGetSubRect(int iCol, int iRow)
sc = iCol - bc * iNumSubRects;
if ((br < 0) || (bc < 0) || (br >= iNumRects) || (bc >= iNumRects))
return NULL;
return (Rects[bc][br].FastGetRect(sc, sr));
return (Rects[bc][br].FastGetSubRect(sc, sr));
}
TSubRect * TGround::GetSubRect(int iCol, int iRow)
@@ -1634,7 +1535,7 @@ TSubRect * TGround::GetSubRect(int iCol, int iRow)
sc = iCol - bc * iNumSubRects;
if ((br < 0) || (bc < 0) || (br >= iNumRects) || (bc >= iNumRects))
return NULL; // jeśli poza mapą
return (Rects[bc][br].SafeGetRect(sc, sr)); // pobranie małego kwadratu
return (Rects[bc][br].SafeGetSubRect(sc, sr)); // pobranie małego kwadratu
}
TEvent * TGround::FindEvent(const std::string &asEventName)
@@ -1670,23 +1571,21 @@ void TGround::FirstInit()
return; // Ra: żeby nie robiło się dwa razy
bInitDone = true;
WriteLog("InitNormals");
int i, j;
for (i = 0; i < TP_LAST; ++i)
{
for (TGroundNode *Current = nRootOfType[i]; Current; Current = Current->nNext)
{
for (int type = 0; type < TP_LAST; ++type) {
for (TGroundNode *Current = nRootOfType[type]; Current != nullptr; Current = Current->nNext) {
Current->InitNormals();
if (Current->iType != TP_DYNAMIC)
{ // pojazdów w ogóle nie dotyczy dodawanie do mapy
if( ( i == TP_EVLAUNCH )
if( ( type == TP_EVLAUNCH )
&& ( true == Current->EvLaunch->IsGlobal() ) ) {
// dodanie do globalnego obiektu
srGlobal.NodeAdd( Current );
}
else if (i == TP_TERRAIN)
else if (type == TP_TERRAIN)
{ // specjalne przetwarzanie terenu wczytanego z pliku E3D
TGroundRect *gr;
for (j = 1; j < Current->iCount; ++j)
for (int j = 1; j < Current->iCount; ++j)
{ // od 1 do końca są zestawy trójkątów
std::string xxxzzz = Current->nNode[j].smTerrain->pName; // pobranie nazwy
gr = GetRect(
@@ -1706,6 +1605,7 @@ void TGround::FirstInit()
// dodajemy do kwadratu kilometrowego
// override visibility ranges, to ensure the content is drawn from far enough
// TODO: subclass NodeAdd() for the ground cell and specialize it, instead of this
// TODO: given their view ranges are the same, combine the geometry in single per-material nodes
Current->fSquareRadius = 50000.0 * 50000.0;
Current->fSquareMinRadius = 0.0;
GetRect( Current->pCenter.x, Current->pCenter.z )->NodeAdd( Current );
@@ -1713,8 +1613,8 @@ void TGround::FirstInit()
}
}
}
for (i = 0; i < iNumRects; ++i)
for (j = 0; j < iNumRects; ++j)
for (std::size_t i = 0; i < iNumRects; ++i)
for (std::size_t j = 0; j < iNumRects; ++j)
Rects[i][j].Optimize(); // optymalizacja obiektów w sektorach
WriteLog("InitNormals OK");
@@ -1751,7 +1651,7 @@ bool TGround::Init(std::string File)
std::stack<Math3D::vector3> OriginStack; // stos zagnieżdżenia origin
TGroundNode *LastNode = NULL; // do użycia w trainset
TGroundNode *LastNode = nullptr; // do użycia w trainset
iNumNodes = 0;
token = "";
parser.getTokens();
@@ -1763,64 +1663,76 @@ bool TGround::Init(std::string File)
++processed;
if( processed % 1000 == 0 )
{
glfwPollEvents();
UILayer.set_progress( parser.getProgress(), parser.getFullProgress() );
GfxRenderer.Render();
glfwPollEvents();
}
str = token;
if (str == "node")
{
LastNode = AddGroundNode(&parser); // rozpoznanie węzła
if (LastNode)
{ // jeżeli przetworzony poprawnie
if (LastNode->iType == GL_TRIANGLES)
{
if (!LastNode->Vertices)
SafeDelete(LastNode); // usuwamy nieprzezroczyste trójkąty terenu
}
else if( ( LastNode->iType == TP_TRACTION )
&& ( false == Global::bLoadTraction ) ) {
SafeDelete( LastNode ); // usuwamy druty, jeśli wyłączone
if (str == "node") {
// rozpoznanie węzła
LastNode = AddGroundNode(&parser);
if (LastNode) {
// jeżeli przetworzony poprawnie
switch( LastNode->iType ) {
// validate the new node
case GL_TRIANGLES: {
if( LastNode->Vertices == nullptr ) {
SafeDelete( LastNode );
}
break;
}
case TP_TRACTION: {
if( false == Global::bLoadTraction ) {
// usuwamy druty, jeśli wyłączone
SafeDelete( LastNode );
}
break;
}
default: {
break;
}
}
if (LastNode) // dopiero na koniec dopisujemy do tablic
if (LastNode->iType != TP_DYNAMIC)
{ // jeśli nie jest pojazdem
// ostatni dodany dołączamy na końcu nowego
LastNode->nNext = nRootOfType[LastNode->iType];
if( LastNode ) {
// dopiero na koniec dopisujemy do tablic
if( LastNode->iType != TP_DYNAMIC ) {
// jeśli nie jest pojazdem ostatni dodany dołączamy na końcu nowego
LastNode->nNext = nRootOfType[ LastNode->iType ];
// ustawienie nowego na początku listy
nRootOfType[LastNode->iType] = LastNode;
iNumNodes++;
nRootOfType[ LastNode->iType ] = LastNode;
++iNumNodes;
}
else
{ // jeśli jest pojazdem
// if (!bInitDone) FirstInit(); //jeśli nie było w scenerii
if (LastNode->DynamicObject->Mechanik) // ale może być pasażer
if (LastNode->DynamicObject->Mechanik
->Primary()) // jeśli jest głównym (pasażer nie jest)
nTrainSetDriver =
LastNode; // pojazd, któremu zostanie wysłany rozkład
else { // jeśli jest pojazdem
if( ( LastNode->DynamicObject->Mechanik != nullptr )
&& ( LastNode->DynamicObject->Mechanik->Primary() ) ) {
// jeśli jest głównym (pasażer nie jest)
nTrainSetDriver = LastNode; // pojazd, któremu zostanie wysłany rozkład
}
LastNode->nNext = nRootDynamic;
nRootDynamic = LastNode; // dopisanie z przodu do listy
// if (bTrainSet && (LastNode?(LastNode->iType==TP_DYNAMIC):false))
if (nTrainSetNode) // jeżeli istnieje wcześniejszy TP_DYNAMIC
if( nTrainSetNode != nullptr ) {
// jeżeli istnieje wcześniejszy TP_DYNAMIC
nTrainSetNode->DynamicObject->AttachPrev(
LastNode->DynamicObject,
TempConnectionType[iTrainSetWehicleNumber - 2]);
TempConnectionType[ iTrainSetWehicleNumber - 2 ] );
}
nTrainSetNode = LastNode; // ostatnio wczytany
if (TempConnectionType[iTrainSetWehicleNumber - 1] ==
0) // jeśli sprzęg jest zerowy, to wysłać rozkład do składu
if( TempConnectionType[ iTrainSetWehicleNumber - 1 ] == 0 ) // jeśli sprzęg jest zerowy, to wysłać rozkład do składu
{ // powinien też tu wchodzić, gdy pojazd bez trainset
if (nTrainSetDriver) // pojazd, któremu zostanie wysłany rozkład
if( nTrainSetDriver ) // pojazd, któremu zostanie wysłany rozkład
{ // wysłanie komendy "Timetable" ustawia odpowiedni tryb jazdy
nTrainSetDriver->DynamicObject->Mechanik->DirectionInitial();
nTrainSetDriver->DynamicObject->Mechanik->PutCommand(
"Timetable:" + asTrainName, fTrainSetVel, 0, NULL);
nTrainSetDriver =
NULL; // a przy "endtrainset" już wtedy nie potrzeba
"Timetable:" + asTrainName,
fTrainSetVel, 0,
nullptr );
nTrainSetDriver = nullptr; // a przy "endtrainset" już wtedy nie potrzeba
}
}
}
}
}
else
{
@@ -1927,10 +1839,11 @@ bool TGround::Init(std::string File)
RootEvent = tmp;
if (!found)
{ // jeśli nazwa wystąpiła, to do kolejki i wyszukiwarki dodawany jest tylko pierwszy
if (RootEvent->Type != tp_Ignored)
if (RootEvent->asName.find(
"onstart") != std::string::npos) // event uruchamiany automatycznie po starcie
AddToQuery(RootEvent, NULL); // dodanie do kolejki
if( ( RootEvent->Type != tp_Ignored )
&& ( RootEvent->asName.find( "onstart" ) != std::string::npos ) ) {
// event uruchamiany automatycznie po starcie
AddToQuery( RootEvent, NULL ); // dodanie do kolejki
}
m_eventmap.emplace( tmp->asName, tmp ); // dodanie do wyszukiwarki
}
}

View File

@@ -21,8 +21,6 @@ http://mozilla.org/MPL/2.0/.
#include "Names.h"
#include "lightarray.h"
using namespace Math3D;
typedef int TGroundNodeType;
// Ra: zmniejszone liczby, aby zrobić tabelkę i zoptymalizować wyszukiwanie
const int TP_MODEL = 10;
@@ -95,8 +93,14 @@ struct TGroundVertex
texture = interpolate( v1.texture, v2.texture, static_cast<float>( factor ) );
}
};
class TGroundNode : public Resource
/*
// ground node holding single, unique piece of 3d geometry. TBD, TODO: unify this with basic 3d model node
struct mesh_node {
std::vector<TGroundVertex> vertices;
geometry_handle geometry; // geometry prepared for drawing
};
*/
class TGroundNode /*: public Resource*/
{ // obiekt scenerii
friend class opengl_renderer;
@@ -138,6 +142,9 @@ public:
int iVersion; // wersja siatki (do wykonania rekompilacji)
GLuint DisplayListID; // numer siatki DisplayLists
int iVboPtr; // indeks w buforze VBO
// NOTE: geometry handle is duplicated in (anim)model(3d), as well as in track and traction type nodes
// TODO: clean this up when node types are refactored into an inheritance/composition scheme
geometry_handle m_geometry; // geometry of the submodel
int iFlags; // tryb przezroczystości: 0x10-nieprz.,0x20-przezroczysty,0x30-mieszany
texture_handle TextureID; // główna (jedna) tekstura obiektu
glm::vec3
@@ -153,25 +160,10 @@ public:
~TGroundNode();
void Init(int n);
void InitNormals();
// bool Disable();
inline TGroundNode * Find(const std::string &asNameToFind, TGroundNodeType iNodeType)
{ // wyszukiwanie czołgowe z typem
if ((iNodeType == iType) && (asNameToFind == asName))
return this;
else if (nNext)
return nNext->Find(asNameToFind, iNodeType);
return NULL;
};
void Compile(glm::dvec3 const &Origin, bool const Multiple = false);
/*
void Release();
*/
void RenderHidden(); // obsługa dźwięków i wyzwalaczy zdarzeń
#ifdef EU07_USE_OLD_RENDERCODE
// (McZapkie-131202)
void RaRenderVBO(); // renderowanie (nieprzezroczystych) ze wspólnego VBO
#endif
};
struct bounding_area {
@@ -180,7 +172,7 @@ struct bounding_area {
float radius { 0.0f }; // radius of the bounding sphere
};
class TSubRect : public Resource, public CMesh
class TSubRect : /*public Resource,*/ public CMesh
{ // sektor składowy kwadratu kilometrowego
public:
bounding_area m_area;
@@ -209,12 +201,13 @@ class TSubRect : public Resource, public CMesh
void LoadNodes(); // utworzenie VBO sektora
public:
virtual ~TSubRect();
/*
virtual void Release(); // zwalnianie VBO sektora
*/
void NodeAdd(TGroundNode *Node); // dodanie obiektu do sektora na etapie rozdzielania na sektory
void Sort(); // optymalizacja obiektów w sektorze (sortowanie wg tekstur)
TTrack * FindTrack(vector3 *Point, int &iConnection, TTrack *Exclude);
TTraction * FindTraction(glm::dvec3 const &Point, int &iConnection, TTraction *Exclude);
bool StartVBO(); // ustwienie VBO sektora dla (nRenderRect), (nRenderRectAlpha) i (nRenderWires)
bool RaTrackAnimAdd(TTrack *t); // zgłoszenie toru do animacji
void RaAnimate(); // przeliczenie animacji torów
void RenderSounds(); // dźwięki pojazdów z niewidocznych sektorów
@@ -244,7 +237,7 @@ private:
public:
virtual ~TGroundRect();
// pobranie wskaźnika do małego kwadratu, utworzenie jeśli trzeba
TSubRect * SafeGetRect(int iCol, int iRow) {
TSubRect * SafeGetSubRect(int iCol, int iRow) {
if( !pSubRects ) {
// utworzenie małych kwadratów
Init();
@@ -252,7 +245,7 @@ public:
return pSubRects + iRow * iNumSubRects + iCol; // zwrócenie właściwego
};
// pobranie wskaźnika do małego kwadratu, bez tworzenia jeśli nie ma
TSubRect * FastGetRect(int iCol, int iRow) {
TSubRect * FastGetSubRect(int iCol, int iRow) {
return (pSubRects ? pSubRects + iRow * iNumSubRects + iCol : NULL);
};
// optymalizacja obiektów w sektorach
@@ -282,7 +275,9 @@ class TGround
*tmpEvent = nullptr,
*tmp2Event = nullptr,
*OldQRE = nullptr;
/*
TSubRect *pRendered[1500]; // lista renderowanych sektorów
*/
int iNumNodes = 0;
vector3 pOrigin;
vector3 aRotate;
@@ -293,6 +288,7 @@ class TGround
event_map m_eventmap;
TNames<TGroundNode *> m_trackmap;
light_array m_lights; // collection of dynamic light sources present in the scene
bool PROBLEND;
private: // metody prywatne
bool EventConditon(TEvent *e);
@@ -351,7 +347,6 @@ class TGround
private:
void RaTriangleDivider(TGroundNode *node);
void Navigate(std::string const &ClassName, UINT Msg, WPARAM wParam, LPARAM lParam);
bool PROBLEND;
public:
void WyslijEvent(const std::string &e, const std::string &d);

View File

@@ -1041,7 +1041,7 @@ void TSubModel::RaAnimation(TAnimType a)
//---------------------------------------------------------------------------
void TSubModel::RaArrayFill(CVertNormTex *Vert)
void TSubModel::RaArrayFill(basic_vertex *Vert)
{ // wypełnianie tablic VBO
if (Child)
Child->RaArrayFill(Vert);
@@ -1159,17 +1159,11 @@ TModel3d::~TModel3d()
{
// SafeDeleteArray(Materials);
if (iFlags & 0x0200)
{ // wczytany z pliku tekstowego, submodele sprzątają
// same
{ // wczytany z pliku tekstowego, submodele sprzątają same
SafeDelete(Root); // submodele się usuną rekurencyjnie
}
else
{ // wczytano z pliku binarnego (jest właścicielem tablic)
#ifdef EU07_USE_OLD_VERTEXBUFFER
m_pVNT = nullptr; // nie usuwać tego, bo wskazuje na iModel
#else
m_pVNT.clear();
#endif
Root = nullptr;
delete[] iModel; // usuwamy cały wczytany plik i to wystarczy
}
@@ -1344,6 +1338,9 @@ void TSubModel::serialize(std::ostream &s,
void TModel3d::SaveToBinFile(char const *FileName)
{
// TODO: re-implement!
return;
WriteLog("saving e3d model..");
//m7todo: można by zoptymalizować robiąc unordered_map
@@ -1379,18 +1376,20 @@ void TModel3d::SaveToBinFile(char const *FileName)
sn_utils::ls_uint32(s, 8 + (uint32_t)transforms.size() * 64);
for (size_t i = 0; i < transforms.size(); i++)
transforms[i].serialize_float32(s);
/*
MakeArray(iNumVerts);
#ifdef EU07_USE_OLD_VERTEXBUFFER
Root->RaArrayFill(m_pVNT);
#else
Root->RaArrayFill( m_pVNT.data() );
#endif
*/
sn_utils::ls_uint32(s, MAKE_ID4('V', 'N', 'T', '0'));
sn_utils::ls_uint32(s, 8 + iNumVerts * 32);
/*
for (size_t i = 0; i < (size_t)iNumVerts; i++)
m_pVNT[i].serialize(s);
*/
if (textures.size())
{
sn_utils::ls_uint32(s, MAKE_ID4('T', 'E', 'X', '0'));
@@ -1470,11 +1469,6 @@ void TSubModel::deserialize(std::istream &s)
void TModel3d::deserialize(std::istream &s, size_t size, bool dynamic)
{
#ifdef EU07_USE_OLD_VERTEXBUFFER
m_pVNT = nullptr;
#else
m_pVNT.clear();
#endif
Root = nullptr;
float4x4 *tm = nullptr;
if( m_geometrybank == NULL ) {
@@ -1507,19 +1501,16 @@ void TModel3d::deserialize(std::istream &s, size_t size, bool dynamic)
}
else if (type == MAKE_ID4('V', 'N', 'T', '0'))
{
#ifdef EU07_USE_OLD_VERTEXBUFFER
if (m_pVNT != nullptr)
#else
if( false == m_pVNT.empty() )
#endif
throw std::runtime_error("e3d: duplicated VNT chunk");
/*
size_t vt_cnt = size / 32;
if (m_pVNT != nullptr)
throw std::runtime_error("e3d: duplicated VNT chunk");
size_t vt_cnt = size / 32;
iNumVerts = (int)vt_cnt;
m_nVertexCount = (int)vt_cnt;
#ifdef EU07_USE_OLD_VERTEXBUFFER
assert( m_pVNT == nullptr );
m_pVNT = new CVertNormTex[vt_cnt];
m_pVNT = new basic_vertex[vt_cnt];
#else
m_pVNT.resize( vt_cnt );
#endif
@@ -1613,13 +1604,9 @@ void TModel3d::deserialize(std::istream &s, size_t size, bool dynamic)
*/
for (size_t i = 0; (int)i < iSubModelsCount; ++i)
{
#ifdef EU07_USE_OLD_VERTEXBUFFER
Root[i].BinInit( Root, tm, &Textures, &Names, dynamic );
#else
Root[ i ].BinInit( Root, tm, (float8*)m_pVNT.data(), &Textures, &Names, dynamic );
#endif
if (Root[i].ChildGet())
if (Root[i].ChildGet())
Root[i].ChildGet()->Parent = &Root[i];
if (Root[i].NextGet())
Root[i].NextGet()->Parent = Root[i].Parent;

View File

@@ -168,7 +168,7 @@ public:
TSubModel * GetFromName(char const *search, bool i = true);
inline float4x4 * GetMatrix() { return fMatrix; };
inline void Hide() { iVisible = 0; };
void RaArrayFill(CVertNormTex *Vert);
void RaArrayFill(basic_vertex *Vert);
int FlagsCheck();
void WillBeAnimated()
{

View File

@@ -319,16 +319,15 @@ vector3 TSegment::FastGetPoint(double t)
return (bCurve ? RaInterpolate(t) : ((1.0 - t) * Point1 + (t)*Point2));
}
int TSegment::RenderLoft( CVertNormTex* &Output, Math3D::vector3 const &Origin, const vector6 *ShapePoints, int iNumShapePoints, double fTextureLength, double Texturescale, int iSkip, int iEnd, double fOffsetX, vector3 **p, bool bRender)
bool TSegment::RenderLoft( vertex_array &Output, Math3D::vector3 const &Origin, const vector6 *ShapePoints, int iNumShapePoints, double fTextureLength, double Texturescale, int iSkip, int iEnd, double fOffsetX, vector3 **p, bool bRender)
{ // generowanie trójkątów dla odcinka trajektorii ruchu
// standardowo tworzy triangle_strip dla prostego albo ich zestaw dla łuku
// po modyfikacji - dla ujemnego (iNumShapePoints) w dodatkowych polach tabeli
// podany jest przekrój końcowy
// podsypka toru jest robiona za pomocą 6 punktów, szyna 12, drogi i rzeki na 3+2+3
int vertexcount{ 0 };
if( !fTsBuffer )
return vertexcount; // prowizoryczne zabezpieczenie przed wysypem - ustalić faktyczną przyczynę
return false; // prowizoryczne zabezpieczenie przed wysypem - ustalić faktyczną przyczynę
vector3 pos1, pos2, dir, parallel1, parallel2, pt, norm;
double s, step, fOffset, tv1, tv2, t, fEnd;
@@ -378,11 +377,6 @@ int TSegment::RenderLoft( CVertNormTex* &Output, Math3D::vector3 const &Origin,
dir = FastGetDirection( t, fOffset ); // nowy wektor kierunku
parallel2 = Normalize( vector3( -dir.z, 0.0, dir.x ) ); // wektor poprzeczny
if( Output == nullptr ) {
// immediate mode
::glBegin( GL_TRIANGLE_STRIP );
}
if( trapez ) {
for( int j = 0; j < iNumShapePoints; ++j ) {
pt = parallel1 * ( jmm1 * ( ShapePoints[ j ].x - fOffsetX ) + m1 * ShapePoints[ j + iNumShapePoints ].x ) + pos1;
@@ -390,25 +384,12 @@ int TSegment::RenderLoft( CVertNormTex* &Output, Math3D::vector3 const &Origin,
pt -= Origin;
norm = ( jmm1 * ShapePoints[ j ].n.x + m1 * ShapePoints[ j + iNumShapePoints ].n.x ) * parallel1;
norm.y += jmm1 * ShapePoints[ j ].n.y + m1 * ShapePoints[ j + iNumShapePoints ].n.y;
if( bRender ) { // skrzyżowania podczas łączenia siatek mogą nie renderować poboczy, ale potrzebować punktów
if( Output == nullptr ) {
// immediate mode
::glNormal3f( norm.x, norm.y, norm.z );
::glTexCoord2f( (jmm1 * ShapePoints[ j ].z + m1 * ShapePoints[ j + iNumShapePoints ].z) / Texturescale, tv1 );
::glVertex3f( pt.x, pt.y, pt.z ); // pt nie mamy gdzie zapamiętać?
}
else {
Output->position.x = pt.x;
Output->position.y = pt.y;
Output->position.z = pt.z;
Output->normal.x = norm.x;
Output->normal.y = norm.y;
Output->normal.z = norm.z;
Output->texture.s = (jmm1 * ShapePoints[ j ].z + m1 * ShapePoints[ j + iNumShapePoints ].z) / Texturescale;
Output->texture.t = tv1;
++Output;
}
++vertexcount;
if( bRender ) {
// skrzyżowania podczas łączenia siatek mogą nie renderować poboczy, ale potrzebować punktów
Output.emplace_back(
glm::vec3 { pt.x, pt.y, pt.z },
glm::vec3 { norm.x, norm.y, norm.z },
glm::vec2 { ( jmm1 * ShapePoints[ j ].z + m1 * ShapePoints[ j + iNumShapePoints ].z ) / Texturescale, tv1 } );
}
if( p ) // jeśli jest wskaźnik do tablicy
if( *p )
@@ -423,25 +404,12 @@ int TSegment::RenderLoft( CVertNormTex* &Output, Math3D::vector3 const &Origin,
pt -= Origin;
norm = ( jmm1 * ShapePoints[ j ].n.x + m1 * ShapePoints[ j + iNumShapePoints ].n.x ) * parallel2;
norm.y += jmm1 * ShapePoints[ j ].n.y + m1 * ShapePoints[ j + iNumShapePoints ].n.y;
if( bRender ) { // skrzyżowania podczas łączenia siatek mogą nie renderować poboczy, ale potrzebować punktów
if( Output == nullptr ) {
// immediate mode
::glNormal3f( norm.x, norm.y, norm.z );
::glTexCoord2f( (jmm2 * ShapePoints[ j ].z + m2 * ShapePoints[ j + iNumShapePoints ].z) / Texturescale, tv2 );
::glVertex3f( pt.x, pt.y, pt.z );
}
else {
Output->position.x = pt.x;
Output->position.y = pt.y;
Output->position.z = pt.z;
Output->normal.x = norm.x;
Output->normal.y = norm.y;
Output->normal.z = norm.z;
Output->texture.s = (jmm2 * ShapePoints[ j ].z + m2 * ShapePoints[ j + iNumShapePoints ].z) / Texturescale;
Output->texture.t = tv2;
++Output;
}
++vertexcount;
if( bRender ) {
// skrzyżowania podczas łączenia siatek mogą nie renderować poboczy, ale potrzebować punktów
Output.emplace_back(
glm::vec3 { pt.x, pt.y, pt.z },
glm::vec3 { norm.x, norm.y, norm.z },
glm::vec2 { ( jmm2 * ShapePoints[ j ].z + m2 * ShapePoints[ j + iNumShapePoints ].z ) / Texturescale, tv2 } );
}
if( p ) // jeśli jest wskaźnik do tablicy
if( *p )
@@ -461,61 +429,30 @@ int TSegment::RenderLoft( CVertNormTex* &Output, Math3D::vector3 const &Origin,
pt -= Origin;
norm = ShapePoints[ j ].n.x * parallel1;
norm.y += ShapePoints[ j ].n.y;
if( Output == nullptr ) {
// immediate mode
::glNormal3f( norm.x, norm.y, norm.z );
::glTexCoord2f( ShapePoints[ j ].z / Texturescale, tv1 );
::glVertex3f( pt.x, pt.y, pt.z ); // punkt na początku odcinka
}
else {
Output->position.x = pt.x;
Output->position.y = pt.y;
Output->position.z = pt.z;
Output->normal.x = norm.x;
Output->normal.y = norm.y;
Output->normal.z = norm.z;
Output->texture.s = ShapePoints[ j ].z / Texturescale;
Output->texture.t = tv1;
++Output;
}
++vertexcount;
Output.emplace_back(
glm::vec3 { pt.x, pt.y, pt.z },
glm::vec3 { norm.x, norm.y, norm.z },
glm::vec2 { ShapePoints[ j ].z / Texturescale, tv1 } );
pt = parallel2 * ShapePoints[ j ].x + pos2;
pt.y += ShapePoints[ j ].y;
pt -= Origin;
norm = ShapePoints[ j ].n.x * parallel2;
norm.y += ShapePoints[ j ].n.y;
if( Output == nullptr ) {
// immediate mode
::glNormal3f( norm.x, norm.y, norm.z );
::glTexCoord2f( ShapePoints[ j ].z / Texturescale, tv2 );
::glVertex3f( pt.x, pt.y, pt.z ); // punkt na końcu odcinka
}
else {
Output->position.x = pt.x;
Output->position.y = pt.y;
Output->position.z = pt.z;
Output->normal.x = norm.x;
Output->normal.y = norm.y;
Output->normal.z = norm.z;
Output->texture.s = ShapePoints[ j ].z / Texturescale;
Output->texture.t = tv2;
++Output;
}
++vertexcount;
Output.emplace_back(
glm::vec3 { pt.x, pt.y, pt.z },
glm::vec3 { norm.x, norm.y, norm.z },
glm::vec2 { ShapePoints[ j ].z / Texturescale, tv2 } );
}
}
}
if( Output == nullptr ) {
// immediate mode
glEnd();
}
pos1 = pos2;
parallel1 = parallel2;
tv1 = tv2;
}
return vertexcount;
return true;
};
void TSegment::Render()

View File

@@ -9,8 +9,10 @@ http://mozilla.org/MPL/2.0/.
#ifndef SegmentH
#define SegmentH
/*
#include "VBO.h"
*/
#include "openglgeometrybank.h"
#include "dumb3d.h"
#include "Classes.h"
#include "usefull.h"
@@ -74,51 +76,35 @@ class TSegment
bool bCurve = false;
TSegment(TTrack *owner);
~TSegment();
bool Init(vector3 NewPoint1, vector3 NewPoint2, double fNewStep, double fNewRoll1 = 0,
double fNewRoll2 = 0);
bool Init(vector3 NewPoint1, vector3 NewPoint2, double fNewStep, double fNewRoll1 = 0, double fNewRoll2 = 0);
bool Init(vector3 &NewPoint1, vector3 NewCPointOut, vector3 NewCPointIn, vector3 &NewPoint2,
double fNewStep, double fNewRoll1 = 0, double fNewRoll2 = 0, bool bIsCurve = true);
inline double ComputeLength(); // McZapkie-150503
inline vector3 GetDirection1()
{
return bCurve ? CPointOut - Point1 : CPointOut;
};
inline vector3 GetDirection2()
{
return bCurve ? CPointIn - Point2 : CPointIn;
};
inline vector3 GetDirection1() {
return bCurve ? CPointOut - Point1 : CPointOut; };
inline vector3 GetDirection2() {
return bCurve ? CPointIn - Point2 : CPointIn; };
vector3 GetDirection(double fDistance);
vector3 GetDirection()
{
return CPointOut;
};
vector3 GetDirection() {
return CPointOut; };
vector3 FastGetDirection(double fDistance, double fOffset);
vector3 GetPoint(double fDistance);
void RaPositionGet(double fDistance, vector3 &p, vector3 &a);
vector3 FastGetPoint(double t);
inline vector3 FastGetPoint_0()
{
return Point1;
};
inline vector3 FastGetPoint_1()
{
return Point2;
};
inline double GetRoll(double const Distance)
{
return interpolate( fRoll1, fRoll2, Distance / fLength );
}
void GetRolls(double &r1, double &r2)
{ // pobranie przechyłek (do generowania trójkątów)
inline vector3 FastGetPoint_0() {
return Point1; };
inline vector3 FastGetPoint_1() {
return Point2; };
inline double GetRoll(double const Distance) {
return interpolate( fRoll1, fRoll2, Distance / fLength ); }
void GetRolls(double &r1, double &r2) {
// pobranie przechyłek (do generowania trójkątów)
r1 = fRoll1;
r2 = fRoll2;
}
int RenderLoft( CVertNormTex* &Output, Math3D::vector3 const &Origin, vector6 const *ShapePoints, int iNumShapePoints, double fTextureLength, double Texturescale = 1.0, int iSkip = 0, int iEnd = 0, double fOffsetX = 0.0, vector3 **p = nullptr, bool bRender = true);
r2 = fRoll2; }
bool RenderLoft( vertex_array &Output, Math3D::vector3 const &Origin, vector6 const *ShapePoints, int iNumShapePoints, double fTextureLength, double Texturescale = 1.0, int iSkip = 0, int iEnd = 0, double fOffsetX = 0.0, vector3 **p = nullptr, bool bRender = true);
void Render();
inline double GetLength()
{
return fLength;
};
inline double GetLength() {
return fLength; };
void MoveMe(vector3 pPosition)
{
Point1 += pPosition;
@@ -129,14 +115,10 @@ class TSegment
CPointOut += pPosition;
}
}
int RaSegCount()
{
return fTsBuffer ? iSegCount : 1;
};
void AngleSet(int i, double a)
{
fAngle[i] = a;
};
int RaSegCount() {
return fTsBuffer ? iSegCount : 1; };
void AngleSet(int i, double a) {
fAngle[i] = a; };
};
//---------------------------------------------------------------------------

558
Track.cpp
View File

@@ -177,7 +177,6 @@ void TTrack::Init()
case tt_Cross: // tylko dla skrzyżowania dróg
SwitchExtension = std::make_shared<TSwitchExtension>( this, 6 ); // 6 po³¹czeñ
SwitchExtension->vPoints = nullptr; // brak tablicy punktów
SwitchExtension->iPoints = 0;
SwitchExtension->bPoints = false; // tablica punktów nie wypełniona
SwitchExtension->iRoads = 4; // domyślnie 4
break;
@@ -203,7 +202,9 @@ TTrack * TTrack::Create400m(int what, double dx)
TSubRect *r = Global::pGround->GetSubRect(tmp->pCenter.x, tmp->pCenter.z);
r->NodeAdd(tmp); // dodanie toru do segmentu
r->Sort(); //żeby wyświetlał tabor z dodanego toru
/*
r->Release(); // usunięcie skompilowanych zasobów
*/
return trk;
};
@@ -313,7 +314,9 @@ TTrack * TTrack::NullCreate(int dir)
if (tmp2)
r->NodeAdd(tmp2); // drugiego też
r->Sort(); //żeby wyświetlał tabor z dodanego toru
/*
r->Release(); // usunięcie skompilowanych zasobów
*/
return trk;
};
@@ -989,22 +992,6 @@ bool TTrack::AddDynamicObject(TDynamicObject *Dynamic)
return true;
};
void TTrack::MoveMe(vector3 pPosition)
{ // to nie jest używane
if (SwitchExtension)
{
SwitchExtension->Segments[0]->MoveMe(1 * pPosition);
SwitchExtension->Segments[1]->MoveMe(1 * pPosition);
SwitchExtension->Segments[2]->MoveMe(3 * pPosition); // Ra: 3 razy?
SwitchExtension->Segments[3]->MoveMe(4 * pPosition);
}
else
{
Segment->MoveMe(pPosition);
};
ResourceManager::Unregister(this);
};
const int numPts = 4;
const int nnumPts = 12;
@@ -1039,10 +1026,10 @@ const vector6 iglica[nnumPts] = // iglica - vextor3(x,y,mapowanie tekstury)
vector6(-0.040, -0.180, 1.00, -1.000, 0.000,
0.000) // 1mm więcej, żeby nie nachodziły tekstury?
};
/*
void TTrack::Compile(GLuint tex)
{
CVertNormTex *immediate{ nullptr };
basic_vertex *immediate{ nullptr };
// generowanie treści dla Display Lists - model proceduralny
if (!tex)
@@ -1656,14 +1643,16 @@ void TTrack::Compile(GLuint tex)
if (Global::bManageNodes)
glEndList();
};
*/
void TTrack::Release()
{
/*
if (DisplayListID)
glDeleteLists(DisplayListID, 1);
DisplayListID = 0;
*/
};
/*
void TTrack::Render()
{
if (bVisible) // Ra: tory są renderowane sektorami i nie ma sensu każdorazowo liczyć odległości
@@ -1682,7 +1671,7 @@ void TTrack::Render()
Release(); // zwrotnica w trakcie animacji do odrysowania
}
};
*/
bool TTrack::CheckDynamicObject(TDynamicObject *Dynamic)
{ // sprawdzenie, czy pojazd jest przypisany do toru
for( auto dynamic : Dynamics ) {
@@ -1774,7 +1763,7 @@ void TTrack::RaAssign(TGroundNode *gn, TAnimModel *am, TEvent *done, TEvent *joi
am->GetContainer(NULL)->EventAssign(done); // zdarzenie zakończenia animacji
}
};
/*
int TTrack::RaArrayPrepare()
{ // przygotowanie tablic do skopiowania do VBO (zliczanie wierzchołków)
if (bVisible) // o ile w ogóle widać
@@ -1803,16 +1792,6 @@ int TTrack::RaArrayPrepare()
+ SwitchExtension->Segments[ 4 ]->RaSegCount()
+ SwitchExtension->Segments[ 5 ]->RaSegCount();
}
/*
if (fTexHeight1 >= 0) {
// normalne pobocze, na razie się składa z
return ( ( TextureID1 ? SwitchExtension->iPoints + SwitchExtension->iRoads + 2 : 0 ) + ( TextureID2 ? SwitchExtension->iPoints * 12 : 0 ) );
}
else {
// jeśli fTexHeight1<0, to są chodniki i może któregoś nie być
return ( ( TextureID1 ? SwitchExtension->iPoints + SwitchExtension->iRoads + 2 : 0 ) + ( TextureID2 ? SwitchExtension->iPoints * 6 : 0 ) );
}
*/
// each sub-segment covers only one side of the road, so it has points for single sideroad, if any
return ( ( TextureID1 ? SwitchExtension->iPoints + SwitchExtension->iRoads + 2 : 0 ) + ( TextureID2 ? SwitchExtension->iPoints * 6 : 0 ) );
}
@@ -1829,28 +1808,28 @@ int TTrack::RaArrayPrepare()
}
return 0;
};
void TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start, int const Vertexcount)
{ // wypełnianie tablic VBO
*/
// wypełnianie tablic VBO
void TTrack::create_geometry( geometrybank_handle const &Bank ) {
// Ra: trzeba rozdzielić szyny od podsypki, aby móc grupować wg tekstur
double fHTW = 0.5 * fabs(fTrackWidth);
double side = fabs(fTexWidth); // szerokść podsypki na zewnątrz szyny albo pobocza
double slop = fabs(fTexSlope); // brzeg zewnętrzny
double rozp = fHTW + side + slop; // brzeg zewnętrzny
double hypot1 = hypot(slop, fTexHeight1); // rozmiar pochylenia do liczenia normalnych
double const fHTW = 0.5 * std::fabs(fTrackWidth);
double const side = std::fabs(fTexWidth); // szerokść podsypki na zewnątrz szyny albo pobocza
double const slop = std::fabs(fTexSlope); // brzeg zewnętrzny
double const rozp = fHTW + side + slop; // brzeg zewnętrzny
double hypot1 = std::hypot(slop, fTexHeight1); // rozmiar pochylenia do liczenia normalnych
if (hypot1 == 0.0)
hypot1 = 1.0;
vector3 normal1 = vector3(fTexSlope / hypot1, fTexHeight1 / hypot1, 0.0); // wektor normalny
vector3 normal1 { fTexSlope / hypot1, fTexHeight1 / hypot1, 0.0 }; // wektor normalny
double fHTW2, side2, slop2, rozp2, fTexHeight2, hypot2;
vector3 normal2;
if (iTrapezoid & 2) // ten bit oznacza, że istnieje odpowiednie pNext
{ // Ra: jest OK
fHTW2 = 0.5 * fabs(trNext->fTrackWidth); // połowa rozstawu/nawierzchni
side2 = fabs(trNext->fTexWidth);
slop2 = fabs(trNext->fTexSlope); // nie jest używane później
fHTW2 = 0.5 * std::fabs(trNext->fTrackWidth); // połowa rozstawu/nawierzchni
side2 = std::fabs(trNext->fTexWidth);
slop2 = std::fabs(trNext->fTexSlope); // nie jest używane później
rozp2 = fHTW2 + side2 + slop2;
fTexHeight2 = trNext->fTexHeight1;
hypot2 = hypot(slop2, fTexHeight2);
hypot2 = std::hypot(slop2, fTexHeight2);
if (hypot2 == 0.0)
hypot2 = 1.0;
normal2 = vector3(trNext->fTexSlope / hypot2, fTexHeight2 / hypot2, 0.0);
@@ -1877,37 +1856,48 @@ void TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start, int cons
Segment->GetRolls(roll1, roll2);
else
roll1 = roll2 = 0.0; // dla zwrotnic
double sin1 = sin(roll1), cos1 = cos(roll1), sin2 = sin(roll2), cos2 = cos(roll2);
double sin1 = std::sin(roll1), cos1 = std::cos(roll1), sin2 = std::sin(roll2), cos2 = std::cos(roll2);
// zwykla szyna: //Ra: czemu główki są asymetryczne na wysokości 0.140?
vector6 rpts1[24], rpts2[24], rpts3[24], rpts4[24];
int i;
for (i = 0; i < 12; ++i)
{
rpts1[i] = vector6((fHTW + szyna[i].x) * cos1 + szyna[i].y * sin1,
-(fHTW + szyna[i].x) * sin1 + szyna[i].y * cos1, szyna[i].z,
+szyna[i].n.x * cos1 + szyna[i].n.y * sin1,
-szyna[i].n.x * sin1 + szyna[i].n.y * cos1, 0.0);
rpts2[11 - i] = vector6((-fHTW - szyna[i].x) * cos1 + szyna[i].y * sin1,
-(-fHTW - szyna[i].x) * sin1 + szyna[i].y * cos1, szyna[i].z,
-szyna[i].n.x * cos1 + szyna[i].n.y * sin1,
+szyna[i].n.x * sin1 + szyna[i].n.y * cos1, 0.0);
rpts1[i] = vector6(
(fHTW + szyna[i].x) * cos1 + szyna[i].y * sin1,
-(fHTW + szyna[i].x) * sin1 + szyna[i].y * cos1,
szyna[i].z,
szyna[i].n.x * cos1 + szyna[i].n.y * sin1,
-szyna[i].n.x * sin1 + szyna[i].n.y * cos1,
0.0);
rpts2[11 - i] = vector6(
(-fHTW - szyna[i].x) * cos1 + szyna[i].y * sin1,
-(-fHTW - szyna[i].x) * sin1 + szyna[i].y * cos1,
szyna[i].z,
-szyna[i].n.x * cos1 + szyna[i].n.y * sin1,
szyna[i].n.x * sin1 + szyna[i].n.y * cos1,
0.0);
}
if (iTrapezoid) // trapez albo przechyłki, to oddzielne punkty na końcu
for (i = 0; i < 12; ++i)
{
rpts1[12 + i] = vector6((fHTW2 + szyna[i].x) * cos2 + szyna[i].y * sin2,
-(fHTW2 + szyna[i].x) * sin2 + szyna[i].y * cos2,
szyna[i].z, +szyna[i].n.x * cos2 + szyna[i].n.y * sin2,
-szyna[i].n.x * sin2 + szyna[i].n.y * cos2, 0.0);
rpts2[23 - i] = vector6((-fHTW2 - szyna[i].x) * cos2 + szyna[i].y * sin2,
-(-fHTW2 - szyna[i].x) * sin2 + szyna[i].y * cos2,
szyna[i].z, -szyna[i].n.x * cos2 + szyna[i].n.y * sin2,
+szyna[i].n.x * sin2 + szyna[i].n.y * cos2, 0.0);
rpts1[12 + i] = vector6(
(fHTW2 + szyna[i].x) * cos2 + szyna[i].y * sin2,
-(fHTW2 + szyna[i].x) * sin2 + szyna[i].y * cos2,
szyna[i].z,
szyna[i].n.x * cos2 + szyna[i].n.y * sin2,
-szyna[i].n.x * sin2 + szyna[i].n.y * cos2,
0.0);
rpts2[23 - i] = vector6(
(-fHTW2 - szyna[i].x) * cos2 + szyna[i].y * sin2,
-(-fHTW2 - szyna[i].x) * sin2 + szyna[i].y * cos2,
szyna[i].z,
-szyna[i].n.x * cos2 + szyna[i].n.y * sin2,
szyna[i].n.x * sin2 + szyna[i].n.y * cos2,
0.0);
}
switch (eType) // dalej zależnie od typu
{
case tt_Table: // obrotnica jak zwykły tor, tylko animacja dochodzi
SwitchExtension->iLeftVBO = Vert - Start; // indeks toru obrotnicy
case tt_Normal:
if (TextureID2)
{ // podsypka z podkładami jest tylko dla zwykłego toru
@@ -1969,12 +1959,33 @@ void TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start, int cons
bpts1[3] = vector6(-rozp, -fTexHeight1 - 0.18, 0.5 + map12, -normal1.x, -normal1.y, 0.0); // prawy skos
}
}
Segment->RenderLoft(Vert, origin, bpts1, iTrapezoid ? -4 : 4, fTexLength);
vertex_array vertices;
Segment->RenderLoft(vertices, origin, bpts1, iTrapezoid ? -4 : 4, fTexLength);
if( ( Bank == 0 ) && ( false == Geometry2.empty() ) ) {
// special variant, replace existing data for a turntable track
GfxRenderer.Replace( vertices, Geometry2[ 0 ] );
}
else {
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
}
}
if (TextureID1)
{ // szyny - generujemy dwie, najwyżej rysować się będzie jedną
Segment->RenderLoft(Vert, origin, rpts1, iTrapezoid ? -nnumPts : nnumPts, fTexLength);
Segment->RenderLoft(Vert, origin, rpts2, iTrapezoid ? -nnumPts : nnumPts, fTexLength);
vertex_array vertices;
if( ( Bank == 0 ) && ( false == Geometry1.empty() ) ) {
Segment->RenderLoft( vertices, origin, rpts1, iTrapezoid ? -nnumPts : nnumPts, fTexLength );
GfxRenderer.Replace( vertices, Geometry1[ 0 ] );
vertices.clear(); // reuse the scratchpad
Segment->RenderLoft( vertices, origin, rpts2, iTrapezoid ? -nnumPts : nnumPts, fTexLength );
GfxRenderer.Replace( vertices, Geometry1[ 1 ] );
}
else {
Segment->RenderLoft( vertices, origin, rpts1, iTrapezoid ? -nnumPts : nnumPts, fTexLength );
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
vertices.clear(); // reuse the scratchpad
Segment->RenderLoft( vertices, origin, rpts2, iTrapezoid ? -nnumPts : nnumPts, fTexLength );
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
}
}
break;
case tt_Switch: // dla zwrotnicy dwa razy szyny
@@ -1984,47 +1995,85 @@ void TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start, int cons
for (i = 0; i < 12; ++i)
{
rpts3[i] =
vector6(+(fHTW + iglica[i].x) * cos1 + iglica[i].y * sin1,
-(+fHTW + iglica[i].x) * sin1 + iglica[i].y * cos1, iglica[i].z);
vector6(
+( fHTW + iglica[i].x) * cos1 + iglica[i].y * sin1,
-(+fHTW + iglica[i].x) * sin1 + iglica[i].y * cos1,
iglica[i].z);
rpts3[i + 12] =
vector6(+(fHTW2 + szyna[i].x) * cos2 + szyna[i].y * sin2,
-(+fHTW2 + szyna[i].x) * sin2 + iglica[i].y * cos2, szyna[i].z);
vector6(
+( fHTW2 + szyna[i].x) * cos2 + szyna[i].y * sin2,
-(+fHTW2 + szyna[i].x) * sin2 + iglica[i].y * cos2,
szyna[i].z);
rpts4[11 - i] =
vector6((-fHTW - iglica[i].x) * cos1 + iglica[i].y * sin1,
-(-fHTW - iglica[i].x) * sin1 + iglica[i].y * cos1, iglica[i].z);
vector6(
(-fHTW - iglica[i].x) * cos1 + iglica[i].y * sin1,
-(-fHTW - iglica[i].x) * sin1 + iglica[i].y * cos1,
iglica[i].z);
rpts4[23 - i] =
vector6((-fHTW2 - szyna[i].x) * cos2 + szyna[i].y * sin2,
-(-fHTW2 - szyna[i].x) * sin2 + iglica[i].y * cos2, szyna[i].z);
vector6(
(-fHTW2 - szyna[i].x) * cos2 + szyna[i].y * sin2,
-(-fHTW2 - szyna[i].x) * sin2 + iglica[i].y * cos2,
szyna[i].z);
}
// TODO, TBD: change all track geometry to triangles, to allow packing data in less, larger buffers
if (SwitchExtension->RightSwitch)
{ // nowa wersja z SPKS, ale odwrotnie lewa/prawa
vertex_array vertices;
if( TextureID1 ) {
SwitchExtension->Segments[ 0 ]->RenderLoft( Vert, origin, rpts2, nnumPts, fTexLength );
SwitchExtension->Segments[ 0 ]->RenderLoft( Vert, origin, rpts1, nnumPts, fTexLength, 1.0, 2 );
SwitchExtension->iLeftVBO = Vert - Start; // indeks lewej iglicy
SwitchExtension->Segments[ 0 ]->RenderLoft( Vert, origin, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, SwitchExtension->fOffset2 );
// fixed parts
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, origin, rpts2, nnumPts, fTexLength );
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
vertices.clear();
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, origin, rpts1, nnumPts, fTexLength, 1.0, 2 );
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
vertices.clear();
// left blade
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, origin, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, SwitchExtension->fOffset2 );
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
vertices.clear();
}
if( TextureID2 ) {
SwitchExtension->iRightVBO = Vert - Start; // indeks prawej iglicy
SwitchExtension->Segments[ 1 ]->RenderLoft( Vert, origin, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -fMaxOffset + SwitchExtension->fOffset1 );
SwitchExtension->Segments[ 1 ]->RenderLoft( Vert, origin, rpts2, nnumPts, fTexLength, 1.0, 2 );
SwitchExtension->Segments[ 1 ]->RenderLoft( Vert, origin, rpts1, nnumPts, fTexLength );
// fixed parts
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, origin, rpts1, nnumPts, fTexLength );
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
vertices.clear();
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, origin, rpts2, nnumPts, fTexLength, 1.0, 2 );
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
vertices.clear();
// right blade
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, origin, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -fMaxOffset + SwitchExtension->fOffset1 );
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
vertices.clear();
}
}
else
{ // lewa działa lepiej niż prawa
vertex_array vertices;
if( TextureID1 ) {
SwitchExtension->Segments[ 0 ]->RenderLoft( Vert, origin, rpts1, nnumPts, fTexLength ); // lewa szyna normalna cała
SwitchExtension->Segments[ 0 ]->RenderLoft( Vert, origin, rpts2, nnumPts, fTexLength, 1.0, 2 ); // prawa szyna za iglicą
SwitchExtension->iLeftVBO = Vert - Start; // indeks lewej iglicy
SwitchExtension->Segments[ 0 ]->RenderLoft( Vert, origin, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -SwitchExtension->fOffset2 ); // prawa iglica
// fixed parts
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, origin, rpts1, nnumPts, fTexLength ); // lewa szyna normalna cała
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
vertices.clear();
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, origin, rpts2, nnumPts, fTexLength, 1.0, 2 ); // prawa szyna za iglicą
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
vertices.clear();
// right blade
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, origin, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -SwitchExtension->fOffset2 );
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
vertices.clear();
}
if( TextureID2 ) {
SwitchExtension->iRightVBO = Vert - Start; // indeks prawej iglicy
SwitchExtension->Segments[ 1 ]->RenderLoft( Vert, origin, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, fMaxOffset - SwitchExtension->fOffset1 ); // lewa iglica
SwitchExtension->Segments[ 1 ]->RenderLoft( Vert, origin, rpts1, nnumPts, fTexLength, 1.0, 2 ); // lewa szyna za iglicą
SwitchExtension->Segments[ 1 ]->RenderLoft( Vert, origin, rpts2, nnumPts, fTexLength ); // prawa szyna normalnie cała
// fixed parts
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, origin, rpts2, nnumPts, fTexLength ); // prawa szyna normalnie cała
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
vertices.clear();
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, origin, rpts1, nnumPts, fTexLength, 1.0, 2 ); // lewa szyna za iglicą
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
vertices.clear();
// left blade
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, origin, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, fMaxOffset - SwitchExtension->fOffset1 );
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
vertices.clear();
}
}
}
@@ -2059,7 +2108,9 @@ void TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start, int cons
}
if (TextureID1) // jeśli podana była tekstura, generujemy trójkąty
{ // tworzenie trójkątów nawierzchni szosy
Segment->RenderLoft(Vert, origin, bpts1, iTrapezoid ? -2 : 2, fTexLength);
vertex_array vertices;
Segment->RenderLoft(vertices, origin, bpts1, iTrapezoid ? -2 : 2, fTexLength);
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
}
if (TextureID2)
{ // pobocze drogi - poziome przy przechyłce (a może krawężnik i chodnik zrobić jak w Midtown Madness 2?)
@@ -2136,22 +2187,31 @@ void TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start, int cons
rpts2[5] = vector6(bpts1[3].x - side2, bpts1[3].y + h2l, 0.484375 - map2l); // lewy brzeg lewego chodnika
}
}
vertex_array vertices;
if( iTrapezoid ) // trapez albo przechyłki
{ // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony
// odcinka
if( ( fTexHeight1 >= 0.0 ) || ( slop != 0.0 ) ) {
Segment->RenderLoft( Vert, origin, rpts1, -3, fTexLength ); // tylko jeśli jest z prawej
Segment->RenderLoft( vertices, origin, rpts1, -3, fTexLength ); // tylko jeśli jest z prawej
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
vertices.clear();
}
if( ( fTexHeight1 >= 0.0 ) || ( side != 0.0 ) ) {
Segment->RenderLoft( Vert, origin, rpts2, -3, fTexLength ); // tylko jeśli jest z lewej
Segment->RenderLoft( vertices, origin, rpts2, -3, fTexLength ); // tylko jeśli jest z lewej
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
vertices.clear();
}
}
else { // pobocza zwykłe, brak przechyłki
if( ( fTexHeight1 >= 0.0 ) || ( slop != 0.0 ) ) {
Segment->RenderLoft( Vert, origin, rpts1, 3, fTexLength );
Segment->RenderLoft( vertices, origin, rpts1, 3, fTexLength );
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
vertices.clear();
}
if( ( fTexHeight1 >= 0.0 ) || ( side != 0.0 ) ) {
Segment->RenderLoft( Vert, origin, rpts2, 3, fTexLength );
Segment->RenderLoft( vertices, origin, rpts2, 3, fTexLength );
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
vertices.clear();
}
}
}
@@ -2182,12 +2242,25 @@ void TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start, int cons
p[3] = SwitchExtension->Segments[1]->FastGetPoint_0(); // Point4 - przy trzech drogach pokrywa się z Point1
// 2014-07: na początek rysować brzegi jak dla łuków
// punkty brzegu nawierzchni uzyskujemy podczas renderowania boków (bez sensu, ale najszybciej było zrobić)
int i; // ile punktów (może byc różna ilość punktów między drogami)
int pointcount;
if( SwitchExtension->iRoads == 3 ) {
// mogą być tylko 3 drogi zamiast 4
pointcount =
SwitchExtension->Segments[ 0 ]->RaSegCount()
+ SwitchExtension->Segments[ 1 ]->RaSegCount()
+ SwitchExtension->Segments[ 2 ]->RaSegCount();
}
else {
pointcount =
SwitchExtension->Segments[ 2 ]->RaSegCount()
+ SwitchExtension->Segments[ 3 ]->RaSegCount()
+ SwitchExtension->Segments[ 4 ]->RaSegCount()
+ SwitchExtension->Segments[ 5 ]->RaSegCount();
}
if (!SwitchExtension->vPoints)
{ // jeśli tablica punktów nie jest jeszcze utworzona, zliczamy punkty i tworzymy ją
// points were already counted during preparation stage
// we'll need to add couple extra points for the complete fan we'll build
SwitchExtension->vPoints = new vector3[SwitchExtension->iPoints + SwitchExtension->iRoads];
SwitchExtension->vPoints = new vector3[pointcount + SwitchExtension->iRoads];
}
vector3 *b =
SwitchExtension->bPoints ?
@@ -2272,22 +2345,50 @@ void TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start, int cons
}
}
bool render = ( TextureID2 != 0 ); // renderować nie trzeba, ale trzeba wyznaczyć punkty brzegowe nawierzchni
// if (iTrapezoid) //trapez albo przechyłki
vertex_array vertices;
if (SwitchExtension->iRoads == 4)
{ // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony odcinka
if( ( fTexHeight1 >= 0.0 ) || ( side != 0.0 ) ) {
SwitchExtension->Segments[ 2 ]->RenderLoft( Vert, origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render );
SwitchExtension->Segments[ 3 ]->RenderLoft( Vert, origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render );
SwitchExtension->Segments[ 4 ]->RenderLoft( Vert, origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render );
SwitchExtension->Segments[ 5 ]->RenderLoft( Vert, origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render );
SwitchExtension->Segments[ 2 ]->RenderLoft( vertices, origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render );
if( true == render ) {
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
vertices.clear();
}
SwitchExtension->Segments[ 3 ]->RenderLoft( vertices, origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render );
if( true == render ) {
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
vertices.clear();
}
SwitchExtension->Segments[ 4 ]->RenderLoft( vertices, origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render );
if( true == render ) {
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
vertices.clear();
}
SwitchExtension->Segments[ 5 ]->RenderLoft( vertices, origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render );
if( true == render ) {
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
vertices.clear();
}
}
}
else {
// punkt 3 pokrywa się z punktem 1, jak w zwrotnicy; połączenie 1->2 nie musi być prostoliniowe
if( ( fTexHeight1 >= 0.0 ) || ( side != 0.0 ) ) {
SwitchExtension->Segments[ 2 ]->RenderLoft( Vert, origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render ); // z P2 do P4
SwitchExtension->Segments[ 1 ]->RenderLoft( Vert, origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render ); // z P4 do P3=P1 (odwrócony)
SwitchExtension->Segments[ 0 ]->RenderLoft( Vert, origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render ); // z P1 do P2
SwitchExtension->Segments[ 2 ]->RenderLoft( vertices, origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render ); // z P2 do P4
if( true == render ) {
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
vertices.clear();
}
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render ); // z P4 do P3=P1 (odwrócony)
if( true == render ) {
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
vertices.clear();
}
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render ); // z P1 do P2
if( true == render ) {
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
vertices.clear();
}
}
}
}
@@ -2299,47 +2400,47 @@ void TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start, int cons
SwitchExtension->bPoints = true; // tablica punktów została wypełniona
}
if (TextureID1) {
if( TextureID1 ) {
vertex_array vertices;
// jeśli podana tekstura nawierzchni
// we start with a vertex in the middle...
Vert->normal.x = 0.0;
Vert->normal.y = 1.0;
Vert->normal.z = 0.0;
Vert->texture.s = 0.5;
Vert->texture.t = 0.5;
Vert->position.x = oxz.x - origin.x;
Vert->position.y = oxz.y - origin.y;
Vert->position.z = oxz.z - origin.z;
++Vert;
vertices.emplace_back(
glm::vec3{
oxz.x - origin.x,
oxz.y - origin.y,
oxz.z - origin.z },
glm::vec3{ 0.0f, 1.0f, 0.0f },
glm::vec2{ 0.5f, 0.5f } );
// ...and add one extra vertex to close the fan...
Vert->normal.x = 0.0;
Vert->normal.y = 1.0;
Vert->normal.z = 0.0;
// mapowanie we współrzędnych scenerii
u = ( SwitchExtension->vPoints[ 0 ].x - oxz.x + origin.x ) / fTexLength;
v = ( SwitchExtension->vPoints[ 0 ].z - oxz.z + origin.z ) / ( fTexRatio1 * fTexLength );
Vert->texture.s = cosa0 * u + sina0 * v + 0.5;
Vert->texture.t = -sina0 * u + cosa0 * v + 0.5;
Vert->position.x = SwitchExtension->vPoints[ 0 ].x;
Vert->position.y = SwitchExtension->vPoints[ 0 ].y;
Vert->position.z = SwitchExtension->vPoints[ 0 ].z;
++Vert;
// ...then draw the precalculated rest
for (i = SwitchExtension->iPoints + SwitchExtension->iRoads - 1; i >= 0; --i)
{
Vert->normal.x = 0.0;
Vert->normal.y = 1.0;
Vert->normal.z = 0.0;
vertices.emplace_back(
glm::vec3 {
SwitchExtension->vPoints[ 0 ].x,
SwitchExtension->vPoints[ 0 ].y,
SwitchExtension->vPoints[ 0 ].z },
glm::vec3{ 0.0f, 1.0f, 0.0f },
// mapowanie we współrzędnych scenerii
u = (SwitchExtension->vPoints[i].x - oxz.x + origin.x ) / fTexLength;
v = (SwitchExtension->vPoints[i].z - oxz.z + origin.z ) / (fTexRatio1 * fTexLength);
Vert->texture.s = cosa0 * u + sina0 * v + 0.5;
Vert->texture.t = -sina0 * u + cosa0 * v + 0.5;
Vert->position.x = SwitchExtension->vPoints[ i ].x;
Vert->position.y = SwitchExtension->vPoints[ i ].y;
Vert->position.z = SwitchExtension->vPoints[ i ].z;
++Vert;
glm::vec2{
cosa0 * u + sina0 * v + 0.5,
-sina0 * u + cosa0 * v + 0.5 } );
// ...then draw the precalculated rest
for (int i = pointcount + SwitchExtension->iRoads - 1; i >= 0; --i) {
// mapowanie we współrzędnych scenerii
u = ( SwitchExtension->vPoints[ i ].x - oxz.x + origin.x ) / fTexLength;
v = ( SwitchExtension->vPoints[ i ].z - oxz.z + origin.z ) / ( fTexRatio1 * fTexLength );
vertices.emplace_back(
glm::vec3 {
SwitchExtension->vPoints[ i ].x,
SwitchExtension->vPoints[ i ].y,
SwitchExtension->vPoints[ i ].z },
glm::vec3{ 0.0f, 1.0f, 0.0f },
// mapowanie we współrzędnych scenerii
glm::vec2{
cosa0 * u + sina0 * v + 0.5,
-sina0 * u + cosa0 * v + 0.5 } );
}
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_FAN ) );
}
break;
} // tt_cross
@@ -2378,11 +2479,13 @@ void TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start, int cons
}
if (TextureID1) // jeśli podana była tekstura, generujemy trójkąty
{ // tworzenie trójkątów nawierzchni szosy
Segment->RenderLoft(Vert, origin, bpts1, iTrapezoid ? -2 : 2, fTexLength);
vertex_array vertices;
Segment->RenderLoft(vertices, origin, bpts1, iTrapezoid ? -2 : 2, fTexLength);
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
}
if (TextureID2)
{ // pobocze drogi - poziome przy przechyłce (a może krawężnik i chodnik zrobić jak w
// Midtown Madness 2?)
{ // pobocze drogi - poziome przy przechyłce (a może krawężnik i chodnik zrobić jak w Midtown Madness 2?)
vertex_array vertices;
vector6 rpts1[6],
rpts2[6]; // współrzędne przekroju i mapowania dla prawej i lewej strony
rpts1[0] = vector6(rozp, -fTexHeight1, 0.0); // lewy brzeg podstawy
@@ -2400,13 +2503,21 @@ void TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start, int cons
rpts2[3] = vector6(bpts1[3].x, bpts1[3].y, 1.0);
rpts2[4] = vector6(bpts1[3].x - side2, bpts1[3].y, 0.5);
rpts2[5] = vector6(-rozp2, -fTexHeight2, 0.0); // prawy brzeg prawego pobocza
Segment->RenderLoft(Vert, origin, rpts1, -3, fTexLength);
Segment->RenderLoft(Vert, origin, rpts2, -3, fTexLength);
Segment->RenderLoft(vertices, origin, rpts1, -3, fTexLength);
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
vertices.clear();
Segment->RenderLoft(vertices, origin, rpts2, -3, fTexLength);
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
vertices.clear();
}
else
{ // pobocza zwykłe, brak przechyłki
Segment->RenderLoft(Vert, origin, rpts1, 3, fTexLength);
Segment->RenderLoft(Vert, origin, rpts2, 3, fTexLength);
Segment->RenderLoft(vertices, origin, rpts1, 3, fTexLength);
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
vertices.clear();
Segment->RenderLoft(vertices, origin, rpts2, 3, fTexLength);
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
vertices.clear();
}
}
}
@@ -2415,10 +2526,9 @@ void TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start, int cons
}
return;
};
/*
void TTrack::RaRenderVBO( int iPtr ) { // renderowanie z użyciem VBO
// Ra 2014-07: trzeba wymienić GL_TRIANGLE_STRIP na GL_TRIANGLES i renderować trójkąty sektora
// dla kolejnych tekstur!
// Ra 2014-07: trzeba wymienić GL_TRIANGLE_STRIP na GL_TRIANGLES i renderować trójkąty sektora dla kolejnych tekstur!
EnvironmentSet();
int seg;
switch( iCategoryFlag & 15 ) {
@@ -2568,7 +2678,7 @@ void TTrack::RaRenderVBO( int iPtr ) { // renderowanie z użyciem VBO
}
EnvironmentReset();
};
*/
void TTrack::EnvironmentSet()
{ // ustawienie zmienionego światła
glColor3f(1.0f, 1.0f, 1.0f); // Ra: potrzebne to?
@@ -2822,11 +2932,11 @@ void TTrack::RaAnimListAdd(TTrack *t)
}
};
TTrack * TTrack::RaAnimate(GLuint const Vertexbuffer)
TTrack * TTrack::RaAnimate()
{ // wykonanie rekurencyjne animacji, wywoływane przed wyświetleniem sektora
// zwraca wskaźnik toru wymagającego dalszej animacji
if( SwitchExtension->pNextAnim )
SwitchExtension->pNextAnim = SwitchExtension->pNextAnim->RaAnimate( Vertexbuffer );
SwitchExtension->pNextAnim = SwitchExtension->pNextAnim->RaAnimate();
bool m = true; // animacja trwa
if (eType == tt_Switch) // dla zwrotnicy tylko szyny
{
@@ -2855,77 +2965,85 @@ TTrack * TTrack::RaAnimate(GLuint const Vertexbuffer)
m = false; // koniec animacji
}
}
if( ( Global::bUseVBO )
&& ( Vertexbuffer != -1 ) )
{ // dla OpenGL 1.4 odświeży się cały sektor, w późniejszych poprawiamy fragment
if (GLEW_VERSION_1_5) // dla OpenGL 1.4 to się nie wykona poprawnie
if (TextureID1) // Ra: !!!! tu jest do poprawienia
{ // iglice liczone tylko dla zwrotnic
vector6 rpts3[24], rpts4[24];
double fHTW = 0.5 * fabs(fTrackWidth);
double fHTW2 = fHTW; // Ra: na razie niech tak będzie
double cos1 = 1.0, sin1 = 0.0, cos2 = 1.0, sin2 = 0.0; // Ra: ...
for( int i = 0; i < 12; ++i ) {
// skip the geometry update if no geometry for this track was generated yet
if( ( ( TextureID1 != 0 )
|| ( TextureID2 != 0 ) )
&& ( ( false == Geometry1.empty() )
|| ( false == Geometry2.empty() ) ) ) {
// iglice liczone tylko dla zwrotnic
double fHTW = 0.5 * fabs( fTrackWidth );
double fHTW2 = fHTW; // Ra: na razie niech tak będzie
double cos1 = 1.0, sin1 = 0.0, cos2 = 1.0, sin2 = 0.0; // Ra: ...
vector6 rpts3[ 24 ], rpts4[ 24 ];
for (int i = 0; i < 12; ++i)
{
rpts3[i] =
vector6(
+( fHTW + iglica[i].x) * cos1 + iglica[i].y * sin1,
-(+fHTW + iglica[i].x) * sin1 + iglica[i].y * cos1,
iglica[i].z);
rpts3[i + 12] =
vector6(
+( fHTW2 + szyna[i].x) * cos2 + szyna[i].y * sin2,
-(+fHTW2 + szyna[i].x) * sin2 + iglica[i].y * cos2,
szyna[i].z);
rpts4[11 - i] =
vector6(
(-fHTW - iglica[i].x) * cos1 + iglica[i].y * sin1,
-(-fHTW - iglica[i].x) * sin1 + iglica[i].y * cos1,
iglica[i].z);
rpts4[23 - i] =
vector6(
(-fHTW2 - szyna[i].x) * cos2 + szyna[i].y * sin2,
-(-fHTW2 - szyna[i].x) * sin2 + iglica[i].y * cos2,
szyna[i].z);
}
rpts3[ i ] =
vector6( +( fHTW + iglica[ i ].x ) * cos1 + iglica[ i ].y * sin1,
-( +fHTW + iglica[ i ].x ) * sin1 + iglica[ i ].y * cos1, iglica[ i ].z );
rpts3[ i + 12 ] =
vector6( +( fHTW2 + szyna[ i ].x ) * cos2 + szyna[ i ].y * sin2,
-( +fHTW2 + szyna[ i ].x ) * sin2 + iglica[ i ].y * cos2, szyna[ i ].z );
rpts4[ 11 - i ] =
vector6( ( -fHTW - iglica[ i ].x ) * cos1 + iglica[ i ].y * sin1,
-( -fHTW - iglica[ i ].x ) * sin1 + iglica[ i ].y * cos1, iglica[ i ].z );
rpts4[ 23 - i ] =
vector6( ( -fHTW2 - szyna[ i ].x ) * cos2 + szyna[ i ].y * sin2,
-( -fHTW2 - szyna[ i ].x ) * sin2 + iglica[ i ].y * cos2, szyna[ i ].z );
}
// NOTE: performance-wise it'd make much more sense to keep the most recent shape cached as part of switch extension,
// and only send updates when/if they take place, instead of the current back-and-forth
// TODO: implement optimized version
auto const origin { pMyNode->m_rootposition };
vertex_array vertices;
// fetch current blade geometry
std::vector<CVertNormTex> bladesbuffer; bladesbuffer.resize( 2 * 2 * 24 ); // 2 blades, 2 segments each
/*
::glGetBufferSubData(
GL_ARRAY_BUFFER,
SwitchExtension->iLeftVBO * sizeof( CVertNormTex ),
bladesbuffer.size() * sizeof( CVertNormTex ),
bladesbuffer.data() );
*/
auto bladevertices = bladesbuffer.data();
auto const origin { pMyNode->m_rootposition };
if( SwitchExtension->RightSwitch ) { // nowa wersja z SPKS, ale odwrotnie lewa/prawa
SwitchExtension->Segments[ 0 ]->RenderLoft( bladevertices, origin, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, SwitchExtension->fOffset2 /*, true*/ );
SwitchExtension->Segments[ 1 ]->RenderLoft( bladevertices, origin, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -fMaxOffset + SwitchExtension->fOffset1 /*, true*/ );
}
else {
SwitchExtension->Segments[ 0 ]->RenderLoft( bladevertices, origin, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -SwitchExtension->fOffset2 /*, true*/ ); // prawa iglica
SwitchExtension->Segments[ 1 ]->RenderLoft( bladevertices, origin, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, fMaxOffset - SwitchExtension->fOffset1 /*, true*/ ); // lewa iglica
}
// push back updated geometry
::glBufferSubData(
GL_ARRAY_BUFFER,
SwitchExtension->iLeftVBO * sizeof( CVertNormTex ),
bladesbuffer.size() * sizeof( CVertNormTex ),
bladesbuffer.data() );
if (SwitchExtension->RightSwitch)
{ // nowa wersja z SPKS, ale odwrotnie lewa/prawa
vertex_array vertices;
if( TextureID1 ) {
// left blade
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, origin, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, SwitchExtension->fOffset2 );
GfxRenderer.Replace( vertices, Geometry1[ 2 ] );
vertices.clear();
}
if( TextureID2 ) {
// right blade
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, origin, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -fMaxOffset + SwitchExtension->fOffset1 );
GfxRenderer.Replace( vertices, Geometry2[ 2 ] );
vertices.clear();
}
}
else { // lewa działa lepiej niż prawa
vertex_array vertices;
if( TextureID1 ) {
// right blade
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, origin, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -SwitchExtension->fOffset2 );
GfxRenderer.Replace( vertices, Geometry1[ 2 ] );
vertices.clear();
}
if( TextureID2 ) {
// left blade
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, origin, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, fMaxOffset - SwitchExtension->fOffset1 );
GfxRenderer.Replace( vertices, Geometry2[ 2 ] );
vertices.clear();
}
}
}
else // gdy Display List
Release(); // niszczenie skompilowanej listy, aby się wygenerowała nowa
}
else if (eType == tt_Table) // dla obrotnicy - szyny i podsypka
{
else if (eType == tt_Table) {
// dla obrotnicy - szyny i podsypka
if (SwitchExtension->pModel &&
SwitchExtension->CurrentIndex) // 0=zablokowana się nie animuje
{ // trzeba każdorazowo porównywać z kątem modelu
// SwitchExtension->fOffset1=SwitchExtension->pAnim?SwitchExtension->pAnim->AngleGet():0.0;
// //pobranie kąta z modelu
TAnimContainer *ac = SwitchExtension->pModel ?
SwitchExtension->pModel->GetContainer(NULL) :
NULL; // pobranie głównego submodelu
// if (ac) ac->EventAssign(SwitchExtension->evMinus); //event zakończenia animacji,
// trochę bez sensu tutaj
if (ac)
if ((ac->AngleGet() != SwitchExtension->fOffset) ||
!(ac->TransGet() ==
@@ -2947,22 +3065,26 @@ TTrack * TTrack::RaAnimate(GLuint const Vertexbuffer)
dynamic->Move( 0.000001 );
}
// kąty
/*
if (Global::bUseVBO)
{ // dla OpenGL 1.4 odświeży się cały sektor, w późniejszych poprawiamy fragment
// aktualizacja pojazdów na torze
if (GLEW_VERSION_1_5) // dla OpenGL 1.4 to się nie wykona poprawnie
{
int size = RaArrayPrepare(); // wielkość tabeli potrzebna dla tej obrotnicy
CVertNormTex *Vert = new CVertNormTex[size]; // bufor roboczy
// CVertNormTex *v=Vert; //zmieniane przez
basic_vertex *Vert = new basic_vertex[size]; // bufor roboczy
// basic_vertex *v=Vert; //zmieniane przez
RaArrayFill(Vert, Vert - SwitchExtension->iLeftVBO, size); // iLeftVBO powinno zostać niezmienione
::glBufferSubData(
GL_ARRAY_BUFFER, SwitchExtension->iLeftVBO * sizeof(CVertNormTex),
size * sizeof(CVertNormTex), Vert); // wysłanie fragmentu bufora VBO
GL_ARRAY_BUFFER, SwitchExtension->iLeftVBO * sizeof(basic_vertex),
size * sizeof(basic_vertex), Vert); // wysłanie fragmentu bufora VBO
}
}
else // gdy Display List
Release(); // niszczenie skompilowanej listy, aby się wygenerowała nowa
*/
// NOTE: passing empty handle is a bit of a hack here. could be refactored into something more elegant
create_geometry( geometrybank_handle() );
} // animacja trwa nadal
}
else

138
Track.h
View File

@@ -15,8 +15,6 @@ http://mozilla.org/MPL/2.0/.
#include "Segment.h"
#include "Texture.h"
class TEvent;
typedef enum
{
tt_Unknown,
@@ -39,6 +37,7 @@ typedef enum
} TEnvironmentType;
// Ra: opracować alternatywny system cieni/świateł z definiowaniem koloru oświetlenia w halach
class TEvent;
class TTrack;
class TGroundNode;
class TSubRect;
@@ -77,10 +76,10 @@ class TSwitchExtension
};
struct
{ // zmienne dla skrzyżowania
vector3 *vPoints; // tablica wierzchołków nawierzchni, generowana przez pobocze
int iPoints; // liczba faktycznie użytych wierzchołków nawierzchni
bool bPoints; // czy utworzone?
int iRoads; // ile dróg się spotyka?
vector3 *vPoints; // tablica wierzchołków nawierzchni, generowana przez pobocze
// int iPoints; // liczba faktycznie użytych wierzchołków nawierzchni
bool bPoints; // czy utworzone?
};
};
bool bMovement = false; // czy w trakcie animacji
@@ -108,46 +107,48 @@ class TIsolated
TIsolated();
TIsolated(const std::string &n, TIsolated *i);
~TIsolated();
static TIsolated * Find(
const std::string &n); // znalezienie obiektu albo utworzenie nowego
static TIsolated * Find(const std::string &n); // znalezienie obiektu albo utworzenie nowego
void Modify(int i, TDynamicObject *o); // dodanie lub odjęcie osi
bool Busy()
{
return (iAxles > 0);
};
static TIsolated * Root()
{
return (pRoot);
};
TIsolated * Next()
{
return (pNext);
};
bool Busy() {
return (iAxles > 0); };
static TIsolated * Root() {
return (pRoot); };
TIsolated * Next() {
return (pNext); };
};
class TTrack : public Resource
{ // trajektoria ruchu - opakowanie
private:
// trajektoria ruchu - opakowanie
class TTrack : public Resource {
friend class opengl_renderer;
private:
TGroundNode * pMyNode = nullptr; // Ra: proteza, żeby tor znał swoją nazwę TODO: odziedziczyć TTrack z TGroundNode
TIsolated * pIsolated = nullptr; // obwód izolowany obsługujący zajęcia/zwolnienia grupy torów
std::shared_ptr<TSwitchExtension> SwitchExtension; // dodatkowe dane do toru, który jest zwrotnicą
std::shared_ptr<TSegment> Segment;
TTrack *trNext = nullptr; // odcinek od strony punktu 2 - to powinno być w segmencie
TTrack *trPrev = nullptr; // odcinek od strony punktu 1
TTrack * trNext = nullptr; // odcinek od strony punktu 2 - to powinno być w segmencie
TTrack * trPrev = nullptr; // odcinek od strony punktu 1
// McZapkie-070402: dodalem zmienne opisujace rozmiary tekstur
texture_handle TextureID1 = 0; // tekstura szyn albo nawierzchni
texture_handle TextureID2 = 0; // tekstura automatycznej podsypki albo pobocza
int iTrapezoid = 0; // 0-standard, 1-przechyłka, 2-trapez, 3-oba
double fRadiusTable[ 2 ]; // dwa promienie, drugi dla zwrotnicy
float fTexLength = 4.0f; // długość powtarzania tekstury w metrach
float fTexRatio1 = 1.0f; // proporcja boków tekstury nawierzchni (żeby zaoszczędzić na rozmiarach tekstur...)
float fTexRatio2 = 1.0f; // proporcja boków tekstury chodnika (żeby zaoszczędzić na rozmiarach tekstur...)
float fTexHeight1 = 0.6f; // wysokość brzegu względem trajektorii
float fTexWidth = 0.9f; // szerokość boku
float fTexSlope = 0.9f;
double fRadiusTable[ 2 ]; // dwa promienie, drugi dla zwrotnicy
int iTrapezoid = 0; // 0-standard, 1-przechyłka, 2-trapez, 3-oba
/*
GLuint DisplayListID = 0;
TIsolated *pIsolated = nullptr; // obwód izolowany obsługujący zajęcia/zwolnienia grupy torów
TGroundNode *
pMyNode = nullptr; // Ra: proteza, żeby tor znał swoją nazwę TODO: odziedziczyć TTrack z TGroundNode
public:
*/
texture_handle TextureID1 = 0; // tekstura szyn albo nawierzchni
texture_handle TextureID2 = 0; // tekstura automatycznej podsypki albo pobocza
typedef std::vector<geometry_handle> geometryhandle_sequence;
geometryhandle_sequence Geometry1; // geometry chunks textured with texture 1
geometryhandle_sequence Geometry2; // geometry chunks textured with texture 2
public:
typedef std::deque<TDynamicObject *> dynamics_sequence;
dynamics_sequence Dynamics;
int iEvents = 0; // Ra: flaga informująca o obecności eventów
@@ -193,39 +194,30 @@ class TTrack : public Resource
void Init();
static TTrack * Create400m(int what, double dx);
TTrack * NullCreate(int dir);
inline bool IsEmpty()
{
return Dynamics.empty();
};
inline bool IsEmpty() {
return Dynamics.empty(); };
void ConnectPrevPrev(TTrack *pNewPrev, int typ);
void ConnectPrevNext(TTrack *pNewPrev, int typ);
void ConnectNextPrev(TTrack *pNewNext, int typ);
void ConnectNextNext(TTrack *pNewNext, int typ);
inline double Length()
{
return Segment->GetLength();
};
inline std::shared_ptr<TSegment> CurrentSegment()
{
return Segment;
};
inline TTrack * CurrentNext()
{
return (trNext);
};
inline TTrack * CurrentPrev()
{
return (trPrev);
};
inline double Length() {
return Segment->GetLength(); };
inline std::shared_ptr<TSegment> CurrentSegment() {
return Segment; };
inline TTrack * CurrentNext() {
return (trNext); };
inline TTrack * CurrentPrev() {
return (trPrev); };
TTrack * Neightbour(int s, double &d);
bool SetConnections(int i);
bool Switch(int i, double t = -1.0, double d = -1.0);
bool SwitchForced(int i, TDynamicObject *o);
int CrossSegment(int from, int into);
inline int GetSwitchState()
{
return (SwitchExtension ? SwitchExtension->CurrentIndex : -1);
};
inline int GetSwitchState() {
return (
SwitchExtension ?
SwitchExtension->CurrentIndex :
-1); };
void Load(cParser *parser, vector3 pOrigin, std::string name);
bool AssignEvents(TEvent *NewEvent0, TEvent *NewEvent1, TEvent *NewEvent2);
bool AssignallEvents(TEvent *NewEvent0, TEvent *NewEvent1, TEvent *NewEvent2);
@@ -233,44 +225,42 @@ class TTrack : public Resource
bool CheckDynamicObject(TDynamicObject *Dynamic);
bool AddDynamicObject(TDynamicObject *Dynamic);
bool RemoveDynamicObject(TDynamicObject *Dynamic);
void MoveMe(vector3 pPosition);
void Release();
/*
void Compile(GLuint tex = 0);
void Render(); // renderowanie z Display Lists
int RaArrayPrepare(); // zliczanie rozmiaru dla VBO sektroa
void RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start, int const Vertexcount); // wypełnianie VBO
*/
void create_geometry(geometrybank_handle const &Bank); // wypełnianie VBO
/*
void RaRenderVBO(int iPtr); // renderowanie z VBO sektora
*/
void RenderDyn(); // renderowanie nieprzezroczystych pojazdów (oba tryby)
void RenderDynAlpha(); // renderowanie przezroczystych pojazdów (oba tryby)
void RenderDynSounds(); // odtwarzanie dźwięków pojazdów jest niezależne od ich
// wyświetlania
void RenderDynSounds(); // odtwarzanie dźwięków pojazdów jest niezależne od ich wyświetlania
void RaOwnerSet(TSubRect *o)
{
void RaOwnerSet(TSubRect *o) {
if (SwitchExtension)
SwitchExtension->pOwner = o;
};
SwitchExtension->pOwner = o; };
bool InMovement(); // czy w trakcie animacji?
void RaAssign(TGroundNode *gn, TAnimContainer *ac);
void RaAssign(TGroundNode *gn, TAnimModel *am, TEvent *done, TEvent *joined);
void RaAnimListAdd(TTrack *t);
TTrack * RaAnimate(GLuint const Vertexbuffer = -1);
TTrack * RaAnimate();
void RadioStop();
void AxleCounter(int i, TDynamicObject *o)
{
void AxleCounter(int i, TDynamicObject *o) {
if (pIsolated)
pIsolated->Modify(i, o);
}; // dodanie lub odjęcie osi
pIsolated->Modify(i, o); }; // dodanie lub odjęcie osi
std::string IsolatedName();
bool IsolatedEventsAssign(TEvent *busy, TEvent *free);
double WidthTotal();
GLuint TextureGet(int i)
{
return i ? TextureID1 : TextureID2;
};
GLuint TextureGet(int i) {
return (
i ?
TextureID1 :
TextureID2 ); };
bool IsGroupable();
int TestPoint(vector3 *Point);
void MovedUp1(double dh);

View File

@@ -358,7 +358,7 @@ void TTraction::ResistanceCalc(int d, double r, TTractionPowerSource *ps)
}
t->psPower[d] = ps; // skopiowanie wskaźnika zasilacza od danej strony
t->fResistance[d] = r; // wpisanie rezystancji w kierunku tego zasilacza
r += t->fResistivity * glm::dot(t->vParametric, t->vParametric ); // doliczenie oporu kolejnego odcinka
r += t->fResistivity * glm::length(t->vParametric); // doliczenie oporu kolejnego odcinka
p = t; // zapamiętanie dotychczasowego
t = p->hvNext[d ^ 1]; // podążanie w tę samą stronę
d = p->iNext[d ^ 1];
@@ -367,8 +367,7 @@ void TTraction::ResistanceCalc(int d, double r, TTractionPowerSource *ps)
}
else
{ // podążanie w obu kierunkach, można by rekurencją, ale szkoda zasobów
r = 0.5 * fResistivity *
glm::dot(vParametric, vParametric ); // powiedzmy, że w zasilanym przęśle jest połowa
r = 0.5 * fResistivity * glm::length(vParametric); // powiedzmy, że w zasilanym przęśle jest połowa
if (fResistance[0] == 0.0)
ResistanceCalc(0, r); // do tyłu (w stronę Point1)
if (fResistance[1] == 0.0)

View File

@@ -56,7 +56,7 @@ class TTraction
void Connect(int my, TTraction *with, int to);
void Init();
bool WhereIs();
void ResistanceCalc(int d = -1, double r = 0, TTractionPowerSource *ps = NULL);
void ResistanceCalc(int d = -1, double r = 0, TTractionPowerSource *ps = nullptr);
void PowerSet(TTractionPowerSource *ps);
double VoltageGet(double u, double i);
private:

145
VBO.cpp
View File

@@ -9,148 +9,3 @@ http://mozilla.org/MPL/2.0/.
#include "stdafx.h"
#include "VBO.h"
#include "GL/glew.h"
#include "usefull.h"
#include "sn_utils.h"
#include "globals.h"
//---------------------------------------------------------------------------
/*
void CVertNormTex::deserialize(std::istream &s)
{
x = sn_utils::ld_float32(s);
y = sn_utils::ld_float32(s);
z = sn_utils::ld_float32(s);
nx = sn_utils::ld_float32(s);
ny = sn_utils::ld_float32(s);
nz = sn_utils::ld_float32(s);
u = sn_utils::ld_float32(s);
v = sn_utils::ld_float32(s);
}
void CVertNormTex::serialize(std::ostream &s)
{
sn_utils::ls_float32(s, x);
sn_utils::ls_float32(s, y);
sn_utils::ls_float32(s, z);
sn_utils::ls_float32(s, nx);
sn_utils::ls_float32(s, ny);
sn_utils::ls_float32(s, nz);
sn_utils::ls_float32(s, u);
sn_utils::ls_float32(s, v);
}
*/
CMesh::CMesh()
{ // utworzenie pustego obiektu
#ifdef EU07_USE_OLD_VERTEXBUFFER
m_pVNT = nullptr;
#endif
m_nVertexCount = -1;
m_nVBOVertices = 0; // nie zarezerwowane
};
CMesh::~CMesh()
{ // usuwanie obiektu
Clear(); // zwolnienie zasobów
};
void CMesh::MakeArray(int n)
{ // tworzenie tablic
m_nVertexCount = n;
#ifdef EU07_USE_OLD_VERTEXBUFFER
assert( m_pVNT == nullptr );
m_pVNT = new CVertNormTex[m_nVertexCount]; // przydzielenie pamięci dla tablicy
#else
m_pVNT.clear();
m_pVNT.resize( m_nVertexCount );
#endif
};
void CMesh::BuildVBOs(bool del)
{ // tworzenie VBO i kasowanie już niepotrzebnych tablic
// pobierz numer VBO oraz ustaw go jako aktywny
glGenBuffers(1, &m_nVBOVertices); // pobierz numer
glBindBuffer(GL_ARRAY_BUFFER, m_nVBOVertices); // ustaw bufor jako aktualny
#ifdef EU07_USE_OLD_VERTEXBUFFER
glBufferData(GL_ARRAY_BUFFER, m_nVertexCount * sizeof(CVertNormTex), m_pVNT, GL_STATIC_DRAW);
#else
glBufferData( GL_ARRAY_BUFFER, m_nVertexCount * sizeof( CVertNormTex ), m_pVNT.data(), GL_STATIC_DRAW );
#endif
// WriteLog("Assigned VBO number "+AnsiString(m_nVBOVertices)+", vertices:
// "+AnsiString(m_nVertexCount));
#ifdef EU07_USE_OLD_VERTEXBUFFER
if (del)
SafeDeleteArray(m_pVNT); // wierzchołki już się nie przydadzą
#else
m_pVNT.clear();
#endif
};
void CMesh::Clear()
{ // niewirtualne zwolnienie zasobów przez sprzątacz albo destruktor
// inna nazwa, żeby nie mieszało się z funkcją wirtualną sprzątacza
if (m_nVBOVertices) // jeśli było coś rezerwowane
{
glDeleteBuffers(1, &m_nVBOVertices); // Free The Memory
// WriteLog("Released VBO number "+AnsiString(m_nVBOVertices));
}
m_nVBOVertices = 0;
m_nVertexCount = -1; // do ponownego zliczenia
#ifdef EU07_USE_OLD_VERTEXBUFFER
SafeDeleteArray(m_pVNT); // usuwanie tablic, gdy były użyte do Vertex Array
#else
m_pVNT.clear();
#endif
};
bool CMesh::StartVBO()
{ // początek rysowania elementów z VBO
if (m_nVertexCount <= 0)
return false; // nie ma nic do rysowania w ten sposób
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
if (m_nVBOVertices)
{
glBindBuffer(GL_ARRAY_BUFFER_ARB, m_nVBOVertices);
glVertexPointer( 3, GL_FLOAT, sizeof( CVertNormTex ), static_cast<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 false;
};
bool CMesh::StartColorVBO()
{ // początek rysowania punktów świecących z VBO
if (m_nVertexCount <= 0)
return false; // nie ma nic do rysowania w ten sposób
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
if (m_nVBOVertices)
{
glBindBuffer(GL_ARRAY_BUFFER, m_nVBOVertices);
glVertexPointer( 3, GL_FLOAT, sizeof( CVertNormTex ), static_cast<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 false;
};
void CMesh::EndVBO()
{ // koniec użycia VBO
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
// glBindBuffer(GL_ARRAY_BUFFER,0); //takie coś psuje, mimo iż polecali użyć
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); // Ra: to na przyszłość
};

43
VBO.h
View File

@@ -11,48 +11,9 @@ http://mozilla.org/MPL/2.0/.
#include "openglgeometrybank.h"
#define EU07_USE_OLD_VERTEXBUFFER
//---------------------------------------------------------------------------
/*
class CVertNormTex
class CMesh
{
public:
float x = 0.0; // X wierzchołka
float y = 0.0; // Y wierzchołka
float z = 0.0; // Z wierzchołka
float nx = 0.0; // X wektora normalnego
float ny = 0.0; // Y wektora normalnego
float nz = 0.0; // Z wektora normalnego
float u = 0.0; // U mapowania
float v = 0.0; // V mapowania
void deserialize(std::istream&);
void serialize(std::ostream&);
};
*/
typedef basic_vertex CVertNormTex;
class CMesh
{ // wsparcie dla VBO
public:
CMesh();
~CMesh();
void MakeArray(int n); // tworzenie tablicy z elementami VNT
void BuildVBOs(bool del = true); // zamiana tablic na VBO
void Clear(); // zwolnienie zasobów
bool StartVBO();
void EndVBO();
bool StartColorVBO();
int m_nVertexCount; // liczba wierzchołków
#ifdef EU07_USE_OLD_VERTEXBUFFER
CVertNormTex *m_pVNT;
#else
std::vector<CVertNormTex> m_pVNT;
#endif
unsigned int m_nVBOVertices; // numer VBO z wierzchołkami
geometrybank_handle m_geometrybank;
bool m_geometrycreated { false };
};

View File

@@ -1267,7 +1267,7 @@ TWorld::Render_Cab() {
}
TDynamicObject *dynamic = Train->Dynamic();
TSubModel::iInstance = reinterpret_cast<size_t>( dynamic );
TSubModel::iInstance = reinterpret_cast<std::size_t>( dynamic );
if( ( true == FreeFlyModeFlag )
|| ( false == dynamic->bDisplayCab )
@@ -1275,8 +1275,6 @@ TWorld::Render_Cab() {
// ABu: Rendering kabiny jako ostatniej, zeby bylo widac przez szyby, tylko w widoku ze srodka
return;
}
::glEnable( GL_LIGHTING ); // po renderowaniu drutów może być to wyłączone. TODO: have the wires render take care of its own shit
/*
glPushMatrix();
vector3 pos = dynamic->GetPosition(); // wszpółrzędne pojazdu z kabiną
@@ -1651,7 +1649,7 @@ TWorld::Update_UI() {
}
case( GLFW_KEY_F8 ) : {
// gfx renderer data
uitextline1 =
"Draw range x " + to_string( Global::fDistanceFactor, 1 )
+ "; FPS: " + to_string( Timer::GetFPS(), 2 );
@@ -1659,28 +1657,16 @@ TWorld::Update_UI() {
uitextline1 += " (slowmotion " + to_string( Global::iSlowMotion ) + ")";
}
uitextline1 +=
", sectors: " + to_string( Ground.iRendered )
+ "/" + to_string( Global::iSegmentsRendered )
", sectors: " + std::to_string( GfxRenderer.m_drawcount )
+ "/" + std::to_string( Global::iSegmentsRendered )
+ "; FoV: " + to_string( Global::FieldOfView / Global::ZoomFactor, 1 );
break;
}
case( GLFW_KEY_F9 ) : {
// informacja o wersji, sposobie wyświetlania i błędach OpenGL
uitextline1 = "MaSzyna " + Global::asVersion; // informacja o wersji
if( Global::iMultiplayer ) {
uitextline1 += " (multiplayer mode is active)";
}
uitextline2 =
std::string("Rendering mode: ")
std::string( "Rendering mode: " )
+ ( Global::bUseVBO ?
"VBO" :
"Display Lists" )
+ ". "
+ GfxRenderer.Info();
+ ". ";
// dump last opengl error, if any
GLenum glerror = ::glGetError();
if( glerror != GL_NO_ERROR ) {
@@ -1689,10 +1675,22 @@ TWorld::Update_UI() {
Global::LastGLError = std::to_string( glerror ) + " (" + glerrorstring + ")";
}
if( false == Global::LastGLError.empty() ) {
uitextline3 =
uitextline2 +=
"Last openGL error: "
+ Global::LastGLError;
}
// renderer stats
uitextline3 = GfxRenderer.Info();
break;
}
case( GLFW_KEY_F9 ) : {
// informacja o wersji
uitextline1 = "MaSzyna " + Global::asVersion; // informacja o wersji
if( Global::iMultiplayer ) {
uitextline1 += " (multiplayer mode is active)";
}
break;
}

View File

@@ -48,13 +48,13 @@ basic_vertex::deserialize( std::istream &s ) {
// creates a new geometry chunk of specified type from supplied vertex data. returns: handle to the chunk
geometry_handle
geometry_bank::create( vertex_array &Vertices, int const Type ) {
geometry_bank::create( vertex_array &Vertices, unsigned int const Type, unsigned int const Streams ) {
if( true == Vertices.empty() ) { return geometry_handle( 0, 0 ); }
m_chunks.emplace_back( Vertices, Type );
m_chunks.emplace_back( Vertices, Type, Streams );
// NOTE: handle is effectively (index into chunk array + 1) this leaves value of 0 to serve as error/empty handle indication
geometry_handle chunkhandle{ 0, m_chunks.size() };
geometry_handle chunkhandle { 0, static_cast<std::uint32_t>(m_chunks.size()) };
// template method
create_( chunkhandle );
// all done

View File

@@ -18,14 +18,30 @@ http://mozilla.org/MPL/2.0/.
#endif
struct basic_vertex {
glm::vec3 position; // 3d space
glm::vec3 normal; // 3d space
glm::vec2 texture; // uv space
basic_vertex() = default;
basic_vertex( glm::vec3 const&Position, glm::vec3 const &Normal, glm::vec2 const &Texture ) :
position( Position ), normal( Normal ), texture( Texture )
{}
void serialize( std::ostream& );
void deserialize( std::istream& );
};
// data streams carried in a vertex
enum stream {
position = 0x1,
normal = 0x2,
color = 0x4, // currently normal and colour streams are stored in the same slot, and mutually exclusive
texture = 0x8
};
unsigned int const basic_streams { stream::position | stream::normal | stream::texture };
unsigned int const color_streams{ stream::position | stream::color | stream::texture };
typedef std::vector<basic_vertex> vertex_array;
// generic geometry bank class, allows storage, update and drawing of geometry chunks
@@ -40,12 +56,20 @@ struct geometry_handle {
{}
// methods
inline
operator std::uint32_t() const {
return bank << 12 | chunk; }
operator std::uint64_t() const {
/*
return bank << 14 | chunk; }
*/
return bank << 32 | chunk; }
// members
/*
std::uint32_t
bank : 20, // 1 mil banks
chunk : 12; // 4 k chunks per bank
bank : 18, // 250k banks
chunk : 14; // 16k chunks per bank
*/
std::uint32_t bank;
std::uint32_t chunk;
};
class geometry_bank {
@@ -62,7 +86,7 @@ public:
// methods:
// creates a new geometry chunk of specified type from supplied vertex data. returns: handle to the chunk or NULL
geometry_handle
create( vertex_array &Vertices, int const Type );
create( vertex_array &Vertices, unsigned int const Type, unsigned int const Streams = stream::position | stream::normal | stream::texture );
// replaces data of specified chunk with the supplied vertex data, starting from specified offset
bool
replace( vertex_array &Vertices, geometry_handle const &Geometry, std::size_t const Offset = 0 );
@@ -83,11 +107,12 @@ public:
protected:
// types:
struct geometry_chunk {
int type; // kind of geometry used by the chunk
unsigned int streams; // data streams carried by vertices
unsigned int type; // kind of geometry used by the chunk
vertex_array vertices; // geometry data
geometry_chunk( vertex_array &Vertices, int const Type ) :
vertices( Vertices ), type( Type )
geometry_chunk( vertex_array &Vertices, unsigned int const Type, unsigned int const Streams ) :
vertices( Vertices ), type( Type ), streams( Streams )
{}
};
@@ -121,9 +146,14 @@ private:
class opengl_vbogeometrybank : public geometry_bank {
public:
// methods:
// destructor
~opengl_vbogeometrybank() {
delete_buffer(); }
// methods:
static
void
reset() {
m_activebuffer = 0; }
private:
// types:
@@ -217,6 +247,12 @@ public:
// draws geometry stored in specified chunk
void
draw( geometry_handle const &Geometry );
template <typename Iterator_>
void
draw( Iterator_ First, Iterator_ Last ) {
while( First != Last ) {
draw( *First );
++First; } }
// provides direct access to vertex data of specfied chunk
vertex_array const &
vertices( geometry_handle const &Geometry ) const;

View File

@@ -30,6 +30,9 @@ cParser::cParser( std::string const &Stream, buffertype const Type, std::string
// mComments.insert(commentmap::value_type("--","\n")); //Ra: to chyba nie używane
// store to calculate sub-sequent includes from relative path
mPath = Path;
if( Type == buffertype::buffer_FILE ) {
mFile = Stream;
}
// reset pointers and attach proper type of buffer
switch (Type)
{
@@ -263,8 +266,15 @@ std::size_t cParser::count() {
return count - 1;
}
void cParser::addCommentStyle( std::string const &Commentstart, std::string const &Commentend ) {
mComments.insert( commentmap::value_type(Commentstart, Commentend) );
}
// returns name of currently open file, or empty string for text type stream
std::string
cParser::Name() {
if( mIncludeParser ) { return mIncludeParser->Name(); }
else { return mPath + mFile; }
}

View File

@@ -85,19 +85,21 @@ class cParser //: public std::stringstream
static std::size_t countTokens( std::string const &Stream, std::string Path = "" );
// add custom definition of text which should be ignored when retrieving tokens
void addCommentStyle( std::string const &Commentstart, std::string const &Commentend );
// returns name of currently open file, or empty string for text type stream
std::string Name();
private:
// methods:
std::string readToken(bool ToLower = true, const char *Break = "\n\r\t ;");
std::string readQuotes( char const Quote = '\"' );
std::string readComment( std::string const &Break = "\n\r\t ;" );
// std::string trtest;
bool findQuotes( std::string &String );
bool trimComments( std::string &String );
std::size_t count();
// members:
bool LoadTraction; // load traction?
std::istream *mStream; // relevant kind of buffer is attached on creation.
std::string mFile; // name of the open file, if any
std::string mPath; // path to open stream, for relative path lookups.
std::streamoff mSize; // size of open stream, for progress report.
typedef std::map<std::string, std::string> commentmap;

View File

@@ -39,7 +39,8 @@ opengl_camera::visible( TDynamicObject const *Dynamic ) const {
static_cast<float>( Dynamic->MoverParameters->Dim.L ),
static_cast<float>( Dynamic->MoverParameters->Dim.H ),
static_cast<float>( Dynamic->MoverParameters->Dim.W ) );
float const radius = glm::length( diagonal ) * 0.5f;
// we're giving vehicles some extra padding, to allow for things like shared bogeys extending past the main body
float const radius = glm::length( diagonal ) * 0.65f;
return ( m_frustum.sphere_inside( Dynamic->GetPosition(), radius ) > 0.0f );
}
@@ -47,10 +48,7 @@ opengl_camera::visible( TDynamicObject const *Dynamic ) const {
bool
opengl_renderer::Init( GLFWwindow *Window ) {
if( false == Init_caps() ) {
return false;
}
if( false == Init_caps() ) { return false; }
m_window = Window;
@@ -111,11 +109,21 @@ opengl_renderer::Init( GLFWwindow *Window ) {
}
// preload some common textures
WriteLog( "Loading common gfx data..." );
m_glaretextureid = GetTextureId( "fx\\lightglare", szTexturePath );
m_suntextureid = GetTextureId( "fx\\sun", szTexturePath );
m_moontextureid = GetTextureId( "fx\\moon", szTexturePath );
m_glaretexture = GetTextureId( "fx\\lightglare", szTexturePath );
m_suntexture = GetTextureId( "fx\\sun", szTexturePath );
m_moontexture = GetTextureId( "fx\\moon", szTexturePath );
WriteLog( "...gfx data pre-loading done" );
// prepare basic geometry chunks
auto const geometrybank = m_geometry.create_bank();
float const size = 2.5f;
m_billboardgeometry = m_geometry.create_chunk(
vertex_array{
{ { -size, size, 0.0f }, glm::vec3(), { 1.0f, 1.0f } },
{ { size, size, 0.0f }, glm::vec3(), { 0.0f, 1.0f } },
{ { -size, -size, 0.0f }, glm::vec3(), { 1.0f, 0.0f } },
{ { size, -size, 0.0f }, glm::vec3(), { 0.0f, 0.0f } } },
geometrybank,
GL_TRIANGLE_STRIP );
// prepare debug mode objects
m_quadric = gluNewQuadric();
gluQuadricNormals( m_quadric, GLU_FLAT );
@@ -157,6 +165,7 @@ opengl_renderer::Render() {
// accumulate last 20 frames worth of render time (cap at 1000 fps to prevent calculations going awry)
m_drawtime = std::max( 20.0f, 0.95f * m_drawtime + std::chrono::duration_cast<std::chrono::milliseconds>( ( std::chrono::steady_clock::now() - timestart ) ).count());
m_drawcount = m_drawqueue.size();
}
UILayer.render();
@@ -189,6 +198,10 @@ opengl_renderer::Render( world_environment *Environment ) {
else { ::glDisable( GL_FOG ); }
Environment->m_skydome.Render();
if( true == Global::bUseVBO ) {
// skydome uses a custom vbo which could potentially confuse the main geometry system. hardly elegant but, eh
opengl_vbogeometrybank::reset();
}
Environment->m_stars.render();
float const duskfactor = 1.0f - clamp( std::abs( Environment->m_sun.getAngle() ), 0.0f, 12.0f ) / 12.0f;
@@ -213,7 +226,7 @@ opengl_renderer::Render( world_environment *Environment ) {
auto const &modelview = OpenGLMatrices.data( GL_MODELVIEW );
// sun
{
Bind( m_suntextureid );
Bind( m_suntexture );
::glColor4f( suncolor.x, suncolor.y, suncolor.z, 1.0f );
auto const sunvector = Environment->m_sun.getDirection();
auto const sunposition = modelview * glm::vec4( sunvector.x, sunvector.y, sunvector.z, 1.0f );
@@ -234,7 +247,7 @@ opengl_renderer::Render( world_environment *Environment ) {
}
// moon
{
Bind( m_moontextureid );
Bind( m_moontexture );
float3 mooncolor( 255.0f / 255.0f, 242.0f / 255.0f, 231.0f / 255.0f );
::glColor4f( mooncolor.x, mooncolor.y, mooncolor.z, static_cast<GLfloat>( 1.0 - Global::fLuminance * 0.5 ) );
@@ -412,7 +425,8 @@ opengl_renderer::Render( TGround *Ground ) {
Global::FieldOfView / Global::ZoomFactor
* std::max( 1.0f, (float)Global::ScreenWidth ) / std::max( 1.0f, (float)Global::ScreenHeight ) ) );
Ground->iRendered = 0; // ilość renderowanych sektorów
m_drawqueue.clear();
Math3D::vector3 direction;
for( k = 0; k < Global::iSegmentsRendered; ++k ) // sektory w kolejności odległości
{ // przerobione na użycie SectorOrder
@@ -436,37 +450,14 @@ opengl_renderer::Render( TGround *Ground ) {
if( ( tmp = Ground->FastGetSubRect( i + c, j + r ) ) != nullptr ) {
if( tmp->iNodeCount ) {
// o ile są jakieś obiekty, bo po co puste sektory przelatywać
Ground->pRendered[ Ground->iRendered++ ] = tmp; // tworzenie listy sektorów do renderowania
m_drawqueue.emplace_back( tmp );
}
}
} while( ( i < 0 ) || ( j < 0 ) ); // są 4 przypadki, oprócz i=j=0
}
/*
// dodać renderowanie terenu z E3D - jedno VBO jest używane dla całego modelu, chyba że jest ich więcej
if( Global::bUseVBO ) {
if( ( Global::pTerrainCompact != nullptr )
&& ( Global::pTerrainCompact->pModel != nullptr ) ) {
#ifdef EU07_USE_OLD_RENDERCODE
Global::pTerrainCompact->TerrainRenderVBO( TGroundRect::iFrameNumber );
#endif
// TODO: remap geometry of terrain cells to allow camera-centric rendering
::glPushMatrix();
::glTranslated( -Global::pCameraPosition.x, -Global::pCameraPosition.y, -Global::pCameraPosition.z );
TSubModel *submodel = Global::pTerrainCompact->pModel->Root;
while( submodel != nullptr ) {
if( submodel->iVisible == TGroundRect::iFrameNumber ) {
// tylko jeśli ma być widoczny w danej ramce (problem dla 0==false)
Render( submodel ); // sub kolejne (Next) się nie wyrenderują
}
submodel = submodel->NextGet();
}
::glPopMatrix();
}
}
*/
// renderowanie nieprzezroczystych
for( i = 0; i < Ground->iRendered; ++i ) {
Render( Ground->pRendered[ i ] );
for( auto subcell : m_drawqueue ) {
Render( subcell );
}
// regular render takes care of all solid geometry present in the scene, thus we can launch alpha parts render here
return Render_Alpha( Ground );
@@ -478,69 +469,23 @@ opengl_renderer::Render( TGroundRect *Groundcell ) {
bool result { false }; // will be true if we do any rendering
// TODO: unify render paths
if( Global::bUseVBO ) {
if( Groundcell->iLastDisplay != Groundcell->iFrameNumber ) {
// tylko jezeli dany kwadrat nie był jeszcze renderowany
Groundcell->LoadNodes(); // ewentualne tworzenie siatek
if ( Groundcell->iLastDisplay != Groundcell->iFrameNumber) {
// tylko jezeli dany kwadrat nie był jeszcze renderowany
Groundcell->LoadNodes(); // ewentualne tworzenie siatek
if( ( Groundcell->nRenderRect != nullptr )
&& ( true == Groundcell->StartVBO() ) ) {
// nieprzezroczyste trójkąty kwadratu kilometrowego
for( TGroundNode *node = Groundcell->nRenderRect; node; node = node->nNext3 ) {
Render( node );
}
Groundcell->EndVBO();
if( Groundcell->nRenderRect != nullptr ) {
// nieprzezroczyste trójkąty kwadratu kilometrowego
for( TGroundNode *node = Groundcell->nRenderRect; node != nullptr; node = node->nNext3 ) {
Render( node );
}
if( Groundcell->nTerrain ) {
Render( Groundcell->nTerrain );
}
Groundcell->iLastDisplay = Groundcell->iFrameNumber; // drugi raz nie potrzeba
result = true;
}
if( Groundcell->nTerrain ) {
Render( Groundcell->nTerrain );
}
Groundcell->iLastDisplay = Groundcell->iFrameNumber; // drugi raz nie potrzeba
result = true;
}
else {
// display list render path
::glPushMatrix();
auto const &cellorigin = Groundcell->m_area.center;
// TODO: unify all math objects
auto const originoffset = Math3D::vector3( cellorigin.x, cellorigin.y, cellorigin.z ) - Global::pCameraPosition;
::glTranslated( originoffset.x, originoffset.y, originoffset.z );
if (Groundcell->iLastDisplay != Groundcell->iFrameNumber)
{ // tylko jezeli dany kwadrat nie był jeszcze renderowany
// for (TGroundNode* node=pRender;node;node=node->pNext3)
// node->Render(); //nieprzezroczyste trójkąty kwadratu kilometrowego
if ( Groundcell->nRender)
{ //łączenie trójkątów w jedną listę - trochę wioska
if (!Groundcell->nRender->DisplayListID || ( Groundcell->nRender->iVersion != Global::iReCompile))
{ // jeżeli nie skompilowany, kompilujemy wszystkie trójkąty w jeden
Groundcell->nRender->fSquareRadius = 5000.0 * 5000.0; // aby agregat nigdy nie znikał
Groundcell->nRender->DisplayListID = glGenLists(1);
glNewList( Groundcell->nRender->DisplayListID, GL_COMPILE);
Groundcell->nRender->iVersion = Global::iReCompile; // aktualna wersja siatek
auto const origin = glm::dvec3( Groundcell->m_area.center );
for (TGroundNode *node = Groundcell->nRender; node; node = node->nNext3) // następny tej grupy
node->Compile(origin, true);
glEndList();
}
Render( Groundcell->nRender ); // nieprzezroczyste trójkąty kwadratu kilometrowego
}
// submodels geometry is world-centric, so at least for the time being we need to pop the stack early
::glPopMatrix();
if( Groundcell->nTerrain ) { Render( Groundcell->nTerrain ); }
Groundcell->iLastDisplay = Groundcell->iFrameNumber; // drugi raz nie potrzeba
result = true;
}
else {
::glPopMatrix();
}
}
return result;
}
@@ -551,32 +496,21 @@ opengl_renderer::Render( TSubRect *Groundsubcell ) {
TGroundNode *node;
// nieprzezroczyste obiekty terenu
if( Global::bUseVBO ) {
// vbo render path
if( Groundsubcell->StartVBO() ) {
for( node = Groundsubcell->nRenderRect; node; node = node->nNext3 ) {
if( node->iVboPtr >= 0 ) {
Render( node );
}
}
Groundsubcell->EndVBO();
}
}
else {
// display list render path
for( node = Groundsubcell->nRenderRect; node; node = node->nNext3 ) {
Render( node ); // nieprzezroczyste obiekty terenu
}
for( node = Groundsubcell->nRenderRect; node != nullptr; node = node->nNext3 ) {
Render( node );
}
// nieprzezroczyste obiekty (oprócz pojazdów)
for( node = Groundsubcell->nRender; node; node = node->nNext3 )
for( node = Groundsubcell->nRender; node != nullptr; node = node->nNext3 ) {
Render( node );
}
// nieprzezroczyste z mieszanych modeli
for( node = Groundsubcell->nRenderMixed; node; node = node->nNext3 )
for( node = Groundsubcell->nRenderMixed; node != nullptr; node = node->nNext3 ) {
Render( node );
}
// nieprzezroczyste fragmenty pojazdów na torach
for( int j = 0; j < Groundsubcell->iTracks; ++j )
for( int j = 0; j < Groundsubcell->iTracks; ++j ) {
Groundsubcell->tTracks[ j ]->RenderDyn();
}
#ifdef EU07_SCENERY_EDITOR
// memcells
if( DebugModeFlag ) {
@@ -590,9 +524,9 @@ opengl_renderer::Render( TSubRect *Groundsubcell ) {
bool
opengl_renderer::Render( TGroundNode *Node ) {
/*
Node->SetLastUsage( Timer::GetSimulationTime() );
*/
switch (Node->iType)
{ // obiekty renderowane niezależnie od odległości
case TP_SUBMODEL:
@@ -611,96 +545,58 @@ opengl_renderer::Render( TGroundNode *Node ) {
return false;
}
switch (Node->iType)
{
case TP_TRACK: {
switch (Node->iType) {
if( Global::bUseVBO && ( Node->iNumVerts <= 0 ) ) {
return false;
}
case TP_TRACK: {
// setup
::glPushMatrix();
auto const originoffset = Node->m_rootposition - Global::pCameraPosition;
::glTranslated( originoffset.x, originoffset.y, originoffset.z );
// TODO: unify the render code after generic buffers are in place
if( Global::bUseVBO ) {
// vbo render path
Node->pTrack->RaRenderVBO( Node->iVboPtr );
}
else {
// display list render path
Node->pTrack->Render();
}
// render
Render( Node->pTrack );
// post-render cleanup
::glPopMatrix();
return true;
}
case TP_MODEL: {
Node->Model->Render( Node->pCenter - Global::pCameraPosition );
return true;
}
case TP_MEMCELL: {
GfxRenderer.Render( Node->MemCell );
return true;
}
}
// TODO: sprawdzic czy jest potrzebny warunek fLineThickness < 0
if( ( Node->iFlags & 0x10 )
|| ( Node->fLineThickness < 0 ) ) {
// TODO: unify the render code after generic buffers are in place
if( false == Global::bUseVBO ) {
// additional setup for display lists
if( ( Node->DisplayListID == 0 )
|| ( Node->iVersion != Global::iReCompile ) ) { // Ra: wymuszenie rekompilacji
Node->Compile(Node->m_rootposition);
if( Global::bManageNodes )
ResourceManager::Register( Node );
};
}
if( ( Node->iType == GL_LINES )
|| ( Node->iType == GL_LINE_STRIP )
|| ( Node->iType == GL_LINE_LOOP ) ) {
// wszelkie linie są rysowane na samym końcu
if( Node->iNumPts ) {
// setup
// w zaleznosci od koloru swiatla
::glColor4fv(
glm::value_ptr(
glm::vec4(
Node->Diffuse * glm::make_vec3( Global::DayLight.ambient ),
std::min(
1.0,
1000.0 * Node->fLineThickness / ( distancesquared + 1.0 ) ) ) ) );
GfxRenderer.Bind( 0 );
// render
// TODO: unify the render code after generic buffers are in place
if( Global::bUseVBO ) {
::glPushMatrix();
auto const originoffset = Node->m_rootposition - Global::pCameraPosition;
::glTranslated( originoffset.x, originoffset.y, originoffset.z );
::glDrawArrays( Node->iType, Node->iVboPtr, Node->iNumPts );
::glPopMatrix();
}
else {
::glCallList( Node->DisplayListID );
}
// post-render cleanup
return true;
}
else {
case GL_LINES: {
if( ( Node->m_geometry == NULL )
|| ( Node->fLineThickness > 0.0 ) ) {
return false;
}
// setup
// w zaleznosci od koloru swiatla
::glColor4fv(
glm::value_ptr(
glm::vec4(
Node->Diffuse * glm::make_vec3( Global::DayLight.ambient ),
std::min(
1.0,
1000.0 * Node->fLineThickness / ( distancesquared + 1.0 ) ) ) ) );
GfxRenderer.Bind( 0 );
::glPushMatrix();
auto const originoffset = Node->m_rootposition - Global::pCameraPosition;
::glTranslated( originoffset.x, originoffset.y, originoffset.z );
// render
m_geometry.draw( Node->m_geometry );
// post-render cleanup
::glPopMatrix();
return true;
}
else {
// GL_TRIANGLE etc
if( ( Global::bUseVBO ?
Node->iVboPtr < 0 :
Node->DisplayListID == 0 ) ) {
case GL_TRIANGLES: {
if( ( Node->m_geometry == NULL )
|| ( ( Node->iFlags & 0x10 ) == 0 ) ) {
return false;
}
// setup
@@ -708,23 +604,25 @@ opengl_renderer::Render( TGroundNode *Node ) {
Bind( Node->TextureID );
::glPushMatrix();
auto const originoffset = Node->m_rootposition - Global::pCameraPosition;
::glTranslated( originoffset.x, originoffset.y, originoffset.z );
// render
// TODO: unify the render code after generic buffers are in place
if( Global::bUseVBO ) {
// vbo render path
::glPushMatrix();
auto const originoffset = Node->m_rootposition - Global::pCameraPosition;
::glTranslated( originoffset.x, originoffset.y, originoffset.z );
::glDrawArrays( Node->iType, Node->iVboPtr, Node->iNumVerts );
::glPopMatrix();
}
else {
// display list render path
::glCallList( Node->DisplayListID );
}
m_geometry.draw( Node->m_geometry );
// post-render cleanup
::glPopMatrix();
return true;
}
case TP_MEMCELL: {
Render( Node->MemCell );
return true;
}
default: { break; }
}
// in theory we shouldn't ever get here but, eh
return false;
@@ -946,7 +844,7 @@ opengl_renderer::Render( TSubModel *Submodel ) {
::glDisableClientState( GL_NORMAL_ARRAY );
::glDisableClientState( GL_TEXTURE_COORD_ARRAY );
::glEnableClientState( GL_COLOR_ARRAY );
::glColorPointer( 3, GL_FLOAT, sizeof( CVertNormTex ), static_cast<char *>( nullptr ) + 12 ); // kolory
::glColorPointer( 3, GL_FLOAT, sizeof( basic_vertex ), static_cast<char *>( nullptr ) + 12 ); // kolory
::glDrawArrays( GL_POINTS, Submodel->iVboPtr, Submodel->iNumVerts );
@@ -978,6 +876,28 @@ opengl_renderer::Render( TSubModel *Submodel ) {
Render( Submodel->Next ); // dalsze rekurencyjnie
}
void
opengl_renderer::Render( TTrack *Track ) {
if( ( Track->TextureID1 == 0 )
&& ( Track->TextureID2 == 0 ) ) {
return;
}
Track->EnvironmentSet();
if( Track->TextureID1 != 0 ) {
Bind( Track->TextureID1 );
m_geometry.draw( std::begin( Track->Geometry1 ), std::end( Track->Geometry1 ) );
}
if( Track->TextureID2 != 0 ) {
Bind( Track->TextureID2 );
m_geometry.draw( std::begin( Track->Geometry2 ), std::end( Track->Geometry2 ) );
}
Track->EnvironmentReset();
}
void
opengl_renderer::Render( TMemCell *Memcell ) {
@@ -999,7 +919,6 @@ opengl_renderer::Render( TMemCell *Memcell ) {
bool
opengl_renderer::Render_Alpha( TGround *Ground ) {
// legacy version of the code:
::glEnable( GL_BLEND );
::glAlphaFunc( GL_GREATER, 0.04f ); // im mniejsza wartość, tym większa ramka, domyślnie 0.1f
::glColor4f( 1.0f, 1.0f, 1.0f, 1.0f );
@@ -1007,54 +926,30 @@ opengl_renderer::Render_Alpha( TGround *Ground ) {
TGroundNode *node;
TSubRect *tmp;
// Ra: renderowanie progresywne - zależne od FPS oraz kierunku patrzenia
for( int i = Ground->iRendered - 1; i >= 0; --i ) // od najdalszych
{ // przezroczyste trójkąty w oddzielnym cyklu przed modelami
tmp = Ground->pRendered[ i ];
if( Global::bUseVBO ) {
// vbo render path
if( tmp->StartVBO() ) {
for( node = tmp->nRenderRectAlpha; node; node = node->nNext3 ) {
if( node->iVboPtr >= 0 ) {
Render_Alpha( node );
}
}
tmp->EndVBO();
}
}
else {
// display list render path
for( node = tmp->nRenderRectAlpha; node; node = node->nNext3 ) {
Render_Alpha( node );
}
for( auto subcell = std::rbegin( m_drawqueue ); subcell != std::rend( m_drawqueue ); ++subcell ) {
// przezroczyste trójkąty w oddzielnym cyklu przed modelami
tmp = *subcell;
for( node = tmp->nRenderRectAlpha; node; node = node->nNext3 ) {
Render_Alpha( node );
}
}
for( int i = Ground->iRendered - 1; i >= 0; --i ) // od najdalszych
for( auto subcell = std::rbegin( m_drawqueue ); subcell != std::rend( m_drawqueue ); ++subcell )
{ // renderowanie przezroczystych modeli oraz pojazdów
Render_Alpha( Ground->pRendered[ i ] );
Render_Alpha( *subcell );
}
::glDisable( GL_LIGHTING ); // linie nie powinny świecić
for( int i = Ground->iRendered - 1; i >= 0; --i ) // od najdalszych
{ // druty na końcu, żeby się nie robiły białe plamy na tle lasu
tmp = Ground->pRendered[ i ];
if( Global::bUseVBO ) {
// vbo render path
if( tmp->StartVBO() ) {
for( node = tmp->nRenderWires; node; node = node->nNext3 ) {
Render_Alpha( node );
}
tmp->EndVBO();
}
}
else {
// display list render path
for( node = tmp->nRenderWires; node; node = node->nNext3 ) {
Render_Alpha( node ); // druty
}
for( auto subcell = std::rbegin( m_drawqueue ); subcell != std::rend( m_drawqueue ); ++subcell ) {
// druty na końcu, żeby się nie robiły białe plamy na tle lasu
tmp = *subcell;
for( node = tmp->nRenderWires; node; node = node->nNext3 ) {
Render_Alpha( node );
}
}
::glEnable( GL_LIGHTING );
return true;
}
@@ -1091,9 +986,9 @@ opengl_renderer::Render_Alpha( TGroundNode *Node ) {
// pozniej sprawdzamy czy jest wlaczony PROBLEND dla aktualnie renderowanego noda TRIANGLE,
// wlasciwie dla kazdego node'a
// i jezeli tak to odpowiedni GL_GREATER w przeciwnym wypadku standardowy 0.04
/*
Node->SetLastUsage( Timer::GetSimulationTime() );
*/
double const distancesquared = SquareMagnitude( ( Node->pCenter - Global::pCameraPosition ) / Global::ZoomFactor );
if( ( distancesquared > ( Node->fSquareRadius * Global::fDistanceFactor ) )
|| ( distancesquared < ( Node->fSquareMinRadius / Global::fDistanceFactor ) ) ) {
@@ -1103,7 +998,6 @@ opengl_renderer::Render_Alpha( TGroundNode *Node ) {
switch (Node->iType)
{
case TP_TRACTION: {
// TODO: unify the render code after generic buffers are in place
if( Node->bVisible ) {
// rysuj jesli sa druty i nie zerwana
if( ( Node->hvTraction->Wires == 0 )
@@ -1111,11 +1005,6 @@ opengl_renderer::Render_Alpha( TGroundNode *Node ) {
return false;
}
// setup
::glPushMatrix();
auto const originoffset = Node->m_rootposition - Global::pCameraPosition;
::glTranslated( originoffset.x, originoffset.y, originoffset.z );
Bind( NULL );
if( !Global::bSmoothTraction ) {
// na liniach kiepsko wygląda - robi gradient
::glDisable( GL_LINE_SMOOTH );
@@ -1129,16 +1018,23 @@ opengl_renderer::Render_Alpha( TGroundNode *Node ) {
auto const color { Node->hvTraction->wire_color() };
::glColor4f( color.r, color.g, color.b, linealpha );
Bind( NULL );
::glPushMatrix();
auto const originoffset = Node->m_rootposition - Global::pCameraPosition;
::glTranslated( originoffset.x, originoffset.y, originoffset.z );
// render
m_geometry.draw( Node->hvTraction->m_geometry );
// post-render cleanup
::glPopMatrix();
::glLineWidth( 1.0 );
if( !Global::bSmoothTraction ) {
::glEnable( GL_LINE_SMOOTH );
}
::glPopMatrix();
return true;
}
else {
@@ -1149,102 +1045,75 @@ opengl_renderer::Render_Alpha( TGroundNode *Node ) {
Node->Model->RenderAlpha( Node->pCenter - Global::pCameraPosition );
return true;
}
}
// TODO: sprawdzic czy jest potrzebny warunek fLineThickness < 0
if( ( Node->iNumVerts && ( Node->iFlags & 0x20 ) )
|| ( Node->iNumPts && ( Node->fLineThickness > 0 ) ) ) {
#ifdef _PROBLEND
if( ( Node->PROBLEND ) ) // sprawdza, czy w nazwie nie ma @ //Q: 13122011 - Szociu: 27012012
{
::glDisable( GL_BLEND );
::glAlphaFunc( GL_GREATER, 0.50f ); // im mniejsza wartość, tym większa ramka, domyślnie 0.1f
};
#endif
// TODO: unify the render code after generic buffers are in place
if( false == Global::bUseVBO ) {
// additional setup for display lists
if( ( Node->DisplayListID == 0 )
|| ( Node->iVersion != Global::iReCompile ) ) { // Ra: wymuszenie rekompilacji
Node->Compile(Node->m_rootposition);
if( Global::bManageNodes )
ResourceManager::Register( Node );
};
}
bool result( false );
if( ( Node->iType == GL_LINES )
|| ( Node->iType == GL_LINE_STRIP )
|| ( Node->iType == GL_LINE_LOOP ) ) {
// wszelkie linie są rysowane na samym końcu
if( Node->iNumPts ) {
// setup
::glPushMatrix();
auto const originoffset = Node->m_rootposition - Global::pCameraPosition;
::glTranslated( originoffset.x, originoffset.y, originoffset.z );
// w zaleznosci od koloru swiatla
::glColor4fv(
glm::value_ptr(
glm::vec4(
Node->Diffuse * glm::make_vec3( Global::DayLight.ambient ),
std::min(
1.0,
1000.0 * Node->fLineThickness / ( distancesquared + 1.0 ) ) ) ) );
GfxRenderer.Bind( 0 );
// render
// TODO: unify the render code after generic buffers are in place
if( Global::bUseVBO ) {
::glDrawArrays( Node->iType, Node->iVboPtr, Node->iNumPts );
}
else {
::glCallList( Node->DisplayListID );
}
// post-render cleanup
::glPopMatrix();
result = true;
case GL_LINES: {
if( ( Node->m_geometry == NULL )
|| ( Node->fLineThickness < 0.0 ) ) {
return false;
}
}
else {
// GL_TRIANGLE etc
// setup
// w zaleznosci od koloru swiatla
::glColor4fv(
glm::value_ptr(
glm::vec4(
Node->Diffuse * glm::make_vec3( Global::DayLight.ambient ),
std::min(
1.0,
1000.0 * Node->fLineThickness / ( distancesquared + 1.0 ) ) ) ) );
GfxRenderer.Bind( 0 );
::glPushMatrix();
auto const originoffset = Node->m_rootposition - Global::pCameraPosition;
::glTranslated( originoffset.x, originoffset.y, originoffset.z );
// render
m_geometry.draw( Node->m_geometry );
// post-render cleanup
::glPopMatrix();
return true;
}
case GL_TRIANGLES: {
if( ( Node->m_geometry == NULL )
|| ( ( Node->iFlags & 0x20 ) == 0 ) ) {
return false;
}
// setup
#ifdef _PROBLEND
if( ( Node->PROBLEND ) ) // sprawdza, czy w nazwie nie ma @ //Q: 13122011 - Szociu: 27012012
{
::glDisable( GL_BLEND );
::glAlphaFunc( GL_GREATER, 0.50f ); // im mniejsza wartość, tym większa ramka, domyślnie 0.1f
};
#endif
::glColor3fv( glm::value_ptr( Node->Diffuse ) );
Bind( Node->TextureID );
::glPushMatrix();
auto const originoffset = Node->m_rootposition - Global::pCameraPosition;
::glTranslated( originoffset.x, originoffset.y, originoffset.z );
// render
// TODO: unify the render code after generic buffers are in place
if( Global::bUseVBO ) {
// vbo render path
if( Node->iVboPtr >= 0 ) {
::glDrawArrays( Node->iType, Node->iVboPtr, Node->iNumVerts );
result = true;
}
}
else {
// display list render path
::glCallList( Node->DisplayListID );
result = true;
}
m_geometry.draw( Node->m_geometry );
// post-render cleanup
::glPopMatrix();
}
#ifdef _PROBLEND
if( ( Node->PROBLEND ) ) // sprawdza, czy w nazwie nie ma @ //Q: 13122011 - Szociu: 27012012
{
::glEnable( GL_BLEND );
::glAlphaFunc( GL_GREATER, 0.04f );
}
if( ( Node->PROBLEND ) ) // sprawdza, czy w nazwie nie ma @ //Q: 13122011 - Szociu: 27012012
{
::glEnable( GL_BLEND );
::glAlphaFunc( GL_GREATER, 0.04f );
}
#endif
return result;
return true;
}
default: { break; }
}
// in theory we shouldn't ever get here but, eh
return false;
@@ -1253,10 +1122,7 @@ opengl_renderer::Render_Alpha( TGroundNode *Node ) {
bool
opengl_renderer::Render_Alpha( TDynamicObject *Dynamic ) {
if( false == Dynamic->renderme ) {
return false;
}
if( false == Dynamic->renderme ) { return false; }
// setup
TSubModel::iInstance = ( size_t )this; //żeby nie robić cudzych animacji
@@ -1426,10 +1292,10 @@ opengl_renderer::Render_Alpha( TSubModel *Submodel ) {
glarelevel = std::max( 0.0f, glarelevel - static_cast<float>(Global::fLuminance) );
if( glarelevel > 0.0f ) {
// setup
::glPushAttrib( GL_ENABLE_BIT | GL_CURRENT_BIT | GL_COLOR_BUFFER_BIT );
Bind( m_glaretextureid );
Bind( m_glaretexture );
::glColor4f( Submodel->f4Diffuse[ 0 ], Submodel->f4Diffuse[ 1 ], Submodel->f4Diffuse[ 2 ], glarelevel );
::glDisable( GL_LIGHTING );
::glBlendFunc( GL_SRC_ALPHA, GL_ONE );
@@ -1437,15 +1303,10 @@ opengl_renderer::Render_Alpha( TSubModel *Submodel ) {
::glPushMatrix();
::glLoadIdentity(); // macierz jedynkowa
::glTranslatef( lightcenter.x, lightcenter.y, lightcenter.z ); // początek układu zostaje bez zmian
::glRotated( atan2( lightcenter.x, lightcenter.z ) * 180.0 / M_PI, 0.0, 1.0, 0.0 ); // jedynie obracamy w pionie o kąt
::glRotated( std::atan2( lightcenter.x, lightcenter.z ) * 180.0 / M_PI, 0.0, 1.0, 0.0 ); // jedynie obracamy w pionie o kąt
// TODO: turn the drawing instructions into a compiled call / array
::glBegin( GL_TRIANGLE_STRIP );
float const size = 2.5f;
::glTexCoord2f( 1.0f, 1.0f ); ::glVertex3f( -size, size, 0.0f );
::glTexCoord2f( 0.0f, 1.0f ); ::glVertex3f( size, size, 0.0f );
::glTexCoord2f( 1.0f, 0.0f ); ::glVertex3f( -size, -size, 0.0f );
::glTexCoord2f( 0.0f, 0.0f ); ::glVertex3f( size, -size, 0.0f );
// main draw call
m_geometry.draw( m_billboardgeometry );
/*
// NOTE: we could do simply...
vec3 vertexPosition_worldspace =
@@ -1454,8 +1315,7 @@ opengl_renderer::Render_Alpha( TSubModel *Submodel ) {
+ CameraUp_worldspace * squareVertices.y * BillboardSize.y;
// ...etc instead IF we had easy access to camera's forward and right vectors. TODO: check if Camera matrix is accessible
*/
::glEnd();
// post-render cleanup
::glPopMatrix();
::glPopAttrib();
}
@@ -1557,8 +1417,12 @@ opengl_renderer::Update ( double const Deltatime ) {
}
// TODO: add garbage collection and other less frequent works here
if( DebugModeFlag )
if( true == DebugModeFlag ) {
m_debuginfo = m_textures.info();
}
else {
m_debuginfo.clear();
}
};
// debug performance string

View File

@@ -172,6 +172,7 @@ public:
// members
GLenum static const sunlight{ GL_LIGHT0 };
std::size_t m_drawcount { 0 };
private:
// types
@@ -194,6 +195,8 @@ private:
Render( TSubRect *Groundsubcell );
bool
Render( TGroundNode *Node );
void
Render( TTrack *Track );
void
Render( TMemCell *Memcell );
bool
@@ -212,16 +215,18 @@ private:
geometrybank_manager m_geometry;
texture_manager m_textures;
opengl_camera m_camera;
rendermode renderpass{ rendermode::color };
float m_drawrange{ 2500.0f }; // current drawing range
float m_drawtime{ 1000.0f / 30.0f * 20.0f }; // start with presumed 'neutral' average of 30 fps
double m_updateaccumulator{ 0.0 };
rendermode renderpass { rendermode::color };
float m_drawrange { 2500.0f }; // current drawing range
float m_drawtime { 1000.0f / 30.0f * 20.0f }; // start with presumed 'neutral' average of 30 fps
double m_updateaccumulator { 0.0 };
std::string m_debuginfo;
GLFWwindow *m_window{ nullptr };
texture_handle m_glaretextureid{ -1 };
texture_handle m_suntextureid{ -1 };
texture_handle m_moontextureid{ -1 };
GLFWwindow *m_window { nullptr };
texture_handle m_glaretexture { -1 };
texture_handle m_suntexture { -1 };
texture_handle m_moontexture { -1 };
geometry_handle m_billboardgeometry { 0, 0 };
GLUquadricObj *m_quadric; // helper object for drawing debug mode scene elements
std::vector< TSubRect* > m_drawqueue; // list of subcells to be drawn in current render pass
};