mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-07-22 20:59:19 +02:00
audio subsystem: completed base functionality of the renderer, external and engine sounds moved from cab to vehicle, minor fixes to various sound-related methods
This commit is contained in:
52
Button.cpp
52
Button.cpp
@@ -13,6 +13,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "Model3d.h"
|
||||
#include "Console.h"
|
||||
#include "logs.h"
|
||||
#include "renderer.h"
|
||||
|
||||
void TButton::Clear(int i)
|
||||
{
|
||||
@@ -24,8 +25,8 @@ void TButton::Clear(int i)
|
||||
Update(); // kasowanie bitu Feedback, o ile jakiś ustawiony
|
||||
};
|
||||
|
||||
void TButton::Init(std::string const &asName, TModel3d *pModel, bool bNewOn)
|
||||
{
|
||||
void TButton::Init( std::string const &asName, TModel3d *pModel, bool bNewOn ) {
|
||||
|
||||
if( pModel == nullptr ) { return; }
|
||||
|
||||
pModelOn = pModel->GetFromName( asName + "_on" );
|
||||
@@ -34,7 +35,7 @@ void TButton::Init(std::string const &asName, TModel3d *pModel, bool bNewOn)
|
||||
Update();
|
||||
};
|
||||
|
||||
void TButton::Load(cParser &Parser, TModel3d *pModel1, TModel3d *pModel2) {
|
||||
void TButton::Load( cParser &Parser, TDynamicObject const *Owner, TModel3d *pModel1, TModel3d *pModel2 ) {
|
||||
|
||||
std::string submodelname;
|
||||
|
||||
@@ -52,25 +53,32 @@ void TButton::Load(cParser &Parser, TModel3d *pModel1, TModel3d *pModel2) {
|
||||
}
|
||||
}
|
||||
|
||||
// bind defined sounds with the button owner
|
||||
m_soundfxincrease.owner( Owner );
|
||||
m_soundfxdecrease.owner( Owner );
|
||||
|
||||
if( pModel1 ) {
|
||||
// poszukiwanie submodeli w modelu
|
||||
Init( submodelname, pModel1, false );
|
||||
if( ( pModelOn != nullptr ) || ( pModelOff != nullptr ) ) {
|
||||
// we got our models, bail out
|
||||
return;
|
||||
}
|
||||
}
|
||||
if( pModel2 ) {
|
||||
if( ( pModelOn == nullptr )
|
||||
&& ( pModelOff == nullptr )
|
||||
&& ( pModel2 != nullptr ) ) {
|
||||
// poszukiwanie submodeli w modelu
|
||||
Init( submodelname, pModel2, false );
|
||||
if( ( pModelOn != nullptr ) || ( pModelOff != nullptr ) ) {
|
||||
// we got our models, bail out
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if( ( pModelOn == nullptr )
|
||||
&& ( pModelOff == nullptr ) ) {
|
||||
// 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
|
||||
TButton::Load_mapping( cParser &Input ) {
|
||||
@@ -85,6 +93,22 @@ TButton::Load_mapping( cParser &Input ) {
|
||||
return true; // return value marks a key: value pair was extracted, nothing about whether it's recognized
|
||||
}
|
||||
|
||||
// returns offset of submodel associated with the button from the model centre
|
||||
glm::vec3
|
||||
TButton::model_offset() const {
|
||||
|
||||
auto const
|
||||
submodel { (
|
||||
pModelOn ? pModelOn :
|
||||
pModelOff ? pModelOff :
|
||||
nullptr ) };
|
||||
|
||||
return (
|
||||
submodel != nullptr ?
|
||||
submodel->offset( 1.f ) :
|
||||
glm::vec3() );
|
||||
}
|
||||
|
||||
void
|
||||
TButton::Turn( bool const State ) {
|
||||
|
||||
|
||||
45
Button.h
45
Button.h
@@ -12,27 +12,11 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "Classes.h"
|
||||
#include "sound.h"
|
||||
|
||||
class TButton
|
||||
{ // animacja dwustanowa, włącza jeden z dwóch submodeli (jednego
|
||||
// z nich może nie być)
|
||||
private:
|
||||
TSubModel
|
||||
*pModelOn { nullptr },
|
||||
*pModelOff { nullptr }; // submodel dla stanu załączonego i wyłączonego
|
||||
bool m_state { false };
|
||||
bool const *bData { nullptr };
|
||||
int iFeedbackBit { 0 }; // Ra: bit informacji zwrotnej, do wyprowadzenia na pulpit
|
||||
sound_source m_soundfxincrease; // sound associated with increasing control's value
|
||||
sound_source m_soundfxdecrease; // sound associated with decreasing control's value
|
||||
// methods
|
||||
// imports member data pair from the config file
|
||||
bool
|
||||
Load_mapping( cParser &Input );
|
||||
// plays the sound associated with current state
|
||||
void
|
||||
play();
|
||||
// animacja dwustanowa, włącza jeden z dwóch submodeli (jednego z nich może nie być)
|
||||
class TButton {
|
||||
|
||||
public:
|
||||
// methods
|
||||
TButton() = default;
|
||||
void Clear(int const i = -1);
|
||||
inline void FeedbackBitSet( int const i ) {
|
||||
@@ -44,8 +28,29 @@ class TButton
|
||||
|| ( pModelOff != nullptr ) ); }
|
||||
void Update();
|
||||
void Init( std::string const &asName, TModel3d *pModel, bool bNewOn = false );
|
||||
void Load(cParser &Parser, TModel3d *pModel1, TModel3d *pModel2 = NULL);
|
||||
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:
|
||||
// methods
|
||||
// imports member data pair from the config file
|
||||
bool
|
||||
Load_mapping( cParser &Input );
|
||||
// plays the sound associated with current state
|
||||
void
|
||||
play();
|
||||
|
||||
// members
|
||||
TSubModel
|
||||
*pModelOn { nullptr },
|
||||
*pModelOff { nullptr }; // submodel dla stanu załączonego i wyłączonego
|
||||
bool m_state { false };
|
||||
bool const *bData { nullptr };
|
||||
int iFeedbackBit { 0 }; // Ra: bit informacji zwrotnej, do wyprowadzenia na pulpit
|
||||
sound_source m_soundfxincrease { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE }; // sound associated with increasing control's value
|
||||
sound_source m_soundfxdecrease { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE }; // sound associated with decreasing control's value
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
41
Driver.cpp
41
Driver.cpp
@@ -998,8 +998,11 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN
|
||||
if (go == cm_Unknown) // jeśli nie było komendy wcześniej
|
||||
go = cm_Ready; // gotów do odjazdu z W4 (semafor może
|
||||
// zatrzymać)
|
||||
if (false == tsGuardSignal->empty()) // jeśli mamy głos kierownika, to odegrać
|
||||
if( ( tsGuardSignal != nullptr )
|
||||
&& ( false == tsGuardSignal->empty() ) ); {
|
||||
// jeśli mamy głos kierownika, to odegrać
|
||||
iDrivigFlags |= moveGuardSignal;
|
||||
}
|
||||
continue; // nie analizować prędkości
|
||||
} // koniec startu z zatrzymania
|
||||
} // koniec obsługi początkowych stacji
|
||||
@@ -2577,6 +2580,10 @@ bool TController::IncSpeed()
|
||||
if (tsGuardSignal->GetStatus() & DSBSTATUS_PLAYING) // jeśli gada, to nie jedziemy
|
||||
return false;
|
||||
#else
|
||||
if( ( tsGuardSignal != nullptr )
|
||||
&& ( true == tsGuardSignal->is_playing() ) ) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
bool OK = true;
|
||||
if( ( iDrivigFlags & moveDoorOpened )
|
||||
@@ -2590,7 +2597,7 @@ bool TController::IncSpeed()
|
||||
}
|
||||
if( true == mvOccupied->DepartureSignal ) {
|
||||
// shut off departure warning
|
||||
mvOccupied->DepartureSignal = false;
|
||||
mvOccupied->signal_departure( false );
|
||||
}
|
||||
if (mvControlling->SlippingWheels)
|
||||
return false; // jak poślizg, to nie przyspieszamy
|
||||
@@ -2984,7 +2991,7 @@ void TController::Doors(bool what)
|
||||
if( ( true == mvOccupied->DoorClosureWarning )
|
||||
&& ( false == mvOccupied->DepartureSignal )
|
||||
&& ( true == TestFlag( iDrivigFlags, moveDoorOpened ) ) ) {
|
||||
mvOccupied->DepartureSignal = true; // załącenie bzyczka
|
||||
mvOccupied->signal_departure( true ); // załącenie bzyczka
|
||||
fActionTime = -3.0 - 0.1 * Random( 10 ); // 3-4 second wait
|
||||
}
|
||||
if( fActionTime > -0.5 ) {
|
||||
@@ -3094,6 +3101,11 @@ bool TController::PutCommand( std::string NewCommand, double NewValue1, double N
|
||||
pVehicle->GetPosition().x, pVehicle->GetPosition().y, pVehicle->GetPosition().z,
|
||||
false);
|
||||
#else
|
||||
tsGuardSignal = new sound_source( sound_placement::external );
|
||||
tsGuardSignal->deserialize( NewCommand, sound_type::single );
|
||||
tsGuardSignal->owner( pVehicle );
|
||||
// place virtual conductor some distance away
|
||||
tsGuardSignal->offset( { pVehicle->MoverParameters->Dim.W * -0.75f, 1.7f, fLength * -0.25f } );
|
||||
#endif
|
||||
iGuardRadio = 0; // nie przez radio
|
||||
}
|
||||
@@ -3109,6 +3121,12 @@ bool TController::PutCommand( std::string NewCommand, double NewValue1, double N
|
||||
pVehicle->GetPosition().x, pVehicle->GetPosition().y, pVehicle->GetPosition().z,
|
||||
false);
|
||||
#else
|
||||
tsGuardSignal = new sound_source( sound_placement::external );
|
||||
tsGuardSignal->deserialize( NewCommand, sound_type::single );
|
||||
tsGuardSignal->owner( pVehicle );
|
||||
// command will be transmitted by radio
|
||||
// TODO: put the exact location in the proper cab
|
||||
tsGuardSignal->offset( { 0.f, 1.f, pVehicle->MoverParameters->Dim.L * 0.75f } );
|
||||
#endif
|
||||
iGuardRadio = iRadioChannel;
|
||||
}
|
||||
@@ -4475,18 +4493,19 @@ TController::UpdateSituation(double dt) {
|
||||
// jeśli można jechać, to odpalić dźwięk kierownika oraz zamknąć drzwi w
|
||||
// składzie, jeśli nie mamy czekać na sygnał też trzeba odpalić
|
||||
if (iDrivigFlags & moveGuardSignal)
|
||||
{ // komunikat od kierownika tu, bo musi być wolna droga i odczekany czas
|
||||
// stania
|
||||
{ // komunikat od kierownika tu, bo musi być wolna droga i odczekany czas stania
|
||||
iDrivigFlags &= ~moveGuardSignal; // tylko raz nadać
|
||||
|
||||
if( iDrivigFlags & moveDoorOpened ) // jeśli drzwi otwarte
|
||||
if( !mvOccupied
|
||||
->DoorOpenCtrl ) // jeśli drzwi niesterowane przez maszynistę
|
||||
if( ( iDrivigFlags & moveDoorOpened )
|
||||
&& ( false == mvOccupied->DoorOpenCtrl ) ) {
|
||||
// jeśli drzwi otwarte, niesterowane przez maszynistę
|
||||
Doors( false ); // a EZT zamknie dopiero po odegraniu komunikatu kierownika
|
||||
|
||||
}
|
||||
if( tsGuardSignal != nullptr ) {
|
||||
#ifdef EU07_USE_OLD_SOUNDCODE
|
||||
tsGuardSignal->Stop();
|
||||
#else
|
||||
tsGuardSignal->stop();
|
||||
#endif
|
||||
// w zasadzie to powinien mieć flagę, czy jest dźwiękiem radiowym, czy
|
||||
// bezpośrednim
|
||||
@@ -4499,6 +4518,7 @@ TController::UpdateSituation(double dt) {
|
||||
#ifdef EU07_USE_OLD_SOUNDCODE
|
||||
tsGuardSignal->Play( 1.0, 0, !FreeFlyModeFlag, pVehicle->GetPosition() ); // dla true jest głośniej
|
||||
#else
|
||||
tsGuardSignal->play( sound_flags::exclusive );
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
@@ -4511,11 +4531,14 @@ TController::UpdateSituation(double dt) {
|
||||
#ifdef EU07_USE_OLD_SOUNDCODE
|
||||
tsGuardSignal->Play( 1.0, 0, true, pVehicle->GetPosition() ); // dźwięk niby przez radio
|
||||
#else
|
||||
// TODO: proper system for sending/receiving radio messages
|
||||
tsGuardSignal->play( sound_flags::exclusive );
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if( mvOccupied->V == 0.0 ) {
|
||||
// Ra 2014-03: jesli skład stoi, to działa na niego składowa styczna grawitacji
|
||||
AbsAccS = fAccGravity;
|
||||
|
||||
1806
DynObj.cpp
1806
DynObj.cpp
File diff suppressed because it is too large
Load Diff
129
DynObj.h
129
DynObj.h
@@ -259,11 +259,32 @@ private:
|
||||
// Ra: koneic animacji do ogarnięcia
|
||||
|
||||
private:
|
||||
void ABuLittleUpdate(double ObjSqrDist);
|
||||
bool btnOn; // ABu: czy byly uzywane buttony, jesli tak, to po renderingu wylacz
|
||||
// bo ten sam model moze byc jeszcze wykorzystany przez inny obiekt!
|
||||
double ComputeRadius( Math3D::vector3 p1, Math3D::vector3 p2, Math3D::vector3 p3, Math3D::vector3 p4);
|
||||
// types
|
||||
struct coupler_sounds {
|
||||
sound_source dsbCouplerAttach { sound_placement::external }; // moved from cab
|
||||
sound_source dsbCouplerDetach { sound_placement::external }; // moved from cab
|
||||
sound_source dsbCouplerStretch { sound_placement::external }; // moved from cab
|
||||
sound_source dsbBufferClamp { sound_placement::external }; // moved from cab
|
||||
};
|
||||
|
||||
struct pantograph_sounds {
|
||||
sound_source sPantUp { sound_placement::external };
|
||||
sound_source sPantDown { sound_placement::external };
|
||||
};
|
||||
|
||||
struct door_sounds {
|
||||
sound_source rsDoorOpen{ sound_placement::general }; // 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 btCoupler2;
|
||||
TAirCoupler btCPneumatic1; // sprzegi powietrzne //yB - zmienione z Button na AirCoupler - krzyzyki
|
||||
@@ -303,44 +324,55 @@ private:
|
||||
double dRailLength;
|
||||
double dRailPosition[MaxAxles]; // licznik pozycji osi w/m szyny
|
||||
double dWheelsPosition[MaxAxles]; // pozycja osi w/m srodka pojazdu
|
||||
sound_source rsStukot[MaxAxles]; // dzwieki poszczegolnych osi //McZapkie-270202
|
||||
sound_source rsSilnik; // McZapkie-010302 - silnik
|
||||
sound_source rsWentylator; // McZapkie-030302
|
||||
sound_source rsPisk; // McZapkie-260302
|
||||
sound_source rsDerailment; // McZapkie-051202
|
||||
sound_source rsPrzekladnia;
|
||||
sound_source sHorn1;
|
||||
sound_source sHorn2;
|
||||
sound_source sCompressor; // NBMX wrzesien 2003
|
||||
sound_source sConverter;
|
||||
sound_source sSmallCompressor;
|
||||
sound_source sDepartureSignal;
|
||||
sound_source sTurbo;
|
||||
sound_source sSand;
|
||||
sound_source sReleaser;
|
||||
|
||||
// Winger 010304
|
||||
sound_source sPantUp;
|
||||
sound_source sPantDown;
|
||||
sound_source rsDoorOpen; // Ra: przeniesione z kabiny
|
||||
sound_source rsDoorClose;
|
||||
std::vector<sound_source> rsStukot; // dzwieki poszczegolnych osi //McZapkie-270202
|
||||
// engine sounds
|
||||
sound_source dsbDieselIgnition { sound_placement::engine }; // moved from cab
|
||||
sound_source rsSilnik { sound_placement::engine };
|
||||
sound_source dsbRelay { sound_placement::engine };
|
||||
sound_source dsbWejscie_na_bezoporow { sound_placement::engine }; // moved from cab
|
||||
sound_source dsbWejscie_na_drugi_uklad { sound_placement::engine }; // moved from cab
|
||||
sound_source rsPrzekladnia { sound_placement::engine };
|
||||
sound_source rsEngageSlippery { sound_placement::engine }; // moved from cab
|
||||
sound_source rsDieselInc { sound_placement::engine }; // youBy
|
||||
sound_source sTurbo { sound_placement::engine };
|
||||
sound_source rsWentylator { sound_placement::engine }; // McZapkie-030302
|
||||
sound_source sConverter { sound_placement::engine };
|
||||
sound_source sCompressor { sound_placement::engine }; // NBMX wrzesien 2003
|
||||
sound_source sSmallCompressor { sound_placement::engine };
|
||||
// braking sounds
|
||||
sound_source dsbPneumaticRelay { sound_placement::external };
|
||||
sound_source rsUnbrake { sound_placement::external }; // yB - odglos luzowania
|
||||
sound_source sReleaser { sound_placement::external };
|
||||
sound_source rsSlippery { sound_placement::external, EU07_SOUND_BRAKINGCUTOFFRANGE }; // moved from cab
|
||||
sound_source sSand { sound_placement::external };
|
||||
sound_source rsBrake { sound_placement::external, EU07_SOUND_BRAKINGCUTOFFRANGE }; // moved from cab
|
||||
sound_source sBrakeAcc { sound_placement::external };
|
||||
bool bBrakeAcc;
|
||||
sound_source rsPisk { sound_placement::external, EU07_SOUND_BRAKINGCUTOFFRANGE }; // McZapkie-260302
|
||||
sound_source rsDerailment { sound_placement::external, 250.f }; // McZapkie-051202
|
||||
// moving part and other external sounds
|
||||
std::array<coupler_sounds, 2> m_couplersounds; // always front and rear
|
||||
std::vector<pantograph_sounds> m_pantographsounds; // typically 2 but can be less (or more?)
|
||||
std::vector<door_sounds> m_doorsounds; // can expect symmetrical arrangement, but don't count on it
|
||||
sound_source sDepartureSignal { sound_placement::general };
|
||||
sound_source sHorn1 { sound_placement::external };
|
||||
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_frq_act;
|
||||
double eng_dfrq;
|
||||
double eng_turbo;
|
||||
void ABuBogies();
|
||||
void ABuModelRoll();
|
||||
Math3D::vector3 modelShake;
|
||||
|
||||
bool renderme; // yB - czy renderowac
|
||||
// TRealSound sBrakeAcc; //dźwięk przyspieszacza
|
||||
sound_source sBrakeAcc;
|
||||
bool bBrakeAcc;
|
||||
sound_source rsUnbrake; // yB - odglos luzowania
|
||||
float ModCamRot;
|
||||
int iInventory[ 2 ] { 0, 0 }; // flagi bitowe posiadanych submodeli (np. świateł)
|
||||
void TurnOff();
|
||||
bool btnOn; // ABu: czy byly uzywane buttony, jesli tak, to po renderingu wylacz
|
||||
// bo ten sam model moze byc jeszcze wykorzystany przez inny obiekt!
|
||||
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:
|
||||
int iHornWarning; // numer syreny do użycia po otrzymaniu sygnału do jazdy
|
||||
@@ -376,10 +408,10 @@ private:
|
||||
void SetPneumatic(bool front, bool red);
|
||||
std::string asName;
|
||||
std::string name() const {
|
||||
return this ? asName : std::string(); };
|
||||
return this ?
|
||||
asName :
|
||||
std::string(); };
|
||||
|
||||
sound_source rsDiesielInc; // youBy
|
||||
sound_source rscurve; // youBy
|
||||
// std::ofstream PneuLogFile; //zapis parametrow pneumatycznych
|
||||
// youBy - dym
|
||||
// TSmoke Smog;
|
||||
@@ -430,13 +462,17 @@ private:
|
||||
inline Math3D::vector3 RearPosition() {
|
||||
return vCoulpler[iDirection]; };
|
||||
inline Math3D::vector3 AxlePositionGet() {
|
||||
return iAxleFirst ? Axle1.pPosition : Axle0.pPosition; };
|
||||
return iAxleFirst ?
|
||||
Axle1.pPosition :
|
||||
Axle0.pPosition; };
|
||||
inline Math3D::vector3 VectorFront() const {
|
||||
return vFront; };
|
||||
inline Math3D::vector3 VectorUp() {
|
||||
inline Math3D::vector3 VectorUp() const {
|
||||
return vUp; };
|
||||
inline Math3D::vector3 VectorLeft() const {
|
||||
return vLeft; };
|
||||
inline double const * Matrix() const {
|
||||
return mMatrix.readArray(); };
|
||||
inline double * Matrix() {
|
||||
return mMatrix.getArray(); };
|
||||
inline double GetVelocity() {
|
||||
@@ -446,7 +482,9 @@ private:
|
||||
inline double GetWidth() const {
|
||||
return MoverParameters->Dim.W; };
|
||||
inline TTrack * GetTrack() {
|
||||
return (iAxleFirst ? Axle1.GetTrack() : Axle0.GetTrack()); };
|
||||
return (iAxleFirst ?
|
||||
Axle1.GetTrack() :
|
||||
Axle0.GetTrack()); };
|
||||
|
||||
// McZapkie-260202
|
||||
void LoadMMediaFile(std::string BaseDir, std::string TypeName, std::string ReplacableSkin);
|
||||
@@ -455,13 +493,22 @@ private:
|
||||
return (Axle1.GetTrack() == MyTrack ? Axle1.GetDirection() : Axle0.GetDirection()); };
|
||||
// zwraca kierunek pojazdu na torze z aktywną osą
|
||||
inline double RaDirectionGet() {
|
||||
return iAxleFirst ? Axle1.GetDirection() : Axle0.GetDirection(); };
|
||||
return iAxleFirst ?
|
||||
Axle1.GetDirection() :
|
||||
Axle0.GetDirection(); };
|
||||
// zwraca przesunięcie wózka względem Point1 toru z aktywną osią
|
||||
inline double RaTranslationGet() {
|
||||
return iAxleFirst ? Axle1.GetTranslation() : Axle0.GetTranslation(); };
|
||||
return iAxleFirst ?
|
||||
Axle1.GetTranslation() :
|
||||
Axle0.GetTranslation(); };
|
||||
// zwraca tor z aktywną osią
|
||||
inline TTrack * RaTrackGet() {
|
||||
return iAxleFirst ? Axle1.GetTrack() : Axle0.GetTrack(); };
|
||||
return iAxleFirst ?
|
||||
Axle1.GetTrack() :
|
||||
Axle0.GetTrack(); };
|
||||
|
||||
void couple( int const Side );
|
||||
int uncouple( int const Side );
|
||||
void CouplersDettach(double MinDist, int MyScanDir);
|
||||
void RadioStop();
|
||||
void Damage(char flag);
|
||||
|
||||
40
Event.cpp
40
Event.cpp
@@ -1022,34 +1022,27 @@ event_manager::CheckQuery() {
|
||||
return false;
|
||||
}
|
||||
case tp_Sound: {
|
||||
#ifdef EU07_USE_OLD_SOUNDCODE
|
||||
if( m_workevent->Params[ 9 ].tsTextSound == nullptr ) {
|
||||
break;
|
||||
}
|
||||
switch( m_workevent->Params[ 0 ].asInt ) {
|
||||
// trzy możliwe przypadki:
|
||||
case 0: {
|
||||
m_workevent->Params[ 9 ].tsTextSound->Stop();
|
||||
m_workevent->Params[ 9 ].tsTextSound->stop();
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
m_workevent->Params[ 9 ].tsTextSound->Play(
|
||||
1,
|
||||
0,
|
||||
true,
|
||||
m_workevent->Params[ 9 ].tsTextSound->vSoundPosition );
|
||||
m_workevent->Params[ 9 ].tsTextSound->play( sound_flags::exclusive );
|
||||
break;
|
||||
}
|
||||
case -1: {
|
||||
m_workevent->Params[ 9 ].tsTextSound->Play(
|
||||
1,
|
||||
DSBPLAY_LOOPING,
|
||||
true,
|
||||
m_workevent->Params[ 9 ].tsTextSound->vSoundPosition );
|
||||
m_workevent->Params[ 9 ].tsTextSound->play( sound_flags::exclusive | sound_flags::looping );
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case tp_Disable:
|
||||
@@ -1574,14 +1567,19 @@ event_manager::InitLaunchers() {
|
||||
}
|
||||
}
|
||||
|
||||
launcher->Event1 = (
|
||||
launcher->asEvent1Name != "none" ?
|
||||
simulation::Events.FindEvent( launcher->asEvent1Name ) :
|
||||
nullptr );
|
||||
launcher->Event2 = (
|
||||
launcher->asEvent2Name != "none" ?
|
||||
simulation::Events.FindEvent( launcher->asEvent2Name ) :
|
||||
nullptr );
|
||||
if( launcher->asEvent1Name != "none" ) {
|
||||
launcher->Event1 = simulation::Events.FindEvent( launcher->asEvent1Name );
|
||||
if( launcher->Event1 == nullptr ) {
|
||||
ErrorLog( "Bad scenario: event launcher \"" + launcher->name() + "\" cannot find event \"" + launcher->asEvent1Name + "\"" );
|
||||
}
|
||||
}
|
||||
|
||||
if( launcher->asEvent2Name != "none" ) {
|
||||
launcher->Event2 = simulation::Events.FindEvent( launcher->asEvent2Name );
|
||||
if( launcher->Event2 == nullptr ) {
|
||||
ErrorLog( "Bad scenario: event launcher \"" + launcher->name() + "\" cannot find event \"" + launcher->asEvent2Name + "\"" );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
49
Gauge.cpp
49
Gauge.cpp
@@ -19,24 +19,23 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "Model3d.h"
|
||||
#include "Timer.h"
|
||||
#include "logs.h"
|
||||
#include "renderer.h"
|
||||
|
||||
void TGauge::Init(TSubModel *NewSubModel, TGaugeType eNewType, double fNewScale, double fNewOffset, double fNewFriction, double fNewValue)
|
||||
{ // ustawienie parametrów animacji submodelu
|
||||
if (NewSubModel)
|
||||
{ // warunek na wszelki wypadek, gdyby się submodel nie
|
||||
// podłączył
|
||||
if (NewSubModel) {
|
||||
// warunek na wszelki wypadek, gdyby się submodel nie podłączył
|
||||
fFriction = fNewFriction;
|
||||
fValue = fNewValue;
|
||||
fOffset = fNewOffset;
|
||||
fScale = fNewScale;
|
||||
SubModel = NewSubModel;
|
||||
eType = eNewType;
|
||||
if (eType == gt_Digital)
|
||||
{
|
||||
if (eType == gt_Digital) {
|
||||
|
||||
TSubModel *sm = SubModel->ChildGet();
|
||||
do
|
||||
{ // pętla po submodelach potomnych i obracanie ich o kąt zależy od
|
||||
// cyfry w (fValue)
|
||||
do {
|
||||
// pętla po submodelach potomnych i obracanie ich o kąt zależy od cyfry w (fValue)
|
||||
if (sm->pName.size())
|
||||
{ // musi mieć niepustą nazwę
|
||||
if (sm->pName[0] >= '0')
|
||||
@@ -48,10 +47,17 @@ void TGauge::Init(TSubModel *NewSubModel, TGaugeType eNewType, double fNewScale,
|
||||
}
|
||||
else // a banan może być z optymalizacją?
|
||||
NewSubModel->WillBeAnimated(); // wyłączenie ignowania jedynkowego transformu
|
||||
// pass submodel location to defined sounds
|
||||
auto const offset { model_offset() };
|
||||
m_soundfxincrease.offset( offset );
|
||||
m_soundfxdecrease.offset( offset );
|
||||
for( auto &soundfxrecord : m_soundfxvalues ) {
|
||||
soundfxrecord.second.offset( offset );
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
bool TGauge::Load(cParser &Parser, TModel3d *md1, TModel3d *md2, double mul) {
|
||||
bool TGauge::Load( cParser &Parser, TDynamicObject const *Owner, TModel3d *md1, TModel3d *md2, double mul ) {
|
||||
|
||||
std::string submodelname, gaugetypename;
|
||||
double scale, offset, friction;
|
||||
@@ -83,10 +89,17 @@ bool TGauge::Load(cParser &Parser, TModel3d *md1, TModel3d *md2, double mul) {
|
||||
}
|
||||
}
|
||||
|
||||
// bind defined sounds with the button owner
|
||||
m_soundfxincrease.owner( Owner );
|
||||
m_soundfxdecrease.owner( Owner );
|
||||
for( auto &soundfxrecord : m_soundfxvalues ) {
|
||||
soundfxrecord.second.owner( Owner );
|
||||
}
|
||||
|
||||
scale *= mul;
|
||||
TSubModel *submodel = md1->GetFromName( submodelname );
|
||||
if( scale == 0.0 ) {
|
||||
ErrorLog( "Scale of 0.0 defined for sub-model \"" + submodelname + "\" in 3d model \"" + md1->NameGet() + "\". Forcing scale of 1.0 to prevent division by 0" );
|
||||
ErrorLog( "Bad model: scale of 0.0 defined for sub-model \"" + submodelname + "\" in 3d model \"" + md1->NameGet() + "\". Forcing scale of 1.0 to prevent division by 0" );
|
||||
scale = 1.0;
|
||||
}
|
||||
if (submodel) // jeśli nie znaleziony
|
||||
@@ -94,7 +107,7 @@ bool TGauge::Load(cParser &Parser, TModel3d *md1, TModel3d *md2, double mul) {
|
||||
else if (md2) // a jest podany drugi model (np. zewnętrzny)
|
||||
submodel = md2->GetFromName(submodelname); // to może tam będzie, co za różnica gdzie
|
||||
if( submodel == nullptr ) {
|
||||
ErrorLog( "Failed to locate sub-model \"" + submodelname + "\" in 3d model \"" + md1->NameGet() + "\"" );
|
||||
ErrorLog( "Bad model: failed to locate sub-model \"" + submodelname + "\" in 3d model \"" + md1->NameGet() + "\"" );
|
||||
}
|
||||
|
||||
std::map<std::string, TGaugeType> gaugetypes {
|
||||
@@ -132,7 +145,7 @@ TGauge::Load_mapping( cParser &Input ) {
|
||||
if( indexstart != std::string::npos ) {
|
||||
m_soundfxvalues.emplace(
|
||||
std::stoi( key.substr( indexstart, indexend - indexstart ) ),
|
||||
sound_source().deserialize( Input, sound_type::single ) );
|
||||
sound_source( sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE ).deserialize( Input, sound_type::single ) );
|
||||
}
|
||||
}
|
||||
return true; // return value marks a key: value pair was extracted, nothing about whether it's recognized
|
||||
@@ -284,8 +297,6 @@ void TGauge::Update() {
|
||||
}
|
||||
};
|
||||
|
||||
void TGauge::Render(){};
|
||||
|
||||
void TGauge::AssignFloat(float *fValue)
|
||||
{
|
||||
cDataType = 'f';
|
||||
@@ -317,4 +328,14 @@ void TGauge::UpdateValue()
|
||||
}
|
||||
};
|
||||
|
||||
// returns offset of submodel associated with the button from the model centre
|
||||
glm::vec3
|
||||
TGauge::model_offset() const {
|
||||
|
||||
return (
|
||||
SubModel != nullptr ?
|
||||
SubModel->offset( 1.f ) :
|
||||
glm::vec3() );
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
50
Gauge.h
50
Gauge.h
@@ -24,6 +24,30 @@ enum TGaugeType {
|
||||
// animowany wskaźnik, mogący przyjmować wiele stanów pośrednich
|
||||
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:
|
||||
// methods
|
||||
// imports member data pair from the config file
|
||||
@@ -44,32 +68,10 @@ private:
|
||||
double *dData { nullptr };
|
||||
int *iData;
|
||||
};
|
||||
sound_source m_soundfxincrease; // sound associated with increasing control's value
|
||||
sound_source m_soundfxdecrease; // sound associated with decreasing control's value
|
||||
sound_source m_soundfxincrease { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE }; // sound associated with increasing control's value
|
||||
sound_source m_soundfxdecrease { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE }; // sound associated with decreasing control's value
|
||||
std::map<int, sound_source> m_soundfxvalues; // sounds associated with specific values
|
||||
|
||||
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, 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 Render();
|
||||
void AssignFloat(float *fValue);
|
||||
void AssignDouble(double *dValue);
|
||||
void AssignInt(int *iValue);
|
||||
void UpdateValue();
|
||||
// members
|
||||
TSubModel *SubModel; // McZapkie-310302: zeby mozna bylo sprawdzac czy zainicjowany poprawnie
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
@@ -132,6 +132,8 @@ bool Global::FullPhysics { true }; // full calculations performed for each simul
|
||||
// parametry testowe (do testowania scenerii i obiektów)
|
||||
bool Global::bWireFrame = false;
|
||||
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
|
||||
bool Global::MultipleLogs{ false };
|
||||
|
||||
|
||||
@@ -166,6 +166,7 @@ public:
|
||||
static bool bFreeFly;
|
||||
static bool bWireFrame;
|
||||
static bool bSoundEnabled;
|
||||
static float AudioVolume;
|
||||
// McZapkie-131202
|
||||
static bool bAdjustScreenFreq;
|
||||
static bool bEnableTraction;
|
||||
|
||||
@@ -197,14 +197,15 @@ static int const s_SHPebrake = 64; //hamuje
|
||||
static int const s_CAtest = 128;
|
||||
|
||||
/*dzwieki*/
|
||||
static int const sound_none = 0;
|
||||
static int const sound_loud = 1;
|
||||
static int const sound_couplerstretch = 2;
|
||||
static int const sound_bufferclamp = 4;
|
||||
static int const sound_bufferbump = 8;
|
||||
static int const sound_relay = 16;
|
||||
static int const sound_manyrelay = 32;
|
||||
static int const sound_brakeacc = 64;
|
||||
enum sound {
|
||||
none,
|
||||
loud = 0x1,
|
||||
couplerstretch = 0x2,
|
||||
bufferclash = 0x4,
|
||||
relay = 0x10,
|
||||
parallel = 0x20,
|
||||
pneumatic = 0x40
|
||||
};
|
||||
|
||||
//szczególne typy pojazdów (inna obsługa) dla zmiennej TrainType
|
||||
//zamienione na flagi bitowe, aby szybko wybierać grupę (np. EZT+SZT)
|
||||
@@ -602,6 +603,8 @@ struct TCoupling {
|
||||
|
||||
power_coupling power_high;
|
||||
power_coupling power_low; // TODO: implement this
|
||||
|
||||
int sounds { 0 }; // sounds emitted by the coupling devices
|
||||
};
|
||||
|
||||
class TMoverParameters
|
||||
@@ -1167,6 +1170,7 @@ public:
|
||||
bool DoorLeft(bool State); //obsluga drzwi lewych
|
||||
bool DoorRight(bool State); //obsluga drzwi prawych
|
||||
bool DoorBlockedFlag(void); //sprawdzenie blokady drzwi
|
||||
bool signal_departure( bool const State, int const Notify = range::consist ); // toggles departure warning
|
||||
|
||||
/* funkcje dla samochodow*/
|
||||
bool ChangeOffsetH(double DeltaOffset);
|
||||
|
||||
@@ -1369,11 +1369,11 @@ double TMoverParameters::ComputeMovement(double dt, double dt1, const TTrackShap
|
||||
if (EngineType == ElectricSeriesMotor)
|
||||
|
||||
if (AutoRelayCheck())
|
||||
SetFlag(SoundFlag, sound_relay);
|
||||
SetFlag(SoundFlag, sound::relay);
|
||||
|
||||
if (EngineType == DieselEngine)
|
||||
if (dizel_Update(dt))
|
||||
SetFlag(SoundFlag, sound_relay);
|
||||
SetFlag(SoundFlag, sound::relay);
|
||||
// uklady hamulcowe:
|
||||
if (VeselVolume > 0)
|
||||
Compressor = CompressedVolume / VeselVolume;
|
||||
@@ -1530,7 +1530,7 @@ double TMoverParameters::FastComputeMovement(double dt, const TTrackShape &Shape
|
||||
|
||||
if (EngineType == DieselEngine)
|
||||
if (dizel_Update(dt))
|
||||
SetFlag(SoundFlag, sound_relay);
|
||||
SetFlag(SoundFlag, sound::relay);
|
||||
// uklady hamulcowe:
|
||||
if (VeselVolume > 0)
|
||||
Compressor = CompressedVolume / VeselVolume;
|
||||
@@ -1703,7 +1703,7 @@ bool TMoverParameters::IncMainCtrl(int CtrlSpeed)
|
||||
if( RList[ MainCtrlPos ].Bn > 1 ) {
|
||||
if( true == MaxCurrentSwitch( false )) {
|
||||
// wylaczanie wysokiego rozruchu
|
||||
SetFlag( SoundFlag, sound_relay );
|
||||
SetFlag( SoundFlag, sound::relay );
|
||||
} // Q TODO:
|
||||
// if (EngineType=ElectricSeriesMotor) and (MainCtrlPos=1)
|
||||
// then
|
||||
@@ -2988,6 +2988,10 @@ bool TMoverParameters::BrakeDelaySwitch(int BDS)
|
||||
}
|
||||
else
|
||||
rBDS = false;
|
||||
if( true == rBDS ) {
|
||||
// if setting was changed emit the sound of pneumatic relay
|
||||
SetFlag( SoundFlag, sound::pneumatic );
|
||||
}
|
||||
return rBDS;
|
||||
}
|
||||
|
||||
@@ -3086,8 +3090,8 @@ void TMoverParameters::CompressorCheck(double dt)
|
||||
else
|
||||
{
|
||||
CompressedVolume = CompressedVolume * 0.8;
|
||||
SetFlag(SoundFlag, sound_relay | sound_loud);
|
||||
// SetFlag(SoundFlag, sound_loud);
|
||||
SetFlag(SoundFlag, sound::relay | sound::loud);
|
||||
// SetFlag(SoundFlag, sound::loud);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4078,6 +4082,31 @@ double TMoverParameters::CouplerForce(int CouplerN, double dt)
|
||||
// tempdist:=tempdist+CoupleDist; //ABu: proby szybkiego naprawienia bledu
|
||||
}
|
||||
|
||||
dV = V - (double)DirPatch( CouplerN, CNext ) * Couplers[ CouplerN ].Connected->V;
|
||||
absdV = abs( dV );
|
||||
// potentially generate sounds on clash or stretch
|
||||
if( ( newdist < 0.0 )
|
||||
&& ( Couplers[ CouplerN ].Dist > newdist )
|
||||
&& ( dV < -0.5 ) ) {
|
||||
// 090503: dzwieki pracy zderzakow
|
||||
SetFlag(
|
||||
Couplers[ CouplerN ].sounds,
|
||||
( absdV > 5.0 ?
|
||||
( sound::bufferclash | sound::loud ) :
|
||||
sound::bufferclash ) );
|
||||
}
|
||||
else if( ( Couplers[ CouplerN ].CouplingFlag != coupling::faux )
|
||||
&& ( newdist > 0.001 )
|
||||
&& ( Couplers[ CouplerN ].Dist <= 0.001 )
|
||||
&& ( absdV > 0.005 ) ) {
|
||||
// 090503: dzwieki pracy sprzegu
|
||||
SetFlag(
|
||||
Couplers[ CouplerN ].sounds,
|
||||
( absdV > 0.1 ?
|
||||
( sound::couplerstretch | sound::loud ) :
|
||||
sound::couplerstretch ) );
|
||||
}
|
||||
|
||||
// blablabla
|
||||
// ABu: proby znalezienia problemu ze zle odbijajacymi sie skladami
|
||||
//if (Couplers[CouplerN].CouplingFlag=ctrain_virtual) and (newdist>0) then
|
||||
@@ -4099,23 +4128,6 @@ double TMoverParameters::CouplerForce(int CouplerN, double dt)
|
||||
Couplers[CouplerN].Connected->Couplers[CNext].FmaxB) *
|
||||
CouplerTune / 2.0;
|
||||
}
|
||||
dV = V - (double)DirPatch(CouplerN, CNext) * Couplers[CouplerN].Connected->V;
|
||||
absdV = abs(dV);
|
||||
if ((newdist < -0.001) && (Couplers[CouplerN].Dist >= -0.001) &&
|
||||
(absdV > 0.010)) // 090503: dzwieki pracy zderzakow
|
||||
{
|
||||
if (SetFlag(SoundFlag, sound_bufferclamp))
|
||||
if (absdV > 0.5)
|
||||
SetFlag(SoundFlag, sound_loud);
|
||||
}
|
||||
else if ((newdist > 0.002) && (Couplers[CouplerN].Dist <= 0.002) &&
|
||||
(absdV > 0.005)) // 090503: dzwieki pracy sprzegu
|
||||
{
|
||||
if (Couplers[CouplerN].CouplingFlag > 0)
|
||||
if (SetFlag(SoundFlag, sound_couplerstretch))
|
||||
if (absdV > 0.1)
|
||||
SetFlag(SoundFlag, sound_loud);
|
||||
}
|
||||
distDelta =
|
||||
abs(newdist) - abs(Couplers[CouplerN].Dist); // McZapkie-191103: poprawka na histereze
|
||||
Couplers[CouplerN].Dist = newdist;
|
||||
@@ -4919,7 +4931,7 @@ bool TMoverParameters::FuseOn(void)
|
||||
{
|
||||
FuseFlag = false; // wlaczenie ponowne obwodu
|
||||
FO = true;
|
||||
SetFlag(SoundFlag, sound_relay | sound_loud);
|
||||
SetFlag(SoundFlag, sound::relay | sound::loud);
|
||||
}
|
||||
}
|
||||
return FO;
|
||||
@@ -4935,7 +4947,7 @@ void TMoverParameters::FuseOff(void)
|
||||
{
|
||||
FuseFlag = true;
|
||||
EventFlag = true;
|
||||
SetFlag(SoundFlag, sound_relay | sound_loud);
|
||||
SetFlag(SoundFlag, sound::relay | sound::loud);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5206,7 +5218,7 @@ bool TMoverParameters::AutoRelayCheck(void)
|
||||
// MainCtrlActualPos:=MainCtrlPos; //hunter-111012:
|
||||
// szybkie wchodzenie na bezoporowa (303E)
|
||||
OK = true;
|
||||
SetFlag(SoundFlag, sound_manyrelay | sound_loud);
|
||||
SetFlag(SoundFlag, sound::parallel | sound::loud);
|
||||
}
|
||||
else if ((LastRelayTime > CtrlDelay) && (ARFASI))
|
||||
{
|
||||
@@ -5240,13 +5252,13 @@ bool TMoverParameters::AutoRelayCheck(void)
|
||||
if ((RList[MainCtrlActualPos].R == 0) &&
|
||||
(!(MainCtrlActualPos == MainCtrlPosNo))) // wejscie na bezoporowa
|
||||
{
|
||||
SetFlag(SoundFlag, sound_manyrelay | sound_loud);
|
||||
SetFlag(SoundFlag, sound::parallel | sound::loud);
|
||||
}
|
||||
else if ((RList[MainCtrlActualPos].R > 0) &&
|
||||
(RList[MainCtrlActualPos - 1].R ==
|
||||
0)) // wejscie na drugi uklad
|
||||
{
|
||||
SetFlag(SoundFlag, sound_manyrelay);
|
||||
SetFlag(SoundFlag, sound::parallel);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5259,7 +5271,7 @@ bool TMoverParameters::AutoRelayCheck(void)
|
||||
// MainCtrlActualPos:=MainCtrlPos; //hunter-111012:
|
||||
// szybkie wchodzenie na bezoporowa (303E)
|
||||
OK = true;
|
||||
SetFlag(SoundFlag, sound_manyrelay);
|
||||
SetFlag(SoundFlag, sound::parallel);
|
||||
}
|
||||
else if (LastRelayTime > CtrlDownDelay)
|
||||
{
|
||||
@@ -5272,7 +5284,7 @@ bool TMoverParameters::AutoRelayCheck(void)
|
||||
if (RList[MainCtrlActualPos].R ==
|
||||
0) // dzwieki schodzenia z bezoporowej}
|
||||
{
|
||||
SetFlag(SoundFlag, sound_manyrelay);
|
||||
SetFlag(SoundFlag, sound::parallel);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5304,7 +5316,7 @@ bool TMoverParameters::AutoRelayCheck(void)
|
||||
StLinFlag = true; // ybARC - zalaczenie stycznikow liniowych
|
||||
MainCtrlActualPos = 1;
|
||||
DelayCtrlFlag = false;
|
||||
SetFlag(SoundFlag, sound_relay | sound_loud);
|
||||
SetFlag(SoundFlag, sound::relay | sound::loud);
|
||||
OK = true;
|
||||
}
|
||||
}
|
||||
@@ -5858,6 +5870,32 @@ bool TMoverParameters::DoorRight(bool State)
|
||||
return DR;
|
||||
}
|
||||
|
||||
// toggles departure warning
|
||||
bool
|
||||
TMoverParameters::signal_departure( bool const State, int const Notify ) {
|
||||
|
||||
if( DepartureSignal == State ) {
|
||||
// TBD: should the command be passed to other vehicles regardless of whether it affected the primary target?
|
||||
return false;
|
||||
}
|
||||
|
||||
DepartureSignal = State;
|
||||
if( Notify != range::local ) {
|
||||
// wysłanie wyłączenia do pozostałych?
|
||||
SendCtrlToNext(
|
||||
"DepartureSignal",
|
||||
( State == true ?
|
||||
1 :
|
||||
0 ),
|
||||
CabNo,
|
||||
( Notify == range::unit ?
|
||||
ctrain_controll | ctrain_depot :
|
||||
ctrain_controll ) );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// *************************************************************************************************
|
||||
// Q: 20160713
|
||||
// Przesuwa pojazd o podaną wartość w bok względem toru (dla samochodów)
|
||||
@@ -8227,6 +8265,13 @@ bool TMoverParameters::RunCommand( std::string Command, double CValue1, double C
|
||||
}
|
||||
OK = SendCtrlToNext( Command, CValue1, CValue2, Couplertype );
|
||||
}
|
||||
else if( Command == "DepartureSignal" ) {
|
||||
DepartureSignal = (
|
||||
CValue1 == 1 ?
|
||||
true :
|
||||
false );
|
||||
OK = SendCtrlToNext( Command, CValue1, CValue2, Couplertype );
|
||||
}
|
||||
else if (Command == "PantFront") /*Winger 160204*/
|
||||
{ // Ra: uwzględnić trzeba jeszcze zgodność sprzęgów
|
||||
// Czemu EZT ma być traktowane inaczej? Ukrotnienie ma, a człon może być odwrócony
|
||||
@@ -8346,6 +8391,8 @@ bool TMoverParameters::RunCommand( std::string Command, double CValue1, double C
|
||||
if( true == Hamulec->SetBDF( brakesetting ) ) {
|
||||
BrakeDelayFlag = brakesetting;
|
||||
OK = true;
|
||||
// if setting was changed emit the sound of pneumatic relay
|
||||
SetFlag( SoundFlag, sound::pneumatic );
|
||||
}
|
||||
else {
|
||||
OK = false;
|
||||
|
||||
@@ -578,48 +578,59 @@ void TESt::CheckReleaser( double const dt )
|
||||
}
|
||||
}
|
||||
|
||||
void TESt::CheckState( double const BCP, double &dV1 )
|
||||
{
|
||||
double VVP;
|
||||
double BVP;
|
||||
double CVP;
|
||||
void TESt::CheckState( double const BCP, double &dV1 ) {
|
||||
|
||||
BVP = BrakeRes->P();
|
||||
VVP = ValveRes->P();
|
||||
// if (BVP<VVP) then
|
||||
// VVP:=(BVP+VVP)/2;
|
||||
CVP = CntrlRes->P() - 0.0;
|
||||
double const VVP { ValveRes->P() };
|
||||
double const BVP { BrakeRes->P() };
|
||||
double const CVP { CntrlRes->P() };
|
||||
|
||||
// sprawdzanie stanu
|
||||
if (((BrakeStatus & b_hld) == b_hld) && (BCP > 0.25))
|
||||
if ((VVP + 0.003 + BCP / BVM < CVP))
|
||||
BrakeStatus |= b_on; // hamowanie stopniowe
|
||||
else if ((VVP - 0.003 + (BCP - 0.1) / BVM > CVP))
|
||||
BrakeStatus &= ~( b_on | b_hld ); // luzowanie
|
||||
else if ((VVP + BCP / BVM > CVP))
|
||||
BrakeStatus &= ~b_on; // zatrzymanie napelaniania
|
||||
else
|
||||
;
|
||||
else if ((VVP + 0.10 < CVP) && (BCP < 0.25)) // poczatek hamowania
|
||||
{
|
||||
if ((BrakeStatus & b_hld) == b_off)
|
||||
{
|
||||
if( BCP > 0.25 ) {
|
||||
|
||||
if( ( BrakeStatus & b_hld ) == b_hld ) {
|
||||
|
||||
if( ( VVP + 0.003 + BCP / BVM ) < CVP ) {
|
||||
// hamowanie stopniowe
|
||||
BrakeStatus |= b_on;
|
||||
}
|
||||
else {
|
||||
if( ( VVP + BCP / BVM ) > CVP ) {
|
||||
// zatrzymanie napelaniania
|
||||
BrakeStatus &= ~b_on;
|
||||
}
|
||||
if( ( VVP - 0.003 + ( BCP - 0.1 ) / BVM ) > CVP ) {
|
||||
// luzowanie
|
||||
BrakeStatus &= ~( b_on | b_hld );
|
||||
}
|
||||
}
|
||||
}
|
||||
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 );
|
||||
SoundFlag |= sf_Acc;
|
||||
ValveRes->Act();
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
double TESt::CVs( double const BP )
|
||||
{
|
||||
@@ -828,6 +839,10 @@ double TEStEP2::GetPF( double const PP, double const dt, double const Vel )
|
||||
else if ((VVP + BCP / BVM < CVP - 0.12) && (BCP > 0.25)) // zatrzymanie luzowanie
|
||||
BrakeStatus |= b_hld;
|
||||
|
||||
if( ( BrakeStatus & b_hld ) == 0 ) {
|
||||
SoundFlag |= sf_CylU;
|
||||
}
|
||||
|
||||
// przeplyw ZS <-> PG
|
||||
if ((BVP < CVP - 0.2) || (BrakeStatus != b_off) || (BCP > 0.25))
|
||||
temp = 0;
|
||||
@@ -1211,6 +1226,40 @@ double TLSt::GetPF( double const PP, double const dt, double const Vel )
|
||||
double dV1{ 0.0 };
|
||||
|
||||
// sprawdzanie stanu
|
||||
// NOTE: partial copypaste from checkstate() of base class
|
||||
// TODO: clean inheritance for checkstate() and checkreleaser() and reuse these instead of manual copypaste
|
||||
if( ( ( BrakeStatus & b_hld ) == b_hld ) && ( BCP > 0.25 ) ) {
|
||||
if( ( VVP + 0.003 + BCP / BVM < CVP ) ) {
|
||||
// hamowanie stopniowe
|
||||
BrakeStatus |= b_on;
|
||||
}
|
||||
else if( ( VVP - 0.003 + ( BCP - 0.1 ) / BVM > CVP ) ) {
|
||||
// luzowanie
|
||||
BrakeStatus &= ~( b_on | b_hld );
|
||||
}
|
||||
else if( ( VVP + BCP / BVM > CVP ) ) {
|
||||
// zatrzymanie napelaniania
|
||||
BrakeStatus &= ~b_on;
|
||||
}
|
||||
}
|
||||
else if ((VVP + 0.10 < CVP) && (BCP < 0.25)) {
|
||||
// poczatek hamowania
|
||||
if ((BrakeStatus & b_hld) == b_off)
|
||||
{
|
||||
SoundFlag |= sf_Acc;
|
||||
}
|
||||
BrakeStatus |= (b_on | b_hld);
|
||||
}
|
||||
else if( ( VVP + ( BCP - 0.1 ) / BVM < CVP )
|
||||
&& ( ( CVP - VVP ) * BVM > 0.25 )
|
||||
&& ( BCP > 0.25 ) ) {
|
||||
// zatrzymanie luzowanie
|
||||
BrakeStatus |= b_hld;
|
||||
}
|
||||
if( ( BrakeStatus & b_hld ) == 0 ) {
|
||||
SoundFlag |= sf_CylU;
|
||||
}
|
||||
// equivalent of checkreleaser() in the base class?
|
||||
if( ( BrakeStatus & b_rls ) == b_rls ) {
|
||||
if( CVP < 0.0 ) {
|
||||
BrakeStatus &= ~b_rls;
|
||||
@@ -1219,18 +1268,11 @@ double TLSt::GetPF( double const PP, double const dt, double const Vel )
|
||||
{ // 008
|
||||
dV = PF1( CVP, BCP, 0.024 ) * dt;
|
||||
CntrlRes->Flow( dV );
|
||||
/*
|
||||
// NOTE: attempted fix, disabled because it breaks when releaser is used while releasing breakes
|
||||
dV = PF1(CVP, VVP, 0.024) * dt;
|
||||
CntrlRes->Flow( dV );
|
||||
dV1 = dV; //minus potem jest
|
||||
ImplsRes->Flow( -dV1 );
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
double temp;
|
||||
// przeplyw ZS <-> PG
|
||||
double temp;
|
||||
if (((CVP - BCP) * BVM > 0.5))
|
||||
temp = 0.0;
|
||||
else if ((VVP > CVP + 0.4))
|
||||
@@ -1888,23 +1930,52 @@ void TKE::CheckState( double const BCP, double &dV1 )
|
||||
CVP = CntrlRes->P();
|
||||
|
||||
// sprawdzanie stanu
|
||||
if ((BrakeStatus & b_hld) == b_hld)
|
||||
if ((VVP + 0.003 + BCP / BVM < CVP))
|
||||
BrakeStatus |= b_on; // hamowanie stopniowe;
|
||||
else if ((VVP - 0.003 + BCP / BVM > CVP))
|
||||
BrakeStatus &= ~( b_on | b_hld ); // luzowanie;
|
||||
else if ((VVP + BCP / BVM > CVP))
|
||||
BrakeStatus &= ~b_on; // zatrzymanie napelaniania;
|
||||
else
|
||||
;
|
||||
else if ((VVP + 0.10 < CVP) && (BCP < 0.1)) // poczatek hamowania
|
||||
{
|
||||
BrakeStatus |= (b_on | b_hld);
|
||||
ValveRes->CreatePress(0.8 * VVP); // przyspieszacz
|
||||
if( BCP > 0.1 ) {
|
||||
|
||||
if( ( BrakeStatus & b_hld ) == b_hld ) {
|
||||
|
||||
if( ( VVP + 0.003 + BCP / BVM ) < CVP ) {
|
||||
// hamowanie stopniowe;
|
||||
BrakeStatus |= b_on;
|
||||
}
|
||||
else if ((VVP + BCP / BVM < CVP) && ((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;
|
||||
}
|
||||
}
|
||||
}
|
||||
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 )
|
||||
{
|
||||
|
||||
50
Model3d.cpp
50
Model3d.cpp
@@ -1050,14 +1050,17 @@ void TSubModel::ColorsSet( glm::vec3 const &Ambient, glm::vec3 const &Diffuse, g
|
||||
*/
|
||||
};
|
||||
|
||||
void TSubModel::ParentMatrix(float4x4 *m)
|
||||
{ // pobranie transformacji względem wstawienia modelu
|
||||
// jeśli nie zostało wykonane Init() (tzn. zaraz po wczytaniu T3D), to
|
||||
// dodatkowy obrót
|
||||
// obrót T3D jest wymagany np. do policzenia wysokości pantografów
|
||||
*m = float4x4(*fMatrix); // skopiowanie, bo będziemy mnożyć
|
||||
// m(3)[1]=m[3][1]+0.054; //w górę o wysokość ślizgu (na razie tak)
|
||||
TSubModel *sm = this;
|
||||
void TSubModel::ParentMatrix( float4x4 *m ) const { // pobranie transformacji względem wstawienia modelu
|
||||
// jeśli nie zostało wykonane Init() (tzn. zaraz po wczytaniu T3D),
|
||||
// to dodatkowy obrót obrót T3D jest wymagany np. do policzenia wysokości pantografów
|
||||
if( fMatrix != nullptr ) {
|
||||
// skopiowanie, bo będziemy mnożyć
|
||||
*m = float4x4( *fMatrix );
|
||||
}
|
||||
else {
|
||||
m->Identity();
|
||||
}
|
||||
auto *sm = this;
|
||||
while (sm->Parent)
|
||||
{ // przenieść tę funkcję do modelu
|
||||
if (sm->Parent->GetMatrix())
|
||||
@@ -1160,6 +1163,37 @@ TSubModel *TModel3d::GetFromName(std::string const &Name)
|
||||
}
|
||||
};
|
||||
|
||||
// returns offset vector from root
|
||||
glm::vec3
|
||||
TSubModel::offset( float const Geometrytestoffsetthreshold ) const {
|
||||
|
||||
float4x4 parentmatrix;
|
||||
ParentMatrix( &parentmatrix );
|
||||
|
||||
auto offset { glm::vec3 { glm::make_mat4( parentmatrix.readArray() ) * glm::vec4 { 0, 0, 0, 1 } } };
|
||||
|
||||
if( glm::length2( offset ) < Geometrytestoffsetthreshold ) {
|
||||
// offset of zero generally means the submodel has optimized identity matrix
|
||||
// for such cases we resort to an estimate from submodel geometry
|
||||
// TODO: do proper bounding area calculation for submodel when loading mesh and grab the centre point from it here
|
||||
if( m_geometry != null_handle ) {
|
||||
auto const &vertices{ GfxRenderer.Vertices( m_geometry ) };
|
||||
if( false == vertices.empty() ) {
|
||||
// transformation matrix for the submodel can still contain rotation and/or scaling,
|
||||
// so we pass the vertex positions through it rather than just grab them directly
|
||||
offset = glm::vec3();
|
||||
auto const vertexfactor { 1.f / vertices.size() };
|
||||
auto const transformationmatrix { glm::make_mat4( parentmatrix.readArray() ) };
|
||||
for( auto const &vertex : vertices ) {
|
||||
offset += glm::vec3 { transformationmatrix * glm::vec4 { vertex.position, 1 } } * vertexfactor;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
bool TModel3d::LoadFromFile(std::string const &FileName, bool dynamic)
|
||||
{
|
||||
// wczytanie modelu z pliku
|
||||
|
||||
@@ -124,7 +124,9 @@ private:
|
||||
|
||||
TSubModel *Next { nullptr };
|
||||
TSubModel *Child { nullptr };
|
||||
public: // temporary access, clean this up during refactoring
|
||||
gfx::geometry_handle m_geometry { 0, 0 }; // geometry of the submodel
|
||||
private:
|
||||
material_handle m_material { null_handle }; // numer tekstury, -1 wymienna, 0 brak
|
||||
bool bWire { false }; // nie używane, ale wczytywane
|
||||
float Opacity { 1.0f };
|
||||
@@ -138,9 +140,7 @@ public: // chwilowo
|
||||
float m_boundingradius { 0 };
|
||||
size_t iAnimOwner{ 0 }; // roboczy numer egzemplarza, który ustawił animację
|
||||
TAnimType b_aAnim{ at_None }; // kody animacji oddzielnie, bo zerowane
|
||||
public:
|
||||
float4x4 *mAnimMatrix{ nullptr }; // macierz do animacji kwaternionowych (należy do AnimContainer)
|
||||
public:
|
||||
TSubModel **smLetter{ nullptr }; // wskaźnik na tablicę submdeli do generoania tekstu (docelowo zapisać do E3D)
|
||||
TSubModel *Parent{ nullptr }; // nadrzędny, np. do wymnażania macierzy
|
||||
int iVisible{ 1 }; // roboczy stan widoczności
|
||||
@@ -172,6 +172,9 @@ public:
|
||||
void SetRotateIK1(float3 vNewAngles);
|
||||
TSubModel * GetFromName( std::string const &search, bool i = true );
|
||||
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; };
|
||||
|
||||
void create_geometry( std::size_t &Dataoffset, gfx::geometrybank_handle const &Bank );
|
||||
@@ -200,7 +203,7 @@ public:
|
||||
return *(fMatrix->TranslationGet()) + Child->Translation1Get(); }
|
||||
material_handle GetMaterial() const {
|
||||
return m_material; }
|
||||
void ParentMatrix(float4x4 *m);
|
||||
void ParentMatrix(float4x4 *m) const;
|
||||
float MaxY( float4x4 const &m );
|
||||
|
||||
void deserialize(std::istream&);
|
||||
|
||||
58
Train.h
58
Train.h
@@ -91,7 +91,6 @@ class TTrain
|
||||
vector3 GetWorldMechPosition();
|
||||
bool Update( double const Deltatime );
|
||||
void update_sounds( double const Deltatime );
|
||||
bool m_updated = false;
|
||||
void MechStop();
|
||||
void SetLights();
|
||||
// McZapkie-310302: ladowanie parametrow z pliku
|
||||
@@ -102,6 +101,7 @@ class TTrain
|
||||
// types
|
||||
typedef void( *command_handler )( TTrain *Train, command_data const &Command );
|
||||
typedef std::unordered_map<user_command, command_handler> commandhandler_map;
|
||||
// methods
|
||||
// clears state of all cabin controls
|
||||
void clear_cab_controls();
|
||||
// sets cabin controls based on current state of the vehicle
|
||||
@@ -226,7 +226,7 @@ public: // reszta może by?publiczna
|
||||
TGauge ggMainCtrl;
|
||||
TGauge ggMainCtrlAct;
|
||||
TGauge ggScndCtrl;
|
||||
TGauge ggScndCtrlButton;
|
||||
TGauge ggScndCtrlButton; // NOTE: not used?
|
||||
TGauge ggDirKey;
|
||||
TGauge ggBrakeCtrl;
|
||||
TGauge ggLocalBrake;
|
||||
@@ -398,42 +398,23 @@ public: // reszta może by?publiczna
|
||||
double fMechRoll;
|
||||
double fMechPitch;
|
||||
|
||||
sound_source dsbNastawnikJazdy;
|
||||
sound_source dsbNastawnikBocz; // hunter-081211
|
||||
sound_source dsbRelay;
|
||||
sound_source dsbPneumaticRelay;
|
||||
sound_source dsbSwitch;
|
||||
sound_source dsbPneumaticSwitch;
|
||||
sound_source dsbReverserKey; // hunter-121211
|
||||
sound_source dsbReverserKey { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE }; // hunter-121211
|
||||
sound_source dsbNastawnikJazdy { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE };
|
||||
sound_source dsbNastawnikBocz { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE }; // hunter-081211
|
||||
sound_source dsbSwitch { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE };
|
||||
sound_source dsbPneumaticSwitch { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE };
|
||||
|
||||
sound_source dsbCouplerAttach; // Ra: w kabinie????
|
||||
sound_source dsbCouplerDetach; // Ra: w kabinie???
|
||||
sound_source rsHiss { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE }; // upuszczanie
|
||||
sound_source rsHissU { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE }; // napelnianie
|
||||
sound_source rsHissE { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE }; // nagle
|
||||
sound_source rsHissX { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE }; // fala
|
||||
sound_source rsHissT { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE }; // czasowy
|
||||
sound_source rsSBHiss { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE }; // local
|
||||
|
||||
sound_source dsbDieselIgnition; // Ra: w kabinie???
|
||||
|
||||
// Winger 010304
|
||||
sound_source dsbWejscie_na_bezoporow;
|
||||
sound_source dsbWejscie_na_drugi_uklad; // hunter-081211: poprawka literowki
|
||||
|
||||
// PSound dsbHiss1;
|
||||
// PSound dsbHiss2;
|
||||
|
||||
// McZapkie-280302
|
||||
sound_source rsBrake;
|
||||
sound_source rsSlippery;
|
||||
sound_source rsHiss; // upuszczanie
|
||||
sound_source rsHissU; // napelnianie
|
||||
sound_source rsHissE; // nagle
|
||||
sound_source rsHissX; // fala
|
||||
sound_source rsHissT; // czasowy
|
||||
sound_source rsSBHiss;
|
||||
sound_source rsRunningNoise;
|
||||
sound_source rsEngageSlippery;
|
||||
sound_source rsFadeSound;
|
||||
|
||||
sound_source dsbHasler;
|
||||
sound_source dsbBuzzer;
|
||||
sound_source dsbSlipAlarm; // Bombardier 011010: alarm przy poslizgu dla 181/182
|
||||
sound_source rsFadeSound { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE };
|
||||
sound_source dsbHasler { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE };
|
||||
sound_source dsbBuzzer { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE };
|
||||
sound_source dsbSlipAlarm { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE }; // Bombardier 011010: alarm przy poslizgu dla 181/182
|
||||
|
||||
int iCabLightFlag; // McZapkie:120503: oswietlenie kabiny (0: wyl, 1: przyciemnione, 2: pelne)
|
||||
bool bCabLight; // hunter-091012: czy swiatlo jest zapalone?
|
||||
@@ -443,9 +424,6 @@ public: // reszta może by?publiczna
|
||||
vector3 MirrorPosition(bool lewe);
|
||||
|
||||
private:
|
||||
sound_source dsbCouplerStretch;
|
||||
sound_source dsbEN57_CouplerStretch;
|
||||
sound_source dsbBufferClamp;
|
||||
double fBlinkTimer;
|
||||
float fHaslerTimer;
|
||||
float fConverterTimer; // hunter-261211: dla przekaznika
|
||||
@@ -494,7 +472,9 @@ private:
|
||||
float fEIMParams[9][10]; // parametry dla silnikow asynchronicznych
|
||||
int RadioChannel() { return iRadioChannel; };
|
||||
inline TDynamicObject *Dynamic() { return DynamicObject; };
|
||||
inline TDynamicObject const *Dynamic() const { return DynamicObject; };
|
||||
inline TMoverParameters *Controlled() { return mvControlled; };
|
||||
inline TMoverParameters const *Controlled() const { return mvControlled; };
|
||||
void DynamicSet(TDynamicObject *d);
|
||||
void Silence();
|
||||
|
||||
|
||||
10
World.cpp
10
World.cpp
@@ -732,7 +732,9 @@ void TWorld::OnKeyDown(int cKey)
|
||||
if (vehicle->MoverParameters->IncLocalBrakeLevelFAST())
|
||||
if (Train)
|
||||
{ // dźwięk oczywiście jest w kabinie
|
||||
#ifdef EU07_USE_OLD_SOUNDCODE
|
||||
Train->dsbPneumaticRelay.play();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -751,7 +753,9 @@ void TWorld::OnKeyDown(int cKey)
|
||||
if (vehicle->MoverParameters->DecLocalBrakeLevelFAST())
|
||||
if (Train)
|
||||
{ // dźwięk oczywiście jest w kabinie
|
||||
#ifdef EU07_USE_OLD_SOUNDCODE
|
||||
Train->dsbPneumaticRelay.play();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2031,15 +2035,15 @@ void TWorld::CreateE3D(std::string const &Path, bool Dynamic)
|
||||
if( dynamic->iCabs ) { // jeśli ma jakąkolwiek kabinę
|
||||
delete Train;
|
||||
Train = new TTrain();
|
||||
if( dynamic->iCabs & 1 ) {
|
||||
if( dynamic->iCabs & 0x1 ) {
|
||||
dynamic->MoverParameters->ActiveCab = 1;
|
||||
Train->Init( dynamic, true );
|
||||
}
|
||||
if( dynamic->iCabs & 4 ) {
|
||||
if( dynamic->iCabs & 0x4 ) {
|
||||
dynamic->MoverParameters->ActiveCab = -1;
|
||||
Train->Init( dynamic, true );
|
||||
}
|
||||
if( dynamic->iCabs & 2 ) {
|
||||
if( dynamic->iCabs & 0x2 ) {
|
||||
dynamic->MoverParameters->ActiveCab = 0;
|
||||
Train->Init( dynamic, true );
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "audio.h"
|
||||
#include "globals.h"
|
||||
#include "mczapkie/mctools.h"
|
||||
#include "logs.h"
|
||||
|
||||
#define DR_WAV_IMPLEMENTATION
|
||||
#include "dr_wav.h"
|
||||
@@ -137,6 +138,7 @@ buffer_manager::create( std::string const &Filename ) {
|
||||
return emplace( filelookup );
|
||||
}
|
||||
// if we still didn't find anything, give up
|
||||
ErrorLog( "Bad file: failed do locate audio file \"" + Filename + "\"" );
|
||||
return null_handle;
|
||||
}
|
||||
|
||||
|
||||
2
audio.h
2
audio.h
@@ -14,7 +14,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
|
||||
namespace audio {
|
||||
|
||||
ALuint const null_resource { ~ALuint{ 0 } };
|
||||
ALuint const null_resource{ ~( ALuint { 0 } ) };
|
||||
|
||||
// wrapper for audio sample
|
||||
struct openal_buffer {
|
||||
|
||||
@@ -11,12 +11,15 @@ http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#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() {
|
||||
@@ -29,17 +32,16 @@ openal_source::play() {
|
||||
void
|
||||
openal_source::stop() {
|
||||
|
||||
::alSourcei( id, AL_LOOPING, AL_FALSE );
|
||||
loop( false );
|
||||
::alSourceStop( id );
|
||||
// NOTE: we don't update the is_playing flag
|
||||
// this way the state will change only on next update loop,
|
||||
// giving the controller a chance to properly change state from cease to none
|
||||
// even with multiple active sounds under control
|
||||
is_playing = false;
|
||||
}
|
||||
|
||||
// updates state of the source
|
||||
void
|
||||
openal_source::update( int const Deltatime ) {
|
||||
openal_source::update( double const Deltatime ) {
|
||||
|
||||
update_deltatime = Deltatime; // cached for time-based processing of data from the controller
|
||||
|
||||
// TODO: test whether the emitter was within range during the last tick, potentially update the counter and flag it for timeout
|
||||
::alGetSourcei( id, AL_BUFFERS_PROCESSED, &buffer_index );
|
||||
@@ -58,10 +60,79 @@ openal_source::update( int const Deltatime ) {
|
||||
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();
|
||||
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 );
|
||||
}
|
||||
}
|
||||
|
||||
// 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,
|
||||
@@ -78,9 +149,7 @@ openal_source::clear() {
|
||||
controller = nullptr;
|
||||
// unqueue bound buffers:
|
||||
// ensure no buffer is in use...
|
||||
::alSourcei( id, AL_LOOPING, AL_FALSE );
|
||||
::alSourceStop( id );
|
||||
is_playing = false;
|
||||
stop();
|
||||
// ...prepare space for returned ids of unqueued buffers (not that we need that info)...
|
||||
std::vector<ALuint> bufferids;
|
||||
bufferids.resize( buffers.size() );
|
||||
@@ -88,6 +157,8 @@ openal_source::clear() {
|
||||
::alSourceUnqueueBuffers( id, bufferids.size(), bufferids.data() );
|
||||
buffers.clear();
|
||||
buffer_index = 0;
|
||||
// reset properties
|
||||
properties = sound_properties();
|
||||
}
|
||||
|
||||
|
||||
@@ -125,6 +196,9 @@ openal_renderer::init() {
|
||||
// basic initialization failed
|
||||
return false;
|
||||
}
|
||||
//
|
||||
// ::alDistanceModel( AL_LINEAR_DISTANCE );
|
||||
::alDistanceModel( AL_INVERSE_DISTANCE_CLAMPED );
|
||||
// all done
|
||||
m_ready = true;
|
||||
return true;
|
||||
@@ -141,10 +215,45 @@ openal_renderer::insert( sound_source *Controller, audio::buffer_handle const So
|
||||
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( int const Deltatime ) {
|
||||
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
|
||||
|
||||
@@ -14,6 +14,15 @@ http://mozilla.org/MPL/2.0/.
|
||||
|
||||
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
|
||||
@@ -29,6 +38,8 @@ struct openal_source {
|
||||
buffer_sequence buffers; // sequence of samples the source will emit
|
||||
int buffer_index; // currently queued sample from the buffer sequence
|
||||
bool is_playing { false };
|
||||
bool is_looping { false };
|
||||
sound_properties properties;
|
||||
|
||||
// methods
|
||||
template <class Iterator_>
|
||||
@@ -47,25 +58,42 @@ struct openal_source {
|
||||
// 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();
|
||||
// updates state of the source
|
||||
void
|
||||
update( int const Deltatime );
|
||||
// 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();
|
||||
@@ -89,9 +117,12 @@ public:
|
||||
// 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( int const Deltatime );
|
||||
update( double const Deltatime );
|
||||
|
||||
private:
|
||||
// types
|
||||
@@ -107,6 +138,7 @@ private:
|
||||
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?
|
||||
@@ -116,6 +148,20 @@ private:
|
||||
|
||||
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
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
2
dumb3d.h
2
dumb3d.h
@@ -162,7 +162,7 @@ class matrix4x4
|
||||
}
|
||||
|
||||
// Low-level access to the array.
|
||||
const scalar_t *readArray(void)
|
||||
const scalar_t *readArray(void) const
|
||||
{
|
||||
return e;
|
||||
}
|
||||
|
||||
22
renderer.cpp
22
renderer.cpp
@@ -441,6 +441,25 @@ opengl_renderer::Render_pass( rendermode const Mode ) {
|
||||
#endif
|
||||
switch_units( true, true, true );
|
||||
Render( simulation::Region );
|
||||
/*
|
||||
// debug: audio nodes
|
||||
for( auto const &audiosource : audio::renderer.m_sources ) {
|
||||
|
||||
::glPushMatrix();
|
||||
auto const position = audiosource.properties.location - m_renderpass.camera.position();
|
||||
::glTranslated( position.x, position.y, position.z );
|
||||
|
||||
::glPushAttrib( GL_ENABLE_BIT );
|
||||
::glDisable( GL_TEXTURE_2D );
|
||||
::glColor3f( 0.36f, 0.75f, 0.35f );
|
||||
|
||||
::gluSphere( m_quadric, 0.125, 4, 2 );
|
||||
|
||||
::glPopAttrib();
|
||||
|
||||
::glPopMatrix();
|
||||
}
|
||||
*/
|
||||
// ...translucent parts
|
||||
setup_drawing( true );
|
||||
Render_Alpha( simulation::Region );
|
||||
@@ -2990,11 +3009,12 @@ opengl_renderer::Render_Alpha( TSubModel *Submodel ) {
|
||||
|
||||
if( glarelevel > 0.0f ) {
|
||||
// setup
|
||||
::glPushAttrib( GL_ENABLE_BIT | GL_CURRENT_BIT | GL_COLOR_BUFFER_BIT );
|
||||
::glPushAttrib( GL_CURRENT_BIT | GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_ENABLE_BIT );
|
||||
|
||||
Bind_Texture( m_glaretexture );
|
||||
::glColor4f( Submodel->f4Diffuse[ 0 ], Submodel->f4Diffuse[ 1 ], Submodel->f4Diffuse[ 2 ], glarelevel );
|
||||
::glDisable( GL_LIGHTING );
|
||||
::glDepthMask( GL_FALSE );
|
||||
::glBlendFunc( GL_SRC_ALPHA, GL_ONE );
|
||||
|
||||
::glPushMatrix();
|
||||
|
||||
@@ -851,7 +851,9 @@ state_manager::deserialize_sound( cParser &Input, scene::scratch_data &Scratchpa
|
||||
auto *sound = new TTextSound( soundname, Nodedata.range_max, location.x, location.y, location.z, false, false, Nodedata.range_min );
|
||||
sound->name( Nodedata.name );
|
||||
#else
|
||||
auto *sound = new sound_source();
|
||||
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
|
||||
|
||||
|
||||
280
sound.cpp
280
sound.cpp
@@ -12,6 +12,20 @@ http://mozilla.org/MPL/2.0/.
|
||||
#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 &
|
||||
@@ -27,14 +41,14 @@ sound_source::deserialize( cParser &Input, sound_type const Legacytype, int cons
|
||||
switch( Legacytype ) {
|
||||
case sound_type::single: {
|
||||
// single sample only
|
||||
m_soundmain = 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 ,;" ) );
|
||||
break;
|
||||
}
|
||||
case sound_type::multipart: {
|
||||
// three samples: start, middle, stop
|
||||
m_soundbegin = audio::renderer.fetch_buffer( Input.getToken<std::string>( true, "\n\r\t ,;" ) );
|
||||
m_soundmain = audio::renderer.fetch_buffer( Input.getToken<std::string>( true, "\n\r\t ,;" ) );
|
||||
m_soundend = audio::renderer.fetch_buffer( Input.getToken<std::string>( true, "\n\r\t ,;" ) );
|
||||
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: {
|
||||
@@ -44,12 +58,19 @@ sound_source::deserialize( cParser &Input, sound_type const Legacytype, int cons
|
||||
|
||||
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;
|
||||
@@ -64,34 +85,41 @@ sound_source::play( int const Flags ) {
|
||||
// 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;
|
||||
|
||||
switch( m_stage ) {
|
||||
case stage::none:
|
||||
case stage::restart: {
|
||||
if( m_soundbegin != null_handle ) {
|
||||
std::vector<audio::buffer_handle> bufferlist{ m_soundbegin, m_soundmain };
|
||||
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 };
|
||||
audio::renderer.insert( this, std::begin( bufferlist ), std::end( bufferlist ) );
|
||||
}
|
||||
else {
|
||||
audio::renderer.insert( this, m_soundmain );
|
||||
audio::renderer.insert( this, m_soundmain.buffer );
|
||||
}
|
||||
break;
|
||||
}
|
||||
case stage::main: {
|
||||
// TODO: schedule another main sample playback, or a suitable sample from the table for combined sources
|
||||
break;
|
||||
}
|
||||
case stage::end: {
|
||||
// schedule stop of current sequence end sample...
|
||||
m_stage = stage::restart;
|
||||
// ... and queue startup or main sound again
|
||||
return play( Flags );
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
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
|
||||
audio::renderer.insert( this, m_soundmain.buffer );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -100,30 +128,14 @@ sound_source::play( int const Flags ) {
|
||||
void
|
||||
sound_source::stop() {
|
||||
|
||||
if( ( m_stage == stage::none )
|
||||
|| ( m_stage == stage::end ) ) {
|
||||
return;
|
||||
}
|
||||
if( false == is_playing() ) { return; }
|
||||
|
||||
switch( m_stage ) {
|
||||
case stage::begin:
|
||||
case stage::main: {
|
||||
// set the source to kill any currently active sounds
|
||||
m_stage = stage::cease;
|
||||
if( m_soundend != null_handle ) {
|
||||
// and if there's defined sample for the sound end, play it instead
|
||||
audio::renderer.insert( this, m_soundend );
|
||||
}
|
||||
break;
|
||||
}
|
||||
case stage::end: {
|
||||
// set the source to kill any currently active sounds
|
||||
m_stage = stage::cease;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
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
|
||||
audio::renderer.insert( this, m_soundend.buffer );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,19 +146,28 @@ sound_source::update( audio::openal_source &Source ) {
|
||||
if( true == Source.is_playing ) {
|
||||
|
||||
// kill the sound if requested
|
||||
if( m_stage == stage::cease ) {
|
||||
if( true == m_stop ) {
|
||||
Source.stop();
|
||||
update_counter( Source.buffers[ Source.buffer_index ], -1 );
|
||||
if( false == is_playing() ) {
|
||||
m_stop = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
// TODO: positional update
|
||||
if( m_soundbegin != null_handle ) {
|
||||
// multipart sound
|
||||
// check and update if needed current sound properties
|
||||
update_location();
|
||||
update_placement_gain();
|
||||
Source.sync_with( m_properties );
|
||||
|
||||
if( m_soundbegin.buffer != null_handle ) {
|
||||
// potentially a multipart sound
|
||||
// detect the moment when the sound moves from startup sample to the main
|
||||
if( ( m_stage == stage::begin )
|
||||
&& ( Source.buffers[ Source.buffer_index ] == m_soundmain ) ) {
|
||||
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_stage = stage::main;
|
||||
--( m_soundbegin.playing );
|
||||
++( m_soundmain.playing );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -155,12 +176,14 @@ sound_source::update( audio::openal_source &Source ) {
|
||||
// we can determine this from number of processed buffers
|
||||
if( Source.buffer_index != Source.buffers.size() ) {
|
||||
auto const buffer { Source.buffers[ Source.buffer_index ] };
|
||||
if( buffer == m_soundbegin ) { m_stage = stage::begin; }
|
||||
// TODO: take ito accound sample table for combined sounds
|
||||
else if( buffer == m_soundmain ) { m_stage = stage::main; }
|
||||
else if( buffer == m_soundend ) { m_stage = stage::end; }
|
||||
// TODO: emitter initialization
|
||||
if( ( buffer == m_soundmain )
|
||||
update_counter( buffer, 1 );
|
||||
// emitter initialization
|
||||
Source.range( m_range );
|
||||
Source.pitch( m_pitchvariation );
|
||||
update_location();
|
||||
update_placement_gain();
|
||||
Source.sync_with( m_properties );
|
||||
if( ( buffer == m_soundmain.buffer )
|
||||
&& ( true == TestFlag( m_flags, sound_flags::looping ) ) ) {
|
||||
// main sample can be optionally set to loop
|
||||
Source.loop( true );
|
||||
@@ -169,15 +192,33 @@ sound_source::update( audio::openal_source &Source ) {
|
||||
Source.play();
|
||||
}
|
||||
else {
|
||||
//
|
||||
auto const buffer { Source.buffers[ Source.buffer_index - 1 ] };
|
||||
if( ( buffer == m_soundend )
|
||||
|| ( ( m_soundend == null_handle )
|
||||
&& ( buffer == m_soundmain ) ) ) {
|
||||
m_stage = stage::none;
|
||||
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
|
||||
@@ -185,14 +226,117 @@ 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 == null_handle );
|
||||
return ( m_soundmain.buffer == null_handle );
|
||||
}
|
||||
|
||||
// returns true if the source is emitting any sound
|
||||
bool
|
||||
sound_source::is_playing() const {
|
||||
sound_source::is_playing( bool const Includesoundends ) const {
|
||||
|
||||
return ( m_stage != stage::none );
|
||||
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;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
100
sound.h
100
sound.h
@@ -13,7 +13,11 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "classes.h"
|
||||
#include "names.h"
|
||||
|
||||
enum sound_type {
|
||||
float const EU07_SOUND_CABCONTROLSCUTOFFRANGE { 7.5f };
|
||||
float const EU07_SOUND_BRAKINGCUTOFFRANGE { 100.f };
|
||||
float const EU07_SOUND_RUNNINGNOISECUTOFFRANGE { 100.f };
|
||||
|
||||
enum class sound_type {
|
||||
single,
|
||||
multipart
|
||||
};
|
||||
@@ -29,27 +33,59 @@ enum sound_flags {
|
||||
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 = NULL );
|
||||
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 = NULL );
|
||||
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 = NULL );
|
||||
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 );
|
||||
@@ -58,38 +94,62 @@ public:
|
||||
// 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
|
||||
// returns true if the source is emitting any sound; by default doesn't take into account optional ending soudnds
|
||||
bool
|
||||
is_playing() const;
|
||||
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
|
||||
enum stage {
|
||||
none,
|
||||
begin,
|
||||
main,
|
||||
end,
|
||||
cease,
|
||||
restart
|
||||
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();
|
||||
|
||||
// members
|
||||
TDynamicObject * m_owner { nullptr }; // optional, the vehicle carrying this sound source
|
||||
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;
|
||||
stage m_stage{ stage::none };
|
||||
int m_flags{ NULL };
|
||||
audio::buffer_handle m_soundmain { null_handle }; // main sound emitted by the source
|
||||
audio::buffer_handle m_soundbegin { null_handle }; // optional, sound emitted before the main sound
|
||||
audio::buffer_handle m_soundend { null_handle }; // optional, sound emitted after the main sound
|
||||
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 generators for power grid present in the scene
|
||||
// collection of sound sources present in the scene
|
||||
class sound_table : public basic_table<sound_source> {
|
||||
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user