mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-03-22 15:05:03 +01: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:
89
DynObj.cpp
89
DynObj.cpp
@@ -527,6 +527,39 @@ void TDynamicObject::UpdateLeverEnum(TAnim *pAnim)
|
||||
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 §ionlight : 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 §ionlight : 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: *********************
|
||||
void TDynamicObject::ABuLittleUpdate(double ObjSqrDist)
|
||||
{ // ABu290105: pozbierane i uporzadkowane powtarzajace
|
||||
@@ -946,6 +979,13 @@ void TDynamicObject::ABuLittleUpdate(double ObjSqrDist)
|
||||
}
|
||||
// else btHeadSignals23.TurnOff();
|
||||
}
|
||||
// interior light levels
|
||||
for( auto const §ion : SectionLightLevels ) {
|
||||
section.compartment->SetLightLevel( section.level, true );
|
||||
if( section.load != nullptr ) {
|
||||
section.load->SetLightLevel( section.level, true );
|
||||
}
|
||||
}
|
||||
}
|
||||
// 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);
|
||||
btMechanik2.Init("mechanik2", mdLowPolyInt, false);
|
||||
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
|
||||
if (mdModel) // jeśli ma w czym szukać
|
||||
for (int i = 0; i < 2; i++)
|
||||
@@ -3416,6 +3491,20 @@ bool TDynamicObject::Update(double dt, double dt1)
|
||||
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: *******************************
|
||||
// Z obserwacji: v>0 -> Coupler 0; v<0 ->coupler1 (Ra: prędkość jest związana
|
||||
// z pojazdem)
|
||||
|
||||
28
DynObj.h
28
DynObj.h
@@ -143,12 +143,8 @@ class TAnim
|
||||
struct material_data {
|
||||
|
||||
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
|
||||
|
||||
material_data() {
|
||||
::SecureZeroMemory( replacable_skins, sizeof( replacable_skins ) );
|
||||
}
|
||||
};
|
||||
|
||||
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
|
||||
vector3 modelRot; // obrot pudła względem świata - do przeanalizowania, czy potrzebne!!!
|
||||
// bool bCameraNear; //blisko kamer są potrzebne dodatkowe obliczenia szczegółów
|
||||
TDynamicObject * ABuFindNearestObject( TTrack *Track, TDynamicObject *MyPointer,
|
||||
int &CouplNr );
|
||||
TDynamicObject * ABuFindNearestObject( TTrack *Track, TDynamicObject *MyPointer, int &CouplNr );
|
||||
|
||||
public: // parametry położenia pojazdu dostępne publicznie
|
||||
std::string asTrack; // nazwa toru początkowego; wywalić?
|
||||
@@ -191,8 +186,18 @@ public: // modele składowe pojazdu
|
||||
TModel3d *mdLoad; // model zmiennego ładunku
|
||||
TModel3d *mdKabina; // model kabiny dla użytkownika; McZapkie-030303: to z train.h
|
||||
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?
|
||||
float InteriorLightLevel{ 0.0f }; // current level of interior lighting
|
||||
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
|
||||
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?)
|
||||
|
||||
private: // zmienne i metody do animacji submodeli; Ra: sprzatam animacje w pojeździe
|
||||
@@ -200,7 +205,9 @@ public: // modele składowe pojazdu
|
||||
|
||||
public:
|
||||
inline
|
||||
material_data const *Material() const { return &m_materialdata; }
|
||||
material_data const
|
||||
*Material() const {
|
||||
return &m_materialdata; }
|
||||
// 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
|
||||
private:
|
||||
@@ -226,6 +233,7 @@ public: // modele składowe pojazdu
|
||||
void UpdateLeverFloat(TAnim *pAnim); // animacja gałki zależna od float
|
||||
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 toggle_lights(); // switch light levels for registered interior sections
|
||||
private: // Ra: ciąg dalszy animacji, dopiero do ogarnięcia
|
||||
// ABuWozki 060504
|
||||
vector3 bogieRot[2]; // Obroty wozkow w/m korpusu
|
||||
|
||||
390
Ground.cpp
390
Ground.cpp
@@ -67,7 +67,6 @@ std::string LogComment;
|
||||
TGroundNode::TGroundNode()
|
||||
{ // nowy obiekt terenu - pusty
|
||||
iType = GL_POINTS;
|
||||
Vertices = NULL;
|
||||
nNext = nNext2 = NULL;
|
||||
iCount = 0; // wierzchołków w trójkącie
|
||||
// iNumPts=0; //punktów w linii
|
||||
@@ -115,9 +114,6 @@ TGroundNode::~TGroundNode()
|
||||
break;
|
||||
case TP_TERRAIN:
|
||||
{ // 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
|
||||
}
|
||||
case TP_SUBMODEL: // dla formalności, nie wymaga usuwania
|
||||
@@ -125,33 +121,31 @@ TGroundNode::~TGroundNode()
|
||||
case GL_LINES:
|
||||
case GL_LINE_STRIP:
|
||||
case GL_LINE_LOOP:
|
||||
SafeDeleteArray(Points);
|
||||
break;
|
||||
case GL_TRIANGLE_STRIP:
|
||||
case GL_TRIANGLE_FAN:
|
||||
case GL_TRIANGLES:
|
||||
SafeDeleteArray(Vertices);
|
||||
SafeDelete( Piece );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
void TGroundNode::Init(int n)
|
||||
{ // utworzenie tablicy wierzchołków
|
||||
bVisible = false;
|
||||
iNumVerts = n;
|
||||
Vertices = new TGroundVertex[iNumVerts];
|
||||
}
|
||||
|
||||
TGroundNode::TGroundNode( TGroundNodeType t, int n ) :
|
||||
*/
|
||||
TGroundNode::TGroundNode( TGroundNodeType t ) :
|
||||
TGroundNode() {
|
||||
// utworzenie obiektu
|
||||
iNumVerts = n;
|
||||
if( iNumVerts ) {
|
||||
Vertices = new TGroundVertex[ iNumVerts ];
|
||||
}
|
||||
iType = t;
|
||||
switch (iType) {
|
||||
// zależnie od typu
|
||||
case GL_TRIANGLES: {
|
||||
Piece = new piece_node;
|
||||
break;
|
||||
}
|
||||
case TP_TRACK: {
|
||||
pTrack = new TTrack( this );
|
||||
break;
|
||||
@@ -171,36 +165,36 @@ void TGroundNode::InitNormals()
|
||||
switch (iType)
|
||||
{
|
||||
case GL_TRIANGLE_STRIP:
|
||||
v1 = Vertices[0].position - Vertices[1].position;
|
||||
v2 = Vertices[1].position - Vertices[2].position;
|
||||
v1 = Piece->vertices[0].position - Piece->vertices[1].position;
|
||||
v2 = Piece->vertices[1].position - Piece->vertices[2].position;
|
||||
n1 = glm::normalize(glm::cross(v1, v2));
|
||||
if (Vertices[0].normal == glm::vec3())
|
||||
Vertices[0].normal = n1;
|
||||
v3 = Vertices[2].position - Vertices[3].position;
|
||||
if (Piece->vertices[0].normal == glm::vec3())
|
||||
Piece->vertices[0].normal = n1;
|
||||
v3 = Piece->vertices[2].position - Piece->vertices[3].position;
|
||||
n2 = glm::normalize(glm::cross(v3, v2));
|
||||
if (Vertices[1].normal == glm::vec3())
|
||||
Vertices[1].normal = (n1 + n2) * 0.5f;
|
||||
if (Piece->vertices[1].normal == glm::vec3())
|
||||
Piece->vertices[1].normal = (n1 + n2) * 0.5f;
|
||||
|
||||
for ( i = 2; i < iNumVerts - 2; i += 2)
|
||||
{
|
||||
v4 = Vertices[i - 1].position - Vertices[i].position;
|
||||
v5 = Vertices[i].position - Vertices[i + 1].position;
|
||||
v4 = Piece->vertices[i - 1].position - Piece->vertices[i].position;
|
||||
v5 = Piece->vertices[i].position - Piece->vertices[i + 1].position;
|
||||
n3 = glm::normalize(glm::cross(v3, v4));
|
||||
n4 = glm::normalize(glm::cross(v5, v4));
|
||||
if (Vertices[i].normal == glm::vec3())
|
||||
Vertices[i].normal = (n1 + n2 + n3) / 3.0f;
|
||||
if (Vertices[i + 1].normal == glm::vec3())
|
||||
Vertices[i + 1].normal = (n2 + n3 + n4) / 3.0f;
|
||||
if (Piece->vertices[i].normal == glm::vec3())
|
||||
Piece->vertices[i].normal = (n1 + n2 + n3) / 3.0f;
|
||||
if (Piece->vertices[i + 1].normal == glm::vec3())
|
||||
Piece->vertices[i + 1].normal = (n2 + n3 + n4) / 3.0f;
|
||||
n1 = n3;
|
||||
n2 = n4;
|
||||
v3 = v5;
|
||||
}
|
||||
if (Vertices[i].normal == glm::vec3())
|
||||
Vertices[i].normal = (n1 + n2) / 2.0f;
|
||||
if (Piece->vertices[i].normal == glm::vec3())
|
||||
Piece->vertices[i].normal = (n1 + n2) / 2.0f;
|
||||
if (i + 1 < iNumVerts)
|
||||
{
|
||||
if (Vertices[i + 1].normal == glm::vec3())
|
||||
Vertices[i + 1].normal = n2;
|
||||
if (Piece->vertices[i + 1].normal == glm::vec3())
|
||||
Piece->vertices[i + 1].normal = n2;
|
||||
}
|
||||
else
|
||||
WriteLog("odd number of vertices, normals may be wrong!");
|
||||
@@ -212,21 +206,21 @@ void TGroundNode::InitNormals()
|
||||
case GL_TRIANGLES:
|
||||
for (i = 0; i < iNumVerts; i += 3)
|
||||
{
|
||||
v1 = Vertices[i + 0].position - Vertices[i + 1].position;
|
||||
v2 = Vertices[i + 1].position - Vertices[i + 2].position;
|
||||
v1 = Piece->vertices[i + 0].position - Piece->vertices[i + 1].position;
|
||||
v2 = Piece->vertices[i + 1].position - Piece->vertices[i + 2].position;
|
||||
n1 = glm::normalize(glm::cross(v1, v2));
|
||||
if (Vertices[i + 0].normal == glm::vec3())
|
||||
Vertices[i + 0].normal = (n1);
|
||||
if (Vertices[i + 1].normal == glm::vec3())
|
||||
Vertices[i + 1].normal = (n1);
|
||||
if (Vertices[i + 2].normal == glm::vec3())
|
||||
Vertices[i + 2].normal = (n1);
|
||||
if( Piece->vertices[i + 0].normal == glm::vec3() )
|
||||
Piece->vertices[i + 0].normal = (n1);
|
||||
if( Piece->vertices[i + 1].normal == glm::vec3() )
|
||||
Piece->vertices[i + 1].normal = (n1);
|
||||
if( Piece->vertices[i + 2].normal == glm::vec3() )
|
||||
Piece->vertices[i + 2].normal = (n1);
|
||||
t1 = glm::vec2(
|
||||
std::floor( Vertices[ i + 0 ].texture.s ),
|
||||
std::floor( Vertices[ i + 0 ].texture.t ) );
|
||||
Vertices[ i + 1 ].texture -= t1;
|
||||
Vertices[ i + 2 ].texture -= t1;
|
||||
Vertices[ i + 0 ].texture -= t1;
|
||||
std::floor( Piece->vertices[ i + 0 ].texture.s ),
|
||||
std::floor( Piece->vertices[ i + 0 ].texture.t ) );
|
||||
Piece->vertices[ i + 1 ].texture -= t1;
|
||||
Piece->vertices[ i + 2 ].texture -= t1;
|
||||
Piece->vertices[ i + 0 ].texture -= t1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -349,8 +343,10 @@ void TSubRect::NodeAdd(TGroundNode *Node)
|
||||
}
|
||||
#endif
|
||||
case TP_TRACTIONPOWERSOURCE: // a te w ogóle pomijamy
|
||||
/*
|
||||
// case TP_ISOLATED: //lista torów w obwodzie izolowanym - na razie ignorowana
|
||||
break;
|
||||
*/
|
||||
case TP_DYNAMIC:
|
||||
return; // tych nie dopisujemy wcale
|
||||
}
|
||||
@@ -380,22 +376,14 @@ void TSubRect::Sort() {
|
||||
|
||||
TTrack * TSubRect::FindTrack(vector3 *Point, int &iConnection, TTrack *Exclude)
|
||||
{ // szukanie toru, którego koniec jest najbliższy (*Point)
|
||||
for (int i = 0; i < iTracks; ++i)
|
||||
if (tTracks[i] != Exclude) // można użyć tabelę torów, bo jest mniejsza
|
||||
for( int i = 0; i < iTracks; ++i ) {
|
||||
if( tTracks[ i ] != Exclude ) // można użyć tabelę torów, bo jest mniejsza
|
||||
{
|
||||
iConnection = tTracks[i]->TestPoint(Point);
|
||||
if (iConnection >= 0)
|
||||
return tTracks[i]; // szukanie TGroundNode nie jest potrzebne
|
||||
iConnection = tTracks[ i ]->TestPoint( Point );
|
||||
if( iConnection >= 0 )
|
||||
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;
|
||||
};
|
||||
|
||||
@@ -449,30 +437,20 @@ void TSubRect::LoadNodes() {
|
||||
auto *node { nRootNode };
|
||||
while( node != nullptr ) {
|
||||
switch (node->iType) {
|
||||
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_TRIANGLES:
|
||||
case GL_LINES: {
|
||||
vertex_array vertices;
|
||||
for( int idx = 0; idx < node->iNumPts; ++idx ) {
|
||||
for( auto const &vertex : node->Piece->vertices ) {
|
||||
vertices.emplace_back(
|
||||
node->Points[ idx ] - node->m_rootposition,
|
||||
glm::vec3(),
|
||||
glm::vec2() );
|
||||
vertex.position - node->m_rootposition,
|
||||
vertex.normal,
|
||||
vertex.texture );
|
||||
}
|
||||
node->m_geometry = GfxRenderer.Insert( vertices, m_geometrybank, GL_LINES );
|
||||
SafeDeleteArray( node->Vertices );
|
||||
node->iNumPts = 0;
|
||||
node->Piece->geometry = GfxRenderer.Insert( vertices, m_geometrybank, node->iType );
|
||||
node->Piece->vertices.swap( std::vector<TGroundVertex>() ); // hipster shrink_to_fit
|
||||
// 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;
|
||||
}
|
||||
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
|
||||
@@ -594,19 +625,19 @@ void TGround::Free()
|
||||
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!)
|
||||
for (TGroundNode *Current = nRootDynamic; Current; Current = Current->nNext)
|
||||
if ((Current->asName == asNameToFind))
|
||||
if ((Current->asName == Name))
|
||||
return Current;
|
||||
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!)
|
||||
for (TGroundNode *Current = nRootDynamic; Current; Current = Current->nNext)
|
||||
if (Current->DynamicObject->Mechanik)
|
||||
if ((Current->asName == asNameToFind))
|
||||
if ((Current->asName == Name))
|
||||
return Current;
|
||||
return NULL;
|
||||
};
|
||||
@@ -685,12 +716,12 @@ void TGround::RaTriangleDivider(TGroundNode *node)
|
||||
double x1 = x0 + 1400.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) &&
|
||||
(node->Vertices[1].position.x >= x0) && (node->Vertices[1].position.x <= x1) &&
|
||||
(node->Vertices[1].position.z >= z0) && (node->Vertices[1].position.z <= z1) &&
|
||||
(node->Vertices[2].position.x >= x0) && (node->Vertices[2].position.x <= x1) &&
|
||||
(node->Vertices[2].position.z >= z0) && (node->Vertices[2].position.z <= z1))
|
||||
if ((node->Piece->vertices[0].position.x >= x0) && (node->Piece->vertices[0].position.x <= x1) &&
|
||||
(node->Piece->vertices[0].position.z >= z0) && (node->Piece->vertices[0].position.z <= z1) &&
|
||||
(node->Piece->vertices[1].position.x >= x0) && (node->Piece->vertices[1].position.x <= x1) &&
|
||||
(node->Piece->vertices[1].position.z >= z0) && (node->Piece->vertices[1].position.z <= z1) &&
|
||||
(node->Piece->vertices[2].position.x >= x0) && (node->Piece->vertices[2].position.x <= x1) &&
|
||||
(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
|
||||
// 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
|
||||
@@ -700,47 +731,46 @@ void TGround::RaTriangleDivider(TGroundNode *node)
|
||||
x1 -= 200.0; // przestawienie na siatkę
|
||||
z0 += 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)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
divide = 14;
|
||||
// tworzymy jeden dodatkowy trójkąt, dzieląc jeden bok na przecięciu siatki kilometrowej
|
||||
TGroundNode *ntri; // wskaźnik na nowy trójkąt
|
||||
ntri = new TGroundNode(); // a ten jest nowy
|
||||
ntri->iType = GL_TRIANGLES; // kopiowanie parametrów, przydałby się konstruktor kopiujący
|
||||
ntri->Init(3);
|
||||
ntri = new TGroundNode(GL_TRIANGLES); // a ten jest nowy
|
||||
// kopiowanie parametrów, przydałby się konstruktor kopiujący
|
||||
ntri->TextureID = node->TextureID;
|
||||
ntri->iFlags = node->iFlags;
|
||||
ntri->Ambient = node->Ambient;
|
||||
@@ -753,42 +783,44 @@ void TGround::RaTriangleDivider(TGroundNode *node)
|
||||
ntri->nNext = nRootOfType[GL_TRIANGLES];
|
||||
nRootOfType[GL_TRIANGLES] = ntri; // dopisanie z przodu do listy
|
||||
++iNumNodes;
|
||||
ntri->iNumVerts = 3;
|
||||
ntri->Piece->vertices.resize( 3 );
|
||||
switch (divide & 3)
|
||||
{ // podzielenie jednego z boków, powstaje wierzchołek D
|
||||
case 0: // podział AB (0-1) -> ADC i DBC
|
||||
ntri->Vertices[2] = node->Vertices[2]; // wierzchołek C jest wspólny
|
||||
ntri->Vertices[1] = node->Vertices[1]; // wierzchołek B przechodzi do nowego
|
||||
ntri->Piece->vertices[2] = node->Piece->vertices[2]; // wierzchołek C jest wspólny
|
||||
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
|
||||
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
|
||||
node->Vertices[1].SetByX(node->Vertices[0], node->Vertices[1], (divide & 8) ? x1 : x0);
|
||||
ntri->Vertices[0] = node->Vertices[1]; // wierzchołek D jest wspólny
|
||||
node->Piece->vertices[1].SetByX(node->Piece->vertices[0], node->Piece->vertices[1], (divide & 8) ? x1 : x0);
|
||||
ntri->Piece->vertices[0] = node->Piece->vertices[1]; // wierzchołek D jest wspólny
|
||||
break;
|
||||
case 1: // podział BC (1-2) -> ABD i ADC
|
||||
ntri->Vertices[0] = node->Vertices[0]; // wierzchołek A jest wspólny
|
||||
ntri->Vertices[2] = node->Vertices[2]; // wierzchołek C przechodzi do nowego
|
||||
ntri->Piece->vertices[0] = node->Piece->vertices[0]; // wierzchołek A jest wspólny
|
||||
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
|
||||
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
|
||||
node->Vertices[2].SetByX(node->Vertices[1], node->Vertices[2], (divide & 8) ? x1 : x0);
|
||||
ntri->Vertices[1] = node->Vertices[2]; // wierzchołek D jest wspólny
|
||||
node->Piece->vertices[2].SetByX(node->Piece->vertices[1], node->Piece->vertices[2], (divide & 8) ? x1 : x0);
|
||||
ntri->Piece->vertices[1] = node->Piece->vertices[2]; // wierzchołek D jest wspólny
|
||||
break;
|
||||
case 2: // podział CA (2-0) -> ABD i DBC
|
||||
ntri->Vertices[1] = node->Vertices[1]; // wierzchołek B jest wspólny
|
||||
ntri->Vertices[2] = node->Vertices[2]; // wierzchołek C przechodzi do nowego
|
||||
ntri->Piece->vertices[1] = node->Piece->vertices[1]; // wierzchołek B jest wspólny
|
||||
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
|
||||
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
|
||||
node->Vertices[2].SetByX(node->Vertices[2], node->Vertices[0], (divide & 8) ? x1 : x0);
|
||||
ntri->Vertices[0] = node->Vertices[2]; // wierzchołek D jest wspólny
|
||||
node->Piece->vertices[2].SetByX(node->Piece->vertices[2], node->Piece->vertices[0], (divide & 8) ? x1 : x0);
|
||||
ntri->Piece->vertices[0] = node->Piece->vertices[2]; // wierzchołek D jest wspólny
|
||||
break;
|
||||
}
|
||||
// przeliczenie środków ciężkości obu
|
||||
node->pCenter = ( node->Vertices[ 0 ].position + node->Vertices[ 1 ].position + node->Vertices[ 2 ].position ) / 3.0;
|
||||
ntri->pCenter = ( ntri->Vertices[ 0 ].position + ntri->Vertices[ 1 ].position + ntri->Vertices[ 2 ].position ) / 3.0;
|
||||
node->pCenter = ( node->Piece->vertices[ 0 ].position + node->Piece->vertices[ 1 ].position + node->Piece->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(ntri);
|
||||
};
|
||||
@@ -1218,7 +1250,6 @@ TGroundNode * TGround::AddGroundNode(cParser *parser)
|
||||
tmp->nNode[i].iFlags = 0x10; // nieprzezroczyste; nie usuwany
|
||||
tmp->nNode[i].bVisible = true;
|
||||
tmp->nNode[i].pCenter = tmp->pCenter; // nie przesuwamy w inne miejsce
|
||||
// tmp->nNode[i].asName=
|
||||
}
|
||||
}
|
||||
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 ) ) ?
|
||||
0x20 :
|
||||
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;
|
||||
std::size_t vertexcount { 0 };
|
||||
@@ -1346,9 +1365,17 @@ TGroundNode * TGround::AddGroundNode(cParser *parser)
|
||||
if( vertexcount == 0 ) { vertex1 = vertex; }
|
||||
else if( vertexcount == 1 ) { vertex2 = vertex; }
|
||||
else if( vertexcount >= 2 ) {
|
||||
importedvertices.emplace_back( vertex1 );
|
||||
importedvertices.emplace_back( vertex2 );
|
||||
// swap order every other triangle, to maintain consistent winding
|
||||
if( vertexcount % 2 == 0 ) {
|
||||
importedvertices.emplace_back( vertex1 );
|
||||
importedvertices.emplace_back( vertex2 );
|
||||
}
|
||||
else {
|
||||
importedvertices.emplace_back( vertex2 );
|
||||
importedvertices.emplace_back( vertex1 );
|
||||
}
|
||||
importedvertices.emplace_back( vertex );
|
||||
|
||||
vertex1 = vertex2;
|
||||
vertex2 = vertex;
|
||||
}
|
||||
@@ -1363,25 +1390,27 @@ TGroundNode * TGround::AddGroundNode(cParser *parser)
|
||||
} while (token.compare("endtri") != 0);
|
||||
|
||||
tmp->iType = GL_TRIANGLES;
|
||||
tmp->Piece = new piece_node();
|
||||
tmp->iNumVerts = importedvertices.size();
|
||||
|
||||
auto const nv = importedvertices.size();
|
||||
tmp->Init(nv); // utworzenie tablicy wierzchołków
|
||||
if( tmp->iNumVerts > 0 ) {
|
||||
|
||||
for( std::size_t i = 0; i < nv; ++i ) {
|
||||
tmp->pCenter += importedvertices[ i ].position;
|
||||
tmp->Piece->vertices.swap( importedvertices );
|
||||
|
||||
for( auto const &vertex : tmp->Piece->vertices ) {
|
||||
tmp->pCenter += vertex.position;
|
||||
}
|
||||
tmp->pCenter /= tmp->iNumVerts;
|
||||
|
||||
r = 0;
|
||||
for( auto const &vertex : tmp->Piece->vertices ) {
|
||||
tf = SquareMagnitude( vertex.position - tmp->pCenter );
|
||||
if( tf > r )
|
||||
r = tf;
|
||||
}
|
||||
tmp->fSquareRadius += r;
|
||||
RaTriangleDivider( tmp ); // Ra: dzielenie trójkątów jest teraz całkiem wydajne
|
||||
}
|
||||
tmp->pCenter /= (nv > 0 ? nv : 1);
|
||||
|
||||
r = 0;
|
||||
for (std::size_t i = 0; i < nv; ++i)
|
||||
{
|
||||
tmp->Vertices[i] = importedvertices[i];
|
||||
tf = SquareMagnitude( tmp->Vertices[ i ].position - tmp->pCenter );
|
||||
if (tf > r)
|
||||
r = tf;
|
||||
}
|
||||
tmp->fSquareRadius += r;
|
||||
RaTriangleDivider(tmp); // Ra: dzielenie trójkątów jest teraz całkiem wydajne
|
||||
} // koniec wczytywania trójkątów
|
||||
break;
|
||||
case GL_LINES:
|
||||
@@ -1394,6 +1423,7 @@ TGroundNode * TGround::AddGroundNode(cParser *parser)
|
||||
>> tmp->Diffuse.b
|
||||
>> tmp->fLineThickness;
|
||||
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;
|
||||
std::size_t vertexcount{ 0 };
|
||||
@@ -1455,15 +1485,25 @@ TGroundNode * TGround::AddGroundNode(cParser *parser)
|
||||
importedvertices.pop_back();
|
||||
}
|
||||
tmp->iType = GL_LINES;
|
||||
tmp->Piece = new piece_node();
|
||||
tmp->iNumPts = importedvertices.size();
|
||||
|
||||
auto const nv = importedvertices.size();
|
||||
tmp->Points = new glm::dvec3[ nv ];
|
||||
tmp->iNumPts = nv;
|
||||
for( std::size_t i = 0; i < nv; ++i ) {
|
||||
tmp->Points[ i ] = importedvertices[ i ].position;
|
||||
tmp->pCenter += importedvertices[ i ].position;
|
||||
if( false == importedvertices.empty() ) {
|
||||
|
||||
tmp->Piece->vertices.swap( importedvertices );
|
||||
|
||||
glm::dvec3 minpoint( std::numeric_limits<double>::max(), 0.0, std::numeric_limits<double>::max() );
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1559,11 +1599,6 @@ void TGround::FirstInit()
|
||||
}
|
||||
else {
|
||||
// dodajemy do kwadratu kilometrowego
|
||||
// override visibility ranges, to ensure the content is drawn from far enough
|
||||
// TODO: subclass NodeAdd() for the ground cell and specialize it, instead of this
|
||||
// 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 );
|
||||
}
|
||||
}
|
||||
@@ -1632,7 +1667,7 @@ bool TGround::Init(std::string File)
|
||||
switch( LastNode->iType ) {
|
||||
// validate the new node
|
||||
case GL_TRIANGLES: {
|
||||
if( LastNode->Vertices == nullptr ) {
|
||||
if( true == LastNode->Piece->vertices.empty() ) {
|
||||
SafeDelete( LastNode );
|
||||
}
|
||||
break;
|
||||
@@ -1692,7 +1727,7 @@ bool TGround::Init(std::string File)
|
||||
}
|
||||
else
|
||||
{
|
||||
Error("Scene parse error near " + token);
|
||||
ErrorLog("Scene parsing error in file \"" + parser.Name() + "\", unexpected token \"" + token + "\"");
|
||||
// break;
|
||||
}
|
||||
}
|
||||
@@ -1722,20 +1757,21 @@ bool TGround::Init(std::string File)
|
||||
fTrainSetVel, 0, NULL);
|
||||
}
|
||||
}
|
||||
if (LastNode) // ostatni wczytany obiekt
|
||||
if (LastNode->iType ==
|
||||
TP_DYNAMIC) // o ile jest pojazdem (na ogół jest, ale kto wie...)
|
||||
if (iTrainSetWehicleNumber ? !TempConnectionType[iTrainSetWehicleNumber - 1] :
|
||||
false) // jeśli ostatni pojazd ma sprzęg 0
|
||||
LastNode->DynamicObject->RaLightsSet(-1, 2 + 32 + 64); // to założymy mu
|
||||
// końcówki blaszane
|
||||
// (jak AI się
|
||||
// odpali, to sobie
|
||||
// poprawi)
|
||||
if( LastNode ) {
|
||||
// ostatni wczytany obiekt
|
||||
if( LastNode->iType == TP_DYNAMIC ) {
|
||||
// o ile jest pojazdem (na ogół jest, ale kto wie...)
|
||||
if( ( iTrainSetWehicleNumber > 0 )
|
||||
&& ( TempConnectionType[ iTrainSetWehicleNumber - 1 ] == 0 ) ) {
|
||||
// jeśli ostatni pojazd ma sprzęg 0 to założymy mu końcówki blaszane
|
||||
// (jak AI się odpali, to sobie poprawi)
|
||||
LastNode->DynamicObject->RaLightsSet( -1, 2 + 32 + 64 );
|
||||
}
|
||||
}
|
||||
}
|
||||
bTrainSet = false;
|
||||
fTrainSetVel = 0;
|
||||
// iTrainSetConnection=0;
|
||||
nTrainSetNode = nTrainSetDriver = NULL;
|
||||
nTrainSetNode = nTrainSetDriver = nullptr;
|
||||
iTrainSetWehicleNumber = 0;
|
||||
}
|
||||
else if (str == "event")
|
||||
|
||||
45
Ground.h
45
Ground.h
@@ -93,15 +93,15 @@ struct TGroundVertex
|
||||
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
|
||||
struct mesh_node {
|
||||
struct piece_node {
|
||||
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;
|
||||
|
||||
@@ -117,9 +117,8 @@ public:
|
||||
TSubModel *smTerrain; // modele terenu (kwadratow kilometrowych)
|
||||
TAnimModel *Model; // model z animacjami
|
||||
TDynamicObject *DynamicObject; // pojazd
|
||||
glm::dvec3 *Points; // punkty dla linii
|
||||
piece_node *Piece; // non-instanced piece of geometry
|
||||
TTrack *pTrack; // trajektoria ruchu
|
||||
TGroundVertex *Vertices; // wierzchołki dla trójkątów
|
||||
TMemCell *MemCell; // komórka pamięci
|
||||
TEventLauncher *EvLaunch; // wyzwalacz zdarzeń
|
||||
TTraction *hvTraction; // drut zasilający
|
||||
@@ -128,6 +127,7 @@ public:
|
||||
TGroundNode *nNode; // obiekt renderujący grupowo ma tu wskaźnik na listę obiektów
|
||||
};
|
||||
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
|
||||
// visualization-related data
|
||||
// TODO: wrap these in a struct, when cleaning objects up
|
||||
@@ -139,9 +139,6 @@ public:
|
||||
int iNumPts; // dla linii
|
||||
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
|
||||
texture_handle TextureID; // główna (jedna) tekstura obiektu
|
||||
glm::vec3
|
||||
@@ -152,9 +149,11 @@ public:
|
||||
bool bVisible;
|
||||
|
||||
TGroundNode();
|
||||
TGroundNode(TGroundNodeType t, int n = 0);
|
||||
TGroundNode(TGroundNodeType t);
|
||||
~TGroundNode();
|
||||
/*
|
||||
void Init(int n);
|
||||
*/
|
||||
void InitNormals();
|
||||
/*
|
||||
void Release();
|
||||
@@ -200,7 +199,7 @@ class TSubRect : /*public Resource,*/ public CMesh
|
||||
/*
|
||||
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)
|
||||
TTrack * FindTrack(vector3 *Point, int &iConnection, TTrack *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
|
||||
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
|
||||
void Optimize() {
|
||||
if( pSubRects ) {
|
||||
for( int i = iNumSubRects * iNumSubRects - 1; i >= 0; --i ) {
|
||||
// optymalizacja obiektów w sektorach
|
||||
pSubRects[ i ].Sort();
|
||||
}
|
||||
}
|
||||
};
|
||||
pSubRects[ i ].Sort(); } } };
|
||||
|
||||
static int iFrameNumber; // numer kolejny wyświetlanej klatki
|
||||
TGroundNode *nTerrain { nullptr }; // model terenu z E3D - użyć nRootMesh?
|
||||
@@ -308,8 +309,8 @@ class TGround
|
||||
bool AddToQuery(TEvent *Event, TDynamicObject *Node);
|
||||
bool GetTraction(TDynamicObject *model);
|
||||
bool CheckQuery();
|
||||
TGroundNode * DynamicFindAny(std::string asNameToFind);
|
||||
TGroundNode * DynamicFind(std::string asNameToFind);
|
||||
TGroundNode * DynamicFindAny(std::string const &Name);
|
||||
TGroundNode * DynamicFind(std::string const &Name);
|
||||
void DynamicList(bool all = false);
|
||||
TGroundNode * FindGroundNode(std::string asNameToFind, TGroundNodeType iNodeType);
|
||||
TGroundRect * GetRect(double x, double z)
|
||||
@@ -343,7 +344,9 @@ class TGround
|
||||
|
||||
public:
|
||||
void WyslijEvent(const std::string &e, const std::string &d);
|
||||
/*
|
||||
int iRendered; // ilość renderowanych sektorów, pobierana przy pokazywniu FPS
|
||||
*/
|
||||
void WyslijString(const std::string &t, int n);
|
||||
void WyslijWolny(const std::string &t);
|
||||
void WyslijNamiary(TGroundNode *t);
|
||||
|
||||
54
Model3d.cpp
54
Model3d.cpp
@@ -78,6 +78,23 @@ void TSubModel::NameSet(std::string const &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)
|
||||
{ // 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
|
||||
@@ -315,9 +332,9 @@ int TSubModel::Load( cParser &parser, TModel3d *Model, /*int Pos,*/ bool dynamic
|
||||
}
|
||||
else
|
||||
{ // jeśli tylko nazwa pliku, to dawać bieżącą ścieżkę do tekstur
|
||||
TextureNameSet(texture.c_str());
|
||||
TextureNameSet(texture);
|
||||
if( texture.find_first_of( "/\\" ) == texture.npos ) {
|
||||
texture.insert( 0, Global::asCurrentTexturePath.c_str() );
|
||||
texture.insert( 0, Global::asCurrentTexturePath );
|
||||
}
|
||||
TextureID = GfxRenderer.GetTextureId( texture, szTexturePath );
|
||||
// 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
|
||||
iNumVerts -= 3; // czyli o 3 wierzchołki
|
||||
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) {
|
||||
// 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
|
||||
}
|
||||
}
|
||||
Vertices.resize( iNumVerts ); // in case we had some degenerate triangles along the way
|
||||
/*
|
||||
delete[] wsp;
|
||||
delete[] n;
|
||||
@@ -534,6 +552,7 @@ int TSubModel::Load( cParser &parser, TModel3d *Model, /*int Pos,*/ bool dynamic
|
||||
else if( eType == TP_FREESPOTLIGHT ) {
|
||||
// single light points only have single data point, duh
|
||||
Vertices.emplace_back();
|
||||
iNumVerts = 1;
|
||||
}
|
||||
// Visible=true; //się potem wyłączy w razie potrzeby
|
||||
// iFlags|=0x0200; //wczytano z pliku tekstowego (jest właścicielem tablic)
|
||||
@@ -711,25 +730,20 @@ void TSubModel::InitialRotate(bool doit)
|
||||
{ // jeśli jest jednostkowy transform, to przeliczamy
|
||||
// wierzchołki, a mnożenie podajemy dalej
|
||||
float swapcopy;
|
||||
// if( false == Vertices.empty() ) {
|
||||
/*
|
||||
for( auto &vertex : Vertices ) {
|
||||
*/
|
||||
for( auto &vertex : Vertices ) {
|
||||
vertex.position.x = -vertex.position.x; // zmiana znaku X
|
||||
swapcopy = vertex.position.y; // zamiana Y i Z
|
||||
vertex.position.y = vertex.position.z;
|
||||
vertex.position.z = swapcopy;
|
||||
// wektory normalne również trzeba przekształcić, bo się źle oświetlają
|
||||
if( eType != TP_STARS ) {
|
||||
// gwiazdki mają kolory zamiast normalnych, to // ich wtedy nie ruszamy
|
||||
vertex.normal.x = -vertex.normal.x; // zmiana znaku X
|
||||
swapcopy = vertex.normal.y; // zamiana Y i Z
|
||||
vertex.normal.y = vertex.normal.z;
|
||||
vertex.normal.z = swapcopy;
|
||||
}
|
||||
vertex.position.x = -vertex.position.x; // zmiana znaku X
|
||||
swapcopy = vertex.position.y; // zamiana Y i Z
|
||||
vertex.position.y = vertex.position.z;
|
||||
vertex.position.z = swapcopy;
|
||||
// wektory normalne również trzeba przekształcić, bo się źle oświetlają
|
||||
if( eType != TP_STARS ) {
|
||||
// gwiazdki mają kolory zamiast normalnych, to // ich wtedy nie ruszamy
|
||||
vertex.normal.x = -vertex.normal.x; // zmiana znaku X
|
||||
swapcopy = vertex.normal.y; // zamiana Y i Z
|
||||
vertex.normal.y = vertex.normal.z;
|
||||
vertex.normal.z = swapcopy;
|
||||
}
|
||||
// }
|
||||
}
|
||||
if (Child)
|
||||
Child->InitialRotate(doit); // potomne ewentualnie obrócimy
|
||||
}
|
||||
|
||||
83
Model3d.h
83
Model3d.h
@@ -56,6 +56,7 @@ class TSubModel
|
||||
|
||||
friend class opengl_renderer;
|
||||
friend class TModel3d; // temporary workaround. TODO: clean up class content/hierarchy
|
||||
friend class TDynamicObject; // temporary etc
|
||||
|
||||
private:
|
||||
int iNext{ NULL };
|
||||
@@ -85,47 +86,41 @@ private:
|
||||
float4x4 *fMatrix = nullptr; // pojedyncza precyzja wystarcza
|
||||
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 iTexture{ 0 }; // numer nazwy tekstury, -1 wymienna, 0 brak
|
||||
float fVisible{ 0.0f }; // próg jasności światła do załączenia submodelu
|
||||
float fLight{ -1.0f }; // próg jasności światła do zadziałania selfillum
|
||||
int iTexture { 0 }; // numer nazwy tekstury, -1 wymienna, 0 brak
|
||||
float fVisible { 0.0f }; // próg jasności światła do załączenia submodelu
|
||||
float fLight { -1.0f }; // próg jasności światła do zadziałania selfillum
|
||||
glm::vec4
|
||||
f4Ambient{ 1.0f,1.0f,1.0f,1.0f },
|
||||
f4Diffuse{ 1.0f,1.0f,1.0f,1.0f },
|
||||
f4Specular{ 0.0f,0.0f,0.0f,1.0f },
|
||||
f4Emision{ 1.0f,1.0f,1.0f,1.0f };
|
||||
float fWireSize{ 0.0f }; // nie używane, ale wczytywane
|
||||
float fSquareMaxDist{ 10000.0f * 10000.0f };
|
||||
float fSquareMinDist{ 0.0f };
|
||||
f4Ambient { 1.0f,1.0f,1.0f,1.0f },
|
||||
f4Diffuse { 1.0f,1.0f,1.0f,1.0f },
|
||||
f4Specular { 0.0f,0.0f,0.0f,1.0f },
|
||||
f4Emision { 1.0f,1.0f,1.0f,1.0f };
|
||||
float fWireSize { 0.0f }; // nie używane, ale wczytywane
|
||||
float fSquareMaxDist { 10000.0f * 10000.0f };
|
||||
float fSquareMinDist { 0.0f };
|
||||
// McZapkie-050702: parametry dla swiatla:
|
||||
float fNearAttenStart{ 40.0f };
|
||||
float fNearAttenEnd{ 80.0f };
|
||||
bool bUseNearAtten{ false }; // te 3 zmienne okreslaja rysowanie aureoli wokol zrodla swiatla
|
||||
int iFarAttenDecay{ 0 }; // ta zmienna okresla typ zaniku natezenia swiatla (0:brak, 1,2: potega 1/R)
|
||||
float fFarDecayRadius{ 100.0f }; // normalizacja j.w.
|
||||
float fCosFalloffAngle{ 0.5f }; // cosinus kąta stożka pod którym widać światło
|
||||
float fCosHotspotAngle{ 0.3f }; // cosinus kąta stożka pod którym widać aureolę i zwiększone natężenie światła
|
||||
float fCosViewAngle{ 0.0f }; // cos kata pod jakim sie teraz patrzy
|
||||
float fNearAttenStart { 40.0f };
|
||||
float fNearAttenEnd { 80.0f };
|
||||
bool bUseNearAtten { false }; // te 3 zmienne okreslaja rysowanie aureoli wokol zrodla swiatla
|
||||
int iFarAttenDecay { 0 }; // ta zmienna okresla typ zaniku natezenia swiatla (0:brak, 1,2: potega 1/R)
|
||||
float fFarDecayRadius { 100.0f }; // normalizacja j.w.
|
||||
float fCosFalloffAngle { 0.5f }; // cosinus kąta stożka pod którym widać światło
|
||||
float fCosHotspotAngle { 0.3f }; // cosinus kąta stożka pod którym widać aureolę i zwiększone natężenie światła
|
||||
float fCosViewAngle { 0.0f }; // cos kata pod jakim sie teraz patrzy
|
||||
|
||||
TSubModel *Next{ nullptr };
|
||||
TSubModel *Child{ nullptr };
|
||||
/*
|
||||
intptr_t iVboPtr;
|
||||
*/
|
||||
geometry_handle m_geometry{ NULL, NULL }; // geometry of the submodel
|
||||
texture_handle TextureID{ NULL }; // numer tekstury, -1 wymienna, 0 brak
|
||||
bool bWire{ false }; // nie używane, ale wczytywane
|
||||
/*
|
||||
GLuint uiDisplayList; // roboczy numer listy wyświetlania
|
||||
*/
|
||||
float Opacity{ 1.0f };
|
||||
float f_Angle{ 0.0f };
|
||||
float3 v_RotateAxis{ 0.0f, 0.0f, 0.0f };
|
||||
TSubModel *Next { nullptr };
|
||||
TSubModel *Child { nullptr };
|
||||
geometry_handle m_geometry { NULL, NULL }; // geometry of the submodel
|
||||
texture_handle TextureID { NULL }; // numer tekstury, -1 wymienna, 0 brak
|
||||
bool bWire { false }; // nie używane, ale wczytywane
|
||||
float Opacity { 1.0f };
|
||||
float f_Angle { 0.0f };
|
||||
float3 v_RotateAxis { 0.0f, 0.0f, 0.0f };
|
||||
float3 v_Angles { 0.0f, 0.0f, 0.0f };
|
||||
|
||||
public: // chwilowo
|
||||
float3 v_TransVector{ 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
|
||||
*/
|
||||
@@ -192,18 +187,14 @@ public:
|
||||
int Flags() { return iFlags; };
|
||||
void UnFlagNext() { iFlags &= 0x00FFFFFF; };
|
||||
void ColorsSet( glm::vec3 const &Ambient, glm::vec3 const &Diffuse, glm::vec3 const &Specular );
|
||||
inline float3 Translation1Get()
|
||||
{
|
||||
return fMatrix ? *(fMatrix->TranslationGet()) + v_TransVector : v_TransVector;
|
||||
}
|
||||
inline float3 Translation2Get()
|
||||
{
|
||||
return *(fMatrix->TranslationGet()) + Child->Translation1Get();
|
||||
}
|
||||
int GetTextureId()
|
||||
{
|
||||
return TextureID;
|
||||
}
|
||||
// sets light level (alpha component of illumination color) to specified value
|
||||
void SetLightLevel( float const Level, bool const Includechildren = false, bool const Includesiblings = false );
|
||||
inline float3 Translation1Get() {
|
||||
return fMatrix ? *(fMatrix->TranslationGet()) + v_TransVector : v_TransVector; }
|
||||
inline float3 Translation2Get() {
|
||||
return *(fMatrix->TranslationGet()) + Child->Translation1Get(); }
|
||||
int GetTextureId() {
|
||||
return TextureID; }
|
||||
void ParentMatrix(float4x4 *m);
|
||||
float MaxY( float4x4 const &m );
|
||||
void AdjustDist();
|
||||
|
||||
@@ -457,7 +457,7 @@ void TPythonScreens::init(cParser &parser, TModel3d *model, std::string const &n
|
||||
WriteLog( "Python Screen: submodel " + subModelName + " not found - Ignoring screen" );
|
||||
return; // nie ma takiego sub modelu w danej kabinie pomijamy
|
||||
}
|
||||
int textureId = GfxRenderer.Texture(subModel->GetTextureId()).id;
|
||||
auto textureId = subModel->GetTextureId();
|
||||
if (textureId <= 0)
|
||||
{
|
||||
WriteLog( "Python Screen: invalid texture id " + std::to_string(textureId) + " - Ignoring screen" );
|
||||
|
||||
@@ -817,8 +817,8 @@ texture_manager::bind( texture_handle const Texture ) {
|
||||
::glBindTexture( GL_TEXTURE_2D, texture(Texture).id );
|
||||
m_activetexture = texture(Texture).id;
|
||||
#else
|
||||
if( Texture( Id ).bind() == resource_state::good ) {
|
||||
m_activetexture = Id;
|
||||
if( texture( Texture ).bind() == resource_state::good ) {
|
||||
m_activetexture = Texture;
|
||||
}
|
||||
else {
|
||||
// TODO: bind a special 'error' texture on failure
|
||||
@@ -839,7 +839,7 @@ texture_manager::delete_textures() {
|
||||
for( auto const &texture : m_textures ) {
|
||||
// usunięcie wszyskich tekstur (bez usuwania struktury)
|
||||
if( ( texture.id > 0 )
|
||||
&& ( texture.id != -1 ) ) {
|
||||
&& ( texture.id != -1 ) ) {
|
||||
::glDeleteTextures( 1, &texture.id );
|
||||
}
|
||||
}
|
||||
@@ -876,7 +876,7 @@ texture_manager::info() const {
|
||||
+ std::to_string( readytexturecount )
|
||||
+ " ("
|
||||
+ to_string( readytexturesize / 1024.0f, 2 ) + " mb)"
|
||||
+ " in vram, ";
|
||||
+ " in vram, "
|
||||
#endif
|
||||
+ std::to_string( totaltexturecount )
|
||||
+ " ("
|
||||
|
||||
14
Texture.h
14
Texture.h
@@ -29,8 +29,18 @@ struct opengl_texture {
|
||||
|
||||
// methods
|
||||
void load();
|
||||
resource_state bind();
|
||||
resource_state create();
|
||||
resource_state
|
||||
bind();
|
||||
resource_state
|
||||
create();
|
||||
inline
|
||||
int
|
||||
width() const {
|
||||
return data_width; }
|
||||
inline
|
||||
int
|
||||
height() const {
|
||||
return data_height; }
|
||||
// members
|
||||
GLuint id{ (GLuint)-1 }; // associated GL resource
|
||||
bool has_alpha{ false }; // indicates the texture has alpha channel
|
||||
|
||||
@@ -2156,7 +2156,6 @@ TTrack * TTrack::RaAnimate()
|
||||
|
||||
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 );
|
||||
@@ -2171,7 +2170,6 @@ TTrack * TTrack::RaAnimate()
|
||||
}
|
||||
}
|
||||
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 );
|
||||
|
||||
@@ -5889,9 +5889,8 @@ bool TTrain::Update( double const Deltatime )
|
||||
}
|
||||
case 2: {
|
||||
//światło wewnętrzne zapalone (255 216 176)
|
||||
if( mvOccupied->ConverterFlag ==
|
||||
true ) // jasnosc dla zalaczonej przetwornicy
|
||||
{
|
||||
if( mvOccupied->ConverterFlag == true ) {
|
||||
// jasnosc dla zalaczonej przetwornicy
|
||||
DynamicObject->InteriorLightLevel = 1.0f;
|
||||
}
|
||||
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
|
||||
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 (token == "none");
|
||||
|
||||
@@ -55,7 +55,7 @@ geometry_bank::create( vertex_array &Vertices, unsigned int const 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
|
||||
geometry_handle chunkhandle { 0, static_cast<std::uint32_t>(m_chunks.size()) };
|
||||
// template method
|
||||
// template method implementation
|
||||
create_( chunkhandle );
|
||||
// all done
|
||||
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.insert( std::end( chunk.vertices ), std::begin( Vertices ), std::end( Vertices ) );
|
||||
}
|
||||
// template method
|
||||
// template method implementation
|
||||
replace_( Geometry );
|
||||
// all done
|
||||
return true;
|
||||
@@ -99,10 +99,17 @@ geometry_bank::append( vertex_array &Vertices, geometry_handle const &Geometry )
|
||||
// draws geometry stored in specified chunk
|
||||
void
|
||||
geometry_bank::draw( geometry_handle const &Geometry, unsigned int const Streams ) {
|
||||
// template method
|
||||
// template method implementation
|
||||
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 &
|
||||
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
|
||||
opengl_vbogeometrybank::bind_buffer() {
|
||||
|
||||
@@ -225,6 +239,7 @@ opengl_vbogeometrybank::delete_buffer() {
|
||||
::glDeleteBuffers( 1, &m_buffer );
|
||||
if( m_activebuffer == m_buffer ) {
|
||||
m_activebuffer = NULL;
|
||||
bind_streams( stream::none );
|
||||
}
|
||||
m_buffer = NULL;
|
||||
m_buffercapacity = 0;
|
||||
@@ -314,6 +329,19 @@ opengl_dlgeometrybank::draw_( geometry_handle const &Geometry, unsigned int cons
|
||||
::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
|
||||
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
|
||||
@@ -327,12 +355,37 @@ opengl_dlgeometrybank::delete_list( geometry_handle const &Geometry ) {
|
||||
|
||||
// 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
|
||||
geometrybank_handle
|
||||
geometrybank_manager::create_bank() {
|
||||
|
||||
if( true == Global::bUseVBO ) { m_geometrybanks.emplace_back( std::make_shared<opengl_vbogeometrybank>() ); }
|
||||
else { m_geometrybanks.emplace_back( std::make_shared<opengl_dlgeometrybank>() ); }
|
||||
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>(), 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
|
||||
return geometrybank_handle( m_geometrybanks.size(), 0 );
|
||||
}
|
||||
@@ -341,7 +394,7 @@ geometrybank_manager::create_bank() {
|
||||
geometry_handle
|
||||
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 ); }
|
||||
else { return geometry_handle( 0, 0 ); }
|
||||
@@ -351,14 +404,14 @@ geometrybank_manager::create_chunk( vertex_array &Vertices, geometrybank_handle
|
||||
bool
|
||||
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
|
||||
bool
|
||||
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
|
||||
void
|
||||
@@ -366,12 +419,15 @@ geometrybank_manager::draw( geometry_handle const &Geometry, unsigned int const
|
||||
|
||||
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
|
||||
vertex_array const &
|
||||
geometrybank_manager::vertices( geometry_handle const &Geometry ) const {
|
||||
|
||||
return bank( Geometry )->vertices( Geometry );
|
||||
return bank( Geometry ).first->vertices( Geometry );
|
||||
}
|
||||
|
||||
@@ -102,6 +102,9 @@ public:
|
||||
template <typename Iterator_>
|
||||
void
|
||||
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
|
||||
vertex_array const &
|
||||
vertices( geometry_handle const &Geometry ) const;
|
||||
@@ -142,6 +145,8 @@ private:
|
||||
virtual void replace_( geometry_handle const &Geometry ) = 0;
|
||||
// draw() subclass details
|
||||
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
|
||||
@@ -149,6 +154,8 @@ private:
|
||||
class opengl_vbogeometrybank : public geometry_bank {
|
||||
|
||||
public:
|
||||
// constructors:
|
||||
opengl_vbogeometrybank() = default;
|
||||
// destructor
|
||||
~opengl_vbogeometrybank() {
|
||||
delete_buffer(); }
|
||||
@@ -179,6 +186,9 @@ private:
|
||||
// draw() subclass details
|
||||
void
|
||||
draw_( geometry_handle const &Geometry, unsigned int const Streams );
|
||||
// release () subclass details
|
||||
void
|
||||
release_();
|
||||
void
|
||||
bind_buffer();
|
||||
void
|
||||
@@ -200,7 +210,9 @@ private:
|
||||
class opengl_dlgeometrybank : public geometry_bank {
|
||||
|
||||
public:
|
||||
// methods:
|
||||
// constructors:
|
||||
opengl_dlgeometrybank() = default;
|
||||
// destructor:
|
||||
~opengl_dlgeometrybank() {
|
||||
for( auto &chunkrecord : m_chunkrecords ) {
|
||||
::glDeleteLists( chunkrecord.list, 1 ); } }
|
||||
@@ -224,6 +236,9 @@ private:
|
||||
// draw() subclass details
|
||||
void
|
||||
draw_( geometry_handle const &Geometry, unsigned int const Streams );
|
||||
// release () subclass details
|
||||
void
|
||||
release_();
|
||||
void
|
||||
delete_list( geometry_handle const &Geometry );
|
||||
|
||||
@@ -240,6 +255,8 @@ class geometrybank_manager {
|
||||
|
||||
public:
|
||||
// methods:
|
||||
// performs a resource sweep
|
||||
void update();
|
||||
// creates a new geometry bank. returns: handle to the bank or NULL
|
||||
geometrybank_handle
|
||||
create_bank();
|
||||
@@ -267,23 +284,31 @@ public:
|
||||
|
||||
private:
|
||||
// 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:
|
||||
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
|
||||
inline
|
||||
bool
|
||||
valid( geometry_handle const &Geometry ) {
|
||||
return ( ( Geometry.bank != 0 )
|
||||
&& ( Geometry.bank <= m_geometrybanks.size() ) ); }
|
||||
return ( ( Geometry.bank != 0 )
|
||||
&& ( Geometry.bank <= m_geometrybanks.size() ) ); }
|
||||
inline
|
||||
geometrybank_sequence::value_type &
|
||||
geometrybanktimepointpair_sequence::value_type &
|
||||
bank( geometry_handle const Geometry ) {
|
||||
return m_geometrybanks[ Geometry.bank - 1 ]; }
|
||||
inline
|
||||
geometrybank_sequence::value_type const &
|
||||
geometrybanktimepointpair_sequence::value_type const &
|
||||
bank( geometry_handle const Geometry ) const {
|
||||
return m_geometrybanks[ Geometry.bank - 1 ]; }
|
||||
|
||||
|
||||
17
parser.cpp
17
parser.cpp
@@ -201,14 +201,19 @@ std::string cParser::readQuotes(char const Quote) { // read the stream until spe
|
||||
return token;
|
||||
}
|
||||
|
||||
std::string cParser::readComment( std::string const &Break ) { // pobieranie znaków aż do znalezienia znacznika końca
|
||||
std::string token = "";
|
||||
void cParser::skipComment( std::string const &Endmark ) { // pobieranie znaków aż do znalezienia znacznika końca
|
||||
std::string input = "";
|
||||
auto const endmarksize = Endmark.size();
|
||||
while( mStream->peek() != EOF ) { // o ile nie koniec pliku
|
||||
token += mStream->get(); // pobranie znaku
|
||||
if( token.rfind( Break ) != std::string::npos ) // szukanie znacznika końca
|
||||
input += mStream->get(); // pobranie znaku
|
||||
if( input.find( Endmark ) != std::string::npos ) // szukanie znacznika końca
|
||||
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 ) {
|
||||
@@ -228,7 +233,7 @@ bool cParser::trimComments(std::string &String)
|
||||
{
|
||||
if (String.rfind((*cmIt).first) != std::string::npos)
|
||||
{
|
||||
readComment((*cmIt).second);
|
||||
skipComment((*cmIt).second);
|
||||
String.resize(String.rfind((*cmIt).first));
|
||||
return true;
|
||||
}
|
||||
|
||||
2
parser.h
2
parser.h
@@ -92,7 +92,7 @@ class cParser //: public std::stringstream
|
||||
// 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 ;" );
|
||||
void skipComment( std::string const &Endmark );
|
||||
bool findQuotes( std::string &String );
|
||||
bool trimComments( std::string &String );
|
||||
std::size_t count();
|
||||
|
||||
65
renderer.cpp
65
renderer.cpp
@@ -157,6 +157,7 @@ opengl_renderer::Render() {
|
||||
// frustum tests are performed in 'world space' but after we set up frustum
|
||||
// we no longer need camera translation, only rotation
|
||||
::glMultMatrixd( glm::value_ptr( glm::dmat4( glm::dmat3( worldcamera ))));
|
||||
|
||||
Render( &World.Environment );
|
||||
Render( &World.Ground );
|
||||
|
||||
@@ -538,19 +539,26 @@ opengl_renderer::Render( TGroundNode *Node ) {
|
||||
}
|
||||
|
||||
case GL_LINES: {
|
||||
if( ( Node->m_geometry == NULL )
|
||||
if( ( Node->Piece->geometry == NULL )
|
||||
|| ( Node->fLineThickness > 0.0 ) ) {
|
||||
return false;
|
||||
}
|
||||
// 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(
|
||||
glm::value_ptr(
|
||||
glm::vec4(
|
||||
Node->Diffuse * glm::make_vec3( Global::DayLight.ambient ),
|
||||
std::min(
|
||||
1.0,
|
||||
1000.0 * Node->fLineThickness / ( distancesquared + 1.0 ) ) ) ) );
|
||||
Node->Diffuse * glm::make_vec3( Global::DayLight.ambient ), // w zaleznosci od koloru swiatla
|
||||
1.0 ) ) ); // if the thickness is defined negative, lines are always drawn opaque
|
||||
auto const linewidth = clamp( 0.5 * linealpha + Node->fLineThickness * Node->m_radius / 1000.0, 1.0, 32.0 );
|
||||
if( linewidth > 1.0 ) {
|
||||
::glLineWidth( static_cast<float>( linewidth ) );
|
||||
}
|
||||
|
||||
GfxRenderer.Bind( 0 );
|
||||
|
||||
@@ -559,16 +567,18 @@ opengl_renderer::Render( TGroundNode *Node ) {
|
||||
::glTranslated( originoffset.x, originoffset.y, originoffset.z );
|
||||
|
||||
// render
|
||||
m_geometry.draw( Node->m_geometry );
|
||||
m_geometry.draw( Node->Piece->geometry );
|
||||
|
||||
// post-render cleanup
|
||||
::glPopMatrix();
|
||||
|
||||
if( linewidth > 1.0 ) { ::glLineWidth( 1.0f ); }
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
case GL_TRIANGLES: {
|
||||
if( ( Node->m_geometry == NULL )
|
||||
if( ( Node->Piece->geometry == NULL )
|
||||
|| ( ( Node->iFlags & 0x10 ) == 0 ) ) {
|
||||
return false;
|
||||
}
|
||||
@@ -582,7 +592,7 @@ opengl_renderer::Render( TGroundNode *Node ) {
|
||||
::glTranslated( originoffset.x, originoffset.y, originoffset.z );
|
||||
|
||||
// render
|
||||
m_geometry.draw( Node->m_geometry );
|
||||
m_geometry.draw( Node->Piece->geometry );
|
||||
|
||||
// post-render cleanup
|
||||
::glPopMatrix();
|
||||
@@ -750,7 +760,7 @@ opengl_renderer::Render( TSubModel *Submodel ) {
|
||||
// ...luminance
|
||||
if( Global::fLuminance < Submodel->fLight ) {
|
||||
// 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
|
||||
@@ -772,7 +782,7 @@ opengl_renderer::Render( TSubModel *Submodel ) {
|
||||
|
||||
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
|
||||
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
|
||||
@@ -946,7 +956,7 @@ opengl_renderer::Render_Alpha( TGroundNode *Node ) {
|
||||
}
|
||||
float const linealpha = static_cast<float>(
|
||||
std::min(
|
||||
1.2,
|
||||
1.25,
|
||||
5000 * Node->hvTraction->WireThickness / ( distancesquared + 1.0 ) ) ); // zbyt grube nie są dobre
|
||||
::glLineWidth( linealpha );
|
||||
// McZapkie-261102: kolor zalezy od materialu i zasniedzenia
|
||||
@@ -982,17 +992,23 @@ opengl_renderer::Render_Alpha( TGroundNode *Node ) {
|
||||
}
|
||||
|
||||
case GL_LINES: {
|
||||
if( ( Node->m_geometry == NULL )
|
||||
if( ( Node->Piece->geometry == NULL )
|
||||
|| ( Node->fLineThickness < 0.0 ) ) {
|
||||
return false;
|
||||
}
|
||||
// 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(
|
||||
glm::value_ptr(
|
||||
glm::vec4(
|
||||
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 ) {
|
||||
::glLineWidth( static_cast<float>(linewidth) );
|
||||
}
|
||||
@@ -1004,20 +1020,18 @@ opengl_renderer::Render_Alpha( TGroundNode *Node ) {
|
||||
::glTranslated( originoffset.x, originoffset.y, originoffset.z );
|
||||
|
||||
// render
|
||||
m_geometry.draw( Node->m_geometry );
|
||||
m_geometry.draw( Node->Piece->geometry );
|
||||
|
||||
// post-render cleanup
|
||||
if( linewidth > 1.0 ) {
|
||||
::glLineWidth( 1.0f );
|
||||
}
|
||||
|
||||
::glPopMatrix();
|
||||
|
||||
if( linewidth > 1.0 ) { ::glLineWidth( 1.0f ); }
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
case GL_TRIANGLES: {
|
||||
if( ( Node->m_geometry == NULL )
|
||||
if( ( Node->Piece->geometry == NULL )
|
||||
|| ( ( Node->iFlags & 0x20 ) == 0 ) ) {
|
||||
return false;
|
||||
}
|
||||
@@ -1031,7 +1045,7 @@ opengl_renderer::Render_Alpha( TGroundNode *Node ) {
|
||||
::glTranslated( originoffset.x, originoffset.y, originoffset.z );
|
||||
|
||||
// render
|
||||
m_geometry.draw( Node->m_geometry );
|
||||
m_geometry.draw( Node->Piece->geometry );
|
||||
|
||||
// post-render cleanup
|
||||
::glPopMatrix();
|
||||
@@ -1188,7 +1202,7 @@ opengl_renderer::Render_Alpha( TSubModel *Submodel ) {
|
||||
// ...luminance
|
||||
if( Global::fLuminance < Submodel->fLight ) {
|
||||
// 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
|
||||
@@ -1311,7 +1325,7 @@ opengl_renderer::Update ( double const Deltatime ) {
|
||||
else if( framerate > 60.0 ) { targetsegments = 225; targetfactor = 1.5f; }
|
||||
else if( framerate > 30.0 ) { targetsegments = 90; targetfactor = Global::ScreenHeight / 768.0f; }
|
||||
else { targetsegments = 9; targetfactor = Global::ScreenHeight / 768.0f * 0.75f; }
|
||||
|
||||
/*
|
||||
if( targetsegments > Global::iSegmentsRendered ) {
|
||||
|
||||
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 );
|
||||
}
|
||||
*/
|
||||
if( targetfactor > Global::fDistanceFactor ) {
|
||||
|
||||
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
|
||||
m_geometry.update();
|
||||
|
||||
if( true == DebugModeFlag ) {
|
||||
m_debuginfo = m_textures.info();
|
||||
}
|
||||
|
||||
22
uilayer.cpp
22
uilayer.cpp
@@ -164,12 +164,22 @@ void
|
||||
ui_layer::render_background() {
|
||||
|
||||
if( m_background == 0 ) return;
|
||||
|
||||
// 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
|
||||
|
||||
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
|
||||
@@ -200,7 +210,11 @@ ui_layer::quad( float4 const &Coordinates, float4 const &Color ) {
|
||||
Global::iWindowHeight / 768.0 :
|
||||
Global::iWindowHeight / 768.0 * screenratio / ( 4.0f / 3.0f ) );
|
||||
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);
|
||||
|
||||
glBegin( GL_TRIANGLE_STRIP );
|
||||
|
||||
Reference in New Issue
Block a user