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

build 171130. merge local branch 'audio_replacement'

This commit is contained in:
tmj-fstate
2017-11-30 16:49:39 +01:00
67 changed files with 4354 additions and 2926 deletions

View File

@@ -13,6 +13,7 @@ http://mozilla.org/MPL/2.0/.
#include "Model3d.h" #include "Model3d.h"
#include "Console.h" #include "Console.h"
#include "logs.h" #include "logs.h"
#include "renderer.h"
void TButton::Clear(int i) void TButton::Clear(int i)
{ {
@@ -24,8 +25,8 @@ void TButton::Clear(int i)
Update(); // kasowanie bitu Feedback, o ile jakiś ustawiony 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; } if( pModel == nullptr ) { return; }
pModelOn = pModel->GetFromName( asName + "_on" ); pModelOn = pModel->GetFromName( asName + "_on" );
@@ -34,7 +35,7 @@ void TButton::Init(std::string const &asName, TModel3d *pModel, bool bNewOn)
Update(); 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; std::string submodelname;
@@ -46,61 +47,68 @@ void TButton::Load(cParser &Parser, TModel3d *pModel1, TModel3d *pModel2) {
else { else {
// new, block type config // new, block type config
// TODO: rework the base part into yaml-compatible flow style mapping // TODO: rework the base part into yaml-compatible flow style mapping
cParser mappingparser( Parser.getToken<std::string>( false, "}" ) ); submodelname = Parser.getToken<std::string>( false );
submodelname = mappingparser.getToken<std::string>( false ); while( true == Load_mapping( Parser ) ) {
// new, variable length section
while( true == Load_mapping( mappingparser ) ) {
; // all work done by while() ; // all work done by while()
} }
} }
// bind defined sounds with the button owner
m_soundfxincrease.owner( Owner );
m_soundfxdecrease.owner( Owner );
if( pModel1 ) { if( pModel1 ) {
// poszukiwanie submodeli w modelu // poszukiwanie submodeli w modelu
Init( submodelname, pModel1, false ); Init( submodelname, pModel1, false );
if( ( pModelOn != nullptr ) || ( pModelOff != nullptr ) ) {
// we got our models, bail out
return;
} }
} if( ( pModelOn == nullptr )
if( pModel2 ) { && ( pModelOff == nullptr )
&& ( pModel2 != nullptr ) ) {
// poszukiwanie submodeli w modelu // poszukiwanie submodeli w modelu
Init( submodelname, pModel2, false ); Init( submodelname, pModel2, false );
if( ( pModelOn != nullptr ) || ( pModelOff != nullptr ) ) {
// we got our models, bail out
return;
}
} }
if( ( pModelOn == nullptr )
&& ( pModelOff == nullptr ) ) {
// if we failed to locate even one state submodel, cry // if we failed to locate even one state submodel, cry
ErrorLog( "Failed to locate sub-model \"" + submodelname + "\" in 3d model \"" + pModel1->NameGet() + "\"" ); 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 bool
TButton::Load_mapping( cParser &Input ) { TButton::Load_mapping( cParser &Input ) {
if( false == Input.getTokens( 2, true, " ,\n\r\t" ) ) { // token can be a key or block end
return false; std::string const key { Input.getToken<std::string>( true, "\n\r\t ,;" ) };
} if( 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" ?
TSoundsManager::GetFromName( value, true ) :
nullptr );
}
else if( key == "sounddec:" ) {
m_soundfxdecrease = (
value != "none" ?
TSoundsManager::GetFromName( value, true ) :
nullptr );
}
return true; // return value marks a key: value pair was extracted, nothing about whether it's recognized 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 void
TButton::Turn( bool const State ) { TButton::Turn( bool const State ) {
@@ -141,19 +149,6 @@ void TButton::AssignBool(bool const *bValue) {
void void
TButton::play() { TButton::play() {
play( if( m_state == true ) { m_soundfxincrease.play(); }
m_state == true ? else { m_soundfxdecrease.play(); }
m_soundfxincrease :
m_soundfxdecrease );
}
void
TButton::play( PSound Sound ) {
if( Sound == nullptr ) { return; }
Sound->SetCurrentPosition( 0 );
Sound->SetVolume( DSBVOLUME_MAX );
Sound->Play( 0, 0, 0 );
return;
} }

View File

@@ -12,18 +12,28 @@ http://mozilla.org/MPL/2.0/.
#include "Classes.h" #include "Classes.h"
#include "sound.h" #include "sound.h"
class TButton // animacja dwustanowa, włącza jeden z dwóch submodeli (jednego z nich może nie być)
{ // animacja dwustanowa, włącza jeden z dwóch submodeli (jednego class TButton {
// z nich może nie być)
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;
private: 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
PSound m_soundfxincrease { nullptr }; // sound associated with increasing control's value
PSound m_soundfxdecrease { nullptr }; // sound associated with decreasing control's value
// methods // methods
// imports member data pair from the config file // imports member data pair from the config file
bool bool
@@ -31,29 +41,16 @@ class TButton
// plays the sound associated with current state // plays the sound associated with current state
void void
play(); play();
// plays specified sound
static
void
play( PSound Sound );
public: // members
TButton() = default; TSubModel
void Clear(int const i = -1); *pModelOn { nullptr },
inline void FeedbackBitSet(int const i) { *pModelOff { nullptr }; // submodel dla stanu załączonego i wyłączonego
iFeedbackBit = 1 << i; }; bool m_state { false };
void Turn( bool const State ); bool const *bData { nullptr };
inline void TurnOn() { int iFeedbackBit { 0 }; // Ra: bit informacji zwrotnej, do wyprowadzenia na pulpit
Turn( true ); }; sound_source m_soundfxincrease { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE }; // sound associated with increasing control's value
inline void TurnOff() { sound_source m_soundfxdecrease { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE }; // sound associated with decreasing control's value
Turn( false ); };
inline void Switch() {
Turn( !m_state ); };
inline bool Active() {
return (pModelOn) || (pModelOff); };
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);
}; };
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------

View File

@@ -23,8 +23,12 @@ class TModel3d; //siatka modelu wspólna dla egzemplarzy
class TSubModel; // fragment modelu (tu do wyświetlania terenu) class TSubModel; // fragment modelu (tu do wyświetlania terenu)
class TMemCell; // komórka pamięci class TMemCell; // komórka pamięci
class cParser; class cParser;
#ifdef EU07_USE_OLD_SOUNDCODE
class TRealSound; // dźwięk ze współrzędnymi XYZ class TRealSound; // dźwięk ze współrzędnymi XYZ
class TTextSound; // dźwięk ze stenogramem class TTextSound; // dźwięk ze stenogramem
#else
class sound_source;
#endif
class TEventLauncher; class TEventLauncher;
class TTraction; // drut class TTraction; // drut
class TTractionPowerSource; // zasilanie drutów class TTractionPowerSource; // zasilanie drutów

View File

@@ -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 if (go == cm_Unknown) // jeśli nie było komendy wcześniej
go = cm_Ready; // gotów do odjazdu z W4 (semafor może go = cm_Ready; // gotów do odjazdu z W4 (semafor może
// zatrzymać) // 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; iDrivigFlags |= moveGuardSignal;
}
continue; // nie analizować prędkości continue; // nie analizować prędkości
} // koniec startu z zatrzymania } // koniec startu z zatrzymania
} // koniec obsługi początkowych stacji } // koniec obsługi początkowych stacji
@@ -2572,9 +2575,16 @@ bool TController::DecBrake()
bool TController::IncSpeed() bool TController::IncSpeed()
{ // zwiększenie prędkości; zwraca false, jeśli dalej się nie da zwiększać { // zwiększenie prędkości; zwraca false, jeśli dalej się nie da zwiększać
#ifdef EU07_USE_OLD_SOUNDCODE
if (tsGuardSignal) // jeśli jest dźwięk kierownika if (tsGuardSignal) // jeśli jest dźwięk kierownika
if (tsGuardSignal->GetStatus() & DSBSTATUS_PLAYING) // jeśli gada, to nie jedziemy if (tsGuardSignal->GetStatus() & DSBSTATUS_PLAYING) // jeśli gada, to nie jedziemy
return false; return false;
#else
if( ( tsGuardSignal != nullptr )
&& ( true == tsGuardSignal->is_playing() ) ) {
return false;
}
#endif
bool OK = true; bool OK = true;
if( ( iDrivigFlags & moveDoorOpened ) if( ( iDrivigFlags & moveDoorOpened )
&& ( VelDesired > 0.0 ) ) { // to prevent door shuffle on stop && ( VelDesired > 0.0 ) ) { // to prevent door shuffle on stop
@@ -2587,7 +2597,7 @@ bool TController::IncSpeed()
} }
if( true == mvOccupied->DepartureSignal ) { if( true == mvOccupied->DepartureSignal ) {
// shut off departure warning // shut off departure warning
mvOccupied->DepartureSignal = false; mvOccupied->signal_departure( false );
} }
if (mvControlling->SlippingWheels) if (mvControlling->SlippingWheels)
return false; // jak poślizg, to nie przyspieszamy return false; // jak poślizg, to nie przyspieszamy
@@ -2977,11 +2987,12 @@ void TController::Doors(bool what)
if (mvOccupied->DoorOpenCtrl == 1) if (mvOccupied->DoorOpenCtrl == 1)
{ // jeśli drzwi sterowane z kabiny { // jeśli drzwi sterowane z kabiny
if( AIControllFlag ) { 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 ) if( ( true == mvOccupied->DoorClosureWarning )
&& ( false == mvOccupied->DepartureSignal ) && ( false == mvOccupied->DepartureSignal )
&& ( true == TestFlag( iDrivigFlags, moveDoorOpened ) ) ) { && ( 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 fActionTime = -3.0 - 0.1 * Random( 10 ); // 3-4 second wait
} }
if( fActionTime > -0.5 ) { if( fActionTime > -0.5 ) {
@@ -3082,22 +3093,34 @@ bool TController::PutCommand( std::string NewCommand, double NewValue1, double N
asNextStop = TrainParams->NextStop(); asNextStop = TrainParams->NextStop();
iDrivigFlags |= movePrimary; // skoro dostał rozkład, to jest teraz głównym iDrivigFlags |= movePrimary; // skoro dostał rozkład, to jest teraz głównym
NewCommand = Global::asCurrentSceneryPath + NewCommand + ".wav"; // na razie jeden NewCommand = Global::asCurrentSceneryPath + NewCommand + ".wav"; // na razie jeden
if (FileExists(NewCommand)) if (FileExists(NewCommand)) {
{ // wczytanie dźwięku odjazdu podawanego bezpośrenido // wczytanie dźwięku odjazdu podawanego bezpośrenido
tsGuardSignal = new TTextSound(NewCommand, 30, pVehicle->GetPosition().x, #ifdef EU07_USE_OLD_SOUNDCODE
pVehicle->GetPosition().y, pVehicle->GetPosition().z, tsGuardSignal =
new TTextSound(
NewCommand, 30,
pVehicle->GetPosition().x, pVehicle->GetPosition().y, pVehicle->GetPosition().z,
false); false);
// rsGuardSignal->Stop(); #else
tsGuardSignal = new sound_source( sound_placement::external, 75.f );
tsGuardSignal->deserialize( NewCommand, sound_type::single );
#endif
iGuardRadio = 0; // nie przez radio iGuardRadio = 0; // nie przez radio
} }
else else {
{
NewCommand = NewCommand.insert(NewCommand.find_last_of("."),"radio"); // wstawienie przed kropkč NewCommand = NewCommand.insert(NewCommand.find_last_of("."),"radio"); // wstawienie przed kropkč
if (FileExists(NewCommand)) if (FileExists(NewCommand)) {
{ // wczytanie dźwięku odjazdu w wersji radiowej (słychać tylko w kabinie) // wczytanie dźwięku odjazdu w wersji radiowej (słychać tylko w kabinie)
tsGuardSignal = new TTextSound(NewCommand, -1, pVehicle->GetPosition().x, #ifdef EU07_USE_OLD_SOUNDCODE
pVehicle->GetPosition().y, pVehicle->GetPosition().z, tsGuardSignal =
new TTextSound(
NewCommand, -1,
pVehicle->GetPosition().x, pVehicle->GetPosition().y, pVehicle->GetPosition().z,
false); false);
#else
tsGuardSignal = new sound_source( sound_placement::internal, 2 * EU07_SOUND_CABCONTROLSCUTOFFRANGE );
tsGuardSignal->deserialize( NewCommand, sound_type::single );
#endif
iGuardRadio = iRadioChannel; iGuardRadio = iRadioChannel;
} }
} }
@@ -4463,35 +4486,56 @@ TController::UpdateSituation(double dt) {
// jeśli można jechać, to odpalić dźwięk kierownika oraz zamknąć drzwi w // 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ć // składzie, jeśli nie mamy czekać na sygnał też trzeba odpalić
if (iDrivigFlags & moveGuardSignal) if (iDrivigFlags & moveGuardSignal)
{ // komunikat od kierownika tu, bo musi być wolna droga i odczekany czas { // komunikat od kierownika tu, bo musi być wolna droga i odczekany czas stania
// stania
iDrivigFlags &= ~moveGuardSignal; // tylko raz nadać iDrivigFlags &= ~moveGuardSignal; // tylko raz nadać
/*
if( iDrivigFlags & moveDoorOpened ) // jeśli drzwi otwarte if( ( iDrivigFlags & moveDoorOpened )
if( !mvOccupied && ( false == mvOccupied->DoorOpenCtrl ) ) {
->DoorOpenCtrl ) // jeśli drzwi niesterowane przez maszynistę // jeśli drzwi otwarte, niesterowane przez maszynistę
Doors( false ); // a EZT zamknie dopiero po odegraniu komunikatu kierownika Doors( false ); // a EZT zamknie dopiero po odegraniu komunikatu kierownika
}
*/
if( tsGuardSignal != nullptr ) {
#ifdef EU07_USE_OLD_SOUNDCODE
tsGuardSignal->Stop(); tsGuardSignal->Stop();
#else
tsGuardSignal->stop();
#endif
// w zasadzie to powinien mieć flagę, czy jest dźwiękiem radiowym, czy // w zasadzie to powinien mieć flagę, czy jest dźwiękiem radiowym, czy
// bezpośrednim // bezpośrednim
// albo trzeba zrobić dwa dźwięki, jeden bezpośredni, słyszalny w // albo trzeba zrobić dwa dźwięki, jeden bezpośredni, słyszalny w
// pobliżu, a drugi radiowy, słyszalny w innych lokomotywach // 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ć // na razie zakładam, że to nie jest dźwięk radiowy, bo trzeba by zrobić
// obsługę kanałów radiowych itd. // obsługę kanałów radiowych itd.
if( !iGuardRadio ) { if( iGuardRadio == 0 ) {
// jeśli nie przez radio // jeśli nie przez radio
#ifdef EU07_USE_OLD_SOUNDCODE
tsGuardSignal->Play( 1.0, 0, !FreeFlyModeFlag, pVehicle->GetPosition() ); // dla true jest głośniej tsGuardSignal->Play( 1.0, 0, !FreeFlyModeFlag, pVehicle->GetPosition() ); // dla true jest głośniej
#else
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 );
#endif
} }
else { else {
// if (iGuardRadio==iRadioChannel) //zgodność kanału // if (iGuardRadio==iRadioChannel) //zgodność kanału
// if (!FreeFlyModeFlag) //obserwator musi być w środku pojazdu // if (!FreeFlyModeFlag) //obserwator musi być w środku pojazdu
// (albo może mieć radio przenośne) - kierownik mógłby powtarzać // (albo może mieć radio przenośne) - kierownik mógłby powtarzać
// przy braku reakcji // przy braku reakcji
#ifdef EU07_USE_OLD_SOUNDCODE
if( SquareMagnitude( pVehicle->GetPosition() - Global::pCameraPosition ) < 2000 * 2000 ) { if( SquareMagnitude( pVehicle->GetPosition() - Global::pCameraPosition ) < 2000 * 2000 ) {
// w odległości mniejszej niż 2km // w odległości mniejszej niż 2km
tsGuardSignal->Play( 1.0, 0, true, pVehicle->GetPosition() ); // dźwięk niby przez radio tsGuardSignal->Play( 1.0, 0, true, pVehicle->GetPosition() ); // dźwięk niby przez radio
} }
#else
// 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 );
#endif
}
} }
} }
} }

View File

@@ -242,7 +242,10 @@ private:
TTrainParameters *TrainParams = nullptr; // rozkład jazdy zawsze jest, nawet jeśli pusty TTrainParameters *TrainParams = nullptr; // rozkład jazdy zawsze jest, nawet jeśli pusty
int iRadioChannel = 1; // numer aktualnego kanału radiowego int iRadioChannel = 1; // numer aktualnego kanału radiowego
int iGuardRadio = 0; // numer kanału radiowego kierownika (0, gdy nie używa radia) int iGuardRadio = 0; // numer kanału radiowego kierownika (0, gdy nie używa radia)
/*
TTextSound *tsGuardSignal = nullptr; // komunikat od kierownika TTextSound *tsGuardSignal = nullptr; // komunikat od kierownika
*/
sound_source *tsGuardSignal { nullptr };
public: public:
double AccPreferred = 0.0; // preferowane przyspieszenie (wg psychiki kierującego, zmniejszana przy wykryciu kolizji) 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) double AccDesired = AccPreferred; // przyspieszenie, jakie ma utrzymywać (<0:nie przyspieszaj,<-0.1:hamuj)

1902
DynObj.cpp

File diff suppressed because it is too large Load Diff

132
DynObj.h
View File

@@ -14,10 +14,9 @@ http://mozilla.org/MPL/2.0/.
#include "TrkFoll.h" #include "TrkFoll.h"
// McZapkie: // McZapkie:
#include "RealSound.h"
#include "AdvSound.h"
#include "Button.h" #include "Button.h"
#include "AirCoupler.h" #include "AirCoupler.h"
#include "sound.h"
#include "texture.h" #include "texture.h"
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@@ -260,11 +259,32 @@ private:
// Ra: koneic animacji do ogarnięcia // Ra: koneic animacji do ogarnięcia
private: private:
void ABuLittleUpdate(double ObjSqrDist); // types
bool btnOn; // ABu: czy byly uzywane buttony, jesli tak, to po renderingu wylacz struct coupler_sounds {
// bo ten sam model moze byc jeszcze wykorzystany przez inny obiekt! sound_source dsbCouplerAttach { sound_placement::external }; // moved from cab
double ComputeRadius( Math3D::vector3 p1, Math3D::vector3 p2, Math3D::vector3 p3, Math3D::vector3 p4); 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 }; // Ra: przeniesione z kabiny
sound_source rsDoorClose{ sound_placement::general };
};
// 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 btCoupler1; // sprzegi
TButton btCoupler2; TButton btCoupler2;
TAirCoupler btCPneumatic1; // sprzegi powietrzne //yB - zmienione z Button na AirCoupler - krzyzyki TAirCoupler btCPneumatic1; // sprzegi powietrzne //yB - zmienione z Button na AirCoupler - krzyzyki
@@ -304,44 +324,55 @@ private:
double dRailLength; double dRailLength;
double dRailPosition[MaxAxles]; // licznik pozycji osi w/m szyny double dRailPosition[MaxAxles]; // licznik pozycji osi w/m szyny
double dWheelsPosition[MaxAxles]; // pozycja osi w/m srodka pojazdu double dWheelsPosition[MaxAxles]; // pozycja osi w/m srodka pojazdu
TRealSound rsStukot[MaxAxles]; // dzwieki poszczegolnych osi //McZapkie-270202 std::vector<sound_source> rsStukot; // dzwieki poszczegolnych osi //McZapkie-270202
TRealSound rsSilnik; // McZapkie-010302 - silnik // engine sounds
TRealSound rsWentylator; // McZapkie-030302 sound_source dsbDieselIgnition { sound_placement::engine }; // moved from cab
TRealSound rsPisk; // McZapkie-260302 sound_source rsSilnik { sound_placement::engine };
TRealSound rsDerailment; // McZapkie-051202 sound_source dsbRelay { sound_placement::engine };
TRealSound rsPrzekladnia; sound_source dsbWejscie_na_bezoporow { sound_placement::engine }; // moved from cab
TAdvancedSound sHorn1; sound_source dsbWejscie_na_drugi_uklad { sound_placement::engine }; // moved from cab
TAdvancedSound sHorn2; sound_source rsPrzekladnia { sound_placement::engine };
TAdvancedSound sCompressor; // NBMX wrzesien 2003 sound_source rsEngageSlippery { sound_placement::engine }; // moved from cab
TAdvancedSound sConverter; sound_source rsDieselInc { sound_placement::engine }; // youBy
TAdvancedSound sSmallCompressor; sound_source sTurbo { sound_placement::engine };
TAdvancedSound sDepartureSignal; sound_source rsWentylator { sound_placement::engine }; // McZapkie-030302
TAdvancedSound sTurbo; sound_source sConverter { sound_placement::engine };
TAdvancedSound sSand; sound_source sCompressor { sound_placement::engine }; // NBMX wrzesien 2003
TAdvancedSound sReleaser; sound_source sSmallCompressor { sound_placement::engine };
// braking sounds
// Winger 010304 sound_source dsbPneumaticRelay { sound_placement::external };
TRealSound sPantUp; sound_source rsUnbrake { sound_placement::external }; // yB - odglos luzowania
TRealSound sPantDown; sound_source sReleaser { sound_placement::external };
TRealSound rsDoorOpen; // Ra: przeniesione z kabiny sound_source rsSlippery { sound_placement::external, EU07_SOUND_BRAKINGCUTOFFRANGE }; // moved from cab
TRealSound rsDoorClose; 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 };
sound_source sHorn2 { sound_placement::external };
sound_source rsRunningNoise { sound_placement::external, EU07_SOUND_RUNNINGNOISECUTOFFRANGE };
sound_source rscurve { sound_placement::external, EU07_SOUND_RUNNINGNOISECUTOFFRANGE }; // youBy
double eng_vol_act; double eng_vol_act;
double eng_frq_act; double eng_frq_act;
double eng_dfrq; double eng_dfrq;
double eng_turbo; double eng_turbo;
void ABuBogies();
void ABuModelRoll();
Math3D::vector3 modelShake; Math3D::vector3 modelShake;
bool renderme; // yB - czy renderowac bool renderme; // yB - czy renderowac
// TRealSound sBrakeAcc; //dźwięk przyspieszacza
PSound sBrakeAcc;
bool bBrakeAcc;
TRealSound rsUnbrake; // yB - odglos luzowania
float ModCamRot; float ModCamRot;
int iInventory[ 2 ] { 0, 0 }; // flagi bitowe posiadanych submodeli (np. świateł) 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!
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
public: public:
int iHornWarning; // numer syreny do użycia po otrzymaniu sygnału do jazdy int iHornWarning; // numer syreny do użycia po otrzymaniu sygnału do jazdy
@@ -377,10 +408,10 @@ private:
void SetPneumatic(bool front, bool red); void SetPneumatic(bool front, bool red);
std::string asName; std::string asName;
std::string name() const { std::string name() const {
return this ? asName : std::string(); }; return this ?
asName :
std::string(); };
TRealSound rsDiesielInc; // youBy
TRealSound rscurve; // youBy
// std::ofstream PneuLogFile; //zapis parametrow pneumatycznych // std::ofstream PneuLogFile; //zapis parametrow pneumatycznych
// youBy - dym // youBy - dym
// TSmoke Smog; // TSmoke Smog;
@@ -431,13 +462,17 @@ private:
inline Math3D::vector3 RearPosition() { inline Math3D::vector3 RearPosition() {
return vCoulpler[iDirection]; }; return vCoulpler[iDirection]; };
inline Math3D::vector3 AxlePositionGet() { inline Math3D::vector3 AxlePositionGet() {
return iAxleFirst ? Axle1.pPosition : Axle0.pPosition; }; return iAxleFirst ?
Axle1.pPosition :
Axle0.pPosition; };
inline Math3D::vector3 VectorFront() const { inline Math3D::vector3 VectorFront() const {
return vFront; }; return vFront; };
inline Math3D::vector3 VectorUp() { inline Math3D::vector3 VectorUp() const {
return vUp; }; return vUp; };
inline Math3D::vector3 VectorLeft() const { inline Math3D::vector3 VectorLeft() const {
return vLeft; }; return vLeft; };
inline double const * Matrix() const {
return mMatrix.readArray(); };
inline double * Matrix() { inline double * Matrix() {
return mMatrix.getArray(); }; return mMatrix.getArray(); };
inline double GetVelocity() { inline double GetVelocity() {
@@ -447,7 +482,9 @@ private:
inline double GetWidth() const { inline double GetWidth() const {
return MoverParameters->Dim.W; }; return MoverParameters->Dim.W; };
inline TTrack * GetTrack() { inline TTrack * GetTrack() {
return (iAxleFirst ? Axle1.GetTrack() : Axle0.GetTrack()); }; return (iAxleFirst ?
Axle1.GetTrack() :
Axle0.GetTrack()); };
// McZapkie-260202 // McZapkie-260202
void LoadMMediaFile(std::string BaseDir, std::string TypeName, std::string ReplacableSkin); void LoadMMediaFile(std::string BaseDir, std::string TypeName, std::string ReplacableSkin);
@@ -456,13 +493,22 @@ private:
return (Axle1.GetTrack() == MyTrack ? Axle1.GetDirection() : Axle0.GetDirection()); }; return (Axle1.GetTrack() == MyTrack ? Axle1.GetDirection() : Axle0.GetDirection()); };
// zwraca kierunek pojazdu na torze z aktywną osą // zwraca kierunek pojazdu na torze z aktywną osą
inline double RaDirectionGet() { 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ą // zwraca przesunięcie wózka względem Point1 toru z aktywną osią
inline double RaTranslationGet() { inline double RaTranslationGet() {
return iAxleFirst ? Axle1.GetTranslation() : Axle0.GetTranslation(); }; return iAxleFirst ?
Axle1.GetTranslation() :
Axle0.GetTranslation(); };
// zwraca tor z aktywną osią // zwraca tor z aktywną osią
inline TTrack * RaTrackGet() { 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 CouplersDettach(double MinDist, int MyScanDir);
void RadioStop(); void RadioStop();
void Damage(char flag); void Damage(char flag);

View File

@@ -25,12 +25,14 @@ Stele, firleju, szociu, hunter, ZiomalCl, OLI_EU and others
#include "Globals.h" #include "Globals.h"
#include "timer.h" #include "timer.h"
#include "Logs.h" #include "Logs.h"
#include "renderer.h"
#include "uilayer.h"
#include "audiorenderer.h"
#include "keyboardinput.h" #include "keyboardinput.h"
#include "mouseinput.h" #include "mouseinput.h"
#include "gamepadinput.h" #include "gamepadinput.h"
#include "Console.h" #include "Console.h"
#include "PyInt.h" #include "PyInt.h"
#include "uilayer.h"
#ifdef EU07_BUILD_STATIC #ifdef EU07_BUILD_STATIC
#pragma comment( lib, "glfw3.lib" ) #pragma comment( lib, "glfw3.lib" )
@@ -46,6 +48,7 @@ Stele, firleju, szociu, hunter, ZiomalCl, OLI_EU and others
#pragma comment( lib, "opengl32.lib" ) #pragma comment( lib, "opengl32.lib" )
#pragma comment( lib, "glu32.lib" ) #pragma comment( lib, "glu32.lib" )
#pragma comment( lib, "dsound.lib" ) #pragma comment( lib, "dsound.lib" )
#pragma comment( lib, "openal32.lib")
#pragma comment( lib, "winmm.lib" ) #pragma comment( lib, "winmm.lib" )
#pragma comment( lib, "setupapi.lib" ) #pragma comment( lib, "setupapi.lib" )
#pragma comment( lib, "python27.lib" ) #pragma comment( lib, "python27.lib" )
@@ -405,6 +408,9 @@ int main(int argc, char *argv[])
return -1; return -1;
} }
audio::renderer.init();
input::Keyboard.init(); input::Keyboard.init();
input::Mouse.init(); input::Mouse.init();
input::Gamepad.init(); input::Gamepad.init();

View File

@@ -1022,26 +1022,21 @@ event_manager::CheckQuery() {
return false; return false;
} }
case tp_Sound: { case tp_Sound: {
if( m_workevent->Params[ 9 ].tsTextSound == nullptr ) {
break;
}
switch( m_workevent->Params[ 0 ].asInt ) { switch( m_workevent->Params[ 0 ].asInt ) {
// trzy możliwe przypadki: // trzy możliwe przypadki:
case 0: { case 0: {
m_workevent->Params[ 9 ].tsTextSound->Stop(); m_workevent->Params[ 9 ].tsTextSound->stop();
break; break;
} }
case 1: { case 1: {
m_workevent->Params[ 9 ].tsTextSound->Play( m_workevent->Params[ 9 ].tsTextSound->play( sound_flags::exclusive );
1,
0,
true,
m_workevent->Params[ 9 ].tsTextSound->vSoundPosition );
break; break;
} }
case -1: { case -1: {
m_workevent->Params[ 9 ].tsTextSound->Play( m_workevent->Params[ 9 ].tsTextSound->play( sound_flags::exclusive | sound_flags::looping );
1,
DSBPLAY_LOOPING,
true,
m_workevent->Params[ 9 ].tsTextSound->vSoundPosition );
break; break;
} }
default: { default: {
@@ -1572,14 +1567,19 @@ event_manager::InitLaunchers() {
} }
} }
launcher->Event1 = ( if( launcher->asEvent1Name != "none" ) {
launcher->asEvent1Name != "none" ? launcher->Event1 = simulation::Events.FindEvent( launcher->asEvent1Name );
simulation::Events.FindEvent( launcher->asEvent1Name ) : if( launcher->Event1 == nullptr ) {
nullptr ); ErrorLog( "Bad scenario: event launcher \"" + launcher->name() + "\" cannot find event \"" + launcher->asEvent1Name + "\"" );
launcher->Event2 = ( }
launcher->asEvent2Name != "none" ? }
simulation::Events.FindEvent( launcher->asEvent2Name ) :
nullptr ); 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 + "\"" );
}
}
} }
} }

View File

@@ -74,7 +74,11 @@ union TParam
bool asBool; bool asBool;
double asdouble; double asdouble;
int asInt; int asInt;
#ifdef EU07_USE_OLD_SOUNDCODE
TTextSound *tsTextSound; TTextSound *tsTextSound;
#else
sound_source *tsTextSound;
#endif
char *asText; char *asText;
TCommandType asCommand; TCommandType asCommand;
TTractionPowerSource *psPower; TTractionPowerSource *psPower;

120
Gauge.cpp
View File

@@ -19,24 +19,23 @@ http://mozilla.org/MPL/2.0/.
#include "Model3d.h" #include "Model3d.h"
#include "Timer.h" #include "Timer.h"
#include "logs.h" #include "logs.h"
#include "renderer.h"
void TGauge::Init(TSubModel *NewSubModel, TGaugeType eNewType, double fNewScale, double fNewOffset, double fNewFriction, double fNewValue) void TGauge::Init(TSubModel *NewSubModel, TGaugeType eNewType, double fNewScale, double fNewOffset, double fNewFriction, double fNewValue)
{ // ustawienie parametrów animacji submodelu { // ustawienie parametrów animacji submodelu
if (NewSubModel) if (NewSubModel) {
{ // warunek na wszelki wypadek, gdyby się submodel nie // warunek na wszelki wypadek, gdyby się submodel nie podłączył
// podłączył
fFriction = fNewFriction; fFriction = fNewFriction;
fValue = fNewValue; fValue = fNewValue;
fOffset = fNewOffset; fOffset = fNewOffset;
fScale = fNewScale; fScale = fNewScale;
SubModel = NewSubModel; SubModel = NewSubModel;
eType = eNewType; eType = eNewType;
if (eType == gt_Digital) if (eType == gt_Digital) {
{
TSubModel *sm = SubModel->ChildGet(); TSubModel *sm = SubModel->ChildGet();
do do {
{ // pętla po submodelach potomnych i obracanie ich o kąt zależy od // pętla po submodelach potomnych i obracanie ich o kąt zależy od cyfry w (fValue)
// cyfry w (fValue)
if (sm->pName.size()) if (sm->pName.size())
{ // musi mieć niepustą nazwę { // musi mieć niepustą nazwę
if (sm->pName[0] >= '0') if (sm->pName[0] >= '0')
@@ -48,10 +47,17 @@ void TGauge::Init(TSubModel *NewSubModel, TGaugeType eNewType, double fNewScale,
} }
else // a banan może być z optymalizacją? else // a banan może być z optymalizacją?
NewSubModel->WillBeAnimated(); // wyłączenie ignowania jedynkowego transformu NewSubModel->WillBeAnimated(); // wyłączenie ignowania jedynkowego transformu
// 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; std::string submodelname, gaugetypename;
double scale, offset, friction; double scale, offset, friction;
@@ -70,24 +76,30 @@ bool TGauge::Load(cParser &Parser, TModel3d *md1, TModel3d *md2, double mul) {
else { else {
// new, block type config // new, block type config
// TODO: rework the base part into yaml-compatible flow style mapping // TODO: rework the base part into yaml-compatible flow style mapping
cParser mappingparser( Parser.getToken<std::string>( false, "}" ) ); submodelname = Parser.getToken<std::string>( false );
submodelname = mappingparser.getToken<std::string>( false ); gaugetypename = Parser.getToken<std::string>( true );
gaugetypename = mappingparser.getToken<std::string>( true ); Parser.getTokens( 3, false );
mappingparser.getTokens( 3, false ); Parser
mappingparser
>> scale >> scale
>> offset >> offset
>> friction; >> friction;
// new, variable length section // new, variable length section
while( true == Load_mapping( mappingparser ) ) { while( true == Load_mapping( Parser ) ) {
; // all work done by while() ; // 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; scale *= mul;
TSubModel *submodel = md1->GetFromName( submodelname ); TSubModel *submodel = md1->GetFromName( submodelname );
if( scale == 0.0 ) { 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; scale = 1.0;
} }
if (submodel) // jeśli nie znaleziony if (submodel) // jeśli nie znaleziony
@@ -95,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) 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 submodel = md2->GetFromName(submodelname); // to może tam będzie, co za różnica gdzie
if( submodel == nullptr ) { 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 { std::map<std::string, TGaugeType> gaugetypes {
@@ -116,26 +128,15 @@ bool TGauge::Load(cParser &Parser, TModel3d *md1, TModel3d *md2, double mul) {
bool bool
TGauge::Load_mapping( cParser &Input ) { TGauge::Load_mapping( cParser &Input ) {
if( false == Input.getTokens( 2, true, ", \n\r\t" ) ) { // token can be a key or block end
return false; 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
std::string key, value;
Input
>> key
>> value;
if( key == "soundinc:" ) { if( key == "soundinc:" ) {
m_soundfxincrease = ( m_soundfxincrease.deserialize( Input, sound_type::single );
value != "none" ?
TSoundsManager::GetFromName( value, true ) :
nullptr );
} }
else if( key == "sounddec:" ) { else if( key == "sounddec:" ) {
m_soundfxdecrease = ( m_soundfxdecrease.deserialize( Input, sound_type::single );
value != "none" ?
TSoundsManager::GetFromName( value, true ) :
nullptr );
} }
else if( key.compare( 0, std::min<std::size_t>( key.size(), 5 ), "sound" ) == 0 ) { 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 // sounds assigned to specific gauge values, defined by key soundFoo: where Foo = value
@@ -144,9 +145,7 @@ TGauge::Load_mapping( cParser &Input ) {
if( indexstart != std::string::npos ) { if( indexstart != std::string::npos ) {
m_soundfxvalues.emplace( m_soundfxvalues.emplace(
std::stoi( key.substr( indexstart, indexend - indexstart ) ), std::stoi( key.substr( indexstart, indexend - indexstart ) ),
( value != "none" ? sound_source( sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE ).deserialize( Input, sound_type::single ) );
TSoundsManager::GetFromName( value, true ) :
nullptr ) );
} }
} }
return true; // return value marks a key: value pair was extracted, nothing about whether it's recognized return true; // return value marks a key: value pair was extracted, nothing about whether it's recognized
@@ -176,9 +175,21 @@ void TGauge::DecValue(double fNewDesired)
fDesiredValue = 0; 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 // ustawienie wartości docelowej. plays provided fallback sound, if no sound was defined in the control itself
void void
TGauge::UpdateValue( double fNewDesired, PSound Fallbacksound ) { TGauge::UpdateValue( double fNewDesired, sound_source *Fallbacksound ) {
auto const desiredtimes100 = static_cast<int>( std::round( 100.0 * fNewDesired ) ); auto const desiredtimes100 = static_cast<int>( std::round( 100.0 * fNewDesired ) );
if( static_cast<int>( std::round( 100.0 * ( fDesiredValue - fOffset ) / fScale ) ) == desiredtimes100 ) { if( static_cast<int>( std::round( 100.0 * ( fDesiredValue - fOffset ) / fScale ) ) == desiredtimes100 ) {
@@ -191,21 +202,25 @@ TGauge::UpdateValue( double fNewDesired, PSound Fallbacksound ) {
// filter out values other than full integers // filter out values other than full integers
auto const lookup = m_soundfxvalues.find( desiredtimes100 / 100 ); auto const lookup = m_soundfxvalues.find( desiredtimes100 / 100 );
if( lookup != m_soundfxvalues.end() ) { if( lookup != m_soundfxvalues.end() ) {
play( lookup->second ); lookup->second.play();
return; return;
} }
} }
// ...and if there isn't any, fall back on the basic set... // ...and if there isn't any, fall back on the basic set...
auto const currentvalue = GetValue(); auto const currentvalue = GetValue();
if( ( currentvalue < fNewDesired ) && ( m_soundfxincrease != nullptr ) ) { if( ( currentvalue < fNewDesired )
play( m_soundfxincrease ); && ( false == m_soundfxincrease.empty() ) ) {
// shift up
m_soundfxincrease.play();
} }
else if( ( currentvalue > fNewDesired ) && ( m_soundfxdecrease != nullptr ) ) { else if( ( currentvalue > fNewDesired )
play( m_soundfxdecrease ); && ( false == m_soundfxdecrease.empty() ) ) {
// shift down
m_soundfxdecrease.play();
} }
else if( Fallbacksound != nullptr ) { else if( Fallbacksound != nullptr ) {
// ...and if that fails too, try the provided fallback sound from legacy system // ...and if that fails too, try the provided fallback sound from legacy system
play( Fallbacksound ); Fallbacksound->play();
} }
}; };
@@ -282,8 +297,6 @@ void TGauge::Update() {
} }
}; };
void TGauge::Render(){};
void TGauge::AssignFloat(float *fValue) void TGauge::AssignFloat(float *fValue)
{ {
cDataType = 'f'; cDataType = 'f';
@@ -315,15 +328,14 @@ void TGauge::UpdateValue()
} }
}; };
void // returns offset of submodel associated with the button from the model centre
TGauge::play( PSound Sound ) { glm::vec3
TGauge::model_offset() const {
if( Sound == nullptr ) { return; } return (
SubModel != nullptr ?
Sound->SetCurrentPosition( 0 ); SubModel->offset( 1.f ) :
Sound->SetVolume( DSBVOLUME_MAX ); glm::vec3() );
Sound->Play( 0, 0, 0 );
return;
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------

62
Gauge.h
View File

@@ -24,7 +24,37 @@ enum TGaugeType {
// animowany wskaźnik, mogący przyjmować wiele stanów pośrednich // animowany wskaźnik, mogący przyjmować wiele stanów pośrednich
class TGauge { class TGauge {
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: 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 TGaugeType eType { gt_Unknown }; // typ ruchu
double fFriction { 0.0 }; // hamowanie przy zliżaniu się do zadanej wartości double fFriction { 0.0 }; // hamowanie przy zliżaniu się do zadanej wartości
double fDesiredValue { 0.0 }; // wartość docelowa double fDesiredValue { 0.0 }; // wartość docelowa
@@ -38,36 +68,10 @@ class TGauge {
double *dData { nullptr }; double *dData { nullptr };
int *iData; int *iData;
}; };
PSound m_soundfxincrease { nullptr }; // sound associated with increasing control's value sound_source m_soundfxincrease { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE }; // sound associated with increasing control's value
PSound m_soundfxdecrease { nullptr }; // sound associated with decreasing control's value sound_source m_soundfxdecrease { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE }; // sound associated with decreasing control's value
std::map<int, PSound> m_soundfxvalues; // sounds associated with specific values std::map<int, sound_source> 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( PSound Sound );
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, PSound 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; // McZapkie-310302: zeby mozna bylo sprawdzac czy zainicjowany poprawnie
}; };
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------

View File

@@ -53,19 +53,15 @@ std::string Global::szTexturesDDS = ".dds"; // lista tekstur od DDS
int Global::iPause = 0; // 0x10; // globalna pauza ruchu int Global::iPause = 0; // 0x10; // globalna pauza ruchu
bool Global::bActive = true; // czy jest aktywnym oknem bool Global::bActive = true; // czy jest aktywnym oknem
TWorld *Global::pWorld = NULL; TWorld *Global::pWorld = NULL;
cParser *Global::pParser = NULL;
TCamera *Global::pCamera = NULL; // parametry kamery 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 TTranscripts Global::tranTexts; // obiekt obsługujący stenogramy dźwięków na ekranie
float4 Global::UITextColor = float4( 225.0 / 255.0f, 225.0f / 255.0f, 225.0f / 255.0f, 1.0f ); float4 Global::UITextColor = float4( 225.0 / 255.0f, 225.0f / 255.0f, 225.0f / 255.0f, 1.0f );
// parametry scenerii
vector3 Global::pCameraPosition; vector3 Global::pCameraPosition;
vector3 Global::DebugCameraPosition; vector3 Global::DebugCameraPosition;
double Global::pCameraRotation;
double Global::pCameraRotationDeg;
std::vector<vector3> Global::FreeCameraInit; std::vector<vector3> Global::FreeCameraInit;
std::vector<vector3> Global::FreeCameraInitAngle; std::vector<vector3> Global::FreeCameraInitAngle;
// parametry scenerii
GLfloat Global::FogColor[] = {0.6f, 0.7f, 0.8f}; GLfloat Global::FogColor[] = {0.6f, 0.7f, 0.8f};
double Global::fFogStart = 1700; double Global::fFogStart = 1700;
double Global::fFogEnd = 2000; double Global::fFogEnd = 2000;
@@ -127,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::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 int Global::iSlowMotionMask = -1; // maska wyłączanych właściwości dla zwiększenia FPS
// bool Global::bTerrainCompact=true; //czy zapisać teren w pliku // 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::fFpsAverage = 20.0; // oczekiwana wartosć FPS
double Global::fFpsDeviation = 5.0; // odchylenie standardowe 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 double Global::fFpsMin = 30.0; // dolna granica FPS, przy której promień scenerii będzie zmniejszany
@@ -138,6 +132,8 @@ bool Global::FullPhysics { true }; // full calculations performed for each simul
// parametry testowe (do testowania scenerii i obiektów) // parametry testowe (do testowania scenerii i obiektów)
bool Global::bWireFrame = false; bool Global::bWireFrame = false;
bool Global::bSoundEnabled = true; bool Global::bSoundEnabled = true;
float Global::AudioVolume = 1.0f;
int Global::iWriteLogEnabled = 3; // maska bitowa: 1-zapis do pliku, 2-okienko, 4-nazwy torów int Global::iWriteLogEnabled = 3; // maska bitowa: 1-zapis do pliku, 2-okienko, 4-nazwy torów
bool Global::MultipleLogs{ false }; bool Global::MultipleLogs{ false };
@@ -965,16 +961,6 @@ void Global::SetCameraPosition(vector3 pNewCameraPosition)
pCameraPosition = 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) void Global::TrainDelete(TDynamicObject *d)
{ // usunięcie pojazdu prowadzonego przez użytkownika { // usunięcie pojazdu prowadzonego przez użytkownika
if (pWorld) if (pWorld)
@@ -983,20 +969,6 @@ void Global::TrainDelete(TDynamicObject *d)
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
bool Global::DoEvents()
{ // wywoływać czasem, żeby nie robił wrażenia zawieszonego
MSG msg;
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
return FALSE;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return TRUE;
}
//---------------------------------------------------------------------------
TTranscripts::TTranscripts() TTranscripts::TTranscripts()
{ {
/* /*

View File

@@ -10,10 +10,8 @@ http://mozilla.org/MPL/2.0/.
#pragma once #pragma once
#include <string> #include <string>
#include <Windows.h>
#include "renderer.h" #include "renderer.h"
#include "glfw/glfw3.h"
#include "gl/glew.h"
#include "dumb3d.h" #include "dumb3d.h"
// definicje klawiszy // definicje klawiszy
@@ -113,16 +111,6 @@ const int k_WalkMode = 73;
int const k_DimHeadlights = 74; int const k_DimHeadlights = 74;
const int MaxKeys = 75; 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 TTextSound;
class TTranscript class TTranscript
{ // klasa obsługująca linijkę napisu do dźwięku { // klasa obsługująca linijkę napisu do dźwięku
public: public:
@@ -159,9 +147,7 @@ public:
static void InitKeys(); static void InitKeys();
inline static Math3D::vector3 GetCameraPosition() { return pCameraPosition; }; inline static Math3D::vector3 GetCameraPosition() { return pCameraPosition; };
static void SetCameraPosition(Math3D::vector3 pNewCameraPosition); static void SetCameraPosition(Math3D::vector3 pNewCameraPosition);
static void SetCameraRotation(double Yaw);
static void TrainDelete(TDynamicObject *d); static void TrainDelete(TDynamicObject *d);
static bool DoEvents();
static std::string Bezogonkow(std::string str, bool _ = false); static std::string Bezogonkow(std::string str, bool _ = false);
static double Min0RSpeed(double vel1, double vel2); static double Min0RSpeed(double vel1, double vel2);
@@ -170,8 +156,6 @@ public:
static bool RealisticControlMode; // controls ability to steer the vehicle from outside views static bool RealisticControlMode; // controls ability to steer the vehicle from outside views
static Math3D::vector3 pCameraPosition; // pozycja kamery w świecie static Math3D::vector3 pCameraPosition; // pozycja kamery w świecie
static Math3D::vector3 DebugCameraPosition; // 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> FreeCameraInit; // pozycje kamery
static std::vector<Math3D::vector3> FreeCameraInitAngle; static std::vector<Math3D::vector3> FreeCameraInitAngle;
static int iWindowWidth; static int iWindowWidth;
@@ -182,6 +166,7 @@ public:
static bool bFreeFly; static bool bFreeFly;
static bool bWireFrame; static bool bWireFrame;
static bool bSoundEnabled; static bool bSoundEnabled;
static float AudioVolume;
// McZapkie-131202 // McZapkie-131202
static bool bAdjustScreenFreq; static bool bAdjustScreenFreq;
static bool bEnableTraction; static bool bEnableTraction;
@@ -272,16 +257,12 @@ public:
static bool bHideConsole; // hunter-271211: ukrywanie konsoli static bool bHideConsole; // hunter-271211: ukrywanie konsoli
static TWorld *pWorld; // wskaźnik na świat do usuwania pojazdów 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 bool bRollFix; // czy wykonać przeliczanie przechyłki
static cParser *pParser;
static double fFpsAverage; // oczekiwana wartosć FPS static double fFpsAverage; // oczekiwana wartosć FPS
static double fFpsDeviation; // odchylenie standardowe FPS static double fFpsDeviation; // odchylenie standardowe FPS
static double fFpsMin; // dolna granica FPS, przy której promień scenerii będzie zmniejszany 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 double fFpsMax; // górna granica FPS, przy której promień scenerii będzie zwiększany
static TCamera *pCamera; // parametry kamery 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 fCalibrateIn[6][6]; // parametry kalibracyjne wejść z pulpitu
static double fCalibrateOut[7][6]; // parametry kalibracyjne wyjść dla pulpitu static double fCalibrateOut[7][6]; // parametry kalibracyjne wyjść dla pulpitu
static double fCalibrateOutMax[7]; // wartości maksymalne wyjść dla pulpitu static double fCalibrateOutMax[7]; // wartości maksymalne wyjść dla pulpitu
@@ -293,7 +274,9 @@ public:
static float4 UITextColor; // base color of UI text static float4 UITextColor; // base color of UI text
static std::string asLang; // domyślny język - http://tools.ietf.org/html/bcp47 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 int iHiddenEvents; // czy łączyć eventy z torami poprzez nazwę toru
/*
static TTextSound *tsRadioBusy[10]; // zajętość kanałów radiowych (wskaźnik na odgrywany dźwięk) static TTextSound *tsRadioBusy[10]; // zajętość kanałów radiowych (wskaźnik na odgrywany dźwięk)
*/
static int iPoKeysPWM[7]; // numery wejść dla PWM static int iPoKeysPWM[7]; // numery wejść dla PWM
//randomizacja //randomizacja

View File

@@ -197,14 +197,15 @@ static int const s_SHPebrake = 64; //hamuje
static int const s_CAtest = 128; static int const s_CAtest = 128;
/*dzwieki*/ /*dzwieki*/
static int const sound_none = 0; enum sound {
static int const sound_loud = 1; none,
static int const sound_couplerstretch = 2; loud = 0x1,
static int const sound_bufferclamp = 4; couplerstretch = 0x2,
static int const sound_bufferbump = 8; bufferclash = 0x4,
static int const sound_relay = 16; relay = 0x10,
static int const sound_manyrelay = 32; parallel = 0x20,
static int const sound_brakeacc = 64; pneumatic = 0x40
};
//szczególne typy pojazdów (inna obsługa) dla zmiennej TrainType //szczególne typy pojazdów (inna obsługa) dla zmiennej TrainType
//zamienione na flagi bitowe, aby szybko wybierać grupę (np. EZT+SZT) //zamienione na flagi bitowe, aby szybko wybierać grupę (np. EZT+SZT)
@@ -547,18 +548,18 @@ struct TMotorParameters
struct TSecuritySystem struct TSecuritySystem
{ {
int SystemType; /*0: brak, 1: czuwak aktywny, 2: SHP/sygnalizacja kabinowa*/ int SystemType { 0 }; /*0: brak, 1: czuwak aktywny, 2: SHP/sygnalizacja kabinowa*/
double AwareDelay; // czas powtarzania czuwaka double AwareDelay { -1.0 }; // czas powtarzania czuwaka
double AwareMinSpeed; // minimalna prędkość załączenia czuwaka, normalnie 10% Vmax double AwareMinSpeed; // minimalna prędkość załączenia czuwaka, normalnie 10% Vmax
double SoundSignalDelay; double SoundSignalDelay { -1.0 };
double EmergencyBrakeDelay; double EmergencyBrakeDelay { -1.0 };
int Status; /*0: wylaczony, 1: wlaczony, 2: czuwak, 4: shp, 8: alarm, 16: hamowanie awaryjne*/ int Status { 0 }; /*0: wylaczony, 1: wlaczony, 2: czuwak, 4: shp, 8: alarm, 16: hamowanie awaryjne*/
double SystemTimer; double SystemTimer { 0.0 };
double SystemSoundCATimer; double SystemSoundCATimer { 0.0 };
double SystemSoundSHPTimer; double SystemSoundSHPTimer { 0.0 };
double SystemBrakeCATimer; double SystemBrakeCATimer { 0.0 };
double SystemBrakeSHPTimer; double SystemBrakeSHPTimer { 0.0 };
double SystemBrakeCATestTimer; // hunter-091012 double SystemBrakeCATestTimer { 0.0 }; // hunter-091012
int VelocityAllowed; int VelocityAllowed;
int NextVelocityAllowed; /*predkosc pokazywana przez sygnalizacje kabinowa*/ int NextVelocityAllowed; /*predkosc pokazywana przez sygnalizacje kabinowa*/
bool RadioStop; // czy jest RadioStop bool RadioStop; // czy jest RadioStop
@@ -602,6 +603,8 @@ struct TCoupling {
power_coupling power_high; power_coupling power_high;
power_coupling power_low; // TODO: implement this power_coupling power_low; // TODO: implement this
int sounds { 0 }; // sounds emitted by the coupling devices
}; };
class TMoverParameters class TMoverParameters
@@ -1167,6 +1170,7 @@ public:
bool DoorLeft(bool State); //obsluga drzwi lewych bool DoorLeft(bool State); //obsluga drzwi lewych
bool DoorRight(bool State); //obsluga drzwi prawych bool DoorRight(bool State); //obsluga drzwi prawych
bool DoorBlockedFlag(void); //sprawdzenie blokady drzwi bool DoorBlockedFlag(void); //sprawdzenie blokady drzwi
bool signal_departure( bool const State, int const Notify = range::consist ); // toggles departure warning
/* funkcje dla samochodow*/ /* funkcje dla samochodow*/
bool ChangeOffsetH(double DeltaOffset); bool ChangeOffsetH(double DeltaOffset);

View File

@@ -1369,11 +1369,11 @@ double TMoverParameters::ComputeMovement(double dt, double dt1, const TTrackShap
if (EngineType == ElectricSeriesMotor) if (EngineType == ElectricSeriesMotor)
if (AutoRelayCheck()) if (AutoRelayCheck())
SetFlag(SoundFlag, sound_relay); SetFlag(SoundFlag, sound::relay);
if (EngineType == DieselEngine) if (EngineType == DieselEngine)
if (dizel_Update(dt)) if (dizel_Update(dt))
SetFlag(SoundFlag, sound_relay); SetFlag(SoundFlag, sound::relay);
// uklady hamulcowe: // uklady hamulcowe:
if (VeselVolume > 0) if (VeselVolume > 0)
Compressor = CompressedVolume / VeselVolume; Compressor = CompressedVolume / VeselVolume;
@@ -1530,7 +1530,7 @@ double TMoverParameters::FastComputeMovement(double dt, const TTrackShape &Shape
if (EngineType == DieselEngine) if (EngineType == DieselEngine)
if (dizel_Update(dt)) if (dizel_Update(dt))
SetFlag(SoundFlag, sound_relay); SetFlag(SoundFlag, sound::relay);
// uklady hamulcowe: // uklady hamulcowe:
if (VeselVolume > 0) if (VeselVolume > 0)
Compressor = CompressedVolume / VeselVolume; Compressor = CompressedVolume / VeselVolume;
@@ -1703,7 +1703,7 @@ bool TMoverParameters::IncMainCtrl(int CtrlSpeed)
if( RList[ MainCtrlPos ].Bn > 1 ) { if( RList[ MainCtrlPos ].Bn > 1 ) {
if( true == MaxCurrentSwitch( false )) { if( true == MaxCurrentSwitch( false )) {
// wylaczanie wysokiego rozruchu // wylaczanie wysokiego rozruchu
SetFlag( SoundFlag, sound_relay ); SetFlag( SoundFlag, sound::relay );
} // Q TODO: } // Q TODO:
// if (EngineType=ElectricSeriesMotor) and (MainCtrlPos=1) // if (EngineType=ElectricSeriesMotor) and (MainCtrlPos=1)
// then // then
@@ -2375,46 +2375,54 @@ bool TMoverParameters::MainSwitch( bool const State, int const Notify )
{ {
bool MS = false; // Ra: przeniesione z końca bool MS = false; // Ra: przeniesione z końca
if ((Mains != State) && (MainCtrlPosNo > 0)) if( ( Mains != State )
{ && ( MainCtrlPosNo > 0 ) ) {
if ((State == false) ||
(((ScndCtrlPos == 0)||(EngineType == ElectricInductionMotor)) && ((ConvOvldFlag == false) || (TrainType == dt_EZT)) && if( ( false == State )
(LastSwitchingTime > CtrlDelay) && !TestFlag(DamageFlag, dtrain_out) && || ( ( ( ScndCtrlPos == 0 ) || ( EngineType == ElectricInductionMotor ) )
!TestFlag(EngDmgFlag, 1))) && ( ( ConvOvldFlag == false ) || ( TrainType == dt_EZT ) )
{ && ( LastSwitchingTime > CtrlDelay )
if( Mains ) { && ( false == TestFlag( DamageFlag, dtrain_out ) )
&& ( false == TestFlag( EngDmgFlag, 1 ) ) ) ) {
if( true == Mains ) {
// jeśli był załączony // jeśli był załączony
if( Notify != range::local ) { if( Notify != range::local ) {
// wysłanie wyłączenia do pozostałych? // wysłanie wyłączenia do pozostałych?
SendCtrlToNext( SendCtrlToNext(
"MainSwitch", int( State ), CabNo, "MainSwitch", int( State ), CabNo,
( Notify == range::unit ? ( Notify == range::unit ?
ctrain_controll | ctrain_depot : coupling::control | coupling::permanent :
ctrain_controll ) ); coupling::control ) );
} }
} }
Mains = State; Mains = State;
if( Mains ) { MS = true; // wartość zwrotna
LastSwitchingTime = 0;
if( true == Mains ) {
// jeśli został załączony // jeśli został załączony
if( Notify != range::local ) { if( Notify != range::local ) {
// wysłanie wyłączenia do pozostałych? // wysłanie wyłączenia do pozostałych?
SendCtrlToNext( SendCtrlToNext(
"MainSwitch", int( State ), CabNo, "MainSwitch", int( State ), CabNo,
( Notify == range::unit ? ( Notify == range::unit ?
ctrain_controll | ctrain_depot : coupling::control | coupling::permanent :
ctrain_controll ) ); coupling::control ) );
} }
} }
MS = true; // wartość zwrotna if( ( EngineType == DieselEngine )
LastSwitchingTime = 0; && ( true == Mains ) ) {
if ((EngineType == DieselEngine) && Mains)
{
dizel_enginestart = State; dizel_enginestart = State;
} }
if (((TrainType == dt_EZT) && (!State))) if( ( TrainType == dt_EZT )
&& ( false == State ) ) {
ConvOvldFlag = true; ConvOvldFlag = true;
} }
} }
}
// else MainSwitch:=false; // else MainSwitch:=false;
return MS; return MS;
} }
@@ -2980,6 +2988,10 @@ bool TMoverParameters::BrakeDelaySwitch(int BDS)
} }
else else
rBDS = false; rBDS = false;
if( true == rBDS ) {
// if setting was changed emit the sound of pneumatic relay
SetFlag( SoundFlag, sound::pneumatic );
}
return rBDS; return rBDS;
} }
@@ -3078,8 +3090,8 @@ void TMoverParameters::CompressorCheck(double dt)
else else
{ {
CompressedVolume = CompressedVolume * 0.8; CompressedVolume = CompressedVolume * 0.8;
SetFlag(SoundFlag, sound_relay | sound_loud); SetFlag(SoundFlag, sound::relay | sound::loud);
// SetFlag(SoundFlag, sound_loud); // SetFlag(SoundFlag, sound::loud);
} }
} }
} }
@@ -3372,7 +3384,7 @@ void TMoverParameters::UpdatePipePressure(double dt)
// dodać jakiś wpis do fizyki na to // dodać jakiś wpis do fizyki na to
if( ( ( Couplers[ b ].Connected->TrainType & ( dt_ET41 | dt_ET42 ) ) != 0 ) && if( ( ( Couplers[ b ].Connected->TrainType & ( dt_ET41 | dt_ET42 ) ) != 0 ) &&
( ( Couplers[ b ].CouplingFlag & 36 ) == 36 ) ) ( ( 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)) //if ((DynamicBrakeFlag) && (EngineType == ElectricInductionMotor))
//{ //{
@@ -4070,6 +4082,31 @@ double TMoverParameters::CouplerForce(int CouplerN, double dt)
// tempdist:=tempdist+CoupleDist; //ABu: proby szybkiego naprawienia bledu // 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 // blablabla
// ABu: proby znalezienia problemu ze zle odbijajacymi sie skladami // ABu: proby znalezienia problemu ze zle odbijajacymi sie skladami
//if (Couplers[CouplerN].CouplingFlag=ctrain_virtual) and (newdist>0) then //if (Couplers[CouplerN].CouplingFlag=ctrain_virtual) and (newdist>0) then
@@ -4091,23 +4128,6 @@ double TMoverParameters::CouplerForce(int CouplerN, double dt)
Couplers[CouplerN].Connected->Couplers[CNext].FmaxB) * Couplers[CouplerN].Connected->Couplers[CNext].FmaxB) *
CouplerTune / 2.0; 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 = distDelta =
abs(newdist) - abs(Couplers[CouplerN].Dist); // McZapkie-191103: poprawka na histereze abs(newdist) - abs(Couplers[CouplerN].Dist); // McZapkie-191103: poprawka na histereze
Couplers[CouplerN].Dist = newdist; Couplers[CouplerN].Dist = newdist;
@@ -4911,7 +4931,7 @@ bool TMoverParameters::FuseOn(void)
{ {
FuseFlag = false; // wlaczenie ponowne obwodu FuseFlag = false; // wlaczenie ponowne obwodu
FO = true; FO = true;
SetFlag(SoundFlag, sound_relay | sound_loud); SetFlag(SoundFlag, sound::relay | sound::loud);
} }
} }
return FO; return FO;
@@ -4927,7 +4947,7 @@ void TMoverParameters::FuseOff(void)
{ {
FuseFlag = true; FuseFlag = true;
EventFlag = true; EventFlag = true;
SetFlag(SoundFlag, sound_relay | sound_loud); SetFlag(SoundFlag, sound::relay | sound::loud);
} }
} }
@@ -5198,7 +5218,7 @@ bool TMoverParameters::AutoRelayCheck(void)
// MainCtrlActualPos:=MainCtrlPos; //hunter-111012: // MainCtrlActualPos:=MainCtrlPos; //hunter-111012:
// szybkie wchodzenie na bezoporowa (303E) // szybkie wchodzenie na bezoporowa (303E)
OK = true; OK = true;
SetFlag(SoundFlag, sound_manyrelay | sound_loud); SetFlag(SoundFlag, sound::parallel | sound::loud);
} }
else if ((LastRelayTime > CtrlDelay) && (ARFASI)) else if ((LastRelayTime > CtrlDelay) && (ARFASI))
{ {
@@ -5232,13 +5252,13 @@ bool TMoverParameters::AutoRelayCheck(void)
if ((RList[MainCtrlActualPos].R == 0) && if ((RList[MainCtrlActualPos].R == 0) &&
(!(MainCtrlActualPos == MainCtrlPosNo))) // wejscie na bezoporowa (!(MainCtrlActualPos == MainCtrlPosNo))) // wejscie na bezoporowa
{ {
SetFlag(SoundFlag, sound_manyrelay | sound_loud); SetFlag(SoundFlag, sound::parallel | sound::loud);
} }
else if ((RList[MainCtrlActualPos].R > 0) && else if ((RList[MainCtrlActualPos].R > 0) &&
(RList[MainCtrlActualPos - 1].R == (RList[MainCtrlActualPos - 1].R ==
0)) // wejscie na drugi uklad 0)) // wejscie na drugi uklad
{ {
SetFlag(SoundFlag, sound_manyrelay); SetFlag(SoundFlag, sound::parallel);
} }
} }
} }
@@ -5251,7 +5271,7 @@ bool TMoverParameters::AutoRelayCheck(void)
// MainCtrlActualPos:=MainCtrlPos; //hunter-111012: // MainCtrlActualPos:=MainCtrlPos; //hunter-111012:
// szybkie wchodzenie na bezoporowa (303E) // szybkie wchodzenie na bezoporowa (303E)
OK = true; OK = true;
SetFlag(SoundFlag, sound_manyrelay); SetFlag(SoundFlag, sound::parallel);
} }
else if (LastRelayTime > CtrlDownDelay) else if (LastRelayTime > CtrlDownDelay)
{ {
@@ -5264,7 +5284,7 @@ bool TMoverParameters::AutoRelayCheck(void)
if (RList[MainCtrlActualPos].R == if (RList[MainCtrlActualPos].R ==
0) // dzwieki schodzenia z bezoporowej} 0) // dzwieki schodzenia z bezoporowej}
{ {
SetFlag(SoundFlag, sound_manyrelay); SetFlag(SoundFlag, sound::parallel);
} }
} }
} }
@@ -5296,7 +5316,7 @@ bool TMoverParameters::AutoRelayCheck(void)
StLinFlag = true; // ybARC - zalaczenie stycznikow liniowych StLinFlag = true; // ybARC - zalaczenie stycznikow liniowych
MainCtrlActualPos = 1; MainCtrlActualPos = 1;
DelayCtrlFlag = false; DelayCtrlFlag = false;
SetFlag(SoundFlag, sound_relay | sound_loud); SetFlag(SoundFlag, sound::relay | sound::loud);
OK = true; OK = true;
} }
} }
@@ -5850,6 +5870,32 @@ bool TMoverParameters::DoorRight(bool State)
return DR; 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 // Q: 20160713
// Przesuwa pojazd o podaną wartość w bok względem toru (dla samochodów) // Przesuwa pojazd o podaną wartość w bok względem toru (dla samochodów)
@@ -8219,6 +8265,13 @@ bool TMoverParameters::RunCommand( std::string Command, double CValue1, double C
} }
OK = SendCtrlToNext( Command, CValue1, CValue2, Couplertype ); 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*/ else if (Command == "PantFront") /*Winger 160204*/
{ // Ra: uwzględnić trzeba jeszcze zgodność sprzęgów { // 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 // Czemu EZT ma być traktowane inaczej? Ukrotnienie ma, a człon może być odwrócony
@@ -8338,6 +8391,8 @@ bool TMoverParameters::RunCommand( std::string Command, double CValue1, double C
if( true == Hamulec->SetBDF( brakesetting ) ) { if( true == Hamulec->SetBDF( brakesetting ) ) {
BrakeDelayFlag = brakesetting; BrakeDelayFlag = brakesetting;
OK = true; OK = true;
// if setting was changed emit the sound of pneumatic relay
SetFlag( SoundFlag, sound::pneumatic );
} }
else { else {
OK = false; OK = false;

View File

@@ -578,48 +578,59 @@ void TESt::CheckReleaser( double const dt )
} }
} }
void TESt::CheckState( double const BCP, double &dV1 ) void TESt::CheckState( double const BCP, double &dV1 ) {
{
double VVP;
double BVP;
double CVP;
BVP = BrakeRes->P(); double const VVP { ValveRes->P() };
VVP = ValveRes->P(); double const BVP { BrakeRes->P() };
// if (BVP<VVP) then double const CVP { CntrlRes->P() };
// VVP:=(BVP+VVP)/2;
CVP = CntrlRes->P() - 0.0;
// sprawdzanie stanu // sprawdzanie stanu
if (((BrakeStatus & b_hld) == b_hld) && (BCP > 0.25)) if( BCP > 0.25 ) {
if ((VVP + 0.003 + BCP / BVM < CVP))
BrakeStatus |= b_on; // hamowanie stopniowe if( ( BrakeStatus & b_hld ) == b_hld ) {
else if ((VVP - 0.003 + (BCP - 0.1) / BVM > CVP))
BrakeStatus &= ~( b_on | b_hld ); // luzowanie if( ( VVP + 0.003 + BCP / BVM ) < CVP ) {
else if ((VVP + BCP / BVM > CVP)) // hamowanie stopniowe
BrakeStatus &= ~b_on; // zatrzymanie napelaniania BrakeStatus |= b_on;
else }
; else {
else if ((VVP + 0.10 < CVP) && (BCP < 0.25)) // poczatek hamowania if( ( VVP + BCP / BVM ) > CVP ) {
{ // zatrzymanie napelaniania
if ((BrakeStatus & b_hld) == b_off) BrakeStatus &= ~b_on;
{ }
if( ( VVP - 0.003 + ( BCP - 0.1 ) / 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.02 * VVP ); ValveRes->CreatePress( 0.02 * VVP );
SoundFlag |= sf_Acc; SoundFlag |= sf_Acc;
ValveRes->Act(); ValveRes->Act();
} }
BrakeStatus |= ( b_on | b_hld ); BrakeStatus |= ( b_on | b_hld );
// ValveRes.CreatePress(0);
// dV1:=1;
} }
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) == b_off) if( ( BrakeStatus & b_hld ) == 0 ) {
SoundFlag |= sf_CylU; SoundFlag |= sf_CylU;
} }
}
double TESt::CVs( double const BP ) 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 else if ((VVP + BCP / BVM < CVP - 0.12) && (BCP > 0.25)) // zatrzymanie luzowanie
BrakeStatus |= b_hld; BrakeStatus |= b_hld;
if( ( BrakeStatus & b_hld ) == 0 ) {
SoundFlag |= sf_CylU;
}
// przeplyw ZS <-> PG // przeplyw ZS <-> PG
if ((BVP < CVP - 0.2) || (BrakeStatus != b_off) || (BCP > 0.25)) if ((BVP < CVP - 0.2) || (BrakeStatus != b_off) || (BCP > 0.25))
temp = 0; temp = 0;
@@ -1211,6 +1226,40 @@ double TLSt::GetPF( double const PP, double const dt, double const Vel )
double dV1{ 0.0 }; double dV1{ 0.0 };
// sprawdzanie stanu // 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( ( BrakeStatus & b_rls ) == b_rls ) {
if( CVP < 0.0 ) { if( CVP < 0.0 ) {
BrakeStatus &= ~b_rls; BrakeStatus &= ~b_rls;
@@ -1219,18 +1268,11 @@ double TLSt::GetPF( double const PP, double const dt, double const Vel )
{ // 008 { // 008
dV = PF1( CVP, BCP, 0.024 ) * dt; dV = PF1( CVP, BCP, 0.024 ) * dt;
CntrlRes->Flow( dV ); 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 // przeplyw ZS <-> PG
double temp;
if (((CVP - BCP) * BVM > 0.5)) if (((CVP - BCP) * BVM > 0.5))
temp = 0.0; temp = 0.0;
else if ((VVP > CVP + 0.4)) else if ((VVP > CVP + 0.4))
@@ -1888,23 +1930,52 @@ void TKE::CheckState( double const BCP, double &dV1 )
CVP = CntrlRes->P(); CVP = CntrlRes->P();
// sprawdzanie stanu // sprawdzanie stanu
if ((BrakeStatus & b_hld) == b_hld) if( BCP > 0.1 ) {
if ((VVP + 0.003 + BCP / BVM < CVP))
BrakeStatus |= b_on; // hamowanie stopniowe; if( ( BrakeStatus & b_hld ) == b_hld ) {
else if ((VVP - 0.003 + BCP / BVM > CVP))
BrakeStatus &= ~( b_on | b_hld ); // luzowanie; if( ( VVP + 0.003 + BCP / BVM ) < CVP ) {
else if ((VVP + BCP / BVM > CVP)) // hamowanie stopniowe;
BrakeStatus &= ~b_on; // zatrzymanie napelaniania; BrakeStatus |= b_on;
else
;
else if ((VVP + 0.10 < CVP) && (BCP < 0.1)) // poczatek hamowania
{
BrakeStatus |= (b_on | b_hld);
ValveRes->CreatePress(0.8 * VVP); // przyspieszacz
} }
else if ((VVP + BCP / BVM < CVP) && ((CVP - VVP) * BVM > 0.25)) // zatrzymanie luzowanie 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; 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;
}
}
double TKE::CVs( double const BP ) double TKE::CVs( double const BP )
{ {

View File

@@ -42,21 +42,13 @@ std::string *TSubModel::pasText;
// 0x3F3F003F - wszystkie wymienne tekstury używane w danym cyklu // 0x3F3F003F - wszystkie wymienne tekstury używane w danym cyklu
// Ale w TModel3d okerśla przezroczystość tekstur wymiennych! // Ale w TModel3d okerśla przezroczystość tekstur wymiennych!
TSubModel::~TSubModel() TSubModel::~TSubModel() {
{
/*
if (uiDisplayList)
glDeleteLists(uiDisplayList, 1);
*/
if (iFlags & 0x0200) if (iFlags & 0x0200)
{ // wczytany z pliku tekstowego musi sam posprzątać { // wczytany z pliku tekstowego musi sam posprzątać
// SafeDeleteArray(Indices);
SafeDelete(Next); SafeDelete(Next);
SafeDelete(Child); SafeDelete(Child);
delete fMatrix; // własny transform trzeba usunąć (zawsze jeden) delete fMatrix; // własny transform trzeba usunąć (zawsze jeden)
/*
delete[] Vertices;
*/
} }
delete[] smLetter; // używany tylko roboczo dla TP_TEXT, do przyspieszenia delete[] smLetter; // używany tylko roboczo dla TP_TEXT, do przyspieszenia
// wyświetlania // wyświetlania
@@ -95,7 +87,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 { // szukanie punktu stycznego do (pt), zwraca numer wierzchołka, a nie trójkąta
int facecount = iNumVerts / 3; // bo maska powierzchni jest jedna na trójkąt int facecount = iNumVerts / 3; // bo maska powierzchni jest jedna na trójkąt
for( int faceidx = Startface; faceidx < facecount; ++faceidx ) { for( int faceidx = Startface; faceidx < facecount; ++faceidx ) {
@@ -983,7 +975,7 @@ void TSubModel::serialize_geometry( std::ostream &Output ) const {
}; };
void 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 // 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) // (the offsets are part of legacy system which we now need to work around for backward compatibility)
@@ -1050,14 +1042,17 @@ void TSubModel::ColorsSet( glm::vec3 const &Ambient, glm::vec3 const &Diffuse, g
*/ */
}; };
void TSubModel::ParentMatrix(float4x4 *m) void TSubModel::ParentMatrix( float4x4 *m ) const { // pobranie transformacji względem wstawienia modelu
{ // pobranie transformacji względem wstawienia modelu // jeśli nie zostało wykonane Init() (tzn. zaraz po wczytaniu T3D),
// jeśli nie zostało wykonane Init() (tzn. zaraz po wczytaniu T3D), to // to dodatkowy obrót obrót T3D jest wymagany np. do policzenia wysokości pantografów
// dodatkowy obrót if( fMatrix != nullptr ) {
// obrót T3D jest wymagany np. do policzenia wysokości pantografów // skopiowanie, bo będziemy mnożyć
*m = float4x4(*fMatrix); // skopiowanie, bo będziemy mnożyć *m = float4x4( *fMatrix );
// m(3)[1]=m[3][1]+0.054; //w górę o wysokość ślizgu (na razie tak) }
TSubModel *sm = this; else {
m->Identity();
}
auto *sm = this;
while (sm->Parent) while (sm->Parent)
{ // przenieść tę funkcję do modelu { // przenieść tę funkcję do modelu
if (sm->Parent->GetMatrix()) if (sm->Parent->GetMatrix())
@@ -1160,6 +1155,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) bool TModel3d::LoadFromFile(std::string const &FileName, bool dynamic)
{ {
// wczytanie modelu z pliku // wczytanie modelu z pliku
@@ -1472,7 +1498,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 // once sorted we can grab geometry as it comes, and assign it to the chunks it belongs to
for( auto const &submodeloffset : submodeloffsets ) { for( auto const &submodeloffset : submodeloffsets ) {
auto &submodel = Root[ submodeloffset.second ]; auto &submodel = Root[ submodeloffset.second ];
vertex_array vertices; vertices.resize( submodel.iNumVerts ); gfx::vertex_array vertices; vertices.resize( submodel.iNumVerts );
iNumVerts += submodel.iNumVerts; iNumVerts += submodel.iNumVerts;
for( auto &vertex : vertices ) { for( auto &vertex : vertices ) {
vertex.deserialize( s ); vertex.deserialize( s );

View File

@@ -13,7 +13,7 @@ http://mozilla.org/MPL/2.0/.
#include "Parser.h" #include "Parser.h"
#include "dumb3d.h" #include "dumb3d.h"
#include "Float3d.h" #include "Float3d.h"
#include "VBO.h" #include "openglgeometrybank.h"
#include "material.h" #include "material.h"
using namespace Math3D; using namespace Math3D;
@@ -124,7 +124,9 @@ private:
TSubModel *Next { nullptr }; TSubModel *Next { nullptr };
TSubModel *Child { 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 material_handle m_material { null_handle }; // numer tekstury, -1 wymienna, 0 brak
bool bWire { false }; // nie używane, ale wczytywane bool bWire { false }; // nie używane, ale wczytywane
float Opacity { 1.0f }; float Opacity { 1.0f };
@@ -134,20 +136,18 @@ private:
public: // chwilowo public: // chwilowo
float3 v_TransVector { 0.0f, 0.0f, 0.0f }; float3 v_TransVector { 0.0f, 0.0f, 0.0f };
vertex_array Vertices; gfx::vertex_array Vertices;
float m_boundingradius { 0 }; float m_boundingradius { 0 };
size_t iAnimOwner{ 0 }; // roboczy numer egzemplarza, który ustawił animację size_t iAnimOwner{ 0 }; // roboczy numer egzemplarza, który ustawił animację
TAnimType b_aAnim{ at_None }; // kody animacji oddzielnie, bo zerowane TAnimType b_aAnim{ at_None }; // kody animacji oddzielnie, bo zerowane
public:
float4x4 *mAnimMatrix{ nullptr }; // macierz do animacji kwaternionowych (należy do AnimContainer) 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 **smLetter{ nullptr }; // wskaźnik na tablicę submdeli do generoania tekstu (docelowo zapisać do E3D)
TSubModel *Parent{ nullptr }; // nadrzędny, np. do wymnażania macierzy TSubModel *Parent{ nullptr }; // nadrzędny, np. do wymnażania macierzy
int iVisible{ 1 }; // roboczy stan widoczności int iVisible{ 1 }; // roboczy stan widoczności
std::string m_materialname; // robocza nazwa tekstury do zapisania w pliku binarnym std::string m_materialname; // robocza nazwa tekstury do zapisania w pliku binarnym
std::string pName; // robocza nazwa std::string pName; // robocza nazwa
private: 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(TAnimType a);
public: public:
@@ -172,9 +172,12 @@ public:
void SetRotateIK1(float3 vNewAngles); void SetRotateIK1(float3 vNewAngles);
TSubModel * GetFromName( std::string const &search, bool i = true ); TSubModel * GetFromName( std::string const &search, bool i = true );
inline float4x4 * GetMatrix() { return fMatrix; }; inline float4x4 * GetMatrix() { return fMatrix; };
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; }; 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(); int FlagsCheck();
void WillBeAnimated() void WillBeAnimated()
{ {
@@ -200,7 +203,7 @@ public:
return *(fMatrix->TranslationGet()) + Child->Translation1Get(); } return *(fMatrix->TranslationGet()) + Child->Translation1Get(); }
material_handle GetMaterial() const { material_handle GetMaterial() const {
return m_material; } return m_material; }
void ParentMatrix(float4x4 *m); void ParentMatrix(float4x4 *m) const;
float MaxY( float4x4 const &m ); float MaxY( float4x4 const &m );
void deserialize(std::istream&); void deserialize(std::istream&);
@@ -213,7 +216,7 @@ public:
// places contained geometry in provided ground node // places contained geometry in provided ground node
}; };
class TModel3d : public CMesh class TModel3d
{ {
friend class opengl_renderer; friend class opengl_renderer;
@@ -222,6 +225,8 @@ private:
int iFlags; // Ra: czy submodele mają przezroczyste tekstury int iFlags; // Ra: czy submodele mają przezroczyste tekstury
public: // Ra: tymczasowo 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: private:
std::vector<std::string> Textures; // nazwy tekstur std::vector<std::string> Textures; // nazwy tekstur
std::vector<std::string> Names; // nazwy submodeli std::vector<std::string> Names; // nazwy submodeli
@@ -229,15 +234,16 @@ private:
int iSubModelsCount; // Ra: używane do tworzenia binarnych int iSubModelsCount; // Ra: używane do tworzenia binarnych
std::string asBinary; // nazwa pod którą zapisać model binarny std::string asBinary; // nazwa pod którą zapisać model binarny
std::string m_filename; std::string m_filename;
public: public:
TModel3d();
~TModel3d();
float bounding_radius() const { float bounding_radius() const {
return ( return (
Root ? Root ?
Root->m_boundingradius : Root->m_boundingradius :
0.f ); } 0.f ); }
inline TSubModel * GetSMRoot() { return (Root); }; inline TSubModel * GetSMRoot() { return (Root); };
TModel3d();
~TModel3d();
TSubModel * GetFromName(std::string const &Name); TSubModel * GetFromName(std::string const &Name);
TSubModel * AddToNamed(const char *Name, TSubModel *SubModel); TSubModel * AddToNamed(const char *Name, TSubModel *SubModel);
void AddTo(TSubModel *tmp, TSubModel *SubModel); void AddTo(TSubModel *tmp, TSubModel *SubModel);

View File

@@ -50,10 +50,10 @@ public:
protected: protected:
// types // types
using type_sequence = std::deque<Type_ *>; 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 // members
type_sequence m_items; type_sequence m_items;
type_map m_itemmap; index_map m_itemmap;
public: public:
// data access // data access

View File

@@ -8,6 +8,16 @@ http://mozilla.org/MPL/2.0/.
*/ */
#pragma once #pragma once
int const null_handle = 0;
enum class resource_state {
none,
loading,
good,
failed
};
/* /*
#include <vector> #include <vector>
#include <algorithm> #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_> template <class Container_>
class garbage_collector { class garbage_collector {

View File

@@ -359,7 +359,7 @@ Math3D::vector3 TSegment::FastGetPoint(double const t) const
interpolate( Point1, Point2, t ) ); 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 { // generowanie trójkątów dla odcinka trajektorii ruchu
// standardowo tworzy triangle_strip dla prostego albo ich zestaw dla łuku // standardowo tworzy triangle_strip dla prostego albo ich zestaw dla łuku
// po modyfikacji - dla ujemnego (iNumShapePoints) w dodatkowych polach tabeli // po modyfikacji - dla ujemnego (iNumShapePoints) w dodatkowych polach tabeli

View File

@@ -97,7 +97,7 @@ public:
r2 = fRoll2; } r2 = fRoll2; }
bool 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 void
Render(); Render();
inline inline

View File

@@ -15,13 +15,6 @@ http://mozilla.org/MPL/2.0/.
#include "GL/glew.h" #include "GL/glew.h"
#include "ResourceManager.h" #include "ResourceManager.h"
enum class resource_state {
none,
loading,
good,
failed
};
struct opengl_texture { struct opengl_texture {
static DDSURFACEDESC2 deserialize_ddsd(std::istream&); static DDSURFACEDESC2 deserialize_ddsd(std::istream&);
static DDCOLORKEY deserialize_ddck(std::istream&); static DDCOLORKEY deserialize_ddck(std::istream&);
@@ -78,7 +71,6 @@ private:
}; };
typedef int texture_handle; typedef int texture_handle;
int const null_handle = 0;
class texture_manager { class texture_manager {
@@ -88,13 +80,16 @@ public:
void void
assign_units( GLint const Helper, GLint const Shadows, GLint const Normals, GLint const Diffuse ); assign_units( GLint const Helper, GLint const Shadows, GLint const Normals, GLint const Diffuse );
// activates specified texture unit
void void
unit( GLint const Textureunit ); unit( GLint const Textureunit );
// creates texture object out of data stored in specified file
texture_handle texture_handle
create( std::string Filename, bool const Loadnow = true ); create( std::string Filename, bool const Loadnow = true );
// binds specified texture to specified texture unit // binds specified texture to specified texture unit
void void
bind( std::size_t const Unit, texture_handle const Texture ); bind( std::size_t const Unit, texture_handle const Texture );
// provides direct access to specified texture object
opengl_texture & opengl_texture &
texture( texture_handle const Texture ) const { return *(m_textures[ Texture ].first); } texture( texture_handle const Texture ) const { return *(m_textures[ Texture ].first); }
// performs a resource sweep // performs a resource sweep
@@ -108,7 +103,7 @@ private:
// types: // types:
typedef std::pair< typedef std::pair<
opengl_texture *, opengl_texture *,
std::chrono::steady_clock::time_point > texturetimepoint_pair; resource_timestamp > texturetimepoint_pair;
typedef std::vector< texturetimepoint_pair > texturetimepointpair_sequence; typedef std::vector< texturetimepoint_pair > texturetimepointpair_sequence;

View File

@@ -38,11 +38,6 @@ double GetDeltaRenderTime()
return DeltaRenderTime; return DeltaRenderTime;
} }
double GetfSinceStart()
{
return fSinceStart;
}
void SetDeltaTime(double t) void SetDeltaTime(double t)
{ {
DeltaTime = t; DeltaTime = t;

View File

@@ -16,8 +16,6 @@ double GetTime();
double GetDeltaTime(); double GetDeltaTime();
double GetDeltaRenderTime(); double GetDeltaRenderTime();
double GetfSinceStart();
void SetDeltaTime(double v); void SetDeltaTime(double v);
bool GetSoundTimer(); bool GetSoundTimer();

View File

@@ -940,7 +940,7 @@ const int nnumPts = 12;
// szyna - vextor6(x,y,mapowanie tekstury,xn,yn,zn) // szyna - vextor6(x,y,mapowanie tekstury,xn,yn,zn)
// tę wersję opracował Tolein (bez pochylenia) // tę wersję opracował Tolein (bez pochylenia)
// TODO: profile definitions in external files // 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.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.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}}, {{ 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) // iglica - vextor3(x,y,mapowanie tekstury)
// 1 mm więcej, żeby nie nachodziły tekstury? // 1 mm więcej, żeby nie nachodziły tekstury?
// TODO: automatic generation from base profile TBD: reuse base profile? // 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.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.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}}, {{ 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 // 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 // Ra: trzeba rozdzielić szyny od podsypki, aby móc grupować wg tekstur
auto const fHTW = 0.5f * std::abs(fTrackWidth); auto const fHTW = 0.5f * std::abs(fTrackWidth);
auto const side = std::abs(fTexWidth); // szerokść podsypki na zewnątrz szyny albo pobocza 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), sin2 = std::sin(roll2),
cos2 = std::cos(roll2); cos2 = std::cos(roll2);
// zwykla szyna: //Ra: czemu główki są asymetryczne na wysokości 0.140? // 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 ) { for( int i = 0; i < 12; ++i ) {
rpts1[ i ] = { rpts1[ i ] = {
@@ -1186,7 +1186,7 @@ void TTrack::create_geometry( geometrybank_handle const &Bank ) {
case tt_Normal: case tt_Normal:
if (m_material2) if (m_material2)
{ // podsypka z podkładami jest tylko dla zwykłego toru { // 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 ) { if( fTexLength == 4.f ) {
// stare mapowanie z różną gęstością pikseli i oddzielnymi teksturami na każdy profil // 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 ) ); 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 {0.5f + map12, 0.f} }; // prawy skos
} }
} }
vertex_array vertices; gfx::vertex_array vertices;
Segment->RenderLoft(vertices, m_origin, bpts1, iTrapezoid ? -4 : 4, fTexLength); Segment->RenderLoft(vertices, m_origin, bpts1, iTrapezoid ? -4 : 4, fTexLength);
if( ( Bank != 0 ) && ( true == Geometry2.empty() ) ) { if( ( Bank != 0 ) && ( true == Geometry2.empty() ) ) {
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); 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) if (m_material1)
{ // szyny - generujemy dwie, najwyżej rysować się będzie jedną { // szyny - generujemy dwie, najwyżej rysować się będzie jedną
vertex_array vertices; gfx::vertex_array vertices;
if( ( Bank != 0 ) && ( true == Geometry1.empty() ) ) { if( ( Bank != 0 ) && ( true == Geometry1.empty() ) ) {
Segment->RenderLoft( vertices, m_origin, rpts1, iTrapezoid ? -nnumPts : nnumPts, fTexLength ); Segment->RenderLoft( vertices, m_origin, rpts1, iTrapezoid ? -nnumPts : nnumPts, fTexLength );
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); 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 case tt_Switch: // dla zwrotnicy dwa razy szyny
if( m_material1 || m_material2 ) { if( m_material1 || m_material2 ) {
// iglice liczone tylko dla zwrotnic // 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 ) { for( int i = 0; i < 12; ++i ) {
rpts3[ 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 // TODO, TBD: change all track geometry to triangles, to allow packing data in less, larger buffers
if (SwitchExtension->RightSwitch) if (SwitchExtension->RightSwitch)
{ // nowa wersja z SPKS, ale odwrotnie lewa/prawa { // nowa wersja z SPKS, ale odwrotnie lewa/prawa
vertex_array vertices; gfx::vertex_array vertices;
if( m_material1 ) { if( m_material1 ) {
// fixed parts // fixed parts
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts2, nnumPts, fTexLength ); SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts2, nnumPts, fTexLength );
@@ -1408,7 +1408,7 @@ void TTrack::create_geometry( geometrybank_handle const &Bank ) {
} }
else else
{ // lewa działa lepiej niż prawa { // lewa działa lepiej niż prawa
vertex_array vertices; gfx::vertex_array vertices;
if( m_material1 ) { if( m_material1 ) {
// fixed parts // fixed parts
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts1, nnumPts, fTexLength ); // lewa szyna normalna cała 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 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) { if (m_material1 || m_material2) {
// punkty się przydadzą, nawet jeśli nawierzchni nie ma // 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 if (m_material1) // jeśli podana była tekstura, generujemy trójkąty
{ // tworzenie trójkątów nawierzchni szosy { // tworzenie trójkątów nawierzchni szosy
vertex_array vertices; gfx::vertex_array vertices;
Segment->RenderLoft(vertices, m_origin, bpts1, iTrapezoid ? -2 : 2, fTexLength); Segment->RenderLoft(vertices, m_origin, bpts1, iTrapezoid ? -2 : 2, fTexLength);
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
} }
if (m_material2) if (m_material2)
{ // pobocze drogi - poziome przy przechyłce (a może krawężnik i chodnik zrobić jak w Midtown Madness 2?) { // pobocze drogi - poziome przy przechyłce (a może krawężnik i chodnik zrobić jak w Midtown Madness 2?)
basic_vertex gfx::basic_vertex
rpts1[6], rpts1[6],
rpts2[6]; // współrzędne przekroju i mapowania dla prawej i lewej strony rpts2[6]; // współrzędne przekroju i mapowania dla prawej i lewej strony
if (fTexHeight1 >= 0.f) 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 {0.484375f - map2l, 0.f} }; // lewy brzeg lewego chodnika
} }
} }
vertex_array vertices; gfx::vertex_array vertices;
if( iTrapezoid ) // trapez albo przechyłki if( iTrapezoid ) // trapez albo przechyłki
{ // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony { // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony
// odcinka // odcinka
@@ -1728,7 +1728,7 @@ void TTrack::create_geometry( geometrybank_handle const &Bank ) {
SwitchExtension->bPoints ? SwitchExtension->bPoints ?
nullptr : nullptr :
SwitchExtension->vPoints; // zmienna robocza, NULL gdy tablica punktów już jest wypełniona 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 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% { // 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 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 // ale pobocza renderują się później, więc nawierzchnia nie załapuje się na renderowanie w swoim czasie
if( m_material2 ) if( m_material2 )
{ // pobocze drogi - poziome przy przechyłce (a może krawężnik i chodnik zrobić jak w Midtown Madness 2?) { // pobocze drogi - poziome przy przechyłce (a może krawężnik i chodnik zrobić jak w Midtown Madness 2?)
basic_vertex gfx::basic_vertex
rpts1[6], rpts1[6],
rpts2[6]; // współrzędne przekroju i mapowania dla prawej i lewej strony 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 // 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 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) if (SwitchExtension->iRoads == 4)
{ // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony odcinka { // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony odcinka
if( ( fTexHeight1 >= 0.0 ) || ( side != 0.0 ) ) { if( ( fTexHeight1 >= 0.0 ) || ( side != 0.0 ) ) {
@@ -1956,7 +1956,7 @@ void TTrack::create_geometry( geometrybank_handle const &Bank ) {
} }
if( m_material1 ) { if( m_material1 ) {
vertex_array vertices; gfx::vertex_array vertices;
// jeśli podana tekstura nawierzchni // jeśli podana tekstura nawierzchni
// we start with a vertex in the middle... // we start with a vertex in the middle...
vertices.emplace_back( vertices.emplace_back(
@@ -2006,7 +2006,7 @@ void TTrack::create_geometry( geometrybank_handle const &Bank ) {
{ {
case tt_Normal: // drogi proste, bo skrzyżowania osobno 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 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% { // double max=2.0*(fHTW>fHTW2?fHTW:fHTW2); //z szerszej strony jest 100%
auto const max = ( 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 if (m_material1) // jeśli podana była tekstura, generujemy trójkąty
{ // tworzenie trójkątów nawierzchni szosy { // tworzenie trójkątów nawierzchni szosy
vertex_array vertices; gfx::vertex_array vertices;
Segment->RenderLoft(vertices, m_origin, bpts1, iTrapezoid ? -2 : 2, fTexLength); Segment->RenderLoft(vertices, m_origin, bpts1, iTrapezoid ? -2 : 2, fTexLength);
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
} }
if (m_material2) if (m_material2)
{ // pobocze drogi - poziome przy przechyłce (a może krawężnik i chodnik zrobić jak w Midtown Madness 2?) { // pobocze drogi - poziome przy przechyłce (a może krawężnik i chodnik zrobić jak w Midtown Madness 2?)
vertex_array vertices; gfx::vertex_array vertices;
basic_vertex gfx::basic_vertex
rpts1[6], rpts1[6],
rpts2[6]; // współrzędne przekroju i mapowania dla prawej i lewej strony 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 fHTW2 = fHTW; // Ra: na razie niech tak będzie
auto const cos1 = 1.0f, sin1 = 0.0f, cos2 = 1.0f, sin2 = 0.0f; // Ra: ... auto const cos1 = 1.0f, sin1 = 0.0f, cos2 = 1.0f, sin2 = 0.0f; // Ra: ...
basic_vertex gfx::basic_vertex
rpts3[ 24 ], rpts3[ 24 ],
rpts4[ 24 ]; rpts4[ 24 ];
for (int i = 0; i < 12; ++i) { for (int i = 0; i < 12; ++i) {
@@ -2456,7 +2456,7 @@ TTrack * TTrack::RaAnimate()
{szyna[ i ].texture.x, 0.f} }; {szyna[ i ].texture.x, 0.f} };
} }
vertex_array vertices; gfx::vertex_array vertices;
if (SwitchExtension->RightSwitch) if (SwitchExtension->RightSwitch)
{ // nowa wersja z SPKS, ale odwrotnie lewa/prawa { // nowa wersja z SPKS, ale odwrotnie lewa/prawa
@@ -2520,7 +2520,7 @@ TTrack * TTrack::RaAnimate()
dynamic->Move( 0.000001 ); dynamic->Move( 0.000001 );
} }
// NOTE: passing empty handle is a bit of a hack here. could be refactored into something more elegant // 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 } // animacja trwa nadal
} }
else else

View File

@@ -147,7 +147,7 @@ private:
glm::dvec3 m_origin; glm::dvec3 m_origin;
material_handle m_material1 = 0; // tekstura szyn albo nawierzchni material_handle m_material1 = 0; // tekstura szyn albo nawierzchni
material_handle m_material2 = 0; // tekstura automatycznej podsypki albo pobocza 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 Geometry1; // geometry chunks textured with texture 1
geometryhandle_sequence Geometry2; // geometry chunks textured with texture 2 geometryhandle_sequence Geometry2; // geometry chunks textured with texture 2
@@ -245,7 +245,7 @@ public:
std::vector<glm::dvec3> std::vector<glm::dvec3>
endpoints() const; 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 RenderDynSounds(); // odtwarzanie dźwięków pojazdów jest niezależne od ich wyświetlania
void RaOwnerSet( scene::basic_cell *o ) { void RaOwnerSet( scene::basic_cell *o ) {

View File

@@ -175,18 +175,18 @@ TTraction::endpoints() const {
} }
std::size_t std::size_t
TTraction::create_geometry( geometrybank_handle const &Bank ) { TTraction::create_geometry( gfx::geometrybank_handle const &Bank ) {
if( m_geometry != null_handle ) { if( m_geometry != null_handle ) {
return GfxRenderer.Vertices( m_geometry ).size() / 2; 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 ); double ddp = std::hypot( pPoint2.x - pPoint1.x, pPoint2.z - pPoint1.z );
if( Wires == 2 ) if( Wires == 2 )
WireOffset = 0; WireOffset = 0;
// jezdny // jezdny
basic_vertex startvertex, endvertex; gfx::basic_vertex startvertex, endvertex;
startvertex.position = startvertex.position =
glm::vec3( glm::vec3(
pPoint1.x - ( pPoint2.z / ddp - pPoint1.z / ddp ) * WireOffset - m_origin.x, pPoint1.x - ( pPoint2.z / ddp - pPoint1.z / ddp ) * WireOffset - m_origin.x,

View File

@@ -50,7 +50,7 @@ class TTraction : public editor::basic_node {
int PowerState { 0 }; // type of incoming power, if any int PowerState { 0 }; // type of incoming power, if any
// visualization data // visualization data
glm::dvec3 m_origin; glm::dvec3 m_origin;
geometry_handle m_geometry; gfx::geometry_handle m_geometry;
explicit TTraction( scene::node_data const &Nodedata ); explicit TTraction( scene::node_data const &Nodedata );
@@ -64,7 +64,7 @@ class TTraction : public editor::basic_node {
endpoints() const; endpoints() const;
// creates geometry data in specified geometry bank. returns: number of created elements, or NULL // 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 // 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); int TestPoint(glm::dvec3 const &Point);
void Connect(int my, TTraction *with, int to); void Connect(int my, TTraction *with, int to);
void Init(); void Init();

1807
Train.cpp

File diff suppressed because it is too large Load Diff

85
Train.h
View File

@@ -14,7 +14,7 @@ http://mozilla.org/MPL/2.0/.
#include "Button.h" #include "Button.h"
#include "Gauge.h" #include "Gauge.h"
#include "Spring.h" #include "Spring.h"
#include "AdvSound.h" #include "sound.h"
#include "PyInt.h" #include "PyInt.h"
#include "command.h" #include "command.h"
@@ -90,7 +90,7 @@ class TTrain
void UpdateMechPosition(double dt); void UpdateMechPosition(double dt);
vector3 GetWorldMechPosition(); vector3 GetWorldMechPosition();
bool Update( double const Deltatime ); bool Update( double const Deltatime );
bool m_updated = false; void update_sounds( double const Deltatime );
void MechStop(); void MechStop();
void SetLights(); void SetLights();
// McZapkie-310302: ladowanie parametrow z pliku // McZapkie-310302: ladowanie parametrow z pliku
@@ -101,6 +101,7 @@ class TTrain
// types // types
typedef void( *command_handler )( TTrain *Train, command_data const &Command ); typedef void( *command_handler )( TTrain *Train, command_data const &Command );
typedef std::unordered_map<user_command, command_handler> commandhandler_map; typedef std::unordered_map<user_command, command_handler> commandhandler_map;
// methods
// clears state of all cabin controls // clears state of all cabin controls
void clear_cab_controls(); void clear_cab_controls();
// sets cabin controls based on current state of the vehicle // sets cabin controls based on current state of the vehicle
@@ -110,10 +111,6 @@ class TTrain
bool initialize_gauge(cParser &Parser, std::string const &Label, int const Cabindex); 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 // 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); 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( PSound Sound, int const Volume = DSBVOLUME_MAX, DWORD const Flags = 0 );
void play_sound( PSound Sound, PSound Fallbacksound, int const Volume, DWORD const Flags );
// helper, returns true for EMU with oerlikon brake // helper, returns true for EMU with oerlikon brake
bool is_eztoer() const; bool is_eztoer() const;
// command handlers // command handlers
@@ -229,7 +226,7 @@ public: // reszta może by?publiczna
TGauge ggMainCtrl; TGauge ggMainCtrl;
TGauge ggMainCtrlAct; TGauge ggMainCtrlAct;
TGauge ggScndCtrl; TGauge ggScndCtrl;
TGauge ggScndCtrlButton; TGauge ggScndCtrlButton; // NOTE: not used?
TGauge ggDirKey; TGauge ggDirKey;
TGauge ggBrakeCtrl; TGauge ggBrakeCtrl;
TGauge ggLocalBrake; TGauge ggLocalBrake;
@@ -308,8 +305,6 @@ public: // reszta może by?publiczna
TGauge ggTrainHeatingButton; TGauge ggTrainHeatingButton;
TGauge ggSignallingButton; TGauge ggSignallingButton;
TGauge ggDoorSignallingButton; TGauge ggDoorSignallingButton;
// TGauge ggDistCounter; //Ra 2014-07: licznik kilometrów
// TGauge ggVelocityDgt; //i od razu prędkościomierz
TButton btLampkaPoslizg; TButton btLampkaPoslizg;
TButton btLampkaStyczn; TButton btLampkaStyczn;
@@ -356,7 +351,6 @@ public: // reszta może by?publiczna
TButton btLampkaRadiotelefon; TButton btLampkaRadiotelefon;
TButton btLampkaHamienie; TButton btLampkaHamienie;
TButton btLampkaED; // Stele 161228 hamowanie elektrodynamiczne TButton btLampkaED; // Stele 161228 hamowanie elektrodynamiczne
TButton btLampkaJazda; // Ra: nie używane
// KURS90 // KURS90
TButton btLampkaBoczniki; TButton btLampkaBoczniki;
TButton btLampkaMaxSila; TButton btLampkaMaxSila;
@@ -384,8 +378,9 @@ public: // reszta może by?publiczna
// Ra 2013-12: wirtualne "lampki" do odbijania na haslerze w PoKeys // Ra 2013-12: wirtualne "lampki" do odbijania na haslerze w PoKeys
TButton btHaslerBrakes; // ciśnienie w cylindrach TButton btHaslerBrakes; // ciśnienie w cylindrach
TButton btHaslerCurrent; // prąd na silnikach TButton btHaslerCurrent; // prąd na silnikach
/*
vector3 pPosition; vector3 pPosition;
*/
vector3 pMechOffset; // driverNpos vector3 pMechOffset; // driverNpos
vector3 vMechMovement; vector3 vMechMovement;
vector3 pMechPosition; vector3 pMechPosition;
@@ -403,48 +398,25 @@ public: // reszta może by?publiczna
double fMechRoll; double fMechRoll;
double fMechPitch; double fMechPitch;
PSound dsbNastawnikJazdy; sound_source dsbReverserKey { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE }; // hunter-121211
PSound dsbNastawnikBocz; // hunter-081211 sound_source dsbNastawnikJazdy { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE };
PSound dsbRelay; sound_source dsbNastawnikBocz { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE }; // hunter-081211
PSound dsbPneumaticRelay; sound_source dsbSwitch { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE };
PSound dsbSwitch; sound_source dsbPneumaticSwitch { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE };
PSound dsbPneumaticSwitch;
PSound dsbReverserKey; // hunter-121211
PSound dsbCouplerAttach; // Ra: w kabinie???? sound_source rsHiss { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE }; // upuszczanie
PSound dsbCouplerDetach; // Ra: w kabinie??? 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
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
PSound dsbDieselIgnition; // Ra: w kabinie??? sound_source rsFadeSound { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE };
sound_source dsbHasler { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE };
PSound dsbDoorClose; // Ra: w kabinie??? sound_source dsbBuzzer { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE };
PSound dsbDoorOpen; // Ra: w kabinie??? sound_source dsbSlipAlarm { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE }; // Bombardier 011010: alarm przy poslizgu dla 181/182
// Winger 010304
PSound dsbPantUp;
PSound dsbPantDown;
PSound dsbWejscie_na_bezoporow;
PSound dsbWejscie_na_drugi_uklad; // hunter-081211: poprawka literowki
// PSound dsbHiss1;
// PSound dsbHiss2;
// McZapkie-280302
TRealSound rsBrake;
TRealSound rsSlippery;
TRealSound rsHiss; // upuszczanie
TRealSound rsHissU; // napelnianie
TRealSound rsHissE; // nagle
TRealSound rsHissX; // fala
TRealSound rsHissT; // czasowy
TRealSound rsSBHiss;
TRealSound rsRunningNoise;
TRealSound rsEngageSlippery;
TRealSound rsFadeSound;
PSound dsbHasler;
PSound dsbBuzzer;
PSound dsbSlipAlarm; // Bombardier 011010: alarm przy poslizgu dla 181/182
int iCabLightFlag; // McZapkie:120503: oswietlenie kabiny (0: wyl, 1: przyciemnione, 2: pelne) int iCabLightFlag; // McZapkie:120503: oswietlenie kabiny (0: wyl, 1: przyciemnione, 2: pelne)
bool bCabLight; // hunter-091012: czy swiatlo jest zapalone? bool bCabLight; // hunter-091012: czy swiatlo jest zapalone?
@@ -454,10 +426,6 @@ public: // reszta może by?publiczna
vector3 MirrorPosition(bool lewe); vector3 MirrorPosition(bool lewe);
private: private:
// PSound dsbBuzzer;
PSound dsbCouplerStretch;
PSound dsbEN57_CouplerStretch;
PSound dsbBufferClamp;
double fBlinkTimer; double fBlinkTimer;
float fHaslerTimer; float fHaslerTimer;
float fConverterTimer; // hunter-261211: dla przekaznika float fConverterTimer; // hunter-261211: dla przekaznika
@@ -465,7 +433,7 @@ public: // reszta może by?publiczna
float fCzuwakTestTimer; // hunter-091012: do testu czuwaka float fCzuwakTestTimer; // hunter-091012: do testu czuwaka
float fLightsTimer; // yB 150617: timer do swiatel 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; double fPoslizgTimer;
TTrack *tor; TTrack *tor;
@@ -495,7 +463,7 @@ public: // reszta może by?publiczna
bool bHeat[8]; // grzanie bool bHeat[8]; // grzanie
// McZapkie: do syczenia // McZapkie: do syczenia
float fPPress, fNPress; float fPPress, fNPress;
float fSPPress, fSNPress; // float fSPPress, fSNPress;
int iSekunda; // Ra: sekunda aktualizacji pr?dko?ci int iSekunda; // Ra: sekunda aktualizacji pr?dko?ci
int iRadioChannel; // numer aktualnego kana?u radiowego int iRadioChannel; // numer aktualnego kana?u radiowego
TPythonScreens pyScreens; TPythonScreens pyScreens;
@@ -506,8 +474,11 @@ public: // reszta może by?publiczna
float fEIMParams[9][10]; // parametry dla silnikow asynchronicznych float fEIMParams[9][10]; // parametry dla silnikow asynchronicznych
int RadioChannel() { return iRadioChannel; }; int RadioChannel() { return iRadioChannel; };
inline TDynamicObject *Dynamic() { return DynamicObject; }; inline TDynamicObject *Dynamic() { return DynamicObject; };
inline TDynamicObject const *Dynamic() const { return DynamicObject; };
inline TMoverParameters *Controlled() { return mvControlled; }; inline TMoverParameters *Controlled() { return mvControlled; };
inline TMoverParameters const *Controlled() const { return mvControlled; };
void DynamicSet(TDynamicObject *d); void DynamicSet(TDynamicObject *d);
void Silence(); void Silence();
}; };
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------

View File

@@ -99,82 +99,72 @@ bool TTrackFollower::Move(double fDistance, bool bPrimary)
bool bCanSkip; // czy przemieścić pojazd na inny tor bool bCanSkip; // czy przemieścić pojazd na inny tor
while (true) // pętla wychodzi, gdy przesunięcie wyjdzie zerowe while (true) // pętla wychodzi, gdy przesunięcie wyjdzie zerowe
{ // pętla przesuwająca wózek przez kolejne tory, aż do trafienia w jakiś { // pętla przesuwająca wózek przez kolejne tory, aż do trafienia w jakiś
if (!pCurrentTrack) if( pCurrentTrack == nullptr ) { return false; } // nie ma toru, to nie ma przesuwania
return false; // nie ma toru, to nie ma przesuwania // TODO: refactor following block as track method
if (pCurrentTrack->iEvents) // sumaryczna informacja o eventach if( pCurrentTrack->iEvents ) { // sumaryczna informacja o eventach
{ // omijamy cały ten blok, gdy tor nie ma on żadnych eventów (większość nie ma) // omijamy cały ten blok, gdy tor nie ma on żadnych eventów (większość nie ma)
if (fDistance < 0) if( std::abs( fDistance ) < 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 ) ) { if( SetFlag( iEventFlag, -1 ) ) {
// zawsze zeruje flagę sprawdzenia, jak mechanik dosiądzie, to się nie wykona // zawsze zeruje flagę sprawdzenia, jak mechanik dosiądzie, to się nie wykona
if( ( Owner->Mechanik != nullptr ) if( ( Owner->Mechanik != nullptr )
&& ( Owner->Mechanik->Primary() ) ) { && ( Owner->Mechanik->Primary() ) ) {
// tylko dla jednego członu // tylko dla jednego członu
// McZapkie-280503: wyzwalanie event tylko dla pojazdow z obsada // McZapkie-280503: wyzwalanie event tylko dla pojazdow z obsada
if( ( bPrimary ) if( ( true == bPrimary )
&& ( pCurrentTrack->evEvent1 ) && ( pCurrentTrack->evEvent1 != nullptr )
&& ( !pCurrentTrack->evEvent1->iQueued ) ) { && ( pCurrentTrack->evEvent1->iQueued == 0 ) ) {
// dodanie do kolejki // dodanie do kolejki
simulation::Events.AddToQuery( pCurrentTrack->evEvent1, Owner ); simulation::Events.AddToQuery( pCurrentTrack->evEvent1, Owner );
} }
} }
} }
// Owner->RaAxleEvent(pCurrentTrack->Event1); //Ra: dynamic zdecyduje, czy dodać do if( SetFlag( iEventallFlag, -1 ) ) {
// kolejki // McZapkie-280503: wyzwalanie eventall dla wszystkich pojazdow
// if (TestFlag(iEventallFlag,1)) if( ( true == bPrimary )
if (SetFlag(iEventallFlag, && ( pCurrentTrack->evEventall1 != nullptr )
-1)) // McZapkie-280503: wyzwalanie eventall dla wszystkich pojazdow && ( pCurrentTrack->evEventall1->iQueued == 0 ) ) {
if (bPrimary && pCurrentTrack->evEventall1 &&
(!pCurrentTrack->evEventall1->iQueued))
simulation::Events.AddToQuery( pCurrentTrack->evEventall1, Owner ); // dodanie do kolejki simulation::Events.AddToQuery( pCurrentTrack->evEventall1, Owner ); // dodanie do kolejki
// Owner->RaAxleEvent(pCurrentTrack->Eventall1); //Ra: dynamic zdecyduje, czy dodać
// do kolejki
} }
else if (fDistance > 0) }
{ }
else if (fDistance > 0) {
// event2, eventall2
if( SetFlag( iEventFlag, -2 ) ) { if( SetFlag( iEventFlag, -2 ) ) {
// zawsze ustawia flagę sprawdzenia, jak mechanik // zawsze ustawia flagę sprawdzenia, jak mechanik dosiądzie, to się nie wykona
// dosiądzie, to się nie wykona
if( ( Owner->Mechanik != nullptr ) if( ( Owner->Mechanik != nullptr )
&& ( Owner->Mechanik->Primary() ) ) { && ( Owner->Mechanik->Primary() ) ) {
// tylko dla jednego członu // tylko dla jednego członu
if( ( bPrimary ) if( ( true == bPrimary )
&& ( pCurrentTrack->evEvent2 ) && ( pCurrentTrack->evEvent2 != nullptr )
&& ( !pCurrentTrack->evEvent2->iQueued ) ) { && ( pCurrentTrack->evEvent2->iQueued == 0 ) ) {
simulation::Events.AddToQuery( pCurrentTrack->evEvent2, Owner ); 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 ) ) { if( SetFlag( iEventallFlag, -2 ) ) {
// sprawdza i zeruje na przyszłość, true jeśli zmieni z 2 na 0 // sprawdza i zeruje na przyszłość, true jeśli zmieni z 2 na 0
if( ( bPrimary ) if( ( true == bPrimary )
&& ( pCurrentTrack->evEventall2 ) && ( pCurrentTrack->evEventall2 != nullptr )
&& ( !pCurrentTrack->evEventall2->iQueued ) ) { && ( pCurrentTrack->evEventall2->iQueued == 0 ) ) {
simulation::Events.AddToQuery( pCurrentTrack->evEventall2, Owner ); 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? if (!pCurrentSegment) // jeżeli nie ma powiązanego segmentu toru?

View File

@@ -77,7 +77,7 @@ simulation_time::init() {
m_time.wSecond = 0; 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 void
@@ -125,16 +125,15 @@ simulation_time::update( double const Deltatime ) {
} }
int 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, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
{ 0, 31, 29, 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 ); int leap { ( Year % 4 == 0 ) && ( Year % 100 != 0 ) || ( Year % 400 == 0 ) };
for( i = 1; i < Month; ++i ) for( int i = 1; i < Month; ++i )
Day += daytab[ leap ][ i ]; Day += daytab[ leap ][ i ];
return Day; return Day;
@@ -196,8 +195,6 @@ TWorld::TWorld()
TWorld::~TWorld() TWorld::~TWorld()
{ {
TrainDelete(); TrainDelete();
// Ground.Free(); //Ra: usunięcie obiektów przed usunięciem dźwięków - sypie się
TSoundsManager::Free();
} }
void TWorld::TrainDelete(TDynamicObject *d) void TWorld::TrainDelete(TDynamicObject *d)
@@ -217,7 +214,6 @@ void TWorld::TrainDelete(TDynamicObject *d)
Train = NULL; Train = NULL;
Controlled = NULL; // tego też już nie ma Controlled = NULL; // tego też już nie ma
mvControlled = NULL; mvControlled = NULL;
Global::pUserDynamic = NULL; // tego też nie ma
}; };
bool TWorld::Init( GLFWwindow *Window ) { bool TWorld::Init( GLFWwindow *Window ) {
@@ -234,7 +230,7 @@ bool TWorld::Init( GLFWwindow *Window ) {
"ShaXbee, Oli_EU, youBy, KURS90, Ra, hunter, szociu, Stele, Q, firleju and others\n" ); "ShaXbee, Oli_EU, youBy, KURS90, Ra, hunter, szociu, Stele, Q, firleju and others\n" );
UILayer.set_background( "logo" ); UILayer.set_background( "logo" );
#ifdef EU07_USE_OLD_SOUNDCODE
if( true == TSoundsManager::Init( glfwGetWin32Window( window ) ) ) { if( true == TSoundsManager::Init( glfwGetWin32Window( window ) ) ) {
WriteLog( "Sound subsystem setup complete" ); WriteLog( "Sound subsystem setup complete" );
} }
@@ -242,7 +238,7 @@ bool TWorld::Init( GLFWwindow *Window ) {
ErrorLog( "Sound subsystem setup failed" ); ErrorLog( "Sound subsystem setup failed" );
return false; return false;
} }
#endif
glfwSetWindowTitle( window, ( Global::AppName + " (" + Global::SceneryFile + ")" ).c_str() ); // nazwa scenerii glfwSetWindowTitle( window, ( Global::AppName + " (" + Global::SceneryFile + ")" ).c_str() ); // nazwa scenerii
UILayer.set_progress(0.01); UILayer.set_progress(0.01);
UILayer.set_progress( "Loading scenery / Wczytywanie scenerii" ); UILayer.set_progress( "Loading scenery / Wczytywanie scenerii" );
@@ -269,7 +265,6 @@ bool TWorld::Init( GLFWwindow *Window ) {
{ {
Controlled = Train->Dynamic(); Controlled = Train->Dynamic();
mvControlled = Controlled->ControlledFind()->MoverParameters; mvControlled = Controlled->ControlledFind()->MoverParameters;
Global::pUserDynamic = Controlled; // renerowanie pojazdu względem kabiny
WriteLog("Player train init OK"); WriteLog("Player train init OK");
glfwSetWindowTitle( window, ( Global::AppName + " (" + Controlled->MoverParameters->Name + " @ " + Global::SceneryFile + ")" ).c_str() ); glfwSetWindowTitle( window, ( Global::AppName + " (" + Controlled->MoverParameters->Name + " @ " + Global::SceneryFile + ")" ).c_str() );
@@ -689,7 +684,7 @@ void TWorld::OnKeyDown(int cKey)
vehicle->MoverParameters->DecBrakeMult()) vehicle->MoverParameters->DecBrakeMult())
if (Train) if (Train)
{ // dźwięk oczywiście jest w kabinie { // dźwięk oczywiście jest w kabinie
Train->play_sound( Train->dsbSwitch ); Train->dsbSwitch.play();
} }
} }
} }
@@ -717,7 +712,7 @@ void TWorld::OnKeyDown(int cKey)
vehicle->iLights[CouplNr] = (vehicle->iLights[CouplNr] & ~mask) | set; vehicle->iLights[CouplNr] = (vehicle->iLights[CouplNr] & ~mask) | set;
if (Train) if (Train)
{ // Ra: ten dźwięk z kabiny to przegięcie, ale na razie zostawiam { // Ra: ten dźwięk z kabiny to przegięcie, ale na razie zostawiam
Train->play_sound( Train->dsbSwitch ); Train->dsbSwitch.play();
} }
} }
} }
@@ -737,7 +732,9 @@ void TWorld::OnKeyDown(int cKey)
if (vehicle->MoverParameters->IncLocalBrakeLevelFAST()) if (vehicle->MoverParameters->IncLocalBrakeLevelFAST())
if (Train) if (Train)
{ // dźwięk oczywiście jest w kabinie { // dźwięk oczywiście jest w kabinie
Train->play_sound( Train->dsbPneumaticRelay ); #ifdef EU07_USE_OLD_SOUNDCODE
Train->dsbPneumaticRelay.play();
#endif
} }
} }
} }
@@ -756,7 +753,9 @@ void TWorld::OnKeyDown(int cKey)
if (vehicle->MoverParameters->DecLocalBrakeLevelFAST()) if (vehicle->MoverParameters->DecLocalBrakeLevelFAST())
if (Train) if (Train)
{ // dźwięk oczywiście jest w kabinie { // dźwięk oczywiście jest w kabinie
Train->play_sound( Train->dsbPneumaticRelay ); #ifdef EU07_USE_OLD_SOUNDCODE
Train->dsbPneumaticRelay.play();
#endif
} }
} }
} }
@@ -773,7 +772,6 @@ void TWorld::InOutKey( bool const Near )
FreeFlyModeFlag = !FreeFlyModeFlag; // zmiana widoku FreeFlyModeFlag = !FreeFlyModeFlag; // zmiana widoku
if (FreeFlyModeFlag) { if (FreeFlyModeFlag) {
// jeżeli poza kabiną, przestawiamy w jej okolicę - OK // jeżeli poza kabiną, przestawiamy w jej okolicę - OK
Global::pUserDynamic = NULL; // bez renderowania względem kamery
if (Train) { if (Train) {
// cache current cab position so there's no need to set it all over again after each out-in switch // cache current cab position so there's no need to set it all over again after each out-in switch
Train->pMechSittingPosition = Train->pMechOffset; Train->pMechSittingPosition = Train->pMechOffset;
@@ -789,7 +787,6 @@ void TWorld::InOutKey( bool const Near )
{ // jazda w kabinie { // jazda w kabinie
if (Train) if (Train)
{ {
Global::pUserDynamic = Controlled; // renerowanie względem kamery
Train->Dynamic()->bDisplayCab = true; Train->Dynamic()->bDisplayCab = true;
Train->Dynamic()->ABuSetModelShake( Train->Dynamic()->ABuSetModelShake(
vector3(0, 0, 0)); // zerowanie przesunięcia przed powrotem? vector3(0, 0, 0)); // zerowanie przesunięcia przed powrotem?
@@ -1063,6 +1060,8 @@ bool TWorld::Update() {
Timer::subsystem.sim_total.stop(); Timer::subsystem.sim_total.stop();
simulation::Region->update_sounds(); simulation::Region->update_sounds();
audio::renderer.update( dt );
GfxRenderer.Update( dt ); GfxRenderer.Update( dt );
ResourceSweep(); ResourceSweep();
@@ -1138,12 +1137,10 @@ TWorld::Update_Camera( double const Deltatime ) {
else if( Global::shiftState ) { else if( Global::shiftState ) {
// patrzenie w bok przez szybę // patrzenie w bok przez szybę
Camera.LookAt = Camera.Pos - ( lr ? -1 : 1 ) * Train->Dynamic()->VectorLeft() * Train->Dynamic()->MoverParameters->ActiveCab; 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, else { // patrzenie w kierunku osi pojazdu, z uwzględnieniem kabiny - jakby z lusterka,
// ale bez odbicia // ale bez odbicia
Camera.LookAt = Camera.Pos - Train->GetDirection() * Train->Dynamic()->MoverParameters->ActiveCab; //-1 albo 1 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.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 Camera.Pitch = 0.5 * std::atan( Train->vMechVelocity.z * Train->fMechPitch ); // hustanie kamery przod tyl
@@ -1176,11 +1173,10 @@ TWorld::Update_Camera( double const Deltatime ) {
else // patrzenie w kierunku osi pojazdu, z uwzględnieniem kabiny 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.LookAt = Train->GetWorldMechPosition() + Train->GetDirection() * 5.0 * Train->Dynamic()->MoverParameters->ActiveCab; //-1 albo 1
Camera.vUp = Train->GetUp(); Camera.vUp = Train->GetUp();
Global::SetCameraRotation( Camera.Yaw - modelrotate ); // tu już trzeba uwzględnić lusterka
} }
} }
else { // kamera nieruchoma else {
Global::SetCameraRotation( Camera.Yaw - M_PI ); // kamera nieruchoma
} }
// all done, update camera position to the new value // all done, update camera position to the new value
Global::pCameraPosition = Camera.Pos; Global::pCameraPosition = Camera.Pos;
@@ -1422,7 +1418,11 @@ TWorld::Update_UI() {
+ ( vehicle->MoverParameters->bPantKurek3 ? "-ZG" : "|ZG" ); + ( vehicle->MoverParameters->bPantKurek3 ? "-ZG" : "|ZG" );
uitextline2 += 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 ) + ", Fb: " + to_string( vehicle->MoverParameters->Fb * 0.001f, 1 )
+ ", Fr: " + to_string( vehicle->MoverParameters->Adhesive( vehicle->MoverParameters->RunningTrack.friction ), 2 ) + ", Fr: " + to_string( vehicle->MoverParameters->Adhesive( vehicle->MoverParameters->RunningTrack.friction ), 2 )
+ ( vehicle->MoverParameters->SlippingWheels ? " (!)" : "" ); + ( vehicle->MoverParameters->SlippingWheels ? " (!)" : "" );
@@ -1640,7 +1640,9 @@ TWorld::Update_UI() {
"HamZ=" + to_string( vehicle->MoverParameters->fBrakeCtrlPos, 2 ) "HamZ=" + to_string( vehicle->MoverParameters->fBrakeCtrlPos, 2 )
+ "; HamP=" + std::to_string( vehicle->MoverParameters->LocalBrakePos ) + "/" + to_string( vehicle->MoverParameters->LocalBrakePosA, 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 ) + ")" + "; 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=" + + "; I=" +
( vehicle->MoverParameters->TrainType == dt_EZT ? ( vehicle->MoverParameters->TrainType == dt_EZT ?
std::to_string( int( vehicle->MoverParameters->ShowCurrent( 0 ) ) ) : std::to_string( int( vehicle->MoverParameters->ShowCurrent( 0 ) ) ) :
@@ -2033,15 +2035,15 @@ void TWorld::CreateE3D(std::string const &Path, bool Dynamic)
if( dynamic->iCabs ) { // jeśli ma jakąkolwiek kabinę if( dynamic->iCabs ) { // jeśli ma jakąkolwiek kabinę
delete Train; delete Train;
Train = new TTrain(); Train = new TTrain();
if( dynamic->iCabs & 1 ) { if( dynamic->iCabs & 0x1 ) {
dynamic->MoverParameters->ActiveCab = 1; dynamic->MoverParameters->ActiveCab = 1;
Train->Init( dynamic, true ); Train->Init( dynamic, true );
} }
if( dynamic->iCabs & 4 ) { if( dynamic->iCabs & 0x4 ) {
dynamic->MoverParameters->ActiveCab = -1; dynamic->MoverParameters->ActiveCab = -1;
Train->Init( dynamic, true ); Train->Init( dynamic, true );
} }
if( dynamic->iCabs & 2 ) { if( dynamic->iCabs & 0x2 ) {
dynamic->MoverParameters->ActiveCab = 0; dynamic->MoverParameters->ActiveCab = 0;
Train->Init( dynamic, true ); Train->Init( dynamic, true );
} }
@@ -2114,7 +2116,6 @@ void TWorld::ChangeDynamic() {
Train->Dynamic()->asBaseDir + Train->Dynamic()->asBaseDir +
Train->Dynamic()->MoverParameters->TypeName + ".mmd" ); Train->Dynamic()->MoverParameters->TypeName + ".mmd" );
if( !FreeFlyModeFlag ) { if( !FreeFlyModeFlag ) {
Global::pUserDynamic = Controlled; // renerowanie względem kamery
Train->Dynamic()->bDisplayCab = true; Train->Dynamic()->bDisplayCab = true;
Train->Dynamic()->ABuSetModelShake( Train->Dynamic()->ABuSetModelShake(
vector3( 0, 0, 0 ) ); // zerowanie przesunięcia przed powrotem? vector3( 0, 0, 0 ) ); // zerowanie przesunięcia przed powrotem?

View File

@@ -39,13 +39,13 @@ public:
second() const { return ( m_time.wMilliseconds * 0.001 + m_time.wSecond ); } second() const { return ( m_time.wMilliseconds * 0.001 + m_time.wSecond ); }
int int
year_day() const { return m_yearday; } 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 int
julian_day() const; julian_day() const;
private: 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 // calculates day and month from given day of year
void void
daymonth( WORD &Day, WORD &Month, WORD const Year, WORD const Yearday ); daymonth( WORD &Day, WORD &Month, WORD const Year, WORD const Yearday );
@@ -115,7 +115,6 @@ TWorld();
// calculates current season of the year based on set simulation date // calculates current season of the year based on set simulation date
void compute_season( int const Yearday ) const; void compute_season( int const Yearday ) const;
private: private:
void Update_Environment(); void Update_Environment();
void Update_Camera( const double Deltatime ); void Update_Camera( const double Deltatime );

205
audio.cpp Normal file
View File

@@ -0,0 +1,205 @@
/*
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"
#define DR_WAV_IMPLEMENTATION
#include "dr_wav.h"
#define DR_FLAC_IMPLEMENTATION
#include "dr_flac.h"
namespace audio {
openal_buffer::openal_buffer( std::string const &Filename ) :
name( Filename ) {
::alGenBuffers( 1, &id );
// fetch audio data
if( Filename.substr( Filename.rfind( '.' ) ) == ".wav" ) {
// .wav file
auto *file { drwav_open_file( Filename.c_str() ) };
rate = file->sampleRate;
auto const samplecount { static_cast<std::size_t>( file->totalSampleCount ) };
data.resize( samplecount );
drwav_read_s16(
file,
samplecount,
&data[ 0 ] );
if( file->channels > 1 ) {
narrow_to_mono( file->channels );
data.resize( samplecount / file->channels );
}
// we're done with the disk data
drwav_close( file );
}
else {
// .flac or .ogg file
auto *file { drflac_open_file( Filename.c_str() ) };
rate = file->sampleRate;
auto const samplecount{ static_cast<std::size_t>( file->totalSampleCount ) };
data.resize( samplecount );
drflac_read_s16(
file,
samplecount,
&data[ 0 ] );
if( file->channels > 1 ) {
narrow_to_mono( file->channels );
data.resize( samplecount / file->channels );
}
// we're done with the disk data
drflac_close( file );
}
// send the data to openal side
::alBufferData( id, AL_FORMAT_MONO16, data.data(), data.size() * sizeof( std::int16_t ), rate );
// and get rid of the source, we shouldn't need it anymore
// TBD, TODO: delay data fetching and transfers until the buffer is actually used?
std::vector<std::int16_t>().swap( data );
}
// mix specified number of interleaved multi-channel data, down to mono
void
openal_buffer::narrow_to_mono( std::uint16_t const Channelcount ) {
std::size_t monodataindex { 0 };
std::int32_t accumulator { 0 };
auto channelcount { Channelcount };
for( auto const channeldata : data ) {
accumulator += channeldata;
if( --channelcount == 0 ) {
data[ monodataindex++ ] = accumulator / Channelcount;
accumulator = 0;
channelcount = Channelcount;
}
}
}
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", ".flac", ".ogg" };
for( auto const &extension : extensions ) {
if( FileExists( Filename + extension ) ) {
// valid name on success
return Filename + extension;
}
}
return {}; // empty string on failure
}
} // audio
//---------------------------------------------------------------------------

78
audio.h Normal file
View File

@@ -0,0 +1,78 @@
/*
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 );
private:
// methods
// mix specified number of interleaved multi-channel data, down to mono
void
narrow_to_mono( std::uint16_t const Channelcount );
// members
std::vector<std::int16_t> data; // audio data
};
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
//---------------------------------------------------------------------------

327
audiorenderer.cpp Normal file
View File

@@ -0,0 +1,327 @@
/*
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() {
::alSourcePlay( id );
is_playing = true;
}
// stops the playback
void
openal_source::stop() {
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
::alGetSourcei( id, AL_BUFFERS_PROCESSED, &buffer_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( ( buffer_index > 0 )
&& ( buffers.size() > 1 ) ) {
::alSourceUnqueueBuffers( id, 1, &bufferid );
buffers.erase( std::begin( buffers ) );
--buffer_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 ) {
/*
// velocity
// not used yet
glm::vec3 const velocity { ( State.location - properties.location ) / update_deltatime };
*/
// location
properties.location = State.location;
auto sourceoffset { glm::vec3 { properties.location - glm::dvec3 { Global::pCameraPosition } } };
if( glm::length2( sourceoffset ) > std::max( ( sound_range * sound_range ), ( EU07_SOUND_CUTOFFRANGE * EU07_SOUND_CUTOFFRANGE ) ) ) {
// range cutoff check
stop();
is_synced = false; // flag sync failure for the controller
return;
}
if( sound_range >= 0 ) {
::alSourcefv( id, AL_POSITION, glm::value_ptr( sourceoffset ) );
}
else {
// sounds with 'unlimited' range are positioned on top of the listener
::alSourcefv( id, AL_POSITION, glm::value_ptr( glm::vec3() ) );
}
// gain
if( ( State.placement_stamp != properties.placement_stamp )
|| ( State.base_gain != properties.base_gain ) ) {
// gain value has changed
properties.base_gain = State.base_gain;
properties.placement_gain = State.placement_gain;
properties.placement_stamp = State.placement_stamp;
::alSourcef( id, AL_GAIN, properties.base_gain * properties.placement_gain * Global::AudioVolume );
}
// pitch
if( State.base_pitch != properties.base_pitch ) {
// pitch value has changed
properties.base_pitch = State.base_pitch;
::alSourcef( id, AL_PITCH, properties.base_pitch * pitch_variation );
}
is_synced = true;
}
// sets max audible distance for sounds emitted by the source
void
openal_source::range( float const Range ) {
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.5f );
// NOTE: we cache actual specified range, as we'll be giving 'unlimited' range special treatment
sound_range = Range;
}
// 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.base_pitch = -1.f;
}
// toggles looping of the sound emitted by the source
void
openal_source::loop( bool const State ) {
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() {
// 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( buffers.size() );
// ...release the buffers...
::alSourceUnqueueBuffers( id, bufferids.size(), bufferids.data() );
// ...and reset reset the properties, except for the id of the allocated source
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 );
// all done
m_ready = true;
return true;
}
// schedules playback of specified sample, under control of the specified emitter
void
openal_renderer::insert( sound_source *Controller, audio::buffer_handle const Sound ) {
audio::openal_source::buffer_sequence buffers { Sound };
return
insert(
Controller,
std::begin( buffers ), std::end( buffers ) );
}
// 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();
m_sourcespares.push( *source );
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 ) {
// 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();
m_sourcespares.push( *source );
source = m_sources.erase( source );
}
else {
// otherwise proceed through the list normally
++source;
}
}
}
// returns an instance of implementation-side part of the sound emitter
audio::openal_source
openal_renderer::fetch_source() {
audio::openal_source soundsource;
if( false == m_sourcespares.empty() ) {
// reuse (a copy of) already allocated source
soundsource = m_sourcespares.top();
m_sourcespares.pop();
}
return soundsource;
}
bool
openal_renderer::init_caps() {
// select the "preferred device"
// TODO: support for opening config-specified device
m_device = ::alcOpenDevice( nullptr );
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 ) } );
m_context = ::alcCreateContext( m_device, nullptr );
if( m_context == nullptr ) {
ErrorLog( "Failed to create audio context" );
return false;
}
return ( ::alcMakeContextCurrent( m_context ) == AL_TRUE );
}
} // audio
//---------------------------------------------------------------------------

168
audiorenderer.h Normal file
View File

@@ -0,0 +1,168 @@
/*
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;
// sound emitter state sync item
struct sound_properties {
glm::dvec3 location;
float base_gain { 1.f };
float placement_gain { 1.f };
std::uintptr_t placement_stamp { ~( std::uintptr_t{ 0 } ) };
float base_pitch { 1.f };
};
namespace audio {
// implementation part of the sound emitter
// TODO: generic interface base, for implementations other than openAL
struct openal_source {
// types
using buffer_sequence = std::vector<audio::buffer_handle>;
// members
ALuint id { audio::null_resource }; // associated AL resource
sound_source *controller { nullptr }; // source controller
buffer_sequence buffers; // sequence of samples the source will emit
int buffer_index { 0 }; // currently queued sample from the buffer sequence
bool is_playing { false };
bool is_looping { false };
bool is_synced { true }; // set to false only if a sync attempt fails
sound_properties properties;
// methods
template <class Iterator_>
openal_source &
bind( sound_source *Controller, Iterator_ First, Iterator_ Last ) {
controller = Controller;
buffers.insert( std::end( buffers ), First, Last );
if( id == audio::null_resource ) {
::alGenSources( 1, &id ); }
// look up and queue assigned buffers
std::vector<ALuint> bufferids;
for( auto const buffer : buffers ) {
bufferids.emplace_back( audio::renderer.buffer( buffer ).id ); }
::alSourceQueueBuffers( id, bufferids.size(), bufferids.data() );
return *this; }
// 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
};
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( sound_source *Controller, Iterator_ First, Iterator_ Last ) {
m_sources.emplace_back( fetch_source().bind( Controller, First, Last ) ); }
// schedules playback of specified sample, under control of the specified sound emitter
void
insert( sound_source *Controller, audio::buffer_handle const Sound );
// 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<audio::openal_source>;
// 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
};
extern openal_renderer renderer;
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
//---------------------------------------------------------------------------

View File

@@ -162,7 +162,7 @@ class matrix4x4
} }
// Low-level access to the array. // Low-level access to the array.
const scalar_t *readArray(void) const scalar_t *readArray(void) const
{ {
return e; return e;
} }

View File

@@ -27,9 +27,6 @@
</Filter> </Filter>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="AdvSound.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="AirCoupler.cpp"> <ClCompile Include="AirCoupler.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
@@ -93,9 +90,6 @@
<ClCompile Include="PyInt.cpp"> <ClCompile Include="PyInt.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="RealSound.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ResourceManager.cpp"> <ClCompile Include="ResourceManager.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
@@ -105,9 +99,6 @@
<ClCompile Include="sky.cpp"> <ClCompile Include="sky.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="Sound.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Spring.cpp"> <ClCompile Include="Spring.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
@@ -132,12 +123,6 @@
<ClCompile Include="TrkFoll.cpp"> <ClCompile Include="TrkFoll.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="VBO.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="wavread.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="World.cpp"> <ClCompile Include="World.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
@@ -240,6 +225,15 @@
<ClCompile Include="messaging.cpp"> <ClCompile Include="messaging.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="sound.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="audiorenderer.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="audio.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="Globals.h"> <ClInclude Include="Globals.h">
@@ -287,9 +281,6 @@
<ClInclude Include="resource.h"> <ClInclude Include="resource.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="VBO.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Float3d.h"> <ClInclude Include="Float3d.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
@@ -320,9 +311,6 @@
<ClInclude Include="Console\LPT.h"> <ClInclude Include="Console\LPT.h">
<Filter>Header Files\input</Filter> <Filter>Header Files\input</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="RealSound.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Segment.h"> <ClInclude Include="Segment.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
@@ -347,12 +335,6 @@
<ClInclude Include="Names.h"> <ClInclude Include="Names.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="Sound.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="AdvSound.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Model3d.h"> <ClInclude Include="Model3d.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
@@ -362,9 +344,6 @@
<ClInclude Include="AnimModel.h"> <ClInclude Include="AnimModel.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="wavread.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Track.h"> <ClInclude Include="Track.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
@@ -470,6 +449,15 @@
<ClInclude Include="messaging.h"> <ClInclude Include="messaging.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="sound.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="audio.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="audiorenderer.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ResourceCompile Include="maszyna.rc"> <ResourceCompile Include="maszyna.rc">

View File

@@ -105,7 +105,7 @@ material_manager::create( std::string const &Filename, bool const Loadnow ) {
// try to locate requested material in the databank // try to locate requested material in the databank
auto const databanklookup = find_in_databank( filename ); auto const databanklookup = find_in_databank( filename );
if( databanklookup != npos ) { if( databanklookup != null_handle ) {
return databanklookup; return databanklookup;
} }
// if this fails, try to look for it on disk // if this fails, try to look for it on disk
@@ -149,7 +149,7 @@ material_manager::find_in_databank( std::string const &Materialname ) const {
return ( return (
lookup != m_materialmappings.end() ? lookup != m_materialmappings.end() ?
lookup->second : lookup->second :
npos ); null_handle );
} }
// checks whether specified file exists. // checks whether specified file exists.

View File

@@ -55,7 +55,6 @@ private:
std::string std::string
find_on_disk( std::string const &Materialname ) const; find_on_disk( std::string const &Materialname ) const;
// members: // members:
material_handle const npos { -1 };
material_sequence m_materials; material_sequence m_materials;
index_map m_materialmappings; index_map m_materialmappings;

View File

View File

@@ -14,6 +14,8 @@ http://mozilla.org/MPL/2.0/.
#include "logs.h" #include "logs.h"
#include "globals.h" #include "globals.h"
namespace gfx {
void void
basic_vertex::serialize( std::ostream &s ) const { 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 // 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 // creates a new geometry chunk of specified type from supplied vertex data. returns: handle to the chunk
geometry_handle gfx::geometry_handle
geometry_bank::create( vertex_array &Vertices, unsigned int const Type ) { geometry_bank::create( gfx::vertex_array &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 ); m_chunks.emplace_back( Vertices, Type );
// NOTE: handle is effectively (index into chunk array + 1) this leaves value of 0 to serve as error/empty handle indication // NOTE: handle is effectively (index into chunk array + 1) this leaves value of 0 to serve as error/empty handle indication
geometry_handle chunkhandle { 0, static_cast<std::uint32_t>(m_chunks.size()) }; gfx::geometry_handle chunkhandle { 0, static_cast<std::uint32_t>(m_chunks.size()) };
// template method implementation // template method implementation
create_( chunkhandle ); create_( chunkhandle );
// all done // 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 // replaces data of specified chunk with the supplied vertex data, starting from specified offset
bool 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; } 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 ) if( ( Offset == 0 )
&& ( Vertices.size() == chunk.vertices.size() ) ) { && ( 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 // ...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 // 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 // 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 ) ); chunk.vertices.insert( std::end( chunk.vertices ), std::begin( Vertices ), std::end( Vertices ) );
} }
// template method implementation // 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 // adds supplied vertex data at the end of specified chunk
bool 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; } 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 // draws geometry stored in specified chunk
void 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 // template method implementation
draw_( Geometry, Units, Streams ); draw_( Geometry, Units, Streams );
} }
@@ -111,7 +113,7 @@ geometry_bank::release() {
} }
vertex_array const & 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; 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 // opengl vbo-based variant of the geometry bank
GLuint opengl_vbogeometrybank::m_activebuffer { 0 }; // buffer bound currently on the opengl end, if any 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 std::vector<GLint> opengl_vbogeometrybank::m_activetexturearrays; // currently enabled texture coord arrays
// create() subclass details // create() subclass details
void 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. // 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 // thus we don't need to initialize the values here
m_chunkrecords.emplace_back( chunk_record() ); m_chunkrecords.emplace_back( chunk_record() );
@@ -134,7 +136,7 @@ opengl_vbogeometrybank::create_( geometry_handle const &Geometry ) {
// replace() subclass details // replace() subclass details
void void
opengl_vbogeometrybank::replace_( geometry_handle const &Geometry ) { opengl_vbogeometrybank::replace_( gfx::geometry_handle const &Geometry ) {
auto &chunkrecord = m_chunkrecords[ Geometry.chunk - 1 ]; auto &chunkrecord = m_chunkrecords[ Geometry.chunk - 1 ];
chunkrecord.is_good = false; chunkrecord.is_good = false;
@@ -149,7 +151,7 @@ opengl_vbogeometrybank::replace_( geometry_handle const &Geometry ) {
// draw() subclass details // draw() subclass details
void 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( m_buffer == 0 ) {
// if there's no buffer, we'll have to make one // 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 // TODO: allow to specify usage hint at the object creation, and pass it here
::glBufferData( ::glBufferData(
GL_ARRAY_BUFFER, GL_ARRAY_BUFFER,
datasize * sizeof( basic_vertex ), datasize * sizeof( gfx::basic_vertex ),
nullptr, nullptr,
GL_STATIC_DRAW ); GL_STATIC_DRAW );
if( ::glGetError() == GL_OUT_OF_MEMORY ) { if( ::glGetError() == GL_OUT_OF_MEMORY ) {
@@ -193,13 +195,13 @@ opengl_vbogeometrybank::draw_( geometry_handle const &Geometry, stream_units con
bind_buffer(); bind_buffer();
} }
auto &chunkrecord = m_chunkrecords[ Geometry.chunk - 1 ]; 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 ) { if( false == chunkrecord.is_good ) {
// we may potentially need to upload new buffer data before we can draw it // we may potentially need to upload new buffer data before we can draw it
::glBufferSubData( ::glBufferSubData(
GL_ARRAY_BUFFER, GL_ARRAY_BUFFER,
chunkrecord.offset * sizeof( basic_vertex ), chunkrecord.offset * sizeof( gfx::basic_vertex ),
chunkrecord.size * sizeof( basic_vertex ), chunkrecord.size * sizeof( gfx::basic_vertex ),
chunk.vertices.data() ); chunk.vertices.data() );
chunkrecord.is_good = true; chunkrecord.is_good = true;
} }
@@ -229,7 +231,7 @@ opengl_vbogeometrybank::bind_buffer() {
::glBindBuffer( GL_ARRAY_BUFFER, m_buffer ); ::glBindBuffer( GL_ARRAY_BUFFER, m_buffer );
m_activebuffer = m_buffer; m_activebuffer = m_buffer;
m_activestreams = stream::none; m_activestreams = gfx::stream::none;
} }
void void
@@ -250,34 +252,34 @@ opengl_vbogeometrybank::delete_buffer() {
} }
void 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 ) { if( Streams & gfx::stream::position ) {
::glVertexPointer( 3, GL_FLOAT, sizeof( basic_vertex ), static_cast<char *>( nullptr ) ); ::glVertexPointer( 3, GL_FLOAT, sizeof( gfx::basic_vertex ), static_cast<char *>( nullptr ) );
::glEnableClientState( GL_VERTEX_ARRAY ); ::glEnableClientState( GL_VERTEX_ARRAY );
} }
else { else {
::glDisableClientState( GL_VERTEX_ARRAY ); ::glDisableClientState( GL_VERTEX_ARRAY );
} }
// NOTE: normal and color streams share the data, making them effectively mutually exclusive // NOTE: normal and color streams share the data, making them effectively mutually exclusive
if( Streams & stream::normal ) { if( Streams & gfx::stream::normal ) {
::glNormalPointer( GL_FLOAT, sizeof( basic_vertex ), static_cast<char *>( nullptr ) + sizeof( float ) * 3 ); ::glNormalPointer( GL_FLOAT, sizeof( gfx::basic_vertex ), static_cast<char *>( nullptr ) + sizeof( float ) * 3 );
::glEnableClientState( GL_NORMAL_ARRAY ); ::glEnableClientState( GL_NORMAL_ARRAY );
} }
else { else {
::glDisableClientState( GL_NORMAL_ARRAY ); ::glDisableClientState( GL_NORMAL_ARRAY );
} }
if( Streams & stream::color ) { if( Streams & gfx::stream::color ) {
::glColorPointer( 3, GL_FLOAT, sizeof( basic_vertex ), static_cast<char *>( nullptr ) + sizeof( float ) * 3 ); ::glColorPointer( 3, GL_FLOAT, sizeof( gfx::basic_vertex ), static_cast<char *>( nullptr ) + sizeof( float ) * 3 );
::glEnableClientState( GL_COLOR_ARRAY ); ::glEnableClientState( GL_COLOR_ARRAY );
} }
else { else {
::glDisableClientState( GL_COLOR_ARRAY ); ::glDisableClientState( GL_COLOR_ARRAY );
} }
if( Streams & stream::texture ) { if( Streams & gfx::stream::texture ) {
for( auto unit : Units.texture ) { for( auto unit : Units.texture ) {
::glClientActiveTexture( unit ); ::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 ); ::glEnableClientState( GL_TEXTURE_COORD_ARRAY );
} }
m_activetexturearrays = Units.texture; m_activetexturearrays = Units.texture;
@@ -304,7 +306,7 @@ opengl_vbogeometrybank::release_streams() {
::glDisableClientState( GL_TEXTURE_COORD_ARRAY ); ::glDisableClientState( GL_TEXTURE_COORD_ARRAY );
} }
m_activestreams = stream::none; m_activestreams = gfx::stream::none;
m_activetexturearrays.clear(); m_activetexturearrays.clear();
} }
@@ -312,21 +314,21 @@ opengl_vbogeometrybank::release_streams() {
// create() subclass details // create() subclass details
void void
opengl_dlgeometrybank::create_( geometry_handle const &Geometry ) { opengl_dlgeometrybank::create_( gfx::geometry_handle const &Geometry ) {
m_chunkrecords.emplace_back( chunk_record() ); m_chunkrecords.emplace_back( chunk_record() );
} }
// replace() subclass details // replace() subclass details
void void
opengl_dlgeometrybank::replace_( geometry_handle const &Geometry ) { opengl_dlgeometrybank::replace_( gfx::geometry_handle const &Geometry ) {
delete_list( Geometry ); delete_list( Geometry );
} }
// draw() subclass details // draw() subclass details
void 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 ]; auto &chunkrecord = m_chunkrecords[ Geometry.chunk - 1 ];
if( chunkrecord.streams != Streams ) { 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 // we don't have a list ready, so compile one
chunkrecord.streams = Streams; chunkrecord.streams = Streams;
chunkrecord.list = ::glGenLists( 1 ); chunkrecord.list = ::glGenLists( 1 );
auto const &chunk = geometry_bank::chunk( Geometry ); auto const &chunk = gfx::geometry_bank::chunk( Geometry );
::glNewList( chunkrecord.list, GL_COMPILE ); ::glNewList( chunkrecord.list, GL_COMPILE );
::glBegin( chunk.type ); ::glBegin( chunk.type );
for( auto const &vertex : chunk.vertices ) { for( auto const &vertex : chunk.vertices ) {
if( Streams & stream::normal ) { ::glNormal3fv( glm::value_ptr( vertex.normal ) ); } if( Streams & gfx::stream::normal ) { ::glNormal3fv( glm::value_ptr( vertex.normal ) ); }
else if( Streams & stream::color ) { ::glColor3fv( glm::value_ptr( vertex.normal ) ); } else if( Streams & gfx::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 & gfx::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::position ) { ::glVertex3fv( glm::value_ptr( vertex.position ) ); }
} }
::glEnd(); ::glEnd();
::glEndList(); ::glEndList();
@@ -362,19 +364,19 @@ opengl_dlgeometrybank::release_() {
::glDeleteLists( chunkrecord.list, 1 ); ::glDeleteLists( chunkrecord.list, 1 );
chunkrecord.list = 0; chunkrecord.list = 0;
} }
chunkrecord.streams = stream::none; chunkrecord.streams = gfx::stream::none;
} }
} }
void 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 // NOTE: given it's our own internal method we trust it to be called with valid parameters
auto &chunkrecord = m_chunkrecords[ Geometry.chunk - 1 ]; auto &chunkrecord = m_chunkrecords[ Geometry.chunk - 1 ];
if( chunkrecord.list != 0 ) { if( chunkrecord.list != 0 ) {
::glDeleteLists( chunkrecord.list, 1 ); ::glDeleteLists( chunkrecord.list, 1 );
chunkrecord.list = 0; chunkrecord.list = 0;
} }
chunkrecord.streams = stream::none; chunkrecord.streams = gfx::stream::none;
} }
// geometry bank manager, holds collection of geometry banks // geometry bank manager, holds collection of geometry banks
@@ -387,41 +389,41 @@ geometrybank_manager::update() {
} }
// creates a new geometry bank. returns: handle to the bank or NULL // creates a new geometry bank. returns: handle to the bank or NULL
geometrybank_handle gfx::geometrybank_handle
geometrybank_manager::create_bank() { geometrybank_manager::create_bank() {
if( true == Global::bUseVBO ) { m_geometrybanks.emplace_back( std::make_shared<opengl_vbogeometrybank>(), std::chrono::steady_clock::time_point() ); } if( true == Global::bUseVBO ) { m_geometrybanks.emplace_back( std::make_shared<opengl_vbogeometrybank>(), std::chrono::steady_clock::time_point() ); }
else { m_geometrybanks.emplace_back( std::make_shared<opengl_dlgeometrybank>(), std::chrono::steady_clock::time_point() ); } else { m_geometrybanks.emplace_back( std::make_shared<opengl_dlgeometrybank>(), std::chrono::steady_clock::time_point() ); }
// NOTE: handle is effectively (index into chunk array + 1) this leaves value of 0 to serve as error/empty handle indication // NOTE: handle is effectively (index into chunk array + 1) this leaves value of 0 to serve as error/empty handle indication
return geometrybank_handle( m_geometrybanks.size(), 0 ); return { 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 // creates a new geometry chunk of specified type from supplied vertex data, in specified bank. returns: handle to the chunk or NULL
geometry_handle gfx::geometry_handle
geometrybank_manager::create_chunk( vertex_array &Vertices, geometrybank_handle const &Geometry, int const Type ) { geometrybank_manager::create_chunk( gfx::vertex_array &Vertices, gfx::geometrybank_handle const &Geometry, int const Type ) {
auto const newchunkhandle = bank( Geometry ).first->create( Vertices, Type ); auto const newchunkhandle = bank( Geometry ).first->create( Vertices, Type );
if( newchunkhandle.chunk != 0 ) { return geometry_handle( Geometry.bank, newchunkhandle.chunk ); } if( newchunkhandle.chunk != 0 ) { return { Geometry.bank, newchunkhandle.chunk }; }
else { return geometry_handle( 0, 0 ); } else { return { 0, 0 }; }
} }
// replaces data of specified chunk with the supplied vertex data, starting from specified offset // replaces data of specified chunk with the supplied vertex data, starting from specified offset
bool 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 ); return bank( Geometry ).first->replace( Vertices, Geometry, Offset );
} }
// adds supplied vertex data at the end of specified chunk // adds supplied vertex data at the end of specified chunk
bool bool
geometrybank_manager::append( vertex_array &Vertices, geometry_handle const &Geometry ) { geometrybank_manager::append( gfx::vertex_array &Vertices, gfx::geometry_handle const &Geometry ) {
return bank( Geometry ).first->append( Vertices, Geometry ); return bank( Geometry ).first->append( Vertices, Geometry );
} }
// draws geometry stored in specified chunk // draws geometry stored in specified chunk
void 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; } if( Geometry == null_handle ) { return; }
@@ -432,8 +434,10 @@ geometrybank_manager::draw( geometry_handle const &Geometry, unsigned int const
} }
// provides direct access to vertex data of specfied chunk // provides direct access to vertex data of specfied chunk
vertex_array const & gfx::vertex_array const &
geometrybank_manager::vertices( geometry_handle const &Geometry ) const { geometrybank_manager::vertices( gfx::geometry_handle const &Geometry ) const {
return bank( Geometry ).first->vertices( Geometry ); return bank( Geometry ).first->vertices( Geometry );
} }
} // namespace gfx

View File

@@ -18,6 +18,8 @@ http://mozilla.org/MPL/2.0/.
#endif #endif
#include "ResourceManager.h" #include "ResourceManager.h"
namespace gfx {
struct basic_vertex { struct basic_vertex {
glm::vec3 position; // 3d space glm::vec3 position; // 3d space
@@ -93,35 +95,35 @@ public:
// methods: // methods:
// creates a new geometry chunk of specified type from supplied vertex data. returns: handle to the chunk or NULL // creates a new geometry chunk of specified type from supplied vertex data. returns: handle to the chunk or NULL
geometry_handle gfx::geometry_handle
create( vertex_array &Vertices, unsigned int const Type ); create( gfx::vertex_array &Vertices, unsigned int const Type );
// replaces data of specified chunk with the supplied vertex data, starting from specified offset // replaces data of specified chunk with the supplied vertex data, starting from specified offset
bool 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 // adds supplied vertex data at the end of specified chunk
bool 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 // draws geometry stored in specified chunk
void 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 // draws geometry stored in supplied list of chunks
template <typename Iterator_> template <typename Iterator_>
void 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 // frees subclass-specific resources associated with the bank, typically called when the bank wasn't in use for a period of time
void void
release(); release();
// provides direct access to vertex data of specfied chunk // provides direct access to vertex data of specfied chunk
vertex_array const & gfx::vertex_array const &
vertices( geometry_handle const &Geometry ) const; vertices( gfx::geometry_handle const &Geometry ) const;
protected: protected:
// types: // types:
struct geometry_chunk { struct geometry_chunk {
unsigned int type; // kind of geometry used by the chunk unsigned int type; // kind of geometry used by the chunk
vertex_array vertices; // geometry data gfx::vertex_array vertices; // geometry data
// NOTE: constructor doesn't copy provided vertex data, but moves it // NOTE: constructor doesn't copy provided vertex data, but moves it
geometry_chunk( vertex_array &Vertices, unsigned int Type ) : geometry_chunk( gfx::vertex_array &Vertices, unsigned int Type ) :
type( Type ) type( Type )
{ {
vertices.swap( Vertices ); vertices.swap( Vertices );
@@ -133,11 +135,11 @@ protected:
// methods // methods
inline inline
geometry_chunk & geometry_chunk &
chunk( geometry_handle const Geometry ) { chunk( gfx::geometry_handle const Geometry ) {
return m_chunks[ Geometry.chunk - 1 ]; } return m_chunks[ Geometry.chunk - 1 ]; }
inline inline
geometry_chunk const & geometry_chunk const &
chunk( geometry_handle const Geometry ) const { chunk( gfx::geometry_handle const Geometry ) const {
return m_chunks[ Geometry.chunk - 1 ]; } return m_chunks[ Geometry.chunk - 1 ]; }
// members: // members:
@@ -146,11 +148,11 @@ protected:
private: private:
// methods: // methods:
// create() subclass details // create() subclass details
virtual void create_( geometry_handle const &Geometry ) = 0; virtual void create_( gfx::geometry_handle const &Geometry ) = 0;
// replace() subclass details // replace() subclass details
virtual void replace_( geometry_handle const &Geometry ) = 0; virtual void replace_( gfx::geometry_handle const &Geometry ) = 0;
// draw() subclass details // 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 // resource release subclass details
virtual void release_() = 0; virtual void release_() = 0;
}; };
@@ -170,7 +172,7 @@ public:
void void
reset() { reset() {
m_activebuffer = 0; m_activebuffer = 0;
m_activestreams = stream::none; } m_activestreams = gfx::stream::none; }
private: private:
// types: // types:
@@ -185,13 +187,13 @@ private:
// methods: // methods:
// create() subclass details // create() subclass details
void void
create_( geometry_handle const &Geometry ); create_( gfx::geometry_handle const &Geometry );
// replace() subclass details // replace() subclass details
void void
replace_( geometry_handle const &Geometry ); replace_( gfx::geometry_handle const &Geometry );
// draw() subclass details // draw() subclass details
void 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 // release() subclass details
void void
release_(); release_();
@@ -201,7 +203,7 @@ private:
delete_buffer(); delete_buffer();
static static
void void
bind_streams( stream_units const &Units, unsigned int const Streams ); bind_streams( gfx::stream_units const &Units, unsigned int const Streams );
static static
void void
release_streams(); release_streams();
@@ -240,18 +242,18 @@ private:
// methods: // methods:
// create() subclass details // create() subclass details
void void
create_( geometry_handle const &Geometry ); create_( gfx::geometry_handle const &Geometry );
// replace() subclass details // replace() subclass details
void void
replace_( geometry_handle const &Geometry ); replace_( gfx::geometry_handle const &Geometry );
// draw() subclass details // draw() subclass details
void 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 // release () subclass details
void void
release_(); release_();
void void
delete_list( geometry_handle const &Geometry ); delete_list( gfx::geometry_handle const &Geometry );
// members: // members:
chunkrecord_sequence m_chunkrecords; // helper data for all stored geometry chunks, in matching order chunkrecord_sequence m_chunkrecords; // helper data for all stored geometry chunks, in matching order
@@ -269,20 +271,20 @@ public:
// performs a resource sweep // performs a resource sweep
void update(); void update();
// creates a new geometry bank. returns: handle to the bank or NULL // creates a new geometry bank. returns: handle to the bank or NULL
geometrybank_handle gfx::geometrybank_handle
create_bank(); create_bank();
// creates a new geometry chunk of specified type from supplied vertex data, in specified bank. returns: handle to the chunk or NULL // creates a new geometry chunk of specified type from supplied vertex data, in specified bank. returns: handle to the chunk or NULL
geometry_handle gfx::geometry_handle
create_chunk( vertex_array &Vertices, geometrybank_handle const &Geometry, int const Type ); create_chunk( 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 // replaces data of specified chunk with the supplied vertex data, starting from specified offset
bool 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 // adds supplied vertex data at the end of specified chunk
bool 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 // draws geometry stored in specified chunk
void 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_> template <typename Iterator_>
void void
draw( Iterator_ First, Iterator_ Last, unsigned int const Streams = basic_streams ) { draw( Iterator_ First, Iterator_ Last, unsigned int const Streams = basic_streams ) {
@@ -290,38 +292,40 @@ public:
draw( *First, Streams ); draw( *First, Streams );
++First; } } ++First; } }
// provides direct access to vertex data of specfied chunk // provides direct access to vertex data of specfied chunk
vertex_array const & gfx::vertex_array const &
vertices( geometry_handle const &Geometry ) const; vertices( gfx::geometry_handle const &Geometry ) const;
// sets target texture unit for the texture data stream // sets target texture unit for the texture data stream
stream_units & gfx::stream_units &
units() { return m_units; } units() { return m_units; }
private: private:
// types: // types:
typedef std::pair< typedef std::pair<
std::shared_ptr<geometry_bank>, std::shared_ptr<geometry_bank>,
std::chrono::steady_clock::time_point > geometrybanktimepoint_pair; resource_timestamp > geometrybanktimepoint_pair;
typedef std::deque< geometrybanktimepoint_pair > geometrybanktimepointpair_sequence; typedef std::deque< geometrybanktimepoint_pair > geometrybanktimepointpair_sequence;
// members: // members:
geometrybanktimepointpair_sequence m_geometrybanks; geometrybanktimepointpair_sequence m_geometrybanks;
garbage_collector<geometrybanktimepointpair_sequence> m_garbagecollector { m_geometrybanks, 60, 120, "geometry buffer" }; garbage_collector<geometrybanktimepointpair_sequence> m_garbagecollector { m_geometrybanks, 60, 120, "geometry buffer" };
stream_units m_units; gfx::stream_units m_units;
// methods // methods
inline inline
bool bool
valid( geometry_handle const &Geometry ) const { valid( gfx::geometry_handle const &Geometry ) const {
return ( ( Geometry.bank != 0 ) return ( ( Geometry.bank != 0 )
&& ( Geometry.bank <= m_geometrybanks.size() ) ); } && ( Geometry.bank <= m_geometrybanks.size() ) ); }
inline inline
geometrybanktimepointpair_sequence::value_type & geometrybanktimepointpair_sequence::value_type &
bank( geometry_handle const Geometry ) { bank( gfx::geometry_handle const Geometry ) {
return m_geometrybanks[ Geometry.bank - 1 ]; } return m_geometrybanks[ Geometry.bank - 1 ]; }
inline inline
geometrybanktimepointpair_sequence::value_type const & geometrybanktimepointpair_sequence::value_type const &
bank( geometry_handle const Geometry ) const { bank( gfx::geometry_handle const Geometry ) const {
return m_geometrybanks[ Geometry.bank - 1 ]; } return m_geometrybanks[ Geometry.bank - 1 ]; }
}; };
} // namespace gfx

View File

@@ -108,7 +108,7 @@ opengl_renderer::Init( GLFWwindow *Window ) {
std::vector<GLint>{ m_normaltextureunit, m_diffusetextureunit } ); std::vector<GLint>{ m_normaltextureunit, m_diffusetextureunit } );
m_textures.assign_units( m_helpertextureunit, m_shadowtextureunit, m_normaltextureunit, m_diffusetextureunit ); // TODO: add reflections unit m_textures.assign_units( m_helpertextureunit, m_shadowtextureunit, m_normaltextureunit, m_diffusetextureunit ); // TODO: add reflections unit
UILayer.set_unit( m_diffusetextureunit ); UILayer.set_unit( m_diffusetextureunit );
Active_Texture( m_diffusetextureunit ); select_unit( m_diffusetextureunit );
::glDepthFunc( GL_LEQUAL ); ::glDepthFunc( GL_LEQUAL );
glEnable( GL_DEPTH_TEST ); glEnable( GL_DEPTH_TEST );
@@ -298,7 +298,7 @@ opengl_renderer::Init( GLFWwindow *Window ) {
auto const geometrybank = m_geometry.create_bank(); auto const geometrybank = m_geometry.create_bank();
float const size = 2.5f; float const size = 2.5f;
m_billboardgeometry = m_geometry.create_chunk( m_billboardgeometry = m_geometry.create_chunk(
vertex_array{ gfx::vertex_array{
{ { -size, size, 0.f }, glm::vec3(), { 1.f, 1.f } }, { { -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(), { 0.f, 1.f } },
{ { -size, -size, 0.f }, glm::vec3(), { 1.f, 0.f } }, { { -size, -size, 0.f }, glm::vec3(), { 1.f, 0.f } },
@@ -441,6 +441,25 @@ opengl_renderer::Render_pass( rendermode const Mode ) {
#endif #endif
switch_units( true, true, true ); switch_units( true, true, true );
Render( simulation::Region ); 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 // ...translucent parts
setup_drawing( true ); setup_drawing( true );
Render_Alpha( simulation::Region ); Render_Alpha( simulation::Region );
@@ -452,10 +471,10 @@ opengl_renderer::Render_pass( rendermode const Mode ) {
if( m_environmentcubetexturesupport ) { if( m_environmentcubetexturesupport ) {
// restore default texture matrix for reflections cube map // restore default texture matrix for reflections cube map
Active_Texture( m_helpertextureunit ); select_unit( m_helpertextureunit );
::glMatrixMode( GL_TEXTURE ); ::glMatrixMode( GL_TEXTURE );
::glPopMatrix(); ::glPopMatrix();
Active_Texture( m_diffusetextureunit ); select_unit( m_diffusetextureunit );
::glMatrixMode( GL_MODELVIEW ); ::glMatrixMode( GL_MODELVIEW );
} }
} }
@@ -696,9 +715,10 @@ opengl_renderer::setup_pass( renderpass_config &Config, rendermode const Mode, f
point = lightviewmatrix * point; point = lightviewmatrix * point;
} }
bounding_box( frustumchunkmin, frustumchunkmax, std::begin( frustumchunkshapepoints ), std::end( frustumchunkshapepoints ) ); 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 // quantize the frustum points and add some padding, to reduce shadow shimmer on scale changes
frustumchunkmin = 50.f * glm::floor( frustumchunkmin * ( 1.f / 50.f ) ); auto const quantizationstep{ std::min( Global::shadowtune.depth, 50.f ) };
frustumchunkmax = 50.f * glm::ceil( frustumchunkmax * ( 1.f / 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... // ...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 // 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() *= camera.projection() *=
@@ -791,11 +811,11 @@ opengl_renderer::setup_matrices() {
if( ( m_renderpass.draw_mode == rendermode::color ) if( ( m_renderpass.draw_mode == rendermode::color )
&& ( m_environmentcubetexturesupport ) ) { && ( m_environmentcubetexturesupport ) ) {
// special case, for colour render pass setup texture matrix for reflections cube map // special case, for colour render pass setup texture matrix for reflections cube map
Active_Texture( m_helpertextureunit ); select_unit( m_helpertextureunit );
::glMatrixMode( GL_TEXTURE ); ::glMatrixMode( GL_TEXTURE );
::glPushMatrix(); ::glPushMatrix();
::glMultMatrixf( glm::value_ptr( glm::inverse( glm::mat4{ glm::mat3{ m_renderpass.camera.modelview() } } ) ) ); ::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 // trim modelview matrix just to rotation, since rendering is done in camera-centric world space
@@ -861,7 +881,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 // darkens previous stage, preparing data for the shadow texture unit to select from
if( m_helpertextureunit >= 0 ) { if( m_helpertextureunit >= 0 ) {
Active_Texture( m_helpertextureunit ); select_unit( m_helpertextureunit );
if( ( true == Reflections ) if( ( true == Reflections )
|| ( ( true == Global::RenderShadows ) && ( true == Shadows ) && ( false == Global::bWireFrame ) ) ) { || ( ( true == Global::RenderShadows ) && ( true == Shadows ) && ( false == Global::bWireFrame ) ) ) {
@@ -948,7 +968,7 @@ opengl_renderer::setup_units( bool const Diffuse, bool const Shadows, bool const
&& ( false == Global::bWireFrame ) && ( false == Global::bWireFrame )
&& ( m_shadowcolor != colors::white ) ) { && ( 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 // NOTE: shadowmap isn't part of regular texture system, so we use direct bind call here
::glBindTexture( GL_TEXTURE_2D, m_shadowtexture ); ::glBindTexture( GL_TEXTURE_2D, m_shadowtexture );
::glEnable( GL_TEXTURE_2D ); ::glEnable( GL_TEXTURE_2D );
@@ -979,7 +999,7 @@ opengl_renderer::setup_units( bool const Diffuse, bool const Shadows, bool const
} }
else { else {
// turn off shadow map tests // turn off shadow map tests
Active_Texture( m_shadowtextureunit ); select_unit( m_shadowtextureunit );
::glDisable( GL_TEXTURE_2D ); ::glDisable( GL_TEXTURE_2D );
::glDisable( GL_TEXTURE_GEN_S ); ::glDisable( GL_TEXTURE_GEN_S );
@@ -992,7 +1012,7 @@ opengl_renderer::setup_units( bool const Diffuse, bool const Shadows, bool const
// NOTE: comes after diffuse stage in the operation chain // NOTE: comes after diffuse stage in the operation chain
if( m_normaltextureunit >= 0 ) { if( m_normaltextureunit >= 0 ) {
Active_Texture( m_normaltextureunit ); select_unit( m_normaltextureunit );
if( true == Reflections ) { if( true == Reflections ) {
::glEnable( GL_TEXTURE_2D ); ::glEnable( GL_TEXTURE_2D );
@@ -1015,7 +1035,7 @@ opengl_renderer::setup_units( bool const Diffuse, bool const Shadows, bool const
} }
// diffuse texture unit. // diffuse texture unit.
// NOTE: diffuse texture mapping is never fully disabled, alpha channel information is always included // 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 ); ::glEnable( GL_TEXTURE_2D );
if( true == Diffuse ) { if( true == Diffuse ) {
// default behaviour, modulate with previous stage // default behaviour, modulate with previous stage
@@ -1053,7 +1073,7 @@ opengl_renderer::switch_units( bool const Diffuse, bool const Shadows, bool cons
// helper texture unit. // helper texture unit.
if( m_helpertextureunit >= 0 ) { if( m_helpertextureunit >= 0 ) {
Active_Texture( m_helpertextureunit ); select_unit( m_helpertextureunit );
if( ( true == Reflections ) if( ( true == Reflections )
|| ( ( true == Global::RenderShadows ) || ( ( true == Global::RenderShadows )
&& ( true == Shadows ) && ( true == Shadows )
@@ -1079,12 +1099,12 @@ opengl_renderer::switch_units( bool const Diffuse, bool const Shadows, bool cons
if( m_shadowtextureunit >= 0 ) { if( m_shadowtextureunit >= 0 ) {
if( ( true == Global::RenderShadows ) && ( true == Shadows ) && ( false == Global::bWireFrame ) ) { if( ( true == Global::RenderShadows ) && ( true == Shadows ) && ( false == Global::bWireFrame ) ) {
Active_Texture( m_shadowtextureunit ); select_unit( m_shadowtextureunit );
::glEnable( GL_TEXTURE_2D ); ::glEnable( GL_TEXTURE_2D );
} }
else { else {
Active_Texture( m_shadowtextureunit ); select_unit( m_shadowtextureunit );
::glDisable( GL_TEXTURE_2D ); ::glDisable( GL_TEXTURE_2D );
} }
} }
@@ -1092,11 +1112,11 @@ opengl_renderer::switch_units( bool const Diffuse, bool const Shadows, bool cons
if( m_normaltextureunit >= 0 ) { if( m_normaltextureunit >= 0 ) {
if( true == Reflections ) { if( true == Reflections ) {
Active_Texture( m_normaltextureunit ); select_unit( m_normaltextureunit );
::glEnable( GL_TEXTURE_2D ); ::glEnable( GL_TEXTURE_2D );
} }
else { else {
Active_Texture( m_normaltextureunit ); select_unit( m_normaltextureunit );
::glDisable( GL_TEXTURE_2D ); ::glDisable( GL_TEXTURE_2D );
} }
} }
@@ -1104,12 +1124,12 @@ opengl_renderer::switch_units( bool const Diffuse, bool const Shadows, bool cons
// NOTE: toggle actually disables diffuse texture mapping, unlike setup counterpart // NOTE: toggle actually disables diffuse texture mapping, unlike setup counterpart
if( true == Diffuse ) { if( true == Diffuse ) {
Active_Texture( m_diffusetextureunit ); select_unit( m_diffusetextureunit );
::glEnable( GL_TEXTURE_2D ); ::glEnable( GL_TEXTURE_2D );
} }
else { else {
Active_Texture( m_diffusetextureunit ); select_unit( m_diffusetextureunit );
::glDisable( GL_TEXTURE_2D ); ::glDisable( GL_TEXTURE_2D );
} }
// update unit state // update unit state
@@ -1121,9 +1141,9 @@ opengl_renderer::switch_units( bool const Diffuse, bool const Shadows, bool cons
void void
opengl_renderer::setup_shadow_color( glm::vec4 const &Shadowcolor ) { 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 ::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 bool
@@ -1155,7 +1175,7 @@ opengl_renderer::Render( world_environment *Environment ) {
Environment->m_skydome.Render(); Environment->m_skydome.Render();
if( true == Global::bUseVBO ) { if( true == Global::bUseVBO ) {
// skydome uses a custom vbo which could potentially confuse the main geometry system. hardly elegant but, eh // 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 // stars
if( Environment->m_stars.m_stars != nullptr ) { if( Environment->m_stars.m_stars != nullptr ) {
@@ -1289,36 +1309,36 @@ opengl_renderer::Render( world_environment *Environment ) {
// geometry methods // geometry methods
// creates a new geometry bank. returns: handle to the bank or NULL // creates a new geometry bank. returns: handle to the bank or NULL
geometrybank_handle gfx::geometrybank_handle
opengl_renderer::Create_Bank() { opengl_renderer::Create_Bank() {
return m_geometry.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 // creates a new geometry chunk of specified type from supplied vertex data, in specified bank. returns: handle to the chunk or NULL
geometry_handle gfx::geometry_handle
opengl_renderer::Insert( vertex_array &Vertices, geometrybank_handle const &Geometry, int const Type ) { opengl_renderer::Insert( gfx::vertex_array &Vertices, gfx::geometrybank_handle const &Geometry, int const Type ) {
return m_geometry.create_chunk( Vertices, Geometry, Type ); return m_geometry.create_chunk( Vertices, Geometry, Type );
} }
// replaces data of specified chunk with the supplied vertex data, starting from specified offset // replaces data of specified chunk with the supplied vertex data, starting from specified offset
bool 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 ); return m_geometry.replace( Vertices, Geometry, Offset );
} }
// adds supplied vertex data at the end of specified chunk // adds supplied vertex data at the end of specified chunk
bool bool
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 ); return m_geometry.append( Vertices, Geometry );
} }
// provides direct access to vertex data of specfied chunk // provides direct access to vertex data of specfied chunk
vertex_array const & gfx::vertex_array const &
opengl_renderer::Vertices( geometry_handle const &Geometry ) const { opengl_renderer::Vertices( gfx::geometry_handle const &Geometry ) const {
return m_geometry.vertices( Geometry ); return m_geometry.vertices( Geometry );
} }
@@ -1348,7 +1368,7 @@ opengl_renderer::Material( material_handle const Material ) const {
// texture methods // texture methods
void void
opengl_renderer::Active_Texture( GLint const Textureunit ) { opengl_renderer::select_unit( GLint const Textureunit ) {
return m_textures.unit( Textureunit ); return m_textures.unit( Textureunit );
} }
@@ -2288,7 +2308,7 @@ opengl_renderer::Render( TSubModel *Submodel ) {
::glDisable( GL_LIGHTING ); ::glDisable( GL_LIGHTING );
// main draw call // main draw call
m_geometry.draw( Submodel->m_geometry, color_streams ); m_geometry.draw( Submodel->m_geometry, gfx::color_streams );
// post-draw reset // post-draw reset
::glPopAttrib(); ::glPopAttrib();
@@ -2989,11 +3009,12 @@ opengl_renderer::Render_Alpha( TSubModel *Submodel ) {
if( glarelevel > 0.0f ) { if( glarelevel > 0.0f ) {
// setup // 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 ); Bind_Texture( m_glaretexture );
::glColor4f( Submodel->f4Diffuse[ 0 ], Submodel->f4Diffuse[ 1 ], Submodel->f4Diffuse[ 2 ], glarelevel ); ::glColor4f( Submodel->f4Diffuse[ 0 ], Submodel->f4Diffuse[ 1 ], Submodel->f4Diffuse[ 2 ], glarelevel );
::glDisable( GL_LIGHTING ); ::glDisable( GL_LIGHTING );
::glDepthMask( GL_FALSE );
::glBlendFunc( GL_SRC_ALPHA, GL_ONE ); ::glBlendFunc( GL_SRC_ALPHA, GL_ONE );
::glPushMatrix(); ::glPushMatrix();

View File

@@ -156,20 +156,20 @@ public:
// geometry methods // 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 // 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 // creates a new geometry bank. returns: handle to the bank or NULL
geometrybank_handle gfx::geometrybank_handle
Create_Bank(); Create_Bank();
// creates a new geometry chunk of specified type from supplied vertex data, in specified bank. returns: handle to the chunk or NULL // creates a new geometry chunk of specified type from supplied vertex data, in specified bank. returns: handle to the chunk or NULL
geometry_handle gfx::geometry_handle
Insert( vertex_array &Vertices, geometrybank_handle const &Geometry, int const Type ); 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 // replaces data of specified chunk with the supplied vertex data, starting from specified offset
bool 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 // adds supplied vertex data at the end of specified chunk
bool 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 // provides direct access to vertex data of specfied chunk
vertex_array const & gfx::vertex_array const &
Vertices( geometry_handle const &Geometry ) const; Vertices( gfx::geometry_handle const &Geometry ) const;
// material methods // material methods
material_handle material_handle
Fetch_Material( std::string const &Filename, bool const Loadnow = true ); Fetch_Material( std::string const &Filename, bool const Loadnow = true );
@@ -178,8 +178,6 @@ public:
opengl_material const & opengl_material const &
Material( material_handle const Material ) const; Material( material_handle const Material ) const;
// texture methods // texture methods
void
Active_Texture( GLint const Textureunit );
texture_handle texture_handle
Fetch_Texture( std::string const &Filename, bool const Loadnow = true ); Fetch_Texture( std::string const &Filename, bool const Loadnow = true );
void void
@@ -194,14 +192,14 @@ public:
Pick_Control() const { return m_pickcontrolitem; } Pick_Control() const { return m_pickcontrolitem; }
editor::basic_node const * editor::basic_node const *
Pick_Node() const { return m_picksceneryitem; } Pick_Node() const { return m_picksceneryitem; }
// maintenance jobs // maintenance methods
void void
Update( double const Deltatime ); Update( double const Deltatime );
TSubModel const * TSubModel const *
Update_Pick_Control(); Update_Pick_Control();
editor::basic_node const * editor::basic_node const *
Update_Pick_Node(); Update_Pick_Node();
// debug performance string // debug methods
std::string const & std::string const &
info_times() const; info_times() const;
std::string const & std::string const &
@@ -275,6 +273,9 @@ private:
setup_shadow_color( glm::vec4 const &Shadowcolor ); setup_shadow_color( glm::vec4 const &Shadowcolor );
void void
switch_units( bool const Diffuse, bool const Shadows, bool const Reflections ); 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 // runs jobs needed to generate graphics for specified render pass
void void
Render_pass( rendermode const Mode ); Render_pass( rendermode const Mode );
@@ -336,12 +337,12 @@ private:
// members // members
GLFWwindow *m_window { nullptr }; GLFWwindow *m_window { nullptr };
geometrybank_manager m_geometry; gfx::geometrybank_manager m_geometry;
material_manager m_materials; material_manager m_materials;
texture_manager m_textures; texture_manager m_textures;
opengllight_array m_lights; 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_glaretexture { -1 };
texture_handle m_suntexture { -1 }; texture_handle m_suntexture { -1 };
texture_handle m_moontexture { -1 }; texture_handle m_moontexture { -1 };

View File

@@ -125,11 +125,13 @@ basic_cell::update_sounds() {
// sounds // sounds
auto const deltatime = Timer::GetDeltaRenderTime(); auto const deltatime = Timer::GetDeltaRenderTime();
for( auto *sound : m_sounds ) { for( auto *sound : m_sounds ) {
#ifdef EU07_USE_OLD_SOUNDCODE
if( ( sound->GetStatus() & DSBSTATUS_PLAYING ) == DSBPLAY_LOOPING ) { if( ( sound->GetStatus() & DSBSTATUS_PLAYING ) == DSBPLAY_LOOPING ) {
sound->Play( 1, DSBPLAY_LOOPING, true, sound->vSoundPosition ); sound->Play( 1, DSBPLAY_LOOPING, true, sound->vSoundPosition );
sound->AdjFreq( 1.0, deltatime ); sound->AdjFreq( 1.0, deltatime );
} }
#else
#endif
} }
// TBD, TODO: move to sound renderer // TBD, TODO: move to sound renderer
for( auto *path : m_paths ) { for( auto *path : m_paths ) {
@@ -348,7 +350,11 @@ basic_cell::insert( TAnimModel *Instance ) {
// adds provided sound instance to the cell // adds provided sound instance to the cell
void void
#ifdef EU07_USE_OLD_SOUNDCODE
basic_cell::insert( TTextSound *Sound ) { basic_cell::insert( TTextSound *Sound ) {
#else
basic_cell::insert( sound_source *Sound ) {
#endif
m_active = true; m_active = true;
@@ -514,7 +520,7 @@ basic_cell::center( glm::dvec3 Center ) {
// generates renderable version of held non-instanced geometry // generates renderable version of held non-instanced geometry
void 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 if( false == m_active ) { return; } // nothing to do here
@@ -873,7 +879,7 @@ void
basic_region::serialize( std::string const &Scenariofile ) const { basic_region::serialize( std::string const &Scenariofile ) const {
auto filename { 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 // trim leading $ char rainsted utility may add to the base name for modified .scn files
filename.erase( 0, 1 ); filename.erase( 0, 1 );
} }
@@ -916,7 +922,7 @@ bool
basic_region::deserialize( std::string const &Scenariofile ) { basic_region::deserialize( std::string const &Scenariofile ) {
auto filename { 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 // trim leading $ char rainsted utility may add to the base name for modified .scn files
filename.erase( 0, 1 ); filename.erase( 0, 1 );
} }
@@ -1171,8 +1177,13 @@ basic_region::insert_instance( TAnimModel *Instance, scratch_data &Scratchpad )
// inserts provided sound in the region // inserts provided sound in the region
void void
#ifdef EU07_USE_OLD_SOUNDCODE
basic_region::insert_sound( TTextSound *Sound, scratch_data &Scratchpad ) { basic_region::insert_sound( TTextSound *Sound, scratch_data &Scratchpad ) {
#else
basic_region::insert_sound( sound_source *Sound, scratch_data &Scratchpad ) {
#endif
#ifdef EU07_USE_OLD_SOUNDCODE
// NOTE: bounding area isn't present/filled until track class and wrapper refactoring is done // NOTE: bounding area isn't present/filled until track class and wrapper refactoring is done
auto location = Sound->location(); auto location = Sound->location();
@@ -1184,6 +1195,8 @@ basic_region::insert_sound( TTextSound *Sound, scratch_data &Scratchpad ) {
// tracks are guaranteed to hava a name so we can skip the check // tracks are guaranteed to hava a name so we can skip the check
ErrorLog( "Bad scenario: sound node \"" + Sound->name() + "\" placed in location outside region bounds (" + to_string( location ) + ")" ); ErrorLog( "Bad scenario: sound node \"" + Sound->name() + "\" placed in location outside region bounds (" + to_string( location ) + ")" );
} }
#else
#endif
} }
// inserts provided event launcher in the region // inserts provided event launcher in the region

17
scene.h
View File

@@ -20,6 +20,7 @@ http://mozilla.org/MPL/2.0/.
#include "scenenode.h" #include "scenenode.h"
#include "track.h" #include "track.h"
#include "traction.h" #include "traction.h"
#include "sound.h"
namespace scene { namespace scene {
@@ -104,7 +105,11 @@ public:
insert( TAnimModel *Instance ); insert( TAnimModel *Instance );
// adds provided sound instance to the cell // adds provided sound instance to the cell
void void
#ifdef EU07_USE_OLD_SOUNDCODE
insert( TTextSound *Sound ); insert( TTextSound *Sound );
#else
insert( sound_source *Sound );
#endif
// adds provided event launcher to the cell // adds provided event launcher to the cell
void void
insert( TEventLauncher *Launcher ); insert( TEventLauncher *Launcher );
@@ -131,7 +136,7 @@ public:
center( glm::dvec3 Center ); center( glm::dvec3 Center );
// generates renderable version of held non-instanced geometry in specified geometry bank // generates renderable version of held non-instanced geometry in specified geometry bank
void void
create_geometry( geometrybank_handle const &Bank ); create_geometry( gfx::geometrybank_handle const &Bank );
// provides access to bounding area data // provides access to bounding area data
bounding_area const & bounding_area const &
area() const { area() const {
@@ -144,7 +149,11 @@ private:
using path_sequence = std::vector<TTrack *>; using path_sequence = std::vector<TTrack *>;
using traction_sequence = std::vector<TTraction *>; using traction_sequence = std::vector<TTraction *>;
using instance_sequence = std::vector<TAnimModel *>; using instance_sequence = std::vector<TAnimModel *>;
#ifdef EU07_USE_OLD_SOUNDCODE
using sound_sequence = std::vector<TTextSound *>; using sound_sequence = std::vector<TTextSound *>;
#else
using sound_sequence = std::vector<sound_source *>;
#endif
using eventlauncher_sequence = std::vector<TEventLauncher *>; using eventlauncher_sequence = std::vector<TEventLauncher *>;
// methods // methods
void void
@@ -258,7 +267,7 @@ private:
shapenode_sequence m_shapes; // large pieces of opaque geometry and (legacy) terrain shapenode_sequence m_shapes; // large pieces of opaque geometry and (legacy) terrain
// TODO: implement dedicated, higher fidelity, fixed resolution terrain mesh item // TODO: implement dedicated, higher fidelity, fixed resolution terrain mesh item
// gfx renderer data // gfx renderer data
geometrybank_handle m_geometrybank; gfx::geometrybank_handle m_geometrybank;
bool m_geometrycreated { false }; bool m_geometrycreated { false };
}; };
@@ -311,7 +320,11 @@ public:
insert_instance( TAnimModel *Instance, scratch_data &Scratchpad ); insert_instance( TAnimModel *Instance, scratch_data &Scratchpad );
// inserts provided sound in the region // inserts provided sound in the region
void void
#ifdef EU07_USE_OLD_SOUNDCODE
insert_sound( TTextSound *Sound, scratch_data &Scratchpad ); insert_sound( TTextSound *Sound, scratch_data &Scratchpad );
#else
insert_sound( sound_source *Sound, scratch_data &Scratchpad );
#endif
// inserts provided event launcher in the region // inserts provided event launcher in the region
void void
insert_launcher( TEventLauncher *Launcher, scratch_data &Scratchpad ); insert_launcher( TEventLauncher *Launcher, scratch_data &Scratchpad );

View File

@@ -80,7 +80,7 @@ shape_node::shapenode_data::serialize( std::ostream &Output ) const {
// vertex count, followed by vertex data // vertex count, followed by vertex data
sn_utils::ls_uint32( Output, vertices.size() ); sn_utils::ls_uint32( Output, vertices.size() );
for( auto const &vertex : vertices ) { for( auto const &vertex : vertices ) {
basic_vertex( gfx::basic_vertex(
glm::vec3{ vertex.position - origin }, glm::vec3{ vertex.position - origin },
vertex.normal, vertex.normal,
vertex.texture ) vertex.texture )
@@ -109,7 +109,7 @@ shape_node::shapenode_data::deserialize( std::istream &Input ) {
// NOTE: geometry handle is acquired during geometry creation // NOTE: geometry handle is acquired during geometry creation
// vertex data // vertex data
vertices.resize( sn_utils::ld_uint32( Input ) ); vertices.resize( sn_utils::ld_uint32( Input ) );
basic_vertex localvertex; gfx::basic_vertex localvertex;
for( auto &vertex : vertices ) { for( auto &vertex : vertices ) {
localvertex.deserialize( Input ); localvertex.deserialize( Input );
vertex.position = origin + glm::dvec3{ localvertex.position }; vertex.position = origin + glm::dvec3{ localvertex.position };
@@ -417,9 +417,9 @@ shape_node::merge( shape_node &Shape ) {
// generates renderable version of held non-instanced geometry in specified geometry bank // generates renderable version of held non-instanced geometry in specified geometry bank
void 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 ) { for( auto const &vertex : m_data.vertices ) {
vertices.emplace_back( vertices.emplace_back(
@@ -464,7 +464,7 @@ lines_node::linesnode_data::serialize( std::ostream &Output ) const {
// vertex count, followed by vertex data // vertex count, followed by vertex data
sn_utils::ls_uint32( Output, vertices.size() ); sn_utils::ls_uint32( Output, vertices.size() );
for( auto const &vertex : vertices ) { for( auto const &vertex : vertices ) {
basic_vertex( gfx::basic_vertex(
glm::vec3{ vertex.position - origin }, glm::vec3{ vertex.position - origin },
vertex.normal, vertex.normal,
vertex.texture ) vertex.texture )
@@ -489,7 +489,7 @@ lines_node::linesnode_data::deserialize( std::istream &Input ) {
// NOTE: geometry handle is acquired during geometry creation // NOTE: geometry handle is acquired during geometry creation
// vertex data // vertex data
vertices.resize( sn_utils::ld_uint32( Input ) ); vertices.resize( sn_utils::ld_uint32( Input ) );
basic_vertex localvertex; gfx::basic_vertex localvertex;
for( auto &vertex : vertices ) { for( auto &vertex : vertices ) {
localvertex.deserialize( Input ); localvertex.deserialize( Input );
vertex.position = origin + glm::dvec3{ localvertex.position }; vertex.position = origin + glm::dvec3{ localvertex.position };
@@ -637,9 +637,9 @@ lines_node::merge( lines_node &Lines ) {
// generates renderable version of held non-instanced geometry in specified geometry bank // generates renderable version of held non-instanced geometry in specified geometry bank
void 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 ) { for( auto const &vertex : m_data.vertices ) {
vertices.emplace_back( vertices.emplace_back(

View File

@@ -93,7 +93,7 @@ public:
lighting_data lighting; lighting_data lighting;
// geometry data // geometry data
glm::dvec3 origin; // world position of the relative coordinate system origin 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 std::vector<world_vertex> vertices; // world space source data of the geometry
// methods: // methods:
// sends content of the struct to provided stream // sends content of the struct to provided stream
@@ -122,7 +122,7 @@ public:
merge( shape_node &Shape ); merge( shape_node &Shape );
// generates renderable version of held non-instanced geometry in specified geometry bank // generates renderable version of held non-instanced geometry in specified geometry bank
void void
create_geometry( geometrybank_handle const &Bank ); create_geometry( gfx::geometrybank_handle const &Bank );
// calculates shape's bounding radius // calculates shape's bounding radius
void void
compute_radius(); compute_radius();
@@ -182,7 +182,7 @@ public:
lighting_data lighting; lighting_data lighting;
// geometry data // geometry data
glm::dvec3 origin; // world position of the relative coordinate system origin 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 std::vector<world_vertex> vertices; // world space source data of the geometry
// methods: // methods:
// sends content of the struct to provided stream // sends content of the struct to provided stream
@@ -208,7 +208,7 @@ public:
merge( lines_node &Lines ); merge( lines_node &Lines );
// generates renderable version of held non-instanced geometry in specified geometry bank // generates renderable version of held non-instanced geometry in specified geometry bank
void void
create_geometry( geometrybank_handle const &Bank ); create_geometry( gfx::geometrybank_handle const &Bank );
// calculates shape's bounding radius // calculates shape's bounding radius
void void
compute_radius(); compute_radius();

View File

@@ -460,7 +460,7 @@ state_manager::deserialize_node( cParser &Input, scene::scratch_data &Scratchpad
auto *sound { deserialize_sound( Input, Scratchpad, nodedata ) }; auto *sound { deserialize_sound( Input, Scratchpad, nodedata ) };
if( false == simulation::Sounds.insert( sound ) ) { if( false == simulation::Sounds.insert( sound ) ) {
ErrorLog( "Bad scenario: sound node with duplicate name \"" + sound->m_name + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" ); 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 ); simulation::Region->insert_sound( sound, Scratchpad );
} }
@@ -830,7 +830,11 @@ state_manager::deserialize_dynamic( cParser &Input, scene::scratch_data &Scratch
return vehicle; return vehicle;
} }
#ifdef EU07_USE_OLD_SOUNDCODE
TTextSound * TTextSound *
#else
sound_source *
#endif
state_manager::deserialize_sound( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ) { state_manager::deserialize_sound( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ) {
glm::dvec3 location; glm::dvec3 location;
@@ -842,9 +846,16 @@ state_manager::deserialize_sound( cParser &Input, scene::scratch_data &Scratchpa
// adjust location // adjust location
location = transform( location, Scratchpad ); location = transform( location, Scratchpad );
#ifdef EU07_USE_OLD_SOUNDCODE
auto const soundname { Input.getToken<std::string>() }; auto const soundname { Input.getToken<std::string>() };
auto *sound = new TTextSound( soundname, Nodedata.range_max, location.x, location.y, location.z, false, false, Nodedata.range_min ); auto *sound = new TTextSound( soundname, Nodedata.range_max, location.x, location.y, location.z, false, false, Nodedata.range_min );
sound->name( Nodedata.name ); sound->name( Nodedata.name );
#else
auto *sound = new sound_source( sound_placement::external, Nodedata.range_max );
sound->offset( location );
sound->name( Nodedata.name );
sound->deserialize( Input.getToken<std::string>(), sound_type::single );
#endif
skip_until( Input, "endsound" ); skip_until( Input, "endsound" );

View File

@@ -17,7 +17,7 @@ http://mozilla.org/MPL/2.0/.
#include "track.h" #include "track.h"
#include "traction.h" #include "traction.h"
#include "tractionpower.h" #include "tractionpower.h"
#include "realsound.h" #include "sound.h"
#include "animmodel.h" #include "animmodel.h"
#include "dynobj.h" #include "dynobj.h"
#include "driver.h" #include "driver.h"
@@ -64,7 +64,11 @@ private:
TEventLauncher * deserialize_eventlauncher( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ); 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 ); 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 ); TDynamicObject * deserialize_dynamic( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata );
#ifdef EU07_USE_OLD_SOUNDCODE
TTextSound * deserialize_sound( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ); TTextSound * deserialize_sound( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata );
#else
sound_source * deserialize_sound( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata );
#endif
// skips content of stream until specified token // skips content of stream until specified token
void skip_until( cParser &Input, std::string const &Token ); void skip_until( cParser &Input, std::string const &Token );
// transforms provided location by specifed rotation and offset // transforms provided location by specifed rotation and offset

360
sound.cpp Normal file
View File

@@ -0,0 +1,360 @@
/*
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 "sound.h"
#include "parser.h"
#include "globals.h"
#include "world.h"
#include "train.h"
// constructors
sound_source::sound_source( sound_placement const Placement, float const Range ) :
m_placement( Placement ),
m_range( Range )
{}
// destructor
sound_source::~sound_source() {
audio::renderer.erase( this );
}
// restores state of the class from provided data stream
sound_source &
sound_source::deserialize( std::string const &Input, sound_type const Legacytype, int const Legacyparameters ) {
return deserialize( cParser{ Input }, Legacytype, Legacyparameters );
}
sound_source &
sound_source::deserialize( cParser &Input, sound_type const Legacytype, int const Legacyparameters ) {
// TODO: implement block type config parsing
switch( Legacytype ) {
case sound_type::single: {
// single sample only
m_soundmain.buffer = audio::renderer.fetch_buffer( Input.getToken<std::string>( true, "\n\r\t ,;" ) );
break;
}
case sound_type::multipart: {
// three samples: start, middle, stop
m_soundbegin.buffer = audio::renderer.fetch_buffer( Input.getToken<std::string>( true, "\n\r\t ,;" ) );
m_soundmain.buffer = audio::renderer.fetch_buffer( Input.getToken<std::string>( true, "\n\r\t ,;" ) );
m_soundend.buffer = audio::renderer.fetch_buffer( Input.getToken<std::string>( true, "\n\r\t ,;" ) );
break;
}
default: {
break;
}
}
if( Legacyparameters & sound_parameters::range ) {
Input.getTokens( 1, false );
Input >> m_range;
}
if( Legacyparameters & sound_parameters::amplitude ) {
Input.getTokens( 2, false );
Input
>> m_amplitudefactor
>> m_amplitudeoffset;
}
if( Legacyparameters & sound_parameters::frequency ) {
Input.getTokens( 2, false );
Input
>> m_frequencyfactor
>> m_frequencyoffset;
}
return *this;
}
// issues contextual play commands for the audio renderer
void
sound_source::play( int const Flags ) {
if( ( false == Global::bSoundEnabled )
|| ( true == empty() ) ) {
// if the sound is disabled altogether or nothing can be emitted from this source, no point wasting time
return;
}
if( m_range > 0 ) {
auto const cutoffrange{ (
( m_soundbegin.buffer != null_handle ) && ( Flags & sound_flags::looping ) ?
m_range * 10 : // larger margin to let the startup sample finish playing at safe distance
m_range * 5 ) };
if( glm::length2( location() - glm::dvec3{ Global::pCameraPosition } ) > std::min( 2750.f * 2750.f, cutoffrange * cutoffrange ) ) {
// drop sounds from beyond sensible and/or audible range
return;
}
}
// initialize emitter-specific pitch variation if it wasn't yet set
if( m_pitchvariation == 0.f ) {
m_pitchvariation = 0.01f * static_cast<float>( Random( 95, 105 ) );
}
m_flags = Flags;
if( false == is_playing() ) {
// dispatch appropriate sound
// TODO: support for parameter-driven sound table
if( m_soundbegin.buffer != null_handle ) {
std::vector<audio::buffer_handle> bufferlist { m_soundbegin.buffer, m_soundmain.buffer };
insert( std::begin( bufferlist ), std::end( bufferlist ) );
}
else {
insert( m_soundmain.buffer );
}
}
else {
if( ( m_soundbegin.buffer == null_handle )
&& ( ( m_flags & ( sound_flags::exclusive | sound_flags::looping ) ) == 0 ) ) {
// for single part non-looping samples we allow spawning multiple instances, if not prevented by set flags
insert( m_soundmain.buffer );
}
}
}
// stops currently active play commands controlled by this emitter
void
sound_source::stop() {
if( false == is_playing() ) { return; }
m_stop = true;
if( ( m_soundend.buffer != null_handle )
&& ( m_soundend.buffer != m_soundmain.buffer ) ) { // end == main can happen in malformed legacy cases
// spawn potentially defined sound end sample, if the emitter is currently active
insert( m_soundend.buffer );
}
}
// adjusts parameters of provided implementation-side sound source
void
sound_source::update( audio::openal_source &Source ) {
if( true == Source.is_playing ) {
// kill the sound if requested
if( true == m_stop ) {
Source.stop();
update_counter( Source.buffers[ Source.buffer_index ], -1 );
if( false == is_playing() ) {
m_stop = false;
}
return;
}
if( m_soundbegin.buffer != null_handle ) {
// potentially a multipart sound
// detect the moment when the sound moves from startup sample to the main
if( ( false == Source.is_looping )
&& ( Source.buffers[ Source.buffer_index ] == m_soundmain.buffer ) ) {
// when it happens update active sample flags, and activate the looping
Source.loop( true );
--( m_soundbegin.playing );
++( m_soundmain.playing );
}
}
// check and update if needed current sound properties
update_location();
update_placement_gain();
Source.sync_with( m_properties );
if( false == Source.is_synced ) {
// if the sync went wrong we let the renderer kill its part of the emitter, and update our playcounter(s) to match
update_counter( Source.buffers[ Source.buffer_index ], -1 );
}
}
else {
// if the emitter isn't playing it's either done or wasn't yet started
// we can determine this from number of processed buffers
if( Source.buffer_index != Source.buffers.size() ) {
auto const buffer { Source.buffers[ Source.buffer_index ] };
// emitter initialization
if( ( buffer == m_soundmain.buffer )
&& ( true == TestFlag( m_flags, sound_flags::looping ) ) ) {
// main sample can be optionally set to loop
Source.loop( true );
}
Source.range( m_range );
Source.pitch( m_pitchvariation );
update_location();
update_placement_gain();
Source.sync_with( m_properties );
if( true == Source.is_synced ) {
// all set, start playback
Source.play();
}
else {
// if the initial sync went wrong we skip the activation so the renderer can clean the emitter on its end
update_counter( buffer, -1 );
}
}
else {
auto const buffer { Source.buffers[ Source.buffer_index - 1 ] };
update_counter( buffer, -1 );
}
}
}
// sets base volume of the emiter to specified value
sound_source &
sound_source::gain( float const Gain ) {
m_properties.base_gain = clamp( Gain, 0.f, 2.f );
return *this;
}
// returns current base volume of the emitter
float
sound_source::gain() const {
return m_properties.base_gain;
}
// sets base pitch of the emitter to specified value
sound_source &
sound_source::pitch( float const Pitch ) {
m_properties.base_pitch = clamp( Pitch, 0.1f, 10.f );
return *this;
}
bool
sound_source::empty() const {
// NOTE: we test only the main sound, won't bother playing potential bookends if this is missing
// TODO: take into account presence of sample table, for combined sounds
return ( m_soundmain.buffer == null_handle );
}
// returns true if the source is emitting any sound
bool
sound_source::is_playing( bool const Includesoundends ) const {
return ( ( m_soundbegin.playing + m_soundmain.playing ) > 0 );
}
// returns location of the sound source in simulation region space
glm::dvec3 const
sound_source::location() const {
if( m_owner == nullptr ) {
// if emitter isn't attached to any vehicle the offset variable defines location in region space
return { m_offset };
}
// otherwise combine offset with the location of the carrier
return {
m_owner->GetPosition()
+ m_owner->VectorLeft() * m_offset.x
+ m_owner->VectorUp() * m_offset.y
+ m_owner->VectorFront() * m_offset.z };
}
void
sound_source::update_counter( audio::buffer_handle const Buffer, int const Value ) {
if( Buffer == m_soundbegin.buffer ) { m_soundbegin.playing += Value; }
// TODO: take ito accound sample table for combined sounds
else if( Buffer == m_soundmain.buffer ) { m_soundmain.playing += Value; }
else if( Buffer == m_soundend.buffer ) { m_soundend.playing += Value; }
}
float const EU07_SOUNDGAIN_LOW { 0.2f };
float const EU07_SOUNDGAIN_MEDIUM { 0.65f };
float const EU07_SOUNDGAIN_FULL { 1.f };
void
sound_source::update_location() {
m_properties.location = location();
}
bool
sound_source::update_placement_gain() {
// NOTE, HACK: current cab id can vary from -1 to +1
// we use this as modifier to force re-calculations when moving between compartments
int const activecab = (
FreeFlyModeFlag ?
0 :
( Global::pWorld->train() ?
Global::pWorld->train()->Dynamic()->MoverParameters->ActiveCab :
0 ) );
// location-based gain factor:
std::uintptr_t placementstamp = reinterpret_cast<std::uintptr_t>( (
FreeFlyModeFlag ?
nullptr :
( Global::pWorld->train() ?
Global::pWorld->train()->Dynamic() :
nullptr ) ) )
+ activecab;
if( placementstamp == m_properties.placement_stamp ) { return false; }
// listener location has changed, calculate new location-based gain factor
switch( m_placement ) {
case sound_placement::general: {
m_properties.placement_gain = EU07_SOUNDGAIN_FULL;
break;
}
case sound_placement::external: {
m_properties.placement_gain = (
placementstamp == 0 ?
EU07_SOUNDGAIN_FULL : // listener outside
EU07_SOUNDGAIN_LOW ); // listener in a vehicle
break;
}
case sound_placement::internal: {
m_properties.placement_gain = (
placementstamp == 0 ?
EU07_SOUNDGAIN_LOW : // listener outside
( Global::pWorld->train()->Dynamic() != m_owner ?
EU07_SOUNDGAIN_LOW : // in another vehicle
( activecab == 0 ?
EU07_SOUNDGAIN_LOW : // listener in the engine compartment
EU07_SOUNDGAIN_FULL ) ) ); // listener in the cab of the same vehicle
break;
}
case sound_placement::engine: {
m_properties.placement_gain = (
placementstamp == 0 ?
EU07_SOUNDGAIN_MEDIUM : // listener outside
( Global::pWorld->train()->Dynamic() != m_owner ?
EU07_SOUNDGAIN_LOW : // in another vehicle
( activecab == 0 ?
EU07_SOUNDGAIN_FULL : // listener in the engine compartment
EU07_SOUNDGAIN_LOW ) ) ); // listener in another compartment of the same vehicle
break;
}
default: {
// shouldn't ever land here, but, eh
m_properties.placement_gain = EU07_SOUNDGAIN_FULL;
break;
}
}
m_properties.placement_stamp = placementstamp;
return true;
}
void
sound_source::insert( audio::buffer_handle Buffer ) {
std::vector<audio::buffer_handle> buffers { Buffer };
return insert( std::begin( buffers ), std::end( buffers ) );
}
//---------------------------------------------------------------------------

166
sound.h Normal file
View File

@@ -0,0 +1,166 @@
/*
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 "audiorenderer.h"
#include "classes.h"
#include "names.h"
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
};
enum sound_parameters {
range = 0x1,
amplitude = 0x2,
frequency = 0x4
};
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
};
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
};
// 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:
// constructors
sound_source( sound_placement const Placement, float const Range = 50.f );
// destructor
~sound_source();
// 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();
// 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 location of the sound source in simulation region space
glm::dvec3 const
location() const;
// 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 { null_handle };
int playing { 0 }; // number of currently active sample instances
};
// methods
void
update_counter( audio::buffer_handle const Buffer, int const Value );
void
update_location();
// potentially updates area-based gain factor of the source. returns: true if location has changed
bool
update_placement_gain();
void
insert( audio::buffer_handle Buffer );
template <class Iterator_>
void
insert( Iterator_ First, Iterator_ Last ) {
audio::renderer.insert( this, First, Last );
update_counter( *First, 1 );
}
// 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
sound_data m_soundmain; // main sound emitted by the source
sound_data m_soundbegin; // optional, sound emitted before the main sound
sound_data m_soundend; // optional, sound emitted after the main sound
// TODO: table of samples with associated values, activated when controlling variable matches the value
};
// 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> {
};
//---------------------------------------------------------------------------

25
sun.cpp
View File

@@ -14,10 +14,6 @@ cSun::cSun() {
setLocation( 19.00f, 52.00f ); // default location roughly in centre of Poland setLocation( 19.00f, 52.00f ); // default location roughly in centre of Poland
m_observer.press = 1013.0; // surface pressure, millibars m_observer.press = 1013.0; // surface pressure, millibars
m_observer.temp = 15.0; // ambient dry-bulb temperature, degrees C m_observer.temp = 15.0; // ambient dry-bulb temperature, degrees C
TIME_ZONE_INFORMATION timezoneinfo; // TODO: timezone dependant on geographic location
::GetTimeZoneInformation( &timezoneinfo );
m_observer.timezone = -timezoneinfo.Bias / 60.0f;
} }
cSun::~cSun() { gluDeleteQuadric( sunsphere ); } cSun::~cSun() { gluDeleteQuadric( sunsphere ); }
@@ -27,6 +23,27 @@ cSun::init() {
sunsphere = gluNewQuadric(); sunsphere = gluNewQuadric();
gluQuadricNormals( sunsphere, GLU_SMOOTH ); gluQuadricNormals( sunsphere, GLU_SMOOTH );
// calculate and set timezone for the current date of the simulation
// TODO: timezone dependant on geographic location
TIME_ZONE_INFORMATION timezoneinfo;
::GetTimeZoneInformation( &timezoneinfo );
// account for potential daylight/normal time bias
// NOTE: we're using xp-compatible time zone information and current year, instead of 'historically proper' values
auto zonebias { timezoneinfo.Bias };
auto const year { simulation::Time.data().wYear };
auto const yearday { simulation::Time.year_day() };
if( yearday < simulation::Time.year_day( timezoneinfo.DaylightDate.wDay, timezoneinfo.DaylightDate.wMonth, year ) ) {
zonebias += timezoneinfo.StandardBias;
}
else if( yearday < simulation::Time.year_day( timezoneinfo.StandardDate.wDay, timezoneinfo.StandardDate.wMonth, year ) ) {
zonebias += timezoneinfo.DaylightBias;
}
else {
zonebias += timezoneinfo.StandardBias;
}
m_observer.timezone = -zonebias / 60.0f;
} }
void void

View File

@@ -1,5 +1,5 @@
#pragma once #pragma once
#define VERSION_MAJOR 17 #define VERSION_MAJOR 17
#define VERSION_MINOR 1112 #define VERSION_MINOR 1130
#define VERSION_REVISION 0 #define VERSION_REVISION 0