From 492c1342b16904f5c469782a0036a11ec0f35eea Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Fri, 10 Nov 2017 16:57:08 +0100 Subject: [PATCH 1/8] audio subsystem replacement: openal audio renderer and buffer class, removed deprecated files --- EU07.cpp | 8 +- McZapkie/Mover.cpp | 46 +++++--- Model3d.h | 13 ++- Names.h | 4 +- ResourceManager.h | 8 ++ Texture.h | 12 +- Train.cpp | 16 +-- World.cpp | 10 +- audio.cpp | 181 +++++++++++++++++++++++++++++ audio.h | 72 ++++++++++++ audiorenderer.cpp | 83 +++++++++++++ audiorenderer.h | 47 ++++++++ maszyna.vcxproj.filters | 42 ++----- material.cpp | 4 +- material.h | 1 - AdvSound.cpp => old/AdvSound.cpp | 0 AdvSound.h => old/AdvSound.h | 0 RealSound.cpp => old/RealSound.cpp | 0 RealSound.h => old/RealSound.h | 0 Sound.cpp => old/Sound.cpp | 0 Sound.h => old/Sound.h | 0 VBO.cpp => old/VBO.cpp | 0 VBO.h => old/VBO.h | 0 wavread.cpp => old/wavread.cpp | 0 wavread.h => old/wavread.h | 0 renderer.cpp | 42 +++---- renderer.h | 9 +- scene.cpp | 4 +- 28 files changed, 498 insertions(+), 104 deletions(-) create mode 100644 audio.cpp create mode 100644 audio.h create mode 100644 audiorenderer.cpp create mode 100644 audiorenderer.h rename AdvSound.cpp => old/AdvSound.cpp (100%) rename AdvSound.h => old/AdvSound.h (100%) rename RealSound.cpp => old/RealSound.cpp (100%) rename RealSound.h => old/RealSound.h (100%) rename Sound.cpp => old/Sound.cpp (100%) rename Sound.h => old/Sound.h (100%) rename VBO.cpp => old/VBO.cpp (100%) rename VBO.h => old/VBO.h (100%) rename wavread.cpp => old/wavread.cpp (100%) rename wavread.h => old/wavread.h (100%) diff --git a/EU07.cpp b/EU07.cpp index eba5e362..361927cf 100644 --- a/EU07.cpp +++ b/EU07.cpp @@ -25,12 +25,14 @@ Stele, firleju, szociu, hunter, ZiomalCl, OLI_EU and others #include "Globals.h" #include "timer.h" #include "Logs.h" +#include "renderer.h" +#include "uilayer.h" +#include "audiorenderer.h" #include "keyboardinput.h" #include "mouseinput.h" #include "gamepadinput.h" #include "Console.h" #include "PyInt.h" -#include "uilayer.h" #ifdef EU07_BUILD_STATIC #pragma comment( lib, "glfw3.lib" ) @@ -46,6 +48,7 @@ Stele, firleju, szociu, hunter, ZiomalCl, OLI_EU and others #pragma comment( lib, "opengl32.lib" ) #pragma comment( lib, "glu32.lib" ) #pragma comment( lib, "dsound.lib" ) +#pragma comment( lib, "openal32.lib") #pragma comment( lib, "winmm.lib" ) #pragma comment( lib, "setupapi.lib" ) #pragma comment( lib, "python27.lib" ) @@ -405,6 +408,9 @@ int main(int argc, char *argv[]) return -1; } + + audio::renderer.init(); + input::Keyboard.init(); input::Mouse.init(); input::Gamepad.init(); diff --git a/McZapkie/Mover.cpp b/McZapkie/Mover.cpp index cac6b709..5a1a95bf 100644 --- a/McZapkie/Mover.cpp +++ b/McZapkie/Mover.cpp @@ -2375,44 +2375,52 @@ bool TMoverParameters::MainSwitch( bool const State, int const Notify ) { bool MS = false; // Ra: przeniesione z końca - if ((Mains != State) && (MainCtrlPosNo > 0)) - { - if ((State == false) || - (((ScndCtrlPos == 0)||(EngineType == ElectricInductionMotor)) && ((ConvOvldFlag == false) || (TrainType == dt_EZT)) && - (LastSwitchingTime > CtrlDelay) && !TestFlag(DamageFlag, dtrain_out) && - !TestFlag(EngDmgFlag, 1))) - { - if( Mains ) { + if( ( Mains != State ) + && ( MainCtrlPosNo > 0 ) ) { + + if( ( false == State ) + || ( ( ( ScndCtrlPos == 0 ) || ( EngineType == ElectricInductionMotor ) ) + && ( ( ConvOvldFlag == false ) || ( TrainType == dt_EZT ) ) + && ( LastSwitchingTime > CtrlDelay ) + && ( false == TestFlag( DamageFlag, dtrain_out ) ) + && ( false == TestFlag( EngDmgFlag, 1 ) ) ) ) { + + if( true == Mains ) { // jeśli był załączony if( Notify != range::local ) { // wysłanie wyłączenia do pozostałych? SendCtrlToNext( "MainSwitch", int( State ), CabNo, ( Notify == range::unit ? - ctrain_controll | ctrain_depot : - ctrain_controll ) ); + coupling::control | coupling::permanent : + coupling::control ) ); } } Mains = State; - if( Mains ) { + MS = true; // wartość zwrotna + LastSwitchingTime = 0; + + if( true == Mains ) { // jeśli został załączony if( Notify != range::local ) { // wysłanie wyłączenia do pozostałych? SendCtrlToNext( "MainSwitch", int( State ), CabNo, ( Notify == range::unit ? - ctrain_controll | ctrain_depot : - ctrain_controll ) ); + coupling::control | coupling::permanent : + coupling::control ) ); } } - MS = true; // wartość zwrotna - LastSwitchingTime = 0; - if ((EngineType == DieselEngine) && Mains) - { + if( ( EngineType == DieselEngine ) + && ( true == Mains ) ) { + dizel_enginestart = State; } - if (((TrainType == dt_EZT) && (!State))) - ConvOvldFlag = true; + if( ( TrainType == dt_EZT ) + && ( false == State ) ) { + + ConvOvldFlag = true; + } } } // else MainSwitch:=false; diff --git a/Model3d.h b/Model3d.h index 70c7c895..1a3ff290 100644 --- a/Model3d.h +++ b/Model3d.h @@ -13,7 +13,7 @@ http://mozilla.org/MPL/2.0/. #include "Parser.h" #include "dumb3d.h" #include "Float3d.h" -#include "VBO.h" +#include "openglgeometrybank.h" #include "material.h" using namespace Math3D; @@ -213,7 +213,7 @@ public: // places contained geometry in provided ground node }; -class TModel3d : public CMesh +class TModel3d { friend class opengl_renderer; @@ -221,7 +221,9 @@ private: TSubModel *Root; // drzewo submodeli int iFlags; // Ra: czy submodele mają przezroczyste tekstury public: // Ra: tymczasowo - int iNumVerts; // ilość wierzchołków (gdy nie ma VBO, to m_nVertexCount=0) + int iNumVerts; // ilość wierzchołków (gdy nie ma VBO, to m_nVertexCount=0) + geometrybank_handle m_geometrybank; + bool m_geometrycreated { false }; private: std::vector Textures; // nazwy tekstur std::vector Names; // nazwy submodeli @@ -229,15 +231,16 @@ private: int iSubModelsCount; // Ra: używane do tworzenia binarnych std::string asBinary; // nazwa pod którą zapisać model binarny std::string m_filename; + public: + TModel3d(); + ~TModel3d(); float bounding_radius() const { return ( Root ? Root->m_boundingradius : 0.f ); } inline TSubModel * GetSMRoot() { return (Root); }; - TModel3d(); - ~TModel3d(); TSubModel * GetFromName(std::string const &Name); TSubModel * AddToNamed(const char *Name, TSubModel *SubModel); void AddTo(TSubModel *tmp, TSubModel *SubModel); diff --git a/Names.h b/Names.h index 1af3e4ca..0a7c534d 100644 --- a/Names.h +++ b/Names.h @@ -50,10 +50,10 @@ public: protected: // types using type_sequence = std::deque; - using type_map = std::unordered_map; + using index_map = std::unordered_map; // members type_sequence m_items; - type_map m_itemmap; + index_map m_itemmap; public: // data access diff --git a/ResourceManager.h b/ResourceManager.h index 0d28f747..2d467e19 100644 --- a/ResourceManager.h +++ b/ResourceManager.h @@ -8,6 +8,14 @@ http://mozilla.org/MPL/2.0/. */ #pragma once + +enum class resource_state { + none, + loading, + good, + failed +}; + /* #include #include diff --git a/Texture.h b/Texture.h index 64c0e11b..c9bd5c7b 100644 --- a/Texture.h +++ b/Texture.h @@ -15,13 +15,6 @@ http://mozilla.org/MPL/2.0/. #include "GL/glew.h" #include "ResourceManager.h" -enum class resource_state { - none, - loading, - good, - failed -}; - struct opengl_texture { static DDSURFACEDESC2 deserialize_ddsd(std::istream&); static DDCOLORKEY deserialize_ddck(std::istream&); @@ -88,13 +81,16 @@ public: void assign_units( GLint const Helper, GLint const Shadows, GLint const Normals, GLint const Diffuse ); + // activates specified texture unit void unit( GLint const Textureunit ); + // creates texture object out of data stored in specified file texture_handle create( std::string Filename, bool const Loadnow = true ); // binds specified texture to specified texture unit void bind( std::size_t const Unit, texture_handle const Texture ); + // provides direct access to specified texture object opengl_texture & texture( texture_handle const Texture ) const { return *(m_textures[ Texture ].first); } // performs a resource sweep @@ -186,7 +182,7 @@ downsample( std::size_t const Width, std::size_t const Height, char *Imagedata ) (*sampler)[idx] + ( *( sampler + 1 ) )[idx] + ( *( sampler + Width ) )[idx] - + (*( sampler + Width + 1 ))[idx] ); + + ( *( sampler + Width + 1 ))[idx] ); color[ idx ] = component /= 4; } *destination++ = color; diff --git a/Train.cpp b/Train.cpp index bb169cea..ee354945 100644 --- a/Train.cpp +++ b/Train.cpp @@ -589,9 +589,9 @@ void TTrain::OnCommand_secondcontrollerincrease( TTrain *Train, command_data con if( Command.action != GLFW_RELEASE ) { // on press or hold if( Train->mvControlled->ShuntMode ) { - Train->mvControlled->AnPos += ( Command.time_delta * 0.75f ); - if( Train->mvControlled->AnPos > 1 ) - Train->mvControlled->AnPos = 1; + Train->mvControlled->AnPos = clamp( + Train->mvControlled->AnPos + ( Command.time_delta * 1.0f ), + 0.0, 1.0 ); } else { Train->mvControlled->IncScndCtrl( 1 ); @@ -650,9 +650,9 @@ void TTrain::OnCommand_secondcontrollerdecrease( TTrain *Train, command_data con if( Command.action != GLFW_RELEASE ) { // on press or hold if( Train->mvControlled->ShuntMode ) { - Train->mvControlled->AnPos -= ( Command.time_delta * 0.75f ); - if( Train->mvControlled->AnPos > 1 ) - Train->mvControlled->AnPos = 1; + Train->mvControlled->AnPos = clamp( + Train->mvControlled->AnPos - ( Command.time_delta * 1.0f ), + 0.0, 1.0 ); } Train->mvControlled->DecScndCtrl( 1 ); } @@ -2030,7 +2030,9 @@ void TTrain::OnCommand_motoroverloadrelaythresholdtoggle( TTrain *Train, command if( Command.action == GLFW_PRESS ) { // only reacting to press, so the switch doesn't flip back and forth if key is held down - if( Train->mvControlled->Imax < Train->mvControlled->ImaxHi ) { + if( ( true == Train->mvControlled->ShuntModeAllow ? + ( false == Train->mvControlled->ShuntMode ) : + ( Train->mvControlled->Imax < Train->mvControlled->ImaxHi ) ) ) { // turn on if( true == Train->mvControlled->CurrentSwitch( true ) ) { // visual feedback diff --git a/World.cpp b/World.cpp index ee4720a2..eafab396 100644 --- a/World.cpp +++ b/World.cpp @@ -1422,7 +1422,11 @@ TWorld::Update_UI() { + ( vehicle->MoverParameters->bPantKurek3 ? "-ZG" : "|ZG" ); uitextline2 += - "; Ft: " + to_string( vehicle->MoverParameters->Ft * 0.001f * vehicle->MoverParameters->ActiveCab, 1 ) + "; Ft: " + to_string( + vehicle->MoverParameters->Ft * 0.001f * ( + vehicle->MoverParameters->ActiveCab ? vehicle->MoverParameters->ActiveCab : + vehicle->ctOwner ? vehicle->ctOwner->Controlling()->ActiveCab : + 1 ), 1 ) + ", Fb: " + to_string( vehicle->MoverParameters->Fb * 0.001f, 1 ) + ", Fr: " + to_string( vehicle->MoverParameters->Adhesive( vehicle->MoverParameters->RunningTrack.friction ), 2 ) + ( vehicle->MoverParameters->SlippingWheels ? " (!)" : "" ); @@ -1640,7 +1644,9 @@ TWorld::Update_UI() { "HamZ=" + to_string( vehicle->MoverParameters->fBrakeCtrlPos, 2 ) + "; HamP=" + std::to_string( vehicle->MoverParameters->LocalBrakePos ) + "/" + to_string( vehicle->MoverParameters->LocalBrakePosA, 2 ) + "; NasJ=" + std::to_string( vehicle->MoverParameters->MainCtrlPos ) + "(" + std::to_string( vehicle->MoverParameters->MainCtrlActualPos ) + ")" - + "; NasB=" + std::to_string( vehicle->MoverParameters->ScndCtrlPos ) + "(" + std::to_string( vehicle->MoverParameters->ScndCtrlActualPos ) + ")" + + ( vehicle->MoverParameters->ShuntMode ? + "; NasB=" + to_string( vehicle->MoverParameters->AnPos, 2 ) : + "; NasB=" + std::to_string( vehicle->MoverParameters->ScndCtrlPos ) + "(" + std::to_string( vehicle->MoverParameters->ScndCtrlActualPos ) + ")" ) + "; I=" + ( vehicle->MoverParameters->TrainType == dt_EZT ? std::to_string( int( vehicle->MoverParameters->ShowCurrent( 0 ) ) ) : diff --git a/audio.cpp b/audio.cpp new file mode 100644 index 00000000..ecb69a1f --- /dev/null +++ b/audio.cpp @@ -0,0 +1,181 @@ +/* +This Source Code Form is subject to the +terms of the Mozilla Public License, v. +2.0. If a copy of the MPL was not +distributed with this file, You can +obtain one at +http://mozilla.org/MPL/2.0/. +*/ + +#include "stdafx.h" + +#include "audio.h" +#include "globals.h" +#include "mczapkie/mctools.h" + +#define DR_WAV_IMPLEMENTATION +#include "dr_wav.h" +#define DR_FLAC_IMPLEMENTATION +#include "dr_flac.h" + +namespace audio { + +openal_buffer::openal_buffer( std::string const &Filename ) : + name( Filename ) { + + ::alGenBuffers( 1, &id ); + // fetch audio data + if( Filename.substr( Filename.rfind( '.' ) ) == ".wav" ) { + // .wav file + auto *file { drwav_open_file( Filename.c_str() ) }; + rate = file->sampleRate; + auto const samplecount { static_cast( file->totalSampleCount ) }; + data.resize( samplecount ); + drwav_read_s16( + file, + samplecount, + &data[ 0 ] ); + if( file->channels > 1 ) { + narrow_to_mono( file->channels ); + data.resize( samplecount / file->channels ); + } + // we're done with the disk data + drwav_close( file ); + } + else { + // .flac or .ogg file + auto *file { drflac_open_file( Filename.c_str() ) }; + rate = file->sampleRate; + auto const samplecount{ static_cast( file->totalSampleCount ) }; + data.resize( samplecount ); + drflac_read_s16( + file, + samplecount, + &data[ 0 ] ); + if( file->channels > 1 ) { + narrow_to_mono( file->channels ); + data.resize( samplecount / file->channels ); + } + // we're done with the disk data + drflac_close( file ); + } + // send the data to openal side + ::alBufferData( id, AL_FORMAT_MONO16, data.data(), data.size() * sizeof( std::int16_t ), rate ); + // and get rid of the source, we shouldn't need it anymore + // TBD, TODO: delay data fetching and transfers until the buffer is actually used? + std::vector().swap( data ); +} + +// mix specified number of interleaved multi-channel data, down to mono +void +openal_buffer::narrow_to_mono( std::uint16_t const Channelcount ) { + + std::size_t monodataindex { 0 }; + std::int32_t accumulator { 0 }; + auto channelcount { Channelcount }; + + for( auto const channeldata : data ) { + + accumulator += channeldata; + if( --channelcount == 0 ) { + + data[ monodataindex++ ] = accumulator / Channelcount; + accumulator = 0; + channelcount = Channelcount; + } + } +} + + + +buffer_manager::~buffer_manager() { + + for( auto &buffer : m_buffers ) { + if( buffer.id != null_resource ) { + ::alDeleteBuffers( 1, &( buffer.id ) ); + } + } +} + +// creates buffer object out of data stored in specified file. returns: handle to the buffer or null_handle if creation failed +buffer_handle +buffer_manager::create( std::string const &Filename ) { + + auto filename { ToLower( Filename ) }; + + auto const dotpos { filename.rfind( '.' ) }; + if( ( dotpos != std::string::npos ) + && ( dotpos != filename.rfind( ".." ) + 1 ) ) { + // trim extension if there's one, but don't mistake folder traverse for extension + filename.erase( dotpos ); + } + // convert slashes + std::replace( + std::begin( filename ), std::end( filename ), + '\\', '/' ); + + // try dynamic-specific sounds first + auto lookup { find_buffer( Global::asCurrentDynamicPath + filename ) }; + if( lookup != null_handle ) { + return lookup; + } + std::string filelookup { find_file( Global::asCurrentDynamicPath + filename ) }; + if( false == filelookup.empty() ) { + return emplace( filelookup ); + } + // if dynamic-specific lookup finds nothing, try the default sound folder + lookup = find_buffer( szSoundPath + filename ); + if( lookup != null_handle ) { + return lookup; + } + filelookup = find_file( szSoundPath + filename ); + if( false == filelookup.empty() ) { + return emplace( filelookup ); + } + // if we still didn't find anything, give up + return null_handle; +} + +// places in the bank a buffer containing data stored in specified file. returns: handle to the buffer +buffer_handle +buffer_manager::emplace( std::string Filename ) { + + buffer_handle const handle { m_buffers.size() }; + m_buffers.emplace_back( Filename ); + + // NOTE: we store mapping without file type extension, to simplify lookups + m_buffermappings.emplace( + Filename.erase( Filename.rfind( '.' ) ), + handle ); + + return handle; +} + +buffer_handle +buffer_manager::find_buffer( std::string const &Buffername ) const { + + auto lookup = m_buffermappings.find( Buffername ); + if( lookup != m_buffermappings.end() ) + return lookup->second; + else + return null_handle; +} + + +std::string +buffer_manager::find_file( std::string const &Filename ) const { + + std::vector const extensions { ".wav", ".flac", ".ogg" }; + + for( auto const &extension : extensions ) { + if( FileExists( Filename + extension ) ) { + // valid name on success + return Filename + extension; + } + } + return {}; // empty string on failure +} + +} // audio + +//--------------------------------------------------------------------------- diff --git a/audio.h b/audio.h new file mode 100644 index 00000000..fd944367 --- /dev/null +++ b/audio.h @@ -0,0 +1,72 @@ +/* +This Source Code Form is subject to the +terms of the Mozilla Public License, v. +2.0. If a copy of the MPL was not +distributed with this file, You can +obtain one at +http://mozilla.org/MPL/2.0/. +*/ + +#pragma once + +#include "al.h" +#include "alc.h" + +namespace audio { + +ALuint const null_resource { ~ALuint{ 0 } }; + +struct openal_buffer { +// members + ALuint id { null_resource }; // associated AL resource + unsigned int rate { 0 }; // sample rate of the data + std::string name; +// constructors + openal_buffer() = default; + explicit openal_buffer( std::string const &Filename ); + +private: +// methods + // mix specified number of interleaved multi-channel data, down to mono + void + narrow_to_mono( std::uint16_t const Channelcount ); +// members + std::vector data; // audio data +}; + +using buffer_handle = std::size_t; + +class buffer_manager { + +public: +// constructors + buffer_manager() { m_buffers.emplace_back( openal_buffer() ); } // empty bindings for null buffer +// destructor + ~buffer_manager(); +// methods + // creates buffer object out of data stored in specified file. returns: handle to the buffer or null_handle if creation failed + buffer_handle + create( std::string const &Filename ); + +private: +// types + using buffer_sequence = std::vector; + using index_map = std::unordered_map; +// methods + // places in the bank a buffer containing data stored in specified file. returns: handle to the buffer + buffer_handle + emplace( std::string Filename ); + // checks whether specified buffer is in the buffer bank. returns: buffer handle, or null_handle. + buffer_handle + find_buffer( std::string const &Buffername ) const; + // checks whether specified file exists. returns: name of the located file, or empty string. + std::string + find_file( std::string const &Filename ) const; +// members + buffer_sequence m_buffers; + index_map m_buffermappings; +}; + +} // audio + +//--------------------------------------------------------------------------- diff --git a/audiorenderer.cpp b/audiorenderer.cpp new file mode 100644 index 00000000..aa06766b --- /dev/null +++ b/audiorenderer.cpp @@ -0,0 +1,83 @@ +/* +This Source Code Form is subject to the +terms of the Mozilla Public License, v. +2.0. If a copy of the MPL was not +distributed with this file, You can +obtain one at +http://mozilla.org/MPL/2.0/. +*/ + +#include "stdafx.h" + +#include "audiorenderer.h" +#include "logs.h" + +namespace audio { + +openal_renderer renderer; + +openal_renderer::~openal_renderer() { + + ::alcMakeContextCurrent( nullptr ); + + if( m_context != nullptr ) { ::alcDestroyContext( m_context ); } + if( m_device != nullptr ) { ::alcCloseDevice( m_device ); } +} + +buffer_handle +openal_renderer::fetch_buffer( std::string const &Filename ) { + + return m_buffers.create( Filename ); +} + +// initializes the service +bool +openal_renderer::init() { + + if( true == m_ready ) { + // already initialized and enabled + return true; + } + if( false == init_caps() ) { + // basic initialization failed + return false; + } + + m_ready = true; + return true; +} + +bool +openal_renderer::init_caps() { + + // select the "preferred device" + // TODO: support for opening config-specified device + m_device = ::alcOpenDevice( nullptr ); + if( m_device == nullptr ) { + ErrorLog( "Failed to obtain audio device" ); + return false; + } + + ALCint versionmajor, versionminor; + ::alcGetIntegerv( m_device, ALC_MAJOR_VERSION, 1, &versionmajor ); + ::alcGetIntegerv( m_device, ALC_MINOR_VERSION, 1, &versionminor ); + auto const oalversion { std::to_string( versionmajor ) + "." + std::to_string( versionminor ) }; + + WriteLog( + "Audio Renderer: " + std::string { (char *)::alcGetString( m_device, ALC_DEVICE_SPECIFIER ) } + + " OpenAL Version: " + oalversion ); + + WriteLog( "Supported extensions: " + std::string{ (char *)::alcGetString( m_device, ALC_EXTENSIONS ) } ); + + m_context = ::alcCreateContext( m_device, nullptr ); + if( m_context == nullptr ) { + ErrorLog( "Failed to create audio context" ); + return false; + } + + return ( ::alcMakeContextCurrent( m_context ) == AL_TRUE ); +} + +} // audio + +//--------------------------------------------------------------------------- diff --git a/audiorenderer.h b/audiorenderer.h new file mode 100644 index 00000000..8e52e016 --- /dev/null +++ b/audiorenderer.h @@ -0,0 +1,47 @@ +/* +This Source Code Form is subject to the +terms of the Mozilla Public License, v. +2.0. If a copy of the MPL was not +distributed with this file, You can +obtain one at +http://mozilla.org/MPL/2.0/. +*/ + +#pragma once + +#include "audio.h" + +namespace audio { + +class openal_renderer { + +public: +// destructor + ~openal_renderer(); +// methods + // buffer methods + // returns handle to a buffer containing audio data from specified file + buffer_handle + fetch_buffer( std::string const &Filename ); + // core methods + // initializes the service + bool + init(); + +private: +// methods + bool + init_caps(); +// members + ALCdevice * m_device { nullptr }; + ALCcontext * m_context { nullptr }; + bool m_ready { false }; // renderer is initialized and functional + + buffer_manager m_buffers; +}; + +extern openal_renderer renderer; + +} // audio + +//--------------------------------------------------------------------------- diff --git a/maszyna.vcxproj.filters b/maszyna.vcxproj.filters index 5deecf08..251ff4a9 100644 --- a/maszyna.vcxproj.filters +++ b/maszyna.vcxproj.filters @@ -27,9 +27,6 @@ - - Source Files - Source Files @@ -93,9 +90,6 @@ Source Files - - Source Files - Source Files @@ -105,9 +99,6 @@ Source Files - - Source Files - Source Files @@ -132,12 +123,6 @@ Source Files - - Source Files - - - Source Files - Source Files @@ -240,6 +225,12 @@ Source Files + + Source Files + + + Source Files + @@ -287,9 +278,6 @@ Header Files - - Header Files - Header Files @@ -320,9 +308,6 @@ Header Files\input - - Header Files - Header Files @@ -347,12 +332,6 @@ Header Files - - Header Files - - - Header Files - Header Files @@ -362,9 +341,6 @@ Header Files - - Header Files - Header Files @@ -470,6 +446,12 @@ Header Files + + Header Files + + + Header Files + diff --git a/material.cpp b/material.cpp index 96100286..ed224744 100644 --- a/material.cpp +++ b/material.cpp @@ -105,7 +105,7 @@ material_manager::create( std::string const &Filename, bool const Loadnow ) { // try to locate requested material in the databank auto const databanklookup = find_in_databank( filename ); - if( databanklookup != npos ) { + if( databanklookup != null_handle ) { return databanklookup; } // if this fails, try to look for it on disk @@ -149,7 +149,7 @@ material_manager::find_in_databank( std::string const &Materialname ) const { return ( lookup != m_materialmappings.end() ? lookup->second : - npos ); + null_handle ); } // checks whether specified file exists. diff --git a/material.h b/material.h index 6f305cb0..72093fc3 100644 --- a/material.h +++ b/material.h @@ -55,7 +55,6 @@ private: std::string find_on_disk( std::string const &Materialname ) const; // members: - material_handle const npos { -1 }; material_sequence m_materials; index_map m_materialmappings; diff --git a/AdvSound.cpp b/old/AdvSound.cpp similarity index 100% rename from AdvSound.cpp rename to old/AdvSound.cpp diff --git a/AdvSound.h b/old/AdvSound.h similarity index 100% rename from AdvSound.h rename to old/AdvSound.h diff --git a/RealSound.cpp b/old/RealSound.cpp similarity index 100% rename from RealSound.cpp rename to old/RealSound.cpp diff --git a/RealSound.h b/old/RealSound.h similarity index 100% rename from RealSound.h rename to old/RealSound.h diff --git a/Sound.cpp b/old/Sound.cpp similarity index 100% rename from Sound.cpp rename to old/Sound.cpp diff --git a/Sound.h b/old/Sound.h similarity index 100% rename from Sound.h rename to old/Sound.h diff --git a/VBO.cpp b/old/VBO.cpp similarity index 100% rename from VBO.cpp rename to old/VBO.cpp diff --git a/VBO.h b/old/VBO.h similarity index 100% rename from VBO.h rename to old/VBO.h diff --git a/wavread.cpp b/old/wavread.cpp similarity index 100% rename from wavread.cpp rename to old/wavread.cpp diff --git a/wavread.h b/old/wavread.h similarity index 100% rename from wavread.h rename to old/wavread.h diff --git a/renderer.cpp b/renderer.cpp index e66f60b5..7d33fc32 100644 --- a/renderer.cpp +++ b/renderer.cpp @@ -108,7 +108,7 @@ opengl_renderer::Init( GLFWwindow *Window ) { std::vector{ m_normaltextureunit, m_diffusetextureunit } ); m_textures.assign_units( m_helpertextureunit, m_shadowtextureunit, m_normaltextureunit, m_diffusetextureunit ); // TODO: add reflections unit UILayer.set_unit( m_diffusetextureunit ); - Active_Texture( m_diffusetextureunit ); + select_unit( m_diffusetextureunit ); ::glDepthFunc( GL_LEQUAL ); glEnable( GL_DEPTH_TEST ); @@ -452,10 +452,10 @@ opengl_renderer::Render_pass( rendermode const Mode ) { if( m_environmentcubetexturesupport ) { // restore default texture matrix for reflections cube map - Active_Texture( m_helpertextureunit ); + select_unit( m_helpertextureunit ); ::glMatrixMode( GL_TEXTURE ); ::glPopMatrix(); - Active_Texture( m_diffusetextureunit ); + select_unit( m_diffusetextureunit ); ::glMatrixMode( GL_MODELVIEW ); } } @@ -765,11 +765,11 @@ opengl_renderer::setup_matrices() { if( ( m_renderpass.draw_mode == rendermode::color ) && ( m_environmentcubetexturesupport ) ) { // special case, for colour render pass setup texture matrix for reflections cube map - Active_Texture( m_helpertextureunit ); + select_unit( m_helpertextureunit ); ::glMatrixMode( GL_TEXTURE ); ::glPushMatrix(); ::glMultMatrixf( glm::value_ptr( glm::inverse( glm::mat4{ glm::mat3{ m_renderpass.camera.modelview() } } ) ) ); - Active_Texture( m_diffusetextureunit ); + select_unit( m_diffusetextureunit ); } // trim modelview matrix just to rotation, since rendering is done in camera-centric world space @@ -835,7 +835,7 @@ opengl_renderer::setup_units( bool const Diffuse, bool const Shadows, bool const // darkens previous stage, preparing data for the shadow texture unit to select from if( m_helpertextureunit >= 0 ) { - Active_Texture( m_helpertextureunit ); + select_unit( m_helpertextureunit ); if( ( true == Reflections ) || ( ( true == Global::RenderShadows ) && ( true == Shadows ) && ( false == Global::bWireFrame ) ) ) { @@ -922,7 +922,7 @@ opengl_renderer::setup_units( bool const Diffuse, bool const Shadows, bool const && ( false == Global::bWireFrame ) && ( m_shadowcolor != colors::white ) ) { - Active_Texture( m_shadowtextureunit ); + select_unit( m_shadowtextureunit ); // NOTE: shadowmap isn't part of regular texture system, so we use direct bind call here ::glBindTexture( GL_TEXTURE_2D, m_shadowtexture ); ::glEnable( GL_TEXTURE_2D ); @@ -953,7 +953,7 @@ opengl_renderer::setup_units( bool const Diffuse, bool const Shadows, bool const } else { // turn off shadow map tests - Active_Texture( m_shadowtextureunit ); + select_unit( m_shadowtextureunit ); ::glDisable( GL_TEXTURE_2D ); ::glDisable( GL_TEXTURE_GEN_S ); @@ -966,7 +966,7 @@ opengl_renderer::setup_units( bool const Diffuse, bool const Shadows, bool const // NOTE: comes after diffuse stage in the operation chain if( m_normaltextureunit >= 0 ) { - Active_Texture( m_normaltextureunit ); + select_unit( m_normaltextureunit ); if( true == Reflections ) { ::glEnable( GL_TEXTURE_2D ); @@ -989,7 +989,7 @@ opengl_renderer::setup_units( bool const Diffuse, bool const Shadows, bool const } // diffuse texture unit. // NOTE: diffuse texture mapping is never fully disabled, alpha channel information is always included - Active_Texture( m_diffusetextureunit ); + select_unit( m_diffusetextureunit ); ::glEnable( GL_TEXTURE_2D ); if( true == Diffuse ) { // default behaviour, modulate with previous stage @@ -1027,7 +1027,7 @@ opengl_renderer::switch_units( bool const Diffuse, bool const Shadows, bool cons // helper texture unit. if( m_helpertextureunit >= 0 ) { - Active_Texture( m_helpertextureunit ); + select_unit( m_helpertextureunit ); if( ( true == Reflections ) || ( ( true == Global::RenderShadows ) && ( true == Shadows ) @@ -1053,12 +1053,12 @@ opengl_renderer::switch_units( bool const Diffuse, bool const Shadows, bool cons if( m_shadowtextureunit >= 0 ) { if( ( true == Global::RenderShadows ) && ( true == Shadows ) && ( false == Global::bWireFrame ) ) { - Active_Texture( m_shadowtextureunit ); + select_unit( m_shadowtextureunit ); ::glEnable( GL_TEXTURE_2D ); } else { - Active_Texture( m_shadowtextureunit ); + select_unit( m_shadowtextureunit ); ::glDisable( GL_TEXTURE_2D ); } } @@ -1066,11 +1066,11 @@ opengl_renderer::switch_units( bool const Diffuse, bool const Shadows, bool cons if( m_normaltextureunit >= 0 ) { if( true == Reflections ) { - Active_Texture( m_normaltextureunit ); + select_unit( m_normaltextureunit ); ::glEnable( GL_TEXTURE_2D ); } else { - Active_Texture( m_normaltextureunit ); + select_unit( m_normaltextureunit ); ::glDisable( GL_TEXTURE_2D ); } } @@ -1078,12 +1078,12 @@ opengl_renderer::switch_units( bool const Diffuse, bool const Shadows, bool cons // NOTE: toggle actually disables diffuse texture mapping, unlike setup counterpart if( true == Diffuse ) { - Active_Texture( m_diffusetextureunit ); + select_unit( m_diffusetextureunit ); ::glEnable( GL_TEXTURE_2D ); } else { - Active_Texture( m_diffusetextureunit ); + select_unit( m_diffusetextureunit ); ::glDisable( GL_TEXTURE_2D ); } // update unit state @@ -1095,9 +1095,9 @@ opengl_renderer::switch_units( bool const Diffuse, bool const Shadows, bool cons void opengl_renderer::setup_shadow_color( glm::vec4 const &Shadowcolor ) { - Active_Texture( m_helpertextureunit ); + select_unit( m_helpertextureunit ); ::glTexEnvfv( GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, glm::value_ptr( Shadowcolor ) ); // in-shadow colour multiplier - Active_Texture( m_diffusetextureunit ); + select_unit( m_diffusetextureunit ); } bool @@ -1322,7 +1322,7 @@ opengl_renderer::Material( material_handle const Material ) const { // texture methods void -opengl_renderer::Active_Texture( GLint const Textureunit ) { +opengl_renderer::select_unit( GLint const Textureunit ) { return m_textures.unit( Textureunit ); } @@ -3327,7 +3327,7 @@ opengl_renderer::Init_caps() { return false; } - WriteLog( "Supported extensions:" + std::string((char *)glGetString( GL_EXTENSIONS )) ); + WriteLog( "Supported extensions: " + std::string((char *)glGetString( GL_EXTENSIONS )) ); WriteLog( std::string("Render path: ") + ( Global::bUseVBO ? "VBO" : "Display lists" ) ); if( GLEW_EXT_framebuffer_object ) { diff --git a/renderer.h b/renderer.h index 15f41e85..cdf91132 100644 --- a/renderer.h +++ b/renderer.h @@ -178,8 +178,6 @@ public: opengl_material const & Material( material_handle const Material ) const; // texture methods - void - Active_Texture( GLint const Textureunit ); texture_handle Fetch_Texture( std::string const &Filename, bool const Loadnow = true ); void @@ -194,14 +192,14 @@ public: Pick_Control() const { return m_pickcontrolitem; } editor::basic_node const * Pick_Node() const { return m_picksceneryitem; } - // maintenance jobs + // maintenance methods void Update( double const Deltatime ); TSubModel const * Update_Pick_Control(); editor::basic_node const * Update_Pick_Node(); - // debug performance string + // debug methods std::string const & info_times() const; std::string const & @@ -275,6 +273,9 @@ private: setup_shadow_color( glm::vec4 const &Shadowcolor ); void switch_units( bool const Diffuse, bool const Shadows, bool const Reflections ); + // helper, texture manager method; activates specified texture unit + void + select_unit( GLint const Textureunit ); // runs jobs needed to generate graphics for specified render pass void Render_pass( rendermode const Mode ); diff --git a/scene.cpp b/scene.cpp index 4d65328b..33e6cd43 100644 --- a/scene.cpp +++ b/scene.cpp @@ -873,7 +873,7 @@ void basic_region::serialize( std::string const &Scenariofile ) const { auto filename { Scenariofile }; - if( filename[ 0 ] == '$' ) { + while( filename[ 0 ] == '$' ) { // trim leading $ char rainsted utility may add to the base name for modified .scn files filename.erase( 0, 1 ); } @@ -916,7 +916,7 @@ bool basic_region::deserialize( std::string const &Scenariofile ) { auto filename { Scenariofile }; - if( filename[ 0 ] == '$' ) { + while( filename[ 0 ] == '$' ) { // trim leading $ char rainsted utility may add to the base name for modified .scn files filename.erase( 0, 1 ); } From 5226fca281656394a9c0a57e2935db63b60b4afa Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Sun, 12 Nov 2017 00:23:21 +0100 Subject: [PATCH 2/8] unified simulation sound sources, gfx namespace for gfx code and structures --- Button.cpp | 48 +- Button.h | 20 +- Classes.h | 4 + Driver.cpp | 37 +- Driver.h | 3 + DynObj.cpp | 407 ++++++---- DynObj.h | 49 +- Event.cpp | 2 + Event.h | 4 + Gauge.cpp | 79 +- Gauge.h | 28 +- Globals.h | 6 +- Model3d.cpp | 6 +- Model3d.h | 10 +- Segment.cpp | 2 +- Segment.h | 2 +- Track.cpp | 50 +- Track.h | 4 +- Traction.cpp | 6 +- Traction.h | 4 +- Train.cpp | 1609 +++++++++++++++++---------------------- Train.h | 81 +- World.cpp | 14 +- maszyna.vcxproj.filters | 6 + openglgeometrybank.cpp | 108 +-- openglgeometrybank.h | 82 +- renderer.cpp | 20 +- renderer.h | 18 +- scene.cpp | 17 +- scene.h | 17 +- scenenode.cpp | 16 +- scenenode.h | 8 +- simulation.cpp | 12 + simulation.h | 6 +- sound.cpp | 66 ++ sound.h | 69 ++ 36 files changed, 1487 insertions(+), 1433 deletions(-) create mode 100644 sound.cpp create mode 100644 sound.h diff --git a/Button.cpp b/Button.cpp index 8629da2b..22cfe6c4 100644 --- a/Button.cpp +++ b/Button.cpp @@ -46,10 +46,7 @@ void TButton::Load(cParser &Parser, TModel3d *pModel1, TModel3d *pModel2) { else { // new, block type config // TODO: rework the base part into yaml-compatible flow style mapping - cParser mappingparser( Parser.getToken( false, "}" ) ); - submodelname = mappingparser.getToken( false ); - // new, variable length section - while( true == Load_mapping( mappingparser ) ) { + while( true == Load_mapping( Parser ) ) { ; // all work done by while() } } @@ -77,27 +74,13 @@ void TButton::Load(cParser &Parser, TModel3d *pModel1, TModel3d *pModel2) { bool TButton::Load_mapping( cParser &Input ) { - if( false == Input.getTokens( 2, true, " ,\n\r\t" ) ) { - return false; - } + // token can be a key or block end + std::string const key { Input.getToken( true, "\n\r\t ,;" ) }; + if( key == "}" ) { return false; } + // if not block end then the key is followed by assigned value or sub-block + if( key == "soundinc:" ) { m_soundfxincrease.deserialize( Input, sound_type::single ); } + else if( key == "sounddec:" ) { m_soundfxdecrease.deserialize( Input, sound_type::single ); } - std::string key, value; - Input - >> key - >> value; - - if( key == "soundinc:" ) { - m_soundfxincrease = ( - value != "none" ? - TSoundsManager::GetFromName( value, true ) : - nullptr ); - } - else if( key == "sounddec:" ) { - m_soundfxdecrease = ( - value != "none" ? - TSoundsManager::GetFromName( value, true ) : - nullptr ); - } return true; // return value marks a key: value pair was extracted, nothing about whether it's recognized } @@ -141,19 +124,6 @@ void TButton::AssignBool(bool const *bValue) { void TButton::play() { - play( - m_state == true ? - m_soundfxincrease : - m_soundfxdecrease ); -} - -void -TButton::play( PSound Sound ) { - - if( Sound == nullptr ) { return; } - - Sound->SetCurrentPosition( 0 ); - Sound->SetVolume( DSBVOLUME_MAX ); - Sound->Play( 0, 0, 0 ); - return; + if( m_state == true ) { m_soundfxincrease.play(); } + else { m_soundfxdecrease.play(); } } diff --git a/Button.h b/Button.h index addc43c0..534bcd6d 100644 --- a/Button.h +++ b/Button.h @@ -22,8 +22,8 @@ class TButton bool m_state { false }; bool const *bData { nullptr }; int iFeedbackBit { 0 }; // Ra: bit informacji zwrotnej, do wyprowadzenia na pulpit - PSound m_soundfxincrease { nullptr }; // sound associated with increasing control's value - PSound m_soundfxdecrease { nullptr }; // sound associated with decreasing control's value + 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 @@ -31,10 +31,6 @@ class TButton // plays the sound associated with current state void play(); - // plays specified sound - static - void - play( PSound Sound ); public: TButton() = default; @@ -42,14 +38,10 @@ class TButton inline void FeedbackBitSet(int const i) { iFeedbackBit = 1 << i; }; void Turn( bool const State ); - inline void TurnOn() { - Turn( true ); }; - inline void TurnOff() { - Turn( false ); }; - inline void Switch() { - Turn( !m_state ); }; - inline bool Active() { - return (pModelOn) || (pModelOff); }; + inline + bool Active() { + return ( ( pModelOn != nullptr ) + || ( pModelOff != nullptr ) ); } void Update(); void Init(std::string const &asName, TModel3d *pModel, bool bNewOn = false); void Load(cParser &Parser, TModel3d *pModel1, TModel3d *pModel2 = NULL); diff --git a/Classes.h b/Classes.h index 74111f52..6f2b74d1 100644 --- a/Classes.h +++ b/Classes.h @@ -23,8 +23,12 @@ class TModel3d; //siatka modelu wspólna dla egzemplarzy class TSubModel; // fragment modelu (tu do wyświetlania terenu) class TMemCell; // komórka pamięci class cParser; +#ifdef EU07_USE_OLD_SOUNDCODE class TRealSound; // dźwięk ze współrzędnymi XYZ class TTextSound; // dźwięk ze stenogramem +#else +class sound_source; +#endif class TEventLauncher; class TTraction; // drut class TTractionPowerSource; // zasilanie drutów diff --git a/Driver.cpp b/Driver.cpp index f53ad097..75c1b2ba 100644 --- a/Driver.cpp +++ b/Driver.cpp @@ -998,7 +998,7 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN if (go == cm_Unknown) // jeśli nie było komendy wcześniej go = cm_Ready; // gotów do odjazdu z W4 (semafor może // zatrzymać) - if (tsGuardSignal) // jeśli mamy głos kierownika, to odegrać + if (false == tsGuardSignal->empty()) // jeśli mamy głos kierownika, to odegrać iDrivigFlags |= moveGuardSignal; continue; // nie analizować prędkości } // koniec startu z zatrzymania @@ -2572,9 +2572,12 @@ bool TController::DecBrake() bool TController::IncSpeed() { // zwiększenie prędkości; zwraca false, jeśli dalej się nie da zwiększać +#ifdef EU07_USE_OLD_SOUNDCODE if (tsGuardSignal) // jeśli jest dźwięk kierownika if (tsGuardSignal->GetStatus() & DSBSTATUS_PLAYING) // jeśli gada, to nie jedziemy return false; +#else +#endif bool OK = true; if( ( iDrivigFlags & moveDoorOpened ) && ( VelDesired > 0.0 ) ) { // to prevent door shuffle on stop @@ -3084,10 +3087,14 @@ bool TController::PutCommand( std::string NewCommand, double NewValue1, double N NewCommand = Global::asCurrentSceneryPath + NewCommand + ".wav"; // na razie jeden if (FileExists(NewCommand)) { // wczytanie dźwięku odjazdu podawanego bezpośrenido - tsGuardSignal = new TTextSound(NewCommand, 30, pVehicle->GetPosition().x, - pVehicle->GetPosition().y, pVehicle->GetPosition().z, - false); - // rsGuardSignal->Stop(); +#ifdef EU07_USE_OLD_SOUNDCODE + tsGuardSignal = + new TTextSound( + NewCommand, 30, + pVehicle->GetPosition().x, pVehicle->GetPosition().y, pVehicle->GetPosition().z, + false); +#else +#endif iGuardRadio = 0; // nie przez radio } else @@ -3095,9 +3102,14 @@ bool TController::PutCommand( std::string NewCommand, double NewValue1, double N NewCommand = NewCommand.insert(NewCommand.find_last_of("."),"radio"); // wstawienie przed kropkč if (FileExists(NewCommand)) { // wczytanie dźwięku odjazdu w wersji radiowej (słychać tylko w kabinie) - tsGuardSignal = new TTextSound(NewCommand, -1, pVehicle->GetPosition().x, - pVehicle->GetPosition().y, pVehicle->GetPosition().z, - false); +#ifdef EU07_USE_OLD_SOUNDCODE + tsGuardSignal = + new TTextSound( + NewCommand, -1, + pVehicle->GetPosition().x, pVehicle->GetPosition().y, pVehicle->GetPosition().z, + false); +#else +#endif iGuardRadio = iRadioChannel; } } @@ -4472,7 +4484,10 @@ TController::UpdateSituation(double dt) { ->DoorOpenCtrl ) // jeśli drzwi niesterowane przez maszynistę Doors( false ); // a EZT zamknie dopiero po odegraniu komunikatu kierownika +#ifdef EU07_USE_OLD_SOUNDCODE tsGuardSignal->Stop(); +#else +#endif // w zasadzie to powinien mieć flagę, czy jest dźwiękiem radiowym, czy // bezpośrednim // albo trzeba zrobić dwa dźwięki, jeden bezpośredni, słyszalny w @@ -4481,7 +4496,10 @@ TController::UpdateSituation(double dt) { // obsługę kanałów radiowych itd. if( !iGuardRadio ) { // jeśli nie przez radio +#ifdef EU07_USE_OLD_SOUNDCODE tsGuardSignal->Play( 1.0, 0, !FreeFlyModeFlag, pVehicle->GetPosition() ); // dla true jest głośniej +#else +#endif } else { // if (iGuardRadio==iRadioChannel) //zgodność kanału @@ -4490,7 +4508,10 @@ TController::UpdateSituation(double dt) { // przy braku reakcji if( SquareMagnitude( pVehicle->GetPosition() - Global::pCameraPosition ) < 2000 * 2000 ) { // w odległości mniejszej niż 2km +#ifdef EU07_USE_OLD_SOUNDCODE tsGuardSignal->Play( 1.0, 0, true, pVehicle->GetPosition() ); // dźwięk niby przez radio +#else +#endif } } } diff --git a/Driver.h b/Driver.h index e4ee16e6..44dd11ed 100644 --- a/Driver.h +++ b/Driver.h @@ -242,7 +242,10 @@ private: TTrainParameters *TrainParams = nullptr; // rozkład jazdy zawsze jest, nawet jeśli pusty int iRadioChannel = 1; // numer aktualnego kanału radiowego int iGuardRadio = 0; // numer kanału radiowego kierownika (0, gdy nie używa radia) +/* TTextSound *tsGuardSignal = nullptr; // komunikat od kierownika +*/ + sound_source *tsGuardSignal { nullptr }; public: double AccPreferred = 0.0; // preferowane przyspieszenie (wg psychiki kierującego, zmniejszana przy wykryciu kolizji) double AccDesired = AccPreferred; // przyspieszenie, jakie ma utrzymywać (<0:nie przyspieszaj,<-0.1:hamuj) diff --git a/DynObj.cpp b/DynObj.cpp index 58ae59fa..574db0c0 100644 --- a/DynObj.cpp +++ b/DynObj.cpp @@ -612,14 +612,14 @@ void TDynamicObject::ABuLittleUpdate(double ObjSqrDist) if ((TestFlag(MoverParameters->Couplers[0].CouplingFlag, ctrain_coupler)) && (MoverParameters->Couplers[0].Render)) { - btCoupler1.TurnOn(); + btCoupler1.Turn( true ); btnOn = true; } // else btCoupler1.TurnOff(); if ((TestFlag(MoverParameters->Couplers[1].CouplingFlag, ctrain_coupler)) && (MoverParameters->Couplers[1].Render)) { - btCoupler2.TurnOn(); + btCoupler2.Turn( true ); btnOn = true; } // else btCoupler2.TurnOff(); @@ -820,26 +820,26 @@ void TDynamicObject::ABuLittleUpdate(double ObjSqrDist) // przewody sterowania ukrotnionego if (TestFlag(MoverParameters->Couplers[0].CouplingFlag, ctrain_controll)) { - btCCtrl1.TurnOn(); + btCCtrl1.Turn( true ); btnOn = true; } // else btCCtrl1.TurnOff(); if (TestFlag(MoverParameters->Couplers[1].CouplingFlag, ctrain_controll)) { - btCCtrl2.TurnOn(); + btCCtrl2.Turn( true ); btnOn = true; } // else btCCtrl2.TurnOff(); // McZapkie-181103: mostki przejsciowe if (TestFlag(MoverParameters->Couplers[0].CouplingFlag, ctrain_passenger)) { - btCPass1.TurnOn(); + btCPass1.Turn( true ); btnOn = true; } // else btCPass1.TurnOff(); if (TestFlag(MoverParameters->Couplers[1].CouplingFlag, ctrain_passenger)) { - btCPass2.TurnOn(); + btCPass2.Turn( true ); btnOn = true; } // else btCPass2.TurnOff(); @@ -849,7 +849,7 @@ void TDynamicObject::ABuLittleUpdate(double ObjSqrDist) { if (TestFlag(iLights[0], 2) || TestFlag(iLights[0], 32)) { - btEndSignals1.TurnOn(); + btEndSignals1.Turn( true ); btnOn = true; } // else btEndSignals1.TurnOff(); @@ -858,13 +858,13 @@ void TDynamicObject::ABuLittleUpdate(double ObjSqrDist) { if (TestFlag(iLights[0], 2)) { - btEndSignals11.TurnOn(); + btEndSignals11.Turn( true ); btnOn = true; } // else btEndSignals11.TurnOff(); if (TestFlag(iLights[0], 32)) { - btEndSignals13.TurnOn(); + btEndSignals13.Turn( true ); btnOn = true; } // else btEndSignals13.TurnOff(); @@ -873,7 +873,7 @@ void TDynamicObject::ABuLittleUpdate(double ObjSqrDist) { if (TestFlag(iLights[1], 2) || TestFlag(iLights[1], 32)) { - btEndSignals2.TurnOn(); + btEndSignals2.Turn( true ); btnOn = true; } // else btEndSignals2.TurnOff(); @@ -882,28 +882,28 @@ void TDynamicObject::ABuLittleUpdate(double ObjSqrDist) { if (TestFlag(iLights[1], 2)) { - btEndSignals21.TurnOn(); + btEndSignals21.Turn( true ); btnOn = true; } // else btEndSignals21.TurnOff(); if (TestFlag(iLights[1], 32)) { - btEndSignals23.TurnOn(); + btEndSignals23.Turn( true ); btnOn = true; } // else btEndSignals23.TurnOff(); } } // tablice blaszane: - if (TestFlag(iLights[0], 64)) + if (TestFlag(iLights[side::front], light::rearendsignals)) { - btEndSignalsTab1.TurnOn(); + btEndSignalsTab1.Turn( true ); btnOn = true; } // else btEndSignalsTab1.TurnOff(); - if (TestFlag(iLights[1], 64)) + if (TestFlag(iLights[side::rear], light::rearendsignals)) { - btEndSignalsTab2.TurnOn(); + btEndSignalsTab2.Turn( true ); btnOn = true; } // else btEndSignalsTab2.TurnOff(); @@ -914,36 +914,17 @@ void TDynamicObject::ABuLittleUpdate(double ObjSqrDist) smWahacze[i]->SetRotate(float3(1, 0, 0), fWahaczeAmp * cos(MoverParameters->eAngle)); - if (Mechanik) - { // rysowanie figurki mechanika - /* - if (smMechanik0) // mechanik od strony sprzęgu 0 - if (smMechanik1) // jak jest drugi, to pierwszego jedynie pokazujemy - smMechanik0->iVisible = MoverParameters->ActiveCab > 0; - else - { // jak jest tylko jeden, to do drugiej kabiny go obracamy - smMechanik0->iVisible = (MoverParameters->ActiveCab != 0); - smMechanik0->SetRotate( - float3(0, 0, 1), - MoverParameters->ActiveCab >= 0 ? 0 : 180); // obrót względem osi Z - } - if (smMechanik1) // mechanik od strony sprzęgu 1 - smMechanik1->iVisible = MoverParameters->ActiveCab < 0; - */ - if (MoverParameters->ActiveCab > 0) - { - btMechanik1.TurnOn(); - btnOn = true; - } - if (MoverParameters->ActiveCab < 0) - { - btMechanik2.TurnOn(); - btnOn = true; - } + if (Mechanik) { + // rysowanie figurki mechanika + if( MoverParameters->ActiveCab > 0 ) { + btMechanik1.Turn( true ); + btnOn = true; + } + if( MoverParameters->ActiveCab < 0 ) { + btMechanik2.Turn( true ); + btnOn = true; + } } - // ABu: Przechyly na zakretach - // Ra: przechyłkę załatwiamy na etapie przesuwania modelu - // if (ObjSqrDist<80000) ABuModelRoll(); //przechyłki od 400m } if( MoverParameters->Battery || MoverParameters->ConverterFlag ) { // sygnały czoła pociagu //Ra: wyświetlamy bez @@ -951,37 +932,37 @@ void TDynamicObject::ABuLittleUpdate(double ObjSqrDist) // daleka if (TestFlag(iLights[0], 1)) { - btHeadSignals11.TurnOn(); + btHeadSignals11.Turn( true ); btnOn = true; } // else btHeadSignals11.TurnOff(); if (TestFlag(iLights[0], 4)) { - btHeadSignals12.TurnOn(); + btHeadSignals12.Turn( true ); btnOn = true; } // else btHeadSignals12.TurnOff(); if (TestFlag(iLights[0], 16)) { - btHeadSignals13.TurnOn(); + btHeadSignals13.Turn( true ); btnOn = true; } // else btHeadSignals13.TurnOff(); if (TestFlag(iLights[1], 1)) { - btHeadSignals21.TurnOn(); + btHeadSignals21.Turn( true ); btnOn = true; } // else btHeadSignals21.TurnOff(); if (TestFlag(iLights[1], 4)) { - btHeadSignals22.TurnOn(); + btHeadSignals22.Turn( true ); btnOn = true; } // else btHeadSignals22.TurnOff(); if (TestFlag(iLights[1], 16)) { - btHeadSignals23.TurnOn(); + btHeadSignals23.Turn( true ); btnOn = true; } // else btHeadSignals23.TurnOff(); @@ -2926,12 +2907,13 @@ bool TDynamicObject::Update(double dt, double dt1) } Global::ABuDebug = dDOMoveLen / dt1; ResetdMoveLen(); + +#ifdef EU07_USE_OLD_SOUNDCODE // McZapkie-260202 // tupot mew, tfu, stukot kol: // taka prowizorka zeby sciszyc stukot dalekiej lokomotywy double ObjectDist; double vol = 0; - // double freq; //Ra: nie używane ObjectDist = SquareMagnitude(Global::pCameraPosition - vPosition); // McZapkie-270202 if (MyTrack->fSoundDistance != -1) @@ -2979,8 +2961,7 @@ bool TDynamicObject::Update(double dt, double dt1) { rsStukot[i + 1].Stop(); } - rsStukot[i].Play(vol, 0, MechInside, - vPosition); // poprawic pozycje o uklad osi + rsStukot[i].Play(vol, 0, MechInside, vPosition); // poprawic pozycje o uklad osi if (i == 1) MoverParameters->AccV -= 0.5 * GetVelocity() / (1 + MoverParameters->Vmax); @@ -3018,7 +2999,7 @@ bool TDynamicObject::Update(double dt, double dt1) else rsUnbrake.Stop(); } - +#endif // fragment z EXE Kursa /* if (MoverParameters->TrainType==dt_ET42) { @@ -3128,13 +3109,16 @@ bool TDynamicObject::Update(double dt, double dt1) else if( ( true == MoverParameters->PantFrontUp ) && ( PantDiff < 0.01 ) ) // tolerancja niedolegania { - if ((MoverParameters->PantFrontVolt == 0.0) && - (MoverParameters->PantRearVolt == 0.0)) - sPantUp.Play(vol, 0, MechInside, vPosition); - if (p->hvPowerWire) // TODO: wyliczyć trzeba prąd przypadający na - // pantograf i - // wstawić do GetVoltage() - { + if( ( MoverParameters->PantFrontVolt == 0.0 ) + && ( MoverParameters->PantRearVolt == 0.0 ) ) { +#ifdef EU07_USE_OLD_SOUNDCODE + sPantUp.Play( vol, 0, MechInside, vPosition ); +#else + sPantUp.play(); +#endif + } + if (p->hvPowerWire) { + // TODO: wyliczyć trzeba prąd przypadający na pantograf i wstawić do GetVoltage() MoverParameters->PantFrontVolt = p->hvPowerWire->VoltageGet(MoverParameters->Voltage, fPantCurrent); fCurrent -= fPantCurrent; // taki prąd płynie przez powyższy pantograf @@ -3159,7 +3143,11 @@ bool TDynamicObject::Update(double dt, double dt1) { if( ( MoverParameters->PantRearVolt == 0.0 ) && ( MoverParameters->PantFrontVolt == 0.0 ) ) { +#ifdef EU07_USE_OLD_SOUNDCODE sPantUp.Play( vol, 0, MechInside, vPosition ); +#else + sPantUp.play(); +#endif } if (p->hvPowerWire) { // TODO: wyliczyć trzeba prąd przypadający na pantograf i wstawić do GetVoltage() @@ -3246,12 +3234,20 @@ bool TDynamicObject::Update(double dt, double dt1) } // koniec pętli po pantografach if ((MoverParameters->PantFrontSP == false) && (MoverParameters->PantFrontUp == false)) { +#ifdef EU07_USE_OLD_SOUNDCODE sPantDown.Play(vol, 0, MechInside, vPosition); +#else + sPantDown.play(); +#endif MoverParameters->PantFrontSP = true; } if ((MoverParameters->PantRearSP == false) && (MoverParameters->PantRearUp == false)) { +#ifdef EU07_USE_OLD_SOUNDCODE sPantDown.Play(vol, 0, MechInside, vPosition); +#else + sPantDown.play(); +#endif MoverParameters->PantRearSP = true; } /* @@ -3354,24 +3350,40 @@ bool TDynamicObject::Update(double dt, double dt1) // NBMX Obsluga drzwi, MC: zuniwersalnione if ((dDoorMoveL < MoverParameters->DoorMaxShiftL) && (MoverParameters->DoorLeftOpened)) { - rsDoorOpen.Play(1, 0, MechInside, vPosition); +#ifdef EU07_USE_OLD_SOUNDCODE + rsDoorOpen.Play(1, 0, MechInside, vPosition); +#else + rsDoorOpen.play(); +#endif dDoorMoveL += dt1 * 0.5 * MoverParameters->DoorOpenSpeed; } if ((dDoorMoveL > 0) && (!MoverParameters->DoorLeftOpened)) { - rsDoorClose.Play(1, 0, MechInside, vPosition); +#ifdef EU07_USE_OLD_SOUNDCODE + rsDoorClose.Play(1, 0, MechInside, vPosition); +#else + rsDoorClose.play(); +#endif dDoorMoveL -= dt1 * MoverParameters->DoorCloseSpeed; if (dDoorMoveL < 0) dDoorMoveL = 0; } if ((dDoorMoveR < MoverParameters->DoorMaxShiftR) && (MoverParameters->DoorRightOpened)) { - rsDoorOpen.Play(1, 0, MechInside, vPosition); +#ifdef EU07_USE_OLD_SOUNDCODE + rsDoorOpen.Play(1, 0, MechInside, vPosition); +#else + rsDoorOpen.play(); +#endif dDoorMoveR += dt1 * 0.5 * MoverParameters->DoorOpenSpeed; } if ((dDoorMoveR > 0) && (!MoverParameters->DoorRightOpened)) { - rsDoorClose.Play(1, 0, MechInside, vPosition); +#ifdef EU07_USE_OLD_SOUNDCODE + rsDoorClose.Play(1, 0, MechInside, vPosition); +#else + rsDoorClose.play(); +#endif dDoorMoveR -= dt1 * MoverParameters->DoorCloseSpeed; if (dDoorMoveR < 0) dDoorMoveR = 0; @@ -3465,8 +3477,8 @@ void TDynamicObject::TurnOff() { // wyłączenie rysowania submodeli zmiennych dla // egemplarza pojazdu btnOn = false; - btCoupler1.TurnOff(); - btCoupler2.TurnOff(); + btCoupler1.Turn( false ); + btCoupler2.Turn( false ); btCPneumatic1.TurnOff(); btCPneumatic1r.TurnOff(); btCPneumatic2.TurnOff(); @@ -3475,45 +3487,41 @@ void TDynamicObject::TurnOff() btPneumatic1r.TurnOff(); btPneumatic2.TurnOff(); btPneumatic2r.TurnOff(); - btCCtrl1.TurnOff(); - btCCtrl2.TurnOff(); - btCPass1.TurnOff(); - btCPass2.TurnOff(); - btEndSignals11.TurnOff(); - btEndSignals13.TurnOff(); - btEndSignals21.TurnOff(); - btEndSignals23.TurnOff(); - btEndSignals1.TurnOff(); - btEndSignals2.TurnOff(); - btEndSignalsTab1.TurnOff(); - btEndSignalsTab2.TurnOff(); - btHeadSignals11.TurnOff(); - btHeadSignals12.TurnOff(); - btHeadSignals13.TurnOff(); - btHeadSignals21.TurnOff(); - btHeadSignals22.TurnOff(); - btHeadSignals23.TurnOff(); - btMechanik1.TurnOff(); - btMechanik2.TurnOff(); + btCCtrl1.Turn( false ); + btCCtrl2.Turn( false ); + btCPass1.Turn( false ); + btCPass2.Turn( false ); + btEndSignals11.Turn( false ); + btEndSignals13.Turn( false ); + btEndSignals21.Turn( false ); + btEndSignals23.Turn( false ); + btEndSignals1.Turn( false ); + btEndSignals2.Turn( false ); + btEndSignalsTab1.Turn( false ); + btEndSignalsTab2.Turn( false ); + btHeadSignals11.Turn( false ); + btHeadSignals12.Turn( false ); + btHeadSignals13.Turn( false ); + btHeadSignals21.Turn( false ); + btHeadSignals22.Turn( false ); + btHeadSignals23.Turn( false ); + btMechanik1.Turn( false ); + btMechanik2.Turn( false ); }; -void TDynamicObject::RenderSounds() -{ // przeliczanie dźwięków, bo będzie słychać bez wyświetlania sektora z pojazdem -// if( Global::iPause > 0 ) { return; } - +// przeliczanie dźwięków, bo będzie słychać bez wyświetlania sektora z pojazdem +void TDynamicObject::RenderSounds() { +#ifdef EU07_USE_OLD_SOUNDCODE // McZapkie-010302: ulepszony dzwiek silnika double freq; double vol = 0; double dt = Timer::GetDeltaRenderTime(); - // double sounddist; - // sounddist=SquareMagnitude(Global::pCameraPosition-vPosition); - if (MoverParameters->Power > 0) { if ((rsSilnik.AM != 0) && ((MoverParameters->Mains) - // McZapkie-280503: zeby dla dumb dzialal silnik na jalowych obrotach + // McZapkie-280503: zeby dla dumb dzialal silnik na jalowych obrotach || (MoverParameters->EngineType == DieselEngine))) { if ((fabs(MoverParameters->enrot) > 0.01) || @@ -3521,8 +3529,7 @@ void TDynamicObject::RenderSounds() { freq = rsSilnik.FM * fabs(MoverParameters->enrot) + rsSilnik.FA; if (MoverParameters->EngineType == Dumb) - freq = freq - - 0.2 * MoverParameters->EnginePower / (1 + MoverParameters->Power * 1000); + freq = freq - 0.2 * MoverParameters->EnginePower / (1 + MoverParameters->Power * 1000); rsSilnik.AdjFreq(freq, dt); if (MoverParameters->EngineType == DieselEngine) { @@ -3561,24 +3568,23 @@ void TDynamicObject::RenderSounds() if (volrnd < 2) vol = vol + volrnd / 200.0; } - switch (MyTrack->eEnvironment) - { - case e_tunnel: - { - vol += 0.1; + switch( MyTrack->eEnvironment ) { + case e_tunnel: { + vol += 0.1; + break; + } + case e_canyon: { + vol += 0.05; + break; + } + default: { + break; + } } - break; - case e_canyon: - { - vol += 0.05; - } - break; - } - if ((MoverParameters->DynamicBrakeFlag) && (MoverParameters->EnginePower > 0.1) && - (MoverParameters->EngineType == - ElectricSeriesMotor)) // Szociu - 29012012 - jeżeli uruchomiony - // jest hamulec - // elektrodynamiczny, odtwarzany jest dźwięk silnika + if( ( MoverParameters->DynamicBrakeFlag ) + && ( MoverParameters->EnginePower > 0.1 ) + && ( MoverParameters->EngineType == ElectricSeriesMotor ) ) + // Szociu - 29012012 - jeżeli uruchomiony jest hamulec elektrodynamiczny, odtwarzany jest dźwięk silnika vol += 0.8; if (enginevolume > 0.0001) @@ -3693,15 +3699,6 @@ void TDynamicObject::RenderSounds() if (MoverParameters->BrakePress < 0.1) releaser_vol = MoverParameters->BrakePress * 10; sReleaser.UpdateAF(releaser_vol, 1, MechInside, GetPosition()); - // if ((MoverParameters->ConverterFlag==false) && - // (MoverParameters->TrainType!=dt_ET22)) - // if - // ((MoverParameters->ConverterFlag==false)&&(MoverParameters->CompressorPower!=0)) - // MoverParameters->CompressorFlag=false; //Ra: wywalić to stąd, tu tylko dla - // wyświetlanych! - // Ra: no to już wiemy, dlaczego pociągi jeżdżą lepiej, gdy się na nie patrzy! - // if (MoverParameters->CompressorPower==2) - // MoverParameters->CompressorAllow=MoverParameters->ConverterFlag; // McZapkie! - dzwiek compressor.wav tylko gdy dziala sprezarka if (MoverParameters->VeselVolume != 0) @@ -3851,15 +3848,7 @@ void TDynamicObject::RenderSounds() if (GetVelocity() == 0) rsDerailment.Stop(); } - /* //Ra: dwa razy? - if (MoverParameters->EventFlag) - { - if (TestFlag(MoverParameters->DamageFlag,dtrain_out) && GetVelocity()>0) - rsDerailment.Play(1,0,true,GetPosition()); - if (GetVelocity()==0) - rsDerailment.Stop(); - } - */ +#endif }; // McZapkie-250202 @@ -4560,10 +4549,16 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName, parser.getTokens(); parser >> token; if( token != "end" ) { - rsStukot[ i ].Init( token, dSDist, GetPosition().x, - GetPosition().y + dWheelsPosition[ i ], GetPosition().z, +#ifdef EU07_USE_OLD_SOUNDCODE + rsStukot[ i ].Init( + token, dSDist, + GetPosition().x, GetPosition().y + dWheelsPosition[ i ], GetPosition().z, true ); - } +#else + rsStukot[ i ].deserialize( token + " " + std::to_string( dSDist ), sound_type::single, sound_parameters::range ); + // TODO: set per-wheel offset +#endif + } } if( token != "end" ) { // TODO: double-check if this if() and/or retrieval makes sense here @@ -4574,6 +4569,7 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName, else if( ( token == "engine:" ) && ( MoverParameters->Power > 0 ) ) { // plik z dzwiekiem silnika, mnozniki i ofsety amp. i czest. +#ifdef EU07_USE_OLD_SOUNDCODE double attenuation; parser.getTokens( 2, false ); parser @@ -4585,7 +4581,7 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName, true, true ); if( rsSilnik.GetWaveTime() == 0 ) { ErrorLog( "Missed sound: \"" + token + "\" for " + asFileName ); - } + } parser.getTokens( 1, false ); parser >> rsSilnik.AM; if( MoverParameters->EngineType == DieselEngine ) { @@ -4605,13 +4601,17 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName, >> rsSilnik.AA >> rsSilnik.FM // MoverParameters->nmax; >> rsSilnik.FA; +#else + rsSilnik.deserialize( parser, sound_type::single, sound_parameters::range | sound_parameters::amplitude | sound_parameters::frequency ); +#endif } else if( ( token == "ventilator:" ) && ( ( MoverParameters->EngineType == ElectricSeriesMotor ) || ( MoverParameters->EngineType == ElectricInductionMotor ) ) ) { // plik z dzwiekiem wentylatora, mnozniki i ofsety amp. i czest. - double attenuation; +#ifdef EU07_USE_OLD_SOUNDCODE + double attenuation; parser.getTokens( 2, false ); parser >> token @@ -4628,12 +4628,16 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName, >> rsWentylator.FA; rsWentylator.AM /= MoverParameters->RVentnmax; rsWentylator.FM /= MoverParameters->RVentnmax; +#else + rsWentylator.deserialize( parser, sound_type::single, sound_parameters::range | sound_parameters::amplitude | sound_parameters::frequency ); +#endif } else if( ( token == "transmission:" ) && ( MoverParameters->EngineType == ElectricSeriesMotor ) ) { // plik z dzwiekiem, mnozniki i ofsety amp. i czest. - double attenuation; +#ifdef EU07_USE_OLD_SOUNDCODE + double attenuation; parser.getTokens( 2, false ); parser >> token @@ -4646,11 +4650,15 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName, rsPrzekladnia.AA = 0.1; rsPrzekladnia.FM = 0.005; rsPrzekladnia.FA = 1.0; +#else + rsPrzekladnia.deserialize( parser, sound_type::single, sound_parameters::range | sound_parameters::amplitude | sound_parameters::frequency ); +#endif } else if( token == "brake:" ){ // plik z piskiem hamulca, mnozniki i ofsety amplitudy. - double attenuation; +#ifdef EU07_USE_OLD_SOUNDCODE + double attenuation; parser.getTokens( 2, false ); parser >> token @@ -4663,23 +4671,26 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName, rsPisk.AA = parser.getToken() * ( 105 - Random( 10 ) ) / 100; rsPisk.FM = 1.0; rsPisk.FA = 0.0; +#else + rsPisk.deserialize( parser, sound_type::single, sound_parameters::range | sound_parameters::amplitude ); +#endif } else if( token == "brakeacc:" ) { // plik z przyspieszaczem (upust po zlapaniu hamowania) - // sBrakeAcc.Init(str.c_str(),Parser->GetNextSymbol().ToDouble(),GetPosition().x,GetPosition().y,GetPosition().z,true); - parser.getTokens( 1, false ); parser >> token; +#ifdef EU07_USE_OLD_SOUNDCODE + parser.getTokens( 1, false ); parser >> token; sBrakeAcc = TSoundsManager::GetFromName( token, true ); +#else + sBrakeAcc.deserialize( parser, sound_type::single ); +#endif bBrakeAcc = true; - // sBrakeAcc.AM=1.0; - // sBrakeAcc.AA=0.0; - // sBrakeAcc.FM=1.0; - // sBrakeAcc.FA=0.0; } else if( token == "unbrake:" ) { // plik z piskiem hamulca, mnozniki i ofsety amplitudy. - double attenuation; +#ifdef EU07_USE_OLD_SOUNDCODE + double attenuation; parser.getTokens( 2, false ); parser >> token @@ -4692,11 +4703,15 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName, rsUnbrake.AA = 0.0; rsUnbrake.FM = 1.0; rsUnbrake.FA = 0.0; +#else + rsUnbrake.deserialize( parser, sound_type::single, sound_parameters::range ); +#endif } else if( token == "derail:" ) { // dzwiek przy wykolejeniu - double attenuation; +#ifdef EU07_USE_OLD_SOUNDCODE + double attenuation; parser.getTokens( 2, false ); parser >> token @@ -4709,11 +4724,15 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName, rsDerailment.AA = 0.0; rsDerailment.FM = 1.0; rsDerailment.FA = 0.0; +#else + rsDerailment.deserialize( parser, sound_type::single, sound_parameters::range ); +#endif } else if( token == "dieselinc:" ) { // dzwiek przy wlazeniu na obroty woodwarda - double attenuation; +#ifdef EU07_USE_OLD_SOUNDCODE + double attenuation; parser.getTokens( 2, false ); parser >> token @@ -4726,12 +4745,16 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName, rsDiesielInc.AA = 0.0; rsDiesielInc.FM = 1.0; rsDiesielInc.FA = 0.0; +#else + rsDiesielInc.deserialize( parser, sound_type::single, sound_parameters::range ); +#endif } else if( token == "curve:" ) { double attenuation; - parser.getTokens( 2, false ); +#ifdef EU07_USE_OLD_SOUNDCODE + parser.getTokens( 2, false ); parser >> token >> attenuation; @@ -4743,91 +4766,143 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName, rscurve.AA = 0.0; rscurve.FM = 1.0; rscurve.FA = 0.0; +#else + rscurve.deserialize( parser, sound_type::single, sound_parameters::range ); +#endif } else if( token == "horn1:" ) { // pliki z trabieniem - sHorn1.Load( parser, GetPosition() ); +#ifdef EU07_USE_OLD_SOUNDCODE + sHorn1.Load( parser, GetPosition() ); +#else + sHorn1.deserialize( parser, sound_type::multipart, sound_parameters::range ); +#endif } else if( token == "horn2:" ) { // pliki z trabieniem wysokoton. - sHorn2.Load( parser, GetPosition() ); - if( iHornWarning ) { +#ifdef EU07_USE_OLD_SOUNDCODE + sHorn2.Load( parser, GetPosition() ); +#else + sHorn2.deserialize( parser, sound_type::multipart, sound_parameters::range ); +#endif + if( iHornWarning ) { iHornWarning = 2; // numer syreny do użycia po otrzymaniu sygnału do jazdy - } + } } else if( token == "departuresignal:" ) { // pliki z sygnalem odjazdu - sDepartureSignal.Load( parser, GetPosition() ); +#ifdef EU07_USE_OLD_SOUNDCODE + sDepartureSignal.Load( parser, GetPosition() ); +#else + sDepartureSignal.deserialize( parser, sound_type::multipart, sound_parameters::range ); +#endif } else if( token == "pantographup:" ) { // pliki dzwiekow pantografow - parser.getTokens( 1, false ); parser >> token; +#ifdef EU07_USE_OLD_SOUNDCODE + parser.getTokens( 1, false ); parser >> token; sPantUp.Init( token, 50, GetPosition().x, GetPosition().y, GetPosition().z, true ); +#else + sPantUp.deserialize( parser, sound_type::single ); +#endif } else if( token == "pantographdown:" ) { // pliki dzwiekow pantografow - parser.getTokens( 1, false ); parser >> token; +#ifdef EU07_USE_OLD_SOUNDCODE + parser.getTokens( 1, false ); parser >> token; sPantDown.Init( token, 50, GetPosition().x, GetPosition().y, GetPosition().z, true ); +#else + sPantDown.deserialize( parser, sound_type::single ); +#endif } else if( token == "compressor:" ) { // pliki ze sprezarka +#ifdef EU07_USE_OLD_SOUNDCODE sCompressor.Load( parser, GetPosition() ); +#else + sCompressor.deserialize( parser, sound_type::multipart, sound_parameters::range ); +#endif } else if( token == "converter:" ) { // pliki z przetwornica - // if (MoverParameters->EngineType==DieselElectric) //będzie modulowany? - sConverter.Load( parser, GetPosition() ); +#ifdef EU07_USE_OLD_SOUNDCODE + sConverter.Load( parser, GetPosition() ); +#else + sConverter.deserialize( parser, sound_type::multipart, sound_parameters::range ); +#endif } else if( token == "turbo:" ) { // pliki z turbogeneratorem - sTurbo.Load( parser, GetPosition() ); +#ifdef EU07_USE_OLD_SOUNDCODE + sTurbo.Load( parser, GetPosition() ); +#else + sTurbo.deserialize( parser, sound_type::multipart, sound_parameters::range ); +#endif } else if( token == "small-compressor:" ) { // pliki z przetwornica - sSmallCompressor.Load( parser, GetPosition() ); +#ifdef EU07_USE_OLD_SOUNDCODE + sSmallCompressor.Load( parser, GetPosition() ); +#else + sSmallCompressor.deserialize( parser, sound_type::multipart, sound_parameters::range ); +#endif } else if( token == "dooropen:" ) { - - parser.getTokens( 1, false ); parser >> token; +#ifdef EU07_USE_OLD_SOUNDCODE + parser.getTokens( 1, false ); parser >> token; rsDoorOpen.Init( token, 50, GetPosition().x, GetPosition().y, GetPosition().z, true ); +#else + rsDoorOpen.deserialize( parser, sound_type::single ); +#endif } else if( token == "doorclose:" ) { - +#ifdef EU07_USE_OLD_SOUNDCODE parser.getTokens( 1, false ); parser >> token; rsDoorClose.Init( token, 50, GetPosition().x, GetPosition().y, GetPosition().z, true ); +#else + rsDoorClose.deserialize( parser, sound_type::single ); +#endif } else if( token == "sand:" ) { - // pliki z piasecznica +#ifdef EU07_USE_OLD_SOUNDCODE + // pliki z piasecznica sSand.Load( parser, GetPosition() ); +#else + sSand.deserialize( parser, sound_type::multipart, sound_parameters::range ); +#endif } else if( token == "releaser:" ) { // pliki z odluzniaczem - sReleaser.Load( parser, GetPosition() ); +#ifdef EU07_USE_OLD_SOUNDCODE + sReleaser.Load( parser, GetPosition() ); +#else + sReleaser.deserialize( parser, sound_type::multipart, sound_parameters::range ); +#endif } } while( ( token != "" ) diff --git a/DynObj.h b/DynObj.h index c3cb5adb..96cba4bf 100644 --- a/DynObj.h +++ b/DynObj.h @@ -14,10 +14,9 @@ http://mozilla.org/MPL/2.0/. #include "TrkFoll.h" // McZapkie: -#include "RealSound.h" -#include "AdvSound.h" #include "Button.h" #include "AirCoupler.h" +#include "sound.h" #include "texture.h" //--------------------------------------------------------------------------- @@ -304,27 +303,27 @@ private: double dRailLength; double dRailPosition[MaxAxles]; // licznik pozycji osi w/m szyny double dWheelsPosition[MaxAxles]; // pozycja osi w/m srodka pojazdu - TRealSound rsStukot[MaxAxles]; // dzwieki poszczegolnych osi //McZapkie-270202 - TRealSound rsSilnik; // McZapkie-010302 - silnik - TRealSound rsWentylator; // McZapkie-030302 - TRealSound rsPisk; // McZapkie-260302 - TRealSound rsDerailment; // McZapkie-051202 - TRealSound rsPrzekladnia; - TAdvancedSound sHorn1; - TAdvancedSound sHorn2; - TAdvancedSound sCompressor; // NBMX wrzesien 2003 - TAdvancedSound sConverter; - TAdvancedSound sSmallCompressor; - TAdvancedSound sDepartureSignal; - TAdvancedSound sTurbo; - TAdvancedSound sSand; - TAdvancedSound sReleaser; + 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 - TRealSound sPantUp; - TRealSound sPantDown; - TRealSound rsDoorOpen; // Ra: przeniesione z kabiny - TRealSound rsDoorClose; + sound_source sPantUp; + sound_source sPantDown; + sound_source rsDoorOpen; // Ra: przeniesione z kabiny + sound_source rsDoorClose; double eng_vol_act; double eng_frq_act; @@ -336,9 +335,9 @@ private: bool renderme; // yB - czy renderowac // TRealSound sBrakeAcc; //dźwięk przyspieszacza - PSound sBrakeAcc; + sound_source sBrakeAcc; bool bBrakeAcc; - TRealSound rsUnbrake; // yB - odglos luzowania + sound_source rsUnbrake; // yB - odglos luzowania float ModCamRot; int iInventory[ 2 ] { 0, 0 }; // flagi bitowe posiadanych submodeli (np. świateł) void TurnOff(); @@ -379,8 +378,8 @@ private: std::string name() const { return this ? asName : std::string(); }; - TRealSound rsDiesielInc; // youBy - TRealSound rscurve; // youBy + sound_source rsDiesielInc; // youBy + sound_source rscurve; // youBy // std::ofstream PneuLogFile; //zapis parametrow pneumatycznych // youBy - dym // TSmoke Smog; diff --git a/Event.cpp b/Event.cpp index 15acc047..9db96750 100644 --- a/Event.cpp +++ b/Event.cpp @@ -1022,6 +1022,7 @@ event_manager::CheckQuery() { return false; } case tp_Sound: { +#ifdef EU07_USE_OLD_SOUNDCODE switch( m_workevent->Params[ 0 ].asInt ) { // trzy możliwe przypadki: case 0: { @@ -1048,6 +1049,7 @@ event_manager::CheckQuery() { break; } } +#endif break; } case tp_Disable: diff --git a/Event.h b/Event.h index d8c90562..642e4cbf 100644 --- a/Event.h +++ b/Event.h @@ -74,7 +74,11 @@ union TParam bool asBool; double asdouble; int asInt; +#ifdef EU07_USE_OLD_SOUNDCODE TTextSound *tsTextSound; +#else + sound_source *tsTextSound; +#endif char *asText; TCommandType asCommand; TTractionPowerSource *psPower; diff --git a/Gauge.cpp b/Gauge.cpp index 01232954..d785599e 100644 --- a/Gauge.cpp +++ b/Gauge.cpp @@ -70,16 +70,15 @@ bool TGauge::Load(cParser &Parser, TModel3d *md1, TModel3d *md2, double mul) { else { // new, block type config // TODO: rework the base part into yaml-compatible flow style mapping - cParser mappingparser( Parser.getToken( false, "}" ) ); - submodelname = mappingparser.getToken( false ); - gaugetypename = mappingparser.getToken( true ); - mappingparser.getTokens( 3, false ); - mappingparser + submodelname = Parser.getToken( false ); + gaugetypename = Parser.getToken( true ); + Parser.getTokens( 3, false ); + Parser >> scale >> offset >> friction; // new, variable length section - while( true == Load_mapping( mappingparser ) ) { + while( true == Load_mapping( Parser ) ) { ; // all work done by while() } } @@ -116,26 +115,15 @@ bool TGauge::Load(cParser &Parser, TModel3d *md1, TModel3d *md2, double mul) { bool TGauge::Load_mapping( cParser &Input ) { - if( false == Input.getTokens( 2, true, ", \n\r\t" ) ) { - return false; - } - - std::string key, value; - Input - >> key - >> value; - + // token can be a key or block end + std::string const key { Input.getToken( true, "\n\r\t ,;" ) }; + if( ( true == key.empty() ) || ( key == "}" ) ) { return false; } + // if not block end then the key is followed by assigned value or sub-block if( key == "soundinc:" ) { - m_soundfxincrease = ( - value != "none" ? - TSoundsManager::GetFromName( value, true ) : - nullptr ); + m_soundfxincrease.deserialize( Input, sound_type::single ); } else if( key == "sounddec:" ) { - m_soundfxdecrease = ( - value != "none" ? - TSoundsManager::GetFromName( value, true ) : - nullptr ); + m_soundfxdecrease.deserialize( Input, sound_type::single ); } else if( key.compare( 0, std::min( key.size(), 5 ), "sound" ) == 0 ) { // sounds assigned to specific gauge values, defined by key soundFoo: where Foo = value @@ -144,9 +132,7 @@ TGauge::Load_mapping( cParser &Input ) { if( indexstart != std::string::npos ) { m_soundfxvalues.emplace( std::stoi( key.substr( indexstart, indexend - indexstart ) ), - ( value != "none" ? - TSoundsManager::GetFromName( value, true ) : - nullptr ) ); + sound_source().deserialize( Input, sound_type::single ) ); } } return true; // return value marks a key: value pair was extracted, nothing about whether it's recognized @@ -176,9 +162,21 @@ void TGauge::DecValue(double fNewDesired) fDesiredValue = 0; }; +void +TGauge::UpdateValue( double fNewDesired ) { + + return UpdateValue( fNewDesired, nullptr ); +} + +void +TGauge::UpdateValue( double fNewDesired, sound_source &Fallbacksound ) { + + return UpdateValue( fNewDesired, &Fallbacksound ); +} + // ustawienie wartości docelowej. plays provided fallback sound, if no sound was defined in the control itself void -TGauge::UpdateValue( double fNewDesired, PSound Fallbacksound ) { +TGauge::UpdateValue( double fNewDesired, sound_source *Fallbacksound ) { auto const desiredtimes100 = static_cast( std::round( 100.0 * fNewDesired ) ); if( static_cast( std::round( 100.0 * ( fDesiredValue - fOffset ) / fScale ) ) == desiredtimes100 ) { @@ -191,21 +189,25 @@ TGauge::UpdateValue( double fNewDesired, PSound Fallbacksound ) { // filter out values other than full integers auto const lookup = m_soundfxvalues.find( desiredtimes100 / 100 ); if( lookup != m_soundfxvalues.end() ) { - play( lookup->second ); + lookup->second.play(); return; } } // ...and if there isn't any, fall back on the basic set... auto const currentvalue = GetValue(); - if( ( currentvalue < fNewDesired ) && ( m_soundfxincrease != nullptr ) ) { - play( m_soundfxincrease ); + if( ( currentvalue < fNewDesired ) + && ( false == m_soundfxincrease.empty() ) ) { + // shift up + m_soundfxincrease.play(); } - else if( ( currentvalue > fNewDesired ) && ( m_soundfxdecrease != nullptr ) ) { - play( m_soundfxdecrease ); + else if( ( currentvalue > fNewDesired ) + && ( false == m_soundfxdecrease.empty() ) ) { + // shift down + m_soundfxdecrease.play(); } else if( Fallbacksound != nullptr ) { // ...and if that fails too, try the provided fallback sound from legacy system - play( Fallbacksound ); + Fallbacksound->play(); } }; @@ -315,15 +317,4 @@ void TGauge::UpdateValue() } }; -void -TGauge::play( PSound Sound ) { - - if( Sound == nullptr ) { return; } - - Sound->SetCurrentPosition( 0 ); - Sound->SetVolume( DSBVOLUME_MAX ); - Sound->Play( 0, 0, 0 ); - return; -} - //--------------------------------------------------------------------------- diff --git a/Gauge.h b/Gauge.h index c437883c..081ffade 100644 --- a/Gauge.h +++ b/Gauge.h @@ -24,7 +24,13 @@ enum TGaugeType { // animowany wskaźnik, mogący przyjmować wiele stanów pośrednich class TGauge { - private: +private: +// methods +// imports member data pair from the config file + bool + Load_mapping( cParser &Input ); + void UpdateValue( double fNewDesired, sound_source *Fallbacksound ); +// members TGaugeType eType { gt_Unknown }; // typ ruchu double fFriction { 0.0 }; // hamowanie przy zliżaniu się do zadanej wartości double fDesiredValue { 0.0 }; // wartość docelowa @@ -38,18 +44,12 @@ class TGauge { double *dData { nullptr }; int *iData; }; - PSound m_soundfxincrease { nullptr }; // sound associated with increasing control's value - PSound m_soundfxdecrease { nullptr }; // sound associated with decreasing control's value - std::map m_soundfxvalues; // sounds associated with specific values -// methods - // imports member data pair from the config file - bool - Load_mapping( cParser &Input ); - // plays specified sound - void - play( PSound Sound ); + sound_source m_soundfxincrease; // sound associated with increasing control's value + sound_source m_soundfxdecrease; // sound associated with decreasing control's value + std::map m_soundfxvalues; // sounds associated with specific values - public: +public: +// methods TGauge() = default; inline void Clear() { *this = TGauge(); } @@ -58,7 +58,8 @@ class TGauge { void PermIncValue(double fNewDesired); void IncValue(double fNewDesired); void DecValue(double fNewDesired); - void UpdateValue(double fNewDesired, PSound Fallbacksound = nullptr ); + void UpdateValue( double fNewDesired ); + void UpdateValue( double fNewDesired, sound_source &Fallbacksound ); void PutValue(double fNewDesired); double GetValue() const; void Update(); @@ -67,6 +68,7 @@ class TGauge { void AssignDouble(double *dValue); void AssignInt(int *iValue); void UpdateValue(); +// members TSubModel *SubModel; // McZapkie-310302: zeby mozna bylo sprawdzac czy zainicjowany poprawnie }; diff --git a/Globals.h b/Globals.h index 478ec2a3..1dba16ae 100644 --- a/Globals.h +++ b/Globals.h @@ -114,6 +114,7 @@ int const k_DimHeadlights = 74; const int MaxKeys = 75; // klasy dla wskaźników globalnych +/* class TGround; class TWorld; class TCamera; @@ -121,8 +122,7 @@ class TDynamicObject; class TAnimModel; // obiekt terenu class cParser; // nowy (powolny!) parser class TEvent; -class TTextSound; - +*/ class TTranscript { // klasa obsługująca linijkę napisu do dźwięku public: @@ -293,7 +293,9 @@ public: static float4 UITextColor; // base color of UI text static std::string asLang; // domyślny język - http://tools.ietf.org/html/bcp47 static int iHiddenEvents; // czy łączyć eventy z torami poprzez nazwę toru +/* static TTextSound *tsRadioBusy[10]; // zajętość kanałów radiowych (wskaźnik na odgrywany dźwięk) +*/ static int iPoKeysPWM[7]; // numery wejść dla PWM //randomizacja diff --git a/Model3d.cpp b/Model3d.cpp index 799c136a..50c9c0d3 100644 --- a/Model3d.cpp +++ b/Model3d.cpp @@ -95,7 +95,7 @@ TSubModel::SetLightLevel( float const Level, bool const Includechildren, bool co } } -int TSubModel::SeekFaceNormal(std::vector const &Masks, int const Startface, unsigned int const Mask, glm::vec3 const &Position, vertex_array const &Vertices) +int TSubModel::SeekFaceNormal(std::vector const &Masks, int const Startface, unsigned int const Mask, glm::vec3 const &Position, gfx::vertex_array const &Vertices) { // szukanie punktu stycznego do (pt), zwraca numer wierzchołka, a nie trójkąta int facecount = iNumVerts / 3; // bo maska powierzchni jest jedna na trójkąt for( int faceidx = Startface; faceidx < facecount; ++faceidx ) { @@ -983,7 +983,7 @@ void TSubModel::serialize_geometry( std::ostream &Output ) const { }; void -TSubModel::create_geometry( std::size_t &Dataoffset, geometrybank_handle const &Bank ) { +TSubModel::create_geometry( std::size_t &Dataoffset, gfx::geometrybank_handle const &Bank ) { // data offset is used to determine data offset of each submodel into single shared geometry bank // (the offsets are part of legacy system which we now need to work around for backward compatibility) @@ -1472,7 +1472,7 @@ void TModel3d::deserialize(std::istream &s, size_t size, bool dynamic) // once sorted we can grab geometry as it comes, and assign it to the chunks it belongs to for( auto const &submodeloffset : submodeloffsets ) { auto &submodel = Root[ submodeloffset.second ]; - vertex_array vertices; vertices.resize( submodel.iNumVerts ); + gfx::vertex_array vertices; vertices.resize( submodel.iNumVerts ); iNumVerts += submodel.iNumVerts; for( auto &vertex : vertices ) { vertex.deserialize( s ); diff --git a/Model3d.h b/Model3d.h index 1a3ff290..57a01408 100644 --- a/Model3d.h +++ b/Model3d.h @@ -124,7 +124,7 @@ private: TSubModel *Next { nullptr }; TSubModel *Child { nullptr }; - geometry_handle m_geometry { 0, 0 }; // geometry of the submodel + gfx::geometry_handle m_geometry { 0, 0 }; // geometry of the submodel material_handle m_material { null_handle }; // numer tekstury, -1 wymienna, 0 brak bool bWire { false }; // nie używane, ale wczytywane float Opacity { 1.0f }; @@ -134,7 +134,7 @@ private: public: // chwilowo float3 v_TransVector { 0.0f, 0.0f, 0.0f }; - vertex_array Vertices; + gfx::vertex_array Vertices; float m_boundingradius { 0 }; size_t iAnimOwner{ 0 }; // roboczy numer egzemplarza, który ustawił animację TAnimType b_aAnim{ at_None }; // kody animacji oddzielnie, bo zerowane @@ -147,7 +147,7 @@ public: std::string m_materialname; // robocza nazwa tekstury do zapisania w pliku binarnym std::string pName; // robocza nazwa private: - int SeekFaceNormal( std::vector const &Masks, int const Startface, unsigned int const Mask, glm::vec3 const &Position, vertex_array const &Vertices ); + int SeekFaceNormal( std::vector const &Masks, int const Startface, unsigned int const Mask, glm::vec3 const &Position, gfx::vertex_array const &Vertices ); void RaAnimation(TAnimType a); public: @@ -174,7 +174,7 @@ public: inline float4x4 * GetMatrix() { return fMatrix; }; inline void Hide() { iVisible = 0; }; - void create_geometry( std::size_t &Dataoffset, geometrybank_handle const &Bank ); + void create_geometry( std::size_t &Dataoffset, gfx::geometrybank_handle const &Bank ); int FlagsCheck(); void WillBeAnimated() { @@ -222,7 +222,7 @@ private: int iFlags; // Ra: czy submodele mają przezroczyste tekstury public: // Ra: tymczasowo int iNumVerts; // ilość wierzchołków (gdy nie ma VBO, to m_nVertexCount=0) - geometrybank_handle m_geometrybank; + gfx::geometrybank_handle m_geometrybank; bool m_geometrycreated { false }; private: std::vector Textures; // nazwy tekstur diff --git a/Segment.cpp b/Segment.cpp index afc6df24..ed478390 100644 --- a/Segment.cpp +++ b/Segment.cpp @@ -359,7 +359,7 @@ Math3D::vector3 TSegment::FastGetPoint(double const t) const interpolate( Point1, Point2, t ) ); } -bool TSegment::RenderLoft( vertex_array &Output, Math3D::vector3 const &Origin, const basic_vertex *ShapePoints, int iNumShapePoints, double fTextureLength, double Texturescale, int iSkip, int iEnd, float fOffsetX, glm::vec3 **p, bool bRender) +bool TSegment::RenderLoft( gfx::vertex_array &Output, Math3D::vector3 const &Origin, const gfx::basic_vertex *ShapePoints, int iNumShapePoints, double fTextureLength, double Texturescale, int iSkip, int iEnd, float fOffsetX, glm::vec3 **p, bool bRender) { // generowanie trójkątów dla odcinka trajektorii ruchu // standardowo tworzy triangle_strip dla prostego albo ich zestaw dla łuku // po modyfikacji - dla ujemnego (iNumShapePoints) w dodatkowych polach tabeli diff --git a/Segment.h b/Segment.h index dfcf09be..319186c9 100644 --- a/Segment.h +++ b/Segment.h @@ -97,7 +97,7 @@ public: r2 = fRoll2; } bool - RenderLoft( vertex_array &Output, Math3D::vector3 const &Origin, basic_vertex const *ShapePoints, int iNumShapePoints, double fTextureLength, double Texturescale = 1.0, int iSkip = 0, int iEnd = 0, float fOffsetX = 0.f, glm::vec3 **p = nullptr, bool bRender = true); + RenderLoft( gfx::vertex_array &Output, Math3D::vector3 const &Origin, gfx::basic_vertex const *ShapePoints, int iNumShapePoints, double fTextureLength, double Texturescale = 1.0, int iSkip = 0, int iEnd = 0, float fOffsetX = 0.f, glm::vec3 **p = nullptr, bool bRender = true); void Render(); inline diff --git a/Track.cpp b/Track.cpp index 0ea4b3c8..a6fbd837 100644 --- a/Track.cpp +++ b/Track.cpp @@ -940,7 +940,7 @@ const int nnumPts = 12; // szyna - vextor6(x,y,mapowanie tekstury,xn,yn,zn) // tę wersję opracował Tolein (bez pochylenia) // TODO: profile definitions in external files -basic_vertex const szyna[ nnumPts ] = { +gfx::basic_vertex const szyna[ nnumPts ] = { {{ 0.111f, -0.180f, 0.f}, { 1.000f, 0.000f, 0.f}, {0.00f, 0.f}}, {{ 0.046f, -0.150f, 0.f}, { 0.707f, 0.707f, 0.f}, {0.15f, 0.f}}, {{ 0.044f, -0.050f, 0.f}, { 0.707f, -0.707f, 0.f}, {0.25f, 0.f}}, @@ -957,7 +957,7 @@ basic_vertex const szyna[ nnumPts ] = { // iglica - vextor3(x,y,mapowanie tekstury) // 1 mm więcej, żeby nie nachodziły tekstury? // TODO: automatic generation from base profile TBD: reuse base profile? -basic_vertex const iglica[ nnumPts ] = { +gfx::basic_vertex const iglica[ nnumPts ] = { {{ 0.010f, -0.180f, 0.f}, { 1.000f, 0.000f, 0.f}, {0.00f, 0.f}}, {{ 0.010f, -0.155f, 0.f}, { 1.000f, 0.000f, 0.f}, {0.15f, 0.f}}, {{ 0.010f, -0.070f, 0.f}, { 1.000f, 0.000f, 0.f}, {0.25f, 0.f}}, @@ -1062,7 +1062,7 @@ void TTrack::RaAssign( TAnimModel *am, TEvent *done, TEvent *joined ) }; // wypełnianie tablic VBO -void TTrack::create_geometry( geometrybank_handle const &Bank ) { +void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) { // Ra: trzeba rozdzielić szyny od podsypki, aby móc grupować wg tekstur auto const fHTW = 0.5f * std::abs(fTrackWidth); auto const side = std::abs(fTexWidth); // szerokść podsypki na zewnątrz szyny albo pobocza @@ -1122,7 +1122,7 @@ void TTrack::create_geometry( geometrybank_handle const &Bank ) { sin2 = std::sin(roll2), cos2 = std::cos(roll2); // zwykla szyna: //Ra: czemu główki są asymetryczne na wysokości 0.140? - basic_vertex rpts1[24], rpts2[24], rpts3[24], rpts4[24]; + gfx::basic_vertex rpts1[24], rpts2[24], rpts3[24], rpts4[24]; for( int i = 0; i < 12; ++i ) { rpts1[ i ] = { @@ -1186,7 +1186,7 @@ void TTrack::create_geometry( geometrybank_handle const &Bank ) { case tt_Normal: if (m_material2) { // podsypka z podkładami jest tylko dla zwykłego toru - basic_vertex bpts1[ 8 ]; // punkty głównej płaszczyzny nie przydają się do robienia boków + gfx::basic_vertex bpts1[ 8 ]; // punkty głównej płaszczyzny nie przydają się do robienia boków if( fTexLength == 4.f ) { // stare mapowanie z różną gęstością pikseli i oddzielnymi teksturami na każdy profil auto const normalx = std::cos( glm::radians( 75.f ) ); @@ -1314,7 +1314,7 @@ void TTrack::create_geometry( geometrybank_handle const &Bank ) { {0.5f + map12, 0.f} }; // prawy skos } } - vertex_array vertices; + gfx::vertex_array vertices; Segment->RenderLoft(vertices, m_origin, bpts1, iTrapezoid ? -4 : 4, fTexLength); if( ( Bank != 0 ) && ( true == Geometry2.empty() ) ) { Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); @@ -1326,7 +1326,7 @@ void TTrack::create_geometry( geometrybank_handle const &Bank ) { } if (m_material1) { // szyny - generujemy dwie, najwyżej rysować się będzie jedną - vertex_array vertices; + gfx::vertex_array vertices; if( ( Bank != 0 ) && ( true == Geometry1.empty() ) ) { Segment->RenderLoft( vertices, m_origin, rpts1, iTrapezoid ? -nnumPts : nnumPts, fTexLength ); Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); @@ -1347,7 +1347,7 @@ void TTrack::create_geometry( geometrybank_handle const &Bank ) { case tt_Switch: // dla zwrotnicy dwa razy szyny if( m_material1 || m_material2 ) { // iglice liczone tylko dla zwrotnic - basic_vertex rpts3[24], rpts4[24]; + gfx::basic_vertex rpts3[24], rpts4[24]; for( int i = 0; i < 12; ++i ) { rpts3[ i ] = { @@ -1378,7 +1378,7 @@ void TTrack::create_geometry( geometrybank_handle const &Bank ) { // TODO, TBD: change all track geometry to triangles, to allow packing data in less, larger buffers if (SwitchExtension->RightSwitch) { // nowa wersja z SPKS, ale odwrotnie lewa/prawa - vertex_array vertices; + gfx::vertex_array vertices; if( m_material1 ) { // fixed parts SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts2, nnumPts, fTexLength ); @@ -1408,7 +1408,7 @@ void TTrack::create_geometry( geometrybank_handle const &Bank ) { } else { // lewa działa lepiej niż prawa - vertex_array vertices; + gfx::vertex_array vertices; if( m_material1 ) { // fixed parts SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts1, nnumPts, fTexLength ); // lewa szyna normalna cała @@ -1446,7 +1446,7 @@ void TTrack::create_geometry( geometrybank_handle const &Bank ) { { case tt_Normal: // drogi proste, bo skrzyżowania osobno { - basic_vertex bpts1[4]; // punkty głównej płaszczyzny przydają się do robienia boków + gfx::basic_vertex bpts1[4]; // punkty głównej płaszczyzny przydają się do robienia boków if (m_material1 || m_material2) { // punkty się przydadzą, nawet jeśli nawierzchni nie ma /* @@ -1489,13 +1489,13 @@ void TTrack::create_geometry( geometrybank_handle const &Bank ) { } if (m_material1) // jeśli podana była tekstura, generujemy trójkąty { // tworzenie trójkątów nawierzchni szosy - vertex_array vertices; + gfx::vertex_array vertices; Segment->RenderLoft(vertices, m_origin, bpts1, iTrapezoid ? -2 : 2, fTexLength); Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); } if (m_material2) { // pobocze drogi - poziome przy przechyłce (a może krawężnik i chodnik zrobić jak w Midtown Madness 2?) - basic_vertex + gfx::basic_vertex rpts1[6], rpts2[6]; // współrzędne przekroju i mapowania dla prawej i lewej strony if (fTexHeight1 >= 0.f) @@ -1649,7 +1649,7 @@ void TTrack::create_geometry( geometrybank_handle const &Bank ) { {0.484375f - map2l, 0.f} }; // lewy brzeg lewego chodnika } } - vertex_array vertices; + gfx::vertex_array vertices; if( iTrapezoid ) // trapez albo przechyłki { // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony // odcinka @@ -1728,7 +1728,7 @@ void TTrack::create_geometry( geometrybank_handle const &Bank ) { SwitchExtension->bPoints ? nullptr : SwitchExtension->vPoints; // zmienna robocza, NULL gdy tablica punktów już jest wypełniona - basic_vertex bpts1[4]; // punkty głównej płaszczyzny przydają się do robienia boków + gfx::basic_vertex bpts1[4]; // punkty głównej płaszczyzny przydają się do robienia boków if (m_material1 || m_material2) // punkty się przydadzą, nawet jeśli nawierzchni nie ma { // double max=2.0*(fHTW>fHTW2?fHTW:fHTW2); //z szerszej strony jest 100% auto const max = fTexRatio1 * fTexLength; // test: szerokość proporcjonalna do długości @@ -1761,7 +1761,7 @@ void TTrack::create_geometry( geometrybank_handle const &Bank ) { // ale pobocza renderują się później, więc nawierzchnia nie załapuje się na renderowanie w swoim czasie if( m_material2 ) { // pobocze drogi - poziome przy przechyłce (a może krawężnik i chodnik zrobić jak w Midtown Madness 2?) - basic_vertex + gfx::basic_vertex rpts1[6], rpts2[6]; // współrzędne przekroju i mapowania dla prawej i lewej strony // Ra 2014-07: trzeba to przerobić na pętlę i pobierać profile (przynajmniej 2..4) z sąsiednich dróg @@ -1900,7 +1900,7 @@ void TTrack::create_geometry( geometrybank_handle const &Bank ) { } } bool render = ( m_material2 != 0 ); // renderować nie trzeba, ale trzeba wyznaczyć punkty brzegowe nawierzchni - vertex_array vertices; + gfx::vertex_array vertices; if (SwitchExtension->iRoads == 4) { // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony odcinka if( ( fTexHeight1 >= 0.0 ) || ( side != 0.0 ) ) { @@ -1956,7 +1956,7 @@ void TTrack::create_geometry( geometrybank_handle const &Bank ) { } if( m_material1 ) { - vertex_array vertices; + gfx::vertex_array vertices; // jeśli podana tekstura nawierzchni // we start with a vertex in the middle... vertices.emplace_back( @@ -2006,7 +2006,7 @@ void TTrack::create_geometry( geometrybank_handle const &Bank ) { { case tt_Normal: // drogi proste, bo skrzyżowania osobno { - basic_vertex bpts1[4]; // punkty głównej płaszczyzny przydają się do robienia boków + gfx::basic_vertex bpts1[4]; // punkty głównej płaszczyzny przydają się do robienia boków if (m_material1 || m_material2) // punkty się przydadzą, nawet jeśli nawierzchni nie ma { // double max=2.0*(fHTW>fHTW2?fHTW:fHTW2); //z szerszej strony jest 100% auto const max = ( @@ -2056,14 +2056,14 @@ void TTrack::create_geometry( geometrybank_handle const &Bank ) { } if (m_material1) // jeśli podana była tekstura, generujemy trójkąty { // tworzenie trójkątów nawierzchni szosy - vertex_array vertices; + gfx::vertex_array vertices; Segment->RenderLoft(vertices, m_origin, bpts1, iTrapezoid ? -2 : 2, fTexLength); Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); } if (m_material2) { // pobocze drogi - poziome przy przechyłce (a może krawężnik i chodnik zrobić jak w Midtown Madness 2?) - vertex_array vertices; - basic_vertex + gfx::vertex_array vertices; + gfx::basic_vertex rpts1[6], rpts2[6]; // współrzędne przekroju i mapowania dla prawej i lewej strony @@ -2425,7 +2425,7 @@ TTrack * TTrack::RaAnimate() auto const fHTW2 = fHTW; // Ra: na razie niech tak będzie auto const cos1 = 1.0f, sin1 = 0.0f, cos2 = 1.0f, sin2 = 0.0f; // Ra: ... - basic_vertex + gfx::basic_vertex rpts3[ 24 ], rpts4[ 24 ]; for (int i = 0; i < 12; ++i) { @@ -2456,7 +2456,7 @@ TTrack * TTrack::RaAnimate() {szyna[ i ].texture.x, 0.f} }; } - vertex_array vertices; + gfx::vertex_array vertices; if (SwitchExtension->RightSwitch) { // nowa wersja z SPKS, ale odwrotnie lewa/prawa @@ -2520,7 +2520,7 @@ TTrack * TTrack::RaAnimate() dynamic->Move( 0.000001 ); } // NOTE: passing empty handle is a bit of a hack here. could be refactored into something more elegant - create_geometry( geometrybank_handle() ); + create_geometry( {} ); } // animacja trwa nadal } else diff --git a/Track.h b/Track.h index 2979525d..3af0fbcd 100644 --- a/Track.h +++ b/Track.h @@ -147,7 +147,7 @@ private: glm::dvec3 m_origin; material_handle m_material1 = 0; // tekstura szyn albo nawierzchni material_handle m_material2 = 0; // tekstura automatycznej podsypki albo pobocza - typedef std::vector geometryhandle_sequence; + typedef std::vector geometryhandle_sequence; geometryhandle_sequence Geometry1; // geometry chunks textured with texture 1 geometryhandle_sequence Geometry2; // geometry chunks textured with texture 2 @@ -245,7 +245,7 @@ public: std::vector endpoints() const; - void create_geometry( geometrybank_handle const &Bank ); // wypełnianie VBO + void create_geometry( gfx::geometrybank_handle const &Bank ); // wypełnianie VBO void RenderDynSounds(); // odtwarzanie dźwięków pojazdów jest niezależne od ich wyświetlania void RaOwnerSet( scene::basic_cell *o ) { diff --git a/Traction.cpp b/Traction.cpp index 348e9e22..6ff114b3 100644 --- a/Traction.cpp +++ b/Traction.cpp @@ -175,18 +175,18 @@ TTraction::endpoints() const { } std::size_t -TTraction::create_geometry( geometrybank_handle const &Bank ) { +TTraction::create_geometry( gfx::geometrybank_handle const &Bank ) { if( m_geometry != null_handle ) { return GfxRenderer.Vertices( m_geometry ).size() / 2; } - vertex_array vertices; + gfx::vertex_array vertices; double ddp = std::hypot( pPoint2.x - pPoint1.x, pPoint2.z - pPoint1.z ); if( Wires == 2 ) WireOffset = 0; // jezdny - basic_vertex startvertex, endvertex; + gfx::basic_vertex startvertex, endvertex; startvertex.position = glm::vec3( pPoint1.x - ( pPoint2.z / ddp - pPoint1.z / ddp ) * WireOffset - m_origin.x, diff --git a/Traction.h b/Traction.h index 3f75d60e..c8ccb432 100644 --- a/Traction.h +++ b/Traction.h @@ -50,7 +50,7 @@ class TTraction : public editor::basic_node { int PowerState { 0 }; // type of incoming power, if any // visualization data glm::dvec3 m_origin; - geometry_handle m_geometry; + gfx::geometry_handle m_geometry; explicit TTraction( scene::node_data const &Nodedata ); @@ -64,7 +64,7 @@ class TTraction : public editor::basic_node { endpoints() const; // creates geometry data in specified geometry bank. returns: number of created elements, or NULL // NOTE: deleting nodes doesn't currently release geometry data owned by the node. TODO: implement erasing individual geometry chunks and banks - std::size_t create_geometry( geometrybank_handle const &Bank ); + std::size_t create_geometry( gfx::geometrybank_handle const &Bank ); int TestPoint(glm::dvec3 const &Point); void Connect(int my, TTraction *with, int to); void Init(); diff --git a/Train.cpp b/Train.cpp index ee354945..02d9c241 100644 --- a/Train.cpp +++ b/Train.cpp @@ -312,28 +312,6 @@ TTrain::TTrain() { //----- pMechSittingPosition = vector3(0, 0, 0); // ABu: 180404 InstrumentLightActive = false; // ABu: 030405 - dsbNastawnikJazdy = NULL; - dsbNastawnikBocz = NULL; - dsbRelay = NULL; - dsbPneumaticRelay = NULL; - dsbSwitch = NULL; - dsbPneumaticSwitch = NULL; - dsbReverserKey = NULL; // hunter-121211 - dsbCouplerAttach = NULL; - dsbCouplerDetach = NULL; - dsbDieselIgnition = NULL; - dsbDoorClose = NULL; - dsbDoorOpen = NULL; - dsbPantUp = NULL; - dsbPantDown = NULL; - dsbWejscie_na_bezoporow = NULL; - dsbWejscie_na_drugi_uklad = NULL; // hunter-081211: poprawka literowki - dsbHasler = NULL; - dsbBuzzer = NULL; - dsbSlipAlarm = NULL; // Bombardier 011010: alarm przy poslizgu dla 181/182 - dsbCouplerStretch = NULL; - dsbEN57_CouplerStretch = NULL; - dsbBufferClamp = NULL; iRadioChannel = 0; fTachoTimer = 0.0; // włączenie skoków wskazań prędkościomierza @@ -749,7 +727,7 @@ void TTrain::OnCommand_trainbrakeincrease( TTrain *Train, command_data const &Co Train->keybrakecount = 0; if( ( Train->is_eztoer() ) && ( Train->mvOccupied->BrakeCtrlPos < 3 ) ) { // Ra: uzależnić dźwięk od zmiany stanu EP, nie od klawisza - Train->play_sound( Train->dsbPneumaticSwitch ); + Train->dsbPneumaticSwitch.play(); } } } @@ -772,7 +750,7 @@ void TTrain::OnCommand_trainbrakedecrease( TTrain *Train, command_data const &Co && ( Train->mvControlled->Mains ) && ( Train->mvOccupied->BrakeCtrlPos != -1 ) ) { // Ra: uzależnić dźwięk od zmiany stanu EP, nie od klawisza - Train->play_sound( Train->dsbPneumaticSwitch ); + Train->dsbPneumaticSwitch.play(); } Train->mvOccupied->BrakeLevelAdd( -Global::fBrakeStep ); } @@ -794,7 +772,7 @@ void TTrain::OnCommand_trainbrakedecrease( TTrain *Train, command_data const &Co if( ( Train->mvOccupied->TrainType == dt_EZT ) && ( Train->mvControlled->Mains ) && ( Train->mvControlled->ActiveDir != 0 ) ) { - Train->play_sound( Train->dsbPneumaticSwitch ); + Train->dsbPneumaticSwitch.play(); } } } @@ -808,7 +786,7 @@ void TTrain::OnCommand_trainbrakecharging( TTrain *Train, command_data const &Co if( ( Train->is_eztoer() ) && ( Train->mvControlled->Mains ) && ( Train->mvOccupied->BrakeCtrlPos != -1 ) ) { - Train->play_sound( Train->dsbPneumaticSwitch ); + Train->dsbPneumaticSwitch.play(); } Train->mvOccupied->BrakeLevelSet( -1 ); @@ -826,7 +804,7 @@ void TTrain::OnCommand_trainbrakecharging( TTrain *Train, command_data const &Co if( ( Train->mvOccupied->TrainType == dt_EZT ) && ( Train->mvControlled->Mains ) && ( Train->mvControlled->ActiveDir != 0 ) ) { - Train->play_sound( Train->dsbPneumaticSwitch ); + Train->dsbPneumaticSwitch.play(); } } } @@ -840,7 +818,7 @@ void TTrain::OnCommand_trainbrakerelease( TTrain *Train, command_data const &Com if( ( Train->is_eztoer() ) && ( ( Train->mvOccupied->BrakeCtrlPos == 1 ) || ( Train->mvOccupied->BrakeCtrlPos == -1 ) ) ) { - Train->play_sound( Train->dsbPneumaticSwitch ); + Train->dsbPneumaticSwitch.play(); } Train->mvOccupied->BrakeLevelSet( 0 ); @@ -855,7 +833,7 @@ void TTrain::OnCommand_trainbrakefirstservice( TTrain *Train, command_data const if( ( Train->is_eztoer() ) && ( Train->mvControlled->Mains ) && ( Train->mvOccupied->BrakeCtrlPos != 1 ) ) { - Train->play_sound( Train->dsbPneumaticSwitch ); + Train->dsbPneumaticSwitch.play(); } Train->mvOccupied->BrakeLevelSet( 1 ); @@ -871,7 +849,7 @@ void TTrain::OnCommand_trainbrakeservice( TTrain *Train, command_data const &Com && ( Train->mvControlled->Mains ) && ( ( Train->mvOccupied->BrakeCtrlPos == 1 ) || ( Train->mvOccupied->BrakeCtrlPos == -1 ) ) ) { - Train->play_sound( Train->dsbPneumaticSwitch ); + Train->dsbPneumaticSwitch.play(); } Train->mvOccupied->BrakeLevelSet( @@ -891,7 +869,7 @@ void TTrain::OnCommand_trainbrakefullservice( TTrain *Train, command_data const && ( Train->mvControlled->Mains ) && ( ( Train->mvOccupied->BrakeCtrlPos == 1 ) || ( Train->mvOccupied->BrakeCtrlPos == -1 ) ) ) { - Train->play_sound( Train->dsbPneumaticSwitch ); + Train->dsbPneumaticSwitch.play(); } Train->mvOccupied->BrakeLevelSet( Train->mvOccupied->BrakeCtrlPosNo - 1 ); } @@ -1024,7 +1002,7 @@ void TTrain::OnCommand_epbrakecontroltoggle( TTrain *Train, command_data const & // turn on if( Train->mvOccupied->EpFuseSwitch( true ) ) { // audio feedback - Train->play_sound( Train->dsbPneumaticSwitch ); + Train->dsbPneumaticSwitch.play(); // visual feedback // NOTE: there's no button for ep brake control switch // TBD, TODO: add ep brake control switch? @@ -1034,7 +1012,7 @@ void TTrain::OnCommand_epbrakecontroltoggle( TTrain *Train, command_data const & //turn off if( Train->mvOccupied->EpFuseSwitch( false ) ) { // audio feedback - Train->play_sound( Train->dsbPneumaticSwitch ); + Train->dsbPneumaticSwitch.play(); // visual feedback // NOTE: there's no button for ep brake control switch // TBD, TODO: add ep brake control switch? @@ -1563,7 +1541,7 @@ void TTrain::OnCommand_linebreakertoggle( TTrain *Train, command_data const &Com if( Train->mvControlled->EngineType == DieselEngine ) { if( Train->mvControlled->MainSwitch( true ) ) { // sound feedback, engine start for diesel vehicle - Train->play_sound( Train->dsbDieselIgnition ); + Train->dsbDieselIgnition.play(); // side-effects Train->mvControlled->ConverterSwitch( ( Train->ggConverterButton.GetValue() > 0.5 ) || ( Train->mvControlled->ConverterStart == start::automatic ) ); Train->mvControlled->CompressorSwitch( Train->ggCompressorButton.GetValue() > 0.5 ); @@ -1606,7 +1584,7 @@ void TTrain::OnCommand_linebreakertoggle( TTrain *Train, command_data const &Com } // play sound immediately when the switch is hit, not after release if( Train->fMainRelayTimer > 0.0f ) { - Train->play_sound( Train->dsbRelay ); + Train->dsbRelay.play(); Train->fMainRelayTimer = 0.0f; } } @@ -1617,7 +1595,7 @@ void TTrain::OnCommand_linebreakertoggle( TTrain *Train, command_data const &Com // ...after opening circuit, or holding for too short time to close it // hunter-091012: przeniesione z mover.pas, zeby dzwiek sie nie zapetlal, if( Train->fMainRelayTimer > 0.0f ) { - Train->play_sound( Train->dsbRelay ); + Train->dsbRelay.play(); Train->fMainRelayTimer = 0.0f; } // we don't exactly know which of the two buttons was used, so reset both @@ -1942,7 +1920,7 @@ void TTrain::OnCommand_motorconnectorsopen( TTrain *Train, command_data const &C Train->ggStLinOffButton.UpdateValue( 1.0, Train->dsbSwitch ); // effect if( true == Train->mvControlled->StLinFlag ) { - Train->play_sound( Train->dsbRelay ); + Train->dsbRelay.play(); } // yBARC - zmienione na przeciwne, bo true to zalaczone Train->mvControlled->StLinFlag = false; @@ -2503,14 +2481,14 @@ void TTrain::OnCommand_interiorlighttoggle( TTrain *Train, command_data const &C if( false == Train->bCabLight ) { // turn on Train->bCabLight = true; - Train->btCabLight.TurnOn(); + Train->btCabLight.Turn( true ); // visual feedback Train->ggCabLightButton.UpdateValue( 1.0, Train->dsbSwitch ); } else { //turn off Train->bCabLight = false; - Train->btCabLight.TurnOff(); + Train->btCabLight.Turn( false ); // visual feedback Train->ggCabLightButton.UpdateValue( 0.0, Train->dsbSwitch ); } @@ -2671,14 +2649,12 @@ void TTrain::OnCommand_doortoggleleft( TTrain *Train, command_data const &Comman if( Train->mvOccupied->ActiveCab == 1 ) { if( Train->mvOccupied->DoorLeft( true ) ) { Train->ggDoorLeftButton.UpdateValue( 1.0, Train->dsbSwitch ); - Train->play_sound( Train->dsbDoorOpen ); } } else { // in the rear cab sides are reversed if( Train->mvOccupied->DoorRight( true ) ) { Train->ggDoorRightButton.UpdateValue( 1.0, Train->dsbSwitch ); - Train->play_sound( Train->dsbDoorOpen ); } } } @@ -2687,14 +2663,12 @@ void TTrain::OnCommand_doortoggleleft( TTrain *Train, command_data const &Comman if( Train->mvOccupied->ActiveCab == 1 ) { if( Train->mvOccupied->DoorLeft( false ) ) { Train->ggDoorLeftButton.UpdateValue( 0.0, Train->dsbSwitch ); - Train->play_sound( Train->dsbDoorClose ); } } else { // in the rear cab sides are reversed if( Train->mvOccupied->DoorRight( false ) ) { Train->ggDoorRightButton.UpdateValue( 0.0, Train->dsbSwitch ); - Train->play_sound( Train->dsbDoorClose ); } } } @@ -2716,14 +2690,12 @@ void TTrain::OnCommand_doortoggleright( TTrain *Train, command_data const &Comma if( Train->mvOccupied->ActiveCab == 1 ) { if( Train->mvOccupied->DoorRight( true ) ) { Train->ggDoorRightButton.UpdateValue( 1.0, Train->dsbSwitch ); - Train->play_sound( Train->dsbDoorOpen ); } } else { // in the rear cab sides are reversed if( Train->mvOccupied->DoorLeft( true ) ) { Train->ggDoorLeftButton.UpdateValue( 1.0, Train->dsbSwitch ); - Train->play_sound( Train->dsbDoorOpen ); } } } @@ -2732,14 +2704,12 @@ void TTrain::OnCommand_doortoggleright( TTrain *Train, command_data const &Comma if( Train->mvOccupied->ActiveCab == 1 ) { if( Train->mvOccupied->DoorRight( false ) ) { Train->ggDoorRightButton.UpdateValue( 0.0, Train->dsbSwitch ); - Train->play_sound( Train->dsbDoorClose ); } } else { // in the rear cab sides are reversed if( Train->mvOccupied->DoorLeft( false ) ) { Train->ggDoorLeftButton.UpdateValue( 0.0, Train->dsbSwitch ); - Train->play_sound( Train->dsbDoorClose ); } } } @@ -2934,13 +2904,13 @@ void TTrain::OnKeyDown(int cKey) if (Global::ctrlState) if (temp->MoverParameters->BrakeDelaySwitch(bdelay_R + bdelay_M)) { - play_sound( dsbPneumaticRelay ); + dsbPneumaticRelay.play(); } else ; else if (temp->MoverParameters->BrakeDelaySwitch(bdelay_P)) { - play_sound( dsbPneumaticRelay ); + dsbPneumaticRelay.play(); } } } @@ -3062,13 +3032,13 @@ void TTrain::OnKeyDown(int cKey) if (Global::ctrlState) if (temp->MoverParameters->BrakeDelaySwitch(bdelay_R)) { - play_sound( dsbPneumaticRelay ); + dsbPneumaticRelay.play(); } else ; else if (temp->MoverParameters->BrakeDelaySwitch(bdelay_G)) { - play_sound( dsbPneumaticRelay ); + dsbPneumaticRelay.play(); } } } @@ -3171,7 +3141,7 @@ if // //podłączony sprzęg będzie widoczny if (DynamicObject->Mechanik) // na wszelki wypadek DynamicObject->Mechanik->CheckVehicles(Connect); // aktualizacja flag kierunku w składzie - play_sound( dsbCouplerAttach ); + dsbCouplerAttach.play(); // one coupling type per key press return; } @@ -3189,7 +3159,7 @@ if (tmp->MoverParameters->Couplers[CouplNr].CouplingFlag | ctrain_pneumatic))) { // TODO: dedicated 'click' sound for connecting cable-type connections - play_sound( dsbCouplerDetach ); + dsbCouplerDetach.play(); // rsHiss.Play( 1, DSBPLAY_LOOPING, true, tmp->GetPosition() ); DynamicObject->SetPneumatic(CouplNr != 0, true); // Ra: to mi się nie podoba !!!! tmp->SetPneumatic(CouplNr != 0, true); @@ -3208,7 +3178,7 @@ if (tmp->MoverParameters->Couplers[CouplNr].CouplingFlag | ctrain_scndpneumatic))) { // TODO: dedicated 'click' sound for connecting cable-type connections - play_sound( dsbCouplerDetach ); + dsbCouplerDetach.play(); // rsHiss.Play( 1, DSBPLAY_LOOPING, true, tmp->GetPosition() ); DynamicObject->SetPneumatic( CouplNr != 0, false ); // Ra: to mi się nie podoba !!!! tmp->SetPneumatic(CouplNr != 0, false); @@ -3227,7 +3197,7 @@ if (tmp->MoverParameters->Couplers[CouplNr].CouplingFlag | ctrain_controll))) { // TODO: dedicated 'click' sound for connecting cable-type connections - play_sound( dsbCouplerAttach ); + dsbCouplerAttach.play(); // one coupling type per key press return; } @@ -3242,7 +3212,7 @@ if tmp->MoverParameters->Couplers[CouplNr].Connected, (tmp->MoverParameters->Couplers[CouplNr].CouplingFlag | ctrain_passenger))) { - play_sound( dsbCouplerAttach ); + dsbCouplerAttach.play(); /* DynamicObject->SetPneumatic(CouplNr != 0, false); tmp->SetPneumatic(CouplNr != 0, false); @@ -3262,7 +3232,7 @@ if ( tmp->MoverParameters->Couplers[ CouplNr ].CouplingFlag | ctrain_heating ) ) ) { // TODO: dedicated 'click' sound for connecting cable-type connections - play_sound( dsbCouplerAttach ); + dsbCouplerAttach.play(); // one coupling type per key press return; } @@ -3282,7 +3252,7 @@ if if (DynamicObject->DettachStatus(iCabn - 1) < 0) // jeśli jest co odczepić if (DynamicObject->Dettach(iCabn - 1)) // iCab==1:przód,iCab==2:tył { - play_sound( dsbCouplerDetach ); // w kabinie ten dźwięk? + dsbCouplerDetach.play(); // w kabinie ten dźwięk? } } else @@ -3298,7 +3268,7 @@ if if (tmp->DettachStatus(CouplNr) < 0) // jeśli jest co odczepić i się da if (!tmp->Dettach(CouplNr)) { // dźwięk odczepiania - play_sound( dsbCouplerDetach ); + dsbCouplerDetach.play(); } } } @@ -3572,29 +3542,6 @@ bool TTrain::Update( double const Deltatime ) fTachoCount -= dt * 0.66; // schodz powoli - niektore haslery to ze 4 // sekundy potrafia stukac - /* Ra: to by trzeba było przemyśleć, zmienione na szybko problemy robi - //McZapkie: predkosc wyswietlana na tachometrze brana jest z obrotow kol - double vel=fabs(11.31*mvControlled->WheelDiameter*mvControlled->nrot); - if (iSekunda!=floor(GlobalTime->mr)||(vel<1.0)) - {fTachoVelocity=vel; - if (fTachoVelocity>1.0) //McZapkie-270503: podkrecanie tachometru - { - if (fTachoCount0) - fTachoCount-=dt; - if (mvControlled->TrainType==dt_EZT) - //dla EZT wskazówka porusza się niestabilnie - if (fTachoVelocity>7.0) - {fTachoVelocity=floor(0.5+fTachoVelocity+random(5)-random(5)); - //*floor(0.2*fTachoVelocity); - if (fTachoVelocity<0.0) fTachoVelocity=0.0; - } - iSekunda=floor(GlobalTime->mr); - } - */ // Ra 2014-09: napięcia i prądy muszą być ustalone najpierw, bo wysyłane są ewentualnie na PoKeys if ((mvControlled->EngineType != DieselElectric) && (mvControlled->EngineType != ElectricInductionMotor)) // Ra 2014-09: czy taki rozdzia? ma sens? @@ -3823,344 +3770,6 @@ bool TTrain::Update( double const Deltatime ) fConverterTimer = 0; //------------------ - double vol = 0; - // int freq=1; - double dfreq; - - // McZapkie-280302 - syczenie - if ((mvOccupied->BrakeHandle == FV4a) || (mvOccupied->BrakeHandle == FVel6)) - { - if (rsHiss.AM != 0) // upuszczanie z PG - { - fPPress = (1 * fPPress + mvOccupied->Handle->GetSound(s_fv4a_b)) / (2); - if (fPPress > 0) - { - vol = 2.0 * rsHiss.AM * fPPress; - } - if (vol > 0.001) - { - rsHiss.Play(vol, DSBPLAY_LOOPING, true, DynamicObject->GetPosition()); - } - else - { - rsHiss.Stop(); - } - } - if (rsHissU.AM != 0) // upuszczanie z PG - { - fNPress = (1 * fNPress + mvOccupied->Handle->GetSound(s_fv4a_u)) / (2); - if (fNPress > 0) - { - vol = rsHissU.AM * fNPress; - } - if (vol > 0.001) - { - rsHissU.Play(vol, DSBPLAY_LOOPING, true, DynamicObject->GetPosition()); - } - else - { - rsHissU.Stop(); - } - } - if (rsHissE.AM != 0) // upuszczanie przy naglym - { - vol = mvOccupied->Handle->GetSound(s_fv4a_e) * rsHissE.AM; - if (vol > 0.001) - { - rsHissE.Play(vol, DSBPLAY_LOOPING, true, DynamicObject->GetPosition()); - } - else - { - rsHissE.Stop(); - } - } - if (rsHissX.AM != 0) // upuszczanie sterujacego fala - { - vol = mvOccupied->Handle->GetSound(s_fv4a_x) * rsHissX.AM; - if (vol > 0.001) - { - rsHissX.Play(vol, DSBPLAY_LOOPING, true, DynamicObject->GetPosition()); - } - else - { - rsHissX.Stop(); - } - } - if (rsHissT.AM != 0) // upuszczanie z czasowego - { - vol = mvOccupied->Handle->GetSound(s_fv4a_t) * rsHissT.AM; - if (vol > 0.001) - { - rsHissT.Play(vol, DSBPLAY_LOOPING, true, DynamicObject->GetPosition()); - } - else - { - rsHissT.Stop(); - } - } - - } // koniec FV4a - else // jesli nie FV4a - { - if (rsHiss.AM != 0.0) // upuszczanie z PG - { - fPPress = (4.0f * fPPress + std::max(mvOccupied->dpLocalValve, mvOccupied->dpMainValve)) / (4.0f + 1.0f); - if (fPPress > 0.0f) - { - vol = 2.0 * rsHiss.AM * fPPress; - } - if (vol > 0.01) - { - rsHiss.Play(vol, DSBPLAY_LOOPING, true, DynamicObject->GetPosition()); - } - else - { - rsHiss.Stop(); - } - } - if (rsHissU.AM != 0.0) // napelnianie PG - { - fNPress = (4.0f * fNPress + Min0R(mvOccupied->dpLocalValve, mvOccupied->dpMainValve)) / (4.0f + 1.0f); - if (fNPress < 0.0f) - { - vol = -1.0 * rsHissU.AM * fNPress; - } - if (vol > 0.01) - { - rsHissU.Play(vol, DSBPLAY_LOOPING, true, DynamicObject->GetPosition()); - } - else - { - rsHissU.Stop(); - } - } - } // koniec nie FV4a - - // Winger-160404 - syczenie pomocniczego (luzowanie) - /* if (rsSBHiss.AM!=0) - { - fSPPress=(mvOccupied->LocalBrakeRatio())-(mvOccupied->LocalBrakePos); - if (fSPPress>0) - { - vol=2*rsSBHiss.AM*fSPPress; - } - if (vol>0.1) - { - rsSBHiss.Play(vol,DSBPLAY_LOOPING,true,DynamicObject->GetPosition()); - } - else - { - rsSBHiss.Stop(); - } - } - */ - // szum w czasie jazdy - vol = 0.0; - dfreq = 1.0; - if (rsRunningNoise.AM != 0) - { - if (DynamicObject->GetVelocity() != 0) - { - if (!TestFlag(mvOccupied->DamageFlag, - dtrain_wheelwear)) // McZpakie-221103: halas zalezny od kola - { - dfreq = rsRunningNoise.FM * mvOccupied->Vel + rsRunningNoise.FA; - vol = rsRunningNoise.AM * mvOccupied->Vel + rsRunningNoise.AA; - switch (tor->eEnvironment) - { - case e_tunnel: - { - vol *= 3; - dfreq *= 0.95; - } - break; - case e_canyon: - { - vol *= 1.1; - } - break; - case e_bridge: - { - vol *= 2; - dfreq *= 0.98; - } - break; - } - } - else // uszkodzone kolo (podkucie) - if (fabs(mvOccupied->nrot) > 0.01) - { - dfreq = rsRunningNoise.FM * mvOccupied->Vel + rsRunningNoise.FA; - vol = rsRunningNoise.AM * mvOccupied->Vel + rsRunningNoise.AA; - switch (tor->eEnvironment) - { - case e_tunnel: - { - vol *= 2; - } - break; - case e_canyon: - { - vol *= 1.1; - } - break; - case e_bridge: - { - vol *= 1.5; - } - break; - } - } - if (fabs(mvOccupied->nrot) > 0.01) - vol *= 1 + - mvOccupied->UnitBrakeForce / - (1 + mvOccupied->MaxBrakeForce); // hamulce wzmagaja halas - vol = vol * (20.0 + tor->iDamageFlag) / 21; - rsRunningNoise.AdjFreq(dfreq, 0); - rsRunningNoise.Play(vol, DSBPLAY_LOOPING, true, DynamicObject->GetPosition()); - } - else - rsRunningNoise.Stop(); - } - - if (rsBrake.AM != 0) - { - if ((!mvOccupied->SlippingWheels) && (mvOccupied->UnitBrakeForce > 10.0) && - (DynamicObject->GetVelocity() > 0.01)) - { - // vol=rsBrake.AA+rsBrake.AM*(DynamicObject->GetVelocity()*100+mvOccupied->UnitBrakeForce); - vol = - rsBrake.AM * sqrt((DynamicObject->GetVelocity() * mvOccupied->UnitBrakeForce)); - dfreq = rsBrake.FA + rsBrake.FM * DynamicObject->GetVelocity(); - rsBrake.AdjFreq(dfreq, 0); - rsBrake.Play(vol, DSBPLAY_LOOPING, true, DynamicObject->GetPosition()); - } - else - { - rsBrake.Stop(); - } - } - - if (rsEngageSlippery.AM != 0) - { - if /*((fabs(mvControlled->dizel_engagedeltaomega)>0.2) && */ ( - mvControlled->dizel_engage > 0.1) - { - if (fabs(mvControlled->dizel_engagedeltaomega) > 0.2) - { - dfreq = rsEngageSlippery.FA + - rsEngageSlippery.FM * fabs(mvControlled->dizel_engagedeltaomega); - vol = rsEngageSlippery.AA + rsEngageSlippery.AM * (mvControlled->dizel_engage); - } - else - { - dfreq = - 1; // rsEngageSlippery.FA+0.7*rsEngageSlippery.FM*(fabs(mvControlled->enrot)+mvControlled->nmax); - if (mvControlled->dizel_engage > 0.2) - vol = - rsEngageSlippery.AA + - 0.2 * rsEngageSlippery.AM * (mvControlled->enrot / mvControlled->nmax); - else - vol = 0; - } - rsEngageSlippery.AdjFreq(dfreq, 0); - rsEngageSlippery.Play(vol, DSBPLAY_LOOPING, true, DynamicObject->GetPosition()); - } - else - { - rsEngageSlippery.Stop(); - } - } - - if (FreeFlyModeFlag) - rsFadeSound.Stop(); // wyłącz to cholerne cykanie! - else - rsFadeSound.Play(1, DSBPLAY_LOOPING, true, DynamicObject->GetPosition()); - - // McZapkie! - to wazne - SoundFlag wystawiane jest przez moje moduly - // gdy zachodza pewne wydarzenia komentowane dzwiekiem. - // Mysle ze wystarczy sprawdzac a potem zerowac SoundFlag tutaj - // a nie w DynObject - gdyby cos poszlo zle to po co szarpac dzwiekiem co - // 10ms. - - if (TestFlag(mvOccupied->SoundFlag, sound_relay)) // przekaznik - gdy - // bezpiecznik, - // automatyczny rozruch - // itp - { - if (mvOccupied->EventFlag || TestFlag(mvOccupied->SoundFlag, sound_loud)) - { - mvOccupied->EventFlag = false; // Ra: w kabinie? - if( dsbRelay != nullptr ) { dsbRelay->SetVolume( DSBVOLUME_MAX ); } - } - else - { - if( dsbRelay != nullptr ) { dsbRelay->SetVolume( -40 ); } - } - if (!TestFlag(mvOccupied->SoundFlag, sound_manyrelay)) - play_sound( dsbRelay ); - else - { - if (TestFlag(mvOccupied->SoundFlag, sound_loud)) - play_sound( dsbWejscie_na_bezoporow ); - else - play_sound( dsbWejscie_na_drugi_uklad ); - } - } - - if( dsbBufferClamp != nullptr ) { - if( TestFlag( mvOccupied->SoundFlag, sound_bufferclamp ) ) // zderzaki uderzaja o siebie - { - if( TestFlag( mvOccupied->SoundFlag, sound_loud ) ) - dsbBufferClamp->SetVolume( DSBVOLUME_MAX ); - else - dsbBufferClamp->SetVolume( -20 ); - play_sound( dsbBufferClamp ); - } - } - if (dsbCouplerStretch) - if (TestFlag(mvOccupied->SoundFlag, sound_couplerstretch)) // sprzegi sie rozciagaja - { - if (TestFlag(mvOccupied->SoundFlag, sound_loud)) - dsbCouplerStretch->SetVolume(DSBVOLUME_MAX); - else - dsbCouplerStretch->SetVolume(-20); - play_sound( dsbCouplerStretch ); - } - - if (mvOccupied->SoundFlag == 0) - if (mvOccupied->EventFlag) - if (TestFlag(mvOccupied->DamageFlag, dtrain_wheelwear)) - { // Ra: przenieść do DynObj! - if (rsRunningNoise.AM != 0) - { - rsRunningNoise.Stop(); - // float aa=rsRunningNoise.AA; - float am = rsRunningNoise.AM; - float fa = rsRunningNoise.FA; - float fm = rsRunningNoise.FM; - rsRunningNoise.Init("lomotpodkucia.wav", -1, 0, 0, 0, - true); // MC: zmiana szumu na lomot - if (rsRunningNoise.AM == 1) - rsRunningNoise.AM = am; - rsRunningNoise.AA = 0.7; - rsRunningNoise.FA = fa; - rsRunningNoise.FM = fm; - } - mvOccupied->EventFlag = false; - } - - mvOccupied->SoundFlag = 0; - /* - for (int b=0; b<2; b++) //MC: aby zerowac stukanie przekaznikow w - czlonie silnikowym - if (TestFlag(mvControlled->Couplers[b].CouplingFlag,ctrain_controll)) - if (mvControlled->Couplers[b].Connected.Power>0.01) - mvControlled->Couplers[b]->Connected->SoundFlag=0; - */ - - // McZapkie! - koniec obslugi dzwiekow z mover.pas - // youBy - prad w drugim czlonie: galaz lub calosc { TDynamicObject *tmp; @@ -4198,42 +3807,6 @@ bool TTrain::Update( double const Deltatime ) } } } - /* - //McZapkie-240302 ggVelocity.UpdateValue(DynamicObject->GetVelocity()); - //fHaslerTimer+=dt; - //if (fHaslerTimer>fHaslerTime) - {//Ra: ryzykowne jest to, gdyż może się nie uaktualniać prędkość - //Ra: prędkość się powinna zaokrąglać tam gdzie się liczy - fTachoVelocity - if (ggVelocity.SubModel) - {//ZiomalCl: wskazanie Haslera w kabinie A ze zwloka czasowa oraz odpowiednia - tolerancja - //Nalezy sie zastanowic na przyszlosc nad rozroznieniem predkosciomierzy - (dokladnosc wskazan, zwloka czasowa wskazania, inne funkcje) - //ZiomalCl: W ezt typu stare EN57 wskazania haslera sa mniej dokladne - (linka) - //ggVelocity.UpdateValue(fTachoVelocity>2?fTachoVelocity+0.5-random(mvControlled->TrainType==dt_EZT?5:2)/2:0); - ggVelocity.UpdateValue(Min0R(fTachoVelocity,mvControlled->Vmax*1.05)); - //ograniczenie maksymalnego wskazania na analogowym - ggVelocity.Update(); - } - if (ggVelocityDgt.SubModel) - {//Ra 2014-07: prędkościomierz cyfrowy - ggVelocityDgt.UpdateValue(fTachoVelocity); - ggVelocityDgt.Update(); - } - if (ggVelocity_B.SubModel) - {//ZiomalCl: wskazanie Haslera w kabinie B ze zwloka czasowa oraz odpowiednia - tolerancja - //Nalezy sie zastanowic na przyszlosc nad rozroznieniem predkosciomierzy - (dokladnosc wskazan, zwloka czasowa wskazania, inne funkcje) - //Velocity_B.UpdateValue(fTachoVelocity>2?fTachoVelocity+0.5-random(mvControlled->TrainType==dt_EZT?5:2)/2:0); - ggVelocity_B.UpdateValue(fTachoVelocity); - ggVelocity_B.Update(); - } - //fHaslerTimer-=fHaslerTime; //1.2s (???) - } - */ // McZapkie-300302: zegarek if (ggClockMInd.SubModel) { @@ -4326,39 +3899,18 @@ bool TTrain::Update( double const Deltatime ) } } - if (mvControlled->SlippingWheels) - { // Ra 2014-12: lokomotywy 181/182 - // dostają SlippingWheels po zahamowaniu - // powyżej 2.85 bara i buczały + if (mvControlled->SlippingWheels) { + // Ra 2014-12: lokomotywy 181/182 dostają SlippingWheels po zahamowaniu powyżej 2.85 bara i buczały double veldiff = (DynamicObject->GetVelocity() - fTachoVelocity) / mvControlled->Vmax; - if (veldiff < -0.01) // 1% Vmax rezerwy, żeby 181/182 nie buczały po - // zahamowaniu, ale to proteza - { - if (fabs(mvControlled->Im) > 10.0) - btLampkaPoslizg.TurnOn(); - rsSlippery.Play(-rsSlippery.AM * veldiff + rsSlippery.AA, DSBPLAY_LOOPING, true, DynamicObject->GetPosition()); - if (mvControlled->TrainType == dt_181) // alarm przy poslizgu dla 181/182 - BOMBARDIER - if (dsbSlipAlarm) - play_sound( dsbSlipAlarm, DSBPLAY_LOOPING ); - } - else - { - if ((mvOccupied->UnitBrakeForce > 100.0) && (DynamicObject->GetVelocity() > 1.0)) - { - rsSlippery.Play(rsSlippery.AM * veldiff + rsSlippery.AA, DSBPLAY_LOOPING, true, DynamicObject->GetPosition()); - if (mvControlled->TrainType == dt_181) - if (dsbSlipAlarm) - dsbSlipAlarm->Stop(); + if( veldiff < -0.01 ) { + // 1% Vmax rezerwy, żeby 181/182 nie buczały po zahamowaniu, ale to proteza + if( std::abs( mvControlled->Im ) > 10.0 ) { + btLampkaPoslizg.Turn( true ); } } } - else - { - btLampkaPoslizg.TurnOff(); - rsSlippery.Stop(); - if (mvControlled->TrainType == dt_181) - if (dsbSlipAlarm) - dsbSlipAlarm->Stop(); + else { + btLampkaPoslizg.Turn( false ); } if ((mvControlled->Mains) || (mvControlled->TrainType == dt_EZT)) @@ -4367,7 +3919,7 @@ bool TTrain::Update( double const Deltatime ) } else { - btLampkaNadmSil.TurnOff(); + btLampkaNadmSil.Turn( false ); } if (mvControlled->Battery || mvControlled->ConverterFlag) @@ -4386,23 +3938,20 @@ bool TTrain::Update( double const Deltatime ) mvControlled->ResistorsFlagCheck() : false ); - btLampkaBezoporowa.Turn(mvControlled->ResistorsFlagCheck() || - (mvControlled->MainCtrlActualPos == 0)); // do EU04 + btLampkaBezoporowa.Turn( mvControlled->ResistorsFlagCheck() || ( mvControlled->MainCtrlActualPos == 0 ) ); // do EU04 if( ( mvControlled->Itot != 0 ) || ( mvOccupied->BrakePress > 2 ) || ( mvOccupied->PipePress < 3.6 ) ) { // Ra: czy to jest udawanie działania styczników liniowych? - btLampkaStyczn.TurnOff(); + btLampkaStyczn.Turn( false ); } - else if (mvOccupied->BrakePress < 1) - btLampkaStyczn.TurnOn(); // mozna prowadzic rozruch - if (((TestFlag(mvControlled->Couplers[1].CouplingFlag, ctrain_controll)) && - (mvControlled->CabNo == 1)) || - ((TestFlag(mvControlled->Couplers[0].CouplingFlag, ctrain_controll)) && - (mvControlled->CabNo == -1))) - btLampkaUkrotnienie.TurnOn(); + else if( mvOccupied->BrakePress < 1 ) + btLampkaStyczn.Turn( true ); // mozna prowadzic rozruch + if( ( ( TestFlag( mvControlled->Couplers[ 1 ].CouplingFlag, ctrain_controll ) ) && ( mvControlled->CabNo == 1 ) ) || + ( ( TestFlag( mvControlled->Couplers[ 0 ].CouplingFlag, ctrain_controll ) ) && ( mvControlled->CabNo == -1 ) ) ) + btLampkaUkrotnienie.Turn( true ); else - btLampkaUkrotnienie.TurnOff(); + btLampkaUkrotnienie.Turn( false ); // if // ((TestFlag(mvControlled->BrakeStatus,+b_Rused+b_Ractive)))//Lampka drugiego stopnia hamowania @@ -4415,13 +3964,15 @@ bool TTrain::Update( double const Deltatime ) btLampkaWysRozr.Turn(!(mvControlled->Imax < mvControlled->ImaxHi)); - if (((mvControlled->ScndCtrlActualPos > 0) || - ((mvControlled->RList[mvControlled->MainCtrlActualPos].ScndAct != 0) && - (mvControlled->RList[mvControlled->MainCtrlActualPos].ScndAct != 255))) && - (!mvControlled->DelayCtrlFlag)) - btLampkaBoczniki.TurnOn(); - else - btLampkaBoczniki.TurnOff(); + if( ( false == mvControlled->DelayCtrlFlag ) + && ( ( mvControlled->ScndCtrlActualPos > 0 ) + || ( ( mvControlled->RList[ mvControlled->MainCtrlActualPos ].ScndAct != 0 ) + && ( mvControlled->RList[ mvControlled->MainCtrlActualPos ].ScndAct != 255 ) ) ) ) { + btLampkaBoczniki.Turn( true ); + } + else { + btLampkaBoczniki.Turn( false ); + } btLampkaNapNastHam.Turn(mvControlled->ActiveDir != 0); // napiecie na nastawniku hamulcowym btLampkaSprezarka.Turn(mvControlled->CompressorFlag); // mutopsitka dziala @@ -4433,17 +3984,17 @@ bool TTrain::Update( double const Deltatime ) scp = (scp == 255 ? 0 : scp); // Ra: whatta hella is this? if ((mvControlled->ScndCtrlPos > 0) || (mvControlled->ScndInMain != 0) && (scp > 0)) { // boczniki pojedynczo - btLampkaBocznik1.TurnOn(); + btLampkaBocznik1.Turn( true ); btLampkaBocznik2.Turn(mvControlled->ScndCtrlPos > 1); btLampkaBocznik3.Turn(mvControlled->ScndCtrlPos > 2); btLampkaBocznik4.Turn(mvControlled->ScndCtrlPos > 3); } else { // wyłączone wszystkie cztery - btLampkaBocznik1.TurnOff(); - btLampkaBocznik2.TurnOff(); - btLampkaBocznik3.TurnOff(); - btLampkaBocznik4.TurnOff(); + btLampkaBocznik1.Turn( false ); + btLampkaBocznik2.Turn( false ); + btLampkaBocznik3.Turn( false ); + btLampkaBocznik4.Turn( false ); } /* { //sprezarka w drugim wozie @@ -4459,36 +4010,37 @@ bool TTrain::Update( double const Deltatime ) btLampkaSprezarkaB.Turn(comptemp); */ } - else // wylaczone - { - btLampkaWylSzybki.TurnOff(); - btLampkaWysRozr.TurnOff(); - btLampkaOpory.TurnOff(); - btLampkaStyczn.TurnOff(); - btLampkaUkrotnienie.TurnOff(); - btLampkaHamPosp.TurnOff(); - btLampkaBoczniki.TurnOff(); - btLampkaNapNastHam.TurnOff(); - btLampkaPrzetw.TurnOff(); - btLampkaSprezarka.TurnOff(); - btLampkaBezoporowa.TurnOff(); + else { + // wylaczone + btLampkaWylSzybki.Turn( false ); + btLampkaWysRozr.Turn( false ); + btLampkaOpory.Turn( false ); + btLampkaStyczn.Turn( false ); + btLampkaUkrotnienie.Turn( false ); + btLampkaHamPosp.Turn( false ); + btLampkaBoczniki.Turn( false ); + btLampkaNapNastHam.Turn( false ); + btLampkaPrzetw.Turn( false ); + btLampkaNadmPrzetw.Turn( false ); + btLampkaSprezarka.Turn( false ); + btLampkaBezoporowa.Turn( false ); } - if (mvControlled->Signalling == true) - { + if (mvControlled->Signalling == true) { - if ((mvOccupied->BrakePress >= 0.145f) && (mvControlled->Battery == true) && - (mvControlled->Signalling == true)) - { - btLampkaHamowanie1zes.TurnOn(); + if( ( mvOccupied->BrakePress >= 0.145f ) + && ( mvControlled->Battery == true ) + && ( mvControlled->Signalling == true ) ) { + + btLampkaHamowanie1zes.Turn( true ); } - if (mvControlled->BrakePress < 0.075f) - { - btLampkaHamowanie1zes.TurnOff(); + if (mvControlled->BrakePress < 0.075f) { + + btLampkaHamowanie1zes.Turn( false ); } } - else - { - btLampkaHamowanie1zes.TurnOff(); + else { + + btLampkaHamowanie1zes.Turn( false ); } btLampkaBlokadaDrzwi.Turn(mvControlled->DoorSignalling ? mvOccupied->DoorBlockedFlag() && mvControlled->Battery : @@ -4507,20 +4059,23 @@ bool TTrain::Update( double const Deltatime ) tmp = DynamicObject->PrevConnected; if (tmp) - if ( mvControlled->Battery || mvControlled->ConverterFlag ) - { + if ( mvControlled->Battery || mvControlled->ConverterFlag ) { + btLampkaWylSzybkiB.Turn( tmp->MoverParameters->Mains ); btLampkaOporyB.Turn(tmp->MoverParameters->ResistorsFlagCheck()); btLampkaBezoporowaB.Turn( - tmp->MoverParameters->ResistorsFlagCheck() || - (tmp->MoverParameters->MainCtrlActualPos == 0)); // do EU04 - if ((tmp->MoverParameters->Itot != 0) || - (tmp->MoverParameters->BrakePress > 0.2) || - (tmp->MoverParameters->PipePress < 0.36)) - btLampkaStycznB.TurnOff(); // - else if (tmp->MoverParameters->BrakePress < 0.1) - btLampkaStycznB.TurnOn(); // mozna prowadzic rozruch + ( true == tmp->MoverParameters->ResistorsFlagCheck() ) + || ( tmp->MoverParameters->MainCtrlActualPos == 0 ) ); // do EU04 + + if( ( tmp->MoverParameters->Itot != 0 ) + || ( tmp->MoverParameters->BrakePress > 0.2 ) + || ( tmp->MoverParameters->PipePress < 0.36 ) ) { + btLampkaStycznB.Turn( false ); + } + else if( tmp->MoverParameters->BrakePress < 0.1 ) { + btLampkaStycznB.Turn( true ); // mozna prowadzic rozruch + } //----------------- // //hunter-271211: brak jazdy w drugim czlonie, gdy w @@ -4550,12 +4105,12 @@ bool TTrain::Update( double const Deltatime ) if ((tmp->MoverParameters->BrakePress >= 0.145f * 10) && (mvControlled->Battery == true) && (mvControlled->Signalling == true)) { - btLampkaHamowanie2zes.TurnOn(); + btLampkaHamowanie2zes.Turn( true ); } if ((tmp->MoverParameters->BrakePress < 0.075f * 10) || (mvControlled->Battery == false) || (mvControlled->Signalling == false)) { - btLampkaHamowanie2zes.TurnOff(); + btLampkaHamowanie2zes.Turn( false ); } btLampkaNadmPrzetwB.Turn( tmp->MoverParameters->ConvOvldFlag); // nadmiarowy przetwornicy? @@ -4564,14 +4119,14 @@ bool TTrain::Update( double const Deltatime ) } else // wylaczone { - btLampkaWylSzybkiB.TurnOff(); - btLampkaOporyB.TurnOff(); - btLampkaStycznB.TurnOff(); - btLampkaSprezarkaB.TurnOff(); - btLampkaBezoporowaB.TurnOff(); - btLampkaHamowanie2zes.TurnOff(); - btLampkaNadmPrzetwB.TurnOn(); - btLampkaPrzetwB.TurnOff(); + btLampkaWylSzybkiB.Turn( false ); + btLampkaOporyB.Turn( false ); + btLampkaStycznB.Turn( false ); + btLampkaSprezarkaB.Turn( false ); + btLampkaBezoporowaB.Turn( false ); + btLampkaHamowanie2zes.Turn( false ); + btLampkaNadmPrzetwB.Turn( false ); + btLampkaPrzetwB.Turn( false ); } } @@ -4619,29 +4174,29 @@ bool TTrain::Update( double const Deltatime ) } else { // gdy bateria wyłączona - btLampkaHamienie.TurnOff(); - btLampkaMaxSila.TurnOff(); - btLampkaPrzekrMaxSila.TurnOff(); - btLampkaRadio.TurnOff(); - btLampkaHamulecReczny.TurnOff(); - btLampkaDoorLeft.TurnOff(); - btLampkaDoorRight.TurnOff(); - btLampkaDepartureSignal.TurnOff(); - btLampkaNapNastHam.TurnOff(); - btLampkaForward.TurnOff(); - btLampkaBackward.TurnOff(); - btLampkaED.TurnOff(); + btLampkaHamienie.Turn( false ); + btLampkaMaxSila.Turn( false ); + btLampkaPrzekrMaxSila.Turn( false ); + btLampkaRadio.Turn( false ); + btLampkaHamulecReczny.Turn( false ); + btLampkaDoorLeft.Turn( false ); + btLampkaDoorRight.Turn( false ); + btLampkaDepartureSignal.Turn( false ); + btLampkaNapNastHam.Turn( false ); + btLampkaForward.Turn( false ); + btLampkaBackward.Turn( false ); + btLampkaED.Turn( false ); // light indicators - btLampkaUpperLight.TurnOff(); - btLampkaLeftLight.TurnOff(); - btLampkaRightLight.TurnOff(); - btLampkaLeftEndLight.TurnOff(); - btLampkaRightEndLight.TurnOff(); - btLampkaRearUpperLight.TurnOff(); - btLampkaRearLeftLight.TurnOff(); - btLampkaRearRightLight.TurnOff(); - btLampkaRearLeftEndLight.TurnOff(); - btLampkaRearRightEndLight.TurnOff(); + btLampkaUpperLight.Turn( false ); + btLampkaLeftLight.Turn( false ); + btLampkaRightLight.Turn( false ); + btLampkaLeftEndLight.Turn( false ); + btLampkaRightEndLight.Turn( false ); + btLampkaRearUpperLight.Turn( false ); + btLampkaRearLeftLight.Turn( false ); + btLampkaRearRightLight.Turn( false ); + btLampkaRearLeftEndLight.Turn( false ); + btLampkaRearRightEndLight.Turn( false ); } // McZapkie-080602: obroty (albo translacje) regulatorow @@ -4909,75 +4464,38 @@ bool TTrain::Update( double const Deltatime ) #endif //--------- // hunter-080812: poprawka na ogrzewanie w elektrykach - usuniete uzaleznienie od przetwornicy - if ((((mvControlled->EngineType == ElectricSeriesMotor) && (mvControlled->Mains == true) && - (mvControlled->ConvOvldFlag == false)) || - (mvControlled->ConverterFlag)) && - (mvControlled->Heating == true)) - btLampkaOgrzewanieSkladu.TurnOn(); + if( ( mvControlled->Heating == true ) + && ( ( mvControlled->ConverterFlag ) + || ( ( mvControlled->EngineType == ElectricSeriesMotor ) + && ( mvControlled->Mains == true ) + && ( mvControlled->ConvOvldFlag == false ) ) ) ) + btLampkaOgrzewanieSkladu.Turn( true ); else - btLampkaOgrzewanieSkladu.TurnOff(); + btLampkaOgrzewanieSkladu.Turn( false ); //---------- // McZapkie-141102: SHP i czuwak, TODO: sygnalizacja kabinowa if (mvOccupied->SecuritySystem.Status > 0) { - if (fBlinkTimer > fCzuwakBlink) + if (fBlinkTimer > fCzuwakBlink) fBlinkTimer = -fCzuwakBlink; else fBlinkTimer += dt; // hunter-091012: dodanie testu czuwaka - if ((TestFlag(mvOccupied->SecuritySystem.Status, s_aware)) || - (TestFlag(mvOccupied->SecuritySystem.Status, s_CAtest))) - { - btLampkaCzuwaka.Turn(fBlinkTimer > 0); + if( ( TestFlag( mvOccupied->SecuritySystem.Status, s_aware ) ) + || ( TestFlag( mvOccupied->SecuritySystem.Status, s_CAtest ) ) ) { + btLampkaCzuwaka.Turn( fBlinkTimer > 0 ); } else - btLampkaCzuwaka.TurnOff(); + btLampkaCzuwaka.Turn( false ); btLampkaSHP.Turn(TestFlag(mvOccupied->SecuritySystem.Status, s_active)); - - // hunter-091012: rozdzielenie alarmow - // if (TestFlag(mvOccupied->SecuritySystem.Status,s_alarm)) - if (TestFlag(mvOccupied->SecuritySystem.Status, s_CAalarm) || - TestFlag(mvOccupied->SecuritySystem.Status, s_SHPalarm)) - { - if (dsbBuzzer) - { - dsbBuzzer->GetStatus(&stat); - if (!(stat & DSBSTATUS_PLAYING)) - { - play_sound( dsbBuzzer, DSBVOLUME_MAX, DSBPLAY_LOOPING ); - Console::BitsSet(1 << 14); // ustawienie bitu 16 na PoKeys - } - } - } - else - { - if (dsbBuzzer) - { - dsbBuzzer->GetStatus(&stat); - if (stat & DSBSTATUS_PLAYING) - { - dsbBuzzer->Stop(); - Console::BitsClear(1 << 14); // ustawienie bitu 16 na PoKeys - } - } - } } else // wylaczone { - btLampkaCzuwaka.TurnOff(); - btLampkaSHP.TurnOff(); - if (dsbBuzzer) - { - dsbBuzzer->GetStatus(&stat); - if (stat & DSBSTATUS_PLAYING) - { - dsbBuzzer->Stop(); - Console::BitsClear(1 << 14); // ustawienie bitu 16 na PoKeys - } - } + btLampkaCzuwaka.Turn( false ); + btLampkaSHP.Turn( true ); } // przelaczniki @@ -5371,24 +4889,23 @@ bool TTrain::Update( double const Deltatime ) } #endif // ABu030405 obsluga lampki uniwersalnej: - if (btInstrumentLight.Active()) // w ogóle jest - if (InstrumentLightActive) // załączona - switch (InstrumentLightType) - { - case 0: - btInstrumentLight.Turn( mvControlled->Battery || mvControlled->ConverterFlag ); - break; - case 1: - btInstrumentLight.Turn(mvControlled->Mains); - break; - case 2: - btInstrumentLight.Turn(mvControlled->ConverterFlag); - break; - default: - btInstrumentLight.TurnOff(); + if( btInstrumentLight.Active() ) // w ogóle jest + if( InstrumentLightActive ) // załączona + switch( InstrumentLightType ) { + case 0: + btInstrumentLight.Turn( mvControlled->Battery || mvControlled->ConverterFlag ); + break; + case 1: + btInstrumentLight.Turn( mvControlled->Mains ); + break; + case 2: + btInstrumentLight.Turn( mvControlled->ConverterFlag ); + break; + default: + btInstrumentLight.Turn( false ); } else - btInstrumentLight.TurnOff(); + btInstrumentLight.Turn( false ); #ifdef EU07_USE_OLD_COMMAND_SYSTEM // hunter-091012: przepisanie univ4 i zrobione z uwzglednieniem przelacznika @@ -5447,43 +4964,6 @@ bool TTrain::Update( double const Deltatime ) } } #endif -/* - // NOTE: disabled, as it doesn't seem to be used. - // TODO: get rid of it altogether when we're cleaninng - // Ra: przeklejka z SPKS - płynne poruszanie hamulcem - // if - // ((mvOccupied->BrakeHandle==FV4a)&&(Console::Pressed(Global::Keys[k_IncBrakeLevel]))) - if ((Console::Pressed(Global::Keys[k_IncBrakeLevel]))) - { - if (Global::ctrlState) - { - // mvOccupied->BrakeCtrlPos2-=dt/20.0; - // if (mvOccupied->BrakeCtrlPos2<-1.5) mvOccupied->BrakeCtrlPos2=-1.5; - } - else - { - // mvOccupied->BrakeCtrlPosR+=(mvOccupied->BrakeCtrlPosR>mvOccupied->BrakeCtrlPosNo?0:dt*2); - // mvOccupied->BrakeCtrlPos= floor(mvOccupied->BrakeCtrlPosR+0.499); - } - } - // if - // ((mvOccupied->BrakeHandle==FV4a)&&(Console::Pressed(Global::Keys[k_DecBrakeLevel]))) - if ((Console::Pressed(Global::Keys[k_DecBrakeLevel]))) - { - if (Global::ctrlState) - { - // mvOccupied->BrakeCtrlPos2+=(mvOccupied->BrakeCtrlPos2>2?0:dt/20.0); - // if (mvOccupied->BrakeCtrlPos2<-3) mvOccupied->BrakeCtrlPos2=-3; - // mvOccupied->BrakeLevelAdd(mvOccupied->fBrakeCtrlPos<-1?0:dt*2); - } - else - { - // mvOccupied->BrakeCtrlPosR-=(mvOccupied->BrakeCtrlPosR<-1?0:dt*2); - // mvOccupied->BrakeCtrlPos= floor(mvOccupied->BrakeCtrlPosR+0.499); - // mvOccupied->BrakeLevelAdd(mvOccupied->fBrakeCtrlPos<-1?0:-dt*2); - } - } -*/ if ((mvOccupied->BrakeHandle == FV4a) && (Console::Pressed(Global::Keys[k_IncBrakeLevel]))) { if (Global::ctrlState) @@ -5522,23 +5002,22 @@ bool TTrain::Update( double const Deltatime ) #endif } - // bool kEP; - // kEP=(mvOccupied->BrakeSubsystem==Knorr)||(mvOccupied->BrakeSubsystem==Hik)||(mvOccupied->BrakeSubsystem==Kk); - if ((mvOccupied->BrakeSystem == ElectroPneumatic) && ((mvOccupied->BrakeHandle == St113)) && - (mvControlled->EpFuse == true)) + if( ( mvOccupied->BrakeSystem == ElectroPneumatic ) + && ( mvOccupied->BrakeHandle == St113 ) + && ( mvControlled->EpFuse == true ) ) if (Console::Pressed(Global::Keys[k_AntiSlipping])) // kEP { ggAntiSlipButton.UpdateValue(1); if (mvOccupied->SwitchEPBrake(1)) { - play_sound( dsbPneumaticSwitch ); + dsbPneumaticSwitch.play(); } } else { if (mvOccupied->SwitchEPBrake(0)) { - play_sound( dsbPneumaticSwitch ); + dsbPneumaticSwitch.play(); } } @@ -5644,59 +5123,6 @@ bool TTrain::Update( double const Deltatime ) ggPantFrontButtonOff.PutValue(0); } #endif - /* if ((mvControlled->Mains) && - (mvControlled->EngineType==ElectricSeriesMotor)) - { - //tu dac w przyszlosci zaleznosc od wlaczenia przetwornicy - if (mvControlled->ConverterFlag) //NBMX -obsluga przetwornicy - { - //glosnosc zalezna od nap. sieci - //-2000 do 0 - long tmpVol; - int trackVol; - trackVol=3550-2000; - if (mvControlled->RunningTraction.TractionVoltage<2000) - { - tmpVol=0; - } - else - { - tmpVol=mvControlled->RunningTraction.TractionVoltage-2000; - } - sConverter.Volume(-2000*(trackVol-tmpVol)/trackVol); - - if (!sConverter.Playing()) - sConverter.TurnOn(); - } - else //wyl przetwornicy - sConverter.TurnOff(); - } - else - { - if (sConverter.Playing()) - sConverter.TurnOff(); - } - sConverter.Update(); - */ - - // if (fabs(DynamicObject->GetVelocity())>0.5) - if( dsbHasler != nullptr ) { - if( ( false == FreeFlyModeFlag ) && ( fTachoCount > maxtacho ) ) { - dsbHasler->GetStatus( &stat ); - if( !( stat & DSBSTATUS_PLAYING ) ) - play_sound( dsbHasler, DSBVOLUME_MAX, DSBPLAY_LOOPING ); - } - else { - if( ( true == FreeFlyModeFlag ) || ( fTachoCount < 1 ) ) { - dsbHasler->GetStatus( &stat ); - if( stat & DSBSTATUS_PLAYING ) - dsbHasler->Stop(); - } - } - } - - // koniec mieszania z dzwiekami - // guziki: ggMainOffButton.Update(); ggMainOnButton.Update(); @@ -5854,10 +5280,427 @@ bool TTrain::Update( double const Deltatime ) } */ + // sounds + update_sounds( Deltatime ); + m_updated = true; return true; //(DynamicObject->Update(dt)); } // koniec update +void +TTrain::update_sounds( double const Deltatime ) { +#ifdef EU07_USE_OLD_SOUNDCODE + double vol = 0; + // int freq=1; + double dfreq; + + // McZapkie-280302 - syczenie + if( ( mvOccupied->BrakeHandle == FV4a ) || ( mvOccupied->BrakeHandle == FVel6 ) ) { + if( rsHiss.AM != 0 ) // upuszczanie z PG + { + fPPress = ( 1 * fPPress + mvOccupied->Handle->GetSound( s_fv4a_b ) ) / ( 2 ); + if( fPPress > 0 ) { + vol = 2.0 * rsHiss.AM * fPPress; + } + if( vol > 0.001 ) { + rsHiss.Play( vol, DSBPLAY_LOOPING, true, DynamicObject->GetPosition() ); + } + else { + rsHiss.Stop(); + } + } + if( rsHissU.AM != 0 ) // upuszczanie z PG + { + fNPress = ( 1 * fNPress + mvOccupied->Handle->GetSound( s_fv4a_u ) ) / ( 2 ); + if( fNPress > 0 ) { + vol = rsHissU.AM * fNPress; + } + if( vol > 0.001 ) { + rsHissU.Play( vol, DSBPLAY_LOOPING, true, DynamicObject->GetPosition() ); + } + else { + rsHissU.Stop(); + } + } + if( rsHissE.AM != 0 ) // upuszczanie przy naglym + { + vol = mvOccupied->Handle->GetSound( s_fv4a_e ) * rsHissE.AM; + if( vol > 0.001 ) { + rsHissE.Play( vol, DSBPLAY_LOOPING, true, DynamicObject->GetPosition() ); + } + else { + rsHissE.Stop(); + } + } + if( rsHissX.AM != 0 ) // upuszczanie sterujacego fala + { + vol = mvOccupied->Handle->GetSound( s_fv4a_x ) * rsHissX.AM; + if( vol > 0.001 ) { + rsHissX.Play( vol, DSBPLAY_LOOPING, true, DynamicObject->GetPosition() ); + } + else { + rsHissX.Stop(); + } + } + if( rsHissT.AM != 0 ) // upuszczanie z czasowego + { + vol = mvOccupied->Handle->GetSound( s_fv4a_t ) * rsHissT.AM; + if( vol > 0.001 ) { + rsHissT.Play( vol, DSBPLAY_LOOPING, true, DynamicObject->GetPosition() ); + } + else { + rsHissT.Stop(); + } + } + + } // koniec FV4a + else // jesli nie FV4a + { + if( rsHiss.AM != 0.0 ) // upuszczanie z PG + { + fPPress = ( 4.0f * fPPress + std::max( mvOccupied->dpLocalValve, mvOccupied->dpMainValve ) ) / ( 4.0f + 1.0f ); + if( fPPress > 0.0f ) { + vol = 2.0 * rsHiss.AM * fPPress; + } + if( vol > 0.01 ) { + rsHiss.Play( vol, DSBPLAY_LOOPING, true, DynamicObject->GetPosition() ); + } + else { + rsHiss.Stop(); + } + } + if( rsHissU.AM != 0.0 ) // napelnianie PG + { + fNPress = ( 4.0f * fNPress + Min0R( mvOccupied->dpLocalValve, mvOccupied->dpMainValve ) ) / ( 4.0f + 1.0f ); + if( fNPress < 0.0f ) { + vol = -1.0 * rsHissU.AM * fNPress; + } + if( vol > 0.01 ) { + rsHissU.Play( vol, DSBPLAY_LOOPING, true, DynamicObject->GetPosition() ); + } + else { + rsHissU.Stop(); + } + } + } // koniec nie FV4a + + // Winger-160404 - syczenie pomocniczego (luzowanie) + /* if (rsSBHiss.AM!=0) + { + fSPPress=(mvOccupied->LocalBrakeRatio())-(mvOccupied->LocalBrakePos); + if (fSPPress>0) + { + vol=2*rsSBHiss.AM*fSPPress; + } + if (vol>0.1) + { + rsSBHiss.Play(vol,DSBPLAY_LOOPING,true,DynamicObject->GetPosition()); + } + else + { + rsSBHiss.Stop(); + } + } + */ + // szum w czasie jazdy + vol = 0.0; + dfreq = 1.0; + if( rsRunningNoise.AM != 0 ) { + if( DynamicObject->GetVelocity() != 0 ) { + if( !TestFlag( mvOccupied->DamageFlag, + dtrain_wheelwear ) ) // McZpakie-221103: halas zalezny od kola + { + dfreq = rsRunningNoise.FM * mvOccupied->Vel + rsRunningNoise.FA; + vol = rsRunningNoise.AM * mvOccupied->Vel + rsRunningNoise.AA; + switch( tor->eEnvironment ) { + case e_tunnel: + { + vol *= 3; + dfreq *= 0.95; + } + break; + case e_canyon: + { + vol *= 1.1; + } + break; + case e_bridge: + { + vol *= 2; + dfreq *= 0.98; + } + break; + } + } + else // uszkodzone kolo (podkucie) + if( fabs( mvOccupied->nrot ) > 0.01 ) { + dfreq = rsRunningNoise.FM * mvOccupied->Vel + rsRunningNoise.FA; + vol = rsRunningNoise.AM * mvOccupied->Vel + rsRunningNoise.AA; + switch( tor->eEnvironment ) { + case e_tunnel: + { + vol *= 2; + } + break; + case e_canyon: + { + vol *= 1.1; + } + break; + case e_bridge: + { + vol *= 1.5; + } + break; + } + } + if( fabs( mvOccupied->nrot ) > 0.01 ) + vol *= 1 + + mvOccupied->UnitBrakeForce / + ( 1 + mvOccupied->MaxBrakeForce ); // hamulce wzmagaja halas + vol = vol * ( 20.0 + tor->iDamageFlag ) / 21; + rsRunningNoise.AdjFreq( dfreq, 0 ); + rsRunningNoise.Play( vol, DSBPLAY_LOOPING, true, DynamicObject->GetPosition() ); + } + else + rsRunningNoise.Stop(); + } + + if( rsBrake.AM != 0 ) { + if( ( !mvOccupied->SlippingWheels ) && ( mvOccupied->UnitBrakeForce > 10.0 ) && + ( DynamicObject->GetVelocity() > 0.01 ) ) { + // vol=rsBrake.AA+rsBrake.AM*(DynamicObject->GetVelocity()*100+mvOccupied->UnitBrakeForce); + vol = + rsBrake.AM * sqrt( ( DynamicObject->GetVelocity() * mvOccupied->UnitBrakeForce ) ); + dfreq = rsBrake.FA + rsBrake.FM * DynamicObject->GetVelocity(); + rsBrake.AdjFreq( dfreq, 0 ); + rsBrake.Play( vol, DSBPLAY_LOOPING, true, DynamicObject->GetPosition() ); + } + else { + rsBrake.Stop(); + } + } + + if( rsEngageSlippery.AM != 0 ) { + if /*((fabs(mvControlled->dizel_engagedeltaomega)>0.2) && */( + mvControlled->dizel_engage > 0.1 ) { + if( fabs( mvControlled->dizel_engagedeltaomega ) > 0.2 ) { + dfreq = rsEngageSlippery.FA + + rsEngageSlippery.FM * fabs( mvControlled->dizel_engagedeltaomega ); + vol = rsEngageSlippery.AA + rsEngageSlippery.AM * ( mvControlled->dizel_engage ); + } + else { + dfreq = + 1; // rsEngageSlippery.FA+0.7*rsEngageSlippery.FM*(fabs(mvControlled->enrot)+mvControlled->nmax); + if( mvControlled->dizel_engage > 0.2 ) + vol = + rsEngageSlippery.AA + + 0.2 * rsEngageSlippery.AM * ( mvControlled->enrot / mvControlled->nmax ); + else + vol = 0; + } + rsEngageSlippery.AdjFreq( dfreq, 0 ); + rsEngageSlippery.Play( vol, DSBPLAY_LOOPING, true, DynamicObject->GetPosition() ); + } + else { + rsEngageSlippery.Stop(); + } + } + + if( FreeFlyModeFlag ) + rsFadeSound.Stop(); // wyłącz to cholerne cykanie! + else + rsFadeSound.Play( 1, DSBPLAY_LOOPING, true, DynamicObject->GetPosition() ); + + // McZapkie! - to wazne - SoundFlag wystawiane jest przez moje moduly + // gdy zachodza pewne wydarzenia komentowane dzwiekiem. + // Mysle ze wystarczy sprawdzac a potem zerowac SoundFlag tutaj + // a nie w DynObject - gdyby cos poszlo zle to po co szarpac dzwiekiem co + // 10ms. + + if( TestFlag( mvOccupied->SoundFlag, sound_relay ) ) { + // przekaznik - gdy bezpiecznik, automatyczny rozruch itp + if( mvOccupied->EventFlag || TestFlag( mvOccupied->SoundFlag, sound_loud ) ) { + mvOccupied->EventFlag = false; // Ra: w kabinie? + if( dsbRelay != nullptr ) { dsbRelay->SetVolume( DSBVOLUME_MAX ); } + } + else { + if( dsbRelay != nullptr ) { dsbRelay->SetVolume( -40 ); } + } + if( !TestFlag( mvOccupied->SoundFlag, sound_manyrelay ) ) + dsbRelay.play(); + else { + if( TestFlag( mvOccupied->SoundFlag, sound_loud ) ) + dsbWejscie_na_bezoporow.play(); + else + dsbWejscie_na_drugi_uklad.play(); + } + } + + if( dsbBufferClamp != nullptr ) { + if( TestFlag( mvOccupied->SoundFlag, sound_bufferclamp ) ) // zderzaki uderzaja o siebie + { + if( TestFlag( mvOccupied->SoundFlag, sound_loud ) ) + dsbBufferClamp->SetVolume( DSBVOLUME_MAX ); + else + dsbBufferClamp->SetVolume( -20 ); + dsbBufferClamp.play(); + } + } + if( dsbCouplerStretch ) + if( TestFlag( mvOccupied->SoundFlag, sound_couplerstretch ) ) // sprzegi sie rozciagaja + { + if( TestFlag( mvOccupied->SoundFlag, sound_loud ) ) + dsbCouplerStretch->SetVolume( DSBVOLUME_MAX ); + else + dsbCouplerStretch->SetVolume( -20 ); + dsbCouplerStretch.play(); + } + + if( mvOccupied->SoundFlag == 0 ) + if( mvOccupied->EventFlag ) + if( TestFlag( mvOccupied->DamageFlag, dtrain_wheelwear ) ) { // Ra: przenieść do DynObj! + if( rsRunningNoise.AM != 0 ) { + rsRunningNoise.Stop(); + float am = rsRunningNoise.AM; + float fa = rsRunningNoise.FA; + float fm = rsRunningNoise.FM; + rsRunningNoise.Init( "lomotpodkucia.wav", -1, 0, 0, 0, true ); // MC: zmiana szumu na lomot + if( rsRunningNoise.AM == 1 ) + rsRunningNoise.AM = am; + rsRunningNoise.AA = 0.7; + rsRunningNoise.FA = fa; + rsRunningNoise.FM = fm; + } + mvOccupied->EventFlag = false; + } + + mvOccupied->SoundFlag = 0; + // McZapkie! - koniec obslugi dzwiekow z mover.pas + + + if( mvControlled->SlippingWheels ) { + // Ra 2014-12: lokomotywy 181/182 dostają SlippingWheels po zahamowaniu powyżej 2.85 bara i buczały + double veldiff = ( DynamicObject->GetVelocity() - fTachoVelocity ) / mvControlled->Vmax; + if( veldiff < -0.01 ) { + // 1% Vmax rezerwy, żeby 181/182 nie buczały po zahamowaniu, ale to proteza + rsSlippery.Play( -rsSlippery.AM * veldiff + rsSlippery.AA, DSBPLAY_LOOPING, true, DynamicObject->GetPosition() ); + if( mvControlled->TrainType == dt_181 ) // alarm przy poslizgu dla 181/182 - BOMBARDIER + if( dsbSlipAlarm ) + play_sound( dsbSlipAlarm, DSBPLAY_LOOPING ); + } + else { + if( ( mvOccupied->UnitBrakeForce > 100.0 ) && ( DynamicObject->GetVelocity() > 1.0 ) ) { + rsSlippery.Play( rsSlippery.AM * veldiff + rsSlippery.AA, DSBPLAY_LOOPING, true, DynamicObject->GetPosition() ); + if( mvControlled->TrainType == dt_181 ) + if( dsbSlipAlarm ) + dsbSlipAlarm->Stop(); + } + } + } + else { + rsSlippery.Stop(); + if( mvControlled->TrainType == dt_181 ) + if( dsbSlipAlarm ) + dsbSlipAlarm->Stop(); + } + + // McZapkie-141102: SHP i czuwak, TODO: sygnalizacja kabinowa + if (mvOccupied->SecuritySystem.Status > 0) + { + // hunter-091012: rozdzielenie alarmow + if (TestFlag(mvOccupied->SecuritySystem.Status, s_CAalarm) || + TestFlag(mvOccupied->SecuritySystem.Status, s_SHPalarm)) + { + if (dsbBuzzer) + { + dsbBuzzer->GetStatus(&stat); + if (!(stat & DSBSTATUS_PLAYING)) + { + play_sound( dsbBuzzer, DSBVOLUME_MAX, DSBPLAY_LOOPING ); + Console::BitsSet(1 << 14); // ustawienie bitu 16 na PoKeys + } + } + } + else + { + if (dsbBuzzer) + { + dsbBuzzer->GetStatus(&stat); + if (stat & DSBSTATUS_PLAYING) + { + dsbBuzzer->Stop(); + Console::BitsClear(1 << 14); // ustawienie bitu 16 na PoKeys + } + } + } + } + else // wylaczone + { + if (dsbBuzzer) + { + dsbBuzzer->GetStatus(&stat); + if (stat & DSBSTATUS_PLAYING) + { + dsbBuzzer->Stop(); + Console::BitsClear(1 << 14); // ustawienie bitu 16 na PoKeys + } + } + } + + /* if ((mvControlled->Mains) && + (mvControlled->EngineType==ElectricSeriesMotor)) + { + //tu dac w przyszlosci zaleznosc od wlaczenia przetwornicy + if (mvControlled->ConverterFlag) //NBMX -obsluga przetwornicy + { + //glosnosc zalezna od nap. sieci + //-2000 do 0 + long tmpVol; + int trackVol; + trackVol=3550-2000; + if (mvControlled->RunningTraction.TractionVoltage<2000) + { + tmpVol=0; + } + else + { + tmpVol=mvControlled->RunningTraction.TractionVoltage-2000; + } + sConverter.Volume(-2000*(trackVol-tmpVol)/trackVol); + + if (!sConverter.Playing()) + sConverter.TurnOn(); + } + else //wyl przetwornicy + sConverter.TurnOff(); + } + else + { + if (sConverter.Playing()) + sConverter.TurnOff(); + } + sConverter.Update(); + */ + + // if (fabs(DynamicObject->GetVelocity())>0.5) + if( dsbHasler != nullptr ) { + if( ( false == FreeFlyModeFlag ) && ( fTachoCount > maxtacho ) ) { + dsbHasler->GetStatus( &stat ); + if( !( stat & DSBSTATUS_PLAYING ) ) + play_sound( dsbHasler, DSBVOLUME_MAX, DSBPLAY_LOOPING ); + } + else { + if( ( true == FreeFlyModeFlag ) || ( fTachoCount < 1 ) ) { + dsbHasler->GetStatus( &stat ); + if( stat & DSBSTATUS_PLAYING ) + dsbHasler->Stop(); + } + } + } +#endif +} + bool TTrain::CabChange(int iDirection) { // McZapkie-090902: zmiana kabiny 1->0->2 i z powrotem if (DynamicObject->Mechanik ? DynamicObject->Mechanik->AIControllFlag : @@ -5896,11 +5739,11 @@ bool TTrain::LoadMMediaFile(std::string const &asFileName) //Wartości domyślne by nie wysypywało przy wybrakowanych mmd @240816 Stele // NOTE: should be no longer needed as safety checks were added, // but leaving the defaults for the sake of incomplete mmd files - dsbPneumaticSwitch = TSoundsManager::GetFromName("silence1.wav", true); - dsbBufferClamp = TSoundsManager::GetFromName("en57_bufferclamp.wav", true); - dsbCouplerDetach = TSoundsManager::GetFromName("couplerdetach.wav", true); - dsbCouplerStretch = TSoundsManager::GetFromName("en57_couplerstretch.wav", true); - dsbCouplerAttach = TSoundsManager::GetFromName("couplerattach.wav", true); + dsbPneumaticSwitch.deserialize( "silence1.wav", sound_type::single ); + dsbBufferClamp.deserialize( "en57_bufferclamp.wav", sound_type::single ); + dsbCouplerDetach.deserialize( "couplerdetach.wav", sound_type::single ); + dsbCouplerStretch.deserialize( "en57_couplerstretch.wav", sound_type::single ); + dsbCouplerAttach.deserialize( "couplerattach.wav", sound_type::single ); std::string token; do @@ -5922,250 +5765,269 @@ bool TTrain::LoadMMediaFile(std::string const &asFileName) if (token == "ctrl:") { // nastawnik: - dsbNastawnikJazdy = - TSoundsManager::GetFromName(parser.getToken(), true); + dsbNastawnikJazdy.deserialize( parser, sound_type::single ); } else if (token == "ctrlscnd:") { // hunter-081211: nastawnik bocznikowania - dsbNastawnikBocz = - TSoundsManager::GetFromName(parser.getToken(), true); + dsbNastawnikBocz.deserialize( parser, sound_type::single ); } else if (token == "reverserkey:") { // hunter-131211: dzwiek kierunkowego - dsbReverserKey = - TSoundsManager::GetFromName(parser.getToken(), true); + dsbReverserKey.deserialize( parser, sound_type::single ); } else if (token == "buzzer:") { // bzyczek shp: - dsbBuzzer = - TSoundsManager::GetFromName(parser.getToken(), true); + dsbBuzzer.deserialize( parser, sound_type::single ); } else if (token == "slipalarm:") { // Bombardier 011010: alarm przy poslizgu: - dsbSlipAlarm = - TSoundsManager::GetFromName(parser.getToken(), true); + dsbSlipAlarm.deserialize( parser, sound_type::single ); } else if (token == "tachoclock:") { // cykanie rejestratora: - dsbHasler = - TSoundsManager::GetFromName(parser.getToken(), true); + dsbHasler.deserialize( parser, sound_type::single ); } else if (token == "switch:") { // przelaczniki: - dsbSwitch = - TSoundsManager::GetFromName(parser.getToken(), true); + dsbSwitch.deserialize( parser, sound_type::single ); } else if (token == "pneumaticswitch:") { // stycznik EP: - dsbPneumaticSwitch = - TSoundsManager::GetFromName(parser.getToken(), true); + dsbPneumaticSwitch.deserialize( parser, sound_type::single ); } else if (token == "wejscie_na_bezoporow:") { // hunter-111211: wydzielenie wejscia na bezoporowa i na drugi uklad do pliku - dsbWejscie_na_bezoporow = - TSoundsManager::GetFromName(parser.getToken(), true); + dsbWejscie_na_bezoporow.deserialize( parser, sound_type::single ); } else if (token == "wejscie_na_drugi_uklad:") { - - dsbWejscie_na_drugi_uklad = - TSoundsManager::GetFromName(parser.getToken(), true); + dsbWejscie_na_drugi_uklad.deserialize( parser, sound_type::single ); } else if (token == "relay:") { // styczniki itp: - dsbRelay = - TSoundsManager::GetFromName(parser.getToken(), true); - if (!dsbWejscie_na_bezoporow) - { // hunter-111211: domyslne, gdy brak - dsbWejscie_na_bezoporow = - TSoundsManager::GetFromName("wejscie_na_bezoporow.wav", true); + dsbRelay.deserialize( parser, sound_type::single ); + if( true == dsbWejscie_na_bezoporow.empty() ) { + // hunter-111211: domyslne, gdy brak + dsbWejscie_na_bezoporow.deserialize( "wejscie_na_bezoporow.wav", sound_type::single ); } - if (!dsbWejscie_na_drugi_uklad) - { - dsbWejscie_na_drugi_uklad = - TSoundsManager::GetFromName("wescie_na_drugi_uklad.wav", true); + if (true == dsbWejscie_na_drugi_uklad.empty()) { + dsbWejscie_na_drugi_uklad.deserialize( "wescie_na_drugi_uklad.wav", sound_type::single ); } } else if (token == "pneumaticrelay:") { // wylaczniki pneumatyczne: - dsbPneumaticRelay = - TSoundsManager::GetFromName(parser.getToken(), true); + dsbPneumaticRelay.deserialize( parser, sound_type::single ); } else if (token == "couplerattach:") { // laczenie: - dsbCouplerAttach = - TSoundsManager::GetFromName(parser.getToken(), true); + dsbCouplerAttach.deserialize( parser, sound_type::single ); } else if (token == "couplerstretch:") { // laczenie: - dsbCouplerStretch = - TSoundsManager::GetFromName(parser.getToken(), true); + dsbCouplerStretch.deserialize( parser, sound_type::single ); } else if (token == "couplerdetach:") { // rozlaczanie: - dsbCouplerDetach = - TSoundsManager::GetFromName(parser.getToken(), true); + dsbCouplerDetach.deserialize( parser, sound_type::single ); } else if (token == "bufferclamp:") { // laczenie: - dsbBufferClamp = - TSoundsManager::GetFromName(parser.getToken(), true); + dsbBufferClamp.deserialize( parser, sound_type::single ); } else if (token == "ignition:") { // odpalanie silnika - dsbDieselIgnition = - TSoundsManager::GetFromName(parser.getToken(), true); + dsbDieselIgnition.deserialize( parser, sound_type::single ); } else if (token == "brakesound:") { // hamowanie zwykle: +/* rsBrake.Init(parser.getToken(), -1, 0, 0, 0, true, true); parser.getTokens(4, false); - parser >> rsBrake.AM >> rsBrake.AA >> rsBrake.FM >> rsBrake.FA; + parser + >> rsBrake.AM + >> rsBrake.AA + >> rsBrake.FM + >> rsBrake.FA; rsBrake.AM /= (1 + mvOccupied->MaxBrakeForce * 1000); rsBrake.FM /= (1 + mvOccupied->Vmax); +*/ + rsBrake.deserialize( parser, sound_type::single, sound_parameters::amplitude | sound_parameters::frequency ); } else if (token == "slipperysound:") { // sanie: +/* rsSlippery.Init(parser.getToken(), -1, 0, 0, 0, true); parser.getTokens(2, false); - parser >> rsSlippery.AM >> rsSlippery.AA; + parser + >> rsSlippery.AM + >> rsSlippery.AA; rsSlippery.FM = 0.0; rsSlippery.FA = 1.0; rsSlippery.AM /= (1 + mvOccupied->Vmax); +*/ + rsSlippery.deserialize( parser, sound_type::single, sound_parameters::amplitude ); } else if (token == "airsound:") { // syk: +/* rsHiss.Init(parser.getToken(), -1, 0, 0, 0, true); parser.getTokens(2, false); - parser >> rsHiss.AM >> rsHiss.AA; + parser + >> rsHiss.AM + >> rsHiss.AA; rsHiss.FM = 0.0; rsHiss.FA = 1.0; +*/ + rsHiss.deserialize( parser, sound_type::single, sound_parameters::amplitude ); } else if (token == "airsound2:") { // syk: +/* rsHissU.Init(parser.getToken(), -1, 0, 0, 0, true); parser.getTokens(2, false); - parser >> rsHissU.AM >> rsHissU.AA; + parser + >> rsHissU.AM + >> rsHissU.AA; rsHissU.FM = 0.0; rsHissU.FA = 1.0; +*/ + rsHissU.deserialize( parser, sound_type::single, sound_parameters::amplitude ); } else if (token == "airsound3:") { // syk: +/* rsHissE.Init(parser.getToken(), -1, 0, 0, 0, true); parser.getTokens(2, false); - parser >> rsHissE.AM >> rsHissE.AA; + parser + >> rsHissE.AM + >> rsHissE.AA; rsHissE.FM = 0.0; rsHissE.FA = 1.0; +*/ + rsHissE.deserialize( parser, sound_type::single, sound_parameters::amplitude ); } else if (token == "airsound4:") { // syk: +/* rsHissX.Init(parser.getToken(), -1, 0, 0, 0, true); parser.getTokens(2, false); - parser >> rsHissX.AM >> rsHissX.AA; + parser + >> rsHissX.AM + >> rsHissX.AA; rsHissX.FM = 0.0; rsHissX.FA = 1.0; +*/ + rsHissX.deserialize( parser, sound_type::single, sound_parameters::amplitude ); } else if (token == "airsound5:") { // syk: +/* rsHissT.Init(parser.getToken(), -1, 0, 0, 0, true); parser.getTokens(2, false); - parser >> rsHissT.AM >> rsHissT.AA; + parser + >> rsHissT.AM + >> rsHissT.AA; rsHissT.FM = 0.0; rsHissT.FA = 1.0; +*/ + rsHissT.deserialize( parser, sound_type::single, sound_parameters::amplitude ); } else if (token == "fadesound:") { // syk: +/* rsFadeSound.Init(parser.getToken(), -1, 0, 0, 0, true); rsFadeSound.AM = 1.0; rsFadeSound.AA = 1.0; rsFadeSound.FM = 1.0; rsFadeSound.FA = 1.0; +*/ + rsFadeSound.deserialize( parser, sound_type::single, sound_parameters::amplitude | sound_parameters::frequency ); } else if (token == "localbrakesound:") { // syk: +/* rsSBHiss.Init(parser.getToken(), -1, 0, 0, 0, true); parser.getTokens(2, false); - parser >> rsSBHiss.AM >> rsSBHiss.AA; + parser + >> rsSBHiss.AM + >> rsSBHiss.AA; rsSBHiss.FM = 0.0; rsSBHiss.FA = 1.0; +*/ + rsSBHiss.deserialize( parser, sound_type::single, sound_parameters::amplitude ); } else if (token == "runningnoise:") { // szum podczas jazdy: +/* rsRunningNoise.Init(parser.getToken(), -1, 0, 0, 0, true, true); parser.getTokens(4, false); - parser >> rsRunningNoise.AM >> rsRunningNoise.AA >> rsRunningNoise.FM >> - rsRunningNoise.FA; + parser + >> rsRunningNoise.AM + >> rsRunningNoise.AA + >> rsRunningNoise.FM + >> rsRunningNoise.FA; rsRunningNoise.AM /= (1 + mvOccupied->Vmax); rsRunningNoise.FM /= (1 + mvOccupied->Vmax); +*/ + rsRunningNoise.deserialize( parser, sound_type::single, sound_parameters::amplitude | sound_parameters::frequency ); } else if (token == "engageslippery:") { // tarcie tarcz sprzegla: +/* rsEngageSlippery.Init(parser.getToken(), -1, 0, 0, 0, true, true); parser.getTokens(4, false); - parser >> rsEngageSlippery.AM >> rsEngageSlippery.AA >> rsEngageSlippery.FM >> - rsEngageSlippery.FA; + parser + >> rsEngageSlippery.AM + >> rsEngageSlippery.AA + >> rsEngageSlippery.FM + >> rsEngageSlippery.FA; rsEngageSlippery.FM /= (1 + mvOccupied->nmax); +*/ + rsEngageSlippery.deserialize( parser, sound_type::single, sound_parameters::amplitude | sound_parameters::frequency ); } else if (token == "mechspring:") { // parametry bujania kamery: double ks, kd; parser.getTokens(2, false); - parser >> ks >> kd; + parser + >> ks + >> kd; MechSpring.Init(MechSpring.restLen, ks, kd); parser.getTokens(6, false); - parser >> fMechSpringX >> fMechSpringY >> fMechSpringZ >> fMechMaxSpring >> - fMechRoll >> fMechPitch; - } - else if (token == "pantographup:") - { - // podniesienie patyka: - dsbPantUp = - TSoundsManager::GetFromName(parser.getToken(), true); - } - else if (token == "pantographdown:") - { - // podniesienie patyka: - dsbPantDown = - TSoundsManager::GetFromName(parser.getToken(), true); - } - else if (token == "doorclose:") - { - // zamkniecie drzwi: - dsbDoorClose = - TSoundsManager::GetFromName(parser.getToken(), true); - } - else if (token == "dooropen:") - { - // otwarcie drzwi: - dsbDoorOpen = - TSoundsManager::GetFromName(parser.getToken(), true); + parser + >> fMechSpringX + >> fMechSpringY + >> fMechSpringZ + >> fMechMaxSpring + >> fMechRoll + >> fMechPitch; } } while (token != ""); @@ -6356,10 +6218,12 @@ bool TTrain::InitializeCab(int NewCabNo, std::string const &asFileName) { DynamicObject->mdKabina->Init(); // obrócenie modelu oraz optymalizacja, również zapisanie binarnego set_cab_controls(); +/* // HACK: for some reason simulation at the start is slow until a sound is played // until we do a proper fix, try to play a 'silent' sound when cab is entered // TBD: it could be instead a legit sound of door closing play_sound( dsbSwitch, DSBVOLUME_MIN ); +*/ return true; } return (token == "none"); @@ -6452,38 +6316,19 @@ void TTrain::DynamicSet(TDynamicObject *d) void TTrain::Silence() { // wyciszenie dźwięków przy wychodzeniu - if (dsbNastawnikJazdy) - dsbNastawnikJazdy->Stop(); - if (dsbNastawnikBocz) - dsbNastawnikBocz->Stop(); - if (dsbRelay) - dsbRelay->Stop(); - if (dsbPneumaticRelay) - dsbPneumaticRelay->Stop(); - if (dsbSwitch) - dsbSwitch->Stop(); - if (dsbPneumaticSwitch) - dsbPneumaticSwitch->Stop(); - if (dsbReverserKey) - dsbReverserKey->Stop(); - if (dsbCouplerAttach) - dsbCouplerAttach->Stop(); - if (dsbCouplerDetach) - dsbCouplerDetach->Stop(); - if (dsbDieselIgnition) - dsbDieselIgnition->Stop(); - if (dsbDoorClose) - dsbDoorClose->Stop(); - if (dsbDoorOpen) - dsbDoorOpen->Stop(); - if (dsbPantUp) - dsbPantUp->Stop(); - if (dsbPantDown) - dsbPantDown->Stop(); - if (dsbWejscie_na_bezoporow) - dsbWejscie_na_bezoporow->Stop(); - if (dsbWejscie_na_drugi_uklad) - dsbWejscie_na_drugi_uklad->Stop(); +#ifdef EU07_USE_OLD_SOUNDCODE + dsbNastawnikJazdy.Stop(); + dsbNastawnikBocz.Stop(); + dsbRelay.Stop(); + dsbPneumaticRelay.Stop(); + dsbSwitch.Stop(); + dsbPneumaticSwitch.Stop(); + dsbReverserKey.Stop(); + dsbCouplerAttach.Stop(); + dsbCouplerDetach.Stop(); + dsbDieselIgnition.Stop(); + dsbWejscie_na_bezoporow.Stop(); + dsbWejscie_na_drugi_uklad.Stop(); rsBrake.Stop(); rsSlippery.Stop(); rsHiss.Stop(); @@ -6495,20 +6340,15 @@ void TTrain::Silence() rsRunningNoise.Stop(); rsEngageSlippery.Stop(); rsFadeSound.Stop(); - if (dsbHasler) - dsbHasler->Stop(); // wyłączenie dźwięków opuszczanej kabiny - if (dsbBuzzer) - dsbBuzzer->Stop(); - if (dsbSlipAlarm) - dsbSlipAlarm->Stop(); // dźwięk alarmu przy poślizgu + dsbHasler.Stop(); // wyłączenie dźwięków opuszczanej kabiny + dsbBuzzer.Stop(); + dsbSlipAlarm.Stop(); // dźwięk alarmu przy poślizgu // sConverter.Stop(); // sSmallCompressor->Stop(); - if (dsbCouplerStretch) - dsbCouplerStretch->Stop(); - if (dsbEN57_CouplerStretch) - dsbEN57_CouplerStretch->Stop(); - if (dsbBufferClamp) - dsbBufferClamp->Stop(); + dsbCouplerStretch.Stop(); + dsbEN57_CouplerStretch.Stop(); + dsbBufferClamp.Stop(); +#endif }; void TTrain::SetLights() @@ -6659,7 +6499,6 @@ void TTrain::clear_cab_controls() btLampkaSprezarka.Clear(); btLampkaSprezarkaB.Clear(); btLampkaNapNastHam.Clear(); - btLampkaJazda.Clear(); btLampkaStycznB.Clear(); btLampkaHamowanie1zes.Clear(); btLampkaHamowanie2zes.Clear(); @@ -7276,31 +7115,3 @@ bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int con return true; } - -void -TTrain::play_sound( PSound Sound, int const Volume, DWORD const Flags ) { - - if( Sound ) { - - Sound->SetCurrentPosition( 0 ); - Sound->SetVolume( Volume ); - Sound->Play( 0, 0, Flags ); - return; - } -} - -void -TTrain::play_sound( PSound Sound, PSound Fallbacksound, int const Volume, DWORD const Flags ) { - - if( Sound ) { - - play_sound( Sound, Volume, Flags ); - return; - } - if( Fallbacksound ) { - - play_sound( Fallbacksound, Volume, Flags ); - return; - } -} - diff --git a/Train.h b/Train.h index 7beeadd4..693ad396 100644 --- a/Train.h +++ b/Train.h @@ -14,7 +14,7 @@ http://mozilla.org/MPL/2.0/. #include "Button.h" #include "Gauge.h" #include "Spring.h" -#include "AdvSound.h" +#include "sound.h" #include "PyInt.h" #include "command.h" @@ -90,6 +90,7 @@ class TTrain void UpdateMechPosition(double dt); vector3 GetWorldMechPosition(); bool Update( double const Deltatime ); + void update_sounds( double const Deltatime ); bool m_updated = false; void MechStop(); void SetLights(); @@ -110,10 +111,6 @@ class TTrain bool initialize_gauge(cParser &Parser, std::string const &Label, int const Cabindex); // initializes a button matching provided label. returns: true if the label was found, false otherwise bool initialize_button(cParser &Parser, std::string const &Label, int const Cabindex); - // plays specified sound, or fallback sound if the primary sound isn't presend - // NOTE: temporary routine until sound system is sorted out and paired with switches - void play_sound( PSound Sound, int const Volume = DSBVOLUME_MAX, DWORD const Flags = 0 ); - void play_sound( PSound Sound, PSound Fallbacksound, int const Volume, DWORD const Flags ); // helper, returns true for EMU with oerlikon brake bool is_eztoer() const; // command handlers @@ -308,8 +305,6 @@ public: // reszta może by?publiczna TGauge ggTrainHeatingButton; TGauge ggSignallingButton; TGauge ggDoorSignallingButton; - // TGauge ggDistCounter; //Ra 2014-07: licznik kilometrów - // TGauge ggVelocityDgt; //i od razu prędkościomierz TButton btLampkaPoslizg; TButton btLampkaStyczn; @@ -356,7 +351,6 @@ public: // reszta może by?publiczna TButton btLampkaRadiotelefon; TButton btLampkaHamienie; TButton btLampkaED; // Stele 161228 hamowanie elektrodynamiczne - TButton btLampkaJazda; // Ra: nie używane // KURS90 TButton btLampkaBoczniki; TButton btLampkaMaxSila; @@ -384,8 +378,9 @@ public: // reszta może by?publiczna // Ra 2013-12: wirtualne "lampki" do odbijania na haslerze w PoKeys TButton btHaslerBrakes; // ciśnienie w cylindrach TButton btHaslerCurrent; // prąd na silnikach - +/* vector3 pPosition; +*/ vector3 pMechOffset; // driverNpos vector3 vMechMovement; vector3 pMechPosition; @@ -403,48 +398,42 @@ public: // reszta może by?publiczna double fMechRoll; double fMechPitch; - PSound dsbNastawnikJazdy; - PSound dsbNastawnikBocz; // hunter-081211 - PSound dsbRelay; - PSound dsbPneumaticRelay; - PSound dsbSwitch; - PSound dsbPneumaticSwitch; - PSound dsbReverserKey; // hunter-121211 + 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 - PSound dsbCouplerAttach; // Ra: w kabinie???? - PSound dsbCouplerDetach; // Ra: w kabinie??? + sound_source dsbCouplerAttach; // Ra: w kabinie???? + sound_source dsbCouplerDetach; // Ra: w kabinie??? - PSound dsbDieselIgnition; // Ra: w kabinie??? - - PSound dsbDoorClose; // Ra: w kabinie??? - PSound dsbDoorOpen; // Ra: w kabinie??? + sound_source dsbDieselIgnition; // Ra: w kabinie??? // Winger 010304 - PSound dsbPantUp; - PSound dsbPantDown; - - PSound dsbWejscie_na_bezoporow; - PSound dsbWejscie_na_drugi_uklad; // hunter-081211: poprawka literowki + sound_source dsbWejscie_na_bezoporow; + sound_source dsbWejscie_na_drugi_uklad; // hunter-081211: poprawka literowki // PSound dsbHiss1; // PSound dsbHiss2; // McZapkie-280302 - TRealSound rsBrake; - TRealSound rsSlippery; - TRealSound rsHiss; // upuszczanie - TRealSound rsHissU; // napelnianie - TRealSound rsHissE; // nagle - TRealSound rsHissX; // fala - TRealSound rsHissT; // czasowy - TRealSound rsSBHiss; - TRealSound rsRunningNoise; - TRealSound rsEngageSlippery; - TRealSound rsFadeSound; + 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; - PSound dsbHasler; - PSound dsbBuzzer; - PSound dsbSlipAlarm; // Bombardier 011010: alarm przy poslizgu dla 181/182 + sound_source dsbHasler; + sound_source dsbBuzzer; + sound_source dsbSlipAlarm; // Bombardier 011010: alarm przy poslizgu dla 181/182 int iCabLightFlag; // McZapkie:120503: oswietlenie kabiny (0: wyl, 1: przyciemnione, 2: pelne) bool bCabLight; // hunter-091012: czy swiatlo jest zapalone? @@ -453,11 +442,10 @@ public: // reszta może by?publiczna vector3 pMechSittingPosition; // ABu 180404 vector3 MirrorPosition(bool lewe); - private: - // PSound dsbBuzzer; - PSound dsbCouplerStretch; - PSound dsbEN57_CouplerStretch; - PSound dsbBufferClamp; +private: + sound_source dsbCouplerStretch; + sound_source dsbEN57_CouplerStretch; + sound_source dsbBufferClamp; double fBlinkTimer; float fHaslerTimer; float fConverterTimer; // hunter-261211: dla przekaznika @@ -509,5 +497,6 @@ public: // reszta może by?publiczna inline TMoverParameters *Controlled() { return mvControlled; }; void DynamicSet(TDynamicObject *d); void Silence(); + }; //--------------------------------------------------------------------------- diff --git a/World.cpp b/World.cpp index eafab396..45470e8c 100644 --- a/World.cpp +++ b/World.cpp @@ -196,8 +196,6 @@ TWorld::TWorld() TWorld::~TWorld() { TrainDelete(); - // Ground.Free(); //Ra: usunięcie obiektów przed usunięciem dźwięków - sypie się - TSoundsManager::Free(); } void TWorld::TrainDelete(TDynamicObject *d) @@ -234,7 +232,7 @@ bool TWorld::Init( GLFWwindow *Window ) { "ShaXbee, Oli_EU, youBy, KURS90, Ra, hunter, szociu, Stele, Q, firleju and others\n" ); UILayer.set_background( "logo" ); - +#ifdef EU07_USE_OLD_SOUNDCODE if( true == TSoundsManager::Init( glfwGetWin32Window( window ) ) ) { WriteLog( "Sound subsystem setup complete" ); } @@ -242,7 +240,7 @@ bool TWorld::Init( GLFWwindow *Window ) { ErrorLog( "Sound subsystem setup failed" ); return false; } - +#endif glfwSetWindowTitle( window, ( Global::AppName + " (" + Global::SceneryFile + ")" ).c_str() ); // nazwa scenerii UILayer.set_progress(0.01); UILayer.set_progress( "Loading scenery / Wczytywanie scenerii" ); @@ -689,7 +687,7 @@ void TWorld::OnKeyDown(int cKey) vehicle->MoverParameters->DecBrakeMult()) if (Train) { // dźwięk oczywiście jest w kabinie - Train->play_sound( Train->dsbSwitch ); + Train->dsbSwitch.play(); } } } @@ -717,7 +715,7 @@ void TWorld::OnKeyDown(int cKey) vehicle->iLights[CouplNr] = (vehicle->iLights[CouplNr] & ~mask) | set; if (Train) { // Ra: ten dźwięk z kabiny to przegięcie, ale na razie zostawiam - Train->play_sound( Train->dsbSwitch ); + Train->dsbSwitch.play(); } } } @@ -737,7 +735,7 @@ void TWorld::OnKeyDown(int cKey) if (vehicle->MoverParameters->IncLocalBrakeLevelFAST()) if (Train) { // dźwięk oczywiście jest w kabinie - Train->play_sound( Train->dsbPneumaticRelay ); + Train->dsbPneumaticRelay.play(); } } } @@ -756,7 +754,7 @@ void TWorld::OnKeyDown(int cKey) if (vehicle->MoverParameters->DecLocalBrakeLevelFAST()) if (Train) { // dźwięk oczywiście jest w kabinie - Train->play_sound( Train->dsbPneumaticRelay ); + Train->dsbPneumaticRelay.play(); } } } diff --git a/maszyna.vcxproj.filters b/maszyna.vcxproj.filters index 251ff4a9..79bade59 100644 --- a/maszyna.vcxproj.filters +++ b/maszyna.vcxproj.filters @@ -231,6 +231,9 @@ Source Files + + Source Files + @@ -452,6 +455,9 @@ Header Files + + Header Files + diff --git a/openglgeometrybank.cpp b/openglgeometrybank.cpp index d1e47062..2e106500 100644 --- a/openglgeometrybank.cpp +++ b/openglgeometrybank.cpp @@ -14,6 +14,8 @@ http://mozilla.org/MPL/2.0/. #include "logs.h" #include "globals.h" +namespace gfx { + void basic_vertex::serialize( std::ostream &s ) const { @@ -47,14 +49,14 @@ basic_vertex::deserialize( std::istream &s ) { // generic geometry bank class, allows storage, update and drawing of geometry chunks // creates a new geometry chunk of specified type from supplied vertex data. returns: handle to the chunk -geometry_handle -geometry_bank::create( vertex_array &Vertices, unsigned int const Type ) { +gfx::geometry_handle +geometry_bank::create( gfx::vertex_array &Vertices, unsigned int const Type ) { - if( true == Vertices.empty() ) { return geometry_handle( 0, 0 ); } + if( true == Vertices.empty() ) { return { 0, 0 }; } m_chunks.emplace_back( Vertices, Type ); // NOTE: handle is effectively (index into chunk array + 1) this leaves value of 0 to serve as error/empty handle indication - geometry_handle chunkhandle { 0, static_cast(m_chunks.size()) }; + gfx::geometry_handle chunkhandle { 0, static_cast(m_chunks.size()) }; // template method implementation create_( chunkhandle ); // all done @@ -63,11 +65,11 @@ geometry_bank::create( vertex_array &Vertices, unsigned int const Type ) { // replaces data of specified chunk with the supplied vertex data, starting from specified offset bool -geometry_bank::replace( vertex_array &Vertices, geometry_handle const &Geometry, std::size_t const Offset ) { +geometry_bank::replace( gfx::vertex_array &Vertices, gfx::geometry_handle const &Geometry, std::size_t const Offset ) { if( ( Geometry.chunk == 0 ) || ( Geometry.chunk > m_chunks.size() ) ) { return false; } - auto &chunk = geometry_bank::chunk( Geometry ); + auto &chunk = gfx::geometry_bank::chunk( Geometry ); if( ( Offset == 0 ) && ( Vertices.size() == chunk.vertices.size() ) ) { @@ -78,7 +80,7 @@ geometry_bank::replace( vertex_array &Vertices, geometry_handle const &Geometry, // ...otherwise we need to do some legwork // NOTE: if the offset is larger than existing size of the chunk, it'll bridge the gap with 'blank' vertices // TBD: we could bail out with an error instead if such request occurs - chunk.vertices.resize( Offset + Vertices.size(), basic_vertex() ); + chunk.vertices.resize( Offset + Vertices.size(), gfx::basic_vertex() ); chunk.vertices.insert( std::end( chunk.vertices ), std::begin( Vertices ), std::end( Vertices ) ); } // template method implementation @@ -89,16 +91,16 @@ geometry_bank::replace( vertex_array &Vertices, geometry_handle const &Geometry, // adds supplied vertex data at the end of specified chunk bool -geometry_bank::append( vertex_array &Vertices, geometry_handle const &Geometry ) { +geometry_bank::append( gfx::vertex_array &Vertices, gfx::geometry_handle const &Geometry ) { if( ( Geometry.chunk == 0 ) || ( Geometry.chunk > m_chunks.size() ) ) { return false; } - return replace( Vertices, Geometry, geometry_bank::chunk( Geometry ).vertices.size() ); + return replace( Vertices, Geometry, gfx::geometry_bank::chunk( Geometry ).vertices.size() ); } // draws geometry stored in specified chunk void -geometry_bank::draw( geometry_handle const &Geometry, stream_units const &Units, unsigned int const Streams ) { +geometry_bank::draw( gfx::geometry_handle const &Geometry, gfx::stream_units const &Units, unsigned int const Streams ) { // template method implementation draw_( Geometry, Units, Streams ); } @@ -111,7 +113,7 @@ geometry_bank::release() { } vertex_array const & -geometry_bank::vertices( geometry_handle const &Geometry ) const { +geometry_bank::vertices( gfx::geometry_handle const &Geometry ) const { return geometry_bank::chunk( Geometry ).vertices; } @@ -119,12 +121,12 @@ geometry_bank::vertices( geometry_handle const &Geometry ) const { // opengl vbo-based variant of the geometry bank GLuint opengl_vbogeometrybank::m_activebuffer { 0 }; // buffer bound currently on the opengl end, if any -unsigned int opengl_vbogeometrybank::m_activestreams { stream::none }; // currently enabled data type pointers +unsigned int opengl_vbogeometrybank::m_activestreams { gfx::stream::none }; // currently enabled data type pointers std::vector opengl_vbogeometrybank::m_activetexturearrays; // currently enabled texture coord arrays // create() subclass details void -opengl_vbogeometrybank::create_( geometry_handle const &Geometry ) { +opengl_vbogeometrybank::create_( gfx::geometry_handle const &Geometry ) { // adding a chunk means we'll be (re)building the buffer, which will fill the chunk records, amongst other things. // thus we don't need to initialize the values here m_chunkrecords.emplace_back( chunk_record() ); @@ -134,7 +136,7 @@ opengl_vbogeometrybank::create_( geometry_handle const &Geometry ) { // replace() subclass details void -opengl_vbogeometrybank::replace_( geometry_handle const &Geometry ) { +opengl_vbogeometrybank::replace_( gfx::geometry_handle const &Geometry ) { auto &chunkrecord = m_chunkrecords[ Geometry.chunk - 1 ]; chunkrecord.is_good = false; @@ -149,7 +151,7 @@ opengl_vbogeometrybank::replace_( geometry_handle const &Geometry ) { // draw() subclass details void -opengl_vbogeometrybank::draw_( geometry_handle const &Geometry, stream_units const &Units, unsigned int const Streams ) { +opengl_vbogeometrybank::draw_( gfx::geometry_handle const &Geometry, gfx::stream_units const &Units, unsigned int const Streams ) { if( m_buffer == 0 ) { // if there's no buffer, we'll have to make one @@ -176,7 +178,7 @@ opengl_vbogeometrybank::draw_( geometry_handle const &Geometry, stream_units con // TODO: allow to specify usage hint at the object creation, and pass it here ::glBufferData( GL_ARRAY_BUFFER, - datasize * sizeof( basic_vertex ), + datasize * sizeof( gfx::basic_vertex ), nullptr, GL_STATIC_DRAW ); if( ::glGetError() == GL_OUT_OF_MEMORY ) { @@ -193,13 +195,13 @@ opengl_vbogeometrybank::draw_( geometry_handle const &Geometry, stream_units con bind_buffer(); } auto &chunkrecord = m_chunkrecords[ Geometry.chunk - 1 ]; - auto const &chunk = geometry_bank::chunk( Geometry ); + auto const &chunk = gfx::geometry_bank::chunk( Geometry ); if( false == chunkrecord.is_good ) { // we may potentially need to upload new buffer data before we can draw it ::glBufferSubData( GL_ARRAY_BUFFER, - chunkrecord.offset * sizeof( basic_vertex ), - chunkrecord.size * sizeof( basic_vertex ), + chunkrecord.offset * sizeof( gfx::basic_vertex ), + chunkrecord.size * sizeof( gfx::basic_vertex ), chunk.vertices.data() ); chunkrecord.is_good = true; } @@ -229,7 +231,7 @@ opengl_vbogeometrybank::bind_buffer() { ::glBindBuffer( GL_ARRAY_BUFFER, m_buffer ); m_activebuffer = m_buffer; - m_activestreams = stream::none; + m_activestreams = gfx::stream::none; } void @@ -250,34 +252,34 @@ opengl_vbogeometrybank::delete_buffer() { } void -opengl_vbogeometrybank::bind_streams( stream_units const &Units, unsigned int const Streams ) { +opengl_vbogeometrybank::bind_streams( gfx::stream_units const &Units, unsigned int const Streams ) { - if( Streams & stream::position ) { - ::glVertexPointer( 3, GL_FLOAT, sizeof( basic_vertex ), static_cast( nullptr ) ); + if( Streams & gfx::stream::position ) { + ::glVertexPointer( 3, GL_FLOAT, sizeof( gfx::basic_vertex ), static_cast( nullptr ) ); ::glEnableClientState( GL_VERTEX_ARRAY ); } else { ::glDisableClientState( GL_VERTEX_ARRAY ); } // NOTE: normal and color streams share the data, making them effectively mutually exclusive - if( Streams & stream::normal ) { - ::glNormalPointer( GL_FLOAT, sizeof( basic_vertex ), static_cast( nullptr ) + sizeof( float ) * 3 ); + if( Streams & gfx::stream::normal ) { + ::glNormalPointer( GL_FLOAT, sizeof( gfx::basic_vertex ), static_cast( nullptr ) + sizeof( float ) * 3 ); ::glEnableClientState( GL_NORMAL_ARRAY ); } else { ::glDisableClientState( GL_NORMAL_ARRAY ); } - if( Streams & stream::color ) { - ::glColorPointer( 3, GL_FLOAT, sizeof( basic_vertex ), static_cast( nullptr ) + sizeof( float ) * 3 ); + if( Streams & gfx::stream::color ) { + ::glColorPointer( 3, GL_FLOAT, sizeof( gfx::basic_vertex ), static_cast( nullptr ) + sizeof( float ) * 3 ); ::glEnableClientState( GL_COLOR_ARRAY ); } else { ::glDisableClientState( GL_COLOR_ARRAY ); } - if( Streams & stream::texture ) { + if( Streams & gfx::stream::texture ) { for( auto unit : Units.texture ) { ::glClientActiveTexture( unit ); - ::glTexCoordPointer( 2, GL_FLOAT, sizeof( basic_vertex ), static_cast( nullptr ) + 24 ); + ::glTexCoordPointer( 2, GL_FLOAT, sizeof( gfx::basic_vertex ), static_cast( nullptr ) + 24 ); ::glEnableClientState( GL_TEXTURE_COORD_ARRAY ); } m_activetexturearrays = Units.texture; @@ -304,7 +306,7 @@ opengl_vbogeometrybank::release_streams() { ::glDisableClientState( GL_TEXTURE_COORD_ARRAY ); } - m_activestreams = stream::none; + m_activestreams = gfx::stream::none; m_activetexturearrays.clear(); } @@ -312,21 +314,21 @@ opengl_vbogeometrybank::release_streams() { // create() subclass details void -opengl_dlgeometrybank::create_( geometry_handle const &Geometry ) { +opengl_dlgeometrybank::create_( gfx::geometry_handle const &Geometry ) { m_chunkrecords.emplace_back( chunk_record() ); } // replace() subclass details void -opengl_dlgeometrybank::replace_( geometry_handle const &Geometry ) { +opengl_dlgeometrybank::replace_( gfx::geometry_handle const &Geometry ) { delete_list( Geometry ); } // draw() subclass details void -opengl_dlgeometrybank::draw_( geometry_handle const &Geometry, stream_units const &Units, unsigned int const Streams ) { +opengl_dlgeometrybank::draw_( gfx::geometry_handle const &Geometry, gfx::stream_units const &Units, unsigned int const Streams ) { auto &chunkrecord = m_chunkrecords[ Geometry.chunk - 1 ]; if( chunkrecord.streams != Streams ) { @@ -336,15 +338,15 @@ opengl_dlgeometrybank::draw_( geometry_handle const &Geometry, stream_units cons // we don't have a list ready, so compile one chunkrecord.streams = Streams; chunkrecord.list = ::glGenLists( 1 ); - auto const &chunk = geometry_bank::chunk( Geometry ); + auto const &chunk = gfx::geometry_bank::chunk( Geometry ); ::glNewList( chunkrecord.list, GL_COMPILE ); ::glBegin( chunk.type ); for( auto const &vertex : chunk.vertices ) { - if( Streams & stream::normal ) { ::glNormal3fv( glm::value_ptr( vertex.normal ) ); } - else if( Streams & stream::color ) { ::glColor3fv( glm::value_ptr( vertex.normal ) ); } - if( Streams & stream::texture ) { for( auto unit : Units.texture ) { ::glMultiTexCoord2fv( unit, glm::value_ptr( vertex.texture ) ); } } - if( Streams & stream::position ) { ::glVertex3fv( glm::value_ptr( vertex.position ) ); } + if( Streams & gfx::stream::normal ) { ::glNormal3fv( glm::value_ptr( vertex.normal ) ); } + else if( Streams & gfx::stream::color ) { ::glColor3fv( glm::value_ptr( vertex.normal ) ); } + if( Streams & gfx::stream::texture ) { for( auto unit : Units.texture ) { ::glMultiTexCoord2fv( unit, glm::value_ptr( vertex.texture ) ); } } + if( Streams & gfx::stream::position ) { ::glVertex3fv( glm::value_ptr( vertex.position ) ); } } ::glEnd(); ::glEndList(); @@ -362,19 +364,19 @@ opengl_dlgeometrybank::release_() { ::glDeleteLists( chunkrecord.list, 1 ); chunkrecord.list = 0; } - chunkrecord.streams = stream::none; + chunkrecord.streams = gfx::stream::none; } } void -opengl_dlgeometrybank::delete_list( geometry_handle const &Geometry ) { +opengl_dlgeometrybank::delete_list( gfx::geometry_handle const &Geometry ) { // NOTE: given it's our own internal method we trust it to be called with valid parameters auto &chunkrecord = m_chunkrecords[ Geometry.chunk - 1 ]; if( chunkrecord.list != 0 ) { ::glDeleteLists( chunkrecord.list, 1 ); chunkrecord.list = 0; } - chunkrecord.streams = stream::none; + chunkrecord.streams = gfx::stream::none; } // geometry bank manager, holds collection of geometry banks @@ -387,41 +389,41 @@ geometrybank_manager::update() { } // creates a new geometry bank. returns: handle to the bank or NULL -geometrybank_handle +gfx::geometrybank_handle geometrybank_manager::create_bank() { if( true == Global::bUseVBO ) { m_geometrybanks.emplace_back( std::make_shared(), std::chrono::steady_clock::time_point() ); } else { m_geometrybanks.emplace_back( std::make_shared(), std::chrono::steady_clock::time_point() ); } // NOTE: handle is effectively (index into chunk array + 1) this leaves value of 0 to serve as error/empty handle indication - return geometrybank_handle( m_geometrybanks.size(), 0 ); + return { m_geometrybanks.size(), 0 }; } // creates a new geometry chunk of specified type from supplied vertex data, in specified bank. returns: handle to the chunk or NULL -geometry_handle -geometrybank_manager::create_chunk( vertex_array &Vertices, geometrybank_handle const &Geometry, int const Type ) { +gfx::geometry_handle +geometrybank_manager::create_chunk( gfx::vertex_array &Vertices, gfx::geometrybank_handle const &Geometry, int const Type ) { auto const newchunkhandle = bank( Geometry ).first->create( Vertices, Type ); - if( newchunkhandle.chunk != 0 ) { return geometry_handle( Geometry.bank, newchunkhandle.chunk ); } - else { return geometry_handle( 0, 0 ); } + if( newchunkhandle.chunk != 0 ) { return { Geometry.bank, newchunkhandle.chunk }; } + else { return { 0, 0 }; } } // replaces data of specified chunk with the supplied vertex data, starting from specified offset bool -geometrybank_manager::replace( vertex_array &Vertices, geometry_handle const &Geometry, std::size_t const Offset ) { +geometrybank_manager::replace( gfx::vertex_array &Vertices, gfx::geometry_handle const &Geometry, std::size_t const Offset ) { return bank( Geometry ).first->replace( Vertices, Geometry, Offset ); } // adds supplied vertex data at the end of specified chunk bool -geometrybank_manager::append( vertex_array &Vertices, geometry_handle const &Geometry ) { +geometrybank_manager::append( gfx::vertex_array &Vertices, gfx::geometry_handle const &Geometry ) { return bank( Geometry ).first->append( Vertices, Geometry ); } // draws geometry stored in specified chunk void -geometrybank_manager::draw( geometry_handle const &Geometry, unsigned int const Streams ) { +geometrybank_manager::draw( gfx::geometry_handle const &Geometry, unsigned int const Streams ) { if( Geometry == null_handle ) { return; } @@ -432,8 +434,10 @@ geometrybank_manager::draw( geometry_handle const &Geometry, unsigned int const } // provides direct access to vertex data of specfied chunk -vertex_array const & -geometrybank_manager::vertices( geometry_handle const &Geometry ) const { +gfx::vertex_array const & +geometrybank_manager::vertices( gfx::geometry_handle const &Geometry ) const { return bank( Geometry ).first->vertices( Geometry ); } + +} // namespace gfx diff --git a/openglgeometrybank.h b/openglgeometrybank.h index a13f803e..00b9cd8a 100644 --- a/openglgeometrybank.h +++ b/openglgeometrybank.h @@ -18,6 +18,8 @@ http://mozilla.org/MPL/2.0/. #endif #include "ResourceManager.h" +namespace gfx { + struct basic_vertex { glm::vec3 position; // 3d space @@ -93,36 +95,36 @@ public: // methods: // creates a new geometry chunk of specified type from supplied vertex data. returns: handle to the chunk or NULL - geometry_handle - create( vertex_array &Vertices, unsigned int const Type ); + gfx::geometry_handle + create( gfx::vertex_array &Vertices, unsigned int const Type ); // replaces data of specified chunk with the supplied vertex data, starting from specified offset bool - replace( vertex_array &Vertices, geometry_handle const &Geometry, std::size_t const Offset = 0 ); + replace( gfx::vertex_array &Vertices, gfx::geometry_handle const &Geometry, std::size_t const Offset = 0 ); // adds supplied vertex data at the end of specified chunk bool - append( vertex_array &Vertices, geometry_handle const &Geometry ); + append( gfx::vertex_array &Vertices, gfx::geometry_handle const &Geometry ); // draws geometry stored in specified chunk void - draw( geometry_handle const &Geometry, stream_units const &Units, unsigned int const Streams = basic_streams ); + draw( gfx::geometry_handle const &Geometry, gfx::stream_units const &Units, unsigned int const Streams = basic_streams ); // draws geometry stored in supplied list of chunks template void - draw( Iterator_ First, Iterator_ Last, stream_units const &Units, unsigned int const Streams = basic_streams ) { while( First != Last ) { draw( *First, Units, Streams ); ++First; } } + draw( Iterator_ First, Iterator_ Last, gfx::stream_units const &Units, unsigned int const Streams = basic_streams ) { while( First != Last ) { draw( *First, Units, Streams ); ++First; } } // frees subclass-specific resources associated with the bank, typically called when the bank wasn't in use for a period of time void release(); // provides direct access to vertex data of specfied chunk - vertex_array const & - vertices( geometry_handle const &Geometry ) const; + gfx::vertex_array const & + vertices( gfx::geometry_handle const &Geometry ) const; protected: // types: struct geometry_chunk { unsigned int type; // kind of geometry used by the chunk - vertex_array vertices; // geometry data + gfx::vertex_array vertices; // geometry data // NOTE: constructor doesn't copy provided vertex data, but moves it - geometry_chunk( vertex_array &Vertices, unsigned int Type ) : - type( Type ) + geometry_chunk( gfx::vertex_array &Vertices, unsigned int Type ) : + type( Type ) { vertices.swap( Vertices ); } @@ -133,11 +135,11 @@ protected: // methods inline geometry_chunk & - chunk( geometry_handle const Geometry ) { + chunk( gfx::geometry_handle const Geometry ) { return m_chunks[ Geometry.chunk - 1 ]; } inline geometry_chunk const & - chunk( geometry_handle const Geometry ) const { + chunk( gfx::geometry_handle const Geometry ) const { return m_chunks[ Geometry.chunk - 1 ]; } // members: @@ -146,11 +148,11 @@ protected: private: // methods: // create() subclass details - virtual void create_( geometry_handle const &Geometry ) = 0; + virtual void create_( gfx::geometry_handle const &Geometry ) = 0; // replace() subclass details - virtual void replace_( geometry_handle const &Geometry ) = 0; + virtual void replace_( gfx::geometry_handle const &Geometry ) = 0; // draw() subclass details - virtual void draw_( geometry_handle const &Geometry, stream_units const &Units, unsigned int const Streams ) = 0; + virtual void draw_( gfx::geometry_handle const &Geometry, gfx::stream_units const &Units, unsigned int const Streams ) = 0; // resource release subclass details virtual void release_() = 0; }; @@ -170,7 +172,7 @@ public: void reset() { m_activebuffer = 0; - m_activestreams = stream::none; } + m_activestreams = gfx::stream::none; } private: // types: @@ -185,13 +187,13 @@ private: // methods: // create() subclass details void - create_( geometry_handle const &Geometry ); + create_( gfx::geometry_handle const &Geometry ); // replace() subclass details void - replace_( geometry_handle const &Geometry ); + replace_( gfx::geometry_handle const &Geometry ); // draw() subclass details void - draw_( geometry_handle const &Geometry, stream_units const &Units, unsigned int const Streams ); + draw_( gfx::geometry_handle const &Geometry, gfx::stream_units const &Units, unsigned int const Streams ); // release() subclass details void release_(); @@ -201,7 +203,7 @@ private: delete_buffer(); static void - bind_streams( stream_units const &Units, unsigned int const Streams ); + bind_streams( gfx::stream_units const &Units, unsigned int const Streams ); static void release_streams(); @@ -240,18 +242,18 @@ private: // methods: // create() subclass details void - create_( geometry_handle const &Geometry ); + create_( gfx::geometry_handle const &Geometry ); // replace() subclass details void - replace_( geometry_handle const &Geometry ); + replace_( gfx::geometry_handle const &Geometry ); // draw() subclass details void - draw_( geometry_handle const &Geometry, stream_units const &Units, unsigned int const Streams ); + draw_( gfx::geometry_handle const &Geometry, gfx::stream_units const &Units, unsigned int const Streams ); // release () subclass details void release_(); void - delete_list( geometry_handle const &Geometry ); + delete_list( gfx::geometry_handle const &Geometry ); // members: chunkrecord_sequence m_chunkrecords; // helper data for all stored geometry chunks, in matching order @@ -269,20 +271,20 @@ public: // performs a resource sweep void update(); // creates a new geometry bank. returns: handle to the bank or NULL - geometrybank_handle + gfx::geometrybank_handle create_bank(); // creates a new geometry chunk of specified type from supplied vertex data, in specified bank. returns: handle to the chunk or NULL - geometry_handle - create_chunk( vertex_array &Vertices, geometrybank_handle const &Geometry, int const Type ); + gfx::geometry_handle + create_chunk( gfx::vertex_array &Vertices, gfx::geometrybank_handle const &Geometry, int const Type ); // replaces data of specified chunk with the supplied vertex data, starting from specified offset bool - replace( vertex_array &Vertices, geometry_handle const &Geometry, std::size_t const Offset = 0 ); + replace( gfx::vertex_array &Vertices, gfx::geometry_handle const &Geometry, std::size_t const Offset = 0 ); // adds supplied vertex data at the end of specified chunk bool - append( vertex_array &Vertices, geometry_handle const &Geometry ); + append( gfx::vertex_array &Vertices, gfx::geometry_handle const &Geometry ); // draws geometry stored in specified chunk void - draw( geometry_handle const &Geometry, unsigned int const Streams = basic_streams ); + draw( gfx::geometry_handle const &Geometry, unsigned int const Streams = basic_streams ); template void draw( Iterator_ First, Iterator_ Last, unsigned int const Streams = basic_streams ) { @@ -290,10 +292,10 @@ public: draw( *First, Streams ); ++First; } } // provides direct access to vertex data of specfied chunk - vertex_array const & - vertices( geometry_handle const &Geometry ) const; + gfx::vertex_array const & + vertices( gfx::geometry_handle const &Geometry ) const; // sets target texture unit for the texture data stream - stream_units & + gfx::stream_units & units() { return m_units; } private: @@ -307,21 +309,23 @@ private: // members: geometrybanktimepointpair_sequence m_geometrybanks; garbage_collector m_garbagecollector { m_geometrybanks, 60, 120, "geometry buffer" }; - stream_units m_units; + gfx::stream_units m_units; // methods inline bool - valid( geometry_handle const &Geometry ) const { + valid( gfx::geometry_handle const &Geometry ) const { return ( ( Geometry.bank != 0 ) && ( Geometry.bank <= m_geometrybanks.size() ) ); } inline geometrybanktimepointpair_sequence::value_type & - bank( geometry_handle const Geometry ) { + bank( gfx::geometry_handle const Geometry ) { return m_geometrybanks[ Geometry.bank - 1 ]; } inline geometrybanktimepointpair_sequence::value_type const & - bank( geometry_handle const Geometry ) const { + bank( gfx::geometry_handle const Geometry ) const { return m_geometrybanks[ Geometry.bank - 1 ]; } -}; \ No newline at end of file +}; + +} // namespace gfx \ No newline at end of file diff --git a/renderer.cpp b/renderer.cpp index 7d33fc32..8aae4da8 100644 --- a/renderer.cpp +++ b/renderer.cpp @@ -298,7 +298,7 @@ opengl_renderer::Init( GLFWwindow *Window ) { auto const geometrybank = m_geometry.create_bank(); float const size = 2.5f; m_billboardgeometry = m_geometry.create_chunk( - vertex_array{ + gfx::vertex_array{ { { -size, size, 0.f }, glm::vec3(), { 1.f, 1.f } }, { { size, size, 0.f }, glm::vec3(), { 0.f, 1.f } }, { { -size, -size, 0.f }, glm::vec3(), { 1.f, 0.f } }, @@ -1129,7 +1129,7 @@ opengl_renderer::Render( world_environment *Environment ) { Environment->m_skydome.Render(); if( true == Global::bUseVBO ) { // skydome uses a custom vbo which could potentially confuse the main geometry system. hardly elegant but, eh - opengl_vbogeometrybank::reset(); + gfx::opengl_vbogeometrybank::reset(); } // stars if( Environment->m_stars.m_stars != nullptr ) { @@ -1263,36 +1263,36 @@ opengl_renderer::Render( world_environment *Environment ) { // geometry methods // creates a new geometry bank. returns: handle to the bank or NULL -geometrybank_handle +gfx::geometrybank_handle opengl_renderer::Create_Bank() { return m_geometry.create_bank(); } // creates a new geometry chunk of specified type from supplied vertex data, in specified bank. returns: handle to the chunk or NULL -geometry_handle -opengl_renderer::Insert( vertex_array &Vertices, geometrybank_handle const &Geometry, int const Type ) { +gfx::geometry_handle +opengl_renderer::Insert( gfx::vertex_array &Vertices, gfx::geometrybank_handle const &Geometry, int const Type ) { return m_geometry.create_chunk( Vertices, Geometry, Type ); } // replaces data of specified chunk with the supplied vertex data, starting from specified offset bool -opengl_renderer::Replace( vertex_array &Vertices, geometry_handle const &Geometry, std::size_t const Offset ) { +opengl_renderer::Replace( gfx::vertex_array &Vertices, gfx::geometry_handle const &Geometry, std::size_t const Offset ) { return m_geometry.replace( Vertices, Geometry, Offset ); } // adds supplied vertex data at the end of specified chunk bool -opengl_renderer::Append( vertex_array &Vertices, geometry_handle const &Geometry ) { +opengl_renderer::Append( gfx::vertex_array &Vertices, gfx::geometry_handle const &Geometry ) { return m_geometry.append( Vertices, Geometry ); } // provides direct access to vertex data of specfied chunk -vertex_array const & -opengl_renderer::Vertices( geometry_handle const &Geometry ) const { +gfx::vertex_array const & +opengl_renderer::Vertices( gfx::geometry_handle const &Geometry ) const { return m_geometry.vertices( Geometry ); } @@ -2262,7 +2262,7 @@ opengl_renderer::Render( TSubModel *Submodel ) { ::glDisable( GL_LIGHTING ); // main draw call - m_geometry.draw( Submodel->m_geometry, color_streams ); + m_geometry.draw( Submodel->m_geometry, gfx::color_streams ); // post-draw reset ::glPopAttrib(); diff --git a/renderer.h b/renderer.h index cdf91132..e8582afc 100644 --- a/renderer.h +++ b/renderer.h @@ -156,20 +156,20 @@ public: // geometry methods // NOTE: hands-on geometry management is exposed as a temporary measure; ultimately all visualization data should be generated/handled automatically by the renderer itself // creates a new geometry bank. returns: handle to the bank or NULL - geometrybank_handle + gfx::geometrybank_handle Create_Bank(); // creates a new geometry chunk of specified type from supplied vertex data, in specified bank. returns: handle to the chunk or NULL - geometry_handle - Insert( vertex_array &Vertices, geometrybank_handle const &Geometry, int const Type ); + gfx::geometry_handle + Insert( gfx::vertex_array &Vertices, gfx::geometrybank_handle const &Geometry, int const Type ); // replaces data of specified chunk with the supplied vertex data, starting from specified offset bool - Replace( vertex_array &Vertices, geometry_handle const &Geometry, std::size_t const Offset = 0 ); + Replace( gfx::vertex_array &Vertices, gfx::geometry_handle const &Geometry, std::size_t const Offset = 0 ); // adds supplied vertex data at the end of specified chunk bool - Append( vertex_array &Vertices, geometry_handle const &Geometry ); + Append( gfx::vertex_array &Vertices, gfx::geometry_handle const &Geometry ); // provides direct access to vertex data of specfied chunk - vertex_array const & - Vertices( geometry_handle const &Geometry ) const; + gfx::vertex_array const & + Vertices( gfx::geometry_handle const &Geometry ) const; // material methods material_handle Fetch_Material( std::string const &Filename, bool const Loadnow = true ); @@ -337,12 +337,12 @@ private: // members GLFWwindow *m_window { nullptr }; - geometrybank_manager m_geometry; + gfx::geometrybank_manager m_geometry; material_manager m_materials; texture_manager m_textures; opengllight_array m_lights; - geometry_handle m_billboardgeometry { 0, 0 }; + gfx::geometry_handle m_billboardgeometry { 0, 0 }; texture_handle m_glaretexture { -1 }; texture_handle m_suntexture { -1 }; texture_handle m_moontexture { -1 }; diff --git a/scene.cpp b/scene.cpp index 33e6cd43..22bda992 100644 --- a/scene.cpp +++ b/scene.cpp @@ -125,11 +125,13 @@ basic_cell::update_sounds() { // sounds auto const deltatime = Timer::GetDeltaRenderTime(); for( auto *sound : m_sounds ) { - +#ifdef EU07_USE_OLD_SOUNDCODE if( ( sound->GetStatus() & DSBSTATUS_PLAYING ) == DSBPLAY_LOOPING ) { sound->Play( 1, DSBPLAY_LOOPING, true, sound->vSoundPosition ); sound->AdjFreq( 1.0, deltatime ); } +#else +#endif } // TBD, TODO: move to sound renderer for( auto *path : m_paths ) { @@ -348,7 +350,11 @@ basic_cell::insert( TAnimModel *Instance ) { // adds provided sound instance to the cell void +#ifdef EU07_USE_OLD_SOUNDCODE basic_cell::insert( TTextSound *Sound ) { +#else +basic_cell::insert( sound_source *Sound ) { +#endif m_active = true; @@ -514,7 +520,7 @@ basic_cell::center( glm::dvec3 Center ) { // generates renderable version of held non-instanced geometry void -basic_cell::create_geometry( geometrybank_handle const &Bank ) { +basic_cell::create_geometry( gfx::geometrybank_handle const &Bank ) { if( false == m_active ) { return; } // nothing to do here @@ -1171,8 +1177,13 @@ basic_region::insert_instance( TAnimModel *Instance, scratch_data &Scratchpad ) // inserts provided sound in the region void +#ifdef EU07_USE_OLD_SOUNDCODE basic_region::insert_sound( TTextSound *Sound, scratch_data &Scratchpad ) { +#else +basic_region::insert_sound( sound_source *Sound, scratch_data &Scratchpad ) { +#endif +#ifdef EU07_USE_OLD_SOUNDCODE // NOTE: bounding area isn't present/filled until track class and wrapper refactoring is done auto location = Sound->location(); @@ -1184,6 +1195,8 @@ basic_region::insert_sound( TTextSound *Sound, scratch_data &Scratchpad ) { // tracks are guaranteed to hava a name so we can skip the check ErrorLog( "Bad scenario: sound node \"" + Sound->name() + "\" placed in location outside region bounds (" + to_string( location ) + ")" ); } +#else +#endif } // inserts provided event launcher in the region diff --git a/scene.h b/scene.h index d4b1853d..ce1db91f 100644 --- a/scene.h +++ b/scene.h @@ -20,6 +20,7 @@ http://mozilla.org/MPL/2.0/. #include "scenenode.h" #include "track.h" #include "traction.h" +#include "sound.h" namespace scene { @@ -104,7 +105,11 @@ public: insert( TAnimModel *Instance ); // adds provided sound instance to the cell void +#ifdef EU07_USE_OLD_SOUNDCODE insert( TTextSound *Sound ); +#else + insert( sound_source *Sound ); +#endif // adds provided event launcher to the cell void insert( TEventLauncher *Launcher ); @@ -131,7 +136,7 @@ public: center( glm::dvec3 Center ); // generates renderable version of held non-instanced geometry in specified geometry bank void - create_geometry( geometrybank_handle const &Bank ); + create_geometry( gfx::geometrybank_handle const &Bank ); // provides access to bounding area data bounding_area const & area() const { @@ -144,7 +149,11 @@ private: using path_sequence = std::vector; using traction_sequence = std::vector; using instance_sequence = std::vector; +#ifdef EU07_USE_OLD_SOUNDCODE using sound_sequence = std::vector; +#else + using sound_sequence = std::vector; +#endif using eventlauncher_sequence = std::vector; // methods void @@ -258,7 +267,7 @@ private: shapenode_sequence m_shapes; // large pieces of opaque geometry and (legacy) terrain // TODO: implement dedicated, higher fidelity, fixed resolution terrain mesh item // gfx renderer data - geometrybank_handle m_geometrybank; + gfx::geometrybank_handle m_geometrybank; bool m_geometrycreated { false }; }; @@ -311,7 +320,11 @@ public: insert_instance( TAnimModel *Instance, scratch_data &Scratchpad ); // inserts provided sound in the region void +#ifdef EU07_USE_OLD_SOUNDCODE insert_sound( TTextSound *Sound, scratch_data &Scratchpad ); +#else + insert_sound( sound_source *Sound, scratch_data &Scratchpad ); +#endif // inserts provided event launcher in the region void insert_launcher( TEventLauncher *Launcher, scratch_data &Scratchpad ); diff --git a/scenenode.cpp b/scenenode.cpp index 97c00424..4ebd51fe 100644 --- a/scenenode.cpp +++ b/scenenode.cpp @@ -80,7 +80,7 @@ shape_node::shapenode_data::serialize( std::ostream &Output ) const { // vertex count, followed by vertex data sn_utils::ls_uint32( Output, vertices.size() ); for( auto const &vertex : vertices ) { - basic_vertex( + gfx::basic_vertex( glm::vec3{ vertex.position - origin }, vertex.normal, vertex.texture ) @@ -109,7 +109,7 @@ shape_node::shapenode_data::deserialize( std::istream &Input ) { // NOTE: geometry handle is acquired during geometry creation // vertex data vertices.resize( sn_utils::ld_uint32( Input ) ); - basic_vertex localvertex; + gfx::basic_vertex localvertex; for( auto &vertex : vertices ) { localvertex.deserialize( Input ); vertex.position = origin + glm::dvec3{ localvertex.position }; @@ -417,9 +417,9 @@ shape_node::merge( shape_node &Shape ) { // generates renderable version of held non-instanced geometry in specified geometry bank void -shape_node::create_geometry( geometrybank_handle const &Bank ) { +shape_node::create_geometry( gfx::geometrybank_handle const &Bank ) { - vertex_array vertices; vertices.reserve( m_data.vertices.size() ); + gfx::vertex_array vertices; vertices.reserve( m_data.vertices.size() ); for( auto const &vertex : m_data.vertices ) { vertices.emplace_back( @@ -464,7 +464,7 @@ lines_node::linesnode_data::serialize( std::ostream &Output ) const { // vertex count, followed by vertex data sn_utils::ls_uint32( Output, vertices.size() ); for( auto const &vertex : vertices ) { - basic_vertex( + gfx::basic_vertex( glm::vec3{ vertex.position - origin }, vertex.normal, vertex.texture ) @@ -489,7 +489,7 @@ lines_node::linesnode_data::deserialize( std::istream &Input ) { // NOTE: geometry handle is acquired during geometry creation // vertex data vertices.resize( sn_utils::ld_uint32( Input ) ); - basic_vertex localvertex; + gfx::basic_vertex localvertex; for( auto &vertex : vertices ) { localvertex.deserialize( Input ); vertex.position = origin + glm::dvec3{ localvertex.position }; @@ -637,9 +637,9 @@ lines_node::merge( lines_node &Lines ) { // generates renderable version of held non-instanced geometry in specified geometry bank void -lines_node::create_geometry( geometrybank_handle const &Bank ) { +lines_node::create_geometry( gfx::geometrybank_handle const &Bank ) { - vertex_array vertices; vertices.reserve( m_data.vertices.size() ); + gfx::vertex_array vertices; vertices.reserve( m_data.vertices.size() ); for( auto const &vertex : m_data.vertices ) { vertices.emplace_back( diff --git a/scenenode.h b/scenenode.h index 7c2c7988..df7c6f64 100644 --- a/scenenode.h +++ b/scenenode.h @@ -93,7 +93,7 @@ public: lighting_data lighting; // geometry data glm::dvec3 origin; // world position of the relative coordinate system origin - geometry_handle geometry { 0, 0 }; // relative origin-centered chunk of geometry held by gfx renderer + gfx::geometry_handle geometry { 0, 0 }; // relative origin-centered chunk of geometry held by gfx renderer std::vector vertices; // world space source data of the geometry // methods: // sends content of the struct to provided stream @@ -122,7 +122,7 @@ public: merge( shape_node &Shape ); // generates renderable version of held non-instanced geometry in specified geometry bank void - create_geometry( geometrybank_handle const &Bank ); + create_geometry( gfx::geometrybank_handle const &Bank ); // calculates shape's bounding radius void compute_radius(); @@ -182,7 +182,7 @@ public: lighting_data lighting; // geometry data glm::dvec3 origin; // world position of the relative coordinate system origin - geometry_handle geometry { 0, 0 }; // relative origin-centered chunk of geometry held by gfx renderer + gfx::geometry_handle geometry { 0, 0 }; // relative origin-centered chunk of geometry held by gfx renderer std::vector vertices; // world space source data of the geometry // methods: // sends content of the struct to provided stream @@ -208,7 +208,7 @@ public: merge( lines_node &Lines ); // generates renderable version of held non-instanced geometry in specified geometry bank void - create_geometry( geometrybank_handle const &Bank ); + create_geometry( gfx::geometrybank_handle const &Bank ); // calculates shape's bounding radius void compute_radius(); diff --git a/simulation.cpp b/simulation.cpp index 9a100dd4..cd176f5f 100644 --- a/simulation.cpp +++ b/simulation.cpp @@ -460,7 +460,10 @@ state_manager::deserialize_node( cParser &Input, scene::scratch_data &Scratchpad auto *sound { deserialize_sound( Input, Scratchpad, nodedata ) }; if( false == simulation::Sounds.insert( sound ) ) { +#ifdef EU07_USE_OLD_SOUNDCODE ErrorLog( "Bad scenario: sound node with duplicate name \"" + sound->m_name + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" ); +#else +#endif } simulation::Region->insert_sound( sound, Scratchpad ); } @@ -830,7 +833,11 @@ state_manager::deserialize_dynamic( cParser &Input, scene::scratch_data &Scratch return vehicle; } +#ifdef EU07_USE_OLD_SOUNDCODE TTextSound * +#else +sound_source * +#endif state_manager::deserialize_sound( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ) { glm::dvec3 location; @@ -842,9 +849,14 @@ state_manager::deserialize_sound( cParser &Input, scene::scratch_data &Scratchpa // adjust location location = transform( location, Scratchpad ); +#ifdef EU07_USE_OLD_SOUNDCODE auto const soundname { Input.getToken() }; 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(); + sound->deserialize( Input.getToken(), sound_type::single ); +#endif skip_until( Input, "endsound" ); diff --git a/simulation.h b/simulation.h index 862f8445..ceceb2ac 100644 --- a/simulation.h +++ b/simulation.h @@ -17,7 +17,7 @@ http://mozilla.org/MPL/2.0/. #include "track.h" #include "traction.h" #include "tractionpower.h" -#include "realsound.h" +#include "sound.h" #include "animmodel.h" #include "dynobj.h" #include "driver.h" @@ -64,7 +64,11 @@ private: TEventLauncher * deserialize_eventlauncher( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ); TAnimModel * deserialize_model( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ); TDynamicObject * deserialize_dynamic( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ); +#ifdef EU07_USE_OLD_SOUNDCODE TTextSound * deserialize_sound( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ); +#else + sound_source * deserialize_sound( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ); +#endif // skips content of stream until specified token void skip_until( cParser &Input, std::string const &Token ); // transforms provided location by specifed rotation and offset diff --git a/sound.cpp b/sound.cpp new file mode 100644 index 00000000..519b51e1 --- /dev/null +++ b/sound.cpp @@ -0,0 +1,66 @@ +/* +This Source Code Form is subject to the +terms of the Mozilla Public License, v. +2.0. If a copy of the MPL was not +distributed with this file, You can +obtain one at +http://mozilla.org/MPL/2.0/. +*/ + +#include "stdafx.h" + +#include "sound.h" + +// restores state of the class from provided data stream +sound_source & +sound_source::deserialize( std::string const &Input, sound_type const Legacytype, int const Legacyparameters ) { + + return deserialize( cParser{ Input }, Legacytype, Legacyparameters ); +} + +sound_source & +sound_source::deserialize( cParser &Input, sound_type const Legacytype, int const Legacyparameters ) { + + // TODO: implement block type config parsing + switch( Legacytype ) { + case sound_type::single: { + // single sample only + Input.getTokens( 1, true, "\n\r\t ,;" ); + break; + } + case sound_type::multipart: { + // three samples: start, middle, stop + Input.getTokens( 3, true, "\n\r\t ,;" ); + break; + } + default: { + break; + } + } + + if( Legacyparameters & sound_parameters::range ) { + Input.getTokens( 1, false ); + } + if( Legacyparameters & sound_parameters::amplitude ) { + Input.getTokens( 2, false ); + } + if( Legacyparameters & sound_parameters::frequency ) { + Input.getTokens( 2, false ); + } + + return *this; +} + +// issues contextual play commands for the audio renderer +void +sound_source::play() { + +} + +bool +sound_source::empty() const { + + return true; +} + +//--------------------------------------------------------------------------- diff --git a/sound.h b/sound.h new file mode 100644 index 00000000..877c5491 --- /dev/null +++ b/sound.h @@ -0,0 +1,69 @@ +/* +This Source Code Form is subject to the +terms of the Mozilla Public License, v. +2.0. If a copy of the MPL was not +distributed with this file, You can +obtain one at +http://mozilla.org/MPL/2.0/. +*/ + +#pragma once + +#include "audiorenderer.h" +#include "parser.h" +#include "names.h" + +enum sound_type { + single, + multipart +}; + +enum sound_parameters { + none, + range = 0x1, + amplitude = 0x2, + frequency = 0x4 +}; + +// mini controller and audio dispatcher; issues play commands for the audio renderer, +// updates parameters of assigned audio sources for the playback duration +// TODO: move to simulation namespace after clean up of owner classes +class sound_source { + +public: +// methods + // restores state of the class from provided data stream + sound_source & + deserialize( cParser &Input, sound_type const Legacytype, int const Legacyparameters = sound_parameters::none ); + sound_source & + deserialize( std::string const &Input, sound_type const Legacytype, int const Legacyparameters = sound_parameters::none ); + // issues contextual play commands for the audio renderer + void + play(); + // sets volume of audio streams associated with this source + sound_source & + volume( float const Volume ); + // sound source name setter/getter + void + name( std::string Name ); + std::string const & + name() const; + // returns true if there isn't any sound buffer associated with the object, false otherwise + bool + empty() const; + +private: +// members + std::string m_name; +}; + +// 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 +class sound_table : public basic_table { + +}; + +//--------------------------------------------------------------------------- From 7fc1256b467a8b8595b6a9828d0e6943348ff75b Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Sun, 12 Nov 2017 20:02:36 +0100 Subject: [PATCH 3/8] partial shadow stabilization, support for vehicle type-specific load models --- DynObj.cpp | 10 ++++++++-- renderer.cpp | 40 +++++++++++++++++++++++++++++++++------- renderer.h | 2 +- version.h | 2 +- 4 files changed, 43 insertions(+), 11 deletions(-) diff --git a/DynObj.cpp b/DynObj.cpp index 574db0c0..ad105306 100644 --- a/DynObj.cpp +++ b/DynObj.cpp @@ -1924,7 +1924,8 @@ TDynamicObject::Init(std::string Name, // nazwa pojazdu, np. "EU07-424" 0.0f ); } ++compartmentindex; - } while( submodel != nullptr ); + } while( ( submodel != nullptr ) + || ( compartmentindex < 2 ) ); // chain can start from prefix00 or prefix01 } } // wyszukiwanie zderzakow @@ -4004,7 +4005,12 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName, else { // Ra: tu wczytywanie modelu ładunku jest w porządku if( false == asLoadName.empty() ) { - mdLoad = TModelsManager::GetModel( asLoadName, true ); // ladunek + // try first specialized version of the load model, vehiclename_loadname + mdLoad = TModelsManager::GetModel( BaseDir + TypeName + "_" + MoverParameters->LoadType + ".t3d", true ); + if( mdLoad == nullptr ) { + // if this fails, try generic load model + mdLoad = TModelsManager::GetModel( asLoadName, true ); + } } } } diff --git a/renderer.cpp b/renderer.cpp index 8aae4da8..e3254003 100644 --- a/renderer.cpp +++ b/renderer.cpp @@ -484,7 +484,7 @@ opengl_renderer::Render_pass( rendermode const Mode ) { ::glEnable( GL_SCISSOR_TEST ); setup_matrices(); ::glEnable( GL_POLYGON_OFFSET_FILL ); // alleviate depth-fighting - ::glPolygonOffset( 2.f, 2.f ); + ::glPolygonOffset( 1.f, 1.f ); // render // opaque parts... setup_drawing( false ); @@ -663,6 +663,7 @@ opengl_renderer::setup_pass( renderpass_config &Config, rendermode const Mode, f } case rendermode::shadows: { + // calculate lightview boundaries based on relevant area of the world camera frustum: // ...setup chunk of frustum we're interested in... auto const znear = 0.f; @@ -695,18 +696,43 @@ opengl_renderer::setup_pass( renderpass_config &Config, rendermode const Mode, f point = lightviewmatrix * point; } bounding_box( frustumchunkmin, frustumchunkmax, std::begin( frustumchunkshapepoints ), std::end( frustumchunkshapepoints ) ); - // ...use the dimensions to set up light projection boundaries + // quantize the frustum points with 50 m resolution, to reduce shadow shimmer on scale/orientation changes + frustumchunkmin = 50.f * glm::floor( frustumchunkmin * ( 1.f / 50.f ) ); + frustumchunkmax = 50.f * glm::ceil( frustumchunkmax * ( 1.f / 50.f ) ); + // ...use the dimensions to set up light projection boundaries... // NOTE: since we only have one cascade map stage, we extend the chunk forward/back to catch areas normally covered by other stages - auto const quantizationstep = ( Global::shadowtune.depth + 1000.f ) / m_shadowbuffersize; - frustumchunkmin.x -= std::remainder( frustumchunkmin.x, quantizationstep ); - frustumchunkmin.y -= std::remainder( frustumchunkmin.y, quantizationstep ); - frustumchunkmax.x -= std::remainder( frustumchunkmax.x, quantizationstep ); - frustumchunkmax.y -= std::remainder( frustumchunkmax.y, quantizationstep ); camera.projection() *= glm::ortho( frustumchunkmin.x, frustumchunkmax.x, frustumchunkmin.y, frustumchunkmax.y, frustumchunkmin.z - 500.f, frustumchunkmax.z + 500.f ); +/* + // fixed ortho projection from old build, for quick quality comparisons + camera.projection() *= + glm::ortho( + -Global::shadowtune.width, Global::shadowtune.width, + -Global::shadowtune.width, Global::shadowtune.width, + -Global::shadowtune.depth, Global::shadowtune.depth ); + camera.position() = Global::pCameraPosition - glm::dvec3{ Global::DayLight.direction }; + if( camera.position().y - Global::pCameraPosition.y < 0.1 ) { + camera.position().y = Global::pCameraPosition.y + 0.1; + } + viewmatrix *= glm::lookAt( + camera.position(), + glm::dvec3{ Global::pCameraPosition }, + glm::dvec3{ 0.f, 1.f, 0.f } ); +*/ + // ... and adjust the projection to sample complete shadow map texels: + // get coordinates for a sample texel... + auto shadowmaptexel = glm::vec2 { camera.projection() * glm::mat4{ viewmatrix } * glm::vec4{ 0.f, 0.f, 0.f, 1.f } }; + // ...convert result from clip space to texture coordinates, and calculate adjustment... + shadowmaptexel *= m_shadowbuffersize * 0.5f; + auto shadowmapadjustment = glm::round( shadowmaptexel ) - shadowmaptexel; + // ...transform coordinate change back to homogenous light space... + shadowmapadjustment /= m_shadowbuffersize * 0.5f; + // ... and bake the adjustment into the projection matrix + camera.projection() = glm::translate( glm::mat4{ 1.f }, glm::vec3{ shadowmapadjustment, 0.f } ) * camera.projection(); + break; } case rendermode::reflections: { diff --git a/renderer.h b/renderer.h index e8582afc..e8613eb6 100644 --- a/renderer.h +++ b/renderer.h @@ -21,7 +21,7 @@ http://mozilla.org/MPL/2.0/. #define EU07_USE_PICKING_FRAMEBUFFER //#define EU07_USE_DEBUG_SHADOWMAP -//#define EU07_USE_DEBUG_CAMERA +#define EU07_USE_DEBUG_CAMERA //#define EU07_USE_DEBUG_CULLING struct opengl_light { diff --git a/version.h b/version.h index 9aaf2c1a..740b7596 100644 --- a/version.h +++ b/version.h @@ -1,5 +1,5 @@ #pragma once #define VERSION_MAJOR 17 -#define VERSION_MINOR 1102 +#define VERSION_MINOR 1112 #define VERSION_REVISION 0 From bc43c21174406883b07324a2ced50b8b344c96db Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Sun, 19 Nov 2017 16:02:12 +0100 Subject: [PATCH 4/8] audio subsystem: openal emitter, minor audio fixes --- Button.cpp | 1 + DynObj.cpp | 73 ++++++++++++++++++--- Globals.cpp | 32 +-------- Globals.h | 22 +------ McZapkie/MOVER.h | 22 +++---- ResourceManager.h | 7 ++ Texture.h | 3 +- Train.cpp | 66 +++++++------------ Train.h | 2 +- World.cpp | 25 +++---- World.h | 7 +- audio.cpp | 33 ++++++---- audio.h | 6 ++ audiorenderer.cpp | 132 ++++++++++++++++++++++++++++++++++++- audiorenderer.h | 76 +++++++++++++++++++++- maszyna.vcxproj.filters | 10 +-- openglgeometrybank.cpp | 2 +- openglgeometrybank.h | 2 +- renderer.cpp | 7 +- renderer.h | 2 +- simulation.cpp | 5 +- sound.cpp | 140 ++++++++++++++++++++++++++++++++++++++-- sound.h | 48 +++++++++++--- sun.cpp | 25 +++++-- 24 files changed, 566 insertions(+), 182 deletions(-) diff --git a/Button.cpp b/Button.cpp index 22cfe6c4..c7b501a4 100644 --- a/Button.cpp +++ b/Button.cpp @@ -46,6 +46,7 @@ void TButton::Load(cParser &Parser, TModel3d *pModel1, TModel3d *pModel2) { else { // new, block type config // TODO: rework the base part into yaml-compatible flow style mapping + submodelname = Parser.getToken( false ); while( true == Load_mapping( Parser ) ) { ; // all work done by while() } diff --git a/DynObj.cpp b/DynObj.cpp index ad105306..c1846335 100644 --- a/DynObj.cpp +++ b/DynObj.cpp @@ -3354,6 +3354,7 @@ bool TDynamicObject::Update(double dt, double dt1) #ifdef EU07_USE_OLD_SOUNDCODE rsDoorOpen.Play(1, 0, MechInside, vPosition); #else + rsDoorClose.stop(); rsDoorOpen.play(); #endif dDoorMoveL += dt1 * 0.5 * MoverParameters->DoorOpenSpeed; @@ -3363,6 +3364,7 @@ bool TDynamicObject::Update(double dt, double dt1) #ifdef EU07_USE_OLD_SOUNDCODE rsDoorClose.Play(1, 0, MechInside, vPosition); #else + rsDoorOpen.stop(); rsDoorClose.play(); #endif dDoorMoveL -= dt1 * MoverParameters->DoorCloseSpeed; @@ -3374,6 +3376,7 @@ bool TDynamicObject::Update(double dt, double dt1) #ifdef EU07_USE_OLD_SOUNDCODE rsDoorOpen.Play(1, 0, MechInside, vPosition); #else + rsDoorClose.stop(); rsDoorOpen.play(); #endif dDoorMoveR += dt1 * 0.5 * MoverParameters->DoorOpenSpeed; @@ -3383,6 +3386,7 @@ bool TDynamicObject::Update(double dt, double dt1) #ifdef EU07_USE_OLD_SOUNDCODE rsDoorClose.Play(1, 0, MechInside, vPosition); #else + rsDoorOpen.stop(); rsDoorClose.play(); #endif dDoorMoveR -= dt1 * MoverParameters->DoorCloseSpeed; @@ -3849,16 +3853,70 @@ void TDynamicObject::RenderSounds() { if (GetVelocity() == 0) rsDerailment.Stop(); } +#else +// McZapkie! - dzwiek compressor.wav tylko gdy dziala sprezarka +if( MoverParameters->VeselVolume != 0 ) { + + if( MoverParameters->TrainType != dt_PseudoDiesel ) { + // NBMX dzwiek przetwornicy + if( MoverParameters->ConverterFlag ) { + sConverter.play(); + } + else { + sConverter.stop(); + } + } + else { + } + + if( MoverParameters->CompressorFlag ) { + sCompressor.play(); + } + else { + sCompressor.stop(); + } + if( MoverParameters->PantCompFlag ) { + // Winger 160404 - dzwiek malej sprezarki + sSmallCompressor.play(); + } + else { + sSmallCompressor.stop(); + } + + + if( TestFlag( MoverParameters->WarningSignal, 1 ) ) { + sHorn1.play(); + } + else { + sHorn1.stop(); + } + if( TestFlag( MoverParameters->WarningSignal, 2 ) ) { + sHorn2.play(); + } + else { + sHorn2.stop(); + } + + if( MoverParameters->DoorClosureWarning ) { + if( MoverParameters->DepartureSignal ) { + // NBMX sygnal odjazdu + // MC: pod warunkiem ze jest zdefiniowane w chk + sDepartureSignal.play(); + } + else { + sDepartureSignal.stop(); + } + } + +} #endif }; // McZapkie-250202 // wczytywanie pliku z danymi multimedialnymi (dzwieki) -void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName, - std::string ReplacableSkin) -{ +void TDynamicObject::LoadMMediaFile( std::string BaseDir, std::string TypeName, std::string ReplacableSkin ) { + double dSDist; - // asBaseDir=BaseDir; Global::asCurrentDynamicPath = BaseDir; std::string asFileName = BaseDir + TypeName + ".mmd"; std::string asLoadName; @@ -3898,8 +3956,7 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName, } m_materialdata.multi_textures = clamp( m_materialdata.multi_textures, 0, 1 ); // na razie ustawiamy na 1 } - asModel = BaseDir + asModel; // McZapkie 2002-07-20: dynamics maja swoje - // modele w dynamics/basedir + asModel = BaseDir + asModel; // McZapkie 2002-07-20: dynamics maja swoje modele w dynamics/basedir Global::asCurrentTexturePath = BaseDir; // biezaca sciezka do tekstur to dynamic/... mdModel = TModelsManager::GetModel(asModel, true); assert( mdModel != nullptr ); // TODO: handle this more gracefully than all going to shit @@ -4757,9 +4814,8 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName, } else if( token == "curve:" ) { - - double attenuation; #ifdef EU07_USE_OLD_SOUNDCODE + double attenuation; parser.getTokens( 2, false ); parser >> token @@ -4959,6 +5015,7 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName, mdLowPolyInt->Init(); Global::asCurrentTexturePath = szTexturePath; // kiedyś uproszczone wnętrze mieszało tekstury nieba + Global::asCurrentDynamicPath = ""; } //--------------------------------------------------------------------------- diff --git a/Globals.cpp b/Globals.cpp index 43c66c17..8bf348b4 100644 --- a/Globals.cpp +++ b/Globals.cpp @@ -53,19 +53,15 @@ std::string Global::szTexturesDDS = ".dds"; // lista tekstur od DDS int Global::iPause = 0; // 0x10; // globalna pauza ruchu bool Global::bActive = true; // czy jest aktywnym oknem TWorld *Global::pWorld = NULL; -cParser *Global::pParser = NULL; TCamera *Global::pCamera = NULL; // parametry kamery -TDynamicObject *Global::pUserDynamic = NULL; // pojazd użytkownika, renderowany bez trzęsienia TTranscripts Global::tranTexts; // obiekt obsługujący stenogramy dźwięków na ekranie float4 Global::UITextColor = float4( 225.0 / 255.0f, 225.0f / 255.0f, 225.0f / 255.0f, 1.0f ); -// parametry scenerii vector3 Global::pCameraPosition; vector3 Global::DebugCameraPosition; -double Global::pCameraRotation; -double Global::pCameraRotationDeg; std::vector Global::FreeCameraInit; std::vector Global::FreeCameraInitAngle; +// parametry scenerii GLfloat Global::FogColor[] = {0.6f, 0.7f, 0.8f}; double Global::fFogStart = 1700; double Global::fFogEnd = 2000; @@ -127,8 +123,6 @@ bool Global::bGlutFont = false; // czy tekst generowany przez GLUT32.DLL int Global::iConvertModels{ 0 }; // temporary override, to prevent generation of .e3d not compatible with old exe int Global::iSlowMotionMask = -1; // maska wyłączanych właściwości dla zwiększenia FPS // bool Global::bTerrainCompact=true; //czy zapisać teren w pliku -TAnimModel *Global::pTerrainCompact = NULL; // do zapisania terenu w pliku -std::string Global::asTerrainModel = ""; // nazwa obiektu terenu do zapisania w pliku double Global::fFpsAverage = 20.0; // oczekiwana wartosć FPS double Global::fFpsDeviation = 5.0; // odchylenie standardowe FPS double Global::fFpsMin = 30.0; // dolna granica FPS, przy której promień scenerii będzie zmniejszany @@ -965,16 +959,6 @@ void Global::SetCameraPosition(vector3 pNewCameraPosition) pCameraPosition = pNewCameraPosition; } -void Global::SetCameraRotation(double Yaw) -{ // ustawienie bezwzględnego kierunku kamery z korekcją do przedziału <-M_PI,M_PI> - pCameraRotation = Yaw; - while (pCameraRotation < -M_PI) - pCameraRotation += 2 * M_PI; - while (pCameraRotation > M_PI) - pCameraRotation -= 2 * M_PI; - pCameraRotationDeg = pCameraRotation * 180.0 / M_PI; -} - void Global::TrainDelete(TDynamicObject *d) { // usunięcie pojazdu prowadzonego przez użytkownika if (pWorld) @@ -983,20 +967,6 @@ void Global::TrainDelete(TDynamicObject *d) //--------------------------------------------------------------------------- -bool Global::DoEvents() -{ // wywoływać czasem, żeby nie robił wrażenia zawieszonego - MSG msg; - while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) - { - if (msg.message == WM_QUIT) - return FALSE; - TranslateMessage(&msg); - DispatchMessage(&msg); - } - return TRUE; -} -//--------------------------------------------------------------------------- - TTranscripts::TTranscripts() { /* diff --git a/Globals.h b/Globals.h index 1dba16ae..9c7fe26a 100644 --- a/Globals.h +++ b/Globals.h @@ -10,10 +10,8 @@ http://mozilla.org/MPL/2.0/. #pragma once #include -#include + #include "renderer.h" -#include "glfw/glfw3.h" -#include "gl/glew.h" #include "dumb3d.h" // definicje klawiszy @@ -113,16 +111,6 @@ const int k_WalkMode = 73; int const k_DimHeadlights = 74; const int MaxKeys = 75; -// klasy dla wskaźników globalnych -/* -class TGround; -class TWorld; -class TCamera; -class TDynamicObject; -class TAnimModel; // obiekt terenu -class cParser; // nowy (powolny!) parser -class TEvent; -*/ class TTranscript { // klasa obsługująca linijkę napisu do dźwięku public: @@ -159,9 +147,7 @@ public: static void InitKeys(); inline static Math3D::vector3 GetCameraPosition() { return pCameraPosition; }; static void SetCameraPosition(Math3D::vector3 pNewCameraPosition); - static void SetCameraRotation(double Yaw); static void TrainDelete(TDynamicObject *d); - static bool DoEvents(); static std::string Bezogonkow(std::string str, bool _ = false); static double Min0RSpeed(double vel1, double vel2); @@ -170,8 +156,6 @@ public: static bool RealisticControlMode; // controls ability to steer the vehicle from outside views static Math3D::vector3 pCameraPosition; // pozycja kamery w świecie static Math3D::vector3 DebugCameraPosition; // pozycja kamery w świecie - static double pCameraRotation; // kierunek bezwzględny kamery w świecie: 0=północ, 90°=zachód (-azymut) - static double pCameraRotationDeg; // w stopniach, dla animacji billboard static std::vector FreeCameraInit; // pozycje kamery static std::vector FreeCameraInitAngle; static int iWindowWidth; @@ -272,16 +256,12 @@ public: static bool bHideConsole; // hunter-271211: ukrywanie konsoli static TWorld *pWorld; // wskaźnik na świat do usuwania pojazdów - static TAnimModel *pTerrainCompact; // obiekt terenu do ewentualnego zapisania w pliku - static std::string asTerrainModel; // nazwa obiektu terenu do zapisania w pliku static bool bRollFix; // czy wykonać przeliczanie przechyłki - static cParser *pParser; static double fFpsAverage; // oczekiwana wartosć FPS static double fFpsDeviation; // odchylenie standardowe FPS static double fFpsMin; // dolna granica FPS, przy której promień scenerii będzie zmniejszany static double fFpsMax; // górna granica FPS, przy której promień scenerii będzie zwiększany static TCamera *pCamera; // parametry kamery - static TDynamicObject *pUserDynamic; // pojazd użytkownika, renderowany bez trzęsienia static double fCalibrateIn[6][6]; // parametry kalibracyjne wejść z pulpitu static double fCalibrateOut[7][6]; // parametry kalibracyjne wyjść dla pulpitu static double fCalibrateOutMax[7]; // wartości maksymalne wyjść dla pulpitu diff --git a/McZapkie/MOVER.h b/McZapkie/MOVER.h index ce949609..e63e297d 100644 --- a/McZapkie/MOVER.h +++ b/McZapkie/MOVER.h @@ -547,18 +547,18 @@ struct TMotorParameters struct TSecuritySystem { - int SystemType; /*0: brak, 1: czuwak aktywny, 2: SHP/sygnalizacja kabinowa*/ - double AwareDelay; // czas powtarzania czuwaka + int SystemType { 0 }; /*0: brak, 1: czuwak aktywny, 2: SHP/sygnalizacja kabinowa*/ + double AwareDelay { -1.0 }; // czas powtarzania czuwaka double AwareMinSpeed; // minimalna prędkość załączenia czuwaka, normalnie 10% Vmax - double SoundSignalDelay; - double EmergencyBrakeDelay; - int Status; /*0: wylaczony, 1: wlaczony, 2: czuwak, 4: shp, 8: alarm, 16: hamowanie awaryjne*/ - double SystemTimer; - double SystemSoundCATimer; - double SystemSoundSHPTimer; - double SystemBrakeCATimer; - double SystemBrakeSHPTimer; - double SystemBrakeCATestTimer; // hunter-091012 + double SoundSignalDelay { -1.0 }; + double EmergencyBrakeDelay { -1.0 }; + int Status { 0 }; /*0: wylaczony, 1: wlaczony, 2: czuwak, 4: shp, 8: alarm, 16: hamowanie awaryjne*/ + double SystemTimer { 0.0 }; + double SystemSoundCATimer { 0.0 }; + double SystemSoundSHPTimer { 0.0 }; + double SystemBrakeCATimer { 0.0 }; + double SystemBrakeSHPTimer { 0.0 }; + double SystemBrakeCATestTimer { 0.0 }; // hunter-091012 int VelocityAllowed; int NextVelocityAllowed; /*predkosc pokazywana przez sygnalizacje kabinowa*/ bool RadioStop; // czy jest RadioStop diff --git a/ResourceManager.h b/ResourceManager.h index 2d467e19..92fec3ca 100644 --- a/ResourceManager.h +++ b/ResourceManager.h @@ -9,6 +9,8 @@ http://mozilla.org/MPL/2.0/. #pragma once +int const null_handle = 0; + enum class resource_state { none, loading, @@ -64,6 +66,11 @@ class ResourceManager }; */ +using resource_timestamp = std::chrono::steady_clock::time_point; + +// takes containers providing access to specific element through operator[] +// with elements of std::pair +// the element should provide method release() freeing resources owned by the element template class garbage_collector { diff --git a/Texture.h b/Texture.h index c9bd5c7b..da69e063 100644 --- a/Texture.h +++ b/Texture.h @@ -71,7 +71,6 @@ private: }; typedef int texture_handle; -int const null_handle = 0; class texture_manager { @@ -104,7 +103,7 @@ private: // types: typedef std::pair< opengl_texture *, - std::chrono::steady_clock::time_point > texturetimepoint_pair; + resource_timestamp > texturetimepoint_pair; typedef std::vector< texturetimepoint_pair > texturetimepointpair_sequence; diff --git a/Train.cpp b/Train.cpp index 02d9c241..81ceec1d 100644 --- a/Train.cpp +++ b/Train.cpp @@ -4490,6 +4490,7 @@ bool TTrain::Update( double const Deltatime ) } else btLampkaCzuwaka.Turn( false ); + btLampkaSHP.Turn(TestFlag(mvOccupied->SecuritySystem.Status, s_active)); } else // wylaczone @@ -5604,50 +5605,34 @@ TTrain::update_sounds( double const Deltatime ) { if( dsbSlipAlarm ) dsbSlipAlarm->Stop(); } - +#endif // McZapkie-141102: SHP i czuwak, TODO: sygnalizacja kabinowa if (mvOccupied->SecuritySystem.Status > 0) { // hunter-091012: rozdzielenie alarmow - if (TestFlag(mvOccupied->SecuritySystem.Status, s_CAalarm) || - TestFlag(mvOccupied->SecuritySystem.Status, s_SHPalarm)) - { - if (dsbBuzzer) - { - dsbBuzzer->GetStatus(&stat); - if (!(stat & DSBSTATUS_PLAYING)) - { - play_sound( dsbBuzzer, DSBVOLUME_MAX, DSBPLAY_LOOPING ); - Console::BitsSet(1 << 14); // ustawienie bitu 16 na PoKeys - } - } - } - else - { - if (dsbBuzzer) - { - dsbBuzzer->GetStatus(&stat); - if (stat & DSBSTATUS_PLAYING) - { - dsbBuzzer->Stop(); - Console::BitsClear(1 << 14); // ustawienie bitu 16 na PoKeys - } - } - } - } - else // wylaczone - { - if (dsbBuzzer) - { - dsbBuzzer->GetStatus(&stat); - if (stat & DSBSTATUS_PLAYING) - { - dsbBuzzer->Stop(); - Console::BitsClear(1 << 14); // ustawienie bitu 16 na PoKeys - } - } - } + if( TestFlag( mvOccupied->SecuritySystem.Status, s_CAalarm ) + || TestFlag( mvOccupied->SecuritySystem.Status, s_SHPalarm ) ) { + if( false == dsbBuzzer.is_playing() ) { + dsbBuzzer.play( sound_flags::looping ); + Console::BitsSet( 1 << 14 ); // ustawienie bitu 16 na PoKeys + } + } + else { + if( true == dsbBuzzer.is_playing() ) { + dsbBuzzer.stop(); + Console::BitsClear( 1 << 14 ); // ustawienie bitu 16 na PoKeys + } + } + } + else { + // wylaczone + if( true == dsbBuzzer.is_playing() ) { + dsbBuzzer.stop(); + Console::BitsClear( 1 << 14 ); // ustawienie bitu 16 na PoKeys + } + } +#ifdef EU07_USE_OLD_SOUNDCODE /* if ((mvControlled->Mains) && (mvControlled->EngineType==ElectricSeriesMotor)) { @@ -5755,7 +5740,6 @@ bool TTrain::LoadMMediaFile(std::string const &asFileName) if (token == "internaldata:") { - do { token = ""; @@ -5964,7 +5948,7 @@ bool TTrain::LoadMMediaFile(std::string const &asFileName) rsFadeSound.FM = 1.0; rsFadeSound.FA = 1.0; */ - rsFadeSound.deserialize( parser, sound_type::single, sound_parameters::amplitude | sound_parameters::frequency ); + rsFadeSound.deserialize( parser, sound_type::single ); } else if (token == "localbrakesound:") { diff --git a/Train.h b/Train.h index 693ad396..fd1bd4fb 100644 --- a/Train.h +++ b/Train.h @@ -453,7 +453,7 @@ private: float fCzuwakTestTimer; // hunter-091012: do testu czuwaka float fLightsTimer; // yB 150617: timer do swiatel - int CAflag; // hunter-131211: dla osobnego zbijania CA i SHP + bool CAflag { false }; // hunter-131211: dla osobnego zbijania CA i SHP double fPoslizgTimer; TTrack *tor; diff --git a/World.cpp b/World.cpp index 45470e8c..4c003b34 100644 --- a/World.cpp +++ b/World.cpp @@ -77,7 +77,7 @@ simulation_time::init() { m_time.wSecond = 0; } - m_yearday = yearday( m_time.wDay, m_time.wMonth, m_time.wYear ); + m_yearday = year_day( m_time.wDay, m_time.wMonth, m_time.wYear ); } void @@ -125,16 +125,15 @@ simulation_time::update( double const Deltatime ) { } int -simulation_time::yearday( int Day, const int Month, const int Year ) { +simulation_time::year_day( int Day, const int Month, const int Year ) const { - char daytab[ 2 ][ 13 ] = { + char const daytab[ 2 ][ 13 ] = { { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } }; - int i, leap; - leap = ( Year % 4 == 0 ) && ( Year % 100 != 0 ) || ( Year % 400 == 0 ); - for( i = 1; i < Month; ++i ) + int leap { ( Year % 4 == 0 ) && ( Year % 100 != 0 ) || ( Year % 400 == 0 ) }; + for( int i = 1; i < Month; ++i ) Day += daytab[ leap ][ i ]; return Day; @@ -215,7 +214,6 @@ void TWorld::TrainDelete(TDynamicObject *d) Train = NULL; Controlled = NULL; // tego też już nie ma mvControlled = NULL; - Global::pUserDynamic = NULL; // tego też nie ma }; bool TWorld::Init( GLFWwindow *Window ) { @@ -267,7 +265,6 @@ bool TWorld::Init( GLFWwindow *Window ) { { Controlled = Train->Dynamic(); mvControlled = Controlled->ControlledFind()->MoverParameters; - Global::pUserDynamic = Controlled; // renerowanie pojazdu względem kabiny WriteLog("Player train init OK"); glfwSetWindowTitle( window, ( Global::AppName + " (" + Controlled->MoverParameters->Name + " @ " + Global::SceneryFile + ")" ).c_str() ); @@ -771,7 +768,6 @@ void TWorld::InOutKey( bool const Near ) FreeFlyModeFlag = !FreeFlyModeFlag; // zmiana widoku if (FreeFlyModeFlag) { // jeżeli poza kabiną, przestawiamy w jej okolicę - OK - Global::pUserDynamic = NULL; // bez renderowania względem kamery if (Train) { // cache current cab position so there's no need to set it all over again after each out-in switch Train->pMechSittingPosition = Train->pMechOffset; @@ -787,7 +783,6 @@ void TWorld::InOutKey( bool const Near ) { // jazda w kabinie if (Train) { - Global::pUserDynamic = Controlled; // renerowanie względem kamery Train->Dynamic()->bDisplayCab = true; Train->Dynamic()->ABuSetModelShake( vector3(0, 0, 0)); // zerowanie przesunięcia przed powrotem? @@ -1061,6 +1056,8 @@ bool TWorld::Update() { Timer::subsystem.sim_total.stop(); simulation::Region->update_sounds(); + audio::renderer.update( dt ); + GfxRenderer.Update( dt ); ResourceSweep(); @@ -1136,12 +1133,10 @@ TWorld::Update_Camera( double const Deltatime ) { else if( Global::shiftState ) { // patrzenie w bok przez szybę Camera.LookAt = Camera.Pos - ( lr ? -1 : 1 ) * Train->Dynamic()->VectorLeft() * Train->Dynamic()->MoverParameters->ActiveCab; - Global::SetCameraRotation( -modelrotate ); } else { // patrzenie w kierunku osi pojazdu, z uwzględnieniem kabiny - jakby z lusterka, // ale bez odbicia Camera.LookAt = Camera.Pos - Train->GetDirection() * Train->Dynamic()->MoverParameters->ActiveCab; //-1 albo 1 - Global::SetCameraRotation( M_PI - modelrotate ); // tu już trzeba uwzględnić lusterka } Camera.Roll = std::atan( Train->pMechShake.x * Train->fMechRoll ); // hustanie kamery na boki Camera.Pitch = 0.5 * std::atan( Train->vMechVelocity.z * Train->fMechPitch ); // hustanie kamery przod tyl @@ -1174,11 +1169,10 @@ TWorld::Update_Camera( double const Deltatime ) { else // patrzenie w kierunku osi pojazdu, z uwzględnieniem kabiny Camera.LookAt = Train->GetWorldMechPosition() + Train->GetDirection() * 5.0 * Train->Dynamic()->MoverParameters->ActiveCab; //-1 albo 1 Camera.vUp = Train->GetUp(); - Global::SetCameraRotation( Camera.Yaw - modelrotate ); // tu już trzeba uwzględnić lusterka } } - else { // kamera nieruchoma - Global::SetCameraRotation( Camera.Yaw - M_PI ); + else { + // kamera nieruchoma } // all done, update camera position to the new value Global::pCameraPosition = Camera.Pos; @@ -2118,7 +2112,6 @@ void TWorld::ChangeDynamic() { Train->Dynamic()->asBaseDir + Train->Dynamic()->MoverParameters->TypeName + ".mmd" ); if( !FreeFlyModeFlag ) { - Global::pUserDynamic = Controlled; // renerowanie względem kamery Train->Dynamic()->bDisplayCab = true; Train->Dynamic()->ABuSetModelShake( vector3( 0, 0, 0 ) ); // zerowanie przesunięcia przed powrotem? diff --git a/World.h b/World.h index 9acc2581..09c9dae9 100644 --- a/World.h +++ b/World.h @@ -39,13 +39,13 @@ public: second() const { return ( m_time.wMilliseconds * 0.001 + m_time.wSecond ); } int year_day() const { return m_yearday; } + // helper, calculates day of year from given date + int + year_day( int Day, int const Month, int const Year ) const; int julian_day() const; private: - // calculates day of year from given date - int - yearday( int Day, int const Month, int const Year ); // calculates day and month from given day of year void daymonth( WORD &Day, WORD &Month, WORD const Year, WORD const Yearday ); @@ -115,7 +115,6 @@ TWorld(); // calculates current season of the year based on set simulation date void compute_season( int const Yearday ) const; - private: void Update_Environment(); void Update_Camera( const double Deltatime ); diff --git a/audio.cpp b/audio.cpp index ecb69a1f..673b64f1 100644 --- a/audio.cpp +++ b/audio.cpp @@ -98,7 +98,7 @@ buffer_manager::~buffer_manager() { } // creates buffer object out of data stored in specified file. returns: handle to the buffer or null_handle if creation failed -buffer_handle +audio::buffer_handle buffer_manager::create( std::string const &Filename ) { auto filename { ToLower( Filename ) }; @@ -114,14 +114,18 @@ buffer_manager::create( std::string const &Filename ) { std::begin( filename ), std::end( filename ), '\\', '/' ); - // try dynamic-specific sounds first - auto lookup { find_buffer( Global::asCurrentDynamicPath + filename ) }; - if( lookup != null_handle ) { - return lookup; - } - std::string filelookup { find_file( Global::asCurrentDynamicPath + filename ) }; - if( false == filelookup.empty() ) { - return emplace( filelookup ); + audio::buffer_handle lookup { null_handle }; + std::string filelookup; + if( false == Global::asCurrentDynamicPath.empty() ) { + // try dynamic-specific sounds first + lookup = find_buffer( Global::asCurrentDynamicPath + filename ); + if( lookup != null_handle ) { + return lookup; + } + filelookup = find_file( Global::asCurrentDynamicPath + filename ); + if( false == filelookup.empty() ) { + return emplace( filelookup ); + } } // if dynamic-specific lookup finds nothing, try the default sound folder lookup = find_buffer( szSoundPath + filename ); @@ -136,8 +140,15 @@ buffer_manager::create( std::string const &Filename ) { return null_handle; } +// provides direct access to a specified buffer +audio::openal_buffer const & +buffer_manager::buffer( audio::buffer_handle const Buffer ) const { + + return m_buffers[ Buffer ]; +} + // places in the bank a buffer containing data stored in specified file. returns: handle to the buffer -buffer_handle +audio::buffer_handle buffer_manager::emplace( std::string Filename ) { buffer_handle const handle { m_buffers.size() }; @@ -151,7 +162,7 @@ buffer_manager::emplace( std::string Filename ) { return handle; } -buffer_handle +audio::buffer_handle buffer_manager::find_buffer( std::string const &Buffername ) const { auto lookup = m_buffermappings.find( Buffername ); diff --git a/audio.h b/audio.h index fd944367..a907a41d 100644 --- a/audio.h +++ b/audio.h @@ -16,6 +16,7 @@ namespace audio { ALuint const null_resource { ~ALuint{ 0 } }; +// wrapper for audio sample struct openal_buffer { // members ALuint id { null_resource }; // associated AL resource @@ -36,6 +37,8 @@ private: using buffer_handle = std::size_t; + +// class buffer_manager { public: @@ -47,6 +50,9 @@ public: // creates buffer object out of data stored in specified file. returns: handle to the buffer or null_handle if creation failed buffer_handle create( std::string const &Filename ); + // provides direct access to a specified buffer + audio::openal_buffer const & + buffer( audio::buffer_handle const Buffer ) const; private: // types diff --git a/audiorenderer.cpp b/audiorenderer.cpp index aa06766b..2a1df7a7 100644 --- a/audiorenderer.cpp +++ b/audiorenderer.cpp @@ -10,12 +10,88 @@ http://mozilla.org/MPL/2.0/. #include "stdafx.h" #include "audiorenderer.h" +#include "sound.h" #include "logs.h" namespace audio { openal_renderer renderer; +// starts playback of queued buffers +void +openal_source::play() { + + ::alSourcePlay( id ); + is_playing = true; +} + +// stops the playback +void +openal_source::stop() { + + ::alSourcei( id, AL_LOOPING, AL_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 +} + +// updates state of the source +void +openal_source::update( int const Deltatime ) { + + // 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 ); + // for multipart sounds trim away processed sources until only one remains, the last one may be set to looping by the controller + ALuint bufferid; + while( ( buffer_index > 0 ) + && ( buffers.size() > 1 ) ) { + ::alSourceUnqueueBuffers( id, 1, &bufferid ); + buffers.erase( std::begin( buffers ) ); + --buffer_index; + } + int state; + ::alGetSourcei( id, AL_SOURCE_STATE, &state ); + is_playing = ( state == AL_PLAYING ); + // request instructions from the controller + controller->update( *this ); +} + +// toggles looping of the sound emitted by the source +void +openal_source::loop( bool const State ) { + + ::alSourcei( + id, + AL_LOOPING, + ( State ? + AL_TRUE : + AL_FALSE ) ); +} + +// releases bound buffers and resets state of the class variables +// NOTE: doesn't release allocated implementation-side source +void +openal_source::clear() { + + controller = nullptr; + // unqueue bound buffers: + // ensure no buffer is in use... + ::alSourcei( id, AL_LOOPING, AL_FALSE ); + ::alSourceStop( id ); + is_playing = false; + // ...prepare space for returned ids of unqueued buffers (not that we need that info)... + std::vector bufferids; + bufferids.resize( buffers.size() ); + // ...release the buffers and update source data to match + ::alSourceUnqueueBuffers( id, bufferids.size(), bufferids.data() ); + buffers.clear(); + buffer_index = 0; +} + + + openal_renderer::~openal_renderer() { ::alcMakeContextCurrent( nullptr ); @@ -24,12 +100,19 @@ openal_renderer::~openal_renderer() { if( m_device != nullptr ) { ::alcCloseDevice( m_device ); } } -buffer_handle +audio::buffer_handle openal_renderer::fetch_buffer( std::string const &Filename ) { return m_buffers.create( Filename ); } +// provides direct access to a specified buffer +audio::openal_buffer const & +openal_renderer::buffer( audio::buffer_handle const Buffer ) const { + + return m_buffers.buffer( Buffer ); +} + // initializes the service bool openal_renderer::init() { @@ -42,11 +125,56 @@ openal_renderer::init() { // basic initialization failed return false; } - + // all done m_ready = true; return true; } +// schedules playback of specified sample, under control of the specified emitter +void +openal_renderer::insert( sound_source *Controller, audio::buffer_handle const Sound ) { + + audio::openal_source::buffer_sequence buffers { Sound }; + return + insert( + Controller, + std::begin( buffers ), std::end( buffers ) ); +} + +// updates state of all active emitters +void +openal_renderer::update( int const Deltatime ) { + + auto source { std::begin( m_sources ) }; + while( source != std::end( m_sources ) ) { + // update each source + source->update( Deltatime ); + // if after the update the source isn't playing, put it away on the spare stack, it's done + if( false == source->is_playing ) { + source->clear(); + m_sourcespares.push( *source ); + source = m_sources.erase( source ); + } + else { + // otherwise proceed through the list normally + ++source; + } + } +} + +// returns an instance of implementation-side part of the sound emitter +audio::openal_source +openal_renderer::fetch_source() { + + audio::openal_source soundsource; + if( false == m_sourcespares.empty() ) { + // reuse (a copy of) already allocated source + soundsource = m_sourcespares.top(); + m_sourcespares.pop(); + } + return soundsource; +} + bool openal_renderer::init_caps() { diff --git a/audiorenderer.h b/audiorenderer.h index 8e52e016..ddc8ed57 100644 --- a/audiorenderer.h +++ b/audiorenderer.h @@ -10,9 +10,60 @@ http://mozilla.org/MPL/2.0/. #pragma once #include "audio.h" +#include "resourcemanager.h" + +class sound_source; namespace audio { +// implementation part of the sound emitter +// TODO: generic interface base, for implementations other than openAL +struct openal_source { + +// types + using buffer_sequence = std::vector; + +// members + ALuint id { audio::null_resource }; // associated AL resource + sound_source *controller { nullptr }; // source controller + buffer_sequence buffers; // sequence of samples the source will emit + int buffer_index; // currently queued sample from the buffer sequence + bool is_playing { false }; + +// methods + template + openal_source & + bind( sound_source *Controller, Iterator_ First, Iterator_ Last ) { + controller = Controller; + buffers.insert( std::end( buffers ), First, Last ); + if( id == audio::null_resource ) { + ::alGenSources( 1, &id ); } + // look up and queue assigned buffers + std::vector bufferids; + for( auto const buffer : buffers ) { + bufferids.emplace_back( audio::renderer.buffer( buffer ).id ); } + ::alSourceQueueBuffers( id, bufferids.size(), bufferids.data() ); + return *this; } + // starts playback of queued buffers + void + play(); + // 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 ); + // releases bound buffers and resets state of the class variables + // NOTE: doesn't release allocated implementation-side source + void + clear(); +}; + + + class openal_renderer { public: @@ -21,23 +72,46 @@ public: // methods // buffer methods // returns handle to a buffer containing audio data from specified file - buffer_handle + audio::buffer_handle fetch_buffer( std::string const &Filename ); + // provides direct access to a specified buffer + audio::openal_buffer const & + buffer( audio::buffer_handle const Buffer ) const; // core methods // initializes the service bool init(); + // schedules playback of provided range of samples, under control of the specified sound emitter + template + void + insert( sound_source *Controller, Iterator_ First, Iterator_ Last ) { + m_sources.emplace_back( fetch_source().bind( Controller, First, Last ) ); } + // schedules playback of specified sample, under control of the specified sound emitter + void + insert( sound_source *Controller, audio::buffer_handle const Sound ); + // updates state of all active emitters + void + update( int const Deltatime ); private: +// types + using source_list = std::list; + using source_sequence = std::stack; // methods bool init_caps(); + // returns an instance of implementation-side part of the sound emitter + audio::openal_source + fetch_source(); // members ALCdevice * m_device { nullptr }; ALCcontext * m_context { nullptr }; bool m_ready { false }; // renderer is initialized and functional buffer_manager m_buffers; + // TBD: list of sources as vector, sorted by distance, for openal implementations with limited number of active sources? + source_list m_sources; + source_sequence m_sourcespares; // already created and currently unused sound sources }; extern openal_renderer renderer; diff --git a/maszyna.vcxproj.filters b/maszyna.vcxproj.filters index 79bade59..7652f761 100644 --- a/maszyna.vcxproj.filters +++ b/maszyna.vcxproj.filters @@ -225,15 +225,15 @@ Source Files + + Source Files + Source Files Source Files - - Source Files - @@ -449,13 +449,13 @@ Header Files - + Header Files Header Files - + Header Files diff --git a/openglgeometrybank.cpp b/openglgeometrybank.cpp index 2e106500..dc8989a3 100644 --- a/openglgeometrybank.cpp +++ b/openglgeometrybank.cpp @@ -395,7 +395,7 @@ geometrybank_manager::create_bank() { if( true == Global::bUseVBO ) { m_geometrybanks.emplace_back( std::make_shared(), std::chrono::steady_clock::time_point() ); } else { m_geometrybanks.emplace_back( std::make_shared(), std::chrono::steady_clock::time_point() ); } // NOTE: handle is effectively (index into chunk array + 1) this leaves value of 0 to serve as error/empty handle indication - return { m_geometrybanks.size(), 0 }; + return { static_cast( m_geometrybanks.size() ), 0 }; } // creates a new geometry chunk of specified type from supplied vertex data, in specified bank. returns: handle to the chunk or NULL diff --git a/openglgeometrybank.h b/openglgeometrybank.h index 00b9cd8a..c2bf6ac2 100644 --- a/openglgeometrybank.h +++ b/openglgeometrybank.h @@ -302,7 +302,7 @@ private: // types: typedef std::pair< std::shared_ptr, - std::chrono::steady_clock::time_point > geometrybanktimepoint_pair; + resource_timestamp > geometrybanktimepoint_pair; typedef std::deque< geometrybanktimepoint_pair > geometrybanktimepointpair_sequence; diff --git a/renderer.cpp b/renderer.cpp index e3254003..80cf167a 100644 --- a/renderer.cpp +++ b/renderer.cpp @@ -696,9 +696,10 @@ opengl_renderer::setup_pass( renderpass_config &Config, rendermode const Mode, f point = lightviewmatrix * point; } bounding_box( frustumchunkmin, frustumchunkmax, std::begin( frustumchunkshapepoints ), std::end( frustumchunkshapepoints ) ); - // quantize the frustum points with 50 m resolution, to reduce shadow shimmer on scale/orientation changes - frustumchunkmin = 50.f * glm::floor( frustumchunkmin * ( 1.f / 50.f ) ); - frustumchunkmax = 50.f * glm::ceil( frustumchunkmax * ( 1.f / 50.f ) ); + // quantize the frustum points and add some padding, to reduce shadow shimmer on scale changes + auto const quantizationstep{ std::min( Global::shadowtune.depth, 50.f ) }; + frustumchunkmin = quantizationstep * glm::floor( frustumchunkmin * ( 1.f / quantizationstep ) ); + frustumchunkmax = quantizationstep * glm::ceil( frustumchunkmax * ( 1.f / quantizationstep ) ); // ...use the dimensions to set up light projection boundaries... // NOTE: since we only have one cascade map stage, we extend the chunk forward/back to catch areas normally covered by other stages camera.projection() *= diff --git a/renderer.h b/renderer.h index e8613eb6..e8582afc 100644 --- a/renderer.h +++ b/renderer.h @@ -21,7 +21,7 @@ http://mozilla.org/MPL/2.0/. #define EU07_USE_PICKING_FRAMEBUFFER //#define EU07_USE_DEBUG_SHADOWMAP -#define EU07_USE_DEBUG_CAMERA +//#define EU07_USE_DEBUG_CAMERA //#define EU07_USE_DEBUG_CULLING struct opengl_light { diff --git a/simulation.cpp b/simulation.cpp index cd176f5f..6ef2c32b 100644 --- a/simulation.cpp +++ b/simulation.cpp @@ -460,10 +460,7 @@ state_manager::deserialize_node( cParser &Input, scene::scratch_data &Scratchpad auto *sound { deserialize_sound( Input, Scratchpad, nodedata ) }; if( false == simulation::Sounds.insert( sound ) ) { -#ifdef EU07_USE_OLD_SOUNDCODE - ErrorLog( "Bad scenario: sound node with duplicate name \"" + sound->m_name + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" ); -#else -#endif + ErrorLog( "Bad scenario: sound node with duplicate name \"" + sound->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" ); } simulation::Region->insert_sound( sound, Scratchpad ); } diff --git a/sound.cpp b/sound.cpp index 519b51e1..d17912f5 100644 --- a/sound.cpp +++ b/sound.cpp @@ -10,6 +10,8 @@ http://mozilla.org/MPL/2.0/. #include "stdafx.h" #include "sound.h" +#include "parser.h" +#include "globals.h" // restores state of the class from provided data stream sound_source & @@ -25,12 +27,14 @@ sound_source::deserialize( cParser &Input, sound_type const Legacytype, int cons switch( Legacytype ) { case sound_type::single: { // single sample only - Input.getTokens( 1, true, "\n\r\t ,;" ); + m_soundmain = audio::renderer.fetch_buffer( Input.getToken( true, "\n\r\t ,;" ) ); break; } case sound_type::multipart: { // three samples: start, middle, stop - Input.getTokens( 3, true, "\n\r\t ,;" ); + m_soundbegin = audio::renderer.fetch_buffer( Input.getToken( true, "\n\r\t ,;" ) ); + m_soundmain = audio::renderer.fetch_buffer( Input.getToken( true, "\n\r\t ,;" ) ); + m_soundend = audio::renderer.fetch_buffer( Input.getToken( true, "\n\r\t ,;" ) ); break; } default: { @@ -53,14 +57,142 @@ sound_source::deserialize( cParser &Input, sound_type const Legacytype, int cons // issues contextual play commands for the audio renderer void -sound_source::play() { +sound_source::play( int const Flags ) { + if( ( false == Global::bSoundEnabled ) + || ( true == empty() ) ) { + // if the sound is disabled altogether or nothing can be emitted from this source, no point wasting time + return; + } + + m_flags = Flags; + + switch( m_stage ) { + case stage::none: + case stage::restart: { + if( m_soundbegin != null_handle ) { + std::vector bufferlist{ m_soundbegin, m_soundmain }; + audio::renderer.insert( this, std::begin( bufferlist ), std::end( bufferlist ) ); + } + else { + audio::renderer.insert( this, m_soundmain ); + } + 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; + } + } +} + +// stops currently active play commands controlled by this emitter +void +sound_source::stop() { + + if( ( m_stage == stage::none ) + || ( m_stage == stage::end ) ) { + 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; + } + } +} + +// adjusts parameters of provided implementation-side sound source +void +sound_source::update( audio::openal_source &Source ) { + + if( true == Source.is_playing ) { + + // kill the sound if requested + if( m_stage == stage::cease ) { + Source.stop(); + return; + } + // TODO: positional update + if( m_soundbegin != null_handle ) { + // 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 ) ) { + // when it happens update active sample flags, and activate the looping + Source.loop( true ); + m_stage = stage::main; + } + } + } + else { + // if the emitter isn't playing it's either done or wasn't yet started + // we can determine this from number of processed buffers + if( Source.buffer_index != Source.buffers.size() ) { + auto const buffer { Source.buffers[ Source.buffer_index ] }; + 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 ) + && ( true == TestFlag( m_flags, sound_flags::looping ) ) ) { + // main sample can be optionally set to loop + Source.loop( true ); + } + // all set, start playback + 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; + } + } + } } bool sound_source::empty() const { - return true; + // 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 ); +} + +// returns true if the source is emitting any sound +bool +sound_source::is_playing() const { + + return ( m_stage != stage::none ); } //--------------------------------------------------------------------------- diff --git a/sound.h b/sound.h index 877c5491..7f9ffb29 100644 --- a/sound.h +++ b/sound.h @@ -10,7 +10,7 @@ http://mozilla.org/MPL/2.0/. #pragma once #include "audiorenderer.h" -#include "parser.h" +#include "classes.h" #include "names.h" enum sound_type { @@ -19,14 +19,18 @@ enum sound_type { }; enum sound_parameters { - none, - range = 0x1, + range = 0x1, amplitude = 0x2, frequency = 0x4 }; +enum sound_flags { + looping = 0x1, // the main sample will be looping; implied for multi-sounds + exclusive = 0x2 // the source won't dispatch more than one active instance of the sound; implied for multi-sounds +}; + // mini controller and audio dispatcher; issues play commands for the audio renderer, -// updates parameters of assigned audio sources for the playback duration +// updates parameters of created audio emitters for the playback duration // TODO: move to simulation namespace after clean up of owner classes class sound_source { @@ -34,15 +38,18 @@ public: // methods // restores state of the class from provided data stream sound_source & - deserialize( cParser &Input, sound_type const Legacytype, int const Legacyparameters = sound_parameters::none ); + deserialize( cParser &Input, sound_type const Legacytype, int const Legacyparameters = NULL ); sound_source & - deserialize( std::string const &Input, sound_type const Legacytype, int const Legacyparameters = sound_parameters::none ); + deserialize( std::string const &Input, sound_type const Legacytype, int const Legacyparameters = NULL ); // issues contextual play commands for the audio renderer void - play(); - // sets volume of audio streams associated with this source - sound_source & - volume( float const Volume ); + play( int const Flags = NULL ); + // 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 ); // sound source name setter/getter void name( std::string Name ); @@ -51,10 +58,31 @@ 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 + bool + is_playing() const; private: +// types + enum stage { + none, + begin, + main, + end, + cease, + restart + }; + // members + TDynamicObject * 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 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 + // TODO: table of samples with associated values, activated when controlling variable matches the value }; // sound source name setter/getter diff --git a/sun.cpp b/sun.cpp index 9f4ac2b5..9e744635 100644 --- a/sun.cpp +++ b/sun.cpp @@ -14,10 +14,6 @@ cSun::cSun() { setLocation( 19.00f, 52.00f ); // default location roughly in centre of Poland m_observer.press = 1013.0; // surface pressure, millibars m_observer.temp = 15.0; // ambient dry-bulb temperature, degrees C - - TIME_ZONE_INFORMATION timezoneinfo; // TODO: timezone dependant on geographic location - ::GetTimeZoneInformation( &timezoneinfo ); - m_observer.timezone = -timezoneinfo.Bias / 60.0f; } cSun::~cSun() { gluDeleteQuadric( sunsphere ); } @@ -27,6 +23,27 @@ cSun::init() { sunsphere = gluNewQuadric(); gluQuadricNormals( sunsphere, GLU_SMOOTH ); + + // calculate and set timezone for the current date of the simulation + // TODO: timezone dependant on geographic location + TIME_ZONE_INFORMATION timezoneinfo; + ::GetTimeZoneInformation( &timezoneinfo ); + // account for potential daylight/normal time bias + // NOTE: we're using xp-compatible time zone information and current year, instead of 'historically proper' values + auto zonebias { timezoneinfo.Bias }; + auto const year { simulation::Time.data().wYear }; + auto const yearday { simulation::Time.year_day() }; + if( yearday < simulation::Time.year_day( timezoneinfo.DaylightDate.wDay, timezoneinfo.DaylightDate.wMonth, year ) ) { + zonebias += timezoneinfo.StandardBias; + } + else if( yearday < simulation::Time.year_day( timezoneinfo.StandardDate.wDay, timezoneinfo.StandardDate.wMonth, year ) ) { + zonebias += timezoneinfo.DaylightBias; + } + else { + zonebias += timezoneinfo.StandardBias; + } + + m_observer.timezone = -zonebias / 60.0f; } void From 3afff7c3ab40037ae09072961ca7f1eb2bfc4128 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Wed, 29 Nov 2017 01:50:57 +0100 Subject: [PATCH 5/8] audio subsystem: completed base functionality of the renderer, external and engine sounds moved from cab to vehicle, minor fixes to various sound-related methods --- Button.cpp | 54 +- Button.h | 57 +- Driver.cpp | 91 +- DynObj.cpp | 1966 +++++++++++++++++++++++++----------------- DynObj.h | 131 ++- Event.cpp | 40 +- Gauge.cpp | 51 +- Gauge.h | 50 +- Globals.cpp | 2 + Globals.h | 1 + McZapkie/MOVER.h | 20 +- McZapkie/Mover.cpp | 109 ++- McZapkie/hamulce.cpp | 183 ++-- Model3d.cpp | 50 +- Model3d.h | 11 +- Train.cpp | 930 +++++--------------- Train.h | 58 +- World.cpp | 10 +- audio.cpp | 2 + audio.h | 2 +- audiorenderer.cpp | 129 ++- audiorenderer.h | 54 +- dumb3d.h | 2 +- renderer.cpp | 22 +- simulation.cpp | 4 +- sound.cpp | 288 +++++-- sound.h | 100 ++- 27 files changed, 2488 insertions(+), 1929 deletions(-) diff --git a/Button.cpp b/Button.cpp index c7b501a4..0636888b 100644 --- a/Button.cpp +++ b/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 we failed to locate even one state submodel, cry - ErrorLog( "Failed to locate sub-model \"" + submodelname + "\" in 3d model \"" + pModel1->NameGet() + "\"" ); -}; + + if( ( pModelOn == nullptr ) + && ( pModelOff == nullptr ) ) { + // if we failed to locate even one state submodel, cry + ErrorLog( "Bad model: failed to locate sub-model \"" + submodelname + "\" in 3d model \"" + pModel1->NameGet() + "\"" ); + } + + // pass submodel location to defined sounds + auto const offset { model_offset() }; + m_soundfxincrease.offset( offset ); + m_soundfxdecrease.offset( offset ); +} bool TButton::Load_mapping( cParser &Input ) { @@ -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 ) { diff --git a/Button.h b/Button.h index 534bcd6d..5ac94579 100644 --- a/Button.h +++ b/Button.h @@ -12,18 +12,28 @@ 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 +// animacja dwustanowa, włącza jeden z dwóch submodeli (jednego z nich może nie być) +class TButton { + +public: +// methods + TButton() = default; + void Clear(int const i = -1); + inline void FeedbackBitSet( int const i ) { + iFeedbackBit = 1 << i; }; + void Turn( bool const State ); + inline + bool Active() { + return ( ( pModelOn != nullptr ) + || ( pModelOff != nullptr ) ); } + void Update(); + void Init( std::string const &asName, TModel3d *pModel, bool bNewOn = false ); + void Load( cParser &Parser, TDynamicObject const *Owner, TModel3d *pModel1, TModel3d *pModel2 = nullptr ); + void AssignBool(bool const *bValue); + // returns offset of submodel associated with the button from the model centre + glm::vec3 model_offset() const; + +private: // methods // imports member data pair from the config file bool @@ -32,20 +42,15 @@ class TButton void play(); - public: - TButton() = default; - void Clear(int const i = -1); - inline void FeedbackBitSet(int const i) { - iFeedbackBit = 1 << i; }; - void Turn( bool const State ); - inline - bool Active() { - return ( ( pModelOn != nullptr ) - || ( pModelOff != nullptr ) ); } - void Update(); - void Init(std::string const &asName, TModel3d *pModel, bool bNewOn = false); - void Load(cParser &Parser, TModel3d *pModel1, TModel3d *pModel2 = NULL); - void AssignBool(bool const *bValue); +// members + TSubModel + *pModelOn { nullptr }, + *pModelOff { nullptr }; // submodel dla stanu załączonego i wyłączonego + bool m_state { false }; + bool const *bData { nullptr }; + int iFeedbackBit { 0 }; // Ra: bit informacji zwrotnej, do wyprowadzenia na pulpit + sound_source m_soundfxincrease { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE }; // sound associated with increasing control's value + sound_source m_soundfxdecrease { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE }; // sound associated with decreasing control's value }; //--------------------------------------------------------------------------- diff --git a/Driver.cpp b/Driver.cpp index 75c1b2ba..24c9e81e 100644 --- a/Driver.cpp +++ b/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,43 +4493,48 @@ 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ę - Doors( false ); // a EZT zamknie dopiero po odegraniu komunikatu kierownika - -#ifdef EU07_USE_OLD_SOUNDCODE - tsGuardSignal->Stop(); -#else -#endif - // w zasadzie to powinien mieć flagę, czy jest dźwiękiem radiowym, czy - // bezpośrednim - // albo trzeba zrobić dwa dźwięki, jeden bezpośredni, słyszalny w - // pobliżu, a drugi radiowy, słyszalny w innych lokomotywach - // na razie zakładam, że to nie jest dźwięk radiowy, bo trzeba by zrobić - // obsługę kanałów radiowych itd. - if( !iGuardRadio ) { - // jeśli nie przez radio -#ifdef EU07_USE_OLD_SOUNDCODE - tsGuardSignal->Play( 1.0, 0, !FreeFlyModeFlag, pVehicle->GetPosition() ); // dla true jest głośniej -#else -#endif + if( ( iDrivigFlags & moveDoorOpened ) + && ( false == mvOccupied->DoorOpenCtrl ) ) { + // jeśli drzwi otwarte, niesterowane przez maszynistę + Doors( false ); // a EZT zamknie dopiero po odegraniu komunikatu kierownika } - else { - // if (iGuardRadio==iRadioChannel) //zgodność kanału - // if (!FreeFlyModeFlag) //obserwator musi być w środku pojazdu - // (albo może mieć radio przenośne) - kierownik mógłby powtarzać - // przy braku reakcji - if( SquareMagnitude( pVehicle->GetPosition() - Global::pCameraPosition ) < 2000 * 2000 ) { - // w odległości mniejszej niż 2km + if( tsGuardSignal != nullptr ) { #ifdef EU07_USE_OLD_SOUNDCODE - tsGuardSignal->Play( 1.0, 0, true, pVehicle->GetPosition() ); // dźwięk niby przez radio + tsGuardSignal->Stop(); #else + tsGuardSignal->stop(); #endif + // w zasadzie to powinien mieć flagę, czy jest dźwiękiem radiowym, czy + // bezpośrednim + // albo trzeba zrobić dwa dźwięki, jeden bezpośredni, słyszalny w + // pobliżu, a drugi radiowy, słyszalny w innych lokomotywach + // na razie zakładam, że to nie jest dźwięk radiowy, bo trzeba by zrobić + // obsługę kanałów radiowych itd. + if( !iGuardRadio ) { + // jeśli nie przez radio +#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 { + // if (iGuardRadio==iRadioChannel) //zgodność kanału + // if (!FreeFlyModeFlag) //obserwator musi być w środku pojazdu + // (albo może mieć radio przenośne) - kierownik mógłby powtarzać + // przy braku reakcji + if( SquareMagnitude( pVehicle->GetPosition() - Global::pCameraPosition ) < 2000 * 2000 ) { + // w odległości mniejszej niż 2km +#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 + } } } } diff --git a/DynObj.cpp b/DynObj.cpp index c1846335..59941932 100644 --- a/DynObj.cpp +++ b/DynObj.cpp @@ -1218,8 +1218,9 @@ int TDynamicObject::DettachStatus(int dir) // rzeczywistych od strony (dir): // 0=przód,1=tył // Ra: dziwne, że ta funkcja nie jest używana - if (!MoverParameters->Couplers[dir].CouplingFlag) + if( MoverParameters->Couplers[ dir ].CouplingFlag == coupling::faux ) { return 0; // jeśli nic nie podłączone, to jest OK + } return (MoverParameters->DettachStatus(dir)); // czy jest w odpowiedniej odległości? } @@ -1243,10 +1244,154 @@ int TDynamicObject::Dettach(int dir) d = d->Next(); // i w drugą stronę } } - if (MoverParameters->Couplers[dir].CouplingFlag) // odczepianie, o ile coś podłączone - MoverParameters->Dettach(dir); - return MoverParameters->Couplers[dir] - .CouplingFlag; // sprzęg po rozłączaniu (czego się nie da odpiąć + if( MoverParameters->Couplers[ dir ].CouplingFlag ) { + // odczepianie, o ile coś podłączone + MoverParameters->Dettach( dir ); + } + // sprzęg po rozłączaniu (czego się nie da odpiąć + return MoverParameters->Couplers[dir].CouplingFlag; +} + +void +TDynamicObject::couple( int const Side ) { + + if( MoverParameters->Couplers[ Side ].Connected == nullptr ) { return; } + + if( MoverParameters->Couplers[ Side ].CouplingFlag == coupling::faux ) { + // najpierw hak + if( ( MoverParameters->Couplers[ Side ].Connected->Couplers[ Side ].AllowedFlag + & MoverParameters->Couplers[ Side ].AllowedFlag + & coupling::coupler ) == coupling::coupler ) { + if( MoverParameters->Attach( + Side, 2, + MoverParameters->Couplers[ Side ].Connected, + coupling::coupler ) ) { + // tmp->MoverParameters->Couplers[CouplNr].Render=true; //podłączony sprzęg będzie widoczny + m_couplersounds[ Side ].dsbCouplerAttach.play(); + // one coupling type per key press + return; + } + else { + WriteLog( "Mechanical coupling failed." ); + } + } + } + if( false == TestFlag( MoverParameters->Couplers[ Side ].CouplingFlag, coupling::brakehose ) ) { + // pneumatyka + if( ( MoverParameters->Couplers[ Side ].Connected->Couplers[ Side ].AllowedFlag + & MoverParameters->Couplers[ Side ].AllowedFlag + & coupling::brakehose ) == coupling::brakehose ) { + if( MoverParameters->Attach( + Side, 2, + MoverParameters->Couplers[ Side ].Connected, + ( MoverParameters->Couplers[ Side ].CouplingFlag | coupling::brakehose ) ) ) { + // TODO: dedicated sound for connecting cable-type connections + m_couplersounds[ Side ].dsbCouplerDetach.play(); + + SetPneumatic( Side != 0, true ); + if( Side == side::front ) { + PrevConnected->SetPneumatic( Side != 0, true ); + } + else { + NextConnected->SetPneumatic( Side != 0, true ); + } + // one coupling type per key press + return; + } + } + } + if( false == TestFlag( MoverParameters->Couplers[ Side ].CouplingFlag, coupling::mainhose ) ) { + // zasilajacy + if( ( MoverParameters->Couplers[ Side ].Connected->Couplers[ Side ].AllowedFlag + & MoverParameters->Couplers[ Side ].AllowedFlag + & coupling::mainhose ) == coupling::mainhose ) { + if( MoverParameters->Attach( + Side, 2, + MoverParameters->Couplers[ Side ].Connected, + ( MoverParameters->Couplers[ Side ].CouplingFlag | coupling::mainhose ) ) ) { + // TODO: dedicated sound for connecting cable-type connections + m_couplersounds[ Side ].dsbCouplerDetach.play(); + + SetPneumatic( Side != 0, false ); + if( Side == side::front ) { + PrevConnected->SetPneumatic( Side != 0, false ); + } + else { + NextConnected->SetPneumatic( Side != 0, false ); + } + // one coupling type per key press + return; + } + } + } + if( false == TestFlag( MoverParameters->Couplers[ Side ].CouplingFlag, coupling::control ) ) { + // ukrotnionko + if( ( MoverParameters->Couplers[ Side ].Connected->Couplers[ Side ].AllowedFlag + & MoverParameters->Couplers[ Side ].AllowedFlag + & coupling::control ) == coupling::control ) { + if( MoverParameters->Attach( + Side, 2, + MoverParameters->Couplers[ Side ].Connected, + ( MoverParameters->Couplers[ Side ].CouplingFlag | coupling::control ) ) ) { + // TODO: dedicated sound for connecting cable-type connections + m_couplersounds[ Side ].dsbCouplerAttach.play(); + // one coupling type per key press + return; + } + } + } + if( false == TestFlag( MoverParameters->Couplers[ Side ].CouplingFlag, coupling::gangway ) ) { + // mostek + if( ( MoverParameters->Couplers[ Side ].Connected->Couplers[ Side ].AllowedFlag + & MoverParameters->Couplers[ Side ].AllowedFlag + & coupling::gangway ) == coupling::gangway ) { + if( MoverParameters->Attach( + Side, 2, + MoverParameters->Couplers[ Side ].Connected, + ( MoverParameters->Couplers[ Side ].CouplingFlag | coupling::gangway ) ) ) { + // TODO: dedicated gangway sound + m_couplersounds[ Side ].dsbCouplerAttach.play(); + // one coupling type per key press + return; + } + } + } + if( false == TestFlag( MoverParameters->Couplers[ Side ].CouplingFlag, coupling::heating ) ) { + // heating + if( ( MoverParameters->Couplers[ Side ].Connected->Couplers[ Side ].AllowedFlag + & MoverParameters->Couplers[ Side ].AllowedFlag + & coupling::heating ) == coupling::heating ) { + if( MoverParameters->Attach( + Side, 2, + MoverParameters->Couplers[ Side ].Connected, + ( MoverParameters->Couplers[ Side ].CouplingFlag | coupling::heating ) ) ) { + + // TODO: dedicated 'click' sound for connecting cable-type connections + m_couplersounds[ Side ].dsbCouplerDetach.play(); + // one coupling type per key press + return; + } + } + } + +} + +int +TDynamicObject::uncouple( int const Side ) { + + if( ( DettachStatus( Side ) >= 0 ) + || ( true == TestFlag( MoverParameters->Couplers[ Side ].CouplingFlag, coupling::permanent ) ) ) { + // can't uncouple, return existing coupling state + return MoverParameters->Couplers[ Side ].CouplingFlag; + } + // jeżeli sprzęg niezablokowany, jest co odczepić i się da + auto const couplingflag { Dettach( Side ) }; + if( couplingflag == coupling::faux ) { + // dźwięk odczepiania + m_couplersounds[ Side ].dsbCouplerAttach.play(); + m_couplersounds[ Side ].dsbCouplerDetach.play(); + } + return couplingflag; } void TDynamicObject::CouplersDettach(double MinDist, int MyScanDir) { @@ -1466,7 +1611,8 @@ void TDynamicObject::ABuScanObjects( int Direction, double Distance ) } //----------ABu: koniec skanowania pojazdow -TDynamicObject::TDynamicObject() +TDynamicObject::TDynamicObject() : + rsStukot( MaxAxles, sound_source( sound_placement::external ) ) { modelShake = vector3(0, 0, 0); fTrackBlock = 10000.0; // brak przeszkody na drodze @@ -1839,58 +1985,63 @@ TDynamicObject::Init(std::string Name, // nazwa pojazdu, np. "EU07-424" create_controller( DriverType, !TrainName.empty() ); // McZapkie-250202 - iAxles = (MaxAxles < MoverParameters->NAxles) ? MaxAxles : MoverParameters->NAxles; // ilość osi + iAxles = std::min( MoverParameters->NAxles, MaxAxles ); // ilość osi + rsStukot.resize( iAxles, sound_source( sound_placement::external ) ); // wczytywanie z pliku nazwatypu.mmd, w tym model LoadMMediaFile(asBaseDir, Type_Name, asReplacableSkin); // McZapkie-100402: wyszukiwanie submodeli sprzegów - btCoupler1.Init("coupler1", mdModel, false); // false - ma być wyłączony - btCoupler2.Init("coupler2", mdModel, false); + btCoupler1.Init( "coupler1", mdModel, false ); // false - ma być wyłączony + btCoupler2.Init( "coupler2", mdModel, false); + // brake hoses btCPneumatic1.Init("cpneumatic1", mdModel); btCPneumatic2.Init("cpneumatic2", mdModel); btCPneumatic1r.Init("cpneumatic1r", mdModel); btCPneumatic2r.Init("cpneumatic2r", mdModel); + // main hoses btPneumatic1.Init("pneumatic1", mdModel); btPneumatic2.Init("pneumatic2", mdModel); btPneumatic1r.Init("pneumatic1r", mdModel); btPneumatic2r.Init("pneumatic2r", mdModel); - btCCtrl1.Init("cctrl1", mdModel, false); - btCCtrl2.Init("cctrl2", mdModel, false); - btCPass1.Init("cpass1", mdModel, false); - btCPass2.Init("cpass2", mdModel, false); + // control cables + btCCtrl1.Init( "cctrl1", mdModel, false); + btCCtrl2.Init( "cctrl2", mdModel, false); + // gangways + btCPass1.Init( "cpass1", mdModel, false); + btCPass2.Init( "cpass2", mdModel, false); // sygnaly // ABu 060205: Zmiany dla koncowek swiecacych: - btEndSignals11.Init("endsignal13", mdModel, false); - btEndSignals21.Init("endsignal23", mdModel, false); - btEndSignals13.Init("endsignal12", mdModel, false); - btEndSignals23.Init("endsignal22", mdModel, false); + btEndSignals11.Init( "endsignal13", mdModel, false); + btEndSignals21.Init( "endsignal23", mdModel, false); + btEndSignals13.Init( "endsignal12", mdModel, false); + btEndSignals23.Init( "endsignal22", mdModel, false); iInventory[ side::front ] |= btEndSignals11.Active() ? light::redmarker_left : 0; // informacja, czy ma poszczególne światła iInventory[ side::front ] |= btEndSignals13.Active() ? light::redmarker_right : 0; iInventory[ side::rear ] |= btEndSignals21.Active() ? light::redmarker_left : 0; iInventory[ side::rear ] |= btEndSignals23.Active() ? light::redmarker_right : 0; // ABu: to niestety zostawione dla kompatybilnosci modeli: - btEndSignals1.Init("endsignals1", mdModel, false); - btEndSignals2.Init("endsignals2", mdModel, false); - btEndSignalsTab1.Init("endtab1", mdModel, false); - btEndSignalsTab2.Init("endtab2", mdModel, false); + btEndSignals1.Init( "endsignals1", mdModel, false); + btEndSignals2.Init( "endsignals2", mdModel, false); + btEndSignalsTab1.Init( "endtab1", mdModel, false); + btEndSignalsTab2.Init( "endtab2", mdModel, false); iInventory[ side::front ] |= btEndSignals1.Active() ? ( light::redmarker_left | light::redmarker_right ) : 0; iInventory[ side::front ] |= btEndSignalsTab1.Active() ? light::rearendsignals : 0; // tabliczki blaszane iInventory[ side::rear ] |= btEndSignals2.Active() ? ( light::redmarker_left | light::redmarker_right ) : 0; iInventory[ side::rear ] |= btEndSignalsTab2.Active() ? light::rearendsignals : 0; // ABu Uwaga! tu zmienic w modelu! - btHeadSignals11.Init("headlamp13", mdModel, false); // lewe - btHeadSignals12.Init("headlamp11", mdModel, false); // górne - btHeadSignals13.Init("headlamp12", mdModel, false); // prawe - btHeadSignals21.Init("headlamp23", mdModel, false); - btHeadSignals22.Init("headlamp21", mdModel, false); - btHeadSignals23.Init("headlamp22", mdModel, false); + btHeadSignals11.Init( "headlamp13", mdModel, false); // lewe + btHeadSignals12.Init( "headlamp11", mdModel, false); // górne + btHeadSignals13.Init( "headlamp12", mdModel, false); // prawe + btHeadSignals21.Init( "headlamp23", mdModel, false); + btHeadSignals22.Init( "headlamp21", mdModel, false); + btHeadSignals23.Init( "headlamp22", mdModel, false); iInventory[ side::front ] |= btHeadSignals11.Active() ? light::headlight_left : 0; iInventory[ side::front ] |= btHeadSignals12.Active() ? light::headlight_upper : 0; iInventory[ side::front ] |= btHeadSignals13.Active() ? light::headlight_right : 0; iInventory[ side::rear ] |= btHeadSignals21.Active() ? light::headlight_left : 0; iInventory[ side::rear ] |= btHeadSignals22.Active() ? light::headlight_upper : 0; iInventory[ side::rear ] |= btHeadSignals23.Active() ? light::headlight_right : 0; - btMechanik1.Init("mechanik1", mdLowPolyInt, false); - btMechanik2.Init("mechanik2", mdLowPolyInt, false); + btMechanik1.Init( "mechanik1", mdLowPolyInt, false); + btMechanik2.Init( "mechanik2", mdLowPolyInt, false); TurnOff(); // resetowanie zmiennych submodeli if( mdLowPolyInt != nullptr ) { @@ -1929,23 +2080,26 @@ TDynamicObject::Init(std::string Name, // nazwa pojazdu, np. "EU07-424" } } // wyszukiwanie zderzakow - if (mdModel) // jeśli ma w czym szukać - for (int i = 0; i < 2; i++) - { - asAnimName = std::string("buffer_left0") + to_string(i + 1); - smBuforLewy[i] = mdModel->GetFromName(asAnimName); - if (smBuforLewy[i]) - smBuforLewy[i]->WillBeAnimated(); // ustawienie flagi animacji - asAnimName = std::string("buffer_right0") + to_string(i + 1); - smBuforPrawy[i] = mdModel->GetFromName(asAnimName); - if (smBuforPrawy[i]) - smBuforPrawy[i]->WillBeAnimated(); + if( mdModel ) { + // jeśli ma w czym szukać + for( int i = 0; i < 2; i++ ) { + asAnimName = std::string( "buffer_left0" ) + to_string( i + 1 ); + smBuforLewy[ i ] = mdModel->GetFromName( asAnimName ); + if( smBuforLewy[ i ] ) + smBuforLewy[ i ]->WillBeAnimated(); // ustawienie flagi animacji + asAnimName = std::string( "buffer_right0" ) + to_string( i + 1 ); + smBuforPrawy[ i ] = mdModel->GetFromName( asAnimName ); + if( smBuforPrawy[ i ] ) + smBuforPrawy[ i ]->WillBeAnimated(); } - for (int i = 0; i < iAxles; i++) // wyszukiwanie osi (0 jest na końcu, dlatego dodajemy - // długość?) - dRailPosition[i] = - (Reversed ? -dWheelsPosition[i] : (dWheelsPosition[i] + MoverParameters->Dim.L)) + - fDist; + } + for( int i = 0; i < iAxles; i++ ) { + // wyszukiwanie osi (0 jest na końcu, dlatego dodajemy długość?) + dRailPosition[ i ] = ( + Reversed ? + -dWheelsPosition[ i ] : + ( dWheelsPosition[ i ] + MoverParameters->Dim.L ) ) + fDist; + } // McZapkie-250202 end. Track->AddDynamicObject(this); // wstawiamy do toru na pozycję 0, a potem przesuniemy // McZapkie: zmieniono na ilosc osi brane z chk @@ -1971,9 +2125,8 @@ TDynamicObject::Init(std::string Name, // nazwa pojazdu, np. "EU07-424" fDist -= 0.5 * MoverParameters->Dim.L; // dodajemy pół długości pojazdu, bo // ustawiamy jego środek (zliczanie na // minus) - switch (iNumAxles) - { // Ra: pojazdy wstawiane są na tor początkowy, a potem - // przesuwane + switch (iNumAxles) { + // Ra: pojazdy wstawiane są na tor początkowy, a potem przesuwane case 2: // ustawianie osi na torze Axle0.Init(Track, this, iDirection ? 1 : -1); Axle0.Move((iDirection ? fDist : -fDist) + fAxleDistHalf, false); @@ -1998,12 +2151,10 @@ TDynamicObject::Init(std::string Name, // nazwa pojazdu, np. "EU07-424" // Axle3.Move((iDirection?fDist:-fDist)+(fAxleDistHalf-MoverParameters->ADist*0.5),false); break; } - Move(0.0001); // potrzebne do wyliczenia aktualnej pozycji; nie może być zero, - // bo nie przeliczy - // pozycji - // teraz jeszcze trzeba przypisać pojazdy do nowego toru, bo przesuwanie - // początkowe osi nie + // potrzebne do wyliczenia aktualnej pozycji; nie może być zero, bo nie przeliczy pozycji + // teraz jeszcze trzeba przypisać pojazdy do nowego toru, bo przesuwanie początkowe osi nie // zrobiło tego + Move( 0.0001 ); ABuCheckMyTrack(); // zmiana toru na ten, co oś Axle0 (oś z przodu) TLocation loc; // Ra: ustawienie pozycji do obliczania sprzęgów loc.X = -vPosition.x; @@ -2029,6 +2180,7 @@ TDynamicObject::Init(std::string Name, // nazwa pojazdu, np. "EU07-424" MoverParameters->ComputeConstans(); // wektor podłogi dla wagonów, przesuwa ładunek vFloor = vector3(0, 0, MoverParameters->Floor); + // długość większa od zera oznacza OK; 2mm docisku? return MoverParameters->Dim.L; } @@ -2260,13 +2412,10 @@ void TDynamicObject::AttachPrev(TDynamicObject *Object, int iType) loc.Z=Object->vPosition.y; Object->MoverParameters->Loc=loc; //ustawienie dodawanego pojazdu */ - MoverParameters->Attach(iDirection, Object->iDirection ^ 1, Object->MoverParameters, iType, - true); + MoverParameters->Attach(iDirection, Object->iDirection ^ 1, Object->MoverParameters, iType, true); MoverParameters->Couplers[iDirection].Render = false; - Object->MoverParameters->Attach(Object->iDirection ^ 1, iDirection, MoverParameters, iType, - true); - Object->MoverParameters->Couplers[Object->iDirection ^ 1].Render = - true; // rysowanie sprzęgu w dołączanym + Object->MoverParameters->Attach(Object->iDirection ^ 1, iDirection, MoverParameters, iType, true); + Object->MoverParameters->Couplers[Object->iDirection ^ 1].Render = true; // rysowanie sprzęgu w dołączanym if (iDirection) { //łączenie standardowe NextConnected = Object; // normalnie doczepiamy go sobie do sprzęgu 1 @@ -2310,9 +2459,10 @@ bool TDynamicObject::UpdateForce(double dt, double dt1, bool FullVer) { if (!bEnabled) return false; - if (dt > 0) - MoverParameters->ComputeTotalForce(dt, dt1, - FullVer); // wywalenie WS zależy od ustawienia kierunku + if( dt > 0 ) { + // wywalenie WS zależy od ustawienia kierunku + MoverParameters->ComputeTotalForce( dt, dt1, FullVer ); + } return true; } @@ -2895,9 +3045,7 @@ bool TDynamicObject::Update(double dt, double dt1) } // McZapkie-260202 - dMoveLen przyda sie przy stukocie kol - dDOMoveLen = - GetdMoveLen() + MoverParameters->ComputeMovement(dt, dt1, ts, tp, tmpTraction, l, r); - // if (dDOMoveLen!=0.0) //Ra: nie może być, bo blokuje Event0 + dDOMoveLen = GetdMoveLen() + MoverParameters->ComputeMovement(dt, dt1, ts, tp, tmpTraction, l, r); if( Mechanik ) Mechanik->MoveDistanceAdd( dDOMoveLen ); // dodanie aktualnego przemieszczenia Move(dDOMoveLen); @@ -2909,65 +3057,52 @@ bool TDynamicObject::Update(double dt, double dt1) Global::ABuDebug = dDOMoveLen / dt1; ResetdMoveLen(); -#ifdef EU07_USE_OLD_SOUNDCODE // McZapkie-260202 // tupot mew, tfu, stukot kol: - // taka prowizorka zeby sciszyc stukot dalekiej lokomotywy - double ObjectDist; - double vol = 0; - ObjectDist = SquareMagnitude(Global::pCameraPosition - vPosition); - // McZapkie-270202 - if (MyTrack->fSoundDistance != -1) - { - if (ObjectDist < rsStukot[0].dSoundAtt * rsStukot[0].dSoundAtt * 15.0) - { - vol = (20.0 + MyTrack->iDamageFlag) / 21; - if (MyTrack->eEnvironment == e_tunnel) - { - vol *= 1.1; - // freq=1.02; + if( MyTrack->fSoundDistance != -1 ) { + + if( MyTrack->fSoundDistance != dRailLength ) { + dRailLength = MyTrack->fSoundDistance; + for( int i = 0; i < iAxles; ++i ) { + dRailPosition[ i ] = dWheelsPosition[ i ] + MoverParameters->Dim.L; } - else if (MyTrack->eEnvironment == e_bridge) - { - vol *= 1.2; - // freq=0.99; //MC: stukot w zaleznosci od - // tego gdzie - // jest tor - } - if (MyTrack->fSoundDistance != dRailLength) - { - dRailLength = MyTrack->fSoundDistance; - for (int i = 0; i < iAxles; i++) - { - dRailPosition[i] = dWheelsPosition[i] + MoverParameters->Dim.L; + } + if( dRailLength != -1 ) { + if( std::abs( MoverParameters->V ) > 0 ) { + + double volume = ( 20.0 + MyTrack->iDamageFlag ) / 21; + switch( MyTrack->eEnvironment ) { + case e_tunnel: { + volume *= 1.1; + break; + } + case e_bridge: { + volume *= 1.2; + break; + } + default: { + break; + } } - } - if (dRailLength != -1) - { - if (abs(MoverParameters->V) > 0) - { - for (int i = 0; i < iAxles; i++) - { - dRailPosition[i] -= dDOMoveLen * Sign(dDOMoveLen); - if (dRailPosition[i] < 0) - { - // McZapkie-040302 - if (i == iAxles - 1) - { - rsStukot[0].Stop(); - MoverParameters->AccV += - 0.5 * GetVelocity() / (1 + MoverParameters->Vmax); - } - else - { - rsStukot[i + 1].Stop(); - } - rsStukot[i].Play(vol, 0, MechInside, vPosition); // poprawic pozycje o uklad osi - if (i == 1) - MoverParameters->AccV -= - 0.5 * GetVelocity() / (1 + MoverParameters->Vmax); - dRailPosition[i] += dRailLength; + + for( int i = 0; i < iAxles; ++i ) { + dRailPosition[ i ] -= dDOMoveLen * Sign( dDOMoveLen ); + if( dRailPosition[ i ] < 0 ) { +/* + // McZapkie-040302 + if( i == iAxles - 1 ) { + rsStukot[ 0 ].stop(); + MoverParameters->AccV += 0.5 * GetVelocity() / ( 1 + MoverParameters->Vmax ); } + else { + rsStukot[ i + 1 ].stop(); + } + if( i == 1 ) { + MoverParameters->AccV -= 0.5 * GetVelocity() / ( 1 + MoverParameters->Vmax ); + } +*/ + rsStukot[ i ].gain( volume ).play(); + dRailPosition[ i ] += dRailLength; } } } @@ -2975,32 +3110,6 @@ bool TDynamicObject::Update(double dt, double dt1) } // McZapkie-260202 end - // yB: przyspieszacz (moze zadziala, ale dzwiek juz jest) - int flag = MoverParameters->Hamulec->GetSoundFlag(); - if ((bBrakeAcc) && (TestFlag(flag, sf_Acc)) && (ObjectDist < 2500)) - { - sBrakeAcc->SetVolume(-ObjectDist * 3 - (FreeFlyModeFlag ? 0 : 2000)); - sBrakeAcc->Play(0, 0, 0); - sBrakeAcc->SetPan(10000 * sin(ModCamRot)); - } - if ((rsUnbrake.AM != 0) && (ObjectDist < 5000)) - { - if ((TestFlag(flag, sf_CylU)) && - ((MoverParameters->BrakePress * MoverParameters->MaxBrakePress[3]) > 0.05)) - { - vol = Min0R( - 0.2 + - 1.6 * sqrt((MoverParameters->BrakePress > 0 ? MoverParameters->BrakePress : 0) / - MoverParameters->MaxBrakePress[3]), - 1); - vol = vol + (FreeFlyModeFlag ? 0 : -0.5) - ObjectDist / 5000; - rsUnbrake.SetPan(10000 * sin(ModCamRot)); - rsUnbrake.Play(vol, DSBPLAY_LOOPING, MechInside, GetPosition()); - } - else - rsUnbrake.Stop(); - } -#endif // fragment z EXE Kursa /* if (MoverParameters->TrainType==dt_ET42) { @@ -3112,11 +3221,12 @@ bool TDynamicObject::Update(double dt, double dt1) { if( ( MoverParameters->PantFrontVolt == 0.0 ) && ( MoverParameters->PantRearVolt == 0.0 ) ) { -#ifdef EU07_USE_OLD_SOUNDCODE - sPantUp.Play( vol, 0, MechInside, vPosition ); -#else - sPantUp.play(); -#endif + for( auto &pantograph : m_pantographsounds ) { + if( pantograph.sPantUp.offset().z > 0 ) { + // limit to pantographs located in the front half of the vehicle + pantograph.sPantUp.play( sound_flags::exclusive ); + } + } } if (p->hvPowerWire) { // TODO: wyliczyć trzeba prąd przypadający na pantograf i wstawić do GetVoltage() @@ -3144,11 +3254,12 @@ bool TDynamicObject::Update(double dt, double dt1) { if( ( MoverParameters->PantRearVolt == 0.0 ) && ( MoverParameters->PantFrontVolt == 0.0 ) ) { -#ifdef EU07_USE_OLD_SOUNDCODE - sPantUp.Play( vol, 0, MechInside, vPosition ); -#else - sPantUp.play(); -#endif + for( auto &pantograph : m_pantographsounds ) { + if( pantograph.sPantUp.offset().z < 0 ) { + // limit to pantographs located in the rear half of the vehicle + pantograph.sPantUp.play( sound_flags::exclusive ); + } + } } if (p->hvPowerWire) { // TODO: wyliczyć trzeba prąd przypadający na pantograf i wstawić do GetVoltage() @@ -3235,20 +3346,22 @@ bool TDynamicObject::Update(double dt, double dt1) } // koniec pętli po pantografach if ((MoverParameters->PantFrontSP == false) && (MoverParameters->PantFrontUp == false)) { -#ifdef EU07_USE_OLD_SOUNDCODE - sPantDown.Play(vol, 0, MechInside, vPosition); -#else - sPantDown.play(); -#endif + for( auto &pantograph : m_pantographsounds ) { + if( pantograph.sPantDown.offset().z > 0 ) { + // limit to pantographs located in the front half of the vehicle + pantograph.sPantDown.play( sound_flags::exclusive ); + } + } MoverParameters->PantFrontSP = true; } if ((MoverParameters->PantRearSP == false) && (MoverParameters->PantRearUp == false)) { -#ifdef EU07_USE_OLD_SOUNDCODE - sPantDown.Play(vol, 0, MechInside, vPosition); -#else - sPantDown.play(); -#endif + for( auto &pantograph : m_pantographsounds ) { + if( pantograph.sPantDown.offset().z < 0 ) { + // limit to pantographs located in the rear half of the vehicle + pantograph.sPantDown.play( sound_flags::exclusive ); + } + } MoverParameters->PantRearSP = true; } /* @@ -3349,59 +3462,29 @@ bool TDynamicObject::Update(double dt, double dt1) } // NBMX Obsluga drzwi, MC: zuniwersalnione - if ((dDoorMoveL < MoverParameters->DoorMaxShiftL) && (MoverParameters->DoorLeftOpened)) - { -#ifdef EU07_USE_OLD_SOUNDCODE - rsDoorOpen.Play(1, 0, MechInside, vPosition); -#else - rsDoorClose.stop(); - rsDoorOpen.play(); -#endif - dDoorMoveL += dt1 * 0.5 * MoverParameters->DoorOpenSpeed; - } - if ((dDoorMoveL > 0) && (!MoverParameters->DoorLeftOpened)) - { -#ifdef EU07_USE_OLD_SOUNDCODE - rsDoorClose.Play(1, 0, MechInside, vPosition); -#else - rsDoorOpen.stop(); - rsDoorClose.play(); -#endif - dDoorMoveL -= dt1 * MoverParameters->DoorCloseSpeed; - if (dDoorMoveL < 0) - dDoorMoveL = 0; + if( ( dDoorMoveL < MoverParameters->DoorMaxShiftL ) + && ( true == MoverParameters->DoorLeftOpened ) ) { + dDoorMoveL += dt1 * MoverParameters->DoorOpenSpeed; + dDoorMoveL = std::min( dDoorMoveL, MoverParameters->DoorMaxShiftL ); } - if ((dDoorMoveR < MoverParameters->DoorMaxShiftR) && (MoverParameters->DoorRightOpened)) - { -#ifdef EU07_USE_OLD_SOUNDCODE - rsDoorOpen.Play(1, 0, MechInside, vPosition); -#else - rsDoorClose.stop(); - rsDoorOpen.play(); -#endif - dDoorMoveR += dt1 * 0.5 * MoverParameters->DoorOpenSpeed; + if( ( dDoorMoveL > 0 ) + && ( false == MoverParameters->DoorLeftOpened ) ) { + dDoorMoveL -= dt1 * MoverParameters->DoorCloseSpeed; + dDoorMoveL = std::max( dDoorMoveL, 0.0 ); + } + if( ( dDoorMoveR < MoverParameters->DoorMaxShiftR ) + && ( true == MoverParameters->DoorRightOpened ) ) { + dDoorMoveR += dt1 * MoverParameters->DoorOpenSpeed; + dDoorMoveR = std::min( dDoorMoveR, MoverParameters->DoorMaxShiftR ); } - if ((dDoorMoveR > 0) && (!MoverParameters->DoorRightOpened)) - { -#ifdef EU07_USE_OLD_SOUNDCODE - rsDoorClose.Play(1, 0, MechInside, vPosition); -#else - rsDoorOpen.stop(); - rsDoorClose.play(); -#endif + if( ( dDoorMoveR > 0 ) + && ( false == MoverParameters->DoorRightOpened ) ) { dDoorMoveR -= dt1 * MoverParameters->DoorCloseSpeed; - if (dDoorMoveR < 0) - dDoorMoveR = 0; + dDoorMoveR = std::max( dDoorMoveR, 0.0 ); } // compartment lights -/* - if( ( ctOwner != nullptr ? - ctOwner->Controlling()->Battery != SectionLightsActive : - MoverParameters->Battery != SectionLightsActive ) ) { - // if the vehicle has a controller, we base the light state on state of the controller otherwise we check the vehicle itself -*/ - // the version above won't work as the vehicles don't turn batteries off :| + // if the vehicle has a controller, we base the light state on state of the controller otherwise we check the vehicle itself if( ( ctOwner != nullptr ? ctOwner->Controlling()->Battery != SectionLightsActive : SectionLightsActive == true ) ) { // without controller lights are off. NOTE: this likely mess up the EMU @@ -3516,241 +3599,147 @@ void TDynamicObject::TurnOff() // przeliczanie dźwięków, bo będzie słychać bez wyświetlania sektora z pojazdem void TDynamicObject::RenderSounds() { -#ifdef EU07_USE_OLD_SOUNDCODE - // McZapkie-010302: ulepszony dzwiek silnika - double freq; - double vol = 0; - double dt = Timer::GetDeltaRenderTime(); - if (MoverParameters->Power > 0) - { - if ((rsSilnik.AM != 0) - && ((MoverParameters->Mains) - // McZapkie-280503: zeby dla dumb dzialal silnik na jalowych obrotach - || (MoverParameters->EngineType == DieselEngine))) - { - if ((fabs(MoverParameters->enrot) > 0.01) || - (MoverParameters->EngineType == Dumb)) //&& (MoverParameters->EnginePower>0.1)) - { - freq = rsSilnik.FM * fabs(MoverParameters->enrot) + rsSilnik.FA; - if (MoverParameters->EngineType == Dumb) - freq = freq - 0.2 * MoverParameters->EnginePower / (1 + MoverParameters->Power * 1000); - rsSilnik.AdjFreq(freq, dt); - if (MoverParameters->EngineType == DieselEngine) - { - if (MoverParameters->enrot > 0) - { - if (MoverParameters->EnginePower > 0) - vol = rsSilnik.AM * MoverParameters->dizel_fill + rsSilnik.AA; - else - vol = - rsSilnik.AM * fabs(MoverParameters->enrot / MoverParameters->dizel_nmax) + - rsSilnik.AA * 0.9; + // McZapkie-010302: ulepszony dzwiek silnika + double frequency { 1.0 }; + double volume { 1.0 }; + double const dt { Timer::GetDeltaRenderTime() }; + + // engine sounds + if( MoverParameters->Power > 0 ) { + + if( ( true == MoverParameters->Mains ) + || ( MoverParameters->EngineType == DieselEngine ) ) { + + if( ( std::fabs( MoverParameters->enrot ) > 0.01 ) + // McZapkie-280503: zeby dla dumb dzialal silnik na jalowych obrotach + || ( MoverParameters->EngineType == Dumb ) ) { + + // frequency calculation + frequency = rsSilnik.m_frequencyfactor * std::fabs( MoverParameters->enrot ) + rsSilnik.m_frequencyoffset; + if( MoverParameters->EngineType == Dumb ) { + frequency -= 0.2 * MoverParameters->EnginePower / ( 1 + MoverParameters->Power * 1000 ); + } + + // base volume calculation + switch( MoverParameters->EngineType ) { + case DieselEngine: { + if( MoverParameters->enrot > 0.0 ) { + if( MoverParameters->EnginePower > 0 ) { + volume = rsSilnik.m_amplitudefactor * MoverParameters->dizel_fill + rsSilnik.m_amplitudeoffset; + } + else { + volume = rsSilnik.m_amplitudefactor * std::fabs( MoverParameters->enrot / MoverParameters->dizel_nmax ) + rsSilnik.m_amplitudeoffset * 0.9f; + } + } + else { + volume = 0.f; + } + break; + } + case DieselElectric: { + volume = + rsSilnik.m_amplitudefactor * ( MoverParameters->EnginePower / 1000 / MoverParameters->Power ) + + 0.2 * ( MoverParameters->enrot * 60 ) / ( MoverParameters->DElist[ MoverParameters->MainCtrlPosNo ].RPM ) + + rsSilnik.m_amplitudeoffset; + break; + } + case ElectricInductionMotor: { + volume = + rsSilnik.m_amplitudefactor * ( MoverParameters->EnginePower + std::fabs( MoverParameters->enrot * 2 ) ) + + rsSilnik.m_amplitudeoffset; + break; + } + default: { + volume = + rsSilnik.m_amplitudefactor * ( MoverParameters->EnginePower / 1000 + std::fabs( MoverParameters->enrot ) * 60.0 ) + + rsSilnik.m_amplitudeoffset; + break; } - else - vol = 0; } - else if (MoverParameters->EngineType == DieselElectric) - vol = rsSilnik.AM * - (MoverParameters->EnginePower / 1000 / MoverParameters->Power) + - 0.2 * (MoverParameters->enrot * 60) / - (MoverParameters->DElist[MoverParameters->MainCtrlPosNo].RPM) + - rsSilnik.AA; - else if (MoverParameters->EngineType == ElectricInductionMotor) - vol = rsSilnik.AM * - (MoverParameters->EnginePower + fabs(MoverParameters->enrot * 2)) + - rsSilnik.AA; - else - vol = rsSilnik.AM * (MoverParameters->EnginePower / 1000 + - fabs(MoverParameters->enrot) * 60.0) + - rsSilnik.AA; - // McZapkie-250302 - natezenie zalezne od obrotow i mocy - if ((vol < 1) && (MoverParameters->EngineType == ElectricSeriesMotor) && - (MoverParameters->EnginePower < 100)) - { - float volrnd = - Random(100) * MoverParameters->enrot / (1 + MoverParameters->nmax); - if (volrnd < 2) - vol = vol + volrnd / 200.0; + + if( MoverParameters->EngineType == ElectricSeriesMotor ) { + + // volume variation + if( ( volume < 1.0 ) + && ( MoverParameters->EnginePower < 100 ) ) { + + auto const volumevariation{ Random( 100 ) * MoverParameters->enrot / ( 1 + MoverParameters->nmax ) }; + if( volumevariation < 2 ) { + volume += volumevariation / 200; + } + } + + if( ( MoverParameters->DynamicBrakeFlag ) + && ( MoverParameters->EnginePower > 0.1 ) ) { + // Szociu - 29012012 - jeżeli uruchomiony jest hamulec elektrodynamiczny, odtwarzany jest dźwięk silnika + volume += 0.8; + } } + + // volume environmental factor switch( MyTrack->eEnvironment ) { case e_tunnel: { - vol += 0.1; + volume += 0.1; break; } case e_canyon: { - vol += 0.05; + volume += 0.05; break; } default: { break; } } - if( ( MoverParameters->DynamicBrakeFlag ) - && ( MoverParameters->EnginePower > 0.1 ) - && ( MoverParameters->EngineType == ElectricSeriesMotor ) ) - // Szociu - 29012012 - jeżeli uruchomiony jest hamulec elektrodynamiczny, odtwarzany jest dźwięk silnika - vol += 0.8; - if (enginevolume > 0.0001) - if (MoverParameters->EngineType != DieselElectric) - { - rsSilnik.Play(enginevolume, DSBPLAY_LOOPING, MechInside, GetPosition()); + if( enginevolume >= 0.05 ) { + + if( MoverParameters->EngineType != DieselElectric ) { + + rsSilnik + .pitch( frequency ) + .gain( enginevolume ) + .play( sound_flags::exclusive | sound_flags::looping ); } - else - { - sConverter.UpdateAF(vol, freq, MechInside, GetPosition()); + else { - float fincvol; - fincvol = 0; - if ((MoverParameters->ConverterFlag) && - (MoverParameters->enrot * 60 > MoverParameters->DElist[0].RPM)) - { - fincvol = (MoverParameters->DElist[MoverParameters->MainCtrlPos].RPM - - (MoverParameters->enrot * 60)); - fincvol /= (0.05 * MoverParameters->DElist[0].RPM); + sConverter + .pitch( frequency ) + .gain( volume ) + .play( sound_flags::exclusive | sound_flags::looping ); + + float fincvol { 0 }; + if( ( MoverParameters->ConverterFlag ) + && ( MoverParameters->enrot * 60 > MoverParameters->DElist[ 0 ].RPM ) ) { + + fincvol = ( MoverParameters->DElist[ MoverParameters->MainCtrlPos ].RPM - ( MoverParameters->enrot * 60 ) ); + fincvol /= ( 0.05 * MoverParameters->DElist[ 0 ].RPM ); }; - if (fincvol > 0.02) - rsDiesielInc.Play(fincvol, DSBPLAY_LOOPING, MechInside, GetPosition()); - else - rsDiesielInc.Stop(); + if( fincvol > 0.02 ) { + rsDieselInc + .gain( fincvol ) + .play( sound_flags::exclusive | sound_flags::looping ); + } + else { + rsDieselInc.stop(); + } } - } - else - rsSilnik.Stop(); - } - enginevolume = (enginevolume + vol) * 0.5; - if( enginevolume < 0.01 ) { - rsSilnik.Stop(); - } - if ( ( MoverParameters->EngineType == ElectricSeriesMotor ) - || ( MoverParameters->EngineType == ElectricInductionMotor ) - && ( rsWentylator.AM != 0 ) ) - { - if (MoverParameters->RventRot > 0.1) { - // play ventilator sound if the ventilators are rotating fast enough... - freq = rsWentylator.FM * MoverParameters->RventRot + rsWentylator.FA; - rsWentylator.AdjFreq(freq, dt); - if( MoverParameters->EngineType == ElectricInductionMotor ) { - - vol = rsWentylator.AM * std::sqrt( std::fabs( MoverParameters->dizel_fill ) ) + rsWentylator.AA; } - else { - - vol = rsWentylator.AM * MoverParameters->RventRot + rsWentylator.AA; - } - rsWentylator.Play(vol, DSBPLAY_LOOPING, MechInside, GetPosition()); } else { - // ...otherwise shut down the sound - rsWentylator.Stop(); + rsSilnik.stop(); } } - if (MoverParameters->TrainType == dt_ET40) - { - if (MoverParameters->Vel > 0.1) - { - freq = rsPrzekladnia.FM * (MoverParameters->Vel) + rsPrzekladnia.FA; - rsPrzekladnia.AdjFreq(freq, dt); - vol = rsPrzekladnia.AM * (MoverParameters->Vel) + rsPrzekladnia.AA; - rsPrzekladnia.Play(vol, DSBPLAY_LOOPING, MechInside, GetPosition()); - } - else - rsPrzekladnia.Stop(); + enginevolume = ( enginevolume + volume ) * 0.5; + if( enginevolume < 0.05 ) { + rsSilnik.stop(); } - } - - // youBy: dzwiek ostrych lukow i ciasnych zwrotek - - if ((ts.R * ts.R > 1) && (MoverParameters->Vel > 0)) - vol = MoverParameters->AccN * MoverParameters->AccN; - else - vol = 0; - // vol+=(50000/ts.R*ts.R); - - if (vol > 0.001) - { - rscurve.Play(2 * vol, DSBPLAY_LOOPING, MechInside, GetPosition()); - } - else - rscurve.Stop(); - - // McZapkie-280302 - pisk mocno zacisnietych hamulcow - trzeba jeszcze - // zabezpieczyc przed - // brakiem deklaracji w mmedia.dta - if (rsPisk.AM != 0) - { - if ((MoverParameters->Vel > (rsPisk.GetStatus() != 0 ? 0.01 : 0.5)) && - (!MoverParameters->SlippingWheels) && (MoverParameters->UnitBrakeForce > rsPisk.AM)) - { - vol = MoverParameters->UnitBrakeForce / (rsPisk.AM + 1) + rsPisk.AA; - rsPisk.Play(vol, DSBPLAY_LOOPING, MechInside, GetPosition()); - } - else - rsPisk.Stop(); - } - - if (MoverParameters->SandDose) // Dzwiek piasecznicy - sSand.TurnOn(MechInside, GetPosition()); - else - sSand.TurnOff(MechInside, GetPosition()); - sSand.Update(MechInside, GetPosition()); - if (MoverParameters->Hamulec->GetStatus() & b_rls) // Dzwiek odluzniacza - sReleaser.TurnOn(MechInside, GetPosition()); - else - sReleaser.TurnOff(MechInside, GetPosition()); - //sReleaser.Update(MechInside, GetPosition()); - double releaser_vol = 1; - if (MoverParameters->BrakePress < 0.1) - releaser_vol = MoverParameters->BrakePress * 10; - sReleaser.UpdateAF(releaser_vol, 1, MechInside, GetPosition()); - - // McZapkie! - dzwiek compressor.wav tylko gdy dziala sprezarka - if (MoverParameters->VeselVolume != 0) - { - if (MoverParameters->CompressorFlag) - sCompressor.TurnOn(MechInside, GetPosition()); - else - sCompressor.TurnOff(MechInside, GetPosition()); - sCompressor.Update(MechInside, GetPosition()); - } - if (MoverParameters->PantCompFlag) // Winger 160404 - dzwiek malej sprezarki - sSmallCompressor.TurnOn(MechInside, GetPosition()); - else - sSmallCompressor.TurnOff(MechInside, GetPosition()); - sSmallCompressor.Update(MechInside, GetPosition()); - - // youBy - przenioslem, bo diesel tez moze miec turbo - if( (MoverParameters->TurboTest > 0) - && (MoverParameters->MainCtrlPos >= MoverParameters->TurboTest)) - { - // udawanie turbo: (6.66*(eng_vol-0.85)) - if (eng_turbo > 6.66 * (enginevolume - 0.8) + 0.2 * dt) - eng_turbo = eng_turbo - 0.2 * dt; // 0.125 - else if (eng_turbo < 6.66 * (enginevolume - 0.8) - 0.4 * dt) - eng_turbo = eng_turbo + 0.4 * dt; // 0.333 - else - eng_turbo = 6.66 * (enginevolume - 0.8); - - sTurbo.TurnOn(MechInside, GetPosition()); - // sTurbo.UpdateAF(eng_turbo,0.7+(eng_turbo*0.6),MechInside,GetPosition()); - sTurbo.UpdateAF(3 * eng_turbo - 1, 0.4 + eng_turbo * 0.4, MechInside, GetPosition()); - // eng_vol_act=enginevolume; - // eng_frq_act=eng_frq; - } - else - sTurbo.TurnOff(MechInside, GetPosition()); - +/* +// NOTE: experimentally disabled to see if it's still used anywhere if (MoverParameters->TrainType == dt_PseudoDiesel) { // ABu: udawanie woodwarda dla lok. spalinowych // jesli silnik jest podpiety pod dzwiek przetwornicy - if (MoverParameters->ConverterFlag) // NBMX dzwiek przetwornicy - { - sConverter.TurnOn(MechInside, GetPosition()); - } - else - sConverter.TurnOff(MechInside, GetPosition()); // glosnosc zalezy od stosunku mocy silnika el. do mocy max double eng_vol; @@ -3812,105 +3801,505 @@ void TDynamicObject::RenderSounds() { eng_vol_act = eng_vol; // eng_frq_act=eng_frq; } - else - { - if (MoverParameters->ConverterFlag) // NBMX dzwiek przetwornicy - sConverter.TurnOn(MechInside, GetPosition()); - else - sConverter.TurnOff(MechInside, GetPosition()); - sConverter.Update(MechInside, GetPosition()); - } +*/ - if( TestFlag( MoverParameters->WarningSignal, 1 ) ) { - sHorn1.TurnOn( MechInside, GetPosition() ); - } - else { - sHorn1.TurnOff( MechInside, GetPosition() ); - } - if( TestFlag( MoverParameters->WarningSignal, 2 ) ) { - sHorn2.TurnOn( MechInside, GetPosition() ); - } - else { - sHorn2.TurnOff( MechInside, GetPosition() ); - } + if( ( MoverParameters->EngineType == ElectricSeriesMotor ) + || ( MoverParameters->EngineType == ElectricInductionMotor ) ) { - if (MoverParameters->DoorClosureWarning) - { - if (MoverParameters->DepartureSignal) // NBMX sygnal odjazdu, MC: pod warunkiem ze jest - // zdefiniowane w chk - sDepartureSignal.TurnOn(MechInside, GetPosition()); - else - sDepartureSignal.TurnOff(MechInside, GetPosition()); - sDepartureSignal.Update(MechInside, GetPosition()); - } - sHorn1.Update(MechInside, GetPosition()); - sHorn2.Update(MechInside, GetPosition()); - // McZapkie: w razie wykolejenia - if (MoverParameters->EventFlag) - { - if (TestFlag(MoverParameters->DamageFlag, dtrain_out) && GetVelocity() > 0) - rsDerailment.Play(1, 0, true, GetPosition()); - if (GetVelocity() == 0) - rsDerailment.Stop(); - } -#else -// McZapkie! - dzwiek compressor.wav tylko gdy dziala sprezarka -if( MoverParameters->VeselVolume != 0 ) { + if( MoverParameters->RventRot > 0.1 ) { + // play ventilator sound if the ventilators are rotating fast enough... + volume = ( + MoverParameters->EngineType == ElectricInductionMotor ? + rsWentylator.m_amplitudefactor * std::sqrt( std::fabs( MoverParameters->dizel_fill ) ) + rsWentylator.m_amplitudeoffset : + rsWentylator.m_amplitudefactor * MoverParameters->RventRot + rsWentylator.m_amplitudeoffset ); - if( MoverParameters->TrainType != dt_PseudoDiesel ) { - // NBMX dzwiek przetwornicy - if( MoverParameters->ConverterFlag ) { - sConverter.play(); + rsWentylator + .pitch( rsWentylator.m_frequencyfactor * MoverParameters->RventRot + rsWentylator.m_frequencyoffset ) + .gain( volume ) + .play( sound_flags::exclusive | sound_flags::looping ); + } + else { + // ...otherwise shut down the sound + rsWentylator.stop(); + } + } + + + if( MoverParameters->TrainType == dt_ET40 ) { + if( MoverParameters->Vel > 0.1 ) { + rsPrzekladnia + .pitch( rsPrzekladnia.m_frequencyfactor * ( MoverParameters->Vel ) + rsPrzekladnia.m_frequencyoffset ) + .gain( rsPrzekladnia.m_amplitudefactor * ( MoverParameters->Vel ) + rsPrzekladnia.m_amplitudeoffset ) + .play( sound_flags::exclusive | sound_flags::looping ); + } + else { + rsPrzekladnia.stop(); + } + } + + + if( MoverParameters->dizel_engage > 0.1 ) { + if( std::abs( MoverParameters->dizel_engagedeltaomega ) > 0.2 ) { + + frequency = rsEngageSlippery.m_frequencyfactor * std::fabs( MoverParameters->dizel_engagedeltaomega ) + rsEngageSlippery.m_frequencyoffset; + volume = rsEngageSlippery.m_amplitudefactor * ( MoverParameters->dizel_engage ) + rsEngageSlippery.m_amplitudeoffset; + } + else { + frequency = 1.f; // rsEngageSlippery.FA+0.7*rsEngageSlippery.FM*(fabs(mvControlled->enrot)+mvControlled->nmax); + volume = ( + MoverParameters->dizel_engage > 0.2 ? + 0.2 * rsEngageSlippery.m_amplitudefactor * ( MoverParameters->enrot / MoverParameters->nmax ) + rsEngageSlippery.m_amplitudeoffset : + 0.f ); + } + rsEngageSlippery + .pitch( frequency ) + .gain( volume ) + .play( sound_flags::exclusive | sound_flags::looping ); } else { - sConverter.stop(); + rsEngageSlippery.stop(); } + + + // youBy - przenioslem, bo diesel tez moze miec turbo + if( MoverParameters->TurboTest > 0 ) { + // udawanie turbo: + auto const goalpitch { 6.66 * ( enginevolume - 0.8 ) }; + auto const goalvolume{ 3 * eng_turbo - 1 }; + auto const currentvolume { sTurbo.gain() }; + auto const changerate{ 0.4 * dt }; + + if( ( MoverParameters->MainCtrlPos >= MoverParameters->TurboTest ) + && ( MoverParameters->enrot > 0.1 ) ) { + + eng_turbo = ( + eng_turbo > goalpitch ? + std::max( goalpitch, eng_turbo - changerate * 0.5 ) : + std::min( goalpitch, eng_turbo + changerate ) ); + + volume = ( + currentvolume > goalvolume ? + std::max( goalvolume, currentvolume - changerate ) : + std::min( goalvolume, currentvolume + changerate ) ); + + sTurbo + .pitch( eng_turbo * 0.4 + 0.4 ) + .gain( volume ) + .play( sound_flags::exclusive | sound_flags::looping ); + } + else { + eng_turbo = std::max( goalpitch, eng_turbo - changerate * 0.5 ); + volume = std::max( 0.0, sTurbo.gain() - 10.0 * dt ); + if( volume > 0.05 ) { + sTurbo + .pitch( 0.4 + eng_turbo * 0.4 ) + .gain( volume ); + } + else { + sTurbo.stop(); + } + } + } + + + // diesel startup + if( MoverParameters->EngineType == DieselEngine ) { + if( true == MoverParameters->dizel_enginestart ) { + dsbDieselIgnition.play( sound_flags::exclusive | sound_flags::looping ); + } + else { + dsbDieselIgnition.stop(); + } + } + + } // if enginepower + + // NBMX dzwiek przetwornicy + if( MoverParameters->ConverterFlag ) { + sConverter.play( sound_flags::exclusive | sound_flags::looping ); } else { + sConverter.stop(); } - if( MoverParameters->CompressorFlag ) { - sCompressor.play(); - } - else { - sCompressor.stop(); + if( MoverParameters->VeselVolume != 0 ) { + // McZapkie! - dzwiek compressor.wav tylko gdy dziala sprezarka + if( MoverParameters->CompressorFlag ) { + sCompressor.play( sound_flags::exclusive | sound_flags::looping ); + } + else { + sCompressor.stop(); + } } + + // Winger 160404 - dzwiek malej sprezarki if( MoverParameters->PantCompFlag ) { - // Winger 160404 - dzwiek malej sprezarki - sSmallCompressor.play(); + sSmallCompressor.play( sound_flags::exclusive | sound_flags::looping ); } else { sSmallCompressor.stop(); } - - if( TestFlag( MoverParameters->WarningSignal, 1 ) ) { - sHorn1.play(); + + // brake system and braking sounds: + if( m_lastbrakepressure != -1.f ) { + // calculate rate of pressure change in brake cylinder, once it's been initialized + auto const brakepressuredifference { m_lastbrakepressure - MoverParameters->BrakePress }; + m_brakepressurechange = interpolate( m_brakepressurechange, 10 * ( brakepressuredifference / dt ), 0.1f ); + } + m_lastbrakepressure = MoverParameters->BrakePress; + if( m_brakepressurechange > 0.05f ) { + // NOTE: can't use the leak rate directly due to irregular results produced by some brake type implementations + rsUnbrake + .gain( static_cast( std::max( MoverParameters->BrakePress, 0.0 ) / MoverParameters->MaxBrakePress[ 3 ] ) ) + .play( sound_flags::exclusive | sound_flags::looping ); } else { - sHorn1.stop(); - } - if( TestFlag( MoverParameters->WarningSignal, 2 ) ) { - sHorn2.play(); - } - else { - sHorn2.stop(); + // don't stop the sound too abruptly + volume = std::max( 0.0, rsUnbrake.gain() - 0.2 * dt ); + rsUnbrake.gain( volume ); + if( volume < 0.05 ) { + rsUnbrake.stop(); + } } + // Dzwiek odluzniacza + if( MoverParameters->Hamulec->GetStatus() & b_rls ) { + sReleaser + .gain( + clamp( + MoverParameters->BrakePress * 1.25f, // arbitrary multiplier + 0.f, 1.f ) ) + .play( sound_flags::exclusive | sound_flags::looping ); + } + else { + sReleaser.stop(); + } + + if( MoverParameters->SlippingWheels ) { + + if( ( MoverParameters->UnitBrakeForce > 100.0 ) + && ( GetVelocity() > 1.0 ) ) { + + auto const velocitydifference { GetVelocity() / MoverParameters->Vmax }; + rsSlippery + .gain( rsSlippery.m_amplitudefactor * velocitydifference + rsSlippery.m_amplitudeoffset ) + .play( sound_flags::exclusive | sound_flags::looping ); + } + } + else { + rsSlippery.stop(); + } + + // Dzwiek piasecznicy + if( MoverParameters->SandDose ) { + sSand.play( sound_flags::exclusive | sound_flags::looping ); + } + else { + sSand.stop(); + } + + if( /*( false == mvOccupied->SlippingWheels ) + &&*/ ( MoverParameters->UnitBrakeForce > 10.0 ) + && ( GetVelocity() > 0.05 ) ) { + + rsBrake + .pitch( clamp( rsBrake.m_frequencyfactor * GetVelocity() + rsBrake.m_frequencyoffset, 0.5, 1.15 ) ) // arbitrary limits + .gain( rsBrake.m_amplitudefactor * std::sqrt( ( GetVelocity() * MoverParameters->UnitBrakeForce ) ) + rsBrake.m_amplitudeoffset ) + .play( sound_flags::exclusive | sound_flags::looping ); + } + else { + rsBrake.stop(); + } + + // yB: przyspieszacz (moze zadziala, ale dzwiek juz jest) + if( true == bBrakeAcc ) { + if( true == TestFlag( MoverParameters->Hamulec->GetSoundFlag(), sf_Acc ) ) { + sBrakeAcc.play( sound_flags::exclusive ); + } + } + + // McZapkie-280302 - pisk mocno zacisnietych hamulcow + if( /*( false == MoverParameters->SlippingWheels ) + &&*/ ( MoverParameters->UnitBrakeForce > rsPisk.m_amplitudefactor ) + && ( MoverParameters->Vel > ( + true == rsPisk.is_playing() ? + 0.05 : + 0.5 ) ) ) { + + rsPisk + .gain( MoverParameters->UnitBrakeForce / ( rsPisk.m_amplitudefactor + 1 ) + rsPisk.m_amplitudeoffset ) + .play( sound_flags::exclusive | sound_flags::looping ); + } + else { + // don't stop the sound too abruptly + volume = std::max( 0.0, rsPisk.gain() - ( rsPisk.gain() * 1.5 * dt ) ); + rsPisk.gain( volume ); + if( volume < 0.05 ) { + rsPisk.stop(); + } + } + + // other sounds + // NBMX sygnal odjazdu if( MoverParameters->DoorClosureWarning ) { if( MoverParameters->DepartureSignal ) { - // NBMX sygnal odjazdu // MC: pod warunkiem ze jest zdefiniowane w chk - sDepartureSignal.play(); + sDepartureSignal.play( sound_flags::exclusive | sound_flags::looping ); } else { sDepartureSignal.stop(); } } + // NBMX Obsluga drzwi, MC: zuniwersalnione + if( ( true == MoverParameters->DoorLeftOpened ) + && ( dDoorMoveL < MoverParameters->DoorMaxShiftL ) ) { -} + for( auto &door : m_doorsounds ) { + if( door.rsDoorClose.offset().x > 0.f ) { + // determine left side doors from their offset + door.rsDoorOpen.play( sound_flags::exclusive ); + door.rsDoorClose.stop(); + } + } + } + if( ( false == MoverParameters->DoorLeftOpened ) + && ( dDoorMoveL > 0.01 ) ) { + + for( auto &door : m_doorsounds ) { + if( door.rsDoorClose.offset().x > 0.f ) { + // determine left side doors from their offset + door.rsDoorClose.play( sound_flags::exclusive ); + door.rsDoorOpen.stop(); + } + } + } + if( ( true == MoverParameters->DoorRightOpened ) + && ( dDoorMoveR < MoverParameters->DoorMaxShiftR ) ) { + + for( auto &door : m_doorsounds ) { + if( door.rsDoorClose.offset().x < 0.f ) { + // determine left side doors from their offset + door.rsDoorOpen.play( sound_flags::exclusive ); + door.rsDoorClose.stop(); + } + } + } + if( ( false == MoverParameters->DoorRightOpened ) + && ( dDoorMoveR > 0.01 ) ) { + + for( auto &door : m_doorsounds ) { + if( door.rsDoorClose.offset().x < 0.f ) { + // determine left side doors from their offset + door.rsDoorClose.play( sound_flags::exclusive ); + door.rsDoorOpen.stop(); + } + } + } + // horns + if( TestFlag( MoverParameters->WarningSignal, 1 ) ) { + sHorn1.play( sound_flags::exclusive | sound_flags::looping ); + } + else { + sHorn1.stop(); + } + if( TestFlag( MoverParameters->WarningSignal, 2 ) ) { + sHorn2.play( sound_flags::exclusive | sound_flags::looping ); + } + else { + sHorn2.stop(); + } + + // szum w czasie jazdy + if( GetVelocity() > 0.5 ) { + + volume = rsRunningNoise.m_amplitudefactor * MoverParameters->Vel + rsRunningNoise.m_amplitudeoffset; + frequency = rsRunningNoise.m_frequencyfactor * MoverParameters->Vel + rsRunningNoise.m_frequencyoffset; + + if( false == TestFlag( MoverParameters->DamageFlag, dtrain_wheelwear ) ) { + // McZpakie-221103: halas zalezny od kola + switch( MyTrack->eEnvironment ) { + case e_tunnel: { + volume *= 3; + frequency *= 0.95; + break; + } + case e_canyon: { + volume *= 1.1; + break; + } + case e_bridge: { + volume *= 2; + frequency *= 0.98; + break; + } + default: { + break; + } + } + } + else { + // uszkodzone kolo (podkucie) + switch( MyTrack->eEnvironment ) { + case e_tunnel: { + volume *= 2; + break; + } + case e_canyon: { + volume *= 1.1; + break; + } + case e_bridge: { + volume *= 1.5; + break; + } + default: { + break; + } + } + } + if( std::abs( MoverParameters->nrot ) > 0.01 ) { + // hamulce wzmagaja halas + volume *= 1 + MoverParameters->UnitBrakeForce / ( 1 + MoverParameters->MaxBrakeForce ); + } + // scale volume by track quality + volume *= ( 20.0 + MyTrack->iDamageFlag ) / 21; + // scale volume with curve radius and vehicle speed + // TBD, TODO: disable the scaling for sounds combined from speed-based samples? + volume *= + interpolate( + 0.0, 1.0, + clamp( + MoverParameters->Vel / 80.0, + 0.0, 1.0 ) ); + rsRunningNoise + .pitch( clamp( frequency, 0.5, 1.15 ) ) // arbitrary limits to prevent the pitch going out of whack + .gain( volume ) + .play( sound_flags::exclusive | sound_flags::looping ); + } + else { + rsRunningNoise.stop(); + } + + // youBy: dzwiek ostrych lukow i ciasnych zwrotek + if( ( ts.R * ts.R > 1 ) + && ( MoverParameters->Vel > 0 ) ) { + // scale volume with curve radius and vehicle speed + volume = + MoverParameters->AccN * MoverParameters->AccN + * interpolate( + 0.0, 1.0, + clamp( + MoverParameters->Vel / 40.0, + 0.0, 1.0 ) ); + } + else { + volume = 0; + } + if( volume > 0.05 ) { + rscurve + .gain( 2.0 * volume ) + .play( sound_flags::exclusive | sound_flags::looping ); + } + else { + rscurve.stop(); + } + + // McZapkie! - to wazne - SoundFlag wystawiane jest przez moje moduly + // gdy zachodza pewne wydarzenia komentowane dzwiekiem. + if( TestFlag( MoverParameters->SoundFlag, sound::relay ) ) { + // przekaznik - gdy bezpiecznik, automatyczny rozruch itp + if( true == TestFlag( MoverParameters->SoundFlag, sound::parallel ) ) { + if( TestFlag( MoverParameters->SoundFlag, sound::loud ) ) + dsbWejscie_na_bezoporow.play(); + else + dsbWejscie_na_drugi_uklad.play(); + } + else { + dsbRelay + .gain( + true == TestFlag( MoverParameters->SoundFlag, sound::loud ) ? + 1.0f : + 0.8f ) + .play(); + } + } + + if( TestFlag( MoverParameters->SoundFlag, sound::pneumatic ) ) { + // pneumatic relay + dsbPneumaticRelay + .gain( + true == TestFlag( MoverParameters->SoundFlag, sound::loud ) ? + 1.0f : + 0.8f ) + .play(); + } + + // couplers + int couplerindex { 0 }; + for( auto &couplersounds : m_couplersounds ) { + + auto &coupler { MoverParameters->Couplers[ couplerindex ] }; + + if( true == TestFlag( coupler.sounds, sound::bufferclash ) ) { + // zderzaki uderzaja o siebie + couplersounds.dsbBufferClamp + .gain( + true == TestFlag( coupler.sounds, sound::loud ) ? + 1.f : + 0.65f ) + .play( sound_flags::exclusive ); + } + if( true == TestFlag( coupler.sounds, sound::couplerstretch ) ) { + // sprzegi sie rozciagaja + couplersounds.dsbCouplerStretch + .gain( + true == TestFlag( coupler.sounds, sound::loud ) ? + 1.f : + 0.65f ) + .play( sound_flags::exclusive ); + } + + coupler.sounds = 0; + ++couplerindex; + } + + MoverParameters->SoundFlag = 0; + // McZapkie! - koniec obslugi dzwiekow z mover.pas + +// special events + if( MoverParameters->EventFlag ) { + // TODO: dedicated sound, played alongside regular noise + if( true == TestFlag( MoverParameters->DamageFlag, dtrain_wheelwear ) ) { +#ifdef EU07_USE_OLD_SOUNDCODE + if( rsRunningNoise.AM != 0 ) { + rsRunningNoise.Stop(); + float am = rsRunningNoise.AM; + float fa = rsRunningNoise.FA; + float fm = rsRunningNoise.FM; + rsRunningNoise.Init( "lomotpodkucia.wav", -1, 0, 0, 0, true ); // MC: zmiana szumu na lomot + if( rsRunningNoise.AM == 1 ) + rsRunningNoise.AM = am; + rsRunningNoise.AA = 0.7; + rsRunningNoise.FA = fa; + rsRunningNoise.FM = fm; + } +#else #endif -}; + } + // McZapkie: w razie wykolejenia + if( true == TestFlag( MoverParameters->DamageFlag, dtrain_out ) ) { + if( GetVelocity() > 0 ) { + rsDerailment.play(); + } + else { + rsDerailment.stop(); + } + } + + MoverParameters->EventFlag = false; + } +} // McZapkie-250202 // wczytywanie pliku z danymi multimedialnymi (dzwieki) @@ -4421,37 +4810,42 @@ void TDynamicObject::LoadMMediaFile( std::string BaseDir, std::string TypeName, pant1x = -pant1x; pant2x = -pant2x; } - if( pants ) { - for( int i = 0; i < iAnimType[ ANIM_PANTS ]; ++i ) { // przepisanie współczynników do pantografów (na razie - // nie będzie lepiej) - pants[ i ].fParamPants->fAngleL = - pants[i].fParamPants->fAngleL0; // początkowy kąt dolnego ramienia - pants[ i ].fParamPants->fAngleU = - pants[i].fParamPants->fAngleU0; // początkowy kąt + if( pants ) { + for( int i = 0; i < iAnimType[ ANIM_PANTS ]; ++i ) { + // przepisanie współczynników do pantografów (na razie nie będzie lepiej) + pants[ i ].fParamPants->fAngleL = pants[ i ].fParamPants->fAngleL0; // początkowy kąt dolnego ramienia + pants[ i ].fParamPants->fAngleU = pants[ i ].fParamPants->fAngleU0; // początkowy kąt // pants[i].fParamPants->PantWys=1.22*sin(pants[i].fParamPants->fAngleL)+1.755*sin(pants[i].fParamPants->fAngleU); // //wysokość początkowa // pants[i].fParamPants->PantWys=1.176289*sin(pants[i].fParamPants->fAngleL)+1.724482197*sin(pants[i].fParamPants->fAngleU); // //wysokość początkowa - if( pants[ i ].fParamPants->fHeight == 0.0 ) // gdy jest nieprawdopodobna wartość (np. nie znaleziony ślizg) + if( pants[ i ].fParamPants->fHeight == 0.0 ) // gdy jest nieprawdopodobna wartość (np. nie znaleziony ślizg) { // gdy pomiary modelu nie udały się, odczyt podanych parametrów z MMD - pants[ i ].fParamPants->vPos.x = ( i & 1 ) ? pant2x : pant1x; - pants[ i ].fParamPants->fHeight = - ( i & 1 ) ? pant2h : - pant1h; // wysokość ślizgu jest zapisana w MMD + pants[ i ].fParamPants->vPos.x = + ( i & 1 ) ? + pant2x : + pant1x; + pants[ i ].fParamPants->fHeight = + ( i & 1 ) ? + pant2h : + pant1h; // wysokość ślizgu jest zapisana w MMD } - pants[ i ].fParamPants->PantWys = - pants[ i ].fParamPants->fLenL1 * sin( pants[ i ].fParamPants->fAngleL ) + - pants[ i ].fParamPants->fLenU1 * sin( pants[ i ].fParamPants->fAngleU ) + - pants[i].fParamPants->fHeight; // wysokość początkowa + pants[ i ].fParamPants->PantWys = + pants[ i ].fParamPants->fLenL1 * sin( pants[ i ].fParamPants->fAngleL ) + + pants[ i ].fParamPants->fLenU1 * sin( pants[ i ].fParamPants->fAngleU ) + + pants[ i ].fParamPants->fHeight; // wysokość początkowa // pants[i].fParamPants->vPos.y=panty-panth-pants[i].fParamPants->PantWys; // //np. 4.429-0.097=4.332=~4.335 // pants[i].fParamPants->vPos.z=0; //niezerowe dla pantografów // asymetrycznych - pants[ i ].fParamPants->PantTraction = pants[ i ].fParamPants->PantWys; + pants[ i ].fParamPants->PantTraction = pants[ i ].fParamPants->PantWys; // połowa szerokości ślizgu; jest w "Power: CSW=" - pants[ i ].fParamPants->fWidth = 0.5 * MoverParameters->EnginePowerSource.CollectorParameters.CSW; + pants[ i ].fParamPants->fWidth = 0.5 * MoverParameters->EnginePowerSource.CollectorParameters.CSW; + + // create sound emitters for the pantograph + m_pantographsounds.emplace_back(); } - } + } } else if (token == "animpistonprefix:") { @@ -4553,16 +4947,16 @@ void TDynamicObject::LoadMMediaFile( std::string BaseDir, std::string TypeName, */ else if( token == "animdoorprefix:" ) { - // nazwa animowanych drzwi + // nazwa animowanych drzwi int i, j; parser.getTokens(1, false); parser >> token; for (i = 0, j = 0; i < ANIM_DOORS; ++i) j += iAnimType[i]; // zliczanie wcześniejszych animacji for (i = 0; i < iAnimType[ANIM_DOORS]; ++i) // liczba drzwi { // NBMX wrzesien 2003: wyszukiwanie drzwi o nazwie str* + // ustalenie submodelu asAnimName = token + std::to_string(i + 1); - pAnimations[i + j].smAnimated = - mdModel->GetFromName(asAnimName); // ustalenie submodelu + pAnimations[i + j].smAnimated = mdModel->GetFromName(asAnimName); if (pAnimations[i + j].smAnimated) { //++iAnimatedDoors; pAnimations[i + j].smAnimated->WillBeAnimated(); // wyłączenie optymalizacji transformu @@ -4589,13 +4983,15 @@ void TDynamicObject::LoadMMediaFile( std::string BaseDir, std::string TypeName, pAnimations[i + j].fSpeed = (pAnimations[i + j].fSpeed + 100) / 100; // Ra: te współczynniki są bez sensu, bo modyfikują wektor przesunięcia } + // create sound emitters for the door + m_doorsounds.emplace_back(); } } } while( ( token != "" ) && ( token != "endmodels" ) ); - } + } // models else if( token == "sounds:" ) { // dzwieki @@ -4606,25 +5002,19 @@ void TDynamicObject::LoadMMediaFile( std::string BaseDir, std::string TypeName, // polozenia osi w/m srodka pojazdu parser.getTokens( 1, false ); parser >> dSDist; - for( int i = 0; i < iAxles; i++ ) { + for( int i = 0; i < iAxles; ++i ) { parser.getTokens( 1, false ); parser >> dWheelsPosition[ i ]; parser.getTokens(); parser >> token; if( token != "end" ) { -#ifdef EU07_USE_OLD_SOUNDCODE - rsStukot[ i ].Init( - token, dSDist, - GetPosition().x, GetPosition().y + dWheelsPosition[ i ], GetPosition().z, - true ); -#else rsStukot[ i ].deserialize( token + " " + std::to_string( dSDist ), sound_type::single, sound_parameters::range ); - // TODO: set per-wheel offset -#endif + rsStukot[ i ].owner( this ); + rsStukot[ i ].offset( { 0, 0, -dWheelsPosition[ i ] } ); } } if( token != "end" ) { - // TODO: double-check if this if() and/or retrieval makes sense here + // TODO: check if this if() and/or retrieval makes sense here parser.getTokens( 1, false ); parser >> token; } } @@ -4632,223 +5022,91 @@ void TDynamicObject::LoadMMediaFile( std::string BaseDir, std::string TypeName, else if( ( token == "engine:" ) && ( MoverParameters->Power > 0 ) ) { // plik z dzwiekiem silnika, mnozniki i ofsety amp. i czest. -#ifdef EU07_USE_OLD_SOUNDCODE - double attenuation; - parser.getTokens( 2, false ); - parser - >> token - >> attenuation; - rsSilnik.Init( - token, attenuation, - GetPosition().x, GetPosition().y, GetPosition().z, - true, true ); - if( rsSilnik.GetWaveTime() == 0 ) { - ErrorLog( "Missed sound: \"" + token + "\" for " + asFileName ); - } - parser.getTokens( 1, false ); - parser >> rsSilnik.AM; - if( MoverParameters->EngineType == DieselEngine ) { - - rsSilnik.AM /= ( MoverParameters->Power + MoverParameters->nmax * 60 ); - } - else if( MoverParameters->EngineType == DieselElectric ) { - - rsSilnik.AM /= ( MoverParameters->Power * 3 ); - } - else { - - rsSilnik.AM /= ( MoverParameters->Power + MoverParameters->nmax * 60 + MoverParameters->Power + MoverParameters->Power ); - } - parser.getTokens( 3, false ); - parser - >> rsSilnik.AA - >> rsSilnik.FM // MoverParameters->nmax; - >> rsSilnik.FA; -#else rsSilnik.deserialize( parser, sound_type::single, sound_parameters::range | sound_parameters::amplitude | sound_parameters::frequency ); -#endif + rsSilnik.owner( this ); + + auto const amplitudedivisor = static_cast( ( + MoverParameters->EngineType == DieselEngine ? MoverParameters->Power + MoverParameters->nmax * 60 : + MoverParameters->EngineType == DieselElectric ? MoverParameters->Power * 3 : + MoverParameters->Power + MoverParameters->nmax * 60 + MoverParameters->Power + MoverParameters->Power ) ); + rsSilnik.m_amplitudefactor /= amplitudedivisor; } else if( ( token == "ventilator:" ) && ( ( MoverParameters->EngineType == ElectricSeriesMotor ) || ( MoverParameters->EngineType == ElectricInductionMotor ) ) ) { // plik z dzwiekiem wentylatora, mnozniki i ofsety amp. i czest. -#ifdef EU07_USE_OLD_SOUNDCODE - double attenuation; - parser.getTokens( 2, false ); - parser - >> token - >> attenuation; - rsWentylator.Init( - token, attenuation, - GetPosition().x, GetPosition().y, GetPosition().z, - true, true ); - parser.getTokens( 4, false ); - parser - >> rsWentylator.AM - >> rsWentylator.AA - >> rsWentylator.FM - >> rsWentylator.FA; - rsWentylator.AM /= MoverParameters->RVentnmax; - rsWentylator.FM /= MoverParameters->RVentnmax; -#else rsWentylator.deserialize( parser, sound_type::single, sound_parameters::range | sound_parameters::amplitude | sound_parameters::frequency ); -#endif + rsWentylator.owner( this ); + + rsWentylator.m_amplitudefactor /= MoverParameters->RVentnmax; + rsWentylator.m_frequencyfactor /= MoverParameters->RVentnmax; } else if( ( token == "transmission:" ) && ( MoverParameters->EngineType == ElectricSeriesMotor ) ) { // plik z dzwiekiem, mnozniki i ofsety amp. i czest. -#ifdef EU07_USE_OLD_SOUNDCODE - double attenuation; - parser.getTokens( 2, false ); - parser - >> token - >> attenuation; - rsPrzekladnia.Init( - token, attenuation, - GetPosition().x, GetPosition().y, GetPosition().z, - true ); - rsPrzekladnia.AM = 0.029; - rsPrzekladnia.AA = 0.1; - rsPrzekladnia.FM = 0.005; - rsPrzekladnia.FA = 1.0; -#else - rsPrzekladnia.deserialize( parser, sound_type::single, sound_parameters::range | sound_parameters::amplitude | sound_parameters::frequency ); -#endif + rsPrzekladnia.deserialize( parser, sound_type::single, sound_parameters::range ); + + // NOTE, TODO: fixed parameters, put them into simulation-side calculations + rsPrzekladnia.m_amplitudefactor = 0.029; + rsPrzekladnia.m_amplitudeoffset = 0.1; + rsPrzekladnia.m_frequencyfactor = 0.005; + rsPrzekladnia.m_frequencyoffset = 1.0; + + rsPrzekladnia.owner( this ); } - else if( token == "brake:" ){ + else if( token == "brake:" ) { // plik z piskiem hamulca, mnozniki i ofsety amplitudy. -#ifdef EU07_USE_OLD_SOUNDCODE - double attenuation; - parser.getTokens( 2, false ); - parser - >> token - >> attenuation; - rsPisk.Init( - token, attenuation, - GetPosition().x, GetPosition().y, GetPosition().z, - true ); - rsPisk.AM = parser.getToken(); - rsPisk.AA = parser.getToken() * ( 105 - Random( 10 ) ) / 100; - rsPisk.FM = 1.0; - rsPisk.FA = 0.0; -#else rsPisk.deserialize( parser, sound_type::single, sound_parameters::range | sound_parameters::amplitude ); -#endif + rsPisk.owner( this ); + + rsPisk.m_amplitudeoffset *= ( 105.f - Random( 10.f ) ) / 100.f; } else if( token == "brakeacc:" ) { // plik z przyspieszaczem (upust po zlapaniu hamowania) -#ifdef EU07_USE_OLD_SOUNDCODE - parser.getTokens( 1, false ); parser >> token; - sBrakeAcc = TSoundsManager::GetFromName( token, true ); -#else sBrakeAcc.deserialize( parser, sound_type::single ); -#endif + sBrakeAcc.owner( this ); + bBrakeAcc = true; } else if( token == "unbrake:" ) { // plik z piskiem hamulca, mnozniki i ofsety amplitudy. -#ifdef EU07_USE_OLD_SOUNDCODE - double attenuation; - parser.getTokens( 2, false ); - parser - >> token - >> attenuation; - rsUnbrake.Init( - token, attenuation, - GetPosition().x, GetPosition().y, GetPosition().z, - true ); - rsUnbrake.AM = 1.0; - rsUnbrake.AA = 0.0; - rsUnbrake.FM = 1.0; - rsUnbrake.FA = 0.0; -#else rsUnbrake.deserialize( parser, sound_type::single, sound_parameters::range ); -#endif + rsUnbrake.owner( this ); } else if( token == "derail:" ) { // dzwiek przy wykolejeniu -#ifdef EU07_USE_OLD_SOUNDCODE - double attenuation; - parser.getTokens( 2, false ); - parser - >> token - >> attenuation; - rsDerailment.Init( - token, attenuation, - GetPosition().x, GetPosition().y, GetPosition().z, - true ); - rsDerailment.AM = 1.0; - rsDerailment.AA = 0.0; - rsDerailment.FM = 1.0; - rsDerailment.FA = 0.0; -#else rsDerailment.deserialize( parser, sound_type::single, sound_parameters::range ); -#endif + rsDerailment.owner( this ); } else if( token == "dieselinc:" ) { // dzwiek przy wlazeniu na obroty woodwarda -#ifdef EU07_USE_OLD_SOUNDCODE - double attenuation; - parser.getTokens( 2, false ); - parser - >> token - >> attenuation; - rsDiesielInc.Init( - token, attenuation, - GetPosition().x, GetPosition().y, GetPosition().z, - true ); - rsDiesielInc.AM = 1.0; - rsDiesielInc.AA = 0.0; - rsDiesielInc.FM = 1.0; - rsDiesielInc.FA = 0.0; -#else - rsDiesielInc.deserialize( parser, sound_type::single, sound_parameters::range ); -#endif + rsDieselInc.deserialize( parser, sound_type::single, sound_parameters::range ); + rsDieselInc.owner( this ); } else if( token == "curve:" ) { -#ifdef EU07_USE_OLD_SOUNDCODE - double attenuation; - parser.getTokens( 2, false ); - parser - >> token - >> attenuation; - rscurve.Init( - token, attenuation, - GetPosition().x, GetPosition().y, GetPosition().z, - true ); - rscurve.AM = 1.0; - rscurve.AA = 0.0; - rscurve.FM = 1.0; - rscurve.FA = 0.0; -#else rscurve.deserialize( parser, sound_type::single, sound_parameters::range ); -#endif + rscurve.owner( this ); } else if( token == "horn1:" ) { // pliki z trabieniem -#ifdef EU07_USE_OLD_SOUNDCODE - sHorn1.Load( parser, GetPosition() ); -#else sHorn1.deserialize( parser, sound_type::multipart, sound_parameters::range ); -#endif + sHorn1.owner( this ); } else if( token == "horn2:" ) { // pliki z trabieniem wysokoton. -#ifdef EU07_USE_OLD_SOUNDCODE - sHorn2.Load( parser, GetPosition() ); -#else sHorn2.deserialize( parser, sound_type::multipart, sound_parameters::range ); -#endif + sHorn2.owner( this ); + if( iHornWarning ) { iHornWarning = 2; // numer syreny do użycia po otrzymaniu sygnału do jazdy } @@ -4856,157 +5114,256 @@ void TDynamicObject::LoadMMediaFile( std::string BaseDir, std::string TypeName, else if( token == "departuresignal:" ) { // pliki z sygnalem odjazdu -#ifdef EU07_USE_OLD_SOUNDCODE - sDepartureSignal.Load( parser, GetPosition() ); -#else sDepartureSignal.deserialize( parser, sound_type::multipart, sound_parameters::range ); -#endif + sDepartureSignal.owner( this ); } else if( token == "pantographup:" ) { // pliki dzwiekow pantografow -#ifdef EU07_USE_OLD_SOUNDCODE - parser.getTokens( 1, false ); parser >> token; - sPantUp.Init( - token, 50, - GetPosition().x, GetPosition().y, GetPosition().z, - true ); -#else - sPantUp.deserialize( parser, sound_type::single ); -#endif + sound_source pantographup { sound_placement::external }; + pantographup.deserialize( parser, sound_type::single ); + pantographup.owner( this ); + for( auto &pantograph : m_pantographsounds ) { + pantograph.sPantUp = pantographup; + } } else if( token == "pantographdown:" ) { // pliki dzwiekow pantografow -#ifdef EU07_USE_OLD_SOUNDCODE - parser.getTokens( 1, false ); parser >> token; - sPantDown.Init( - token, 50, - GetPosition().x, GetPosition().y, GetPosition().z, - true ); -#else - sPantDown.deserialize( parser, sound_type::single ); -#endif + sound_source pantographdown { sound_placement::external }; + pantographdown.deserialize( parser, sound_type::single ); + pantographdown.owner( this ); + for( auto &pantograph : m_pantographsounds ) { + pantograph.sPantDown = pantographdown; + } } else if( token == "compressor:" ) { // pliki ze sprezarka -#ifdef EU07_USE_OLD_SOUNDCODE - sCompressor.Load( parser, GetPosition() ); -#else sCompressor.deserialize( parser, sound_type::multipart, sound_parameters::range ); -#endif + sCompressor.owner( this ); } else if( token == "converter:" ) { // pliki z przetwornica -#ifdef EU07_USE_OLD_SOUNDCODE - sConverter.Load( parser, GetPosition() ); -#else sConverter.deserialize( parser, sound_type::multipart, sound_parameters::range ); -#endif + sConverter.owner( this ); } else if( token == "turbo:" ) { // pliki z turbogeneratorem -#ifdef EU07_USE_OLD_SOUNDCODE - sTurbo.Load( parser, GetPosition() ); -#else sTurbo.deserialize( parser, sound_type::multipart, sound_parameters::range ); -#endif + sTurbo.owner( this ); } else if( token == "small-compressor:" ) { // pliki z przetwornica -#ifdef EU07_USE_OLD_SOUNDCODE - sSmallCompressor.Load( parser, GetPosition() ); -#else sSmallCompressor.deserialize( parser, sound_type::multipart, sound_parameters::range ); -#endif + sSmallCompressor.owner( this ); } else if( token == "dooropen:" ) { -#ifdef EU07_USE_OLD_SOUNDCODE - parser.getTokens( 1, false ); parser >> token; - rsDoorOpen.Init( - token, 50, - GetPosition().x, GetPosition().y, GetPosition().z, - true ); -#else - rsDoorOpen.deserialize( parser, sound_type::single ); -#endif + sound_source dooropen { sound_placement::general }; + dooropen.deserialize( parser, sound_type::single ); + dooropen.owner( this ); + for( auto &door : m_doorsounds ) { + door.rsDoorOpen = dooropen; + } } else if( token == "doorclose:" ) { -#ifdef EU07_USE_OLD_SOUNDCODE - parser.getTokens( 1, false ); parser >> token; - rsDoorClose.Init( - token, 50, - GetPosition().x, GetPosition().y, GetPosition().z, - true ); -#else - rsDoorClose.deserialize( parser, sound_type::single ); -#endif + sound_source doorclose { sound_placement::general }; + doorclose.deserialize( parser, sound_type::single ); + doorclose.owner( this ); + for( auto &door : m_doorsounds ) { + door.rsDoorClose = doorclose; + } } else if( token == "sand:" ) { -#ifdef EU07_USE_OLD_SOUNDCODE - // pliki z piasecznica - sSand.Load( parser, GetPosition() ); -#else sSand.deserialize( parser, sound_type::multipart, sound_parameters::range ); -#endif + sSand.owner( this ); } else if( token == "releaser:" ) { // pliki z odluzniaczem -#ifdef EU07_USE_OLD_SOUNDCODE - sReleaser.Load( parser, GetPosition() ); -#else sReleaser.deserialize( parser, sound_type::multipart, sound_parameters::range ); -#endif + sReleaser.owner( this ); } } while( ( token != "" ) && ( token != "endsounds" ) ); - } + } // sounds: - else if (token == "internaldata:") { - // dalej nie czytaj - do { - // zbieranie informacji o kabinach - token = ""; - parser.getTokens(); parser >> token; - if(token == "cab0model:") - { - parser.getTokens(); parser >> token; - if( token != "none" ) { iCabs = 2; } + else if( token == "internaldata:" ) { + // dalej nie czytaj + do { + // zbieranie informacji o kabinach + token = ""; + parser.getTokens(); parser >> token; + if( token == "cab0model:" ) { + parser.getTokens(); parser >> token; + if( token != "none" ) { iCabs |= 0x2; } } - else if (token == "cab1model:") - { - parser.getTokens(); parser >> token; - if( token != "none" ) { iCabs = 1; } + else if( token == "cab1model:" ) { + parser.getTokens(); parser >> token; + if( token != "none" ) { iCabs |= 0x1; } } - else if (token == "cab2model:") - { - parser.getTokens(); parser >> token; - if( token != "none" ) { iCabs = 4; } - } + else if( token == "cab2model:" ) { + parser.getTokens(); parser >> token; + if( token != "none" ) { iCabs |= 0x4; } + } + // engine sounds + else if( token == "ignition:" ) { + // odpalanie silnika + dsbDieselIgnition.deserialize( parser, sound_type::single ); + dsbDieselIgnition.owner( this ); + } + else if( token == "engageslippery:" ) { + // tarcie tarcz sprzegla: + rsEngageSlippery.deserialize( parser, sound_type::single, sound_parameters::amplitude | sound_parameters::frequency ); + rsEngageSlippery.owner( this ); - } while( token != "" ); + rsEngageSlippery.m_frequencyfactor /= ( 1 + MoverParameters->nmax ); + } + else if( token == "relay:" ) { + // styczniki itp: + dsbRelay.deserialize( parser, sound_type::single ); + dsbRelay.owner( this ); + } + else if( token == "pneumaticrelay:" ) { + // wylaczniki pneumatyczne: + dsbPneumaticRelay.deserialize( parser, sound_type::single ); + dsbPneumaticRelay.owner( this ); + } + else if( token == "wejscie_na_bezoporow:" ) { + // hunter-111211: wydzielenie wejscia na bezoporowa i na drugi uklad do pliku + dsbWejscie_na_bezoporow.deserialize( parser, sound_type::single ); + dsbWejscie_na_bezoporow.owner( this ); + } + else if( token == "wejscie_na_drugi_uklad:" ) { + dsbWejscie_na_drugi_uklad.deserialize( parser, sound_type::single ); + dsbWejscie_na_drugi_uklad.owner( this ); + } + // braking sounds + else if( token == "brakesound:" ) { + // hamowanie zwykle: + rsBrake.deserialize( parser, sound_type::single, sound_parameters::amplitude | sound_parameters::frequency ); + rsBrake.owner( this ); - Stop_InternalData = true; - } + rsBrake.m_amplitudefactor /= ( 1 + MoverParameters->MaxBrakeForce * 1000 ); + rsBrake.m_frequencyfactor /= ( 1 + MoverParameters->Vmax ); + } + else if( token == "slipperysound:" ) { + // sanie: + rsSlippery.deserialize( parser, sound_type::single, sound_parameters::amplitude ); + rsSlippery.owner( this ); - } while( ( token != "" ) - && ( false == Stop_InternalData ) ); + rsSlippery.m_amplitudefactor /= ( 1 + MoverParameters->Vmax ); + } + // coupler sounds + else if( token == "couplerattach:" ) { + // laczenie: + sound_source couplerattach { sound_placement::external }; + couplerattach.deserialize( parser, sound_type::single ); + couplerattach.owner( this ); + for( auto &couplersounds : m_couplersounds ) { + couplersounds.dsbCouplerAttach = couplerattach; + } + } + else if( token == "couplerdetach:" ) { + // rozlaczanie: + sound_source couplerdetach { sound_placement::external }; + couplerdetach.deserialize( parser, sound_type::single ); + couplerdetach.owner( this ); + for( auto &couplersounds : m_couplersounds ) { + couplersounds.dsbCouplerDetach = couplerdetach; + } + } + else if( token == "couplerstretch:" ) { + // coupler stretching + sound_source couplerstretch { sound_placement::external }; + couplerstretch.deserialize( parser, sound_type::single ); + couplerstretch.owner( this ); + for( auto &couplersounds : m_couplersounds ) { + couplersounds.dsbCouplerStretch = couplerstretch; + } + } + else if( token == "bufferclamp:" ) { + // buffers hitting one another + sound_source bufferclash { sound_placement::external }; + bufferclash.deserialize( parser, sound_type::single ); + bufferclash.owner( this ); + for( auto &couplersounds : m_couplersounds ) { + couplersounds.dsbBufferClamp = bufferclash; + } + } + else if( token == "runningnoise:" ) { + // szum podczas jazdy: + rsRunningNoise.deserialize( parser, sound_type::single, sound_parameters::amplitude | sound_parameters::frequency ); + rsRunningNoise.owner( this ); + + rsRunningNoise.m_amplitudefactor /= ( 1 + MoverParameters->Vmax ); + rsRunningNoise.m_frequencyfactor /= ( 1 + MoverParameters->Vmax ); + } + + } while( token != "" ); + + } // internaldata: + + } while( token != "" ); if( !iAnimations ) { // if the animations weren't defined the model is likely to be non-functional. warrants a warning. ErrorLog( "Animations tag is missing from the .mmd file \"" + asFileName + "\"" ); } + // assign default samples to sound emitters which weren't included in the config file + // engine + if( MoverParameters->Power > 0 ) { + if( true == dsbWejscie_na_bezoporow.empty() ) { + // hunter-111211: domyslne, gdy brak + dsbWejscie_na_bezoporow.deserialize( "wejscie_na_bezoporow.wav", sound_type::single ); + dsbWejscie_na_bezoporow.owner( this ); + } + if( true == dsbWejscie_na_drugi_uklad.empty() ) { + dsbWejscie_na_drugi_uklad.deserialize( "wescie_na_drugi_uklad.wav", sound_type::single ); + dsbWejscie_na_drugi_uklad.owner( this ); + } + } + // braking sounds + if( true == rsUnbrake.empty() ) { + rsUnbrake.deserialize( "[1007]estluz.wav", sound_type::single ); + rsUnbrake.owner( this ); + } + // couplers + for( auto &couplersounds : m_couplersounds ) { + if( true == couplersounds.dsbCouplerAttach.empty() ) { + couplersounds.dsbCouplerAttach.deserialize( "couplerattach.wav", sound_type::single ); + couplersounds.dsbCouplerAttach.owner( this ); + } + if( true == couplersounds.dsbCouplerDetach.empty() ) { + couplersounds.dsbCouplerDetach.deserialize( "couplerdetach.wav", sound_type::single ); + couplersounds.dsbCouplerDetach.owner( this ); + } + if( true == couplersounds.dsbCouplerStretch.empty() ) { + couplersounds.dsbCouplerStretch.deserialize( "en57_couplerstretch.wav", sound_type::single ); + couplersounds.dsbCouplerStretch.owner( this ); + } + if( true == couplersounds.dsbBufferClamp.empty() ) { + couplersounds.dsbBufferClamp.deserialize( "en57_bufferclamp.wav", sound_type::single ); + couplersounds.dsbBufferClamp.owner( this ); + } + } + // other sounds + if( true == rscurve.empty() ) { + // hunter-111211: domyslne, gdy brak + rscurve.deserialize( "curve.wav", sound_type::single ); + rscurve.owner( this ); + } + + if (mdModel) mdModel->Init(); // obrócenie modelu oraz optymalizacja, również zapisanie binarnego if (mdLoad) @@ -5016,6 +5373,67 @@ void TDynamicObject::LoadMMediaFile( std::string BaseDir, std::string TypeName, Global::asCurrentTexturePath = szTexturePath; // kiedyś uproszczone wnętrze mieszało tekstury nieba Global::asCurrentDynamicPath = ""; + + // position sound emitters which weren't defined in the config file + auto const nullvector { glm::vec3() }; + // engine sounds , centre of the vehicle + auto const enginelocation { glm::vec3 {0.f, MoverParameters->Dim.H * 0.5f, 0.f } }; + std::vector enginesounds = { + &dsbDieselIgnition, + &rsSilnik, + &dsbRelay, &dsbWejscie_na_bezoporow, &dsbWejscie_na_drugi_uklad, + &rsPrzekladnia, &rsEngageSlippery, &rsDieselInc, &sTurbo, + &rsWentylator, &sConverter, &sCompressor, &sSmallCompressor + }; + for( auto sound : enginesounds ) { + if( sound->offset() == nullvector ) { + sound->offset( enginelocation ); + } + } + // TODO: other sound types + // pantographs + if( pants != nullptr ) { + std::size_t pantographindex { 0 }; + for( auto &pantographsounds : m_pantographsounds ) { + auto const pantographoffset { + glm::vec3( + 0.f, + pants[ pantographindex ].fParamPants->vPos.y, + -pants[ pantographindex ].fParamPants->vPos.x ) }; + pantographsounds.sPantUp.offset( pantographoffset ); + pantographsounds.sPantDown.offset( pantographoffset ); + ++pantographindex; + } + } + // doors + std::size_t dooranimationfirstindex { 0 }; + for( std::size_t i = 0; i < ANIM_DOORS; ++i ) { + // zliczanie wcześniejszych animacji + dooranimationfirstindex += iAnimType[ i ]; + } + std::size_t doorindex { 0 }; + for( auto &doorsounds : m_doorsounds ) { + + auto submodel { pAnimations[ dooranimationfirstindex + doorindex ].smAnimated }; + if( submodel == nullptr ) { continue; } + + auto const dooroffset { pAnimations[ dooranimationfirstindex + doorindex ].smAnimated->offset( std::numeric_limits::max() ) }; + + doorsounds.rsDoorClose.offset( dooroffset ); + doorsounds.rsDoorOpen.offset( dooroffset ); + ++doorindex; + } + // couplers + auto const frontcoupleroffset { glm::vec3{ 0.f, 1.f, MoverParameters->Dim.L * 0.5f } }; + m_couplersounds[ side::front ].dsbCouplerAttach.offset( frontcoupleroffset ); + m_couplersounds[ side::front ].dsbCouplerDetach.offset( frontcoupleroffset ); + m_couplersounds[ side::front ].dsbCouplerStretch.offset( frontcoupleroffset ); + m_couplersounds[ side::front ].dsbBufferClamp.offset( frontcoupleroffset ); + auto const rearcoupleroffset{ glm::vec3{ 0.f, 1.f, MoverParameters->Dim.L * -0.5f } }; + m_couplersounds[ side::rear ].dsbCouplerAttach.offset( rearcoupleroffset ); + m_couplersounds[ side::rear ].dsbCouplerDetach.offset( rearcoupleroffset ); + m_couplersounds[ side::rear ].dsbCouplerStretch.offset( rearcoupleroffset ); + m_couplersounds[ side::rear ].dsbBufferClamp.offset( rearcoupleroffset ); } //--------------------------------------------------------------------------- diff --git a/DynObj.h b/DynObj.h index 96cba4bf..1288ab8a 100644 --- a/DynObj.h +++ b/DynObj.h @@ -258,12 +258,33 @@ private: TSubModel *smWiper; // wycieraczka (poniekąd też wajcha) // Ra: koneic animacji do ogarnięcia - private: - void ABuLittleUpdate(double ObjSqrDist); - bool btnOn; // ABu: czy byly uzywane buttony, jesli tak, to po renderingu wylacz - // bo ten sam model moze byc jeszcze wykorzystany przez inny obiekt! - double ComputeRadius( Math3D::vector3 p1, Math3D::vector3 p2, Math3D::vector3 p3, Math3D::vector3 p4); +private: +// types + struct coupler_sounds { + sound_source dsbCouplerAttach { sound_placement::external }; // moved from cab + sound_source dsbCouplerDetach { sound_placement::external }; // moved from cab + sound_source dsbCouplerStretch { sound_placement::external }; // moved from cab + sound_source dsbBufferClamp { sound_placement::external }; // moved from cab + }; + struct pantograph_sounds { + sound_source sPantUp { sound_placement::external }; + sound_source sPantDown { sound_placement::external }; + }; + + struct door_sounds { + sound_source rsDoorOpen{ sound_placement::general }; // 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 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 m_couplersounds; // always front and rear + std::vector m_pantographsounds; // typically 2 but can be less (or more?) + std::vector 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); diff --git a/Event.cpp b/Event.cpp index 9db96750..534f618b 100644 --- a/Event.cpp +++ b/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 + "\"" ); + } + } } } diff --git a/Gauge.cpp b/Gauge.cpp index d785599e..c22d156d 100644 --- a/Gauge.cpp +++ b/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 ); + 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 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() ); +} + //--------------------------------------------------------------------------- diff --git a/Gauge.h b/Gauge.h index 081ffade..9f76b335 100644 --- a/Gauge.h +++ b/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 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 }; //--------------------------------------------------------------------------- diff --git a/Globals.cpp b/Globals.cpp index 8bf348b4..adaa1160 100644 --- a/Globals.cpp +++ b/Globals.cpp @@ -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 }; diff --git a/Globals.h b/Globals.h index 9c7fe26a..3d88a3f1 100644 --- a/Globals.h +++ b/Globals.h @@ -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; diff --git a/McZapkie/MOVER.h b/McZapkie/MOVER.h index e63e297d..241295c0 100644 --- a/McZapkie/MOVER.h +++ b/McZapkie/MOVER.h @@ -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); diff --git a/McZapkie/Mover.cpp b/McZapkie/Mover.cpp index 5a1a95bf..e339284f 100644 --- a/McZapkie/Mover.cpp +++ b/McZapkie/Mover.cpp @@ -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; diff --git a/McZapkie/hamulce.cpp b/McZapkie/hamulce.cpp index 7951791b..fdfa2bbc 100644 --- a/McZapkie/hamulce.cpp +++ b/McZapkie/hamulce.cpp @@ -578,47 +578,58 @@ void TESt::CheckReleaser( double const dt ) } } -void TESt::CheckState( double const BCP, double &dV1 ) -{ - double VVP; - double BVP; - double CVP; +void TESt::CheckState( double const BCP, double &dV1 ) { - BVP = BrakeRes->P(); - VVP = ValveRes->P(); - // if (BVPP() - 0.0; + double const VVP { ValveRes->P() }; + double const BVP { BrakeRes->P() }; + double const CVP { CntrlRes->P() }; // sprawdzanie stanu - if (((BrakeStatus & b_hld) == b_hld) && (BCP > 0.25)) - if ((VVP + 0.003 + BCP / BVM < CVP)) - BrakeStatus |= b_on; // hamowanie stopniowe - else if ((VVP - 0.003 + (BCP - 0.1) / BVM > CVP)) - BrakeStatus &= ~( b_on | b_hld ); // luzowanie - else if ((VVP + BCP / BVM > CVP)) - BrakeStatus &= ~b_on; // zatrzymanie napelaniania - else - ; - else if ((VVP + 0.10 < CVP) && (BCP < 0.25)) // poczatek hamowania - { - if ((BrakeStatus & b_hld) == b_off) - { - ValveRes->CreatePress(0.02 * VVP); - SoundFlag |= sf_Acc; - ValveRes->Act(); + if( BCP > 0.25 ) { + + if( ( BrakeStatus & b_hld ) == b_hld ) { + + if( ( VVP + 0.003 + BCP / BVM ) < CVP ) { + // hamowanie stopniowe + BrakeStatus |= b_on; + } + else { + if( ( VVP + BCP / BVM ) > CVP ) { + // zatrzymanie napelaniania + BrakeStatus &= ~b_on; + } + if( ( VVP - 0.003 + ( BCP - 0.1 ) / BVM ) > CVP ) { + // luzowanie + BrakeStatus &= ~( b_on | b_hld ); + } + } } - BrakeStatus |= (b_on | b_hld); + else { - // ValveRes.CreatePress(0); - // dV1:=1; + if( ( VVP + BCP / BVM < CVP ) + && ( ( CVP - VVP ) * BVM > 0.25 ) ) { + // zatrzymanie luzowanie + BrakeStatus |= b_hld; + } + } } - else if ((VVP + (BCP - 0.1) / BVM < CVP) && ((CVP - VVP) * BVM > 0.25) && - (BCP > 0.25)) // zatrzymanie luzowanie - BrakeStatus |= b_hld; + else { - if ((BrakeStatus & b_hld) == b_off) + if( VVP + 0.1 < CVP ) { + // poczatek hamowania + if( ( BrakeStatus & b_hld ) == 0 ) { + // przyspieszacz + ValveRes->CreatePress( 0.02 * VVP ); + SoundFlag |= sf_Acc; + ValveRes->Act(); + } + BrakeStatus |= ( b_on | b_hld ); + } + } + + if( ( BrakeStatus & b_hld ) == 0 ) { SoundFlag |= sf_CylU; + } } double TESt::CVs( double const BP ) @@ -828,6 +839,10 @@ double TEStEP2::GetPF( double const PP, double const dt, double const Vel ) else if ((VVP + BCP / BVM < CVP - 0.12) && (BCP > 0.25)) // zatrzymanie luzowanie BrakeStatus |= b_hld; + if( ( BrakeStatus & b_hld ) == 0 ) { + SoundFlag |= sf_CylU; + } + // przeplyw ZS <-> PG if ((BVP < CVP - 0.2) || (BrakeStatus != b_off) || (BCP > 0.25)) temp = 0; @@ -1211,6 +1226,40 @@ double TLSt::GetPF( double const PP, double const dt, double const Vel ) double dV1{ 0.0 }; // sprawdzanie stanu + // NOTE: partial copypaste from checkstate() of base class + // TODO: clean inheritance for checkstate() and checkreleaser() and reuse these instead of manual copypaste + if( ( ( BrakeStatus & b_hld ) == b_hld ) && ( BCP > 0.25 ) ) { + if( ( VVP + 0.003 + BCP / BVM < CVP ) ) { + // hamowanie stopniowe + BrakeStatus |= b_on; + } + else if( ( VVP - 0.003 + ( BCP - 0.1 ) / BVM > CVP ) ) { + // luzowanie + BrakeStatus &= ~( b_on | b_hld ); + } + else if( ( VVP + BCP / BVM > CVP ) ) { + // zatrzymanie napelaniania + BrakeStatus &= ~b_on; + } + } + else if ((VVP + 0.10 < CVP) && (BCP < 0.25)) { + // poczatek hamowania + if ((BrakeStatus & b_hld) == b_off) + { + SoundFlag |= sf_Acc; + } + BrakeStatus |= (b_on | b_hld); + } + else if( ( VVP + ( BCP - 0.1 ) / BVM < CVP ) + && ( ( CVP - VVP ) * BVM > 0.25 ) + && ( BCP > 0.25 ) ) { + // zatrzymanie luzowanie + BrakeStatus |= b_hld; + } + if( ( BrakeStatus & b_hld ) == 0 ) { + SoundFlag |= sf_CylU; + } + // equivalent of checkreleaser() in the base class? if( ( BrakeStatus & b_rls ) == b_rls ) { if( CVP < 0.0 ) { BrakeStatus &= ~b_rls; @@ -1219,18 +1268,11 @@ double TLSt::GetPF( double const PP, double const dt, double const Vel ) { // 008 dV = PF1( CVP, BCP, 0.024 ) * dt; CntrlRes->Flow( dV ); -/* - // NOTE: attempted fix, disabled because it breaks when releaser is used while releasing breakes - dV = PF1(CVP, VVP, 0.024) * dt; - CntrlRes->Flow( dV ); - dV1 = dV; //minus potem jest - ImplsRes->Flow( -dV1 ); -*/ } } - double temp; // przeplyw ZS <-> PG + double temp; if (((CVP - BCP) * BVM > 0.5)) temp = 0.0; else if ((VVP > CVP + 0.4)) @@ -1888,22 +1930,51 @@ void TKE::CheckState( double const BCP, double &dV1 ) CVP = CntrlRes->P(); // sprawdzanie stanu - if ((BrakeStatus & b_hld) == b_hld) - if ((VVP + 0.003 + BCP / BVM < CVP)) - BrakeStatus |= b_on; // hamowanie stopniowe; - else if ((VVP - 0.003 + BCP / BVM > CVP)) - BrakeStatus &= ~( b_on | b_hld ); // luzowanie; - else if ((VVP + BCP / BVM > CVP)) - BrakeStatus &= ~b_on; // zatrzymanie napelaniania; - else - ; - else if ((VVP + 0.10 < CVP) && (BCP < 0.1)) // poczatek hamowania - { - BrakeStatus |= (b_on | b_hld); - ValveRes->CreatePress(0.8 * VVP); // przyspieszacz + if( BCP > 0.1 ) { + + if( ( BrakeStatus & b_hld ) == b_hld ) { + + if( ( VVP + 0.003 + BCP / BVM ) < CVP ) { + // hamowanie stopniowe; + BrakeStatus |= b_on; + } + else { + if( ( VVP + BCP / BVM ) > CVP ) { + // zatrzymanie napelaniania; + BrakeStatus &= ~b_on; + } + if( ( VVP - 0.003 + BCP / BVM ) > CVP ) { + // luzowanie; + BrakeStatus &= ~( b_on | b_hld ); + } + } + } + else { + + if( ( VVP + BCP / BVM < CVP ) + && ( ( CVP - VVP ) * BVM > 0.25 ) ) { + // zatrzymanie luzowanie + BrakeStatus |= b_hld; + } + } + } + else { + + if( VVP + 0.1 < CVP ) { + // poczatek hamowania + if( ( BrakeStatus & b_hld ) == 0 ) { + // przyspieszacz + ValveRes->CreatePress( 0.8 * VVP ); + SoundFlag |= sf_Acc; + ValveRes->Act(); + } + BrakeStatus |= ( b_on | b_hld ); + } + } + + if( ( BrakeStatus & b_hld ) == 0 ) { + SoundFlag |= sf_CylU; } - else if ((VVP + BCP / BVM < CVP) && ((CVP - VVP) * BVM > 0.25)) // zatrzymanie luzowanie - BrakeStatus |= b_hld; } double TKE::CVs( double const BP ) diff --git a/Model3d.cpp b/Model3d.cpp index 50c9c0d3..d2e5e6c8 100644 --- a/Model3d.cpp +++ b/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 diff --git a/Model3d.h b/Model3d.h index 57a01408..8244835d 100644 --- a/Model3d.h +++ b/Model3d.h @@ -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,7 +172,10 @@ public: void SetRotateIK1(float3 vNewAngles); TSubModel * GetFromName( std::string const &search, bool i = true ); inline float4x4 * GetMatrix() { return fMatrix; }; - inline void Hide() { iVisible = 0; }; + inline float4x4 const * GetMatrix() const { return fMatrix; }; + // returns offset vector from root + glm::vec3 offset( float const Geometrytestoffsetthreshold = 0.f ) const; + inline void Hide() { iVisible = 0; }; void create_geometry( std::size_t &Dataoffset, gfx::geometrybank_handle const &Bank ); int FlagsCheck(); @@ -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&); diff --git a/Train.cpp b/Train.cpp index 81ceec1d..db9f5a56 100644 --- a/Train.cpp +++ b/Train.cpp @@ -1540,8 +1540,6 @@ void TTrain::OnCommand_linebreakertoggle( TTrain *Train, command_data const &Com // TODO: consider arranging a better way to start the diesel engines if( Train->mvControlled->EngineType == DieselEngine ) { if( Train->mvControlled->MainSwitch( true ) ) { - // sound feedback, engine start for diesel vehicle - Train->dsbDieselIgnition.play(); // side-effects Train->mvControlled->ConverterSwitch( ( Train->ggConverterButton.GetValue() > 0.5 ) || ( Train->mvControlled->ConverterStart == start::automatic ) ); Train->mvControlled->CompressorSwitch( Train->ggCompressorButton.GetValue() > 0.5 ); @@ -1584,7 +1582,9 @@ void TTrain::OnCommand_linebreakertoggle( TTrain *Train, command_data const &Com } // play sound immediately when the switch is hit, not after release if( Train->fMainRelayTimer > 0.0f ) { +#ifdef EU07_USE_OLD_SOUNDCODE Train->dsbRelay.play(); +#endif Train->fMainRelayTimer = 0.0f; } } @@ -1595,7 +1595,9 @@ void TTrain::OnCommand_linebreakertoggle( TTrain *Train, command_data const &Com // ...after opening circuit, or holding for too short time to close it // hunter-091012: przeniesione z mover.pas, zeby dzwiek sie nie zapetlal, if( Train->fMainRelayTimer > 0.0f ) { +#ifdef EU07_USE_OLD_SOUNDCODE Train->dsbRelay.play(); +#endif Train->fMainRelayTimer = 0.0f; } // we don't exactly know which of the two buttons was used, so reset both @@ -1920,7 +1922,9 @@ void TTrain::OnCommand_motorconnectorsopen( TTrain *Train, command_data const &C Train->ggStLinOffButton.UpdateValue( 1.0, Train->dsbSwitch ); // effect if( true == Train->mvControlled->StLinFlag ) { +#ifdef EU07_USE_OLD_SOUNDCODE Train->dsbRelay.play(); +#endif } // yBARC - zmienione na przeciwne, bo true to zalaczone Train->mvControlled->StLinFlag = false; @@ -2729,14 +2733,14 @@ void TTrain::OnCommand_departureannounce( TTrain *Train, command_data const &Com // only reacting to press, so the sound can loop uninterrupted if( false == Train->mvControlled->DepartureSignal ) { // turn on - Train->mvControlled->DepartureSignal = true; + Train->mvControlled->signal_departure( true ); // visual feedback Train->ggDepartureSignalButton.UpdateValue( 1.0, Train->dsbSwitch ); } } else if( Command.action == GLFW_RELEASE ) { // turn off - Train->mvControlled->DepartureSignal = false; + Train->mvControlled->signal_departure( false ); // visual feedback Train->ggDepartureSignalButton.UpdateValue( 0.0, Train->dsbSwitch ); } @@ -2899,18 +2903,23 @@ void TTrain::OnKeyDown(int cKey) CouplNr = -2; temp = (DynamicObject->ABuScanNearestObject(DynamicObject->GetTrack(), 1, 1500, CouplNr)); } - if (temp) + if( (temp) + && (temp != DynamicObject ) ) + // NOTE: the command to occupied vehicle will be passed through new command system, so we skip it here + // TODO: clean this up when whole control system is unified { - if (Global::ctrlState) - if (temp->MoverParameters->BrakeDelaySwitch(bdelay_R + bdelay_M)) - { - dsbPneumaticRelay.play(); - } - else - ; - else if (temp->MoverParameters->BrakeDelaySwitch(bdelay_P)) - { + if( ( temp->MoverParameters->BrakeDelayFlag & bdelay_M ) != 0 ) { + // can't speed it up any more than this + return; + } + auto const fasterbrakesetting = ( + temp->MoverParameters->BrakeDelayFlag < bdelay_R ? + temp->MoverParameters->BrakeDelayFlag << 1 : + temp->MoverParameters->BrakeDelayFlag | bdelay_M ); + if( true == temp->MoverParameters->BrakeDelaySwitch( fasterbrakesetting ) ) { +#ifdef EU07_USE_OLD_SOUNDCODE dsbPneumaticRelay.play(); +#endif } } } @@ -3002,8 +3011,7 @@ void TTrain::OnKeyDown(int cKey) // bylo mozna ustawic dowolny // wagon int CouplNr = -2; - if( !FreeFlyModeFlag ) - { + if( false == FreeFlyModeFlag ) { #ifdef EU07_USE_OLD_COMMAND_SYSTEM if( Global::ctrlState ) if (mvOccupied->BrakeDelaySwitch(bdelay_R)) @@ -3018,8 +3026,7 @@ void TTrain::OnKeyDown(int cKey) } #endif } - else - { + else { TDynamicObject *temp; temp = (DynamicObject->ABuScanNearestObject(DynamicObject->GetTrack(), -1, 1500, CouplNr)); if (temp == NULL) @@ -3027,18 +3034,24 @@ void TTrain::OnKeyDown(int cKey) CouplNr = -2; temp = (DynamicObject->ABuScanNearestObject(DynamicObject->GetTrack(), 1, 1500, CouplNr)); } - if (temp) + if( (temp) + && (temp != DynamicObject ) ) + // NOTE: the command to occupied vehicle will be passed through new command system, so we skip it here + // TODO: clean this up when whole control system is unified { - if (Global::ctrlState) - if (temp->MoverParameters->BrakeDelaySwitch(bdelay_R)) - { - dsbPneumaticRelay.play(); - } - else - ; - else if (temp->MoverParameters->BrakeDelaySwitch(bdelay_G)) - { + if( temp->MoverParameters->BrakeDelayFlag == bdelay_G ) { + // can't slow it down any more than this + return; + } + auto const slowerbrakesetting = ( + temp->MoverParameters->BrakeDelayFlag < bdelay_M ? + temp->MoverParameters->BrakeDelayFlag >> 1 : + temp->MoverParameters->BrakeDelayFlag ^ bdelay_M ); + + if( true == temp->MoverParameters->BrakeDelaySwitch( slowerbrakesetting ) ) { +#ifdef EU07_USE_OLD_SOUNDCODE dsbPneumaticRelay.play(); +#endif } } } @@ -3082,221 +3095,52 @@ void TTrain::OnKeyDown(int cKey) false; // wyjście z maszynowego wyłącza sprężarkę pomocniczą */ } - else if (cKey == Global::Keys[k_Couple]) - { // ABu051104: male zmiany, zeby mozna bylo laczyc odlegle wagony - // da sie zoptymalizowac, ale nie ma na to czasu :( - if (iCabn > 0) - { - if (!FreeFlyModeFlag) // tryb 'kabinowy' - { /* - if (mvControlled->Couplers[iCabn-1].CouplingFlag==0) - { -if - (mvControlled->Attach(iCabn-1,mvControlled->Couplers[iCabn-1].Connected,ctrain_coupler)) - { - dsbCouplerAttach->SetVolume(DSBVOLUME_MAX); - dsbCouplerAttach->Play(0,0,0); - //ABu: aha, a guzik, nie dziala i nie bedzie, a przydalo by sie - cos takiego: - //DynamicObject->NextConnected=mvControlled->Couplers[iCabn-1].Connected; - //DynamicObject->PrevConnected=mvControlled->Couplers[iCabn-1].Connected; - } - } - else - if - (!TestFlag(mvControlled->Couplers[iCabn-1].CouplingFlag,ctrain_pneumatic)) - { - //ABu021104: zeby caly czas bylo widac sprzegi: -if - (mvControlled->Attach(iCabn-1,mvControlled->Couplers[iCabn-1].Connected,mvControlled->Couplers[iCabn-1].CouplingFlag+ctrain_pneumatic)) -//if - (mvControlled->Attach(iCabn-1,mvControlled->Couplers[iCabn-1].Connected,ctrain_pneumatic)) - { - rsHiss.Play(1,DSBPLAY_LOOPING,true,DynamicObject->GetPosition()); - } - }*/ - } - else - { // tryb freefly - int CouplNr = -1; // normalnie żaden ze sprzęgów - TDynamicObject *tmp; - tmp = DynamicObject->ABuScanNearestObject(DynamicObject->GetTrack(), 1, 1500, CouplNr); - if (tmp == nullptr) - tmp = DynamicObject->ABuScanNearestObject(DynamicObject->GetTrack(), -1, 1500, CouplNr); - if( ( CouplNr != -1 ) - && ( tmp != nullptr ) - && ( tmp->MoverParameters->Couplers[ CouplNr ].Connected != nullptr ) ) - { - if (tmp->MoverParameters->Couplers[CouplNr].CouplingFlag == 0) // najpierw hak - { - if ((tmp->MoverParameters->Couplers[CouplNr].Connected->Couplers[CouplNr].AllowedFlag - & tmp->MoverParameters->Couplers[CouplNr].AllowedFlag - & ctrain_coupler) == ctrain_coupler) - if (tmp->MoverParameters->Attach( - CouplNr, 2, - tmp->MoverParameters->Couplers[CouplNr].Connected, - ctrain_coupler)) - { - // tmp->MoverParameters->Couplers[CouplNr].Render=true; - // //podłączony sprzęg będzie widoczny - if (DynamicObject->Mechanik) // na wszelki wypadek - DynamicObject->Mechanik->CheckVehicles(Connect); // aktualizacja flag kierunku w składzie - dsbCouplerAttach.play(); - // one coupling type per key press - return; - } - else - WriteLog("Mechanical coupling failed."); - } - if (!TestFlag(tmp->MoverParameters->Couplers[CouplNr].CouplingFlag, ctrain_pneumatic)) // pneumatyka - { - if ((tmp->MoverParameters->Couplers[CouplNr].Connected->Couplers[CouplNr].AllowedFlag - & tmp->MoverParameters->Couplers[CouplNr].AllowedFlag - & ctrain_pneumatic) == ctrain_pneumatic) - if (tmp->MoverParameters->Attach( - CouplNr, 2, - tmp->MoverParameters->Couplers[CouplNr].Connected, - (tmp->MoverParameters->Couplers[CouplNr].CouplingFlag | ctrain_pneumatic))) - { - // TODO: dedicated 'click' sound for connecting cable-type connections - dsbCouplerDetach.play(); -// rsHiss.Play( 1, DSBPLAY_LOOPING, true, tmp->GetPosition() ); - DynamicObject->SetPneumatic(CouplNr != 0, true); // Ra: to mi się nie podoba !!!! - tmp->SetPneumatic(CouplNr != 0, true); - // one coupling type per key press - return; - } - } - if (!TestFlag(tmp->MoverParameters->Couplers[CouplNr].CouplingFlag, ctrain_scndpneumatic)) // zasilajacy - { - if ((tmp->MoverParameters->Couplers[CouplNr].Connected->Couplers[CouplNr].AllowedFlag - & tmp->MoverParameters->Couplers[CouplNr].AllowedFlag - & ctrain_scndpneumatic) == ctrain_scndpneumatic) - if (tmp->MoverParameters->Attach( - CouplNr, 2, - tmp->MoverParameters->Couplers[CouplNr].Connected, - (tmp->MoverParameters->Couplers[CouplNr].CouplingFlag | ctrain_scndpneumatic))) - { - // TODO: dedicated 'click' sound for connecting cable-type connections - dsbCouplerDetach.play(); -// rsHiss.Play( 1, DSBPLAY_LOOPING, true, tmp->GetPosition() ); - DynamicObject->SetPneumatic( CouplNr != 0, false ); // Ra: to mi się nie podoba !!!! - tmp->SetPneumatic(CouplNr != 0, false); - // one coupling type per key press - return; - } - } - if (!TestFlag(tmp->MoverParameters->Couplers[CouplNr].CouplingFlag, ctrain_controll)) // ukrotnionko - { - if ((tmp->MoverParameters->Couplers[CouplNr].Connected->Couplers[CouplNr].AllowedFlag & - tmp->MoverParameters->Couplers[CouplNr].AllowedFlag & - ctrain_controll) == ctrain_controll) - if (tmp->MoverParameters->Attach( - CouplNr, 2, - tmp->MoverParameters->Couplers[CouplNr].Connected, - (tmp->MoverParameters->Couplers[CouplNr].CouplingFlag | ctrain_controll))) - { - // TODO: dedicated 'click' sound for connecting cable-type connections - dsbCouplerAttach.play(); - // one coupling type per key press - return; - } - } - if (!TestFlag(tmp->MoverParameters->Couplers[CouplNr].CouplingFlag, ctrain_passenger)) // mostek - { - if ((tmp->MoverParameters->Couplers[CouplNr].Connected->Couplers[CouplNr].AllowedFlag & - tmp->MoverParameters->Couplers[CouplNr].AllowedFlag & - ctrain_passenger) == ctrain_passenger) - if (tmp->MoverParameters->Attach( - CouplNr, 2, - tmp->MoverParameters->Couplers[CouplNr].Connected, - (tmp->MoverParameters->Couplers[CouplNr].CouplingFlag | ctrain_passenger))) - { - dsbCouplerAttach.play(); -/* - DynamicObject->SetPneumatic(CouplNr != 0, false); - tmp->SetPneumatic(CouplNr != 0, false); -*/ - // one coupling type per key press - return; - } - } - if( false == TestFlag( tmp->MoverParameters->Couplers[ CouplNr ].CouplingFlag, ctrain_heating ) ) { - // heating - if( ( tmp->MoverParameters->Couplers[ CouplNr ].Connected->Couplers[ CouplNr ].AllowedFlag - & tmp->MoverParameters->Couplers[ CouplNr ].AllowedFlag - & ctrain_heating ) == ctrain_heating ) - if( tmp->MoverParameters->Attach( - CouplNr, 2, - tmp->MoverParameters->Couplers[ CouplNr ].Connected, - ( tmp->MoverParameters->Couplers[ CouplNr ].CouplingFlag | ctrain_heating ) ) ) { + else if (cKey == Global::Keys[k_Couple]) { - // TODO: dedicated 'click' sound for connecting cable-type connections - dsbCouplerAttach.play(); - // one coupling type per key press - return; - } - } - } + if( true == FreeFlyModeFlag ) { + // tryb freefly + int CouplNr = -1; // normalnie żaden ze sprzęgów + TDynamicObject *tmp; + tmp = DynamicObject->ABuScanNearestObject(DynamicObject->GetTrack(), 1, 1500, CouplNr); + if (tmp == nullptr) + tmp = DynamicObject->ABuScanNearestObject(DynamicObject->GetTrack(), -1, 1500, CouplNr); + + if( ( CouplNr != -1 ) + && ( tmp != nullptr ) ) { + + tmp->couple( CouplNr ); } + if( DynamicObject->Mechanik ) { + // aktualizacja flag kierunku w składzie + DynamicObject->Mechanik->CheckVehicles( Connect ); + } + } + } - else if (cKey == Global::Keys[k_DeCouple]) - { // ABu051104: male zmiany, - // zeby mozna bylo rozlaczac - // odlegle wagony - if (iCabn > 0) - { - if (!FreeFlyModeFlag) // tryb 'kabinowy' (pozwala również rozłączyć sprzęgi zablokowane) - { - if (DynamicObject->DettachStatus(iCabn - 1) < 0) // jeśli jest co odczepić - if (DynamicObject->Dettach(iCabn - 1)) // iCab==1:przód,iCab==2:tył - { - dsbCouplerDetach.play(); // w kabinie ten dźwięk? - } + else if (cKey == Global::Keys[k_DeCouple]) { + + if( true == FreeFlyModeFlag ) { + // tryb freefly + int CouplNr = -1; + auto *tmp { DynamicObject->ABuScanNearestObject( DynamicObject->GetTrack(), 1, 1500, CouplNr ) }; + if( tmp == nullptr ) { + tmp = DynamicObject->ABuScanNearestObject( DynamicObject->GetTrack(), -1, 1500, CouplNr ); } - else - { // tryb freefly - int CouplNr = -1; - TDynamicObject *tmp; - tmp = DynamicObject->ABuScanNearestObject(DynamicObject->GetTrack(), 1, 1500, CouplNr); - if (tmp == NULL) - tmp = DynamicObject->ABuScanNearestObject(DynamicObject->GetTrack(), -1, 1500, CouplNr); - if (tmp && (CouplNr != -1)) - { - if ((tmp->MoverParameters->Couplers[CouplNr].CouplingFlag & ctrain_depot) == 0) // jeżeli sprzęg niezablokowany - if (tmp->DettachStatus(CouplNr) < 0) // jeśli jest co odczepić i się da - if (!tmp->Dettach(CouplNr)) - { // dźwięk odczepiania - dsbCouplerDetach.play(); - } - } + + if( ( CouplNr != -1 ) + && ( tmp != nullptr ) ) { + + tmp->uncouple( CouplNr ); } if( DynamicObject->Mechanik ) { // aktualizacja skrajnych pojazdów w składzie DynamicObject->Mechanik->CheckVehicles( Disconnect ); } } + } -#ifdef EU07_USE_OLD_COMMAND_SYSTEM - else if (cKey == Global::Keys[k_UpperSign]) // ABu 060205: światło górne - - // wyłączenie - { - if (mvOccupied->LightsPosNo > 0) //kręciolek od swiatel - { - if ((mvOccupied->LightsPos > 1) || (mvOccupied->LightsWrap)) - { - mvOccupied->LightsPos--; - if (mvOccupied->LightsPos < 1) - { - mvOccupied->LightsPos = mvOccupied->LightsPosNo; - } - play_sound( dsbSwitch ); - SetLights(); - } - } - } -#endif + // else if (DebugModeFlag) { // przesuwanie składu o 100m @@ -3510,9 +3354,6 @@ bool TTrain::Update( double const Deltatime ) vMechMovement = Vec; } - DWORD stat; - double dt = Deltatime; // Timer::GetDeltaTime(); - if (DynamicObject->mdKabina) { // Ra: TODO: odczyty klawiatury/pulpitu nie // powinny być uzależnione od istnienia modelu @@ -3536,10 +3377,10 @@ bool TTrain::Update( double const Deltatime ) if (fTachoVelocity > 1) // McZapkie-270503: podkrecanie tachometru { if (fTachoCount < maxtacho) - fTachoCount += dt * 3; // szybciej zacznij stukac + fTachoCount += Deltatime * 3; // szybciej zacznij stukac } else if (fTachoCount > 0) - fTachoCount -= dt * 0.66; // schodz powoli - niektore haslery to ze 4 + fTachoCount -= Deltatime * 0.66; // schodz powoli - niektore haslery to ze 4 // sekundy potrafia stukac // Ra 2014-09: napięcia i prądy muszą być ustalone najpierw, bo wysyłane są ewentualnie na PoKeys @@ -3747,7 +3588,7 @@ bool TTrain::Update( double const Deltatime ) // Ra 15-01: to musi stąd wylecieć - zależności nie mogą być w kabinie if (mvControlled->ConverterFlag == true) { - fConverterTimer += dt; + fConverterTimer += Deltatime; if ((mvControlled->CompressorFlag == true) && (mvControlled->CompressorPower == 1) && ((mvControlled->EngineType == ElectricSeriesMotor) || (mvControlled->TrainType == dt_EZT)) && @@ -4481,7 +4322,7 @@ bool TTrain::Update( double const Deltatime ) if (fBlinkTimer > fCzuwakBlink) fBlinkTimer = -fCzuwakBlink; else - fBlinkTimer += dt; + fBlinkTimer += Deltatime; // hunter-091012: dodanie testu czuwaka if( ( TestFlag( mvOccupied->SecuritySystem.Status, s_aware ) ) @@ -4969,7 +4810,7 @@ bool TTrain::Update( double const Deltatime ) { if (Global::ctrlState) { - mvOccupied->BrakeCtrlPos2 -= dt / 20.0; + mvOccupied->BrakeCtrlPos2 -= Deltatime / 20.0; if (mvOccupied->BrakeCtrlPos2 < -1.5) mvOccupied->BrakeCtrlPos2 = -1.5; } @@ -4988,7 +4829,7 @@ bool TTrain::Update( double const Deltatime ) { if (Global::ctrlState) { - mvOccupied->BrakeCtrlPos2 += (mvOccupied->BrakeCtrlPos2 > 2 ? 0 : dt / 20.0); + mvOccupied->BrakeCtrlPos2 += (mvOccupied->BrakeCtrlPos2 > 2 ? 0 : Deltatime / 20.0); if (mvOccupied->BrakeCtrlPos2 < -3) mvOccupied->BrakeCtrlPos2 = -3; } @@ -5284,7 +5125,6 @@ bool TTrain::Update( double const Deltatime ) // sounds update_sounds( Deltatime ); - m_updated = true; return true; //(DynamicObject->Update(dt)); } // koniec update @@ -5403,212 +5243,25 @@ TTrain::update_sounds( double const Deltatime ) { } } */ - // szum w czasie jazdy - vol = 0.0; - dfreq = 1.0; - if( rsRunningNoise.AM != 0 ) { - if( DynamicObject->GetVelocity() != 0 ) { - if( !TestFlag( mvOccupied->DamageFlag, - dtrain_wheelwear ) ) // McZpakie-221103: halas zalezny od kola - { - dfreq = rsRunningNoise.FM * mvOccupied->Vel + rsRunningNoise.FA; - vol = rsRunningNoise.AM * mvOccupied->Vel + rsRunningNoise.AA; - switch( tor->eEnvironment ) { - case e_tunnel: - { - vol *= 3; - dfreq *= 0.95; - } - break; - case e_canyon: - { - vol *= 1.1; - } - break; - case e_bridge: - { - vol *= 2; - dfreq *= 0.98; - } - break; - } - } - else // uszkodzone kolo (podkucie) - if( fabs( mvOccupied->nrot ) > 0.01 ) { - dfreq = rsRunningNoise.FM * mvOccupied->Vel + rsRunningNoise.FA; - vol = rsRunningNoise.AM * mvOccupied->Vel + rsRunningNoise.AA; - switch( tor->eEnvironment ) { - case e_tunnel: - { - vol *= 2; - } - break; - case e_canyon: - { - vol *= 1.1; - } - break; - case e_bridge: - { - vol *= 1.5; - } - break; - } - } - if( fabs( mvOccupied->nrot ) > 0.01 ) - vol *= 1 + - mvOccupied->UnitBrakeForce / - ( 1 + mvOccupied->MaxBrakeForce ); // hamulce wzmagaja halas - vol = vol * ( 20.0 + tor->iDamageFlag ) / 21; - rsRunningNoise.AdjFreq( dfreq, 0 ); - rsRunningNoise.Play( vol, DSBPLAY_LOOPING, true, DynamicObject->GetPosition() ); - } - else - rsRunningNoise.Stop(); - } - - if( rsBrake.AM != 0 ) { - if( ( !mvOccupied->SlippingWheels ) && ( mvOccupied->UnitBrakeForce > 10.0 ) && - ( DynamicObject->GetVelocity() > 0.01 ) ) { - // vol=rsBrake.AA+rsBrake.AM*(DynamicObject->GetVelocity()*100+mvOccupied->UnitBrakeForce); - vol = - rsBrake.AM * sqrt( ( DynamicObject->GetVelocity() * mvOccupied->UnitBrakeForce ) ); - dfreq = rsBrake.FA + rsBrake.FM * DynamicObject->GetVelocity(); - rsBrake.AdjFreq( dfreq, 0 ); - rsBrake.Play( vol, DSBPLAY_LOOPING, true, DynamicObject->GetPosition() ); - } - else { - rsBrake.Stop(); - } - } - - if( rsEngageSlippery.AM != 0 ) { - if /*((fabs(mvControlled->dizel_engagedeltaomega)>0.2) && */( - mvControlled->dizel_engage > 0.1 ) { - if( fabs( mvControlled->dizel_engagedeltaomega ) > 0.2 ) { - dfreq = rsEngageSlippery.FA + - rsEngageSlippery.FM * fabs( mvControlled->dizel_engagedeltaomega ); - vol = rsEngageSlippery.AA + rsEngageSlippery.AM * ( mvControlled->dizel_engage ); - } - else { - dfreq = - 1; // rsEngageSlippery.FA+0.7*rsEngageSlippery.FM*(fabs(mvControlled->enrot)+mvControlled->nmax); - if( mvControlled->dizel_engage > 0.2 ) - vol = - rsEngageSlippery.AA + - 0.2 * rsEngageSlippery.AM * ( mvControlled->enrot / mvControlled->nmax ); - else - vol = 0; - } - rsEngageSlippery.AdjFreq( dfreq, 0 ); - rsEngageSlippery.Play( vol, DSBPLAY_LOOPING, true, DynamicObject->GetPosition() ); - } - else { - rsEngageSlippery.Stop(); - } - } - - if( FreeFlyModeFlag ) - rsFadeSound.Stop(); // wyłącz to cholerne cykanie! - else - rsFadeSound.Play( 1, DSBPLAY_LOOPING, true, DynamicObject->GetPosition() ); - - // McZapkie! - to wazne - SoundFlag wystawiane jest przez moje moduly - // gdy zachodza pewne wydarzenia komentowane dzwiekiem. - // Mysle ze wystarczy sprawdzac a potem zerowac SoundFlag tutaj - // a nie w DynObject - gdyby cos poszlo zle to po co szarpac dzwiekiem co - // 10ms. - - if( TestFlag( mvOccupied->SoundFlag, sound_relay ) ) { - // przekaznik - gdy bezpiecznik, automatyczny rozruch itp - if( mvOccupied->EventFlag || TestFlag( mvOccupied->SoundFlag, sound_loud ) ) { - mvOccupied->EventFlag = false; // Ra: w kabinie? - if( dsbRelay != nullptr ) { dsbRelay->SetVolume( DSBVOLUME_MAX ); } - } - else { - if( dsbRelay != nullptr ) { dsbRelay->SetVolume( -40 ); } - } - if( !TestFlag( mvOccupied->SoundFlag, sound_manyrelay ) ) - dsbRelay.play(); - else { - if( TestFlag( mvOccupied->SoundFlag, sound_loud ) ) - dsbWejscie_na_bezoporow.play(); - else - dsbWejscie_na_drugi_uklad.play(); - } - } - - if( dsbBufferClamp != nullptr ) { - if( TestFlag( mvOccupied->SoundFlag, sound_bufferclamp ) ) // zderzaki uderzaja o siebie - { - if( TestFlag( mvOccupied->SoundFlag, sound_loud ) ) - dsbBufferClamp->SetVolume( DSBVOLUME_MAX ); - else - dsbBufferClamp->SetVolume( -20 ); - dsbBufferClamp.play(); - } - } - if( dsbCouplerStretch ) - if( TestFlag( mvOccupied->SoundFlag, sound_couplerstretch ) ) // sprzegi sie rozciagaja - { - if( TestFlag( mvOccupied->SoundFlag, sound_loud ) ) - dsbCouplerStretch->SetVolume( DSBVOLUME_MAX ); - else - dsbCouplerStretch->SetVolume( -20 ); - dsbCouplerStretch.play(); - } - - if( mvOccupied->SoundFlag == 0 ) - if( mvOccupied->EventFlag ) - if( TestFlag( mvOccupied->DamageFlag, dtrain_wheelwear ) ) { // Ra: przenieść do DynObj! - if( rsRunningNoise.AM != 0 ) { - rsRunningNoise.Stop(); - float am = rsRunningNoise.AM; - float fa = rsRunningNoise.FA; - float fm = rsRunningNoise.FM; - rsRunningNoise.Init( "lomotpodkucia.wav", -1, 0, 0, 0, true ); // MC: zmiana szumu na lomot - if( rsRunningNoise.AM == 1 ) - rsRunningNoise.AM = am; - rsRunningNoise.AA = 0.7; - rsRunningNoise.FA = fa; - rsRunningNoise.FM = fm; - } - mvOccupied->EventFlag = false; - } - - mvOccupied->SoundFlag = 0; - // McZapkie! - koniec obslugi dzwiekow z mover.pas - - - if( mvControlled->SlippingWheels ) { - // Ra 2014-12: lokomotywy 181/182 dostają SlippingWheels po zahamowaniu powyżej 2.85 bara i buczały - double veldiff = ( DynamicObject->GetVelocity() - fTachoVelocity ) / mvControlled->Vmax; - if( veldiff < -0.01 ) { - // 1% Vmax rezerwy, żeby 181/182 nie buczały po zahamowaniu, ale to proteza - rsSlippery.Play( -rsSlippery.AM * veldiff + rsSlippery.AA, DSBPLAY_LOOPING, true, DynamicObject->GetPosition() ); - if( mvControlled->TrainType == dt_181 ) // alarm przy poslizgu dla 181/182 - BOMBARDIER - if( dsbSlipAlarm ) - play_sound( dsbSlipAlarm, DSBPLAY_LOOPING ); - } - else { - if( ( mvOccupied->UnitBrakeForce > 100.0 ) && ( DynamicObject->GetVelocity() > 1.0 ) ) { - rsSlippery.Play( rsSlippery.AM * veldiff + rsSlippery.AA, DSBPLAY_LOOPING, true, DynamicObject->GetPosition() ); - if( mvControlled->TrainType == dt_181 ) - if( dsbSlipAlarm ) - dsbSlipAlarm->Stop(); - } - } - } - else { - rsSlippery.Stop(); - if( mvControlled->TrainType == dt_181 ) - if( dsbSlipAlarm ) - dsbSlipAlarm->Stop(); - } #endif + + // ambient sound + // since it's typically ticking of the clock we can center it on tachometer or on middle of compartment bounding area + rsFadeSound.play( sound_flags::exclusive | sound_flags::looping ); + + if( mvControlled->TrainType == dt_181 ) { + // alarm przy poslizgu dla 181/182 - BOMBARDIER + if( ( mvControlled->SlippingWheels ) + && ( DynamicObject->GetVelocity() > 1.0 ) ) { + dsbSlipAlarm.play( sound_flags::exclusive | sound_flags::looping ); + } + else { + dsbSlipAlarm.stop(); + } + } + // McZapkie-141102: SHP i czuwak, TODO: sygnalizacja kabinowa - if (mvOccupied->SecuritySystem.Status > 0) - { + if (mvOccupied->SecuritySystem.Status > 0) { // hunter-091012: rozdzielenie alarmow if( TestFlag( mvOccupied->SecuritySystem.Status, s_CAalarm ) || TestFlag( mvOccupied->SecuritySystem.Status, s_SHPalarm ) ) { @@ -5632,65 +5285,21 @@ TTrain::update_sounds( double const Deltatime ) { Console::BitsClear( 1 << 14 ); // ustawienie bitu 16 na PoKeys } } -#ifdef EU07_USE_OLD_SOUNDCODE - /* if ((mvControlled->Mains) && - (mvControlled->EngineType==ElectricSeriesMotor)) - { - //tu dac w przyszlosci zaleznosc od wlaczenia przetwornicy - if (mvControlled->ConverterFlag) //NBMX -obsluga przetwornicy - { - //glosnosc zalezna od nap. sieci - //-2000 do 0 - long tmpVol; - int trackVol; - trackVol=3550-2000; - if (mvControlled->RunningTraction.TractionVoltage<2000) - { - tmpVol=0; - } - else - { - tmpVol=mvControlled->RunningTraction.TractionVoltage-2000; - } - sConverter.Volume(-2000*(trackVol-tmpVol)/trackVol); - if (!sConverter.Playing()) - sConverter.TurnOn(); - } - else //wyl przetwornicy - sConverter.TurnOff(); - } - else - { - if (sConverter.Playing()) - sConverter.TurnOff(); - } - sConverter.Update(); - */ - - // if (fabs(DynamicObject->GetVelocity())>0.5) - if( dsbHasler != nullptr ) { - if( ( false == FreeFlyModeFlag ) && ( fTachoCount > maxtacho ) ) { - dsbHasler->GetStatus( &stat ); - if( !( stat & DSBSTATUS_PLAYING ) ) - play_sound( dsbHasler, DSBVOLUME_MAX, DSBPLAY_LOOPING ); - } - else { - if( ( true == FreeFlyModeFlag ) || ( fTachoCount < 1 ) ) { - dsbHasler->GetStatus( &stat ); - if( stat & DSBSTATUS_PLAYING ) - dsbHasler->Stop(); - } - } + if( fTachoCount > 3.f ) { + dsbHasler.play( sound_flags::exclusive | sound_flags::looping ); + } + else if( fTachoCount < 1.f ) { + dsbHasler.stop(); } -#endif } bool TTrain::CabChange(int iDirection) { // McZapkie-090902: zmiana kabiny 1->0->2 i z powrotem - if (DynamicObject->Mechanik ? DynamicObject->Mechanik->AIControllFlag : - true) // jeśli prowadzi AI albo jest w innym członie - { // jak AI prowadzi, to nie można mu mieszać + if( ( DynamicObject->Mechanik == nullptr ) + || ( true == DynamicObject->Mechanik->AIControllFlag ) ) { + // jeśli prowadzi AI albo jest w innym członie + // jak AI prowadzi, to nie można mu mieszać if (abs(DynamicObject->MoverParameters->ActiveCab + iDirection) > 1) return false; // ewentualna zmiana pojazdu DynamicObject->MoverParameters->ActiveCab = @@ -5721,14 +5330,6 @@ bool TTrain::LoadMMediaFile(std::string const &asFileName) cParser parser(asFileName, cParser::buffer_FILE); // NOTE: yaml-style comments are disabled until conflict in use of # is resolved // parser.addCommentStyle( "#", "\n" ); - //Wartości domyślne by nie wysypywało przy wybrakowanych mmd @240816 Stele - // NOTE: should be no longer needed as safety checks were added, - // but leaving the defaults for the sake of incomplete mmd files - dsbPneumaticSwitch.deserialize( "silence1.wav", sound_type::single ); - dsbBufferClamp.deserialize( "en57_bufferclamp.wav", sound_type::single ); - dsbCouplerDetach.deserialize( "couplerdetach.wav", sound_type::single ); - dsbCouplerStretch.deserialize( "en57_couplerstretch.wav", sound_type::single ); - dsbCouplerAttach.deserialize( "couplerattach.wav", sound_type::single ); std::string token; do @@ -5750,250 +5351,91 @@ bool TTrain::LoadMMediaFile(std::string const &asFileName) { // nastawnik: dsbNastawnikJazdy.deserialize( parser, sound_type::single ); + dsbNastawnikJazdy.owner( DynamicObject ); } else if (token == "ctrlscnd:") { // hunter-081211: nastawnik bocznikowania dsbNastawnikBocz.deserialize( parser, sound_type::single ); + dsbNastawnikBocz.owner( DynamicObject ); } else if (token == "reverserkey:") { // hunter-131211: dzwiek kierunkowego dsbReverserKey.deserialize( parser, sound_type::single ); + dsbReverserKey.owner( DynamicObject ); } else if (token == "buzzer:") { // bzyczek shp: dsbBuzzer.deserialize( parser, sound_type::single ); + dsbBuzzer.owner( DynamicObject ); } else if (token == "slipalarm:") { // Bombardier 011010: alarm przy poslizgu: dsbSlipAlarm.deserialize( parser, sound_type::single ); + dsbSlipAlarm.owner( DynamicObject ); } else if (token == "tachoclock:") { // cykanie rejestratora: dsbHasler.deserialize( parser, sound_type::single ); + dsbHasler.owner( DynamicObject ); } else if (token == "switch:") { // przelaczniki: dsbSwitch.deserialize( parser, sound_type::single ); + dsbSwitch.owner( DynamicObject ); } else if (token == "pneumaticswitch:") { // stycznik EP: dsbPneumaticSwitch.deserialize( parser, sound_type::single ); - } - else if (token == "wejscie_na_bezoporow:") - { - // hunter-111211: wydzielenie wejscia na bezoporowa i na drugi uklad do pliku - dsbWejscie_na_bezoporow.deserialize( parser, sound_type::single ); - } - else if (token == "wejscie_na_drugi_uklad:") - { - dsbWejscie_na_drugi_uklad.deserialize( parser, sound_type::single ); - } - else if (token == "relay:") - { - // styczniki itp: - dsbRelay.deserialize( parser, sound_type::single ); - if( true == dsbWejscie_na_bezoporow.empty() ) { - // hunter-111211: domyslne, gdy brak - dsbWejscie_na_bezoporow.deserialize( "wejscie_na_bezoporow.wav", sound_type::single ); - } - if (true == dsbWejscie_na_drugi_uklad.empty()) { - dsbWejscie_na_drugi_uklad.deserialize( "wescie_na_drugi_uklad.wav", sound_type::single ); - } - } - else if (token == "pneumaticrelay:") - { - // wylaczniki pneumatyczne: - dsbPneumaticRelay.deserialize( parser, sound_type::single ); - } - else if (token == "couplerattach:") - { - // laczenie: - dsbCouplerAttach.deserialize( parser, sound_type::single ); - } - else if (token == "couplerstretch:") - { - // laczenie: - dsbCouplerStretch.deserialize( parser, sound_type::single ); - } - else if (token == "couplerdetach:") - { - // rozlaczanie: - dsbCouplerDetach.deserialize( parser, sound_type::single ); - } - else if (token == "bufferclamp:") - { - // laczenie: - dsbBufferClamp.deserialize( parser, sound_type::single ); - } - else if (token == "ignition:") - { - // odpalanie silnika - dsbDieselIgnition.deserialize( parser, sound_type::single ); - } - else if (token == "brakesound:") - { - // hamowanie zwykle: -/* - rsBrake.Init(parser.getToken(), -1, 0, 0, 0, true, true); - parser.getTokens(4, false); - parser - >> rsBrake.AM - >> rsBrake.AA - >> rsBrake.FM - >> rsBrake.FA; - rsBrake.AM /= (1 + mvOccupied->MaxBrakeForce * 1000); - rsBrake.FM /= (1 + mvOccupied->Vmax); -*/ - rsBrake.deserialize( parser, sound_type::single, sound_parameters::amplitude | sound_parameters::frequency ); - } - else if (token == "slipperysound:") - { - // sanie: -/* - rsSlippery.Init(parser.getToken(), -1, 0, 0, 0, true); - parser.getTokens(2, false); - parser - >> rsSlippery.AM - >> rsSlippery.AA; - rsSlippery.FM = 0.0; - rsSlippery.FA = 1.0; - rsSlippery.AM /= (1 + mvOccupied->Vmax); -*/ - rsSlippery.deserialize( parser, sound_type::single, sound_parameters::amplitude ); + dsbPneumaticSwitch.owner( DynamicObject ); } else if (token == "airsound:") { // syk: -/* - rsHiss.Init(parser.getToken(), -1, 0, 0, 0, true); - parser.getTokens(2, false); - parser - >> rsHiss.AM - >> rsHiss.AA; - rsHiss.FM = 0.0; - rsHiss.FA = 1.0; -*/ rsHiss.deserialize( parser, sound_type::single, sound_parameters::amplitude ); + rsHiss.owner( DynamicObject ); } else if (token == "airsound2:") { // syk: -/* - rsHissU.Init(parser.getToken(), -1, 0, 0, 0, true); - parser.getTokens(2, false); - parser - >> rsHissU.AM - >> rsHissU.AA; - rsHissU.FM = 0.0; - rsHissU.FA = 1.0; -*/ rsHissU.deserialize( parser, sound_type::single, sound_parameters::amplitude ); + rsHissU.owner( DynamicObject ); } else if (token == "airsound3:") { // syk: -/* - rsHissE.Init(parser.getToken(), -1, 0, 0, 0, true); - parser.getTokens(2, false); - parser - >> rsHissE.AM - >> rsHissE.AA; - rsHissE.FM = 0.0; - rsHissE.FA = 1.0; -*/ rsHissE.deserialize( parser, sound_type::single, sound_parameters::amplitude ); + rsHissE.owner( DynamicObject ); } else if (token == "airsound4:") { // syk: -/* - rsHissX.Init(parser.getToken(), -1, 0, 0, 0, true); - parser.getTokens(2, false); - parser - >> rsHissX.AM - >> rsHissX.AA; - rsHissX.FM = 0.0; - rsHissX.FA = 1.0; -*/ rsHissX.deserialize( parser, sound_type::single, sound_parameters::amplitude ); + rsHissX.owner( DynamicObject ); } else if (token == "airsound5:") { // syk: -/* - rsHissT.Init(parser.getToken(), -1, 0, 0, 0, true); - parser.getTokens(2, false); - parser - >> rsHissT.AM - >> rsHissT.AA; - rsHissT.FM = 0.0; - rsHissT.FA = 1.0; -*/ rsHissT.deserialize( parser, sound_type::single, sound_parameters::amplitude ); - } - else if (token == "fadesound:") - { - // syk: -/* - rsFadeSound.Init(parser.getToken(), -1, 0, 0, 0, true); - rsFadeSound.AM = 1.0; - rsFadeSound.AA = 1.0; - rsFadeSound.FM = 1.0; - rsFadeSound.FA = 1.0; -*/ - rsFadeSound.deserialize( parser, sound_type::single ); + rsHissT.owner( DynamicObject ); } else if (token == "localbrakesound:") { // syk: -/* - rsSBHiss.Init(parser.getToken(), -1, 0, 0, 0, true); - parser.getTokens(2, false); - parser - >> rsSBHiss.AM - >> rsSBHiss.AA; - rsSBHiss.FM = 0.0; - rsSBHiss.FA = 1.0; -*/ rsSBHiss.deserialize( parser, sound_type::single, sound_parameters::amplitude ); + rsSBHiss.owner( DynamicObject ); } - else if (token == "runningnoise:") + else if (token == "fadesound:") { - // szum podczas jazdy: -/* - rsRunningNoise.Init(parser.getToken(), -1, 0, 0, 0, true, true); - parser.getTokens(4, false); - parser - >> rsRunningNoise.AM - >> rsRunningNoise.AA - >> rsRunningNoise.FM - >> rsRunningNoise.FA; - rsRunningNoise.AM /= (1 + mvOccupied->Vmax); - rsRunningNoise.FM /= (1 + mvOccupied->Vmax); -*/ - rsRunningNoise.deserialize( parser, sound_type::single, sound_parameters::amplitude | sound_parameters::frequency ); - } - else if (token == "engageslippery:") - { - // tarcie tarcz sprzegla: -/* - rsEngageSlippery.Init(parser.getToken(), -1, 0, 0, 0, true, true); - parser.getTokens(4, false); - parser - >> rsEngageSlippery.AM - >> rsEngageSlippery.AA - >> rsEngageSlippery.FM - >> rsEngageSlippery.FA; - rsEngageSlippery.FM /= (1 + mvOccupied->nmax); -*/ - rsEngageSlippery.deserialize( parser, sound_type::single, sound_parameters::amplitude | sound_parameters::frequency ); + // ambient sound: + rsFadeSound.deserialize( parser, sound_type::single ); + rsFadeSound.owner( DynamicObject ); } else if (token == "mechspring:") { @@ -6202,6 +5644,45 @@ bool TTrain::InitializeCab(int NewCabNo, std::string const &asFileName) { DynamicObject->mdKabina->Init(); // obrócenie modelu oraz optymalizacja, również zapisanie binarnego set_cab_controls(); + + // configure placement of sound emitters which aren't bound with any device model, and weren't placed manually + auto const nullvector { glm::vec3() }; + // try first to bind sounds to location of possible devices + if( dsbReverserKey.offset() == nullvector ) { + dsbReverserKey.offset( ggDirKey.model_offset() ); + } + if( dsbNastawnikJazdy.offset() == nullvector ) { + dsbNastawnikJazdy.offset( ggMainCtrl.model_offset() ); + } + if( dsbNastawnikBocz.offset() == nullvector ) { + dsbNastawnikBocz.offset( ggScndCtrl.model_offset() ); + } + if( dsbBuzzer.offset() == nullvector ) { + dsbBuzzer.offset( btLampkaCzuwaka.model_offset() ); + } + auto const brakeoffset { ggBrakeCtrl.model_offset() }; + std::vector brakesounds = { + &rsHiss, &rsHissU, &rsHissE, &rsHissX, &rsHissT, &rsSBHiss, + }; + for( auto sound : brakesounds ) { + if( sound->offset() == nullvector ) { + sound->offset( brakeoffset ); + } + } + // for whatever is left fallback on generic location, centre of the cab + auto const caboffset { glm::dvec3 { ( Cabine[ NewCabNo ].CabPos1 + Cabine[ NewCabNo ].CabPos2 ) * 0.5 } + glm::dvec3 { 0, 1, 0 } }; + std::vector sounds = { + &dsbReverserKey, &dsbNastawnikJazdy, &dsbNastawnikBocz, + &dsbSwitch, &dsbPneumaticSwitch, + &rsHiss, &rsHissU, &rsHissE, &rsHissX, &rsHissT, &rsSBHiss, + &rsFadeSound, + &dsbHasler, &dsbBuzzer, &dsbSlipAlarm + }; + for( auto sound : sounds ) { + if( sound->offset() == nullvector ) { + sound->offset( caboffset ); + } + } /* // HACK: for some reason simulation at the start is slow until a sound is played // until we do a proper fix, try to play a 'silent' sound when cab is entered @@ -6330,7 +5811,6 @@ void TTrain::Silence() // sConverter.Stop(); // sSmallCompressor->Stop(); dsbCouplerStretch.Stop(); - dsbEN57_CouplerStretch.Stop(); dsbBufferClamp.Stop(); #endif }; @@ -6776,26 +6256,26 @@ bool TTrain::initialize_button(cParser &Parser, std::string const &Label, int co }; auto lookup = lights.find( Label ); if( lookup != lights.end() ) { - lookup->second.Load( Parser, DynamicObject->mdKabina ); + lookup->second.Load( Parser, DynamicObject, DynamicObject->mdKabina ); } else if( Label == "i-instrumentlight:" ) { - btInstrumentLight.Load( Parser, DynamicObject->mdKabina, DynamicObject->mdModel ); + btInstrumentLight.Load( Parser, DynamicObject, DynamicObject->mdKabina, DynamicObject->mdModel ); InstrumentLightType = 0; } else if( Label == "i-instrumentlight_M:" ) { - btInstrumentLight.Load( Parser, DynamicObject->mdKabina, DynamicObject->mdModel ); + btInstrumentLight.Load( Parser, DynamicObject, DynamicObject->mdKabina, DynamicObject->mdModel ); InstrumentLightType = 1; } else if( Label == "i-instrumentlight_C:" ) { - btInstrumentLight.Load( Parser, DynamicObject->mdKabina, DynamicObject->mdModel ); + btInstrumentLight.Load( Parser, DynamicObject, DynamicObject->mdKabina, DynamicObject->mdModel ); InstrumentLightType = 2; } else if (Label == "i-doors:") { int i = Parser.getToken() - 1; auto &button = Cabine[Cabindex].Button(-1); // pierwsza wolna lampka - button.Load(Parser, DynamicObject->mdKabina); + button.Load(Parser, DynamicObject, DynamicObject->mdKabina); button.AssignBool(bDoors[0] + 3 * i); } else @@ -6887,61 +6367,73 @@ bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int con }; auto lookup = gauges.find( Label ); if( lookup != gauges.end() ) { - lookup->second.Load( Parser, DynamicObject->mdKabina ); + lookup->second.Load( Parser, DynamicObject, DynamicObject->mdKabina ); m_controlmapper.insert( lookup->second, lookup->first ); } // ABu 090305: uniwersalne przyciski lub inne rzeczy else if( Label == "mainctrlact:" ) { - ggMainCtrlAct.Load( Parser, DynamicObject->mdKabina, DynamicObject->mdModel ); + ggMainCtrlAct.Load( Parser, DynamicObject, DynamicObject->mdKabina, DynamicObject->mdModel ); } // SEKCJA WSKAZNIKOW else if ((Label == "tachometer:") || (Label == "tachometerb:")) { // predkosciomierz wskaźnikowy z szarpaniem auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka - gauge.Load(Parser, DynamicObject->mdKabina); + gauge.Load(Parser, DynamicObject, DynamicObject->mdKabina); gauge.AssignFloat(&fTachoVelocityJump); + // bind tachometer sound location to the meter + if( dsbHasler.offset() == glm::vec3() ) { + dsbHasler.offset( gauge.model_offset() ); + } } else if (Label == "tachometern:") { // predkosciomierz wskaźnikowy bez szarpania auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka - gauge.Load(Parser, DynamicObject->mdKabina); + gauge.Load(Parser, DynamicObject, DynamicObject->mdKabina); gauge.AssignFloat(&fTachoVelocity); + // bind tachometer sound location to the meter + if( dsbHasler.offset() == glm::vec3() ) { + dsbHasler.offset( gauge.model_offset() ); + } } else if (Label == "tachometerd:") { // predkosciomierz cyfrowy auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka - gauge.Load(Parser, DynamicObject->mdKabina); + gauge.Load(Parser, DynamicObject, DynamicObject->mdKabina); gauge.AssignFloat(&fTachoVelocity); + // bind tachometer sound location to the meter + if( dsbHasler.offset() == glm::vec3() ) { + dsbHasler.offset( gauge.model_offset() ); + } } else if ((Label == "hvcurrent1:") || (Label == "hvcurrent1b:")) { // 1szy amperomierz auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka - gauge.Load(Parser, DynamicObject->mdKabina); + gauge.Load(Parser, DynamicObject, DynamicObject->mdKabina); gauge.AssignFloat(fHCurrent + 1); } else if ((Label == "hvcurrent2:") || (Label == "hvcurrent2b:")) { // 2gi amperomierz auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka - gauge.Load(Parser, DynamicObject->mdKabina); + gauge.Load(Parser, DynamicObject, DynamicObject->mdKabina); gauge.AssignFloat(fHCurrent + 2); } else if ((Label == "hvcurrent3:") || (Label == "hvcurrent3b:")) { // 3ci amperomierz auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałska - gauge.Load(Parser, DynamicObject->mdKabina); + gauge.Load(Parser, DynamicObject, DynamicObject->mdKabina); gauge.AssignFloat(fHCurrent + 3); } else if ((Label == "hvcurrent:") || (Label == "hvcurrentb:")) { // amperomierz calkowitego pradu auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka - gauge.Load(Parser, DynamicObject->mdKabina); + gauge.Load(Parser, DynamicObject, DynamicObject->mdKabina); gauge.AssignFloat(fHCurrent); } else if (Label == "eimscreen:") @@ -6951,7 +6443,7 @@ bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int con Parser.getTokens(2, false); Parser >> i >> j; auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka - gauge.Load(Parser, DynamicObject->mdKabina); + gauge.Load(Parser, DynamicObject, DynamicObject->mdKabina); gauge.AssignFloat(&fEIMParams[i][j]); } else if (Label == "brakes:") @@ -6961,7 +6453,7 @@ bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int con Parser.getTokens(2, false); Parser >> i >> j; auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka - gauge.Load(Parser, DynamicObject->mdKabina); + gauge.Load(Parser, DynamicObject, DynamicObject->mdKabina); gauge.AssignFloat(&fPress[i - 1][j]); } else if ((Label == "brakepress:") || (Label == "brakepressb:")) @@ -6969,55 +6461,55 @@ bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int con // manometr cylindrow hamulcowych // Ra 2014-08: przeniesione do TCab auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka - gauge.Load(Parser, DynamicObject->mdKabina, nullptr, 0.1); + gauge.Load(Parser, DynamicObject, DynamicObject->mdKabina, nullptr, 0.1); gauge.AssignDouble(&mvOccupied->BrakePress); } else if ((Label == "pipepress:") || (Label == "pipepressb:")) { // manometr przewodu hamulcowego auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka - gauge.Load(Parser, DynamicObject->mdKabina, nullptr, 0.1); + gauge.Load(Parser, DynamicObject, DynamicObject->mdKabina, nullptr, 0.1); gauge.AssignDouble(&mvOccupied->PipePress); } else if (Label == "limpipepress:") { // manometr zbiornika sterujacego zaworu maszynisty - ggZbS.Load(Parser, DynamicObject->mdKabina, nullptr, 0.1); + ggZbS.Load(Parser, DynamicObject, DynamicObject->mdKabina, nullptr, 0.1); } else if (Label == "cntrlpress:") { // manometr zbiornika kontrolnego/rorzďż˝du auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka - gauge.Load(Parser, DynamicObject->mdKabina, nullptr, 0.1); + gauge.Load(Parser, DynamicObject, DynamicObject->mdKabina, nullptr, 0.1); gauge.AssignDouble(&mvControlled->PantPress); } else if ((Label == "compressor:") || (Label == "compressorb:")) { // manometr sprezarki/zbiornika glownego auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka - gauge.Load(Parser, DynamicObject->mdKabina, nullptr, 0.1); + gauge.Load(Parser, DynamicObject, DynamicObject->mdKabina, nullptr, 0.1); gauge.AssignDouble(&mvOccupied->Compressor); } // yB - dla drugiej sekcji else if (Label == "hvbcurrent1:") { // 1szy amperomierz - ggI1B.Load(Parser, DynamicObject->mdKabina); + ggI1B.Load(Parser, DynamicObject, DynamicObject->mdKabina); } else if (Label == "hvbcurrent2:") { // 2gi amperomierz - ggI2B.Load(Parser, DynamicObject->mdKabina); + ggI2B.Load(Parser, DynamicObject, DynamicObject->mdKabina); } else if (Label == "hvbcurrent3:") { // 3ci amperomierz - ggI3B.Load(Parser, DynamicObject->mdKabina); + ggI3B.Load(Parser, DynamicObject, DynamicObject->mdKabina); } else if (Label == "hvbcurrent:") { // amperomierz calkowitego pradu - ggItotalB.Load(Parser, DynamicObject->mdKabina); + ggItotalB.Load(Parser, DynamicObject, DynamicObject->mdKabina); } //************************************************************* else if (Label == "clock:") @@ -7034,61 +6526,61 @@ bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int con else if (Label == "evoltage:") { // woltomierz napiecia silnikow - ggEngineVoltage.Load(Parser, DynamicObject->mdKabina); + ggEngineVoltage.Load(Parser, DynamicObject, DynamicObject->mdKabina); } else if (Label == "hvoltage:") { // woltomierz wysokiego napiecia auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka - gauge.Load(Parser, DynamicObject->mdKabina); + gauge.Load(Parser, DynamicObject, DynamicObject->mdKabina); gauge.AssignFloat(&fHVoltage); } else if (Label == "lvoltage:") { // woltomierz niskiego napiecia - ggLVoltage.Load(Parser, DynamicObject->mdKabina); + ggLVoltage.Load(Parser, DynamicObject, DynamicObject->mdKabina); } else if (Label == "enrot1m:") { // obrotomierz auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka - gauge.Load(Parser, DynamicObject->mdKabina); + gauge.Load(Parser, DynamicObject, DynamicObject->mdKabina); gauge.AssignFloat(fEngine + 1); } // ggEnrot1m.Load(Parser,DynamicObject->mdKabina); else if (Label == "enrot2m:") { // obrotomierz auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka - gauge.Load(Parser, DynamicObject->mdKabina); + gauge.Load(Parser, DynamicObject, DynamicObject->mdKabina); gauge.AssignFloat(fEngine + 2); } // ggEnrot2m.Load(Parser,DynamicObject->mdKabina); else if (Label == "enrot3m:") { // obrotomierz auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka - gauge.Load(Parser, DynamicObject->mdKabina); + gauge.Load(Parser, DynamicObject, DynamicObject->mdKabina); gauge.AssignFloat(fEngine + 3); } // ggEnrot3m.Load(Parser,DynamicObject->mdKabina); else if (Label == "engageratio:") { // np. ciśnienie sterownika sprzęgła auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka - gauge.Load(Parser, DynamicObject->mdKabina); + gauge.Load(Parser, DynamicObject, DynamicObject->mdKabina); gauge.AssignDouble(&mvControlled->dizel_engage); } // ggEngageRatio.Load(Parser,DynamicObject->mdKabina); else if (Label == "maingearstatus:") { // np. ciśnienie sterownika skrzyni biegów - ggMainGearStatus.Load(Parser, DynamicObject->mdKabina); + ggMainGearStatus.Load(Parser, DynamicObject, DynamicObject->mdKabina); } else if (Label == "ignitionkey:") { - ggIgnitionKey.Load(Parser, DynamicObject->mdKabina); + ggIgnitionKey.Load(Parser, DynamicObject, DynamicObject->mdKabina); } else if (Label == "distcounter:") { // Ra 2014-07: licznik kilometrów auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka - gauge.Load(Parser, DynamicObject->mdKabina); + gauge.Load(Parser, DynamicObject, DynamicObject->mdKabina); gauge.AssignDouble(&mvControlled->DistCounter); } else diff --git a/Train.h b/Train.h index fd1bd4fb..e60f3667 100644 --- a/Train.h +++ b/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 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(); diff --git a/World.cpp b/World.cpp index 4c003b34..8bd79a40 100644 --- a/World.cpp +++ b/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 ); } diff --git a/audio.cpp b/audio.cpp index 673b64f1..3e0c8f70 100644 --- a/audio.cpp +++ b/audio.cpp @@ -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; } diff --git a/audio.h b/audio.h index a907a41d..8bec3f11 100644 --- a/audio.h +++ b/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 { diff --git a/audiorenderer.cpp b/audiorenderer.cpp index 2a1df7a7..55b97197 100644 --- a/audiorenderer.cpp +++ b/audiorenderer.cpp @@ -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 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( 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 diff --git a/audiorenderer.h b/audiorenderer.h index ddc8ed57..220be99f 100644 --- a/audiorenderer.h +++ b/audiorenderer.h @@ -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 @@ -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 //--------------------------------------------------------------------------- diff --git a/dumb3d.h b/dumb3d.h index 74c4c312..2c59083b 100644 --- a/dumb3d.h +++ b/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; } diff --git a/renderer.cpp b/renderer.cpp index 80cf167a..92c9e79d 100644 --- a/renderer.cpp +++ b/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(); diff --git a/simulation.cpp b/simulation.cpp index 6ef2c32b..0a4a02cd 100644 --- a/simulation.cpp +++ b/simulation.cpp @@ -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(), sound_type::single ); #endif diff --git a/sound.cpp b/sound.cpp index d17912f5..e0cdff2d 100644 --- a/sound.cpp +++ b/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( true, "\n\r\t ,;" ) ); + m_soundmain.buffer = audio::renderer.fetch_buffer( Input.getToken( true, "\n\r\t ,;" ) ); break; } case sound_type::multipart: { // three samples: start, middle, stop - m_soundbegin = audio::renderer.fetch_buffer( Input.getToken( true, "\n\r\t ,;" ) ); - m_soundmain = audio::renderer.fetch_buffer( Input.getToken( true, "\n\r\t ,;" ) ); - m_soundend = audio::renderer.fetch_buffer( Input.getToken( true, "\n\r\t ,;" ) ); + m_soundbegin.buffer = audio::renderer.fetch_buffer( Input.getToken( true, "\n\r\t ,;" ) ); + m_soundmain.buffer = audio::renderer.fetch_buffer( Input.getToken( true, "\n\r\t ,;" ) ); + m_soundend.buffer = audio::renderer.fetch_buffer( Input.getToken( 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( Random( 95, 105 ) ); + } m_flags = Flags; - switch( m_stage ) { - case stage::none: - case stage::restart: { - if( m_soundbegin != null_handle ) { - std::vector bufferlist{ m_soundbegin, m_soundmain }; - audio::renderer.insert( this, std::begin( bufferlist ), std::end( bufferlist ) ); - } - else { - audio::renderer.insert( this, m_soundmain ); - } - break; + if( false == is_playing() ) { + // dispatch appropriate sound + // TODO: support for parameter-driven sound table + if( m_soundbegin.buffer != null_handle ) { + std::vector bufferlist { m_soundbegin.buffer, m_soundmain.buffer }; + audio::renderer.insert( this, std::begin( bufferlist ), std::end( bufferlist ) ); } - case stage::main: { - // TODO: schedule another main sample playback, or a suitable sample from the table for combined sources - break; + else { + audio::renderer.insert( this, m_soundmain.buffer ); } - 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,30 +192,151 @@ 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 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( ( + 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; } //--------------------------------------------------------------------------- diff --git a/sound.h b/sound.h index 7f9ffb29..8a636b20 100644 --- a/sound.h +++ b/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 { }; From 59e8c705641cefc73e90d38e4c7626c071bd6986 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Thu, 30 Nov 2017 16:30:29 +0100 Subject: [PATCH 6/8] less strict trigger conditions for track event0 and event0all --- TrkFoll.cpp | 92 ++++++++++++++++++++++++----------------------------- 1 file changed, 41 insertions(+), 51 deletions(-) diff --git a/TrkFoll.cpp b/TrkFoll.cpp index ddfa4fee..38b61d1a 100644 --- a/TrkFoll.cpp +++ b/TrkFoll.cpp @@ -99,82 +99,72 @@ bool TTrackFollower::Move(double fDistance, bool bPrimary) bool bCanSkip; // czy przemieścić pojazd na inny tor while (true) // pętla wychodzi, gdy przesunięcie wyjdzie zerowe { // pętla przesuwająca wózek przez kolejne tory, aż do trafienia w jakiś - if (!pCurrentTrack) - return false; // nie ma toru, to nie ma przesuwania - if (pCurrentTrack->iEvents) // sumaryczna informacja o eventach - { // omijamy cały ten blok, gdy tor nie ma on żadnych eventów (większość nie ma) - if (fDistance < 0) - { + if( pCurrentTrack == nullptr ) { return false; } // nie ma toru, to nie ma przesuwania + // TODO: refactor following block as track method + if( pCurrentTrack->iEvents ) { // sumaryczna informacja o eventach + // omijamy cały ten blok, gdy tor nie ma on żadnych eventów (większość nie ma) + if( std::abs( fDistance ) < 0.01 ) { + //McZapkie-140602: wyzwalanie zdarzenia gdy pojazd stoi + if( ( Owner->Mechanik != nullptr ) + && ( Owner->Mechanik->Primary() ) ) { + // tylko dla jednego członu + if( ( pCurrentTrack->evEvent0 ) + && ( pCurrentTrack->evEvent0->iQueued == 0 ) ) { + simulation::Events.AddToQuery( pCurrentTrack->evEvent0, Owner ); + } + } + if( ( pCurrentTrack->evEventall0 ) + && ( pCurrentTrack->evEventall0->iQueued == 0 ) ) { + simulation::Events.AddToQuery( pCurrentTrack->evEventall0, Owner ); + } + } + else if (fDistance < 0) { + // event1, eventall1 if( SetFlag( iEventFlag, -1 ) ) { // zawsze zeruje flagę sprawdzenia, jak mechanik dosiądzie, to się nie wykona if( ( Owner->Mechanik != nullptr ) && ( Owner->Mechanik->Primary() ) ) { // tylko dla jednego członu // McZapkie-280503: wyzwalanie event tylko dla pojazdow z obsada - if( ( bPrimary ) - && ( pCurrentTrack->evEvent1 ) - && ( !pCurrentTrack->evEvent1->iQueued ) ) { + if( ( true == bPrimary ) + && ( pCurrentTrack->evEvent1 != nullptr ) + && ( pCurrentTrack->evEvent1->iQueued == 0 ) ) { // dodanie do kolejki simulation::Events.AddToQuery( pCurrentTrack->evEvent1, Owner ); } } } - // Owner->RaAxleEvent(pCurrentTrack->Event1); //Ra: dynamic zdecyduje, czy dodać do - // kolejki - // if (TestFlag(iEventallFlag,1)) - if (SetFlag(iEventallFlag, - -1)) // McZapkie-280503: wyzwalanie eventall dla wszystkich pojazdow - if (bPrimary && pCurrentTrack->evEventall1 && - (!pCurrentTrack->evEventall1->iQueued)) - simulation::Events.AddToQuery(pCurrentTrack->evEventall1, Owner); // dodanie do kolejki - // Owner->RaAxleEvent(pCurrentTrack->Eventall1); //Ra: dynamic zdecyduje, czy dodać - // do kolejki + if( SetFlag( iEventallFlag, -1 ) ) { + // McZapkie-280503: wyzwalanie eventall dla wszystkich pojazdow + if( ( true == bPrimary ) + && ( pCurrentTrack->evEventall1 != nullptr ) + && ( pCurrentTrack->evEventall1->iQueued == 0 ) ) { + simulation::Events.AddToQuery( pCurrentTrack->evEventall1, Owner ); // dodanie do kolejki + } + } } - else if (fDistance > 0) - { + else if (fDistance > 0) { + // event2, eventall2 if( SetFlag( iEventFlag, -2 ) ) { - // zawsze ustawia flagę sprawdzenia, jak mechanik - // dosiądzie, to się nie wykona + // zawsze ustawia flagę sprawdzenia, jak mechanik dosiądzie, to się nie wykona if( ( Owner->Mechanik != nullptr ) && ( Owner->Mechanik->Primary() ) ) { // tylko dla jednego członu - if( ( bPrimary ) - && ( pCurrentTrack->evEvent2 ) - && ( !pCurrentTrack->evEvent2->iQueued ) ) { + if( ( true == bPrimary ) + && ( pCurrentTrack->evEvent2 != nullptr ) + && ( pCurrentTrack->evEvent2->iQueued == 0 ) ) { simulation::Events.AddToQuery( pCurrentTrack->evEvent2, Owner ); } } } - // Owner->RaAxleEvent(pCurrentTrack->Event2); //Ra: dynamic zdecyduje, czy dodać do - // kolejki - // if (TestFlag(iEventallFlag,2)) if( SetFlag( iEventallFlag, -2 ) ) { // sprawdza i zeruje na przyszłość, true jeśli zmieni z 2 na 0 - if( ( bPrimary ) - && ( pCurrentTrack->evEventall2 ) - && ( !pCurrentTrack->evEventall2->iQueued ) ) { + if( ( true == bPrimary ) + && ( pCurrentTrack->evEventall2 != nullptr ) + && ( pCurrentTrack->evEventall2->iQueued == 0 ) ) { simulation::Events.AddToQuery( pCurrentTrack->evEventall2, Owner ); } } - // Owner->RaAxleEvent(pCurrentTrack->Eventall2); //Ra: dynamic zdecyduje, czy dodać - // do kolejki - } - else // if (fDistance==0) //McZapkie-140602: wyzwalanie zdarzenia gdy pojazd stoi - { - if( ( Owner->Mechanik != nullptr ) - && ( Owner->Mechanik->Primary() ) ) { - // tylko dla jednego członu - if( pCurrentTrack->evEvent0 ) - if( !pCurrentTrack->evEvent0->iQueued ) - simulation::Events.AddToQuery( pCurrentTrack->evEvent0, Owner ); - } - // Owner->RaAxleEvent(pCurrentTrack->Event0); //Ra: dynamic zdecyduje, czy dodać do - // kolejki - if (pCurrentTrack->evEventall0) - if (!pCurrentTrack->evEventall0->iQueued) - simulation::Events.AddToQuery(pCurrentTrack->evEventall0, Owner); - // Owner->RaAxleEvent(pCurrentTrack->Eventall0); //Ra: dynamic zdecyduje, czy dodać - // do kolejki } } if (!pCurrentSegment) // jeżeli nie ma powiązanego segmentu toru? From ef2195fbccf33db9bdd9057de968d728768940d3 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Thu, 30 Nov 2017 16:32:59 +0100 Subject: [PATCH 7/8] maintenance: minor code cleanup --- McZapkie/Mover.cpp | 2 +- Model3d.cpp | 14 +++----------- Timer.cpp | 5 ----- Timer.h | 2 -- 4 files changed, 4 insertions(+), 19 deletions(-) diff --git a/McZapkie/Mover.cpp b/McZapkie/Mover.cpp index e339284f..5971367f 100644 --- a/McZapkie/Mover.cpp +++ b/McZapkie/Mover.cpp @@ -3384,7 +3384,7 @@ void TMoverParameters::UpdatePipePressure(double dt) // dodać jakiś wpis do fizyki na to if( ( ( Couplers[ b ].Connected->TrainType & ( dt_ET41 | dt_ET42 ) ) != 0 ) && ( ( Couplers[ b ].CouplingFlag & 36 ) == 36 ) ) - LocBrakePress = Max0R( Couplers[ b ].Connected->LocHandle->GetCP(), LocBrakePress ); + LocBrakePress = std::max( Couplers[ b ].Connected->LocHandle->GetCP(), LocBrakePress ); //if ((DynamicBrakeFlag) && (EngineType == ElectricInductionMotor)) //{ diff --git a/Model3d.cpp b/Model3d.cpp index d2e5e6c8..737ef26e 100644 --- a/Model3d.cpp +++ b/Model3d.cpp @@ -42,21 +42,13 @@ std::string *TSubModel::pasText; // 0x3F3F003F - wszystkie wymienne tekstury używane w danym cyklu // Ale w TModel3d okerśla przezroczystość tekstur wymiennych! -TSubModel::~TSubModel() -{ -/* - if (uiDisplayList) - glDeleteLists(uiDisplayList, 1); -*/ - if (iFlags & 0x0200) +TSubModel::~TSubModel() { + + if (iFlags & 0x0200) { // wczytany z pliku tekstowego musi sam posprzątać - // SafeDeleteArray(Indices); SafeDelete(Next); SafeDelete(Child); delete fMatrix; // własny transform trzeba usunąć (zawsze jeden) -/* - delete[] Vertices; -*/ } delete[] smLetter; // używany tylko roboczo dla TP_TEXT, do przyspieszenia // wyświetlania diff --git a/Timer.cpp b/Timer.cpp index dcfb6780..6220655a 100644 --- a/Timer.cpp +++ b/Timer.cpp @@ -38,11 +38,6 @@ double GetDeltaRenderTime() return DeltaRenderTime; } -double GetfSinceStart() -{ - return fSinceStart; -} - void SetDeltaTime(double t) { DeltaTime = t; diff --git a/Timer.h b/Timer.h index d0d9e5c9..ffcb45e0 100644 --- a/Timer.h +++ b/Timer.h @@ -16,8 +16,6 @@ double GetTime(); double GetDeltaTime(); double GetDeltaRenderTime(); -double GetfSinceStart(); - void SetDeltaTime(double v); bool GetSoundTimer(); From 34f96595fdceb1df76b62d653b2847911beb4540 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Thu, 30 Nov 2017 16:37:25 +0100 Subject: [PATCH 8/8] audio source reinitialization fix, sound volume level tweaks --- Driver.cpp | 52 +++++------ DynObj.cpp | 12 +-- Train.cpp | 214 ++++++++++++++++++++++++---------------------- Train.h | 4 +- audio.cpp | 13 ++- audiorenderer.cpp | 23 +++-- audiorenderer.h | 3 +- sound.cpp | 50 +++++++---- sound.h | 11 ++- 9 files changed, 222 insertions(+), 160 deletions(-) diff --git a/Driver.cpp b/Driver.cpp index 24c9e81e..cb11fa8f 100644 --- a/Driver.cpp +++ b/Driver.cpp @@ -2987,7 +2987,8 @@ void TController::Doors(bool what) if (mvOccupied->DoorOpenCtrl == 1) { // jeśli drzwi sterowane z kabiny if( AIControllFlag ) { - if( mvOccupied->DoorLeftOpened || mvOccupied->DoorRightOpened ) { // AI zamyka drzwi przed odjazdem + if( mvOccupied->DoorLeftOpened || mvOccupied->DoorRightOpened ) { + // AI zamyka drzwi przed odjazdem if( ( true == mvOccupied->DoorClosureWarning ) && ( false == mvOccupied->DepartureSignal ) && ( true == TestFlag( iDrivigFlags, moveDoorOpened ) ) ) { @@ -3092,8 +3093,8 @@ bool TController::PutCommand( std::string NewCommand, double NewValue1, double N asNextStop = TrainParams->NextStop(); iDrivigFlags |= movePrimary; // skoro dostał rozkład, to jest teraz głównym NewCommand = Global::asCurrentSceneryPath + NewCommand + ".wav"; // na razie jeden - if (FileExists(NewCommand)) - { // wczytanie dźwięku odjazdu podawanego bezpośrenido + if (FileExists(NewCommand)) { + // wczytanie dźwięku odjazdu podawanego bezpośrenido #ifdef EU07_USE_OLD_SOUNDCODE tsGuardSignal = new TTextSound( @@ -3101,19 +3102,15 @@ 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 = new sound_source( sound_placement::external, 75.f ); 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 } - else - { + else { NewCommand = NewCommand.insert(NewCommand.find_last_of("."),"radio"); // wstawienie przed kropkč - if (FileExists(NewCommand)) - { // wczytanie dźwięku odjazdu w wersji radiowej (słychać tylko w kabinie) + if (FileExists(NewCommand)) { + // wczytanie dźwięku odjazdu w wersji radiowej (słychać tylko w kabinie) #ifdef EU07_USE_OLD_SOUNDCODE tsGuardSignal = new TTextSound( @@ -3121,12 +3118,8 @@ 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 = new sound_source( sound_placement::internal, 2 * EU07_SOUND_CABCONTROLSCUTOFFRANGE ); 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; } @@ -4487,20 +4480,21 @@ TController::UpdateSituation(double dt) { } if (VelDesired > 0.0) if( ( ( iDrivigFlags & moveStopHere ) == 0 ) - || ( ( SemNextIndex != -1 ) - && ( SemNextIndex < sSpeedTable.size() ) // BUG: index can point at non-existing slot. investigate reason(s) - && ( sSpeedTable[SemNextIndex].fVelNext != 0.0 ) ) ) { + || ( ( SemNextIndex != -1 ) + && ( SemNextIndex < sSpeedTable.size() ) // BUG: index can point at non-existing slot. investigate reason(s) + && ( sSpeedTable[SemNextIndex].fVelNext != 0.0 ) ) ) { // jeśli można jechać, to odpalić dźwięk kierownika oraz zamknąć drzwi w // składzie, jeśli nie mamy czekać na sygnał też trzeba odpalić if (iDrivigFlags & moveGuardSignal) { // komunikat od kierownika tu, bo musi być wolna droga i odczekany czas stania iDrivigFlags &= ~moveGuardSignal; // tylko raz nadać - +/* 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(); @@ -4513,11 +4507,14 @@ TController::UpdateSituation(double dt) { // pobliżu, a drugi radiowy, słyszalny w innych lokomotywach // na razie zakładam, że to nie jest dźwięk radiowy, bo trzeba by zrobić // obsługę kanałów radiowych itd. - if( !iGuardRadio ) { + if( iGuardRadio == 0 ) { // jeśli nie przez radio #ifdef EU07_USE_OLD_SOUNDCODE tsGuardSignal->Play( 1.0, 0, !FreeFlyModeFlag, pVehicle->GetPosition() ); // dla true jest głośniej #else + tsGuardSignal->owner( pVehicle ); + // place virtual conductor some distance away + tsGuardSignal->offset( { pVehicle->MoverParameters->Dim.W * -0.75f, 1.7f, std::min( -20.0, -0.2 * fLength ) } ); tsGuardSignal->play( sound_flags::exclusive ); #endif } @@ -4526,15 +4523,18 @@ TController::UpdateSituation(double dt) { // if (!FreeFlyModeFlag) //obserwator musi być w środku pojazdu // (albo może mieć radio przenośne) - kierownik mógłby powtarzać // przy braku reakcji +#ifdef EU07_USE_OLD_SOUNDCODE if( SquareMagnitude( pVehicle->GetPosition() - Global::pCameraPosition ) < 2000 * 2000 ) { // w odległości mniejszej niż 2km -#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 } +#else + // TODO: proper system for sending/receiving radio messages + // place the sound in appropriate cab of the manned vehicle + tsGuardSignal->owner( pVehicle ); + tsGuardSignal->offset( { 0.f, 2.f, pVehicle->MoverParameters->Dim.L * 0.4f * ( pVehicle->MoverParameters->ActiveCab < 0 ? -1 : 1 ) } ); + tsGuardSignal->play( sound_flags::exclusive ); +#endif } } } diff --git a/DynObj.cpp b/DynObj.cpp index 59941932..f2ff0bc0 100644 --- a/DynObj.cpp +++ b/DynObj.cpp @@ -3605,6 +3605,8 @@ void TDynamicObject::RenderSounds() { double volume { 1.0 }; double const dt { Timer::GetDeltaRenderTime() }; + if( dt == 0.0 ) { return; } + // engine sounds if( MoverParameters->Power > 0 ) { @@ -3889,7 +3891,7 @@ void TDynamicObject::RenderSounds() { } else { eng_turbo = std::max( goalpitch, eng_turbo - changerate * 0.5 ); - volume = std::max( 0.0, sTurbo.gain() - 10.0 * dt ); + volume = std::max( 0.0, sTurbo.gain() - 2.0 * dt ); if( volume > 0.05 ) { sTurbo .pitch( 0.4 + eng_turbo * 0.4 ) @@ -3943,7 +3945,7 @@ void TDynamicObject::RenderSounds() { // brake system and braking sounds: if( m_lastbrakepressure != -1.f ) { - // calculate rate of pressure change in brake cylinder, once it's been initialized + // calculate rate of pressure drop in brake cylinder, once it's been initialized auto const brakepressuredifference { m_lastbrakepressure - MoverParameters->BrakePress }; m_brakepressurechange = interpolate( m_brakepressurechange, 10 * ( brakepressuredifference / dt ), 0.1f ); } @@ -3951,7 +3953,7 @@ void TDynamicObject::RenderSounds() { if( m_brakepressurechange > 0.05f ) { // NOTE: can't use the leak rate directly due to irregular results produced by some brake type implementations rsUnbrake - .gain( static_cast( std::max( MoverParameters->BrakePress, 0.0 ) / MoverParameters->MaxBrakePress[ 3 ] ) ) + .gain( static_cast( 1.25 * std::max( MoverParameters->BrakePress, 0.0 ) / MoverParameters->MaxBrakePress[ 3 ] ) ) .play( sound_flags::exclusive | sound_flags::looping ); } else { @@ -4164,13 +4166,13 @@ void TDynamicObject::RenderSounds() { } // scale volume by track quality volume *= ( 20.0 + MyTrack->iDamageFlag ) / 21; - // scale volume with curve radius and vehicle speed + // scale volume with vehicle speed // TBD, TODO: disable the scaling for sounds combined from speed-based samples? volume *= interpolate( 0.0, 1.0, clamp( - MoverParameters->Vel / 80.0, + MoverParameters->Vel / 60.0, 0.0, 1.0 ) ); rsRunningNoise .pitch( clamp( frequency, 0.5, 1.15 ) ) // arbitrary limits to prevent the pitch going out of whack diff --git a/Train.cpp b/Train.cpp index db9f5a56..213c9683 100644 --- a/Train.cpp +++ b/Train.cpp @@ -5130,120 +5130,128 @@ bool TTrain::Update( double const Deltatime ) void TTrain::update_sounds( double const Deltatime ) { -#ifdef EU07_USE_OLD_SOUNDCODE - double vol = 0; - // int freq=1; - double dfreq; + + if( Deltatime == 0.0 ) { return; } + + double volume { 0.0 }; + double const brakevolumescale { 0.5 }; // McZapkie-280302 - syczenie - if( ( mvOccupied->BrakeHandle == FV4a ) || ( mvOccupied->BrakeHandle == FVel6 ) ) { - if( rsHiss.AM != 0 ) // upuszczanie z PG - { - fPPress = ( 1 * fPPress + mvOccupied->Handle->GetSound( s_fv4a_b ) ) / ( 2 ); - if( fPPress > 0 ) { - vol = 2.0 * rsHiss.AM * fPPress; - } - if( vol > 0.001 ) { - rsHiss.Play( vol, DSBPLAY_LOOPING, true, DynamicObject->GetPosition() ); - } - else { - rsHiss.Stop(); - } + // TODO: softer volume reduction than plain abrupt stop, perhaps as reusable wrapper? + if( ( mvOccupied->BrakeHandle == FV4a ) + || ( mvOccupied->BrakeHandle == FVel6 ) ) { + // upuszczanie z PG + fPPress = interpolate( fPPress, mvOccupied->Handle->GetSound( s_fv4a_b ), 0.05 ); + volume = ( + fPPress > 0 ? + rsHiss.m_amplitudefactor * fPPress * 0.25 : + 0 ); + if( volume * brakevolumescale > 0.05 ) { + rsHiss + .gain( volume * brakevolumescale ) + .play( sound_flags::exclusive | sound_flags::looping ); } - if( rsHissU.AM != 0 ) // upuszczanie z PG - { - fNPress = ( 1 * fNPress + mvOccupied->Handle->GetSound( s_fv4a_u ) ) / ( 2 ); - if( fNPress > 0 ) { - vol = rsHissU.AM * fNPress; - } - if( vol > 0.001 ) { - rsHissU.Play( vol, DSBPLAY_LOOPING, true, DynamicObject->GetPosition() ); - } - else { - rsHissU.Stop(); - } + else { + rsHiss.stop(); } - if( rsHissE.AM != 0 ) // upuszczanie przy naglym - { - vol = mvOccupied->Handle->GetSound( s_fv4a_e ) * rsHissE.AM; - if( vol > 0.001 ) { - rsHissE.Play( vol, DSBPLAY_LOOPING, true, DynamicObject->GetPosition() ); - } - else { - rsHissE.Stop(); - } + // napelnianie PG + fNPress = interpolate( fNPress, mvOccupied->Handle->GetSound( s_fv4a_u ), 0.25 ); + volume = ( + fNPress > 0 ? + rsHissU.m_amplitudefactor * fNPress : + 0 ); + if( volume * brakevolumescale > 0.05 ) { + rsHissU + .gain( volume * brakevolumescale ) + .play( sound_flags::exclusive | sound_flags::looping ); } - if( rsHissX.AM != 0 ) // upuszczanie sterujacego fala - { - vol = mvOccupied->Handle->GetSound( s_fv4a_x ) * rsHissX.AM; - if( vol > 0.001 ) { - rsHissX.Play( vol, DSBPLAY_LOOPING, true, DynamicObject->GetPosition() ); - } - else { - rsHissX.Stop(); - } + else { + rsHissU.stop(); } - if( rsHissT.AM != 0 ) // upuszczanie z czasowego - { - vol = mvOccupied->Handle->GetSound( s_fv4a_t ) * rsHissT.AM; - if( vol > 0.001 ) { - rsHissT.Play( vol, DSBPLAY_LOOPING, true, DynamicObject->GetPosition() ); - } - else { - rsHissT.Stop(); - } + // upuszczanie przy naglym + volume = mvOccupied->Handle->GetSound( s_fv4a_e ) * rsHissE.m_amplitudefactor; + if( volume * brakevolumescale > 0.05 ) { + rsHissE + .gain( volume * brakevolumescale ) + .play( sound_flags::exclusive | sound_flags::looping ); + } + else { + rsHissE.stop(); + } + // upuszczanie sterujacego fala + volume = mvOccupied->Handle->GetSound( s_fv4a_x ) * rsHissX.m_amplitudefactor; + if( volume * brakevolumescale > 0.05 ) { + rsHissX + .gain( volume * brakevolumescale ) + .play( sound_flags::exclusive | sound_flags::looping ); + } + else { + rsHissX.stop(); + } + // upuszczanie z czasowego + volume = mvOccupied->Handle->GetSound( s_fv4a_t ) * rsHissT.m_amplitudefactor; + if( volume * brakevolumescale > 0.05 ) { + rsHissT + .gain( volume * brakevolumescale ) + .play( sound_flags::exclusive | sound_flags::looping ); + } + else { + rsHissT.stop(); } - } // koniec FV4a - else // jesli nie FV4a - { - if( rsHiss.AM != 0.0 ) // upuszczanie z PG - { - fPPress = ( 4.0f * fPPress + std::max( mvOccupied->dpLocalValve, mvOccupied->dpMainValve ) ) / ( 4.0f + 1.0f ); - if( fPPress > 0.0f ) { - vol = 2.0 * rsHiss.AM * fPPress; - } - if( vol > 0.01 ) { - rsHiss.Play( vol, DSBPLAY_LOOPING, true, DynamicObject->GetPosition() ); - } - else { - rsHiss.Stop(); - } + } else { + // jesli nie FV4a + // upuszczanie z PG + fPPress = ( 4.0f * fPPress + std::max( mvOccupied->dpLocalValve, mvOccupied->dpMainValve ) ) / ( 4.0f + 1.0f ); + volume = ( + fPPress > 0.0f ? + 2.0 * rsHiss.m_amplitudefactor * fPPress : + 0.0 ); + if( volume > 0.05 ) { + rsHiss + .gain( volume ) + .play( sound_flags::exclusive | sound_flags::looping ); } - if( rsHissU.AM != 0.0 ) // napelnianie PG - { - fNPress = ( 4.0f * fNPress + Min0R( mvOccupied->dpLocalValve, mvOccupied->dpMainValve ) ) / ( 4.0f + 1.0f ); - if( fNPress < 0.0f ) { - vol = -1.0 * rsHissU.AM * fNPress; - } - if( vol > 0.01 ) { - rsHissU.Play( vol, DSBPLAY_LOOPING, true, DynamicObject->GetPosition() ); - } - else { - rsHissU.Stop(); - } + else { + rsHiss.stop(); + } + // napelnianie PG + fNPress = ( 4.0f * fNPress + Min0R( mvOccupied->dpLocalValve, mvOccupied->dpMainValve ) ) / ( 4.0f + 1.0f ); + volume = ( + fNPress < 0.0f ? + -1.0 * rsHissU.m_amplitudefactor * fNPress : + 0.0 ); + if( volume > 0.01 ) { + rsHissU + .gain( volume ) + .play( sound_flags::exclusive | sound_flags::looping ); + } + else { + rsHissU.stop(); } } // koniec nie FV4a // Winger-160404 - syczenie pomocniczego (luzowanie) - /* if (rsSBHiss.AM!=0) - { - fSPPress=(mvOccupied->LocalBrakeRatio())-(mvOccupied->LocalBrakePos); - if (fSPPress>0) - { - vol=2*rsSBHiss.AM*fSPPress; - } - if (vol>0.1) - { - rsSBHiss.Play(vol,DSBPLAY_LOOPING,true,DynamicObject->GetPosition()); - } - else - { - rsSBHiss.Stop(); - } - } - */ -#endif + if( m_lastlocalbrakepressure != -1.f ) { + // calculate rate of pressure drop in local brake cylinder, once it's been initialized + auto const brakepressuredifference { m_lastlocalbrakepressure - mvOccupied->LocBrakePress }; + m_localbrakepressurechange = interpolate( m_localbrakepressurechange, 10 * ( brakepressuredifference / Deltatime ), 0.1f ); + } + m_lastlocalbrakepressure = mvOccupied->LocBrakePress; + if( ( m_localbrakepressurechange > 0.05f ) + && ( mvOccupied->LocBrakePress > mvOccupied->BrakePress - 0.05 ) ) { + rsSBHiss + .gain( clamp( 0.05 * m_localbrakepressurechange, 0.0, 1.5 ) ) + .play( sound_flags::exclusive | sound_flags::looping ); + } + else { + // don't stop the sound too abruptly + volume = std::max( 0.0, rsSBHiss.gain() - 0.1 * Deltatime ); + rsSBHiss.gain( volume ); + if( volume < 0.05 ) { + rsSBHiss.stop(); + } + } // ambient sound // since it's typically ticking of the clock we can center it on tachometer or on middle of compartment bounding area @@ -5400,6 +5408,10 @@ bool TTrain::LoadMMediaFile(std::string const &asFileName) // syk: rsHiss.deserialize( parser, sound_type::single, sound_parameters::amplitude ); rsHiss.owner( DynamicObject ); + if( true == rsSBHiss.empty() ) { + // fallback for vehicles without defined local brake hiss sound + rsSBHiss = rsHiss; + } } else if (token == "airsound2:") { diff --git a/Train.h b/Train.h index e60f3667..968917cd 100644 --- a/Train.h +++ b/Train.h @@ -410,6 +410,8 @@ public: // reszta może by?publiczna sound_source rsHissX { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE }; // fala sound_source rsHissT { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE }; // czasowy sound_source rsSBHiss { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE }; // local + float m_lastlocalbrakepressure { -1.f }; // helper, cached level of pressure in local brake cylinder + float m_localbrakepressurechange { 0.f }; // recent change of pressure in local brake cylinder sound_source rsFadeSound { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE }; sound_source dsbHasler { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE }; @@ -461,7 +463,7 @@ private: bool bHeat[8]; // grzanie // McZapkie: do syczenia float fPPress, fNPress; - float fSPPress, fSNPress; +// float fSPPress, fSNPress; int iSekunda; // Ra: sekunda aktualizacji pr?dko?ci int iRadioChannel; // numer aktualnego kana?u radiowego TPythonScreens pyScreens; diff --git a/audio.cpp b/audio.cpp index 3e0c8f70..e3b4f6e1 100644 --- a/audio.cpp +++ b/audio.cpp @@ -128,7 +128,18 @@ buffer_manager::create( std::string const &Filename ) { return emplace( filelookup ); } } - // if dynamic-specific lookup finds nothing, try the default sound folder + if( filename.find( '/' ) != std::string::npos ) { + // if the filename includes path, try to use it directly + lookup = find_buffer( filename ); + if( lookup != null_handle ) { + return lookup; + } + filelookup = find_file( filename ); + if( false == filelookup.empty() ) { + return emplace( filelookup ); + } + } + // if dynamic-specific and/or direct lookups find nothing, try the default sound folder lookup = find_buffer( szSoundPath + filename ); if( lookup != null_handle ) { return lookup; diff --git a/audiorenderer.cpp b/audiorenderer.cpp index 55b97197..5bb4985d 100644 --- a/audiorenderer.cpp +++ b/audiorenderer.cpp @@ -33,6 +33,12 @@ void openal_source::stop() { loop( false ); + // NOTE: workaround for potential edge cases where ::alSourceStop() doesn't set source which wasn't yet started to AL_STOPPED + int state; + ::alGetSourcei( id, AL_SOURCE_STATE, &state ); + if( state == AL_INITIAL ) { + play(); + } ::alSourceStop( id ); is_playing = false; } @@ -43,7 +49,6 @@ 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 ); // for multipart sounds trim away processed sources until only one remains, the last one may be set to looping by the controller ALuint bufferid; @@ -53,9 +58,11 @@ openal_source::update( double const Deltatime ) { buffers.erase( std::begin( buffers ) ); --buffer_index; } + int state; ::alGetSourcei( id, AL_SOURCE_STATE, &state ); is_playing = ( state == AL_PLAYING ); + // request instructions from the controller controller->update( *this ); } @@ -75,6 +82,7 @@ openal_source::sync_with( sound_properties const &State ) { if( glm::length2( sourceoffset ) > std::max( ( sound_range * sound_range ), ( EU07_SOUND_CUTOFFRANGE * EU07_SOUND_CUTOFFRANGE ) ) ) { // range cutoff check stop(); + is_synced = false; // flag sync failure for the controller return; } if( sound_range >= 0 ) { @@ -101,6 +109,7 @@ openal_source::sync_with( sound_properties const &State ) { ::alSourcef( id, AL_PITCH, properties.base_pitch * pitch_variation ); } + is_synced = true; } // sets max audible distance for sounds emitted by the source @@ -145,20 +154,18 @@ openal_source::loop( bool const State ) { // NOTE: doesn't release allocated implementation-side source void openal_source::clear() { - - controller = nullptr; // unqueue bound buffers: // ensure no buffer is in use... stop(); // ...prepare space for returned ids of unqueued buffers (not that we need that info)... std::vector bufferids; bufferids.resize( buffers.size() ); - // ...release the buffers and update source data to match + // ...release the buffers... ::alSourceUnqueueBuffers( id, bufferids.size(), bufferids.data() ); - buffers.clear(); - buffer_index = 0; - // reset properties - properties = sound_properties(); + // ...and reset reset the properties, except for the id of the allocated source + auto const sourceid { id }; + *this = openal_source(); + id = sourceid; } diff --git a/audiorenderer.h b/audiorenderer.h index 220be99f..79f7facb 100644 --- a/audiorenderer.h +++ b/audiorenderer.h @@ -36,9 +36,10 @@ struct openal_source { ALuint id { audio::null_resource }; // associated AL resource sound_source *controller { nullptr }; // source controller buffer_sequence buffers; // sequence of samples the source will emit - int buffer_index; // currently queued sample from the buffer sequence + int buffer_index { 0 }; // currently queued sample from the buffer sequence bool is_playing { false }; bool is_looping { false }; + bool is_synced { true }; // set to false only if a sync attempt fails sound_properties properties; // methods diff --git a/sound.cpp b/sound.cpp index e0cdff2d..69da3b1a 100644 --- a/sound.cpp +++ b/sound.cpp @@ -108,10 +108,10 @@ sound_source::play( int const Flags ) { // TODO: support for parameter-driven sound table if( m_soundbegin.buffer != null_handle ) { std::vector bufferlist { m_soundbegin.buffer, m_soundmain.buffer }; - audio::renderer.insert( this, std::begin( bufferlist ), std::end( bufferlist ) ); + insert( std::begin( bufferlist ), std::end( bufferlist ) ); } else { - audio::renderer.insert( this, m_soundmain.buffer ); + insert( m_soundmain.buffer ); } } else { @@ -119,7 +119,7 @@ sound_source::play( int const Flags ) { 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 ); + insert( m_soundmain.buffer ); } } } @@ -135,7 +135,7 @@ sound_source::stop() { 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 ); + insert( m_soundend.buffer ); } } @@ -154,10 +154,6 @@ sound_source::update( audio::openal_source &Source ) { } return; } - // 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 @@ -170,26 +166,41 @@ sound_source::update( audio::openal_source &Source ) { ++( m_soundmain.playing ); } } + + // check and update if needed current sound properties + update_location(); + update_placement_gain(); + Source.sync_with( m_properties ); + if( false == Source.is_synced ) { + // if the sync went wrong we let the renderer kill its part of the emitter, and update our playcounter(s) to match + update_counter( Source.buffers[ Source.buffer_index ], -1 ); + } + } else { // if the emitter isn't playing it's either done or wasn't yet started // we can determine this from number of processed buffers if( Source.buffer_index != Source.buffers.size() ) { auto const buffer { Source.buffers[ Source.buffer_index ] }; - 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 ); } - // all set, start playback - Source.play(); + Source.range( m_range ); + Source.pitch( m_pitchvariation ); + update_location(); + update_placement_gain(); + Source.sync_with( m_properties ); + if( true == Source.is_synced ) { + // all set, start playback + Source.play(); + } + else { + // if the initial sync went wrong we skip the activation so the renderer can clean the emitter on its end + update_counter( buffer, -1 ); + } } else { auto const buffer { Source.buffers[ Source.buffer_index - 1 ] }; @@ -339,4 +350,11 @@ sound_source::update_placement_gain() { return true; } +void +sound_source::insert( audio::buffer_handle Buffer ) { + + std::vector buffers { Buffer }; + return insert( std::begin( buffers ), std::end( buffers ) ); +} + //--------------------------------------------------------------------------- diff --git a/sound.h b/sound.h index 8a636b20..ee916c9a 100644 --- a/sound.h +++ b/sound.h @@ -15,7 +15,7 @@ http://mozilla.org/MPL/2.0/. float const EU07_SOUND_CABCONTROLSCUTOFFRANGE { 7.5f }; float const EU07_SOUND_BRAKINGCUTOFFRANGE { 100.f }; -float const EU07_SOUND_RUNNINGNOISECUTOFFRANGE { 100.f }; +float const EU07_SOUND_RUNNINGNOISECUTOFFRANGE { 200.f }; enum class sound_type { single, @@ -122,6 +122,15 @@ private: // potentially updates area-based gain factor of the source. returns: true if location has changed bool update_placement_gain(); + void + insert( audio::buffer_handle Buffer ); + template + void + insert( Iterator_ First, Iterator_ Last ) { + + audio::renderer.insert( this, First, Last ); + update_counter( *First, 1 ); + } // members TDynamicObject const * m_owner { nullptr }; // optional, the vehicle carrying this sound source