diff --git a/CMakeLists.txt b/CMakeLists.txt index 7ceff26f..cc488c59 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -457,6 +457,12 @@ endif () +# add ref/discord-rpc to the project in the same way other dependencies are added +add_subdirectory(ref/discord-rpc) +target_link_libraries(${PROJECT_NAME} discord-rpc) + + + find_package(OpenAL REQUIRED) if (TARGET OpenAL::OpenAL) target_link_libraries(${PROJECT_NAME} OpenAL::OpenAL) diff --git a/DynObj.cpp b/DynObj.cpp index 7176a231..3754c43e 100644 --- a/DynObj.cpp +++ b/DynObj.cpp @@ -770,7 +770,7 @@ void TDynamicObject::UpdateWiper(TAnim* pAnim) if (!pAnim || !pAnim->smElement) return; - int i = pAnim->iNumber; + int i = pAnim->iNumber; // odwaramy animacje dla parzystych indexow const double rotateAngle = (i + 1) % 2 == 0 ? -MoverParameters->WiperAngle : MoverParameters->WiperAngle; @@ -1319,7 +1319,7 @@ void TDynamicObject::ABuLittleUpdate(double ObjSqrDist) m_highbeam12.TurnxOnWithOnAsFallback(); else m_highbeam12.TurnOff(); - + // i to samo od dupy strony if (TestFlag(MoverParameters->iLights[end::rear], light::highbeamlight_left)) m_highbeam23.TurnxOnWithOnAsFallback(); @@ -2364,8 +2364,8 @@ TDynamicObject::Init(std::string Name, // nazwa pojazdu, np. "EU07-424" m_headlamp21.Init( "headlamp21", mdModel ); m_headlamp22.Init( "headlamp22", mdModel ); m_headlamp23.Init( "headlamp23", mdModel ); - m_highbeam22.Init("highbeam22", mdModel); - m_highbeam23.Init("highbeam23", mdModel); + m_highbeam22.Init("highbeam22", mdModel); + m_highbeam23.Init("highbeam23", mdModel); m_headsignal12.Init( "headsignal12", mdModel ); m_headsignal13.Init( "headsignal13", mdModel ); m_headsignal22.Init( "headsignal22", mdModel ); @@ -3677,8 +3677,8 @@ bool TDynamicObject::Update(double dt, double dt1) } case e_bridge: { volume *= 1.5; - break; - } + break; + } default: { break; } @@ -4974,8 +4974,8 @@ void TDynamicObject::RenderSounds() { } case e_bridge: { volume *= 1.5; - break; - } + break; + } default: { break; } @@ -6328,7 +6328,7 @@ void TDynamicObject::LoadMMediaFile( std::string const &TypeName, std::string co sConverter.deserialize( parser, sound_type::multipart, sound_parameters::range ); sConverter.owner( this ); } - + // Dzwiek wentylatora rezystora hamowania else if (token == "brakingresistorventilator:") { @@ -6726,12 +6726,12 @@ void TDynamicObject::LoadMMediaFile( std::string const &TypeName, std::string co else if (token == "wiperFromPark:") { sWiperFromPark.deserialize(parser, sound_type::single); - sWiperFromPark.owner(this); + sWiperFromPark.owner(this); } else if (token == "wiperToPark:") { sWiperToPark.deserialize(parser, sound_type::single); - sWiperToPark.owner(this); + sWiperToPark.owner(this); } else if (token == "retarder:") { diff --git a/Globals.cpp b/Globals.cpp index 1df21179..23b9e425 100644 --- a/Globals.cpp +++ b/Globals.cpp @@ -395,10 +395,7 @@ global_settings::ConfigParse(cParser &Parser) { // selected device for audio renderer Parser.getTokens(); Parser >> AirTemperature; - if (false == DebugModeFlag) - { - AirTemperature = clamp(AirTemperature, -15.f, 45.f); - } + AirTemperature = clamp(AirTemperature, -15.f, 45.f); } else if (token == "scalespeculars") { diff --git a/Globals.h b/Globals.h index 36275d67..f0eef20f 100644 --- a/Globals.h +++ b/Globals.h @@ -79,7 +79,7 @@ struct global_settings { int iConvertModels{ 0 }; // tworzenie plików binarnych int iConvertIndexRange{ 1000 }; // range of duplicate vertex scan bool file_binary_terrain{ true }; // enable binary terrain (de)serialization - bool file_binary_terrain_state{true}; + bool file_binary_terrain_state{true}; // logs int iWriteLogEnabled{ 3 }; // maska bitowa: 1-zapis do pliku, 2-okienko, 4-nazwy torów bool MultipleLogs{ false }; @@ -94,6 +94,7 @@ struct global_settings { float Overcast{ 0.1f }; // NOTE: all this weather stuff should be moved elsewhere glm::vec3 FogColor = { 0.6f, 0.7f, 0.8f }; float fFogEnd{ 7500 }; + float fTurbidity{ 128 }; std::string Season{}; // season of the year, based on simulation date std::string Weather{ "cloudy:" }; // current weather std::string Period{}; // time of the day, based on sun position diff --git a/McZapkie/MOVER.h b/McZapkie/MOVER.h index 59f61e46..f953c8ee 100644 --- a/McZapkie/MOVER.h +++ b/McZapkie/MOVER.h @@ -1377,7 +1377,7 @@ class TMoverParameters TDESchemeTable DElist; TWiperSchemeTable WiperList; int WiperListSize; - + double Vadd = 1.0; TMPTRelayTable MPTRelay; int RelayType = 0; @@ -1786,7 +1786,7 @@ class TMoverParameters double dimMultiplier{0.6f}; // mnoznik swiatel przyciemnionych double normMultiplier{1.0f}; // mnoznik swiatel zwyklych double highDimMultiplier{2.5f}; // mnoznik dlugich przyciemnionych - double highMultiplier{2.8f}; // mnoznik dlugich + double highMultiplier{2.8f}; // mnoznik dlugich plc::basic_controller m_plc; diff --git a/Model3d.cpp b/Model3d.cpp index faa1f691..5156e255 100644 --- a/Model3d.cpp +++ b/Model3d.cpp @@ -209,6 +209,21 @@ inline void readMatrix(cParser &parser, float4x4 &matrix) parser >> matrix(x)[y]; }; +template void UserdataParse(cParser &parser, gfx::vertex_userdata &vertex) +{ + parser.getTokens(4); + union + { + T InType; + float FloatType; + } buf{}; + for (int i = 0; i < 4; ++i) + { + parser >> buf.InType; + vertex.data[i] = buf.FloatType; + } +} + std::pair TSubModel::Load( cParser &parser, bool dynamic ) { // Ra: VBO tworzone na poziomie modelu, a nie submodeli auto token { parser.getToken() }; @@ -478,8 +493,15 @@ std::pair TSubModel::Load( cParser &parser, bool dynamic ) } if (eType < TP_ROTATOR) { // wczytywanie wierzchołków - token = parser.getToken(); - if( token == "numindices:" ) // optional block, potentially preceeding vertex list + token = parser.getToken(); + bool has_userdata = false; + if (token == "userdata:") + { + has_userdata = parser.getToken(); + + token = parser.getToken(); + } + if( token == "numindices:" ) // optional block, potentially preceeding vertex list { m_geometry.index_count = parser.getToken( false ); Indices.resize( m_geometry.index_count ); @@ -656,13 +678,22 @@ std::pair TSubModel::Load( cParser &parser, bool dynamic ) } } Vertices.resize( m_geometry.vertex_count ); // in case we had some degenerate triangles along the way - gfx::calculate_indices( Indices, Vertices, transformscalestack ); + gfx::calculate_indices( Indices, Vertices, Userdata, transformscalestack ); gfx::calculate_tangents( Vertices, Indices, GL_TRIANGLES ); // update values potentially changed by indexing m_geometry.index_count = Indices.size(); m_geometry.vertex_count = Vertices.size(); } - } + if (has_userdata) + { + Userdata.resize(m_geometry.vertex_count); + auto userdata { std::begin( Userdata ) }; + for( auto idx = 0; idx < m_geometry.vertex_count; ++idx ) { + auto vertex { userdata + idx }; + UserdataParse(parser, *vertex); + } + } + } else // gdy brak wierzchołków { eType = TP_ROTATOR; // submodel pomocniczy, ma tylko macierz przekształcenia @@ -1160,25 +1191,45 @@ void TSubModel::RaAnimation(glm::mat4 &m, TAnimType a) //--------------------------------------------------------------------------- -void TSubModel::serialize_geometry( std::ostream &Output, bool const Packed, bool const Indexed ) const { +void TSubModel::serialize_geometry( std::ostream &Output, bool const Packed, bool const Indexed, bool const UserData ) const { if( Child ) { - Child->serialize_geometry( Output, Packed, Indexed ); + Child->serialize_geometry( Output, Packed, Indexed, UserData ); } if( m_geometry.handle != null_handle ) { if( Packed ) { - for( auto const &vertex : GfxRenderer->Vertices( m_geometry.handle ) ) { - vertex.serialize_packed( Output, Indexed ); - } + auto vertices = GfxRenderer->Vertices( m_geometry.handle ); + auto userdatas = GfxRenderer->UserData( m_geometry.handle ); + bool has_userdata = !userdatas.empty(); + for( int i = 0; i < vertices.size(); ++i ) { + vertices[i].serialize_packed( Output, Indexed ); + if (UserData) + { + if (has_userdata) + userdatas[i].serialize_packed(Output); + else + gfx::vertex_userdata{}.serialize_packed( Output ); + } + } } else { - for( auto const &vertex : GfxRenderer->Vertices( m_geometry.handle ) ) { - vertex.serialize( Output, Indexed ); + auto vertices = GfxRenderer->Vertices( m_geometry.handle ); + auto userdatas = GfxRenderer->UserData( m_geometry.handle ); + bool has_userdata = !userdatas.empty(); + for( int i = 0; i < vertices.size(); ++i ) { + vertices[i].serialize( Output, Indexed ); + if (UserData) + { + if (has_userdata) + userdatas[i].serialize(Output); + else + gfx::vertex_userdata{}.serialize( Output ); + } } } } if( Next ) { - Next->serialize_geometry( Output, Packed, Indexed ); + Next->serialize_geometry( Output, Packed, Indexed, UserData ); } }; @@ -1254,7 +1305,7 @@ TSubModel::create_geometry( std::size_t &Indexoffset, std::size_t &Vertexoffset, eType < TP_ROTATOR ? eType : GL_POINTS ); - m_geometry.handle = GfxRenderer->Insert( Indices, Vertices, Bank, type ); + m_geometry.handle = GfxRenderer->Insert( Indices, Vertices, Userdata, Bank, type ); } if( m_geometry.handle != 0 ) { @@ -1653,6 +1704,7 @@ void TModel3d::SaveToBinFile(std::string const &FileName) sn_utils::ls_uint32(s, MAKE_ID4('E', '3', 'D', '0')); auto const e3d_spos = s.tellp(); sn_utils::ls_uint32(s, 0); + bool has_any_userdata = Root->HasAnyVertexUserData(); { sn_utils::ls_uint32(s, MAKE_ID4('S', 'U', 'B', '0')); @@ -1679,20 +1731,41 @@ void TModel3d::SaveToBinFile(std::string const &FileName) Root->serialize_indices( s, indexsize ); if (!(Global.iConvertModels & 8)) { - sn_utils::ls_uint32( s, MAKE_ID4( 'V', 'N', 'T', '1' ) ); - sn_utils::ls_uint32( s, 8 + m_vertexcount * 20 ); - Root->serialize_geometry( s, true, true ); + int modeltype = 1; + int vertexsize = 20; + if(has_any_userdata) + { + modeltype |= 4; + vertexsize += 8; + } + sn_utils::ls_uint32( s, MAKE_ID4( 'V', 'N', 'T', '0' + modeltype ) ); + sn_utils::ls_uint32( s, 8 + m_vertexcount * vertexsize ); + Root->serialize_geometry( s, true, true, has_any_userdata ); } else { - sn_utils::ls_uint32( s, MAKE_ID4( 'V', 'N', 'T', '2' ) ); - sn_utils::ls_uint32( s, 8 + m_vertexcount * 48 ); - Root->serialize_geometry( s, false, true ); + int modeltype = 2; + int vertexsize = 48; + if(has_any_userdata) + { + modeltype |= 4; + vertexsize += 16; + } + sn_utils::ls_uint32( s, MAKE_ID4( 'V', 'N', 'T', '0' + modeltype ) ); + sn_utils::ls_uint32( s, 8 + m_vertexcount * vertexsize ); + Root->serialize_geometry( s, false, true, has_any_userdata ); } } else { - sn_utils::ls_uint32( s, MAKE_ID4( 'V', 'N', 'T', '0' ) ); - sn_utils::ls_uint32( s, 8 + m_vertexcount * 32 ); - Root->serialize_geometry( s, false, false ); + int modeltype = 0; + int vertexsize = 32; + if(has_any_userdata) + { + modeltype |= 4; + vertexsize += 16; + } + sn_utils::ls_uint32( s, MAKE_ID4( 'V', 'N', 'T', '0' + modeltype ) ); + sn_utils::ls_uint32( s, 8 + m_vertexcount * vertexsize ); + Root->serialize_geometry( s, false, false, has_any_userdata ); } if (textures.size()) @@ -1782,6 +1855,7 @@ void TModel3d::deserialize(std::istream &s, size_t size, bool dynamic) std::streampos end = s.tellg() + (std::streampos)size; bool hastangents { false }; + bool hasuserdata {false}; while (s.tellg() < end) { @@ -1825,21 +1899,26 @@ void TModel3d::deserialize(std::istream &s, size_t size, bool dynamic) return (Left.first) < (Right.first); } ); // once sorted we can grab geometry as it comes, and assign it to the chunks it belongs to size_t const vertextype { ( ( ( type & 0xFF000000 ) >> 24 ) - '0' ) }; - hastangents = ( vertextype > 0 ); + hastangents = ( (vertextype & 3) > 0 ); + hasuserdata = (vertextype & 4); for( auto const &submodeloffset : submodeloffsets ) { auto &submodel { Root[ submodeloffset.second ] }; auto const &submodelgeometry { submodel.m_geometry }; submodel.Vertices.resize( submodelgeometry.vertex_count ); + if(hasuserdata) + submodel.Userdata.resize( submodelgeometry.vertex_count ); m_vertexcount += submodelgeometry.vertex_count; - switch( vertextype ) { + switch( vertextype & 3 ) { case 0: { // legacy vnt0 format - for( auto &vertex : submodel.Vertices ) { - vertex.deserialize( s, hastangents ); + for( int i = 0; i < submodel.Vertices.size(); ++i ) { + submodel.Vertices[i].deserialize( s, hastangents ); + if(hasuserdata) + submodel.Userdata[i].deserialize( s ); if( submodel.eType < TP_ROTATOR ) { // normal vectors debug routine if( ( false == submodel.m_normalizenormals ) - && ( std::abs( glm::length2( vertex.normal ) - 1.0f ) > 0.01f ) ) { + && ( std::abs( glm::length2( submodel.Vertices[i].normal ) - 1.0f ) > 0.01f ) ) { submodel.m_normalizenormals = TSubModel::normalize; // we don't know if uniform scaling would suffice WriteLog( "Bad model: non-unit normal vector(s) encountered during sub-model geometry deserialization", logtype::model ); } @@ -1849,15 +1928,19 @@ void TModel3d::deserialize(std::istream &s, size_t size, bool dynamic) } case 1: { // expanded chunk formats - for( auto &vertex : submodel.Vertices ) { - vertex.deserialize_packed( s, hastangents ); + for( int i = 0; i < submodel.Vertices.size(); ++i ) { + submodel.Vertices[i].deserialize_packed( s, hastangents ); + if(hasuserdata) + submodel.Userdata[i].deserialize_packed( s ); } break; } case 2: { // expanded chunk formats - for( auto &vertex : submodel.Vertices ) { - vertex.deserialize( s, hastangents ); + for( int i = 0; i < submodel.Vertices.size(); ++i ) { + submodel.Vertices[i].deserialize( s, hastangents ); + if(hasuserdata) + submodel.Userdata[i].deserialize( s ); } break; } @@ -1988,7 +2071,7 @@ void TModel3d::deserialize(std::istream &s, size_t size, bool dynamic) if( false == hastangents ) { gfx::calculate_tangents( Root[i].Vertices, Root[i].Indices, type ); } - Root[i].m_geometry.handle = GfxRenderer->Insert( Root[i].Indices, Root[i].Vertices, m_geometrybank, type ); + Root[i].m_geometry.handle = GfxRenderer->Insert( Root[i].Indices, Root[i].Vertices, Root[i].Userdata, m_geometrybank, type ); } } @@ -2127,6 +2210,26 @@ void TSubModel::BinInit(TSubModel *s, float4x4 *m, std::vector *t, normalize ); } } +} + +bool TSubModel::HasAnyVertexUserData() const +{ + for (const TSubModel *sm = this; sm; sm = sm->Next) + { + if (m_geometry.handle) + { + if (!GfxRenderer->UserData(m_geometry.handle).empty()) + return true; + } + else + { + if (!sm->Userdata.empty()) + return true; + } + if (sm->Child && sm->Child->HasAnyVertexUserData()) + return true; + } + return false; }; void TModel3d::LoadFromBinFile(std::string const &FileName, bool dynamic) diff --git a/Model3d.h b/Model3d.h index d6455ca7..2c019434 100644 --- a/Model3d.h +++ b/Model3d.h @@ -85,6 +85,8 @@ public: public: // chwilowo TAnimType b_Anim{ TAnimType::at_None }; + bool HasAnyVertexUserData() const; + public: uint32_t iFlags{ 0x0200 }; // bit 9=1: submodel został utworzony a nie ustawiony na wczytany plik // flagi informacyjne: @@ -145,6 +147,7 @@ public: // chwilowo float3 v_TransVector { 0.0f, 0.0f, 0.0f }; geometry_data m_geometry { /*this,*/ { 0, 0 }, 0, 0, 0, 0 }; gfx::vertex_array Vertices; + gfx::userdata_array Userdata; gfx::index_array Indices; float m_boundingradius { 0 }; std::uintptr_t iAnimOwner{ 0 }; // roboczy numer egzemplarza, który ustawił animację @@ -244,7 +247,7 @@ public: std::vector&, std::vector&, std::vector&); - void serialize_geometry( std::ostream &Output, bool const Packed, bool const Indexed ) const; + void serialize_geometry( std::ostream &Output, bool const Packed, bool const Indexed, bool const UserData ) const; int index_size() const; void serialize_indices( std::ostream &Output, int const Size ) const; // places contained geometry in provided ground node diff --git a/README.md b/README.md index a58849ce..bab04fe7 100644 --- a/README.md +++ b/README.md @@ -25,14 +25,15 @@ List of requirements for compiling executable. For usage/runtime requirements [s **Note:** There's some issue in our build system. If link error occurs, use `-DGLFW3_LIBRARIES=''` in CMake. - [GLM](https://glm.g-truc.net/) (0.9.9.0) -- serialport (0.1.1) +- [serialport](https://sigrok.org/wiki/Libserialport) (0.1.1) - [sndfile](https://github.com/erikd/libsndfile) (1.0.28) -- [LuajIT](http://luajit.org/) (2.0.5) -- [GLEW](http://glew.sourceforge.net/) (2.1.0) +- [LuajIT](http://luajit.org) (2.0.5) +- [GLEW](http://glew.sourceforge.net) (2.1.0) - [PNG](http://www.libpng.org/pub/png/libpng.html) (1.6.34) -- [OpenAL](https://www.openal.org/) (1.18.2) +- [OpenAL](https://www.openal.org) (1.18.2) - pthread - [Python 2.7](https://www.python.org) +- [asio](https://think-async.com/Asio) (1.12) ### **3. OpenGL 3.0.** diff --git a/Track.cpp b/Track.cpp index 48a1a35c..e37d0026 100644 --- a/Track.cpp +++ b/Track.cpp @@ -1146,6 +1146,7 @@ void TTrack::create_map_geometry(std::vector &Bank, const gfx { if (iCategoryFlag != 1) return; // only tracks for now + gfx::userdata_array empty_userdata{}; switch (eType) { @@ -1154,7 +1155,7 @@ void TTrack::create_map_geometry(std::vector &Bank, const gfx Segment->render_lines(vertices, 0.5f); std::copy(vertices.begin(), vertices.end(), std::back_inserter(Bank)); - extra_map_geometry = GfxRenderer->Insert(vertices, Extra, GL_LINES); + extra_map_geometry = GfxRenderer->Insert(vertices, empty_userdata, Extra, GL_LINES); break; } @@ -1163,12 +1164,12 @@ void TTrack::create_map_geometry(std::vector &Bank, const gfx SwitchExtension->Segments[0]->render_lines(vertices, 0.5f); std::copy(vertices.begin(), vertices.end(), std::back_inserter(Bank)); - SwitchExtension->map_geometry[0] = GfxRenderer->Insert(vertices, Extra, GL_LINES); + SwitchExtension->map_geometry[0] = GfxRenderer->Insert(vertices, empty_userdata, Extra, GL_LINES); vertices.clear(); SwitchExtension->Segments[1]->render_lines(vertices, 0.5f); std::copy(vertices.begin(), vertices.end(), std::back_inserter(Bank)); - SwitchExtension->map_geometry[1] = GfxRenderer->Insert(vertices, Extra, GL_LINES); + SwitchExtension->map_geometry[1] = GfxRenderer->Insert(vertices, empty_userdata, Extra, GL_LINES); break; } default: @@ -1309,7 +1310,7 @@ glm::vec3 TTrack::get_nearest_point(const glm::dvec3 &point) const // wypełnianie tablic VBO void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) { - + gfx::userdata_array empty_userdata; switch (iCategoryFlag & 15) { case 1: // tor @@ -1329,11 +1330,11 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) { gfx::vertex_array vertices; Segment->RenderLoft(vertices, m_origin, bpts1, iTrapezoid > 0, texturelength); if( ( Bank != 0 ) && ( true == Geometry2.empty() ) ) { - Geometry2.emplace_back( GfxRenderer->Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); + Geometry2.emplace_back(GfxRenderer->Insert(vertices, empty_userdata, Bank, GL_TRIANGLE_STRIP)); } if( ( Bank == 0 ) && ( false == Geometry2.empty() ) ) { // special variant, replace existing data for a turntable track - GfxRenderer->Replace( vertices, Geometry2[ 0 ], GL_TRIANGLE_STRIP ); + GfxRenderer->Replace(vertices, empty_userdata, Geometry2[0], GL_TRIANGLE_STRIP); } } if (m_material1) @@ -1343,18 +1344,18 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) { gfx::vertex_array vertices; if( ( Bank != 0 ) && ( true == Geometry1.empty() ) ) { Segment->RenderLoft( vertices, m_origin, rpts1, iTrapezoid > 0, texturelength ); - Geometry1.emplace_back( GfxRenderer->Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); + Geometry1.emplace_back(GfxRenderer->Insert(vertices, empty_userdata, Bank, GL_TRIANGLE_STRIP)); vertices.clear(); // reuse the scratchpad Segment->RenderLoft( vertices, m_origin, rpts2, iTrapezoid > 0, texturelength ); - Geometry1.emplace_back( GfxRenderer->Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); + Geometry1.emplace_back(GfxRenderer->Insert(vertices, empty_userdata, Bank, GL_TRIANGLE_STRIP)); } if( ( Bank == 0 ) && ( false == Geometry1.empty() ) ) { // special variant, replace existing data for a turntable track Segment->RenderLoft( vertices, m_origin, rpts1, iTrapezoid > 0, texturelength ); - GfxRenderer->Replace( vertices, Geometry1[ 0 ], GL_TRIANGLE_STRIP ); + GfxRenderer->Replace(vertices, empty_userdata, Geometry1[0], GL_TRIANGLE_STRIP); vertices.clear(); // reuse the scratchpad Segment->RenderLoft( vertices, m_origin, rpts2, iTrapezoid > 0, texturelength ); - GfxRenderer->Replace( vertices, Geometry1[ 1 ], GL_TRIANGLE_STRIP ); + GfxRenderer->Replace(vertices, empty_userdata, Geometry1[1], GL_TRIANGLE_STRIP); } } break; @@ -1379,21 +1380,21 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) { // composed from two parts: transition from blade to regular rail, and regular rail SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts3, true, texturelength, 1.0, 0, bladelength / 2, { SwitchExtension->fOffset2, SwitchExtension->fOffset2 / 2 } ); SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts1, false, texturelength, 1.0, bladelength / 2, bladelength, { SwitchExtension->fOffset2 / 2, 0.f } ); - Geometry1.emplace_back( GfxRenderer->Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); + Geometry1.emplace_back(GfxRenderer->Insert(vertices, empty_userdata, Bank, GL_TRIANGLE_STRIP)); vertices.clear(); // fixed parts SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts1, false, texturelength, 1.0, bladelength ); - Geometry1.emplace_back( GfxRenderer->Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); + Geometry1.emplace_back(GfxRenderer->Insert(vertices, empty_userdata, Bank, GL_TRIANGLE_STRIP)); vertices.clear(); if( jointlength > 0 ) { // part of the diverging rail touched by wheels of vehicle going straight SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts1, false, texturelength, 1.0, 0, jointlength ); - Geometry1.emplace_back( GfxRenderer->Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); + Geometry1.emplace_back(GfxRenderer->Insert(vertices, empty_userdata, Bank, GL_TRIANGLE_STRIP)); vertices.clear(); } // other rail, full length SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts2, false, texturelength ); - Geometry1.emplace_back( GfxRenderer->Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); + Geometry1.emplace_back(GfxRenderer->Insert(vertices, empty_userdata, Bank, GL_TRIANGLE_STRIP)); vertices.clear(); } if( m_material2 ) { @@ -1402,15 +1403,15 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) { // composed from two parts: transition from blade to regular rail, and regular rail SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts4, true, texturelength, 1.0, 0, bladelength / 2, { -fMaxOffset + SwitchExtension->fOffset1, ( -fMaxOffset + SwitchExtension->fOffset1 ) / 2 } ); SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts2, false, texturelength, 1.0, bladelength / 2, bladelength, { ( -fMaxOffset + SwitchExtension->fOffset1 ) / 2, 0.f } ); - Geometry2.emplace_back( GfxRenderer->Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); + Geometry2.emplace_back(GfxRenderer->Insert(vertices, empty_userdata, Bank, GL_TRIANGLE_STRIP)); vertices.clear(); // fixed parts SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts2, false, texturelength, 1.0, bladelength ); - Geometry2.emplace_back( GfxRenderer->Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); + Geometry2.emplace_back(GfxRenderer->Insert(vertices, empty_userdata, Bank, GL_TRIANGLE_STRIP)); vertices.clear(); // diverging rail, potentially minus part touched by wheels of vehicle going straight SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts1, false, texturelength, 1.0, jointlength ); - Geometry2.emplace_back( GfxRenderer->Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); + Geometry2.emplace_back(GfxRenderer->Insert(vertices, empty_userdata, Bank, GL_TRIANGLE_STRIP)); vertices.clear(); } } @@ -1423,22 +1424,22 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) { // composed from two parts: transition from blade to regular rail, and regular rail SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts4, true, texturelength, 1.0, 0, bladelength / 2, { -SwitchExtension->fOffset2, -SwitchExtension->fOffset2 / 2 } ); SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts2, false, texturelength, 1.0, bladelength / 2, bladelength, { -SwitchExtension->fOffset2 / 2, 0.f } ); - Geometry1.emplace_back( GfxRenderer->Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); + Geometry1.emplace_back(GfxRenderer->Insert(vertices, empty_userdata, Bank, GL_TRIANGLE_STRIP)); vertices.clear(); // fixed parts // prawa szyna za iglicą SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts2, false, texturelength, 1.0, bladelength ); - Geometry1.emplace_back( GfxRenderer->Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); + Geometry1.emplace_back(GfxRenderer->Insert(vertices, empty_userdata, Bank, GL_TRIANGLE_STRIP)); vertices.clear(); if( jointlength > 0 ) { // part of the diverging rail touched by wheels of vehicle going straight SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts2, false, texturelength, 1.0, 0, jointlength ); - Geometry1.emplace_back( GfxRenderer->Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); + Geometry1.emplace_back(GfxRenderer->Insert(vertices, empty_userdata, Bank, GL_TRIANGLE_STRIP)); vertices.clear(); } // other rail, full length SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts1, false, texturelength ); - Geometry1.emplace_back( GfxRenderer->Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); + Geometry1.emplace_back(GfxRenderer->Insert(vertices, empty_userdata, Bank, GL_TRIANGLE_STRIP)); vertices.clear(); } if( m_material2 ) { @@ -1447,16 +1448,16 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) { // composed from two parts: transition from blade to regular rail, and regular rail SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts3, true, texturelength, 1.0, 0, bladelength / 2, { fMaxOffset - SwitchExtension->fOffset1, ( fMaxOffset - SwitchExtension->fOffset1 ) / 2 } ); SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts1, false, texturelength, 1.0, bladelength / 2, bladelength, { ( fMaxOffset - SwitchExtension->fOffset1 ) / 2, 0.f } ); - Geometry2.emplace_back( GfxRenderer->Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); + Geometry2.emplace_back(GfxRenderer->Insert(vertices, empty_userdata, Bank, GL_TRIANGLE_STRIP)); vertices.clear(); // fixed parts // lewa szyna za iglicą SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts1, false, texturelength, 1.0, bladelength ); - Geometry2.emplace_back( GfxRenderer->Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); + Geometry2.emplace_back(GfxRenderer->Insert(vertices, empty_userdata, Bank, GL_TRIANGLE_STRIP)); vertices.clear(); // diverging rail, potentially minus part touched by wheels of vehicle going straight SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts2, false, texturelength, 1.0, jointlength ); - Geometry2.emplace_back( GfxRenderer->Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); + Geometry2.emplace_back(GfxRenderer->Insert(vertices, empty_userdata, Bank, GL_TRIANGLE_STRIP)); vertices.clear(); } } @@ -1465,7 +1466,7 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) { if( true == Global.CreateSwitchTrackbeds ) { gfx::vertex_array vertices; create_switch_trackbed( vertices ); - SwitchExtension->Geometry3 = GfxRenderer->Insert( vertices, Bank, GL_TRIANGLE_STRIP ); + SwitchExtension->Geometry3 = GfxRenderer->Insert(vertices, empty_userdata, Bank, GL_TRIANGLE_STRIP); vertices.clear(); } @@ -1488,7 +1489,7 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) { auto const texturelength { texture_length( m_material1 ) }; gfx::vertex_array vertices; Segment->RenderLoft(vertices, m_origin, bpts1, iTrapezoid > 0, texturelength); - Geometry1.emplace_back( GfxRenderer->Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); + Geometry1.emplace_back(GfxRenderer->Insert(vertices, empty_userdata, 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?) @@ -1501,13 +1502,13 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) { if( ( fTexHeight1 >= 0.0 ) || ( slop != 0.0 ) ) { // tylko jeśli jest z prawej Segment->RenderLoft( vertices, m_origin, rpts1, iTrapezoid > 0, texturelength ); - Geometry2.emplace_back( GfxRenderer->Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); + Geometry2.emplace_back(GfxRenderer->Insert(vertices, empty_userdata, Bank, GL_TRIANGLE_STRIP)); vertices.clear(); } if( ( fTexHeight1 >= 0.0 ) || ( side != 0.0 ) ) { // tylko jeśli jest z lewej Segment->RenderLoft( vertices, m_origin, rpts2, iTrapezoid > 0, texturelength ); - Geometry2.emplace_back( GfxRenderer->Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); + Geometry2.emplace_back(GfxRenderer->Insert(vertices, empty_userdata, Bank, GL_TRIANGLE_STRIP)); vertices.clear(); } } @@ -1584,22 +1585,22 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) { if( ( fTexHeight1 >= 0.0 ) || ( side != 0.0 ) ) { SwitchExtension->Segments[ 2 ]->RenderLoft( vertices, m_origin, rpts2, true, texturelength, 1.0, 0, 0, {}, &b, render ); if( true == render ) { - Geometry2.emplace_back( GfxRenderer->Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); + Geometry2.emplace_back(GfxRenderer->Insert(vertices, empty_userdata, Bank, GL_TRIANGLE_STRIP)); vertices.clear(); } SwitchExtension->Segments[ 3 ]->RenderLoft( vertices, m_origin, rpts2, true, texturelength, 1.0, 0, 0, {}, &b, render ); if( true == render ) { - Geometry2.emplace_back( GfxRenderer->Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); + Geometry2.emplace_back(GfxRenderer->Insert(vertices, empty_userdata, Bank, GL_TRIANGLE_STRIP)); vertices.clear(); } SwitchExtension->Segments[ 4 ]->RenderLoft( vertices, m_origin, rpts2, true, texturelength, 1.0, 0, 0, {}, &b, render ); if( true == render ) { - Geometry2.emplace_back( GfxRenderer->Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); + Geometry2.emplace_back(GfxRenderer->Insert(vertices, empty_userdata, Bank, GL_TRIANGLE_STRIP)); vertices.clear(); } SwitchExtension->Segments[ 5 ]->RenderLoft( vertices, m_origin, rpts2, true, texturelength, 1.0, 0, 0, {}, &b, render ); if( true == render ) { - Geometry2.emplace_back( GfxRenderer->Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); + Geometry2.emplace_back(GfxRenderer->Insert(vertices, empty_userdata, Bank, GL_TRIANGLE_STRIP)); vertices.clear(); } } @@ -1609,17 +1610,17 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) { if( ( fTexHeight1 >= 0.0 ) || ( side != 0.0 ) ) { SwitchExtension->Segments[ 2 ]->RenderLoft( vertices, m_origin, rpts2, true, texturelength, 1.0, 0, 0, {}, &b, render ); // z P2 do P4 if( true == render ) { - Geometry2.emplace_back( GfxRenderer->Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); + Geometry2.emplace_back(GfxRenderer->Insert(vertices, empty_userdata, Bank, GL_TRIANGLE_STRIP)); vertices.clear(); } SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts2, true, texturelength, 1.0, 0, 0, {}, &b, render ); // z P4 do P3=P1 (odwrócony) if( true == render ) { - Geometry2.emplace_back( GfxRenderer->Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); + Geometry2.emplace_back(GfxRenderer->Insert(vertices, empty_userdata, Bank, GL_TRIANGLE_STRIP)); vertices.clear(); } SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts2, true, texturelength, 1.0, 0, 0, {}, &b, render ); // z P1 do P2 if( true == render ) { - Geometry2.emplace_back( GfxRenderer->Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); + Geometry2.emplace_back(GfxRenderer->Insert(vertices, empty_userdata, Bank, GL_TRIANGLE_STRIP)); vertices.clear(); } } @@ -1674,7 +1675,7 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) { cosa0 * u + sina0 * v + 0.5, -sina0 * u + cosa0 * v + 0.5 } ); } - Geometry1.emplace_back( GfxRenderer->Insert( vertices, Bank, GL_TRIANGLE_FAN ) ); + Geometry1.emplace_back(GfxRenderer->Insert(vertices, empty_userdata, Bank, GL_TRIANGLE_FAN)); } break; } // tt_cross @@ -1693,7 +1694,7 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) { { // tworzenie trójkątów nawierzchni szosy gfx::vertex_array vertices; Segment->RenderLoft(vertices, m_origin, bpts1, iTrapezoid > 0, fTexLength); - Geometry1.emplace_back( GfxRenderer->Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); + Geometry1.emplace_back(GfxRenderer->Insert(vertices, empty_userdata, 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?) @@ -1701,10 +1702,10 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) { create_road_side_profile( rpts1, rpts2, bpts1 ); gfx::vertex_array vertices; Segment->RenderLoft( vertices, m_origin, rpts1, iTrapezoid > 0, fTexLength ); - Geometry2.emplace_back( GfxRenderer->Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); + Geometry2.emplace_back(GfxRenderer->Insert(vertices, empty_userdata, Bank, GL_TRIANGLE_STRIP)); vertices.clear(); Segment->RenderLoft( vertices, m_origin, rpts2, iTrapezoid > 0, fTexLength ); - Geometry2.emplace_back( GfxRenderer->Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); + Geometry2.emplace_back(GfxRenderer->Insert(vertices, empty_userdata, Bank, GL_TRIANGLE_STRIP)); vertices.clear(); } } @@ -1931,6 +1932,7 @@ void TTrack::RaAnimListAdd(TTrack *t) TTrack * TTrack::RaAnimate() { // wykonanie rekurencyjne animacji, wywoływane przed wyświetleniem sektora // zwraca wskaźnik toru wymagającego dalszej animacji + gfx::userdata_array empty_userdata; if( SwitchExtension->pNextAnim ) SwitchExtension->pNextAnim = SwitchExtension->pNextAnim->RaAnimate(); bool m = true; // animacja trwa @@ -1982,7 +1984,7 @@ TTrack * TTrack::RaAnimate() // composed from two parts: transition from blade to regular rail, and regular rail SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts3, true, texturelength, 1.0, 0, bladelength / 2, { SwitchExtension->fOffset2, SwitchExtension->fOffset2 / 2 } ); SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts1, false, texturelength, 1.0, bladelength / 2, bladelength, { SwitchExtension->fOffset2 / 2, 0.f } ); - GfxRenderer->Replace( vertices, Geometry1[ 0 ], GL_TRIANGLE_STRIP ); + GfxRenderer->Replace(vertices, empty_userdata, Geometry1[0], GL_TRIANGLE_STRIP); vertices.clear(); } if( m_material2 ) { @@ -1991,7 +1993,7 @@ TTrack * TTrack::RaAnimate() // composed from two parts: transition from blade to regular rail, and regular rail SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts4, true, texturelength, 1.0, 0, bladelength / 2, { -fMaxOffset + SwitchExtension->fOffset1, ( -fMaxOffset + SwitchExtension->fOffset1 ) / 2 } ); SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts2, false, texturelength, 1.0, bladelength / 2, bladelength, { ( -fMaxOffset + SwitchExtension->fOffset1 ) / 2, 0.f } ); - GfxRenderer->Replace( vertices, Geometry2[ 0 ], GL_TRIANGLE_STRIP ); + GfxRenderer->Replace(vertices, empty_userdata, Geometry2[0], GL_TRIANGLE_STRIP); vertices.clear(); } } @@ -2002,7 +2004,7 @@ TTrack * TTrack::RaAnimate() // composed from two parts: transition from blade to regular rail, and regular rail SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts4, true, texturelength, 1.0, 0, bladelength / 2, { -SwitchExtension->fOffset2, -SwitchExtension->fOffset2 / 2 } ); SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts2, false, texturelength, 1.0, bladelength / 2, bladelength, { -SwitchExtension->fOffset2 / 2, 0.f } ); - GfxRenderer->Replace( vertices, Geometry1[ 0 ], GL_TRIANGLE_STRIP ); + GfxRenderer->Replace(vertices, empty_userdata, Geometry1[0], GL_TRIANGLE_STRIP); vertices.clear(); } if( m_material2 ) { @@ -2011,7 +2013,7 @@ TTrack * TTrack::RaAnimate() // composed from two parts: transition from blade to regular rail, and regular rail SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts3, true, texturelength, 1.0, 0, bladelength / 2, { fMaxOffset - SwitchExtension->fOffset1, ( fMaxOffset - SwitchExtension->fOffset1 ) / 2 } ); SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts1, false, texturelength, 1.0, bladelength / 2, bladelength, { ( fMaxOffset - SwitchExtension->fOffset1 ) / 2, 0.f } ); - GfxRenderer->Replace( vertices, Geometry2[ 0 ], GL_TRIANGLE_STRIP ); + GfxRenderer->Replace(vertices, empty_userdata, Geometry2[0], GL_TRIANGLE_STRIP); vertices.clear(); } } diff --git a/Traction.cpp b/Traction.cpp index 89f7580b..1a2811c9 100644 --- a/Traction.cpp +++ b/Traction.cpp @@ -342,7 +342,9 @@ TTraction::create_geometry( gfx::geometrybank_handle const &Bank ) { } auto const elementcount = vertices.size() / 2; - m_geometry = GfxRenderer->Insert( vertices, Bank, GL_LINES ); + + gfx::userdata_array empty_userdata{}; + m_geometry = GfxRenderer->Insert( vertices, empty_userdata, Bank, GL_LINES ); return elementcount; } diff --git a/Train.cpp b/Train.cpp index 31f12513..5fa32bf6 100644 --- a/Train.cpp +++ b/Train.cpp @@ -254,6 +254,8 @@ TTrain::commandhandler_map const TTrain::m_commandhandlers = { { user_command::autosandboxactivate, &TTrain::OnCommand_autosandboxactivate }, { user_command::autosandboxdeactivate, &TTrain::OnCommand_autosandboxdeactivate }, { user_command::epbrakecontroltoggle, &TTrain::OnCommand_epbrakecontroltoggle }, + { user_command::epbrakecontrolenable, &TTrain::OnCommand_epbrakecontrolenable }, + { user_command::epbrakecontroldisable, &TTrain::OnCommand_epbrakecontroldisable }, { user_command::trainbrakeoperationmodeincrease, &TTrain::OnCommand_trainbrakeoperationmodeincrease }, { user_command::trainbrakeoperationmodedecrease, &TTrain::OnCommand_trainbrakeoperationmodedecrease }, { user_command::brakeactingspeedincrease, &TTrain::OnCommand_brakeactingspeedincrease }, @@ -1983,6 +1985,34 @@ void TTrain::OnCommand_autosandboxdeactivate(TTrain *Train, command_data const & } }; +void TTrain::OnCommand_epbrakecontrolenable( TTrain *Train, command_data const &Command ) { + auto const istoggle{ ( static_cast( Train->ggEPFuseButton.type() ) & static_cast( TGaugeType::toggle ) ) != 0 }; + if( Command.action == GLFW_PRESS ) { + // command only works for bistable switch + if(istoggle) { + if( Train->mvOccupied->EpFuseSwitch( true ) ) { + // audio feedback + if( Train->dsbPneumaticSwitch ) { + Train->dsbPneumaticSwitch->play(); + } + Train->ggEPFuseButton.UpdateValue(1.0f, Train->dsbSwitch); + }; + } + } +} + +void TTrain::OnCommand_epbrakecontroldisable( TTrain *Train, command_data const &Command ) { + auto const istoggle{ ( static_cast( Train->ggEPFuseButton.type() ) & static_cast( TGaugeType::toggle ) ) != 0 }; + if( Command.action == GLFW_PRESS ) { + // command only works for bistable switch + if(istoggle) { + if( Train->mvOccupied->EpFuseSwitch( false ) ) { + Train->ggEPFuseButton.UpdateValue(0.0f, Train->dsbSwitch); + }; + } + } +} + void TTrain::OnCommand_epbrakecontroltoggle( TTrain *Train, command_data const &Command ) { if( Command.action == GLFW_REPEAT ) { return; } @@ -2440,14 +2470,14 @@ void TTrain::OnCommand_batteryenable( TTrain *Train, command_data const &Command } } else // impulse button behavior - { + { if (Command.action == GLFW_PRESS) { if (Train->mvOccupied->shouldHoldBatteryButton) { // jesli przycisk trzeba przytrzymac Train->ggBatteryButton.UpdateValue(1.0f, Train->dsbSwitch); - Train->ggBatteryOnButton.UpdateValue(1.0f, Train->dsbSwitch); + Train->ggBatteryOnButton.UpdateValue(1.0f, Train->dsbSwitch); Train->fBatteryTimer = Train->mvOccupied->BatteryButtonHoldTime; // start timer } else @@ -2463,15 +2493,15 @@ void TTrain::OnCommand_batteryenable( TTrain *Train, command_data const &Command // visual feedback Train->ggBatteryButton.UpdateValue(1.0f, Train->dsbSwitch); - Train->ggBatteryOnButton.UpdateValue(1.0f, Train->dsbSwitch); + Train->ggBatteryOnButton.UpdateValue(1.0f, Train->dsbSwitch); } } else if (Command.action == GLFW_RELEASE) { // visual feedback Train->ggBatteryButton.UpdateValue(0.0f, Train->dsbSwitch); - Train->ggBatteryOnButton.UpdateValue(0.0f, Train->dsbSwitch); - Train->fBatteryTimer = -1.f; // + Train->ggBatteryOnButton.UpdateValue(0.0f, Train->dsbSwitch); + Train->fBatteryTimer = -1.f; // Train->allowBatteryToggle = true; } else if (Command.action == GLFW_REPEAT && Train->mvOccupied->shouldHoldBatteryButton) @@ -2526,7 +2556,7 @@ void TTrain::OnCommand_batterydisable( TTrain *Train, command_data const &Comman { // jesli przycisk trzeba przytrzymac Train->ggBatteryButton.UpdateValue(1.0f, Train->dsbSwitch); - Train->ggBatteryOffButton.UpdateValue(1.0f, Train->dsbSwitch); + Train->ggBatteryOffButton.UpdateValue(1.0f, Train->dsbSwitch); Train->fBatteryTimer = Train->mvOccupied->BatteryButtonHoldTime; // start timer } else @@ -2542,14 +2572,14 @@ void TTrain::OnCommand_batterydisable( TTrain *Train, command_data const &Comman } // visual feedback Train->ggBatteryButton.UpdateValue(1.0f, Train->dsbSwitch); - Train->ggBatteryOffButton.UpdateValue(1.0f, Train->dsbSwitch); + Train->ggBatteryOffButton.UpdateValue(1.0f, Train->dsbSwitch); } } else if (Command.action == GLFW_RELEASE) { // visual feedback Train->ggBatteryButton.UpdateValue(0.0f, Train->dsbSwitch); - Train->ggBatteryOffButton.UpdateValue(0.0f, Train->dsbSwitch); + Train->ggBatteryOffButton.UpdateValue(0.0f, Train->dsbSwitch); Train->allowBatteryToggle = true; } else if (Command.action == GLFW_REPEAT && Train->mvOccupied->shouldHoldBatteryButton) @@ -2989,7 +3019,7 @@ void TTrain::OnCommand_pantographvalvesupdate( TTrain *Train, command_data const } // Old logic to maintain compatibility - else + else { Train->update_pantograph_valves(); Train->ggPantValvesButton.UpdateValue(1.0, Train->dsbSwitch); @@ -4853,7 +4883,7 @@ void TTrain::OnCommand_headlightdisablerearupper( TTrain *Train, command_data co } } -void TTrain::OnCommand_modernlightdimmerincrease(TTrain* Train, command_data const& Command) +void TTrain::OnCommand_modernlightdimmerincrease(TTrain* Train, command_data const& Command) { if (!Train->mvOccupied->enableModernDimmer) return; // if modern dimmer is disabled, skip entire command @@ -4871,7 +4901,7 @@ void TTrain::OnCommand_modernlightdimmerincrease(TTrain* Train, command_data con Train->ggModernLightDimSw.UpdateValue(Train->mvOccupied->modernDimmerState - 1, Train->dsbSwitch); } } -void TTrain::OnCommand_modernlightdimmerdecrease(TTrain *Train, command_data const &Command) +void TTrain::OnCommand_modernlightdimmerdecrease(TTrain *Train, command_data const &Command) { if (!Train->mvOccupied->enableModernDimmer) return; // if modern dimmer is disabled, skip entire command @@ -7629,6 +7659,7 @@ bool TTrain::Update( double const Deltatime ) else btAKLVents.Turn(false); + if( true == lowvoltagepower ) { // McZapkie-141102: SHP i czuwak, TODO: sygnalizacja kabinowa if( mvOccupied->SecuritySystem.is_vigilance_blinking() ) { @@ -7800,12 +7831,12 @@ bool TTrain::Update( double const Deltatime ) btLampkaDoorLockOff.Turn( false == mvOccupied->Doors.lock_enabled ); btLampkaDepartureSignal.Turn( mvControlled->DepartureSignal ); btLampkaNapNastHam.Turn((mvControlled->DirActive != 0) && (mvOccupied->EpFuse)); // napiecie na nastawniku hamulcowym - + // Wylaczanie lampek kierunku gdy jedziemy // Feature uruchamiany z fiz z sekcji Ctrl. wpisem HideDirStatusWhenMoving=Yes (domyslnie No) if (mvOccupied->HideDirStatusWhenMoving && // Czy ta funkcja jest w ogole wlaczona mvOccupied->Vel > mvOccupied->HideDirStatusSpeed) // Uzaleznienie od predkosci - { + { btLampkaForward.Turn(false); btLampkaBackward.Turn(false); btLampkaNeutral.Turn(false); @@ -8580,6 +8611,16 @@ TTrain::update_sounds( double const Deltatime ) { } } + // dzwiek wiatru rozbijajacego sie o szyby w kabinie + if (rsWindSound) + { + if (!FreeFlyModeFlag && !Global.CabWindowOpen && DynamicObject->GetVelocity() > 0.5) + update_sounds_resonancenoise(*rsWindSound); + else + rsWindSound->stop(FreeFlyModeFlag); + } + + // dzwiek rezonansu (taki drugi runningnoise w sumie) if (rsResonanceNoise) { @@ -9898,7 +9939,7 @@ void TTrain::set_cab_controls( int const Cab ) { if (ggModernLightDimSw.SubModel != nullptr) { if (mvOccupied->modernContainOffPos) ggModernLightDimSw.PutValue(mvOccupied->modernDimmerState); - else + else ggModernLightDimSw.PutValue(mvOccupied->modernDimmerState - 1); } @@ -9906,7 +9947,7 @@ void TTrain::set_cab_controls( int const Cab ) { if (ggPantValvesUpdate.SubModel != nullptr) { ggPantValvesUpdate.PutValue(0.f); - } + } if (ggPantValvesOff.SubModel != nullptr) { ggPantValvesOff.PutValue(0.f); diff --git a/Train.h b/Train.h index 84c3fbba..8940f5b5 100644 --- a/Train.h +++ b/Train.h @@ -278,6 +278,8 @@ class TTrain { static void OnCommand_autosandboxactivate(TTrain *Train, command_data const &Command); static void OnCommand_autosandboxdeactivate(TTrain *Train, command_data const &Command); static void OnCommand_epbrakecontroltoggle( TTrain *Train, command_data const &Command ); + static void OnCommand_epbrakecontrolenable( TTrain *Train, command_data const &Command ); + static void OnCommand_epbrakecontroldisable( TTrain *Train, command_data const &Command ); static void OnCommand_trainbrakeoperationmodeincrease(TTrain *Train, command_data const &Command); static void OnCommand_trainbrakeoperationmodedecrease(TTrain *Train, command_data const &Command); static void OnCommand_brakeactingspeedincrease( TTrain *Train, command_data const &Command ); @@ -816,7 +818,8 @@ public: // reszta może by?publiczna rsBrake, rsFadeSound, rsRunningNoise, - rsResonanceNoise, rsWindSound, + rsResonanceNoise, + rsWindSound, rsHuntingNoise, m_rainsound; sound_source m_radiosound { sound_placement::internal, 2 * EU07_SOUND_CABCONTROLSCUTOFFRANGE }; // cached template for radio messages diff --git a/application.cpp b/application.cpp index c6efdc6b..e0771fa2 100644 --- a/application.cpp +++ b/application.cpp @@ -29,6 +29,9 @@ http://mozilla.org/MPL/2.0/. #include "Timer.h" #include "dictionary.h" #include "version_info.h" +#include "ref/discord-rpc/include/discord_rpc.h" +#include +#include "translation.h" #if WITH_DISCORD_RPC #include diff --git a/driverkeyboardinput.cpp b/driverkeyboardinput.cpp index 16b4a468..ded09670 100644 --- a/driverkeyboardinput.cpp +++ b/driverkeyboardinput.cpp @@ -24,265 +24,267 @@ void driverkeyboard_input::default_bindings() { m_bindingsetups = { - { user_command::aidriverenable, GLFW_KEY_Q | keymodifier::shift }, - { user_command::aidriverdisable, GLFW_KEY_Q }, + { user_command::aidriverenable, {GLFW_KEY_Q | keymodifier::shift, ""} }, + { user_command::aidriverdisable, {GLFW_KEY_Q, ""} }, // jointcontrollerset, - { user_command::mastercontrollerincrease, GLFW_KEY_KP_ADD }, - { user_command::mastercontrollerincreasefast, GLFW_KEY_KP_ADD | keymodifier::shift }, - { user_command::mastercontrollerdecrease, GLFW_KEY_KP_SUBTRACT }, - { user_command::mastercontrollerdecreasefast, GLFW_KEY_KP_SUBTRACT | keymodifier::shift }, + { user_command::mastercontrollerincrease, {GLFW_KEY_KP_ADD, ""} }, + { user_command::mastercontrollerincreasefast, {GLFW_KEY_KP_ADD | keymodifier::shift, ""} }, + { user_command::mastercontrollerdecrease, {GLFW_KEY_KP_SUBTRACT, ""} }, + { user_command::mastercontrollerdecreasefast, {GLFW_KEY_KP_SUBTRACT | keymodifier::shift, ""} }, // mastercontrollerset, - { user_command::secondcontrollerincrease, GLFW_KEY_KP_DIVIDE }, - { user_command::secondcontrollerincreasefast, GLFW_KEY_KP_DIVIDE | keymodifier::shift }, - { user_command::secondcontrollerdecrease, GLFW_KEY_KP_MULTIPLY }, - { user_command::secondcontrollerdecreasefast, GLFW_KEY_KP_MULTIPLY | keymodifier::shift }, + { user_command::secondcontrollerincrease, {GLFW_KEY_KP_DIVIDE, ""} }, + { user_command::secondcontrollerincreasefast, {GLFW_KEY_KP_DIVIDE | keymodifier::shift, ""} }, + { user_command::secondcontrollerdecrease, {GLFW_KEY_KP_MULTIPLY, ""} }, + { user_command::secondcontrollerdecreasefast, {GLFW_KEY_KP_MULTIPLY | keymodifier::shift, ""} }, // secondcontrollerset, - { user_command::mucurrentindicatorothersourceactivate, GLFW_KEY_Z | keymodifier::shift }, - { user_command::independentbrakeincrease, GLFW_KEY_KP_1 }, - { user_command::independentbrakeincreasefast, GLFW_KEY_KP_1 | keymodifier::shift }, - { user_command::independentbrakedecrease, GLFW_KEY_KP_7 }, - { user_command::independentbrakedecreasefast, GLFW_KEY_KP_7 | keymodifier::shift }, + { user_command::mucurrentindicatorothersourceactivate, {GLFW_KEY_Z | keymodifier::shift, ""} }, + { user_command::independentbrakeincrease, {GLFW_KEY_KP_1, ""} }, + { user_command::independentbrakeincreasefast, {GLFW_KEY_KP_1 | keymodifier::shift, ""} }, + { user_command::independentbrakedecrease, {GLFW_KEY_KP_7, ""} }, + { user_command::independentbrakedecreasefast, {GLFW_KEY_KP_7 | keymodifier::shift, ""} }, // independentbrakeset, - { user_command::independentbrakebailoff, GLFW_KEY_KP_4 }, + { user_command::independentbrakebailoff, {GLFW_KEY_KP_4, ""} }, // universalbrakebutton1, // universalbrakebutton2, // universalbrakebutton3, - { user_command::trainbrakeincrease, GLFW_KEY_KP_3 }, - { user_command::trainbrakedecrease, GLFW_KEY_KP_9 }, + { user_command::trainbrakeincrease, {GLFW_KEY_KP_3, ""} }, + { user_command::trainbrakedecrease, {GLFW_KEY_KP_9, ""} }, // trainbrakeset, - { user_command::trainbrakecharging, GLFW_KEY_KP_DECIMAL }, - { user_command::trainbrakerelease, GLFW_KEY_KP_6 }, - { user_command::trainbrakefirstservice, GLFW_KEY_KP_8 }, - { user_command::trainbrakeservice, GLFW_KEY_KP_5 }, - { user_command::trainbrakefullservice, GLFW_KEY_KP_2 }, - { user_command::trainbrakehandleoff, GLFW_KEY_KP_5 | keymodifier::control }, - { user_command::trainbrakeemergency, GLFW_KEY_KP_0 }, - { user_command::trainbrakebasepressureincrease, GLFW_KEY_KP_3 | keymodifier::control }, - { user_command::trainbrakebasepressuredecrease, GLFW_KEY_KP_9 | keymodifier::control }, - { user_command::trainbrakebasepressurereset, GLFW_KEY_KP_6 | keymodifier::control }, - { user_command::trainbrakeoperationtoggle, GLFW_KEY_KP_4 | keymodifier::control }, - { user_command::manualbrakeincrease, GLFW_KEY_KP_1 | keymodifier::control }, - { user_command::manualbrakedecrease, GLFW_KEY_KP_7 | keymodifier::control }, - { user_command::alarmchaintoggle, GLFW_KEY_B | keymodifier::shift | keymodifier::control }, + { user_command::trainbrakecharging, {GLFW_KEY_KP_DECIMAL, ""} }, + { user_command::trainbrakerelease, {GLFW_KEY_KP_6, ""} }, + { user_command::trainbrakefirstservice, {GLFW_KEY_KP_8, ""} }, + { user_command::trainbrakeservice, {GLFW_KEY_KP_5, ""} }, + { user_command::trainbrakefullservice, {GLFW_KEY_KP_2, ""} }, + { user_command::trainbrakehandleoff, {GLFW_KEY_KP_5 | keymodifier::control, ""} }, + { user_command::trainbrakeemergency, {GLFW_KEY_KP_0, ""} }, + { user_command::trainbrakebasepressureincrease, {GLFW_KEY_KP_3 | keymodifier::control, ""} }, + { user_command::trainbrakebasepressuredecrease, {GLFW_KEY_KP_9 | keymodifier::control, ""} }, + { user_command::trainbrakebasepressurereset, {GLFW_KEY_KP_6 | keymodifier::control, ""} }, + { user_command::trainbrakeoperationtoggle, {GLFW_KEY_KP_4 | keymodifier::control, ""} }, + { user_command::manualbrakeincrease, {GLFW_KEY_KP_1 | keymodifier::control, ""} }, + { user_command::manualbrakedecrease, {GLFW_KEY_KP_7 | keymodifier::control, ""} }, + { user_command::alarmchaintoggle, {GLFW_KEY_B | keymodifier::shift | keymodifier::control, ""} }, // alarmchainenable, // alarmchaindisable, - { user_command::wheelspinbrakeactivate, GLFW_KEY_KP_ENTER }, - { user_command::sandboxactivate, GLFW_KEY_S | keymodifier::shift }, + { user_command::wheelspinbrakeactivate, {GLFW_KEY_KP_ENTER, ""} }, + { user_command::sandboxactivate, {GLFW_KEY_S | keymodifier::shift, ""} }, // autosandboxtoggle, // autosandboxactivate, // autosandboxdeactivate, - { user_command::reverserincrease, GLFW_KEY_D }, - { user_command::reverserdecrease, GLFW_KEY_R }, + { user_command::reverserincrease, {GLFW_KEY_D, ""} }, + { user_command::reverserdecrease, {GLFW_KEY_R, ""} }, // reverserforwardhigh, // reverserforward, // reverserneutral, // reverserbackward, - { user_command::waterpumpbreakertoggle, GLFW_KEY_W | keymodifier::control }, + { user_command::waterpumpbreakertoggle, {GLFW_KEY_W | keymodifier::control, ""} }, // waterpumpbreakerclose, // waterpumpbreakeropen, - { user_command::waterpumptoggle, GLFW_KEY_W }, + { user_command::waterpumptoggle, {GLFW_KEY_W, ""} }, // waterpumpenable, // waterpumpdisable, - { user_command::waterheaterbreakertoggle, GLFW_KEY_W | keymodifier::control | keymodifier::shift }, + { user_command::waterheaterbreakertoggle, {GLFW_KEY_W | keymodifier::control | keymodifier::shift, ""} }, // waterheaterbreakerclose, // waterheaterbreakeropen, - { user_command::waterheatertoggle, GLFW_KEY_W | keymodifier::shift }, + { user_command::waterheatertoggle, {GLFW_KEY_W | keymodifier::shift, ""} }, // waterheaterenable, // waterheaterdisable, - { user_command::watercircuitslinktoggle, GLFW_KEY_H | keymodifier::shift }, + { user_command::watercircuitslinktoggle, {GLFW_KEY_H | keymodifier::shift, ""} }, // watercircuitslinkenable, // watercircuitslinkdisable, - { user_command::fuelpumptoggle, GLFW_KEY_F }, + { user_command::fuelpumptoggle, {GLFW_KEY_F, ""} }, // fuelpumpenable, // fuelpumpdisable, - { user_command::oilpumptoggle, GLFW_KEY_F | keymodifier::shift }, + { user_command::oilpumptoggle, {GLFW_KEY_F | keymodifier::shift, ""} }, // oilpumpenable, // oilpumpdisable, - { user_command::linebreakertoggle, GLFW_KEY_M }, + { user_command::linebreakertoggle, {GLFW_KEY_M, ""} }, // linebreakeropen, // linebreakerclose, - { user_command::convertertoggle, GLFW_KEY_X }, + { user_command::convertertoggle, {GLFW_KEY_X, ""} }, // converterenable, // converterdisable, - { user_command::convertertogglelocal, GLFW_KEY_X | keymodifier::shift }, - { user_command::converteroverloadrelayreset, GLFW_KEY_N | keymodifier::control }, - { user_command::compressortoggle, GLFW_KEY_C }, + { user_command::convertertogglelocal, {GLFW_KEY_X | keymodifier::shift, ""} }, + { user_command::converteroverloadrelayreset, {GLFW_KEY_N | keymodifier::control, ""} }, + { user_command::compressortoggle, {GLFW_KEY_C, ""} }, // compressorenable, // compressordisable, - { user_command::compressortogglelocal, GLFW_KEY_C | keymodifier::shift }, + { user_command::compressortogglelocal, {GLFW_KEY_C | keymodifier::shift, ""} }, // compressorpresetactivatenext, // compressorpresetactivateprevious, // compressorpresetactivatedefault, - { user_command::motoroverloadrelaythresholdtoggle, GLFW_KEY_F | keymodifier::control }, + { user_command::motoroverloadrelaythresholdtoggle, {GLFW_KEY_F | keymodifier::control, ""} }, // motoroverloadrelaythresholdsetlow, // motoroverloadrelaythresholdsethigh, - { user_command::motoroverloadrelayreset, GLFW_KEY_N }, + { user_command::motoroverloadrelayreset, {GLFW_KEY_N, ""} }, // universalrelayreset1, // universalrelayreset2, // universalrelayreset3, - { user_command::notchingrelaytoggle, GLFW_KEY_G }, - { user_command::epbrakecontroltoggle, GLFW_KEY_Z | keymodifier::control }, - { user_command::trainbrakeoperationmodeincrease, GLFW_KEY_KP_2 | keymodifier::control }, - { user_command::trainbrakeoperationmodedecrease, GLFW_KEY_KP_8 | keymodifier::control }, - { user_command::brakeactingspeedincrease, GLFW_KEY_B | keymodifier::shift }, - { user_command::brakeactingspeeddecrease, GLFW_KEY_B }, + { user_command::notchingrelaytoggle, {GLFW_KEY_G, ""} }, + { user_command::epbrakecontroltoggle, {GLFW_KEY_Z | keymodifier::control, ""} }, + // epbrakecontrolenable + // epbrakecontroldisable + { user_command::trainbrakeoperationmodeincrease, {GLFW_KEY_KP_2 | keymodifier::control, ""} }, + { user_command::trainbrakeoperationmodedecrease, {GLFW_KEY_KP_8 | keymodifier::control, ""} }, + { user_command::brakeactingspeedincrease, {GLFW_KEY_B | keymodifier::shift, ""} }, + { user_command::brakeactingspeeddecrease, {GLFW_KEY_B, ""} }, // brakeactingspeedsetcargo, // brakeactingspeedsetpassenger, // brakeactingspeedsetrapid, - { user_command::brakeloadcompensationincrease, GLFW_KEY_H | keymodifier::shift | keymodifier::control }, - { user_command::brakeloadcompensationdecrease, GLFW_KEY_H | keymodifier::control }, - { user_command::mubrakingindicatortoggle, GLFW_KEY_L | keymodifier::shift }, - { user_command::alerteracknowledge, GLFW_KEY_SPACE }, - { user_command::hornlowactivate, GLFW_KEY_A }, - { user_command::hornhighactivate, GLFW_KEY_S }, - { user_command::whistleactivate, GLFW_KEY_Z }, - { user_command::radiotoggle, GLFW_KEY_R | keymodifier::control }, + { user_command::brakeloadcompensationincrease, {GLFW_KEY_H | keymodifier::shift | keymodifier::control, ""} }, + { user_command::brakeloadcompensationdecrease, {GLFW_KEY_H | keymodifier::control, ""} }, + { user_command::mubrakingindicatortoggle, {GLFW_KEY_L | keymodifier::shift, ""} }, + { user_command::alerteracknowledge, {GLFW_KEY_SPACE, ""} }, + { user_command::hornlowactivate, {GLFW_KEY_A, ""} }, + { user_command::hornhighactivate, {GLFW_KEY_S, ""} }, + { user_command::whistleactivate, {GLFW_KEY_Z, ""} }, + { user_command::radiotoggle, {GLFW_KEY_R | keymodifier::control, ""} }, // radioenable // radiodisable - { user_command::radiochannelincrease, GLFW_KEY_EQUAL }, - { user_command::radiochanneldecrease, GLFW_KEY_MINUS }, + { user_command::radiochannelincrease, {GLFW_KEY_EQUAL, ""} }, + { user_command::radiochanneldecrease, {GLFW_KEY_MINUS, ""} }, // radiochannelset - { user_command::radiostopsend, GLFW_KEY_PAUSE | keymodifier::shift | keymodifier::control }, + { user_command::radiostopsend, {GLFW_KEY_PAUSE | keymodifier::shift | keymodifier::control, ""} }, // radiostopenable // radiostopdisable - { user_command::radiostoptest, GLFW_KEY_R | keymodifier::shift | keymodifier::control }, - { user_command::radiocall3send, GLFW_KEY_BACKSPACE }, + { user_command::radiostoptest, {GLFW_KEY_R | keymodifier::shift | keymodifier::control, ""} }, + { user_command::radiocall3send, {GLFW_KEY_BACKSPACE, ""} }, // radiovolumeincrease, // radiovolumedecrease, // radiovolumeset, - { user_command::cabchangeforward, GLFW_KEY_HOME }, - { user_command::cabchangebackward, GLFW_KEY_END }, + { user_command::cabchangeforward, {GLFW_KEY_HOME, ""} }, + { user_command::cabchangebackward, {GLFW_KEY_END, ""} }, // viewturn, // movehorizontal, // movehorizontalfast, // movevertical, // moveverticalfast, - { user_command::moveleft, GLFW_KEY_LEFT }, - { user_command::moveright, GLFW_KEY_RIGHT }, - { user_command::moveforward, GLFW_KEY_UP }, - { user_command::moveback, GLFW_KEY_DOWN }, - { user_command::moveup, GLFW_KEY_PAGE_UP }, - { user_command::movedown, GLFW_KEY_PAGE_DOWN }, - { user_command::nearestcarcouplingincrease, GLFW_KEY_INSERT }, - { user_command::nearestcarcouplingdisconnect, GLFW_KEY_DELETE }, - { user_command::nearestcarcoupleradapterattach, GLFW_KEY_INSERT | keymodifier::control }, - { user_command::nearestcarcoupleradapterremove, GLFW_KEY_DELETE | keymodifier::control }, - { user_command::occupiedcarcouplingdisconnect, GLFW_KEY_DELETE | keymodifier::shift }, - { user_command::doortoggleleft, GLFW_KEY_COMMA }, - { user_command::doortoggleright, GLFW_KEY_PERIOD }, - { user_command::doorpermitleft, GLFW_KEY_COMMA | keymodifier::shift }, - { user_command::doorpermitright, GLFW_KEY_PERIOD | keymodifier::shift }, - { user_command::doorpermitpresetactivatenext, GLFW_KEY_PERIOD | keymodifier::shift | keymodifier::control }, - { user_command::doorpermitpresetactivateprevious, GLFW_KEY_COMMA | keymodifier::shift | keymodifier::control }, + { user_command::moveleft, {GLFW_KEY_LEFT, "Move left"} }, + { user_command::moveright, {GLFW_KEY_RIGHT, "Move right"} }, + { user_command::moveforward, {GLFW_KEY_UP, "Move forwards"} }, + { user_command::moveback, {GLFW_KEY_DOWN, "Move backwards"} }, + { user_command::moveup, {GLFW_KEY_PAGE_UP, "Move up"} }, + { user_command::movedown, {GLFW_KEY_PAGE_DOWN, "Move down"} }, + { user_command::nearestcarcouplingincrease, {GLFW_KEY_INSERT, ""} }, + { user_command::nearestcarcouplingdisconnect, {GLFW_KEY_DELETE, ""} }, + { user_command::nearestcarcoupleradapterattach, {GLFW_KEY_INSERT | keymodifier::control, ""} }, + { user_command::nearestcarcoupleradapterremove, {GLFW_KEY_DELETE | keymodifier::control, ""} }, + { user_command::occupiedcarcouplingdisconnect, {GLFW_KEY_DELETE | keymodifier::shift, ""} }, + { user_command::doortoggleleft, {GLFW_KEY_COMMA, ""} }, + { user_command::doortoggleright, {GLFW_KEY_PERIOD, ""} }, + { user_command::doorpermitleft, {GLFW_KEY_COMMA | keymodifier::shift, ""} }, + { user_command::doorpermitright, {GLFW_KEY_PERIOD | keymodifier::shift, ""} }, + { user_command::doorpermitpresetactivatenext, {GLFW_KEY_PERIOD | keymodifier::shift | keymodifier::control, ""} }, + { user_command::doorpermitpresetactivateprevious, {GLFW_KEY_COMMA | keymodifier::shift | keymodifier::control, ""} }, // dooropenleft, // dooropenright, - { user_command::dooropenall, GLFW_KEY_SLASH | keymodifier::shift }, + { user_command::dooropenall, {GLFW_KEY_SLASH | keymodifier::shift, ""} }, // doorcloseleft, // doorcloseright, - { user_command::doorcloseall, GLFW_KEY_SLASH | keymodifier::control }, + { user_command::doorcloseall, {GLFW_KEY_SLASH | keymodifier::control, ""} }, // doorsteptoggle, - { user_command::doormodetoggle, GLFW_KEY_SLASH | keymodifier::shift | keymodifier::control }, + { user_command::doormodetoggle, {GLFW_KEY_SLASH | keymodifier::shift | keymodifier::control, ""} }, // mirrorstoggle, - { user_command::departureannounce, GLFW_KEY_SLASH }, - { user_command::doorlocktoggle, GLFW_KEY_S | keymodifier::control }, - { user_command::pantographcompressorvalvetoggle, GLFW_KEY_V | keymodifier::control }, + { user_command::departureannounce, {GLFW_KEY_SLASH, ""} }, + { user_command::doorlocktoggle, {GLFW_KEY_S | keymodifier::control, ""} }, + { user_command::pantographcompressorvalvetoggle, {GLFW_KEY_V | keymodifier::control, ""} }, // pantographcompressorvalveenable, // pantographcompressorvalvedisable, - { user_command::pantographcompressoractivate, GLFW_KEY_V | keymodifier::shift }, - { user_command::pantographtogglefront, GLFW_KEY_P }, - { user_command::pantographtogglerear, GLFW_KEY_O }, + { user_command::pantographcompressoractivate, {GLFW_KEY_V | keymodifier::shift, ""} }, + { user_command::pantographtogglefront, {GLFW_KEY_P, ""} }, + { user_command::pantographtogglerear, {GLFW_KEY_O, ""} }, // pantographraisefront, // pantographraiserear, // pantographlowerfront, // pantographlowerrear, - { user_command::pantographlowerall, GLFW_KEY_P | keymodifier::control }, - { user_command::pantographselectnext, GLFW_KEY_P | keymodifier::shift }, - { user_command::pantographselectprevious, GLFW_KEY_O | keymodifier::shift }, - { user_command::pantographtoggleselected, GLFW_KEY_O | keymodifier::shift | keymodifier::control }, + { user_command::pantographlowerall, {GLFW_KEY_P | keymodifier::control, ""} }, + { user_command::pantographselectnext, {GLFW_KEY_P | keymodifier::shift, ""} }, + { user_command::pantographselectprevious, {GLFW_KEY_O | keymodifier::shift, ""} }, + { user_command::pantographtoggleselected, {GLFW_KEY_O | keymodifier::shift | keymodifier::control, ""} }, // pantographraiseselected, // pantographlowerselected, // pantographvalvesupdate, // pantographvalvesoff, - { user_command::heatingtoggle, GLFW_KEY_H }, + { user_command::heatingtoggle, {GLFW_KEY_H, ""} }, // heatingenable, // heatingdisable, - { user_command::lightspresetactivatenext, GLFW_KEY_T | keymodifier::shift }, - { user_command::lightspresetactivateprevious, GLFW_KEY_T }, - { user_command::headlighttoggleleft, GLFW_KEY_Y }, + { user_command::lightspresetactivatenext, {GLFW_KEY_T | keymodifier::shift, ""} }, + { user_command::lightspresetactivateprevious, {GLFW_KEY_T, ""} }, + { user_command::headlighttoggleleft, {GLFW_KEY_Y, ""} }, // headlightenableleft, // headlightdisableleft, - { user_command::headlighttoggleright, GLFW_KEY_I }, + { user_command::headlighttoggleright, {GLFW_KEY_I, ""} }, // headlightenableright, // headlightdisableright, - { user_command::headlighttoggleupper, GLFW_KEY_U }, + { user_command::headlighttoggleupper, {GLFW_KEY_U, ""} }, // headlightenableupper, // headlightdisableupper, - { user_command::redmarkertoggleleft, GLFW_KEY_Y | keymodifier::shift }, + { user_command::redmarkertoggleleft, {GLFW_KEY_Y | keymodifier::shift, ""} }, // redmarkerenableleft, // redmarkerdisableleft, - { user_command::redmarkertoggleright, GLFW_KEY_I | keymodifier::shift }, + { user_command::redmarkertoggleright, {GLFW_KEY_I | keymodifier::shift, ""} }, // redmarkerenableright, // redmarkerdisableright, - { user_command::headlighttogglerearleft, GLFW_KEY_Y | keymodifier::control }, + { user_command::headlighttogglerearleft, {GLFW_KEY_Y | keymodifier::control, ""} }, // headlightenablerearleft // headlightdisablerearleft - { user_command::headlighttogglerearright, GLFW_KEY_I | keymodifier::control }, + { user_command::headlighttogglerearright, {GLFW_KEY_I | keymodifier::control, ""} }, // headlightenablerearright // headlightdisablerearright - { user_command::headlighttogglerearupper, GLFW_KEY_U | keymodifier::control }, + { user_command::headlighttogglerearupper, {GLFW_KEY_U | keymodifier::control, ""} }, // headlightenablerearupper // headlightdisablerearupper - { user_command::redmarkertogglerearleft, GLFW_KEY_Y | keymodifier::control | keymodifier::shift }, + { user_command::redmarkertogglerearleft, {GLFW_KEY_Y | keymodifier::control | keymodifier::shift, ""} }, // redmarkerenablerearleft // redmarkerdisablerearleft - { user_command::redmarkertogglerearright, GLFW_KEY_I | keymodifier::control | keymodifier::shift }, + { user_command::redmarkertogglerearright, {GLFW_KEY_I | keymodifier::control | keymodifier::shift, ""} }, // redmarkerenablerearright // redmarkerdisablerearright - { user_command::redmarkerstoggle, GLFW_KEY_E | keymodifier::shift }, - { user_command::endsignalstoggle, GLFW_KEY_E }, - { user_command::headlightsdimtoggle, GLFW_KEY_L | keymodifier::control }, + { user_command::redmarkerstoggle, {GLFW_KEY_E | keymodifier::shift, ""} }, + { user_command::endsignalstoggle, {GLFW_KEY_E, ""} }, + { user_command::headlightsdimtoggle, {GLFW_KEY_L | keymodifier::control, ""} }, // headlightsdimenable, // headlightsdimdisable, - { user_command::motorconnectorsopen, GLFW_KEY_L }, + { user_command::motorconnectorsopen, {GLFW_KEY_L, ""} }, // motorconnectorsclose, - { user_command::motordisconnect, GLFW_KEY_E | keymodifier::control }, - { user_command::interiorlighttoggle, GLFW_KEY_APOSTROPHE }, + { user_command::motordisconnect, {GLFW_KEY_E | keymodifier::control, ""} }, + { user_command::interiorlighttoggle, {GLFW_KEY_APOSTROPHE, ""} }, // interiorlightenable, // interiorlightdisable, - { user_command::interiorlightdimtoggle, GLFW_KEY_APOSTROPHE | keymodifier::control }, + { user_command::interiorlightdimtoggle, {GLFW_KEY_APOSTROPHE | keymodifier::control, ""} }, // interiorlightdimenable, // interiorlightdimdisable, // compartmentlightstoggle, // compartmentlightsenable, // compartmentlightsdisable, - { user_command::instrumentlighttoggle, GLFW_KEY_SEMICOLON }, + { user_command::instrumentlighttoggle, {GLFW_KEY_SEMICOLON, ""} }, // instrumentlightenable, // instrumentlightdisable, - { user_command::dashboardlighttoggle, GLFW_KEY_SEMICOLON | keymodifier::shift }, + { user_command::dashboardlighttoggle, {GLFW_KEY_SEMICOLON | keymodifier::shift, ""} }, // dashboardlightenable // dashboardlightdisable - { user_command::timetablelighttoggle, GLFW_KEY_APOSTROPHE | keymodifier::shift }, + { user_command::timetablelighttoggle, {GLFW_KEY_APOSTROPHE | keymodifier::shift, ""} }, // timetablelightenable // timetablelightdisable - { user_command::generictoggle0, GLFW_KEY_0 }, - { user_command::generictoggle1, GLFW_KEY_1 }, - { user_command::generictoggle2, GLFW_KEY_2 }, - { user_command::generictoggle3, GLFW_KEY_3 }, - { user_command::generictoggle4, GLFW_KEY_4 }, - { user_command::generictoggle5, GLFW_KEY_5 }, - { user_command::generictoggle6, GLFW_KEY_6 }, - { user_command::generictoggle7, GLFW_KEY_7 }, - { user_command::generictoggle8, GLFW_KEY_8 }, - { user_command::generictoggle9, GLFW_KEY_9 }, - { user_command::batterytoggle, GLFW_KEY_J }, + { user_command::generictoggle0, {GLFW_KEY_0, ""} }, + { user_command::generictoggle1, {GLFW_KEY_1, ""} }, + { user_command::generictoggle2, {GLFW_KEY_2, ""} }, + { user_command::generictoggle3, {GLFW_KEY_3, ""} }, + { user_command::generictoggle4, {GLFW_KEY_4, ""} }, + { user_command::generictoggle5, {GLFW_KEY_5, ""} }, + { user_command::generictoggle6, {GLFW_KEY_6, ""} }, + { user_command::generictoggle7, {GLFW_KEY_7, ""} }, + { user_command::generictoggle8, {GLFW_KEY_8, ""} }, + { user_command::generictoggle9, {GLFW_KEY_9, ""} }, + { user_command::batterytoggle, {GLFW_KEY_J, ""} }, // batteryenable, // batterydisable, // cabactivationtoggle, // cabactivationenable, // cabactivationdisable, - { user_command::motorblowerstogglefront, GLFW_KEY_N | keymodifier::shift }, - { user_command::motorblowerstogglerear, GLFW_KEY_M | keymodifier::shift }, - { user_command::motorblowersdisableall, GLFW_KEY_M | keymodifier::control }, + { user_command::motorblowerstogglefront, {GLFW_KEY_N | keymodifier::shift, ""} }, + { user_command::motorblowerstogglerear, {GLFW_KEY_M | keymodifier::shift, ""} }, + { user_command::motorblowersdisableall, {GLFW_KEY_M | keymodifier::control, ""} }, // coolingfanstoggle, // tempomattoggle, // springbraketoggle, @@ -308,14 +310,14 @@ driverkeyboard_input::default_bindings() { // speedcontrolbutton8, // speedcontrolbutton9, // admin_timejump, - { user_command::timejumplarge, GLFW_KEY_F1 | keymodifier::control }, - { user_command::timejumpsmall, GLFW_KEY_F1 | keymodifier::shift }, + { user_command::timejumplarge, {GLFW_KEY_F1 | keymodifier::control, "Big time jump (Debug Mode only)"} }, + { user_command::timejumpsmall, {GLFW_KEY_F1 | keymodifier::shift, "Small time jump (Debug Mode only)"} }, // admin_vehiclemove, - { user_command::vehiclemoveforwards, GLFW_KEY_LEFT_BRACKET | keymodifier::control }, - { user_command::vehiclemovebackwards, GLFW_KEY_RIGHT_BRACKET | keymodifier::control }, - { user_command::vehicleboost, GLFW_KEY_TAB | keymodifier::control }, - { user_command::debugtoggle, GLFW_KEY_F12 | keymodifier::control | keymodifier::shift }, - { user_command::pausetoggle, GLFW_KEY_ESCAPE } + { user_command::vehiclemoveforwards, {GLFW_KEY_LEFT_BRACKET | keymodifier::control, "Move the train forwards (Debug Mode only)"} }, + { user_command::vehiclemovebackwards, {GLFW_KEY_RIGHT_BRACKET | keymodifier::control, "Move the train backwards (Debug Mode only)"} }, + { user_command::vehicleboost, {GLFW_KEY_TAB | keymodifier::control, "Boost the train (Debug Mode only)"} }, + { user_command::debugtoggle, {GLFW_KEY_F12 | keymodifier::control | keymodifier::shift, "Toggle Debug Mode"} }, + { user_command::pausetoggle, {GLFW_KEY_ESCAPE, "Pause the game"} } }; } diff --git a/drivermouseinput.cpp b/drivermouseinput.cpp index 2436db0f..a6f99e56 100644 --- a/drivermouseinput.cpp +++ b/drivermouseinput.cpp @@ -281,8 +281,8 @@ drivermouse_input::move( double Mousex, double Mousey ) { void drivermouse_input::scroll( double const Xoffset, double const Yoffset ) { - if( Global.ctrlState || m_buttons[1] == GLFW_PRESS ) { - // ctrl + scroll wheel or holding right mouse button + scroll wheel adjusts fov + if( Global.ctrlState ) { + // ctrl + scroll wheel adjusts fov Global.FieldOfView = clamp( static_cast( Global.FieldOfView - Yoffset * 20.0 / Timer::subsystem.mainloop_total.average() ), 15.0f, 75.0f ); } else { @@ -638,6 +638,12 @@ drivermouse_input::default_bindings() { { "epbrake_bt:",{ user_command::epbrakecontroltoggle, user_command::none } }, + { "epbrakeon_bt:",{ + user_command::epbrakecontrolenable, + user_command::none } }, + { "epbrakeoff_bt:",{ + user_command::epbrakecontroldisable, + user_command::none } }, { "sand_bt:", { user_command::sandboxactivate, user_command::none } }, diff --git a/driveruipanels.cpp b/driveruipanels.cpp index 99bff6d0..b7044b18 100644 --- a/driveruipanels.cpp +++ b/driveruipanels.cpp @@ -485,11 +485,13 @@ timetable_panel::render() { | ImGuiWindowFlags_NoCollapse | ( size.x > 0 ? ImGuiWindowFlags_NoResize : 0 ); + // HACK: Make sure the timetable window is of correct width when using a larger font size. + float horizontalScale = Global.ui_fontsize / 13; if( size.x > 0 ) { - ImGui::SetNextWindowSize( ImVec2S( size.x, size.y ) ); + ImGui::SetNextWindowSize( ImVec2S( size.x * horizontalScale, size.y ) ); } if( size_min.x > 0 ) { - ImGui::SetNextWindowSizeConstraints( ImVec2S( size_min.x, size_min.y ), ImVec2S( size_max.x, size_max.y ) ); + ImGui::SetNextWindowSizeConstraints( ImVec2S( size_min.x * horizontalScale, size_min.y ), ImVec2S( size_max.x * horizontalScale, size_max.y ) ); } auto const panelname { ( title.empty() ? @@ -657,15 +659,29 @@ debug_panel::render_section_scenario() { { auto fogrange = std::log( Global.fFogEnd ); if( ImGui::SliderFloat( - ( to_string( std::exp( fogrange ), 0, 5 ) + " m###fogend" ).c_str(), &fogrange, std::log( 10.0f ), std::log( 25000.0f ), "Fog distance" ) ) { + ( to_string( std::exp( fogrange ), 0, 5 ) + " m###fogend" ).c_str(), &fogrange, std::log( 10.0f ), std::log( 50000.0f ), "Fog distance" ) ) { command_relay relay; relay.post( user_command::setweather, - clamp( std::exp( fogrange ), 10.0f, 25000.0f ), + clamp( std::exp( fogrange ), 10.0f, 50000.0f ), Global.Overcast, GLFW_PRESS, 0 ); } } + { + auto Airtemperature = Global.AirTemperature; + if (ImGui::SliderFloat( + (to_string(Airtemperature, 1) + " deg C###Airtemperature").c_str(), + &Airtemperature, -35.0f, 40.0f, "Air Temperature")) + { + command_relay relay; + relay.post( + user_command::settemperature, + clamp(Airtemperature, -35.0f, 40.0f), + Global.Overcast, + GLFW_PRESS, 0 ); + } + } // cloud cover slider { if( ImGui::SliderFloat( @@ -1286,7 +1302,7 @@ debug_panel::update_section_scenario( std::vector &Output ) { Output.emplace_back( textline, Global.UITextColor ); // current luminance level - textline = "Light level: " + to_string( Global.fLuminance, 3 ) + ( Global.FakeLight ? "(*)" : "" ); + textline = "Light level: " + to_string( Global.fLuminance, 3 ) + ( Global.FakeLight ? "(*)" : "" )+ to_string(Global.SunAngle,2); textline += "\nWind: azimuth " + to_string( simulation::Environment.wind_azimuth(), 0 ) // ma być azymut, czyli 0 na północy i rośnie na wschód diff --git a/editorkeyboardinput.cpp b/editorkeyboardinput.cpp index 139e2f53..154af92b 100644 --- a/editorkeyboardinput.cpp +++ b/editorkeyboardinput.cpp @@ -25,12 +25,12 @@ void editorkeyboard_input::default_bindings() { m_bindingsetups = { - { user_command::moveleft, GLFW_KEY_LEFT }, - { user_command::moveright, GLFW_KEY_RIGHT }, - { user_command::moveforward, GLFW_KEY_UP }, - { user_command::moveback, GLFW_KEY_DOWN }, - { user_command::moveup, GLFW_KEY_PAGE_UP }, - { user_command::movedown, GLFW_KEY_PAGE_DOWN }, + { user_command::moveleft, {GLFW_KEY_LEFT, "Move left"} }, + { user_command::moveright, {GLFW_KEY_RIGHT, "Move right"} }, + { user_command::moveforward, {GLFW_KEY_UP, "Move forwards"} }, + { user_command::moveback, {GLFW_KEY_DOWN, "Move backwards"} }, + { user_command::moveup, {GLFW_KEY_PAGE_UP, "Move up"} }, + { user_command::movedown, {GLFW_KEY_PAGE_DOWN, "Move down"} }, }; } diff --git a/geometrybank.cpp b/geometrybank.cpp index 47dd316c..4371bb3f 100644 --- a/geometrybank.cpp +++ b/geometrybank.cpp @@ -9,6 +9,7 @@ http://mozilla.org/MPL/2.0/. #include "stdafx.h" #include "geometrybank.h" +#include "vertex.h" #include "sn_utils.h" #include "Logs.h" @@ -16,6 +17,26 @@ http://mozilla.org/MPL/2.0/. namespace gfx { +basic_vertex basic_vertex::convert(world_vertex const &world, glm::dvec3 const& origin) +{ + basic_vertex vertex{}; + vertex.position = static_cast(world.position - origin); + vertex.normal = world.normal; + vertex.texture = world.texture; + return vertex; +} + +world_vertex basic_vertex::to_world(const glm::dvec3 &origin) const +{ + world_vertex vertex{}; + + vertex.position = static_cast(position) + origin; + vertex.normal = normal; + vertex.texture = texture; + + return vertex; +} + void basic_vertex::serialize( std::ostream &s, bool const Tangent ) const { @@ -183,14 +204,18 @@ void calculate_tangents(vertex_array &vertices, index_array const &indices, int } } -void calculate_indices( index_array &Indices, vertex_array &Vertices, float tolerancescale ) { +void calculate_indices( index_array &Indices, vertex_array &Vertices, userdata_array &Userdata, float tolerancescale ) { Indices.resize( Vertices.size() ); std::iota( std::begin( Indices ), std::end( Indices ), 0 ); // gather instances of used vertices, replace the original vertex bank with it after you're done - vertex_array indexedvertices; + vertex_array indexedvertices{}; + userdata_array indexeduserdata{}; indexedvertices.reserve( std::max( 100, Vertices.size() / 3 ) ); // optimistic guesstimate, but should reduce re-allocation somewhat - auto const matchtolerance { 1e-5f * tolerancescale }; + bool has_userdata = !Userdata.empty(); + if (has_userdata) + indexeduserdata.reserve(std::max(100, Userdata.size() / 3)); + auto const matchtolerance { 1e-5f * tolerancescale }; for( auto idx = 0; idx < Indices.size(); ++idx ) { if( Indices[ idx ] < idx ) { // this index is pointing to a vertex out of linear order, i.e. it's an already processed duplicate we can skip @@ -200,31 +225,38 @@ void calculate_indices( index_array &Indices, vertex_array &Vertices, float tole Indices[ idx ] = indexedvertices.size(); // see if there's any pointers in the remaining index subrange to similar enough vertices // if found, remap these to use our current vertex instead - auto vertex { Vertices[ idx ] }; + const auto& vertex { Vertices[ idx ] }; + const auto* userdata{ has_userdata ? &Userdata[idx] : nullptr }; auto matchiter { std::cbegin( Vertices ) + idx }; + auto matchuserdata = userdata; for( auto matchidx = idx + 1; matchidx < Indices.size() && matchidx < idx + Global.iConvertIndexRange; ++matchidx ) { ++matchiter; + ++matchuserdata; if( ( glm::all( glm::epsilonEqual( vertex.position, matchiter->position, matchtolerance ) ) ) && ( glm::all( glm::epsilonEqual( vertex.normal, matchiter->normal, matchtolerance ) ) ) - && ( glm::all( glm::epsilonEqual( vertex.texture, matchiter->texture, matchtolerance ) ) ) ) { + && ( glm::all( glm::epsilonEqual( vertex.texture, matchiter->texture, matchtolerance ) ) ) + && ( !userdata || glm::all( glm::epsilonEqual( userdata->data, matchuserdata->data, matchtolerance ) ) ) ) { Indices[ matchidx ] = Indices[ idx ]; } } indexedvertices.emplace_back( vertex ); + if(userdata) + indexeduserdata.emplace_back( *userdata ); } // done indexing, swap the source vertex bank with the processed one Vertices.swap( indexedvertices ); + Userdata.swap( indexeduserdata ); } // generic geometry bank class, allows storage, update and drawing of geometry chunks // creates a new geometry chunk of specified type from supplied data. returns: handle to the chunk or NULL gfx::geometry_handle -geometry_bank::create( gfx::vertex_array &Vertices, unsigned int const Type ) { +geometry_bank::create( gfx::vertex_array &Vertices, userdata_array &Userdata, unsigned int const Type ) { - if( true == Vertices.empty() ) { return { 0, 0 }; } + if(Vertices.empty()) { return { 0, 0 }; } - m_chunks.emplace_back( Vertices, Type ); + m_chunks.emplace_back( Vertices, Userdata, Type ); // NOTE: handle is effectively (index into chunk array + 1) this leaves value of 0 to serve as error/empty handle indication gfx::geometry_handle chunkhandle { 0, static_cast(m_chunks.size()) }; // template method implementation @@ -235,11 +267,11 @@ geometry_bank::create( gfx::vertex_array &Vertices, unsigned int const Type ) { // creates a new indexed geometry chunk of specified type from supplied data. returns: handle to the chunk or NULL gfx::geometry_handle -geometry_bank::create( gfx::index_array &Indices, gfx::vertex_array &Vertices, unsigned int const Type ) { +geometry_bank::create( gfx::index_array &Indices, gfx::vertex_array &Vertices, userdata_array &Userdata, unsigned int const Type ) { - if( true == Vertices.empty() ) { return { 0, 0 }; } + if(Vertices.empty()) { return { 0, 0 }; } - m_chunks.emplace_back( Indices, Vertices, Type ); + m_chunks.emplace_back( Indices, Vertices, Userdata, Type ); // NOTE: handle is effectively (index into chunk array + 1) this leaves value of 0 to serve as error/empty handle indication gfx::geometry_handle chunkhandle { 0, static_cast(m_chunks.size()) }; // template method implementation @@ -250,7 +282,7 @@ geometry_bank::create( gfx::index_array &Indices, gfx::vertex_array &Vertices, u // replaces data of specified chunk with the supplied vertex data, starting from specified offset bool -geometry_bank::replace( gfx::vertex_array &Vertices, gfx::geometry_handle const &Geometry, std::size_t const Offset ) { +geometry_bank::replace( gfx::vertex_array &Vertices, userdata_array &Userdata, gfx::geometry_handle const &Geometry, std::size_t const Offset ) { if( ( Geometry.chunk == 0 ) || ( Geometry.chunk > m_chunks.size() ) ) { return false; } @@ -260,13 +292,16 @@ geometry_bank::replace( gfx::vertex_array &Vertices, gfx::geometry_handle const && ( Vertices.size() == chunk.vertices.size() ) ) { // check first if we can get away with a simple swap... chunk.vertices.swap( Vertices ); + chunk.userdata.swap( Userdata ); } else { // ...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(), gfx::basic_vertex() ); + chunk.userdata.resize( Offset + Userdata.size(), gfx::vertex_userdata() ); chunk.vertices.insert( std::end( chunk.vertices ), std::begin( Vertices ), std::end( Vertices ) ); + chunk.userdata.insert( std::end( chunk.userdata ), std::begin( Userdata ), std::end( Userdata ) ); } // template method implementation replace_( Geometry ); @@ -276,11 +311,11 @@ geometry_bank::replace( gfx::vertex_array &Vertices, gfx::geometry_handle const // adds supplied vertex data at the end of specified chunk bool -geometry_bank::append( gfx::vertex_array &Vertices, gfx::geometry_handle const &Geometry ) { +geometry_bank::append( gfx::vertex_array &Vertices, userdata_array &Userdata, gfx::geometry_handle const &Geometry ) { if( ( Geometry.chunk == 0 ) || ( Geometry.chunk > m_chunks.size() ) ) { return false; } - return replace( Vertices, Geometry, gfx::geometry_bank::chunk( Geometry ).vertices.size() ); + return replace( Vertices, Userdata, Geometry, gfx::geometry_bank::chunk( Geometry ).vertices.size() ); } // draws geometry stored in specified chunk @@ -311,6 +346,13 @@ geometry_bank::vertices( gfx::geometry_handle const &Geometry ) const { return geometry_bank::chunk( Geometry ).vertices; } +// provides direct access to vertex user data of specfied chunk +userdata_array const & +geometry_bank::userdata( gfx::geometry_handle const &Geometry ) const { + + return geometry_bank::chunk( Geometry ).userdata; +} + // geometry bank manager, holds collection of geometry banks // performs a resource sweep @@ -331,9 +373,9 @@ geometrybank_manager::register_bank(std::unique_ptr bank) { // creates a new geometry chunk of specified type from supplied data, in specified bank. returns: handle to the chunk or NULL gfx::geometry_handle -geometrybank_manager::create_chunk(vertex_array &Vertices, gfx::geometrybank_handle const &Geometry, int const Type ) { +geometrybank_manager::create_chunk(vertex_array &Vertices, userdata_array &Userdata, gfx::geometrybank_handle const &Geometry, int const Type ) { - auto const newchunkhandle = bank( Geometry ).first->create( Vertices, Type ); + auto const newchunkhandle = bank( Geometry ).first->create( Vertices, Userdata, Type ); if( newchunkhandle.chunk != 0 ) { return { Geometry.bank, newchunkhandle.chunk }; } else { return { 0, 0 }; } @@ -341,9 +383,9 @@ geometrybank_manager::create_chunk(vertex_array &Vertices, gfx::geometrybank_han // creates a new indexed geometry chunk of specified type from supplied data, in specified bank. returns: handle to the chunk or NULL gfx::geometry_handle -geometrybank_manager::create_chunk( gfx::index_array &Indices, gfx::vertex_array &Vertices, gfx::geometrybank_handle const &Geometry, unsigned int const Type ) { +geometrybank_manager::create_chunk( gfx::index_array &Indices, gfx::vertex_array &Vertices, userdata_array &Userdata, gfx::geometrybank_handle const &Geometry, unsigned int const Type ) { - auto const newchunkhandle = bank( Geometry ).first->create( Indices, Vertices, Type ); + auto const newchunkhandle = bank( Geometry ).first->create( Indices, Vertices, Userdata, Type ); if( newchunkhandle.chunk != 0 ) { return { Geometry.bank, newchunkhandle.chunk }; } else { return { 0, 0 }; } @@ -351,16 +393,16 @@ geometrybank_manager::create_chunk( gfx::index_array &Indices, gfx::vertex_array // replaces data of specified chunk with the supplied vertex data, starting from specified offset bool -geometrybank_manager::replace( gfx::vertex_array &Vertices, gfx::geometry_handle const &Geometry, std::size_t const Offset ) { +geometrybank_manager::replace( gfx::vertex_array &Vertices, userdata_array &Userdata, gfx::geometry_handle const &Geometry, std::size_t const Offset ) { - return bank( Geometry ).first->replace( Vertices, Geometry, Offset ); + return bank( Geometry ).first->replace( Vertices, Userdata, Geometry, Offset ); } // adds supplied vertex data at the end of specified chunk bool -geometrybank_manager::append( gfx::vertex_array &Vertices, gfx::geometry_handle const &Geometry ) { +geometrybank_manager::append( gfx::vertex_array &Vertices, userdata_array &Userdata, gfx::geometry_handle const &Geometry ) { - return bank( Geometry ).first->append( Vertices, Geometry ); + return bank( Geometry ).first->append( Vertices, Userdata, Geometry ); } // draws geometry stored in specified chunk void @@ -388,4 +430,31 @@ geometrybank_manager::vertices( gfx::geometry_handle const &Geometry ) const { return bank( Geometry ).first->vertices( Geometry ); } +// provides direct access to vertex user data of specfied chunk +gfx::userdata_array const & +geometrybank_manager::userdata( gfx::geometry_handle const &Geometry ) const { + + return bank( Geometry ).first->userdata( Geometry ); +} + +void vertex_userdata::serialize(std::ostream &s) const +{ + sn_utils::s_vec4(s, data); +} + +void vertex_userdata::deserialize(std::istream &s) +{ + data = sn_utils::d_vec4(s); +} + +void vertex_userdata::serialize_packed(std::ostream &s) const +{ + sn_utils::ls_uint64(s, glm::packHalf4x16(data)); +} + +void vertex_userdata::deserialize_packed(std::istream &s) +{ + data = glm::unpackHalf4x16(sn_utils::ld_uint64(s)); +} + } // namespace gfx diff --git a/geometrybank.h b/geometrybank.h index 2f067388..e12d51ba 100644 --- a/geometrybank.h +++ b/geometrybank.h @@ -11,6 +11,8 @@ http://mozilla.org/MPL/2.0/. #include "ResourceManager.h" +struct world_vertex; + namespace gfx { struct basic_vertex { @@ -24,12 +26,22 @@ struct basic_vertex { basic_vertex( glm::vec3 Position, glm::vec3 Normal, glm::vec2 Texture ) : position( Position ), normal( Normal ), texture( Texture ) {} - void serialize( std::ostream&, bool const Tangent = false ) const; + static basic_vertex convert(world_vertex const &world, glm::dvec3 const &origin); + world_vertex to_world(glm::dvec3 const &origin = glm::dvec3(0.)) const; + void serialize( std::ostream&, bool const Tangent = false ) const; void deserialize( std::istream&, bool const Tangent = false ); void serialize_packed( std::ostream&, bool const Tangent = false ) const; void deserialize_packed( std::istream&, bool const Tangent = false ); }; +struct vertex_userdata{ + glm::vec4 data; // user data (for color or additional uv channels, not subject to post-processing) + void serialize( std::ostream& ) const; + void deserialize( std::istream& ); + void serialize_packed( std::ostream& ) const; + void deserialize_packed( std::istream& ); +}; + // data streams carried in a vertex enum stream { none = 0x0, @@ -50,10 +62,11 @@ struct stream_units { using basic_index = std::uint32_t; using vertex_array = std::vector; +using userdata_array = std::vector; using index_array = std::vector; void calculate_tangents( vertex_array &vertices, index_array const &indices, int const type ); -void calculate_indices( index_array &Indices, vertex_array &Vertices, float tolerancescale = 1.0f ); +void calculate_indices( index_array &Indices, vertex_array &Vertices, userdata_array &Userdata, float tolerancescale = 1.0f ); // generic geometry bank class, allows storage, update and drawing of geometry chunks @@ -97,13 +110,13 @@ public: // methods: // creates a new geometry chunk of specified type from supplied data. returns: handle to the chunk or NULL - auto create( gfx::vertex_array &Vertices, unsigned int const Type ) -> gfx::geometry_handle; + auto create( gfx::vertex_array &Vertices, gfx::userdata_array& Userdata, unsigned int const Type ) -> gfx::geometry_handle; // creates a new indexed geometry chunk of specified type from supplied data. returns: handle to the chunk or NULL - auto create( gfx::index_array &Indices, gfx::vertex_array &Vertices, unsigned int const Type ) -> gfx::geometry_handle; + auto create( gfx::index_array &Indices, gfx::vertex_array &Vertices, gfx::userdata_array& Userdata, unsigned int const Type ) -> gfx::geometry_handle; // replaces vertex data of specified chunk with the supplied data, starting from specified offset - auto replace( gfx::vertex_array &Vertices, gfx::geometry_handle const &Geometry, std::size_t const Offset = 0 ) -> bool; + auto replace( gfx::vertex_array &Vertices, gfx::userdata_array& Userdata, gfx::geometry_handle const &Geometry, std::size_t const Offset = 0 ) -> bool; // adds supplied vertex data at the end of specified chunk - auto append( gfx::vertex_array &Vertices, gfx::geometry_handle const &Geometry ) -> bool; + auto append( gfx::vertex_array &Vertices, gfx::userdata_array& Userdata, gfx::geometry_handle const &Geometry ) -> bool; // draws geometry stored in specified chunk auto draw( gfx::geometry_handle const &Geometry, gfx::stream_units const &Units, unsigned int const Streams = basic_streams ) -> std::size_t; // draws geometry stored in supplied list of chunks @@ -117,8 +130,10 @@ public: void release(); // provides direct access to index data of specfied chunk auto indices( gfx::geometry_handle const &Geometry ) const -> gfx::index_array const &; - // provides direct access to vertex data of specfied chunk - auto vertices( gfx::geometry_handle const &Geometry ) const -> gfx::vertex_array const &; + // provides direct access to vertex data of specfied chunk + auto vertices( gfx::geometry_handle const &Geometry ) const -> gfx::vertex_array const &; + // provides direct access to vertex user data of specfied chunk + auto userdata( gfx::geometry_handle const &Geometry ) const -> gfx::userdata_array const &; protected: // types: @@ -126,17 +141,20 @@ protected: unsigned int type; // kind of geometry used by the chunk gfx::vertex_array vertices; // geometry data gfx::index_array indices; // index data + gfx::userdata_array userdata; // NOTE: constructor doesn't copy provided geometry data, but moves it - geometry_chunk( gfx::vertex_array &Vertices, unsigned int Type ) : + geometry_chunk( gfx::vertex_array &Vertices, gfx::userdata_array& Userdata, unsigned int Type ) : type( Type ) { vertices.swap( Vertices ); + userdata.swap( Userdata ); } // NOTE: constructor doesn't copy provided geometry data, but moves it - geometry_chunk( gfx::index_array &Indices, gfx::vertex_array &Vertices, unsigned int Type ) : + geometry_chunk( gfx::index_array &Indices, gfx::vertex_array &Vertices, gfx::userdata_array& Userdata, unsigned int Type ) : type( Type ) { vertices.swap( Vertices ); + userdata.swap( Userdata ); indices.swap( Indices ); } }; @@ -181,13 +199,13 @@ public: // registers a new geometry bank. returns: handle to the bank auto register_bank(std::unique_ptr bank) -> gfx::geometrybank_handle; // creates a new geometry chunk of specified type from supplied data, in specified bank. returns: handle to the chunk or NULL - auto create_chunk( gfx::vertex_array &Vertices, gfx::geometrybank_handle const &Geometry, int const Type ) -> gfx::geometry_handle; + auto create_chunk( gfx::vertex_array &Vertices, gfx::userdata_array &Userdata, gfx::geometrybank_handle const &Geometry, int const Type ) -> gfx::geometry_handle; // creates a new indexed geometry chunk of specified type from supplied data, in specified bank. returns: handle to the chunk or NULL - auto create_chunk( gfx::index_array &Indices, gfx::vertex_array &Vertices, gfx::geometrybank_handle const &Geometry, unsigned int const Type ) -> gfx::geometry_handle; + auto create_chunk( gfx::index_array &Indices, gfx::vertex_array &Vertices, gfx::userdata_array &Userdata, gfx::geometrybank_handle const &Geometry, unsigned int const Type ) -> gfx::geometry_handle; // replaces data of specified chunk with the supplied vertex data, starting from specified offset - auto replace( gfx::vertex_array &Vertices, gfx::geometry_handle const &Geometry, std::size_t const Offset = 0 ) -> bool; + auto replace( gfx::vertex_array &Vertices, gfx::userdata_array &Userdata, gfx::geometry_handle const &Geometry, std::size_t const Offset = 0 ) -> bool; // adds supplied vertex data at the end of specified chunk - auto append( gfx::vertex_array &Vertices, gfx::geometry_handle const &Geometry ) -> bool; + auto append( gfx::vertex_array &Vertices, gfx::userdata_array &Userdata, gfx::geometry_handle const &Geometry ) -> bool; // draws geometry stored in specified chunk void draw( gfx::geometry_handle const &Geometry, unsigned int const Streams = basic_streams ); template @@ -197,8 +215,10 @@ public: ++First; } } // provides direct access to index data of specfied chunk auto indices( gfx::geometry_handle const &Geometry ) const -> gfx::index_array const &; - // provides direct access to vertex data of specfied chunk - auto vertices( gfx::geometry_handle const &Geometry ) const -> gfx::vertex_array const &; + // provides direct access to vertex data of specfied chunk + auto vertices( gfx::geometry_handle const &Geometry ) const -> gfx::vertex_array const &; + // provides direct access to vertex data of specfied chunk + auto userdata( gfx::geometry_handle const &Geometry ) const -> gfx::userdata_array const &; // sets target texture unit for the texture data stream auto units() -> gfx::stream_units & { return m_units; } // provides access to primitives count diff --git a/gl/vao.cpp b/gl/vao.cpp index 85735b5b..6d1e055d 100644 --- a/gl/vao.cpp +++ b/gl/vao.cpp @@ -66,7 +66,7 @@ void gl::vao::bind() glEnableVertexAttribArray(param.attrib); } - for (size_t i = params.size(); i < 4; i++) + for (size_t i = params.size(); i < 5; i++) glDisableVertexAttribArray(i); if (ebo) diff --git a/keyboardinput.cpp b/keyboardinput.cpp index 0b74c9fa..6fcdede8 100644 --- a/keyboardinput.cpp +++ b/keyboardinput.cpp @@ -122,6 +122,7 @@ bool keyboard_input::recall_bindings() { cParser bindingparser( "eu07_input-keyboard.ini", cParser::buffer_FILE ); + bindingparser.skipComments = false; if( false == bindingparser.ok() ) { return false; } @@ -147,6 +148,7 @@ keyboard_input::recall_bindings() { std::string bindingentry; bindingparser >> bindingentry; cParser entryparser( bindingentry ); + entryparser.skipComments = false; if( true == entryparser.getTokens( 1, true, "\n\r\t " ) ) { std::string commandname; @@ -158,32 +160,47 @@ keyboard_input::recall_bindings() { WriteLog( "Keyboard binding defined for unknown command, \"" + commandname + "\"" ); } else { - int binding{ 0 }; + int keycode = 0; + std::string description = ""; + bool descriptionStarted = false; while( entryparser.getTokens( 1, true, "\n\r\t " ) ) { std::string bindingkeyname; entryparser >> bindingkeyname; - if( bindingkeyname == "shift" ) { binding |= keymodifier::shift; } - else if( bindingkeyname == "ctrl" ) { binding |= keymodifier::control; } - else if( bindingkeyname == "none" ) { binding = 0; } - else { - // regular key, convert it to glfw key code - auto const keylookup = nametokeymap.find( bindingkeyname ); - if( keylookup == nametokeymap.end() ) { - - WriteLog( "Keyboard binding included unrecognized key, \"" + bindingkeyname + "\"" ); + // Parse command description, starting with "//". + // TODO: At some point, rewind this and add translation keys instead for multilingual support. + // This can't be done now as by default this would destroy all command descriptions, + // which are used by Starter. + // Do this when szczawik's Starter becomes deprecated or implements command descriptions in some other way. + if (descriptionStarted) { + if (description.size() > 0) { + description += " "; } + description += bindingkeyname; + } else if (bindingkeyname == "//") { + descriptionStarted = true; + } else { + if( bindingkeyname == "shift" ) { keycode |= keymodifier::shift; } + else if( bindingkeyname == "ctrl" ) { keycode |= keymodifier::control; } + else if( bindingkeyname == "none" ) { keycode = 0; } else { - // replace any existing binding, preserve modifiers - // (protection from cases where there's more than one key listed in the entry) - binding = keylookup->second | ( binding & 0xffff0000 ); + // regular key, convert it to glfw key code + auto const keylookup = nametokeymap.find( bindingkeyname ); + if( keylookup == nametokeymap.end() ) { + + WriteLog( "Keyboard binding included unrecognized key, \"" + bindingkeyname + "\"" ); + } + else { + // replace any existing binding, preserve modifiers + // (protection from cases where there's more than one key listed in the entry) + keycode = keylookup->second | ( keycode & 0xffff0000 ); + } } } - if( ( binding & 0xffff ) != 0 ) { - m_bindingsetups.insert_or_assign(lookup->second, binding); - } + std::tuple binding{keycode, description}; + m_bindingsetups.insert_or_assign(lookup->second, binding); } } } @@ -202,20 +219,25 @@ void keyboard_input::dump_bindings() return; } - for (const std::pair &binding : m_bindingsetups) { + for (const std::pair> &binding : m_bindingsetups) { stream << simulation::Commands_descriptions[static_cast(binding.first)].name << ' '; - auto it = keytonamemap.find(binding.second & 0xFFFF); + int keycode = std::get(binding.second); + auto it = keytonamemap.find(keycode & 0xFFFF); if (it != keytonamemap.end()) { - if (binding.second & keymodifier::control) + if (keycode & keymodifier::control) stream << "ctrl "; - if (binding.second & keymodifier::shift) + if (keycode & keymodifier::shift) stream << "shift "; - stream << it->second << "\r\n"; + stream << it->second; } else { - stream << "none\r\n"; + stream << "none"; } + + std::string description = std::get(binding.second); + if (description.size() > 0) + stream << " // " << description << "\r\n"; } } @@ -295,7 +317,7 @@ keyboard_input::bind() { for( auto const &bindingsetup : m_bindingsetups ) { - m_bindings[ bindingsetup.second ] = bindingsetup.first; + m_bindings[ std::get(bindingsetup.second) ] = bindingsetup.first; } // cache movement key bindings diff --git a/keyboardinput.h b/keyboardinput.h index 0fc92d80..efb4921f 100644 --- a/keyboardinput.h +++ b/keyboardinput.h @@ -31,7 +31,7 @@ class keyboard_input { public: // types - using bindingsetup_sequence = std::map; + using bindingsetup_sequence = std::map>; enum keymodifier : int { diff --git a/launcher/keymapper.cpp b/launcher/keymapper.cpp index b952e739..e3209e1c 100644 --- a/launcher/keymapper.cpp +++ b/launcher/keymapper.cpp @@ -21,8 +21,15 @@ bool ui::keymapper_panel::key(int key) key |= keyboard_input::keymodifier::shift; if (Global.ctrlState) key |= keyboard_input::keymodifier::control; + // F10 unbinds the key. + if (it->second.compare("f10") == 0) + key = 0; - keyboard.bindings().insert_or_assign(bind_active, key); + // Replace the binding with a new key. + auto it2 = keyboard.bindings().find(bind_active); + if (it2 != keyboard.bindings().end()) { + it2->second = std::tuple(key, std::get(it2->second)); + } bind_active = user_command::none; keyboard.bind(); @@ -45,18 +52,26 @@ void ui::keymapper_panel::render() if (ImGui::Button(STR_C("Save"))) keyboard.dump_bindings(); - for (const std::pair &binding : keyboard.bindings()) { + for (const std::pair> &binding : keyboard.bindings()) { + // Binding ID ImGui::AlignTextToFramePadding(); ImGui::Text(simulation::Commands_descriptions[static_cast(binding.first)].name.c_str()); + // Binding description + std::string description = std::get(binding.second); + ImGui::SameLine(260); + ImGui::Text((description.size() > 0 ? description : "(No description)").c_str()); + + // Binding key button + int keycode = std::get(binding.second); std::string label; - if (binding.second & keyboard_input::keymodifier::control) + if (keycode & keyboard_input::keymodifier::control) label += "ctrl + "; - if (binding.second & keyboard_input::keymodifier::shift) + if (keycode & keyboard_input::keymodifier::shift) label += "shift + "; - auto it = keyboard.keytonamemap.find(binding.second & 0xFFFF); + auto it = keyboard.keytonamemap.find(keycode & 0xFFFF); if (it != keyboard.keytonamemap.end()) label += it->second; @@ -64,7 +79,7 @@ void ui::keymapper_panel::render() bool styles_pushed = false; if (bind_active == binding.first) { - label = "?"; + label = "Press key (F10 to unbind)"; ImVec4 active_col = ImGui::GetStyleColorVec4(ImGuiCol_ButtonActive); ImGui::PushStyleColor(ImGuiCol_Button, active_col); styles_pushed = true; diff --git a/launcher/textures_scanner.cpp b/launcher/textures_scanner.cpp index 6d575244..1a511774 100644 --- a/launcher/textures_scanner.cpp +++ b/launcher/textures_scanner.cpp @@ -95,7 +95,7 @@ void ui::vehicles_bank::parse_category_entry(const std::string ¶m) std::string mini; std::getline(stream, mini, ','); - category_icons.emplace(ctx_type, "textures/mini/" + ToLower(mini)); + category_icons.emplace(ctx_type, "textures/mini/" + ToLower(mini) + ".bmp"); } void ui::vehicles_bank::parse_controllable_entry(const std::string &target, const std::string ¶m) @@ -122,12 +122,12 @@ void ui::vehicles_bank::parse_texture_info(const std::string &target, const std: set.meta = meta; if (!mini.empty()) - group_icons.emplace(mini, std::move(deferred_image("textures/mini/" + ToLower(mini)))); + group_icons.emplace(mini, std::move(deferred_image("textures/mini/" + ToLower(mini) + ".bmp"))); if (!miniplus.empty()) - set.mini = std::move(deferred_image("textures/mini/" + ToLower(miniplus))); + set.mini = std::move(deferred_image("textures/mini/" + ToLower(miniplus) + ".bmp")); else if (!mini.empty()) - set.mini = std::move(deferred_image("textures/mini/" + ToLower(mini))); + set.mini = std::move(deferred_image("textures/mini/" + ToLower(mini) + ".bmp")); set.skin = ToLower(target); erase_extension(set.skin); diff --git a/launcher/vehicle_picker.h b/launcher/vehicle_picker.h index 8ff2c80d..ed850d11 100644 --- a/launcher/vehicle_picker.h +++ b/launcher/vehicle_picker.h @@ -19,7 +19,7 @@ private: std::shared_ptr selected_vehicle; const std::string *selected_group = nullptr; const skin_set *selected_skinset = nullptr; - bool display_by_groups = false; + bool display_by_groups = true; deferred_image placeholder_mini; std::array search_query = { 0 }; diff --git a/nullrenderer.h b/nullrenderer.h index e21df61c..e67cdc59 100644 --- a/nullrenderer.h +++ b/nullrenderer.h @@ -66,28 +66,25 @@ public: gfx::geometrybank_handle Create_Bank() override { return m_geometry.register_bank(std::make_unique()); } // creates a new indexed geometry chunk of specified type from supplied data, in specified bank. returns: handle to the chunk or NULL - gfx::geometry_handle - Insert( gfx::index_array &Indices, gfx::vertex_array &Vertices, gfx::geometrybank_handle const &Geometry, int const Type ) override { return m_geometry.create_chunk( Indices, Vertices, Geometry, Type ); } + gfx::geometry_handle Insert(gfx::index_array &Indices, gfx::vertex_array &Vertices, gfx::userdata_array &Userdata, gfx::geometrybank_handle const &Geometry, int const Type) override { + return m_geometry.create_chunk( Indices, Vertices, Userdata, Geometry, Type ); } // creates a new geometry chunk of specified type from supplied data, in specified bank. returns: handle to the chunk or NULL - gfx::geometry_handle - Insert( gfx::vertex_array &Vertices, gfx::geometrybank_handle const &Geometry, int const Type ) override { + gfx::geometry_handle Insert(gfx::vertex_array &Vertices, gfx::userdata_array &Userdata, gfx::geometrybank_handle const &Geometry, int const Type) override { gfx::calculate_tangents(Vertices, gfx::index_array(), Type); - return m_geometry.create_chunk(Vertices, Geometry, Type); + return m_geometry.create_chunk(Vertices, Userdata, Geometry, Type); } // replaces data of specified chunk with the supplied vertex data, starting from specified offset - bool - Replace( gfx::vertex_array &Vertices, gfx::geometry_handle const &Geometry, int const Type, std::size_t const Offset = 0 ) override { + bool Replace(gfx::vertex_array &Vertices, gfx::userdata_array &Userdata, gfx::geometry_handle const &Geometry, int const Type, const std::size_t Offset = 0) override { gfx::calculate_tangents(Vertices, gfx::index_array(), Type); - return m_geometry.replace(Vertices, Geometry, Offset); + return m_geometry.replace(Vertices, Userdata, Geometry, Offset); } // adds supplied vertex data at the end of specified chunk - bool - Append( gfx::vertex_array &Vertices, gfx::geometry_handle const &Geometry, int const Type ) override { + bool Append(gfx::vertex_array &Vertices, gfx::userdata_array &Userdata, gfx::geometry_handle const &Geometry, int const Type) override { gfx::calculate_tangents(Vertices, gfx::index_array(), Type); - return m_geometry.append(Vertices, Geometry); + return m_geometry.append(Vertices, Userdata, Geometry); } // provides direct access to index data of specfied chunk gfx::index_array const & @@ -95,6 +92,9 @@ public: // provides direct access to vertex data of specfied chunk gfx::vertex_array const & Vertices( gfx::geometry_handle const &Geometry ) const override { return m_geometry.vertices(Geometry); } + // provides direct access to vertex data of specfied chunk + gfx::userdata_array const & + UserData( gfx::geometry_handle const &Geometry ) const override { return m_geometry.userdata(Geometry); } // material methods material_handle Fetch_Material( std::string const &Filename, bool const Loadnow = true ) override { diff --git a/opengl33geometrybank.cpp b/opengl33geometrybank.cpp index 62ff4f47..63f0ef8c 100644 --- a/opengl33geometrybank.cpp +++ b/opengl33geometrybank.cpp @@ -53,6 +53,7 @@ void opengl33_vaogeometrybank::setup_buffer() vertexcount{ 0 }, indexcount{ 0 }; auto chunkiterator = m_chunks.cbegin(); + bool has_userdata{ false }; for( auto &chunkrecord : m_chunkrecords ) { // fill records for all chunks, based on the chunk data chunkrecord.is_good = false; // if we're re-creating buffer, chunks might've been uploaded in the old one @@ -61,7 +62,9 @@ void opengl33_vaogeometrybank::setup_buffer() vertexcount += chunkrecord.vertex_count; chunkrecord.index_offset = indexcount; chunkrecord.index_count = chunkiterator->indices.size(); + chunkrecord.has_userdata = !chunkiterator->userdata.empty(); indexcount += chunkrecord.index_count; + has_userdata |= chunkrecord.has_userdata; ++chunkiterator; } // the odds for all created chunks to get replaced with empty ones are quite low, but the possibility does exist @@ -89,25 +92,33 @@ void opengl33_vaogeometrybank::setup_buffer() m_vertexbuffer.emplace(); // NOTE: we're using static_draw since it's generally true for all we have implemented at the moment // TODO: allow to specify usage hint at the object creation, and pass it here - m_vertexbuffer->allocate( gl::buffer::ARRAY_BUFFER, vertexcount * sizeof( gfx::basic_vertex ), GL_STATIC_DRAW ); + const int vertex_size = has_userdata ? sizeof( gfx::basic_vertex ) + sizeof(gfx::vertex_userdata) : sizeof(gfx::basic_vertex); + m_vertexbuffer->allocate( gl::buffer::ARRAY_BUFFER, static_cast(vertexcount * vertex_size), GL_STATIC_DRAW ); if( ::glGetError() == GL_OUT_OF_MEMORY ) { ErrorLog( "openGL error: out of memory; failed to create a geometry buffer" ); throw std::bad_alloc(); } + m_vertex_count = static_cast(vertexcount); setup_attrib(); + if(has_userdata) + setup_userdata(); } void opengl33_vaogeometrybank::setup_attrib(size_t offset) { - m_vao->setup_attrib( *m_vertexbuffer, 0, 3, GL_FLOAT, sizeof( basic_vertex ), 0 * sizeof( float ) + offset * sizeof( basic_vertex ) ); + m_vao->setup_attrib( *m_vertexbuffer, 0, 3, GL_FLOAT, sizeof( basic_vertex ), offsetof(basic_vertex, position) + offset * sizeof( basic_vertex ) ); // NOTE: normal and color streams share the data - m_vao->setup_attrib( *m_vertexbuffer, 1, 3, GL_FLOAT, sizeof( basic_vertex ), 3 * sizeof( float ) + offset * sizeof( basic_vertex ) ); - m_vao->setup_attrib( *m_vertexbuffer, 2, 2, GL_FLOAT, sizeof( basic_vertex ), 6 * sizeof( float ) + offset * sizeof( basic_vertex ) ); - m_vao->setup_attrib( *m_vertexbuffer, 3, 4, GL_FLOAT, sizeof( basic_vertex ), 8 * sizeof( float ) + offset * sizeof( basic_vertex ) ); + m_vao->setup_attrib( *m_vertexbuffer, 1, 3, GL_FLOAT, sizeof( basic_vertex ), offsetof(basic_vertex, normal) + offset * sizeof( basic_vertex ) ); + m_vao->setup_attrib( *m_vertexbuffer, 2, 2, GL_FLOAT, sizeof( basic_vertex ), offsetof(basic_vertex, texture) + offset * sizeof( basic_vertex ) ); + m_vao->setup_attrib( *m_vertexbuffer, 3, 4, GL_FLOAT, sizeof( basic_vertex ), offsetof(basic_vertex, tangent) + offset * sizeof( basic_vertex ) ); } +void opengl33_vaogeometrybank::setup_userdata(size_t offset) { + const size_t offset_evaluated = m_vertex_count * sizeof(basic_vertex) + offset * sizeof( vertex_userdata ); + m_vao->setup_attrib( *m_vertexbuffer, 4, 4, GL_FLOAT, sizeof( vertex_userdata ), offsetof(vertex_userdata, data) + offset_evaluated );} + // draw() subclass details // NOTE: units and stream parameters are unused, but they're part of (legacy) interface // TBD: specialized bank/manager pair without the cruft? @@ -122,14 +133,18 @@ opengl33_vaogeometrybank::draw_( gfx::geometry_handle const &Geometry, gfx::stre return 0; auto const &chunk = gfx::geometry_bank::chunk( Geometry ); - if( false == chunkrecord.is_good ) { + if( !chunkrecord.is_good ) { m_vao->bind(); // we may potentially need to upload new buffer data before we can draw it if( chunkrecord.index_count > 0 ) { m_indexbuffer->upload( gl::buffer::ELEMENT_ARRAY_BUFFER, chunk.indices.data(), chunkrecord.index_offset * sizeof( gfx::basic_index ), chunkrecord.index_count * sizeof( gfx::basic_index ) ); } m_vertexbuffer->upload( gl::buffer::ARRAY_BUFFER, chunk.vertices.data(), chunkrecord.vertex_offset * sizeof( gfx::basic_vertex ), chunkrecord.vertex_count * sizeof( gfx::basic_vertex ) ); - chunkrecord.is_good = true; + if(chunkrecord.has_userdata) + m_vertexbuffer->upload(gl::buffer::ARRAY_BUFFER, chunk.userdata.data(), + static_cast(m_vertex_count * sizeof(gfx::basic_vertex) + chunkrecord.vertex_offset * sizeof(gfx::vertex_userdata)), + static_cast(chunkrecord.vertex_count * sizeof(gfx::vertex_userdata))); + chunkrecord.is_good = true; } // render if( chunkrecord.index_count > 0 ) { diff --git a/opengl33geometrybank.h b/opengl33geometrybank.h index 809479a6..f6f8af0a 100644 --- a/opengl33geometrybank.h +++ b/opengl33geometrybank.h @@ -37,6 +37,7 @@ private: std::size_t vertex_count{ 0 }; // size of the chunk in the last established buffer std::size_t index_offset{ 0 }; std::size_t index_count{ 0 }; + bool has_userdata{ false }; bool is_good{ false }; // true if local content of the chunk matches the data on the opengl end }; @@ -59,6 +60,8 @@ private: setup_buffer(); void setup_attrib(size_t offset = 0); + void + setup_userdata(size_t offset = 0); void delete_buffer(); @@ -67,6 +70,7 @@ private: std::optional m_indexbuffer; // index buffer data on the opengl end std::optional m_vao; chunkrecord_sequence m_chunkrecords; // helper data for all stored geometry chunks, in matching order + int m_vertex_count; }; } // namespace gfx diff --git a/opengl33renderer.cpp b/opengl33renderer.cpp index f3816cee..c6449881 100644 --- a/opengl33renderer.cpp +++ b/opengl33renderer.cpp @@ -113,7 +113,8 @@ bool opengl33_renderer::Init(GLFWwindow *Window) gfx::vertex_array billboard_array{ {{-size, size, 0.f}, glm::vec3(), {1.f, 1.f}}, {{size, size, 0.f}, glm::vec3(), {0.f, 1.f}}, {{-size, -size, 0.f}, glm::vec3(), {1.f, 0.f}}, {{size, -size, 0.f}, glm::vec3(), {0.f, 0.f}}}; - m_billboardgeometry = m_geometry.create_chunk(billboard_array, geometrybank, GL_TRIANGLE_STRIP); + gfx::userdata_array userdata{}; + m_billboardgeometry = m_geometry.create_chunk(billboard_array, userdata, geometrybank, GL_TRIANGLE_STRIP); m_empty_vao = std::make_unique(); try @@ -1967,34 +1968,34 @@ gfx::geometrybank_handle opengl33_renderer::Create_Bank() } // creates a new indexed geometry chunk of specified type from supplied data, in specified bank. returns: handle to the chunk or NULL -gfx::geometry_handle opengl33_renderer::Insert( gfx::index_array &Indices, gfx::vertex_array &Vertices, gfx::geometrybank_handle const &Geometry, int const Type ) +gfx::geometry_handle opengl33_renderer::Insert(gfx::index_array &Indices, gfx::vertex_array &Vertices, gfx::userdata_array &Userdata, gfx::geometrybank_handle const &Geometry, int const Type) { // NOTE: we expect indexed geometry to come with calculated tangents - return m_geometry.create_chunk( Indices, Vertices, Geometry, Type ); + return m_geometry.create_chunk( Indices, Vertices, Userdata, Geometry, Type ); } // creates a new geometry chunk of specified type from supplied data, in specified bank. returns: handle to the chunk or NULL -gfx::geometry_handle opengl33_renderer::Insert(gfx::vertex_array &Vertices, gfx::geometrybank_handle const &Geometry, int const Type) +gfx::geometry_handle opengl33_renderer::Insert(gfx::vertex_array &Vertices, gfx::userdata_array &Userdata, gfx::geometrybank_handle const &Geometry, int const Type) { gfx::calculate_tangents(Vertices, gfx::index_array(), Type); - return m_geometry.create_chunk(Vertices, Geometry, Type); + return m_geometry.create_chunk(Vertices, Userdata, Geometry, Type); } // replaces data of specified chunk with the supplied vertex data, starting from specified offset -bool opengl33_renderer::Replace(gfx::vertex_array &Vertices, gfx::geometry_handle const &Geometry, int const Type, std::size_t const Offset) +bool opengl33_renderer::Replace(gfx::vertex_array &Vertices, gfx::userdata_array &Userdata, gfx::geometry_handle const &Geometry, int const Type, const std::size_t Offset) { gfx::calculate_tangents(Vertices, gfx::index_array(), Type); - return m_geometry.replace(Vertices, Geometry, Offset); + return m_geometry.replace(Vertices, Userdata, Geometry, Offset); } // adds supplied vertex data at the end of specified chunk -bool opengl33_renderer::Append(gfx::vertex_array &Vertices, gfx::geometry_handle const &Geometry, int const Type) +bool opengl33_renderer::Append(gfx::vertex_array &Vertices, gfx::userdata_array &Userdata, gfx::geometry_handle const &Geometry, int const Type) { gfx::calculate_tangents(Vertices, gfx::index_array(), Type); - return m_geometry.append(Vertices, Geometry); + return m_geometry.append(Vertices, Userdata, Geometry); } // provides direct access to index data of specfied chunk @@ -2009,6 +2010,11 @@ gfx::vertex_array const &opengl33_renderer::Vertices(gfx::geometry_handle const return m_geometry.vertices(Geometry); } +gfx::userdata_array const &opengl33_renderer::UserData(const gfx::geometry_handle &Geometry) const +{ + return m_geometry.userdata(Geometry); +} + // material methods material_handle opengl33_renderer::Fetch_Material(std::string const &Filename, bool const Loadnow) { @@ -4850,7 +4856,7 @@ bool opengl33_renderer::opengl33_imgui_renderer::Init() return ImGui_ImplOpenGL3_Init("#version 330 core"); } -void opengl33_renderer::opengl33_imgui_renderer::Shutdown() +void opengl33_renderer::opengl33_imgui_renderer::Shutdown() { ImGui_ImplOpenGL3_Shutdown(); } @@ -4865,3 +4871,4 @@ void opengl33_renderer::opengl33_imgui_renderer::Render() gl::buffer::unbind(gl::buffer::ARRAY_BUFFER); ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); } + diff --git a/opengl33renderer.h b/opengl33renderer.h index b8d885bb..021bef78 100644 --- a/opengl33renderer.h +++ b/opengl33renderer.h @@ -58,23 +58,22 @@ class opengl33_renderer : public gfx_renderer { gfx::geometrybank_handle Create_Bank() override; // creates a new indexed geometry chunk of specified type from supplied data, in specified bank. returns: handle to the chunk or NULL - gfx::geometry_handle - Insert( gfx::index_array &Indices, gfx::vertex_array &Vertices, gfx::geometrybank_handle const &Geometry, int const Type ) override; + gfx::geometry_handle Insert(gfx::index_array &Indices, gfx::vertex_array &Vertices, gfx::userdata_array &Userdata, gfx::geometrybank_handle const &Geometry, int const Type) override; // creates a new geometry chunk of specified type from supplied data, in specified bank. returns: handle to the chunk or NULL - gfx::geometry_handle - Insert( gfx::vertex_array &Vertices, gfx::geometrybank_handle const &Geometry, int const Type ) override; + gfx::geometry_handle Insert(gfx::vertex_array &Vertices, gfx::userdata_array &Userdata, gfx::geometrybank_handle const &Geometry, int const Type) override; // replaces data of specified chunk with the supplied vertex data, starting from specified offset - bool - Replace( gfx::vertex_array &Vertices, gfx::geometry_handle const &Geometry, int const Type, std::size_t const Offset = 0 ) override; + bool Replace(gfx::vertex_array &Vertices, gfx::userdata_array &Userdata, gfx::geometry_handle const &Geometry, int const Type, const std::size_t Offset = 0) override; // adds supplied vertex data at the end of specified chunk - bool - Append( gfx::vertex_array &Vertices, gfx::geometry_handle const &Geometry, int const Type ) override; + bool Append(gfx::vertex_array &Vertices, gfx::userdata_array &Userdata, gfx::geometry_handle const &Geometry, int const Type) override; // provides direct access to index data of specfied chunk gfx::index_array const & Indices( gfx::geometry_handle const &Geometry ) const override; // provides direct access to vertex data of specfied chunk gfx::vertex_array const & Vertices( gfx::geometry_handle const &Geometry ) const override; + // provides direct access to vertex data of specfied chunk + gfx::userdata_array const & + UserData( gfx::geometry_handle const &Geometry ) const override; // material methods material_handle Fetch_Material( std::string const &Filename, bool const Loadnow = true ) override; diff --git a/openglgeometrybank.cpp b/openglgeometrybank.cpp index 961b2716..43aeb0f3 100644 --- a/openglgeometrybank.cpp +++ b/openglgeometrybank.cpp @@ -227,7 +227,7 @@ void opengl_vbogeometrybank::bind_streams( gfx::stream_units const &Units, unsigned int const Streams, size_t offset ) { if( Streams & gfx::stream::position ) { - ::glVertexPointer( 3, GL_FLOAT, sizeof( gfx::basic_vertex ), reinterpret_cast( sizeof( gfx::basic_vertex ) * offset ) ); + ::glVertexPointer( 3, GL_FLOAT, sizeof( gfx::basic_vertex ), reinterpret_cast( offsetof(gfx::basic_vertex, position) + sizeof( gfx::basic_vertex ) * offset ) ); ::glEnableClientState( GL_VERTEX_ARRAY ); } else { @@ -235,14 +235,14 @@ opengl_vbogeometrybank::bind_streams( gfx::stream_units const &Units, unsigned i } // NOTE: normal and color streams share the data, making them effectively mutually exclusive if( Streams & gfx::stream::normal ) { - ::glNormalPointer( GL_FLOAT, sizeof( gfx::basic_vertex ), reinterpret_cast( 12 + sizeof( gfx::basic_vertex ) * offset ) ); + ::glNormalPointer( GL_FLOAT, sizeof( gfx::basic_vertex ), reinterpret_cast( offsetof(gfx::basic_vertex, normal) + sizeof( gfx::basic_vertex ) * offset ) ); ::glEnableClientState( GL_NORMAL_ARRAY ); } else { ::glDisableClientState( GL_NORMAL_ARRAY ); } if( Streams & gfx::stream::color ) { - ::glColorPointer( 3, GL_FLOAT, sizeof( gfx::basic_vertex ), reinterpret_cast( 12 + sizeof( gfx::basic_vertex ) * offset ) ); + ::glColorPointer( 3, GL_FLOAT, sizeof( gfx::basic_vertex ), reinterpret_cast( offsetof(gfx::basic_vertex, normal) + sizeof( gfx::basic_vertex ) * offset ) ); ::glEnableClientState( GL_COLOR_ARRAY ); } else { @@ -251,7 +251,7 @@ opengl_vbogeometrybank::bind_streams( gfx::stream_units const &Units, unsigned i if( Streams & gfx::stream::texture ) { for( auto unit : Units.texture ) { ::glClientActiveTexture( GL_TEXTURE0 + unit ); - ::glTexCoordPointer( 2, GL_FLOAT, sizeof( gfx::basic_vertex ), reinterpret_cast( 24 + sizeof( gfx::basic_vertex ) * offset ) ); + ::glTexCoordPointer( 2, GL_FLOAT, sizeof( gfx::basic_vertex ), reinterpret_cast( offsetof(gfx::basic_vertex, texture) + sizeof( gfx::basic_vertex ) * offset ) ); ::glEnableClientState( GL_TEXTURE_COORD_ARRAY ); } m_activetexturearrays = Units.texture; diff --git a/openglrenderer.cpp b/openglrenderer.cpp index 704f5653..4c35946d 100644 --- a/openglrenderer.cpp +++ b/openglrenderer.cpp @@ -308,7 +308,8 @@ opengl_renderer::Init( GLFWwindow *Window ) { { { size, size, 0.f }, glm::vec3(), { 0.f, 1.f } }, { { -size, -size, 0.f }, glm::vec3(), { 1.f, 0.f } }, { { size, -size, 0.f }, glm::vec3(), { 0.f, 0.f } } }; - m_billboardgeometry = m_geometry.create_chunk(billboard_array, geometrybank, GL_TRIANGLE_STRIP); + gfx::userdata_array userdata{}; + m_billboardgeometry = m_geometry.create_chunk(billboard_array, userdata, geometrybank, GL_TRIANGLE_STRIP); // prepare debug mode objects //m_quadric = ::gluNewQuadric(); //::gluQuadricNormals( m_quadric, GLU_FLAT ); @@ -1691,31 +1692,31 @@ opengl_renderer::Create_Bank() { } // creates a new indexed geometry chunk of specified type from supplied data, in specified bank. returns: handle to the chunk or NULL -gfx::geometry_handle -opengl_renderer::Insert( gfx::index_array &Indices, gfx::vertex_array &Vertices, gfx::geometrybank_handle const &Geometry, int const Type ) { +gfx::geometry_handle opengl_renderer::Insert(gfx::index_array &Indices, gfx::vertex_array &Vertices, gfx::userdata_array &Userdata, gfx::geometrybank_handle const &Geometry, int const Type) +{ - return m_geometry.create_chunk( Indices, Vertices, Geometry, Type ); + return m_geometry.create_chunk( Indices, Vertices, Userdata, Geometry, Type ); } // creates a new geometry chunk of specified type from supplied data, in specified bank. returns: handle to the chunk or NULL -gfx::geometry_handle -opengl_renderer::Insert( gfx::vertex_array &Vertices, gfx::geometrybank_handle const &Geometry, int const Type ) { +gfx::geometry_handle opengl_renderer::Insert(gfx::vertex_array &Vertices, gfx::userdata_array &Userdata, gfx::geometrybank_handle const &Geometry, int const Type) +{ - return m_geometry.create_chunk( Vertices, Geometry, Type ); + return m_geometry.create_chunk( Vertices, Userdata, Geometry, Type ); } // replaces data of specified chunk with the supplied vertex data, starting from specified offset -bool -opengl_renderer::Replace( gfx::vertex_array &Vertices, gfx::geometry_handle const &Geometry, int const Type, std::size_t const Offset ) { +bool opengl_renderer::Replace(gfx::vertex_array &Vertices, gfx::userdata_array &Userdata, gfx::geometry_handle const &Geometry, int const Type, const std::size_t Offset) +{ - return m_geometry.replace( Vertices, Geometry, Offset ); + return m_geometry.replace( Vertices, Userdata, Geometry, Offset ); } // adds supplied vertex data at the end of specified chunk -bool -opengl_renderer::Append( gfx::vertex_array &Vertices, gfx::geometry_handle const &Geometry, int const Type ) { +bool opengl_renderer::Append(gfx::vertex_array &Vertices, gfx::userdata_array &Userdata, gfx::geometry_handle const &Geometry, int const Type) +{ - return m_geometry.append( Vertices, Geometry ); + return m_geometry.append( Vertices, Userdata, Geometry ); } // provides direct access to vertex data of specfied chunk @@ -1732,6 +1733,11 @@ opengl_renderer::Vertices( gfx::geometry_handle const &Geometry ) const { return m_geometry.vertices( Geometry ); } +gfx::userdata_array const &opengl_renderer::UserData(const gfx::geometry_handle &Geometry) const +{ + return m_geometry.userdata( Geometry ); +} + // material methods material_handle opengl_renderer::Fetch_Material( std::string const &Filename, bool const Loadnow ) { @@ -4524,7 +4530,7 @@ bool opengl_renderer::opengl_imgui_renderer::Init() return ImGui_ImplOpenGL2_Init(); } -void opengl_renderer::opengl_imgui_renderer::Shutdown() +void opengl_renderer::opengl_imgui_renderer::Shutdown() { ImGui_ImplOpenGL2_Shutdown(); } @@ -4539,3 +4545,4 @@ void opengl_renderer::opengl_imgui_renderer::Render() gl::buffer::unbind(gl::buffer::ARRAY_BUFFER); ImGui_ImplOpenGL2_RenderDrawData(ImGui::GetDrawData()); } + diff --git a/openglrenderer.h b/openglrenderer.h index 5a3a1493..a055da12 100644 --- a/openglrenderer.h +++ b/openglrenderer.h @@ -58,23 +58,22 @@ public: gfx::geometrybank_handle Create_Bank() override; // creates a new indexed geometry chunk of specified type from supplied data, in specified bank. returns: handle to the chunk or NULL - gfx::geometry_handle - Insert( gfx::index_array &Indices, gfx::vertex_array &Vertices, gfx::geometrybank_handle const &Geometry, int const Type ) override; + gfx::geometry_handle Insert(gfx::index_array &Indices, gfx::vertex_array &Vertices, gfx::userdata_array &Userdata, gfx::geometrybank_handle const &Geometry, int const Type) override; // creates a new geometry chunk of specified type from supplied data, in specified bank. returns: handle to the chunk or NULL - gfx::geometry_handle - Insert( gfx::vertex_array &Vertices, gfx::geometrybank_handle const &Geometry, int const Type ) override; + gfx::geometry_handle Insert(gfx::vertex_array &Vertices, gfx::userdata_array &Userdata, gfx::geometrybank_handle const &Geometry, int const Type) override; // replaces data of specified chunk with the supplied vertex data, starting from specified offset - bool - Replace( gfx::vertex_array &Vertices, gfx::geometry_handle const &Geometry, int const Type, std::size_t const Offset = 0 ) override; + bool Replace(gfx::vertex_array &Vertices, gfx::userdata_array &Userdata, gfx::geometry_handle const &Geometry, int const Type, const std::size_t Offset = 0) override; // adds supplied vertex data at the end of specified chunk - bool - Append( gfx::vertex_array &Vertices, gfx::geometry_handle const &Geometry, int const Type ) override; + bool Append(gfx::vertex_array &Vertices, gfx::userdata_array &Userdata, gfx::geometry_handle const &Geometry, int const Type) override; // provides direct access to index data of specfied chunk gfx::index_array const & Indices( gfx::geometry_handle const &Geometry ) const override; // provides direct access to vertex data of specfied chunk gfx::vertex_array const & Vertices( gfx::geometry_handle const &Geometry ) const override; + // provides direct access to vertex data of specfied chunk + gfx::userdata_array const & + UserData( gfx::geometry_handle const &Geometry ) const override; // material methods material_handle Fetch_Material( std::string const &Filename, bool const Loadnow = true ) override; diff --git a/parser.cpp b/parser.cpp index 19acbfa1..8a3151a3 100644 --- a/parser.cpp +++ b/parser.cpp @@ -203,7 +203,7 @@ std::string cParser::readToken( bool ToLower, const char *Break ) { token += c; if( findQuotes( token ) ) // do glue together words enclosed in quotes continue; - if( trimComments( token ) ) // don't glue together words separated with comment + if( skipComments && trimComments( token ) ) // don't glue together words separated with comment break; } if( c == '\n' ) { diff --git a/parser.h b/parser.h index 57dae579..d9d96670 100644 --- a/parser.h +++ b/parser.h @@ -91,6 +91,8 @@ class cParser //: public std::stringstream // returns number of currently processed line in main file, -1 if inside include int LineMain() const; bool expandIncludes = true; + bool allowRandomIncludes = false; + bool skipComments = true; private: // methods: @@ -118,7 +120,6 @@ class cParser //: public std::stringstream std::shared_ptr mIncludeParser; // child class to handle include directives. std::vector parameters; // parameter list for included file. std::deque tokens; - bool allowRandomIncludes = false; }; diff --git a/renderer.h b/renderer.h index ba166254..e30ac645 100644 --- a/renderer.h +++ b/renderer.h @@ -41,17 +41,19 @@ public: // creates a new geometry bank. returns: handle to the bank or NULL virtual auto Create_Bank() -> gfx::geometrybank_handle = 0; // creates a new indexed geometry chunk of specified type from supplied data, in specified bank. returns: handle to the chunk or NULL - virtual auto Insert( gfx::index_array &Indices, gfx::vertex_array &Vertices, gfx::geometrybank_handle const &Geometry, int const Type ) -> gfx::geometry_handle = 0; + virtual auto Insert(gfx::index_array &Indices, gfx::vertex_array &Vertices, gfx::userdata_array &Userdata, gfx::geometrybank_handle const &Geometry, int const Type) -> gfx::geometry_handle = 0; // creates a new geometry chunk of specified type from supplied data, in specified bank. returns: handle to the chunk or NULL - virtual auto Insert( gfx::vertex_array &Vertices, gfx::geometrybank_handle const &Geometry, int const Type ) -> gfx::geometry_handle = 0; + virtual auto Insert(gfx::vertex_array &Vertices, gfx::userdata_array &Userdata, gfx::geometrybank_handle const &Geometry, int const Type) -> gfx::geometry_handle = 0; // replaces data of specified chunk with the supplied vertex data, starting from specified offset - virtual auto Replace( gfx::vertex_array &Vertices, gfx::geometry_handle const &Geometry, int const Type, std::size_t const Offset = 0 ) -> bool = 0; + virtual auto Replace(gfx::vertex_array &Vertices, gfx::userdata_array &Userdata, gfx::geometry_handle const &Geometry, int const Type, const std::size_t Offset = 0) -> bool = 0; // adds supplied vertex data at the end of specified chunk - virtual auto Append( gfx::vertex_array &Vertices, gfx::geometry_handle const &Geometry, int const Type ) -> bool = 0; + virtual auto Append(gfx::vertex_array &Vertices, gfx::userdata_array &Userdata, gfx::geometry_handle const &Geometry, int const Type) -> bool = 0; // provides direct access to index data of specfied chunk virtual auto Indices( gfx::geometry_handle const &Geometry ) const->gfx::index_array const & = 0; - // provides direct access to vertex data of specfied chunk - virtual auto Vertices( gfx::geometry_handle const &Geometry ) const ->gfx::vertex_array const & = 0; + // provides direct access to vertex data of specfied chunk + virtual auto Vertices( gfx::geometry_handle const &Geometry ) const ->gfx::vertex_array const & = 0; + // provides direct access to vertex user data of specfied chunk + virtual auto UserData( gfx::geometry_handle const &Geometry ) const ->gfx::userdata_array const & = 0; // material methods virtual auto Fetch_Material( std::string const &Filename, bool const Loadnow = true ) -> material_handle = 0; virtual void Bind_Material( material_handle const Material, TSubModel const *sm = nullptr, lighting_data const *lighting = nullptr ) = 0; diff --git a/scene.cpp b/scene.cpp index cb97e386..fc3efc4e 100644 --- a/scene.cpp +++ b/scene.cpp @@ -26,7 +26,7 @@ namespace scene { std::string const EU07_FILEEXTENSION_REGION { ".sbt" }; std::uint32_t const EU07_FILEHEADER { MAKE_ID4( 'E','U','0','7' ) }; -std::uint32_t const EU07_FILEVERSION_REGION { MAKE_ID4( 'S', 'B', 'T', 1 ) }; +std::uint32_t const EU07_FILEVERSION_REGION { MAKE_ID4( 'S', 'B', 'T', '2' ) }; // potentially activates event handler with the same name as provided node, and within handler activation range void @@ -962,10 +962,11 @@ basic_section::create_geometry() { void basic_section::create_map_geometry(const gfx::geometrybank_handle handle) { std::vector lines; + gfx::userdata_array userdata{}; for (auto &cell : m_cells) cell.create_map_geometry(lines, handle); - m_map_geometryhandle = GfxRenderer->Insert(lines, handle, GL_LINES); + m_map_geometryhandle = GfxRenderer->Insert(lines, userdata, handle, GL_LINES); } void basic_section::get_map_active_paths(map_colored_paths &handles) @@ -1727,15 +1728,16 @@ void basic_region::create_map_geometry() void basic_region::update_poi_geometry() { std::vector vertices; + gfx::userdata_array userdata; for (const auto sem : map::Objects.entries) vertices.push_back(std::move(sem->vertex())); if (!m_map_poipoints) { gfx::geometrybank_handle poibank = GfxRenderer->Create_Bank(); - m_map_poipoints = GfxRenderer->Insert(vertices, poibank, GL_POINTS); + m_map_poipoints = GfxRenderer->Insert(vertices, userdata, poibank, GL_POINTS); } else { - GfxRenderer->Replace(vertices, m_map_poipoints, GL_POINTS); + GfxRenderer->Replace(vertices, userdata, m_map_poipoints, GL_POINTS); } } diff --git a/scenenode.cpp b/scenenode.cpp index 266cd87b..df9e2b21 100644 --- a/scenenode.cpp +++ b/scenenode.cpp @@ -62,12 +62,14 @@ void shape_node::shapenode_data::serialize( std::ostream &Output ) const { // bounding area area.serialize( Output ); + bool has_userdata = !userdata.empty(); // visibility sn_utils::ls_float64( Output, rangesquared_min ); sn_utils::ls_float64( Output, rangesquared_max ); sn_utils::s_bool( Output, visible ); // material sn_utils::s_bool( Output, translucent ); + sn_utils::s_bool( Output, has_userdata ); // NOTE: material handle is created dynamically on load sn_utils::s_str( Output, @@ -80,12 +82,12 @@ shape_node::shapenode_data::serialize( std::ostream &Output ) const { // NOTE: geometry handle is created dynamically on load // vertex count, followed by vertex data sn_utils::ls_uint32( Output, vertices.size() ); - for( auto const &vertex : vertices ) { - gfx::basic_vertex( - glm::vec3{ vertex.position - origin }, - vertex.normal, - vertex.texture ) - .serialize( Output ); + for( int i = 0; i < vertices.size(); ++i ) { + gfx::basic_vertex::convert(vertices[i], origin) + .serialize( Output, false ); + if(has_userdata){ + userdata[i].serialize(Output); + } } } @@ -100,6 +102,7 @@ shape_node::shapenode_data::deserialize( std::istream &Input ) { visible = sn_utils::d_bool( Input ); // material translucent = sn_utils::d_bool( Input ); + bool has_userdata = sn_utils::d_bool( Input ); auto const materialname { sn_utils::d_str( Input ) }; if( false == materialname.empty() ) { material = GfxRenderer->Fetch_Material( materialname ); @@ -110,12 +113,14 @@ 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 ) ); + if(has_userdata) + userdata.resize(vertices.size()); gfx::basic_vertex localvertex; - for( auto &vertex : vertices ) { - localvertex.deserialize( Input ); - vertex.position = origin + glm::dvec3{ localvertex.position }; - vertex.normal = localvertex.normal; - vertex.texture = localvertex.texture; + for( int i = 0; i < vertices.size(); ++i ) { + localvertex.deserialize( Input, false ); + vertices[i] = localvertex.to_world(origin); + if(has_userdata) + userdata[i].deserialize( Input ); } } @@ -352,29 +357,53 @@ shape_node::convert( TSubModel const *Submodel ) { int vertexcount { 0 }; std::vector importedvertices; - world_vertex vertex, vertex1, vertex2; - for( auto const &sourcevertex : GfxRenderer->Vertices( Submodel->m_geometry.handle ) ) { - vertex.position = sourcevertex.position; - vertex.normal = sourcevertex.normal; - vertex.texture = sourcevertex.texture; - if( vertexcount == 0 ) { vertex1 = vertex; } - else if( vertexcount == 1 ) { vertex2 = vertex; } - else if( vertexcount >= 2 ) { - if( false == degenerate( vertex1.position, vertex2.position, vertex.position ) ) { - importedvertices.emplace_back( vertex1 ); - importedvertices.emplace_back( vertex2 ); - importedvertices.emplace_back( vertex ); - } - // start a new triangle - vertexcount = -1; - } - ++vertexcount; - } + gfx::userdata_array importeduserdata; + if(!GfxRenderer->Indices(Submodel->m_geometry.handle).empty()){ + const auto& vertices = GfxRenderer->Vertices(Submodel->m_geometry.handle); + const auto& userdatas = GfxRenderer->UserData(Submodel->m_geometry.handle); + bool has_userdata = !userdatas.empty(); + world_vertex vertex; + for(const auto index : GfxRenderer->Indices(Submodel->m_geometry.handle)){ + vertex = vertices[index].to_world(); + importedvertices.emplace_back(vertex); + if (has_userdata) + importeduserdata.emplace_back(userdatas[index]); + } + } + else{ + world_vertex vertex, vertex1, vertex2; + gfx::vertex_userdata userdata, userdata1, userdata2; + const auto& vertices = GfxRenderer->Vertices(Submodel->m_geometry.handle); + const auto& userdatas = GfxRenderer->UserData(Submodel->m_geometry.handle); + bool has_userdata = !userdatas.empty(); + for( int i = 0; i < vertices.size(); ++i ) { + vertex = vertices[i].to_world(); + if( has_userdata ) userdata = userdatas[i]; + if( vertexcount == 0 ) { vertex1 = vertex; userdata1 = userdata; } + else if( vertexcount == 1 ) { vertex2 = vertex; userdata2 = userdata; } + else if( vertexcount >= 2 ) { + if( !degenerate( vertex1.position, vertex2.position, vertex.position ) ) { + importedvertices.emplace_back( vertex1 ); + importedvertices.emplace_back( vertex2 ); + importedvertices.emplace_back( vertex ); + if( has_userdata ) { + importeduserdata.emplace_back( userdata1 ); + importeduserdata.emplace_back( userdata2 ); + importeduserdata.emplace_back( userdata ); + } + } + // start a new triangle + vertexcount = -1; + } + ++vertexcount; + } + } if( true == importedvertices.empty() ) { return *this; } // assign imported geometry to the node... m_data.vertices.swap( importedvertices ); + m_data.userdata.swap( importeduserdata ); // ...and calculate center... for( auto const &vertex : m_data.vertices ) { m_data.area.center += vertex.position; @@ -423,12 +452,9 @@ shape_node::create_geometry( gfx::geometrybank_handle const &Bank ) { gfx::vertex_array vertices; vertices.reserve( m_data.vertices.size() ); for( auto const &vertex : m_data.vertices ) { - vertices.emplace_back( - vertex.position - m_data.origin, - vertex.normal, - vertex.texture ); + vertices.emplace_back(gfx::basic_vertex::convert(vertex, m_data.origin)); } - m_data.geometry = GfxRenderer->Insert( vertices, Bank, GL_TRIANGLES ); + m_data.geometry = GfxRenderer->Insert(vertices, m_data.userdata, Bank, GL_TRIANGLES); std::vector().swap( m_data.vertices ); // hipster shrink_to_fit } @@ -657,7 +683,7 @@ lines_node::create_geometry( gfx::geometrybank_handle const &Bank ) { vertex.normal, vertex.texture ); } - m_data.geometry = GfxRenderer->Insert( vertices, Bank, GL_LINES ); + m_data.geometry = GfxRenderer->Insert( vertices, m_data.userdata, Bank, GL_LINES ); std::vector().swap( m_data.vertices ); // hipster shrink_to_fit } diff --git a/scenenode.h b/scenenode.h index 6689755e..02fe05da 100644 --- a/scenenode.h +++ b/scenenode.h @@ -96,6 +96,7 @@ public: glm::highp_dvec3 origin; // world position of the relative coordinate system origin 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 + gfx::userdata_array userdata; // methods: // sends content of the struct to provided stream void @@ -191,6 +192,7 @@ public: glm::dvec3 origin; // world position of the relative coordinate system origin 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 + gfx::userdata_array userdata; // methods: // sends content of the struct to provided stream void diff --git a/shaders/color.frag b/shaders/color.frag index f969af27..45c0829e 100644 --- a/shaders/color.frag +++ b/shaders/color.frag @@ -12,7 +12,7 @@ layout(location = 1) out vec4 out_motion; void main() { - vec3 col = pow(f_color.rgb, vec3(2.2)); + vec3 col = clamp(pow(f_color.rgb, vec3(2.2)),0, 1); #if POSTFX_ENABLED out_color = vec4(apply_fog(col), 1.0f); #else diff --git a/shaders/vertex.vert b/shaders/vertex.vert index 4d274e71..feadbe1e 100644 --- a/shaders/vertex.vert +++ b/shaders/vertex.vert @@ -2,6 +2,7 @@ layout(location = 0) in vec3 v_vert; layout(location = 1) in vec3 v_normal; layout(location = 2) in vec2 v_coord; layout(location = 3) in vec4 v_tangent; +layout(location = 4) in vec4 v_userdata; #include @@ -18,6 +19,7 @@ out vec4 f_clip_future_pos; //out vec3 TangentLightPos; //out vec3 TangentViewPos; out vec3 TangentFragPos; +out vec4 UserData; void main() { @@ -43,4 +45,5 @@ void main() // TangentLightPos = TBN * f_light_pos.xyz; // TangentViewPos = TBN * vec3(0.0, 0.0, 0.0); TangentFragPos = TBN * f_pos.xyz; + UserData = v_userdata; } diff --git a/simulation.cpp b/simulation.cpp index 1fe8a63e..b40782c1 100644 --- a/simulation.cpp +++ b/simulation.cpp @@ -339,6 +339,8 @@ void state_manager::process_commands() { if (commanddata.command == user_command::settemperature) { Global.AirTemperature = commanddata.param1; + Global.Overcast = commanddata.param2; + simulation::Environment.compute_weather(); } if (commanddata.command == user_command::insertmodel) { diff --git a/simulationenvironment.cpp b/simulationenvironment.cpp index 7707ddfb..0006899f 100644 --- a/simulationenvironment.cpp +++ b/simulationenvironment.cpp @@ -66,9 +66,23 @@ world_environment::compute_weather() { Global.Overcast <= 0.50 ? "scattered:" : Global.Overcast <= 0.90 ? "broken:" : Global.Overcast <= 1.00 ? "overcast:" : - ( Global.Season != "winter:" ? - "rain:" : + + (Global.AirTemperature > 1 ? "rain:" : "snow:" ) ); + + Global.fTurbidity = ( + Global.Overcast <= 0.10 ? 3 : + Global.Overcast <= 0.20 ? 4 : + Global.Overcast <= 0.30 ? 5 : + Global.Overcast <= 0.40 ? 5 : + Global.Overcast <= 0.50 ? 5 : + Global.Overcast <= 0.60 ? 5 : + Global.Overcast <= 0.70 ? 6 : + Global.Overcast <= 0.80 ? 7 : + Global.Overcast <= 0.90 ? 8 : + Global.Overcast > 0.90 ? 9 : + 9 + ); } void @@ -120,7 +134,9 @@ world_environment::update() { float keylightintensity; glm::vec3 keylightcolor; - if( moonlightlevel > sunlightlevel ) { + Global.SunAngle = m_sun.getAngle(); + if ((moonlightlevel > sunlightlevel) && (Global.SunAngle <(-20))) + { // rare situations when the moon is brighter than the sun, typically at night Global.SunAngle = m_moon.getAngle(); Global.DayLight.position = m_moon.getDirection(); @@ -139,10 +155,10 @@ world_environment::update() { keylightintensity = sunlightlevel; m_lightintensity = 1.0f; // include 'golden hour' effect in twilight lighting - float const duskfactor = 1.0f - clamp( Global.SunAngle, 0.0f, 18.0f ) / 18.0f; + float const duskfactor = 1.25f - clamp( Global.SunAngle, 0.0f, 18.0f ) / 18.0f; keylightcolor = interpolate( glm::vec3( 255.0f / 255.0f, 242.0f / 255.0f, 231.0f / 255.0f ), - glm::vec3( 235.0f / 255.0f, 140.0f / 255.0f, 36.0f / 255.0f ), + glm::vec3( 235.0f / 255.0f, 120.0f / 255.0f, 36.0f / 255.0f ), duskfactor ); } // ...retrieve current sky colour and brightness... @@ -174,9 +190,9 @@ world_environment::update() { // update the fog. setting it to match the average colour of the sky dome is cheap // but quite effective way to make the distant items blend with background better - Global.FogColor = - interpolate( m_skydome.GetAverageColor(), m_skydome.GetAverageHorizonColor(), 0.25f ) - * clamp( Global.fLuminance, 0.25f, 1.f ); + Global.FogColor = ((m_skydome.GetAverageHorizonColor()) * keylightcolor) * + clamp(Global.fLuminance, 0.0f, 1.f); + // weather-related simulation factors Global.FrictionWeatherFactor = ( diff --git a/skydome.cpp b/skydome.cpp index f0a8250d..cc7ad696 100644 --- a/skydome.cpp +++ b/skydome.cpp @@ -10,8 +10,8 @@ // by A. J. Preetham Peter Shirley Brian Smits (University of Utah) float CSkyDome::m_distributionluminance[ 5 ][ 2 ] = { // Perez distributions - { 0.17872f , -1.46303f }, // a = darkening or brightening of the horizon - { -0.35540f , 0.42749f }, // b = luminance gradient near the horizon, + { 0.17872f , -1.66303f }, // a = darkening or brightening of the horizon + { -0.35540f , 0.42750f }, // b = luminance gradient near the horizon, { -0.02266f , 5.32505f }, // c = relative intensity of the circumsolar region { 0.12064f , -2.57705f }, // d = width of the circumsolar region { -0.06696f , 0.37027f } // e = relative backscattered light @@ -48,8 +48,8 @@ CSkyDome::CSkyDome (int const Tesselation) : m_tesselation( Tesselation ) { // SetSunPosition( Math3D::vector3(75.0f, 0.0f, 0.0f) ); - SetTurbidity( 3.0f ); - SetExposure( true, 20.0f ); + SetTurbidity( Global.fTurbidity ); + SetExposure( true, 10.0f ); SetOvercastFactor( 0.05f ); Generate(); } @@ -109,7 +109,7 @@ void CSkyDome::Generate() { } void CSkyDome::Update( glm::vec3 const &Sun ) { - + SetTurbidity(Global.fTurbidity); if( true == SetSunPosition( Sun ) ) { // build colors if there's a change in sun position RebuildColors(); @@ -134,7 +134,7 @@ bool CSkyDome::SetSunPosition( glm::vec3 const &Direction ) { void CSkyDome::SetTurbidity( float const Turbidity ) { - m_turbidity = clamp( Turbidity, 1.f, 4.f ); + m_turbidity = clamp( Turbidity, 1.f, 128.f ); } void CSkyDome::SetExposure( bool const Linearexposure, float const Expfactor ) { @@ -296,20 +296,20 @@ void CSkyDome::RebuildColors() { color.y = 0.65f * color.z; } // simple gradient, darkening towards the top - color *= clamp( ( 1.25f - vertex.y ), 0.f, 1.f ); -// color *= ( 1.25f - vertex.y ); + color *= clamp( ( 1.0f - vertex.y ), 0.f, 1.f ); + //color *= ( 0.25f - vertex.y ); // gamma correction color = glm::pow( color, gammacorrection ); m_colours[ i ] = color; averagecolor += color; - if( ( m_vertices.size() - i ) <= ( m_tesselation * 3 + 3 ) ) { + if( ( m_vertices.size() - i ) <= ( m_tesselation * 10 + 10 ) ) { // calculate horizon colour from the bottom band of tris averagehorizoncolor += color; } } m_averagecolour = glm::max( glm::vec3(), averagecolor / static_cast( m_vertices.size() ) ); - m_averagehorizoncolour = glm::max( glm::vec3(), averagehorizoncolor / static_cast( m_tesselation * 3 + 3 ) ); + m_averagehorizoncolour = glm::max( glm::vec3(), averagehorizoncolor / static_cast( m_tesselation * 10 + 10 ) ); m_dirty = true; } diff --git a/widgets/map.cpp b/widgets/map.cpp index 611a1227..b841bcb0 100644 --- a/widgets/map.cpp +++ b/widgets/map.cpp @@ -621,7 +621,8 @@ void ui::obstacle_insert_window::render_content() std::vector vertices; vertices.emplace_back(std::move(obstacle->vertex())); - GfxRenderer->Append(vertices, simulation::Region->get_map_poi_geometry(), GL_POINTS); + gfx::userdata_array userdata{}; + GfxRenderer->Append(vertices, userdata, simulation::Region->get_map_poi_geometry(), GL_POINTS); map::Objects.entries.push_back(std::move(obstacle));