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

model lights state transition toggle, ambient sounds support, departure time based event delay, minor bug fixes

This commit is contained in:
tmj-fstate
2020-08-18 22:19:58 +02:00
parent 82ebe1ab4a
commit 8cc11bcd8d
14 changed files with 226 additions and 122 deletions

View File

@@ -438,7 +438,8 @@ TAnimModel::is_keyword( std::string const &Token ) const {
return ( Token == "endmodel" ) return ( Token == "endmodel" )
|| ( Token == "lights" ) || ( Token == "lights" )
|| ( Token == "lightcolors" ) || ( Token == "lightcolors" )
|| ( Token == "angles" ); || ( Token == "angles" )
|| ( Token == "notransition" );
} }
bool TAnimModel::Load(cParser *parser, bool ter) bool TAnimModel::Load(cParser *parser, bool ter)
@@ -529,6 +530,10 @@ bool TAnimModel::Load(cParser *parser, bool ter)
>> vAngle[ 2 ]; >> vAngle[ 2 ];
} }
if( token == "notransition" ) {
m_transition = false;
}
} while( ( false == token.empty() ) } while( ( false == token.empty() )
&& ( token != "endmodel" ) ); && ( token != "endmodel" ) );
@@ -589,6 +594,13 @@ void TAnimModel::RaAnimate( unsigned int const Framestamp ) {
auto &timer { m_lighttimers[ idx ] }; auto &timer { m_lighttimers[ idx ] };
if( ( modeintegral < ls_Blink ) && ( modefractional < 0.01f ) ) { if( ( modeintegral < ls_Blink ) && ( modefractional < 0.01f ) ) {
// simple flip modes // simple flip modes
auto const transitiontime { (
m_transition ?
std::min(
1.f,
std::min( fOnTime, fOffTime ) * 0.9f ) :
0.01f ) };
switch( mode ) { switch( mode ) {
case ls_Off: { case ls_Off: {
// reduce to zero // reduce to zero
@@ -597,14 +609,14 @@ void TAnimModel::RaAnimate( unsigned int const Framestamp ) {
} }
case ls_On: { case ls_On: {
// increase to max value // increase to max value
timer = std::min<float>( fTransitionTime, timer + timedelta ); timer = std::min<float>( transitiontime, timer + timedelta );
break; break;
} }
default: { default: {
break; break;
} }
} }
opacity = timer / fTransitionTime; opacity = timer / transitiontime;
} }
else { else {
// blink modes // blink modes
@@ -618,10 +630,12 @@ void TAnimModel::RaAnimate( unsigned int const Framestamp ) {
( mode == ls_Off ) ? ontime : ( mode == ls_Off ) ? ontime :
( mode == ls_On ) ? ( fOnTime + fOffTime ) - ontime : ( mode == ls_On ) ? ( fOnTime + fOffTime ) - ontime :
fOffTime ) }; // fallback fOffTime ) }; // fallback
auto const transitiontime { auto const transitiontime { (
std::min( m_transition ?
1.f, std::min(
std::min( ontime, offtime ) * 0.9f ) }; 1.f,
std::min( ontime, offtime ) * 0.9f ) :
0.01f ) };
timer = clamp_circular<float>( timer + timedelta * ( lsLights[ idx ] > 0.f ? 1.f : -1.f ), ontime + offtime ); timer = clamp_circular<float>( timer + timedelta * ( lsLights[ idx ] > 0.f ? 1.f : -1.f ), ontime + offtime );
// set opacity depending on blink stage // set opacity depending on blink stage
@@ -958,6 +972,10 @@ TAnimModel::export_as_text_( std::ostream &Output ) const {
Output << lsLights[ lightidx ] << ' '; Output << lsLights[ lightidx ] << ' ';
} }
} }
// potential light transition switch
if( false == m_transition ) {
Output << "notransition" << ' ';
}
// footer // footer
Output Output
<< "endmodel" << "endmodel"

View File

@@ -198,7 +198,8 @@ private:
std::array<float, iMaxNumLights> m_lightopacities; // {1} in constructor std::array<float, iMaxNumLights> m_lightopacities; // {1} in constructor
float fOnTime { 1.f / 2 };// { 60.f / 45.f / 2 }; float fOnTime { 1.f / 2 };// { 60.f / 45.f / 2 };
float fOffTime { 1.f / 2 };// { 60.f / 45.f / 2 }; // były stałymi, teraz mogą być zmienne dla każdego egzemplarza float fOffTime { 1.f / 2 };// { 60.f / 45.f / 2 }; // były stałymi, teraz mogą być zmienne dla każdego egzemplarza
float fTransitionTime { fOnTime * 0.9f }; // time // float fTransitionTime { fOnTime * 0.9f }; // time
bool m_transition { true }; // smooth transition between light states
unsigned int m_framestamp { 0 }; // id of last rendered gfx frame unsigned int m_framestamp { 0 }; // id of last rendered gfx frame
}; };

View File

@@ -190,7 +190,7 @@ void TCamera::Update()
auto movement { Velocity * -2.0 }; auto movement { Velocity * -2.0 };
movement.y = -movement.y; movement.y = -movement.y;
if( ( m_owner->ctOwner ) if( ( m_owner->ctOwner )
&& ( m_owner->ctOwner->Vehicle()->MoverParameters->CabOccupied < 0 ) ) { && ( m_owner->ctOwner->Vehicle()->DirectionGet() != m_owner->DirectionGet() ) ) {
movement *= -1.f; movement *= -1.f;
movement.y = -movement.y; movement.y = -movement.y;
} }

View File

@@ -1909,24 +1909,24 @@ void TController::Activation()
mvOccupied->CabOccupied = mvOccupied->CabActive; // użytkownik moze zmienić CabOccupied wychodząc mvOccupied->CabOccupied = mvOccupied->CabActive; // użytkownik moze zmienić CabOccupied wychodząc
mvOccupied->CabDeactivisation(); // tak jest w Train.cpp mvOccupied->CabDeactivisation(); // tak jest w Train.cpp
// przejście AI na drugą stronę EN57, ET41 itp. // przejście AI na drugą stronę EN57, ET41 itp.
while (TestFlag(d->MoverParameters->Couplers[iDirection < 0 ? end::rear : end::front].CouplingFlag, coupling::control)) {
{ // jeśli pojazd z przodu jest ukrotniony, to przechodzimy do niego int movedirection { ( iDirection < 0 ? end::rear : end::front ) };
d = iDirection * d->DirectionGet() < 0 ? d->Next() : d = pVehicle->FirstFind( movedirection, coupling::control );
d->Prev(); // przechodzimy do następnego członu if( pVehicle != d ) {
if (d)
{
drugi = d->Mechanik; // zapamiętanie tego, co ewentualnie tam siedzi, żeby w razie dwóch zamienić miejscami drugi = d->Mechanik; // zapamiętanie tego, co ewentualnie tam siedzi, żeby w razie dwóch zamienić miejscami
d->Mechanik = this; // na razie bilokacja d->Mechanik = this; // na razie bilokacja
d->MoverParameters->SetInternalCommand("", 0, 0); // usunięcie ewentualnie zalegającej komendy (Change_direction?) d->MoverParameters->SetInternalCommand("", 0, 0); // usunięcie ewentualnie zalegającej komendy (Change_direction?)
if (d->DirectionGet() != pVehicle->DirectionGet()) // jeśli są przeciwne do siebie if( d->DirectionGet() != pVehicle->DirectionGet() ) {
iDirection = -iDirection; // to będziemy jechać w drugą stronę względem zasiedzianego pojazdu // jeśli są przeciwne do siebie to będziemy jechać w drugą stronę względem zasiedzianego pojazdu
iDirection = -iDirection;
}
pVehicle->Mechanik = drugi; // wsadzamy tego, co ewentualnie był (podwójna trakcja) pVehicle->Mechanik = drugi; // wsadzamy tego, co ewentualnie był (podwójna trakcja)
/*
pVehicle->MoverParameters->CabActive = 0; // wyłączanie kabin po drodze pVehicle->MoverParameters->CabActive = 0; // wyłączanie kabin po drodze
pVehicle->MoverParameters->CabOccupied = 0; // i zaznaczenie, że nie ma tam nikogo pVehicle->MoverParameters->CabOccupied = 0; // i zaznaczenie, że nie ma tam nikogo
*/
pVehicle = d; // a mechu ma nowy pojazd (no, człon) pVehicle = d; // a mechu ma nowy pojazd (no, człon)
} }
else
break; // jak koniec składu, to mechanik dalej nie idzie
} }
if (pVehicle != old) if (pVehicle != old)
{ // jeśli zmieniony został pojazd prowadzony { // jeśli zmieniony został pojazd prowadzony
@@ -2371,7 +2371,7 @@ bool TController::CheckVehicles(TOrders user)
( ( mvControlling->EngineType == TEngineType::DieselElectric ) ( ( mvControlling->EngineType == TEngineType::DieselElectric )
|| ( mvControlling->EngineType == TEngineType::DieselEngine ) ) ? ( Global.AirTemperature < 10 ) : || ( mvControlling->EngineType == TEngineType::DieselEngine ) ) ? ( Global.AirTemperature < 10 ) :
true ); true );
} }
} }
else { // gdy człowiek i gdy nastąpiło połącznie albo rozłączenie else { // gdy człowiek i gdy nastąpiło połącznie albo rozłączenie
// Ra 2014-02: lepiej tu niż w pętli obsługującej komendy, bo tam się zmieni informacja o składzie // Ra 2014-02: lepiej tu niż w pętli obsługującej komendy, bo tam się zmieni informacja o składzie
@@ -3197,7 +3197,7 @@ bool TController::DecBrakeEIM()
{ {
case 0: { case 0: {
if( mvOccupied->MED_amax != 9.81 ) { if( mvOccupied->MED_amax != 9.81 ) {
auto const brakeposition { clamp( -1.0 * mvOccupied->AIHintLocalBrakeAccFactor * AccDesired / mvOccupied->MED_amax, 0.0, 1.0 ) }; auto const brakeposition { clamp( -1.0 * mvOccupied->AIHintLocalBrakeAccFactor * std::max( 0.0, AccDesired ) / mvOccupied->MED_amax, 0.0, 1.0 ) };
OK = ( brakeposition != mvOccupied->LocalBrakePosA ); OK = ( brakeposition != mvOccupied->LocalBrakePosA );
mvOccupied->LocalBrakePosA = brakeposition; mvOccupied->LocalBrakePosA = brakeposition;
} }

View File

@@ -4298,7 +4298,7 @@ void TDynamicObject::RenderSounds() {
// NBMX sygnal odjazdu // NBMX sygnal odjazdu
if( MoverParameters->Doors.has_warning ) { if( MoverParameters->Doors.has_warning ) {
auto const lowvoltagepower { MoverParameters->Power24vIsAvailable || MoverParameters->Power110vIsAvailable }; auto const lowvoltagepower { MoverParameters->Power24vIsAvailable || MoverParameters->Power110vIsAvailable };
for( auto &speaker : m_speakers ) { for( auto &doorspeaker : m_doorspeakers ) {
// TBD, TODO: per-location door state triggers? // TBD, TODO: per-location door state triggers?
if( ( MoverParameters->DepartureSignal ) if( ( MoverParameters->DepartureSignal )
&& ( lowvoltagepower ) && ( lowvoltagepower )
@@ -4310,30 +4310,31 @@ void TDynamicObject::RenderSounds() {
) { ) {
// for the autonomous doors play the warning automatically whenever a door is closing // for the autonomous doors play the warning automatically whenever a door is closing
// MC: pod warunkiem ze jest zdefiniowane w chk // MC: pod warunkiem ze jest zdefiniowane w chk
speaker.departure_signal.play( sound_flags::exclusive | sound_flags::looping ); doorspeaker.departure_signal.play( sound_flags::exclusive | sound_flags::looping );
} }
else { else {
speaker.departure_signal.stop(); doorspeaker.departure_signal.stop();
} }
} }
} }
// announcements // announcements
for( auto &speaker : m_speakers ) { {
auto const lowvoltagepower { MoverParameters->Power24vIsAvailable || MoverParameters->Power110vIsAvailable }; auto const lowvoltagepower { MoverParameters->Power24vIsAvailable || MoverParameters->Power110vIsAvailable };
if( lowvoltagepower ) { if( lowvoltagepower ) {
// speaker is powered up, can play queued announcements // system is powered up, can play queued announcements
if( speaker.announcement.is_playing() ) { continue; } if( ( false == m_pasystem.announcement_queue.empty() )
if( speaker.announcement_queue.empty() ) { continue; } && ( false == m_pasystem.announcement.is_playing() ) ) {
// pull first sound from the queue // pull first sound from the queue
speaker.announcement = speaker.announcement_queue.front(); m_pasystem.announcement = m_pasystem.announcement_queue.front();
speaker.announcement.owner( this ); m_pasystem.announcement.owner( this );
speaker.announcement.offset( speaker.offset ); m_pasystem.announcement.range( 0.5 * MoverParameters->Dim.L * -1 );
speaker.announcement.play(); m_pasystem.announcement.play();
speaker.announcement_queue.pop_front(); m_pasystem.announcement_queue.pop_front();
}
} }
else { else {
speaker.announcement.stop(); m_pasystem.announcement.stop();
speaker.announcement_queue.clear(); m_pasystem.announcement_queue.clear();
} }
} }
// NBMX Obsluga drzwi, MC: zuniwersalnione // NBMX Obsluga drzwi, MC: zuniwersalnione
@@ -5708,7 +5709,7 @@ void TDynamicObject::LoadMMediaFile( std::string const &TypeName, std::string co
sound_source soundtemplate { sound_placement::general, 25.f }; sound_source soundtemplate { sound_placement::general, 25.f };
soundtemplate.deserialize( parser, sound_type::multipart, sound_parameters::range ); soundtemplate.deserialize( parser, sound_type::multipart, sound_parameters::range );
soundtemplate.owner( this ); soundtemplate.owner( this );
for( auto &speaker : m_speakers ) { for( auto &speaker : m_doorspeakers ) {
speaker.departure_signal = soundtemplate; speaker.departure_signal = soundtemplate;
speaker.departure_signal.offset( speaker.offset ); speaker.departure_signal.offset( speaker.offset );
} }
@@ -5787,11 +5788,13 @@ void TDynamicObject::LoadMMediaFile( std::string const &TypeName, std::string co
} }
else if( token == "unloading:" ) { else if( token == "unloading:" ) {
m_exchangesounds.unloading.range( MoverParameters->Dim.L * 0.5f * -1 );
m_exchangesounds.unloading.deserialize( parser, sound_type::single ); m_exchangesounds.unloading.deserialize( parser, sound_type::single );
m_exchangesounds.unloading.owner( this ); m_exchangesounds.unloading.owner( this );
} }
else if( token == "loading:" ) { else if( token == "loading:" ) {
m_exchangesounds.loading.range( MoverParameters->Dim.L * 0.5f * -1 );
m_exchangesounds.loading.deserialize( parser, sound_type::single ); m_exchangesounds.loading.deserialize( parser, sound_type::single );
m_exchangesounds.loading.owner( this ); m_exchangesounds.loading.owner( this );
} }
@@ -5878,10 +5881,10 @@ void TDynamicObject::LoadMMediaFile( std::string const &TypeName, std::string co
if( announcementtype == announcement_t::idle ) { if( announcementtype == announcement_t::idle ) {
continue; continue;
} }
sound_source soundtemplate { sound_placement::general, EU07_SOUND_CABANNOUNCEMENTCUTOFFRANGE }; sound_source soundtemplate { sound_placement::engine }; // NOTE: sound range gets filled by pa system
soundtemplate.deserialize( announcementsound, sound_type::single ); soundtemplate.deserialize( announcementsound, sound_type::single );
soundtemplate.owner( this ); soundtemplate.owner( this );
m_announcements[ static_cast<int>( announcementtype ) ] = soundtemplate; m_pasystem.announcements[ static_cast<int>( announcementtype ) ] = soundtemplate;
} }
} }
} }
@@ -5933,10 +5936,9 @@ void TDynamicObject::LoadMMediaFile( std::string const &TypeName, std::string co
door.step_open.offset( location ); door.step_open.offset( location );
m_doorsounds.emplace_back( door ); m_doorsounds.emplace_back( door );
} }
m_speakers.emplace_back( m_doorspeakers.emplace_back(
speaker_sounds { doorspeaker_sounds {
{ 0.f, 3.f, offset }, { 0.f, 3.f, offset },
{},
{} } ); {} } );
} }
} }
@@ -7053,7 +7055,7 @@ material_handle TDynamicObject::DestinationFind( std::string Destination ) {
void TDynamicObject::announce( announcement_t const Announcement, bool const Chime ) { void TDynamicObject::announce( announcement_t const Announcement, bool const Chime ) {
if( m_speakers.empty() ) { return; } if( m_doorspeakers.empty() ) { return; }
auto const *driver { ( auto const *driver { (
ctOwner != nullptr ? ctOwner != nullptr ?
@@ -7062,9 +7064,10 @@ void TDynamicObject::announce( announcement_t const Announcement, bool const Chi
if( driver == nullptr ) { return; } if( driver == nullptr ) { return; }
auto const &timetable { driver->TrainTimetable() }; auto const &timetable { driver->TrainTimetable() };
auto const &announcements { m_pasystem.announcements };
auto playchime { Chime }; auto playchime { Chime };
if( m_announcements[ static_cast<int>( Announcement ) ].empty() ) { if( announcements[ static_cast<int>( Announcement ) ].empty() ) {
goto followup; goto followup;
} }
// if the announcement sound was defined queue playback // if the announcement sound was defined queue playback
@@ -7093,17 +7096,13 @@ void TDynamicObject::announce( announcement_t const Announcement, bool const Chi
} }
// potentially precede the announcement with a chime... // potentially precede the announcement with a chime...
if( ( true == playchime ) if( ( true == playchime )
&& ( false == m_announcements[ static_cast<int>( announcement_t::chime ) ].empty() ) ) { && ( false == announcements[ static_cast<int>( announcement_t::chime ) ].empty() ) ) {
for( auto &speaker : m_speakers ) { m_pasystem.announcement_queue.emplace_back( announcements[ static_cast<int>( announcement_t::chime ) ] );
speaker.announcement_queue.emplace_back( m_announcements[ static_cast<int>( announcement_t::chime ) ] );
}
playchime = false; playchime = false;
} }
// ...then play the announcement itself // ...then play the announcement itself
for( auto &speaker : m_speakers ) { m_pasystem.announcement_queue.emplace_back( announcements[ static_cast<int>( Announcement ) ] );
speaker.announcement_queue.emplace_back( m_announcements[ static_cast<int>( Announcement ) ] ); m_pasystem.announcement_queue.emplace_back( stopnamesound );
speaker.announcement_queue.emplace_back( stopnamesound );
}
} }
followup: followup:
// potentially follow up with another announcement // potentially follow up with another announcement

View File

@@ -406,9 +406,13 @@ private:
void render( TMoverParameters const &Vehicle, double const Deltatime ); void render( TMoverParameters const &Vehicle, double const Deltatime );
}; };
// single source per door (pair) on the centreline // single source per door (pair) on the centreline
struct speaker_sounds { struct doorspeaker_sounds {
glm::vec3 offset; glm::vec3 offset;
sound_source departure_signal; sound_source departure_signal;
};
// single source per vehicle
struct pasystem_sounds {
std::array<sound_source, static_cast<int>( announcement_t::end )> announcements;
sound_source announcement; sound_source announcement;
std::deque<sound_source> announcement_queue; // fifo queue std::deque<sound_source> announcement_queue; // fifo queue
}; };
@@ -509,8 +513,8 @@ private:
exchange_data m_exchange; // state of active load exchange procedure, if any exchange_data m_exchange; // state of active load exchange procedure, if any
exchange_sounds m_exchangesounds; // sounds associated with the load exchange exchange_sounds m_exchangesounds; // sounds associated with the load exchange
std::vector<speaker_sounds> m_speakers; std::vector<doorspeaker_sounds> m_doorspeakers;
std::array<sound_source, static_cast<int>( announcement_t::end )> m_announcements; pasystem_sounds m_pasystem;
coupleradapter_data m_coupleradapter; coupleradapter_data m_coupleradapter;

View File

@@ -17,6 +17,7 @@ http://mozilla.org/MPL/2.0/.
#include "Event.h" #include "Event.h"
#include "simulation.h" #include "simulation.h"
#include "simulationtime.h"
#include "messaging.h" #include "messaging.h"
#include "Globals.h" #include "Globals.h"
#include "MemCell.h" #include "MemCell.h"
@@ -307,6 +308,10 @@ basic_event::deserialize( cParser &Input, scene::scratch_data &Scratchpad ) {
Input.getTokens(); Input.getTokens();
Input >> m_delayrandom; // Ra 2014-03-11 Input >> m_delayrandom; // Ra 2014-03-11
} }
if( token == "departuredelay" ) { // timetable-based delay
Input.getTokens();
Input >> m_delaydeparture;
}
Input.getTokens(); Input.getTokens();
} }
} }
@@ -363,6 +368,11 @@ basic_event::export_as_text( std::ostream &Output ) const {
<< "randomdelay " << "randomdelay "
<< m_delayrandom << ' '; << m_delayrandom << ' ';
} }
if( false == std::isnan( m_delayrandom ) ) {
Output
<< "departuredelay "
<< m_delaydeparture << ' ';
}
// footer // footer
Output Output
<< "endevent" << "endevent"
@@ -428,9 +438,10 @@ basic_event::input_location() const {
bool bool
basic_event::is_keyword( std::string const &Token ) { basic_event::is_keyword( std::string const &Token ) {
// TODO: convert to array lookup if keyword list gets longer
return ( Token == "endevent" ) return ( Token == "endevent" )
|| ( Token == "randomdelay" ); || ( Token == "randomdelay" )
|| ( Token == "departuredelay" );
} }
@@ -2289,11 +2300,25 @@ event_manager::AddToQuery( basic_event *Event, TDynamicObject const *Owner ) {
// standardowe dodanie do kolejki // standardowe dodanie do kolejki
++(Event->m_inqueue); // zabezpieczenie przed podwójnym dodaniem do kolejki ++(Event->m_inqueue); // zabezpieczenie przed podwójnym dodaniem do kolejki
WriteLog( "EVENT ADDED TO QUEUE" + ( Owner ? ( " by " + Owner->asName ) : "" ) + ": " + Event->m_name ); WriteLog( "EVENT ADDED TO QUEUE" + ( Owner ? ( " by " + Owner->asName ) : "" ) + ": " + Event->m_name );
Event->m_launchtime = std::abs( Event->m_delay ) + Timer::GetTime(); // czas od uruchomienia scenerii Event->m_launchtime = Timer::GetTime() + std::abs( Event->m_delay ); // czas od uruchomienia scenerii
if( Event->m_delayrandom > 0.0 ) { if( Event->m_delayrandom > 0.0 ) {
// doliczenie losowego czasu opóźnienia // doliczenie losowego czasu opóźnienia
Event->m_launchtime += Event->m_delayrandom * Random(); Event->m_launchtime += Event->m_delayrandom * Random();
} }
if( ( Owner != nullptr )
&& ( false == std::isnan( Event->m_delaydeparture ) ) ) {
auto const *timetableowner { (
( ( Owner->Mechanik != nullptr ) && ( Owner->Mechanik->primary() ) ) ?
Owner->Mechanik :
Owner->ctOwner ) };
if( timetableowner != nullptr ) {
auto const &timetable { timetableowner->TrainTimetable() };
auto const &time { simulation::Time.data() };
Event->m_launchtime +=
timetable.seconds_until_departure( time.wHour, time.wMinute + time.wSecond * 0.0167 )
+ Event->m_delaydeparture;
}
}
if( QueryRootEvent != nullptr ) { if( QueryRootEvent != nullptr ) {
basic_event *target { QueryRootEvent }; basic_event *target { QueryRootEvent };
basic_event *previous { nullptr }; basic_event *previous { nullptr };

View File

@@ -91,6 +91,7 @@ public:
double m_launchtime { 0.0 }; double m_launchtime { 0.0 };
double m_delay { 0.0 }; double m_delay { 0.0 };
double m_delayrandom { 0.0 }; // zakres dodatkowego opóźnienia // standardowo nie będzie dodatkowego losowego opóźnienia double m_delayrandom { 0.0 }; // zakres dodatkowego opóźnienia // standardowo nie będzie dodatkowego losowego opóźnienia
double m_delaydeparture { std::numeric_limits<double>::quiet_NaN() }; // departure-based event delay
protected: protected:
// types // types

View File

@@ -6025,7 +6025,9 @@ bool TTrain::Update( double const Deltatime )
} }
} }
// helper variables // helper variables
m_doors = ( DynamicObject->Mechanik->IsAnyDoorOpen[ side::right ] || DynamicObject->Mechanik->IsAnyDoorOpen[ side::left ] ); if( DynamicObject->Mechanik != nullptr ) {
m_doors = ( DynamicObject->Mechanik->IsAnyDoorOpen[ side::right ] || DynamicObject->Mechanik->IsAnyDoorOpen[ side::left ] );
}
m_dirforward = ( mvControlled->DirActive > 0 ); m_dirforward = ( mvControlled->DirActive > 0 );
m_dirneutral = ( mvControlled->DirActive == 0 ); m_dirneutral = ( mvControlled->DirActive == 0 );
m_dirbackward = ( mvControlled->DirActive <0 ); m_dirbackward = ( mvControlled->DirActive <0 );
@@ -6991,9 +6993,9 @@ bool TTrain::Update( double const Deltatime )
} }
ggLocalBrake.Update(); ggLocalBrake.Update();
} }
ggDirForwardButton.Update(); ggDirForwardButton.Update( lowvoltagepower );
ggDirNeutralButton.Update(); ggDirNeutralButton.Update( lowvoltagepower );
ggDirBackwardButton.Update(); ggDirBackwardButton.Update( lowvoltagepower );
ggAlarmChain.Update(); ggAlarmChain.Update();
ggBrakeProfileCtrl.Update(); ggBrakeProfileCtrl.Update();
ggBrakeProfileG.Update(); ggBrakeProfileG.Update();
@@ -7001,8 +7003,8 @@ bool TTrain::Update( double const Deltatime )
ggBrakeOperationModeCtrl.Update(); ggBrakeOperationModeCtrl.Update();
ggMaxCurrentCtrl.Update(); ggMaxCurrentCtrl.Update();
// NBMX wrzesien 2003 - drzwi // NBMX wrzesien 2003 - drzwi
ggDoorLeftPermitButton.Update(); ggDoorLeftPermitButton.Update( lowvoltagepower );
ggDoorRightPermitButton.Update(); ggDoorRightPermitButton.Update( lowvoltagepower );
ggDoorPermitPresetButton.Update(); ggDoorPermitPresetButton.Update();
ggDoorLeftButton.Update(); ggDoorLeftButton.Update();
ggDoorRightButton.Update(); ggDoorRightButton.Update();
@@ -7011,7 +7013,7 @@ bool TTrain::Update( double const Deltatime )
ggDoorLeftOffButton.Update(); ggDoorLeftOffButton.Update();
ggDoorRightOffButton.Update(); ggDoorRightOffButton.Update();
ggDoorAllOnButton.Update(); ggDoorAllOnButton.Update();
ggDoorAllOffButton.Update(); ggDoorAllOffButton.Update( lowvoltagepower );
ggDoorSignallingButton.Update(); ggDoorSignallingButton.Update();
// NBMX dzwignia sprezarki // NBMX dzwignia sprezarki
ggCompressorButton.Update(); ggCompressorButton.Update();
@@ -7534,6 +7536,7 @@ void TTrain::update_sounds_radio() {
for( auto &message : m_radiomessages ) { for( auto &message : m_radiomessages ) {
auto const volume { auto const volume {
( true == radioenabled ) ( true == radioenabled )
&& ( Dynamic()->Mechanik != nullptr )
&& ( message.first == RadioChannel() ) ? && ( message.first == RadioChannel() ) ?
Global.RadioVolume : Global.RadioVolume :
0.0 }; 0.0 };
@@ -8125,24 +8128,13 @@ bool TTrain::InitializeCab(int NewCabNo, std::string const &asFileName)
Math3D::vector3 TTrain::MirrorPosition(bool lewe) Math3D::vector3 TTrain::MirrorPosition(bool lewe)
{ // zwraca współrzędne widoku kamery z lusterka { // zwraca współrzędne widoku kamery z lusterka
switch (iCabn) auto const shiftdirection { ( lewe ? -1 : 1 ) * ( iCabn == 2 ? 1 : -1 ) };
{
case 2: // tylna (-1) return DynamicObject->mMatrix
return DynamicObject->mMatrix * * Math3D::vector3(
Math3D::vector3( mvOccupied->Dim.W * ( 0.5 * shiftdirection ) + ( 0.2 * shiftdirection ),
mvOccupied->Dim.W * ( lewe ? -0.5 : 0.5 ) + 0.2 * ( lewe ? -1 : 1 ), 1.5 + Cabine[iCabn].CabPos1.y,
1.5 + Cabine[iCabn].CabPos1.y, interpolate( Cabine[ iCabn ].CabPos1.z , Cabine[ iCabn ].CabPos2.z, 0.5 ) );
Cabine[iCabn].CabPos1.z);
case 1: // przednia (1)
[[fallthrough]];
default:
return DynamicObject->mMatrix *
Math3D::vector3(
mvOccupied->Dim.W * ( lewe ? 0.5 : -0.5 ) + 0.2 * ( lewe ? 1 : -1 ),
1.5 + Cabine[iCabn].CabPos1.y,
Cabine[iCabn].CabPos2.z);
}
// return DynamicObject->GetPosition(); // współrzędne środka pojazdu
}; };
void TTrain::DynamicSet(TDynamicObject *d) void TTrain::DynamicSet(TDynamicObject *d)
@@ -8337,6 +8329,7 @@ TTrain::radio_message( sound_source *Message, int const Channel ) {
auto const radioenabled { ( true == mvOccupied->Radio ) && ( mvOccupied->Power24vIsAvailable || mvOccupied->Power110vIsAvailable ) }; auto const radioenabled { ( true == mvOccupied->Radio ) && ( mvOccupied->Power24vIsAvailable || mvOccupied->Power110vIsAvailable ) };
auto const volume { auto const volume {
( true == radioenabled ) ( true == radioenabled )
&& ( Dynamic()->Mechanik != nullptr )
&& ( Channel == RadioChannel() ) ? && ( Channel == RadioChannel() ) ?
1.0 : 1.0 :
0.0 }; 0.0 };

View File

@@ -135,8 +135,9 @@ openal_source::sync_with( sound_properties const &State ) {
// location // location
properties.location = State.location; properties.location = State.location;
sound_distance = properties.location - glm::dvec3 { Global.pCamera.Pos }; sound_distance = properties.location - glm::dvec3 { Global.pCamera.Pos };
if( sound_range > 0 ) { if( sound_range != -1 ) {
// range cutoff check // range cutoff check for songs other than 'unlimited'
// NOTE: since we're comparing squared distances we can ignore that sound range can be negative
auto const cutoffrange = ( auto const cutoffrange = (
is_multipart ? is_multipart ?
EU07_SOUND_CUTOFFRANGE : // we keep multi-part sounds around longer, to minimize restarts as the sounds get out and back in range EU07_SOUND_CUTOFFRANGE : // we keep multi-part sounds around longer, to minimize restarts as the sounds get out and back in range
@@ -151,7 +152,7 @@ openal_source::sync_with( sound_properties const &State ) {
::alSourcefv( id, AL_POSITION, glm::value_ptr( sound_distance ) ); ::alSourcefv( id, AL_POSITION, glm::value_ptr( sound_distance ) );
} }
else { else {
// sounds with 'unlimited' range are positioned on top of the listener // sounds with 'unlimited' or negative range are positioned on top of the listener
::alSourcefv( id, AL_POSITION, glm::value_ptr( glm::vec3() ) ); ::alSourcefv( id, AL_POSITION, glm::value_ptr( glm::vec3() ) );
} }
// gain // gain
@@ -168,7 +169,7 @@ openal_source::sync_with( sound_properties const &State ) {
5 ) }; // range of -1 means sound of unlimited range, positioned at the listener 5 ) }; // range of -1 means sound of unlimited range, positioned at the listener
::alSourcef( id, AL_REFERENCE_DISTANCE, range * ( 1.f / 16.f ) * properties.soundproofing ); ::alSourcef( id, AL_REFERENCE_DISTANCE, range * ( 1.f / 16.f ) * properties.soundproofing );
} }
if( sound_range > 0 ) { if( sound_range != -1 ) {
auto const rangesquared { sound_range * sound_range }; auto const rangesquared { sound_range * sound_range };
auto const distancesquared { glm::length2( sound_distance ) }; auto const distancesquared { glm::length2( sound_distance ) };
if( ( distancesquared > rangesquared ) if( ( distancesquared > rangesquared )
@@ -428,7 +429,7 @@ openal_renderer::fetch_source() {
continue; continue;
} }
auto const sourceweight { ( auto const sourceweight { (
source->sound_range > 0 ? source->sound_range != -1 ?
( source->sound_range * source->sound_range ) / ( glm::length2( source->sound_distance ) + 1 ) : ( source->sound_range * source->sound_range ) / ( glm::length2( source->sound_distance ) + 1 ) :
std::numeric_limits<float>::max() ) }; std::numeric_limits<float>::max() ) };
if( sourceweight < leastimportantweight ) { if( sourceweight < leastimportantweight ) {

View File

@@ -45,7 +45,7 @@ std::string TTrainParameters::NextStop() const
sound_source sound_source
TTrainParameters::next_stop_sound() const { TTrainParameters::next_stop_sound() const {
if( StationIndex > StationCount ) { if( StationIndex > StationCount ) {
return { sound_placement::general }; return { sound_placement::engine };
} }
for( auto stationidx { StationIndex }; stationidx < StationCount + 1; ++stationidx ) { for( auto stationidx { StationIndex }; stationidx < StationCount + 1; ++stationidx ) {
auto &station{ TimeTable[ stationidx ] }; auto &station{ TimeTable[ stationidx ] };
@@ -56,7 +56,7 @@ TTrainParameters::next_stop_sound() const {
return station.name_sound; return station.name_sound;
} }
// shouldn't normally get here, unless the timetable is malformed // shouldn't normally get here, unless the timetable is malformed
return { sound_placement::general }; return { sound_placement::engine };
} }
sound_source sound_source
@@ -98,7 +98,7 @@ sound_source TTrainParameters::current_stop_sound() const {
if( ( StationIndex <= StationCount ) ) if( ( StationIndex <= StationCount ) )
return TimeTable[ StationIndex ].name_sound; return TimeTable[ StationIndex ].name_sound;
else else
return { sound_placement::general }; return { sound_placement::engine };
} }
bool TTrainParameters::UpdateMTable( scenario_time const &Time, std::string const &NewName ) { bool TTrainParameters::UpdateMTable( scenario_time const &Time, std::string const &NewName ) {
@@ -181,6 +181,15 @@ bool TTrainParameters::IsTimeToGo(double hh, double mm)
return false; // dalej nie jechać return false; // dalej nie jechać
} }
// returns: difference between specified time and scheduled departure from current stop, in seconds
double TTrainParameters::seconds_until_departure( double const Hour, double const Minute ) const {
if( ( TimeTable[ StationIndex ].Ah < 0 ) ) { // passthrough
return 0;
}
return ( 60.0 * CompareTime( Hour, Minute, TimeTable[ StationIndex ].Dh, TimeTable[ StationIndex ].Dm ) );
}
std::string TTrainParameters::ShowRelation() const std::string TTrainParameters::ShowRelation() const
/*zwraca informację o relacji*/ /*zwraca informację o relacji*/
{ {
@@ -595,7 +604,7 @@ TTrainParameters::load_sounds() {
} }
// wczytanie dźwięku odjazdu w wersji radiowej (słychać tylko w kabinie) // wczytanie dźwięku odjazdu w wersji radiowej (słychać tylko w kabinie)
station.name_sound = station.name_sound =
sound_source{ sound_placement::general, EU07_SOUND_CABANNOUNCEMENTCUTOFFRANGE } sound_source{ sound_placement::engine, EU07_SOUND_CABANNOUNCEMENTCUTOFFRANGE }
.deserialize( lookup.first + lookup.second, sound_type::single ); .deserialize( lookup.first + lookup.second, sound_type::single );
} }
} }

View File

@@ -39,7 +39,7 @@ struct TMTableLine
float tm{ 0.f }; // czas jazdy do tej stacji w min. (z kolumny) float tm{ 0.f }; // czas jazdy do tej stacji w min. (z kolumny)
bool is_maintenance{ false }; bool is_maintenance{ false };
int radio_channel{ -1 }; int radio_channel{ -1 };
sound_source name_sound{ sound_placement::internal }; sound_source name_sound{ sound_placement::engine };
}; };
typedef TMTableLine TMTable[MaxTTableSize + 1]; typedef TMTableLine TMTable[MaxTTableSize + 1];
@@ -73,6 +73,8 @@ class TTrainParameters
bool IsLastStop() const; bool IsLastStop() const;
bool IsMaintenance() const; bool IsMaintenance() const;
bool IsTimeToGo(double hh, double mm); bool IsTimeToGo(double hh, double mm);
// returns: difference between specified time and scheduled departure from current stop, in seconds
double seconds_until_departure( double const Hour, double const Minute ) const;
bool UpdateMTable(double hh, double mm, std::string const &NewName); bool UpdateMTable(double hh, double mm, std::string const &NewName);
bool UpdateMTable( scenario_time const &Time, std::string const &NewName ); bool UpdateMTable( scenario_time const &Time, std::string const &NewName );
bool RewindTimeTable( std::string actualStationName ); bool RewindTimeTable( std::string actualStationName );

105
sound.cpp
View File

@@ -341,8 +341,8 @@ sound_source::play( int const Flags ) {
// NOTE: we cache the flags early, even if the sound is out of range, to mark activated event sounds // NOTE: we cache the flags early, even if the sound is out of range, to mark activated event sounds
m_flags = Flags; m_flags = Flags;
if( m_range > 0 ) { if( m_range != -1 ) {
auto const cutoffrange { m_range * 5 }; auto const cutoffrange { std::abs( m_range * 5 ) };
if( glm::length2( location() - glm::dvec3 { Global.pCamera.Pos } ) > std::min( 2750.f * 2750.f, cutoffrange * cutoffrange ) ) { if( glm::length2( location() - glm::dvec3 { Global.pCamera.Pos } ) > std::min( 2750.f * 2750.f, cutoffrange * cutoffrange ) ) {
// while we drop sounds from beyond sensible and/or audible range // while we drop sounds from beyond sensible and/or audible range
// we act as if it was activated normally, meaning no need to include the opening bookend in subsequent calls // we act as if it was activated normally, meaning no need to include the opening bookend in subsequent calls
@@ -887,6 +887,12 @@ sound_source::location() const {
+ m_owner->VectorFront() * m_offset.z }; + m_owner->VectorFront() * m_offset.z };
} }
void
sound_source::range( float const Range ) {
m_range = Range;
}
// returns defined range of the sound // returns defined range of the sound
float const float const
sound_source::range() const { sound_source::range() const {
@@ -920,24 +926,31 @@ sound_source::update_location() {
m_properties.location = location(); m_properties.location = location();
} }
float const EU07_SOUNDPROOFING_STRONG { 0.5f }; // 0.25 after squaring float const EU07_SOUNDPROOFING_GLOBAL_VERYSTRONG { 0.01f };
float const EU07_SOUNDPROOFING_SOME { 0.8f }; // ~0.65 after squaring float const EU07_SOUNDPROOFING_GLOBAL_STRONG { std::sqrtf( 0.025 ) };
float const EU07_SOUNDPROOFING_GLOBAL_SOME { std::sqrtf( 0.15 ) };
float const EU07_SOUNDPROOFING_GLOBAL_NONE { std::sqrtf( 0.40 ) };
float const EU07_SOUNDPROOFING_STRONG { std::sqrtf( 0.20 ) };
float const EU07_SOUNDPROOFING_SOME { std::sqrtf( 0.65 ) };
float const EU07_SOUNDPROOFING_NONE { 1.f }; float const EU07_SOUNDPROOFING_NONE { 1.f };
bool bool
sound_source::update_soundproofing() { sound_source::update_soundproofing() {
// NOTE, HACK: current cab id can vary from -1 to +1, and we use another higher priority value for open cab window // NOTE, HACK: current cab id can vary from -1 to +1, and we use higher priority values for open cab window and external views
// we use this as modifier to force re-calculations when moving between compartments or changing window state // we use this as modifier to force re-calculations when moving between compartments or changing window state
int const occupiedcab = ( int const occupiedcab = (
Global.CabWindowOpen ? 2 : Global.CabWindowOpen ? 2 :
FreeFlyModeFlag ? 0 : FreeFlyModeFlag ? (
Global.pCamera.m_owner ?
3 :
0 ) :
( simulation::Train ? ( simulation::Train ?
simulation::Train->Occupied()->CabOccupied : simulation::Train->Occupied()->CabOccupied :
0 ) ); 0 ) );
// location-based gain factor: // location-based gain factor:
std::uintptr_t soundproofingstamp = reinterpret_cast<std::uintptr_t>( ( std::uintptr_t soundproofingstamp = reinterpret_cast<std::uintptr_t>( (
FreeFlyModeFlag ? FreeFlyModeFlag ?
nullptr : Global.pCamera.m_owner :
( simulation::Train ? ( simulation::Train ?
simulation::Train->Dynamic() : simulation::Train->Dynamic() :
nullptr ) ) ) nullptr ) ) )
@@ -948,36 +961,72 @@ sound_source::update_soundproofing() {
// listener location has changed, calculate new location-based gain factor // listener location has changed, calculate new location-based gain factor
switch( m_placement ) { switch( m_placement ) {
case sound_placement::general: { case sound_placement::general: {
m_properties.soundproofing = EU07_SOUNDPROOFING_NONE; m_properties.soundproofing = (
m_range >= -1 ?
EU07_SOUNDPROOFING_NONE :
EU07_SOUNDPROOFING_GLOBAL_NONE );
break; break;
} }
case sound_placement::external: { case sound_placement::external: {
m_properties.soundproofing = ( if( m_range >= -1 ) { // limited range sound...
( ( soundproofingstamp == 0 ) || ( true == Global.CabWindowOpen ) ) ? m_properties.soundproofing = (
EU07_SOUNDPROOFING_NONE : // listener outside or has a window open ( soundproofingstamp == 0 ? EU07_SOUNDPROOFING_NONE : // ...and listener outside
EU07_SOUNDPROOFING_STRONG ); // listener in a vehicle with windows shut true == Global.CabWindowOpen ? EU07_SOUNDPROOFING_SOME : // ...and window open
EU07_SOUNDPROOFING_STRONG ) ); // ...and window closed
}
else { // global sound...
auto const externalcamera { ( Global.CabWindowOpen ) || ( Global.pCamera.m_owner && FreeFlyModeFlag ) };
m_properties.soundproofing = (
( soundproofingstamp == 0 ? EU07_SOUNDPROOFING_GLOBAL_NONE : // ...and listener outside
externalcamera ? EU07_SOUNDPROOFING_GLOBAL_STRONG : // ...and window open
EU07_SOUNDPROOFING_GLOBAL_VERYSTRONG ) ); // ...and window closed
}
break; break;
} }
case sound_placement::internal: { case sound_placement::internal: {
m_properties.soundproofing = ( if( m_range >= -1 ) {
soundproofingstamp == 0 ? m_properties.soundproofing = (
EU07_SOUNDPROOFING_STRONG : // listener outside HACK: won't be true if active vehicle has open window soundproofingstamp == 0 ?
( simulation::Train->Dynamic() != m_owner ? EU07_SOUNDPROOFING_STRONG : // listener outside HACK: won't be true if active vehicle has open window
EU07_SOUNDPROOFING_STRONG : // in another vehicle ( simulation::Train->Dynamic() != m_owner ?
( occupiedcab == 0 ? EU07_SOUNDPROOFING_STRONG : // in another vehicle
EU07_SOUNDPROOFING_STRONG : // listener in the engine compartment ( occupiedcab == 0 ?
EU07_SOUNDPROOFING_NONE ) ) ); // listener in the cab of the same vehicle EU07_SOUNDPROOFING_STRONG : // listener in the engine compartment
EU07_SOUNDPROOFING_NONE ) ) ); // listener in the cab of the same vehicle
}
else {
m_properties.soundproofing = (
soundproofingstamp == 0 ?
EU07_SOUNDPROOFING_GLOBAL_STRONG : // listener outside HACK: won't be true if active vehicle has open window
( simulation::Train->Dynamic() != m_owner ?
EU07_SOUNDPROOFING_GLOBAL_VERYSTRONG : // in another vehicle
( occupiedcab == 0 ?
EU07_SOUNDPROOFING_GLOBAL_NONE : // listener in the engine compartment
EU07_SOUNDPROOFING_GLOBAL_STRONG ) ) ); // listener in the cab of the same vehicle
}
break; break;
} }
case sound_placement::engine: { case sound_placement::engine: {
m_properties.soundproofing = ( if( m_range >= -1 ) {
( ( soundproofingstamp == 0 ) || ( true == Global.CabWindowOpen ) ) ? m_properties.soundproofing = (
EU07_SOUNDPROOFING_SOME : // listener outside or has a window open ( ( soundproofingstamp == 0 ) || ( true == Global.CabWindowOpen ) ) ?
( simulation::Train->Dynamic() != m_owner ? EU07_SOUNDPROOFING_SOME : // listener outside or has a window open
EU07_SOUNDPROOFING_STRONG : // in another vehicle ( simulation::Train->Dynamic() != m_owner ?
( occupiedcab == 0 ? EU07_SOUNDPROOFING_STRONG : // in another vehicle
EU07_SOUNDPROOFING_NONE : // listener in the engine compartment ( occupiedcab == 0 ?
EU07_SOUNDPROOFING_STRONG ) ) ); // listener in another compartment of the same vehicle EU07_SOUNDPROOFING_NONE : // listener in the engine compartment
EU07_SOUNDPROOFING_STRONG ) ) ); // listener in another compartment of the same vehicle
}
else {
m_properties.soundproofing = (
( ( soundproofingstamp == 0 ) || ( true == Global.CabWindowOpen ) ) ?
EU07_SOUNDPROOFING_GLOBAL_STRONG : // listener outside or has a window open
( simulation::Train->Dynamic() != m_owner ?
EU07_SOUNDPROOFING_GLOBAL_VERYSTRONG : // in another vehicle
( occupiedcab == 0 ?
EU07_SOUNDPROOFING_NONE : // listener in the engine compartment
EU07_SOUNDPROOFING_GLOBAL_STRONG ) ) ); // listener in another compartment of the same vehicle
}
break; break;
} }
default: { default: {

View File

@@ -15,7 +15,7 @@ http://mozilla.org/MPL/2.0/.
float const EU07_SOUND_GLOBALRANGE { -1.f }; float const EU07_SOUND_GLOBALRANGE { -1.f };
float const EU07_SOUND_CABCONTROLSCUTOFFRANGE { 7.5f }; float const EU07_SOUND_CABCONTROLSCUTOFFRANGE { 7.5f };
float const EU07_SOUND_CABANNOUNCEMENTCUTOFFRANGE{ 30.f }; float const EU07_SOUND_CABANNOUNCEMENTCUTOFFRANGE{ -10.f };
float const EU07_SOUND_BRAKINGCUTOFFRANGE { 100.f }; float const EU07_SOUND_BRAKINGCUTOFFRANGE { 100.f };
float const EU07_SOUND_RUNNINGNOISECUTOFFRANGE { 200.f }; float const EU07_SOUND_RUNNINGNOISECUTOFFRANGE { 200.f };
float const EU07_SOUND_HANDHELDRADIORANGE { 3500.f }; float const EU07_SOUND_HANDHELDRADIORANGE { 3500.f };
@@ -122,6 +122,8 @@ public:
glm::dvec3 const glm::dvec3 const
location() const; location() const;
// returns defined range of the sound // returns defined range of the sound
void
range( float const Range );
float const float const
range() const; range() const;