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

build 170626. individual self-illumination levels for interior sections, automatic merging of suitable terrain geometry during load from text files, unused resource release by geometry bank manager, support for ui backgrounds with width:height ratio other than 4:3, comment parsing optimization, minor bug fixes

This commit is contained in:
tmj-fstate
2017-06-26 16:57:25 +02:00
parent 34a899239f
commit 5d7b3fb036
18 changed files with 608 additions and 339 deletions

View File

@@ -527,6 +527,39 @@ void TDynamicObject::UpdateLeverEnum(TAnim *pAnim)
pAnim->smAnimated->SetRotate(float3(1, 0, 0), pAnim->fParam[*pAnim->iIntBase]); pAnim->smAnimated->SetRotate(float3(1, 0, 0), pAnim->fParam[*pAnim->iIntBase]);
}; };
// sets light levels for registered interior sections
void
TDynamicObject::toggle_lights() {
if( true == SectionLightsActive ) {
// switch all lights off
for( auto &sectionlight : SectionLightLevels ) {
sectionlight.level = 0.0f;
}
SectionLightsActive = false;
}
else {
std::string compartmentname;
// set lights with probability depending on the compartment type. TODO: expose this in .mmd file
for( auto &sectionlight : SectionLightLevels ) {
compartmentname = sectionlight.compartment->pName;
if( ( compartmentname.find( "corridor" ) != std::string::npos )
|| ( compartmentname.find( "korytarz" ) != std::string::npos ) ) {
// corridors are lit 100% of time
sectionlight.level = 0.75f;
}
else if(
( compartmentname.find( "compartment" ) != std::string::npos )
|| ( compartmentname.find( "przedzial" ) != std::string::npos ) ) {
// compartments are lit with 75% probability
sectionlight.level = ( Random() < 0.75 ? 0.75f : 0.05f );
}
}
SectionLightsActive = true;
}
}
// ABu 29.01.05 przeklejone z render i renderalpha: ********************* // ABu 29.01.05 przeklejone z render i renderalpha: *********************
void TDynamicObject::ABuLittleUpdate(double ObjSqrDist) void TDynamicObject::ABuLittleUpdate(double ObjSqrDist)
{ // ABu290105: pozbierane i uporzadkowane powtarzajace { // ABu290105: pozbierane i uporzadkowane powtarzajace
@@ -946,6 +979,13 @@ void TDynamicObject::ABuLittleUpdate(double ObjSqrDist)
} }
// else btHeadSignals23.TurnOff(); // else btHeadSignals23.TurnOff();
} }
// interior light levels
for( auto const &section : SectionLightLevels ) {
section.compartment->SetLightLevel( section.level, true );
if( section.load != nullptr ) {
section.load->SetLightLevel( section.level, true );
}
}
} }
// ABu 29.01.05 koniec przeklejenia ************************************* // ABu 29.01.05 koniec przeklejenia *************************************
@@ -1949,6 +1989,41 @@ TDynamicObject::Init(std::string Name, // nazwa pojazdu, np. "EU07-424"
btMechanik1.Init("mechanik1", mdLowPolyInt, false); btMechanik1.Init("mechanik1", mdLowPolyInt, false);
btMechanik2.Init("mechanik2", mdLowPolyInt, false); btMechanik2.Init("mechanik2", mdLowPolyInt, false);
TurnOff(); // resetowanie zmiennych submodeli TurnOff(); // resetowanie zmiennych submodeli
if( mdLowPolyInt != nullptr ) {
// check the low poly interior for potential compartments of interest, ie ones which can be individually lit
// TODO: definition of relevant compartments in the .mmd file
TSubModel *submodel { nullptr };
if( ( submodel = mdLowPolyInt->GetFromName( "cab1" ) ) != nullptr ) { SectionLightLevels.emplace_back( submodel, nullptr, 0.0f ); }
if( ( submodel = mdLowPolyInt->GetFromName( "cab2" ) ) != nullptr ) { SectionLightLevels.emplace_back( submodel, nullptr, 0.0f ); }
if( ( submodel = mdLowPolyInt->GetFromName( "cab0" ) ) != nullptr ) { SectionLightLevels.emplace_back( submodel, nullptr, 0.0f ); }
// passenger car compartments
std::vector<std::string> nameprefixes = { "corridor", "korytarz", "compartment", "przedzial" };
int compartmentindex;
std::string compartmentname;
for( auto const &nameprefix : nameprefixes ) {
compartmentindex = 0;
do {
compartmentname =
nameprefix + (
compartmentindex < 10 ?
"0" + std::to_string( compartmentindex ) :
std::to_string( compartmentindex ) );
submodel = mdLowPolyInt->GetFromName( compartmentname.c_str() );
if( submodel != nullptr ) {
// if specified compartment was found we check also for potential matching section in the currently assigned load
// NOTE: if the load gets changed this will invalidate stored pointers. TODO: rebuild the table on load change
SectionLightLevels.emplace_back(
submodel,
( mdLoad != nullptr ?
mdLoad->GetFromName( compartmentname.c_str() ):
nullptr ),
0.0f );
}
++compartmentindex;
} while( submodel != nullptr );
}
}
// wyszukiwanie zderzakow // wyszukiwanie zderzakow
if (mdModel) // jeśli ma w czym szukać if (mdModel) // jeśli ma w czym szukać
for (int i = 0; i < 2; i++) for (int i = 0; i < 2; i++)
@@ -3416,6 +3491,20 @@ bool TDynamicObject::Update(double dt, double dt1)
dDoorMoveR = 0; dDoorMoveR = 0;
} }
// compartment lights
/*
if( ( ctOwner != nullptr ?
ctOwner->Controlling()->Battery != SectionLightsActive :
MoverParameters->Battery != SectionLightsActive ) ) {
// if the vehicle has a controller, we base the light state on state of the controller otherwise we check the vehicle itself
*/
// the version above won't work as the vehicles don't turn batteries off :|
if( ( ctOwner != nullptr ?
ctOwner->Controlling()->Battery != SectionLightsActive :
SectionLightsActive == true ) ) { // without controller lights are off. NOTE: this likely mess up the EMU
toggle_lights();
}
// ABu-160303 sledzenie toru przed obiektem: ******************************* // ABu-160303 sledzenie toru przed obiektem: *******************************
// Z obserwacji: v>0 -> Coupler 0; v<0 ->coupler1 (Ra: prędkość jest związana // Z obserwacji: v>0 -> Coupler 0; v<0 ->coupler1 (Ra: prędkość jest związana
// z pojazdem) // z pojazdem)

View File

@@ -143,12 +143,8 @@ class TAnim
struct material_data { struct material_data {
int textures_alpha{ 0x30300030 }; // maska przezroczystości tekstur. default: tekstury wymienne nie mają przezroczystości int textures_alpha{ 0x30300030 }; // maska przezroczystości tekstur. default: tekstury wymienne nie mają przezroczystości
texture_handle replacable_skins[ 5 ]; // McZapkie:zmienialne nadwozie texture_handle replacable_skins[ 5 ] = { NULL, NULL, NULL, NULL, NULL }; // McZapkie:zmienialne nadwozie
int multi_textures{ 0 }; //<0 tekstury wskazane wpisem, >0 tekstury z przecinkami, =0 jedna int multi_textures{ 0 }; //<0 tekstury wskazane wpisem, >0 tekstury z przecinkami, =0 jedna
material_data() {
::SecureZeroMemory( replacable_skins, sizeof( replacable_skins ) );
}
}; };
class TDynamicObject { // klasa pojazdu class TDynamicObject { // klasa pojazdu
@@ -169,8 +165,7 @@ private: // położenie pojazdu w świecie oraz parametry ruchu
float fAxleDist; // rozstaw wózków albo osi do liczenia proporcji zacienienia float fAxleDist; // rozstaw wózków albo osi do liczenia proporcji zacienienia
vector3 modelRot; // obrot pudła względem świata - do przeanalizowania, czy potrzebne!!! vector3 modelRot; // obrot pudła względem świata - do przeanalizowania, czy potrzebne!!!
// bool bCameraNear; //blisko kamer są potrzebne dodatkowe obliczenia szczegółów // bool bCameraNear; //blisko kamer są potrzebne dodatkowe obliczenia szczegółów
TDynamicObject * ABuFindNearestObject( TTrack *Track, TDynamicObject *MyPointer, TDynamicObject * ABuFindNearestObject( TTrack *Track, TDynamicObject *MyPointer, int &CouplNr );
int &CouplNr );
public: // parametry położenia pojazdu dostępne publicznie public: // parametry położenia pojazdu dostępne publicznie
std::string asTrack; // nazwa toru początkowego; wywalić? std::string asTrack; // nazwa toru początkowego; wywalić?
@@ -191,8 +186,18 @@ public: // modele składowe pojazdu
TModel3d *mdLoad; // model zmiennego ładunku TModel3d *mdLoad; // model zmiennego ładunku
TModel3d *mdKabina; // model kabiny dla użytkownika; McZapkie-030303: to z train.h TModel3d *mdKabina; // model kabiny dla użytkownika; McZapkie-030303: to z train.h
TModel3d *mdLowPolyInt; // ABu 010305: wnetrze lowpoly TModel3d *mdLowPolyInt; // ABu 010305: wnetrze lowpoly
float3 InteriorLight{ 0.9f * 255.0f / 255.0f, 0.9f * 216.0f / 255.0f, 0.9f * 176.0f / 255.0f }; // tungsten light. TODO: allow definition of light type? float3 InteriorLight { 0.9f * 255.0f / 255.0f, 0.9f * 216.0f / 255.0f, 0.9f * 176.0f / 255.0f }; // tungsten light. TODO: allow definition of light type?
float InteriorLightLevel{ 0.0f }; // current level of interior lighting float InteriorLightLevel { 0.0f }; // current level of interior lighting
struct section_light {
TSubModel *compartment;
TSubModel *load;
float level;
section_light( TSubModel *Compartment, TSubModel *Load, float const Level ) :
compartment(Compartment), load(Load), level(Level)
{}
};
std::vector<section_light> SectionLightLevels; // table of light levels for specific compartments of associated 3d model
bool SectionLightsActive { false }; // flag indicating whether section lights were set.
float fShade; // zacienienie: 0:normalnie, -1:w ciemności, +1:dodatkowe światło (brak koloru?) float fShade; // zacienienie: 0:normalnie, -1:w ciemności, +1:dodatkowe światło (brak koloru?)
private: // zmienne i metody do animacji submodeli; Ra: sprzatam animacje w pojeździe private: // zmienne i metody do animacji submodeli; Ra: sprzatam animacje w pojeździe
@@ -200,7 +205,9 @@ public: // modele składowe pojazdu
public: public:
inline inline
material_data const *Material() const { return &m_materialdata; } material_data const
*Material() const {
return &m_materialdata; }
// tymczasowo udostępnione do wyszukiwania drutu // tymczasowo udostępnione do wyszukiwania drutu
int iAnimType[ ANIM_TYPES ]; // 0-osie,1-drzwi,2-obracane,3-zderzaki,4-wózki,5-pantografy,6-tłoki int iAnimType[ ANIM_TYPES ]; // 0-osie,1-drzwi,2-obracane,3-zderzaki,4-wózki,5-pantografy,6-tłoki
private: private:
@@ -226,6 +233,7 @@ public: // modele składowe pojazdu
void UpdateLeverFloat(TAnim *pAnim); // animacja gałki zależna od float void UpdateLeverFloat(TAnim *pAnim); // animacja gałki zależna od float
void UpdateLeverInt(TAnim *pAnim); // animacja gałki zależna od int (wartość) void UpdateLeverInt(TAnim *pAnim); // animacja gałki zależna od int (wartość)
void UpdateLeverEnum(TAnim *pAnim); // animacja gałki zależna od int (lista kątów) void UpdateLeverEnum(TAnim *pAnim); // animacja gałki zależna od int (lista kątów)
void toggle_lights(); // switch light levels for registered interior sections
private: // Ra: ciąg dalszy animacji, dopiero do ogarnięcia private: // Ra: ciąg dalszy animacji, dopiero do ogarnięcia
// ABuWozki 060504 // ABuWozki 060504
vector3 bogieRot[2]; // Obroty wozkow w/m korpusu vector3 bogieRot[2]; // Obroty wozkow w/m korpusu

View File

@@ -67,7 +67,6 @@ std::string LogComment;
TGroundNode::TGroundNode() TGroundNode::TGroundNode()
{ // nowy obiekt terenu - pusty { // nowy obiekt terenu - pusty
iType = GL_POINTS; iType = GL_POINTS;
Vertices = NULL;
nNext = nNext2 = NULL; nNext = nNext2 = NULL;
iCount = 0; // wierzchołków w trójkącie iCount = 0; // wierzchołków w trójkącie
// iNumPts=0; //punktów w linii // iNumPts=0; //punktów w linii
@@ -115,9 +114,6 @@ TGroundNode::~TGroundNode()
break; break;
case TP_TERRAIN: case TP_TERRAIN:
{ // pierwsze nNode zawiera model E3D, reszta to trójkąty { // pierwsze nNode zawiera model E3D, reszta to trójkąty
for (int i = 1; i < iCount; ++i)
nNode->Vertices =
NULL; // zerowanie wskaźników w kolejnych elementach, bo nie są do usuwania
delete[] nNode; // usunięcie tablicy i pierwszego elementu delete[] nNode; // usunięcie tablicy i pierwszego elementu
} }
case TP_SUBMODEL: // dla formalności, nie wymaga usuwania case TP_SUBMODEL: // dla formalności, nie wymaga usuwania
@@ -125,33 +121,31 @@ TGroundNode::~TGroundNode()
case GL_LINES: case GL_LINES:
case GL_LINE_STRIP: case GL_LINE_STRIP:
case GL_LINE_LOOP: case GL_LINE_LOOP:
SafeDeleteArray(Points);
break;
case GL_TRIANGLE_STRIP: case GL_TRIANGLE_STRIP:
case GL_TRIANGLE_FAN: case GL_TRIANGLE_FAN:
case GL_TRIANGLES: case GL_TRIANGLES:
SafeDeleteArray(Vertices); SafeDelete( Piece );
break; break;
} }
} }
/*
void TGroundNode::Init(int n) void TGroundNode::Init(int n)
{ // utworzenie tablicy wierzchołków { // utworzenie tablicy wierzchołków
bVisible = false; bVisible = false;
iNumVerts = n; iNumVerts = n;
Vertices = new TGroundVertex[iNumVerts]; Vertices = new TGroundVertex[iNumVerts];
} }
*/
TGroundNode::TGroundNode( TGroundNodeType t, int n ) : TGroundNode::TGroundNode( TGroundNodeType t ) :
TGroundNode() { TGroundNode() {
// utworzenie obiektu // utworzenie obiektu
iNumVerts = n;
if( iNumVerts ) {
Vertices = new TGroundVertex[ iNumVerts ];
}
iType = t; iType = t;
switch (iType) { switch (iType) {
// zależnie od typu // zależnie od typu
case GL_TRIANGLES: {
Piece = new piece_node;
break;
}
case TP_TRACK: { case TP_TRACK: {
pTrack = new TTrack( this ); pTrack = new TTrack( this );
break; break;
@@ -171,36 +165,36 @@ void TGroundNode::InitNormals()
switch (iType) switch (iType)
{ {
case GL_TRIANGLE_STRIP: case GL_TRIANGLE_STRIP:
v1 = Vertices[0].position - Vertices[1].position; v1 = Piece->vertices[0].position - Piece->vertices[1].position;
v2 = Vertices[1].position - Vertices[2].position; v2 = Piece->vertices[1].position - Piece->vertices[2].position;
n1 = glm::normalize(glm::cross(v1, v2)); n1 = glm::normalize(glm::cross(v1, v2));
if (Vertices[0].normal == glm::vec3()) if (Piece->vertices[0].normal == glm::vec3())
Vertices[0].normal = n1; Piece->vertices[0].normal = n1;
v3 = Vertices[2].position - Vertices[3].position; v3 = Piece->vertices[2].position - Piece->vertices[3].position;
n2 = glm::normalize(glm::cross(v3, v2)); n2 = glm::normalize(glm::cross(v3, v2));
if (Vertices[1].normal == glm::vec3()) if (Piece->vertices[1].normal == glm::vec3())
Vertices[1].normal = (n1 + n2) * 0.5f; Piece->vertices[1].normal = (n1 + n2) * 0.5f;
for ( i = 2; i < iNumVerts - 2; i += 2) for ( i = 2; i < iNumVerts - 2; i += 2)
{ {
v4 = Vertices[i - 1].position - Vertices[i].position; v4 = Piece->vertices[i - 1].position - Piece->vertices[i].position;
v5 = Vertices[i].position - Vertices[i + 1].position; v5 = Piece->vertices[i].position - Piece->vertices[i + 1].position;
n3 = glm::normalize(glm::cross(v3, v4)); n3 = glm::normalize(glm::cross(v3, v4));
n4 = glm::normalize(glm::cross(v5, v4)); n4 = glm::normalize(glm::cross(v5, v4));
if (Vertices[i].normal == glm::vec3()) if (Piece->vertices[i].normal == glm::vec3())
Vertices[i].normal = (n1 + n2 + n3) / 3.0f; Piece->vertices[i].normal = (n1 + n2 + n3) / 3.0f;
if (Vertices[i + 1].normal == glm::vec3()) if (Piece->vertices[i + 1].normal == glm::vec3())
Vertices[i + 1].normal = (n2 + n3 + n4) / 3.0f; Piece->vertices[i + 1].normal = (n2 + n3 + n4) / 3.0f;
n1 = n3; n1 = n3;
n2 = n4; n2 = n4;
v3 = v5; v3 = v5;
} }
if (Vertices[i].normal == glm::vec3()) if (Piece->vertices[i].normal == glm::vec3())
Vertices[i].normal = (n1 + n2) / 2.0f; Piece->vertices[i].normal = (n1 + n2) / 2.0f;
if (i + 1 < iNumVerts) if (i + 1 < iNumVerts)
{ {
if (Vertices[i + 1].normal == glm::vec3()) if (Piece->vertices[i + 1].normal == glm::vec3())
Vertices[i + 1].normal = n2; Piece->vertices[i + 1].normal = n2;
} }
else else
WriteLog("odd number of vertices, normals may be wrong!"); WriteLog("odd number of vertices, normals may be wrong!");
@@ -212,21 +206,21 @@ void TGroundNode::InitNormals()
case GL_TRIANGLES: case GL_TRIANGLES:
for (i = 0; i < iNumVerts; i += 3) for (i = 0; i < iNumVerts; i += 3)
{ {
v1 = Vertices[i + 0].position - Vertices[i + 1].position; v1 = Piece->vertices[i + 0].position - Piece->vertices[i + 1].position;
v2 = Vertices[i + 1].position - Vertices[i + 2].position; v2 = Piece->vertices[i + 1].position - Piece->vertices[i + 2].position;
n1 = glm::normalize(glm::cross(v1, v2)); n1 = glm::normalize(glm::cross(v1, v2));
if (Vertices[i + 0].normal == glm::vec3()) if( Piece->vertices[i + 0].normal == glm::vec3() )
Vertices[i + 0].normal = (n1); Piece->vertices[i + 0].normal = (n1);
if (Vertices[i + 1].normal == glm::vec3()) if( Piece->vertices[i + 1].normal == glm::vec3() )
Vertices[i + 1].normal = (n1); Piece->vertices[i + 1].normal = (n1);
if (Vertices[i + 2].normal == glm::vec3()) if( Piece->vertices[i + 2].normal == glm::vec3() )
Vertices[i + 2].normal = (n1); Piece->vertices[i + 2].normal = (n1);
t1 = glm::vec2( t1 = glm::vec2(
std::floor( Vertices[ i + 0 ].texture.s ), std::floor( Piece->vertices[ i + 0 ].texture.s ),
std::floor( Vertices[ i + 0 ].texture.t ) ); std::floor( Piece->vertices[ i + 0 ].texture.t ) );
Vertices[ i + 1 ].texture -= t1; Piece->vertices[ i + 1 ].texture -= t1;
Vertices[ i + 2 ].texture -= t1; Piece->vertices[ i + 2 ].texture -= t1;
Vertices[ i + 0 ].texture -= t1; Piece->vertices[ i + 0 ].texture -= t1;
} }
break; break;
} }
@@ -349,8 +343,10 @@ void TSubRect::NodeAdd(TGroundNode *Node)
} }
#endif #endif
case TP_TRACTIONPOWERSOURCE: // a te w ogóle pomijamy case TP_TRACTIONPOWERSOURCE: // a te w ogóle pomijamy
/*
// case TP_ISOLATED: //lista torów w obwodzie izolowanym - na razie ignorowana // case TP_ISOLATED: //lista torów w obwodzie izolowanym - na razie ignorowana
break; break;
*/
case TP_DYNAMIC: case TP_DYNAMIC:
return; // tych nie dopisujemy wcale return; // tych nie dopisujemy wcale
} }
@@ -380,22 +376,14 @@ void TSubRect::Sort() {
TTrack * TSubRect::FindTrack(vector3 *Point, int &iConnection, TTrack *Exclude) TTrack * TSubRect::FindTrack(vector3 *Point, int &iConnection, TTrack *Exclude)
{ // szukanie toru, którego koniec jest najbliższy (*Point) { // szukanie toru, którego koniec jest najbliższy (*Point)
for (int i = 0; i < iTracks; ++i) for( int i = 0; i < iTracks; ++i ) {
if (tTracks[i] != Exclude) // można użyć tabelę torów, bo jest mniejsza if( tTracks[ i ] != Exclude ) // można użyć tabelę torów, bo jest mniejsza
{ {
iConnection = tTracks[i]->TestPoint(Point); iConnection = tTracks[ i ]->TestPoint( Point );
if (iConnection >= 0) if( iConnection >= 0 )
return tTracks[i]; // szukanie TGroundNode nie jest potrzebne return tTracks[ i ]; // szukanie TGroundNode nie jest potrzebne
} }
/*
TGroundNode *Current;
for (Current=nRootNode;Current;Current=Current->Next)
if ((Current->iType==TP_TRACK)&&(Current->pTrack!=Exclude)) //można użyć tabelę torów
{
iConnection=Current->pTrack->TestPoint(Point);
if (iConnection>=0) return Current;
} }
*/
return NULL; return NULL;
}; };
@@ -449,30 +437,20 @@ void TSubRect::LoadNodes() {
auto *node { nRootNode }; auto *node { nRootNode };
while( node != nullptr ) { while( node != nullptr ) {
switch (node->iType) { switch (node->iType) {
case GL_TRIANGLES: { case GL_TRIANGLES:
vertex_array vertices;
for( int idx = 0; idx < node->iNumVerts; ++idx ) {
vertices.emplace_back(
node->Vertices[ idx ].position - node->m_rootposition,
node->Vertices[ idx ].normal,
node->Vertices[ idx ].texture );
}
node->m_geometry = GfxRenderer.Insert( vertices, m_geometrybank, GL_TRIANGLES );
SafeDeleteArray( node->Vertices );
node->iNumVerts = 0;
break;
}
case GL_LINES: { case GL_LINES: {
vertex_array vertices; vertex_array vertices;
for( int idx = 0; idx < node->iNumPts; ++idx ) { for( auto const &vertex : node->Piece->vertices ) {
vertices.emplace_back( vertices.emplace_back(
node->Points[ idx ] - node->m_rootposition, vertex.position - node->m_rootposition,
glm::vec3(), vertex.normal,
glm::vec2() ); vertex.texture );
} }
node->m_geometry = GfxRenderer.Insert( vertices, m_geometrybank, GL_LINES ); node->Piece->geometry = GfxRenderer.Insert( vertices, m_geometrybank, node->iType );
SafeDeleteArray( node->Vertices ); node->Piece->vertices.swap( std::vector<TGroundVertex>() ); // hipster shrink_to_fit
node->iNumPts = 0; // TODO: get rid of the vertex counters, they're obsolete at this point
if( node->iType == GL_LINES ) { node->iNumVerts = 0; }
else { node->iNumPts = 0; }
break; break;
} }
case TP_TRACK: case TP_TRACK:
@@ -529,6 +507,59 @@ TGroundRect::Init() {
} }
}; };
// dodanie obiektu do sektora na etapie rozdzielania na sektory
void
TGroundRect::NodeAdd( TGroundNode *Node ) {
// override visibility ranges, to ensure the content is drawn from far enough
Node->fSquareRadius = 50000.0 * 50000.0;
Node->fSquareMinRadius = 0.0;
// if the cell already has a node with matching material settings, we can just add the new geometry to it
if( ( Node->iType == GL_TRIANGLES ) ) {
// cell node only receives opaque geometry, so we can skip transparency test
auto matchingnode { nRenderRect };
while( ( matchingnode != nullptr )
&& ( false == mergeable( *Node, *matchingnode ) ) ) {
// search will get us either a matching node, or a nullptr
matchingnode = matchingnode->nNext3;
}
if( matchingnode != nullptr ) {
// a valid match, so dump the content into it
// updating centre points isn't strictly necessary since render is based off the cell's middle, but, eh
matchingnode->pCenter =
interpolate(
matchingnode->pCenter, Node->pCenter,
static_cast<float>( Node->iNumVerts ) / ( Node->iNumVerts + matchingnode->iNumVerts ) );
matchingnode->iNumVerts += Node->iNumVerts;
matchingnode->Piece->vertices.resize( matchingnode->iNumVerts, TGroundVertex() );
matchingnode->Piece->vertices.insert(
std::end( matchingnode->Piece->vertices ),
std::begin( Node->Piece->vertices ), std::end( Node->Piece->vertices ) );
// clear content of the node we're copying. a minor memory saving at best, but still a saving
Node->Piece->vertices.swap( std::vector<TGroundVertex>() );
Node->iNumVerts = 0;
// since we've put the data in existing node we can skip adding the new one...
return;
// ...for others, they'll go through the regular procedure, along with other non-mergeable types
}
}
return TSubRect::NodeAdd( Node );
}
// compares two provided nodes, returns true if their content can be merged
bool
TGroundRect::mergeable( TGroundNode const &Left, TGroundNode const &Right ) {
// since view ranges and transparency type for all nodes put through this method are guaranteed to be equal,
// we can skip their tests and only do the material check.
// TODO, TBD: material as dedicated type, and refactor this method into a simple equality test
return ( ( Left.TextureID == Right.TextureID )
&& ( Left.Ambient == Right.Ambient )
&& ( Left.Diffuse == Right.Diffuse )
&& ( Left.Specular == Right.Specular ) );
}
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
BYTE TempConnectionType[ 200 ]; // Ra: sprzêgi w sk³adzie; ujemne, gdy odwrotnie BYTE TempConnectionType[ 200 ]; // Ra: sprzêgi w sk³adzie; ujemne, gdy odwrotnie
@@ -594,19 +625,19 @@ void TGround::Free()
nRootDynamic = NULL; nRootDynamic = NULL;
} }
TGroundNode * TGround::DynamicFindAny(std::string asNameToFind) TGroundNode * TGround::DynamicFindAny(std::string const &Name)
{ // wyszukanie pojazdu o podanej nazwie, szukanie po wszystkich (użyć drzewa!) { // wyszukanie pojazdu o podanej nazwie, szukanie po wszystkich (użyć drzewa!)
for (TGroundNode *Current = nRootDynamic; Current; Current = Current->nNext) for (TGroundNode *Current = nRootDynamic; Current; Current = Current->nNext)
if ((Current->asName == asNameToFind)) if ((Current->asName == Name))
return Current; return Current;
return NULL; return NULL;
}; };
TGroundNode * TGround::DynamicFind(std::string asNameToFind) TGroundNode * TGround::DynamicFind(std::string const &Name)
{ // wyszukanie pojazdu z obsadą o podanej nazwie (użyć drzewa!) { // wyszukanie pojazdu z obsadą o podanej nazwie (użyć drzewa!)
for (TGroundNode *Current = nRootDynamic; Current; Current = Current->nNext) for (TGroundNode *Current = nRootDynamic; Current; Current = Current->nNext)
if (Current->DynamicObject->Mechanik) if (Current->DynamicObject->Mechanik)
if ((Current->asName == asNameToFind)) if ((Current->asName == Name))
return Current; return Current;
return NULL; return NULL;
}; };
@@ -685,12 +716,12 @@ void TGround::RaTriangleDivider(TGroundNode *node)
double x1 = x0 + 1400.0; double x1 = x0 + 1400.0;
double z0 = 1000.0 * std::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; double z1 = z0 + 1400.0;
if ((node->Vertices[0].position.x >= x0) && (node->Vertices[0].position.x <= x1) && if ((node->Piece->vertices[0].position.x >= x0) && (node->Piece->vertices[0].position.x <= x1) &&
(node->Vertices[0].position.z >= z0) && (node->Vertices[0].position.z <= z1) && (node->Piece->vertices[0].position.z >= z0) && (node->Piece->vertices[0].position.z <= z1) &&
(node->Vertices[1].position.x >= x0) && (node->Vertices[1].position.x <= x1) && (node->Piece->vertices[1].position.x >= x0) && (node->Piece->vertices[1].position.x <= x1) &&
(node->Vertices[1].position.z >= z0) && (node->Vertices[1].position.z <= z1) && (node->Piece->vertices[1].position.z >= z0) && (node->Piece->vertices[1].position.z <= z1) &&
(node->Vertices[2].position.x >= x0) && (node->Vertices[2].position.x <= x1) && (node->Piece->vertices[2].position.x >= x0) && (node->Piece->vertices[2].position.x <= x1) &&
(node->Vertices[2].position.z >= z0) && (node->Vertices[2].position.z <= z1)) (node->Piece->vertices[2].position.z >= z0) && (node->Piece->vertices[2].position.z <= z1))
return; // trójkąt wystający mniej niż 200m z kw. kilometrowego jest do przyjęcia return; // trójkąt wystający mniej niż 200m z kw. kilometrowego jest do przyjęcia
// Ra: przerobić na dzielenie na 2 trójkąty, podział w przecięciu z siatką kilometrową // Ra: przerobić na dzielenie na 2 trójkąty, podział w przecięciu z siatką kilometrową
// Ra: i z rekurencją będzie dzielić trzy trójkąty, jeśli będzie taka potrzeba // Ra: i z rekurencją będzie dzielić trzy trójkąty, jeśli będzie taka potrzeba
@@ -700,47 +731,46 @@ void TGround::RaTriangleDivider(TGroundNode *node)
x1 -= 200.0; // przestawienie na siatkę x1 -= 200.0; // przestawienie na siatkę
z0 += 200.0; z0 += 200.0;
z1 -= 200.0; z1 -= 200.0;
mul = (node->Vertices[0].position.x - x0) * (node->Vertices[1].position.x - x0); // AB na wschodzie mul = (node->Piece->vertices[0].position.x - x0) * (node->Piece->vertices[1].position.x - x0); // AB na wschodzie
if (mul < min) if (mul < min)
min = mul, divide = 0; min = mul, divide = 0;
mul = (node->Vertices[1].position.x - x0) * (node->Vertices[2].position.x - x0); // BC na wschodzie mul = (node->Piece->vertices[1].position.x - x0) * (node->Piece->vertices[2].position.x - x0); // BC na wschodzie
if (mul < min) if (mul < min)
min = mul, divide = 1; min = mul, divide = 1;
mul = (node->Vertices[2].position.x - x0) * (node->Vertices[0].position.x - x0); // CA na wschodzie mul = (node->Piece->vertices[2].position.x - x0) * (node->Piece->vertices[0].position.x - x0); // CA na wschodzie
if (mul < min) if (mul < min)
min = mul, divide = 2; min = mul, divide = 2;
mul = (node->Vertices[0].position.x - x1) * (node->Vertices[1].position.x - x1); // AB na zachodzie mul = (node->Piece->vertices[0].position.x - x1) * (node->Piece->vertices[1].position.x - x1); // AB na zachodzie
if (mul < min) if (mul < min)
min = mul, divide = 8; min = mul, divide = 8;
mul = (node->Vertices[1].position.x - x1) * (node->Vertices[2].position.x - x1); // BC na zachodzie mul = (node->Piece->vertices[1].position.x - x1) * (node->Piece->vertices[2].position.x - x1); // BC na zachodzie
if (mul < min) if (mul < min)
min = mul, divide = 9; min = mul, divide = 9;
mul = (node->Vertices[2].position.x - x1) * (node->Vertices[0].position.x - x1); // CA na zachodzie mul = (node->Piece->vertices[2].position.x - x1) * (node->Piece->vertices[0].position.x - x1); // CA na zachodzie
if (mul < min) if (mul < min)
min = mul, divide = 10; min = mul, divide = 10;
mul = (node->Vertices[0].position.z - z0) * (node->Vertices[1].position.z - z0); // AB na południu mul = (node->Piece->vertices[0].position.z - z0) * (node->Piece->vertices[1].position.z - z0); // AB na południu
if (mul < min) if (mul < min)
min = mul, divide = 4; min = mul, divide = 4;
mul = (node->Vertices[1].position.z - z0) * (node->Vertices[2].position.z - z0); // BC na południu mul = (node->Piece->vertices[1].position.z - z0) * (node->Piece->vertices[2].position.z - z0); // BC na południu
if (mul < min) if (mul < min)
min = mul, divide = 5; min = mul, divide = 5;
mul = (node->Vertices[2].position.z - z0) * (node->Vertices[0].position.z - z0); // CA na południu mul = (node->Piece->vertices[2].position.z - z0) * (node->Piece->vertices[0].position.z - z0); // CA na południu
if (mul < min) if (mul < min)
min = mul, divide = 6; min = mul, divide = 6;
mul = (node->Vertices[0].position.z - z1) * (node->Vertices[1].position.z - z1); // AB na północy mul = (node->Piece->vertices[0].position.z - z1) * (node->Piece->vertices[1].position.z - z1); // AB na północy
if (mul < min) if (mul < min)
min = mul, divide = 12; min = mul, divide = 12;
mul = (node->Vertices[1].position.z - z1) * (node->Vertices[2].position.z - z1); // BC na północy mul = (node->Piece->vertices[1].position.z - z1) * (node->Piece->vertices[2].position.z - z1); // BC na północy
if (mul < min) if (mul < min)
min = mul, divide = 13; min = mul, divide = 13;
mul = (node->Vertices[2].position.z - z1) * (node->Vertices[0].position.z - z1); // CA na północy mul = (node->Piece->vertices[2].position.z - z1) * (node->Piece->vertices[0].position.z - z1); // CA na północy
if (mul < min) if (mul < min)
divide = 14; divide = 14;
// tworzymy jeden dodatkowy trójkąt, dzieląc jeden bok na przecięciu siatki kilometrowej // tworzymy jeden dodatkowy trójkąt, dzieląc jeden bok na przecięciu siatki kilometrowej
TGroundNode *ntri; // wskaźnik na nowy trójkąt TGroundNode *ntri; // wskaźnik na nowy trójkąt
ntri = new TGroundNode(); // a ten jest nowy ntri = new TGroundNode(GL_TRIANGLES); // a ten jest nowy
ntri->iType = GL_TRIANGLES; // kopiowanie parametrów, przydałby się konstruktor kopiujący // kopiowanie parametrów, przydałby się konstruktor kopiujący
ntri->Init(3);
ntri->TextureID = node->TextureID; ntri->TextureID = node->TextureID;
ntri->iFlags = node->iFlags; ntri->iFlags = node->iFlags;
ntri->Ambient = node->Ambient; ntri->Ambient = node->Ambient;
@@ -753,42 +783,44 @@ void TGround::RaTriangleDivider(TGroundNode *node)
ntri->nNext = nRootOfType[GL_TRIANGLES]; ntri->nNext = nRootOfType[GL_TRIANGLES];
nRootOfType[GL_TRIANGLES] = ntri; // dopisanie z przodu do listy nRootOfType[GL_TRIANGLES] = ntri; // dopisanie z przodu do listy
++iNumNodes; ++iNumNodes;
ntri->iNumVerts = 3;
ntri->Piece->vertices.resize( 3 );
switch (divide & 3) switch (divide & 3)
{ // podzielenie jednego z boków, powstaje wierzchołek D { // podzielenie jednego z boków, powstaje wierzchołek D
case 0: // podział AB (0-1) -> ADC i DBC case 0: // podział AB (0-1) -> ADC i DBC
ntri->Vertices[2] = node->Vertices[2]; // wierzchołek C jest wspólny ntri->Piece->vertices[2] = node->Piece->vertices[2]; // wierzchołek C jest wspólny
ntri->Vertices[1] = node->Vertices[1]; // wierzchołek B przechodzi do nowego ntri->Piece->vertices[1] = node->Piece->vertices[1]; // wierzchołek B przechodzi do nowego
// node->Vertices[1].HalfSet(node->Vertices[0],node->Vertices[1]); //na razie D tak // node->Vertices[1].HalfSet(node->Vertices[0],node->Vertices[1]); //na razie D tak
if (divide & 4) if (divide & 4)
node->Vertices[1].SetByZ(node->Vertices[0], node->Vertices[1], (divide & 8) ? z1 : z0); node->Piece->vertices[1].SetByZ(node->Piece->vertices[0], node->Piece->vertices[1], (divide & 8) ? z1 : z0);
else else
node->Vertices[1].SetByX(node->Vertices[0], node->Vertices[1], (divide & 8) ? x1 : x0); node->Piece->vertices[1].SetByX(node->Piece->vertices[0], node->Piece->vertices[1], (divide & 8) ? x1 : x0);
ntri->Vertices[0] = node->Vertices[1]; // wierzchołek D jest wspólny ntri->Piece->vertices[0] = node->Piece->vertices[1]; // wierzchołek D jest wspólny
break; break;
case 1: // podział BC (1-2) -> ABD i ADC case 1: // podział BC (1-2) -> ABD i ADC
ntri->Vertices[0] = node->Vertices[0]; // wierzchołek A jest wspólny ntri->Piece->vertices[0] = node->Piece->vertices[0]; // wierzchołek A jest wspólny
ntri->Vertices[2] = node->Vertices[2]; // wierzchołek C przechodzi do nowego ntri->Piece->vertices[2] = node->Piece->vertices[2]; // wierzchołek C przechodzi do nowego
// node->Vertices[2].HalfSet(node->Vertices[1],node->Vertices[2]); //na razie D tak // node->Vertices[2].HalfSet(node->Vertices[1],node->Vertices[2]); //na razie D tak
if (divide & 4) if (divide & 4)
node->Vertices[2].SetByZ(node->Vertices[1], node->Vertices[2], (divide & 8) ? z1 : z0); node->Piece->vertices[2].SetByZ(node->Piece->vertices[1], node->Piece->vertices[2], (divide & 8) ? z1 : z0);
else else
node->Vertices[2].SetByX(node->Vertices[1], node->Vertices[2], (divide & 8) ? x1 : x0); node->Piece->vertices[2].SetByX(node->Piece->vertices[1], node->Piece->vertices[2], (divide & 8) ? x1 : x0);
ntri->Vertices[1] = node->Vertices[2]; // wierzchołek D jest wspólny ntri->Piece->vertices[1] = node->Piece->vertices[2]; // wierzchołek D jest wspólny
break; break;
case 2: // podział CA (2-0) -> ABD i DBC case 2: // podział CA (2-0) -> ABD i DBC
ntri->Vertices[1] = node->Vertices[1]; // wierzchołek B jest wspólny ntri->Piece->vertices[1] = node->Piece->vertices[1]; // wierzchołek B jest wspólny
ntri->Vertices[2] = node->Vertices[2]; // wierzchołek C przechodzi do nowego ntri->Piece->vertices[2] = node->Piece->vertices[2]; // wierzchołek C przechodzi do nowego
// node->Vertices[2].HalfSet(node->Vertices[2],node->Vertices[0]); //na razie D tak // node->Vertices[2].HalfSet(node->Vertices[2],node->Vertices[0]); //na razie D tak
if (divide & 4) if (divide & 4)
node->Vertices[2].SetByZ(node->Vertices[2], node->Vertices[0], (divide & 8) ? z1 : z0); node->Piece->vertices[2].SetByZ(node->Piece->vertices[2], node->Piece->vertices[0], (divide & 8) ? z1 : z0);
else else
node->Vertices[2].SetByX(node->Vertices[2], node->Vertices[0], (divide & 8) ? x1 : x0); node->Piece->vertices[2].SetByX(node->Piece->vertices[2], node->Piece->vertices[0], (divide & 8) ? x1 : x0);
ntri->Vertices[0] = node->Vertices[2]; // wierzchołek D jest wspólny ntri->Piece->vertices[0] = node->Piece->vertices[2]; // wierzchołek D jest wspólny
break; break;
} }
// przeliczenie środków ciężkości obu // przeliczenie środków ciężkości obu
node->pCenter = ( node->Vertices[ 0 ].position + node->Vertices[ 1 ].position + node->Vertices[ 2 ].position ) / 3.0; node->pCenter = ( node->Piece->vertices[ 0 ].position + node->Piece->vertices[ 1 ].position + node->Piece->vertices[ 2 ].position ) / 3.0;
ntri->pCenter = ( ntri->Vertices[ 0 ].position + ntri->Vertices[ 1 ].position + ntri->Vertices[ 2 ].position ) / 3.0; ntri->pCenter = ( ntri->Piece->vertices[ 0 ].position + ntri->Piece->vertices[ 1 ].position + ntri->Piece->vertices[ 2 ].position ) / 3.0;
RaTriangleDivider(node); // rekurencja, bo nawet na TD raz nie wystarczy RaTriangleDivider(node); // rekurencja, bo nawet na TD raz nie wystarczy
RaTriangleDivider(ntri); RaTriangleDivider(ntri);
}; };
@@ -1218,7 +1250,6 @@ TGroundNode * TGround::AddGroundNode(cParser *parser)
tmp->nNode[i].iFlags = 0x10; // nieprzezroczyste; nie usuwany tmp->nNode[i].iFlags = 0x10; // nieprzezroczyste; nie usuwany
tmp->nNode[i].bVisible = true; tmp->nNode[i].bVisible = true;
tmp->nNode[i].pCenter = tmp->pCenter; // nie przesuwamy w inne miejsce tmp->nNode[i].pCenter = tmp->pCenter; // nie przesuwamy w inne miejsce
// tmp->nNode[i].asName=
} }
} }
else if (!tmp->asName.empty()) // jest pusta gdy "none" else if (!tmp->asName.empty()) // jest pusta gdy "none"
@@ -1291,18 +1322,6 @@ TGroundNode * TGround::AddGroundNode(cParser *parser)
&& ( true == GfxRenderer.Texture( tmp->TextureID ).has_alpha ) ) ? && ( true == GfxRenderer.Texture( tmp->TextureID ).has_alpha ) ) ?
0x20 : 0x20 :
0x10 ); 0x10 );
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, vertex1, vertex2; TGroundVertex vertex, vertex1, vertex2;
std::size_t vertexcount { 0 }; std::size_t vertexcount { 0 };
@@ -1346,9 +1365,17 @@ TGroundNode * TGround::AddGroundNode(cParser *parser)
if( vertexcount == 0 ) { vertex1 = vertex; } if( vertexcount == 0 ) { vertex1 = vertex; }
else if( vertexcount == 1 ) { vertex2 = vertex; } else if( vertexcount == 1 ) { vertex2 = vertex; }
else if( vertexcount >= 2 ) { else if( vertexcount >= 2 ) {
// swap order every other triangle, to maintain consistent winding
if( vertexcount % 2 == 0 ) {
importedvertices.emplace_back( vertex1 ); importedvertices.emplace_back( vertex1 );
importedvertices.emplace_back( vertex2 ); importedvertices.emplace_back( vertex2 );
}
else {
importedvertices.emplace_back( vertex2 );
importedvertices.emplace_back( vertex1 );
}
importedvertices.emplace_back( vertex ); importedvertices.emplace_back( vertex );
vertex1 = vertex2; vertex1 = vertex2;
vertex2 = vertex; vertex2 = vertex;
} }
@@ -1363,25 +1390,27 @@ TGroundNode * TGround::AddGroundNode(cParser *parser)
} while (token.compare("endtri") != 0); } while (token.compare("endtri") != 0);
tmp->iType = GL_TRIANGLES; tmp->iType = GL_TRIANGLES;
tmp->Piece = new piece_node();
tmp->iNumVerts = importedvertices.size();
auto const nv = importedvertices.size(); if( tmp->iNumVerts > 0 ) {
tmp->Init(nv); // utworzenie tablicy wierzchołków
for( std::size_t i = 0; i < nv; ++i ) { tmp->Piece->vertices.swap( importedvertices );
tmp->pCenter += importedvertices[ i ].position;
for( auto const &vertex : tmp->Piece->vertices ) {
tmp->pCenter += vertex.position;
} }
tmp->pCenter /= (nv > 0 ? nv : 1); tmp->pCenter /= tmp->iNumVerts;
r = 0; r = 0;
for (std::size_t i = 0; i < nv; ++i) for( auto const &vertex : tmp->Piece->vertices ) {
{ tf = SquareMagnitude( vertex.position - tmp->pCenter );
tmp->Vertices[i] = importedvertices[i]; if( tf > r )
tf = SquareMagnitude( tmp->Vertices[ i ].position - tmp->pCenter );
if (tf > r)
r = tf; r = tf;
} }
tmp->fSquareRadius += r; tmp->fSquareRadius += r;
RaTriangleDivider(tmp); // Ra: dzielenie trójkątów jest teraz całkiem wydajne RaTriangleDivider( tmp ); // Ra: dzielenie trójkątów jest teraz całkiem wydajne
}
} // koniec wczytywania trójkątów } // koniec wczytywania trójkątów
break; break;
case GL_LINES: case GL_LINES:
@@ -1394,6 +1423,7 @@ TGroundNode * TGround::AddGroundNode(cParser *parser)
>> tmp->Diffuse.b >> tmp->Diffuse.b
>> tmp->fLineThickness; >> tmp->fLineThickness;
tmp->Diffuse /= 255.0f; tmp->Diffuse /= 255.0f;
tmp->fLineThickness = std::min( 30.0, tmp->fLineThickness ); // 30 pix equals rougly width of a signal pole viewed from ~1m away
TGroundVertex vertex, vertex0, vertex1; TGroundVertex vertex, vertex0, vertex1;
std::size_t vertexcount{ 0 }; std::size_t vertexcount{ 0 };
@@ -1455,15 +1485,25 @@ TGroundNode * TGround::AddGroundNode(cParser *parser)
importedvertices.pop_back(); importedvertices.pop_back();
} }
tmp->iType = GL_LINES; tmp->iType = GL_LINES;
tmp->Piece = new piece_node();
tmp->iNumPts = importedvertices.size();
auto const nv = importedvertices.size(); if( false == importedvertices.empty() ) {
tmp->Points = new glm::dvec3[ nv ];
tmp->iNumPts = nv; tmp->Piece->vertices.swap( importedvertices );
for( std::size_t i = 0; i < nv; ++i ) {
tmp->Points[ i ] = importedvertices[ i ].position; glm::dvec3 minpoint( std::numeric_limits<double>::max(), 0.0, std::numeric_limits<double>::max() );
tmp->pCenter += importedvertices[ i ].position; glm::dvec3 maxpoint( std::numeric_limits<double>::lowest(), 0.0, std::numeric_limits<double>::lowest() );
for( auto const &vertex : tmp->Piece->vertices ) {
tmp->pCenter += vertex.position;
minpoint.x = std::min( minpoint.x, vertex.position.x );
minpoint.z = std::min( minpoint.z, vertex.position.z );
maxpoint.x = std::max( maxpoint.x, vertex.position.x );
maxpoint.z = std::max( maxpoint.z, vertex.position.z );
}
tmp->pCenter /= tmp->iNumPts;
tmp->m_radius = static_cast<float>( glm::distance( maxpoint, minpoint ) * 0.5 );
} }
tmp->pCenter /= ( nv > 0 ? nv : 1 );
break; break;
} }
} }
@@ -1559,11 +1599,6 @@ void TGround::FirstInit()
} }
else { else {
// dodajemy do kwadratu kilometrowego // 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 ); GetRect( Current->pCenter.x, Current->pCenter.z )->NodeAdd( Current );
} }
} }
@@ -1632,7 +1667,7 @@ bool TGround::Init(std::string File)
switch( LastNode->iType ) { switch( LastNode->iType ) {
// validate the new node // validate the new node
case GL_TRIANGLES: { case GL_TRIANGLES: {
if( LastNode->Vertices == nullptr ) { if( true == LastNode->Piece->vertices.empty() ) {
SafeDelete( LastNode ); SafeDelete( LastNode );
} }
break; break;
@@ -1692,7 +1727,7 @@ bool TGround::Init(std::string File)
} }
else else
{ {
Error("Scene parse error near " + token); ErrorLog("Scene parsing error in file \"" + parser.Name() + "\", unexpected token \"" + token + "\"");
// break; // break;
} }
} }
@@ -1722,20 +1757,21 @@ bool TGround::Init(std::string File)
fTrainSetVel, 0, NULL); fTrainSetVel, 0, NULL);
} }
} }
if (LastNode) // ostatni wczytany obiekt if( LastNode ) {
if (LastNode->iType == // ostatni wczytany obiekt
TP_DYNAMIC) // o ile jest pojazdem (na ogół jest, ale kto wie...) if( LastNode->iType == TP_DYNAMIC ) {
if (iTrainSetWehicleNumber ? !TempConnectionType[iTrainSetWehicleNumber - 1] : // o ile jest pojazdem (na ogół jest, ale kto wie...)
false) // jeśli ostatni pojazd ma sprzęg 0 if( ( iTrainSetWehicleNumber > 0 )
LastNode->DynamicObject->RaLightsSet(-1, 2 + 32 + 64); // to założymy mu && ( TempConnectionType[ iTrainSetWehicleNumber - 1 ] == 0 ) ) {
// końcówki blaszane // jeśli ostatni pojazd ma sprzęg 0 to założymy mu końcówki blaszane
// (jak AI się // (jak AI się odpali, to sobie poprawi)
// odpali, to sobie LastNode->DynamicObject->RaLightsSet( -1, 2 + 32 + 64 );
// poprawi) }
}
}
bTrainSet = false; bTrainSet = false;
fTrainSetVel = 0; fTrainSetVel = 0;
// iTrainSetConnection=0; nTrainSetNode = nTrainSetDriver = nullptr;
nTrainSetNode = nTrainSetDriver = NULL;
iTrainSetWehicleNumber = 0; iTrainSetWehicleNumber = 0;
} }
else if (str == "event") else if (str == "event")

View File

@@ -93,15 +93,15 @@ struct TGroundVertex
texture = interpolate( v1.texture, v2.texture, static_cast<float>( factor ) ); texture = interpolate( v1.texture, v2.texture, static_cast<float>( factor ) );
} }
}; };
/*
// ground node holding single, unique piece of 3d geometry. TBD, TODO: unify this with basic 3d model node // ground node holding single, unique piece of 3d geometry. TBD, TODO: unify this with basic 3d model node
struct mesh_node { struct piece_node {
std::vector<TGroundVertex> vertices; std::vector<TGroundVertex> vertices;
geometry_handle geometry; // geometry prepared for drawing geometry_handle geometry { 0,0 }; // geometry prepared for drawing
}; };
*/
class TGroundNode /*: public Resource*/ // obiekt scenerii
{ // obiekt scenerii class TGroundNode {
friend class opengl_renderer; friend class opengl_renderer;
@@ -117,9 +117,8 @@ public:
TSubModel *smTerrain; // modele terenu (kwadratow kilometrowych) TSubModel *smTerrain; // modele terenu (kwadratow kilometrowych)
TAnimModel *Model; // model z animacjami TAnimModel *Model; // model z animacjami
TDynamicObject *DynamicObject; // pojazd TDynamicObject *DynamicObject; // pojazd
glm::dvec3 *Points; // punkty dla linii piece_node *Piece; // non-instanced piece of geometry
TTrack *pTrack; // trajektoria ruchu TTrack *pTrack; // trajektoria ruchu
TGroundVertex *Vertices; // wierzchołki dla trójkątów
TMemCell *MemCell; // komórka pamięci TMemCell *MemCell; // komórka pamięci
TEventLauncher *EvLaunch; // wyzwalacz zdarzeń TEventLauncher *EvLaunch; // wyzwalacz zdarzeń
TTraction *hvTraction; // drut zasilający TTraction *hvTraction; // drut zasilający
@@ -128,6 +127,7 @@ public:
TGroundNode *nNode; // obiekt renderujący grupowo ma tu wskaźnik na listę obiektów TGroundNode *nNode; // obiekt renderujący grupowo ma tu wskaźnik na listę obiektów
}; };
Math3D::vector3 pCenter; // współrzędne środka do przydzielenia sektora Math3D::vector3 pCenter; // współrzędne środka do przydzielenia sektora
float m_radius { 0.0f }; // bounding radius of geometry stored in the node. TODO: reuse bounding_area struct for radius and center
glm::dvec3 m_rootposition; // position of the ground (sub)rectangle holding the node, in the 3d world glm::dvec3 m_rootposition; // position of the ground (sub)rectangle holding the node, in the 3d world
// visualization-related data // visualization-related data
// TODO: wrap these in a struct, when cleaning objects up // TODO: wrap these in a struct, when cleaning objects up
@@ -139,9 +139,6 @@ public:
int iNumPts; // dla linii int iNumPts; // dla linii
int iCount; // dla terenu int iCount; // dla terenu
}; };
// 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 int iFlags; // tryb przezroczystości: 0x10-nieprz.,0x20-przezroczysty,0x30-mieszany
texture_handle TextureID; // główna (jedna) tekstura obiektu texture_handle TextureID; // główna (jedna) tekstura obiektu
glm::vec3 glm::vec3
@@ -152,9 +149,11 @@ public:
bool bVisible; bool bVisible;
TGroundNode(); TGroundNode();
TGroundNode(TGroundNodeType t, int n = 0); TGroundNode(TGroundNodeType t);
~TGroundNode(); ~TGroundNode();
/*
void Init(int n); void Init(int n);
*/
void InitNormals(); void InitNormals();
/* /*
void Release(); void Release();
@@ -200,7 +199,7 @@ class TSubRect : /*public Resource,*/ public CMesh
/* /*
virtual void Release(); // zwalnianie VBO sektora virtual void Release(); // zwalnianie VBO sektora
*/ */
void NodeAdd(TGroundNode *Node); // dodanie obiektu do sektora na etapie rozdzielania na sektory virtual void NodeAdd(TGroundNode *Node); // dodanie obiektu do sektora na etapie rozdzielania na sektory
void Sort(); // optymalizacja obiektów w sektorze (sortowanie wg tekstur) void Sort(); // optymalizacja obiektów w sektorze (sortowanie wg tekstur)
TTrack * FindTrack(vector3 *Point, int &iConnection, TTrack *Exclude); TTrack * FindTrack(vector3 *Point, int &iConnection, TTrack *Exclude);
TTraction * FindTraction(glm::dvec3 const &Point, int &iConnection, TTraction *Exclude); TTraction * FindTraction(glm::dvec3 const &Point, int &iConnection, TTraction *Exclude);
@@ -242,17 +241,19 @@ public:
}; };
// pobranie wskaźnika do małego kwadratu, bez tworzenia jeśli nie ma // pobranie wskaźnika do małego kwadratu, bez tworzenia jeśli nie ma
TSubRect * FastGetSubRect(int iCol, int iRow) { TSubRect * FastGetSubRect(int iCol, int iRow) {
return (pSubRects ? pSubRects + iRow * iNumSubRects + iCol : NULL); return (
}; pSubRects ?
pSubRects + iRow * iNumSubRects + iCol :
nullptr); };
void NodeAdd( TGroundNode *Node ); // dodanie obiektu do sektora na etapie rozdzielania na sektory
// compares two provided nodes, returns true if their content can be merged
bool mergeable( TGroundNode const &Left, TGroundNode const &Right );
// optymalizacja obiektów w sektorach // optymalizacja obiektów w sektorach
void Optimize() { void Optimize() {
if( pSubRects ) { if( pSubRects ) {
for( int i = iNumSubRects * iNumSubRects - 1; i >= 0; --i ) { for( int i = iNumSubRects * iNumSubRects - 1; i >= 0; --i ) {
// optymalizacja obiektów w sektorach // optymalizacja obiektów w sektorach
pSubRects[ i ].Sort(); pSubRects[ i ].Sort(); } } };
}
}
};
static int iFrameNumber; // numer kolejny wyświetlanej klatki static int iFrameNumber; // numer kolejny wyświetlanej klatki
TGroundNode *nTerrain { nullptr }; // model terenu z E3D - użyć nRootMesh? TGroundNode *nTerrain { nullptr }; // model terenu z E3D - użyć nRootMesh?
@@ -308,8 +309,8 @@ class TGround
bool AddToQuery(TEvent *Event, TDynamicObject *Node); bool AddToQuery(TEvent *Event, TDynamicObject *Node);
bool GetTraction(TDynamicObject *model); bool GetTraction(TDynamicObject *model);
bool CheckQuery(); bool CheckQuery();
TGroundNode * DynamicFindAny(std::string asNameToFind); TGroundNode * DynamicFindAny(std::string const &Name);
TGroundNode * DynamicFind(std::string asNameToFind); TGroundNode * DynamicFind(std::string const &Name);
void DynamicList(bool all = false); void DynamicList(bool all = false);
TGroundNode * FindGroundNode(std::string asNameToFind, TGroundNodeType iNodeType); TGroundNode * FindGroundNode(std::string asNameToFind, TGroundNodeType iNodeType);
TGroundRect * GetRect(double x, double z) TGroundRect * GetRect(double x, double z)
@@ -343,7 +344,9 @@ class TGround
public: public:
void WyslijEvent(const std::string &e, const std::string &d); void WyslijEvent(const std::string &e, const std::string &d);
/*
int iRendered; // ilość renderowanych sektorów, pobierana przy pokazywniu FPS int iRendered; // ilość renderowanych sektorów, pobierana przy pokazywniu FPS
*/
void WyslijString(const std::string &t, int n); void WyslijString(const std::string &t, int n);
void WyslijWolny(const std::string &t); void WyslijWolny(const std::string &t);
void WyslijNamiary(TGroundNode *t); void WyslijNamiary(TGroundNode *t);

View File

@@ -78,6 +78,23 @@ void TSubModel::NameSet(std::string const &Name)
pName = Name; pName = Name;
}; };
// sets light level (alpha component of illumination color) to specified value
void
TSubModel::SetLightLevel( float const Level, bool const Includechildren, bool const Includesiblings ) {
f4Emision.a = Level;
if( true == Includesiblings ) {
auto sibling { this };
while( ( sibling = sibling->Next ) != nullptr ) {
sibling->f4Emision.a = Level;
}
}
if( ( true == Includechildren )
&& ( Child != nullptr ) ) {
Child->SetLightLevel( Level, true, true ); // node's children include child's siblings and children
}
}
int TSubModel::SeekFaceNormal(std::vector<unsigned int> const &Masks, int const Startface, unsigned int const Mask, glm::vec3 const &Position, vertex_array const &Vertices) int TSubModel::SeekFaceNormal(std::vector<unsigned int> const &Masks, int const Startface, unsigned int const Mask, glm::vec3 const &Position, vertex_array const &Vertices)
{ // szukanie punktu stycznego do (pt), zwraca numer wierzchołka, a nie trójkąta { // szukanie punktu stycznego do (pt), zwraca numer wierzchołka, a nie trójkąta
int facecount = iNumVerts / 3; // bo maska powierzchni jest jedna na trójkąt int facecount = iNumVerts / 3; // bo maska powierzchni jest jedna na trójkąt
@@ -315,9 +332,9 @@ int TSubModel::Load( cParser &parser, TModel3d *Model, /*int Pos,*/ bool dynamic
} }
else else
{ // jeśli tylko nazwa pliku, to dawać bieżącą ścieżkę do tekstur { // jeśli tylko nazwa pliku, to dawać bieżącą ścieżkę do tekstur
TextureNameSet(texture.c_str()); TextureNameSet(texture);
if( texture.find_first_of( "/\\" ) == texture.npos ) { if( texture.find_first_of( "/\\" ) == texture.npos ) {
texture.insert( 0, Global::asCurrentTexturePath.c_str() ); texture.insert( 0, Global::asCurrentTexturePath );
} }
TextureID = GfxRenderer.GetTextureId( texture, szTexturePath ); TextureID = GfxRenderer.GetTextureId( texture, szTexturePath );
// renderowanie w cyklu przezroczystych tylko jeśli: // renderowanie w cyklu przezroczystych tylko jeśli:
@@ -429,7 +446,7 @@ int TSubModel::Load( cParser &parser, TModel3d *Model, /*int Pos,*/ bool dynamic
--facecount; // o jeden trójkąt mniej --facecount; // o jeden trójkąt mniej
iNumVerts -= 3; // czyli o 3 wierzchołki iNumVerts -= 3; // czyli o 3 wierzchołki
i -= 3; // wczytanie kolejnego w to miejsce i -= 3; // wczytanie kolejnego w to miejsce
WriteLog("Degenerated triangle ignored in: \"" + pName + "\", verticle " + std::to_string(i)); WriteLog("Degenerated triangle ignored in: \"" + pName + "\", vertice " + std::to_string(i));
} }
if (i > 0) { if (i > 0) {
// jeśli pierwszy trójkąt będzie zdegenerowany, to zostanie usunięty i nie ma co sprawdzać // jeśli pierwszy trójkąt będzie zdegenerowany, to zostanie usunięty i nie ma co sprawdzać
@@ -487,6 +504,7 @@ int TSubModel::Load( cParser &parser, TModel3d *Model, /*int Pos,*/ bool dynamic
glm::vec3() ); // przepisanie do wierzchołka trójkąta glm::vec3() ); // przepisanie do wierzchołka trójkąta
} }
} }
Vertices.resize( iNumVerts ); // in case we had some degenerate triangles along the way
/* /*
delete[] wsp; delete[] wsp;
delete[] n; delete[] n;
@@ -534,6 +552,7 @@ int TSubModel::Load( cParser &parser, TModel3d *Model, /*int Pos,*/ bool dynamic
else if( eType == TP_FREESPOTLIGHT ) { else if( eType == TP_FREESPOTLIGHT ) {
// single light points only have single data point, duh // single light points only have single data point, duh
Vertices.emplace_back(); Vertices.emplace_back();
iNumVerts = 1;
} }
// Visible=true; //się potem wyłączy w razie potrzeby // Visible=true; //się potem wyłączy w razie potrzeby
// iFlags|=0x0200; //wczytano z pliku tekstowego (jest właścicielem tablic) // iFlags|=0x0200; //wczytano z pliku tekstowego (jest właścicielem tablic)
@@ -711,10 +730,6 @@ void TSubModel::InitialRotate(bool doit)
{ // jeśli jest jednostkowy transform, to przeliczamy { // jeśli jest jednostkowy transform, to przeliczamy
// wierzchołki, a mnożenie podajemy dalej // wierzchołki, a mnożenie podajemy dalej
float swapcopy; float swapcopy;
// if( false == Vertices.empty() ) {
/*
for( auto &vertex : Vertices ) {
*/
for( auto &vertex : Vertices ) { for( auto &vertex : Vertices ) {
vertex.position.x = -vertex.position.x; // zmiana znaku X vertex.position.x = -vertex.position.x; // zmiana znaku X
swapcopy = vertex.position.y; // zamiana Y i Z swapcopy = vertex.position.y; // zamiana Y i Z
@@ -729,7 +744,6 @@ void TSubModel::InitialRotate(bool doit)
vertex.normal.z = swapcopy; vertex.normal.z = swapcopy;
} }
} }
// }
if (Child) if (Child)
Child->InitialRotate(doit); // potomne ewentualnie obrócimy Child->InitialRotate(doit); // potomne ewentualnie obrócimy
} }

View File

@@ -56,6 +56,7 @@ class TSubModel
friend class opengl_renderer; friend class opengl_renderer;
friend class TModel3d; // temporary workaround. TODO: clean up class content/hierarchy friend class TModel3d; // temporary workaround. TODO: clean up class content/hierarchy
friend class TDynamicObject; // temporary etc
private: private:
int iNext{ NULL }; int iNext{ NULL };
@@ -85,47 +86,41 @@ private:
float4x4 *fMatrix = nullptr; // pojedyncza precyzja wystarcza float4x4 *fMatrix = nullptr; // pojedyncza precyzja wystarcza
int iMatrix; // w pliku binarnym jest numer matrycy int iMatrix; // w pliku binarnym jest numer matrycy
}; };
int iNumVerts{ -1 }; // ilość wierzchołków (1 dla FreeSpotLight) int iNumVerts { -1 }; // ilość wierzchołków (1 dla FreeSpotLight)
int tVboPtr; // początek na liście wierzchołków albo indeksów int tVboPtr; // początek na liście wierzchołków albo indeksów
int iTexture{ 0 }; // numer nazwy tekstury, -1 wymienna, 0 brak int iTexture { 0 }; // numer nazwy tekstury, -1 wymienna, 0 brak
float fVisible{ 0.0f }; // próg jasności światła do załączenia submodelu float fVisible { 0.0f }; // próg jasności światła do załączenia submodelu
float fLight{ -1.0f }; // próg jasności światła do zadziałania selfillum float fLight { -1.0f }; // próg jasności światła do zadziałania selfillum
glm::vec4 glm::vec4
f4Ambient{ 1.0f,1.0f,1.0f,1.0f }, f4Ambient { 1.0f,1.0f,1.0f,1.0f },
f4Diffuse{ 1.0f,1.0f,1.0f,1.0f }, f4Diffuse { 1.0f,1.0f,1.0f,1.0f },
f4Specular{ 0.0f,0.0f,0.0f,1.0f }, f4Specular { 0.0f,0.0f,0.0f,1.0f },
f4Emision{ 1.0f,1.0f,1.0f,1.0f }; f4Emision { 1.0f,1.0f,1.0f,1.0f };
float fWireSize{ 0.0f }; // nie używane, ale wczytywane float fWireSize { 0.0f }; // nie używane, ale wczytywane
float fSquareMaxDist{ 10000.0f * 10000.0f }; float fSquareMaxDist { 10000.0f * 10000.0f };
float fSquareMinDist{ 0.0f }; float fSquareMinDist { 0.0f };
// McZapkie-050702: parametry dla swiatla: // McZapkie-050702: parametry dla swiatla:
float fNearAttenStart{ 40.0f }; float fNearAttenStart { 40.0f };
float fNearAttenEnd{ 80.0f }; float fNearAttenEnd { 80.0f };
bool bUseNearAtten{ false }; // te 3 zmienne okreslaja rysowanie aureoli wokol zrodla swiatla bool bUseNearAtten { false }; // te 3 zmienne okreslaja rysowanie aureoli wokol zrodla swiatla
int iFarAttenDecay{ 0 }; // ta zmienna okresla typ zaniku natezenia swiatla (0:brak, 1,2: potega 1/R) int iFarAttenDecay { 0 }; // ta zmienna okresla typ zaniku natezenia swiatla (0:brak, 1,2: potega 1/R)
float fFarDecayRadius{ 100.0f }; // normalizacja j.w. float fFarDecayRadius { 100.0f }; // normalizacja j.w.
float fCosFalloffAngle{ 0.5f }; // cosinus kąta stożka pod którym widać światło float fCosFalloffAngle { 0.5f }; // cosinus kąta stożka pod którym widać światło
float fCosHotspotAngle{ 0.3f }; // cosinus kąta stożka pod którym widać aureolę i zwiększone natężenie światła float fCosHotspotAngle { 0.3f }; // cosinus kąta stożka pod którym widać aureolę i zwiększone natężenie światła
float fCosViewAngle{ 0.0f }; // cos kata pod jakim sie teraz patrzy float fCosViewAngle { 0.0f }; // cos kata pod jakim sie teraz patrzy
TSubModel *Next{ nullptr }; TSubModel *Next { nullptr };
TSubModel *Child{ nullptr }; TSubModel *Child { nullptr };
/* geometry_handle m_geometry { NULL, NULL }; // geometry of the submodel
intptr_t iVboPtr; texture_handle TextureID { NULL }; // numer tekstury, -1 wymienna, 0 brak
*/ bool bWire { false }; // nie używane, ale wczytywane
geometry_handle m_geometry{ NULL, NULL }; // geometry of the submodel float Opacity { 1.0f };
texture_handle TextureID{ NULL }; // numer tekstury, -1 wymienna, 0 brak float f_Angle { 0.0f };
bool bWire{ false }; // nie używane, ale wczytywane float3 v_RotateAxis { 0.0f, 0.0f, 0.0f };
/*
GLuint uiDisplayList; // roboczy numer listy wyświetlania
*/
float Opacity{ 1.0f };
float f_Angle{ 0.0f };
float3 v_RotateAxis{ 0.0f, 0.0f, 0.0f };
float3 v_Angles { 0.0f, 0.0f, 0.0f }; float3 v_Angles { 0.0f, 0.0f, 0.0f };
public: // chwilowo public: // chwilowo
float3 v_TransVector{ 0.0f, 0.0f, 0.0f }; float3 v_TransVector { 0.0f, 0.0f, 0.0f };
/* /*
basic_vertex *Vertices; // roboczy wskaźnik - wczytanie T3D do VBO basic_vertex *Vertices; // roboczy wskaźnik - wczytanie T3D do VBO
*/ */
@@ -192,18 +187,14 @@ public:
int Flags() { return iFlags; }; int Flags() { return iFlags; };
void UnFlagNext() { iFlags &= 0x00FFFFFF; }; void UnFlagNext() { iFlags &= 0x00FFFFFF; };
void ColorsSet( glm::vec3 const &Ambient, glm::vec3 const &Diffuse, glm::vec3 const &Specular ); void ColorsSet( glm::vec3 const &Ambient, glm::vec3 const &Diffuse, glm::vec3 const &Specular );
inline float3 Translation1Get() // sets light level (alpha component of illumination color) to specified value
{ void SetLightLevel( float const Level, bool const Includechildren = false, bool const Includesiblings = false );
return fMatrix ? *(fMatrix->TranslationGet()) + v_TransVector : v_TransVector; inline float3 Translation1Get() {
} return fMatrix ? *(fMatrix->TranslationGet()) + v_TransVector : v_TransVector; }
inline float3 Translation2Get() inline float3 Translation2Get() {
{ return *(fMatrix->TranslationGet()) + Child->Translation1Get(); }
return *(fMatrix->TranslationGet()) + Child->Translation1Get(); int GetTextureId() {
} return TextureID; }
int GetTextureId()
{
return TextureID;
}
void ParentMatrix(float4x4 *m); void ParentMatrix(float4x4 *m);
float MaxY( float4x4 const &m ); float MaxY( float4x4 const &m );
void AdjustDist(); void AdjustDist();

View File

@@ -457,7 +457,7 @@ void TPythonScreens::init(cParser &parser, TModel3d *model, std::string const &n
WriteLog( "Python Screen: submodel " + subModelName + " not found - Ignoring screen" ); WriteLog( "Python Screen: submodel " + subModelName + " not found - Ignoring screen" );
return; // nie ma takiego sub modelu w danej kabinie pomijamy return; // nie ma takiego sub modelu w danej kabinie pomijamy
} }
int textureId = GfxRenderer.Texture(subModel->GetTextureId()).id; auto textureId = subModel->GetTextureId();
if (textureId <= 0) if (textureId <= 0)
{ {
WriteLog( "Python Screen: invalid texture id " + std::to_string(textureId) + " - Ignoring screen" ); WriteLog( "Python Screen: invalid texture id " + std::to_string(textureId) + " - Ignoring screen" );

View File

@@ -817,8 +817,8 @@ texture_manager::bind( texture_handle const Texture ) {
::glBindTexture( GL_TEXTURE_2D, texture(Texture).id ); ::glBindTexture( GL_TEXTURE_2D, texture(Texture).id );
m_activetexture = texture(Texture).id; m_activetexture = texture(Texture).id;
#else #else
if( Texture( Id ).bind() == resource_state::good ) { if( texture( Texture ).bind() == resource_state::good ) {
m_activetexture = Id; m_activetexture = Texture;
} }
else { else {
// TODO: bind a special 'error' texture on failure // TODO: bind a special 'error' texture on failure
@@ -876,7 +876,7 @@ texture_manager::info() const {
+ std::to_string( readytexturecount ) + std::to_string( readytexturecount )
+ " (" + " ("
+ to_string( readytexturesize / 1024.0f, 2 ) + " mb)" + to_string( readytexturesize / 1024.0f, 2 ) + " mb)"
+ " in vram, "; + " in vram, "
#endif #endif
+ std::to_string( totaltexturecount ) + std::to_string( totaltexturecount )
+ " (" + " ("

View File

@@ -29,8 +29,18 @@ struct opengl_texture {
// methods // methods
void load(); void load();
resource_state bind(); resource_state
resource_state create(); bind();
resource_state
create();
inline
int
width() const {
return data_width; }
inline
int
height() const {
return data_height; }
// members // members
GLuint id{ (GLuint)-1 }; // associated GL resource GLuint id{ (GLuint)-1 }; // associated GL resource
bool has_alpha{ false }; // indicates the texture has alpha channel bool has_alpha{ false }; // indicates the texture has alpha channel

View File

@@ -2156,7 +2156,6 @@ TTrack * TTrack::RaAnimate()
if (SwitchExtension->RightSwitch) if (SwitchExtension->RightSwitch)
{ // nowa wersja z SPKS, ale odwrotnie lewa/prawa { // nowa wersja z SPKS, ale odwrotnie lewa/prawa
vertex_array vertices;
if( TextureID1 ) { if( TextureID1 ) {
// left blade // left blade
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, origin, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, SwitchExtension->fOffset2 ); SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, origin, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, SwitchExtension->fOffset2 );
@@ -2171,7 +2170,6 @@ TTrack * TTrack::RaAnimate()
} }
} }
else { // lewa działa lepiej niż prawa else { // lewa działa lepiej niż prawa
vertex_array vertices;
if( TextureID1 ) { if( TextureID1 ) {
// right blade // right blade
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, origin, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -SwitchExtension->fOffset2 ); SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, origin, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -SwitchExtension->fOffset2 );

View File

@@ -5889,9 +5889,8 @@ bool TTrain::Update( double const Deltatime )
} }
case 2: { case 2: {
//światło wewnętrzne zapalone (255 216 176) //światło wewnętrzne zapalone (255 216 176)
if( mvOccupied->ConverterFlag == if( mvOccupied->ConverterFlag == true ) {
true ) // jasnosc dla zalaczonej przetwornicy // jasnosc dla zalaczonej przetwornicy
{
DynamicObject->InteriorLightLevel = 1.0f; DynamicObject->InteriorLightLevel = 1.0f;
} }
else { else {
@@ -6441,6 +6440,10 @@ bool TTrain::InitializeCab(int NewCabNo, std::string const &asFileName)
{ {
DynamicObject->mdKabina->Init(); // obrócenie modelu oraz optymalizacja, również zapisanie binarnego DynamicObject->mdKabina->Init(); // obrócenie modelu oraz optymalizacja, również zapisanie binarnego
set_cab_controls(); set_cab_controls();
// HACK: for some reason simulation at the start is slow until a sound is played
// until we do a proper fix, try to play a 'silent' sound when cab is entered
// TBD: it could be instead a legit sound of door closing
play_sound( dsbSwitch, DSBVOLUME_MIN );
return true; return true;
} }
return (token == "none"); return (token == "none");

View File

@@ -55,7 +55,7 @@ geometry_bank::create( vertex_array &Vertices, unsigned int const Type ) {
m_chunks.emplace_back( Vertices, Type ); m_chunks.emplace_back( Vertices, Type );
// NOTE: handle is effectively (index into chunk array + 1) this leaves value of 0 to serve as error/empty handle indication // NOTE: handle is effectively (index into chunk array + 1) this leaves value of 0 to serve as error/empty handle indication
geometry_handle chunkhandle { 0, static_cast<std::uint32_t>(m_chunks.size()) }; geometry_handle chunkhandle { 0, static_cast<std::uint32_t>(m_chunks.size()) };
// template method // template method implementation
create_( chunkhandle ); create_( chunkhandle );
// all done // all done
return chunkhandle; return chunkhandle;
@@ -81,7 +81,7 @@ geometry_bank::replace( vertex_array &Vertices, geometry_handle const &Geometry,
chunk.vertices.resize( Offset + Vertices.size(), basic_vertex() ); chunk.vertices.resize( Offset + Vertices.size(), basic_vertex() );
chunk.vertices.insert( std::end( chunk.vertices ), std::begin( Vertices ), std::end( Vertices ) ); chunk.vertices.insert( std::end( chunk.vertices ), std::begin( Vertices ), std::end( Vertices ) );
} }
// template method // template method implementation
replace_( Geometry ); replace_( Geometry );
// all done // all done
return true; return true;
@@ -99,10 +99,17 @@ geometry_bank::append( vertex_array &Vertices, geometry_handle const &Geometry )
// draws geometry stored in specified chunk // draws geometry stored in specified chunk
void void
geometry_bank::draw( geometry_handle const &Geometry, unsigned int const Streams ) { geometry_bank::draw( geometry_handle const &Geometry, unsigned int const Streams ) {
// template method // template method implementation
draw_( Geometry, Streams ); draw_( Geometry, Streams );
} }
// frees subclass-specific resources associated with the bank, typically called when the bank wasn't in use for a period of time
void
geometry_bank::release() {
// template method implementation
release_();
}
vertex_array const & vertex_array const &
geometry_bank::vertices( geometry_handle const &Geometry ) const { geometry_bank::vertices( geometry_handle const &Geometry ) const {
@@ -209,6 +216,13 @@ opengl_vbogeometrybank::draw_( geometry_handle const &Geometry, unsigned int con
*/ */
} }
// release () subclass details
void
opengl_vbogeometrybank::release_() {
delete_buffer();
}
void void
opengl_vbogeometrybank::bind_buffer() { opengl_vbogeometrybank::bind_buffer() {
@@ -225,6 +239,7 @@ opengl_vbogeometrybank::delete_buffer() {
::glDeleteBuffers( 1, &m_buffer ); ::glDeleteBuffers( 1, &m_buffer );
if( m_activebuffer == m_buffer ) { if( m_activebuffer == m_buffer ) {
m_activebuffer = NULL; m_activebuffer = NULL;
bind_streams( stream::none );
} }
m_buffer = NULL; m_buffer = NULL;
m_buffercapacity = 0; m_buffercapacity = 0;
@@ -314,6 +329,19 @@ opengl_dlgeometrybank::draw_( geometry_handle const &Geometry, unsigned int cons
::glCallList( chunkrecord.list ); ::glCallList( chunkrecord.list );
} }
// release () subclass details
void
opengl_dlgeometrybank::release_() {
for( auto &chunkrecord : m_chunkrecords ) {
if( chunkrecord.list != 0 ) {
::glDeleteLists( chunkrecord.list, 1 );
chunkrecord.list = 0;
}
chunkrecord.streams = stream::none;
}
}
void void
opengl_dlgeometrybank::delete_list( geometry_handle const &Geometry ) { opengl_dlgeometrybank::delete_list( geometry_handle const &Geometry ) {
// NOTE: given it's our own internal method we trust it to be called with valid parameters // NOTE: given it's our own internal method we trust it to be called with valid parameters
@@ -327,12 +355,37 @@ opengl_dlgeometrybank::delete_list( geometry_handle const &Geometry ) {
// geometry bank manager, holds collection of geometry banks // geometry bank manager, holds collection of geometry banks
// performs a resource sweep
void
geometrybank_manager::update() {
m_resourcetimestamp = std::chrono::steady_clock::now();
// garbage collection sweep is limited to a number of records per call, to reduce impact on framerate
auto const sweeplastindex =
std::min(
m_resourcesweepindex + geometrybank_manager::unusedresourcesweepsize,
m_geometrybanks.size() );
auto const blanktimestamp { std::chrono::steady_clock::time_point() };
for( auto bankindex = m_resourcesweepindex; bankindex < sweeplastindex; ++bankindex ) {
if( ( m_geometrybanks[ bankindex ].second != blanktimestamp )
&& ( m_resourcetimestamp - m_geometrybanks[ bankindex ].second > geometrybank_manager::unusedresourcetimetolive ) ) {
m_geometrybanks[ bankindex ].first->release();
m_geometrybanks[ bankindex ].second = blanktimestamp;
}
}
m_resourcesweepindex = (
m_resourcesweepindex + geometrybank_manager::unusedresourcesweepsize >= m_geometrybanks.size() ?
0 : // if the next sweep chunk is beyond actual data, so start anew
m_resourcesweepindex + geometrybank_manager::unusedresourcesweepsize );
}
// creates a new geometry bank. returns: handle to the bank or NULL // creates a new geometry bank. returns: handle to the bank or NULL
geometrybank_handle geometrybank_handle
geometrybank_manager::create_bank() { geometrybank_manager::create_bank() {
if( true == Global::bUseVBO ) { m_geometrybanks.emplace_back( std::make_shared<opengl_vbogeometrybank>() ); } if( true == Global::bUseVBO ) { m_geometrybanks.emplace_back( std::make_shared<opengl_vbogeometrybank>(), std::chrono::steady_clock::time_point() ); }
else { m_geometrybanks.emplace_back( std::make_shared<opengl_dlgeometrybank>() ); } else { m_geometrybanks.emplace_back( std::make_shared<opengl_dlgeometrybank>(), std::chrono::steady_clock::time_point() ); }
// NOTE: handle is effectively (index into chunk array + 1) this leaves value of 0 to serve as error/empty handle indication // NOTE: handle is effectively (index into chunk array + 1) this leaves value of 0 to serve as error/empty handle indication
return geometrybank_handle( m_geometrybanks.size(), 0 ); return geometrybank_handle( m_geometrybanks.size(), 0 );
} }
@@ -341,7 +394,7 @@ geometrybank_manager::create_bank() {
geometry_handle geometry_handle
geometrybank_manager::create_chunk( vertex_array &Vertices, geometrybank_handle const &Geometry, int const Type ) { geometrybank_manager::create_chunk( vertex_array &Vertices, geometrybank_handle const &Geometry, int const Type ) {
auto const newchunkhandle = bank( Geometry )->create( Vertices, Type ); auto const newchunkhandle = bank( Geometry ).first->create( Vertices, Type );
if( newchunkhandle.chunk != 0 ) { return geometry_handle( Geometry.bank, newchunkhandle.chunk ); } if( newchunkhandle.chunk != 0 ) { return geometry_handle( Geometry.bank, newchunkhandle.chunk ); }
else { return geometry_handle( 0, 0 ); } else { return geometry_handle( 0, 0 ); }
@@ -351,14 +404,14 @@ geometrybank_manager::create_chunk( vertex_array &Vertices, geometrybank_handle
bool bool
geometrybank_manager::replace( vertex_array &Vertices, geometry_handle const &Geometry, std::size_t const Offset ) { geometrybank_manager::replace( vertex_array &Vertices, geometry_handle const &Geometry, std::size_t const Offset ) {
return bank( Geometry )->replace( Vertices, Geometry, Offset ); return bank( Geometry ).first->replace( Vertices, Geometry, Offset );
} }
// adds supplied vertex data at the end of specified chunk // adds supplied vertex data at the end of specified chunk
bool bool
geometrybank_manager::append( vertex_array &Vertices, geometry_handle const &Geometry ) { geometrybank_manager::append( vertex_array &Vertices, geometry_handle const &Geometry ) {
return bank( Geometry )->append( Vertices, Geometry ); return bank( Geometry ).first->append( Vertices, Geometry );
} }
// draws geometry stored in specified chunk // draws geometry stored in specified chunk
void void
@@ -366,12 +419,15 @@ geometrybank_manager::draw( geometry_handle const &Geometry, unsigned int const
if( Geometry == NULL ) { return; } if( Geometry == NULL ) { return; }
return bank( Geometry )->draw( Geometry, Streams ); auto &bankrecord = bank( Geometry );
bankrecord.second = m_resourcetimestamp;
bankrecord.first->draw( Geometry, Streams );
} }
// provides direct access to vertex data of specfied chunk // provides direct access to vertex data of specfied chunk
vertex_array const & vertex_array const &
geometrybank_manager::vertices( geometry_handle const &Geometry ) const { geometrybank_manager::vertices( geometry_handle const &Geometry ) const {
return bank( Geometry )->vertices( Geometry ); return bank( Geometry ).first->vertices( Geometry );
} }

View File

@@ -102,6 +102,9 @@ public:
template <typename Iterator_> template <typename Iterator_>
void void
draw( Iterator_ First, Iterator_ Last, unsigned int const Streams = basic_streams ) { while( First != Last ) { draw( *First, Streams ); ++First; } } draw( Iterator_ First, Iterator_ Last, unsigned int const Streams = basic_streams ) { while( First != Last ) { draw( *First, Streams ); ++First; } }
// frees subclass-specific resources associated with the bank, typically called when the bank wasn't in use for a period of time
void
release();
// provides direct access to vertex data of specfied chunk // provides direct access to vertex data of specfied chunk
vertex_array const & vertex_array const &
vertices( geometry_handle const &Geometry ) const; vertices( geometry_handle const &Geometry ) const;
@@ -142,6 +145,8 @@ private:
virtual void replace_( geometry_handle const &Geometry ) = 0; virtual void replace_( geometry_handle const &Geometry ) = 0;
// draw() subclass details // draw() subclass details
virtual void draw_( geometry_handle const &Geometry, unsigned int const Streams ) = 0; virtual void draw_( geometry_handle const &Geometry, unsigned int const Streams ) = 0;
// resource release subclass details
virtual void release_() = 0;
}; };
// opengl vbo-based variant of the geometry bank // opengl vbo-based variant of the geometry bank
@@ -149,6 +154,8 @@ private:
class opengl_vbogeometrybank : public geometry_bank { class opengl_vbogeometrybank : public geometry_bank {
public: public:
// constructors:
opengl_vbogeometrybank() = default;
// destructor // destructor
~opengl_vbogeometrybank() { ~opengl_vbogeometrybank() {
delete_buffer(); } delete_buffer(); }
@@ -179,6 +186,9 @@ private:
// draw() subclass details // draw() subclass details
void void
draw_( geometry_handle const &Geometry, unsigned int const Streams ); draw_( geometry_handle const &Geometry, unsigned int const Streams );
// release () subclass details
void
release_();
void void
bind_buffer(); bind_buffer();
void void
@@ -200,7 +210,9 @@ private:
class opengl_dlgeometrybank : public geometry_bank { class opengl_dlgeometrybank : public geometry_bank {
public: public:
// methods: // constructors:
opengl_dlgeometrybank() = default;
// destructor:
~opengl_dlgeometrybank() { ~opengl_dlgeometrybank() {
for( auto &chunkrecord : m_chunkrecords ) { for( auto &chunkrecord : m_chunkrecords ) {
::glDeleteLists( chunkrecord.list, 1 ); } } ::glDeleteLists( chunkrecord.list, 1 ); } }
@@ -224,6 +236,9 @@ private:
// draw() subclass details // draw() subclass details
void void
draw_( geometry_handle const &Geometry, unsigned int const Streams ); draw_( geometry_handle const &Geometry, unsigned int const Streams );
// release () subclass details
void
release_();
void void
delete_list( geometry_handle const &Geometry ); delete_list( geometry_handle const &Geometry );
@@ -240,6 +255,8 @@ class geometrybank_manager {
public: public:
// methods: // methods:
// performs a resource sweep
void update();
// creates a new geometry bank. returns: handle to the bank or NULL // creates a new geometry bank. returns: handle to the bank or NULL
geometrybank_handle geometrybank_handle
create_bank(); create_bank();
@@ -267,10 +284,18 @@ public:
private: private:
// types: // types:
typedef std::deque< std::shared_ptr<geometry_bank> > geometrybank_sequence; typedef std::pair<
std::shared_ptr<geometry_bank>,
std::chrono::steady_clock::time_point > geometrybanktimepoint_pair;
typedef std::deque< geometrybanktimepoint_pair > geometrybanktimepointpair_sequence;
// members: // members:
geometrybank_sequence m_geometrybanks; std::chrono::nanoseconds const unusedresourcetimetolive { std::chrono::seconds { 60 } };
geometrybanktimepointpair_sequence::size_type const unusedresourcesweepsize { 300 };
geometrybanktimepointpair_sequence m_geometrybanks;
geometrybanktimepointpair_sequence::size_type m_resourcesweepindex { 0 };
std::chrono::steady_clock::time_point m_resourcetimestamp { std::chrono::steady_clock::now() };
// methods // methods
inline inline
@@ -279,11 +304,11 @@ private:
return ( ( Geometry.bank != 0 ) return ( ( Geometry.bank != 0 )
&& ( Geometry.bank <= m_geometrybanks.size() ) ); } && ( Geometry.bank <= m_geometrybanks.size() ) ); }
inline inline
geometrybank_sequence::value_type & geometrybanktimepointpair_sequence::value_type &
bank( geometry_handle const Geometry ) { bank( geometry_handle const Geometry ) {
return m_geometrybanks[ Geometry.bank - 1 ]; } return m_geometrybanks[ Geometry.bank - 1 ]; }
inline inline
geometrybank_sequence::value_type const & geometrybanktimepointpair_sequence::value_type const &
bank( geometry_handle const Geometry ) const { bank( geometry_handle const Geometry ) const {
return m_geometrybanks[ Geometry.bank - 1 ]; } return m_geometrybanks[ Geometry.bank - 1 ]; }

View File

@@ -201,14 +201,19 @@ std::string cParser::readQuotes(char const Quote) { // read the stream until spe
return token; return token;
} }
std::string cParser::readComment( std::string const &Break ) { // pobieranie znaków aż do znalezienia znacznika końca void cParser::skipComment( std::string const &Endmark ) { // pobieranie znaków aż do znalezienia znacznika końca
std::string token = ""; std::string input = "";
auto const endmarksize = Endmark.size();
while( mStream->peek() != EOF ) { // o ile nie koniec pliku while( mStream->peek() != EOF ) { // o ile nie koniec pliku
token += mStream->get(); // pobranie znaku input += mStream->get(); // pobranie znaku
if( token.rfind( Break ) != std::string::npos ) // szukanie znacznika końca if( input.find( Endmark ) != std::string::npos ) // szukanie znacznika końca
break; break;
if( input.size() >= endmarksize ) {
// keep the read text short, to avoid pointless string re-allocations on longer comments
input = input.substr( 1 );
} }
return token; }
return;
} }
bool cParser::findQuotes( std::string &String ) { bool cParser::findQuotes( std::string &String ) {
@@ -228,7 +233,7 @@ bool cParser::trimComments(std::string &String)
{ {
if (String.rfind((*cmIt).first) != std::string::npos) if (String.rfind((*cmIt).first) != std::string::npos)
{ {
readComment((*cmIt).second); skipComment((*cmIt).second);
String.resize(String.rfind((*cmIt).first)); String.resize(String.rfind((*cmIt).first));
return true; return true;
} }

View File

@@ -92,7 +92,7 @@ class cParser //: public std::stringstream
// methods: // methods:
std::string readToken(bool ToLower = true, const char *Break = "\n\r\t ;"); std::string readToken(bool ToLower = true, const char *Break = "\n\r\t ;");
std::string readQuotes( char const Quote = '\"' ); std::string readQuotes( char const Quote = '\"' );
std::string readComment( std::string const &Break = "\n\r\t ;" ); void skipComment( std::string const &Endmark );
bool findQuotes( std::string &String ); bool findQuotes( std::string &String );
bool trimComments( std::string &String ); bool trimComments( std::string &String );
std::size_t count(); std::size_t count();

View File

@@ -157,6 +157,7 @@ opengl_renderer::Render() {
// frustum tests are performed in 'world space' but after we set up frustum // frustum tests are performed in 'world space' but after we set up frustum
// we no longer need camera translation, only rotation // we no longer need camera translation, only rotation
::glMultMatrixd( glm::value_ptr( glm::dmat4( glm::dmat3( worldcamera )))); ::glMultMatrixd( glm::value_ptr( glm::dmat4( glm::dmat3( worldcamera ))));
Render( &World.Environment ); Render( &World.Environment );
Render( &World.Ground ); Render( &World.Ground );
@@ -538,19 +539,26 @@ opengl_renderer::Render( TGroundNode *Node ) {
} }
case GL_LINES: { case GL_LINES: {
if( ( Node->m_geometry == NULL ) if( ( Node->Piece->geometry == NULL )
|| ( Node->fLineThickness > 0.0 ) ) { || ( Node->fLineThickness > 0.0 ) ) {
return false; return false;
} }
// setup // setup
// w zaleznosci od koloru swiatla auto const distance = std::sqrt( distancesquared );
auto const linealpha =
10.0 * Node->fLineThickness
/ std::max(
0.5 * Node->m_radius + 1.0,
distance - ( 0.5 * Node->m_radius ) );
::glColor4fv( ::glColor4fv(
glm::value_ptr( glm::value_ptr(
glm::vec4( glm::vec4(
Node->Diffuse * glm::make_vec3( Global::DayLight.ambient ), Node->Diffuse * glm::make_vec3( Global::DayLight.ambient ), // w zaleznosci od koloru swiatla
std::min( 1.0 ) ) ); // if the thickness is defined negative, lines are always drawn opaque
1.0, auto const linewidth = clamp( 0.5 * linealpha + Node->fLineThickness * Node->m_radius / 1000.0, 1.0, 32.0 );
1000.0 * Node->fLineThickness / ( distancesquared + 1.0 ) ) ) ) ); if( linewidth > 1.0 ) {
::glLineWidth( static_cast<float>( linewidth ) );
}
GfxRenderer.Bind( 0 ); GfxRenderer.Bind( 0 );
@@ -559,16 +567,18 @@ opengl_renderer::Render( TGroundNode *Node ) {
::glTranslated( originoffset.x, originoffset.y, originoffset.z ); ::glTranslated( originoffset.x, originoffset.y, originoffset.z );
// render // render
m_geometry.draw( Node->m_geometry ); m_geometry.draw( Node->Piece->geometry );
// post-render cleanup // post-render cleanup
::glPopMatrix(); ::glPopMatrix();
if( linewidth > 1.0 ) { ::glLineWidth( 1.0f ); }
return true; return true;
} }
case GL_TRIANGLES: { case GL_TRIANGLES: {
if( ( Node->m_geometry == NULL ) if( ( Node->Piece->geometry == NULL )
|| ( ( Node->iFlags & 0x10 ) == 0 ) ) { || ( ( Node->iFlags & 0x10 ) == 0 ) ) {
return false; return false;
} }
@@ -582,7 +592,7 @@ opengl_renderer::Render( TGroundNode *Node ) {
::glTranslated( originoffset.x, originoffset.y, originoffset.z ); ::glTranslated( originoffset.x, originoffset.y, originoffset.z );
// render // render
m_geometry.draw( Node->m_geometry ); m_geometry.draw( Node->Piece->geometry );
// post-render cleanup // post-render cleanup
::glPopMatrix(); ::glPopMatrix();
@@ -750,7 +760,7 @@ opengl_renderer::Render( TSubModel *Submodel ) {
// ...luminance // ...luminance
if( Global::fLuminance < Submodel->fLight ) { if( Global::fLuminance < Submodel->fLight ) {
// zeby swiecilo na kolorowo // zeby swiecilo na kolorowo
::glMaterialfv( GL_FRONT, GL_EMISSION, glm::value_ptr(Submodel->f4Diffuse) ); ::glMaterialfv( GL_FRONT, GL_EMISSION, glm::value_ptr( Submodel->f4Diffuse * Submodel->f4Emision.a ) );
} }
// main draw call // main draw call
@@ -772,7 +782,7 @@ opengl_renderer::Render( TSubModel *Submodel ) {
if( Submodel->fCosViewAngle > Submodel->fCosFalloffAngle ) // kąt większy niż maksymalny stożek swiatła if( Submodel->fCosViewAngle > Submodel->fCosFalloffAngle ) // kąt większy niż maksymalny stożek swiatła
{ {
float lightlevel = 1.0f; float lightlevel = 1.0f; // TODO, TBD: parameter to control light strength
// view angle attenuation // view angle attenuation
float const anglefactor = ( Submodel->fCosViewAngle - Submodel->fCosFalloffAngle ) / ( 1.0f - Submodel->fCosFalloffAngle ); float const anglefactor = ( Submodel->fCosViewAngle - Submodel->fCosFalloffAngle ) / ( 1.0f - Submodel->fCosFalloffAngle );
// distance attenuation. NOTE: since it's fixed pipeline with built-in gamma correction we're using linear attenuation // distance attenuation. NOTE: since it's fixed pipeline with built-in gamma correction we're using linear attenuation
@@ -946,7 +956,7 @@ opengl_renderer::Render_Alpha( TGroundNode *Node ) {
} }
float const linealpha = static_cast<float>( float const linealpha = static_cast<float>(
std::min( std::min(
1.2, 1.25,
5000 * Node->hvTraction->WireThickness / ( distancesquared + 1.0 ) ) ); // zbyt grube nie są dobre 5000 * Node->hvTraction->WireThickness / ( distancesquared + 1.0 ) ) ); // zbyt grube nie są dobre
::glLineWidth( linealpha ); ::glLineWidth( linealpha );
// McZapkie-261102: kolor zalezy od materialu i zasniedzenia // McZapkie-261102: kolor zalezy od materialu i zasniedzenia
@@ -982,17 +992,23 @@ opengl_renderer::Render_Alpha( TGroundNode *Node ) {
} }
case GL_LINES: { case GL_LINES: {
if( ( Node->m_geometry == NULL ) if( ( Node->Piece->geometry == NULL )
|| ( Node->fLineThickness < 0.0 ) ) { || ( Node->fLineThickness < 0.0 ) ) {
return false; return false;
} }
// setup // setup
auto const linewidth = clamp( 100.0 * Node->fLineThickness / ( distancesquared + 1.0 ), 1.0, 10.0 ); auto const distance = std::sqrt( distancesquared );
auto const linealpha =
10.0 * Node->fLineThickness
/ std::max(
0.5 * Node->m_radius + 1.0,
distance - ( 0.5 * Node->m_radius ) );
::glColor4fv( ::glColor4fv(
glm::value_ptr( glm::value_ptr(
glm::vec4( glm::vec4(
Node->Diffuse * glm::make_vec3( Global::DayLight.ambient ), // w zaleznosci od koloru swiatla Node->Diffuse * glm::make_vec3( Global::DayLight.ambient ), // w zaleznosci od koloru swiatla
std::min( 1.0, linewidth ) ) ) ); std::min( 1.0, linealpha ) ) ) );
auto const linewidth = clamp( 0.5 * linealpha + Node->fLineThickness * Node->m_radius / 1000.0, 1.0, 32.0 );
if( linewidth > 1.0 ) { if( linewidth > 1.0 ) {
::glLineWidth( static_cast<float>(linewidth) ); ::glLineWidth( static_cast<float>(linewidth) );
} }
@@ -1004,20 +1020,18 @@ opengl_renderer::Render_Alpha( TGroundNode *Node ) {
::glTranslated( originoffset.x, originoffset.y, originoffset.z ); ::glTranslated( originoffset.x, originoffset.y, originoffset.z );
// render // render
m_geometry.draw( Node->m_geometry ); m_geometry.draw( Node->Piece->geometry );
// post-render cleanup // post-render cleanup
if( linewidth > 1.0 ) {
::glLineWidth( 1.0f );
}
::glPopMatrix(); ::glPopMatrix();
if( linewidth > 1.0 ) { ::glLineWidth( 1.0f ); }
return true; return true;
} }
case GL_TRIANGLES: { case GL_TRIANGLES: {
if( ( Node->m_geometry == NULL ) if( ( Node->Piece->geometry == NULL )
|| ( ( Node->iFlags & 0x20 ) == 0 ) ) { || ( ( Node->iFlags & 0x20 ) == 0 ) ) {
return false; return false;
} }
@@ -1031,7 +1045,7 @@ opengl_renderer::Render_Alpha( TGroundNode *Node ) {
::glTranslated( originoffset.x, originoffset.y, originoffset.z ); ::glTranslated( originoffset.x, originoffset.y, originoffset.z );
// render // render
m_geometry.draw( Node->m_geometry ); m_geometry.draw( Node->Piece->geometry );
// post-render cleanup // post-render cleanup
::glPopMatrix(); ::glPopMatrix();
@@ -1188,7 +1202,7 @@ opengl_renderer::Render_Alpha( TSubModel *Submodel ) {
// ...luminance // ...luminance
if( Global::fLuminance < Submodel->fLight ) { if( Global::fLuminance < Submodel->fLight ) {
// zeby swiecilo na kolorowo // zeby swiecilo na kolorowo
::glMaterialfv( GL_FRONT, GL_EMISSION, glm::value_ptr(Submodel->f4Diffuse) ); ::glMaterialfv( GL_FRONT, GL_EMISSION, glm::value_ptr( Submodel->f4Diffuse * Submodel->f4Emision.a ) );
} }
// main draw call // main draw call
@@ -1311,7 +1325,7 @@ opengl_renderer::Update ( double const Deltatime ) {
else if( framerate > 60.0 ) { targetsegments = 225; targetfactor = 1.5f; } else if( framerate > 60.0 ) { targetsegments = 225; targetfactor = 1.5f; }
else if( framerate > 30.0 ) { targetsegments = 90; targetfactor = Global::ScreenHeight / 768.0f; } else if( framerate > 30.0 ) { targetsegments = 90; targetfactor = Global::ScreenHeight / 768.0f; }
else { targetsegments = 9; targetfactor = Global::ScreenHeight / 768.0f * 0.75f; } else { targetsegments = 9; targetfactor = Global::ScreenHeight / 768.0f * 0.75f; }
/*
if( targetsegments > Global::iSegmentsRendered ) { if( targetsegments > Global::iSegmentsRendered ) {
Global::iSegmentsRendered = std::min( targetsegments, Global::iSegmentsRendered + 5 ); Global::iSegmentsRendered = std::min( targetsegments, Global::iSegmentsRendered + 5 );
@@ -1320,6 +1334,7 @@ opengl_renderer::Update ( double const Deltatime ) {
Global::iSegmentsRendered = std::max( targetsegments, Global::iSegmentsRendered - 5 ); Global::iSegmentsRendered = std::max( targetsegments, Global::iSegmentsRendered - 5 );
} }
*/
if( targetfactor > Global::fDistanceFactor ) { if( targetfactor > Global::fDistanceFactor ) {
Global::fDistanceFactor = std::min( targetfactor, Global::fDistanceFactor + 0.05f ); Global::fDistanceFactor = std::min( targetfactor, Global::fDistanceFactor + 0.05f );
@@ -1343,6 +1358,8 @@ opengl_renderer::Update ( double const Deltatime ) {
} }
// TODO: add garbage collection and other less frequent works here // TODO: add garbage collection and other less frequent works here
m_geometry.update();
if( true == DebugModeFlag ) { if( true == DebugModeFlag ) {
m_debuginfo = m_textures.info(); m_debuginfo = m_textures.info();
} }

View File

@@ -164,12 +164,22 @@ void
ui_layer::render_background() { ui_layer::render_background() {
if( m_background == 0 ) return; if( m_background == 0 ) return;
// NOTE: we limit/expect the background to come with 4:3 ratio. // NOTE: we limit/expect the background to come with 4:3 ratio.
// TODO, TBD: if we expose texture width or ratio from texture object, this limitation could be lifted // TODO, TBD: if we expose texture width or ratio from texture object, this limitation could be lifted
GfxRenderer.Bind( m_background ); GfxRenderer.Bind( m_background );
quad( float4( 0.0f, 0.0f, 1024.0f, 768.0f ), float4( 1.0f, 1.0f, 1.0f, 1.0f ) ); auto const height { 768.0f };
auto const &texture = GfxRenderer.Texture( m_background );
float const width = (
texture.width() == texture.height() ?
1024.0f : // legacy mode, square texture displayed as 4:3 image
texture.width() / ( texture.height() / 768.0f ) );
quad(
float4(
( 1024.0f * 0.5f ) - ( width * 0.5f ),
( 768.0f * 0.5f ) - ( height * 0.5f ),
( 1024.0f * 0.5f ) - ( width * 0.5f ) + width,
( 768.0f * 0.5f ) - ( height * 0.5f ) + height ),
float4( 1.0f, 1.0f, 1.0f, 1.0f ) );
} }
void void
@@ -200,7 +210,11 @@ ui_layer::quad( float4 const &Coordinates, float4 const &Color ) {
Global::iWindowHeight / 768.0 : Global::iWindowHeight / 768.0 :
Global::iWindowHeight / 768.0 * screenratio / ( 4.0f / 3.0f ) ); Global::iWindowHeight / 768.0 * screenratio / ( 4.0f / 3.0f ) );
float const height = 768.0f * heightratio; float const height = 768.0f * heightratio;
/*
float const heightratio = Global::iWindowHeight / 768.0f;
float const height = 768.0f * heightratio;
float const width = Global::iWindowWidth * heightratio;
*/
glColor4fv(&Color.x); glColor4fv(&Color.x);
glBegin( GL_TRIANGLE_STRIP ); glBegin( GL_TRIANGLE_STRIP );

View File

@@ -1,5 +1,5 @@
#pragma once #pragma once
#define VERSION_MAJOR 17 #define VERSION_MAJOR 17
#define VERSION_MINOR 617 #define VERSION_MINOR 626
#define VERSION_REVISION 0 #define VERSION_REVISION 0