mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-07-22 22:09:19 +02:00
Merge branch 'tmj-dev' into dev
This commit is contained in:
@@ -574,16 +574,17 @@ void TAnimModel::RaPrepare()
|
||||
bool state; // stan światła
|
||||
for (int i = 0; i < iNumLights; ++i)
|
||||
{
|
||||
switch (lsLights[i])
|
||||
auto const lightmode { static_cast<int>( lsLights[ i ] ) };
|
||||
switch (lightmode)
|
||||
{
|
||||
case ls_Blink: // migotanie
|
||||
state = fBlinkTimer < fOnTime;
|
||||
break;
|
||||
case ls_Dark: // zapalone, gdy ciemno
|
||||
state = Global::fLuminance <= fDark;
|
||||
state = Global::fLuminance <= ( lsLights[i] - 3.0 );
|
||||
break;
|
||||
default: // zapalony albo zgaszony
|
||||
state = (lsLights[i] == ls_On);
|
||||
state = (lightmode == ls_On);
|
||||
}
|
||||
if (LightsOn[i])
|
||||
LightsOn[i]->iVisible = state;
|
||||
@@ -755,12 +756,12 @@ void TAnimModel::AnimationVND(void *pData, double a, double b, double c, double
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void TAnimModel::LightSet(int n, float v)
|
||||
void TAnimModel::LightSet(int const n, float const v)
|
||||
{ // ustawienie światła (n) na wartość (v)
|
||||
if (n >= iMaxNumLights)
|
||||
return; // przekroczony zakres
|
||||
lsLights[ n ] = TLightState( static_cast<int>( v ) );
|
||||
switch( lsLights[ n ] ) {
|
||||
lsLights[ n ] = v;
|
||||
switch( static_cast<int>( lsLights[ n ] ) ) {
|
||||
// interpretacja ułamka zależnie od typu
|
||||
case ls_Off: {
|
||||
// ustalenie czasu migotania, t<1s (f>1Hz), np. 0.1 => t=0.1 (f=10Hz)
|
||||
@@ -776,8 +777,10 @@ void TAnimModel::LightSet(int n, float v)
|
||||
}
|
||||
case ls_Dark: {
|
||||
// zapalenie świateł zależne od oświetlenia scenerii
|
||||
if( v > 3.0 ) { fDark = v - 3.0; } // ustawienie indywidualnego progu zapalania
|
||||
else { fDark = DefaultDarkThresholdLevel; } // standardowy próg zaplania
|
||||
if( v == 3.0 ) {
|
||||
// standardowy próg zaplania
|
||||
lsLights[ n ] = 3.0 + DefaultDarkThresholdLevel;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,7 +139,7 @@ public:
|
||||
vAngle.x = Angles.x;
|
||||
vAngle.y = Angles.y;
|
||||
vAngle.z = Angles.z; };
|
||||
void LightSet( int n, float v );
|
||||
void LightSet( int const n, float const v );
|
||||
void AnimationVND( void *pData, double a, double b, double c, double d );
|
||||
bool TerrainLoaded();
|
||||
int TerrainCount();
|
||||
@@ -178,8 +178,8 @@ private:
|
||||
|
||||
std::string asText; // tekst dla wyświetlacza znakowego
|
||||
TAnimAdvanced *pAdvanced { nullptr };
|
||||
TLightState lsLights[ iMaxNumLights ];
|
||||
float fDark { DefaultDarkThresholdLevel }; // poziom zapalanie światła (powinno być chyba powiązane z danym światłem?)
|
||||
float lsLights[ iMaxNumLights ];
|
||||
// float fDark { DefaultDarkThresholdLevel }; // poziom zapalanie światła (powinno być chyba powiązane z danym światłem?)
|
||||
float fOnTime { 0.66f };
|
||||
float fOffTime { 0.66f + 0.66f }; // były stałymi, teraz mogą być zmienne dla każdego egzemplarza
|
||||
unsigned int m_framestamp { 0 }; // id of last rendered gfx frame
|
||||
|
||||
104
Button.cpp
104
Button.cpp
@@ -13,6 +13,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "Model3d.h"
|
||||
#include "Console.h"
|
||||
#include "Logs.h"
|
||||
#include "renderer.h"
|
||||
|
||||
void TButton::Clear(int i)
|
||||
{
|
||||
@@ -24,8 +25,8 @@ void TButton::Clear(int i)
|
||||
Update(); // kasowanie bitu Feedback, o ile jakiś ustawiony
|
||||
};
|
||||
|
||||
void TButton::Init(std::string const &asName, TModel3d *pModel, bool bNewOn)
|
||||
{
|
||||
void TButton::Init( std::string const &asName, TModel3d *pModel, bool bNewOn ) {
|
||||
|
||||
if( pModel == nullptr ) { return; }
|
||||
|
||||
pModelOn = pModel->GetFromName( asName + "_on" );
|
||||
@@ -34,7 +35,7 @@ void TButton::Init(std::string const &asName, TModel3d *pModel, bool bNewOn)
|
||||
Update();
|
||||
};
|
||||
|
||||
void TButton::Load(cParser &Parser, TModel3d *pModel1, TModel3d *pModel2) {
|
||||
void TButton::Load( cParser &Parser, TDynamicObject const *Owner, TModel3d *pModel1, TModel3d *pModel2 ) {
|
||||
|
||||
std::string submodelname;
|
||||
|
||||
@@ -46,61 +47,68 @@ void TButton::Load(cParser &Parser, TModel3d *pModel1, TModel3d *pModel2) {
|
||||
else {
|
||||
// new, block type config
|
||||
// TODO: rework the base part into yaml-compatible flow style mapping
|
||||
cParser mappingparser( Parser.getToken<std::string>( false, "}" ) );
|
||||
submodelname = mappingparser.getToken<std::string>( false );
|
||||
// new, variable length section
|
||||
while( true == Load_mapping( mappingparser ) ) {
|
||||
submodelname = Parser.getToken<std::string>( false );
|
||||
while( true == Load_mapping( Parser ) ) {
|
||||
; // all work done by while()
|
||||
}
|
||||
}
|
||||
|
||||
// bind defined sounds with the button owner
|
||||
m_soundfxincrease.owner( Owner );
|
||||
m_soundfxdecrease.owner( Owner );
|
||||
|
||||
if( pModel1 ) {
|
||||
// poszukiwanie submodeli w modelu
|
||||
Init( submodelname, pModel1, false );
|
||||
if( ( pModelOn != nullptr ) || ( pModelOff != nullptr ) ) {
|
||||
// we got our models, bail out
|
||||
return;
|
||||
}
|
||||
}
|
||||
if( pModel2 ) {
|
||||
if( ( pModelOn == nullptr )
|
||||
&& ( pModelOff == nullptr )
|
||||
&& ( pModel2 != nullptr ) ) {
|
||||
// poszukiwanie submodeli w modelu
|
||||
Init( submodelname, pModel2, false );
|
||||
if( ( pModelOn != nullptr ) || ( pModelOff != nullptr ) ) {
|
||||
// we got our models, bail out
|
||||
return;
|
||||
}
|
||||
}
|
||||
// if we failed to locate even one state submodel, cry
|
||||
ErrorLog( "Failed to locate sub-model \"" + submodelname + "\" in 3d model \"" + pModel1->NameGet() + "\"" );
|
||||
};
|
||||
|
||||
if( ( pModelOn == nullptr )
|
||||
&& ( pModelOff == nullptr ) ) {
|
||||
// if we failed to locate even one state submodel, cry
|
||||
ErrorLog( "Bad model: failed to locate sub-model \"" + submodelname + "\" in 3d model \"" + pModel1->NameGet() + "\"" );
|
||||
}
|
||||
|
||||
// pass submodel location to defined sounds
|
||||
auto const offset { model_offset() };
|
||||
m_soundfxincrease.offset( offset );
|
||||
m_soundfxdecrease.offset( offset );
|
||||
}
|
||||
|
||||
bool
|
||||
TButton::Load_mapping( cParser &Input ) {
|
||||
|
||||
if( false == Input.getTokens( 2, true, " ,\n\r\t" ) ) {
|
||||
return false;
|
||||
}
|
||||
// token can be a key or block end
|
||||
std::string const key { Input.getToken<std::string>( true, "\n\r\t ,;" ) };
|
||||
if( ( true == key.empty() ) || ( key == "}" ) ) { return false; }
|
||||
// if not block end then the key is followed by assigned value or sub-block
|
||||
if( key == "soundinc:" ) { m_soundfxincrease.deserialize( Input, sound_type::single ); }
|
||||
else if( key == "sounddec:" ) { m_soundfxdecrease.deserialize( Input, sound_type::single ); }
|
||||
|
||||
std::string key, value;
|
||||
Input
|
||||
>> key
|
||||
>> value;
|
||||
|
||||
if( key == "soundinc:" ) {
|
||||
m_soundfxincrease = (
|
||||
value != "none" ?
|
||||
sound_man->create_sound(value) :
|
||||
nullptr );
|
||||
}
|
||||
else if( key == "sounddec:" ) {
|
||||
m_soundfxdecrease = (
|
||||
value != "none" ?
|
||||
sound_man->create_sound(value) :
|
||||
nullptr );
|
||||
}
|
||||
return true; // return value marks a key: value pair was extracted, nothing about whether it's recognized
|
||||
}
|
||||
|
||||
// returns offset of submodel associated with the button from the model centre
|
||||
glm::vec3
|
||||
TButton::model_offset() const {
|
||||
|
||||
auto const
|
||||
submodel { (
|
||||
pModelOn ? pModelOn :
|
||||
pModelOff ? pModelOff :
|
||||
nullptr ) };
|
||||
|
||||
return (
|
||||
submodel != nullptr ?
|
||||
submodel->offset( 1.f ) :
|
||||
glm::vec3() );
|
||||
}
|
||||
|
||||
void
|
||||
TButton::Turn( bool const State ) {
|
||||
|
||||
@@ -142,20 +150,6 @@ void TButton::AssignBool(bool const *bValue) {
|
||||
|
||||
void
|
||||
TButton::play() {
|
||||
|
||||
play(
|
||||
m_state == true ?
|
||||
m_soundfxincrease :
|
||||
m_soundfxdecrease );
|
||||
}
|
||||
|
||||
void
|
||||
TButton::play( sound* Sound ) {
|
||||
|
||||
if( Sound == nullptr ) { return; }
|
||||
|
||||
Sound->stop();
|
||||
Sound->play();
|
||||
|
||||
return;
|
||||
if( m_state == true ) { m_soundfxincrease.play(); }
|
||||
else { m_soundfxdecrease.play(); }
|
||||
}
|
||||
|
||||
67
Button.h
67
Button.h
@@ -12,18 +12,29 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "Classes.h"
|
||||
#include "sound.h"
|
||||
|
||||
class TButton
|
||||
{ // animacja dwustanowa, włącza jeden z dwóch submodeli (jednego
|
||||
// z nich może nie być)
|
||||
private:
|
||||
TSubModel
|
||||
*pModelOn { nullptr },
|
||||
*pModelOff { nullptr }; // submodel dla stanu załączonego i wyłączonego
|
||||
bool m_state { false };
|
||||
bool const *bData { nullptr };
|
||||
int iFeedbackBit { 0 }; // Ra: bit informacji zwrotnej, do wyprowadzenia na pulpit
|
||||
sound* m_soundfxincrease { nullptr }; // sound associated with increasing control's value
|
||||
sound* m_soundfxdecrease { nullptr }; // sound associated with decreasing control's value
|
||||
// animacja dwustanowa, włącza jeden z dwóch submodeli (jednego z nich może nie być)
|
||||
class TButton {
|
||||
|
||||
public:
|
||||
// methods
|
||||
TButton() = default;
|
||||
void Clear(int const i = -1);
|
||||
inline void FeedbackBitSet( int const i ) {
|
||||
iFeedbackBit = 1 << i; };
|
||||
void Turn( bool const State );
|
||||
inline
|
||||
bool Active() {
|
||||
return ( ( pModelOn != nullptr )
|
||||
|| ( pModelOff != nullptr ) ); }
|
||||
void Update();
|
||||
void Init( std::string const &asName, TModel3d *pModel, bool bNewOn = false );
|
||||
void Load( cParser &Parser, TDynamicObject const *Owner, TModel3d *pModel1, TModel3d *pModel2 = nullptr );
|
||||
void AssignBool(bool const *bValue);
|
||||
// returns offset of submodel associated with the button from the model centre
|
||||
glm::vec3 model_offset() const;
|
||||
inline uint8_t b() { return m_state ? 1 : 0; };
|
||||
|
||||
private:
|
||||
// methods
|
||||
// imports member data pair from the config file
|
||||
bool
|
||||
@@ -31,30 +42,16 @@ class TButton
|
||||
// plays the sound associated with current state
|
||||
void
|
||||
play();
|
||||
// plays specified sound
|
||||
static
|
||||
void
|
||||
play( sound *Sound );
|
||||
|
||||
public:
|
||||
TButton() = default;
|
||||
void Clear(int const i = -1);
|
||||
inline void FeedbackBitSet(int const i) {
|
||||
iFeedbackBit = 1 << i; };
|
||||
void Turn( bool const State );
|
||||
inline void TurnOn() {
|
||||
Turn( true ); };
|
||||
inline void TurnOff() {
|
||||
Turn( false ); };
|
||||
inline void Switch() {
|
||||
Turn( !m_state ); };
|
||||
inline bool Active() {
|
||||
return (pModelOn) || (pModelOff); };
|
||||
inline uint8_t b() { return m_state ? 1 : 0; };
|
||||
void Update();
|
||||
void Init(std::string const &asName, TModel3d *pModel, bool bNewOn = false);
|
||||
void Load(cParser &Parser, TModel3d *pModel1, TModel3d *pModel2 = NULL);
|
||||
void AssignBool(bool const *bValue);
|
||||
// members
|
||||
TSubModel
|
||||
*pModelOn { nullptr },
|
||||
*pModelOff { nullptr }; // submodel dla stanu załączonego i wyłączonego
|
||||
bool m_state { false };
|
||||
bool const *bData { nullptr };
|
||||
int iFeedbackBit { 0 }; // Ra: bit informacji zwrotnej, do wyprowadzenia na pulpit
|
||||
sound_source m_soundfxincrease { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE }; // sound associated with increasing control's value
|
||||
sound_source m_soundfxdecrease { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE }; // sound associated with decreasing control's value
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
@@ -18,7 +18,6 @@ set(SOURCES
|
||||
"TractionPower.cpp"
|
||||
"Train.cpp"
|
||||
"TrkFoll.cpp"
|
||||
"VBO.cpp"
|
||||
"World.cpp"
|
||||
"AirCoupler.cpp"
|
||||
"AnimModel.cpp"
|
||||
@@ -76,6 +75,8 @@ set(SOURCES
|
||||
"scenenode.cpp"
|
||||
"simulation.cpp"
|
||||
"vertex.cpp"
|
||||
"audio.cpp"
|
||||
"audiorenderer.cpp"
|
||||
)
|
||||
|
||||
set (PREFIX "")
|
||||
|
||||
@@ -23,8 +23,7 @@ class TModel3d; //siatka modelu wspólna dla egzemplarzy
|
||||
class TSubModel; // fragment modelu (tu do wyświetlania terenu)
|
||||
class TMemCell; // komórka pamięci
|
||||
class cParser;
|
||||
class sound;
|
||||
class text_sound;
|
||||
class sound_source;
|
||||
class TEventLauncher;
|
||||
class TTraction; // drut
|
||||
class TTractionPowerSource; // zasilanie drutów
|
||||
|
||||
424
Data.h
424
Data.h
@@ -1,424 +0,0 @@
|
||||
/*
|
||||
This Source Code Form is subject to the
|
||||
terms of the Mozilla Public License, v.
|
||||
2.0. If a copy of the MPL was not
|
||||
distributed with this file, You can
|
||||
obtain one at
|
||||
http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#ifndef DataH
|
||||
#define DataH
|
||||
//---------------------------------------------------------------------------
|
||||
// Moduł z danymi
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
struct TDist
|
||||
{
|
||||
int x, y;
|
||||
};
|
||||
const TDist SectorOrder[] = {
|
||||
// tabela współrzędnych sektorów, posortowana wg odległości
|
||||
{0, 0}, // 0.00
|
||||
{1, 0}, // 1.00
|
||||
{0, 1}, // 1.00
|
||||
{1, 1}, // 1.41
|
||||
{2, 0}, // 2.00
|
||||
{0, 2}, // 2.00
|
||||
{2, 1}, // 2.24
|
||||
{1, 2}, // 2.24
|
||||
{2, 2}, // 2.83 - 9 (566m)
|
||||
{3, 0}, // 3.00
|
||||
{0, 3}, // 3.00
|
||||
{3, 1}, // 3.16
|
||||
{1, 3}, // 3.16
|
||||
{3, 2}, // 3.61
|
||||
{2, 3}, // 3.61
|
||||
{4, 0}, // 4.00 - 16 (800m)
|
||||
{0, 4}, // 4.00
|
||||
{4, 1}, // 4.12
|
||||
{1, 4}, // 4.12
|
||||
{3, 3}, // 4.24 - 20
|
||||
{4, 2}, // 4.47
|
||||
{2, 4}, // 4.47
|
||||
{4, 3}, // 5.00
|
||||
{3, 4}, // 5.00
|
||||
{5, 0}, // 5.00 - 25
|
||||
{0, 5}, // 5.00
|
||||
{5, 1}, // 5.10
|
||||
{1, 5}, // 5.10 - 28
|
||||
{5, 2}, // 5.39
|
||||
{2, 5}, // 5.39
|
||||
{4, 4}, // 5.66
|
||||
{5, 3}, // 5.83
|
||||
{3, 5}, // 5.83
|
||||
{6, 0}, // 6.00
|
||||
{0, 6}, // 6.00
|
||||
{6, 1}, // 6.08 - 36
|
||||
{1, 6}, // 6.08
|
||||
{6, 2}, // 6.32
|
||||
{2, 6}, // 6.32
|
||||
{5, 4}, // 6.40
|
||||
{4, 5}, // 6.40
|
||||
{6, 3}, // 6.71
|
||||
{3, 6}, // 6.71
|
||||
{7, 0}, // 7.00
|
||||
{0, 7}, // 7.00
|
||||
{5, 5}, // 7.07
|
||||
{7, 1}, // 7.07
|
||||
{1, 7}, // 7.07
|
||||
{6, 4}, // 7.21
|
||||
{4, 6}, // 7.21
|
||||
{7, 2}, // 7.28
|
||||
{2, 7}, // 7.28
|
||||
{7, 3}, // 7.62
|
||||
{3, 7}, // 7.62
|
||||
{6, 5}, // 7.81
|
||||
{5, 6}, // 7.81
|
||||
{8, 0}, // 8.00
|
||||
{0, 8}, // 8.00
|
||||
{7, 4}, // 8.06
|
||||
{4, 7}, // 8.06
|
||||
{8, 1}, // 8.06
|
||||
{1, 8}, // 8.06
|
||||
{8, 2}, // 8.25
|
||||
{2, 8}, // 8.25
|
||||
{6, 6}, // 8.49
|
||||
{8, 3}, // 8.54
|
||||
{3, 8}, // 8.54
|
||||
{7, 5}, // 8.60
|
||||
{5, 7}, // 8.60
|
||||
{8, 4}, // 8.94
|
||||
{4, 8}, // 8.94
|
||||
{9, 0}, // 9.00
|
||||
{0, 9}, // 9.00
|
||||
{9, 1}, // 9.06
|
||||
{1, 9}, // 9.06
|
||||
{7, 6}, // 9.22
|
||||
{6, 7}, // 9.22
|
||||
{9, 2}, // 9.22
|
||||
{2, 9}, // 9.22
|
||||
{8, 5}, // 9.43
|
||||
{5, 8}, // 9.43
|
||||
{9, 3}, // 9.49
|
||||
{3, 9}, // 9.49
|
||||
{9, 4}, // 9.85
|
||||
{4, 9}, // 9.85
|
||||
{7, 7}, // 9.90
|
||||
{8, 6}, // 10.00
|
||||
{6, 8}, // 10.00
|
||||
{10, 0}, // 10.00
|
||||
{0, 10}, // 10.00
|
||||
{10, 1}, // 10.05
|
||||
{1, 10}, // 10.05
|
||||
{10, 2}, // 10.20
|
||||
{2, 10}, // 10.20
|
||||
{9, 5}, // 10.30
|
||||
{5, 9}, // 10.30
|
||||
{10, 3}, // 10.44
|
||||
{3, 10}, // 10.44
|
||||
{8, 7}, // 10.63
|
||||
{7, 8}, // 10.63
|
||||
{10, 4}, // 10.77
|
||||
{4, 10}, // 10.77
|
||||
{9, 6}, // 10.82
|
||||
{6, 9}, // 10.82
|
||||
{11, 0}, // 11.00
|
||||
{0, 11}, // 11.00
|
||||
{11, 1}, // 11.05
|
||||
{1, 11}, // 11.05
|
||||
{10, 5}, // 11.18
|
||||
{5, 10}, // 11.18
|
||||
{11, 2}, // 11.18
|
||||
{2, 11}, // 11.18
|
||||
{8, 8}, // 11.31
|
||||
{9, 7}, // 11.40
|
||||
{7, 9}, // 11.40
|
||||
{11, 3}, // 11.40
|
||||
{3, 11}, // 11.40
|
||||
{10, 6}, // 11.66
|
||||
{6, 10}, // 11.66
|
||||
{11, 4}, // 11.70
|
||||
{4, 11}, // 11.70
|
||||
{12, 0}, // 12.00
|
||||
{0, 12}, // 12.00
|
||||
{9, 8}, // 12.04
|
||||
{8, 9}, // 12.04
|
||||
{12, 1}, // 12.04
|
||||
{1, 12}, // 12.04
|
||||
{11, 5}, // 12.08
|
||||
{5, 11}, // 12.08
|
||||
{12, 2}, // 12.17
|
||||
{2, 12}, // 12.17
|
||||
{10, 7}, // 12.21
|
||||
{7, 10}, // 12.21
|
||||
{12, 3}, // 12.37
|
||||
{3, 12}, // 12.37
|
||||
{11, 6}, // 12.53
|
||||
{6, 11}, // 12.53
|
||||
{12, 4}, // 12.65
|
||||
{4, 12}, // 12.65
|
||||
{9, 9}, // 12.73
|
||||
{10, 8}, // 12.81
|
||||
{8, 10}, // 12.81
|
||||
{12, 5}, // 13.00
|
||||
{5, 12}, // 13.00
|
||||
{13, 0}, // 13.00
|
||||
{0, 13}, // 13.00
|
||||
{11, 7}, // 13.04
|
||||
{7, 11}, // 13.04
|
||||
{13, 1}, // 13.04
|
||||
{1, 13}, // 13.04
|
||||
{13, 2}, // 13.15
|
||||
{2, 13}, // 13.15
|
||||
{13, 3}, // 13.34
|
||||
{3, 13}, // 13.34
|
||||
{12, 6}, // 13.42
|
||||
{6, 12}, // 13.42
|
||||
{10, 9}, // 13.45
|
||||
{9, 10}, // 13.45
|
||||
{11, 8}, // 13.60
|
||||
{8, 11}, // 13.60
|
||||
{13, 4}, // 13.60
|
||||
{4, 13}, // 13.60
|
||||
{12, 7}, // 13.89
|
||||
{7, 12}, // 13.89
|
||||
{13, 5}, // 13.93
|
||||
{5, 13}, // 13.93
|
||||
{14, 0}, // 14.00
|
||||
{0, 14}, // 14.00
|
||||
{14, 1}, // 14.04
|
||||
{1, 14}, // 14.04
|
||||
{10, 10}, // 14.14
|
||||
{14, 2}, // 14.14
|
||||
{2, 14}, // 14.14
|
||||
{11, 9}, // 14.21
|
||||
{9, 11}, // 14.21
|
||||
{13, 6}, // 14.32
|
||||
{6, 13}, // 14.32
|
||||
{14, 3}, // 14.32
|
||||
{3, 14}, // 14.32
|
||||
{12, 8}, // 14.42
|
||||
{8, 12}, // 14.42
|
||||
{14, 4}, // 14.56
|
||||
{4, 14}, // 14.56
|
||||
{13, 7}, // 14.76
|
||||
{7, 13}, // 14.76
|
||||
{11, 10}, // 14.87
|
||||
{10, 11}, // 14.87
|
||||
{14, 5}, // 14.87
|
||||
{5, 14}, // 14.87
|
||||
{12, 9}, // 15.00
|
||||
{9, 12}, // 15.00
|
||||
{15, 0}, // 15.00
|
||||
{0, 15}, // 15.00
|
||||
{15, 1}, // 15.03
|
||||
{1, 15}, // 15.03
|
||||
{15, 2}, // 15.13
|
||||
{2, 15}, // 15.13
|
||||
{14, 6}, // 15.23
|
||||
{6, 14}, // 15.23
|
||||
{13, 8}, // 15.26
|
||||
{8, 13}, // 15.26
|
||||
{15, 3}, // 15.30
|
||||
{3, 15}, // 15.30
|
||||
{15, 4}, // 15.52
|
||||
{4, 15}, // 15.52
|
||||
{11, 11}, // 15.56
|
||||
{12, 10}, // 15.62
|
||||
{10, 12}, // 15.62
|
||||
{14, 7}, // 15.65
|
||||
{7, 14}, // 15.65
|
||||
{13, 9}, // 15.81
|
||||
{9, 13}, // 15.81
|
||||
{15, 5}, // 15.81
|
||||
{5, 15}, // 15.81
|
||||
{16, 0}, // 16.00
|
||||
{0, 16}, // 16.00
|
||||
{16, 1}, // 16.03
|
||||
{1, 16}, // 16.03
|
||||
{14, 8}, // 16.12
|
||||
{8, 14}, // 16.12
|
||||
{16, 2}, // 16.12
|
||||
{2, 16}, // 16.12
|
||||
{15, 6}, // 16.16
|
||||
{6, 15}, // 16.16
|
||||
{12, 11}, // 16.28
|
||||
{11, 12}, // 16.28
|
||||
{16, 3}, // 16.28
|
||||
{3, 16}, // 16.28
|
||||
{13, 10}, // 16.40
|
||||
{10, 13}, // 16.40
|
||||
{16, 4}, // 16.49
|
||||
{4, 16}, // 16.49
|
||||
{15, 7}, // 16.55
|
||||
{7, 15}, // 16.55
|
||||
{14, 9}, // 16.64
|
||||
{9, 14}, // 16.64
|
||||
{16, 5}, // 16.76
|
||||
{5, 16}, // 16.76
|
||||
{12, 12}, // 16.97
|
||||
{15, 8}, // 17.00
|
||||
{8, 15}, // 17.00
|
||||
{17, 0}, // 17.00
|
||||
{0, 17}, // 17.00
|
||||
{13, 11}, // 17.03
|
||||
{11, 13}, // 17.03
|
||||
{17, 1}, // 17.03
|
||||
{1, 17}, // 17.03
|
||||
{16, 6}, // 17.09
|
||||
{6, 16}, // 17.09
|
||||
{17, 2}, // 17.12
|
||||
{2, 17}, // 17.12
|
||||
{14, 10}, // 17.20
|
||||
{10, 14}, // 17.20
|
||||
{17, 3}, // 17.26
|
||||
{3, 17}, // 17.26
|
||||
{16, 7}, // 17.46
|
||||
{7, 16}, // 17.46
|
||||
{17, 4}, // 17.46
|
||||
{4, 17}, // 17.46
|
||||
{15, 9}, // 17.49
|
||||
{9, 15}, // 17.49
|
||||
{13, 12}, // 17.69
|
||||
{12, 13}, // 17.69
|
||||
{17, 5}, // 17.72
|
||||
{5, 17}, // 17.72
|
||||
{14, 11}, // 17.80
|
||||
{11, 14}, // 17.80
|
||||
{16, 8}, // 17.89
|
||||
{8, 16}, // 17.89
|
||||
{18, 0}, // 18.00
|
||||
{0, 18}, // 18.00
|
||||
{15, 10}, // 18.03
|
||||
{10, 15}, // 18.03
|
||||
{17, 6}, // 18.03
|
||||
{6, 17}, // 18.03
|
||||
{18, 1}, // 18.03
|
||||
{1, 18}, // 18.03
|
||||
{18, 2}, // 18.11
|
||||
{2, 18}, // 18.11
|
||||
{18, 3}, // 18.25
|
||||
{3, 18}, // 18.25
|
||||
{16, 9}, // 18.36
|
||||
{9, 16}, // 18.36
|
||||
{13, 13}, // 18.38
|
||||
{17, 7}, // 18.38
|
||||
{7, 17}, // 18.38
|
||||
{14, 12}, // 18.44
|
||||
{12, 14}, // 18.44
|
||||
{18, 4}, // 18.44
|
||||
{4, 18}, // 18.44
|
||||
{15, 11}, // 18.60
|
||||
{11, 15}, // 18.60
|
||||
{18, 5}, // 18.68
|
||||
{5, 18}, // 18.68
|
||||
{17, 8}, // 18.79
|
||||
{8, 17}, // 18.79
|
||||
{16, 10}, // 18.87
|
||||
{10, 16}, // 18.87
|
||||
{18, 6}, // 18.97
|
||||
{6, 18}, // 18.97
|
||||
{19, 0}, // 19.00
|
||||
{0, 19}, // 19.00
|
||||
{19, 1}, // 19.03
|
||||
{1, 19}, // 19.03
|
||||
{14, 13}, // 19.10
|
||||
{13, 14}, // 19.10
|
||||
{19, 2}, // 19.10
|
||||
{2, 19}, // 19.10
|
||||
{15, 12}, // 19.21
|
||||
{12, 15}, // 19.21
|
||||
{17, 9}, // 19.24
|
||||
{9, 17}, // 19.24
|
||||
{19, 3}, // 19.24
|
||||
{3, 19}, // 19.24
|
||||
{18, 7}, // 19.31
|
||||
{7, 18}, // 19.31
|
||||
{16, 11}, // 19.42
|
||||
{11, 16}, // 19.42
|
||||
{19, 4}, // 19.42
|
||||
{4, 19}, // 19.42
|
||||
{19, 5}, // 19.65
|
||||
{5, 19}, // 19.65
|
||||
{18, 8}, // 19.70
|
||||
{8, 18}, // 19.70
|
||||
{17, 10}, // 19.72
|
||||
{10, 17}, // 19.72
|
||||
{14, 14}, // 19.80
|
||||
{15, 13}, // 19.85
|
||||
{13, 15}, // 19.85
|
||||
{19, 6}, // 19.92
|
||||
{6, 19}, // 19.92
|
||||
{16, 12}, // 20.00
|
||||
{12, 16}, // 20.00
|
||||
{18, 9}, // 20.12
|
||||
{9, 18}, // 20.12
|
||||
{17, 11}, // 20.25
|
||||
{11, 17}, // 20.25
|
||||
{19, 7}, // 20.25
|
||||
{7, 19}, // 20.25
|
||||
{15, 14}, // 20.52
|
||||
{14, 15}, // 20.52
|
||||
{18, 10}, // 20.59
|
||||
{10, 18}, // 20.59
|
||||
{16, 13}, // 20.62
|
||||
{13, 16}, // 20.62
|
||||
{19, 8}, // 20.62
|
||||
{8, 19}, // 20.62
|
||||
{17, 12}, // 20.81
|
||||
{12, 17}, // 20.81
|
||||
{19, 9}, // 21.02
|
||||
{9, 19}, // 21.02
|
||||
{18, 11}, // 21.10
|
||||
{11, 18}, // 21.10
|
||||
{15, 15}, // 21.21
|
||||
{16, 14}, // 21.26
|
||||
{14, 16}, // 21.26
|
||||
{17, 13}, // 21.40
|
||||
{13, 17}, // 21.40
|
||||
{19, 10}, // 21.47
|
||||
{10, 19}, // 21.47
|
||||
{18, 12}, // 21.63
|
||||
{12, 18}, // 21.63
|
||||
{16, 15}, // 21.93
|
||||
{15, 16}, // 21.93
|
||||
{19, 11}, // 21.95
|
||||
{11, 19}, // 21.95
|
||||
{17, 14}, // 22.02
|
||||
{14, 17}, // 22.02
|
||||
{18, 13}, // 22.20
|
||||
{13, 18}, // 22.20
|
||||
{19, 12}, // 22.47
|
||||
{12, 19}, // 22.47
|
||||
{16, 16}, // 22.63
|
||||
{17, 15}, // 22.67
|
||||
{15, 17}, // 22.67
|
||||
{18, 14}, // 22.80
|
||||
{14, 18}, // 22.80
|
||||
{19, 13}, // 23.02
|
||||
{13, 19}, // 23.02
|
||||
{17, 16}, // 23.35
|
||||
{16, 17}, // 23.35
|
||||
{18, 15}, // 23.43
|
||||
{15, 18}, // 23.43
|
||||
{19, 14}, // 23.60
|
||||
{14, 19}, // 23.60
|
||||
{17, 17}, // 24.04
|
||||
{18, 16}, // 24.08
|
||||
{16, 18}, // 24.08
|
||||
{19, 15}, // 24.21
|
||||
{15, 19}, // 24.21
|
||||
{18, 17}, // 24.76
|
||||
{17, 18}, // 24.76
|
||||
{19, 16}, // 24.84
|
||||
{16, 19}, // 24.84
|
||||
{18, 18}, // 25.46
|
||||
{19, 17}, // 25.50
|
||||
{17, 19}, // 25.50
|
||||
{19, 18}, // 26.17
|
||||
{18, 19}, // 26.17
|
||||
{19, 19} // 26.87 - 400 (5374m)
|
||||
};
|
||||
|
||||
#endif
|
||||
144
Driver.cpp
144
Driver.cpp
@@ -998,8 +998,11 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN
|
||||
if (go == cm_Unknown) // jeśli nie było komendy wcześniej
|
||||
go = cm_Ready; // gotów do odjazdu z W4 (semafor może
|
||||
// zatrzymać)
|
||||
if (tsGuardSignal) // jeśli mamy głos kierownika, to odegrać
|
||||
if( ( tsGuardSignal != nullptr )
|
||||
&& ( false == tsGuardSignal->empty() ) ) {
|
||||
// jeśli mamy głos kierownika, to odegrać
|
||||
iDrivigFlags |= moveGuardSignal;
|
||||
}
|
||||
continue; // nie analizować prędkości
|
||||
} // koniec startu z zatrzymania
|
||||
} // koniec obsługi początkowych stacji
|
||||
@@ -1444,7 +1447,7 @@ void TController::TableSort() {
|
||||
return;
|
||||
}
|
||||
TSpeedPos sp_temp = TSpeedPos(); // uzywany do przenoszenia
|
||||
for( std::size_t i = 0; i < ( iLast - 1 ); ++i ) {
|
||||
for( int i = 0; i < ( iLast - 1 ); ++i ) {
|
||||
// pętla tylko do dwóch pozycji od końca bo ostatniej nie modyfikujemy
|
||||
if (sSpeedTable[i].fDist > sSpeedTable[i + 1].fDist)
|
||||
{ // jesli pozycja wcześniejsza jest dalej to źle
|
||||
@@ -1554,7 +1557,6 @@ void TController::CloseLog()
|
||||
|
||||
TController::~TController()
|
||||
{ // wykopanie mechanika z roboty
|
||||
sound_man->destroy_sound(&tsGuardSignal);
|
||||
delete TrainParams;
|
||||
CloseLog();
|
||||
};
|
||||
@@ -2369,19 +2371,25 @@ bool TController::ReleaseEngine()
|
||||
else
|
||||
OK = true;
|
||||
}
|
||||
else if (mvOccupied->ActiveDir == 0)
|
||||
OK = mvControlling->Mains; // tylko to testujemy dla pojazdu człowieka
|
||||
if (AIControllFlag)
|
||||
if (!mvOccupied->DecBrakeLevel()) // tu moze zmieniać na -2, ale to bez znaczenia
|
||||
if (!mvOccupied->IncLocalBrakeLevel(1))
|
||||
{
|
||||
while (DecSpeed(true))
|
||||
else if( mvOccupied->ActiveDir == 0 ) {
|
||||
// tylko to testujemy dla pojazdu człowieka
|
||||
OK = mvControlling->Mains;
|
||||
}
|
||||
|
||||
if( AIControllFlag ) {
|
||||
mvOccupied->BrakeReleaser( 0 );
|
||||
if( !mvOccupied->DecBrakeLevel() ) {
|
||||
// tu moze zmieniać na -2, ale to bez znaczenia
|
||||
if( !mvOccupied->IncLocalBrakeLevel( 1 ) ) {
|
||||
while( DecSpeed( true ) )
|
||||
; // zerowanie nastawników
|
||||
while (mvOccupied->ActiveDir > 0)
|
||||
while( mvOccupied->ActiveDir > 0 )
|
||||
mvOccupied->DirectionBackward();
|
||||
while (mvOccupied->ActiveDir < 0)
|
||||
while( mvOccupied->ActiveDir < 0 )
|
||||
mvOccupied->DirectionForward();
|
||||
}
|
||||
}
|
||||
}
|
||||
OK = OK && (mvOccupied->Vel < 0.01);
|
||||
if (OK)
|
||||
{ // jeśli się zatrzymał
|
||||
@@ -2576,9 +2584,10 @@ bool TController::DecBrake()
|
||||
|
||||
bool TController::IncSpeed()
|
||||
{ // zwiększenie prędkości; zwraca false, jeśli dalej się nie da zwiększać
|
||||
if (tsGuardSignal) // jeśli jest dźwięk kierownika
|
||||
if (tsGuardSignal->is_playing()) // jeśli gada, to nie jedziemy
|
||||
return false;
|
||||
if( ( tsGuardSignal != nullptr )
|
||||
&& ( true == tsGuardSignal->is_playing() ) ) {
|
||||
return false;
|
||||
}
|
||||
bool OK = true;
|
||||
if( ( iDrivigFlags & moveDoorOpened )
|
||||
&& ( VelDesired > 0.0 ) ) { // to prevent door shuffle on stop
|
||||
@@ -2591,7 +2600,7 @@ bool TController::IncSpeed()
|
||||
}
|
||||
if( true == mvOccupied->DepartureSignal ) {
|
||||
// shut off departure warning
|
||||
mvOccupied->DepartureSignal = false;
|
||||
mvOccupied->signal_departure( false );
|
||||
}
|
||||
if (mvControlling->SlippingWheels)
|
||||
return false; // jak poślizg, to nie przyspieszamy
|
||||
@@ -2981,11 +2990,12 @@ void TController::Doors(bool what)
|
||||
if (mvOccupied->DoorOpenCtrl == 1)
|
||||
{ // jeśli drzwi sterowane z kabiny
|
||||
if( AIControllFlag ) {
|
||||
if( mvOccupied->DoorLeftOpened || mvOccupied->DoorRightOpened ) { // AI zamyka drzwi przed odjazdem
|
||||
if( mvOccupied->DoorLeftOpened || mvOccupied->DoorRightOpened ) {
|
||||
// AI zamyka drzwi przed odjazdem
|
||||
if( ( true == mvOccupied->DoorClosureWarning )
|
||||
&& ( false == mvOccupied->DepartureSignal )
|
||||
&& ( true == TestFlag( iDrivigFlags, moveDoorOpened ) ) ) {
|
||||
mvOccupied->DepartureSignal = true; // załącenie bzyczka
|
||||
mvOccupied->signal_departure( true ); // załącenie bzyczka
|
||||
fActionTime = -3.0 - 0.1 * Random( 10 ); // 3-4 second wait
|
||||
}
|
||||
if( fActionTime > -0.5 ) {
|
||||
@@ -3064,7 +3074,6 @@ bool TController::PutCommand( std::string NewCommand, double NewValue1, double N
|
||||
TrainParams = new TTrainParameters(NewCommand); // rozkład jazdy
|
||||
else
|
||||
TrainParams->NewName(NewCommand); // czyści tabelkę przystanków
|
||||
sound_man->destroy_sound(&tsGuardSignal); // wywalenie kierownika
|
||||
if (NewCommand != "none")
|
||||
{
|
||||
if (!TrainParams->LoadTTfile(
|
||||
@@ -3085,22 +3094,18 @@ bool TController::PutCommand( std::string NewCommand, double NewValue1, double N
|
||||
asNextStop = TrainParams->NextStop();
|
||||
iDrivigFlags |= movePrimary; // skoro dostał rozkład, to jest teraz głównym
|
||||
NewCommand = Global::asCurrentSceneryPath + NewCommand + ".wav"; // na razie jeden
|
||||
if (FileExists(NewCommand))
|
||||
{ // wczytanie dźwięku odjazdu podawanego bezpośrenido
|
||||
tsGuardSignal = sound_man->create_text_sound(NewCommand);
|
||||
if (tsGuardSignal)
|
||||
tsGuardSignal->position(pVehicle->GetPosition());
|
||||
// rsGuardSignal->Stop();
|
||||
if (FileExists(NewCommand)) {
|
||||
// wczytanie dźwięku odjazdu podawanego bezpośrenido
|
||||
tsGuardSignal = new sound_source( sound_placement::external, 75.f );
|
||||
tsGuardSignal->deserialize( NewCommand, sound_type::single );
|
||||
iGuardRadio = 0; // nie przez radio
|
||||
}
|
||||
else
|
||||
{
|
||||
NewCommand = NewCommand.insert(NewCommand.find_last_of("."),"radio"); // wstawienie przed kropkč
|
||||
if (FileExists(NewCommand))
|
||||
{ // wczytanie dźwięku odjazdu w wersji radiowej (słychać tylko w kabinie)
|
||||
tsGuardSignal = sound_man->create_text_sound(NewCommand);
|
||||
if (tsGuardSignal)
|
||||
tsGuardSignal->position(pVehicle->GetPosition());
|
||||
else {
|
||||
NewCommand = NewCommand.insert(NewCommand.rfind('.'),"radio"); // wstawienie przed kropkč
|
||||
if (FileExists(NewCommand)) {
|
||||
// wczytanie dźwięku odjazdu w wersji radiowej (słychać tylko w kabinie)
|
||||
tsGuardSignal = new sound_source( sound_placement::internal, 2 * EU07_SOUND_CABCONTROLSCUTOFFRANGE );
|
||||
tsGuardSignal->deserialize( NewCommand, sound_type::single );
|
||||
iGuardRadio = iRadioChannel;
|
||||
}
|
||||
}
|
||||
@@ -4460,45 +4465,48 @@ TController::UpdateSituation(double dt) {
|
||||
}
|
||||
if (VelDesired > 0.0)
|
||||
if( ( ( iDrivigFlags & moveStopHere ) == 0 )
|
||||
|| ( ( SemNextIndex != -1 )
|
||||
&& ( SemNextIndex < sSpeedTable.size() ) // BUG: index can point at non-existing slot. investigate reason(s)
|
||||
&& ( sSpeedTable[SemNextIndex].fVelNext != 0.0 ) ) ) {
|
||||
|| ( ( SemNextIndex != -1 )
|
||||
&& ( SemNextIndex < sSpeedTable.size() ) // BUG: index can point at non-existing slot. investigate reason(s)
|
||||
&& ( sSpeedTable[SemNextIndex].fVelNext != 0.0 ) ) ) {
|
||||
// jeśli można jechać, to odpalić dźwięk kierownika oraz zamknąć drzwi w
|
||||
// składzie, jeśli nie mamy czekać na sygnał też trzeba odpalić
|
||||
if (iDrivigFlags & moveGuardSignal)
|
||||
{ // komunikat od kierownika tu, bo musi być wolna droga i odczekany czas
|
||||
// stania
|
||||
{ // komunikat od kierownika tu, bo musi być wolna droga i odczekany czas stania
|
||||
iDrivigFlags &= ~moveGuardSignal; // tylko raz nadać
|
||||
|
||||
if( iDrivigFlags & moveDoorOpened ) // jeśli drzwi otwarte
|
||||
if( !mvOccupied
|
||||
->DoorOpenCtrl ) // jeśli drzwi niesterowane przez maszynistę
|
||||
Doors( false ); // a EZT zamknie dopiero po odegraniu komunikatu kierownika
|
||||
|
||||
if (tsGuardSignal)
|
||||
{
|
||||
tsGuardSignal->stop();
|
||||
// w zasadzie to powinien mieć flagę, czy jest dźwiękiem radiowym, czy
|
||||
// bezpośrednim
|
||||
// albo trzeba zrobić dwa dźwięki, jeden bezpośredni, słyszalny w
|
||||
// pobliżu, a drugi radiowy, słyszalny w innych lokomotywach
|
||||
// na razie zakładam, że to nie jest dźwięk radiowy, bo trzeba by zrobić
|
||||
// obsługę kanałów radiowych itd.
|
||||
if( !iGuardRadio ) {
|
||||
// jeśli nie przez radio
|
||||
tsGuardSignal->position(pVehicle->GetPosition()).play();
|
||||
}
|
||||
else {
|
||||
// if (iGuardRadio==iRadioChannel) //zgodność kanału
|
||||
// if (!FreeFlyModeFlag) //obserwator musi być w środku pojazdu
|
||||
// (albo może mieć radio przenośne) - kierownik mógłby powtarzać
|
||||
// przy braku reakcji
|
||||
if( SquareMagnitude( pVehicle->GetPosition() - Global::pCameraPosition ) < 2000 * 2000 ) {
|
||||
// w odległości mniejszej niż 2km
|
||||
tsGuardSignal->position(pVehicle->GetPosition()).play();
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
if( ( iDrivigFlags & moveDoorOpened )
|
||||
&& ( false == mvOccupied->DoorOpenCtrl ) ) {
|
||||
// jeśli drzwi otwarte, niesterowane przez maszynistę
|
||||
Doors( false ); // a EZT zamknie dopiero po odegraniu komunikatu kierownika
|
||||
}
|
||||
*/
|
||||
if( tsGuardSignal != nullptr ) {
|
||||
tsGuardSignal->stop();
|
||||
// w zasadzie to powinien mieć flagę, czy jest dźwiękiem radiowym, czy
|
||||
// bezpośrednim
|
||||
// albo trzeba zrobić dwa dźwięki, jeden bezpośredni, słyszalny w
|
||||
// pobliżu, a drugi radiowy, słyszalny w innych lokomotywach
|
||||
// na razie zakładam, że to nie jest dźwięk radiowy, bo trzeba by zrobić
|
||||
// obsługę kanałów radiowych itd.
|
||||
if( iGuardRadio == 0 ) {
|
||||
// jeśli nie przez radio
|
||||
tsGuardSignal->owner( pVehicle );
|
||||
// place virtual conductor some distance away
|
||||
tsGuardSignal->offset( { pVehicle->MoverParameters->Dim.W * -0.75f, 1.7f, std::min( -20.0, -0.2 * fLength ) } );
|
||||
tsGuardSignal->play( sound_flags::exclusive );
|
||||
}
|
||||
else {
|
||||
// if (iGuardRadio==iRadioChannel) //zgodność kanału
|
||||
// if (!FreeFlyModeFlag) //obserwator musi być w środku pojazdu
|
||||
// (albo może mieć radio przenośne) - kierownik mógłby powtarzać
|
||||
// przy braku reakcji
|
||||
// TODO: proper system for sending/receiving radio messages
|
||||
// place the sound in appropriate cab of the manned vehicle
|
||||
tsGuardSignal->owner( pVehicle );
|
||||
tsGuardSignal->offset( { 0.f, 2.f, pVehicle->MoverParameters->Dim.L * 0.4f * ( pVehicle->MoverParameters->ActiveCab < 0 ? -1 : 1 ) } );
|
||||
tsGuardSignal->play( sound_flags::exclusive );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if( mvOccupied->V == 0.0 ) {
|
||||
|
||||
2
Driver.h
2
Driver.h
@@ -242,7 +242,7 @@ private:
|
||||
TTrainParameters *TrainParams = nullptr; // rozkład jazdy zawsze jest, nawet jeśli pusty
|
||||
int iRadioChannel = 1; // numer aktualnego kanału radiowego
|
||||
int iGuardRadio = 0; // numer kanału radiowego kierownika (0, gdy nie używa radia)
|
||||
sound *tsGuardSignal = nullptr; // komunikat od kierownika
|
||||
sound_source *tsGuardSignal { nullptr };
|
||||
public:
|
||||
double AccPreferred = 0.0; // preferowane przyspieszenie (wg psychiki kierującego, zmniejszana przy wykryciu kolizji)
|
||||
double AccDesired = AccPreferred; // przyspieszenie, jakie ma utrzymywać (<0:nie przyspieszaj,<-0.1:hamuj)
|
||||
|
||||
2261
DynObj.cpp
2261
DynObj.cpp
File diff suppressed because it is too large
Load Diff
179
DynObj.h
179
DynObj.h
@@ -17,6 +17,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "Button.h"
|
||||
#include "AirCoupler.h"
|
||||
#include "Texture.h"
|
||||
#include "sound.h"
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//---------------------------------------------------------------------------
|
||||
@@ -257,12 +258,62 @@ private:
|
||||
TSubModel *smWiper; // wycieraczka (poniekąd też wajcha)
|
||||
// Ra: koneic animacji do ogarnięcia
|
||||
|
||||
private:
|
||||
void ABuLittleUpdate(double ObjSqrDist);
|
||||
bool btnOn; // ABu: czy byly uzywane buttony, jesli tak, to po renderingu wylacz
|
||||
// bo ten sam model moze byc jeszcze wykorzystany przez inny obiekt!
|
||||
double ComputeRadius( Math3D::vector3 p1, Math3D::vector3 p2, Math3D::vector3 p3, Math3D::vector3 p4);
|
||||
private:
|
||||
// types
|
||||
struct coupler_sounds {
|
||||
sound_source dsbCouplerAttach { sound_placement::external }; // moved from cab
|
||||
sound_source dsbCouplerDetach { sound_placement::external }; // moved from cab
|
||||
sound_source dsbCouplerStretch { sound_placement::external }; // moved from cab
|
||||
sound_source dsbBufferClamp { sound_placement::external }; // moved from cab
|
||||
};
|
||||
|
||||
struct pantograph_sounds {
|
||||
sound_source sPantUp { sound_placement::external };
|
||||
sound_source sPantDown { sound_placement::external };
|
||||
};
|
||||
|
||||
struct door_sounds {
|
||||
sound_source rsDoorOpen { sound_placement::general, 25.f }; // Ra: przeniesione z kabiny
|
||||
sound_source rsDoorClose { sound_placement::general, 25.f };
|
||||
};
|
||||
|
||||
struct axle_sounds {
|
||||
double distance; // distance to rail joint
|
||||
double offset; // axle offset from centre of the vehicle
|
||||
sound_source clatter; // clatter emitter
|
||||
};
|
||||
|
||||
struct powertrain_sounds {
|
||||
sound_source motor { sound_placement::external }; // generally traction motor
|
||||
double motor_volume { 0.0 }; // MC: pomocnicze zeby gladziej silnik buczal
|
||||
float motor_momentum { 0.f }; // recent change in motor revolutions
|
||||
sound_source motor_relay { sound_placement::engine };
|
||||
sound_source dsbWejscie_na_bezoporow { sound_placement::engine }; // moved from cab
|
||||
sound_source motor_parallel { sound_placement::engine }; // moved from cab
|
||||
sound_source rsWentylator { sound_placement::engine }; // McZapkie-030302
|
||||
sound_source engine { sound_placement::engine }; // generally diesel engine
|
||||
sound_source engine_ignition { sound_placement::engine }; // moved from cab
|
||||
double engine_volume { 0.0 }; // MC: pomocnicze zeby gladziej silnik buczal
|
||||
sound_source engine_revving { sound_placement::engine }; // youBy
|
||||
float engine_revs_last { -1.f }; // helper, cached rpm of the engine
|
||||
float engine_revs_change { 0.f }; // recent change in engine revolutions
|
||||
sound_source engine_turbo { sound_placement::engine };
|
||||
double engine_turbo_pitch { 1.0 };
|
||||
sound_source transmission { sound_placement::engine };
|
||||
sound_source rsEngageSlippery { sound_placement::engine }; // moved from cab
|
||||
|
||||
void position( glm::vec3 const Location );
|
||||
void render( TMoverParameters const &Vehicle, double const Deltatime );
|
||||
};
|
||||
|
||||
// methods
|
||||
void ABuLittleUpdate(double ObjSqrDist);
|
||||
double ComputeRadius( Math3D::vector3 p1, Math3D::vector3 p2, Math3D::vector3 p3, Math3D::vector3 p4);
|
||||
void ABuBogies();
|
||||
void ABuModelRoll();
|
||||
void TurnOff();
|
||||
|
||||
// members
|
||||
TButton btCoupler1; // sprzegi
|
||||
TButton btCoupler2;
|
||||
AirCoupler btCPneumatic1; // sprzegi powietrzne //yB - zmienione z Button na AirCoupler - krzyzyki
|
||||
@@ -296,50 +347,67 @@ private:
|
||||
TButton btHeadSignals23;
|
||||
TButton btMechanik1;
|
||||
TButton btMechanik2;
|
||||
double enginevolume; // MC: pomocnicze zeby gladziej silnik buczal
|
||||
|
||||
int iAxles; // McZapkie: to potem mozna skasowac i zastapic iNumAxles
|
||||
double dRailLength;
|
||||
double dRailPosition[MaxAxles]; // licznik pozycji osi w/m szyny
|
||||
double dWheelsPosition[MaxAxles]; // pozycja osi w/m srodka pojazdu
|
||||
sound* rsStukot[MaxAxles] = { nullptr }; // dzwieki poszczegolnych osi //McZapkie-270202
|
||||
sound* rsSilnik = nullptr; // McZapkie-010302 - silnik
|
||||
sound* rsWentylator = nullptr; // McZapkie-030302
|
||||
sound* rsPisk = nullptr; // McZapkie-260302
|
||||
sound* rsDerailment = nullptr; // McZapkie-051202
|
||||
sound* rsPrzekladnia = nullptr;
|
||||
sound* sHorn1 = nullptr;
|
||||
sound* sHorn2 = nullptr;
|
||||
sound* sCompressor = nullptr; // NBMX wrzesien 2003
|
||||
sound* sConverter = nullptr;
|
||||
sound* sSmallCompressor = nullptr;
|
||||
sound* sDepartureSignal = nullptr;
|
||||
sound* sTurbo = nullptr;
|
||||
sound* sSand = nullptr;
|
||||
sound* sReleaser = nullptr;
|
||||
|
||||
// Winger 010304
|
||||
sound* sPantUp = nullptr;
|
||||
sound* sPantDown = nullptr;
|
||||
sound* rsDoorOpen = nullptr; // Ra: przeniesione z kabiny
|
||||
sound* rsDoorClose = nullptr;
|
||||
// int iAxles; // McZapkie: to potem mozna skasowac i zastapic iNumAxles
|
||||
double dRailLength { 0.0 };
|
||||
std::vector<axle_sounds> m_axlesounds;
|
||||
powertrain_sounds m_powertrainsounds;
|
||||
// engine sounds
|
||||
/*
|
||||
sound_source dsbDieselIgnition { sound_placement::engine }; // moved from cab
|
||||
sound_source rsSilnik { sound_placement::engine };
|
||||
double enginevolume { 0.0 }; // MC: pomocnicze zeby gladziej silnik buczal
|
||||
sound_source m_tractionmotor { sound_placement::external };
|
||||
sound_source dsbRelay { sound_placement::engine };
|
||||
sound_source dsbWejscie_na_bezoporow { sound_placement::engine }; // moved from cab
|
||||
sound_source dsbWejscie_na_drugi_uklad { sound_placement::engine }; // moved from cab
|
||||
sound_source rsPrzekladnia { sound_placement::engine };
|
||||
sound_source rsEngageSlippery { sound_placement::engine }; // moved from cab
|
||||
sound_source rsDieselInc { sound_placement::engine }; // youBy
|
||||
float m_lastenginerevolutions { -1.f }; // helper, cached rpm of the engine
|
||||
float m_enginerevolutionschange { 0.f }; // recent change of engine revolutions
|
||||
sound_source sTurbo { sound_placement::engine };
|
||||
sound_source rsWentylator { sound_placement::engine }; // McZapkie-030302
|
||||
sound_source sConverter { sound_placement::engine };
|
||||
sound_source sCompressor { sound_placement::engine }; // NBMX wrzesien 2003
|
||||
sound_source sSmallCompressor { sound_placement::engine };
|
||||
*/
|
||||
sound_source sConverter { sound_placement::engine };
|
||||
sound_source sCompressor { sound_placement::engine }; // NBMX wrzesien 2003
|
||||
sound_source sSmallCompressor { sound_placement::engine };
|
||||
// braking sounds
|
||||
sound_source dsbPneumaticRelay { sound_placement::external };
|
||||
sound_source rsUnbrake { sound_placement::external }; // yB - odglos luzowania
|
||||
float m_lastbrakepressure { -1.f }; // helper, cached level of pressure in brake cylinder
|
||||
float m_brakepressurechange { 0.f }; // recent change of pressure in brake cylinder
|
||||
sound_source sReleaser { sound_placement::external };
|
||||
sound_source rsSlippery { sound_placement::external, EU07_SOUND_BRAKINGCUTOFFRANGE }; // moved from cab
|
||||
sound_source sSand { sound_placement::external };
|
||||
sound_source rsBrake { sound_placement::external, EU07_SOUND_BRAKINGCUTOFFRANGE }; // moved from cab
|
||||
sound_source sBrakeAcc { sound_placement::external };
|
||||
bool bBrakeAcc;
|
||||
sound_source rsPisk { sound_placement::external, EU07_SOUND_BRAKINGCUTOFFRANGE }; // McZapkie-260302
|
||||
sound_source rsDerailment { sound_placement::external, 250.f }; // McZapkie-051202
|
||||
// moving part and other external sounds
|
||||
std::array<coupler_sounds, 2> m_couplersounds; // always front and rear
|
||||
std::vector<pantograph_sounds> m_pantographsounds; // typically 2 but can be less (or more?)
|
||||
std::vector<door_sounds> m_doorsounds; // can expect symmetrical arrangement, but don't count on it
|
||||
sound_source sDepartureSignal { sound_placement::general };
|
||||
sound_source sHorn1 { sound_placement::external, 5 * EU07_SOUND_RUNNINGNOISECUTOFFRANGE };
|
||||
sound_source sHorn2 { sound_placement::external, 5 * EU07_SOUND_RUNNINGNOISECUTOFFRANGE };
|
||||
sound_source rsOuterNoise { sound_placement::external, EU07_SOUND_RUNNINGNOISECUTOFFRANGE };
|
||||
sound_source rscurve { sound_placement::external, EU07_SOUND_RUNNINGNOISECUTOFFRANGE }; // youBy
|
||||
|
||||
double eng_vol_act;
|
||||
double eng_frq_act;
|
||||
double eng_dfrq;
|
||||
double eng_turbo;
|
||||
void ABuBogies();
|
||||
void ABuModelRoll();
|
||||
Math3D::vector3 modelShake;
|
||||
|
||||
bool renderme; // yB - czy renderowac
|
||||
// sound* sBrakeAcc; //dźwięk przyspieszacza
|
||||
sound* sBrakeAcc = nullptr;
|
||||
bool bBrakeAcc;
|
||||
sound* rsUnbrake = nullptr; // yB - odglos luzowania
|
||||
float ModCamRot;
|
||||
int iInventory[ 2 ] { 0, 0 }; // flagi bitowe posiadanych submodeli (np. świateł)
|
||||
void TurnOff();
|
||||
bool btnOn; // ABu: czy byly uzywane buttony, jesli tak, to po renderingu wylacz
|
||||
// bo ten sam model moze byc jeszcze wykorzystany przez inny obiekt!
|
||||
|
||||
public:
|
||||
int iHornWarning; // numer syreny do użycia po otrzymaniu sygnału do jazdy
|
||||
@@ -375,10 +443,10 @@ private:
|
||||
void SetPneumatic(bool front, bool red);
|
||||
std::string asName;
|
||||
std::string name() const {
|
||||
return this ? asName : std::string(); };
|
||||
return this ?
|
||||
asName :
|
||||
std::string(); };
|
||||
|
||||
sound* rsDiesielInc = nullptr; // youBy
|
||||
sound* rscurve = nullptr; // youBy
|
||||
// std::ofstream PneuLogFile; //zapis parametrow pneumatycznych
|
||||
// youBy - dym
|
||||
// TSmoke Smog;
|
||||
@@ -428,13 +496,17 @@ private:
|
||||
inline Math3D::vector3 RearPosition() {
|
||||
return vCoulpler[iDirection]; };
|
||||
inline Math3D::vector3 AxlePositionGet() {
|
||||
return iAxleFirst ? Axle1.pPosition : Axle0.pPosition; };
|
||||
return iAxleFirst ?
|
||||
Axle1.pPosition :
|
||||
Axle0.pPosition; };
|
||||
inline Math3D::vector3 VectorFront() const {
|
||||
return vFront; };
|
||||
inline Math3D::vector3 VectorUp() {
|
||||
inline Math3D::vector3 VectorUp() const {
|
||||
return vUp; };
|
||||
inline Math3D::vector3 VectorLeft() const {
|
||||
return vLeft; };
|
||||
inline double const * Matrix() const {
|
||||
return mMatrix.readArray(); };
|
||||
inline double * Matrix() {
|
||||
return mMatrix.getArray(); };
|
||||
inline double GetVelocity() {
|
||||
@@ -444,7 +516,9 @@ private:
|
||||
inline double GetWidth() const {
|
||||
return MoverParameters->Dim.W; };
|
||||
inline TTrack * GetTrack() {
|
||||
return (iAxleFirst ? Axle1.GetTrack() : Axle0.GetTrack()); };
|
||||
return (iAxleFirst ?
|
||||
Axle1.GetTrack() :
|
||||
Axle0.GetTrack()); };
|
||||
|
||||
// McZapkie-260202
|
||||
void LoadMMediaFile(std::string BaseDir, std::string TypeName, std::string ReplacableSkin);
|
||||
@@ -453,13 +527,22 @@ private:
|
||||
return (Axle1.GetTrack() == MyTrack ? Axle1.GetDirection() : Axle0.GetDirection()); };
|
||||
// zwraca kierunek pojazdu na torze z aktywną osą
|
||||
inline double RaDirectionGet() {
|
||||
return iAxleFirst ? Axle1.GetDirection() : Axle0.GetDirection(); };
|
||||
return iAxleFirst ?
|
||||
Axle1.GetDirection() :
|
||||
Axle0.GetDirection(); };
|
||||
// zwraca przesunięcie wózka względem Point1 toru z aktywną osią
|
||||
inline double RaTranslationGet() {
|
||||
return iAxleFirst ? Axle1.GetTranslation() : Axle0.GetTranslation(); };
|
||||
return iAxleFirst ?
|
||||
Axle1.GetTranslation() :
|
||||
Axle0.GetTranslation(); };
|
||||
// zwraca tor z aktywną osią
|
||||
inline TTrack * RaTrackGet() {
|
||||
return iAxleFirst ? Axle1.GetTrack() : Axle0.GetTrack(); };
|
||||
return iAxleFirst ?
|
||||
Axle1.GetTrack() :
|
||||
Axle0.GetTrack(); };
|
||||
|
||||
void couple( int const Side );
|
||||
int uncouple( int const Side );
|
||||
void CouplersDettach(double MinDist, int MyScanDir);
|
||||
void RadioStop();
|
||||
void Damage(char flag);
|
||||
|
||||
7
EU07.cpp
7
EU07.cpp
@@ -25,6 +25,9 @@ Stele, firleju, szociu, hunter, ZiomalCl, OLI_EU and others
|
||||
#include "Globals.h"
|
||||
#include "Timer.h"
|
||||
#include "Logs.h"
|
||||
#include "renderer.h"
|
||||
#include "uilayer.h"
|
||||
#include "audiorenderer.h"
|
||||
#include "keyboardinput.h"
|
||||
#include "mouseinput.h"
|
||||
#include "gamepadinput.h"
|
||||
@@ -49,7 +52,6 @@ Stele, firleju, szociu, hunter, ZiomalCl, OLI_EU and others
|
||||
#pragma comment(linker, "/subsystem:windows /ENTRY:mainCRTStartup")
|
||||
#endif
|
||||
|
||||
std::unique_ptr<sound_manager> sound_man;
|
||||
TWorld World;
|
||||
|
||||
namespace input {
|
||||
@@ -346,10 +348,9 @@ int main(int argc, char *argv[])
|
||||
|| (false == UILayer.init(window)))
|
||||
return -1;
|
||||
|
||||
sound_man = std::make_unique<sound_manager>();
|
||||
|
||||
Global::pWorld = &World;
|
||||
|
||||
audio::renderer.init();
|
||||
input::Keyboard.init();
|
||||
input::Mouse.init();
|
||||
input::Gamepad.init();
|
||||
|
||||
25
Event.cpp
25
Event.cpp
@@ -1027,11 +1027,11 @@ event_manager::CheckQuery() {
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
m_workevent->Params[ 9 ].tsTextSound->loop(false).play();
|
||||
m_workevent->Params[ 9 ].tsTextSound->play( sound_flags::exclusive );
|
||||
break;
|
||||
}
|
||||
case -1: {
|
||||
m_workevent->Params[ 9 ].tsTextSound->loop().play();
|
||||
m_workevent->Params[ 9 ].tsTextSound->play( sound_flags::exclusive | sound_flags::looping );
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
@@ -1565,14 +1565,19 @@ event_manager::InitLaunchers() {
|
||||
}
|
||||
}
|
||||
|
||||
launcher->Event1 = (
|
||||
launcher->asEvent1Name != "none" ?
|
||||
simulation::Events.FindEvent( launcher->asEvent1Name ) :
|
||||
nullptr );
|
||||
launcher->Event2 = (
|
||||
launcher->asEvent2Name != "none" ?
|
||||
simulation::Events.FindEvent( launcher->asEvent2Name ) :
|
||||
nullptr );
|
||||
if( launcher->asEvent1Name != "none" ) {
|
||||
launcher->Event1 = simulation::Events.FindEvent( launcher->asEvent1Name );
|
||||
if( launcher->Event1 == nullptr ) {
|
||||
ErrorLog( "Bad scenario: event launcher \"" + launcher->name() + "\" cannot find event \"" + launcher->asEvent1Name + "\"" );
|
||||
}
|
||||
}
|
||||
|
||||
if( launcher->asEvent2Name != "none" ) {
|
||||
launcher->Event2 = simulation::Events.FindEvent( launcher->asEvent2Name );
|
||||
if( launcher->Event2 == nullptr ) {
|
||||
ErrorLog( "Bad scenario: event launcher \"" + launcher->name() + "\" cannot find event \"" + launcher->asEvent2Name + "\"" );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
2
Event.h
2
Event.h
@@ -75,7 +75,7 @@ union TParam
|
||||
bool asBool;
|
||||
double asdouble;
|
||||
int asInt;
|
||||
sound *tsTextSound;
|
||||
sound_source *tsTextSound;
|
||||
char *asText;
|
||||
TCommandType asCommand;
|
||||
TTractionPowerSource *psPower;
|
||||
|
||||
143
Gauge.cpp
143
Gauge.cpp
@@ -19,26 +19,23 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "Model3d.h"
|
||||
#include "Timer.h"
|
||||
#include "Logs.h"
|
||||
#include "World.h"
|
||||
#include "Train.h"
|
||||
#include "renderer.h"
|
||||
|
||||
void TGauge::Init(TSubModel *NewSubModel, TGaugeType eNewType, double fNewScale, double fNewOffset, double fNewFriction, double fNewValue)
|
||||
{ // ustawienie parametrów animacji submodelu
|
||||
if (NewSubModel)
|
||||
{ // warunek na wszelki wypadek, gdyby się submodel nie
|
||||
// podłączył
|
||||
if (NewSubModel) {
|
||||
// warunek na wszelki wypadek, gdyby się submodel nie podłączył
|
||||
fFriction = fNewFriction;
|
||||
fValue = fNewValue;
|
||||
fOffset = fNewOffset;
|
||||
fScale = fNewScale;
|
||||
SubModel = NewSubModel;
|
||||
eType = eNewType;
|
||||
if (eType == gt_Digital)
|
||||
{
|
||||
if (eType == gt_Digital) {
|
||||
|
||||
TSubModel *sm = SubModel->ChildGet();
|
||||
do
|
||||
{ // pętla po submodelach potomnych i obracanie ich o kąt zależy od
|
||||
// cyfry w (fValue)
|
||||
do {
|
||||
// pętla po submodelach potomnych i obracanie ich o kąt zależy od cyfry w (fValue)
|
||||
if (sm->pName.size())
|
||||
{ // musi mieć niepustą nazwę
|
||||
if (sm->pName[0] >= '0')
|
||||
@@ -50,14 +47,17 @@ void TGauge::Init(TSubModel *NewSubModel, TGaugeType eNewType, double fNewScale,
|
||||
}
|
||||
else // a banan może być z optymalizacją?
|
||||
NewSubModel->WillBeAnimated(); // wyłączenie ignowania jedynkowego transformu
|
||||
|
||||
float4x4 mat;
|
||||
SubModel->ParentMatrix(&mat);
|
||||
model_pos = *mat.TranslationGet();
|
||||
// pass submodel location to defined sounds
|
||||
auto const offset { model_offset() };
|
||||
m_soundfxincrease.offset( offset );
|
||||
m_soundfxdecrease.offset( offset );
|
||||
for( auto &soundfxrecord : m_soundfxvalues ) {
|
||||
soundfxrecord.second.offset( offset );
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
bool TGauge::Load(cParser &Parser, TModel3d *md1, TModel3d *md2, double mul) {
|
||||
bool TGauge::Load( cParser &Parser, TDynamicObject const *Owner, TModel3d *md1, TModel3d *md2, double mul ) {
|
||||
|
||||
std::string submodelname, gaugetypename;
|
||||
double scale, offset, friction;
|
||||
@@ -76,24 +76,30 @@ bool TGauge::Load(cParser &Parser, TModel3d *md1, TModel3d *md2, double mul) {
|
||||
else {
|
||||
// new, block type config
|
||||
// TODO: rework the base part into yaml-compatible flow style mapping
|
||||
cParser mappingparser( Parser.getToken<std::string>( false, "}" ) );
|
||||
submodelname = mappingparser.getToken<std::string>( false );
|
||||
gaugetypename = mappingparser.getToken<std::string>( true );
|
||||
mappingparser.getTokens( 3, false );
|
||||
mappingparser
|
||||
submodelname = Parser.getToken<std::string>( false );
|
||||
gaugetypename = Parser.getToken<std::string>( true );
|
||||
Parser.getTokens( 3, false );
|
||||
Parser
|
||||
>> scale
|
||||
>> offset
|
||||
>> friction;
|
||||
// new, variable length section
|
||||
while( true == Load_mapping( mappingparser ) ) {
|
||||
while( true == Load_mapping( Parser ) ) {
|
||||
; // all work done by while()
|
||||
}
|
||||
}
|
||||
|
||||
// bind defined sounds with the button owner
|
||||
m_soundfxincrease.owner( Owner );
|
||||
m_soundfxdecrease.owner( Owner );
|
||||
for( auto &soundfxrecord : m_soundfxvalues ) {
|
||||
soundfxrecord.second.owner( Owner );
|
||||
}
|
||||
|
||||
scale *= mul;
|
||||
TSubModel *submodel = md1->GetFromName( submodelname );
|
||||
TSubModel *submodel = md1->GetFromName( submodelname );
|
||||
if( scale == 0.0 ) {
|
||||
ErrorLog( "Scale of 0.0 defined for sub-model \"" + submodelname + "\" in 3d model \"" + md1->NameGet() + "\". Forcing scale of 1.0 to prevent division by 0" );
|
||||
ErrorLog( "Bad model: scale of 0.0 defined for sub-model \"" + submodelname + "\" in 3d model \"" + md1->NameGet() + "\". Forcing scale of 1.0 to prevent division by 0" );
|
||||
scale = 1.0;
|
||||
}
|
||||
if (submodel) // jeśli nie znaleziony
|
||||
@@ -101,7 +107,7 @@ bool TGauge::Load(cParser &Parser, TModel3d *md1, TModel3d *md2, double mul) {
|
||||
else if (md2) // a jest podany drugi model (np. zewnętrzny)
|
||||
submodel = md2->GetFromName(submodelname); // to może tam będzie, co za różnica gdzie
|
||||
if( submodel == nullptr ) {
|
||||
ErrorLog( "Failed to locate sub-model \"" + submodelname + "\" in 3d model \"" + md1->NameGet() + "\"" );
|
||||
ErrorLog( "Bad model: failed to locate sub-model \"" + submodelname + "\" in 3d model \"" + md1->NameGet() + "\"" );
|
||||
}
|
||||
|
||||
std::map<std::string, TGaugeType> gaugetypes {
|
||||
@@ -122,26 +128,15 @@ bool TGauge::Load(cParser &Parser, TModel3d *md1, TModel3d *md2, double mul) {
|
||||
bool
|
||||
TGauge::Load_mapping( cParser &Input ) {
|
||||
|
||||
if( false == Input.getTokens( 2, true, ", \n\r\t" ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string key, value;
|
||||
Input
|
||||
>> key
|
||||
>> value;
|
||||
|
||||
// token can be a key or block end
|
||||
std::string const key { Input.getToken<std::string>( true, "\n\r\t ,;" ) };
|
||||
if( ( true == key.empty() ) || ( key == "}" ) ) { return false; }
|
||||
// if not block end then the key is followed by assigned value or sub-block
|
||||
if( key == "soundinc:" ) {
|
||||
m_soundfxincrease = (
|
||||
value != "none" ?
|
||||
sound_man->create_sound(value) :
|
||||
nullptr );
|
||||
m_soundfxincrease.deserialize( Input, sound_type::single );
|
||||
}
|
||||
else if( key == "sounddec:" ) {
|
||||
m_soundfxdecrease = (
|
||||
value != "none" ?
|
||||
sound_man->create_sound(value) :
|
||||
nullptr );
|
||||
m_soundfxdecrease.deserialize( Input, sound_type::single );
|
||||
}
|
||||
else if( key.compare( 0, std::min<std::size_t>( key.size(), 5 ), "sound" ) == 0 ) {
|
||||
// sounds assigned to specific gauge values, defined by key soundFoo: where Foo = value
|
||||
@@ -150,9 +145,7 @@ TGauge::Load_mapping( cParser &Input ) {
|
||||
if( indexstart != std::string::npos ) {
|
||||
m_soundfxvalues.emplace(
|
||||
std::stoi( key.substr( indexstart, indexend - indexstart ) ),
|
||||
( value != "none" ?
|
||||
sound_man->create_sound(value) :
|
||||
nullptr ) );
|
||||
sound_source( sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE ).deserialize( Input, sound_type::single ) );
|
||||
}
|
||||
}
|
||||
return true; // return value marks a key: value pair was extracted, nothing about whether it's recognized
|
||||
@@ -182,9 +175,21 @@ void TGauge::DecValue(double fNewDesired)
|
||||
fDesiredValue = 0;
|
||||
};
|
||||
|
||||
void
|
||||
TGauge::UpdateValue( double fNewDesired ) {
|
||||
|
||||
return UpdateValue( fNewDesired, nullptr );
|
||||
}
|
||||
|
||||
void
|
||||
TGauge::UpdateValue( double fNewDesired, sound_source &Fallbacksound ) {
|
||||
|
||||
return UpdateValue( fNewDesired, &Fallbacksound );
|
||||
}
|
||||
|
||||
// ustawienie wartości docelowej. plays provided fallback sound, if no sound was defined in the control itself
|
||||
void
|
||||
TGauge::UpdateValue( double fNewDesired, sound* Fallbacksound ) {
|
||||
TGauge::UpdateValue( double fNewDesired, sound_source *Fallbacksound ) {
|
||||
|
||||
auto const desiredtimes100 = static_cast<int>( std::round( 100.0 * fNewDesired ) );
|
||||
if( static_cast<int>( std::round( 100.0 * ( fDesiredValue - fOffset ) / fScale ) ) == desiredtimes100 ) {
|
||||
@@ -197,21 +202,25 @@ TGauge::UpdateValue( double fNewDesired, sound* Fallbacksound ) {
|
||||
// filter out values other than full integers
|
||||
auto const lookup = m_soundfxvalues.find( desiredtimes100 / 100 );
|
||||
if( lookup != m_soundfxvalues.end() ) {
|
||||
play( lookup->second );
|
||||
lookup->second.play();
|
||||
return;
|
||||
}
|
||||
}
|
||||
// ...and if there isn't any, fall back on the basic set...
|
||||
auto const currentvalue = GetValue();
|
||||
if( ( currentvalue < fNewDesired ) && ( m_soundfxincrease != nullptr ) ) {
|
||||
play( m_soundfxincrease );
|
||||
if( ( currentvalue < fNewDesired )
|
||||
&& ( false == m_soundfxincrease.empty() ) ) {
|
||||
// shift up
|
||||
m_soundfxincrease.play();
|
||||
}
|
||||
else if( ( currentvalue > fNewDesired ) && ( m_soundfxdecrease != nullptr ) ) {
|
||||
play( m_soundfxdecrease );
|
||||
else if( ( currentvalue > fNewDesired )
|
||||
&& ( false == m_soundfxdecrease.empty() ) ) {
|
||||
// shift down
|
||||
m_soundfxdecrease.play();
|
||||
}
|
||||
else if( Fallbacksound != nullptr ) {
|
||||
// ...and if that fails too, try the provided fallback sound from legacy system
|
||||
play( Fallbacksound );
|
||||
Fallbacksound->play();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -288,8 +297,6 @@ void TGauge::Update() {
|
||||
}
|
||||
};
|
||||
|
||||
void TGauge::Render(){};
|
||||
|
||||
void TGauge::AssignFloat(float *fValue)
|
||||
{
|
||||
cDataType = 'f';
|
||||
@@ -321,28 +328,12 @@ void TGauge::UpdateValue()
|
||||
}
|
||||
};
|
||||
|
||||
// todo: ugly approach to getting train translation
|
||||
// returns offset of submodel associated with the button from the model centre
|
||||
glm::vec3
|
||||
TGauge::model_offset() const {
|
||||
|
||||
extern TWorld World;
|
||||
|
||||
void TGauge::play( sound *Sound )
|
||||
{
|
||||
if (!Sound)
|
||||
return;
|
||||
|
||||
Sound->stop();
|
||||
|
||||
if (SubModel && World.train())
|
||||
{
|
||||
if (glm::length(model_pos) > 1.0f)
|
||||
{
|
||||
auto pos = glm::vec3(glm::vec4(model_pos, 1.0f) * glm::inverse((glm::mat4)World.train()->Dynamic()->mMatrix));
|
||||
pos += (glm::vec3)World.train()->Dynamic()->GetPosition();
|
||||
|
||||
Sound->set_mode(sound::anchored).dist(3.0f).position(pos);
|
||||
}
|
||||
}
|
||||
|
||||
Sound->play();
|
||||
return;
|
||||
return (
|
||||
SubModel != nullptr ?
|
||||
SubModel->offset( 1.f ) :
|
||||
glm::vec3() );
|
||||
}
|
||||
|
||||
66
Gauge.h
66
Gauge.h
@@ -24,7 +24,37 @@ enum TGaugeType {
|
||||
// animowany wskaźnik, mogący przyjmować wiele stanów pośrednich
|
||||
class TGauge {
|
||||
|
||||
private:
|
||||
public:
|
||||
// methods
|
||||
TGauge() = default;
|
||||
inline
|
||||
void Clear() { *this = TGauge(); }
|
||||
void Init(TSubModel *NewSubModel, TGaugeType eNewTyp, double fNewScale = 1, double fNewOffset = 0, double fNewFriction = 0, double fNewValue = 0);
|
||||
bool Load(cParser &Parser, TDynamicObject const *Owner, TModel3d *md1, TModel3d *md2 = nullptr, double mul = 1.0);
|
||||
void PermIncValue(double fNewDesired);
|
||||
void IncValue(double fNewDesired);
|
||||
void DecValue(double fNewDesired);
|
||||
void UpdateValue( double fNewDesired );
|
||||
void UpdateValue( double fNewDesired, sound_source &Fallbacksound );
|
||||
void PutValue(double fNewDesired);
|
||||
double GetValue() const;
|
||||
void Update();
|
||||
void AssignFloat(float *fValue);
|
||||
void AssignDouble(double *dValue);
|
||||
void AssignInt(int *iValue);
|
||||
void UpdateValue();
|
||||
// returns offset of submodel associated with the button from the model centre
|
||||
glm::vec3 model_offset() const;
|
||||
// members
|
||||
TSubModel *SubModel; // McZapkie-310302: zeby mozna bylo sprawdzac czy zainicjowany poprawnie
|
||||
|
||||
private:
|
||||
// methods
|
||||
// imports member data pair from the config file
|
||||
bool
|
||||
Load_mapping( cParser &Input );
|
||||
void UpdateValue( double fNewDesired, sound_source *Fallbacksound );
|
||||
// members
|
||||
TGaugeType eType { gt_Unknown }; // typ ruchu
|
||||
double fFriction { 0.0 }; // hamowanie przy zliżaniu się do zadanej wartości
|
||||
double fDesiredValue { 0.0 }; // wartość docelowa
|
||||
@@ -38,38 +68,10 @@ class TGauge {
|
||||
double *dData { nullptr };
|
||||
int *iData;
|
||||
};
|
||||
sound *m_soundfxincrease { nullptr }; // sound associated with increasing control's value
|
||||
sound *m_soundfxdecrease { nullptr }; // sound associated with decreasing control's value
|
||||
std::map<int, sound*> m_soundfxvalues; // sounds associated with specific values
|
||||
// methods
|
||||
// imports member data pair from the config file
|
||||
bool
|
||||
Load_mapping( cParser &Input );
|
||||
// plays specified sound
|
||||
void
|
||||
play( sound* Sound );
|
||||
sound_source m_soundfxincrease { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE }; // sound associated with increasing control's value
|
||||
sound_source m_soundfxdecrease { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE }; // sound associated with decreasing control's value
|
||||
std::map<int, sound_source> m_soundfxvalues; // sounds associated with specific values
|
||||
|
||||
glm::vec3 model_pos;
|
||||
|
||||
public:
|
||||
TGauge() = default;
|
||||
inline
|
||||
void Clear() { *this = TGauge(); }
|
||||
void Init(TSubModel *NewSubModel, TGaugeType eNewTyp, double fNewScale = 1, double fNewOffset = 0, double fNewFriction = 0, double fNewValue = 0);
|
||||
bool Load(cParser &Parser, TModel3d *md1, TModel3d *md2 = nullptr, double mul = 1.0);
|
||||
void PermIncValue(double fNewDesired);
|
||||
void IncValue(double fNewDesired);
|
||||
void DecValue(double fNewDesired);
|
||||
void UpdateValue(double fNewDesired, sound *Fallbacksound = nullptr );
|
||||
void PutValue(double fNewDesired);
|
||||
double GetValue() const;
|
||||
void Update();
|
||||
void Render();
|
||||
void AssignFloat(float *fValue);
|
||||
void AssignDouble(double *dValue);
|
||||
void AssignInt(int *iValue);
|
||||
void UpdateValue();
|
||||
TSubModel *SubModel = nullptr; // McZapkie-310302: zeby mozna bylo sprawdzac czy zainicjowany poprawnie
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
34
Globals.cpp
34
Globals.cpp
@@ -40,6 +40,7 @@ float Global::FieldOfView = 45.0f;
|
||||
GLFWwindow *Global::window;
|
||||
bool Global::shiftState;
|
||||
bool Global::ctrlState;
|
||||
bool Global::CabWindowOpen { false };
|
||||
int Global::iCameraLast = -1;
|
||||
std::string Global::asVersion = "UNKNOWN";
|
||||
bool Global::ControlPicking = false; // indicates controls pick mode is enabled
|
||||
@@ -53,19 +54,15 @@ std::string Global::szTexturesDDS = ".dds"; // lista tekstur od DDS
|
||||
int Global::iPause = 0; // 0x10; // globalna pauza ruchu
|
||||
bool Global::bActive = true; // czy jest aktywnym oknem
|
||||
TWorld *Global::pWorld = NULL;
|
||||
cParser *Global::pParser = NULL;
|
||||
TCamera *Global::pCamera = NULL; // parametry kamery
|
||||
TDynamicObject *Global::pUserDynamic = NULL; // pojazd użytkownika, renderowany bez trzęsienia
|
||||
TTranscripts Global::tranTexts; // obiekt obsługujący stenogramy dźwięków na ekranie
|
||||
float4 Global::UITextColor = float4( 225.0f / 255.0f, 225.0f / 255.0f, 225.0f / 255.0f, 1.0f );
|
||||
|
||||
// parametry scenerii
|
||||
vector3 Global::pCameraPosition;
|
||||
vector3 Global::DebugCameraPosition;
|
||||
double Global::pCameraRotation;
|
||||
double Global::pCameraRotationDeg;
|
||||
std::vector<vector3> Global::FreeCameraInit;
|
||||
std::vector<vector3> Global::FreeCameraInitAngle;
|
||||
// parametry scenerii
|
||||
GLfloat Global::FogColor[] = {0.6f, 0.7f, 0.8f};
|
||||
double Global::fFogStart = 1700;
|
||||
double Global::fFogEnd = 2000;
|
||||
@@ -126,8 +123,6 @@ bool Global::bGlutFont = false; // czy tekst generowany przez GLUT32.DLL
|
||||
int Global::iConvertModels{ 0 }; // temporary override, to prevent generation of .e3d not compatible with old exe
|
||||
int Global::iSlowMotionMask = -1; // maska wyłączanych właściwości dla zwiększenia FPS
|
||||
// bool Global::bTerrainCompact=true; //czy zapisać teren w pliku
|
||||
TAnimModel *Global::pTerrainCompact = NULL; // do zapisania terenu w pliku
|
||||
std::string Global::asTerrainModel = ""; // nazwa obiektu terenu do zapisania w pliku
|
||||
double Global::fFpsAverage = 20.0; // oczekiwana wartosć FPS
|
||||
double Global::fFpsDeviation = 5.0; // odchylenie standardowe FPS
|
||||
double Global::fFpsMin = 30.0; // dolna granica FPS, przy której promień scenerii będzie zmniejszany
|
||||
@@ -136,7 +131,12 @@ bool Global::FullPhysics { true }; // full calculations performed for each simul
|
||||
|
||||
// parametry testowe (do testowania scenerii i obiektów)
|
||||
bool Global::bWireFrame = false;
|
||||
|
||||
// sound renderer
|
||||
bool Global::bSoundEnabled = true;
|
||||
float Global::AudioVolume = 1.5f;
|
||||
std::string Global::AudioRenderer;
|
||||
|
||||
int Global::iWriteLogEnabled = 3; // maska bitowa: 1-zapis do pliku, 2-okienko, 4-nazwy torów
|
||||
bool Global::MultipleLogs{ false };
|
||||
|
||||
@@ -275,6 +275,16 @@ void Global::ConfigParse(cParser &Parser)
|
||||
Parser.getTokens();
|
||||
Parser >> Global::bSoundEnabled;
|
||||
}
|
||||
else if( token == "sound.openal.renderer" ) {
|
||||
// selected device for audio renderer
|
||||
Global::AudioRenderer = Parser.getToken<std::string>( false ); // case-sensitive
|
||||
}
|
||||
else if( token == "sound.volume" ) {
|
||||
// selected device for audio renderer
|
||||
Parser.getTokens();
|
||||
Parser >> Global::AudioVolume;
|
||||
Global::AudioVolume = clamp( Global::AudioVolume, 1.f, 4.f );
|
||||
}
|
||||
// else if (str==AnsiString("renderalpha")) //McZapkie-1312302 - dwuprzebiegowe renderowanie
|
||||
// bRenderAlpha=(GetNextSymbol().LowerCase()==AnsiString("yes"));
|
||||
else if (token == "physicslog")
|
||||
@@ -918,16 +928,6 @@ void Global::SetCameraPosition(vector3 pNewCameraPosition)
|
||||
pCameraPosition = pNewCameraPosition;
|
||||
}
|
||||
|
||||
void Global::SetCameraRotation(double Yaw)
|
||||
{ // ustawienie bezwzględnego kierunku kamery z korekcją do przedziału <-M_PI,M_PI>
|
||||
pCameraRotation = Yaw;
|
||||
while (pCameraRotation < -M_PI)
|
||||
pCameraRotation += 2 * M_PI;
|
||||
while (pCameraRotation > M_PI)
|
||||
pCameraRotation -= 2 * M_PI;
|
||||
pCameraRotationDeg = pCameraRotation * 180.0 / M_PI;
|
||||
}
|
||||
|
||||
void Global::TrainDelete(TDynamicObject *d)
|
||||
{ // usunięcie pojazdu prowadzonego przez użytkownika
|
||||
if (pWorld)
|
||||
|
||||
28
Globals.h
28
Globals.h
@@ -10,10 +10,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
//#include <Windows.h>
|
||||
#include "renderer.h"
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <GL/glew.h>
|
||||
#include "dumb3d.h"
|
||||
|
||||
// definicje klawiszy
|
||||
@@ -113,16 +110,6 @@ const int k_WalkMode = 73;
|
||||
int const k_DimHeadlights = 74;
|
||||
const int MaxKeys = 75;
|
||||
|
||||
// klasy dla wskaźników globalnych
|
||||
class TGround;
|
||||
class TWorld;
|
||||
class TCamera;
|
||||
class TDynamicObject;
|
||||
class TAnimModel; // obiekt terenu
|
||||
class cParser; // nowy (powolny!) parser
|
||||
class TEvent;
|
||||
class sound;
|
||||
|
||||
class TTranscript
|
||||
{ // klasa obsługująca linijkę napisu do dźwięku
|
||||
public:
|
||||
@@ -159,9 +146,7 @@ public:
|
||||
static void InitKeys();
|
||||
inline static Math3D::vector3 GetCameraPosition() { return pCameraPosition; };
|
||||
static void SetCameraPosition(Math3D::vector3 pNewCameraPosition);
|
||||
static void SetCameraRotation(double Yaw);
|
||||
static void TrainDelete(TDynamicObject *d);
|
||||
static bool DoEvents();
|
||||
static std::string Bezogonkow(std::string str, bool _ = false);
|
||||
static double Min0RSpeed(double vel1, double vel2);
|
||||
|
||||
@@ -170,8 +155,6 @@ public:
|
||||
static bool RealisticControlMode; // controls ability to steer the vehicle from outside views
|
||||
static Math3D::vector3 pCameraPosition; // pozycja kamery w świecie
|
||||
static Math3D::vector3 DebugCameraPosition; // pozycja kamery w świecie
|
||||
static double pCameraRotation; // kierunek bezwzględny kamery w świecie: 0=północ, 90°=zachód (-azymut)
|
||||
static double pCameraRotationDeg; // w stopniach, dla animacji billboard
|
||||
static std::vector<Math3D::vector3> FreeCameraInit; // pozycje kamery
|
||||
static std::vector<Math3D::vector3> FreeCameraInitAngle;
|
||||
static int iWindowWidth;
|
||||
@@ -181,7 +164,6 @@ public:
|
||||
static bool VSync;
|
||||
static bool bFreeFly;
|
||||
static bool bWireFrame;
|
||||
static bool bSoundEnabled;
|
||||
// McZapkie-131202
|
||||
static bool bAdjustScreenFreq;
|
||||
static bool bEnableTraction;
|
||||
@@ -229,6 +211,10 @@ public:
|
||||
static bool bSmoothTraction; // wygładzanie drutów
|
||||
static float SplineFidelity; // determines segment size during conversion of splines to geometry
|
||||
static GLfloat FogColor[];
|
||||
// sound renderer variables
|
||||
static bool bSoundEnabled;
|
||||
static float AudioVolume;
|
||||
static std::string AudioRenderer;
|
||||
|
||||
static bool FullPhysics; // full calculations performed for each simulation step
|
||||
static int iSlowMotion;
|
||||
@@ -247,6 +233,7 @@ public:
|
||||
static GLFWwindow *window;
|
||||
static bool shiftState; //m7todo: brzydko
|
||||
static bool ctrlState;
|
||||
static bool CabWindowOpen; // controls sound attenuation between cab and outside
|
||||
static int iCameraLast;
|
||||
static std::string asVersion; // z opisem
|
||||
static bool ControlPicking; // indicates controls pick mode is active
|
||||
@@ -272,16 +259,12 @@ public:
|
||||
static bool bHideConsole; // hunter-271211: ukrywanie konsoli
|
||||
|
||||
static TWorld *pWorld; // wskaźnik na świat do usuwania pojazdów
|
||||
static TAnimModel *pTerrainCompact; // obiekt terenu do ewentualnego zapisania w pliku
|
||||
static std::string asTerrainModel; // nazwa obiektu terenu do zapisania w pliku
|
||||
static bool bRollFix; // czy wykonać przeliczanie przechyłki
|
||||
static cParser *pParser;
|
||||
static double fFpsAverage; // oczekiwana wartosć FPS
|
||||
static double fFpsDeviation; // odchylenie standardowe FPS
|
||||
static double fFpsMin; // dolna granica FPS, przy której promień scenerii będzie zmniejszany
|
||||
static double fFpsMax; // górna granica FPS, przy której promień scenerii będzie zwiększany
|
||||
static TCamera *pCamera; // parametry kamery
|
||||
static TDynamicObject *pUserDynamic; // pojazd użytkownika, renderowany bez trzęsienia
|
||||
static double fCalibrateIn[6][6]; // parametry kalibracyjne wejść z pulpitu
|
||||
static double fCalibrateOut[7][6]; // parametry kalibracyjne wyjść dla pulpitu
|
||||
static double fCalibrateOutMax[7]; // wartości maksymalne wyjść dla pulpitu
|
||||
@@ -293,7 +276,6 @@ public:
|
||||
static float4 UITextColor; // base color of UI text
|
||||
static std::string asLang; // domyślny język - http://tools.ietf.org/html/bcp47
|
||||
static int iHiddenEvents; // czy łączyć eventy z torami poprzez nazwę toru
|
||||
static sound *tsRadioBusy[10]; // zajętość kanałów radiowych (wskaźnik na odgrywany dźwięk)
|
||||
static int iPoKeysPWM[7]; // numery wejść dla PWM
|
||||
|
||||
//randomizacja
|
||||
|
||||
@@ -197,14 +197,15 @@ static int const s_SHPebrake = 64; //hamuje
|
||||
static int const s_CAtest = 128;
|
||||
|
||||
/*dzwieki*/
|
||||
static int const sound_none = 0;
|
||||
static int const sound_loud = 1;
|
||||
static int const sound_couplerstretch = 2;
|
||||
static int const sound_bufferclamp = 4;
|
||||
static int const sound_bufferbump = 8;
|
||||
static int const sound_relay = 16;
|
||||
static int const sound_manyrelay = 32;
|
||||
static int const sound_brakeacc = 64;
|
||||
enum sound {
|
||||
none,
|
||||
loud = 0x1,
|
||||
couplerstretch = 0x2,
|
||||
bufferclash = 0x4,
|
||||
relay = 0x10,
|
||||
parallel = 0x20,
|
||||
pneumatic = 0x40
|
||||
};
|
||||
|
||||
//szczególne typy pojazdów (inna obsługa) dla zmiennej TrainType
|
||||
//zamienione na flagi bitowe, aby szybko wybierać grupę (np. EZT+SZT)
|
||||
@@ -547,18 +548,18 @@ struct TMotorParameters
|
||||
|
||||
struct TSecuritySystem
|
||||
{
|
||||
int SystemType; /*0: brak, 1: czuwak aktywny, 2: SHP/sygnalizacja kabinowa*/
|
||||
double AwareDelay; // czas powtarzania czuwaka
|
||||
int SystemType { 0 }; /*0: brak, 1: czuwak aktywny, 2: SHP/sygnalizacja kabinowa*/
|
||||
double AwareDelay { -1.0 }; // czas powtarzania czuwaka
|
||||
double AwareMinSpeed; // minimalna prędkość załączenia czuwaka, normalnie 10% Vmax
|
||||
double SoundSignalDelay;
|
||||
double EmergencyBrakeDelay;
|
||||
int Status; /*0: wylaczony, 1: wlaczony, 2: czuwak, 4: shp, 8: alarm, 16: hamowanie awaryjne*/
|
||||
double SystemTimer;
|
||||
double SystemSoundCATimer;
|
||||
double SystemSoundSHPTimer;
|
||||
double SystemBrakeCATimer;
|
||||
double SystemBrakeSHPTimer;
|
||||
double SystemBrakeCATestTimer; // hunter-091012
|
||||
double SoundSignalDelay { -1.0 };
|
||||
double EmergencyBrakeDelay { -1.0 };
|
||||
int Status { 0 }; /*0: wylaczony, 1: wlaczony, 2: czuwak, 4: shp, 8: alarm, 16: hamowanie awaryjne*/
|
||||
double SystemTimer { 0.0 };
|
||||
double SystemSoundCATimer { 0.0 };
|
||||
double SystemSoundSHPTimer { 0.0 };
|
||||
double SystemBrakeCATimer { 0.0 };
|
||||
double SystemBrakeSHPTimer { 0.0 };
|
||||
double SystemBrakeCATestTimer { 0.0 }; // hunter-091012
|
||||
int VelocityAllowed;
|
||||
int NextVelocityAllowed; /*predkosc pokazywana przez sygnalizacje kabinowa*/
|
||||
bool RadioStop; // czy jest RadioStop
|
||||
@@ -602,6 +603,8 @@ struct TCoupling {
|
||||
|
||||
power_coupling power_high;
|
||||
power_coupling power_low; // TODO: implement this
|
||||
|
||||
int sounds { 0 }; // sounds emitted by the coupling devices
|
||||
};
|
||||
|
||||
class TMoverParameters
|
||||
@@ -1167,6 +1170,7 @@ public:
|
||||
bool DoorLeft(bool State); //obsluga drzwi lewych
|
||||
bool DoorRight(bool State); //obsluga drzwi prawych
|
||||
bool DoorBlockedFlag(void); //sprawdzenie blokady drzwi
|
||||
bool signal_departure( bool const State, int const Notify = range::consist ); // toggles departure warning
|
||||
|
||||
/* funkcje dla samochodow*/
|
||||
bool ChangeOffsetH(double DeltaOffset);
|
||||
|
||||
@@ -46,7 +46,7 @@ inline long ROUND(float f)
|
||||
return Trunc(f + 0.5f);
|
||||
}
|
||||
|
||||
inline double sqr(double val) // SQR() zle liczylo w current() ...
|
||||
inline double square(double val) // SQR() zle liczylo w current() ...
|
||||
{
|
||||
return val * val;
|
||||
}
|
||||
@@ -224,7 +224,7 @@ double TMoverParameters::Current(double n, double U)
|
||||
// writepaslog("fi ", FloatToStr(MotorParam[SP].fi));
|
||||
Isf = Sign(U1) * MotorParam[SP].Isat;
|
||||
// writepaslog("Isf ", FloatToStr(Isf));
|
||||
Delta = sqr(Isf * Rz + Mn * MotorParam[SP].fi * n - U1) +
|
||||
Delta = square(Isf * Rz + Mn * MotorParam[SP].fi * n - U1) +
|
||||
4.0 * U1 * Isf * Rz; // 105 * 1.67 + Mn * 140.9 * 20.532 - U1
|
||||
// DeltaQ = Isf * Rz + Mn * MotorParam[SP].fi * n - U1 + 4 * U1 * Isf * Rz;
|
||||
// writepaslog("Delta ", FloatToStr(Delta));
|
||||
@@ -1271,7 +1271,7 @@ double TMoverParameters::ComputeMovement(double dt, double dt1, const TTrackShap
|
||||
|
||||
// przyspieszenie normalne
|
||||
if (abs(Shape.R) > 0.01)
|
||||
AccN = sqr(V) / Shape.R + g * Shape.dHrail / TrackW; // Q: zamieniam SQR() na sqr()
|
||||
AccN = square(V) / Shape.R + g * Shape.dHrail / TrackW; // Q: zamieniam SQR() na sqr()
|
||||
else
|
||||
AccN = g * Shape.dHrail / TrackW;
|
||||
|
||||
@@ -1368,11 +1368,14 @@ double TMoverParameters::ComputeMovement(double dt, double dt1, const TTrackShap
|
||||
if (EngineType == ElectricSeriesMotor)
|
||||
|
||||
if (AutoRelayCheck())
|
||||
SetFlag(SoundFlag, sound_relay);
|
||||
SetFlag(SoundFlag, sound::relay);
|
||||
|
||||
if (EngineType == DieselEngine)
|
||||
if (dizel_Update(dt))
|
||||
SetFlag(SoundFlag, sound_relay);
|
||||
if( ( EngineType == DieselEngine )
|
||||
|| ( EngineType == DieselElectric ) ) {
|
||||
if( dizel_Update( dt ) ) {
|
||||
SetFlag( SoundFlag, sound::relay );
|
||||
}
|
||||
}
|
||||
// uklady hamulcowe:
|
||||
if (VeselVolume > 0)
|
||||
Compressor = CompressedVolume / VeselVolume;
|
||||
@@ -1529,7 +1532,7 @@ double TMoverParameters::FastComputeMovement(double dt, const TTrackShape &Shape
|
||||
|
||||
if (EngineType == DieselEngine)
|
||||
if (dizel_Update(dt))
|
||||
SetFlag(SoundFlag, sound_relay);
|
||||
SetFlag(SoundFlag, sound::relay);
|
||||
// uklady hamulcowe:
|
||||
if (VeselVolume > 0)
|
||||
Compressor = CompressedVolume / VeselVolume;
|
||||
@@ -1702,7 +1705,7 @@ bool TMoverParameters::IncMainCtrl(int CtrlSpeed)
|
||||
if( RList[ MainCtrlPos ].Bn > 1 ) {
|
||||
if( true == MaxCurrentSwitch( false )) {
|
||||
// wylaczanie wysokiego rozruchu
|
||||
SetFlag( SoundFlag, sound_relay );
|
||||
SetFlag( SoundFlag, sound::relay );
|
||||
} // Q TODO:
|
||||
// if (EngineType=ElectricSeriesMotor) and (MainCtrlPos=1)
|
||||
// then
|
||||
@@ -2374,44 +2377,52 @@ bool TMoverParameters::MainSwitch( bool const State, int const Notify )
|
||||
{
|
||||
bool MS = false; // Ra: przeniesione z końca
|
||||
|
||||
if ((Mains != State) && (MainCtrlPosNo > 0))
|
||||
{
|
||||
if ((State == false) ||
|
||||
(((ScndCtrlPos == 0)||(EngineType == ElectricInductionMotor)) && ((ConvOvldFlag == false) || (TrainType == dt_EZT)) &&
|
||||
(LastSwitchingTime > CtrlDelay) && !TestFlag(DamageFlag, dtrain_out) &&
|
||||
!TestFlag(EngDmgFlag, 1)))
|
||||
{
|
||||
if( Mains ) {
|
||||
if( ( Mains != State )
|
||||
&& ( MainCtrlPosNo > 0 ) ) {
|
||||
|
||||
if( ( false == State )
|
||||
|| ( ( ( ScndCtrlPos == 0 ) || ( EngineType == ElectricInductionMotor ) )
|
||||
&& ( ( ConvOvldFlag == false ) || ( TrainType == dt_EZT ) )
|
||||
&& ( LastSwitchingTime > CtrlDelay )
|
||||
&& ( false == TestFlag( DamageFlag, dtrain_out ) )
|
||||
&& ( false == TestFlag( EngDmgFlag, 1 ) ) ) ) {
|
||||
|
||||
if( true == Mains ) {
|
||||
// jeśli był załączony
|
||||
if( Notify != range::local ) {
|
||||
// wysłanie wyłączenia do pozostałych?
|
||||
SendCtrlToNext(
|
||||
"MainSwitch", int( State ), CabNo,
|
||||
( Notify == range::unit ?
|
||||
ctrain_controll | ctrain_depot :
|
||||
ctrain_controll ) );
|
||||
coupling::control | coupling::permanent :
|
||||
coupling::control ) );
|
||||
}
|
||||
}
|
||||
Mains = State;
|
||||
if( Mains ) {
|
||||
MS = true; // wartość zwrotna
|
||||
LastSwitchingTime = 0;
|
||||
|
||||
if( true == Mains ) {
|
||||
// jeśli został załączony
|
||||
if( Notify != range::local ) {
|
||||
// wysłanie wyłączenia do pozostałych?
|
||||
SendCtrlToNext(
|
||||
"MainSwitch", int( State ), CabNo,
|
||||
( Notify == range::unit ?
|
||||
ctrain_controll | ctrain_depot :
|
||||
ctrain_controll ) );
|
||||
coupling::control | coupling::permanent :
|
||||
coupling::control ) );
|
||||
}
|
||||
}
|
||||
MS = true; // wartość zwrotna
|
||||
LastSwitchingTime = 0;
|
||||
if ((EngineType == DieselEngine) && Mains)
|
||||
{
|
||||
if( ( EngineType == DieselEngine )
|
||||
|| ( EngineType == DieselElectric ) ) {
|
||||
|
||||
dizel_enginestart = State;
|
||||
}
|
||||
if (((TrainType == dt_EZT) && (!State)))
|
||||
ConvOvldFlag = true;
|
||||
if( ( TrainType == dt_EZT )
|
||||
&& ( false == State ) ) {
|
||||
|
||||
ConvOvldFlag = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// else MainSwitch:=false;
|
||||
@@ -2979,6 +2990,10 @@ bool TMoverParameters::BrakeDelaySwitch(int BDS)
|
||||
}
|
||||
else
|
||||
rBDS = false;
|
||||
if( true == rBDS ) {
|
||||
// if setting was changed emit the sound of pneumatic relay
|
||||
SetFlag( SoundFlag, sound::pneumatic );
|
||||
}
|
||||
return rBDS;
|
||||
}
|
||||
|
||||
@@ -3077,8 +3092,8 @@ void TMoverParameters::CompressorCheck(double dt)
|
||||
else
|
||||
{
|
||||
CompressedVolume = CompressedVolume * 0.8;
|
||||
SetFlag(SoundFlag, sound_relay | sound_loud);
|
||||
// SetFlag(SoundFlag, sound_loud);
|
||||
SetFlag(SoundFlag, sound::relay | sound::loud);
|
||||
// SetFlag(SoundFlag, sound::loud);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3371,7 +3386,7 @@ void TMoverParameters::UpdatePipePressure(double dt)
|
||||
// dodać jakiś wpis do fizyki na to
|
||||
if( ( ( Couplers[ b ].Connected->TrainType & ( dt_ET41 | dt_ET42 ) ) != 0 ) &&
|
||||
( ( Couplers[ b ].CouplingFlag & 36 ) == 36 ) )
|
||||
LocBrakePress = Max0R( Couplers[ b ].Connected->LocHandle->GetCP(), LocBrakePress );
|
||||
LocBrakePress = std::max( Couplers[ b ].Connected->LocHandle->GetCP(), LocBrakePress );
|
||||
|
||||
//if ((DynamicBrakeFlag) && (EngineType == ElectricInductionMotor))
|
||||
//{
|
||||
@@ -3724,8 +3739,8 @@ void TMoverParameters::ComputeTotalForce(double dt, double dt1, bool FullVer)
|
||||
Voltage = RunningTraction.TractionVoltage * DirAbsolute; // ActiveDir*CabNo;
|
||||
} // bo nie dzialalo
|
||||
else if( ( EngineType == ElectricInductionMotor )
|
||||
|| ( ( ( Couplers[ side::front ].CouplingFlag & ctrain_power ) == ctrain_power )
|
||||
|| ( ( Couplers[ side::rear ].CouplingFlag & ctrain_power ) == ctrain_power ) ) ) {
|
||||
|| ( ( ( Couplers[ side::front ].CouplingFlag & ctrain_power ) == ctrain_power )
|
||||
|| ( ( Couplers[ side::rear ].CouplingFlag & ctrain_power ) == ctrain_power ) ) ) {
|
||||
// potem ulepszyc! pantogtrafy!
|
||||
Voltage =
|
||||
std::max(
|
||||
@@ -3774,7 +3789,7 @@ void TMoverParameters::ComputeTotalForce(double dt, double dt1, bool FullVer)
|
||||
}
|
||||
if (nrot < 0.1)
|
||||
{
|
||||
WheelFlat = sqrt(sqr(WheelFlat) + abs(Fwheels) / NAxles*Vel*0.000002);
|
||||
WheelFlat = sqrt(square(WheelFlat) + abs(Fwheels) / NAxles*Vel*0.000002);
|
||||
}
|
||||
if (Sign(nrot * M_PI * WheelDiameter - V)*Sign(temp_nrot * M_PI * WheelDiameter - V) < 0)
|
||||
{
|
||||
@@ -4069,6 +4084,31 @@ double TMoverParameters::CouplerForce(int CouplerN, double dt)
|
||||
// tempdist:=tempdist+CoupleDist; //ABu: proby szybkiego naprawienia bledu
|
||||
}
|
||||
|
||||
dV = V - (double)DirPatch( CouplerN, CNext ) * Couplers[ CouplerN ].Connected->V;
|
||||
absdV = abs( dV );
|
||||
// potentially generate sounds on clash or stretch
|
||||
if( ( newdist < 0.0 )
|
||||
&& ( Couplers[ CouplerN ].Dist > newdist )
|
||||
&& ( dV < -0.5 ) ) {
|
||||
// 090503: dzwieki pracy zderzakow
|
||||
SetFlag(
|
||||
Couplers[ CouplerN ].sounds,
|
||||
( absdV > 5.0 ?
|
||||
( sound::bufferclash | sound::loud ) :
|
||||
sound::bufferclash ) );
|
||||
}
|
||||
else if( ( Couplers[ CouplerN ].CouplingFlag != coupling::faux )
|
||||
&& ( newdist > 0.001 )
|
||||
&& ( Couplers[ CouplerN ].Dist <= 0.001 )
|
||||
&& ( absdV > 0.005 ) ) {
|
||||
// 090503: dzwieki pracy sprzegu
|
||||
SetFlag(
|
||||
Couplers[ CouplerN ].sounds,
|
||||
( absdV > 0.1 ?
|
||||
( sound::couplerstretch | sound::loud ) :
|
||||
sound::couplerstretch ) );
|
||||
}
|
||||
|
||||
// blablabla
|
||||
// ABu: proby znalezienia problemu ze zle odbijajacymi sie skladami
|
||||
//if (Couplers[CouplerN].CouplingFlag=ctrain_virtual) and (newdist>0) then
|
||||
@@ -4090,23 +4130,6 @@ double TMoverParameters::CouplerForce(int CouplerN, double dt)
|
||||
Couplers[CouplerN].Connected->Couplers[CNext].FmaxB) *
|
||||
CouplerTune / 2.0;
|
||||
}
|
||||
dV = V - (double)DirPatch(CouplerN, CNext) * Couplers[CouplerN].Connected->V;
|
||||
absdV = abs(dV);
|
||||
if ((newdist < -0.001) && (Couplers[CouplerN].Dist >= -0.001) &&
|
||||
(absdV > 0.010)) // 090503: dzwieki pracy zderzakow
|
||||
{
|
||||
if (SetFlag(SoundFlag, sound_bufferclamp))
|
||||
if (absdV > 0.5)
|
||||
SetFlag(SoundFlag, sound_loud);
|
||||
}
|
||||
else if ((newdist > 0.002) && (Couplers[CouplerN].Dist <= 0.002) &&
|
||||
(absdV > 0.005)) // 090503: dzwieki pracy sprzegu
|
||||
{
|
||||
if (Couplers[CouplerN].CouplingFlag > 0)
|
||||
if (SetFlag(SoundFlag, sound_couplerstretch))
|
||||
if (absdV > 0.1)
|
||||
SetFlag(SoundFlag, sound_loud);
|
||||
}
|
||||
distDelta =
|
||||
abs(newdist) - abs(Couplers[CouplerN].Dist); // McZapkie-191103: poprawka na histereze
|
||||
Couplers[CouplerN].Dist = newdist;
|
||||
@@ -4176,7 +4199,7 @@ double TMoverParameters::CouplerForce(int CouplerN, double dt)
|
||||
// *************************************************************************************************
|
||||
double TMoverParameters::TractionForce(double dt)
|
||||
{
|
||||
double PosRatio, dmoment, dtrans, tmp, tmpV;
|
||||
double PosRatio, dmoment, dtrans, tmp;// , tmpV;
|
||||
int i;
|
||||
|
||||
Ft = 0;
|
||||
@@ -4223,38 +4246,82 @@ double TMoverParameters::TractionForce(double dt)
|
||||
// eAngle = Pirazy2 - eAngle; <- ABu: a nie czasem tak, jak nizej?
|
||||
eAngle -= M_PI * 2.0;
|
||||
*/
|
||||
// hunter-091012: przeniesione z if ActiveDir<>0 (zeby po zejsciu z kierunku dalej spadala
|
||||
// predkosc wentylatorow)
|
||||
if (EngineType == ElectricSeriesMotor)
|
||||
{
|
||||
switch (RVentType) // wentylatory rozruchowe}
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
if ((ActiveDir != 0) && (RList[MainCtrlActualPos].R > RVentCutOff))
|
||||
RventRot += (RVentnmax - RventRot) * RVentSpeed * dt;
|
||||
else
|
||||
RventRot *= (1.0 - RVentSpeed * dt);
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
if ((abs(Itot) > RVentMinI) && (RList[MainCtrlActualPos].R > RVentCutOff))
|
||||
RventRot +=
|
||||
(RVentnmax * abs(Itot) / (ImaxLo * RList[MainCtrlActualPos].Bn) - RventRot) *
|
||||
RVentSpeed * dt;
|
||||
else if ((DynamicBrakeType == dbrake_automatic) && (DynamicBrakeFlag))
|
||||
RventRot += (RVentnmax * Im / ImaxLo - RventRot) * RVentSpeed * dt;
|
||||
else
|
||||
{
|
||||
RventRot *= (1.0 - RVentSpeed * dt);
|
||||
if (RventRot < 0.1)
|
||||
RventRot = 0;
|
||||
// hunter-091012: przeniesione z if ActiveDir<>0 (zeby po zejsciu z kierunku dalej spadala predkosc wentylatorow)
|
||||
// wentylatory rozruchowe
|
||||
// TODO: move this to update, it doesn't exactly have much to do with traction
|
||||
if( true == Mains ) {
|
||||
|
||||
switch( EngineType ) {
|
||||
case ElectricInductionMotor: {
|
||||
// TBD, TODO: currently ignores RVentType, fix this?
|
||||
auto const tmpV { std::abs( eimv[ eimv_fp ] ) };
|
||||
|
||||
if( ( RlistSize > 0 )
|
||||
&& ( ( std::abs( eimv[ eimv_If ] ) > 1.0 )
|
||||
|| ( tmpV > 0.1 ) ) ) {
|
||||
|
||||
i = 0;
|
||||
while( ( i < RlistSize - 1 )
|
||||
&& ( DElist[ i + 1 ].RPM < tmpV ) ) {
|
||||
++i;
|
||||
}
|
||||
RventRot =
|
||||
( tmpV - DElist[ i ].RPM )
|
||||
/ std::max( 1.0, ( DElist[ i + 1 ].RPM - DElist[ i ].RPM ) )
|
||||
* ( DElist[ i + 1 ].GenPower - DElist[ i ].GenPower )
|
||||
+ DElist[ i ].GenPower;
|
||||
}
|
||||
else {
|
||||
RventRot *= std::max( 0.0, 1.0 - RVentSpeed * dt );
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
case ElectricSeriesMotor: {
|
||||
switch( RVentType ) {
|
||||
case 1: { // manual
|
||||
if( ( ActiveDir != 0 )
|
||||
&& ( RList[ MainCtrlActualPos ].R > RVentCutOff ) ) {
|
||||
RventRot += ( RVentnmax - RventRot ) * RVentSpeed * dt;
|
||||
}
|
||||
else {
|
||||
RventRot *= std::max( 0.0, 1.0 - RVentSpeed * dt );
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 2: { // automatic
|
||||
if( ( std::abs( Itot ) > RVentMinI )
|
||||
&& ( RList[ MainCtrlActualPos ].R > RVentCutOff ) ) {
|
||||
RventRot += ( RVentnmax * abs( Itot ) / ( ImaxLo * RList[ MainCtrlActualPos ].Bn ) - RventRot ) * RVentSpeed * dt;
|
||||
}
|
||||
else if( ( DynamicBrakeType == dbrake_automatic )
|
||||
&& ( true == DynamicBrakeFlag ) ) {
|
||||
RventRot += ( RVentnmax * Im / ImaxLo - RventRot ) * RVentSpeed * dt;
|
||||
}
|
||||
else {
|
||||
RventRot *= std::max( 0.0, 1.0 - RVentSpeed * dt );
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
} // rventtype
|
||||
}
|
||||
case DieselElectric: {
|
||||
// TBD, TODO: currently ignores RVentType, fix this?
|
||||
RventRot += clamp( DElist[ MainCtrlPos ].RPM - RventRot, -100.0, 50.0 ) * dt;
|
||||
break;
|
||||
}
|
||||
case DieselEngine:
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
} // enginetype
|
||||
}
|
||||
else {
|
||||
RventRot *= std::max( 0.0, 1.0 - RVentSpeed * dt );
|
||||
}
|
||||
RventRot = std::max( 0.0, RventRot );
|
||||
|
||||
if (ActiveDir != 0)
|
||||
switch (EngineType)
|
||||
@@ -4367,7 +4434,7 @@ double TMoverParameters::TractionForce(double dt)
|
||||
dizel_Mstand * (0.2 * enrot / dizel_nmax); // dodatkowe opory z powodu sprezarki}
|
||||
Mm = dizel_engage * dmoment;
|
||||
Mw = Mm * dtrans; // dmoment i dtrans policzone przy okazji enginerotation
|
||||
Fw = Mw * 2.0 / WheelDiameter;
|
||||
Fw = Mw * 2.0 / WheelDiameter / NPoweredAxles;
|
||||
Ft = Fw * NPoweredAxles; // sila trakcyjna
|
||||
Ft = Ft * DirAbsolute; // ActiveDir*CabNo;
|
||||
break;
|
||||
@@ -4376,7 +4443,7 @@ double TMoverParameters::TractionForce(double dt)
|
||||
case DieselElectric: // youBy
|
||||
{
|
||||
// tmpV:=V*CabNo*ActiveDir;
|
||||
tmpV = nrot * Pirazy2 * 0.5 * WheelDiameter * DirAbsolute; //*CabNo*ActiveDir;
|
||||
auto const tmpV { nrot * Pirazy2 * 0.5 * WheelDiameter * DirAbsolute }; //*CabNo*ActiveDir;
|
||||
// jazda manewrowa
|
||||
if (ShuntMode)
|
||||
{
|
||||
@@ -4456,8 +4523,8 @@ double TMoverParameters::TractionForce(double dt)
|
||||
else // charakterystyka pradnicy obcowzbudnej (elipsa) - twierdzenie Pitagorasa
|
||||
|
||||
{
|
||||
Voltage = sqrt(abs(sqr(DElist[MainCtrlPos].Umax) -
|
||||
sqr(DElist[MainCtrlPos].Umax * Im /
|
||||
Voltage = sqrt(abs(square(DElist[MainCtrlPos].Umax) -
|
||||
square(DElist[MainCtrlPos].Umax * Im /
|
||||
DElist[MainCtrlPos].Imax))) *
|
||||
(MainCtrlPos - 1) +
|
||||
(1.0 - Im / DElist[MainCtrlPos].Imax) * DElist[MainCtrlPos].Umax *
|
||||
@@ -4644,7 +4711,6 @@ double TMoverParameters::TractionForce(double dt)
|
||||
MainSwitch( false, ( TrainType == dt_EZT ? range::unit : range::local ) ); // TODO: check whether we need to send this EMU-wide
|
||||
}
|
||||
}
|
||||
tmpV = abs(nrot) * (PI * WheelDiameter) * 3.6; //*DirAbsolute*eimc[eimc_s_p]; - do przemyslenia dzialanie pp
|
||||
if ((Mains))
|
||||
{
|
||||
|
||||
@@ -4725,21 +4791,27 @@ double TMoverParameters::TractionForce(double dt)
|
||||
|
||||
eimv[eimv_Uzsmax] = Min0R(Voltage - eimc[eimc_f_DU], tmp);
|
||||
eimv[eimv_fkr] = eimv[eimv_Uzsmax] / eimc[eimc_f_cfu];
|
||||
if ((dizel_fill < 0))
|
||||
eimv[eimv_Pmax] = eimc[eimc_p_Ph];
|
||||
else
|
||||
eimv[eimv_Pmax] =
|
||||
Min0R(eimc[eimc_p_Pmax],
|
||||
0.001 * Voltage * (eimc[eimc_p_Imax] - eimc[eimc_f_I0]) * Pirazy2 *
|
||||
eimc[eimc_s_cim] / eimc[eimc_s_p] / eimc[eimc_s_cfu]);
|
||||
eimv[eimv_FMAXMAX] =
|
||||
0.001 * sqr(Min0R(eimv[eimv_fkr] / Max0R(abs(enrot) * eimc[eimc_s_p] +
|
||||
eimc[eimc_s_dfmax] * eimv[eimv_ks],
|
||||
eimc[eimc_s_dfmax]),
|
||||
1) *
|
||||
eimc[eimc_f_cfu] / eimc[eimc_s_cfu]) *
|
||||
(eimc[eimc_s_dfmax] * eimc[eimc_s_dfic] * eimc[eimc_s_cim]) *
|
||||
Transmision.Ratio * NPoweredAxles * 2.0 / WheelDiameter;
|
||||
if( ( dizel_fill < 0 ) ) {
|
||||
eimv[ eimv_Pmax ] = eimc[ eimc_p_Ph ];
|
||||
}
|
||||
else {
|
||||
eimv[ eimv_Pmax ] =
|
||||
std::min(
|
||||
eimc[ eimc_p_Pmax ],
|
||||
0.001 * Voltage * ( eimc[ eimc_p_Imax ] - eimc[ eimc_f_I0 ] ) * Pirazy2 * eimc[ eimc_s_cim ] / eimc[ eimc_s_p ] / eimc[ eimc_s_cfu ] );
|
||||
}
|
||||
eimv[ eimv_FMAXMAX ] =
|
||||
0.001
|
||||
* square(
|
||||
std::min(
|
||||
1.0,
|
||||
eimv[ eimv_fkr ] / std::max(
|
||||
abs( enrot ) * eimc[ eimc_s_p ] + eimc[ eimc_s_dfmax ] * eimv[ eimv_ks ],
|
||||
eimc[ eimc_s_dfmax ] ) )
|
||||
* eimc[ eimc_f_cfu ]
|
||||
/ eimc[ eimc_s_cfu ] )
|
||||
* ( eimc[ eimc_s_dfmax ] * eimc[ eimc_s_dfic ] * eimc[ eimc_s_cim ] )
|
||||
* Transmision.Ratio * NPoweredAxles * 2.0 / WheelDiameter;
|
||||
if ((dizel_fill < 0))
|
||||
{
|
||||
eimv[eimv_Fful] = std::min(eimc[eimc_p_Ph] * 3.6 / (Vel != 0.0 ? Vel : 0.001),
|
||||
@@ -4808,19 +4880,6 @@ double TMoverParameters::TractionForce(double dt)
|
||||
Itot = eimv[eimv_Ipoj] * (0.01 + Min0R(0.99, 0.99 - Vadd));
|
||||
|
||||
EnginePower = abs(eimv[eimv_Ic] * eimv[eimv_U] * NPoweredAxles) / 1000;
|
||||
tmpV = eimv[eimv_fp];
|
||||
if (((abs(eimv[eimv_If]) > 1) || (abs(tmpV) > 0.1)) && (RlistSize > 0))
|
||||
{
|
||||
i = 0;
|
||||
while ((i < RlistSize - 1) && (DElist[i + 1].RPM < abs(tmpV)))
|
||||
i++;
|
||||
RventRot = (abs(tmpV) - DElist[i].RPM) /
|
||||
(DElist[i + 1].RPM - DElist[i].RPM) *
|
||||
(DElist[i + 1].GenPower - DElist[i].GenPower) +
|
||||
DElist[i].GenPower;
|
||||
}
|
||||
else
|
||||
RventRot = 0;
|
||||
|
||||
Mm = eimv[eimv_M] * DirAbsolute;
|
||||
Mw = Mm * Transmision.Ratio;
|
||||
@@ -4910,7 +4969,7 @@ bool TMoverParameters::FuseOn(void)
|
||||
{
|
||||
FuseFlag = false; // wlaczenie ponowne obwodu
|
||||
FO = true;
|
||||
SetFlag(SoundFlag, sound_relay | sound_loud);
|
||||
SetFlag(SoundFlag, sound::relay | sound::loud);
|
||||
}
|
||||
}
|
||||
return FO;
|
||||
@@ -4926,7 +4985,7 @@ void TMoverParameters::FuseOff(void)
|
||||
{
|
||||
FuseFlag = true;
|
||||
EventFlag = true;
|
||||
SetFlag(SoundFlag, sound_relay | sound_loud);
|
||||
SetFlag(SoundFlag, sound::relay | sound::loud);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5197,7 +5256,7 @@ bool TMoverParameters::AutoRelayCheck(void)
|
||||
// MainCtrlActualPos:=MainCtrlPos; //hunter-111012:
|
||||
// szybkie wchodzenie na bezoporowa (303E)
|
||||
OK = true;
|
||||
SetFlag(SoundFlag, sound_manyrelay | sound_loud);
|
||||
SetFlag(SoundFlag, sound::parallel | sound::loud);
|
||||
}
|
||||
else if ((LastRelayTime > CtrlDelay) && (ARFASI))
|
||||
{
|
||||
@@ -5231,13 +5290,13 @@ bool TMoverParameters::AutoRelayCheck(void)
|
||||
if ((RList[MainCtrlActualPos].R == 0) &&
|
||||
(!(MainCtrlActualPos == MainCtrlPosNo))) // wejscie na bezoporowa
|
||||
{
|
||||
SetFlag(SoundFlag, sound_manyrelay | sound_loud);
|
||||
SetFlag(SoundFlag, sound::parallel | sound::loud);
|
||||
}
|
||||
else if ((RList[MainCtrlActualPos].R > 0) &&
|
||||
(RList[MainCtrlActualPos - 1].R ==
|
||||
0)) // wejscie na drugi uklad
|
||||
{
|
||||
SetFlag(SoundFlag, sound_manyrelay);
|
||||
SetFlag(SoundFlag, sound::parallel);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5250,7 +5309,7 @@ bool TMoverParameters::AutoRelayCheck(void)
|
||||
// MainCtrlActualPos:=MainCtrlPos; //hunter-111012:
|
||||
// szybkie wchodzenie na bezoporowa (303E)
|
||||
OK = true;
|
||||
SetFlag(SoundFlag, sound_manyrelay);
|
||||
SetFlag(SoundFlag, sound::parallel);
|
||||
}
|
||||
else if (LastRelayTime > CtrlDownDelay)
|
||||
{
|
||||
@@ -5263,7 +5322,7 @@ bool TMoverParameters::AutoRelayCheck(void)
|
||||
if (RList[MainCtrlActualPos].R ==
|
||||
0) // dzwieki schodzenia z bezoporowej}
|
||||
{
|
||||
SetFlag(SoundFlag, sound_manyrelay);
|
||||
SetFlag(SoundFlag, sound::parallel);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5295,7 +5354,7 @@ bool TMoverParameters::AutoRelayCheck(void)
|
||||
StLinFlag = true; // ybARC - zalaczenie stycznikow liniowych
|
||||
MainCtrlActualPos = 1;
|
||||
DelayCtrlFlag = false;
|
||||
SetFlag(SoundFlag, sound_relay | sound_loud);
|
||||
SetFlag(SoundFlag, sound::relay | sound::loud);
|
||||
OK = true;
|
||||
}
|
||||
}
|
||||
@@ -5585,22 +5644,28 @@ bool TMoverParameters::dizel_AutoGearCheck(void)
|
||||
// *************************************************************************************************
|
||||
bool TMoverParameters::dizel_Update(double dt)
|
||||
{
|
||||
const double fillspeed = 2;
|
||||
bool DU;
|
||||
double const fillspeed { 2 };
|
||||
bool DU { false };
|
||||
|
||||
// dizel_Update:=false;
|
||||
if (dizel_enginestart && (LastSwitchingTime >= InitialCtrlDelay))
|
||||
{
|
||||
if( ( true == dizel_enginestart )
|
||||
&& ( LastSwitchingTime >= InitialCtrlDelay ) ) {
|
||||
dizel_enginestart = false;
|
||||
LastSwitchingTime = 0;
|
||||
enrot = dizel_nmin / 2.0; // TODO: dac zaleznie od temperatury i baterii
|
||||
|
||||
enrot = std::max(
|
||||
enrot,
|
||||
0.1 * ( // TODO: dac zaleznie od temperatury i baterii
|
||||
EngineType == DieselEngine ?
|
||||
dizel_nmin :
|
||||
DElist[ 0 ].RPM / 60.0 ) );
|
||||
}
|
||||
|
||||
if( EngineType == DieselEngine ) {
|
||||
dizel_EngageChange( dt );
|
||||
DU = dizel_AutoGearCheck();
|
||||
dizel_fill = dizel_fill + fillspeed * dt * ( dizel_fillcheck( MainCtrlPos ) - dizel_fill );
|
||||
}
|
||||
/*OK=*/dizel_EngageChange(dt);
|
||||
// if AutoRelayFlag then Poprawka na SM03
|
||||
DU = dizel_AutoGearCheck();
|
||||
// dizel_fill:=(dizel_fill+dizel_fillcheck(MainCtrlPos))/2;
|
||||
dizel_fill = dizel_fill + fillspeed * dt * (dizel_fillcheck(MainCtrlPos) - dizel_fill);
|
||||
// dizel_Update:=OK;
|
||||
|
||||
return DU;
|
||||
}
|
||||
@@ -5662,21 +5727,19 @@ double TMoverParameters::dizel_Momentum(double dizel_fill, double n, double dt)
|
||||
{ // liczy moment sily wytwarzany przez silnik spalinowy}
|
||||
double Moment = 0, enMoment = 0, eps = 0, newn = 0, friction = 0;
|
||||
|
||||
// friction =dizel_engagefriction*(11-2*random)/10;
|
||||
friction = dizel_engagefriction;
|
||||
if (enrot > 0)
|
||||
{ // sqr TODO: sqr c++
|
||||
Moment = dizel_Mmax * dizel_fill -
|
||||
(dizel_Mmax - dizel_Mnmax * dizel_fill) *
|
||||
sqr(enrot / (dizel_nmax - dizel_nMmax * dizel_fill)) -
|
||||
dizel_Mstand; // Q: zamieniam SQR() na sqr()
|
||||
// Moment:=Moment*(1+sin(eAngle*4))-dizel_Mstand*(1+cos(eAngle*4));}
|
||||
if( enrot > 0 ) {
|
||||
// Moment = dizel_Mmax * dizel_fill - ( dizel_Mmax - dizel_Mnmax * dizel_fill ) * sqr( enrot / ( dizel_nmax - dizel_nMmax * dizel_fill ) ) - dizel_Mstand; // Q: zamieniam SQR() na sqr()
|
||||
Moment = ( dizel_Mmax - ( dizel_Mmax - dizel_Mnmax ) * square( ( enrot - dizel_nMmax ) / ( dizel_nMmax - dizel_nmax ) ) ) * dizel_fill - dizel_Mstand;
|
||||
}
|
||||
else
|
||||
else {
|
||||
Moment = -dizel_Mstand;
|
||||
if (enrot < dizel_nmin / 10.0)
|
||||
if (eAngle < PI / 2.0)
|
||||
Moment -= dizel_Mstand; // wstrzymywanie przy malych obrotach
|
||||
}
|
||||
if( ( enrot < dizel_nmin / 10.0 )
|
||||
&& ( eAngle < PI / 2.0 ) ) {
|
||||
// wstrzymywanie przy malych obrotach
|
||||
Moment -= dizel_Mstand;
|
||||
}
|
||||
//!! abs
|
||||
if (abs(abs(n) - enrot) < 0.1)
|
||||
{
|
||||
@@ -5849,6 +5912,32 @@ bool TMoverParameters::DoorRight(bool State)
|
||||
return DR;
|
||||
}
|
||||
|
||||
// toggles departure warning
|
||||
bool
|
||||
TMoverParameters::signal_departure( bool const State, int const Notify ) {
|
||||
|
||||
if( DepartureSignal == State ) {
|
||||
// TBD: should the command be passed to other vehicles regardless of whether it affected the primary target?
|
||||
return false;
|
||||
}
|
||||
|
||||
DepartureSignal = State;
|
||||
if( Notify != range::local ) {
|
||||
// wysłanie wyłączenia do pozostałych?
|
||||
SendCtrlToNext(
|
||||
"DepartureSignal",
|
||||
( State == true ?
|
||||
1 :
|
||||
0 ),
|
||||
CabNo,
|
||||
( Notify == range::unit ?
|
||||
ctrain_controll | ctrain_depot :
|
||||
ctrain_controll ) );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// *************************************************************************************************
|
||||
// Q: 20160713
|
||||
// Przesuwa pojazd o podaną wartość w bok względem toru (dla samochodów)
|
||||
@@ -7471,6 +7560,8 @@ void TMoverParameters::LoadFIZ_Circuit( std::string const &Input ) {
|
||||
|
||||
void TMoverParameters::LoadFIZ_RList( std::string const &Input ) {
|
||||
|
||||
extract_value( RlistSize, "Size", Input, "" );
|
||||
|
||||
auto const venttype = extract_value( "RVent", Input );
|
||||
if( venttype == "Automatic" ) {
|
||||
|
||||
@@ -8219,6 +8310,13 @@ bool TMoverParameters::RunCommand( std::string Command, double CValue1, double C
|
||||
}
|
||||
OK = SendCtrlToNext( Command, CValue1, CValue2, Couplertype );
|
||||
}
|
||||
else if( Command == "DepartureSignal" ) {
|
||||
DepartureSignal = (
|
||||
CValue1 == 1 ?
|
||||
true :
|
||||
false );
|
||||
OK = SendCtrlToNext( Command, CValue1, CValue2, Couplertype );
|
||||
}
|
||||
else if (Command == "PantFront") /*Winger 160204*/
|
||||
{ // Ra: uwzględnić trzeba jeszcze zgodność sprzęgów
|
||||
// Czemu EZT ma być traktowane inaczej? Ukrotnienie ma, a człon może być odwrócony
|
||||
@@ -8338,6 +8436,8 @@ bool TMoverParameters::RunCommand( std::string Command, double CValue1, double C
|
||||
if( true == Hamulec->SetBDF( brakesetting ) ) {
|
||||
BrakeDelayFlag = brakesetting;
|
||||
OK = true;
|
||||
// if setting was changed emit the sound of pneumatic relay
|
||||
SetFlag( SoundFlag, sound::pneumatic );
|
||||
}
|
||||
else {
|
||||
OK = false;
|
||||
|
||||
@@ -578,47 +578,58 @@ void TESt::CheckReleaser( double const dt )
|
||||
}
|
||||
}
|
||||
|
||||
void TESt::CheckState( double const BCP, double &dV1 )
|
||||
{
|
||||
double VVP;
|
||||
double BVP;
|
||||
double CVP;
|
||||
void TESt::CheckState( double const BCP, double &dV1 ) {
|
||||
|
||||
BVP = BrakeRes->P();
|
||||
VVP = ValveRes->P();
|
||||
// if (BVP<VVP) then
|
||||
// VVP:=(BVP+VVP)/2;
|
||||
CVP = CntrlRes->P() - 0.0;
|
||||
double const VVP { ValveRes->P() };
|
||||
double const BVP { BrakeRes->P() };
|
||||
double const CVP { CntrlRes->P() };
|
||||
|
||||
// sprawdzanie stanu
|
||||
if (((BrakeStatus & b_hld) == b_hld) && (BCP > 0.25))
|
||||
if ((VVP + 0.003 + BCP / BVM < CVP))
|
||||
BrakeStatus |= b_on; // hamowanie stopniowe
|
||||
else if ((VVP - 0.003 + (BCP - 0.1) / BVM > CVP))
|
||||
BrakeStatus &= ~( b_on | b_hld ); // luzowanie
|
||||
else if ((VVP + BCP / BVM > CVP))
|
||||
BrakeStatus &= ~b_on; // zatrzymanie napelaniania
|
||||
else
|
||||
;
|
||||
else if ((VVP + 0.10 < CVP) && (BCP < 0.25)) // poczatek hamowania
|
||||
{
|
||||
if ((BrakeStatus & b_hld) == b_off)
|
||||
{
|
||||
ValveRes->CreatePress(0.02 * VVP);
|
||||
SoundFlag |= sf_Acc;
|
||||
ValveRes->Act();
|
||||
if( BCP > 0.25 ) {
|
||||
|
||||
if( ( BrakeStatus & b_hld ) == b_hld ) {
|
||||
|
||||
if( ( VVP + 0.003 + BCP / BVM ) < CVP ) {
|
||||
// hamowanie stopniowe
|
||||
BrakeStatus |= b_on;
|
||||
}
|
||||
else {
|
||||
if( ( VVP + BCP / BVM ) > CVP ) {
|
||||
// zatrzymanie napelaniania
|
||||
BrakeStatus &= ~b_on;
|
||||
}
|
||||
if( ( VVP - 0.003 + ( BCP - 0.1 ) / BVM ) > CVP ) {
|
||||
// luzowanie
|
||||
BrakeStatus &= ~( b_on | b_hld );
|
||||
}
|
||||
}
|
||||
}
|
||||
BrakeStatus |= (b_on | b_hld);
|
||||
else {
|
||||
|
||||
// ValveRes.CreatePress(0);
|
||||
// dV1:=1;
|
||||
if( ( VVP + BCP / BVM < CVP )
|
||||
&& ( ( CVP - VVP ) * BVM > 0.25 ) ) {
|
||||
// zatrzymanie luzowanie
|
||||
BrakeStatus |= b_hld;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ((VVP + (BCP - 0.1) / BVM < CVP) && ((CVP - VVP) * BVM > 0.25) &&
|
||||
(BCP > 0.25)) // zatrzymanie luzowanie
|
||||
BrakeStatus |= b_hld;
|
||||
else {
|
||||
|
||||
if ((BrakeStatus & b_hld) == b_off)
|
||||
if( VVP + 0.1 < CVP ) {
|
||||
// poczatek hamowania
|
||||
if( ( BrakeStatus & b_hld ) == 0 ) {
|
||||
// przyspieszacz
|
||||
ValveRes->CreatePress( 0.02 * VVP );
|
||||
SoundFlag |= sf_Acc;
|
||||
ValveRes->Act();
|
||||
}
|
||||
BrakeStatus |= ( b_on | b_hld );
|
||||
}
|
||||
}
|
||||
|
||||
if( ( BrakeStatus & b_hld ) == 0 ) {
|
||||
SoundFlag |= sf_CylU;
|
||||
}
|
||||
}
|
||||
|
||||
double TESt::CVs( double const BP )
|
||||
@@ -828,6 +839,10 @@ double TEStEP2::GetPF( double const PP, double const dt, double const Vel )
|
||||
else if ((VVP + BCP / BVM < CVP - 0.12) && (BCP > 0.25)) // zatrzymanie luzowanie
|
||||
BrakeStatus |= b_hld;
|
||||
|
||||
if( ( BrakeStatus & b_hld ) == 0 ) {
|
||||
SoundFlag |= sf_CylU;
|
||||
}
|
||||
|
||||
// przeplyw ZS <-> PG
|
||||
if ((BVP < CVP - 0.2) || (BrakeStatus != b_off) || (BCP > 0.25))
|
||||
temp = 0;
|
||||
@@ -1211,6 +1226,40 @@ double TLSt::GetPF( double const PP, double const dt, double const Vel )
|
||||
double dV1{ 0.0 };
|
||||
|
||||
// sprawdzanie stanu
|
||||
// NOTE: partial copypaste from checkstate() of base class
|
||||
// TODO: clean inheritance for checkstate() and checkreleaser() and reuse these instead of manual copypaste
|
||||
if( ( ( BrakeStatus & b_hld ) == b_hld ) && ( BCP > 0.25 ) ) {
|
||||
if( ( VVP + 0.003 + BCP / BVM < CVP ) ) {
|
||||
// hamowanie stopniowe
|
||||
BrakeStatus |= b_on;
|
||||
}
|
||||
else if( ( VVP - 0.003 + ( BCP - 0.1 ) / BVM > CVP ) ) {
|
||||
// luzowanie
|
||||
BrakeStatus &= ~( b_on | b_hld );
|
||||
}
|
||||
else if( ( VVP + BCP / BVM > CVP ) ) {
|
||||
// zatrzymanie napelaniania
|
||||
BrakeStatus &= ~b_on;
|
||||
}
|
||||
}
|
||||
else if ((VVP + 0.10 < CVP) && (BCP < 0.25)) {
|
||||
// poczatek hamowania
|
||||
if ((BrakeStatus & b_hld) == b_off)
|
||||
{
|
||||
SoundFlag |= sf_Acc;
|
||||
}
|
||||
BrakeStatus |= (b_on | b_hld);
|
||||
}
|
||||
else if( ( VVP + ( BCP - 0.1 ) / BVM < CVP )
|
||||
&& ( ( CVP - VVP ) * BVM > 0.25 )
|
||||
&& ( BCP > 0.25 ) ) {
|
||||
// zatrzymanie luzowanie
|
||||
BrakeStatus |= b_hld;
|
||||
}
|
||||
if( ( BrakeStatus & b_hld ) == 0 ) {
|
||||
SoundFlag |= sf_CylU;
|
||||
}
|
||||
// equivalent of checkreleaser() in the base class?
|
||||
if( ( BrakeStatus & b_rls ) == b_rls ) {
|
||||
if( CVP < 0.0 ) {
|
||||
BrakeStatus &= ~b_rls;
|
||||
@@ -1219,18 +1268,11 @@ double TLSt::GetPF( double const PP, double const dt, double const Vel )
|
||||
{ // 008
|
||||
dV = PF1( CVP, BCP, 0.024 ) * dt;
|
||||
CntrlRes->Flow( dV );
|
||||
/*
|
||||
// NOTE: attempted fix, disabled because it breaks when releaser is used while releasing breakes
|
||||
dV = PF1(CVP, VVP, 0.024) * dt;
|
||||
CntrlRes->Flow( dV );
|
||||
dV1 = dV; //minus potem jest
|
||||
ImplsRes->Flow( -dV1 );
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
double temp;
|
||||
// przeplyw ZS <-> PG
|
||||
double temp;
|
||||
if (((CVP - BCP) * BVM > 0.5))
|
||||
temp = 0.0;
|
||||
else if ((VVP > CVP + 0.4))
|
||||
@@ -1888,22 +1930,51 @@ void TKE::CheckState( double const BCP, double &dV1 )
|
||||
CVP = CntrlRes->P();
|
||||
|
||||
// sprawdzanie stanu
|
||||
if ((BrakeStatus & b_hld) == b_hld)
|
||||
if ((VVP + 0.003 + BCP / BVM < CVP))
|
||||
BrakeStatus |= b_on; // hamowanie stopniowe;
|
||||
else if ((VVP - 0.003 + BCP / BVM > CVP))
|
||||
BrakeStatus &= ~( b_on | b_hld ); // luzowanie;
|
||||
else if ((VVP + BCP / BVM > CVP))
|
||||
BrakeStatus &= ~b_on; // zatrzymanie napelaniania;
|
||||
else
|
||||
;
|
||||
else if ((VVP + 0.10 < CVP) && (BCP < 0.1)) // poczatek hamowania
|
||||
{
|
||||
BrakeStatus |= (b_on | b_hld);
|
||||
ValveRes->CreatePress(0.8 * VVP); // przyspieszacz
|
||||
if( BCP > 0.1 ) {
|
||||
|
||||
if( ( BrakeStatus & b_hld ) == b_hld ) {
|
||||
|
||||
if( ( VVP + 0.003 + BCP / BVM ) < CVP ) {
|
||||
// hamowanie stopniowe;
|
||||
BrakeStatus |= b_on;
|
||||
}
|
||||
else {
|
||||
if( ( VVP + BCP / BVM ) > CVP ) {
|
||||
// zatrzymanie napelaniania;
|
||||
BrakeStatus &= ~b_on;
|
||||
}
|
||||
if( ( VVP - 0.003 + BCP / BVM ) > CVP ) {
|
||||
// luzowanie;
|
||||
BrakeStatus &= ~( b_on | b_hld );
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
if( ( VVP + BCP / BVM < CVP )
|
||||
&& ( ( CVP - VVP ) * BVM > 0.25 ) ) {
|
||||
// zatrzymanie luzowanie
|
||||
BrakeStatus |= b_hld;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
if( VVP + 0.1 < CVP ) {
|
||||
// poczatek hamowania
|
||||
if( ( BrakeStatus & b_hld ) == 0 ) {
|
||||
// przyspieszacz
|
||||
ValveRes->CreatePress( 0.8 * VVP );
|
||||
SoundFlag |= sf_Acc;
|
||||
ValveRes->Act();
|
||||
}
|
||||
BrakeStatus |= ( b_on | b_hld );
|
||||
}
|
||||
}
|
||||
|
||||
if( ( BrakeStatus & b_hld ) == 0 ) {
|
||||
SoundFlag |= sf_CylU;
|
||||
}
|
||||
else if ((VVP + BCP / BVM < CVP) && ((CVP - VVP) * BVM > 0.25)) // zatrzymanie luzowanie
|
||||
BrakeStatus |= b_hld;
|
||||
}
|
||||
|
||||
double TKE::CVs( double const BP )
|
||||
|
||||
@@ -116,11 +116,12 @@ void win1250_to_ascii( std::string &Input );
|
||||
inline
|
||||
std::string
|
||||
extract_value( std::string const &Key, std::string const &Input ) {
|
||||
|
||||
// NOTE, HACK: the leading space allows to uniformly look for " variable=" substring
|
||||
std::string const input { " " + Input };
|
||||
std::string value;
|
||||
auto lookup = Input.find( Key + "=" );
|
||||
auto lookup = input.find( " " + Key + "=" );
|
||||
if( lookup != std::string::npos ) {
|
||||
value = Input.substr( Input.find_first_not_of( ' ', lookup + Key.size() + 1 ) );
|
||||
value = input.substr( input.find_first_not_of( ' ', lookup + Key.size() + 2 ) );
|
||||
lookup = value.find( ' ' );
|
||||
if( lookup != std::string::npos ) {
|
||||
// trim everything past the value
|
||||
|
||||
72
Model3d.cpp
72
Model3d.cpp
@@ -46,21 +46,13 @@ std::string *TSubModel::pasText;
|
||||
// 0x3F3F003F - wszystkie wymienne tekstury używane w danym cyklu
|
||||
// Ale w TModel3d okerśla przezroczystość tekstur wymiennych!
|
||||
|
||||
TSubModel::~TSubModel()
|
||||
{
|
||||
/*
|
||||
if (uiDisplayList)
|
||||
glDeleteLists(uiDisplayList, 1);
|
||||
*/
|
||||
if (iFlags & 0x0200)
|
||||
TSubModel::~TSubModel() {
|
||||
|
||||
if (iFlags & 0x0200)
|
||||
{ // wczytany z pliku tekstowego musi sam posprzątać
|
||||
// SafeDeleteArray(Indices);
|
||||
SafeDelete(Next);
|
||||
SafeDelete(Child);
|
||||
delete fMatrix; // własny transform trzeba usunąć (zawsze jeden)
|
||||
/*
|
||||
delete[] Vertices;
|
||||
*/
|
||||
}
|
||||
delete[] smLetter; // używany tylko roboczo dla TP_TEXT, do przyspieszenia
|
||||
// wyświetlania
|
||||
@@ -99,7 +91,7 @@ TSubModel::SetLightLevel( float const Level, bool const Includechildren, bool co
|
||||
}
|
||||
}
|
||||
|
||||
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, gfx::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
|
||||
for( int faceidx = Startface; faceidx < facecount; ++faceidx ) {
|
||||
@@ -984,7 +976,7 @@ void TSubModel::serialize_geometry( std::ostream &Output ) const {
|
||||
};
|
||||
|
||||
void
|
||||
TSubModel::create_geometry( std::size_t &Dataoffset, geometrybank_handle const &Bank ) {
|
||||
TSubModel::create_geometry( std::size_t &Dataoffset, gfx::geometrybank_handle const &Bank ) {
|
||||
|
||||
// data offset is used to determine data offset of each submodel into single shared geometry bank
|
||||
// (the offsets are part of legacy system which we now need to work around for backward compatibility)
|
||||
@@ -1051,16 +1043,17 @@ void TSubModel::ColorsSet( glm::vec3 const &Ambient, glm::vec3 const &Diffuse, g
|
||||
*/
|
||||
};
|
||||
|
||||
void TSubModel::ParentMatrix(float4x4 *m)
|
||||
{ // pobranie transformacji względem wstawienia modelu
|
||||
// jeśli nie zostało wykonane Init() (tzn. zaraz po wczytaniu T3D), to
|
||||
// dodatkowy obrót
|
||||
// obrót T3D jest wymagany np. do policzenia wysokości pantografów
|
||||
m->Identity();
|
||||
if (fMatrix)
|
||||
*m = float4x4(*fMatrix); // skopiowanie, bo będziemy mnożyć
|
||||
// m(3)[1]=m[3][1]+0.054; //w górę o wysokość ślizgu (na razie tak)
|
||||
TSubModel *sm = this;
|
||||
void TSubModel::ParentMatrix( float4x4 *m ) const { // pobranie transformacji względem wstawienia modelu
|
||||
// jeśli nie zostało wykonane Init() (tzn. zaraz po wczytaniu T3D),
|
||||
// to dodatkowy obrót obrót T3D jest wymagany np. do policzenia wysokości pantografów
|
||||
if( fMatrix != nullptr ) {
|
||||
// skopiowanie, bo będziemy mnożyć
|
||||
*m = float4x4( *fMatrix );
|
||||
}
|
||||
else {
|
||||
m->Identity();
|
||||
}
|
||||
auto *sm = this;
|
||||
while (sm->Parent)
|
||||
{ // przenieść tę funkcję do modelu
|
||||
if (sm->Parent->GetMatrix())
|
||||
@@ -1163,6 +1156,37 @@ TSubModel *TModel3d::GetFromName(std::string const &Name)
|
||||
}
|
||||
};
|
||||
|
||||
// returns offset vector from root
|
||||
glm::vec3
|
||||
TSubModel::offset( float const Geometrytestoffsetthreshold ) const {
|
||||
|
||||
float4x4 parentmatrix;
|
||||
ParentMatrix( &parentmatrix );
|
||||
|
||||
auto offset { glm::vec3 { glm::make_mat4( parentmatrix.readArray() ) * glm::vec4 { 0, 0, 0, 1 } } };
|
||||
|
||||
if( glm::length2( offset ) < Geometrytestoffsetthreshold ) {
|
||||
// offset of zero generally means the submodel has optimized identity matrix
|
||||
// for such cases we resort to an estimate from submodel geometry
|
||||
// TODO: do proper bounding area calculation for submodel when loading mesh and grab the centre point from it here
|
||||
if( m_geometry != null_handle ) {
|
||||
auto const &vertices{ GfxRenderer.Vertices( m_geometry ) };
|
||||
if( false == vertices.empty() ) {
|
||||
// transformation matrix for the submodel can still contain rotation and/or scaling,
|
||||
// so we pass the vertex positions through it rather than just grab them directly
|
||||
offset = glm::vec3();
|
||||
auto const vertexfactor { 1.f / vertices.size() };
|
||||
auto const transformationmatrix { glm::make_mat4( parentmatrix.readArray() ) };
|
||||
for( auto const &vertex : vertices ) {
|
||||
offset += glm::vec3 { transformationmatrix * glm::vec4 { vertex.position, 1 } } * vertexfactor;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
bool TModel3d::LoadFromFile(std::string const &FileName, bool dynamic)
|
||||
{
|
||||
// wczytanie modelu z pliku
|
||||
@@ -1475,7 +1499,7 @@ void TModel3d::deserialize(std::istream &s, size_t size, bool dynamic)
|
||||
// once sorted we can grab geometry as it comes, and assign it to the chunks it belongs to
|
||||
for( auto const &submodeloffset : submodeloffsets ) {
|
||||
auto &submodel = Root[ submodeloffset.second ];
|
||||
vertex_array vertices; vertices.resize( submodel.iNumVerts );
|
||||
gfx::vertex_array vertices; vertices.resize( submodel.iNumVerts );
|
||||
iNumVerts += submodel.iNumVerts;
|
||||
for( auto &vertex : vertices ) {
|
||||
vertex.deserialize( s );
|
||||
|
||||
32
Model3d.h
32
Model3d.h
@@ -13,7 +13,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "parser.h"
|
||||
#include "dumb3d.h"
|
||||
#include "Float3d.h"
|
||||
#include "VBO.h"
|
||||
#include "openglgeometrybank.h"
|
||||
#include "material.h"
|
||||
|
||||
using namespace Math3D;
|
||||
@@ -124,7 +124,9 @@ private:
|
||||
|
||||
TSubModel *Next { nullptr };
|
||||
TSubModel *Child { nullptr };
|
||||
geometry_handle m_geometry { 0, 0 }; // geometry of the submodel
|
||||
public: // temporary access, clean this up during refactoring
|
||||
gfx::geometry_handle m_geometry { 0, 0 }; // geometry of the submodel
|
||||
private:
|
||||
material_handle m_material { null_handle }; // numer tekstury, -1 wymienna, 0 brak
|
||||
bool bWire { false }; // nie używane, ale wczytywane
|
||||
float Opacity { 1.0f };
|
||||
@@ -134,20 +136,18 @@ private:
|
||||
|
||||
public: // chwilowo
|
||||
float3 v_TransVector { 0.0f, 0.0f, 0.0f };
|
||||
vertex_array Vertices;
|
||||
gfx::vertex_array Vertices;
|
||||
float m_boundingradius { 0 };
|
||||
size_t iAnimOwner{ 0 }; // roboczy numer egzemplarza, który ustawił animację
|
||||
TAnimType b_aAnim{ at_None }; // kody animacji oddzielnie, bo zerowane
|
||||
public:
|
||||
float4x4 *mAnimMatrix{ nullptr }; // macierz do animacji kwaternionowych (należy do AnimContainer)
|
||||
public:
|
||||
TSubModel **smLetter{ nullptr }; // wskaźnik na tablicę submdeli do generoania tekstu (docelowo zapisać do E3D)
|
||||
TSubModel *Parent{ nullptr }; // nadrzędny, np. do wymnażania macierzy
|
||||
int iVisible{ 1 }; // roboczy stan widoczności
|
||||
std::string m_materialname; // robocza nazwa tekstury do zapisania w pliku binarnym
|
||||
std::string pName; // robocza nazwa
|
||||
private:
|
||||
int SeekFaceNormal( std::vector<unsigned int> const &Masks, int const Startface, unsigned int const Mask, glm::vec3 const &Position, vertex_array const &Vertices );
|
||||
int SeekFaceNormal( std::vector<unsigned int> const &Masks, int const Startface, unsigned int const Mask, glm::vec3 const &Position, gfx::vertex_array const &Vertices );
|
||||
void RaAnimation(TAnimType a);
|
||||
void RaAnimation(glm::mat4 &m, TAnimType a);
|
||||
|
||||
@@ -173,9 +173,12 @@ public:
|
||||
void SetRotateIK1(float3 vNewAngles);
|
||||
TSubModel * GetFromName( std::string const &search, bool i = true );
|
||||
inline float4x4 * GetMatrix() { return fMatrix; };
|
||||
inline void Hide() { iVisible = 0; };
|
||||
inline float4x4 const * GetMatrix() const { return fMatrix; };
|
||||
// returns offset vector from root
|
||||
glm::vec3 offset( float const Geometrytestoffsetthreshold = 0.f ) const;
|
||||
inline void Hide() { iVisible = 0; };
|
||||
|
||||
void create_geometry( std::size_t &Dataoffset, geometrybank_handle const &Bank );
|
||||
void create_geometry( std::size_t &Dataoffset, gfx::geometrybank_handle const &Bank );
|
||||
int FlagsCheck();
|
||||
void WillBeAnimated()
|
||||
{
|
||||
@@ -201,7 +204,7 @@ public:
|
||||
return *(fMatrix->TranslationGet()) + Child->Translation1Get(); }
|
||||
material_handle GetMaterial() const {
|
||||
return m_material; }
|
||||
void ParentMatrix(float4x4 *m);
|
||||
void ParentMatrix(float4x4 *m) const;
|
||||
float MaxY( float4x4 const &m );
|
||||
|
||||
void deserialize(std::istream&);
|
||||
@@ -214,7 +217,7 @@ public:
|
||||
// places contained geometry in provided ground node
|
||||
};
|
||||
|
||||
class TModel3d : public CMesh
|
||||
class TModel3d
|
||||
{
|
||||
friend class opengl_renderer;
|
||||
|
||||
@@ -222,7 +225,9 @@ private:
|
||||
TSubModel *Root; // drzewo submodeli
|
||||
int iFlags; // Ra: czy submodele mają przezroczyste tekstury
|
||||
public: // Ra: tymczasowo
|
||||
int iNumVerts; // ilość wierzchołków (gdy nie ma VBO, to m_nVertexCount=0)
|
||||
int iNumVerts; // ilość wierzchołków (gdy nie ma VBO, to m_nVertexCount=0)
|
||||
gfx::geometrybank_handle m_geometrybank;
|
||||
bool m_geometrycreated { false };
|
||||
private:
|
||||
std::vector<std::string> Textures; // nazwy tekstur
|
||||
std::vector<std::string> Names; // nazwy submodeli
|
||||
@@ -230,15 +235,16 @@ private:
|
||||
int iSubModelsCount; // Ra: używane do tworzenia binarnych
|
||||
std::string asBinary; // nazwa pod którą zapisać model binarny
|
||||
std::string m_filename;
|
||||
|
||||
public:
|
||||
TModel3d();
|
||||
~TModel3d();
|
||||
float bounding_radius() const {
|
||||
return (
|
||||
Root ?
|
||||
Root->m_boundingradius :
|
||||
0.f ); }
|
||||
inline TSubModel * GetSMRoot() { return (Root); };
|
||||
TModel3d();
|
||||
~TModel3d();
|
||||
TSubModel * GetFromName(std::string const &Name);
|
||||
TSubModel * AddToNamed(const char *Name, TSubModel *SubModel);
|
||||
void AddTo(TSubModel *tmp, TSubModel *SubModel);
|
||||
|
||||
4
Names.h
4
Names.h
@@ -53,10 +53,10 @@ public:
|
||||
protected:
|
||||
// types
|
||||
using type_sequence = std::deque<Type_ *>;
|
||||
using type_map = std::unordered_map<std::string, std::size_t>;
|
||||
using index_map = std::unordered_map<std::string, std::size_t>;
|
||||
// members
|
||||
type_sequence m_items;
|
||||
type_map m_itemmap;
|
||||
index_map m_itemmap;
|
||||
|
||||
public:
|
||||
// data access
|
||||
|
||||
@@ -8,6 +8,16 @@ http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
int const null_handle = 0;
|
||||
|
||||
enum class resource_state {
|
||||
none,
|
||||
loading,
|
||||
good,
|
||||
failed
|
||||
};
|
||||
|
||||
/*
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
@@ -56,6 +66,11 @@ class ResourceManager
|
||||
};
|
||||
*/
|
||||
|
||||
using resource_timestamp = std::chrono::steady_clock::time_point;
|
||||
|
||||
// takes containers providing access to specific element through operator[]
|
||||
// with elements of std::pair<resource *, resource_timestamp>
|
||||
// the element should provide method release() freeing resources owned by the element
|
||||
template <class Container_>
|
||||
class garbage_collector {
|
||||
|
||||
|
||||
@@ -359,7 +359,7 @@ Math3D::vector3 TSegment::FastGetPoint(double const t) const
|
||||
interpolate( Point1, Point2, t ) );
|
||||
}
|
||||
|
||||
bool TSegment::RenderLoft( vertex_array &Output, Math3D::vector3 const &Origin, const basic_vertex *ShapePoints, int iNumShapePoints, double fTextureLength, double Texturescale, int iSkip, int iEnd, float fOffsetX, glm::vec3 **p, bool bRender)
|
||||
bool TSegment::RenderLoft( gfx::vertex_array &Output, Math3D::vector3 const &Origin, const gfx::basic_vertex *ShapePoints, int iNumShapePoints, double fTextureLength, double Texturescale, int iSkip, int iEnd, float fOffsetX, glm::vec3 **p, bool bRender)
|
||||
{ // generowanie trójkątów dla odcinka trajektorii ruchu
|
||||
// standardowo tworzy triangle_strip dla prostego albo ich zestaw dla łuku
|
||||
// po modyfikacji - dla ujemnego (iNumShapePoints) w dodatkowych polach tabeli
|
||||
|
||||
@@ -97,7 +97,7 @@ public:
|
||||
r2 = fRoll2; }
|
||||
|
||||
bool
|
||||
RenderLoft( vertex_array &Output, Math3D::vector3 const &Origin, basic_vertex const *ShapePoints, int iNumShapePoints, double fTextureLength, double Texturescale = 1.0, int iSkip = 0, int iEnd = 0, float fOffsetX = 0.f, glm::vec3 **p = nullptr, bool bRender = true);
|
||||
RenderLoft( gfx::vertex_array &Output, Math3D::vector3 const &Origin, gfx::basic_vertex const *ShapePoints, int iNumShapePoints, double fTextureLength, double Texturescale = 1.0, int iSkip = 0, int iEnd = 0, float fOffsetX = 0.f, glm::vec3 **p = nullptr, bool bRender = true);
|
||||
void
|
||||
Render();
|
||||
inline
|
||||
|
||||
15
Texture.h
15
Texture.h
@@ -15,13 +15,6 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "GL/glew.h"
|
||||
#include "ResourceManager.h"
|
||||
|
||||
enum class resource_state {
|
||||
none,
|
||||
loading,
|
||||
good,
|
||||
failed
|
||||
};
|
||||
|
||||
struct opengl_texture {
|
||||
static DDSURFACEDESC2 deserialize_ddsd(std::istream&);
|
||||
static DDCOLORKEY deserialize_ddck(std::istream&);
|
||||
@@ -79,7 +72,6 @@ private:
|
||||
};
|
||||
|
||||
typedef int texture_handle;
|
||||
int const null_handle = 0;
|
||||
|
||||
class texture_manager {
|
||||
|
||||
@@ -89,13 +81,16 @@ public:
|
||||
|
||||
void
|
||||
assign_units( GLint const Helper, GLint const Shadows, GLint const Normals, GLint const Diffuse );
|
||||
// activates specified texture unit
|
||||
void
|
||||
unit( GLint const Textureunit );
|
||||
// creates texture object out of data stored in specified file
|
||||
texture_handle
|
||||
create( std::string Filename, bool const Loadnow = true );
|
||||
// binds specified texture to specified texture unit
|
||||
void
|
||||
bind( std::size_t const Unit, texture_handle const Texture );
|
||||
// provides direct access to specified texture object
|
||||
opengl_texture &
|
||||
texture( texture_handle const Texture ) const { return *(m_textures[ Texture ].first); }
|
||||
// performs a resource sweep
|
||||
@@ -109,7 +104,7 @@ private:
|
||||
// types:
|
||||
typedef std::pair<
|
||||
opengl_texture *,
|
||||
std::chrono::steady_clock::time_point > texturetimepoint_pair;
|
||||
resource_timestamp > texturetimepoint_pair;
|
||||
|
||||
typedef std::vector< texturetimepoint_pair > texturetimepointpair_sequence;
|
||||
|
||||
@@ -187,7 +182,7 @@ downsample( std::size_t const Width, std::size_t const Height, char *Imagedata )
|
||||
(*sampler)[idx]
|
||||
+ ( *( sampler + 1 ) )[idx]
|
||||
+ ( *( sampler + Width ) )[idx]
|
||||
+ (*( sampler + Width + 1 ))[idx] );
|
||||
+ ( *( sampler + Width + 1 ))[idx] );
|
||||
color[ idx ] = component /= 4;
|
||||
}
|
||||
*destination++ = color;
|
||||
|
||||
@@ -38,11 +38,6 @@ double GetDeltaRenderTime()
|
||||
return DeltaRenderTime;
|
||||
}
|
||||
|
||||
double GetfSinceStart()
|
||||
{
|
||||
return fSinceStart;
|
||||
}
|
||||
|
||||
void SetDeltaTime(double t)
|
||||
{
|
||||
DeltaTime = t;
|
||||
|
||||
2
Timer.h
2
Timer.h
@@ -16,8 +16,6 @@ double GetTime();
|
||||
double GetDeltaTime();
|
||||
double GetDeltaRenderTime();
|
||||
|
||||
double GetfSinceStart();
|
||||
|
||||
void SetDeltaTime(double v);
|
||||
|
||||
bool GetSoundTimer();
|
||||
|
||||
50
Track.cpp
50
Track.cpp
@@ -940,7 +940,7 @@ const int nnumPts = 12;
|
||||
// szyna - vextor6(x,y,mapowanie tekstury,xn,yn,zn)
|
||||
// tę wersję opracował Tolein (bez pochylenia)
|
||||
// TODO: profile definitions in external files
|
||||
basic_vertex const szyna[ nnumPts ] = {
|
||||
gfx::basic_vertex const szyna[ nnumPts ] = {
|
||||
{{ 0.111f, -0.180f, 0.f}, { 1.000f, 0.000f, 0.f}, {0.00f, 0.f}},
|
||||
{{ 0.046f, -0.150f, 0.f}, { 0.707f, 0.707f, 0.f}, {0.15f, 0.f}},
|
||||
{{ 0.044f, -0.050f, 0.f}, { 0.707f, -0.707f, 0.f}, {0.25f, 0.f}},
|
||||
@@ -957,7 +957,7 @@ basic_vertex const szyna[ nnumPts ] = {
|
||||
// iglica - vextor3(x,y,mapowanie tekstury)
|
||||
// 1 mm więcej, żeby nie nachodziły tekstury?
|
||||
// TODO: automatic generation from base profile TBD: reuse base profile?
|
||||
basic_vertex const iglica[ nnumPts ] = {
|
||||
gfx::basic_vertex const iglica[ nnumPts ] = {
|
||||
{{ 0.010f, -0.180f, 0.f}, { 1.000f, 0.000f, 0.f}, {0.00f, 0.f}},
|
||||
{{ 0.010f, -0.155f, 0.f}, { 1.000f, 0.000f, 0.f}, {0.15f, 0.f}},
|
||||
{{ 0.010f, -0.070f, 0.f}, { 1.000f, 0.000f, 0.f}, {0.25f, 0.f}},
|
||||
@@ -1062,7 +1062,7 @@ void TTrack::RaAssign( TAnimModel *am, TEvent *done, TEvent *joined )
|
||||
};
|
||||
|
||||
// wypełnianie tablic VBO
|
||||
void TTrack::create_geometry( geometrybank_handle const &Bank ) {
|
||||
void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) {
|
||||
// Ra: trzeba rozdzielić szyny od podsypki, aby móc grupować wg tekstur
|
||||
auto const fHTW = 0.5f * std::abs(fTrackWidth);
|
||||
auto const side = std::abs(fTexWidth); // szerokść podsypki na zewnątrz szyny albo pobocza
|
||||
@@ -1122,7 +1122,7 @@ void TTrack::create_geometry( geometrybank_handle const &Bank ) {
|
||||
sin2 = std::sin(roll2),
|
||||
cos2 = std::cos(roll2);
|
||||
// zwykla szyna: //Ra: czemu główki są asymetryczne na wysokości 0.140?
|
||||
basic_vertex rpts1[24], rpts2[24], rpts3[24], rpts4[24];
|
||||
gfx::basic_vertex rpts1[24], rpts2[24], rpts3[24], rpts4[24];
|
||||
for( int i = 0; i < 12; ++i ) {
|
||||
|
||||
rpts1[ i ] = {
|
||||
@@ -1186,7 +1186,7 @@ void TTrack::create_geometry( geometrybank_handle const &Bank ) {
|
||||
case tt_Normal:
|
||||
if (m_material2)
|
||||
{ // podsypka z podkładami jest tylko dla zwykłego toru
|
||||
basic_vertex bpts1[ 8 ]; // punkty głównej płaszczyzny nie przydają się do robienia boków
|
||||
gfx::basic_vertex bpts1[ 8 ]; // punkty głównej płaszczyzny nie przydają się do robienia boków
|
||||
if( fTexLength == 4.f ) {
|
||||
// stare mapowanie z różną gęstością pikseli i oddzielnymi teksturami na każdy profil
|
||||
auto const normalx = std::cos( glm::radians( 75.f ) );
|
||||
@@ -1314,7 +1314,7 @@ void TTrack::create_geometry( geometrybank_handle const &Bank ) {
|
||||
{0.5f + map12, 0.f} }; // prawy skos
|
||||
}
|
||||
}
|
||||
vertex_array vertices;
|
||||
gfx::vertex_array vertices;
|
||||
Segment->RenderLoft(vertices, m_origin, bpts1, iTrapezoid ? -4 : 4, fTexLength);
|
||||
if( ( Bank != 0 ) && ( true == Geometry2.empty() ) ) {
|
||||
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||
@@ -1326,7 +1326,7 @@ void TTrack::create_geometry( geometrybank_handle const &Bank ) {
|
||||
}
|
||||
if (m_material1)
|
||||
{ // szyny - generujemy dwie, najwyżej rysować się będzie jedną
|
||||
vertex_array vertices;
|
||||
gfx::vertex_array vertices;
|
||||
if( ( Bank != 0 ) && ( true == Geometry1.empty() ) ) {
|
||||
Segment->RenderLoft( vertices, m_origin, rpts1, iTrapezoid ? -nnumPts : nnumPts, fTexLength );
|
||||
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||
@@ -1347,7 +1347,7 @@ void TTrack::create_geometry( geometrybank_handle const &Bank ) {
|
||||
case tt_Switch: // dla zwrotnicy dwa razy szyny
|
||||
if( m_material1 || m_material2 ) {
|
||||
// iglice liczone tylko dla zwrotnic
|
||||
basic_vertex rpts3[24], rpts4[24];
|
||||
gfx::basic_vertex rpts3[24], rpts4[24];
|
||||
for( int i = 0; i < 12; ++i ) {
|
||||
|
||||
rpts3[ i ] = {
|
||||
@@ -1378,7 +1378,7 @@ void TTrack::create_geometry( geometrybank_handle const &Bank ) {
|
||||
// TODO, TBD: change all track geometry to triangles, to allow packing data in less, larger buffers
|
||||
if (SwitchExtension->RightSwitch)
|
||||
{ // nowa wersja z SPKS, ale odwrotnie lewa/prawa
|
||||
vertex_array vertices;
|
||||
gfx::vertex_array vertices;
|
||||
if( m_material1 ) {
|
||||
// fixed parts
|
||||
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts2, nnumPts, fTexLength );
|
||||
@@ -1408,7 +1408,7 @@ void TTrack::create_geometry( geometrybank_handle const &Bank ) {
|
||||
}
|
||||
else
|
||||
{ // lewa działa lepiej niż prawa
|
||||
vertex_array vertices;
|
||||
gfx::vertex_array vertices;
|
||||
if( m_material1 ) {
|
||||
// fixed parts
|
||||
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts1, nnumPts, fTexLength ); // lewa szyna normalna cała
|
||||
@@ -1446,7 +1446,7 @@ void TTrack::create_geometry( geometrybank_handle const &Bank ) {
|
||||
{
|
||||
case tt_Normal: // drogi proste, bo skrzyżowania osobno
|
||||
{
|
||||
basic_vertex bpts1[4]; // punkty głównej płaszczyzny przydają się do robienia boków
|
||||
gfx::basic_vertex bpts1[4]; // punkty głównej płaszczyzny przydają się do robienia boków
|
||||
if (m_material1 || m_material2) {
|
||||
// punkty się przydadzą, nawet jeśli nawierzchni nie ma
|
||||
/*
|
||||
@@ -1489,13 +1489,13 @@ void TTrack::create_geometry( geometrybank_handle const &Bank ) {
|
||||
}
|
||||
if (m_material1) // jeśli podana była tekstura, generujemy trójkąty
|
||||
{ // tworzenie trójkątów nawierzchni szosy
|
||||
vertex_array vertices;
|
||||
gfx::vertex_array vertices;
|
||||
Segment->RenderLoft(vertices, m_origin, bpts1, iTrapezoid ? -2 : 2, fTexLength);
|
||||
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||
}
|
||||
if (m_material2)
|
||||
{ // pobocze drogi - poziome przy przechyłce (a może krawężnik i chodnik zrobić jak w Midtown Madness 2?)
|
||||
basic_vertex
|
||||
gfx::basic_vertex
|
||||
rpts1[6],
|
||||
rpts2[6]; // współrzędne przekroju i mapowania dla prawej i lewej strony
|
||||
if (fTexHeight1 >= 0.f)
|
||||
@@ -1649,7 +1649,7 @@ void TTrack::create_geometry( geometrybank_handle const &Bank ) {
|
||||
{0.484375f - map2l, 0.f} }; // lewy brzeg lewego chodnika
|
||||
}
|
||||
}
|
||||
vertex_array vertices;
|
||||
gfx::vertex_array vertices;
|
||||
if( iTrapezoid ) // trapez albo przechyłki
|
||||
{ // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony
|
||||
// odcinka
|
||||
@@ -1728,7 +1728,7 @@ void TTrack::create_geometry( geometrybank_handle const &Bank ) {
|
||||
SwitchExtension->bPoints ?
|
||||
nullptr :
|
||||
SwitchExtension->vPoints; // zmienna robocza, NULL gdy tablica punktów już jest wypełniona
|
||||
basic_vertex bpts1[4]; // punkty głównej płaszczyzny przydają się do robienia boków
|
||||
gfx::basic_vertex bpts1[4]; // punkty głównej płaszczyzny przydają się do robienia boków
|
||||
if (m_material1 || m_material2) // punkty się przydadzą, nawet jeśli nawierzchni nie ma
|
||||
{ // double max=2.0*(fHTW>fHTW2?fHTW:fHTW2); //z szerszej strony jest 100%
|
||||
auto const max = fTexRatio1 * fTexLength; // test: szerokość proporcjonalna do długości
|
||||
@@ -1761,7 +1761,7 @@ void TTrack::create_geometry( geometrybank_handle const &Bank ) {
|
||||
// ale pobocza renderują się później, więc nawierzchnia nie załapuje się na renderowanie w swoim czasie
|
||||
if( m_material2 )
|
||||
{ // pobocze drogi - poziome przy przechyłce (a może krawężnik i chodnik zrobić jak w Midtown Madness 2?)
|
||||
basic_vertex
|
||||
gfx::basic_vertex
|
||||
rpts1[6],
|
||||
rpts2[6]; // współrzędne przekroju i mapowania dla prawej i lewej strony
|
||||
// Ra 2014-07: trzeba to przerobić na pętlę i pobierać profile (przynajmniej 2..4) z sąsiednich dróg
|
||||
@@ -1900,7 +1900,7 @@ void TTrack::create_geometry( geometrybank_handle const &Bank ) {
|
||||
}
|
||||
}
|
||||
bool render = ( m_material2 != 0 ); // renderować nie trzeba, ale trzeba wyznaczyć punkty brzegowe nawierzchni
|
||||
vertex_array vertices;
|
||||
gfx::vertex_array vertices;
|
||||
if (SwitchExtension->iRoads == 4)
|
||||
{ // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony odcinka
|
||||
if( ( fTexHeight1 >= 0.0 ) || ( side != 0.0 ) ) {
|
||||
@@ -1956,7 +1956,7 @@ void TTrack::create_geometry( geometrybank_handle const &Bank ) {
|
||||
}
|
||||
|
||||
if( m_material1 ) {
|
||||
vertex_array vertices;
|
||||
gfx::vertex_array vertices;
|
||||
// jeśli podana tekstura nawierzchni
|
||||
// we start with a vertex in the middle...
|
||||
vertices.emplace_back(
|
||||
@@ -2006,7 +2006,7 @@ void TTrack::create_geometry( geometrybank_handle const &Bank ) {
|
||||
{
|
||||
case tt_Normal: // drogi proste, bo skrzyżowania osobno
|
||||
{
|
||||
basic_vertex bpts1[4]; // punkty głównej płaszczyzny przydają się do robienia boków
|
||||
gfx::basic_vertex bpts1[4]; // punkty głównej płaszczyzny przydają się do robienia boków
|
||||
if (m_material1 || m_material2) // punkty się przydadzą, nawet jeśli nawierzchni nie ma
|
||||
{ // double max=2.0*(fHTW>fHTW2?fHTW:fHTW2); //z szerszej strony jest 100%
|
||||
auto const max = (
|
||||
@@ -2056,14 +2056,14 @@ void TTrack::create_geometry( geometrybank_handle const &Bank ) {
|
||||
}
|
||||
if (m_material1) // jeśli podana była tekstura, generujemy trójkąty
|
||||
{ // tworzenie trójkątów nawierzchni szosy
|
||||
vertex_array vertices;
|
||||
gfx::vertex_array vertices;
|
||||
Segment->RenderLoft(vertices, m_origin, bpts1, iTrapezoid ? -2 : 2, fTexLength);
|
||||
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||
}
|
||||
if (m_material2)
|
||||
{ // pobocze drogi - poziome przy przechyłce (a może krawężnik i chodnik zrobić jak w Midtown Madness 2?)
|
||||
vertex_array vertices;
|
||||
basic_vertex
|
||||
gfx::vertex_array vertices;
|
||||
gfx::basic_vertex
|
||||
rpts1[6],
|
||||
rpts2[6]; // współrzędne przekroju i mapowania dla prawej i lewej strony
|
||||
|
||||
@@ -2425,7 +2425,7 @@ TTrack * TTrack::RaAnimate()
|
||||
auto const fHTW2 = fHTW; // Ra: na razie niech tak będzie
|
||||
auto const cos1 = 1.0f, sin1 = 0.0f, cos2 = 1.0f, sin2 = 0.0f; // Ra: ...
|
||||
|
||||
basic_vertex
|
||||
gfx::basic_vertex
|
||||
rpts3[ 24 ],
|
||||
rpts4[ 24 ];
|
||||
for (int i = 0; i < 12; ++i) {
|
||||
@@ -2456,7 +2456,7 @@ TTrack * TTrack::RaAnimate()
|
||||
{szyna[ i ].texture.x, 0.f} };
|
||||
}
|
||||
|
||||
vertex_array vertices;
|
||||
gfx::vertex_array vertices;
|
||||
|
||||
if (SwitchExtension->RightSwitch)
|
||||
{ // nowa wersja z SPKS, ale odwrotnie lewa/prawa
|
||||
@@ -2520,7 +2520,7 @@ TTrack * TTrack::RaAnimate()
|
||||
dynamic->Move( 0.000001 );
|
||||
}
|
||||
// NOTE: passing empty handle is a bit of a hack here. could be refactored into something more elegant
|
||||
create_geometry( geometrybank_handle() );
|
||||
create_geometry( {} );
|
||||
} // animacja trwa nadal
|
||||
}
|
||||
else
|
||||
|
||||
4
Track.h
4
Track.h
@@ -147,7 +147,7 @@ private:
|
||||
glm::dvec3 m_origin;
|
||||
material_handle m_material1 = 0; // tekstura szyn albo nawierzchni
|
||||
material_handle m_material2 = 0; // tekstura automatycznej podsypki albo pobocza
|
||||
typedef std::vector<geometry_handle> geometryhandle_sequence;
|
||||
typedef std::vector<gfx::geometry_handle> geometryhandle_sequence;
|
||||
geometryhandle_sequence Geometry1; // geometry chunks textured with texture 1
|
||||
geometryhandle_sequence Geometry2; // geometry chunks textured with texture 2
|
||||
|
||||
@@ -245,7 +245,7 @@ public:
|
||||
std::vector<glm::dvec3>
|
||||
endpoints() const;
|
||||
|
||||
void create_geometry( geometrybank_handle const &Bank ); // wypełnianie VBO
|
||||
void create_geometry( gfx::geometrybank_handle const &Bank ); // wypełnianie VBO
|
||||
void RenderDynSounds(); // odtwarzanie dźwięków pojazdów jest niezależne od ich wyświetlania
|
||||
|
||||
void RaOwnerSet( scene::basic_cell *o ) {
|
||||
|
||||
@@ -175,18 +175,18 @@ TTraction::endpoints() const {
|
||||
}
|
||||
|
||||
std::size_t
|
||||
TTraction::create_geometry( geometrybank_handle const &Bank ) {
|
||||
TTraction::create_geometry( gfx::geometrybank_handle const &Bank ) {
|
||||
if( m_geometry != null_handle ) {
|
||||
return GfxRenderer.Vertices( m_geometry ).size() / 2;
|
||||
}
|
||||
|
||||
vertex_array vertices;
|
||||
gfx::vertex_array vertices;
|
||||
|
||||
double ddp = std::hypot( pPoint2.x - pPoint1.x, pPoint2.z - pPoint1.z );
|
||||
if( Wires == 2 )
|
||||
WireOffset = 0;
|
||||
// jezdny
|
||||
basic_vertex startvertex, endvertex;
|
||||
gfx::basic_vertex startvertex, endvertex;
|
||||
startvertex.position =
|
||||
glm::vec3(
|
||||
pPoint1.x - ( pPoint2.z / ddp - pPoint1.z / ddp ) * WireOffset - m_origin.x,
|
||||
|
||||
@@ -51,7 +51,7 @@ class TTraction : public editor::basic_node {
|
||||
int PowerState { 0 }; // type of incoming power, if any
|
||||
// visualization data
|
||||
glm::dvec3 m_origin;
|
||||
geometry_handle m_geometry;
|
||||
gfx::geometry_handle m_geometry;
|
||||
|
||||
explicit TTraction( scene::node_data const &Nodedata );
|
||||
|
||||
@@ -65,7 +65,7 @@ class TTraction : public editor::basic_node {
|
||||
endpoints() const;
|
||||
// creates geometry data in specified geometry bank. returns: number of created elements, or NULL
|
||||
// NOTE: deleting nodes doesn't currently release geometry data owned by the node. TODO: implement erasing individual geometry chunks and banks
|
||||
std::size_t create_geometry( geometrybank_handle const &Bank );
|
||||
std::size_t create_geometry( gfx::geometrybank_handle const &Bank );
|
||||
int TestPoint(glm::dvec3 const &Point);
|
||||
void Connect(int my, TTraction *with, int to);
|
||||
void Init();
|
||||
|
||||
86
Train.h
86
Train.h
@@ -14,6 +14,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "Button.h"
|
||||
#include "Gauge.h"
|
||||
#include "Spring.h"
|
||||
#include "sound.h"
|
||||
#include "PyInt.h"
|
||||
#include "command.h"
|
||||
|
||||
@@ -90,7 +91,7 @@ class TTrain
|
||||
void UpdateMechPosition(double dt);
|
||||
vector3 GetWorldMechPosition();
|
||||
bool Update( double const Deltatime );
|
||||
bool m_updated = false;
|
||||
void update_sounds( double const Deltatime );
|
||||
void MechStop();
|
||||
void SetLights();
|
||||
// McZapkie-310302: ladowanie parametrow z pliku
|
||||
@@ -101,6 +102,7 @@ class TTrain
|
||||
// types
|
||||
typedef void( *command_handler )( TTrain *Train, command_data const &Command );
|
||||
typedef std::unordered_map<user_command, command_handler> commandhandler_map;
|
||||
// methods
|
||||
// clears state of all cabin controls
|
||||
void clear_cab_controls();
|
||||
// sets cabin controls based on current state of the vehicle
|
||||
@@ -110,10 +112,6 @@ class TTrain
|
||||
bool initialize_gauge(cParser &Parser, std::string const &Label, int const Cabindex);
|
||||
// initializes a button matching provided label. returns: true if the label was found, false otherwise
|
||||
bool initialize_button(cParser &Parser, std::string const &Label, int const Cabindex);
|
||||
// plays specified sound, or fallback sound if the primary sound isn't presend
|
||||
// NOTE: temporary routine until sound system is sorted out and paired with switches
|
||||
void play_sound( sound* Sound, float gain = 1.0f);
|
||||
void play_sound( sound* Sound, sound* Fallbacksound, float gain = 1.0f );
|
||||
// helper, returns true for EMU with oerlikon brake
|
||||
bool is_eztoer() const;
|
||||
// command handlers
|
||||
@@ -229,7 +227,7 @@ public: // reszta może by?publiczna
|
||||
TGauge ggMainCtrl;
|
||||
TGauge ggMainCtrlAct;
|
||||
TGauge ggScndCtrl;
|
||||
TGauge ggScndCtrlButton;
|
||||
TGauge ggScndCtrlButton; // NOTE: not used?
|
||||
TGauge ggDirKey;
|
||||
TGauge ggBrakeCtrl;
|
||||
TGauge ggLocalBrake;
|
||||
@@ -308,8 +306,6 @@ public: // reszta może by?publiczna
|
||||
TGauge ggTrainHeatingButton;
|
||||
TGauge ggSignallingButton;
|
||||
TGauge ggDoorSignallingButton;
|
||||
// TGauge ggDistCounter; //Ra 2014-07: licznik kilometrów
|
||||
// TGauge ggVelocityDgt; //i od razu prędkościomierz
|
||||
|
||||
TButton btLampkaPoslizg;
|
||||
TButton btLampkaStyczn;
|
||||
@@ -356,7 +352,6 @@ public: // reszta może by?publiczna
|
||||
TButton btLampkaRadiotelefon;
|
||||
TButton btLampkaHamienie;
|
||||
TButton btLampkaED; // Stele 161228 hamowanie elektrodynamiczne
|
||||
TButton btLampkaJazda; // Ra: nie używane
|
||||
// KURS90
|
||||
TButton btLampkaBoczniki;
|
||||
TButton btLampkaMaxSila;
|
||||
@@ -384,8 +379,9 @@ public: // reszta może by?publiczna
|
||||
// Ra 2013-12: wirtualne "lampki" do odbijania na haslerze w PoKeys
|
||||
TButton btHaslerBrakes; // ciśnienie w cylindrach
|
||||
TButton btHaslerCurrent; // prąd na silnikach
|
||||
|
||||
/*
|
||||
vector3 pPosition;
|
||||
*/
|
||||
vector3 pMechOffset; // driverNpos
|
||||
vector3 vMechMovement;
|
||||
vector3 pMechPosition;
|
||||
@@ -403,48 +399,28 @@ public: // reszta może by?publiczna
|
||||
double fMechRoll;
|
||||
double fMechPitch;
|
||||
|
||||
sound* dsbNastawnikJazdy = nullptr;
|
||||
sound* dsbNastawnikBocz = nullptr; // hunter-081211
|
||||
sound* dsbRelay = nullptr;
|
||||
sound* dsbPneumaticRelay = nullptr;
|
||||
sound* dsbSwitch = nullptr;
|
||||
sound* dsbPneumaticSwitch = nullptr;
|
||||
sound* dsbReverserKey = nullptr; // hunter-121211
|
||||
sound_source dsbReverserKey { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE }; // hunter-121211
|
||||
sound_source dsbNastawnikJazdy { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE };
|
||||
sound_source dsbNastawnikBocz { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE }; // hunter-081211
|
||||
sound_source dsbSwitch { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE };
|
||||
sound_source dsbPneumaticSwitch { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE };
|
||||
|
||||
sound* dsbCouplerAttach = nullptr; // Ra: w kabinie????
|
||||
sound* dsbCouplerDetach = nullptr; // Ra: w kabinie???
|
||||
sound_source rsHiss { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE }; // upuszczanie
|
||||
sound_source rsHissU { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE }; // napelnianie
|
||||
sound_source rsHissE { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE }; // nagle
|
||||
sound_source rsHissX { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE }; // fala
|
||||
sound_source rsHissT { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE }; // czasowy
|
||||
sound_source rsSBHiss { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE }; // local
|
||||
sound_source rsSBHissU { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE }; // local, engage brakes
|
||||
float m_lastlocalbrakepressure { -1.f }; // helper, cached level of pressure in local brake cylinder
|
||||
float m_localbrakepressurechange { 0.f }; // recent change of pressure in local brake cylinder
|
||||
|
||||
sound* dsbDieselIgnition = nullptr; // Ra: w kabinie???
|
||||
sound_source rsFadeSound { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE };
|
||||
sound_source rsRunningNoise{ sound_placement::internal, 2 * EU07_SOUND_CABCONTROLSCUTOFFRANGE };
|
||||
|
||||
sound* dsbDoorClose = nullptr; // Ra: w kabinie???
|
||||
sound* dsbDoorOpen = nullptr; // Ra: w kabinie???
|
||||
|
||||
// Winger 010304
|
||||
sound* dsbPantUp = nullptr;
|
||||
sound* dsbPantDown = nullptr;
|
||||
|
||||
sound* dsbWejscie_na_bezoporow = nullptr;
|
||||
sound* dsbWejscie_na_drugi_uklad = nullptr; // hunter-081211: poprawka literowki
|
||||
|
||||
// sound* dsbHiss1;
|
||||
// sound* dsbHiss2;
|
||||
|
||||
// McZapkie-280302
|
||||
sound* rsBrake = nullptr;
|
||||
sound* rsSlippery = nullptr;
|
||||
sound* rsHiss = nullptr; // upuszczanie
|
||||
sound* rsHissU = nullptr; // napelnianie
|
||||
sound* rsHissE = nullptr; // nagle
|
||||
sound* rsHissX = nullptr; // fala
|
||||
sound* rsHissT = nullptr; // czasowy
|
||||
sound* rsSBHiss = nullptr;
|
||||
sound* rsRunningNoise = nullptr;
|
||||
sound* rsEngageSlippery = nullptr;
|
||||
sound* rsFadeSound = nullptr;
|
||||
|
||||
sound* dsbHasler = nullptr;
|
||||
sound* dsbBuzzer = nullptr;
|
||||
sound* dsbSlipAlarm = nullptr; // Bombardier 011010: alarm przy poslizgu dla 181/182
|
||||
sound_source dsbHasler { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE };
|
||||
sound_source dsbBuzzer { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE };
|
||||
sound_source dsbSlipAlarm { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE }; // Bombardier 011010: alarm przy poslizgu dla 181/182
|
||||
|
||||
int iCabLightFlag; // McZapkie:120503: oswietlenie kabiny (0: wyl, 1: przyciemnione, 2: pelne)
|
||||
bool bCabLight; // hunter-091012: czy swiatlo jest zapalone?
|
||||
@@ -453,11 +429,7 @@ public: // reszta może by?publiczna
|
||||
vector3 pMechSittingPosition; // ABu 180404
|
||||
vector3 MirrorPosition(bool lewe);
|
||||
|
||||
private:
|
||||
sound* dsbCouplerStretch = nullptr;
|
||||
sound* dsbEN57_CouplerStretch = nullptr;
|
||||
sound* dsbBufferClamp = nullptr;
|
||||
|
||||
private:
|
||||
double fBlinkTimer;
|
||||
float fHaslerTimer;
|
||||
float fConverterTimer; // hunter-261211: dla przekaznika
|
||||
@@ -465,7 +437,7 @@ public: // reszta może by?publiczna
|
||||
float fCzuwakTestTimer; // hunter-091012: do testu czuwaka
|
||||
float fLightsTimer; // yB 150617: timer do swiatel
|
||||
|
||||
int CAflag; // hunter-131211: dla osobnego zbijania CA i SHP
|
||||
bool CAflag { false }; // hunter-131211: dla osobnego zbijania CA i SHP
|
||||
|
||||
double fPoslizgTimer;
|
||||
TTrack *tor;
|
||||
@@ -495,7 +467,7 @@ public: // reszta może by?publiczna
|
||||
bool bHeat[8]; // grzanie
|
||||
// McZapkie: do syczenia
|
||||
float fPPress, fNPress;
|
||||
float fSPPress, fSNPress;
|
||||
// float fSPPress, fSNPress;
|
||||
int iSekunda; // Ra: sekunda aktualizacji pr?dko?ci
|
||||
int iRadioChannel; // numer aktualnego kana?u radiowego
|
||||
TPythonScreens pyScreens;
|
||||
@@ -506,7 +478,9 @@ public: // reszta może by?publiczna
|
||||
float fEIMParams[9][10]; // parametry dla silnikow asynchronicznych
|
||||
int RadioChannel() { return iRadioChannel; };
|
||||
inline TDynamicObject *Dynamic() { return DynamicObject; };
|
||||
inline TDynamicObject const *Dynamic() const { return DynamicObject; };
|
||||
inline TMoverParameters *Controlled() { return mvControlled; };
|
||||
inline TMoverParameters const *Controlled() const { return mvControlled; };
|
||||
void DynamicSet(TDynamicObject *d);
|
||||
void Silence();
|
||||
|
||||
|
||||
93
TrkFoll.cpp
93
TrkFoll.cpp
@@ -99,82 +99,73 @@ bool TTrackFollower::Move(double fDistance, bool bPrimary)
|
||||
bool bCanSkip; // czy przemieścić pojazd na inny tor
|
||||
while (true) // pętla wychodzi, gdy przesunięcie wyjdzie zerowe
|
||||
{ // pętla przesuwająca wózek przez kolejne tory, aż do trafienia w jakiś
|
||||
if (!pCurrentTrack)
|
||||
return false; // nie ma toru, to nie ma przesuwania
|
||||
if (pCurrentTrack->iEvents) // sumaryczna informacja o eventach
|
||||
{ // omijamy cały ten blok, gdy tor nie ma on żadnych eventów (większość nie ma)
|
||||
if (fDistance < 0)
|
||||
{
|
||||
if( pCurrentTrack == nullptr ) { return false; } // nie ma toru, to nie ma przesuwania
|
||||
// TODO: refactor following block as track method
|
||||
if( pCurrentTrack->iEvents ) { // sumaryczna informacja o eventach
|
||||
// omijamy cały ten blok, gdy tor nie ma on żadnych eventów (większość nie ma)
|
||||
if( ( std::abs( fDistance ) < 0.01 )
|
||||
&& ( Owner->GetVelocity() < 0.01 ) ) {
|
||||
//McZapkie-140602: wyzwalanie zdarzenia gdy pojazd stoi
|
||||
if( ( Owner->Mechanik != nullptr )
|
||||
&& ( Owner->Mechanik->Primary() ) ) {
|
||||
// tylko dla jednego członu
|
||||
if( ( pCurrentTrack->evEvent0 )
|
||||
&& ( pCurrentTrack->evEvent0->iQueued == 0 ) ) {
|
||||
simulation::Events.AddToQuery( pCurrentTrack->evEvent0, Owner );
|
||||
}
|
||||
}
|
||||
if( ( pCurrentTrack->evEventall0 )
|
||||
&& ( pCurrentTrack->evEventall0->iQueued == 0 ) ) {
|
||||
simulation::Events.AddToQuery( pCurrentTrack->evEventall0, Owner );
|
||||
}
|
||||
}
|
||||
else if (fDistance < 0) {
|
||||
// event1, eventall1
|
||||
if( SetFlag( iEventFlag, -1 ) ) {
|
||||
// zawsze zeruje flagę sprawdzenia, jak mechanik dosiądzie, to się nie wykona
|
||||
if( ( Owner->Mechanik != nullptr )
|
||||
&& ( Owner->Mechanik->Primary() ) ) {
|
||||
// tylko dla jednego członu
|
||||
// McZapkie-280503: wyzwalanie event tylko dla pojazdow z obsada
|
||||
if( ( bPrimary )
|
||||
&& ( pCurrentTrack->evEvent1 )
|
||||
&& ( !pCurrentTrack->evEvent1->iQueued ) ) {
|
||||
if( ( true == bPrimary )
|
||||
&& ( pCurrentTrack->evEvent1 != nullptr )
|
||||
&& ( pCurrentTrack->evEvent1->iQueued == 0 ) ) {
|
||||
// dodanie do kolejki
|
||||
simulation::Events.AddToQuery( pCurrentTrack->evEvent1, Owner );
|
||||
}
|
||||
}
|
||||
}
|
||||
// Owner->RaAxleEvent(pCurrentTrack->Event1); //Ra: dynamic zdecyduje, czy dodać do
|
||||
// kolejki
|
||||
// if (TestFlag(iEventallFlag,1))
|
||||
if (SetFlag(iEventallFlag,
|
||||
-1)) // McZapkie-280503: wyzwalanie eventall dla wszystkich pojazdow
|
||||
if (bPrimary && pCurrentTrack->evEventall1 &&
|
||||
(!pCurrentTrack->evEventall1->iQueued))
|
||||
simulation::Events.AddToQuery(pCurrentTrack->evEventall1, Owner); // dodanie do kolejki
|
||||
// Owner->RaAxleEvent(pCurrentTrack->Eventall1); //Ra: dynamic zdecyduje, czy dodać
|
||||
// do kolejki
|
||||
if( SetFlag( iEventallFlag, -1 ) ) {
|
||||
// McZapkie-280503: wyzwalanie eventall dla wszystkich pojazdow
|
||||
if( ( true == bPrimary )
|
||||
&& ( pCurrentTrack->evEventall1 != nullptr )
|
||||
&& ( pCurrentTrack->evEventall1->iQueued == 0 ) ) {
|
||||
simulation::Events.AddToQuery( pCurrentTrack->evEventall1, Owner ); // dodanie do kolejki
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (fDistance > 0)
|
||||
{
|
||||
else if (fDistance > 0) {
|
||||
// event2, eventall2
|
||||
if( SetFlag( iEventFlag, -2 ) ) {
|
||||
// zawsze ustawia flagę sprawdzenia, jak mechanik
|
||||
// dosiądzie, to się nie wykona
|
||||
// zawsze ustawia flagę sprawdzenia, jak mechanik dosiądzie, to się nie wykona
|
||||
if( ( Owner->Mechanik != nullptr )
|
||||
&& ( Owner->Mechanik->Primary() ) ) {
|
||||
// tylko dla jednego członu
|
||||
if( ( bPrimary )
|
||||
&& ( pCurrentTrack->evEvent2 )
|
||||
&& ( !pCurrentTrack->evEvent2->iQueued ) ) {
|
||||
if( ( true == bPrimary )
|
||||
&& ( pCurrentTrack->evEvent2 != nullptr )
|
||||
&& ( pCurrentTrack->evEvent2->iQueued == 0 ) ) {
|
||||
simulation::Events.AddToQuery( pCurrentTrack->evEvent2, Owner );
|
||||
}
|
||||
}
|
||||
}
|
||||
// Owner->RaAxleEvent(pCurrentTrack->Event2); //Ra: dynamic zdecyduje, czy dodać do
|
||||
// kolejki
|
||||
// if (TestFlag(iEventallFlag,2))
|
||||
if( SetFlag( iEventallFlag, -2 ) ) {
|
||||
// sprawdza i zeruje na przyszłość, true jeśli zmieni z 2 na 0
|
||||
if( ( bPrimary )
|
||||
&& ( pCurrentTrack->evEventall2 )
|
||||
&& ( !pCurrentTrack->evEventall2->iQueued ) ) {
|
||||
if( ( true == bPrimary )
|
||||
&& ( pCurrentTrack->evEventall2 != nullptr )
|
||||
&& ( pCurrentTrack->evEventall2->iQueued == 0 ) ) {
|
||||
simulation::Events.AddToQuery( pCurrentTrack->evEventall2, Owner );
|
||||
}
|
||||
}
|
||||
// Owner->RaAxleEvent(pCurrentTrack->Eventall2); //Ra: dynamic zdecyduje, czy dodać
|
||||
// do kolejki
|
||||
}
|
||||
else // if (fDistance==0) //McZapkie-140602: wyzwalanie zdarzenia gdy pojazd stoi
|
||||
{
|
||||
if( ( Owner->Mechanik != nullptr )
|
||||
&& ( Owner->Mechanik->Primary() ) ) {
|
||||
// tylko dla jednego członu
|
||||
if( pCurrentTrack->evEvent0 )
|
||||
if( !pCurrentTrack->evEvent0->iQueued )
|
||||
simulation::Events.AddToQuery( pCurrentTrack->evEvent0, Owner );
|
||||
}
|
||||
// Owner->RaAxleEvent(pCurrentTrack->Event0); //Ra: dynamic zdecyduje, czy dodać do
|
||||
// kolejki
|
||||
if (pCurrentTrack->evEventall0)
|
||||
if (!pCurrentTrack->evEventall0->iQueued)
|
||||
simulation::Events.AddToQuery(pCurrentTrack->evEventall0, Owner);
|
||||
// Owner->RaAxleEvent(pCurrentTrack->Eventall0); //Ra: dynamic zdecyduje, czy dodać
|
||||
// do kolejki
|
||||
}
|
||||
}
|
||||
if (!pCurrentSegment) // jeżeli nie ma powiązanego segmentu toru?
|
||||
|
||||
11
VBO.cpp
11
VBO.cpp
@@ -1,11 +0,0 @@
|
||||
/*
|
||||
This Source Code Form is subject to the
|
||||
terms of the Mozilla Public License, v.
|
||||
2.0. If a copy of the MPL was not
|
||||
distributed with this file, You can
|
||||
obtain one at
|
||||
http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "VBO.h"
|
||||
20
VBO.h
20
VBO.h
@@ -1,20 +0,0 @@
|
||||
/*
|
||||
This Source Code Form is subject to the
|
||||
terms of the Mozilla Public License, v.
|
||||
2.0. If a copy of the MPL was not
|
||||
distributed with this file, You can
|
||||
obtain one at
|
||||
http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "shader.h"
|
||||
|
||||
#include "openglgeometrybank.h"
|
||||
|
||||
class CMesh
|
||||
{
|
||||
public:
|
||||
geometrybank_handle m_geometrybank;
|
||||
bool m_geometrycreated { false };
|
||||
};
|
||||
98
World.cpp
98
World.cpp
@@ -94,7 +94,7 @@ simulation_time::init() {
|
||||
m_time.wSecond = 0;
|
||||
}
|
||||
|
||||
m_yearday = yearday( m_time.wDay, m_time.wMonth, m_time.wYear );
|
||||
m_yearday = year_day( m_time.wDay, m_time.wMonth, m_time.wYear );
|
||||
}
|
||||
|
||||
void
|
||||
@@ -142,16 +142,15 @@ simulation_time::update( double const Deltatime ) {
|
||||
}
|
||||
|
||||
int
|
||||
simulation_time::yearday( int Day, const int Month, const int Year ) {
|
||||
simulation_time::year_day( int Day, const int Month, const int Year ) const {
|
||||
|
||||
char daytab[ 2 ][ 13 ] = {
|
||||
char const daytab[ 2 ][ 13 ] = {
|
||||
{ 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
|
||||
{ 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
|
||||
};
|
||||
int i, leap;
|
||||
|
||||
leap = ( Year % 4 == 0 ) && ( Year % 100 != 0 ) || ( Year % 400 == 0 );
|
||||
for( i = 1; i < Month; ++i )
|
||||
int leap { ( Year % 4 == 0 ) && ( Year % 100 != 0 ) || ( Year % 400 == 0 ) };
|
||||
for( int i = 1; i < Month; ++i )
|
||||
Day += daytab[ leap ][ i ];
|
||||
|
||||
return Day;
|
||||
@@ -213,7 +212,6 @@ TWorld::TWorld()
|
||||
TWorld::~TWorld()
|
||||
{
|
||||
TrainDelete();
|
||||
// Ground.Free(); //Ra: usunięcie obiektów przed usunięciem dźwięków - sypie się
|
||||
}
|
||||
|
||||
void TWorld::TrainDelete(TDynamicObject *d)
|
||||
@@ -233,7 +231,6 @@ void TWorld::TrainDelete(TDynamicObject *d)
|
||||
Train = NULL;
|
||||
Controlled = NULL; // tego też już nie ma
|
||||
mvControlled = NULL;
|
||||
Global::pUserDynamic = NULL; // tego też nie ma
|
||||
};
|
||||
|
||||
bool TWorld::Init( GLFWwindow *Window ) {
|
||||
@@ -248,7 +245,6 @@ bool TWorld::Init( GLFWwindow *Window ) {
|
||||
WriteLog( "For online documentation and additional files refer to: http://eu07.pl");
|
||||
|
||||
UILayer.set_background( "logo" );
|
||||
|
||||
glfwSetWindowTitle( window, ( Global::AppName + " (" + Global::SceneryFile + ")" ).c_str() ); // nazwa scenerii
|
||||
UILayer.set_progress(0.01);
|
||||
UILayer.set_progress( "Loading scenery / Wczytywanie scenerii" );
|
||||
@@ -276,7 +272,6 @@ bool TWorld::Init( GLFWwindow *Window ) {
|
||||
{
|
||||
Controlled = Train->Dynamic();
|
||||
mvControlled = Controlled->ControlledFind()->MoverParameters;
|
||||
Global::pUserDynamic = Controlled; // renerowanie pojazdu względem kabiny
|
||||
WriteLog("Player train init OK");
|
||||
|
||||
glfwSetWindowTitle( window, ( Global::AppName + " (" + Controlled->MoverParameters->Name + " @ " + Global::SceneryFile + ")" ).c_str() );
|
||||
@@ -697,7 +692,7 @@ void TWorld::OnKeyDown(int cKey)
|
||||
vehicle->MoverParameters->DecBrakeMult())
|
||||
if (Train)
|
||||
{ // dźwięk oczywiście jest w kabinie
|
||||
Train->play_sound( Train->dsbSwitch );
|
||||
Train->dsbSwitch.play();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -725,7 +720,7 @@ void TWorld::OnKeyDown(int cKey)
|
||||
vehicle->iLights[CouplNr] = (vehicle->iLights[CouplNr] & ~mask) | set;
|
||||
if (Train)
|
||||
{ // Ra: ten dźwięk z kabiny to przegięcie, ale na razie zostawiam
|
||||
Train->play_sound( Train->dsbSwitch );
|
||||
Train->dsbSwitch.play();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -739,14 +734,6 @@ void TWorld::OnKeyDown(int cKey)
|
||||
if ((vehicle->MoverParameters->LocalBrake == ManualBrake) ||
|
||||
(vehicle->MoverParameters->MBrake == true))
|
||||
vehicle->MoverParameters->IncManualBrakeLevel(1);
|
||||
else
|
||||
;
|
||||
else if (vehicle->MoverParameters->LocalBrake != ManualBrake)
|
||||
if (vehicle->MoverParameters->IncLocalBrakeLevelFAST())
|
||||
if (Train)
|
||||
{ // dźwięk oczywiście jest w kabinie
|
||||
Train->play_sound( Train->dsbPneumaticRelay );
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (cKey == Global::Keys[k_DecLocalBrakeLevel])
|
||||
@@ -758,14 +745,6 @@ void TWorld::OnKeyDown(int cKey)
|
||||
if ((vehicle->MoverParameters->LocalBrake == ManualBrake) ||
|
||||
(vehicle->MoverParameters->MBrake == true))
|
||||
vehicle->MoverParameters->DecManualBrakeLevel(1);
|
||||
else
|
||||
;
|
||||
else if (vehicle->MoverParameters->LocalBrake != ManualBrake)
|
||||
if (vehicle->MoverParameters->DecLocalBrakeLevelFAST())
|
||||
if (Train)
|
||||
{ // dźwięk oczywiście jest w kabinie
|
||||
Train->play_sound( Train->dsbPneumaticRelay );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -781,7 +760,6 @@ void TWorld::InOutKey( bool const Near )
|
||||
FreeFlyModeFlag = !FreeFlyModeFlag; // zmiana widoku
|
||||
if (FreeFlyModeFlag) {
|
||||
// jeżeli poza kabiną, przestawiamy w jej okolicę - OK
|
||||
Global::pUserDynamic = NULL; // bez renderowania względem kamery
|
||||
if (Train) {
|
||||
// cache current cab position so there's no need to set it all over again after each out-in switch
|
||||
Train->pMechSittingPosition = Train->pMechOffset;
|
||||
@@ -797,7 +775,6 @@ void TWorld::InOutKey( bool const Near )
|
||||
{ // jazda w kabinie
|
||||
if (Train)
|
||||
{
|
||||
Global::pUserDynamic = Controlled; // renerowanie względem kamery
|
||||
Train->Dynamic()->bDisplayCab = true;
|
||||
Train->Dynamic()->ABuSetModelShake(
|
||||
vector3(0, 0, 0)); // zerowanie przesunięcia przed powrotem?
|
||||
@@ -909,7 +886,7 @@ bool TWorld::Update() {
|
||||
Timer::UpdateTimers(Global::iPause != 0);
|
||||
Timer::subsystem.sim_total.start();
|
||||
|
||||
if( (Global::iPause == false)
|
||||
if( (Global::iPause == 0)
|
||||
|| (m_init == false) ) {
|
||||
// jak pauza, to nie ma po co tego przeliczać
|
||||
simulation::Time.update( Timer::GetDeltaTime() );
|
||||
@@ -1072,18 +1049,11 @@ bool TWorld::Update() {
|
||||
|
||||
Update_Camera( dt );
|
||||
|
||||
{
|
||||
glm::dmat4 cam_matrix;
|
||||
Camera.SetMatrix(cam_matrix);
|
||||
|
||||
glm::vec3 pos(Camera.Pos.x, Camera.Pos.y, Camera.Pos.z);
|
||||
sound_man->set_listener(pos, glm::mat3(cam_matrix));
|
||||
sound_man->update(Global::iPause ? 0.0f : dt);
|
||||
}
|
||||
|
||||
Timer::subsystem.sim_total.stop();
|
||||
|
||||
simulation::Region->update_sounds();
|
||||
audio::renderer.update( Global::iPause ? 0.0 : dt );
|
||||
|
||||
GfxRenderer.Update( dt );
|
||||
ResourceSweep();
|
||||
|
||||
@@ -1138,6 +1108,8 @@ TWorld::Update_Camera( double const Deltatime ) {
|
||||
|
||||
if( DebugCameraFlag ) { DebugCamera.Update(); }
|
||||
else { Camera.Update(); } // uwzględnienie ruchu wywołanego klawiszami
|
||||
// reset window state, it'll be set again if applicable in a check below
|
||||
Global::CabWindowOpen = false;
|
||||
|
||||
if( ( Train != nullptr )
|
||||
&& ( Camera.Type == tp_Follow )
|
||||
@@ -1150,6 +1122,8 @@ TWorld::Update_Camera( double const Deltatime ) {
|
||||
&& ( (Console::Pressed( Global::Keys[ k_MechLeft ])
|
||||
|| (Console::Pressed( Global::Keys[ k_MechRight ]))))) {
|
||||
// jeśli lusterko lewe albo prawe (bez rzucania na razie)
|
||||
Global::CabWindowOpen = true;
|
||||
|
||||
bool lr = Console::Pressed( Global::Keys[ k_MechLeft ] );
|
||||
// Camera.Yaw powinno być wyzerowane, aby po powrocie patrzeć do przodu
|
||||
Camera.Pos = Controlled->GetPosition() + Train->MirrorPosition( lr ); // pozycja lusterka
|
||||
@@ -1159,12 +1133,10 @@ TWorld::Update_Camera( double const Deltatime ) {
|
||||
else if( Global::shiftState ) {
|
||||
// patrzenie w bok przez szybę
|
||||
Camera.LookAt = Camera.Pos - ( lr ? -1 : 1 ) * Train->Dynamic()->VectorLeft() * Train->Dynamic()->MoverParameters->ActiveCab;
|
||||
Global::SetCameraRotation( -modelrotate );
|
||||
}
|
||||
else { // patrzenie w kierunku osi pojazdu, z uwzględnieniem kabiny - jakby z lusterka,
|
||||
// ale bez odbicia
|
||||
Camera.LookAt = Camera.Pos - Train->GetDirection() * Train->Dynamic()->MoverParameters->ActiveCab; //-1 albo 1
|
||||
Global::SetCameraRotation( M_PI - modelrotate ); // tu już trzeba uwzględnić lusterka
|
||||
}
|
||||
Camera.Roll = std::atan( Train->pMechShake.x * Train->fMechRoll ); // hustanie kamery na boki
|
||||
Camera.Pitch = 0.5 * std::atan( Train->vMechVelocity.z * Train->fMechPitch ); // hustanie kamery przod tyl
|
||||
@@ -1197,11 +1169,10 @@ TWorld::Update_Camera( double const Deltatime ) {
|
||||
else // patrzenie w kierunku osi pojazdu, z uwzględnieniem kabiny
|
||||
Camera.LookAt = Train->GetWorldMechPosition() + Train->GetDirection() * 5.0 * Train->Dynamic()->MoverParameters->ActiveCab; //-1 albo 1
|
||||
Camera.vUp = Train->GetUp();
|
||||
Global::SetCameraRotation( Camera.Yaw - modelrotate ); // tu już trzeba uwzględnić lusterka
|
||||
}
|
||||
}
|
||||
else { // kamera nieruchoma
|
||||
Global::SetCameraRotation( Camera.Yaw - M_PI );
|
||||
else {
|
||||
// kamera nieruchoma
|
||||
}
|
||||
// all done, update camera position to the new value
|
||||
Global::pCameraPosition = Camera.Pos;
|
||||
@@ -1443,7 +1414,11 @@ TWorld::Update_UI() {
|
||||
+ ( vehicle->MoverParameters->bPantKurek3 ? "-ZG" : "|ZG" );
|
||||
|
||||
uitextline2 +=
|
||||
"; Ft: " + to_string( vehicle->MoverParameters->Ft * 0.001f * vehicle->MoverParameters->ActiveCab, 1 )
|
||||
"; Ft: " + to_string(
|
||||
vehicle->MoverParameters->Ft * 0.001f * (
|
||||
vehicle->MoverParameters->ActiveCab ? vehicle->MoverParameters->ActiveCab :
|
||||
vehicle->ctOwner ? vehicle->ctOwner->Controlling()->ActiveCab :
|
||||
1 ), 1 )
|
||||
+ ", Fb: " + to_string( vehicle->MoverParameters->Fb * 0.001f, 1 )
|
||||
+ ", Fr: " + to_string( vehicle->MoverParameters->Adhesive( vehicle->MoverParameters->RunningTrack.friction ), 2 )
|
||||
+ ( vehicle->MoverParameters->SlippingWheels ? " (!)" : "" );
|
||||
@@ -1645,21 +1620,25 @@ TWorld::Update_UI() {
|
||||
if( vehicle == nullptr ) {
|
||||
break;
|
||||
}
|
||||
uitextline1 =
|
||||
"vel: " + to_string(vehicle->GetVelocity(), 2) + "/" + to_string(vehicle->MoverParameters->nrot* M_PI * vehicle->MoverParameters->WheelDiameter * 3.6, 2)
|
||||
+ " km/h" + (vehicle->MoverParameters->SlippingWheels ? " (!)" : " ")
|
||||
+ "; dist: " + to_string(vehicle->MoverParameters->DistCounter, 2) + " km"
|
||||
+ "; pos: ("
|
||||
+ to_string(vehicle->GetPosition().x, 2) + ", "
|
||||
+ to_string(vehicle->GetPosition().y, 2) + ", "
|
||||
+ to_string(vehicle->GetPosition().z, 2) + "), PM="
|
||||
+ to_string(vehicle->MoverParameters->WheelFlat, 1) + " mm";
|
||||
uitextline1 =
|
||||
"vel: " + to_string( vehicle->GetVelocity(), 2 ) + "/" + to_string( vehicle->MoverParameters->nrot* M_PI * vehicle->MoverParameters->WheelDiameter * 3.6, 2 )
|
||||
+ " km/h;" + ( vehicle->MoverParameters->SlippingWheels ? " (!)" : " " )
|
||||
+ " dist: " + to_string( vehicle->MoverParameters->DistCounter, 2 ) + " km"
|
||||
+ "; pos: ("
|
||||
+ to_string( vehicle->GetPosition().x, 2 ) + ", "
|
||||
+ to_string( vehicle->GetPosition().y, 2 ) + ", "
|
||||
+ to_string( vehicle->GetPosition().z, 2 ) + "), PM="
|
||||
+ to_string( vehicle->MoverParameters->WheelFlat, 1 ) + " mm; enrot="
|
||||
+ to_string( vehicle->MoverParameters->enrot * 60, 0 ) + " tmrot="
|
||||
+ to_string( std::abs( vehicle->MoverParameters->nrot ) * vehicle->MoverParameters->Transmision.Ratio * 60, 0 );
|
||||
|
||||
uitextline2 =
|
||||
"HamZ=" + to_string( vehicle->MoverParameters->fBrakeCtrlPos, 2 )
|
||||
+ "; HamP=" + std::to_string( vehicle->MoverParameters->LocalBrakePos ) + "/" + to_string( vehicle->MoverParameters->LocalBrakePosA, 2 )
|
||||
+ "; NasJ=" + std::to_string( vehicle->MoverParameters->MainCtrlPos ) + "(" + std::to_string( vehicle->MoverParameters->MainCtrlActualPos ) + ")"
|
||||
+ "; NasB=" + std::to_string( vehicle->MoverParameters->ScndCtrlPos ) + "(" + std::to_string( vehicle->MoverParameters->ScndCtrlActualPos ) + ")"
|
||||
+ ( vehicle->MoverParameters->ShuntMode ?
|
||||
"; NasB=" + to_string( vehicle->MoverParameters->AnPos, 2 ) :
|
||||
"; NasB=" + std::to_string( vehicle->MoverParameters->ScndCtrlPos ) + "(" + std::to_string( vehicle->MoverParameters->ScndCtrlActualPos ) + ")" )
|
||||
+ "; I=" +
|
||||
( vehicle->MoverParameters->TrainType == dt_EZT ?
|
||||
std::to_string( int( vehicle->MoverParameters->ShowCurrent( 0 ) ) ) :
|
||||
@@ -2052,15 +2031,15 @@ void TWorld::CreateE3D(std::string const &Path, bool Dynamic)
|
||||
if( dynamic->iCabs ) { // jeśli ma jakąkolwiek kabinę
|
||||
delete Train;
|
||||
Train = new TTrain();
|
||||
if( dynamic->iCabs & 1 ) {
|
||||
if( dynamic->iCabs & 0x1 ) {
|
||||
dynamic->MoverParameters->ActiveCab = 1;
|
||||
Train->Init( dynamic, true );
|
||||
}
|
||||
if( dynamic->iCabs & 4 ) {
|
||||
if( dynamic->iCabs & 0x4 ) {
|
||||
dynamic->MoverParameters->ActiveCab = -1;
|
||||
Train->Init( dynamic, true );
|
||||
}
|
||||
if( dynamic->iCabs & 2 ) {
|
||||
if( dynamic->iCabs & 0x2 ) {
|
||||
dynamic->MoverParameters->ActiveCab = 0;
|
||||
Train->Init( dynamic, true );
|
||||
}
|
||||
@@ -2133,7 +2112,6 @@ void TWorld::ChangeDynamic() {
|
||||
Train->Dynamic()->asBaseDir +
|
||||
Train->Dynamic()->MoverParameters->TypeName + ".mmd" );
|
||||
if( !FreeFlyModeFlag ) {
|
||||
Global::pUserDynamic = Controlled; // renerowanie względem kamery
|
||||
Train->Dynamic()->bDisplayCab = true;
|
||||
Train->Dynamic()->ABuSetModelShake(
|
||||
vector3( 0, 0, 0 ) ); // zerowanie przesunięcia przed powrotem?
|
||||
|
||||
7
World.h
7
World.h
@@ -39,13 +39,13 @@ public:
|
||||
second() const { return ( m_time.wMilliseconds * 0.001 + m_time.wSecond ); }
|
||||
int
|
||||
year_day() const { return m_yearday; }
|
||||
// helper, calculates day of year from given date
|
||||
int
|
||||
year_day( int Day, int const Month, int const Year ) const;
|
||||
int
|
||||
julian_day() const;
|
||||
|
||||
private:
|
||||
// calculates day of year from given date
|
||||
int
|
||||
yearday( int Day, int const Month, int const Year );
|
||||
// calculates day and month from given day of year
|
||||
void
|
||||
daymonth( WORD &Day, WORD &Month, WORD const Year, WORD const Yearday );
|
||||
@@ -116,7 +116,6 @@ TWorld();
|
||||
// calculates current season of the year based on set simulation date
|
||||
void compute_season( int const Yearday ) const;
|
||||
|
||||
|
||||
private:
|
||||
void Update_Environment();
|
||||
void Update_Camera( const double Deltatime );
|
||||
|
||||
182
audio.cpp
Normal file
182
audio.cpp
Normal file
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
This Source Code Form is subject to the
|
||||
terms of the Mozilla Public License, v.
|
||||
2.0. If a copy of the MPL was not
|
||||
distributed with this file, You can
|
||||
obtain one at
|
||||
http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
#include "audio.h"
|
||||
#include "Globals.h"
|
||||
#include "McZapkie/mctools.h"
|
||||
#include "Logs.h"
|
||||
#include <sndfile.h>
|
||||
|
||||
namespace audio {
|
||||
|
||||
openal_buffer::openal_buffer( std::string const &Filename ) :
|
||||
name( Filename ) {
|
||||
|
||||
SF_INFO si;
|
||||
si.format = 0;
|
||||
|
||||
std::string file = Filename;
|
||||
std::replace(file.begin(), file.end(), '\\', '/');
|
||||
|
||||
SNDFILE *sf = sf_open(file.c_str(), SFM_READ, &si);
|
||||
if (sf == nullptr)
|
||||
throw std::runtime_error("sound: sf_open failed");
|
||||
|
||||
int16_t *fbuf = new int16_t[si.frames * si.channels];
|
||||
if (sf_readf_short(sf, fbuf, si.frames) != si.frames)
|
||||
throw std::runtime_error("sound: incomplete file");
|
||||
|
||||
sf_close(sf);
|
||||
|
||||
rate = si.samplerate;
|
||||
|
||||
int16_t *buf = nullptr;
|
||||
if (si.channels == 1)
|
||||
buf = fbuf;
|
||||
else
|
||||
{
|
||||
WriteLog("sound: warning: mixing multichannel file to mono");
|
||||
buf = new int16_t[si.frames];
|
||||
for (size_t i = 0; i < si.frames; i++)
|
||||
{
|
||||
int32_t accum = 0;
|
||||
for (size_t j = 0; j < si.channels; j++)
|
||||
accum += fbuf[i * si.channels + j];
|
||||
buf[i] = accum / si.channels;
|
||||
}
|
||||
}
|
||||
|
||||
id = 0;
|
||||
alGenBuffers(1, &id);
|
||||
if (!id)
|
||||
throw std::runtime_error("sound: cannot generate buffer");
|
||||
|
||||
alBufferData(id, AL_FORMAT_MONO16, buf, si.frames * 2, rate);
|
||||
|
||||
if (si.channels != 1)
|
||||
delete[] buf;
|
||||
delete[] fbuf;
|
||||
}
|
||||
|
||||
buffer_manager::~buffer_manager() {
|
||||
|
||||
for( auto &buffer : m_buffers ) {
|
||||
if( buffer.id != null_resource ) {
|
||||
::alDeleteBuffers( 1, &( buffer.id ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// creates buffer object out of data stored in specified file. returns: handle to the buffer or null_handle if creation failed
|
||||
audio::buffer_handle
|
||||
buffer_manager::create( std::string const &Filename ) {
|
||||
|
||||
auto filename { ToLower( Filename ) };
|
||||
|
||||
auto const dotpos { filename.rfind( '.' ) };
|
||||
if( ( dotpos != std::string::npos )
|
||||
&& ( dotpos != filename.rfind( ".." ) + 1 ) ) {
|
||||
// trim extension if there's one, but don't mistake folder traverse for extension
|
||||
filename.erase( dotpos );
|
||||
}
|
||||
// convert slashes
|
||||
std::replace(
|
||||
std::begin( filename ), std::end( filename ),
|
||||
'\\', '/' );
|
||||
|
||||
audio::buffer_handle lookup { null_handle };
|
||||
std::string filelookup;
|
||||
if( false == Global::asCurrentDynamicPath.empty() ) {
|
||||
// try dynamic-specific sounds first
|
||||
lookup = find_buffer( Global::asCurrentDynamicPath + filename );
|
||||
if( lookup != null_handle ) {
|
||||
return lookup;
|
||||
}
|
||||
filelookup = find_file( Global::asCurrentDynamicPath + filename );
|
||||
if( false == filelookup.empty() ) {
|
||||
return emplace( filelookup );
|
||||
}
|
||||
}
|
||||
if( filename.find( '/' ) != std::string::npos ) {
|
||||
// if the filename includes path, try to use it directly
|
||||
lookup = find_buffer( filename );
|
||||
if( lookup != null_handle ) {
|
||||
return lookup;
|
||||
}
|
||||
filelookup = find_file( filename );
|
||||
if( false == filelookup.empty() ) {
|
||||
return emplace( filelookup );
|
||||
}
|
||||
}
|
||||
// if dynamic-specific and/or direct lookups find nothing, try the default sound folder
|
||||
lookup = find_buffer( szSoundPath + filename );
|
||||
if( lookup != null_handle ) {
|
||||
return lookup;
|
||||
}
|
||||
filelookup = find_file( szSoundPath + filename );
|
||||
if( false == filelookup.empty() ) {
|
||||
return emplace( filelookup );
|
||||
}
|
||||
// if we still didn't find anything, give up
|
||||
ErrorLog( "Bad file: failed do locate audio file \"" + Filename + "\"" );
|
||||
return null_handle;
|
||||
}
|
||||
|
||||
// provides direct access to a specified buffer
|
||||
audio::openal_buffer const &
|
||||
buffer_manager::buffer( audio::buffer_handle const Buffer ) const {
|
||||
|
||||
return m_buffers[ Buffer ];
|
||||
}
|
||||
|
||||
// places in the bank a buffer containing data stored in specified file. returns: handle to the buffer
|
||||
audio::buffer_handle
|
||||
buffer_manager::emplace( std::string Filename ) {
|
||||
|
||||
buffer_handle const handle { m_buffers.size() };
|
||||
m_buffers.emplace_back( Filename );
|
||||
|
||||
// NOTE: we store mapping without file type extension, to simplify lookups
|
||||
m_buffermappings.emplace(
|
||||
Filename.erase( Filename.rfind( '.' ) ),
|
||||
handle );
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
audio::buffer_handle
|
||||
buffer_manager::find_buffer( std::string const &Buffername ) const {
|
||||
|
||||
auto lookup = m_buffermappings.find( Buffername );
|
||||
if( lookup != m_buffermappings.end() )
|
||||
return lookup->second;
|
||||
else
|
||||
return null_handle;
|
||||
}
|
||||
|
||||
|
||||
std::string
|
||||
buffer_manager::find_file( std::string const &Filename ) const {
|
||||
|
||||
std::vector<std::string> const extensions { ".wav", ".WAV", ".flac", ".ogg" };
|
||||
|
||||
for( auto const &extension : extensions ) {
|
||||
if( FileExists( Filename + extension ) ) {
|
||||
// valid name on success
|
||||
return Filename + extension;
|
||||
}
|
||||
}
|
||||
return {}; // empty string on failure
|
||||
}
|
||||
|
||||
} // audio
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
70
audio.h
Normal file
70
audio.h
Normal file
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
This Source Code Form is subject to the
|
||||
terms of the Mozilla Public License, v.
|
||||
2.0. If a copy of the MPL was not
|
||||
distributed with this file, You can
|
||||
obtain one at
|
||||
http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "al.h"
|
||||
#include "alc.h"
|
||||
|
||||
namespace audio {
|
||||
|
||||
ALuint const null_resource{ ~( ALuint { 0 } ) };
|
||||
|
||||
// wrapper for audio sample
|
||||
struct openal_buffer {
|
||||
// members
|
||||
ALuint id { null_resource }; // associated AL resource
|
||||
unsigned int rate { 0 }; // sample rate of the data
|
||||
std::string name;
|
||||
// constructors
|
||||
openal_buffer() = default;
|
||||
explicit openal_buffer( std::string const &Filename );
|
||||
};
|
||||
|
||||
using buffer_handle = std::size_t;
|
||||
|
||||
|
||||
//
|
||||
class buffer_manager {
|
||||
|
||||
public:
|
||||
// constructors
|
||||
buffer_manager() { m_buffers.emplace_back( openal_buffer() ); } // empty bindings for null buffer
|
||||
// destructor
|
||||
~buffer_manager();
|
||||
// methods
|
||||
// creates buffer object out of data stored in specified file. returns: handle to the buffer or null_handle if creation failed
|
||||
buffer_handle
|
||||
create( std::string const &Filename );
|
||||
// provides direct access to a specified buffer
|
||||
audio::openal_buffer const &
|
||||
buffer( audio::buffer_handle const Buffer ) const;
|
||||
|
||||
private:
|
||||
// types
|
||||
using buffer_sequence = std::vector<openal_buffer>;
|
||||
using index_map = std::unordered_map<std::string, std::size_t>;
|
||||
// methods
|
||||
// places in the bank a buffer containing data stored in specified file. returns: handle to the buffer
|
||||
buffer_handle
|
||||
emplace( std::string Filename );
|
||||
// checks whether specified buffer is in the buffer bank. returns: buffer handle, or null_handle.
|
||||
buffer_handle
|
||||
find_buffer( std::string const &Buffername ) const;
|
||||
// checks whether specified file exists. returns: name of the located file, or empty string.
|
||||
std::string
|
||||
find_file( std::string const &Filename ) const;
|
||||
// members
|
||||
buffer_sequence m_buffers;
|
||||
index_map m_buffermappings;
|
||||
};
|
||||
|
||||
} // audio
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
465
audiorenderer.cpp
Normal file
465
audiorenderer.cpp
Normal file
@@ -0,0 +1,465 @@
|
||||
/*
|
||||
This Source Code Form is subject to the
|
||||
terms of the Mozilla Public License, v.
|
||||
2.0. If a copy of the MPL was not
|
||||
distributed with this file, You can
|
||||
obtain one at
|
||||
http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
#include "audiorenderer.h"
|
||||
#include "sound.h"
|
||||
#include "Globals.h"
|
||||
#include "Logs.h"
|
||||
|
||||
namespace audio {
|
||||
|
||||
openal_renderer renderer;
|
||||
|
||||
float const EU07_SOUND_CUTOFFRANGE { 3000.f }; // 2750 m = max expected emitter spawn range, plus safety margin
|
||||
|
||||
// starts playback of queued buffers
|
||||
void
|
||||
openal_source::play() {
|
||||
|
||||
if( id == audio::null_resource ) { return; } // no implementation-side source to match, no point
|
||||
|
||||
::alSourcePlay( id );
|
||||
is_playing = true;
|
||||
}
|
||||
|
||||
// stops the playback
|
||||
void
|
||||
openal_source::stop() {
|
||||
|
||||
if( id == audio::null_resource ) { return; } // no implementation-side source to match, no point
|
||||
|
||||
loop( false );
|
||||
// NOTE: workaround for potential edge cases where ::alSourceStop() doesn't set source which wasn't yet started to AL_STOPPED
|
||||
int state;
|
||||
::alGetSourcei( id, AL_SOURCE_STATE, &state );
|
||||
if( state == AL_INITIAL ) {
|
||||
play();
|
||||
}
|
||||
::alSourceStop( id );
|
||||
is_playing = false;
|
||||
}
|
||||
|
||||
// updates state of the source
|
||||
void
|
||||
openal_source::update( double const Deltatime ) {
|
||||
|
||||
update_deltatime = Deltatime; // cached for time-based processing of data from the controller
|
||||
|
||||
if( id != audio::null_resource ) {
|
||||
|
||||
::alGetSourcei( id, AL_BUFFERS_PROCESSED, &sound_index );
|
||||
// for multipart sounds trim away processed sources until only one remains, the last one may be set to looping by the controller
|
||||
ALuint bufferid;
|
||||
while( ( sound_index > 0 )
|
||||
&& ( sounds.size() > 1 ) ) {
|
||||
::alSourceUnqueueBuffers( id, 1, &bufferid );
|
||||
sounds.erase( std::begin( sounds ) );
|
||||
--sound_index;
|
||||
}
|
||||
|
||||
int state;
|
||||
::alGetSourcei( id, AL_SOURCE_STATE, &state );
|
||||
is_playing = ( state == AL_PLAYING );
|
||||
}
|
||||
|
||||
// request instructions from the controller
|
||||
controller->update( *this );
|
||||
}
|
||||
|
||||
// configures state of the source to match the provided set of properties
|
||||
void
|
||||
openal_source::sync_with( sound_properties const &State ) {
|
||||
|
||||
if( id == audio::null_resource ) {
|
||||
// no implementation-side source to match, return sync error so the controller can clean up on its end
|
||||
sync = sync_state::bad_resource;
|
||||
return;
|
||||
}
|
||||
/*
|
||||
// velocity
|
||||
// not used yet
|
||||
glm::vec3 const velocity { ( State.location - properties.location ) / update_deltatime };
|
||||
*/
|
||||
// location
|
||||
properties.location = State.location;
|
||||
sound_distance = properties.location - glm::dvec3 { Global::pCameraPosition };
|
||||
if( sound_range > 0 ) {
|
||||
// range cutoff check
|
||||
auto const cutoffrange = (
|
||||
is_multipart ?
|
||||
EU07_SOUND_CUTOFFRANGE : // we keep multi-part sounds around longer, to minimize restarts as the sounds get out and back in range
|
||||
sound_range * 7.5f );
|
||||
if( glm::length2( sound_distance ) > std::min( ( cutoffrange * cutoffrange ), ( EU07_SOUND_CUTOFFRANGE * EU07_SOUND_CUTOFFRANGE ) ) ) {
|
||||
stop();
|
||||
sync = sync_state::bad_distance; // flag sync failure for the controller
|
||||
return;
|
||||
}
|
||||
}
|
||||
if( sound_range >= 0 ) {
|
||||
::alSourcefv( id, AL_POSITION, glm::value_ptr( sound_distance ) );
|
||||
}
|
||||
else {
|
||||
// sounds with 'unlimited' range are positioned on top of the listener
|
||||
::alSourcefv( id, AL_POSITION, glm::value_ptr( glm::vec3() ) );
|
||||
}
|
||||
// gain
|
||||
if( ( State.soundproofing_stamp != properties.soundproofing_stamp )
|
||||
|| ( State.gain != properties.gain ) ) {
|
||||
// gain value has changed
|
||||
properties.gain = State.gain;
|
||||
properties.soundproofing = State.soundproofing;
|
||||
properties.soundproofing_stamp = State.soundproofing_stamp;
|
||||
|
||||
::alSourcef( id, AL_GAIN, properties.gain * properties.soundproofing * Global::AudioVolume );
|
||||
}
|
||||
if( sound_range > 0 ) {
|
||||
auto const rangesquared { sound_range * sound_range };
|
||||
auto const distancesquared { glm::length2( sound_distance ) };
|
||||
if( ( distancesquared > rangesquared )
|
||||
|| ( false == is_in_range ) ) {
|
||||
// if the emitter is outside of its nominal hearing range or was outside of it during last check
|
||||
// adjust the volume to a suitable fraction of nominal value
|
||||
auto const fadedistance { sound_range * 0.75 };
|
||||
auto const rangefactor {
|
||||
interpolate(
|
||||
1.f, 0.f,
|
||||
clamp<float>(
|
||||
( distancesquared - rangesquared ) / ( fadedistance * fadedistance ),
|
||||
0.f, 1.f ) ) };
|
||||
::alSourcef( id, AL_GAIN, properties.gain * properties.soundproofing * rangefactor * Global::AudioVolume );
|
||||
}
|
||||
is_in_range = ( distancesquared <= rangesquared );
|
||||
}
|
||||
// pitch
|
||||
if( State.pitch != properties.pitch ) {
|
||||
// pitch value has changed
|
||||
properties.pitch = State.pitch;
|
||||
|
||||
::alSourcef( id, AL_PITCH, clamp( properties.pitch * pitch_variation, 0.1f, 10.f ) );
|
||||
}
|
||||
sync = sync_state::good;
|
||||
}
|
||||
|
||||
// sets max audible distance for sounds emitted by the source
|
||||
void
|
||||
openal_source::range( float const Range ) {
|
||||
|
||||
// NOTE: we cache actual specified range, as we'll be giving 'unlimited' range special treatment
|
||||
sound_range = Range;
|
||||
|
||||
if( id == audio::null_resource ) { return; } // no implementation-side source to match, no point
|
||||
|
||||
auto const range { (
|
||||
Range >= 0 ?
|
||||
Range :
|
||||
5 ) }; // range of -1 means sound of unlimited range, positioned at the listener
|
||||
::alSourcef( id, AL_REFERENCE_DISTANCE, range * ( 1.f / 16.f ) );
|
||||
::alSourcef( id, AL_ROLLOFF_FACTOR, 1.75f );
|
||||
}
|
||||
|
||||
// sets modifier applied to the pitch of sounds emitted by the source
|
||||
void
|
||||
openal_source::pitch( float const Pitch ) {
|
||||
|
||||
pitch_variation = Pitch;
|
||||
// invalidate current pitch value to enforce change of next syns
|
||||
properties.pitch = -1.f;
|
||||
}
|
||||
|
||||
// toggles looping of the sound emitted by the source
|
||||
void
|
||||
openal_source::loop( bool const State ) {
|
||||
|
||||
if( id == audio::null_resource ) { return; } // no implementation-side source to match, no point
|
||||
if( is_looping == State ) { return; }
|
||||
|
||||
is_looping = State;
|
||||
::alSourcei(
|
||||
id,
|
||||
AL_LOOPING,
|
||||
( State ?
|
||||
AL_TRUE :
|
||||
AL_FALSE ) );
|
||||
}
|
||||
|
||||
// releases bound buffers and resets state of the class variables
|
||||
// NOTE: doesn't release allocated implementation-side source
|
||||
void
|
||||
openal_source::clear() {
|
||||
|
||||
if( id != audio::null_resource ) {
|
||||
// unqueue bound buffers:
|
||||
// ensure no buffer is in use...
|
||||
stop();
|
||||
// ...prepare space for returned ids of unqueued buffers (not that we need that info)...
|
||||
std::vector<ALuint> bufferids;
|
||||
bufferids.resize( sounds.size() );
|
||||
// ...release the buffers...
|
||||
::alSourceUnqueueBuffers( id, bufferids.size(), bufferids.data() );
|
||||
}
|
||||
// ...and reset reset the properties, except for the id of the allocated source
|
||||
// NOTE: not strictly necessary since except for the id the source data typically get discarded in next step
|
||||
auto const sourceid { id };
|
||||
*this = openal_source();
|
||||
id = sourceid;
|
||||
}
|
||||
|
||||
|
||||
|
||||
openal_renderer::~openal_renderer() {
|
||||
|
||||
::alcMakeContextCurrent( nullptr );
|
||||
|
||||
if( m_context != nullptr ) { ::alcDestroyContext( m_context ); }
|
||||
if( m_device != nullptr ) { ::alcCloseDevice( m_device ); }
|
||||
}
|
||||
|
||||
audio::buffer_handle
|
||||
openal_renderer::fetch_buffer( std::string const &Filename ) {
|
||||
|
||||
return m_buffers.create( Filename );
|
||||
}
|
||||
|
||||
// provides direct access to a specified buffer
|
||||
audio::openal_buffer const &
|
||||
openal_renderer::buffer( audio::buffer_handle const Buffer ) const {
|
||||
|
||||
return m_buffers.buffer( Buffer );
|
||||
}
|
||||
|
||||
// initializes the service
|
||||
bool
|
||||
openal_renderer::init() {
|
||||
|
||||
if( true == m_ready ) {
|
||||
// already initialized and enabled
|
||||
return true;
|
||||
}
|
||||
if( false == init_caps() ) {
|
||||
// basic initialization failed
|
||||
return false;
|
||||
}
|
||||
//
|
||||
// ::alDistanceModel( AL_LINEAR_DISTANCE );
|
||||
::alDistanceModel( AL_INVERSE_DISTANCE_CLAMPED );
|
||||
::alListenerf( AL_GAIN, clamp( Global::AudioVolume, 1.f, 4.f ) );
|
||||
// all done
|
||||
m_ready = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
// removes from the queue all sounds controlled by the specified sound emitter
|
||||
void
|
||||
openal_renderer::erase( sound_source const *Controller ) {
|
||||
|
||||
auto source { std::begin( m_sources ) };
|
||||
while( source != std::end( m_sources ) ) {
|
||||
if( source->controller == Controller ) {
|
||||
// if the controller is the one specified, kill it
|
||||
source->clear();
|
||||
if( source->id != audio::null_resource ) {
|
||||
// keep around functional sources, but no point in doing it with the above-the-limit ones
|
||||
m_sourcespares.push( source->id );
|
||||
}
|
||||
source = m_sources.erase( source );
|
||||
}
|
||||
else {
|
||||
// otherwise proceed through the list normally
|
||||
++source;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// updates state of all active emitters
|
||||
void
|
||||
openal_renderer::update( double const Deltatime ) {
|
||||
|
||||
ALenum err = alGetError();
|
||||
if (err != AL_NO_ERROR)
|
||||
{
|
||||
std::string errname;
|
||||
if (err == AL_INVALID_NAME)
|
||||
errname = "AL_INVALID_NAME";
|
||||
else if (err == AL_INVALID_ENUM)
|
||||
errname = "AL_INVALID_ENUM";
|
||||
else if (err == AL_INVALID_VALUE)
|
||||
errname = "AL_INVALID_VALUE";
|
||||
else if (err == AL_INVALID_OPERATION)
|
||||
errname = "AL_INVALID_OPERATION";
|
||||
else if (err == AL_OUT_OF_MEMORY)
|
||||
errname = "AL_OUT_OF_MEMORY";
|
||||
else
|
||||
errname = "unknown";
|
||||
|
||||
ErrorLog("sound: al error: " + errname);
|
||||
}
|
||||
|
||||
if (Deltatime == 0.0)
|
||||
{
|
||||
if (alcDevicePauseSOFT)
|
||||
alcDevicePauseSOFT(m_device);
|
||||
return;
|
||||
}
|
||||
|
||||
if (alcDeviceResumeSOFT)
|
||||
alcDeviceResumeSOFT(m_device);
|
||||
|
||||
// update listener
|
||||
glm::dmat4 cameramatrix;
|
||||
Global::pCamera->SetMatrix( cameramatrix );
|
||||
auto rotationmatrix { glm::mat3{ cameramatrix } };
|
||||
glm::vec3 const orientation[] = {
|
||||
glm::vec3{ 0, 0,-1 } * rotationmatrix ,
|
||||
glm::vec3{ 0, 1, 0 } * rotationmatrix };
|
||||
::alListenerfv( AL_ORIENTATION, reinterpret_cast<ALfloat const *>( orientation ) );
|
||||
/*
|
||||
glm::dvec3 const listenerposition { Global::pCameraPosition };
|
||||
// not used yet
|
||||
glm::vec3 const velocity { ( listenerposition - m_listenerposition ) / Deltatime };
|
||||
m_listenerposition = listenerposition;
|
||||
*/
|
||||
|
||||
// update active emitters
|
||||
auto source { std::begin( m_sources ) };
|
||||
while( source != std::end( m_sources ) ) {
|
||||
// update each source
|
||||
source->update( Deltatime );
|
||||
// if after the update the source isn't playing, put it away on the spare stack, it's done
|
||||
if( false == source->is_playing ) {
|
||||
source->clear();
|
||||
if( source->id != audio::null_resource ) {
|
||||
// keep around functional sources, but no point in doing it with the above-the-limit ones
|
||||
m_sourcespares.push( source->id );
|
||||
}
|
||||
source = m_sources.erase( source );
|
||||
}
|
||||
else {
|
||||
// otherwise proceed through the list normally
|
||||
++source;
|
||||
}
|
||||
}
|
||||
|
||||
if (alProcessUpdatesSOFT)
|
||||
{
|
||||
alProcessUpdatesSOFT();
|
||||
alDeferUpdatesSOFT();
|
||||
}
|
||||
}
|
||||
|
||||
// returns an instance of implementation-side part of the sound emitter
|
||||
audio::openal_source
|
||||
openal_renderer::fetch_source() {
|
||||
|
||||
audio::openal_source newsource;
|
||||
if( false == m_sourcespares.empty() ) {
|
||||
// reuse (a copy of) already allocated source
|
||||
newsource.id = m_sourcespares.top();
|
||||
m_sourcespares.pop();
|
||||
}
|
||||
if( newsource.id == audio::null_resource ) {
|
||||
// if there's no source to reuse, try to generate a new one
|
||||
::alGenSources( 1, &( newsource.id ) );
|
||||
}
|
||||
if( newsource.id == audio::null_resource ) {
|
||||
// if we still don't have a working source, see if we can sacrifice an already active one
|
||||
// under presumption it's more important to play new sounds than keep the old ones going
|
||||
// TBD, TODO: for better results we could use range and/or position for the new sound
|
||||
// to better weight whether the new sound is really more important
|
||||
auto leastimportantsource { std::end( m_sources ) };
|
||||
auto leastimportantweight { std::numeric_limits<float>::max() };
|
||||
|
||||
for( auto source { std::begin( m_sources ) }; source != std::cend( m_sources ); ++source ) {
|
||||
|
||||
if( ( source->id == audio::null_resource )
|
||||
|| ( true == source->is_multipart )
|
||||
|| ( false == source->is_playing ) ) {
|
||||
|
||||
continue;
|
||||
}
|
||||
auto const sourceweight { (
|
||||
source->sound_range > 0 ?
|
||||
( source->sound_range * source->sound_range ) / ( glm::length2( source->sound_distance ) + 1 ) :
|
||||
std::numeric_limits<float>::max() ) };
|
||||
if( sourceweight < leastimportantweight ) {
|
||||
leastimportantsource = source;
|
||||
leastimportantweight = sourceweight;
|
||||
}
|
||||
}
|
||||
if( ( leastimportantsource != std::end( m_sources ) )
|
||||
&& ( leastimportantweight < 1.f ) ) {
|
||||
// only accept the candidate if it's outside of its nominal hearing range
|
||||
leastimportantsource->stop();
|
||||
leastimportantsource->update( 0 ); // HACK: a roundabout way to notify the controller its emitter has stopped
|
||||
leastimportantsource->clear();
|
||||
// we should be now free to grab the id and get rid of the remains
|
||||
newsource.id = leastimportantsource->id;
|
||||
m_sources.erase( leastimportantsource );
|
||||
}
|
||||
}
|
||||
|
||||
return newsource;
|
||||
}
|
||||
|
||||
bool
|
||||
openal_renderer::init_caps() {
|
||||
|
||||
// NOTE: default value of audio renderer variable is empty string, meaning argument of NULL i.e. 'preferred' device
|
||||
m_device = ::alcOpenDevice( Global::AudioRenderer.c_str() );
|
||||
if( m_device == nullptr ) {
|
||||
ErrorLog( "Failed to obtain audio device" );
|
||||
return false;
|
||||
}
|
||||
|
||||
ALCint versionmajor, versionminor;
|
||||
::alcGetIntegerv( m_device, ALC_MAJOR_VERSION, 1, &versionmajor );
|
||||
::alcGetIntegerv( m_device, ALC_MINOR_VERSION, 1, &versionminor );
|
||||
auto const oalversion { std::to_string( versionmajor ) + "." + std::to_string( versionminor ) };
|
||||
|
||||
WriteLog(
|
||||
"Audio Renderer: " + std::string { (char *)::alcGetString( m_device, ALC_DEVICE_SPECIFIER ) }
|
||||
+ " OpenAL Version: " + oalversion );
|
||||
|
||||
WriteLog( "Supported extensions: " + std::string{ (char *)::alcGetString( m_device, ALC_EXTENSIONS ) } );
|
||||
|
||||
ALCint attr[3] = { ALC_MONO_SOURCES, 50, 0 }; // request more sounds
|
||||
|
||||
m_context = ::alcCreateContext( m_device, attr );
|
||||
if( m_context == nullptr ) {
|
||||
ErrorLog( "Failed to create audio context" );
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!alcMakeContextCurrent(m_context))
|
||||
{
|
||||
ErrorLog("sound: cannot select context");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (alIsExtensionPresent("AL_SOFT_deferred_updates"))
|
||||
{
|
||||
alDeferUpdatesSOFT = (void(*)())alGetProcAddress("alDeferUpdatesSOFT");
|
||||
alProcessUpdatesSOFT = (void(*)())alGetProcAddress("alProcessUpdatesSOFT");
|
||||
}
|
||||
if (!alDeferUpdatesSOFT || !alProcessUpdatesSOFT)
|
||||
WriteLog("sound: warning: extension AL_SOFT_deferred_updates not found");
|
||||
|
||||
if (alcIsExtensionPresent(m_device, "ALC_SOFT_pause_device"))
|
||||
{
|
||||
alcDevicePauseSOFT = (void(*)(ALCdevice*))alcGetProcAddress(m_device, "alcDevicePauseSOFT");
|
||||
alcDeviceResumeSOFT = (void(*)(ALCdevice*))alcGetProcAddress(m_device, "alcDeviceResumeSOFT");
|
||||
}
|
||||
if (!alcDevicePauseSOFT || !alcDeviceResumeSOFT)
|
||||
WriteLog("sound: warning: extension ALC_SOFT_pause_device not found");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // audio
|
||||
196
audiorenderer.h
Normal file
196
audiorenderer.h
Normal file
@@ -0,0 +1,196 @@
|
||||
/*
|
||||
This Source Code Form is subject to the
|
||||
terms of the Mozilla Public License, v.
|
||||
2.0. If a copy of the MPL was not
|
||||
distributed with this file, You can
|
||||
obtain one at
|
||||
http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "audio.h"
|
||||
#include "ResourceManager.h"
|
||||
|
||||
class sound_source;
|
||||
|
||||
using uint32_sequence = std::vector<std::uint32_t>;
|
||||
|
||||
// sound emitter state sync item
|
||||
struct sound_properties {
|
||||
glm::dvec3 location;
|
||||
float gain { 1.f };
|
||||
float soundproofing { 1.f };
|
||||
std::uintptr_t soundproofing_stamp { ~( std::uintptr_t{ 0 } ) };
|
||||
float pitch { 1.f };
|
||||
};
|
||||
|
||||
enum class sync_state {
|
||||
good,
|
||||
bad_distance,
|
||||
bad_resource
|
||||
};
|
||||
|
||||
namespace audio {
|
||||
|
||||
// implementation part of the sound emitter
|
||||
// TODO: generic interface base, for implementations other than openAL
|
||||
struct openal_source {
|
||||
|
||||
friend class openal_renderer;
|
||||
|
||||
// types
|
||||
using buffer_sequence = std::vector<audio::buffer_handle>;
|
||||
|
||||
// members
|
||||
ALuint id { audio::null_resource }; // associated AL resource
|
||||
sound_source *controller { nullptr }; // source controller
|
||||
uint32_sequence sounds; //
|
||||
// buffer_sequence buffers; // sequence of samples the source will emit
|
||||
int sound_index { 0 }; // currently queued sample from the buffer sequence
|
||||
bool is_playing { false };
|
||||
bool is_looping { false };
|
||||
sound_properties properties;
|
||||
sync_state sync { sync_state::good };
|
||||
|
||||
// methods
|
||||
template <class Iterator_>
|
||||
openal_source &
|
||||
bind( sound_source *Controller, uint32_sequence Sounds, Iterator_ First, Iterator_ Last );
|
||||
// starts playback of queued buffers
|
||||
void
|
||||
play();
|
||||
// updates state of the source
|
||||
void
|
||||
update( double const Deltatime );
|
||||
// configures state of the source to match the provided set of properties
|
||||
void
|
||||
sync_with( sound_properties const &State );
|
||||
// stops the playback
|
||||
void
|
||||
stop();
|
||||
// toggles looping of the sound emitted by the source
|
||||
void
|
||||
loop( bool const State );
|
||||
// sets max audible distance for sounds emitted by the source
|
||||
void
|
||||
range( float const Range );
|
||||
// sets modifier applied to the pitch of sounds emitted by the source
|
||||
void
|
||||
pitch( float const Pitch );
|
||||
// releases bound buffers and resets state of the class variables
|
||||
// NOTE: doesn't release allocated implementation-side source
|
||||
void
|
||||
clear();
|
||||
|
||||
private:
|
||||
// members
|
||||
double update_deltatime; // time delta of most current update
|
||||
float pitch_variation { 1.f }; // emitter-specific variation of the base pitch
|
||||
float sound_range { 50.f }; // cached audible range of the emitted samples
|
||||
glm::vec3 sound_distance; // cached distance between sound and the listener
|
||||
bool is_in_range { false }; // helper, indicates the source was recently within audible range
|
||||
bool is_multipart { false }; // multi-part sounds are kept alive at longer ranges
|
||||
};
|
||||
|
||||
|
||||
|
||||
class openal_renderer {
|
||||
|
||||
friend class opengl_renderer;
|
||||
|
||||
public:
|
||||
// destructor
|
||||
~openal_renderer();
|
||||
// methods
|
||||
// buffer methods
|
||||
// returns handle to a buffer containing audio data from specified file
|
||||
audio::buffer_handle
|
||||
fetch_buffer( std::string const &Filename );
|
||||
// provides direct access to a specified buffer
|
||||
audio::openal_buffer const &
|
||||
buffer( audio::buffer_handle const Buffer ) const;
|
||||
// core methods
|
||||
// initializes the service
|
||||
bool
|
||||
init();
|
||||
// schedules playback of provided range of samples, under control of the specified sound emitter
|
||||
template <class Iterator_>
|
||||
void
|
||||
insert( Iterator_ First, Iterator_ Last, sound_source *Controller, uint32_sequence Sounds ) {
|
||||
m_sources.emplace_back( fetch_source().bind( Controller, Sounds, First, Last ) ); }
|
||||
// removes from the queue all sounds controlled by the specified sound emitter
|
||||
void
|
||||
erase( sound_source const *Controller );
|
||||
// updates state of all active emitters
|
||||
void
|
||||
update( double const Deltatime );
|
||||
|
||||
private:
|
||||
// types
|
||||
using source_list = std::list<audio::openal_source>;
|
||||
using source_sequence = std::stack<ALuint>;
|
||||
// methods
|
||||
bool
|
||||
init_caps();
|
||||
// returns an instance of implementation-side part of the sound emitter
|
||||
audio::openal_source
|
||||
fetch_source();
|
||||
// members
|
||||
ALCdevice * m_device { nullptr };
|
||||
ALCcontext * m_context { nullptr };
|
||||
bool m_ready { false }; // renderer is initialized and functional
|
||||
glm::dvec3 m_listenerposition;
|
||||
|
||||
buffer_manager m_buffers;
|
||||
// TBD: list of sources as vector, sorted by distance, for openal implementations with limited number of active sources?
|
||||
source_list m_sources;
|
||||
source_sequence m_sourcespares; // already created and currently unused sound sources
|
||||
|
||||
void (*alDeferUpdatesSOFT)() = nullptr;
|
||||
void (*alProcessUpdatesSOFT)() = nullptr;
|
||||
void (*alcDevicePauseSOFT)(ALCdevice*) = nullptr;
|
||||
void (*alcDeviceResumeSOFT)(ALCdevice*) = nullptr;
|
||||
};
|
||||
|
||||
extern openal_renderer renderer;
|
||||
|
||||
template <class Iterator_>
|
||||
openal_source &
|
||||
openal_source::bind( sound_source *Controller, uint32_sequence Sounds, Iterator_ First, Iterator_ Last ) {
|
||||
|
||||
controller = Controller;
|
||||
sounds = Sounds;
|
||||
// look up and queue assigned buffers
|
||||
std::vector<ALuint> buffers;
|
||||
std::for_each(
|
||||
First, Last,
|
||||
[&]( audio::buffer_handle const &buffer ) {
|
||||
buffers.emplace_back( audio::renderer.buffer( buffer ).id ); } );
|
||||
|
||||
if( id != audio::null_resource ) {
|
||||
::alSourceQueueBuffers( id, static_cast<ALsizei>( buffers.size() ), buffers.data() );
|
||||
::alSourceRewind( id );
|
||||
}
|
||||
is_multipart = ( buffers.size() > 1 );
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline
|
||||
float
|
||||
amplitude_to_db( float const Amplitude ) {
|
||||
|
||||
return 20.f * std::log10( Amplitude );
|
||||
}
|
||||
|
||||
inline
|
||||
float
|
||||
db_to_amplitude( float const Decibels ) {
|
||||
|
||||
return std::pow( 10.f, Decibels / 20.f );
|
||||
}
|
||||
|
||||
} // audio
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
2
dumb3d.h
2
dumb3d.h
@@ -166,7 +166,7 @@ class matrix4x4
|
||||
}
|
||||
|
||||
// Low-level access to the array.
|
||||
const scalar_t *readArray(void)
|
||||
const scalar_t *readArray(void) const
|
||||
{
|
||||
return e;
|
||||
}
|
||||
|
||||
@@ -103,7 +103,7 @@ material_manager::create( std::string const &Filename, bool const Loadnow ) {
|
||||
|
||||
// try to locate requested material in the databank
|
||||
auto const databanklookup = find_in_databank( filename );
|
||||
if( databanklookup != npos ) {
|
||||
if( databanklookup != null_handle ) {
|
||||
return databanklookup;
|
||||
}
|
||||
// if this fails, try to look for it on disk
|
||||
@@ -147,7 +147,7 @@ material_manager::find_in_databank( std::string const &Materialname ) const {
|
||||
return (
|
||||
lookup != m_materialmappings.end() ?
|
||||
lookup->second :
|
||||
npos );
|
||||
null_handle );
|
||||
}
|
||||
|
||||
// checks whether specified file exists.
|
||||
|
||||
@@ -55,7 +55,6 @@ private:
|
||||
std::string
|
||||
find_on_disk( std::string const &Materialname ) const;
|
||||
// members:
|
||||
material_handle const npos { -1 };
|
||||
material_sequence m_materials;
|
||||
index_map m_materialmappings;
|
||||
|
||||
|
||||
@@ -14,6 +14,8 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "Logs.h"
|
||||
#include "Globals.h"
|
||||
|
||||
namespace gfx {
|
||||
|
||||
void
|
||||
basic_vertex::serialize( std::ostream &s ) const {
|
||||
|
||||
@@ -47,14 +49,14 @@ basic_vertex::deserialize( std::istream &s ) {
|
||||
// generic geometry bank class, allows storage, update and drawing of geometry chunks
|
||||
|
||||
// creates a new geometry chunk of specified type from supplied vertex data. returns: handle to the chunk
|
||||
geometry_handle
|
||||
geometry_bank::create( vertex_array &Vertices, unsigned int const Type ) {
|
||||
gfx::geometry_handle
|
||||
geometry_bank::create( gfx::vertex_array const &Vertices, unsigned int const Type ) {
|
||||
|
||||
if( true == Vertices.empty() ) { return geometry_handle( 0, 0 ); }
|
||||
if( true == Vertices.empty() ) { return { 0, 0 }; }
|
||||
|
||||
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()) };
|
||||
gfx::geometry_handle chunkhandle { 0, static_cast<std::uint32_t>(m_chunks.size()) };
|
||||
// template method implementation
|
||||
create_( chunkhandle );
|
||||
// all done
|
||||
@@ -63,11 +65,11 @@ geometry_bank::create( vertex_array &Vertices, unsigned int const Type ) {
|
||||
|
||||
// replaces data of specified chunk with the supplied vertex data, starting from specified offset
|
||||
bool
|
||||
geometry_bank::replace( vertex_array &Vertices, geometry_handle const &Geometry, std::size_t const Offset ) {
|
||||
geometry_bank::replace( gfx::vertex_array &Vertices, gfx::geometry_handle const &Geometry, std::size_t const Offset ) {
|
||||
|
||||
if( ( Geometry.chunk == 0 ) || ( Geometry.chunk > m_chunks.size() ) ) { return false; }
|
||||
|
||||
auto &chunk = geometry_bank::chunk( Geometry );
|
||||
auto &chunk = gfx::geometry_bank::chunk( Geometry );
|
||||
|
||||
if( ( Offset == 0 )
|
||||
&& ( Vertices.size() == chunk.vertices.size() ) ) {
|
||||
@@ -78,7 +80,7 @@ geometry_bank::replace( vertex_array &Vertices, geometry_handle const &Geometry,
|
||||
// ...otherwise we need to do some legwork
|
||||
// NOTE: if the offset is larger than existing size of the chunk, it'll bridge the gap with 'blank' vertices
|
||||
// TBD: we could bail out with an error instead if such request occurs
|
||||
chunk.vertices.resize( Offset + Vertices.size(), basic_vertex() );
|
||||
chunk.vertices.resize( Offset + Vertices.size(), gfx::basic_vertex() );
|
||||
chunk.vertices.insert( std::end( chunk.vertices ), std::begin( Vertices ), std::end( Vertices ) );
|
||||
}
|
||||
// template method implementation
|
||||
@@ -89,16 +91,16 @@ geometry_bank::replace( vertex_array &Vertices, geometry_handle const &Geometry,
|
||||
|
||||
// adds supplied vertex data at the end of specified chunk
|
||||
bool
|
||||
geometry_bank::append( vertex_array &Vertices, geometry_handle const &Geometry ) {
|
||||
geometry_bank::append( gfx::vertex_array &Vertices, gfx::geometry_handle const &Geometry ) {
|
||||
|
||||
if( ( Geometry.chunk == 0 ) || ( Geometry.chunk > m_chunks.size() ) ) { return false; }
|
||||
|
||||
return replace( Vertices, Geometry, geometry_bank::chunk( Geometry ).vertices.size() );
|
||||
return replace( Vertices, Geometry, gfx::geometry_bank::chunk( Geometry ).vertices.size() );
|
||||
}
|
||||
|
||||
// draws geometry stored in specified chunk
|
||||
void
|
||||
geometry_bank::draw( geometry_handle const &Geometry, stream_units const &Units, unsigned int const Streams ) {
|
||||
geometry_bank::draw( gfx::geometry_handle const &Geometry, gfx::stream_units const &Units, unsigned int const Streams ) {
|
||||
// template method implementation
|
||||
draw_( Geometry, Units, Streams );
|
||||
}
|
||||
@@ -111,7 +113,7 @@ geometry_bank::release() {
|
||||
}
|
||||
|
||||
vertex_array const &
|
||||
geometry_bank::vertices( geometry_handle const &Geometry ) const {
|
||||
geometry_bank::vertices( gfx::geometry_handle const &Geometry ) const {
|
||||
|
||||
return geometry_bank::chunk( Geometry ).vertices;
|
||||
}
|
||||
@@ -119,12 +121,12 @@ geometry_bank::vertices( geometry_handle const &Geometry ) const {
|
||||
// opengl vbo-based variant of the geometry bank
|
||||
|
||||
GLuint opengl_vbogeometrybank::m_activebuffer { 0 }; // buffer bound currently on the opengl end, if any
|
||||
unsigned int opengl_vbogeometrybank::m_activestreams { stream::none }; // currently enabled data type pointers
|
||||
unsigned int opengl_vbogeometrybank::m_activestreams { gfx::stream::none }; // currently enabled data type pointers
|
||||
std::vector<GLint> opengl_vbogeometrybank::m_activetexturearrays; // currently enabled texture coord arrays
|
||||
|
||||
// create() subclass details
|
||||
void
|
||||
opengl_vbogeometrybank::create_( geometry_handle const &Geometry ) {
|
||||
opengl_vbogeometrybank::create_( gfx::geometry_handle const &Geometry ) {
|
||||
// adding a chunk means we'll be (re)building the buffer, which will fill the chunk records, amongst other things.
|
||||
// thus we don't need to initialize the values here
|
||||
m_chunkrecords.emplace_back( chunk_record() );
|
||||
@@ -134,7 +136,7 @@ opengl_vbogeometrybank::create_( geometry_handle const &Geometry ) {
|
||||
|
||||
// replace() subclass details
|
||||
void
|
||||
opengl_vbogeometrybank::replace_( geometry_handle const &Geometry ) {
|
||||
opengl_vbogeometrybank::replace_( gfx::geometry_handle const &Geometry ) {
|
||||
|
||||
auto &chunkrecord = m_chunkrecords[ Geometry.chunk - 1 ];
|
||||
chunkrecord.is_good = false;
|
||||
@@ -149,7 +151,7 @@ opengl_vbogeometrybank::replace_( geometry_handle const &Geometry ) {
|
||||
|
||||
// draw() subclass details
|
||||
void
|
||||
opengl_vbogeometrybank::draw_( geometry_handle const &Geometry, stream_units const &Units, unsigned int const Streams ) {
|
||||
opengl_vbogeometrybank::draw_( gfx::geometry_handle const &Geometry, gfx::stream_units const &Units, unsigned int const Streams ) {
|
||||
|
||||
if( m_buffer == 0 ) {
|
||||
// if there's no buffer, we'll have to make one
|
||||
@@ -176,7 +178,7 @@ opengl_vbogeometrybank::draw_( geometry_handle const &Geometry, stream_units con
|
||||
// TODO: allow to specify usage hint at the object creation, and pass it here
|
||||
::glBufferData(
|
||||
GL_ARRAY_BUFFER,
|
||||
datasize * sizeof( basic_vertex ),
|
||||
datasize * sizeof( gfx::basic_vertex ),
|
||||
nullptr,
|
||||
GL_STATIC_DRAW );
|
||||
if( ::glGetError() == GL_OUT_OF_MEMORY ) {
|
||||
@@ -193,13 +195,13 @@ opengl_vbogeometrybank::draw_( geometry_handle const &Geometry, stream_units con
|
||||
bind_buffer();
|
||||
}
|
||||
auto &chunkrecord = m_chunkrecords[ Geometry.chunk - 1 ];
|
||||
auto const &chunk = geometry_bank::chunk( Geometry );
|
||||
auto const &chunk = gfx::geometry_bank::chunk( Geometry );
|
||||
if( false == chunkrecord.is_good ) {
|
||||
// we may potentially need to upload new buffer data before we can draw it
|
||||
::glBufferSubData(
|
||||
GL_ARRAY_BUFFER,
|
||||
chunkrecord.offset * sizeof( basic_vertex ),
|
||||
chunkrecord.size * sizeof( basic_vertex ),
|
||||
chunkrecord.offset * sizeof( gfx::basic_vertex ),
|
||||
chunkrecord.size * sizeof( gfx::basic_vertex ),
|
||||
chunk.vertices.data() );
|
||||
chunkrecord.is_good = true;
|
||||
}
|
||||
@@ -229,7 +231,7 @@ opengl_vbogeometrybank::bind_buffer() {
|
||||
|
||||
::glBindBuffer( GL_ARRAY_BUFFER, m_buffer );
|
||||
m_activebuffer = m_buffer;
|
||||
m_activestreams = stream::none;
|
||||
m_activestreams = gfx::stream::none;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -250,34 +252,34 @@ opengl_vbogeometrybank::delete_buffer() {
|
||||
}
|
||||
|
||||
void
|
||||
opengl_vbogeometrybank::bind_streams( stream_units const &Units, unsigned int const Streams ) {
|
||||
opengl_vbogeometrybank::bind_streams( gfx::stream_units const &Units, unsigned int const Streams ) {
|
||||
|
||||
if( Streams & stream::position ) {
|
||||
::glVertexPointer( 3, GL_FLOAT, sizeof( basic_vertex ), static_cast<char *>( nullptr ) );
|
||||
if( Streams & gfx::stream::position ) {
|
||||
::glVertexPointer( 3, GL_FLOAT, sizeof( gfx::basic_vertex ), static_cast<char *>( nullptr ) );
|
||||
::glEnableClientState( GL_VERTEX_ARRAY );
|
||||
}
|
||||
else {
|
||||
::glDisableClientState( GL_VERTEX_ARRAY );
|
||||
}
|
||||
// NOTE: normal and color streams share the data, making them effectively mutually exclusive
|
||||
if( Streams & stream::normal ) {
|
||||
::glNormalPointer( GL_FLOAT, sizeof( basic_vertex ), static_cast<char *>( nullptr ) + sizeof( float ) * 3 );
|
||||
if( Streams & gfx::stream::normal ) {
|
||||
::glNormalPointer( GL_FLOAT, sizeof( gfx::basic_vertex ), static_cast<char *>( nullptr ) + sizeof( float ) * 3 );
|
||||
::glEnableClientState( GL_NORMAL_ARRAY );
|
||||
}
|
||||
else {
|
||||
::glDisableClientState( GL_NORMAL_ARRAY );
|
||||
}
|
||||
if( Streams & stream::color ) {
|
||||
::glColorPointer( 3, GL_FLOAT, sizeof( basic_vertex ), static_cast<char *>( nullptr ) + sizeof( float ) * 3 );
|
||||
if( Streams & gfx::stream::color ) {
|
||||
::glColorPointer( 3, GL_FLOAT, sizeof( gfx::basic_vertex ), static_cast<char *>( nullptr ) + sizeof( float ) * 3 );
|
||||
::glEnableClientState( GL_COLOR_ARRAY );
|
||||
}
|
||||
else {
|
||||
::glDisableClientState( GL_COLOR_ARRAY );
|
||||
}
|
||||
if( Streams & stream::texture ) {
|
||||
if( Streams & gfx::stream::texture ) {
|
||||
for( auto unit : Units.texture ) {
|
||||
::glClientActiveTexture( unit );
|
||||
::glTexCoordPointer( 2, GL_FLOAT, sizeof( basic_vertex ), static_cast<char *>( nullptr ) + 24 );
|
||||
::glTexCoordPointer( 2, GL_FLOAT, sizeof( gfx::basic_vertex ), static_cast<char *>( nullptr ) + 24 );
|
||||
::glEnableClientState( GL_TEXTURE_COORD_ARRAY );
|
||||
}
|
||||
m_activetexturearrays = Units.texture;
|
||||
@@ -304,7 +306,7 @@ opengl_vbogeometrybank::release_streams() {
|
||||
::glDisableClientState( GL_TEXTURE_COORD_ARRAY );
|
||||
}
|
||||
|
||||
m_activestreams = stream::none;
|
||||
m_activestreams = gfx::stream::none;
|
||||
m_activetexturearrays.clear();
|
||||
}
|
||||
|
||||
@@ -312,21 +314,21 @@ opengl_vbogeometrybank::release_streams() {
|
||||
|
||||
// create() subclass details
|
||||
void
|
||||
opengl_dlgeometrybank::create_( geometry_handle const &Geometry ) {
|
||||
opengl_dlgeometrybank::create_( gfx::geometry_handle const &Geometry ) {
|
||||
|
||||
m_chunkrecords.emplace_back( chunk_record() );
|
||||
}
|
||||
|
||||
// replace() subclass details
|
||||
void
|
||||
opengl_dlgeometrybank::replace_( geometry_handle const &Geometry ) {
|
||||
opengl_dlgeometrybank::replace_( gfx::geometry_handle const &Geometry ) {
|
||||
|
||||
delete_list( Geometry );
|
||||
}
|
||||
|
||||
// draw() subclass details
|
||||
void
|
||||
opengl_dlgeometrybank::draw_( geometry_handle const &Geometry, stream_units const &Units, unsigned int const Streams ) {
|
||||
opengl_dlgeometrybank::draw_( gfx::geometry_handle const &Geometry, gfx::stream_units const &Units, unsigned int const Streams ) {
|
||||
|
||||
auto &chunkrecord = m_chunkrecords[ Geometry.chunk - 1 ];
|
||||
if( chunkrecord.streams != Streams ) {
|
||||
@@ -336,15 +338,15 @@ opengl_dlgeometrybank::draw_( geometry_handle const &Geometry, stream_units cons
|
||||
// we don't have a list ready, so compile one
|
||||
chunkrecord.streams = Streams;
|
||||
chunkrecord.list = ::glGenLists( 1 );
|
||||
auto const &chunk = geometry_bank::chunk( Geometry );
|
||||
auto const &chunk = gfx::geometry_bank::chunk( Geometry );
|
||||
::glNewList( chunkrecord.list, GL_COMPILE );
|
||||
|
||||
::glBegin( chunk.type );
|
||||
for( auto const &vertex : chunk.vertices ) {
|
||||
if( Streams & stream::normal ) { ::glNormal3fv( glm::value_ptr( vertex.normal ) ); }
|
||||
else if( Streams & stream::color ) { ::glColor3fv( glm::value_ptr( vertex.normal ) ); }
|
||||
if( Streams & stream::texture ) { for( auto unit : Units.texture ) { ::glMultiTexCoord2fv( unit, glm::value_ptr( vertex.texture ) ); } }
|
||||
if( Streams & stream::position ) { ::glVertex3fv( glm::value_ptr( vertex.position ) ); }
|
||||
if( Streams & gfx::stream::normal ) { ::glNormal3fv( glm::value_ptr( vertex.normal ) ); }
|
||||
else if( Streams & gfx::stream::color ) { ::glColor3fv( glm::value_ptr( vertex.normal ) ); }
|
||||
if( Streams & gfx::stream::texture ) { for( auto unit : Units.texture ) { ::glMultiTexCoord2fv( unit, glm::value_ptr( vertex.texture ) ); } }
|
||||
if( Streams & gfx::stream::position ) { ::glVertex3fv( glm::value_ptr( vertex.position ) ); }
|
||||
}
|
||||
::glEnd();
|
||||
::glEndList();
|
||||
@@ -362,19 +364,19 @@ opengl_dlgeometrybank::release_() {
|
||||
::glDeleteLists( chunkrecord.list, 1 );
|
||||
chunkrecord.list = 0;
|
||||
}
|
||||
chunkrecord.streams = stream::none;
|
||||
chunkrecord.streams = gfx::stream::none;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
opengl_dlgeometrybank::delete_list( geometry_handle const &Geometry ) {
|
||||
opengl_dlgeometrybank::delete_list( gfx::geometry_handle const &Geometry ) {
|
||||
// NOTE: given it's our own internal method we trust it to be called with valid parameters
|
||||
auto &chunkrecord = m_chunkrecords[ Geometry.chunk - 1 ];
|
||||
if( chunkrecord.list != 0 ) {
|
||||
::glDeleteLists( chunkrecord.list, 1 );
|
||||
chunkrecord.list = 0;
|
||||
}
|
||||
chunkrecord.streams = stream::none;
|
||||
chunkrecord.streams = gfx::stream::none;
|
||||
}
|
||||
|
||||
// geometry bank manager, holds collection of geometry banks
|
||||
@@ -387,40 +389,40 @@ geometrybank_manager::update() {
|
||||
}
|
||||
|
||||
// creates a new geometry bank. returns: handle to the bank or NULL
|
||||
geometrybank_handle
|
||||
gfx::geometrybank_handle
|
||||
geometrybank_manager::create_bank() {
|
||||
|
||||
m_geometrybanks.emplace_back( std::make_shared<opengl_vbogeometrybank>(), 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 );
|
||||
return { static_cast<std::uint32_t>( m_geometrybanks.size() ), 0 };
|
||||
}
|
||||
|
||||
// creates a new geometry chunk of specified type from supplied vertex data, in specified bank. returns: handle to the chunk or NULL
|
||||
geometry_handle
|
||||
geometrybank_manager::create_chunk( vertex_array &Vertices, geometrybank_handle const &Geometry, int const Type ) {
|
||||
gfx::geometry_handle
|
||||
geometrybank_manager::create_chunk( gfx::vertex_array const &Vertices, gfx::geometrybank_handle const &Geometry, int const 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 ); }
|
||||
if( newchunkhandle.chunk != 0 ) { return { Geometry.bank, newchunkhandle.chunk }; }
|
||||
else { return { 0, 0 }; }
|
||||
}
|
||||
|
||||
// replaces data of specified chunk with the supplied vertex data, starting from specified offset
|
||||
bool
|
||||
geometrybank_manager::replace( vertex_array &Vertices, geometry_handle const &Geometry, std::size_t const Offset ) {
|
||||
geometrybank_manager::replace( gfx::vertex_array &Vertices, gfx::geometry_handle const &Geometry, std::size_t const 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 ) {
|
||||
geometrybank_manager::append( gfx::vertex_array &Vertices, gfx::geometry_handle const &Geometry ) {
|
||||
|
||||
return bank( Geometry ).first->append( Vertices, Geometry );
|
||||
}
|
||||
// draws geometry stored in specified chunk
|
||||
void
|
||||
geometrybank_manager::draw( geometry_handle const &Geometry, unsigned int const Streams ) {
|
||||
geometrybank_manager::draw( gfx::geometry_handle const &Geometry, unsigned int const Streams ) {
|
||||
|
||||
if( Geometry == null_handle ) { return; }
|
||||
|
||||
@@ -431,8 +433,10 @@ geometrybank_manager::draw( geometry_handle const &Geometry, unsigned int const
|
||||
}
|
||||
|
||||
// provides direct access to vertex data of specfied chunk
|
||||
vertex_array const &
|
||||
geometrybank_manager::vertices( geometry_handle const &Geometry ) const {
|
||||
gfx::vertex_array const &
|
||||
geometrybank_manager::vertices( gfx::geometry_handle const &Geometry ) const {
|
||||
|
||||
return bank( Geometry ).first->vertices( Geometry );
|
||||
}
|
||||
|
||||
} // namespace gfx
|
||||
|
||||
@@ -18,6 +18,8 @@ http://mozilla.org/MPL/2.0/.
|
||||
#endif
|
||||
#include "ResourceManager.h"
|
||||
|
||||
namespace gfx {
|
||||
|
||||
struct basic_vertex {
|
||||
|
||||
glm::vec3 position; // 3d space
|
||||
@@ -93,38 +95,37 @@ public:
|
||||
|
||||
// methods:
|
||||
// creates a new geometry chunk of specified type from supplied vertex data. returns: handle to the chunk or NULL
|
||||
geometry_handle
|
||||
create( vertex_array &Vertices, unsigned int const Type );
|
||||
gfx::geometry_handle
|
||||
create( gfx::vertex_array const &Vertices, unsigned int const Type );
|
||||
// replaces data of specified chunk with the supplied vertex data, starting from specified offset
|
||||
bool
|
||||
replace( vertex_array &Vertices, geometry_handle const &Geometry, std::size_t const Offset = 0 );
|
||||
replace( gfx::vertex_array &Vertices, gfx::geometry_handle const &Geometry, std::size_t const Offset = 0 );
|
||||
// adds supplied vertex data at the end of specified chunk
|
||||
bool
|
||||
append( vertex_array &Vertices, geometry_handle const &Geometry );
|
||||
append( gfx::vertex_array &Vertices, gfx::geometry_handle const &Geometry );
|
||||
// draws geometry stored in specified chunk
|
||||
void
|
||||
draw( geometry_handle const &Geometry, stream_units const &Units, unsigned int const Streams = basic_streams );
|
||||
draw( gfx::geometry_handle const &Geometry, gfx::stream_units const &Units, unsigned int const Streams = basic_streams );
|
||||
// draws geometry stored in supplied list of chunks
|
||||
template <typename Iterator_>
|
||||
void
|
||||
draw( Iterator_ First, Iterator_ Last, stream_units const &Units, unsigned int const Streams = basic_streams ) { while( First != Last ) { draw( *First, Units, Streams ); ++First; } }
|
||||
draw( Iterator_ First, Iterator_ Last, gfx::stream_units const &Units, unsigned int const Streams = basic_streams ) { while( First != Last ) { draw( *First, Units, 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;
|
||||
gfx::vertex_array const &
|
||||
vertices( gfx::geometry_handle const &Geometry ) const;
|
||||
|
||||
protected:
|
||||
// types:
|
||||
struct geometry_chunk {
|
||||
unsigned int type; // kind of geometry used by the chunk
|
||||
vertex_array vertices; // geometry data
|
||||
// NOTE: constructor doesn't copy provided vertex data, but moves it
|
||||
geometry_chunk( vertex_array &Vertices, unsigned int Type ) :
|
||||
type( Type )
|
||||
gfx::vertex_array vertices; // geometry data
|
||||
geometry_chunk( gfx::vertex_array const &Vertices, unsigned int Type ) :
|
||||
type( Type )
|
||||
{
|
||||
vertices.swap( Vertices );
|
||||
vertices = Vertices;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -133,11 +134,11 @@ protected:
|
||||
// methods
|
||||
inline
|
||||
geometry_chunk &
|
||||
chunk( geometry_handle const Geometry ) {
|
||||
chunk( gfx::geometry_handle const Geometry ) {
|
||||
return m_chunks[ Geometry.chunk - 1 ]; }
|
||||
inline
|
||||
geometry_chunk const &
|
||||
chunk( geometry_handle const Geometry ) const {
|
||||
chunk( gfx::geometry_handle const Geometry ) const {
|
||||
return m_chunks[ Geometry.chunk - 1 ]; }
|
||||
|
||||
// members:
|
||||
@@ -146,11 +147,11 @@ protected:
|
||||
private:
|
||||
// methods:
|
||||
// create() subclass details
|
||||
virtual void create_( geometry_handle const &Geometry ) = 0;
|
||||
virtual void create_( gfx::geometry_handle const &Geometry ) = 0;
|
||||
// replace() subclass details
|
||||
virtual void replace_( geometry_handle const &Geometry ) = 0;
|
||||
virtual void replace_( gfx::geometry_handle const &Geometry ) = 0;
|
||||
// draw() subclass details
|
||||
virtual void draw_( geometry_handle const &Geometry, stream_units const &Units, unsigned int const Streams ) = 0;
|
||||
virtual void draw_( gfx::geometry_handle const &Geometry, gfx::stream_units const &Units, unsigned int const Streams ) = 0;
|
||||
// resource release subclass details
|
||||
virtual void release_() = 0;
|
||||
};
|
||||
@@ -170,7 +171,7 @@ public:
|
||||
void
|
||||
reset() {
|
||||
m_activebuffer = 0;
|
||||
m_activestreams = stream::none; }
|
||||
m_activestreams = gfx::stream::none; }
|
||||
|
||||
private:
|
||||
// types:
|
||||
@@ -185,13 +186,13 @@ private:
|
||||
// methods:
|
||||
// create() subclass details
|
||||
void
|
||||
create_( geometry_handle const &Geometry );
|
||||
create_( gfx::geometry_handle const &Geometry );
|
||||
// replace() subclass details
|
||||
void
|
||||
replace_( geometry_handle const &Geometry );
|
||||
replace_( gfx::geometry_handle const &Geometry );
|
||||
// draw() subclass details
|
||||
void
|
||||
draw_( geometry_handle const &Geometry, stream_units const &Units, unsigned int const Streams );
|
||||
draw_( gfx::geometry_handle const &Geometry, gfx::stream_units const &Units, unsigned int const Streams );
|
||||
// release() subclass details
|
||||
void
|
||||
release_();
|
||||
@@ -201,7 +202,7 @@ private:
|
||||
delete_buffer();
|
||||
static
|
||||
void
|
||||
bind_streams( stream_units const &Units, unsigned int const Streams );
|
||||
bind_streams( gfx::stream_units const &Units, unsigned int const Streams );
|
||||
static
|
||||
void
|
||||
release_streams();
|
||||
@@ -240,18 +241,18 @@ private:
|
||||
// methods:
|
||||
// create() subclass details
|
||||
void
|
||||
create_( geometry_handle const &Geometry );
|
||||
create_( gfx::geometry_handle const &Geometry );
|
||||
// replace() subclass details
|
||||
void
|
||||
replace_( geometry_handle const &Geometry );
|
||||
replace_( gfx::geometry_handle const &Geometry );
|
||||
// draw() subclass details
|
||||
void
|
||||
draw_( geometry_handle const &Geometry, stream_units const &Units, unsigned int const Streams );
|
||||
draw_( gfx::geometry_handle const &Geometry, gfx::stream_units const &Units, unsigned int const Streams );
|
||||
// release () subclass details
|
||||
void
|
||||
release_();
|
||||
void
|
||||
delete_list( geometry_handle const &Geometry );
|
||||
delete_list( gfx::geometry_handle const &Geometry );
|
||||
|
||||
// members:
|
||||
chunkrecord_sequence m_chunkrecords; // helper data for all stored geometry chunks, in matching order
|
||||
@@ -269,20 +270,20 @@ public:
|
||||
// performs a resource sweep
|
||||
void update();
|
||||
// creates a new geometry bank. returns: handle to the bank or NULL
|
||||
geometrybank_handle
|
||||
gfx::geometrybank_handle
|
||||
create_bank();
|
||||
// creates a new geometry chunk of specified type from supplied vertex data, in specified bank. returns: handle to the chunk or NULL
|
||||
geometry_handle
|
||||
create_chunk( vertex_array &Vertices, geometrybank_handle const &Geometry, int const Type );
|
||||
gfx::geometry_handle
|
||||
create_chunk( gfx::vertex_array const &Vertices, gfx::geometrybank_handle const &Geometry, int const Type );
|
||||
// replaces data of specified chunk with the supplied vertex data, starting from specified offset
|
||||
bool
|
||||
replace( vertex_array &Vertices, geometry_handle const &Geometry, std::size_t const Offset = 0 );
|
||||
replace( gfx::vertex_array &Vertices, gfx::geometry_handle const &Geometry, std::size_t const Offset = 0 );
|
||||
// adds supplied vertex data at the end of specified chunk
|
||||
bool
|
||||
append( vertex_array &Vertices, geometry_handle const &Geometry );
|
||||
append( gfx::vertex_array &Vertices, gfx::geometry_handle const &Geometry );
|
||||
// draws geometry stored in specified chunk
|
||||
void
|
||||
draw( geometry_handle const &Geometry, unsigned int const Streams = basic_streams );
|
||||
draw( gfx::geometry_handle const &Geometry, unsigned int const Streams = basic_streams );
|
||||
template <typename Iterator_>
|
||||
void
|
||||
draw( Iterator_ First, Iterator_ Last, unsigned int const Streams = basic_streams ) {
|
||||
@@ -290,38 +291,40 @@ public:
|
||||
draw( *First, Streams );
|
||||
++First; } }
|
||||
// provides direct access to vertex data of specfied chunk
|
||||
vertex_array const &
|
||||
vertices( geometry_handle const &Geometry ) const;
|
||||
gfx::vertex_array const &
|
||||
vertices( gfx::geometry_handle const &Geometry ) const;
|
||||
// sets target texture unit for the texture data stream
|
||||
stream_units &
|
||||
gfx::stream_units &
|
||||
units() { return m_units; }
|
||||
|
||||
private:
|
||||
// types:
|
||||
typedef std::pair<
|
||||
std::shared_ptr<geometry_bank>,
|
||||
std::chrono::steady_clock::time_point > geometrybanktimepoint_pair;
|
||||
resource_timestamp > geometrybanktimepoint_pair;
|
||||
|
||||
typedef std::deque< geometrybanktimepoint_pair > geometrybanktimepointpair_sequence;
|
||||
|
||||
// members:
|
||||
geometrybanktimepointpair_sequence m_geometrybanks;
|
||||
garbage_collector<geometrybanktimepointpair_sequence> m_garbagecollector { m_geometrybanks, 60, 120, "geometry buffer" };
|
||||
stream_units m_units;
|
||||
gfx::stream_units m_units;
|
||||
|
||||
// methods
|
||||
inline
|
||||
bool
|
||||
valid( geometry_handle const &Geometry ) const {
|
||||
valid( gfx::geometry_handle const &Geometry ) const {
|
||||
return ( ( Geometry.bank != 0 )
|
||||
&& ( Geometry.bank <= m_geometrybanks.size() ) ); }
|
||||
inline
|
||||
geometrybanktimepointpair_sequence::value_type &
|
||||
bank( geometry_handle const Geometry ) {
|
||||
bank( gfx::geometry_handle const Geometry ) {
|
||||
return m_geometrybanks[ Geometry.bank - 1 ]; }
|
||||
inline
|
||||
geometrybanktimepointpair_sequence::value_type const &
|
||||
bank( geometry_handle const Geometry ) const {
|
||||
bank( gfx::geometry_handle const Geometry ) const {
|
||||
return m_geometrybanks[ Geometry.bank - 1 ]; }
|
||||
|
||||
};
|
||||
|
||||
} // namespace gfx
|
||||
|
||||
17
parser.cpp
17
parser.cpp
@@ -110,9 +110,21 @@ cParser::getToken<bool>( bool const ToLower, const char *Break ) {
|
||||
}
|
||||
|
||||
// methods
|
||||
cParser &
|
||||
cParser::autoclear( bool const Autoclear ) {
|
||||
|
||||
m_autoclear = Autoclear;
|
||||
if( mIncludeParser ) { mIncludeParser->autoclear( Autoclear ); }
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool cParser::getTokens(unsigned int Count, bool ToLower, const char *Break)
|
||||
{
|
||||
tokens.clear(); // emulates old parser behaviour. TODO, TBD: allow manual reset?
|
||||
if( true == m_autoclear ) {
|
||||
// legacy parser behaviour
|
||||
tokens.clear();
|
||||
}
|
||||
/*
|
||||
if (LoadTraction==true)
|
||||
trtest="niemaproblema"; //wczytywać
|
||||
@@ -124,7 +136,7 @@ bool cParser::getTokens(unsigned int Count, bool ToLower, const char *Break)
|
||||
this->str("");
|
||||
this->clear();
|
||||
*/
|
||||
for (unsigned int i = 0; i < Count; ++i)
|
||||
for (unsigned int i = tokens.size(); i < Count; ++i)
|
||||
{
|
||||
std::string token = readToken(ToLower, Break);
|
||||
if( true == token.empty() ) {
|
||||
@@ -216,6 +228,7 @@ std::string cParser::readToken( bool ToLower, const char *Break ) {
|
||||
parameter = readToken( false );
|
||||
}
|
||||
mIncludeParser = std::make_shared<cParser>( includefile, buffer_FILE, mPath, LoadTraction, includeparameters );
|
||||
mIncludeParser->autoclear( m_autoclear );
|
||||
if( mIncludeParser->mSize <= 0 ) {
|
||||
ErrorLog( "Bad include: can't open file \"" + includefile + "\"" );
|
||||
}
|
||||
|
||||
6
parser.h
6
parser.h
@@ -61,6 +61,11 @@ class cParser //: public std::stringstream
|
||||
bool
|
||||
ok() {
|
||||
return !mStream->fail(); };
|
||||
cParser &
|
||||
autoclear( bool const Autoclear );
|
||||
bool
|
||||
autoclear() const {
|
||||
return m_autoclear; }
|
||||
bool
|
||||
getTokens( unsigned int Count = 1, bool ToLower = true, char const *Break = "\n\r\t ;" );
|
||||
// returns next incoming token, if any, without removing it from the set
|
||||
@@ -91,6 +96,7 @@ class cParser //: public std::stringstream
|
||||
bool trimComments( std::string &String );
|
||||
std::size_t count();
|
||||
// members:
|
||||
bool m_autoclear { true }; // not retrieved tokens are discarded when another read command is issued (legacy behaviour)
|
||||
bool LoadTraction; // load traction?
|
||||
std::shared_ptr<std::istream> mStream; // relevant kind of buffer is attached on creation.
|
||||
std::string mFile; // name of the open file, if any
|
||||
|
||||
101
renderer.cpp
101
renderer.cpp
@@ -14,7 +14,6 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "Timer.h"
|
||||
#include "World.h"
|
||||
#include "Train.h"
|
||||
#include "Data.h"
|
||||
#include "DynObj.h"
|
||||
#include "AnimModel.h"
|
||||
#include "Traction.h"
|
||||
@@ -108,7 +107,7 @@ opengl_renderer::Init( GLFWwindow *Window ) {
|
||||
std::vector<GLint>{ m_normaltextureunit, m_diffusetextureunit } );
|
||||
m_textures.assign_units( m_helpertextureunit, m_shadowtextureunit, m_normaltextureunit, m_diffusetextureunit ); // TODO: add reflections unit
|
||||
UILayer.set_unit( m_diffusetextureunit );
|
||||
Active_Texture( m_diffusetextureunit );
|
||||
select_unit( m_diffusetextureunit );
|
||||
|
||||
::glDepthFunc( GL_LEQUAL );
|
||||
glEnable( GL_DEPTH_TEST );
|
||||
@@ -297,16 +296,14 @@ opengl_renderer::Init( GLFWwindow *Window ) {
|
||||
// prepare basic geometry chunks
|
||||
auto const geometrybank = m_geometry.create_bank();
|
||||
float const size = 2.5f;
|
||||
auto tmp =
|
||||
vertex_array{
|
||||
m_billboardgeometry = m_geometry.create_chunk(
|
||||
gfx::vertex_array{
|
||||
{ { -size, size, 0.f }, glm::vec3(), { 1.f, 1.f } },
|
||||
{ { size, size, 0.f }, glm::vec3(), { 0.f, 1.f } },
|
||||
{ { -size, -size, 0.f }, glm::vec3(), { 1.f, 0.f } },
|
||||
{ { size, -size, 0.f }, glm::vec3(), { 0.f, 0.f } } };
|
||||
m_billboardgeometry = m_geometry.create_chunk(
|
||||
tmp,
|
||||
{ { size, -size, 0.f }, glm::vec3(), { 0.f, 0.f } } },
|
||||
geometrybank,
|
||||
GL_TRIANGLE_STRIP );
|
||||
GL_TRIANGLE_STRIP );
|
||||
// prepare debug mode objects
|
||||
m_quadric = ::gluNewQuadric();
|
||||
::gluQuadricNormals( m_quadric, GLU_FLAT );
|
||||
@@ -443,6 +440,25 @@ opengl_renderer::Render_pass( rendermode const Mode ) {
|
||||
#endif
|
||||
switch_units( true, true, true );
|
||||
Render( simulation::Region );
|
||||
/*
|
||||
// debug: audio nodes
|
||||
for( auto const &audiosource : audio::renderer.m_sources ) {
|
||||
|
||||
::glPushMatrix();
|
||||
auto const position = audiosource.properties.location - m_renderpass.camera.position();
|
||||
::glTranslated( position.x, position.y, position.z );
|
||||
|
||||
::glPushAttrib( GL_ENABLE_BIT );
|
||||
::glDisable( GL_TEXTURE_2D );
|
||||
::glColor3f( 0.36f, 0.75f, 0.35f );
|
||||
|
||||
::gluSphere( m_quadric, 0.125, 4, 2 );
|
||||
|
||||
::glPopAttrib();
|
||||
|
||||
::glPopMatrix();
|
||||
}
|
||||
*/
|
||||
// ...translucent parts
|
||||
setup_drawing( true );
|
||||
Render_Alpha( simulation::Region );
|
||||
@@ -454,10 +470,10 @@ opengl_renderer::Render_pass( rendermode const Mode ) {
|
||||
|
||||
if( m_environmentcubetexturesupport ) {
|
||||
// restore default texture matrix for reflections cube map
|
||||
Active_Texture( m_helpertextureunit );
|
||||
select_unit( m_helpertextureunit );
|
||||
::glMatrixMode( GL_TEXTURE );
|
||||
::glPopMatrix();
|
||||
Active_Texture( m_diffusetextureunit );
|
||||
select_unit( m_diffusetextureunit );
|
||||
::glMatrixMode( GL_MODELVIEW );
|
||||
}
|
||||
}
|
||||
@@ -698,9 +714,10 @@ opengl_renderer::setup_pass( renderpass_config &Config, rendermode const Mode, f
|
||||
point = lightviewmatrix * point;
|
||||
}
|
||||
bounding_box( frustumchunkmin, frustumchunkmax, std::begin( frustumchunkshapepoints ), std::end( frustumchunkshapepoints ) );
|
||||
// quantize the frustum points with 50 m resolution, to reduce shadow shimmer on scale/orientation changes
|
||||
frustumchunkmin = 50.f * glm::floor( frustumchunkmin * ( 1.f / 50.f ) );
|
||||
frustumchunkmax = 50.f * glm::ceil( frustumchunkmax * ( 1.f / 50.f ) );
|
||||
// quantize the frustum points and add some padding, to reduce shadow shimmer on scale changes
|
||||
auto const quantizationstep{ std::min( Global::shadowtune.depth, 50.f ) };
|
||||
frustumchunkmin = quantizationstep * glm::floor( frustumchunkmin * ( 1.f / quantizationstep ) );
|
||||
frustumchunkmax = quantizationstep * glm::ceil( frustumchunkmax * ( 1.f / quantizationstep ) );
|
||||
// ...use the dimensions to set up light projection boundaries...
|
||||
// NOTE: since we only have one cascade map stage, we extend the chunk forward/back to catch areas normally covered by other stages
|
||||
camera.projection() *=
|
||||
@@ -793,11 +810,11 @@ opengl_renderer::setup_matrices() {
|
||||
if( ( m_renderpass.draw_mode == rendermode::color )
|
||||
&& ( m_environmentcubetexturesupport ) ) {
|
||||
// special case, for colour render pass setup texture matrix for reflections cube map
|
||||
Active_Texture( m_helpertextureunit );
|
||||
select_unit( m_helpertextureunit );
|
||||
::glMatrixMode( GL_TEXTURE );
|
||||
::glPushMatrix();
|
||||
::glMultMatrixf( glm::value_ptr( glm::inverse( glm::mat4{ glm::mat3{ m_renderpass.camera.modelview() } } ) ) );
|
||||
Active_Texture( m_diffusetextureunit );
|
||||
select_unit( m_diffusetextureunit );
|
||||
}
|
||||
|
||||
// trim modelview matrix just to rotation, since rendering is done in camera-centric world space
|
||||
@@ -863,7 +880,7 @@ opengl_renderer::setup_units( bool const Diffuse, bool const Shadows, bool const
|
||||
// darkens previous stage, preparing data for the shadow texture unit to select from
|
||||
if( m_helpertextureunit >= 0 ) {
|
||||
|
||||
Active_Texture( m_helpertextureunit );
|
||||
select_unit( m_helpertextureunit );
|
||||
|
||||
if( ( true == Reflections )
|
||||
|| ( ( true == Global::RenderShadows ) && ( true == Shadows ) && ( false == Global::bWireFrame ) ) ) {
|
||||
@@ -950,7 +967,7 @@ opengl_renderer::setup_units( bool const Diffuse, bool const Shadows, bool const
|
||||
&& ( false == Global::bWireFrame )
|
||||
&& ( m_shadowcolor != colors::white ) ) {
|
||||
|
||||
Active_Texture( m_shadowtextureunit );
|
||||
select_unit( m_shadowtextureunit );
|
||||
// NOTE: shadowmap isn't part of regular texture system, so we use direct bind call here
|
||||
::glBindTexture( GL_TEXTURE_2D, m_shadowtexture );
|
||||
::glEnable( GL_TEXTURE_2D );
|
||||
@@ -981,7 +998,7 @@ opengl_renderer::setup_units( bool const Diffuse, bool const Shadows, bool const
|
||||
}
|
||||
else {
|
||||
// turn off shadow map tests
|
||||
Active_Texture( m_shadowtextureunit );
|
||||
select_unit( m_shadowtextureunit );
|
||||
|
||||
::glDisable( GL_TEXTURE_2D );
|
||||
::glDisable( GL_TEXTURE_GEN_S );
|
||||
@@ -994,7 +1011,7 @@ opengl_renderer::setup_units( bool const Diffuse, bool const Shadows, bool const
|
||||
// NOTE: comes after diffuse stage in the operation chain
|
||||
if( m_normaltextureunit >= 0 ) {
|
||||
|
||||
Active_Texture( m_normaltextureunit );
|
||||
select_unit( m_normaltextureunit );
|
||||
|
||||
if( true == Reflections ) {
|
||||
::glEnable( GL_TEXTURE_2D );
|
||||
@@ -1017,7 +1034,7 @@ opengl_renderer::setup_units( bool const Diffuse, bool const Shadows, bool const
|
||||
}
|
||||
// diffuse texture unit.
|
||||
// NOTE: diffuse texture mapping is never fully disabled, alpha channel information is always included
|
||||
Active_Texture( m_diffusetextureunit );
|
||||
select_unit( m_diffusetextureunit );
|
||||
::glEnable( GL_TEXTURE_2D );
|
||||
if( true == Diffuse ) {
|
||||
// default behaviour, modulate with previous stage
|
||||
@@ -1055,7 +1072,7 @@ opengl_renderer::switch_units( bool const Diffuse, bool const Shadows, bool cons
|
||||
// helper texture unit.
|
||||
if( m_helpertextureunit >= 0 ) {
|
||||
|
||||
Active_Texture( m_helpertextureunit );
|
||||
select_unit( m_helpertextureunit );
|
||||
if( ( true == Reflections )
|
||||
|| ( ( true == Global::RenderShadows )
|
||||
&& ( true == Shadows )
|
||||
@@ -1081,12 +1098,12 @@ opengl_renderer::switch_units( bool const Diffuse, bool const Shadows, bool cons
|
||||
if( m_shadowtextureunit >= 0 ) {
|
||||
if( ( true == Global::RenderShadows ) && ( true == Shadows ) && ( false == Global::bWireFrame ) ) {
|
||||
|
||||
Active_Texture( m_shadowtextureunit );
|
||||
select_unit( m_shadowtextureunit );
|
||||
::glEnable( GL_TEXTURE_2D );
|
||||
}
|
||||
else {
|
||||
|
||||
Active_Texture( m_shadowtextureunit );
|
||||
select_unit( m_shadowtextureunit );
|
||||
::glDisable( GL_TEXTURE_2D );
|
||||
}
|
||||
}
|
||||
@@ -1094,11 +1111,11 @@ opengl_renderer::switch_units( bool const Diffuse, bool const Shadows, bool cons
|
||||
if( m_normaltextureunit >= 0 ) {
|
||||
if( true == Reflections ) {
|
||||
|
||||
Active_Texture( m_normaltextureunit );
|
||||
select_unit( m_normaltextureunit );
|
||||
::glEnable( GL_TEXTURE_2D );
|
||||
}
|
||||
else {
|
||||
Active_Texture( m_normaltextureunit );
|
||||
select_unit( m_normaltextureunit );
|
||||
::glDisable( GL_TEXTURE_2D );
|
||||
}
|
||||
}
|
||||
@@ -1106,12 +1123,12 @@ opengl_renderer::switch_units( bool const Diffuse, bool const Shadows, bool cons
|
||||
// NOTE: toggle actually disables diffuse texture mapping, unlike setup counterpart
|
||||
if( true == Diffuse ) {
|
||||
|
||||
Active_Texture( m_diffusetextureunit );
|
||||
select_unit( m_diffusetextureunit );
|
||||
::glEnable( GL_TEXTURE_2D );
|
||||
}
|
||||
else {
|
||||
|
||||
Active_Texture( m_diffusetextureunit );
|
||||
select_unit( m_diffusetextureunit );
|
||||
::glDisable( GL_TEXTURE_2D );
|
||||
}
|
||||
// update unit state
|
||||
@@ -1123,9 +1140,9 @@ opengl_renderer::switch_units( bool const Diffuse, bool const Shadows, bool cons
|
||||
void
|
||||
opengl_renderer::setup_shadow_color( glm::vec4 const &Shadowcolor ) {
|
||||
|
||||
Active_Texture( m_helpertextureunit );
|
||||
select_unit( m_helpertextureunit );
|
||||
::glTexEnvfv( GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, glm::value_ptr( Shadowcolor ) ); // in-shadow colour multiplier
|
||||
Active_Texture( m_diffusetextureunit );
|
||||
select_unit( m_diffusetextureunit );
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -1156,8 +1173,7 @@ opengl_renderer::Render( world_environment *Environment ) {
|
||||
// skydome
|
||||
Environment->m_skydome.Render();
|
||||
// skydome uses a custom vbo which could potentially confuse the main geometry system. hardly elegant but, eh
|
||||
opengl_vbogeometrybank::reset();
|
||||
|
||||
gfx::opengl_vbogeometrybank::reset();
|
||||
// stars
|
||||
if( Environment->m_stars.m_stars != nullptr ) {
|
||||
// setup
|
||||
@@ -1290,36 +1306,36 @@ opengl_renderer::Render( world_environment *Environment ) {
|
||||
|
||||
// geometry methods
|
||||
// creates a new geometry bank. returns: handle to the bank or NULL
|
||||
geometrybank_handle
|
||||
gfx::geometrybank_handle
|
||||
opengl_renderer::Create_Bank() {
|
||||
|
||||
return m_geometry.create_bank();
|
||||
}
|
||||
|
||||
// creates a new geometry chunk of specified type from supplied vertex data, in specified bank. returns: handle to the chunk or NULL
|
||||
geometry_handle
|
||||
opengl_renderer::Insert( vertex_array &Vertices, geometrybank_handle const &Geometry, int const Type ) {
|
||||
gfx::geometry_handle
|
||||
opengl_renderer::Insert( gfx::vertex_array &Vertices, gfx::geometrybank_handle const &Geometry, int const Type ) {
|
||||
|
||||
return m_geometry.create_chunk( Vertices, Geometry, Type );
|
||||
}
|
||||
|
||||
// replaces data of specified chunk with the supplied vertex data, starting from specified offset
|
||||
bool
|
||||
opengl_renderer::Replace( vertex_array &Vertices, geometry_handle const &Geometry, std::size_t const Offset ) {
|
||||
opengl_renderer::Replace( gfx::vertex_array &Vertices, gfx::geometry_handle const &Geometry, std::size_t const Offset ) {
|
||||
|
||||
return m_geometry.replace( Vertices, Geometry, Offset );
|
||||
}
|
||||
|
||||
// adds supplied vertex data at the end of specified chunk
|
||||
bool
|
||||
opengl_renderer::Append( vertex_array &Vertices, geometry_handle const &Geometry ) {
|
||||
opengl_renderer::Append( gfx::vertex_array &Vertices, gfx::geometry_handle const &Geometry ) {
|
||||
|
||||
return m_geometry.append( Vertices, Geometry );
|
||||
}
|
||||
|
||||
// provides direct access to vertex data of specfied chunk
|
||||
vertex_array const &
|
||||
opengl_renderer::Vertices( geometry_handle const &Geometry ) const {
|
||||
gfx::vertex_array const &
|
||||
opengl_renderer::Vertices( gfx::geometry_handle const &Geometry ) const {
|
||||
|
||||
return m_geometry.vertices( Geometry );
|
||||
}
|
||||
@@ -1349,7 +1365,7 @@ opengl_renderer::Material( material_handle const Material ) const {
|
||||
|
||||
// texture methods
|
||||
void
|
||||
opengl_renderer::Active_Texture( GLint const Textureunit ) {
|
||||
opengl_renderer::select_unit( GLint const Textureunit ) {
|
||||
|
||||
return m_textures.unit( Textureunit );
|
||||
}
|
||||
@@ -2289,7 +2305,7 @@ opengl_renderer::Render( TSubModel *Submodel ) {
|
||||
::glDisable( GL_LIGHTING );
|
||||
|
||||
// main draw call
|
||||
m_geometry.draw( Submodel->m_geometry, color_streams );
|
||||
m_geometry.draw( Submodel->m_geometry, gfx::color_streams );
|
||||
|
||||
// post-draw reset
|
||||
::glPopAttrib();
|
||||
@@ -2990,11 +3006,12 @@ opengl_renderer::Render_Alpha( TSubModel *Submodel ) {
|
||||
|
||||
if( glarelevel > 0.0f ) {
|
||||
// setup
|
||||
::glPushAttrib( GL_ENABLE_BIT | GL_CURRENT_BIT | GL_COLOR_BUFFER_BIT );
|
||||
::glPushAttrib( GL_CURRENT_BIT | GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_ENABLE_BIT );
|
||||
|
||||
Bind_Texture( m_glaretexture );
|
||||
::glColor4f( Submodel->f4Diffuse[ 0 ], Submodel->f4Diffuse[ 1 ], Submodel->f4Diffuse[ 2 ], glarelevel );
|
||||
::glDisable( GL_LIGHTING );
|
||||
::glDepthMask( GL_FALSE );
|
||||
::glBlendFunc( GL_SRC_ALPHA, GL_ONE );
|
||||
|
||||
::glPushMatrix();
|
||||
@@ -3354,7 +3371,7 @@ opengl_renderer::Init_caps() {
|
||||
return false;
|
||||
}
|
||||
|
||||
WriteLog( "Supported extensions:" + std::string((char *)glGetString( GL_EXTENSIONS )) );
|
||||
WriteLog( "Supported extensions: " + std::string((char *)glGetString( GL_EXTENSIONS )) );
|
||||
|
||||
WriteLog( std::string("Render path: NOGFX" ) );
|
||||
if( GLEW_EXT_framebuffer_object ) {
|
||||
|
||||
27
renderer.h
27
renderer.h
@@ -156,20 +156,20 @@ public:
|
||||
// geometry methods
|
||||
// NOTE: hands-on geometry management is exposed as a temporary measure; ultimately all visualization data should be generated/handled automatically by the renderer itself
|
||||
// creates a new geometry bank. returns: handle to the bank or NULL
|
||||
geometrybank_handle
|
||||
gfx::geometrybank_handle
|
||||
Create_Bank();
|
||||
// creates a new geometry chunk of specified type from supplied vertex data, in specified bank. returns: handle to the chunk or NULL
|
||||
geometry_handle
|
||||
Insert( vertex_array &Vertices, geometrybank_handle const &Geometry, int const Type );
|
||||
gfx::geometry_handle
|
||||
Insert( gfx::vertex_array &Vertices, gfx::geometrybank_handle const &Geometry, int const Type );
|
||||
// replaces data of specified chunk with the supplied vertex data, starting from specified offset
|
||||
bool
|
||||
Replace( vertex_array &Vertices, geometry_handle const &Geometry, std::size_t const Offset = 0 );
|
||||
Replace( gfx::vertex_array &Vertices, gfx::geometry_handle const &Geometry, std::size_t const Offset = 0 );
|
||||
// adds supplied vertex data at the end of specified chunk
|
||||
bool
|
||||
Append( vertex_array &Vertices, geometry_handle const &Geometry );
|
||||
Append( gfx::vertex_array &Vertices, gfx::geometry_handle const &Geometry );
|
||||
// provides direct access to vertex data of specfied chunk
|
||||
vertex_array const &
|
||||
Vertices( geometry_handle const &Geometry ) const;
|
||||
gfx::vertex_array const &
|
||||
Vertices( gfx::geometry_handle const &Geometry ) const;
|
||||
// material methods
|
||||
material_handle
|
||||
Fetch_Material( std::string const &Filename, bool const Loadnow = true );
|
||||
@@ -178,8 +178,6 @@ public:
|
||||
opengl_material const &
|
||||
Material( material_handle const Material ) const;
|
||||
// texture methods
|
||||
void
|
||||
Active_Texture( GLint const Textureunit );
|
||||
texture_handle
|
||||
Fetch_Texture( std::string const &Filename, bool const Loadnow = true );
|
||||
void
|
||||
@@ -194,14 +192,14 @@ public:
|
||||
Pick_Control() const { return m_pickcontrolitem; }
|
||||
editor::basic_node const *
|
||||
Pick_Node() const { return m_picksceneryitem; }
|
||||
// maintenance jobs
|
||||
// maintenance methods
|
||||
void
|
||||
Update( double const Deltatime );
|
||||
TSubModel const *
|
||||
Update_Pick_Control();
|
||||
editor::basic_node const *
|
||||
Update_Pick_Node();
|
||||
// debug performance string
|
||||
// debug methods
|
||||
std::string const &
|
||||
info_times() const;
|
||||
std::string const &
|
||||
@@ -275,6 +273,9 @@ private:
|
||||
setup_shadow_color( glm::vec4 const &Shadowcolor );
|
||||
void
|
||||
switch_units( bool const Diffuse, bool const Shadows, bool const Reflections );
|
||||
// helper, texture manager method; activates specified texture unit
|
||||
void
|
||||
select_unit( GLint const Textureunit );
|
||||
// runs jobs needed to generate graphics for specified render pass
|
||||
void
|
||||
Render_pass( rendermode const Mode );
|
||||
@@ -336,12 +337,12 @@ private:
|
||||
|
||||
// members
|
||||
GLFWwindow *m_window { nullptr };
|
||||
geometrybank_manager m_geometry;
|
||||
gfx::geometrybank_manager m_geometry;
|
||||
material_manager m_materials;
|
||||
texture_manager m_textures;
|
||||
opengllight_array m_lights;
|
||||
|
||||
geometry_handle m_billboardgeometry { 0, 0 };
|
||||
gfx::geometry_handle m_billboardgeometry { 0, 0 };
|
||||
texture_handle m_glaretexture { -1 };
|
||||
texture_handle m_suntexture { -1 };
|
||||
texture_handle m_moontexture { -1 };
|
||||
|
||||
22
scene.cpp
22
scene.cpp
@@ -338,7 +338,7 @@ basic_cell::insert( TAnimModel *Instance ) {
|
||||
|
||||
// adds provided sound instance to the cell
|
||||
void
|
||||
basic_cell::insert( sound *Sound ) {
|
||||
basic_cell::insert( sound_source *Sound ) {
|
||||
|
||||
m_active = true;
|
||||
|
||||
@@ -504,7 +504,7 @@ basic_cell::center( glm::dvec3 Center ) {
|
||||
|
||||
// generates renderable version of held non-instanced geometry
|
||||
void
|
||||
basic_cell::create_geometry( geometrybank_handle const &Bank ) {
|
||||
basic_cell::create_geometry( gfx::geometrybank_handle const &Bank ) {
|
||||
|
||||
if( false == m_active ) { return; } // nothing to do here
|
||||
|
||||
@@ -863,7 +863,7 @@ void
|
||||
basic_region::serialize( std::string const &Scenariofile ) const {
|
||||
|
||||
auto filename { Scenariofile };
|
||||
if( filename[ 0 ] == '$' ) {
|
||||
while( filename[ 0 ] == '$' ) {
|
||||
// trim leading $ char rainsted utility may add to the base name for modified .scn files
|
||||
filename.erase( 0, 1 );
|
||||
}
|
||||
@@ -906,7 +906,7 @@ bool
|
||||
basic_region::deserialize( std::string const &Scenariofile ) {
|
||||
|
||||
auto filename { Scenariofile };
|
||||
if( filename[ 0 ] == '$' ) {
|
||||
while( filename[ 0 ] == '$' ) {
|
||||
// trim leading $ char rainsted utility may add to the base name for modified .scn files
|
||||
filename.erase( 0, 1 );
|
||||
}
|
||||
@@ -1161,19 +1161,7 @@ basic_region::insert_instance( TAnimModel *Instance, scratch_data &Scratchpad )
|
||||
|
||||
// inserts provided sound in the region
|
||||
void
|
||||
basic_region::insert_sound( sound *Sound, scratch_data &Scratchpad ) {
|
||||
|
||||
// NOTE: bounding area isn't present/filled until track class and wrapper refactoring is done
|
||||
auto location = Sound->location();
|
||||
|
||||
if( point_inside( location ) ) {
|
||||
// NOTE: nodes placed outside of region boundaries are discarded
|
||||
section( location ).insert( Sound );
|
||||
}
|
||||
else {
|
||||
// tracks are guaranteed to hava a name so we can skip the check
|
||||
ErrorLog( "Bad scenario: sound node placed in location outside region bounds (" + to_string( location ) + ")" );
|
||||
}
|
||||
basic_region::insert_sound( sound_source *Sound, scratch_data &Scratchpad ) {
|
||||
}
|
||||
|
||||
// inserts provided event launcher in the region
|
||||
|
||||
11
scene.h
11
scene.h
@@ -20,6 +20,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "scenenode.h"
|
||||
#include "Track.h"
|
||||
#include "Traction.h"
|
||||
#include "sound.h"
|
||||
|
||||
class opengl_renderer;
|
||||
namespace scene {
|
||||
@@ -105,7 +106,7 @@ public:
|
||||
insert( TAnimModel *Instance );
|
||||
// adds provided sound instance to the cell
|
||||
void
|
||||
insert( sound *Sound );
|
||||
insert( sound_source *Sound );
|
||||
// adds provided event launcher to the cell
|
||||
void
|
||||
insert( TEventLauncher *Launcher );
|
||||
@@ -132,7 +133,7 @@ public:
|
||||
center( glm::dvec3 Center );
|
||||
// generates renderable version of held non-instanced geometry in specified geometry bank
|
||||
void
|
||||
create_geometry( geometrybank_handle const &Bank );
|
||||
create_geometry( gfx::geometrybank_handle const &Bank );
|
||||
// provides access to bounding area data
|
||||
bounding_area const &
|
||||
area() const {
|
||||
@@ -144,7 +145,7 @@ private:
|
||||
using linesnode_sequence = std::vector<lines_node>;
|
||||
using traction_sequence = std::vector<TTraction *>;
|
||||
using instance_sequence = std::vector<TAnimModel *>;
|
||||
using sound_sequence = std::vector<sound *>;
|
||||
using sound_sequence = std::vector<sound_source *>;
|
||||
using eventlauncher_sequence = std::vector<TEventLauncher *>;
|
||||
// methods
|
||||
void
|
||||
@@ -258,7 +259,7 @@ private:
|
||||
shapenode_sequence m_shapes; // large pieces of opaque geometry and (legacy) terrain
|
||||
// TODO: implement dedicated, higher fidelity, fixed resolution terrain mesh item
|
||||
// gfx renderer data
|
||||
geometrybank_handle m_geometrybank;
|
||||
gfx::geometrybank_handle m_geometrybank;
|
||||
bool m_geometrycreated { false };
|
||||
};
|
||||
|
||||
@@ -311,7 +312,7 @@ public:
|
||||
insert_instance( TAnimModel *Instance, scratch_data &Scratchpad );
|
||||
// inserts provided sound in the region
|
||||
void
|
||||
insert_sound( sound *Sound, scratch_data &Scratchpad );
|
||||
insert_sound( sound_source *Sound, scratch_data &Scratchpad );
|
||||
// inserts provided event launcher in the region
|
||||
void
|
||||
insert_launcher( TEventLauncher *Launcher, scratch_data &Scratchpad );
|
||||
|
||||
@@ -77,7 +77,7 @@ shape_node::shapenode_data::serialize( std::ostream &Output ) const {
|
||||
// vertex count, followed by vertex data
|
||||
sn_utils::ls_uint32( Output, vertices.size() );
|
||||
for( auto const &vertex : vertices ) {
|
||||
basic_vertex(
|
||||
gfx::basic_vertex(
|
||||
glm::vec3{ vertex.position - origin },
|
||||
vertex.normal,
|
||||
vertex.texture )
|
||||
@@ -106,7 +106,7 @@ shape_node::shapenode_data::deserialize( std::istream &Input ) {
|
||||
// NOTE: geometry handle is acquired during geometry creation
|
||||
// vertex data
|
||||
vertices.resize( sn_utils::ld_uint32( Input ) );
|
||||
basic_vertex localvertex;
|
||||
gfx::basic_vertex localvertex;
|
||||
for( auto &vertex : vertices ) {
|
||||
localvertex.deserialize( Input );
|
||||
vertex.position = origin + glm::dvec3{ localvertex.position };
|
||||
@@ -414,9 +414,9 @@ shape_node::merge( shape_node &Shape ) {
|
||||
|
||||
// generates renderable version of held non-instanced geometry in specified geometry bank
|
||||
void
|
||||
shape_node::create_geometry( geometrybank_handle const &Bank ) {
|
||||
shape_node::create_geometry( gfx::geometrybank_handle const &Bank ) {
|
||||
|
||||
vertex_array vertices; vertices.reserve( m_data.vertices.size() );
|
||||
gfx::vertex_array vertices; vertices.reserve( m_data.vertices.size() );
|
||||
|
||||
for( auto const &vertex : m_data.vertices ) {
|
||||
vertices.emplace_back(
|
||||
@@ -461,7 +461,7 @@ lines_node::linesnode_data::serialize( std::ostream &Output ) const {
|
||||
// vertex count, followed by vertex data
|
||||
sn_utils::ls_uint32( Output, vertices.size() );
|
||||
for( auto const &vertex : vertices ) {
|
||||
basic_vertex(
|
||||
gfx::basic_vertex(
|
||||
glm::vec3{ vertex.position - origin },
|
||||
vertex.normal,
|
||||
vertex.texture )
|
||||
@@ -486,7 +486,7 @@ lines_node::linesnode_data::deserialize( std::istream &Input ) {
|
||||
// NOTE: geometry handle is acquired during geometry creation
|
||||
// vertex data
|
||||
vertices.resize( sn_utils::ld_uint32( Input ) );
|
||||
basic_vertex localvertex;
|
||||
gfx::basic_vertex localvertex;
|
||||
for( auto &vertex : vertices ) {
|
||||
localvertex.deserialize( Input );
|
||||
vertex.position = origin + glm::dvec3{ localvertex.position };
|
||||
@@ -634,9 +634,9 @@ lines_node::merge( lines_node &Lines ) {
|
||||
|
||||
// generates renderable version of held non-instanced geometry in specified geometry bank
|
||||
void
|
||||
lines_node::create_geometry( geometrybank_handle const &Bank ) {
|
||||
lines_node::create_geometry( gfx::geometrybank_handle const &Bank ) {
|
||||
|
||||
vertex_array vertices; vertices.reserve( m_data.vertices.size() );
|
||||
gfx::vertex_array vertices; vertices.reserve( m_data.vertices.size() );
|
||||
|
||||
for( auto const &vertex : m_data.vertices ) {
|
||||
vertices.emplace_back(
|
||||
|
||||
@@ -93,7 +93,7 @@ public:
|
||||
lighting_data lighting;
|
||||
// geometry data
|
||||
glm::dvec3 origin; // world position of the relative coordinate system origin
|
||||
geometry_handle geometry { 0, 0 }; // relative origin-centered chunk of geometry held by gfx renderer
|
||||
gfx::geometry_handle geometry { 0, 0 }; // relative origin-centered chunk of geometry held by gfx renderer
|
||||
std::vector<world_vertex> vertices; // world space source data of the geometry
|
||||
// methods:
|
||||
// sends content of the struct to provided stream
|
||||
@@ -122,7 +122,7 @@ public:
|
||||
merge( shape_node &Shape );
|
||||
// generates renderable version of held non-instanced geometry in specified geometry bank
|
||||
void
|
||||
create_geometry( geometrybank_handle const &Bank );
|
||||
create_geometry( gfx::geometrybank_handle const &Bank );
|
||||
// calculates shape's bounding radius
|
||||
void
|
||||
compute_radius();
|
||||
@@ -182,7 +182,7 @@ public:
|
||||
lighting_data lighting;
|
||||
// geometry data
|
||||
glm::dvec3 origin; // world position of the relative coordinate system origin
|
||||
geometry_handle geometry { 0, 0 }; // relative origin-centered chunk of geometry held by gfx renderer
|
||||
gfx::geometry_handle geometry { 0, 0 }; // relative origin-centered chunk of geometry held by gfx renderer
|
||||
std::vector<world_vertex> vertices; // world space source data of the geometry
|
||||
// methods:
|
||||
// sends content of the struct to provided stream
|
||||
@@ -208,7 +208,7 @@ public:
|
||||
merge( lines_node &Lines );
|
||||
// generates renderable version of held non-instanced geometry in specified geometry bank
|
||||
void
|
||||
create_geometry( geometrybank_handle const &Bank );
|
||||
create_geometry( gfx::geometrybank_handle const &Bank );
|
||||
// calculates shape's bounding radius
|
||||
void
|
||||
compute_radius();
|
||||
|
||||
@@ -317,8 +317,8 @@ state_manager::deserialize_node( cParser &Input, scene::scratch_data &Scratchpad
|
||||
}
|
||||
|
||||
if( ( vehicle->MoverParameters->CategoryFlag == 1 ) // trains only
|
||||
&& ( ( vehicle->LightList( side::front ) & ( light::headlight_left | light::headlight_right | light::headlight_upper ) != 0 )
|
||||
|| ( vehicle->LightList( side::rear ) & ( light::headlight_left | light::headlight_right | light::headlight_upper ) != 0 ) ) ) {
|
||||
&& ( ( ( vehicle->LightList( side::front ) & ( light::headlight_left | light::headlight_right | light::headlight_upper ) ) != 0 )
|
||||
|| ( ( vehicle->LightList( side::rear ) & ( light::headlight_left | light::headlight_right | light::headlight_upper ) ) != 0 ) ) ) {
|
||||
simulation::Lights.insert( vehicle );
|
||||
}
|
||||
}
|
||||
@@ -469,8 +469,9 @@ state_manager::deserialize_node( cParser &Input, scene::scratch_data &Scratchpad
|
||||
else if( nodedata.type == "sound" )
|
||||
{
|
||||
auto *sound { deserialize_sound( Input, Scratchpad, nodedata ) };
|
||||
if( false == simulation::Sounds.insert( sound, nodedata.name ) )
|
||||
ErrorLog( "Bad scenario: sound node with duplicate name \"" + nodedata.name + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" );
|
||||
if( false == simulation::Sounds.insert( sound ) ) {
|
||||
ErrorLog( "Bad scenario: sound node with duplicate name \"" + sound->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" );
|
||||
}
|
||||
simulation::Region->insert_sound( sound, Scratchpad );
|
||||
}
|
||||
|
||||
@@ -839,7 +840,7 @@ state_manager::deserialize_dynamic( cParser &Input, scene::scratch_data &Scratch
|
||||
return vehicle;
|
||||
}
|
||||
|
||||
sound *
|
||||
sound_source *
|
||||
state_manager::deserialize_sound( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ) {
|
||||
|
||||
glm::dvec3 location;
|
||||
@@ -851,13 +852,10 @@ state_manager::deserialize_sound( cParser &Input, scene::scratch_data &Scratchpa
|
||||
// adjust location
|
||||
location = transform( location, Scratchpad );
|
||||
|
||||
auto const soundname { Input.getToken<std::string>() };
|
||||
auto *sound = sound_man->create_text_sound(soundname);
|
||||
sound->position((glm::vec3)location);
|
||||
if (Nodedata.range_max != -1.0)
|
||||
sound->dist(Nodedata.range_max);
|
||||
else
|
||||
sound->set_mode(sound::global);
|
||||
auto *sound = new sound_source( sound_placement::external, Nodedata.range_max );
|
||||
sound->offset( location );
|
||||
sound->name( Nodedata.name );
|
||||
sound->deserialize( Input, sound_type::single );
|
||||
|
||||
skip_until( Input, "endsound" );
|
||||
|
||||
|
||||
@@ -67,17 +67,13 @@ private:
|
||||
TEventLauncher * deserialize_eventlauncher( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata );
|
||||
TAnimModel * deserialize_model( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata );
|
||||
TDynamicObject * deserialize_dynamic( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata );
|
||||
sound * deserialize_sound( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata );
|
||||
sound_source * deserialize_sound( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata );
|
||||
// skips content of stream until specified token
|
||||
void skip_until( cParser &Input, std::string const &Token );
|
||||
// transforms provided location by specifed rotation and offset
|
||||
glm::dvec3 transform( glm::dvec3 Location, scene::scratch_data const &Scratchpad );
|
||||
};
|
||||
|
||||
class sound_table : public basic_table<sound>
|
||||
{
|
||||
};
|
||||
|
||||
extern state_manager State;
|
||||
extern event_manager Events;
|
||||
extern memory_table Memory;
|
||||
|
||||
358
sound.h
358
sound.h
@@ -1,184 +1,218 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
/*
|
||||
This Source Code Form is subject to the
|
||||
terms of the Mozilla Public License, v.
|
||||
2.0. If a copy of the MPL was not
|
||||
distributed with this file, You can
|
||||
obtain one at
|
||||
http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AL/al.h>
|
||||
#include <AL/alc.h>
|
||||
#include <cinttypes>
|
||||
#include <chrono>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <glm/glm.hpp>
|
||||
#include "dumb3d.h"
|
||||
#include "parser.h"
|
||||
#include "audiorenderer.h"
|
||||
#include "Classes.h"
|
||||
#include "Names.h"
|
||||
|
||||
class load_error : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
load_error(std::string const &f);
|
||||
float const EU07_SOUND_CABCONTROLSCUTOFFRANGE { 7.5f };
|
||||
float const EU07_SOUND_BRAKINGCUTOFFRANGE { 100.f };
|
||||
float const EU07_SOUND_RUNNINGNOISECUTOFFRANGE { 200.f };
|
||||
|
||||
enum class sound_type {
|
||||
single,
|
||||
multipart
|
||||
};
|
||||
|
||||
class sound_buffer
|
||||
{
|
||||
ALuint id;
|
||||
uint32_t refcount;
|
||||
std::chrono::time_point<std::chrono::steady_clock> last_unref;
|
||||
int samplerate;
|
||||
|
||||
public:
|
||||
sound_buffer(std::string &file);
|
||||
~sound_buffer();
|
||||
|
||||
int get_samplerate();
|
||||
ALuint get_id();
|
||||
void ref();
|
||||
void unref();
|
||||
std::chrono::time_point<std::chrono::steady_clock> unused_since();
|
||||
enum sound_parameters {
|
||||
range = 0x1,
|
||||
amplitude = 0x2,
|
||||
frequency = 0x4
|
||||
};
|
||||
|
||||
//m7todo: make constructor/destructor private friend to sound_manager
|
||||
class sound
|
||||
{
|
||||
bool pos_dirty;
|
||||
glm::vec3 last_pos;
|
||||
float dt_sum;
|
||||
|
||||
public:
|
||||
enum mode_t
|
||||
{
|
||||
global,
|
||||
spatial,
|
||||
anchored
|
||||
};
|
||||
|
||||
protected:
|
||||
float max_dist;
|
||||
mode_t mode;
|
||||
glm::vec3 pos;
|
||||
int samplerate;
|
||||
|
||||
ALuint id;
|
||||
sound();
|
||||
|
||||
public:
|
||||
float gain_off;
|
||||
float gain_mul;
|
||||
float pitch_off;
|
||||
float pitch_mul;
|
||||
|
||||
virtual ~sound();
|
||||
|
||||
glm::vec3 location(); //get position
|
||||
virtual bool is_playing() = 0;
|
||||
|
||||
virtual void play() = 0;
|
||||
virtual void stop() = 0;
|
||||
virtual void update(float dt);
|
||||
|
||||
sound& set_mode(mode_t);
|
||||
sound& dist(float);
|
||||
sound& gain(float);
|
||||
sound& pitch(float);
|
||||
virtual sound& loop(bool loop = true) = 0;
|
||||
|
||||
sound& position(glm::vec3);
|
||||
sound& position(Math3D::vector3 const &);
|
||||
enum sound_flags {
|
||||
looping = 0x1, // the main sample will be looping; implied for multi-sounds
|
||||
exclusive = 0x2 // the source won't dispatch more than one active instance of the sound; implied for multi-sounds
|
||||
};
|
||||
|
||||
class simple_sound : public sound
|
||||
{
|
||||
sound_buffer *buffer;
|
||||
|
||||
bool looping;
|
||||
bool playing;
|
||||
|
||||
public:
|
||||
simple_sound(sound_buffer *buf);
|
||||
~simple_sound();
|
||||
|
||||
void play();
|
||||
void stop();
|
||||
void update(float dt);
|
||||
|
||||
sound& loop(bool loop = true);
|
||||
|
||||
bool is_playing();
|
||||
enum class sound_placement {
|
||||
general, // source is equally audible in potential carrier and outside of it
|
||||
internal, // source is located inside of the carrier, and less audible when the listener is outside
|
||||
engine, // source is located in the engine compartment, less audible when the listener is outside and even less in the cabs
|
||||
external // source is located on the outside of the carrier, and less audible when the listener is inside
|
||||
};
|
||||
|
||||
class complex_sound : public sound
|
||||
{
|
||||
sound_buffer *pre, *buffer, *post;
|
||||
|
||||
enum class state
|
||||
{
|
||||
premain, // playing pre and continue to main
|
||||
prepost, // playing pre and jump to post
|
||||
main, //playing main
|
||||
post // playing post or idling
|
||||
} cs;
|
||||
|
||||
bool shut_by_dist;
|
||||
// mini controller and audio dispatcher; issues play commands for the audio renderer,
|
||||
// updates parameters of created audio emitters for the playback duration
|
||||
// TODO: move to simulation namespace after clean up of owner classes
|
||||
class sound_source {
|
||||
|
||||
public:
|
||||
complex_sound(sound_buffer* pre, sound_buffer* main, sound_buffer* post);
|
||||
~complex_sound();
|
||||
// constructors
|
||||
sound_source( sound_placement const Placement, float const Range = 50.f );
|
||||
|
||||
bool is_playing();
|
||||
// destructor
|
||||
~sound_source();
|
||||
|
||||
void play();
|
||||
void stop();
|
||||
void update(float dt);
|
||||
// methods
|
||||
// restores state of the class from provided data stream
|
||||
sound_source &
|
||||
deserialize( cParser &Input, sound_type const Legacytype, int const Legacyparameters = 0 );
|
||||
sound_source &
|
||||
deserialize( std::string const &Input, sound_type const Legacytype, int const Legacyparameters = 0 );
|
||||
// issues contextual play commands for the audio renderer
|
||||
void
|
||||
play( int const Flags = 0 );
|
||||
// stops currently active play commands controlled by this emitter
|
||||
void
|
||||
stop( bool const Skipend = false );
|
||||
// adjusts parameters of provided implementation-side sound source
|
||||
void
|
||||
update( audio::openal_source &Source );
|
||||
// sets base volume of the emiter to specified value
|
||||
sound_source &
|
||||
gain( float const Gain );
|
||||
// returns current base volume of the emitter
|
||||
float
|
||||
gain() const;
|
||||
// sets base pitch of the emitter to specified value
|
||||
sound_source &
|
||||
pitch( float const Pitch );
|
||||
// owner setter/getter
|
||||
void
|
||||
owner( TDynamicObject const *Owner );
|
||||
TDynamicObject const *
|
||||
owner() const;
|
||||
// sound source offset setter/getter
|
||||
void
|
||||
offset( glm::vec3 const Offset );
|
||||
glm::vec3 const &
|
||||
offset() const;
|
||||
// sound source name setter/getter
|
||||
void
|
||||
name( std::string Name );
|
||||
std::string const &
|
||||
name() const;
|
||||
// returns true if there isn't any sound buffer associated with the object, false otherwise
|
||||
bool
|
||||
empty() const;
|
||||
// returns true if the source is emitting any sound; by default doesn't take into account optional ending soudnds
|
||||
bool
|
||||
is_playing( bool const Includesoundends = false ) const;
|
||||
// returns true if the source uses sample table
|
||||
bool
|
||||
is_combined() const;
|
||||
// returns location of the sound source in simulation region space
|
||||
glm::dvec3 const
|
||||
location() const;
|
||||
|
||||
sound& loop(bool loop = true);
|
||||
// members
|
||||
float m_amplitudefactor { 1.f }; // helper, value potentially used by gain calculation
|
||||
float m_amplitudeoffset { 0.f }; // helper, value potentially used by gain calculation
|
||||
float m_frequencyfactor { 1.f }; // helper, value potentially used by pitch calculation
|
||||
float m_frequencyoffset { 0.f }; // helper, value potentially used by pitch calculation
|
||||
|
||||
private:
|
||||
// types
|
||||
struct sound_data {
|
||||
audio::buffer_handle buffer;
|
||||
int playing; // number of currently active sample instances
|
||||
};
|
||||
|
||||
struct chunk_data {
|
||||
int threshold; // nominal point of activation for the given chunk
|
||||
float fadein; // actual activation point for the given chunk
|
||||
float fadeout; // actual end point of activation range for the given chunk
|
||||
float pitch; // base pitch of the chunk
|
||||
};
|
||||
|
||||
using soundchunk_pair = std::pair<sound_data, chunk_data>;
|
||||
|
||||
using sound_handle = std::uint32_t;
|
||||
enum sound_id : std::uint32_t {
|
||||
begin,
|
||||
main,
|
||||
end,
|
||||
// 31 bits for index into relevant array, msb selects between the sample table and the basic array
|
||||
chunk = ( 1u << 31 )
|
||||
};
|
||||
|
||||
// methods
|
||||
// extracts name of the sound file from provided data stream
|
||||
std::string
|
||||
deserialize_filename( cParser &Input );
|
||||
// imports member data pair from the provided data stream
|
||||
bool
|
||||
deserialize_mapping( cParser &Input );
|
||||
// imports values for initial, main and ending sounds from provided data stream
|
||||
void
|
||||
deserialize_soundset( cParser &Input );
|
||||
// issues contextual play commands for the audio renderer
|
||||
void
|
||||
play_basic();
|
||||
void
|
||||
play_combined();
|
||||
// calculates requested sound point, used to select specific sample from the sample table
|
||||
float
|
||||
compute_combined_point() const;
|
||||
void
|
||||
update_basic( audio::openal_source &Source );
|
||||
void
|
||||
update_combined( audio::openal_source &Source );
|
||||
void
|
||||
update_crossfade( sound_handle const Chunk );
|
||||
void
|
||||
update_counter( sound_handle const Sound, int const Value );
|
||||
void
|
||||
update_location();
|
||||
// potentially updates area-based gain factor of the source. returns: true if location has changed
|
||||
bool
|
||||
update_soundproofing();
|
||||
void
|
||||
insert( sound_handle const Sound );
|
||||
template <class Iterator_>
|
||||
void
|
||||
insert( Iterator_ First, Iterator_ Last ) {
|
||||
uint32_sequence sounds;
|
||||
std::vector<audio::buffer_handle> buffers;
|
||||
std::for_each(
|
||||
First, Last,
|
||||
[&]( sound_handle const &soundhandle ) {
|
||||
sounds.emplace_back( soundhandle );
|
||||
buffers.emplace_back( sound( soundhandle ).buffer ); } );
|
||||
audio::renderer.insert( std::begin( buffers ), std::end( buffers ), this, sounds );
|
||||
update_counter( *First, 1 ); }
|
||||
sound_data &
|
||||
sound( sound_handle const Sound );
|
||||
sound_data const &
|
||||
sound( sound_handle const Sound ) const;
|
||||
|
||||
// members
|
||||
TDynamicObject const * m_owner { nullptr }; // optional, the vehicle carrying this sound source
|
||||
glm::vec3 m_offset; // relative position of the source, either from the owner or the region centre
|
||||
sound_placement m_placement;
|
||||
float m_range { 50.f }; // audible range of the emitted sounds
|
||||
std::string m_name;
|
||||
int m_flags { 0 }; // requested playback parameters
|
||||
sound_properties m_properties; // current properties of the emitted sounds
|
||||
float m_pitchvariation { 0.f }; // emitter-specific shift in base pitch
|
||||
bool m_stop { false }; // indicates active sample instances should be terminated
|
||||
bool m_playbeginning { true }; // indicates started sounds should be preceeded by opening bookend if there's one
|
||||
std::array<sound_data, 3> m_sounds { {} }; // basic sounds emitted by the source, main and optional bookends
|
||||
std::vector<soundchunk_pair> m_soundchunks; // table of samples activated when associated variable is within certain range
|
||||
bool m_soundchunksempty { true }; // helper, cached check whether sample table is linked with any actual samples
|
||||
int m_crossfaderange {}; // range of transition from one chunk to another
|
||||
};
|
||||
|
||||
class text_sound : public simple_sound
|
||||
{
|
||||
public:
|
||||
text_sound(sound_buffer *buf);
|
||||
// owner setter/getter
|
||||
inline void sound_source::owner( TDynamicObject const *Owner ) { m_owner = Owner; }
|
||||
inline TDynamicObject const * sound_source::owner() const { return m_owner; }
|
||||
// sound source offset setter/getter
|
||||
inline void sound_source::offset( glm::vec3 const Offset ) { m_offset = Offset; }
|
||||
inline glm::vec3 const & sound_source::offset() const { return m_offset; }
|
||||
// sound source name setter/getter
|
||||
inline void sound_source::name( std::string Name ) { m_name = Name; }
|
||||
inline std::string const & sound_source::name() const { return m_name; }
|
||||
|
||||
// collection of sound sources present in the scene
|
||||
class sound_table : public basic_table<sound_source> {
|
||||
|
||||
void play();
|
||||
};
|
||||
|
||||
class sound_manager
|
||||
{
|
||||
static bool created;
|
||||
|
||||
ALCdevice *dev;
|
||||
ALCcontext *ctx;
|
||||
|
||||
void (*alDeferUpdatesSOFT)() = nullptr;
|
||||
void (*alProcessUpdatesSOFT)() = nullptr;
|
||||
void (*alcDevicePauseSOFT)(ALCdevice*) = nullptr;
|
||||
void (*alcDeviceResumeSOFT)(ALCdevice*) = nullptr;
|
||||
|
||||
const std::chrono::duration<float> gc_time = std::chrono::duration<float>(60.0f);
|
||||
std::unordered_map<std::string, sound_buffer*> buffers;
|
||||
std::unordered_set<sound*> sounds;
|
||||
|
||||
std::string find_file(std::string);
|
||||
sound_buffer* find_buffer(std::string);
|
||||
|
||||
sound_buffer* get_buffer(std::string const &);
|
||||
|
||||
public:
|
||||
glm::vec3 pos, last_pos;
|
||||
glm::mat3 rot;
|
||||
|
||||
sound_manager();
|
||||
~sound_manager();
|
||||
|
||||
simple_sound* create_sound(std::string const &file);
|
||||
text_sound* create_text_sound(std::string const &file);
|
||||
complex_sound* create_complex_sound(std::string const &pre, std::string const &main, std::string const &post);
|
||||
complex_sound* create_complex_sound(cParser &);
|
||||
void destroy_sound(sound**);
|
||||
|
||||
void update(float dt);
|
||||
void set_listener(glm::vec3 const &pos, glm::mat3 const &rot);
|
||||
};
|
||||
|
||||
extern std::unique_ptr<sound_manager> sound_man;
|
||||
|
||||
18
sun.cpp
18
sun.cpp
@@ -13,6 +13,15 @@ cSun::cSun() {
|
||||
setLocation( 19.00f, 52.00f ); // default location roughly in centre of Poland
|
||||
m_observer.press = 1013.0; // surface pressure, millibars
|
||||
m_observer.temp = 15.0; // ambient dry-bulb temperature, degrees C
|
||||
}
|
||||
|
||||
cSun::~cSun() { gluDeleteQuadric( sunsphere ); }
|
||||
|
||||
void
|
||||
cSun::init() {
|
||||
|
||||
sunsphere = gluNewQuadric();
|
||||
gluQuadricNormals( sunsphere, GLU_SMOOTH );
|
||||
|
||||
#ifdef _WIN32
|
||||
TIME_ZONE_INFORMATION timezoneinfo; // TODO: timezone dependant on geographic location
|
||||
@@ -27,15 +36,6 @@ cSun::cSun() {
|
||||
#endif
|
||||
}
|
||||
|
||||
cSun::~cSun() { gluDeleteQuadric( sunsphere ); }
|
||||
|
||||
void
|
||||
cSun::init() {
|
||||
|
||||
sunsphere = gluNewQuadric();
|
||||
gluQuadricNormals( sunsphere, GLU_SMOOTH );
|
||||
}
|
||||
|
||||
void
|
||||
cSun::update() {
|
||||
|
||||
|
||||
Reference in New Issue
Block a user