From 9a008ecff5e17f75425821aa1de3c52ac2b0e05d Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Sun, 9 Jul 2017 16:45:40 +0200 Subject: [PATCH 1/6] build 170708. cursor-based item picking, mouse support for cab controls, rudimentary render modes support in renderer --- AnimModel.cpp | 4 +- Camera.cpp | 19 +- Camera.h | 1 - EU07.cpp | 45 +- Globals.cpp | 2 +- Globals.h | 2 +- Ground.cpp | 283 ++++++---- Ground.h | 30 +- McZapkie/Mover.cpp | 16 +- McZapkie/mctools.h | 9 +- Model3d.cpp | 12 +- Segment.cpp | 8 +- Track.cpp | 10 +- Train.cpp | 408 ++++---------- Train.h | 18 +- World.cpp | 170 +++--- World.h | 71 ++- command.h | 3 +- dumb3d.h | 16 +- keyboardinput.cpp | 256 +++++++++ keyboardinput.h | 20 + renderer.cpp | 1299 ++++++++++++++++++++++++++++++++++---------- renderer.h | 94 +++- uilayer.cpp | 45 +- uilayer.h | 19 +- version.h | 2 +- 26 files changed, 1931 insertions(+), 931 deletions(-) diff --git a/AnimModel.cpp b/AnimModel.cpp index 95e45c41..73b5524e 100644 --- a/AnimModel.cpp +++ b/AnimModel.cpp @@ -447,7 +447,7 @@ bool TAnimModel::Init(std::string const &asName, std::string const &asReplacable m_materialdata.replacable_skins[1] = GfxRenderer.GetTextureId( asReplacableTexture, "" ); if( ( m_materialdata.replacable_skins[ 1 ] != 0 ) - && ( GfxRenderer.Texture( m_materialdata.replacable_skins[ 1 ] ).has_alpha ) ) { + && ( GfxRenderer.Texture( m_materialdata.replacable_skins[ 1 ] ).has_alpha ) ) { // tekstura z kanałem alfa - nie renderować w cyklu nieprzezroczystych m_materialdata.textures_alpha = 0x31310031; } @@ -470,7 +470,7 @@ bool TAnimModel::Load(cParser *parser, bool ter) if (ter) // jeśli teren { if( name.substr( name.rfind( '.' ) ) == ".t3d" ) { - name[ name.length() - 2 ] = 'e'; + name[ name.length() - 3 ] = 'e'; } Global::asTerrainModel = name; WriteLog("Terrain model \"" + name + "\" will be created."); diff --git a/Camera.cpp b/Camera.cpp index b1354746..2c59684f 100644 --- a/Camera.cpp +++ b/Camera.cpp @@ -419,29 +419,18 @@ bool TCamera::SetMatrix( glm::dmat4 &Matrix ) { if( Type == tp_Follow ) { Matrix *= glm::lookAt( - glm::dvec3( Pos.x, Pos.y, Pos.z ), - glm::dvec3( LookAt.x, LookAt.y, LookAt.z ), - glm::dvec3( vUp.x, vUp.y, vUp.z ) ); + glm::dvec3{ Pos }, + glm::dvec3{ LookAt }, + glm::dvec3{ vUp } ); } else { - Matrix = glm::translate( Matrix, glm::dvec3( -Pos.x, -Pos.y, -Pos.z ) ); // nie zmienia kierunku patrzenia + Matrix = glm::translate( Matrix, glm::dvec3{ -Pos } ); // nie zmienia kierunku patrzenia } Global::SetCameraPosition( Pos ); // było +pOffset return true; } -void TCamera::SetCabMatrix(vector3 &p) -{ // ustawienie widoku z kamery bez przesunięcia robionego przez OpenGL - nie powinno tak trząść - - glRotated(-Roll * 180.0 / M_PI, 0.0, 0.0, 1.0); - glRotated(-Pitch * 180.0 / M_PI, 1.0, 0.0, 0.0); - glRotated(-Yaw * 180.0 / M_PI, 0.0, 1.0, 0.0); // w zewnętrznym widoku: kierunek patrzenia - if (Type == tp_Follow) - gluLookAt(Pos.x - p.x, Pos.y - p.y, Pos.z - p.z, LookAt.x - p.x, LookAt.y - p.y, - LookAt.z - p.z, vUp.x, vUp.y, vUp.z); // Ra: pOffset is zero -} - void TCamera::RaLook() { // zmiana kierunku patrzenia - przelicza Yaw vector3 where = LookAt - Pos + vector3(0, 3, 0); // trochę w górę od szyn diff --git a/Camera.h b/Camera.h index 760a9294..f978047f 100644 --- a/Camera.h +++ b/Camera.h @@ -59,7 +59,6 @@ class TCamera vector3 GetDirection(); bool SetMatrix(); bool SetMatrix(glm::dmat4 &Matrix); - void SetCabMatrix( vector3 &p ); void RaLook(); void Stop(); // bool GetMatrix(matrix4x4 &Matrix); diff --git a/EU07.cpp b/EU07.cpp index 280f36fc..27aea200 100644 --- a/EU07.cpp +++ b/EU07.cpp @@ -66,6 +66,7 @@ namespace input { keyboard_input Keyboard; gamepad_input Gamepad; +glm::dvec2 mouse_pos; // stores last mouse position in control picking mode } @@ -122,11 +123,22 @@ void window_resize_callback(GLFWwindow *window, int w, int h) void cursor_pos_callback(GLFWwindow *window, double x, double y) { - input::Keyboard.mouse( x, y ); -#ifdef EU07_USE_OLD_COMMAND_SYSTEM - World.OnMouseMove(x * 0.005, y * 0.01); -#endif - glfwSetCursorPos(window, 0.0, 0.0); + if( true == Global::ControlPicking ) { + glfwSetCursorPos( window, x, y ); + } + else { + input::Keyboard.mouse( x, y ); + glfwSetCursorPos( window, 0, 0 ); + } +} + +void mouse_button_callback( GLFWwindow* window, int button, int action, int mods ) { + + if( ( button == GLFW_MOUSE_BUTTON_LEFT ) + || ( button == GLFW_MOUSE_BUTTON_RIGHT ) ) { + // we don't care about other mouse buttons at the moment + input::Keyboard.mouse( button, action ); + } } void key_callback( GLFWwindow *window, int key, int scancode, int action, int mods ) @@ -136,6 +148,27 @@ void key_callback( GLFWwindow *window, int key, int scancode, int action, int mo Global::shiftState = ( mods & GLFW_MOD_SHIFT ) ? true : false; Global::ctrlState = ( mods & GLFW_MOD_CONTROL ) ? true : false; + if( ( key == GLFW_KEY_LEFT_ALT ) + || ( key == GLFW_KEY_RIGHT_ALT ) ) { + // if the alt key was pressed toggle control picking mode and set matching cursor behaviour + if( action == GLFW_RELEASE ) { + + if( Global::ControlPicking ) { + // switch off + glfwGetCursorPos( window, &input::mouse_pos.x, &input::mouse_pos.y ); + glfwSetInputMode( window, GLFW_CURSOR, GLFW_CURSOR_DISABLED ); + glfwSetCursorPos( window, 0, 0 ); + } + else { + // enter picking mode + glfwSetInputMode( window, GLFW_CURSOR, GLFW_CURSOR_NORMAL ); + glfwSetCursorPos( window, input::mouse_pos.x, input::mouse_pos.y ); + } + // actually toggle the mode + Global::ControlPicking = !Global::ControlPicking; + } + } + if( ( key == GLFW_KEY_LEFT_SHIFT ) || ( key == GLFW_KEY_LEFT_CONTROL ) || ( key == GLFW_KEY_LEFT_ALT ) @@ -340,6 +373,7 @@ int main(int argc, char *argv[]) glfwSetCursorPos(window, 0.0, 0.0); glfwSetFramebufferSizeCallback(window, window_resize_callback); glfwSetCursorPosCallback(window, cursor_pos_callback); + glfwSetMouseButtonCallback( window, mouse_button_callback ); glfwSetKeyCallback(window, key_callback); glfwSetScrollCallback( window, scroll_callback ); glfwSetWindowFocusCallback(window, focus_callback); @@ -417,6 +451,7 @@ int main(int argc, char *argv[]) && ( true == World.Update() ) && ( true == GfxRenderer.Render() ) ) { glfwPollEvents(); + input::Keyboard.poll(); if( true == Global::InputGamepad ) { input::Gamepad.poll(); } diff --git a/Globals.cpp b/Globals.cpp index 6401aa1e..8712aeed 100644 --- a/Globals.cpp +++ b/Globals.cpp @@ -38,7 +38,6 @@ double Global::ABuDebug = 0; std::string Global::asSky = "1"; double Global::fLuminance = 1.0; // jasność światła do automatycznego zapalania float Global::SunAngle = 0.0f; -int Global::iReCompile = 0; // zwiększany, gdy trzeba odświeżyć siatki int Global::ScreenWidth = 1; int Global::ScreenHeight = 1; float Global::ZoomFactor = 1.0f; @@ -48,6 +47,7 @@ bool Global::shiftState; bool Global::ctrlState; int Global::iCameraLast = -1; std::string Global::asVersion = "couldn't retrieve version string"; +bool Global::ControlPicking = false; // indicates controls pick mode is enabled int Global::iTextMode = 0; // tryb pracy wyświetlacza tekstowego int Global::iScreenMode[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // numer ekranu wyświetlacza tekstowego double Global::fSunDeclination = 0.0; // deklinacja Słońca diff --git a/Globals.h b/Globals.h index b4bc804c..b31d6b94 100644 --- a/Globals.h +++ b/Globals.h @@ -238,7 +238,6 @@ class Global static int iBallastFiltering; // domyślne rozmywanie tekstury podsypki static int iRailProFiltering; // domyślne rozmywanie tekstury szyn static int iDynamicFiltering; // domyślne rozmywanie tekstur pojazdów - static int iReCompile; // zwiększany, gdy trzeba odświeżyć siatki static bool bUseVBO; // czy jest VBO w karcie graficznej static std::string LastGLError; static int iFeedbackMode; // tryb pracy informacji zwrotnej @@ -257,6 +256,7 @@ class Global static int iCameraLast; static std::string asVersion; // z opisem static GLint iMaxTextureSize; // maksymalny rozmiar tekstury + static bool ControlPicking; // indicates controls pick mode is enabled static int iTextMode; // tryb pracy wyświetlacza tekstowego static int iScreenMode[12]; // numer ekranu wyświetlacza tekstowego static bool bDoubleAmbient; // podwójna jasność ambient diff --git a/Ground.cpp b/Ground.cpp index a131644e..b4640ea4 100644 --- a/Ground.cpp +++ b/Ground.cpp @@ -49,8 +49,14 @@ extern "C" bool bCondition; // McZapkie: do testowania warunku na event multiple std::string LogComment; -// TODO: switch to the new unified code after we have in place merging of individual triangle nodes into material-based soups -#define EU07_USE_OLD_RENDERCODE +// tests whether provided points form a degenerate triangle +bool +degenerate( glm::dvec3 const &Vertex1, glm::dvec3 const &Vertex2, glm::dvec3 const &Vertex3 ) { + + return ( ( Vertex1 == Vertex2 ) + || ( Vertex2 == Vertex3 ) + || ( Vertex3 == Vertex1 ) ); +} //--------------------------------------------------------------------------- // Obiekt renderujący siatkę jest sztucznie tworzonym obiektem pomocniczym, @@ -692,6 +698,21 @@ TGroundNode * TGround::FindGroundNode(std::string asNameToFind, TGroundNodeType return NULL; } +TGroundRect * +TGround::GetRect( double x, double z ) { + + auto const column = GetColFromX( x ) / iNumSubRects; + auto const row = GetRowFromZ( z ) / iNumSubRects; + + if( ( column >= 0 ) && ( column < iNumRects ) + && ( row >= 0 ) && ( row < iNumRects ) ) { + return &Rects[ column ][ row ]; + } + else { + return nullptr; + } +}; + double fTrainSetVel = 0; double fTrainSetDir = 0; double fTrainSetDist = 0; // odległość składu od punktu 1 w stronę punktu 2 @@ -934,25 +955,25 @@ TGroundNode * TGround::AddGroundNode(cParser *parser) >> tmp->hvTraction->pPoint1.x >> tmp->hvTraction->pPoint1.y >> tmp->hvTraction->pPoint1.z; - tmp->hvTraction->pPoint1 += glm::dvec3( pOrigin.x, pOrigin.y, pOrigin.z ); + tmp->hvTraction->pPoint1 += glm::dvec3{ pOrigin }; parser->getTokens(3); *parser >> tmp->hvTraction->pPoint2.x >> tmp->hvTraction->pPoint2.y >> tmp->hvTraction->pPoint2.z; - tmp->hvTraction->pPoint2 += glm::dvec3( pOrigin.x, pOrigin.y, pOrigin.z ); + tmp->hvTraction->pPoint2 += glm::dvec3{ pOrigin }; parser->getTokens(3); *parser >> tmp->hvTraction->pPoint3.x >> tmp->hvTraction->pPoint3.y >> tmp->hvTraction->pPoint3.z; - tmp->hvTraction->pPoint3 += glm::dvec3( pOrigin.x, pOrigin.y, pOrigin.z ); + tmp->hvTraction->pPoint3 += glm::dvec3{ pOrigin }; parser->getTokens(3); *parser >> tmp->hvTraction->pPoint4.x >> tmp->hvTraction->pPoint4.y >> tmp->hvTraction->pPoint4.z; - tmp->hvTraction->pPoint4 += glm::dvec3( pOrigin.x, pOrigin.y, pOrigin.z ); + tmp->hvTraction->pPoint4 += glm::dvec3{ pOrigin }; parser->getTokens(); *parser >> tf1; tmp->hvTraction->fHeightDifference = @@ -1238,6 +1259,7 @@ TGroundNode * TGround::AddGroundNode(cParser *parser) { // jeśli model jest terenem, trzeba utworzyć dodatkowe obiekty // po wczytaniu model ma już utworzone DL albo VBO Global::pTerrainCompact = tmp->Model; // istnieje co najmniej jeden obiekt terenu + tmp->pCenter = Math3D::vector3( 0.0, 0.0, 0.0 ); // enforce placement in the world center tmp->iCount = Global::pTerrainCompact->TerrainCount() + 1; // zliczenie submodeli tmp->nNode = new TGroundNode[tmp->iCount]; // sztuczne node dla kwadratów tmp->nNode[0].iType = TP_MODEL; // pierwszy zawiera model (dla delete) @@ -1245,7 +1267,7 @@ TGroundNode * TGround::AddGroundNode(cParser *parser) tmp->nNode[0].iFlags = 0x200; // nie wyświetlany, ale usuwany for (int i = 1; i < tmp->iCount; ++i) { // a reszta to submodele - tmp->nNode[i].iType = TP_SUBMODEL; // + tmp->nNode[i].iType = TP_SUBMODEL; tmp->nNode[i].smTerrain = Global::pTerrainCompact->TerrainSquare(i - 1); tmp->nNode[i].iFlags = 0x10; // nieprzezroczyste; nie usuwany tmp->nNode[i].bVisible = true; @@ -1264,27 +1286,24 @@ TGroundNode * TGround::AddGroundNode(cParser *parser) // case TP_GEOMETRY : case GL_TRIANGLES: case GL_TRIANGLE_STRIP: - case GL_TRIANGLE_FAN: + case GL_TRIANGLE_FAN: { + parser->getTokens(); *parser >> token; // McZapkie-050702: opcjonalne wczytywanie parametrow materialu (ambient,diffuse,specular) - if (token.compare("material") == 0) - { + if( token.compare( "material" ) == 0 ) { parser->getTokens(); *parser >> token; - while (token.compare("endmaterial") != 0) - { - if (token.compare("ambient:") == 0) - { - parser->getTokens(3); + while( token.compare( "endmaterial" ) != 0 ) { + if( token.compare( "ambient:" ) == 0 ) { + parser->getTokens( 3 ); *parser >> tmp->Ambient.r >> tmp->Ambient.g >> tmp->Ambient.b; tmp->Ambient /= 255.0f; } - else if (token.compare("diffuse:") == 0) - { // Ra: coś jest nie tak, bo w jednej linijce nie działa + else if( token.compare( "diffuse:" ) == 0 ) { // Ra: coś jest nie tak, bo w jednej linijce nie działa parser->getTokens( 3 ); *parser >> tmp->Diffuse.r @@ -1292,8 +1311,7 @@ TGroundNode * TGround::AddGroundNode(cParser *parser) >> tmp->Diffuse.b; tmp->Diffuse /= 255.0f; } - else if (token.compare("specular:") == 0) - { + else if( token.compare( "specular:" ) == 0 ) { parser->getTokens( 3 ); *parser >> tmp->Specular.r @@ -1302,18 +1320,25 @@ TGroundNode * TGround::AddGroundNode(cParser *parser) tmp->Specular /= 255.0f; } else - Error("Scene material failure!"); + Error( "Scene material failure!" ); parser->getTokens(); *parser >> token; } } - if (token.compare("endmaterial") == 0) - { + if( token.compare( "endmaterial" ) == 0 ) { parser->getTokens(); *parser >> token; } str = token; tmp->TextureID = GfxRenderer.GetTextureId( str, szTexturePath ); + bool const clamps = ( + tmp->TextureID ? + GfxRenderer.Texture( tmp->TextureID ).traits.find( 's' ) != std::string::npos : + false ); + bool const clampt = ( + tmp->TextureID ? + GfxRenderer.Texture( tmp->TextureID ).traits.find( 't' ) != std::string::npos : + false ); tmp->iFlags |= 200; // z usuwaniem // remainder of legacy 'problend' system -- geometry assigned a texture with '@' in its name is treated as translucent, opaque otherwise @@ -1322,49 +1347,76 @@ TGroundNode * TGround::AddGroundNode(cParser *parser) && ( true == GfxRenderer.Texture( tmp->TextureID ).has_alpha ) ) ? 0x20 : 0x10 ); - { - TGroundVertex vertex, vertex1, vertex2; - std::size_t vertexcount { 0 }; - do { - parser->getTokens( 8, false ); - *parser - >> vertex.position.x - >> vertex.position.y - >> vertex.position.z - >> vertex.normal.x - >> vertex.normal.y - >> vertex.normal.z - >> vertex.texture.s - >> vertex.texture.t; - vertex.position = glm::rotateZ( vertex.position, aRotate.z / 180 * M_PI ); - vertex.position = glm::rotateX( vertex.position, aRotate.x / 180 * M_PI ); - vertex.position = glm::rotateY( vertex.position, aRotate.y / 180 * M_PI ); - vertex.normal = glm::rotateZ( vertex.normal, static_cast( aRotate.z / 180 * M_PI ) ); - vertex.normal = glm::rotateX( vertex.normal, static_cast( aRotate.x / 180 * M_PI ) ); - vertex.normal = glm::rotateY( vertex.normal, static_cast( aRotate.y / 180 * M_PI ) ); - vertex.position += glm::dvec3( pOrigin.x, pOrigin.y, pOrigin.z ); - // convert all data to gl_triangles to allow data merge for matching nodes - switch( tmp->iType ) { - case GL_TRIANGLES: { - importedvertices.emplace_back( vertex ); - break; + + TGroundVertex vertex, vertex1, vertex2; + std::size_t vertexcount{ 0 }; + do { + parser->getTokens( 8, false ); + *parser + >> vertex.position.x + >> vertex.position.y + >> vertex.position.z + >> vertex.normal.x + >> vertex.normal.y + >> vertex.normal.z + >> vertex.texture.s + >> vertex.texture.t; + vertex.position = glm::rotateZ( vertex.position, aRotate.z / 180 * M_PI ); + vertex.position = glm::rotateX( vertex.position, aRotate.x / 180 * M_PI ); + vertex.position = glm::rotateY( vertex.position, aRotate.y / 180 * M_PI ); + vertex.normal = glm::rotateZ( vertex.normal, static_cast( aRotate.z / 180 * M_PI ) ); + vertex.normal = glm::rotateX( vertex.normal, static_cast( aRotate.x / 180 * M_PI ) ); + vertex.normal = glm::rotateY( vertex.normal, static_cast( aRotate.y / 180 * M_PI ) ); + vertex.position += glm::dvec3{ pOrigin }; + if( true == clamps ) { vertex.texture.s = clamp( vertex.texture.s, 0.001f, 0.999f ); } + if( true == clampt ) { vertex.texture.t = clamp( vertex.texture.t, 0.001f, 0.999f ); } + // convert all data to gl_triangles to allow data merge for matching nodes + switch( tmp->iType ) { + case GL_TRIANGLES: { + 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 ); + } + else { + ErrorLog( + "Bad geometry: degenerate triangle encountered" + + ( tmp->asName != "" ? " in node \"" + tmp->asName + "\"" : "" ) + + " (vertices: " + to_string( vertex1.position ) + " + " + to_string( vertex2.position ) + " + " + to_string( vertex.position ) + ")" ); + } } - case GL_TRIANGLE_FAN: { - if( vertexcount == 0 ) { vertex1 = vertex; } - else if( vertexcount == 1 ) { vertex2 = vertex; } - else if( vertexcount >= 2 ) { + ++vertexcount; + if( vertexcount > 2 ) { vertexcount = 0; } // start new triangle if needed + break; + } + case GL_TRIANGLE_FAN: { + 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 ); vertex2 = vertex; } - ++vertexcount; - break; + else { + ErrorLog( + "Bad geometry: degenerate triangle encountered" + + ( tmp->asName != "" ? " in node \"" + tmp->asName + "\"" : "" ) + + " (vertices: " + to_string( vertex1.position ) + " + " + to_string( vertex2.position ) + " + " + to_string( vertex.position ) + ")" ); + } } - case GL_TRIANGLE_STRIP: { - if( vertexcount == 0 ) { vertex1 = vertex; } - else if( vertexcount == 1 ) { vertex2 = vertex; } - else if( vertexcount >= 2 ) { + ++vertexcount; + break; + } + case GL_TRIANGLE_STRIP: { + if( vertexcount == 0 ) { vertex1 = vertex; } + else if( vertexcount == 1 ) { vertex2 = vertex; } + else if( vertexcount >= 2 ) { + if( false == degenerate( vertex1.position, vertex2.position, vertex.position ) ) { // swap order every other triangle, to maintain consistent winding if( vertexcount % 2 == 0 ) { importedvertices.emplace_back( vertex1 ); @@ -1379,40 +1431,47 @@ TGroundNode * TGround::AddGroundNode(cParser *parser) vertex1 = vertex2; vertex2 = vertex; } - ++vertexcount; - break; + else { + ErrorLog( + "Bad geometry: degenerate triangle encountered" + + ( tmp->asName != "" ? " in node \"" + tmp->asName + "\"" : "" ) + + " (vertices: " + to_string( vertex1.position ) + " + " + to_string( vertex2.position ) + " + " + to_string( vertex.position ) + ")" ); + } } - default: { break; } + ++vertexcount; + break; } - parser->getTokens(); - *parser >> token; - - } while (token.compare("endtri") != 0); - - tmp->iType = GL_TRIANGLES; - tmp->Piece = new piece_node(); - tmp->iNumVerts = importedvertices.size(); - - if( tmp->iNumVerts > 0 ) { - - tmp->Piece->vertices.swap( importedvertices ); - - for( auto const &vertex : tmp->Piece->vertices ) { - tmp->pCenter += vertex.position; - } - tmp->pCenter /= tmp->iNumVerts; - - r = 0; - for( auto const &vertex : tmp->Piece->vertices ) { - tf = SquareMagnitude( vertex.position - tmp->pCenter ); - if( tf > r ) - r = tf; - } - tmp->fSquareRadius += r; - RaTriangleDivider( tmp ); // Ra: dzielenie trójkątów jest teraz całkiem wydajne + default: { break; } } + parser->getTokens(); + *parser >> token; + + } while( token.compare( "endtri" ) != 0 ); + + tmp->iType = GL_TRIANGLES; + tmp->Piece = new piece_node(); + tmp->iNumVerts = importedvertices.size(); + + if( tmp->iNumVerts > 0 ) { + + tmp->Piece->vertices.swap( importedvertices ); + + for( auto const &vertex : tmp->Piece->vertices ) { + tmp->pCenter += vertex.position; + } + tmp->pCenter /= tmp->iNumVerts; + + r = 0; + for( auto const &vertex : tmp->Piece->vertices ) { + tf = glm::length2( vertex.position - glm::dvec3{ tmp->pCenter } ); + if( tf > r ) + r = tf; + } + tmp->fSquareRadius += r; + RaTriangleDivider( tmp ); // Ra: dzielenie trójkątów jest teraz całkiem wydajne } // koniec wczytywania trójkątów break; + } case GL_LINES: case GL_LINE_STRIP: case GL_LINE_LOOP: { @@ -1440,7 +1499,7 @@ TGroundNode * TGround::AddGroundNode(cParser *parser) vertex.position = glm::rotateX( vertex.position, aRotate.x / 180 * M_PI ); vertex.position = glm::rotateY( vertex.position, aRotate.y / 180 * M_PI ); - vertex.position += glm::dvec3( pOrigin.x, pOrigin.y, pOrigin.z ); + vertex.position += glm::dvec3{ pOrigin }; // convert all data to gl_lines to allow data merge for matching nodes switch( tmp->iType ) { case GL_LINES: { @@ -1578,11 +1637,11 @@ void TGround::FirstInit() // dodanie do globalnego obiektu srGlobal.NodeAdd( Current ); } - else if (type == TP_TERRAIN) - { // specjalne przetwarzanie terenu wczytanego z pliku E3D + else if (type == TP_TERRAIN) { + // specjalne przetwarzanie terenu wczytanego z pliku E3D TGroundRect *gr; - for (int j = 1; j < Current->iCount; ++j) - { // od 1 do końca są zestawy trójkątów + for (int j = 1; j < Current->iCount; ++j) { + // od 1 do końca są zestawy trójkątów std::string xxxzzz = Current->nNode[j].smTerrain->pName; // pobranie nazwy gr = GetRect( ( std::stoi( xxxzzz.substr( 0, 3 )) - 500 ) * 1000, @@ -1590,16 +1649,30 @@ void TGround::FirstInit() gr->nTerrain = Current->nNode + j; // zapamiętanie } } - else if( ( Current->iType != GL_TRIANGLES ) - || ( Current->iFlags & 0x20 ) - || ( Current->fSquareMinRadius != 0.0 ) - || ( Current->fSquareRadius <= 90000.0 ) ) { - // add to sub-rectangle - GetSubRect( Current->pCenter.x, Current->pCenter.z )->NodeAdd( Current ); - } else { - // dodajemy do kwadratu kilometrowego - GetRect( Current->pCenter.x, Current->pCenter.z )->NodeAdd( Current ); + TSubRect *targetcell { nullptr }; + // test whether we can add the node to a ground cell, or a subcell + if( ( Current->iType != GL_TRIANGLES ) + || ( Current->iFlags & 0x20 ) + || ( Current->fSquareMinRadius != 0.0 ) + || ( Current->fSquareRadius <= 90000.0 ) ) { + // add to sub-rectangle + targetcell = GetSubRect( Current->pCenter.x, Current->pCenter.z ); + } + else { + // dodajemy do kwadratu kilometrowego + targetcell = GetRect( Current->pCenter.x, Current->pCenter.z ); + } + if( targetcell != nullptr ) { + targetcell->NodeAdd( Current ); + } + else { + ErrorLog( "Scenery node" + ( + Current->asName == "" ? + "" : + " \"" + Current->asName + "\"" ) + + " placed in location outside of map bounds (location: " + to_string( glm::dvec3{ Current->pCenter } ) + ")" ); + } } } } @@ -2900,7 +2973,7 @@ TTraction * TGround::TractionNearestFind(glm::dvec3 &p, int dir, TGroundNode *n) if (nCurrent->hvTraction->fResistance[k] >= 0.0) //żeby się nie propagowały jakieś ujemne { // znaleziony kandydat do połączenia - d = SquareMagnitude( p - nCurrent->pCenter ); // kwadrat odległości środków + d = glm::length2( p - glm::dvec3{ nCurrent->pCenter } ); // kwadrat odległości środków if (dist > d) { // zapamiętanie nowego najbliższego dist = d; // nowy rekord odległości @@ -3568,10 +3641,10 @@ bool TGround::GetTraction(TDynamicObject *model) vParam = node->hvTraction ->vParametric; // współczynniki równania parametrycznego - fRaParam = -DotProduct(pant0, vFront); - auto const paramfrontdot = DotProduct( vParam, vFront ); + fRaParam = -glm::dot(pant0, vFront); + auto const paramfrontdot = glm::dot( vParam, vFront ); fRaParam = - -( DotProduct( node->hvTraction->pPoint1, vFront ) + fRaParam ) + -( glm::dot( node->hvTraction->pPoint1, vFront ) + fRaParam ) / ( paramfrontdot != 0.0 ? paramfrontdot : 0.001 ); // div0 trap if ((fRaParam >= -0.001) ? (fRaParam <= 1.001) : false) { // jeśli tylko jest w przedziale, wyznaczyć odległość wzdłuż diff --git a/Ground.h b/Ground.h index 04e66754..1005ab3f 100644 --- a/Ground.h +++ b/Ground.h @@ -313,27 +313,21 @@ class TGround TGroundNode * DynamicFind(std::string const &Name); void DynamicList(bool all = false); TGroundNode * FindGroundNode(std::string asNameToFind, TGroundNodeType iNodeType); - TGroundRect * GetRect(double x, double z) - { - return &Rects[GetColFromX(x) / iNumSubRects][GetRowFromZ(z) / iNumSubRects]; - }; + TGroundRect * GetRect( double x, double z ); TSubRect * GetSubRect( int iCol, int iRow ); - TSubRect * GetSubRect(double x, double z) - { - return GetSubRect(GetColFromX(x), GetRowFromZ(z)); - }; + inline + TSubRect * GetSubRect(double x, double z) { + return GetSubRect(GetColFromX(x), GetRowFromZ(z)); }; TSubRect * FastGetSubRect( int iCol, int iRow ); + inline TSubRect * FastGetSubRect( double x, double z ) { - return FastGetSubRect( GetColFromX( x ), GetRowFromZ( z ) ); - }; - int GetRowFromZ(double z) - { - return (int)(z / fSubRectSize + fHalfTotalNumSubRects); - }; - int GetColFromX(double x) - { - return (int)(x / fSubRectSize + fHalfTotalNumSubRects); - }; + return FastGetSubRect( GetColFromX( x ), GetRowFromZ( z ) ); }; + inline + int GetRowFromZ(double z) { + return (int)(z / fSubRectSize + fHalfTotalNumSubRects); }; + inline + int GetColFromX(double x) { + return (int)(x / fSubRectSize + fHalfTotalNumSubRects); }; TEvent * FindEvent(const std::string &asEventName); TEvent * FindEventScan(const std::string &asEventName); void TrackJoin(TGroundNode *Current); diff --git a/McZapkie/Mover.cpp b/McZapkie/Mover.cpp index b707b944..31a3226d 100644 --- a/McZapkie/Mover.cpp +++ b/McZapkie/Mover.cpp @@ -814,9 +814,11 @@ void TMoverParameters::UpdateBatteryVoltage(double dt) sn3 = 0.0, sn4 = 0.0, sn5 = 0.0; // Ra: zrobić z tego amperomierz NN - if ((BatteryVoltage > 0) && (EngineType != DieselEngine) && (EngineType != WheelsDriven) && - (NominalBatteryVoltage > 0)) - { + if( ( BatteryVoltage > 0 ) + && ( EngineType != DieselEngine ) + && ( EngineType != WheelsDriven ) + && ( NominalBatteryVoltage > 0 ) ) { + if ((NominalBatteryVoltage / BatteryVoltage < 1.22) && Battery) { // 110V if (!ConverterFlag) @@ -884,10 +886,10 @@ void TMoverParameters::UpdateBatteryVoltage(double dt) if (BatteryVoltage < 0.01) BatteryVoltage = 0.01; } - else if (NominalBatteryVoltage == 0) - BatteryVoltage = 0; - else - BatteryVoltage = 90; + else { + // TODO: check and implement proper way to handle this for diesel engines + BatteryVoltage = NominalBatteryVoltage; + } }; /* Ukrotnienie EN57: diff --git a/McZapkie/mctools.h b/McZapkie/mctools.h index c6b7932b..c8171572 100644 --- a/McZapkie/mctools.h +++ b/McZapkie/mctools.h @@ -121,11 +121,16 @@ std::string to_string(double _Val, int precision); std::string to_string(double _Val, int precision, int width); std::string to_hex_str( int const _Val, int const width = 4 ); -inline std::string to_string(bool _Val) -{ +inline std::string to_string(bool _Val) { + return _Val == true ? "true" : "false"; } +template +std::string to_string( glm::tvec3 const &Value ) { + return to_string( Value.x, 2 ) + ", " + to_string( Value.y, 2 ) + ", " + to_string( Value.z, 2 ); +} + int stol_def(const std::string & str, const int & DefaultValue); std::string ToLower(std::string const &text); diff --git a/Model3d.cpp b/Model3d.cpp index 56916097..27614b73 100644 --- a/Model3d.cpp +++ b/Model3d.cpp @@ -381,11 +381,7 @@ int TSubModel::Load( cParser &parser, TModel3d *Model, /*int Pos,*/ bool dynamic if( ( std::abs( scale.x - 1.0f ) > 0.01 ) || ( std::abs( scale.y - 1.0f ) > 0.01 ) || ( std::abs( scale.z - 1.0f ) > 0.01 ) ) { - ErrorLog( - "Bad model: transformation matrix for sub-model \"" + pName + "\" imposes geometry scaling (factors: " - + to_string( scale.x, 2 ) + ", " - + to_string( scale.y, 2 ) + ", " - + to_string( scale.z, 2 ) + ")" ); + ErrorLog( "Bad model: transformation matrix for sub-model \"" + pName + "\" imposes geometry scaling (factors: " + to_string( scale ) + ")" ); m_normalizenormals = ( ( ( std::abs( scale.x - scale.y ) < 0.01f ) && ( std::abs( scale.y - scale.z ) < 0.01f ) ) ? rescale : @@ -1719,11 +1715,7 @@ void TSubModel::BinInit(TSubModel *s, float4x4 *m, std::vector *t, if( ( std::abs( scale.x - 1.0f ) > 0.01 ) || ( std::abs( scale.y - 1.0f ) > 0.01 ) || ( std::abs( scale.z - 1.0f ) > 0.01 ) ) { - ErrorLog( - "Bad model: transformation matrix for sub-model \"" + pName + "\" imposes geometry scaling (factors: " - + to_string( scale.x, 2 ) + ", " - + to_string( scale.y, 2 ) + ", " - + to_string( scale.z, 2 ) + ")" ); + ErrorLog( "Bad model: transformation matrix for sub-model \"" + pName + "\" imposes geometry scaling (factors: " + to_string( scale ) + ")" ); m_normalizenormals = ( ( ( std::abs( scale.x - scale.y ) < 0.01f ) && ( std::abs( scale.y - scale.z ) < 0.01f ) ) ? rescale : diff --git a/Segment.cpp b/Segment.cpp index c74451bd..ea9a8e6b 100644 --- a/Segment.cpp +++ b/Segment.cpp @@ -19,10 +19,6 @@ http://mozilla.org/MPL/2.0/. // 101206 Ra: trapezoidalne drogi // 110806 Ra: odwrócone mapowanie wzdłuż - Point1 == 1.0 -std::string Where(vector3 p) -{ // zamiana współrzędnych na tekst, używana w błędach - return std::to_string(p.x) + " " + std::to_string(p.y) + " " + std::to_string(p.z); -}; TSegment::TSegment(TTrack *owner) : pOwner( owner ) @@ -112,7 +108,7 @@ bool TSegment::Init(vector3 &NewPoint1, vector3 NewCPointOut, vector3 NewCPointI fStep = fNewStep; if (fLength <= 0) { - ErrorLog( "Bad geometry (zero length) for spline \"" + pOwner->NameGet() + "\" at " + Where( Point1 ) ); + ErrorLog( "Bad geometry: zero length spline \"" + pOwner->NameGet() + "\" (location: " + to_string( glm::dvec3{ Point1 } ) + ")" ); // MessageBox(0,"Length<=0","TSegment::Init",MB_OK); fLength = 0.01; // crude workaround TODO: fix this properly /* @@ -215,7 +211,7 @@ double TSegment::GetTFromS(double s) // Newton's method failed. If this happens, increase iterations or // tolerance or integration accuracy. // return -1; //Ra: tu nigdy nie dojdzie - ErrorLog( "Bad geometry (shape estimation failed) for spline \"" + pOwner->NameGet() + "\" at " + Where( Point1 ) ); + ErrorLog( "Bad geometry: shape estimation failed for spline \"" + pOwner->NameGet() + "\" (location: " + to_string( glm::dvec3{ Point1 } ) + ")" ); // MessageBox(0,"Too many iterations","GetTFromS",MB_OK); return fTime; }; diff --git a/Track.cpp b/Track.cpp index 59a7a44f..29e85e3f 100644 --- a/Track.cpp +++ b/Track.cpp @@ -307,10 +307,12 @@ TTrack * TTrack::NullCreate(int dir) tmp2->pCenter = tmp->pCenter; // ten sam środek jest // Ra: to poniżej to porażka, ale na razie się nie da inaczej TSubRect *r = Global::pGround->GetSubRect(tmp->pCenter.x, tmp->pCenter.z); - r->NodeAdd(tmp); // dodanie toru do segmentu - if (tmp2) - r->NodeAdd(tmp2); // drugiego też - r->Sort(); //żeby wyświetlał tabor z dodanego toru + if( r != nullptr ) { + r->NodeAdd( tmp ); // dodanie toru do segmentu + if( tmp2 ) + r->NodeAdd( tmp2 ); // drugiego też + r->Sort(); //żeby wyświetlał tabor z dodanego toru + } return trk; }; diff --git a/Train.cpp b/Train.cpp index 1bc9832d..398cc87e 100644 --- a/Train.cpp +++ b/Train.cpp @@ -22,6 +22,27 @@ http://mozilla.org/MPL/2.0/. #include "Driver.h" #include "Console.h" +void +control_mapper::insert( TGauge const &Gauge, std::string const &Label ) { + + auto const submodel = Gauge.SubModel; + if( submodel != nullptr ) { + m_controlnames.emplace( submodel, Label ); + } +} + +std::string +control_mapper::find( TSubModel const *Control ) const { + + auto const lookup = m_controlnames.find( Control ); + if( lookup != m_controlnames.end() ) { + return lookup->second; + } + else { + return ""; + } +} + TCab::TCab() { CabPos1.x = -1.0; @@ -5943,13 +5964,16 @@ bool TTrain::Update( double const Deltatime ) // TODO: rework it into something more elegant, when redoing the whole consist/unit/cab etc arrangement if( ( mvControlled->Battery ) || ( mvControlled->ConverterFlag ) ) { - if( ( false == mvControlled->PantFrontUp ) - && ( ggPantFrontButton.GetValue() >= 1.0 ) ) { - mvControlled->PantFront( true ); - } - if( ( false == mvControlled->PantRearUp ) - && ( ggPantRearButton.GetValue() >= 1.0 ) ) { - mvControlled->PantRear( true ); + if( ggPantAllDownButton.GetValue() == 0.0 ) { + // the 'lower all' button overrides state of switches, while active itself + if( ( false == mvControlled->PantFrontUp ) + && ( ggPantFrontButton.GetValue() >= 1.0 ) ) { + mvControlled->PantFront( true ); + } + if( ( false == mvControlled->PantRearUp ) + && ( ggPantRearButton.GetValue() >= 1.0 ) ) { + mvControlled->PantRear( true ); + } } } /* @@ -6309,6 +6333,7 @@ bool TTrain::LoadMMediaFile(std::string const &asFileName) bool TTrain::InitializeCab(int NewCabNo, std::string const &asFileName) { + m_controlmapper.clear(); pyScreens.reset(this); pyScreens.setLookupPath(DynamicObject->asBaseDir); bool parse = false; @@ -7195,309 +7220,78 @@ bool TTrain::initialize_button(cParser &Parser, std::string const &Label, int co // otherwise // NOTE: this is temporary work-around for compiler else-if limit // TODO: refactor the cabin controls into some sensible structure -bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int const Cabindex) -{ +bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int const Cabindex) { - TGauge *gg; // roboczy wskaźnik na obiekt animujący gałkę - - /* sanity check - if( !DynamicObject->mdKabina ) { - WriteLog( "Cab not initialised!" ); - return false; - } - */ - // SEKCJA REGULATOROW - if (Label == "mainctrl:") - { - // nastawnik - ggMainCtrl.Load(Parser, DynamicObject->mdKabina); - } - else if (Label == "mainctrlact:") - { - // zabek pozycji aktualnej - ggMainCtrlAct.Load(Parser, DynamicObject->mdKabina); - } - else if (Label == "scndctrl:") - { - // bocznik - ggScndCtrl.Load(Parser, DynamicObject->mdKabina); - } - else if (Label == "dirkey:") - { - // klucz kierunku - ggDirKey.Load(Parser, DynamicObject->mdKabina); - } - else if (Label == "brakectrl:") - { - // hamulec zasadniczy - ggBrakeCtrl.Load(Parser, DynamicObject->mdKabina); - } - else if (Label == "localbrake:") - { - // hamulec pomocniczy - ggLocalBrake.Load(Parser, DynamicObject->mdKabina); - } - else if (Label == "manualbrake:") - { - // hamulec reczny - ggManualBrake.Load(Parser, DynamicObject->mdKabina); - } - // sekcja przelacznikow obrotowych - else if (Label == "brakeprofile_sw:") - { - // przelacznik tow/osob/posp - ggBrakeProfileCtrl.Load(Parser, DynamicObject->mdKabina); - } - else if (Label == "brakeprofileg_sw:") - { - // przelacznik tow/osob - ggBrakeProfileG.Load(Parser, DynamicObject->mdKabina); - } - else if (Label == "brakeprofiler_sw:") - { - // przelacznik osob/posp - ggBrakeProfileR.Load(Parser, DynamicObject->mdKabina); - } - else if (Label == "maxcurrent_sw:") - { - // przelacznik rozruchu - ggMaxCurrentCtrl.Load(Parser, DynamicObject->mdKabina); - } - // SEKCJA przyciskow sprezynujacych - else if (Label == "main_off_bt:") - { - // przycisk wylaczajacy (w EU07 wyl szybki czerwony) - ggMainOffButton.Load(Parser, DynamicObject->mdKabina); - } - else if (Label == "main_on_bt:") - { - // przycisk wlaczajacy (w EU07 wyl szybki zielony) - ggMainOnButton.Load(Parser, DynamicObject->mdKabina); - } - else if (Label == "security_reset_bt:") - { - // przycisk zbijajacy SHP/czuwak - ggSecurityResetButton.Load(Parser, DynamicObject->mdKabina); - } - else if (Label == "releaser_bt:") - { - // przycisk odluzniacza - ggReleaserButton.Load(Parser, DynamicObject->mdKabina); - } - else if (Label == "sand_bt:") - { - // przycisk piasecznicy - ggSandButton.Load(Parser, DynamicObject->mdKabina); - } - else if (Label == "antislip_bt:") - { - // przycisk antyposlizgowy - ggAntiSlipButton.Load(Parser, DynamicObject->mdKabina); - } - else if (Label == "horn_bt:") - { - // dzwignia syreny - ggHornButton.Load(Parser, DynamicObject->mdKabina); - } - else if( Label == "hornlow_bt:" ) { - // dzwignia syreny - ggHornLowButton.Load( Parser, DynamicObject->mdKabina ); - } - else if( Label == "hornhigh_bt:" ) { - // dzwignia syreny - ggHornHighButton.Load( Parser, DynamicObject->mdKabina ); - } - else if( Label == "fuse_bt:" ) - { - // bezp. nadmiarowy - ggFuseButton.Load(Parser, DynamicObject->mdKabina); - } - else if (Label == "converterfuse_bt:") - { - // hunter-261211: - // odblokowanie przekaznika nadm. przetw. i ogrz. - ggConverterFuseButton.Load(Parser, DynamicObject->mdKabina); - } - else if (Label == "stlinoff_bt:") - { - // st. liniowe - ggStLinOffButton.Load(Parser, DynamicObject->mdKabina); - } - else if (Label == "door_left_sw:") - { - // drzwi lewe - ggDoorLeftButton.Load(Parser, DynamicObject->mdKabina); - } - else if (Label == "door_right_sw:") - { - // drzwi prawe - ggDoorRightButton.Load(Parser, DynamicObject->mdKabina); - } - else if (Label == "departure_signal_bt:") - { - // sygnal odjazdu - ggDepartureSignalButton.Load(Parser, DynamicObject->mdKabina); - } - else if (Label == "upperlight_sw:") - { - // swiatlo - ggUpperLightButton.Load(Parser, DynamicObject->mdKabina); - } - else if (Label == "leftlight_sw:") - { - // swiatlo - ggLeftLightButton.Load(Parser, DynamicObject->mdKabina); - } - else if (Label == "rightlight_sw:") - { - // swiatlo - ggRightLightButton.Load(Parser, DynamicObject->mdKabina); - } - else if( Label == "dimheadlights_sw:" ) { - // swiatlo - ggDimHeadlightsButton.Load( Parser, DynamicObject->mdKabina ); - } - else if( Label == "leftend_sw:" ) - { - // swiatlo - ggLeftEndLightButton.Load(Parser, DynamicObject->mdKabina); - } - else if (Label == "rightend_sw:") - { - // swiatlo - ggRightEndLightButton.Load(Parser, DynamicObject->mdKabina); - } - else if (Label == "lights_sw:") - { - // swiatla wszystkie - ggLightsButton.Load(Parser, DynamicObject->mdKabina); - } - //--------------------- - // hunter-230112: przelaczniki swiatel tylnich - else if (Label == "rearupperlight_sw:") - { - // swiatlo - ggRearUpperLightButton.Load(Parser, DynamicObject->mdKabina); - } - else if (Label == "rearleftlight_sw:") - { - // swiatlo - ggRearLeftLightButton.Load(Parser, DynamicObject->mdKabina); - } - else if (Label == "rearrightlight_sw:") - { - // swiatlo - ggRearRightLightButton.Load(Parser, DynamicObject->mdKabina); - } - else if (Label == "rearleftend_sw:") - { - // swiatlo - ggRearLeftEndLightButton.Load(Parser, DynamicObject->mdKabina); - } - else if (Label == "rearrightend_sw:") - { - // swiatlo - ggRearRightEndLightButton.Load(Parser, DynamicObject->mdKabina); - } - //------------------ - else if (Label == "compressor_sw:") - { - // sprezarka - ggCompressorButton.Load(Parser, DynamicObject->mdKabina); - } - else if( Label == "compressorlocal_sw:" ) { - // sprezarka - ggCompressorLocalButton.Load( Parser, DynamicObject->mdKabina ); - } - else if (Label == "converter_sw:") - { - // przetwornica - ggConverterButton.Load(Parser, DynamicObject->mdKabina); - } - else if( Label == "converterlocal_sw:" ) { - // przetwornica - ggConverterLocalButton.Load( Parser, DynamicObject->mdKabina ); - } - else if (Label == "converteroff_sw:") - { - // przetwornica wyl - ggConverterOffButton.Load(Parser, DynamicObject->mdKabina); - } - else if (Label == "main_sw:") - { - // wyl szybki (ezt) - ggMainButton.Load(Parser, DynamicObject->mdKabina); - } - else if (Label == "radio_sw:") - { - // radio - ggRadioButton.Load(Parser, DynamicObject->mdKabina); - } - else if (Label == "pantfront_sw:") - { - // patyk przedni - ggPantFrontButton.Load(Parser, DynamicObject->mdKabina); - } - else if (Label == "pantrear_sw:") - { - // patyk tylny - ggPantRearButton.Load(Parser, DynamicObject->mdKabina); - } - else if( Label == "pantfrontoff_sw:" ) - { - // patyk przedni w dol - ggPantFrontButtonOff.Load(Parser, DynamicObject->mdKabina); - } - else if( Label == "pantrearoff_sw:" ) { - // rear pant down - ggPantRearButtonOff.Load( Parser, DynamicObject->mdKabina ); - } - else if( Label == "pantalloff_sw:" ) { - // both pantographs down - ggPantAllDownButton.Load(Parser, DynamicObject->mdKabina); - } - else if( Label == "pantselected_sw:" ) { - // operate selected pantograph(s) - ggPantSelectedButton.Load( Parser, DynamicObject->mdKabina ); - } - else if( Label == "pantselectedoff_sw:" ) { - // operate selected pantograph(s) - ggPantSelectedDownButton.Load( Parser, DynamicObject->mdKabina ); - } - else if (Label == "trainheating_sw:") { - // grzanie skladu - ggTrainHeatingButton.Load(Parser, DynamicObject->mdKabina); - } - else if (Label == "signalling_sw:") - { - // Sygnalizacja hamowania - ggSignallingButton.Load(Parser, DynamicObject->mdKabina); - } - else if (Label == "door_signalling_sw:") - { - // Sygnalizacja blokady drzwi - ggDoorSignallingButton.Load(Parser, DynamicObject->mdKabina); - } - else if (Label == "nextcurrent_sw:") - { - // prąd drugiego członu - ggNextCurrentButton.Load(Parser, DynamicObject->mdKabina); - } - else if (Label == "cablight_sw:") - { - // hunter-091012: swiatlo w kabinie - ggCabLightButton.Load(Parser, DynamicObject->mdKabina); - } - else if (Label == "cablightdim_sw:") - { - // hunter-091012: przyciemnienie swiatla w kabinie - ggCabLightDimButton.Load(Parser, DynamicObject->mdKabina); - } - else if( Label == "battery_sw:" ) { - - ggBatteryButton.Load( Parser, DynamicObject->mdKabina ); + TGauge *gg { nullptr }; // roboczy wskaźnik na obiekt animujący gałkę + std::unordered_map gauges = { + { "mainctrl:", ggMainCtrl }, + { "scndctrl:", ggScndCtrl }, + { "dirkey:" , ggDirKey }, + { "brakectrl:", ggBrakeCtrl }, + { "localbrake:", ggLocalBrake }, + { "manualbrake:", ggManualBrake }, + { "brakeprofile_sw:", ggBrakeProfileCtrl }, + { "brakeprofileg_sw:", ggBrakeProfileG }, + { "brakeprofiler_sw:", ggBrakeProfileR }, + { "maxcurrent_sw:", ggMaxCurrentCtrl }, + { "main_off_bt:", ggMainOffButton }, + { "main_on_bt:", ggMainOnButton }, + { "security_reset_bt:", ggSecurityResetButton }, + { "releaser_bt:", ggReleaserButton }, + { "sand_bt:", ggSandButton }, + { "antislip_bt:", ggAntiSlipButton }, + { "horn_bt:", ggHornButton }, + { "hornlow_bt:", ggHornLowButton }, + { "hornhigh_bt:", ggHornHighButton }, + { "fuse_bt:", ggFuseButton }, + { "converterfuse_bt:", ggConverterFuseButton }, + { "stlinoff_bt:", ggStLinOffButton }, + { "door_left_sw:", ggDoorLeftButton }, + { "door_right_sw:", ggDoorRightButton }, + { "departure_signal_bt:", ggDepartureSignalButton }, + { "upperlight_sw:", ggUpperLightButton }, + { "leftlight_sw:", ggLeftLightButton }, + { "rightlight_sw:", ggRightLightButton }, + { "dimheadlights_sw:", ggDimHeadlightsButton }, + { "leftend_sw:", ggLeftEndLightButton }, + { "rightend_sw:", ggRightEndLightButton }, + { "lights_sw:", ggLightsButton }, + { "rearupperlight_sw:", ggRearUpperLightButton }, + { "rearleftlight_sw:", ggRearLeftLightButton }, + { "rearrightlight_sw:", ggRearRightLightButton }, + { "rearleftend_sw:", ggRearLeftEndLightButton }, + { "rearrightend_sw:", ggRearRightEndLightButton }, + { "compressor_sw:", ggCompressorButton }, + { "compressorlocal_sw:", ggCompressorLocalButton }, + { "converter_sw:", ggConverterButton }, + { "converterlocal_sw:", ggConverterLocalButton }, + { "converteroff_sw:", ggConverterOffButton }, + { "main_sw:", ggMainButton }, + { "radio_sw:", ggRadioButton }, + { "pantfront_sw:", ggPantFrontButton }, + { "pantrear_sw:", ggPantRearButton }, + { "pantfrontoff_sw:", ggPantFrontButtonOff }, + { "pantrearoff_sw:", ggPantRearButtonOff }, + { "pantalloff_sw:", ggPantAllDownButton }, + { "pantselected_sw:", ggPantSelectedButton }, + { "pantselectedoff_sw:", ggPantSelectedDownButton }, + { "trainheating_sw:", ggTrainHeatingButton }, + { "signalling_sw:", ggSignallingButton }, + { "door_signalling_sw:", ggDoorSignallingButton }, + { "nextcurrent_sw:", ggNextCurrentButton }, + { "cablight_sw:", ggCabLightButton }, + { "cablightdim_sw:", ggCabLightDimButton }, + { "battery_sw:", ggBatteryButton } + }; + auto lookup = gauges.find( Label ); + if( lookup != gauges.end() ) { + lookup->second.Load( Parser, DynamicObject->mdKabina ); + m_controlmapper.insert( lookup->second, lookup->first ); } // ABu 090305: uniwersalne przyciski lub inne rzeczy + else if( Label == "mainctrlact:" ) { + ggMainCtrlAct.Load( Parser, DynamicObject->mdKabina, DynamicObject->mdModel ); + } else if (Label == "universal1:") { ggUniversal1Button.Load(Parser, DynamicObject->mdKabina, DynamicObject->mdModel); diff --git a/Train.h b/Train.h index 2c70dc70..6daf8ac7 100644 --- a/Train.h +++ b/Train.h @@ -57,6 +57,18 @@ class TCab void Update(); }; +class control_mapper { + typedef std::unordered_map< TSubModel const *, std::string> submodelstring_map; + submodelstring_map m_controlnames; +public: + void + clear() { m_controlnames.clear(); } + void + insert( TGauge const &Gauge, std::string const &Label ); + std::string + find( TSubModel const *Control ) const; +}; + class TTrain { public: @@ -72,6 +84,7 @@ class TTrain inline vector3 GetDirection() { return DynamicObject->VectorFront(); }; inline vector3 GetUp() { return DynamicObject->VectorUp(); }; + inline std::string GetLabel( TSubModel const *Control ) const { return m_controlmapper.find( Control ); } void UpdateMechPosition(double dt); vector3 GetWorldMechPosition(); bool Update( double const Deltatime ); @@ -84,7 +97,7 @@ class TTrain private: // types - typedef void( *command_handler )( TTrain *Train, command_data const &Command ); + typedef void( *command_handler )( TTrain *Train, command_data const &Command ); typedef std::unordered_map commandhandler_map; // clears state of all cabin controls void clear_cab_controls(); @@ -184,8 +197,9 @@ class TTrain TMoverParameters *mvSecond; // drugi człon (ET40, ET41, ET42, ukrotnienia) TMoverParameters *mvThird; // trzeci człon (SN61) // helper variable, to prevent immediate switch between closing and opening line breaker circuit - int m_linebreakerstate{ 0 }; // -1: freshly open, 0: open, 1: closed, 2: freshly closed (and yes this is awful way to go about it) + int m_linebreakerstate { 0 }; // -1: freshly open, 0: open, 1: closed, 2: freshly closed (and yes this is awful way to go about it) static const commandhandler_map m_commandhandlers; + control_mapper m_controlmapper; public: // reszta może by?publiczna diff --git a/World.cpp b/World.cpp index 261e3308..c01d1264 100644 --- a/World.cpp +++ b/World.cpp @@ -180,6 +180,20 @@ simulation_time::julian_day() const { return JD; } +namespace locale { + +std::string +control( std::string const &Label ) { + + auto const lookup = m_controls.find( Label ); + return ( + lookup != m_controls.end() ? + lookup->second : + "" ); +} + +} + TWorld::TWorld() { // randomize(); @@ -1135,43 +1149,44 @@ void TWorld::Update_Camera( double const Deltatime ) { // Console::Update(); //tu jest zależne od FPS, co nie jest korzystne - if( glfwGetMouseButton( window, GLFW_MOUSE_BUTTON_LEFT ) == GLFW_PRESS ) { - Camera.Reset(); // likwidacja obrotów - patrzy horyzontalnie na południe - // if (!FreeFlyModeFlag) //jeśli wewnątrz - patrzymy do tyłu - // Camera.LookAt=Train->pMechPosition-Normalize(Train->GetDirection())*10; - if( Controlled ? LengthSquared3( Controlled->GetPosition() - Camera.Pos ) < 2250000 : - false ) // gdy bliżej niż 1.5km - Camera.LookAt = Controlled->GetPosition(); - else { - TDynamicObject *d = - Ground.DynamicNearest( Camera.Pos, 300 ); // szukaj w promieniu 300m - if( !d ) - d = Ground.DynamicNearest( Camera.Pos, - 1000 ); // dalej szukanie, jesli bliżej nie ma - if( d && pDynamicNearest ) // jeśli jakiś jest znaleziony wcześniej - if( 100.0 * LengthSquared3( d->GetPosition() - Camera.Pos ) > - LengthSquared3( pDynamicNearest->GetPosition() - Camera.Pos ) ) - d = pDynamicNearest; // jeśli najbliższy nie jest 10 razy bliżej niż - // poprzedni najbliższy, zostaje poprzedni - if( d ) - pDynamicNearest = d; // zmiana na nowy, jeśli coś znaleziony niepusty - if( pDynamicNearest ) - Camera.LookAt = pDynamicNearest->GetPosition(); + if( false == Global::ControlPicking ) { + if( glfwGetMouseButton( window, GLFW_MOUSE_BUTTON_LEFT ) == GLFW_PRESS ) { + Camera.Reset(); // likwidacja obrotów - patrzy horyzontalnie na południe + // if (!FreeFlyModeFlag) //jeśli wewnątrz - patrzymy do tyłu + // Camera.LookAt=Train->pMechPosition-Normalize(Train->GetDirection())*10; + if( Controlled && LengthSquared3( Controlled->GetPosition() - Camera.Pos ) < ( 1500 * 1500 ) ) // gdy bliżej niż 1.5km + Camera.LookAt = Controlled->GetPosition(); + else { + TDynamicObject *d = + Ground.DynamicNearest( Camera.Pos, 300 ); // szukaj w promieniu 300m + if( !d ) + d = Ground.DynamicNearest( Camera.Pos, + 1000 ); // dalej szukanie, jesli bliżej nie ma + if( d && pDynamicNearest ) // jeśli jakiś jest znaleziony wcześniej + if( 100.0 * LengthSquared3( d->GetPosition() - Camera.Pos ) > + LengthSquared3( pDynamicNearest->GetPosition() - Camera.Pos ) ) + d = pDynamicNearest; // jeśli najbliższy nie jest 10 razy bliżej niż + // poprzedni najbliższy, zostaje poprzedni + if( d ) + pDynamicNearest = d; // zmiana na nowy, jeśli coś znaleziony niepusty + if( pDynamicNearest ) + Camera.LookAt = pDynamicNearest->GetPosition(); + } + if( FreeFlyModeFlag ) + Camera.RaLook(); // jednorazowe przestawienie kamery + } + else if( glfwGetMouseButton( window, GLFW_MOUSE_BUTTON_RIGHT ) == GLFW_PRESS ) { //||Console::Pressed(VK_F4)) + FollowView( false ); // bez wyciszania dźwięków + } + else if( glfwGetMouseButton( window, GLFW_MOUSE_BUTTON_MIDDLE ) == GLFW_PRESS ) { + // middle mouse button controls zoom. + Global::ZoomFactor = std::min( 4.5f, Global::ZoomFactor + 15.0f * static_cast( Deltatime ) ); + } + else if( glfwGetMouseButton( window, GLFW_MOUSE_BUTTON_MIDDLE ) != GLFW_PRESS ) { + // reset zoom level if the button is no longer held down. + // NOTE: yes, this is terrible way to go about it. it'll do for now. + Global::ZoomFactor = std::max( 1.0f, Global::ZoomFactor - 15.0f * static_cast( Deltatime ) ); } - if( FreeFlyModeFlag ) - Camera.RaLook(); // jednorazowe przestawienie kamery - } - else if( glfwGetMouseButton( window, GLFW_MOUSE_BUTTON_RIGHT ) == GLFW_PRESS ) { //||Console::Pressed(VK_F4)) - FollowView( false ); // bez wyciszania dźwięków - } - else if( glfwGetMouseButton( window, GLFW_MOUSE_BUTTON_MIDDLE ) == GLFW_PRESS ) { - // middle mouse button controls zoom. - Global::ZoomFactor = std::min( 4.5f, Global::ZoomFactor + 15.0f * static_cast( Deltatime ) ); - } - else if( glfwGetMouseButton( window, GLFW_MOUSE_BUTTON_MIDDLE ) != GLFW_PRESS ) { - // reset zoom level if the button is no longer held down. - // NOTE: yes, this is terrible way to go about it. it'll do for now. - Global::ZoomFactor = std::max( 1.0f, Global::ZoomFactor - 15.0f * static_cast( Deltatime ) ); } Camera.Update(); // uwzględnienie ruchu wywołanego klawiszami @@ -1258,74 +1273,28 @@ void TWorld::ResourceSweep() */ }; -// rendering kabiny gdy jest oddzielnym modelem i ma byc wyswietlana -void -TWorld::Render_Cab() { - - if( Train == nullptr ) { - - TSubModel::iInstance = 0; - return; - } - - TDynamicObject *dynamic = Train->Dynamic(); - TSubModel::iInstance = reinterpret_cast( dynamic ); - - if( ( true == FreeFlyModeFlag ) - || ( false == dynamic->bDisplayCab ) - || ( dynamic->mdKabina == dynamic->mdModel ) ) { - // ABu: Rendering kabiny jako ostatniej, zeby bylo widac przez szyby, tylko w widoku ze srodka - return; - } -/* - glPushMatrix(); - vector3 pos = dynamic->GetPosition(); // wszpółrzędne pojazdu z kabiną - // glTranslatef(pos.x,pos.y,pos.z); //przesunięcie o wektor (tak było i trzęsło) - // aby pozbyć się choć trochę trzęsienia, trzeba by nie przeliczać kabiny do punktu - // zerowego scenerii - glLoadIdentity(); // zacząć od macierzy jedynkowej - Camera.SetCabMatrix( pos ); // widok z kamery po przesunięciu - glMultMatrixd( dynamic->mMatrix.getArray() ); // ta macierz nie ma przesunięcia -*/ - ::glPushMatrix(); - auto const originoffset = dynamic->GetPosition() - Global::pCameraPosition; - ::glTranslated( originoffset.x, originoffset.y, originoffset.z ); - ::glMultMatrixd( dynamic->mMatrix.getArray() ); - - if( dynamic->mdKabina ) // bo mogła zniknąć przy przechodzeniu do innego pojazdu - { - // setup - if( dynamic->fShade > 0.0f ) { - // change light level based on light level of the occupied track - Global::DayLight.apply_intensity( dynamic->fShade ); - } - if( dynamic->InteriorLightLevel > 0.0f ) { - // crude way to light the cabin, until we have something more complete in place - auto const cablight = dynamic->InteriorLight * dynamic->InteriorLightLevel; - ::glLightModelfv( GL_LIGHT_MODEL_AMBIENT, &cablight.x ); - } - // render - GfxRenderer.Render( dynamic->mdKabina, dynamic->Material(), 0.0 ); - GfxRenderer.Render_Alpha( dynamic->mdKabina, dynamic->Material(), 0.0 ); - // post-render restore - if( dynamic->fShade > 0.0f ) { - // change light level based on light level of the occupied track - Global::DayLight.apply_intensity(); - } - if( dynamic->InteriorLightLevel > 0.0f ) { - // reset the overall ambient - GLfloat ambient[] = { 0.0f, 0.0f, 0.0f, 1.0f }; - ::glLightModelfv( GL_LIGHT_MODEL_AMBIENT, ambient ); - } - } - glPopMatrix(); -} - void TWorld::Update_UI() { UITable->text_lines.clear(); std::string uitextline1, uitextline2, uitextline3, uitextline4; + UILayer.set_tooltip( "" ); + + if( ( Train != nullptr ) && ( false == FreeFlyModeFlag ) ) { + if( false == DebugModeFlag ) { + // in regular mode show control functions, for defined controls + UILayer.set_tooltip( locale::control( Train->GetLabel( GfxRenderer.Pick_Control() ) ) ); + } + else { + // in debug mode show names of submodels, to help with cab setup and/or debugging + auto const cabcontrol = GfxRenderer.Pick_Control(); + UILayer.set_tooltip( ( cabcontrol ? cabcontrol->pName : "" ) ); + } + } + if( ( true == Global::ControlPicking ) && ( true == FreeFlyModeFlag ) && ( true == DebugModeFlag ) ) { + auto const scenerynode = GfxRenderer.Pick_Node(); + UILayer.set_tooltip( ( scenerynode ? scenerynode->asName : "" ) ); + } switch( Global::iTextMode ) { @@ -2338,9 +2307,6 @@ world_environment::update() { Global::FogColor[ 0 ] = skydomecolour.x; Global::FogColor[ 1 ] = skydomecolour.y; Global::FogColor[ 2 ] = skydomecolour.z; - ::glFogfv( GL_FOG_COLOR, Global::FogColor ); // kolor mgły - - ::glClearColor( skydomecolour.x, skydomecolour.y, skydomecolour.z, 1.0f ); // kolor nieba } void diff --git a/World.h b/World.h index 36ae1b76..67d8d2bb 100644 --- a/World.h +++ b/World.h @@ -60,6 +60,74 @@ extern simulation_time Time; } +namespace locale { + +std::string + control( std::string const &Label ); + +static std::unordered_map m_controls = { + { "mainctrl:", "master controller" }, + { "scndctrl:", "second controller" }, + { "dirkey:" , "reverser" }, + { "brakectrl:", "train brake" }, + { "localbrake:", "independent brake" }, + { "manualbrake:", "manual brake" }, + { "brakeprofile_sw:", "brake acting speed" }, + { "brakeprofileg_sw:", "brake acting speed: cargo" }, + { "brakeprofiler_sw:", "brake acting speed: rapid" }, + { "maxcurrent_sw:", "motor overload relay threshold" }, + { "main_off_bt:", "line breaker" }, + { "main_on_bt:", "line breaker" }, + { "security_reset_bt:", "alerter" }, + { "releaser_bt:", "independent brake releaser" }, + { "sand_bt:", "sandbox" }, + { "antislip_bt:", "wheelspin brake" }, + { "horn_bt:", "horn" }, + { "hornlow_bt:", "low tone horn" }, + { "hornhigh_bt:", "high tone horn" }, + { "fuse_bt:", "motor overload relay reset" }, + { "converterfuse_bt:", "converter overload relay reset" }, + { "stlinoff_bt:", "motor connectors" }, + { "door_left_sw:", "left door" }, + { "door_right_sw:", "right door" }, + { "departure_signal_bt:", "departure signal" }, + { "upperlight_sw:", "upper headlight" }, + { "leftlight_sw:", "left headlight" }, + { "rightlight_sw:", "right headlight" }, + { "dimheadlights_sw:", "headlights dimmer" }, + { "leftend_sw:", "left marker light" }, + { "rightend_sw:", "right marker light" }, + { "lights_sw:", "light pattern" }, + { "rearupperlight_sw:", "rear upper headlight" }, + { "rearleftlight_sw:", "rear left headlight" }, + { "rearrightlight_sw:", "rear right headlight" }, + { "rearleftend_sw:", "rear left marker light" }, + { "rearrightend_sw:", "rear right marker light" }, + { "compressor_sw:", "compressor" }, + { "compressorlocal_sw:", "local compressor" }, + { "converter_sw:", "converter" }, + { "converterlocal_sw:", "local converter" }, + { "converteroff_sw:", "converter" }, + { "main_sw:", "line breaker" }, + { "radio_sw:", "radio" }, + { "pantfront_sw:", "front pantograph" }, + { "pantrear_sw:", "rear pantograph" }, + { "pantfrontoff_sw:", "front pantograph" }, + { "pantrearoff_sw:", "rear pantograph" }, + { "pantalloff_sw:", "all pantographs" }, + { "pantselected_sw:", "selected pantograph" }, + { "pantselectedoff_sw:", "selected pantograph" }, + { "trainheating_sw:", "heating" }, + { "signalling_sw:", "braking indicator" }, + { "door_signalling_sw:", "door locking" }, + { "nextcurrent_sw:", "current indicator source" }, + { "cablight_sw:", "interior light" }, + { "cablightdim_sw:", "interior light dimmer" }, + { "battery_sw:", "battery" } +}; + +} + // wrapper for environment elements -- sky, sun, stars, clouds etc class world_environment { @@ -106,6 +174,8 @@ TWorld(); void OnCommandGet(DaneRozkaz *pRozkaz); bool Update(); void TrainDelete(TDynamicObject *d = NULL); + TTrain const * + train() const { return Train; } // switches between static and dynamic daylight calculation void ToggleDaylight(); @@ -114,7 +184,6 @@ private: void Update_Camera( const double Deltatime ); void Update_UI(); void ResourceSweep(); - void Render_Cab(); TCamera Camera; TGround Ground; diff --git a/command.h b/command.h index 35649d9e..5d688827 100644 --- a/command.h +++ b/command.h @@ -120,10 +120,11 @@ const int k_Univ4 = 69; const int k_EndSign = 70; const int k_Active = 71; */ - batterytoggle + batterytoggle, /* const int k_WalkMode = 73; */ + none = -1 }; enum class command_target { diff --git a/dumb3d.h b/dumb3d.h index 66e7fda3..74c4c312 100644 --- a/dumb3d.h +++ b/dumb3d.h @@ -64,18 +64,16 @@ class vector3 public: vector3(void) : x(0.0), y(0.0), z(0.0) - { - } - vector3(scalar_t a, scalar_t b, scalar_t c) - { - x = a; - y = b; - z = c; - } + {} + vector3( scalar_t X, scalar_t Y, scalar_t Z ) : + x( X ), y( Y ), z( Z ) + {} vector3( glm::dvec3 const &Vector ) : x( Vector.x ), y( Vector.y ), z( Vector.z ) {} - + template + operator glm::tvec3() const { + return glm::tvec3{ x, y, z }; } // The int parameter is the number of elements to copy from initArray (3 or 4) // explicit vector3(scalar_t* initArray, int arraySize = 3) // { for (int i = 0;iGetLabel( GfxRenderer.Update_Pick_Control() ) ); + if( lookup != m_mousecommands.end() ) { + mousecommand = ( + Button == GLFW_MOUSE_BUTTON_LEFT ? + lookup->second.left : + lookup->second.right + ); + if( mousecommand != user_command::none ) { + // NOTE: basic keyboard controls don't have any parameters + // as we haven't yet implemented either item id system or multiplayer, the 'local' controlled vehicle and entity have temporary ids of 0 + // TODO: pass correct entity id once the missing systems are in place + m_relay.post( mousecommand, 0, 0, Action, 0 ); + m_updateaccumulator = 0.0; // prevent potential command repeat right after issuing one + } + } + } + } +} + +void +keyboard_input::poll() { + + m_updateaccumulator += Timer::GetDeltaRenderTime(); + + if( m_updateaccumulator < 0.2 ) { + // too early for any work + return; + } + m_updateaccumulator -= 0.2; + + if( m_mousecommandleft != user_command::none ) { + // NOTE: basic keyboard controls don't have any parameters + // as we haven't yet implemented either item id system or multiplayer, the 'local' controlled vehicle and entity have temporary ids of 0 + // TODO: pass correct entity id once the missing systems are in place + m_relay.post( m_mousecommandleft, 0, 0, GLFW_REPEAT, 0 ); + } + if( m_mousecommandright != user_command::none ) { + // NOTE: basic keyboard controls don't have any parameters + // as we haven't yet implemented either item id system or multiplayer, the 'local' controlled vehicle and entity have temporary ids of 0 + // TODO: pass correct entity id once the missing systems are in place + m_relay.post( m_mousecommandright, 0, 0, GLFW_REPEAT, 0 ); + } +} + void keyboard_input::default_bindings() { @@ -366,6 +445,183 @@ const int k_WalkMode = 73; }; bind(); + + m_mousecommands = { + { "mainctrl:", { + user_command::mastercontrollerincrease, + user_command::mastercontrollerdecrease } }, + { "scndctrl:", { + user_command::secondcontrollerincrease, + user_command::secondcontrollerdecrease } }, + { "dirkey:", { + user_command::reverserincrease, + user_command::reverserdecrease } }, + { "brakectrl:", { + user_command::trainbrakedecrease, + user_command::trainbrakeincrease } }, + { "localbrake:", { + user_command::independentbrakedecrease, + user_command::independentbrakeincrease } }, + { "manualbrake:", { + user_command::none, + user_command::none } }, + { "brakeprofile_sw:", { + user_command::brakeactingspeedincrease, + user_command::brakeactingspeeddecrease } }, + { "brakeprofileg_sw:", { + user_command::brakeactingspeeddecrease, + user_command::none } }, + { "brakeprofiler_sw:", { + user_command::brakeactingspeedincrease, + user_command::none } }, + { "maxcurrent_sw:", { + user_command::motoroverloadrelaythresholdtoggle, + user_command::none } }, + { "main_off_bt:", { + user_command::linebreakertoggle, + user_command::none } }, + { "main_on_bt:",{ + user_command::linebreakertoggle, + user_command::none } }, // TODO: dedicated on and off line breaker commands + { "security_reset_bt:", { + user_command::alerteracknowledge, + user_command::none } }, + { "releaser_bt:", { + user_command::independentbrakebailoff, + user_command::none } }, + { "sand_bt:", { + user_command::sandboxactivate, + user_command::none } }, + { "antislip_bt:", { + user_command::wheelspinbrakeactivate, + user_command::none } }, + { "horn_bt:", { + user_command::hornhighactivate, + user_command::hornlowactivate } }, + { "hornlow_bt:", { + user_command::hornlowactivate, + user_command::none } }, + { "hornhigh_bt:", { + user_command::hornhighactivate, + user_command::none } }, + { "fuse_bt:", { + user_command::motoroverloadrelayreset, + user_command::none } }, + { "converterfuse_bt:", { + user_command::converteroverloadrelayreset, + user_command::none } }, + { "stlinoff_bt:", { + user_command::motorconnectorsopen, + user_command::none } }, + { "door_left_sw:", { + user_command::doortoggleleft, + user_command::none } }, + { "door_right_sw:", { + user_command::doortoggleright, + user_command::none } }, + { "departure_signal_bt:", { + user_command::departureannounce, + user_command::none } }, + { "upperlight_sw:", { + user_command::headlighttoggleupper, + user_command::none } }, + { "leftlight_sw:", { + user_command::headlighttoggleleft, + user_command::none } }, + { "rightlight_sw:", { + user_command::headlighttoggleright, + user_command::none } }, + { "dimheadlights_sw:", { + user_command::headlightsdimtoggle, + user_command::none } }, + { "leftend_sw:", { + user_command::redmarkertoggleleft, + user_command::none } }, + { "rightend_sw:", { + user_command::redmarkertoggleright, + user_command::none } }, + { "lights_sw:", { + user_command::none, + user_command::none } }, // TODO: implement commands for lights controller + { "rearupperlight_sw:", { + user_command::headlighttogglerearupper, + user_command::none } }, + { "rearleftlight_sw:", { + user_command::headlighttogglerearleft, + user_command::none } }, + { "rearrightlight_sw:", { + user_command::headlighttogglerearright, + user_command::none } }, + { "rearleftend_sw:", { + user_command::redmarkertogglerearleft, + user_command::none } }, + { "rearrightend_sw:", { + user_command::redmarkertogglerearright, + user_command::none } }, + { "compressor_sw:", { + user_command::compressortoggle, + user_command::none } }, + { "compressorlocal_sw:", { + user_command::compressortogglelocal, + user_command::none } }, + { "converter_sw:", { + user_command::convertertoggle, + user_command::none } }, + { "converterlocal_sw:", { + user_command::convertertogglelocal, + user_command::none } }, + { "converteroff_sw:", { + user_command::convertertoggle, + user_command::none } }, // TODO: dedicated converter shutdown command + { "main_sw:", { + user_command::linebreakertoggle, + user_command::none } }, + { "radio_sw:", { + user_command::radiotoggle, + user_command::none } }, + { "pantfront_sw:", { + user_command::pantographtogglefront, + user_command::none } }, + { "pantrear_sw:", { + user_command::pantographtogglerear, + user_command::none } }, + { "pantfrontoff_sw:", { + user_command::pantographtogglefront, + user_command::none } }, // TODO: dedicated lower pantograph commands + { "pantrearoff_sw:", { + user_command::pantographtogglerear, + user_command::none } }, // TODO: dedicated lower pantograph commands + { "pantalloff_sw:", { + user_command::pantographlowerall, + user_command::none } }, + { "pantselected_sw:", { + user_command::none, + user_command::none } }, // TODO: selected pantograph(s) operation command + { "pantselectedoff_sw:", { + user_command::none, + user_command::none } }, // TODO: lower selected pantograp(s) command + { "trainheating_sw:", { + user_command::heatingtoggle, + user_command::none } }, + { "signalling_sw:", { + user_command::mubrakingindicatortoggle, + user_command::none } }, + { "door_signalling_sw:", { + user_command::doorlocktoggle, + user_command::none } }, + { "nextcurrent_sw:", { + user_command::mucurrentindicatorothersourceactivate, + user_command::none } }, + { "cablight_sw:", { + user_command::interiorlighttoggle, + user_command::none } }, + { "cablightdim_sw:", { + user_command::interiorlightdimtoggle, + user_command::none } }, + { "battery_sw:", { + user_command::batterytoggle, + user_command::none } } + }; } void diff --git a/keyboardinput.h b/keyboardinput.h index 65a4546c..dd15b2c1 100644 --- a/keyboardinput.h +++ b/keyboardinput.h @@ -28,6 +28,10 @@ public: key( int const Key, int const Action ); void mouse( double const Mousex, double const Mousey ); + void + mouse( int const Button, int const Action ); + void + poll(); private: // types @@ -45,6 +49,18 @@ private: typedef std::vector commandsetup_sequence; typedef std::unordered_map usercommand_map; + struct mouse_commands { + + user_command left; + user_command right; + + mouse_commands( user_command const Left, user_command const Right ): + left(Left), right(Right) + {} + }; + + typedef std::unordered_map controlcommands_map; + struct bindings_cache { int forward{ -1 }; @@ -66,9 +82,13 @@ private: // members commandsetup_sequence m_commands; usercommand_map m_bindings; + controlcommands_map m_mousecommands; + user_command m_mousecommandleft { user_command::none }; // last if any command issued with mouse + user_command m_mousecommandright { user_command::none }; command_relay m_relay; bool m_shift{ false }; bool m_ctrl{ false }; + double m_updateaccumulator { 0.0 }; bindings_cache m_bindingscache; std::array m_keys; }; diff --git a/renderer.cpp b/renderer.cpp index 32c4272d..bde34e81 100644 --- a/renderer.cpp +++ b/renderer.cpp @@ -13,6 +13,7 @@ http://mozilla.org/MPL/2.0/. #include "globals.h" #include "timer.h" #include "world.h" +#include "train.h" #include "data.h" #include "dynobj.h" #include "animmodel.h" @@ -118,6 +119,42 @@ opengl_renderer::Init( GLFWwindow *Window ) { m_lights.emplace_back( light ); } +#ifdef EU07_USE_PICKING_FRAMEBUFFER + if( true == m_framebuffersupport ) { + // try to create the pick buffer. RGBA8 2D texture, 24 bit depth texture, 1024x512 + int const width { 1024 }; + int const height { 512 }; + // texture + ::glGenTextures( 1, &m_picktexture ); + ::glBindTexture( GL_TEXTURE_2D, m_picktexture ); + ::glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); + ::glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); + ::glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); + ::glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); + ::glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL ); + // depth buffer + ::glGenRenderbuffersEXT( 1, &m_pickdepthbuffer ); + ::glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, m_pickdepthbuffer ); + ::glRenderbufferStorageEXT( GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24, width, height ); + // create and set up the framebuffer + ::glGenFramebuffersEXT( 1, &m_pickframebuffer ); + ::glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, m_pickframebuffer ); + ::glFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, m_picktexture, 0 ); + ::glFramebufferRenderbufferEXT( GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_pickdepthbuffer ); + //------------------------- + //Does the GPU support current FBO configuration? + GLenum status = ::glCheckFramebufferStatusEXT( GL_FRAMEBUFFER_EXT ); + if( status == GL_FRAMEBUFFER_COMPLETE_EXT ) { + WriteLog( "Picking framebuffer setup complete" ); + } + else{ + ErrorLog( "Picking framebuffer setup failed" ); + m_framebuffersupport = false; + } + ::glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 ); // switch back to primary render target for now + } +#endif + ::glPixelStorei( GL_UNPACK_ALIGNMENT, 1 ); // preload some common textures WriteLog( "Loading common gfx data..." ); m_glaretexture = GetTextureId( "fx\\lightglare", szTexturePath ); @@ -136,8 +173,8 @@ opengl_renderer::Init( GLFWwindow *Window ) { geometrybank, GL_TRIANGLE_STRIP ); // prepare debug mode objects - m_quadric = gluNewQuadric(); - gluQuadricNormals( m_quadric, GLU_FLAT ); + m_quadric = ::gluNewQuadric(); + ::gluQuadricNormals( m_quadric, GLU_FLAT ); return true; } @@ -145,54 +182,252 @@ opengl_renderer::Init( GLFWwindow *Window ) { bool opengl_renderer::Render() { - auto timestart = std::chrono::steady_clock::now(); + auto const drawstart = std::chrono::steady_clock::now(); - ::glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); - ::glDepthFunc( GL_LEQUAL ); + Render_pass( rendermode::color ); + glfwSwapBuffers( m_window ); - ::glMatrixMode( GL_PROJECTION ); // select the Projection Matrix - ::gluPerspective( - Global::FieldOfView / Global::ZoomFactor, - std::max( 1.0f, (float)Global::ScreenWidth ) / std::max( 1.0f, (float)Global::ScreenHeight ), - 0.1f * Global::ZoomFactor, - m_drawrange * Global::fDistanceFactor ); + m_drawcount = m_renderpass.draw_queue.size(); + // accumulate last 20 frames worth of render time (cap at 1000 fps to prevent calculations going awry) + m_drawtime = std::max( 20.0f, 0.95f * m_drawtime + std::chrono::duration_cast( ( std::chrono::steady_clock::now() - drawstart ) ).count() ); + + return true; // for now always succeed +} + +// runs jobs needed to generate graphics for specified render pass +void +opengl_renderer::Render_pass( rendermode const Mode ) { + + m_renderpass.draw_mode = Mode; + switch( m_renderpass.draw_mode ) { + + case rendermode::color: { + + // TODO: run shadowmap pass before color + +// ::glViewport( 0, 0, Global::ScreenWidth, Global::ScreenHeight ); + auto const skydomecolour = World.Environment.m_skydome.GetAverageColor(); + ::glClearColor( skydomecolour.x, skydomecolour.y, skydomecolour.z, 0.0f ); // kolor nieba + ::glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); + + if( World.InitPerformed() ) { + // setup + m_renderpass.draw_range = 2500.0f; // arbitrary base draw range + Render_projection(); + Render_camera(); + ::glDepthFunc( GL_LEQUAL ); + // render + Render_setup( true ); + Render( &World.Environment ); + // opaque parts... + Render_setup(); + Render( &World.Ground ); + // ...translucent parts + Render_setup( true ); + Render_Alpha( &World.Ground ); + // cab render is done in translucent phase to deal with badly configured vehicles + if( World.Train != nullptr ) { Render_cab( World.Train->Dynamic() ); } + } + UILayer.render(); + break; + } + + case rendermode::pickcontrols: { + +// ::glViewport( 0, 0, 1024, 512 ); + ::glClearColor( 0.0f, 0.0f, 0.0f, 0.0f ); + ::glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); + + if( World.InitPerformed() ) { + // setup + m_pickcontrolsitems.clear(); + m_renderpass.draw_range = 50.0f; // doesn't really matter for control picking + Render_projection(); + Render_camera(); + ::glDepthFunc( GL_LEQUAL ); + // render + // opaque parts... + Render_setup(); + // cab render skips translucent parts, so we can do it here + if( World.Train != nullptr ) { Render_cab( World.Train->Dynamic() ); } + } + // post-render cleanup + break; + } + + case rendermode::pickscenery: { + +// ::glViewport( 0, 0, 1024, 512 ); + ::glClearColor( 0.0f, 0.0f, 0.0f, 0.0f ); + ::glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); + + if( World.InitPerformed() ) { + // setup + m_picksceneryitems.clear(); + m_renderpass.draw_range = 1000.0f; // scenery picking is likely to focus on nearby nodes + Render_projection(); + Render_camera(); + ::glDepthFunc( GL_LEQUAL ); + // render + // opaque parts... + Render_setup(); + Render( &World.Ground ); + } + break; + } + + default: { + break; + } + } + +} + +// configures projection matrix for the current render pass +void +opengl_renderer::Render_projection() { + + ::glMatrixMode( GL_PROJECTION ); + ::glLoadIdentity(); + + switch( m_renderpass.draw_mode ) { + + case rendermode::color: + case rendermode::pickcontrols: + case rendermode::pickscenery: { + ::gluPerspective( + Global::FieldOfView / Global::ZoomFactor, + std::max( 1.0f, (float)Global::ScreenWidth ) / std::max( 1.0f, (float)Global::ScreenHeight ), + 0.1f * Global::ZoomFactor, + m_renderpass.draw_range * Global::fDistanceFactor ); + break; + } +/* + // version for the smaller pickbuffer. ultimately scratched because resolution isn't comfortable/reliable enough for the user + case rendermode::pickcontrols: + case rendermode::pickscenery: { + // TODO: render to buffer and scissor test for pick modes + ::gluPerspective( + Global::FieldOfView / Global::ZoomFactor, + std::max( 1.0f, (float)Global::ScreenWidth ) / std::max( 1.0f, (float)Global::ScreenHeight ) / ( Global::ScreenWidth / 1024.0f ), + 0.1f * Global::ZoomFactor, + m_renderpass.draw_range * Global::fDistanceFactor ); + break; + } +*/ + case rendermode::shadows: { + // TODO: set parallel projection + break; + } + + default: { + break; + } + } +} + +// configures modelview matrix for the current render pass +void +opengl_renderer::Render_camera() { ::glMatrixMode( GL_MODELVIEW ); // Select The Modelview Matrix ::glLoadIdentity(); - if( World.InitPerformed() ) { + glm::dmat4 viewmatrix; - glm::dmat4 viewmatrix; - // camera view - World.Camera.SetMatrix( viewmatrix ); - m_camera.position() = glm::make_vec3( Global::pCameraPosition.getArray() ); -/* - // light view - m_camera.position() = glm::make_vec3( Global::pCameraPosition.getArray() ) - glm::dvec3( Global::DayLight.direction * 750.0f ); - m_camera.position().y = std::max( 50.0, m_camera.position().y ); // prevent shadow source from dipping too low - viewmatrix = glm::lookAt( - m_camera.position(), - glm::dvec3( Global::pCameraPosition.x, 0.0, Global::pCameraPosition.z ), - glm::dvec3( 0.0f, 1.0f, 0.0f ) ); -*/ - m_camera.update_frustum( OpenGLMatrices.data( GL_PROJECTION ), viewmatrix ); - // frustum tests are performed in 'world space' but after we set up frustum we no longer need camera translation, only rotation - ::glMultMatrixd( glm::value_ptr( glm::dmat4( glm::dmat3( viewmatrix )))); - - Render( &World.Environment ); - Render( &World.Ground ); - - World.Render_Cab(); - - // accumulate last 20 frames worth of render time (cap at 1000 fps to prevent calculations going awry) - m_drawtime = std::max( 20.0f, 0.95f * m_drawtime + std::chrono::duration_cast( ( std::chrono::steady_clock::now() - timestart ) ).count()); - m_drawcount = m_drawqueue.size(); + switch( m_renderpass.draw_mode ) { + case rendermode::color: + case rendermode::pickcontrols: + case rendermode::pickscenery: { + World.Camera.SetMatrix( viewmatrix ); + m_renderpass.camera.position() = Global::pCameraPosition; + break; + } + case rendermode::shadows: { + m_renderpass.camera.position() = Global::pCameraPosition - glm::dvec3{ Global::DayLight.direction * 750.0f }; + m_renderpass.camera.position().y = std::max( 50.0, m_renderpass.camera.position().y ); // prevent shadow source from dipping too low + viewmatrix = glm::lookAt( + m_renderpass.camera.position(), + glm::dvec3{ Global::pCameraPosition.x, 0.0, Global::pCameraPosition.z }, + glm::dvec3{ 0.0f, 1.0f, 0.0f } ); + break; + } + default: { + break; } } - UILayer.render(); + m_renderpass.camera.update_frustum( OpenGLMatrices.data( GL_PROJECTION ), viewmatrix ); + // frustum tests are performed in 'world space' but after we set up frustum we no longer need camera translation, only rotation + ::glMultMatrixd( glm::value_ptr( glm::dmat4( glm::dmat3( viewmatrix ) ) ) ); +} - glfwSwapBuffers( m_window ); - return true; // for now always succeed +void +opengl_renderer::Render_setup( bool const Alpha ) { + + if( true == Alpha ) { + + ::glEnable( GL_BLEND ); + ::glAlphaFunc( GL_GREATER, 0.04f ); + } + else { + ::glDisable( GL_BLEND ); + ::glAlphaFunc( GL_GREATER, 0.50f ); + } + + switch( m_renderpass.draw_mode ) { + case rendermode::color: { + ::glEnable( GL_LIGHTING ); + ::glShadeModel( GL_SMOOTH ); + // setup fog + if( Global::fFogEnd > 0 ) { + // fog setup + ::glFogfv( GL_FOG_COLOR, Global::FogColor ); + ::glFogf( GL_FOG_DENSITY, static_cast( 1.0 / Global::fFogEnd ) ); + ::glEnable( GL_FOG ); + } + else { ::glDisable( GL_FOG ); } + + if( m_texenvmode != m_renderpass.draw_mode ) { + // texture colour and alpha + ::glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE ); + ::glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE ); + ::glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE ); + ::glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR ); +/* + ::glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE ); + ::glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE ); + ::glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA ); +*/ + m_texenvmode = m_renderpass.draw_mode; + } + break; + } + case rendermode::shadows: + case rendermode::pickcontrols: + case rendermode::pickscenery: { + ::glDisable( GL_FOG ); + ::glDisable( GL_LIGHTING ); + ::glShadeModel( GL_FLAT ); + + if( m_texenvmode != m_renderpass.draw_mode ) { + // solid colour with texture alpha + ::glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE ); + ::glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE ); + ::glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PRIMARY_COLOR ); // or GL_PREVIOUS + ::glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR ); +/* + ::glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE ); + ::glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE ); + ::glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA ); +*/ + m_texenvmode = m_renderpass.draw_mode; + } + break; + } + default: { + break; + } + } } bool @@ -209,14 +444,6 @@ opengl_renderer::Render( world_environment *Environment ) { ::glDisable( GL_DEPTH_TEST ); ::glDepthMask( GL_FALSE ); ::glPushMatrix(); - // setup fog - if( Global::fFogEnd > 0 ) { - // fog setup - ::glFogfv( GL_FOG_COLOR, Global::FogColor ); - ::glFogf( GL_FOG_DENSITY, static_cast( 1.0 / Global::fFogEnd ) ); - ::glEnable( GL_FOG ); - } - else { ::glDisable( GL_FOG ); } Environment->m_skydome.Render(); if( true == Global::bUseVBO ) { @@ -381,65 +608,96 @@ opengl_renderer::Texture( texture_handle const Texture ) { bool opengl_renderer::Render( TGround *Ground ) { - ::glEnable( GL_LIGHTING ); - ::glDisable( GL_BLEND ); - ::glAlphaFunc( GL_GREATER, 0.50f ); // im mniejsza wartość, tym większa ramka, domyślnie 0.1f - ::glColor3f( 1.0f, 1.0f, 1.0f ); - ++TGroundRect::iFrameNumber; // zwięszenie licznika ramek (do usuwniania nadanimacji) - Update_Lights( Ground->m_lights ); + m_renderpass.draw_queue.clear(); - m_drawqueue.clear(); - - // rednerowanie globalnych (nie za często?) - for( TGroundNode *node = Ground->srGlobal.nRenderHidden; node; node = node->nNext3 ) { - node->RenderHidden(); - } - - glm::vec3 const cameraposition { m_camera.position() }; - int const camerax = static_cast( std::floor( cameraposition.x / 1000.0f ) + iNumRects / 2 ); - int const cameraz = static_cast( std::floor( cameraposition.z / 1000.0f ) + iNumRects / 2 ); - int const segmentcount = 2 * static_cast(std::ceil( m_drawrange * Global::fDistanceFactor / 1000.0f )); - int const originx = std::max( 0, camerax - segmentcount / 2 ); - int const originz = std::max( 0, cameraz - segmentcount / 2 ); - - for( int column = originx; column <= originx + segmentcount; ++column ) { - for( int row = originz; row <= originz + segmentcount; ++row ) { - - auto *cell = &Ground->Rects[ column ][ row ]; - - for( int subcellcolumn = 0; subcellcolumn < iNumSubRects; ++subcellcolumn ) { - for( int subcellrow = 0; subcellrow < iNumSubRects; ++subcellrow ) { - auto subcell = cell->FastGetSubRect( subcellcolumn, subcellrow ); - if( subcell == nullptr ) { continue; } - // renderowanie obiektów aktywnych a niewidocznych - for( auto node = subcell->nRenderHidden; node; node = node->nNext3 ) { - node->RenderHidden(); - } - // jeszcze dźwięki pojazdów by się przydały, również niewidocznych - subcell->RenderSounds(); - } - } - - if( m_camera.visible( cell->m_area ) ) { - Render( cell ); + switch( m_renderpass.draw_mode ) { + case rendermode::color: { + // rednerowanie globalnych (nie za często?) + for( TGroundNode *node = Ground->srGlobal.nRenderHidden; node; node = node->nNext3 ) { + node->RenderHidden(); } + break; + } + default: { + break; } } - // draw queue was filled while rendering content of ground cells. now sort the nodes based on their distance to viewer... - std::sort( - std::begin( m_drawqueue ), - std::end( m_drawqueue ), - []( distancesubcell_pair const &Left, distancesubcell_pair const &Right ) { - return ( Left.first ) < ( Right.first ); } ); - // ...then render the opaque content of the visible subcells. - for( auto subcellpair : m_drawqueue ) { - Render( subcellpair.second ); + glm::vec3 const cameraposition { m_renderpass.camera.position() }; + int const camerax = static_cast( std::floor( cameraposition.x / 1000.0f ) + iNumRects / 2 ); + int const cameraz = static_cast( std::floor( cameraposition.z / 1000.0f ) + iNumRects / 2 ); + int const segmentcount = 2 * static_cast(std::ceil( m_renderpass.draw_range * Global::fDistanceFactor / 1000.0f )); + int const originx = std::max( 0, camerax - segmentcount / 2 ); + int const originz = std::max( 0, cameraz - segmentcount / 2 ); + + switch( m_renderpass.draw_mode ) { + case rendermode::color: { + + Update_Lights( Ground->m_lights ); + + for( int column = originx; column <= originx + segmentcount; ++column ) { + for( int row = originz; row <= originz + segmentcount; ++row ) { + + auto *cell = &Ground->Rects[ column ][ row ]; + + for( int subcellcolumn = 0; subcellcolumn < iNumSubRects; ++subcellcolumn ) { + for( int subcellrow = 0; subcellrow < iNumSubRects; ++subcellrow ) { + auto subcell = cell->FastGetSubRect( subcellcolumn, subcellrow ); + if( subcell == nullptr ) { continue; } + // renderowanie obiektów aktywnych a niewidocznych + for( auto node = subcell->nRenderHidden; node; node = node->nNext3 ) { + node->RenderHidden(); + } + // jeszcze dźwięki pojazdów by się przydały, również niewidocznych + subcell->RenderSounds(); + } + } + + if( m_renderpass.camera.visible( cell->m_area ) ) { + Render( cell ); + } + } + } + // draw queue was filled while rendering content of ground cells. now sort the nodes based on their distance to viewer... + std::sort( + std::begin( m_renderpass.draw_queue ), + std::end( m_renderpass.draw_queue ), + []( distancesubcell_pair const &Left, distancesubcell_pair const &Right ) { + return ( Left.first ) < ( Right.first ); } ); + // ...then render the opaque content of the visible subcells. + for( auto subcellpair : m_renderpass.draw_queue ) { + Render( subcellpair.second ); + } + break; + } + case rendermode::shadows: + case rendermode::pickscenery: { + // these render modes don't bother with anything non-visual, or lights + for( int column = originx; column <= originx + segmentcount; ++column ) { + for( int row = originz; row <= originz + segmentcount; ++row ) { + + auto *cell = &Ground->Rects[ column ][ row ]; + if( m_renderpass.camera.visible( cell->m_area ) ) { + Render( cell ); + } + } + } + // they can also skip queue sorting, as they only deal with opaque geometry + // NOTE: there's benefit from rendering front-to-back, but is it significant enough? TODO: investigate + for( auto subcellpair : m_renderpass.draw_queue ) { + Render( subcellpair.second ); + } + break; + } + case rendermode::pickcontrols: + default: { + break; + } } - // now hand the control over to the renderer of translucent parts, it'll do the rest - return Render_Alpha( Ground ); + + return true; } bool @@ -451,6 +709,19 @@ opengl_renderer::Render( TGroundRect *Groundcell ) { // tylko jezeli dany kwadrat nie był jeszcze renderowany Groundcell->LoadNodes(); // ewentualne tworzenie siatek + switch( m_renderpass.draw_mode ) { + case rendermode::pickscenery: { + // non-interactive scenery elements get neutral colour + ::glColor3fv( glm::value_ptr( colors::none ) ); + break; + } + case rendermode::shadows: + case rendermode::color: + case rendermode::pickcontrols: + default: { + break; + } + } if( Groundcell->nRenderRect != nullptr ) { // nieprzezroczyste trójkąty kwadratu kilometrowego for( TGroundNode *node = Groundcell->nRenderRect; node != nullptr; node = node->nNext3 ) { @@ -470,8 +741,8 @@ opengl_renderer::Render( TGroundRect *Groundcell ) { auto subcell = Groundcell->pSubRects + subcellindex; if( subcell->iNodeCount ) { // o ile są jakieś obiekty, bo po co puste sektory przelatywać - m_drawqueue.emplace_back( - glm::length2( m_camera.position() - glm::dvec3( subcell->m_area.center ) ), + m_renderpass.draw_queue.emplace_back( + glm::length2( m_renderpass.camera.position() - glm::dvec3( subcell->m_area.center ) ), subcell ); } } @@ -489,43 +760,90 @@ opengl_renderer::Render( TSubRect *Groundsubcell ) { Groundsubcell->RaAnimate(); // przeliczenia animacji torów w sektorze TGroundNode *node; - // nieprzezroczyste obiekty terenu - for( node = Groundsubcell->nRenderRect; node != nullptr; node = node->nNext3 ) { - Render( node ); - } - // nieprzezroczyste obiekty (oprócz pojazdów) - for( node = Groundsubcell->nRender; node != nullptr; node = node->nNext3 ) { - Render( node ); - } - // nieprzezroczyste z mieszanych modeli - for( node = Groundsubcell->nRenderMixed; node != nullptr; node = node->nNext3 ) { - Render( node ); - } - // nieprzezroczyste fragmenty pojazdów na torach - for( int j = 0; j < Groundsubcell->iTracks; ++j ) { - Groundsubcell->tTracks[ j ]->RenderDyn(); - } + + switch( m_renderpass.draw_mode ) { + case rendermode::color: + case rendermode::shadows: { + // nieprzezroczyste obiekty terenu + for( node = Groundsubcell->nRenderRect; node != nullptr; node = node->nNext3 ) { + Render( node ); + } + // nieprzezroczyste obiekty (oprócz pojazdów) + for( node = Groundsubcell->nRender; node != nullptr; node = node->nNext3 ) { + Render( node ); + } + // nieprzezroczyste z mieszanych modeli + for( node = Groundsubcell->nRenderMixed; node != nullptr; node = node->nNext3 ) { + Render( node ); + } + // nieprzezroczyste fragmenty pojazdów na torach + for( int trackidx = 0; trackidx < Groundsubcell->iTracks; ++trackidx ) { + for( auto dynamic : Groundsubcell->tTracks[ trackidx ]->Dynamics ) { + Render( dynamic ); + } + } #ifdef EU07_SCENERY_EDITOR - // memcells - if( DebugModeFlag ) { - for( auto const memcell : m_memcells ) { - memcell->RenderDL(); + // memcells + if( EditorModeFlag ) { + for( auto const memcell : m_memcells ) { + Render( memcell ); + } + } +#endif + break; + } + case rendermode::pickscenery: { + // same procedure like with regular render, but each node receives custom colour used for picking + // nieprzezroczyste obiekty terenu + for( node = Groundsubcell->nRenderRect; node != nullptr; node = node->nNext3 ) { + ::glColor3fv( glm::value_ptr( pick_color( m_picksceneryitems.size() + 1 ) ) ); + Render( node ); + } + // nieprzezroczyste obiekty (oprócz pojazdów) + for( node = Groundsubcell->nRender; node != nullptr; node = node->nNext3 ) { + ::glColor3fv( glm::value_ptr( pick_color( m_picksceneryitems.size() + 1 ) ) ); + Render( node ); + } + // nieprzezroczyste z mieszanych modeli + for( node = Groundsubcell->nRenderMixed; node != nullptr; node = node->nNext3 ) { + ::glColor3fv( glm::value_ptr( pick_color( m_picksceneryitems.size() + 1 ) ) ); + Render( node ); + } + // nieprzezroczyste fragmenty pojazdów na torach + for( int trackidx = 0; trackidx < Groundsubcell->iTracks; ++trackidx ) { + for( auto dynamic : Groundsubcell->tTracks[ trackidx ]->Dynamics ) { + ::glColor3fv( glm::value_ptr( pick_color( m_picksceneryitems.size() + 1 ) ) ); + Render( dynamic ); + } + } +#ifdef EU07_SCENERY_EDITOR + // memcells + if( EditorModeFlag ) { + for( auto const memcell : m_memcells ) { + ::glColor3fv( glm::value_ptr( pick_color( m_picksceneryitems.size() + 1 ) ) ); + Render( memcell ); + } + } +#endif + break; + } + case rendermode::pickcontrols: + default: { + break; } } -#endif + return true; } bool opengl_renderer::Render( TGroundNode *Node ) { -/* - Node->SetLastUsage( Timer::GetSimulationTime() ); -*/ + switch (Node->iType) { // obiekty renderowane niezależnie od odległości case TP_SUBMODEL: ::glPushMatrix(); - auto const originoffset = Node->pCenter - m_camera.position(); + auto const originoffset = Node->pCenter - m_renderpass.camera.position(); ::glTranslated( originoffset.x, originoffset.y, originoffset.z ); TSubModel::fSquareDist = 0; Render( Node->smTerrain ); @@ -533,7 +851,7 @@ opengl_renderer::Render( TGroundNode *Node ) { return true; } - double const distancesquared = SquareMagnitude( ( Node->pCenter - m_camera.position() ) / Global::ZoomFactor ); + double const distancesquared = SquareMagnitude( ( Node->pCenter - m_renderpass.camera.position() ) / Global::ZoomFactor ); if( ( distancesquared > ( Node->fSquareRadius * Global::fDistanceFactor ) ) || ( distancesquared < ( Node->fSquareMinRadius / Global::fDistanceFactor ) ) ) { return false; @@ -544,8 +862,18 @@ opengl_renderer::Render( TGroundNode *Node ) { case TP_TRACK: { // setup ::glPushMatrix(); - auto const originoffset = Node->m_rootposition - m_camera.position(); + auto const originoffset = Node->m_rootposition - m_renderpass.camera.position(); ::glTranslated( originoffset.x, originoffset.y, originoffset.z ); + switch( m_renderpass.draw_mode ) { + case rendermode::pickscenery: { + // add the node to the pick list + m_picksceneryitems.emplace_back( Node ); + break; + } + default: { + break; + } + } // render Render( Node->pTrack ); // post-render cleanup @@ -554,7 +882,17 @@ opengl_renderer::Render( TGroundNode *Node ) { } case TP_MODEL: { - Node->Model->Render( Node->pCenter - m_camera.position() ); + switch( m_renderpass.draw_mode ) { + case rendermode::pickscenery: { + // add the node to the pick list + m_picksceneryitems.emplace_back( Node ); + break; + } + default: { + break; + } + } + Node->Model->Render( Node->pCenter - m_renderpass.camera.position() ); return true; } @@ -570,11 +908,23 @@ opengl_renderer::Render( TGroundNode *Node ) { / std::max( 0.5 * Node->m_radius + 1.0, distance - ( 0.5 * Node->m_radius ) ); - ::glColor4fv( - glm::value_ptr( - glm::vec4( - Node->Diffuse * glm::vec3( Global::DayLight.ambient ), // w zaleznosci od koloru swiatla - 1.0 ) ) ); // if the thickness is defined negative, lines are always drawn opaque + switch( m_renderpass.draw_mode ) { + // wire colouring is disabled for modes other than colour + case rendermode::color: { + ::glColor4fv( + glm::value_ptr( + glm::vec4( + Node->Diffuse * glm::vec3( Global::DayLight.ambient ), // w zaleznosci od koloru swiatla + 1.0 ) ) ); // if the thickness is defined negative, lines are always drawn opaque + break; + } + case rendermode::shadows: + case rendermode::pickcontrols: + case rendermode::pickscenery: + default: { + break; + } + } auto const linewidth = clamp( 0.5 * linealpha + Node->fLineThickness * Node->m_radius / 1000.0, 1.0, 32.0 ); if( linewidth > 1.0 ) { ::glLineWidth( static_cast( linewidth ) ); @@ -583,9 +933,19 @@ opengl_renderer::Render( TGroundNode *Node ) { GfxRenderer.Bind( 0 ); ::glPushMatrix(); - auto const originoffset = Node->m_rootposition - m_camera.position(); + auto const originoffset = Node->m_rootposition - m_renderpass.camera.position(); ::glTranslated( originoffset.x, originoffset.y, originoffset.z ); + switch( m_renderpass.draw_mode ) { + case rendermode::pickscenery: { + // add the node to the pick list + m_picksceneryitems.emplace_back( Node ); + break; + } + default: { + break; + } + } // render m_geometry.draw( Node->Piece->geometry ); @@ -603,14 +963,35 @@ opengl_renderer::Render( TGroundNode *Node ) { return false; } // setup - ::glColor3fv( glm::value_ptr( Node->Diffuse ) ); - Bind( Node->TextureID ); + switch( m_renderpass.draw_mode ) { + case rendermode::color: { + ::glColor3fv( glm::value_ptr( Node->Diffuse ) ); + break; + } + // pick modes get custom colours, and shadow pass doesn't use any + case rendermode::shadows: + case rendermode::pickcontrols: + case rendermode::pickscenery: + default: { + break; + } + } ::glPushMatrix(); - auto const originoffset = Node->m_rootposition - m_camera.position(); + auto const originoffset = Node->m_rootposition - m_renderpass.camera.position(); ::glTranslated( originoffset.x, originoffset.y, originoffset.z ); + switch( m_renderpass.draw_mode ) { + case rendermode::pickscenery: { + // add the node to the pick list + m_picksceneryitems.emplace_back( Node ); + break; + } + default: { + break; + } + } // render m_geometry.draw( Node->Piece->geometry ); @@ -621,6 +1002,16 @@ opengl_renderer::Render( TGroundNode *Node ) { } case TP_MEMCELL: { + switch( m_renderpass.draw_mode ) { + case rendermode::pickscenery: { + // add the node to the pick list + m_picksceneryitems.emplace_back( Node ); + break; + } + default: { + break; + } + } Render( Node->MemCell ); return true; } @@ -634,14 +1025,14 @@ opengl_renderer::Render( TGroundNode *Node ) { bool opengl_renderer::Render( TDynamicObject *Dynamic ) { - Dynamic->renderme = m_camera.visible( Dynamic ); + Dynamic->renderme = m_renderpass.camera.visible( Dynamic ); if( false == Dynamic->renderme ) { return false; } // setup TSubModel::iInstance = ( size_t )this; //żeby nie robić cudzych animacji - auto const originoffset = Dynamic->vPosition - m_camera.position(); + auto const originoffset = Dynamic->vPosition - m_renderpass.camera.position(); double const squaredistance = SquareMagnitude( originoffset / Global::ZoomFactor ); Dynamic->ABuLittleUpdate( squaredistance ); // ustawianie zmiennych submodeli dla wspólnego modelu ::glPushMatrix(); @@ -649,44 +1040,68 @@ opengl_renderer::Render( TDynamicObject *Dynamic ) { ::glTranslated( originoffset.x, originoffset.y, originoffset.z ); ::glMultMatrixd( Dynamic->mMatrix.getArray() ); - if( Dynamic->fShade > 0.0f ) { - // change light level based on light level of the occupied track - Global::DayLight.apply_intensity( Dynamic->fShade ); - } - m_renderspecular = true; // vehicles are rendered with specular component. static models without, at least for the time being + switch( m_renderpass.draw_mode ) { - // render - if( Dynamic->mdLowPolyInt ) { - // low poly interior - if( FreeFlyModeFlag ? true : !Dynamic->mdKabina || !Dynamic->bDisplayCab ) { - // enable cab light if needed - if( Dynamic->InteriorLightLevel > 0.0f ) { + case rendermode::color: { + if( Dynamic->fShade > 0.0f ) { + // change light level based on light level of the occupied track + Global::DayLight.apply_intensity( Dynamic->fShade ); + } + m_renderspecular = true; // vehicles are rendered with specular component. static models without, at least for the time being + // render + if( Dynamic->mdLowPolyInt ) { + // low poly interior + if( FreeFlyModeFlag ? true : !Dynamic->mdKabina || !Dynamic->bDisplayCab ) { + // enable cab light if needed + if( Dynamic->InteriorLightLevel > 0.0f ) { - // crude way to light the cabin, until we have something more complete in place - auto const cablight = Dynamic->InteriorLight * Dynamic->InteriorLightLevel; - ::glLightModelfv( GL_LIGHT_MODEL_AMBIENT, &cablight.x ); + // crude way to light the cabin, until we have something more complete in place + auto const cablight = Dynamic->InteriorLight * Dynamic->InteriorLightLevel; + ::glLightModelfv( GL_LIGHT_MODEL_AMBIENT, &cablight.x ); + } + + Render( Dynamic->mdLowPolyInt, Dynamic->Material(), squaredistance ); + + if( Dynamic->InteriorLightLevel > 0.0f ) { + // reset the overall ambient + ::glLightModelfv( GL_LIGHT_MODEL_AMBIENT, glm::value_ptr( m_baseambient ) ); + } + } } - Render( Dynamic->mdLowPolyInt, Dynamic->Material(), squaredistance ); + if( Dynamic->mdModel ) + Render( Dynamic->mdModel, Dynamic->Material(), squaredistance ); - if( Dynamic->InteriorLightLevel > 0.0f ) { - // reset the overall ambient - ::glLightModelfv( GL_LIGHT_MODEL_AMBIENT, glm::value_ptr(m_baseambient) ); + if( Dynamic->mdLoad ) // renderowanie nieprzezroczystego ładunku + Render( Dynamic->mdLoad, Dynamic->Material(), squaredistance ); + + // post-render cleanup + m_renderspecular = false; + if( Dynamic->fShade > 0.0f ) { + // restore regular light level + Global::DayLight.apply_intensity(); } + break; + } + case rendermode::shadows: { + if( Dynamic->mdLowPolyInt ) { + // low poly interior + if( FreeFlyModeFlag ? true : !Dynamic->mdKabina || !Dynamic->bDisplayCab ) { + Render( Dynamic->mdLowPolyInt, Dynamic->Material(), squaredistance ); + } + } + if( Dynamic->mdModel ) + Render( Dynamic->mdModel, Dynamic->Material(), squaredistance ); + if( Dynamic->mdLoad ) // renderowanie nieprzezroczystego ładunku + Render( Dynamic->mdLoad, Dynamic->Material(), squaredistance ); + // post-render cleanup + break; + } + case rendermode::pickcontrols: + case rendermode::pickscenery: + default: { + break; } - } - - if( Dynamic->mdModel ) - Render( Dynamic->mdModel, Dynamic->Material(), squaredistance ); - - if( Dynamic->mdLoad ) // renderowanie nieprzezroczystego ładunku - Render( Dynamic->mdLoad, Dynamic->Material(), squaredistance ); - - // post-render cleanup - m_renderspecular = false; - if( Dynamic->fShade > 0.0f ) { - // restore regular light level - Global::DayLight.apply_intensity(); } ::glPopMatrix(); @@ -698,6 +1113,77 @@ opengl_renderer::Render( TDynamicObject *Dynamic ) { return true; } +// rendering kabiny gdy jest oddzielnym modelem i ma byc wyswietlana +bool +opengl_renderer::Render_cab( TDynamicObject *Dynamic ) { + + if( Dynamic == nullptr ) { + + TSubModel::iInstance = 0; + return false; + } + + TSubModel::iInstance = reinterpret_cast( Dynamic ); + + if( ( true == FreeFlyModeFlag ) + || ( false == Dynamic->bDisplayCab ) + || ( Dynamic->mdKabina == Dynamic->mdModel ) ) { + // ABu: Rendering kabiny jako ostatniej, zeby bylo widac przez szyby, tylko w widoku ze srodka + return false; + } + + if( Dynamic->mdKabina ) { // bo mogła zniknąć przy przechodzeniu do innego pojazdu + // setup shared by all render paths + ::glPushMatrix(); + + auto const originoffset = Dynamic->GetPosition() - m_renderpass.camera.position(); + ::glTranslated( originoffset.x, originoffset.y, originoffset.z ); + ::glMultMatrixd( Dynamic->mMatrix.getArray() ); + + switch( m_renderpass.draw_mode ) { + case rendermode::color: { + // render path specific setup: + if( Dynamic->fShade > 0.0f ) { + // change light level based on light level of the occupied track + Global::DayLight.apply_intensity( Dynamic->fShade ); + } + if( Dynamic->InteriorLightLevel > 0.0f ) { + // crude way to light the cabin, until we have something more complete in place + auto const cablight = Dynamic->InteriorLight * Dynamic->InteriorLightLevel; + ::glLightModelfv( GL_LIGHT_MODEL_AMBIENT, &cablight.x ); + } + // render + Render( Dynamic->mdKabina, Dynamic->Material(), 0.0 ); + Render_Alpha( Dynamic->mdKabina, Dynamic->Material(), 0.0 ); + // post-render restore + if( Dynamic->fShade > 0.0f ) { + // change light level based on light level of the occupied track + Global::DayLight.apply_intensity(); + } + if( Dynamic->InteriorLightLevel > 0.0f ) { + // reset the overall ambient + ::glLightModelfv( GL_LIGHT_MODEL_AMBIENT, glm::value_ptr(m_baseambient) ); + } + break; + } + case rendermode::pickcontrols: { + // control picking mode skips lighting setup and translucent parts + // render + Render( Dynamic->mdKabina, Dynamic->Material(), 0.0 ); + // since the setup is simpler, there's nothing to reset afterwards + break; + } + default: { + break; + } + } + // post-render restore + ::glPopMatrix(); + } + + return true; +} + bool opengl_renderer::Render( TModel3d *Model, material_data const *Material, double const Squaredistance ) { @@ -766,108 +1252,167 @@ opengl_renderer::Render( TSubModel *Submodel ) { if( Submodel->eType < TP_ROTATOR ) { // renderowanie obiektów OpenGL - if( Submodel->iAlpha & Submodel->iFlags & 0x1F ) // rysuj gdy element nieprzezroczysty - { - switch( Submodel->m_normalizenormals ) { - case TSubModel::normalize: { - ::glEnable( GL_NORMALIZE ); break; } - case TSubModel::rescale: { - ::glEnable( GL_RESCALE_NORMAL ); break; } + if( Submodel->iAlpha & Submodel->iFlags & 0x1F ) { + // rysuj gdy element nieprzezroczysty + switch( m_renderpass.draw_mode ) { + case rendermode::color: { + switch( Submodel->m_normalizenormals ) { + case TSubModel::normalize: { + ::glEnable( GL_NORMALIZE ); break; } + case TSubModel::rescale: { + ::glEnable( GL_RESCALE_NORMAL ); break; } + default: { + break; } + } + // material configuration: + // textures... + if( Submodel->TextureID < 0 ) { // zmienialne skóry + Bind( Submodel->ReplacableSkinId[ -Submodel->TextureID ] ); + } + else { + // również 0 + Bind( Submodel->TextureID ); + } + // ...colors... + ::glColor3fv( glm::value_ptr( Submodel->f4Diffuse ) ); // McZapkie-240702: zamiast ub + if( ( true == m_renderspecular ) && ( Global::DayLight.specular.a > 0.01f ) ) { + // specular strength in legacy models is set uniformly to 150, 150, 150 so we scale it down for opaque elements + ::glMaterialfv( GL_FRONT, GL_SPECULAR, glm::value_ptr( Submodel->f4Specular * Global::DayLight.specular.a * m_specularopaquescalefactor ) ); + } + // ...luminance + if( Global::fLuminance < Submodel->fLight ) { + // zeby swiecilo na kolorowo + ::glMaterialfv( GL_FRONT, GL_EMISSION, glm::value_ptr( Submodel->f4Diffuse * Submodel->f4Emision.a ) ); + } + + // main draw call + m_geometry.draw( Submodel->m_geometry ); + + // post-draw reset + if( ( true == m_renderspecular ) && ( Global::DayLight.specular.a > 0.01f ) ) { + ::glMaterialfv( GL_FRONT, GL_SPECULAR, glm::value_ptr( colors::none ) ); + } + if( Global::fLuminance < Submodel->fLight ) { + // restore default (lack of) brightness + ::glMaterialfv( GL_FRONT, GL_EMISSION, glm::value_ptr( colors::none ) ); + } + switch( Submodel->m_normalizenormals ) { + case TSubModel::normalize: { + ::glDisable( GL_NORMALIZE ); break; } + case TSubModel::rescale: { + ::glDisable( GL_RESCALE_NORMAL ); break; } + default: { + break; } + } + break; + } + case rendermode::shadows: + case rendermode::pickscenery: { + // scenery picking and shadow both use enforced colour and no frills + // material configuration: + // textures... + if( Submodel->TextureID < 0 ) { // zmienialne skóry + Bind( Submodel->ReplacableSkinId[ -Submodel->TextureID ] ); + } + else { + // również 0 + Bind( Submodel->TextureID ); + } + // main draw call + m_geometry.draw( Submodel->m_geometry ); + // post-draw reset + break; + } + case rendermode::pickcontrols: { + // material configuration: + // control picking applies individual colour for each submodel + m_pickcontrolsitems.emplace_back( Submodel ); + ::glColor3fv( glm::value_ptr( pick_color( m_pickcontrolsitems.size() ) ) ); + // textures... + if( Submodel->TextureID < 0 ) { // zmienialne skóry + Bind( Submodel->ReplacableSkinId[ -Submodel->TextureID ] ); + } + else { + // również 0 + Bind( Submodel->TextureID ); + } + // main draw call + m_geometry.draw( Submodel->m_geometry ); + // post-draw reset + break; + } default: { - break; } - } - - // material configuration: - // textures... - if( Submodel->TextureID < 0 ) - { // zmienialne skóry - Bind( Submodel->ReplacableSkinId[ -Submodel->TextureID ] ); - } - else { - // również 0 - Bind( Submodel->TextureID ); - } - // ...colors... - ::glColor3fv( glm::value_ptr(Submodel->f4Diffuse) ); // McZapkie-240702: zamiast ub - if( ( true == m_renderspecular ) && ( Global::DayLight.specular.a > 0.01f ) ) { - // specular strength in legacy models is set uniformly to 150, 150, 150 so we scale it down for opaque elements - ::glMaterialfv( GL_FRONT, GL_SPECULAR, glm::value_ptr( Submodel->f4Specular * Global::DayLight.specular.a * m_specularopaquescalefactor ) ); - } - // ...luminance - if( Global::fLuminance < Submodel->fLight ) { - // zeby swiecilo na kolorowo - ::glMaterialfv( GL_FRONT, GL_EMISSION, glm::value_ptr( Submodel->f4Diffuse * Submodel->f4Emision.a ) ); - } - - // main draw call - m_geometry.draw( Submodel->m_geometry ); - - // post-draw reset - if( ( true == m_renderspecular ) && ( Global::DayLight.specular.a > 0.01f ) ) { - ::glMaterialfv( GL_FRONT, GL_SPECULAR, glm::value_ptr( colors::none ) ); - } - if( Global::fLuminance < Submodel->fLight ) { - // restore default (lack of) brightness - ::glMaterialfv( GL_FRONT, GL_EMISSION, glm::value_ptr( colors::none ) ); - } - switch( Submodel->m_normalizenormals ) { - case TSubModel::normalize: { - ::glDisable( GL_NORMALIZE ); break; } - case TSubModel::rescale: { - ::glDisable( GL_RESCALE_NORMAL ); break; } - default: { - break; } + break; + } } } } else if( Submodel->eType == TP_FREESPOTLIGHT ) { - auto const &modelview = OpenGLMatrices.data( GL_MODELVIEW ); - auto const lightcenter = modelview * glm::vec4( 0.0f, 0.0f, -0.05f, 1.0f ); // pozycja punktu świecącego względem kamery - Submodel->fCosViewAngle = glm::dot( glm::normalize( modelview * glm::vec4( 0.0f, 0.0f, -1.0f, 1.0f ) - lightcenter ), glm::normalize( -lightcenter ) ); + switch( m_renderpass.draw_mode ) { + // spotlights are only rendered in colour mode(s) + case rendermode::color: { + auto const &modelview = OpenGLMatrices.data( GL_MODELVIEW ); + auto const lightcenter = modelview * glm::vec4( 0.0f, 0.0f, -0.05f, 1.0f ); // pozycja punktu świecącego względem kamery + Submodel->fCosViewAngle = glm::dot( glm::normalize( modelview * glm::vec4( 0.0f, 0.0f, -1.0f, 1.0f ) - lightcenter ), glm::normalize( -lightcenter ) ); - if( Submodel->fCosViewAngle > Submodel->fCosFalloffAngle ) // kąt większy niż maksymalny stożek swiatła - { - float lightlevel = 1.0f; // TODO, TBD: parameter to control light strength - // view angle attenuation - float const anglefactor = ( Submodel->fCosViewAngle - Submodel->fCosFalloffAngle ) / ( 1.0f - Submodel->fCosFalloffAngle ); - // distance attenuation. NOTE: since it's fixed pipeline with built-in gamma correction we're using linear attenuation - // we're capping how much effect the distance attenuation can have, otherwise the lights get too tiny at regular distances - float const distancefactor = static_cast( std::max( 0.5, ( Submodel->fSquareMaxDist - TSubModel::fSquareDist ) / ( Submodel->fSquareMaxDist * Global::fDistanceFactor ) ) ); + if( Submodel->fCosViewAngle > Submodel->fCosFalloffAngle ) // kąt większy niż maksymalny stożek swiatła + { + float lightlevel = 1.0f; // TODO, TBD: parameter to control light strength + // view angle attenuation + float const anglefactor = ( Submodel->fCosViewAngle - Submodel->fCosFalloffAngle ) / ( 1.0f - Submodel->fCosFalloffAngle ); + // distance attenuation. NOTE: since it's fixed pipeline with built-in gamma correction we're using linear attenuation + // we're capping how much effect the distance attenuation can have, otherwise the lights get too tiny at regular distances + float const distancefactor = static_cast( std::max( 0.5, ( Submodel->fSquareMaxDist - TSubModel::fSquareDist ) / ( Submodel->fSquareMaxDist * Global::fDistanceFactor ) ) ); - if( lightlevel > 0.0f ) { - // material configuration: - ::glPushAttrib( GL_ENABLE_BIT | GL_CURRENT_BIT | GL_COLOR_BUFFER_BIT | GL_POINT_BIT ); + if( lightlevel > 0.0f ) { + // material configuration: + ::glPushAttrib( GL_ENABLE_BIT | GL_CURRENT_BIT | GL_COLOR_BUFFER_BIT | GL_POINT_BIT ); - Bind( 0 ); - ::glPointSize( std::max( 2.0f, 4.0f * distancefactor * anglefactor ) ); - ::glColor4f( Submodel->f4Diffuse[ 0 ], Submodel->f4Diffuse[ 1 ], Submodel->f4Diffuse[ 2 ], lightlevel * anglefactor ); - ::glDisable( GL_LIGHTING ); - ::glEnable( GL_BLEND ); + Bind( 0 ); + ::glPointSize( std::max( 2.0f, 4.0f * distancefactor * anglefactor ) ); + ::glColor4f( Submodel->f4Diffuse[ 0 ], Submodel->f4Diffuse[ 1 ], Submodel->f4Diffuse[ 2 ], lightlevel * anglefactor ); + ::glDisable( GL_LIGHTING ); + ::glEnable( GL_BLEND ); - // main draw call - m_geometry.draw( Submodel->m_geometry ); + // main draw call + m_geometry.draw( Submodel->m_geometry ); - // post-draw reset - ::glPopAttrib(); + // post-draw reset + ::glPopAttrib(); + } + } + break; + } + default: { + break; } } } else if( Submodel->eType == TP_STARS ) { - if( Global::fLuminance < Submodel->fLight ) { + switch( m_renderpass.draw_mode ) { + // colour points are only rendered in colour mode(s) + case rendermode::color: { + if( Global::fLuminance < Submodel->fLight ) { - // material configuration: - ::glPushAttrib( GL_ENABLE_BIT | GL_CURRENT_BIT ); + // material configuration: + ::glPushAttrib( GL_ENABLE_BIT | GL_CURRENT_BIT ); - Bind( 0 ); - ::glDisable( GL_LIGHTING ); + Bind( 0 ); + ::glDisable( GL_LIGHTING ); - // main draw call - m_geometry.draw( Submodel->m_geometry, color_streams ); + // main draw call + m_geometry.draw( Submodel->m_geometry, color_streams ); - // post-draw reset - ::glPopAttrib(); + // post-draw reset + ::glPopAttrib(); + } + break; + } + default: { + break; + } } } if( Submodel->Child != NULL ) @@ -877,10 +1422,10 @@ opengl_renderer::Render( TSubModel *Submodel ) { if( Submodel->iFlags & 0xC000 ) ::glPopMatrix(); } - +/* if( Submodel->b_Anim < at_SecondsJump ) Submodel->b_Anim = at_None; // wyłączenie animacji dla kolejnego użycia subm - +*/ if( Submodel->Next ) if( Submodel->iAlpha & Submodel->iFlags & 0x1F000000 ) Render( Submodel->Next ); // dalsze rekurencyjnie @@ -894,18 +1439,37 @@ opengl_renderer::Render( TTrack *Track ) { return; } - Track->EnvironmentSet(); - - if( Track->TextureID1 != 0 ) { - Bind( Track->TextureID1 ); - m_geometry.draw( std::begin( Track->Geometry1 ), std::end( Track->Geometry1 ) ); + switch( m_renderpass.draw_mode ) { + case rendermode::color: { + Track->EnvironmentSet(); + if( Track->TextureID1 != 0 ) { + Bind( Track->TextureID1 ); + m_geometry.draw( std::begin( Track->Geometry1 ), std::end( Track->Geometry1 ) ); + } + if( Track->TextureID2 != 0 ) { + Bind( Track->TextureID2 ); + m_geometry.draw( std::begin( Track->Geometry2 ), std::end( Track->Geometry2 ) ); + } + Track->EnvironmentReset(); + break; + } + case rendermode::pickscenery: + case rendermode::shadows: { + if( Track->TextureID1 != 0 ) { + Bind( Track->TextureID1 ); + m_geometry.draw( std::begin( Track->Geometry1 ), std::end( Track->Geometry1 ) ); + } + if( Track->TextureID2 != 0 ) { + Bind( Track->TextureID2 ); + m_geometry.draw( std::begin( Track->Geometry2 ), std::end( Track->Geometry2 ) ); + } + break; + } + case rendermode::pickcontrols: + default: { + break; + } } - if( Track->TextureID2 != 0 ) { - Bind( Track->TextureID2 ); - m_geometry.draw( std::begin( Track->Geometry2 ), std::end( Track->Geometry2 ) ); - } - - Track->EnvironmentReset(); } void @@ -929,28 +1493,24 @@ opengl_renderer::Render( TMemCell *Memcell ) { bool opengl_renderer::Render_Alpha( TGround *Ground ) { - ::glEnable( GL_BLEND ); - ::glAlphaFunc( GL_GREATER, 0.04f ); // im mniejsza wartość, tym większa ramka, domyślnie 0.1f - ::glColor4f( 1.0f, 1.0f, 1.0f, 1.0f ); - TGroundNode *node; TSubRect *tmp; // Ra: renderowanie progresywne - zależne od FPS oraz kierunku patrzenia - for( auto subcellpair = std::rbegin( m_drawqueue ); subcellpair != std::rend( m_drawqueue ); ++subcellpair ) { + for( auto subcellpair = std::rbegin( m_renderpass.draw_queue ); subcellpair != std::rend( m_renderpass.draw_queue ); ++subcellpair ) { // przezroczyste trójkąty w oddzielnym cyklu przed modelami tmp = subcellpair->second; for( node = tmp->nRenderRectAlpha; node; node = node->nNext3 ) { Render_Alpha( node ); } } - for( auto subcellpair = std::rbegin( m_drawqueue ); subcellpair != std::rend( m_drawqueue ); ++subcellpair ) + for( auto subcellpair = std::rbegin( m_renderpass.draw_queue ); subcellpair != std::rend( m_renderpass.draw_queue ); ++subcellpair ) { // renderowanie przezroczystych modeli oraz pojazdów Render_Alpha( subcellpair->second ); } ::glDisable( GL_LIGHTING ); // linie nie powinny świecić - for( auto subcellpair = std::rbegin( m_drawqueue ); subcellpair != std::rend( m_drawqueue ); ++subcellpair ) { + for( auto subcellpair = std::rbegin( m_renderpass.draw_queue ); subcellpair != std::rend( m_renderpass.draw_queue ); ++subcellpair ) { // druty na końcu, żeby się nie robiły białe plamy na tle lasu tmp = subcellpair->second; for( node = tmp->nRenderWires; node; node = node->nNext3 ) { @@ -980,7 +1540,7 @@ opengl_renderer::Render_Alpha( TSubRect *Groundsubcell ) { bool opengl_renderer::Render_Alpha( TGroundNode *Node ) { - double const distancesquared = SquareMagnitude( ( Node->pCenter - m_camera.position() ) / Global::ZoomFactor ); + double const distancesquared = SquareMagnitude( ( Node->pCenter - m_renderpass.camera.position() ) / Global::ZoomFactor ); if( ( distancesquared > ( Node->fSquareRadius * Global::fDistanceFactor ) ) || ( distancesquared < ( Node->fSquareMinRadius / Global::fDistanceFactor ) ) ) { return false; @@ -1012,7 +1572,7 @@ opengl_renderer::Render_Alpha( TGroundNode *Node ) { Bind( NULL ); ::glPushMatrix(); - auto const originoffset = Node->m_rootposition - m_camera.position(); + auto const originoffset = Node->m_rootposition - m_renderpass.camera.position(); ::glTranslated( originoffset.x, originoffset.y, originoffset.z ); // render @@ -1033,7 +1593,7 @@ opengl_renderer::Render_Alpha( TGroundNode *Node ) { } } case TP_MODEL: { - Node->Model->RenderAlpha( Node->pCenter - m_camera.position() ); + Node->Model->RenderAlpha( Node->pCenter - m_renderpass.camera.position() ); return true; } @@ -1062,7 +1622,7 @@ opengl_renderer::Render_Alpha( TGroundNode *Node ) { GfxRenderer.Bind( 0 ); ::glPushMatrix(); - auto const originoffset = Node->m_rootposition - m_camera.position(); + auto const originoffset = Node->m_rootposition - m_renderpass.camera.position(); ::glTranslated( originoffset.x, originoffset.y, originoffset.z ); // render @@ -1087,7 +1647,7 @@ opengl_renderer::Render_Alpha( TGroundNode *Node ) { Bind( Node->TextureID ); ::glPushMatrix(); - auto const originoffset = Node->m_rootposition - m_camera.position(); + auto const originoffset = Node->m_rootposition - m_renderpass.camera.position(); ::glTranslated( originoffset.x, originoffset.y, originoffset.z ); // render @@ -1112,7 +1672,7 @@ opengl_renderer::Render_Alpha( TDynamicObject *Dynamic ) { // setup TSubModel::iInstance = ( size_t )this; //żeby nie robić cudzych animacji - auto const originoffset = Dynamic->vPosition - m_camera.position(); + auto const originoffset = Dynamic->vPosition - m_renderpass.camera.position(); double const squaredistance = SquareMagnitude( originoffset / Global::ZoomFactor ); Dynamic->ABuLittleUpdate( squaredistance ); // ustawianie zmiennych submodeli dla wspólnego modelu ::glPushMatrix(); @@ -1371,8 +1931,95 @@ opengl_renderer::Render_Alpha( TSubModel *Submodel ) { Render_Alpha( Submodel->Next ); }; +// utility methods +TSubModel const * +opengl_renderer::Update_Pick_Control() { + +#ifdef EU07_USE_PICKING_FRAMEBUFFER + if( true == m_framebuffersupport ) { + ::glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, m_pickframebuffer ); + ::glReadBuffer( GL_COLOR_ATTACHMENT0_EXT ); + } + else { + ::glReadBuffer( GL_BACK ); + } +#else + ::glReadBuffer( GL_BACK ); +#endif + + Render_pass( rendermode::pickcontrols ); + // determine point to examine + glm::dvec2 mousepos; + glfwGetCursorPos( m_window, &mousepos.x, &mousepos.y ); + mousepos.y = Global::ScreenHeight - mousepos.y; // cursor coordinates are flipped compared to opengl +/* + glm::ivec2 pickbufferpos { + mousepos.x * 1024.0f / Global::ScreenWidth, + mousepos.y * 512.0f / Global::ScreenHeight }; +*/ + glm::ivec2 pickbufferpos{ mousepos }; + + unsigned char pickreadout[4]; + ::glReadPixels( pickbufferpos.x, pickbufferpos.y, 1, 1, GL_BGRA, GL_UNSIGNED_BYTE, pickreadout ); + auto const controlindex = pick_index( glm::ivec3{ pickreadout[ 2 ], pickreadout[ 1 ], pickreadout[ 0 ] } ); + TSubModel const *control { nullptr }; + if( ( controlindex > 0 ) + && ( controlindex <= m_pickcontrolsitems.size() ) ) { + control = m_pickcontrolsitems[ controlindex - 1 ]; + } +#ifdef EU07_USE_PICKING_FRAMEBUFFER + if( true == m_framebuffersupport ) { + ::glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 ); + } +#endif + return control; +} + +TGroundNode const * +opengl_renderer::Update_Pick_Node() { + +#ifdef EU07_USE_PICKING_FRAMEBUFFER + if( true == m_framebuffersupport ) { + ::glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, m_pickframebuffer ); + ::glReadBuffer( GL_COLOR_ATTACHMENT0_EXT ); + } + else { + ::glReadBuffer( GL_BACK ); + } +#else + ::glReadBuffer( GL_BACK ); +#endif + + Render_pass( rendermode::pickscenery ); + // determine point to examine + glm::dvec2 mousepos; + glfwGetCursorPos( m_window, &mousepos.x, &mousepos.y ); + mousepos.y = Global::ScreenHeight - mousepos.y; // cursor coordinates are flipped compared to opengl +/* + glm::ivec2 pickbufferpos { + mousepos.x * 1024.0f / Global::ScreenWidth, + mousepos.y * 512.0f / Global::ScreenHeight }; +*/ + glm::ivec2 pickbufferpos{ mousepos }; + + unsigned char pickreadout[4]; + ::glReadPixels( pickbufferpos.x, pickbufferpos.y, 1, 1, GL_BGRA, GL_UNSIGNED_BYTE, pickreadout ); + auto const nodeindex = pick_index( glm::ivec3{ pickreadout[ 2 ], pickreadout[ 1 ], pickreadout[ 0 ] } ); + TGroundNode const *node { nullptr }; + if( ( nodeindex > 0 ) + && ( nodeindex <= m_picksceneryitems.size() ) ) { + node = m_picksceneryitems[ nodeindex - 1 ]; + } +#ifdef EU07_USE_PICKING_FRAMEBUFFER + if( true == m_framebuffersupport ) { + ::glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 ); + } +#endif + return node; +} + void -opengl_renderer::Update ( double const Deltatime ) { +opengl_renderer::Update( double const Deltatime ) { m_updateaccumulator += Deltatime; @@ -1395,16 +2042,7 @@ opengl_renderer::Update ( double const Deltatime ) { else if( framerate > 60.0 ) { targetsegments = 225; targetfactor = 1.5f; } else if( framerate > 30.0 ) { targetsegments = 90; targetfactor = Global::ScreenHeight / 768.0f; } else { targetsegments = 9; targetfactor = Global::ScreenHeight / 768.0f * 0.75f; } -/* - if( targetsegments > Global::iSegmentsRendered ) { - Global::iSegmentsRendered = std::min( targetsegments, Global::iSegmentsRendered + 5 ); - } - else if( targetsegments < Global::iSegmentsRendered ) { - - Global::iSegmentsRendered = std::max( targetsegments, Global::iSegmentsRendered - 5 ); - } -*/ if( targetfactor > Global::fDistanceFactor ) { Global::fDistanceFactor = std::min( targetfactor, Global::fDistanceFactor + 0.05f ); @@ -1427,9 +2065,11 @@ opengl_renderer::Update ( double const Deltatime ) { ::glEnable( GL_MULTISAMPLE ); } - // TODO: add garbage collection and other less frequent works here - m_geometry.update(); - m_textures.update(); + if( true == World.InitPerformed() ) { + // garbage collection + m_geometry.update(); + m_textures.update(); + } if( true == DebugModeFlag ) { m_debuginfo = m_textures.info(); @@ -1437,6 +2077,23 @@ opengl_renderer::Update ( double const Deltatime ) { else { m_debuginfo.clear(); } + + if( ( true == Global::ControlPicking ) + && ( false == FreeFlyModeFlag ) ) { + m_pickcontrolitem = Update_Pick_Control(); + } + else { + m_pickcontrolitem = nullptr; + } + // temporary conditions for testing. eventually will be coupled with editor mode + if( ( true == Global::ControlPicking ) + && ( true == DebugModeFlag ) + && ( true == FreeFlyModeFlag ) ) { + m_picksceneryitem = Update_Pick_Node(); + } + else { + m_picksceneryitem = nullptr; + } }; // debug performance string @@ -1464,13 +2121,13 @@ opengl_renderer::Update_Lights( light_array const &Lights ) { // all lights past this one are bound to be off break; } - if( ( m_camera.position() - scenelight.position ).Length() > 1000.0f ) { + if( ( m_renderpass.camera.position() - scenelight.position ).Length() > 1000.0f ) { // we don't care about lights past arbitrary limit of 1 km. // but there could still be weaker lights which are closer, so keep looking continue; } // if the light passed tests so far, it's good enough - renderlight->set_position( glm::make_vec3( (scenelight.position - m_camera.position()).readArray() ) ); + renderlight->set_position( glm::make_vec3( (scenelight.position - m_renderpass.camera.position()).readArray() ) ); renderlight->direction = scenelight.direction; auto luminance = Global::fLuminance; // TODO: adjust this based on location, e.g. for tunnels @@ -1537,17 +2194,67 @@ opengl_renderer::Init_caps() { WriteLog( "Supported extensions:" + std::string((char *)glGetString( GL_EXTENSIONS )) ); WriteLog( std::string("Render path: ") + ( Global::bUseVBO ? "VBO" : "Display lists" ) ); +#ifdef EU07_USE_PICKING_FRAMEBUFFER + if( GLEW_EXT_framebuffer_object ) { + m_framebuffersupport = true; + WriteLog( "Framebuffer objects enabled" ); + } + else { + WriteLog( "Framebuffer objects not supported, resorting to back buffer rendering" ); + } +#endif if( Global::iMultisampling ) WriteLog( "Using multisampling x" + std::to_string( 1 << Global::iMultisampling ) ); - { // ograniczenie maksymalnego rozmiaru tekstur - parametr dla skalowania tekstur + // ograniczenie maksymalnego rozmiaru tekstur - parametr dla skalowania tekstur + { GLint i; glGetIntegerv( GL_MAX_TEXTURE_SIZE, &i ); if( i < Global::iMaxTextureSize ) Global::iMaxTextureSize = i; WriteLog( "Texture sizes capped at " + std::to_string( Global::iMaxTextureSize ) + " pixels" ); - } return true; } + +glm::vec3 +opengl_renderer::pick_color( std::size_t const Index ) { +/* + // pick colours are set with step of 4 for some slightly easier visual debugging. not strictly needed but, eh + int const colourstep = 4; + int const componentcapacity = 256 / colourstep; + auto const redgreen = std::div( Index, componentcapacity * componentcapacity ); + auto const greenblue = std::div( redgreen.rem, componentcapacity ); + auto const blue = Index % componentcapacity; + return + glm::vec3 { + redgreen.quot * colourstep / 255.0f, + greenblue.quot * colourstep / 255.0f, + greenblue.rem * colourstep / 255.0f }; +*/ + // alternatively + return + glm::vec3{ + ( ( Index & 0xff0000 ) >> 16 ) / 255.0f, + ( ( Index & 0x00ff00 ) >> 8 ) / 255.0f, + ( Index & 0x0000ff ) / 255.0f }; + +} + +std::size_t +opengl_renderer::pick_index( glm::ivec3 const &Color ) { +/* + return ( + std::floor( Color.b / 4 ) + + std::floor( Color.g / 4 ) * 64 + + std::floor( Color.r / 4 ) * 64 * 64 ); +*/ + // alternatively + return + Color.b + + ( Color.g * 256 ) + + ( Color.r * 256 * 256 ); + +} + //--------------------------------------------------------------------------- diff --git a/renderer.h b/renderer.h index 2754feb3..4459e48d 100644 --- a/renderer.h +++ b/renderer.h @@ -134,15 +134,6 @@ public: Render_Alpha( TModel3d *Model, material_data const *Material, Math3D::vector3 const &Position, Math3D::vector3 const &Angle ); bool Render_Alpha( TModel3d *Model, material_data const *Material, double const Squaredistance ); - // maintenance jobs - void - Update( double const Deltatime ); - // debug performance string - std::string const & - Info() const; - // light methods - void - Disable_Lights(); // geometry methods // NOTE: hands-on geometry management is exposed as a temporary measure; ultimately all visualization data should be generated/handled automatically by the renderer itself // creates a new geometry bank. returns: handle to the bank or NULL @@ -167,6 +158,24 @@ public: Bind( texture_handle const Texture ); opengl_texture const & Texture( texture_handle const Texture ); + // light methods + void + Disable_Lights(); + // utility methods + TSubModel const * + Pick_Control() const { return m_pickcontrolitem; } + TGroundNode const * + Pick_Node() const { return m_picksceneryitem; } + // maintenance jobs + void + Update( double const Deltatime ); + TSubModel const * + Update_Pick_Control(); + TGroundNode const * + Update_Pick_Node(); + // debug performance string + std::string const & + Info() const; // members GLenum static const sunlight{ GL_LIGHT0 }; @@ -175,16 +184,37 @@ public: private: // types enum class rendermode { - color + color, + shadows, + pickcontrols, + pickscenery + }; + + typedef std::pair< double, TSubRect * > distancesubcell_pair; + + struct renderpass_config { + opengl_camera camera; + rendermode draw_mode { rendermode::color }; + float draw_range { 0.0f }; + std::vector draw_queue; // list of subcells to be drawn in current render pass }; typedef std::vector opengllight_array; - typedef std::pair< double, TSubRect * > distancesubcell_pair; - // methods bool Init_caps(); + // runs jobs needed to generate graphics for specified render pass + void + Render_pass( rendermode const Mode ); + // configures projection matrix for the current render pass + void + Render_projection(); + // configures camera for the current render pass + void + Render_camera(); + void + Render_setup( bool const Alpha = false ); bool Render( world_environment *Environment ); bool @@ -197,6 +227,8 @@ private: Render( TGroundNode *Node ); void Render( TTrack *Track ); + bool + Render_cab( TDynamicObject *Dynamic ); void Render( TMemCell *Memcell ); bool @@ -209,29 +241,43 @@ private: Render_Alpha( TSubModel *Submodel ); void Update_Lights( light_array const &Lights ); - + glm::vec3 + pick_color( std::size_t const Index ); + std::size_t + pick_index( glm::ivec3 const &Color ); // members - opengllight_array m_lights; geometrybank_manager m_geometry; texture_manager m_textures; - opengl_camera m_camera; - rendermode renderpass { rendermode::color }; - float m_drawrange { 2500.0f }; // current drawing range - float m_drawtime { 1000.0f / 30.0f * 20.0f }; // start with presumed 'neutral' average of 30 fps - double m_updateaccumulator { 0.0 }; - std::string m_debuginfo; + opengllight_array m_lights; GLFWwindow *m_window { nullptr }; +#ifdef EU07_USE_PICKING_FRAMEBUFFER + GLuint m_pickframebuffer { 0 }; // TODO: refactor pick framebuffer stuff into an object + GLuint m_picktexture { 0 }; + GLuint m_pickdepthbuffer { 0 }; +#endif + GLUquadricObj *m_quadric { nullptr }; // helper object for drawing debug mode scene elements + + geometry_handle m_billboardgeometry { 0, 0 }; texture_handle m_glaretexture { -1 }; texture_handle m_suntexture { -1 }; texture_handle m_moontexture { -1 }; - geometry_handle m_billboardgeometry { 0, 0 }; - GLUquadricObj *m_quadric; // helper object for drawing debug mode scene elements - std::vector m_drawqueue; // list of subcells to be drawn in current render pass + + float m_drawtime { 1000.0f / 30.0f * 20.0f }; // start with presumed 'neutral' average of 30 fps + double m_updateaccumulator { 0.0 }; + std::string m_debuginfo; + glm::vec4 m_baseambient { 0.0f, 0.0f, 0.0f, 1.0f }; - bool m_renderspecular{ false }; // controls whether to include specular component in the calculations float m_specularopaquescalefactor { 1.0f }; float m_speculartranslucentscalefactor { 1.0f }; + bool m_framebuffersupport { false }; + rendermode m_texenvmode { rendermode::color }; // last configured texture environment + renderpass_config m_renderpass; + bool m_renderspecular { false }; // controls whether to include specular component in the calculations + std::vector m_picksceneryitems; + std::vector m_pickcontrolsitems; + TSubModel const *m_pickcontrolitem { nullptr }; + TGroundNode const *m_picksceneryitem { nullptr }; }; extern opengl_renderer GfxRenderer; diff --git a/uilayer.cpp b/uilayer.cpp index 7fb5f212..ef753b38 100644 --- a/uilayer.cpp +++ b/uilayer.cpp @@ -25,9 +25,10 @@ ui_layer::~ui_layer() { bool ui_layer::init( GLFWwindow *Window ) { + m_window = Window; HFONT font; // Windows Font ID m_fontbase = ::glGenLists(96); // storage for 96 characters - HDC hDC = ::GetDC( glfwGetWin32Window( Window ) ); + HDC hDC = ::GetDC( glfwGetWin32Window( m_window ) ); font = ::CreateFont( -MulDiv( 10, ::GetDeviceCaps( hDC, LOGPIXELSY ), 72 ), // height of font 0, // width of font 0, // angle of escapement @@ -79,6 +80,7 @@ ui_layer::render() { render_background(); render_progress(); render_panels(); + render_tooltip(); glPopAttrib(); } @@ -94,12 +96,14 @@ void ui_layer::set_background( std::string const &Filename ) { if( false == Filename.empty() ) { - m_background = GfxRenderer.GetTextureId( Filename, szTexturePath ); } else { - - m_background = 0; + m_background = NULL; + } + if( m_background != NULL ) { + auto const &texture = GfxRenderer.Texture( m_background ); + m_progressbottom = ( texture.width() != texture.height() ); } } /* @@ -115,17 +119,27 @@ ui_layer::render_progress() { glPushAttrib( GL_ENABLE_BIT ); glDisable( GL_TEXTURE_2D ); - quad( float4( 75.0f, 640.0f, 75.0f + 320.0f, 640.0f + 16.0f ), float4(0.0f, 0.0f, 0.0f, 0.25f) ); + glm::vec2 origin, size; + if( m_progressbottom == true ) { + origin = glm::vec2{ 0.0f, 768.0f - 20.0f }; + size = glm::vec2{ 1024.0f, 20.0f }; + } + else { + origin = glm::vec2{ 75.0f, 640.0f }; + size = glm::vec2{ 320.0f, 16.0f }; + } + + quad( float4( origin.x, origin.y, origin.x + size.x, origin.y + size.y ), float4(0.0f, 0.0f, 0.0f, 0.25f) ); // secondary bar if( m_subtaskprogress ) { quad( - float4( 75.0f, 640.0f, 75.0f + 320.0f * m_subtaskprogress, 640.0f + 16.0f), + float4( origin.x, origin.y, origin.x + size.x * m_subtaskprogress, origin.y + size.y), float4( 8.0f/255.0f, 160.0f/255.0f, 8.0f/255.0f, 0.35f ) ); } // primary bar if( m_progress ) { quad( - float4( 75.0f, 640.0f, 75.0f + 320.0f * m_progress, 640.0f + 16.0f ), + float4( origin.x, origin.y, origin.x + size.x * m_progress, origin.y + size.y ), float4( 8.0f / 255.0f, 160.0f / 255.0f, 8.0f / 255.0f, 1.0f ) ); } @@ -160,6 +174,23 @@ ui_layer::render_panels() { glPopAttrib(); } +void +ui_layer::render_tooltip() { + + if( m_tooltip.empty() ) { return; } + + glm::dvec2 mousepos; + glfwGetCursorPos( m_window, &mousepos.x, &mousepos.y ); + + glPushAttrib( GL_ENABLE_BIT ); + glDisable( GL_TEXTURE_2D ); + ::glColor4f( 1.0f, 1.0f, 1.0f, 1.0f ); + ::glRasterPos2f( mousepos.x + 20.0f, mousepos.y + 25.0f ); + print( m_tooltip ); + + glPopAttrib(); +} + void ui_layer::render_background() { diff --git a/uilayer.h b/uilayer.h index 2fb8d30b..86ed2417 100644 --- a/uilayer.h +++ b/uilayer.h @@ -50,6 +50,8 @@ public: // sets the ui background texture, if any void set_background( std::string const &Filename = "" ); + void + set_tooltip( std::string const &Tooltip ) { m_tooltip = Tooltip; } void clear_texts() { m_panels.clear(); } void @@ -67,6 +69,8 @@ private: render_progress(); void render_panels(); + void + render_tooltip(); // prints specified text, using display lists font void print( std::string const &Text ); @@ -76,11 +80,18 @@ private: // members: - GLuint m_fontbase{ (GLuint)-1 }; // numer DL dla znakw w napisach - float m_progress{ 0.0f }; // percentage of filled progres bar, to indicate lengthy operations. - float m_subtaskprogress{ 0.0f }; // percentage of filled progres bar, to indicate lengthy operations. - texture_handle m_background; // path to texture used as the background. size depends on mAspect. + GLFWwindow *m_window { nullptr }; + GLuint m_fontbase { (GLuint)-1 }; // numer DL dla znakw w napisach + + // progress bar config. TODO: put these together into an object + float m_progress { 0.0f }; // percentage of filled progres bar, to indicate lengthy operations. + float m_subtaskprogress{ 0.0f }; // percentage of filled progres bar, to indicate lengthy operations. + std::string m_progresstext; // label placed over the progress bar + bool m_progressbottom { false }; // location of the progress bar + + texture_handle m_background { NULL }; // path to texture used as the background. size depends on mAspect. std::vector > m_panels; + std::string m_tooltip; }; extern ui_layer UILayer; diff --git a/version.h b/version.h index 3be4407c..6ca9253b 100644 --- a/version.h +++ b/version.h @@ -1,5 +1,5 @@ #pragma once #define VERSION_MAJOR 17 -#define VERSION_MINOR 701 +#define VERSION_MINOR 708 #define VERSION_REVISION 0 From 16718d53bba89dd17d664fae6a91c36eab964a47 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Mon, 10 Jul 2017 19:36:23 +0200 Subject: [PATCH 2/6] refactored mouse input processor, tweaks to mouse input support, fix for diesel engine compressor, added progress bar label --- EU07.cpp | 18 ++- Gauge.cpp | 24 +-- Globals.cpp | 6 + Globals.h | 3 +- McZapkie/Mover.cpp | 61 +++++--- World.cpp | 21 ++- keyboardinput.cpp | 267 +------------------------------- keyboardinput.h | 22 +-- maszyna.vcxproj.filters | 6 + mouseinput.cpp | 335 ++++++++++++++++++++++++++++++++++++++++ mouseinput.h | 60 +++++++ renderer.cpp | 12 +- uilayer.cpp | 24 ++- uilayer.h | 2 + version.h | 2 +- 15 files changed, 520 insertions(+), 343 deletions(-) create mode 100644 mouseinput.cpp create mode 100644 mouseinput.h diff --git a/EU07.cpp b/EU07.cpp index 27aea200..20b79d34 100644 --- a/EU07.cpp +++ b/EU07.cpp @@ -23,6 +23,7 @@ Stele, firleju, szociu, hunter, ZiomalCl, OLI_EU and others #include "Globals.h" #include "Logs.h" #include "keyboardinput.h" +#include "mouseinput.h" #include "gamepadinput.h" #include "Console.h" #include "PyInt.h" @@ -65,6 +66,7 @@ TWorld World; namespace input { keyboard_input Keyboard; +mouse_input Mouse; gamepad_input Gamepad; glm::dvec2 mouse_pos; // stores last mouse position in control picking mode @@ -123,11 +125,12 @@ void window_resize_callback(GLFWwindow *window, int w, int h) void cursor_pos_callback(GLFWwindow *window, double x, double y) { + input::Mouse.move( x, y ); + if( true == Global::ControlPicking ) { glfwSetCursorPos( window, x, y ); } else { - input::Keyboard.mouse( x, y ); glfwSetCursorPos( window, 0, 0 ); } } @@ -137,7 +140,7 @@ void mouse_button_callback( GLFWwindow* window, int button, int action, int mods if( ( button == GLFW_MOUSE_BUTTON_LEFT ) || ( button == GLFW_MOUSE_BUTTON_RIGHT ) ) { // we don't care about other mouse buttons at the moment - input::Keyboard.mouse( button, action ); + input::Mouse.button( button, action ); } } @@ -148,8 +151,9 @@ void key_callback( GLFWwindow *window, int key, int scancode, int action, int mo Global::shiftState = ( mods & GLFW_MOD_SHIFT ) ? true : false; Global::ctrlState = ( mods & GLFW_MOD_CONTROL ) ? true : false; - if( ( key == GLFW_KEY_LEFT_ALT ) - || ( key == GLFW_KEY_RIGHT_ALT ) ) { + if( ( true == Global::InputMouse ) + && ( ( key == GLFW_KEY_LEFT_ALT ) + || ( key == GLFW_KEY_RIGHT_ALT ) ) ) { // if the alt key was pressed toggle control picking mode and set matching cursor behaviour if( action == GLFW_RELEASE ) { @@ -413,6 +417,7 @@ int main(int argc, char *argv[]) return -1; } input::Keyboard.init(); + input::Mouse.init(); input::Gamepad.init(); Global::pWorld = &World; // Ra: wskaźnik potrzebny do usuwania pojazdów @@ -452,9 +457,8 @@ int main(int argc, char *argv[]) && ( true == GfxRenderer.Render() ) ) { glfwPollEvents(); input::Keyboard.poll(); - if( true == Global::InputGamepad ) { - input::Gamepad.poll(); - } + if( true == Global::InputMouse ) { input::Mouse.poll(); } + if( true == Global::InputGamepad ) { input::Gamepad.poll(); } } } catch( std::bad_alloc const &Error ) { diff --git a/Gauge.cpp b/Gauge.cpp index f31138a5..3883a231 100644 --- a/Gauge.cpp +++ b/Gauge.cpp @@ -152,17 +152,19 @@ double TGauge::GetValue() const { void TGauge::Update() { - float dt = Timer::GetDeltaTime(); - if( ( fFriction > 0 ) && ( dt < 0.5 * fFriction ) ) { - // McZapkie-281102: zabezpieczenie przed oscylacjami dla dlugich czasow - fValue += dt * ( fDesiredValue - fValue ) / fFriction; - } - else { - fValue = fDesiredValue; - } - if( std::abs( fDesiredValue - fValue ) <= 0.001 ) { - // close enough, we can stop updating the model - fValue = fDesiredValue; // set it exactly as requested just in case it matters + if( fValue != fDesiredValue ) { + float dt = Timer::GetDeltaTime(); + if( ( fFriction > 0 ) && ( dt < 0.5 * fFriction ) ) { + // McZapkie-281102: zabezpieczenie przed oscylacjami dla dlugich czasow + fValue += dt * ( fDesiredValue - fValue ) / fFriction; + if( std::abs( fDesiredValue - fValue ) <= 0.0001 ) { + // close enough, we can stop updating the model + fValue = fDesiredValue; // set it exactly as requested just in case it matters + } + } + else { + fValue = fDesiredValue; + } } if( SubModel ) { // warunek na wszelki wypadek, gdyby się submodel nie podłączył diff --git a/Globals.cpp b/Globals.cpp index 8712aeed..2a9aa97b 100644 --- a/Globals.cpp +++ b/Globals.cpp @@ -48,6 +48,7 @@ bool Global::ctrlState; int Global::iCameraLast = -1; std::string Global::asVersion = "couldn't retrieve version string"; bool Global::ControlPicking = false; // indicates controls pick mode is enabled +bool Global::InputMouse = true; // whether control pick mode can be activated int Global::iTextMode = 0; // tryb pracy wyświetlacza tekstowego int Global::iScreenMode[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // numer ekranu wyświetlacza tekstowego double Global::fSunDeclination = 0.0; // deklinacja Słońca @@ -371,6 +372,11 @@ void Global::ConfigParse(cParser &Parser) Parser.getTokens(2, false); Parser >> Global::fMouseXScale >> Global::fMouseYScale; } + else if( token == "mousecontrol" ) { + // whether control pick mode can be activated + Parser.getTokens(); + Parser >> Global::InputMouse; + } else if (token == "enabletraction") { // Winger 040204 - 'zywe' patyki dostosowujace sie do trakcji; Ra 2014-03: teraz łamanie diff --git a/Globals.h b/Globals.h index b31d6b94..4aa05ee3 100644 --- a/Globals.h +++ b/Globals.h @@ -256,7 +256,8 @@ class Global static int iCameraLast; static std::string asVersion; // z opisem static GLint iMaxTextureSize; // maksymalny rozmiar tekstury - static bool ControlPicking; // indicates controls pick mode is enabled + static bool ControlPicking; // indicates controls pick mode is active + static bool InputMouse; // whether control pick mode can be activated static int iTextMode; // tryb pracy wyświetlacza tekstowego static int iScreenMode[12]; // numer ekranu wyświetlacza tekstowego static bool bDoubleAmbient; // podwójna jasność ambient diff --git a/McZapkie/Mover.cpp b/McZapkie/Mover.cpp index 31a3226d..246575be 100644 --- a/McZapkie/Mover.cpp +++ b/McZapkie/Mover.cpp @@ -1544,7 +1544,7 @@ double TMoverParameters::ShowEngineRotation(int VehN) switch (VehN) { // numer obrotomierza case 1: - return fabs(enrot); + return std::abs(enrot); case 2: for (b = 0; b <= 1; ++b) if (TestFlag(Couplers[b].CouplingFlag, ctrain_controll)) @@ -3045,6 +3045,11 @@ void TMoverParameters::CompressorCheck(double dt) } else { + if( ( EngineType == DieselEngine ) + && ( CompressorPower == 0 ) ) { + // experimental: make sure compressor coupled with diesel engine is always ready for work + CompressorAllow = true; + } if (CompressorFlag) // jeśli sprężarka załączona { // sprawdzić możliwe warunki wyłączenia sprężarki if (CompressorPower == 5) // jeśli zasilanie z sąsiedniego członu @@ -3172,29 +3177,38 @@ void TMoverParameters::CompressorCheck(double dt) } } - if (CompressorFlag) - if ((EngineType == DieselElectric) && (CompressorPower > 0)) - CompressedVolume += dt * CompressorSpeed * (2.0 * MaxCompressor - Compressor) / - MaxCompressor * - (DElist[MainCtrlPos].RPM / DElist[MainCtrlPosNo].RPM); - else - { + if( CompressorFlag ) { + if( ( EngineType == DieselElectric ) && ( CompressorPower > 0 ) ) { CompressedVolume += - dt * CompressorSpeed * (2.0 * MaxCompressor - Compressor) / MaxCompressor; - if ((CompressorPower == 5) && (Couplers[1].Connected != NULL)) - Couplers[1].Connected->TotalCurrent += - 0.0015 * Couplers[1].Connected->Voltage; // tymczasowo tylko obciążenie - // sprężarki, tak z 5A na - // sprężarkę - else if ((CompressorPower == 4) && (Couplers[0].Connected != NULL)) - Couplers[0].Connected->TotalCurrent += - 0.0015 * Couplers[0].Connected->Voltage; // tymczasowo tylko obciążenie - // sprężarki, tak z 5A na - // sprężarkę + dt * CompressorSpeed + * ( 2.0 * MaxCompressor - Compressor ) / MaxCompressor + * ( DElist[ MainCtrlPos ].RPM / DElist[ MainCtrlPosNo ].RPM ); + } + else if( ( EngineType == DieselEngine ) && ( CompressorPower == 0 ) ) { + // experimental: compressor coupled with diesel engine, output scaled by current engine rotational speed + CompressedVolume += + dt * CompressorSpeed + * ( 2.0 * MaxCompressor - Compressor ) / MaxCompressor + * ( std::abs( enrot ) / nmax ); + } + else { + CompressedVolume += + dt * CompressorSpeed * ( 2.0 * MaxCompressor - Compressor ) / MaxCompressor; + if( ( CompressorPower == 5 ) && ( Couplers[ 1 ].Connected != NULL ) ) + Couplers[ 1 ].Connected->TotalCurrent += + 0.0015 * Couplers[ 1 ].Connected->Voltage; // tymczasowo tylko obciążenie + // sprężarki, tak z 5A na + // sprężarkę + else if( ( CompressorPower == 4 ) && ( Couplers[ 0 ].Connected != NULL ) ) + Couplers[ 0 ].Connected->TotalCurrent += + 0.0015 * Couplers[ 0 ].Connected->Voltage; // tymczasowo tylko obciążenie + // sprężarki, tak z 5A na + // sprężarkę else TotalCurrent += 0.0015 * - Voltage; // tymczasowo tylko obciążenie sprężarki, tak z 5A na sprężarkę + Voltage; // tymczasowo tylko obciążenie sprężarki, tak z 5A na sprężarkę } + } } } } @@ -7236,9 +7250,10 @@ void TMoverParameters::LoadFIZ_Engine( std::string const &Input ) { extract_value( dizel_nmin, "nmin", Input, "" ); dizel_nmin /= 60.0; - extract_value( dizel_nmax, "nmax", Input, "" ); - dizel_nmax /= 60.0; - nmax = dizel_nmax; // not sure if this is needed, but just in case + // TODO: unify naming scheme and sort out which diesel engine params are used where and how + extract_value( nmax, "nmax", Input, "" ); + nmax /= 60.0; +// nmax = dizel_nmax; // not sure if this is needed, but just in case extract_value( dizel_nmax_cutoff, "nmax_cutoff", Input, "0.0" ); dizel_nmax_cutoff /= 60.0; extract_value( dizel_AIM, "AIM", Input, "1.0" ); diff --git a/World.cpp b/World.cpp index c01d1264..7b8120d4 100644 --- a/World.cpp +++ b/World.cpp @@ -301,34 +301,38 @@ bool TWorld::Init( GLFWwindow *Window ) { "ShaXbee, Oli_EU, youBy, KURS90, Ra, hunter, szociu, Stele, Q, firleju and others\n" ); UILayer.set_background( "logo" ); - +/* std::shared_ptr initpanel = std::make_shared(85, 600); - +*/ TSoundsManager::Init( glfwGetWin32Window( window ) ); WriteLog("Sound Init OK"); TModelsManager::Init(); WriteLog("Models init OK"); - +/* initpanel->text_lines.emplace_back( "Loading scenery / Wczytywanie scenerii:", float4( 0.0f, 0.0f, 0.0f, 1.0f ) ); initpanel->text_lines.emplace_back( Global::SceneryFile.substr(0, 40), float4( 0.0f, 0.0f, 0.0f, 1.0f ) ); UILayer.push_back( initpanel ); +*/ + glfwSetWindowTitle( window, ( Global::AppName + " (" + Global::SceneryFile + ")" ).c_str() ); // nazwa scenerii UILayer.set_progress(0.01); + UILayer.set_progress( "Loading scenery / Wczytywanie scenerii" ); GfxRenderer.Render(); WriteLog( "Ground init" ); - Ground.Init(Global::SceneryFile); - WriteLog( "Ground init OK" ); - - glfwSetWindowTitle( window, ( Global::AppName + " (" + Global::SceneryFile + ")" ).c_str() ); // nazwa scenerii + if( true == Ground.Init( Global::SceneryFile ) ) { + WriteLog( "Ground init OK" ); + } simulation::Time.init(); Environment.init(); Camera.Init(Global::FreeCameraInit[0], Global::FreeCameraInitAngle[0]); - +/* initpanel->text_lines.clear(); initpanel->text_lines.emplace_back( "Preparing train / Przygotowanie kabiny:", float4( 0.0f, 0.0f, 0.0f, 1.0f ) ); +*/ + UILayer.set_progress( "Preparing train / Przygotowanie kabiny" ); GfxRenderer.Render(); WriteLog( "Player train init: " + Global::asHumanCtrlVehicle ); @@ -396,6 +400,7 @@ bool TWorld::Init( GLFWwindow *Window ) { Train->Dynamic()->Mechanik->TakeControl(true); */ UILayer.set_progress(); + UILayer.set_progress( "" ); UILayer.set_background( "" ); UILayer.clear_texts(); diff --git a/keyboardinput.cpp b/keyboardinput.cpp index b28781f0..7a2969b6 100644 --- a/keyboardinput.cpp +++ b/keyboardinput.cpp @@ -11,11 +11,7 @@ http://mozilla.org/MPL/2.0/. #include "keyboardinput.h" #include "logs.h" #include "parser.h" -#include "globals.h" -#include "timer.h" -//#include "world.h" -#include "train.h" -#include "renderer.h" +#include "world.h" extern TWorld World; @@ -162,91 +158,6 @@ keyboard_input::key( int const Key, int const Action ) { return true; } -void -keyboard_input::mouse( double Mousex, double Mousey ) { - - m_relay.post( - user_command::viewturn, - reinterpret_cast( Mousex ), - reinterpret_cast( Mousey ), - GLFW_PRESS, - // as we haven't yet implemented either item id system or multiplayer, the 'local' controlled vehicle and entity have temporary ids of 0 - // TODO: pass correct entity id once the missing systems are in place - 0 ); -} - -void -keyboard_input::mouse( int const Button, int const Action ) { - - if( false == Global::ControlPicking ) { return; } - if( true == FreeFlyModeFlag ) { - // for now we're only interested in cab controls - return; - } - - user_command &mousecommand = ( - Button == GLFW_MOUSE_BUTTON_LEFT ? - m_mousecommandleft : - m_mousecommandright - ); - - if( Action == GLFW_RELEASE ) { - if( mousecommand != user_command::none ) { - // NOTE: basic keyboard controls don't have any parameters - // as we haven't yet implemented either item id system or multiplayer, the 'local' controlled vehicle and entity have temporary ids of 0 - // TODO: pass correct entity id once the missing systems are in place - m_relay.post( mousecommand, 0, 0, Action, 0 ); - mousecommand = user_command::none; - } - } - else { - // if not release then it's press - auto train = World.train(); - if( train != nullptr ) { - auto lookup = m_mousecommands.find( train->GetLabel( GfxRenderer.Update_Pick_Control() ) ); - if( lookup != m_mousecommands.end() ) { - mousecommand = ( - Button == GLFW_MOUSE_BUTTON_LEFT ? - lookup->second.left : - lookup->second.right - ); - if( mousecommand != user_command::none ) { - // NOTE: basic keyboard controls don't have any parameters - // as we haven't yet implemented either item id system or multiplayer, the 'local' controlled vehicle and entity have temporary ids of 0 - // TODO: pass correct entity id once the missing systems are in place - m_relay.post( mousecommand, 0, 0, Action, 0 ); - m_updateaccumulator = 0.0; // prevent potential command repeat right after issuing one - } - } - } - } -} - -void -keyboard_input::poll() { - - m_updateaccumulator += Timer::GetDeltaRenderTime(); - - if( m_updateaccumulator < 0.2 ) { - // too early for any work - return; - } - m_updateaccumulator -= 0.2; - - if( m_mousecommandleft != user_command::none ) { - // NOTE: basic keyboard controls don't have any parameters - // as we haven't yet implemented either item id system or multiplayer, the 'local' controlled vehicle and entity have temporary ids of 0 - // TODO: pass correct entity id once the missing systems are in place - m_relay.post( m_mousecommandleft, 0, 0, GLFW_REPEAT, 0 ); - } - if( m_mousecommandright != user_command::none ) { - // NOTE: basic keyboard controls don't have any parameters - // as we haven't yet implemented either item id system or multiplayer, the 'local' controlled vehicle and entity have temporary ids of 0 - // TODO: pass correct entity id once the missing systems are in place - m_relay.post( m_mousecommandright, 0, 0, GLFW_REPEAT, 0 ); - } -} - void keyboard_input::default_bindings() { @@ -446,182 +357,6 @@ const int k_WalkMode = 73; bind(); - m_mousecommands = { - { "mainctrl:", { - user_command::mastercontrollerincrease, - user_command::mastercontrollerdecrease } }, - { "scndctrl:", { - user_command::secondcontrollerincrease, - user_command::secondcontrollerdecrease } }, - { "dirkey:", { - user_command::reverserincrease, - user_command::reverserdecrease } }, - { "brakectrl:", { - user_command::trainbrakedecrease, - user_command::trainbrakeincrease } }, - { "localbrake:", { - user_command::independentbrakedecrease, - user_command::independentbrakeincrease } }, - { "manualbrake:", { - user_command::none, - user_command::none } }, - { "brakeprofile_sw:", { - user_command::brakeactingspeedincrease, - user_command::brakeactingspeeddecrease } }, - { "brakeprofileg_sw:", { - user_command::brakeactingspeeddecrease, - user_command::none } }, - { "brakeprofiler_sw:", { - user_command::brakeactingspeedincrease, - user_command::none } }, - { "maxcurrent_sw:", { - user_command::motoroverloadrelaythresholdtoggle, - user_command::none } }, - { "main_off_bt:", { - user_command::linebreakertoggle, - user_command::none } }, - { "main_on_bt:",{ - user_command::linebreakertoggle, - user_command::none } }, // TODO: dedicated on and off line breaker commands - { "security_reset_bt:", { - user_command::alerteracknowledge, - user_command::none } }, - { "releaser_bt:", { - user_command::independentbrakebailoff, - user_command::none } }, - { "sand_bt:", { - user_command::sandboxactivate, - user_command::none } }, - { "antislip_bt:", { - user_command::wheelspinbrakeactivate, - user_command::none } }, - { "horn_bt:", { - user_command::hornhighactivate, - user_command::hornlowactivate } }, - { "hornlow_bt:", { - user_command::hornlowactivate, - user_command::none } }, - { "hornhigh_bt:", { - user_command::hornhighactivate, - user_command::none } }, - { "fuse_bt:", { - user_command::motoroverloadrelayreset, - user_command::none } }, - { "converterfuse_bt:", { - user_command::converteroverloadrelayreset, - user_command::none } }, - { "stlinoff_bt:", { - user_command::motorconnectorsopen, - user_command::none } }, - { "door_left_sw:", { - user_command::doortoggleleft, - user_command::none } }, - { "door_right_sw:", { - user_command::doortoggleright, - user_command::none } }, - { "departure_signal_bt:", { - user_command::departureannounce, - user_command::none } }, - { "upperlight_sw:", { - user_command::headlighttoggleupper, - user_command::none } }, - { "leftlight_sw:", { - user_command::headlighttoggleleft, - user_command::none } }, - { "rightlight_sw:", { - user_command::headlighttoggleright, - user_command::none } }, - { "dimheadlights_sw:", { - user_command::headlightsdimtoggle, - user_command::none } }, - { "leftend_sw:", { - user_command::redmarkertoggleleft, - user_command::none } }, - { "rightend_sw:", { - user_command::redmarkertoggleright, - user_command::none } }, - { "lights_sw:", { - user_command::none, - user_command::none } }, // TODO: implement commands for lights controller - { "rearupperlight_sw:", { - user_command::headlighttogglerearupper, - user_command::none } }, - { "rearleftlight_sw:", { - user_command::headlighttogglerearleft, - user_command::none } }, - { "rearrightlight_sw:", { - user_command::headlighttogglerearright, - user_command::none } }, - { "rearleftend_sw:", { - user_command::redmarkertogglerearleft, - user_command::none } }, - { "rearrightend_sw:", { - user_command::redmarkertogglerearright, - user_command::none } }, - { "compressor_sw:", { - user_command::compressortoggle, - user_command::none } }, - { "compressorlocal_sw:", { - user_command::compressortogglelocal, - user_command::none } }, - { "converter_sw:", { - user_command::convertertoggle, - user_command::none } }, - { "converterlocal_sw:", { - user_command::convertertogglelocal, - user_command::none } }, - { "converteroff_sw:", { - user_command::convertertoggle, - user_command::none } }, // TODO: dedicated converter shutdown command - { "main_sw:", { - user_command::linebreakertoggle, - user_command::none } }, - { "radio_sw:", { - user_command::radiotoggle, - user_command::none } }, - { "pantfront_sw:", { - user_command::pantographtogglefront, - user_command::none } }, - { "pantrear_sw:", { - user_command::pantographtogglerear, - user_command::none } }, - { "pantfrontoff_sw:", { - user_command::pantographtogglefront, - user_command::none } }, // TODO: dedicated lower pantograph commands - { "pantrearoff_sw:", { - user_command::pantographtogglerear, - user_command::none } }, // TODO: dedicated lower pantograph commands - { "pantalloff_sw:", { - user_command::pantographlowerall, - user_command::none } }, - { "pantselected_sw:", { - user_command::none, - user_command::none } }, // TODO: selected pantograph(s) operation command - { "pantselectedoff_sw:", { - user_command::none, - user_command::none } }, // TODO: lower selected pantograp(s) command - { "trainheating_sw:", { - user_command::heatingtoggle, - user_command::none } }, - { "signalling_sw:", { - user_command::mubrakingindicatortoggle, - user_command::none } }, - { "door_signalling_sw:", { - user_command::doorlocktoggle, - user_command::none } }, - { "nextcurrent_sw:", { - user_command::mucurrentindicatorothersourceactivate, - user_command::none } }, - { "cablight_sw:", { - user_command::interiorlighttoggle, - user_command::none } }, - { "cablightdim_sw:", { - user_command::interiorlightdimtoggle, - user_command::none } }, - { "battery_sw:", { - user_command::batterytoggle, - user_command::none } } - }; } void diff --git a/keyboardinput.h b/keyboardinput.h index dd15b2c1..d31a81f8 100644 --- a/keyboardinput.h +++ b/keyboardinput.h @@ -27,11 +27,7 @@ public: bool key( int const Key, int const Action ); void - mouse( double const Mousex, double const Mousey ); - void - mouse( int const Button, int const Action ); - void - poll(); + poll() {} private: // types @@ -49,18 +45,6 @@ private: typedef std::vector commandsetup_sequence; typedef std::unordered_map usercommand_map; - struct mouse_commands { - - user_command left; - user_command right; - - mouse_commands( user_command const Left, user_command const Right ): - left(Left), right(Right) - {} - }; - - typedef std::unordered_map controlcommands_map; - struct bindings_cache { int forward{ -1 }; @@ -82,13 +66,9 @@ private: // members commandsetup_sequence m_commands; usercommand_map m_bindings; - controlcommands_map m_mousecommands; - user_command m_mousecommandleft { user_command::none }; // last if any command issued with mouse - user_command m_mousecommandright { user_command::none }; command_relay m_relay; bool m_shift{ false }; bool m_ctrl{ false }; - double m_updateaccumulator { 0.0 }; bindings_cache m_bindingscache; std::array m_keys; }; diff --git a/maszyna.vcxproj.filters b/maszyna.vcxproj.filters index 2e0bf701..a12e1e90 100644 --- a/maszyna.vcxproj.filters +++ b/maszyna.vcxproj.filters @@ -225,6 +225,9 @@ Source Files + + Source Files\input + @@ -440,6 +443,9 @@ Header Files + + Header Files\input + diff --git a/mouseinput.cpp b/mouseinput.cpp new file mode 100644 index 00000000..1b99fc27 --- /dev/null +++ b/mouseinput.cpp @@ -0,0 +1,335 @@ +/* +This Source Code Form is subject to the +terms of the Mozilla Public License, v. +2.0. If a copy of the MPL was not +distributed with this file, You can +obtain one at +http://mozilla.org/MPL/2.0/. +*/ + +#include "stdafx.h" +#include "mouseinput.h" +#include "globals.h" +#include "timer.h" +#include "world.h" +#include "train.h" +#include "renderer.h" + +extern TWorld World; + +void +mouse_input::move( double Mousex, double Mousey ) { + + if( false == Global::ControlPicking ) { + // default control mode + m_relay.post( + user_command::viewturn, + reinterpret_cast( Mousex ), + reinterpret_cast( Mousey ), + GLFW_PRESS, + // as we haven't yet implemented either item id system or multiplayer, the 'local' controlled vehicle and entity have temporary ids of 0 + // TODO: pass correct entity id once the missing systems are in place + 0 ); + } + else { + if( false == m_pickmodepanning ) { + // even if the view panning isn't active we capture the cursor position in case it does get activated + m_cursorposition.x = Mousex; + m_cursorposition.y = Mousey; + return; + } + glm::dvec2 cursorposition { Mousex, Mousey }; + auto const viewoffset = cursorposition - m_cursorposition; + m_relay.post( + user_command::viewturn, + reinterpret_cast( viewoffset.x ), + reinterpret_cast( viewoffset.y ), + GLFW_PRESS, + // as we haven't yet implemented either item id system or multiplayer, the 'local' controlled vehicle and entity have temporary ids of 0 + // TODO: pass correct entity id once the missing systems are in place + 0 ); + m_cursorposition = cursorposition; + } +} + +void +mouse_input::button( int const Button, int const Action ) { + + if( false == Global::ControlPicking ) { return; } + if( true == FreeFlyModeFlag ) { + // for now we're only interested in cab controls + return; + } + + user_command &mousecommand = ( + Button == GLFW_MOUSE_BUTTON_LEFT ? + m_mousecommandleft : + m_mousecommandright + ); + + if( Action == GLFW_RELEASE ) { + if( mousecommand != user_command::none ) { + // NOTE: basic keyboard controls don't have any parameters + // as we haven't yet implemented either item id system or multiplayer, the 'local' controlled vehicle and entity have temporary ids of 0 + // TODO: pass correct entity id once the missing systems are in place + m_relay.post( mousecommand, 0, 0, Action, 0 ); + mousecommand = user_command::none; + } + else { + // if it's the right mouse button that got released, stop view panning + if( Button == GLFW_MOUSE_BUTTON_RIGHT ) { + m_pickmodepanning = false; + } + } + } + else { + // if not release then it's press + auto train = World.train(); + if( train != nullptr ) { + auto lookup = m_mousecommands.find( train->GetLabel( GfxRenderer.Update_Pick_Control() ) ); + if( lookup != m_mousecommands.end() ) { + mousecommand = ( + Button == GLFW_MOUSE_BUTTON_LEFT ? + lookup->second.left : + lookup->second.right + ); + if( mousecommand != user_command::none ) { + // check manually for commands which have 'fast' variants launched with shift modifier + if( Global::shiftState ) { + switch( mousecommand ) { + case user_command::mastercontrollerincrease: { mousecommand = user_command::mastercontrollerincreasefast; break; } + case user_command::mastercontrollerdecrease: { mousecommand = user_command::mastercontrollerdecreasefast; break; } + case user_command::secondcontrollerincrease: { mousecommand = user_command::secondcontrollerincreasefast; break; } + case user_command::secondcontrollerdecrease: { mousecommand = user_command::secondcontrollerdecreasefast; break; } + case user_command::independentbrakeincrease: { mousecommand = user_command::independentbrakeincreasefast; break; } + case user_command::independentbrakedecrease: { mousecommand = user_command::independentbrakedecreasefast; break; } + default: { break; } + } + } + // NOTE: basic keyboard controls don't have any parameters + // as we haven't yet implemented either item id system or multiplayer, the 'local' controlled vehicle and entity have temporary ids of 0 + // TODO: pass correct entity id once the missing systems are in place + m_relay.post( mousecommand, 0, 0, Action, 0 ); + m_updateaccumulator = 0.0; // prevent potential command repeat right after issuing one + if( mousecommand == user_command::mastercontrollerincrease ) { + m_updateaccumulator -= 0.15; // extra pause on first increase of master controller + } + } + } + else { + // if we don't have any recognized element under the cursor and the right button was pressed, enter view panning mode + if( Button == GLFW_MOUSE_BUTTON_RIGHT ) { + m_pickmodepanning = true; + } + } + } + } +} + +void +mouse_input::poll() { + + m_updateaccumulator += Timer::GetDeltaRenderTime(); + + if( m_updateaccumulator < 0.1 ) { + // too early for any work + return; + } + m_updateaccumulator -= 0.1; + + if( m_mousecommandleft != user_command::none ) { + // NOTE: basic keyboard controls don't have any parameters + // as we haven't yet implemented either item id system or multiplayer, the 'local' controlled vehicle and entity have temporary ids of 0 + // TODO: pass correct entity id once the missing systems are in place + m_relay.post( m_mousecommandleft, 0, 0, GLFW_REPEAT, 0 ); + } + if( m_mousecommandright != user_command::none ) { + // NOTE: basic keyboard controls don't have any parameters + // as we haven't yet implemented either item id system or multiplayer, the 'local' controlled vehicle and entity have temporary ids of 0 + // TODO: pass correct entity id once the missing systems are in place + m_relay.post( m_mousecommandright, 0, 0, GLFW_REPEAT, 0 ); + } +} + +void +mouse_input::default_bindings() { + + m_mousecommands = { + { "mainctrl:", { + user_command::mastercontrollerincrease, + user_command::mastercontrollerdecrease } }, + { "scndctrl:", { + user_command::secondcontrollerincrease, + user_command::secondcontrollerdecrease } }, + { "dirkey:", { + user_command::reverserincrease, + user_command::reverserdecrease } }, + { "brakectrl:", { + user_command::trainbrakeincrease, + user_command::trainbrakedecrease } }, + { "localbrake:", { + user_command::independentbrakeincrease, + user_command::independentbrakedecrease } }, + { "manualbrake:", { + user_command::none, + user_command::none } }, + { "brakeprofile_sw:", { + user_command::brakeactingspeedincrease, + user_command::brakeactingspeeddecrease } }, + { "brakeprofileg_sw:", { + user_command::brakeactingspeeddecrease, + user_command::none } }, + { "brakeprofiler_sw:", { + user_command::brakeactingspeedincrease, + user_command::none } }, + { "maxcurrent_sw:", { + user_command::motoroverloadrelaythresholdtoggle, + user_command::none } }, + { "main_off_bt:", { + user_command::linebreakertoggle, + user_command::none } }, + { "main_on_bt:",{ + user_command::linebreakertoggle, + user_command::none } }, // TODO: dedicated on and off line breaker commands + { "security_reset_bt:", { + user_command::alerteracknowledge, + user_command::none } }, + { "releaser_bt:", { + user_command::independentbrakebailoff, + user_command::none } }, + { "sand_bt:", { + user_command::sandboxactivate, + user_command::none } }, + { "antislip_bt:", { + user_command::wheelspinbrakeactivate, + user_command::none } }, + { "horn_bt:", { + user_command::hornhighactivate, + user_command::hornlowactivate } }, + { "hornlow_bt:", { + user_command::hornlowactivate, + user_command::none } }, + { "hornhigh_bt:", { + user_command::hornhighactivate, + user_command::none } }, + { "fuse_bt:", { + user_command::motoroverloadrelayreset, + user_command::none } }, + { "converterfuse_bt:", { + user_command::converteroverloadrelayreset, + user_command::none } }, + { "stlinoff_bt:", { + user_command::motorconnectorsopen, + user_command::none } }, + { "door_left_sw:", { + user_command::doortoggleleft, + user_command::none } }, + { "door_right_sw:", { + user_command::doortoggleright, + user_command::none } }, + { "departure_signal_bt:", { + user_command::departureannounce, + user_command::none } }, + { "upperlight_sw:", { + user_command::headlighttoggleupper, + user_command::none } }, + { "leftlight_sw:", { + user_command::headlighttoggleleft, + user_command::none } }, + { "rightlight_sw:", { + user_command::headlighttoggleright, + user_command::none } }, + { "dimheadlights_sw:", { + user_command::headlightsdimtoggle, + user_command::none } }, + { "leftend_sw:", { + user_command::redmarkertoggleleft, + user_command::none } }, + { "rightend_sw:", { + user_command::redmarkertoggleright, + user_command::none } }, + { "lights_sw:", { + user_command::none, + user_command::none } }, // TODO: implement commands for lights controller + { "rearupperlight_sw:", { + user_command::headlighttogglerearupper, + user_command::none } }, + { "rearleftlight_sw:", { + user_command::headlighttogglerearleft, + user_command::none } }, + { "rearrightlight_sw:", { + user_command::headlighttogglerearright, + user_command::none } }, + { "rearleftend_sw:", { + user_command::redmarkertogglerearleft, + user_command::none } }, + { "rearrightend_sw:", { + user_command::redmarkertogglerearright, + user_command::none } }, + { "compressor_sw:", { + user_command::compressortoggle, + user_command::none } }, + { "compressorlocal_sw:", { + user_command::compressortogglelocal, + user_command::none } }, + { "converter_sw:", { + user_command::convertertoggle, + user_command::none } }, + { "converterlocal_sw:", { + user_command::convertertogglelocal, + user_command::none } }, + { "converteroff_sw:", { + user_command::convertertoggle, + user_command::none } }, // TODO: dedicated converter shutdown command + { "main_sw:", { + user_command::linebreakertoggle, + user_command::none } }, + { "radio_sw:", { + user_command::radiotoggle, + user_command::none } }, + { "pantfront_sw:", { + user_command::pantographtogglefront, + user_command::none } }, + { "pantrear_sw:", { + user_command::pantographtogglerear, + user_command::none } }, + { "pantfrontoff_sw:", { + user_command::pantographtogglefront, + user_command::none } }, // TODO: dedicated lower pantograph commands + { "pantrearoff_sw:", { + user_command::pantographtogglerear, + user_command::none } }, // TODO: dedicated lower pantograph commands + { "pantalloff_sw:", { + user_command::pantographlowerall, + user_command::none } }, + { "pantselected_sw:", { + user_command::none, + user_command::none } }, // TODO: selected pantograph(s) operation command + { "pantselectedoff_sw:", { + user_command::none, + user_command::none } }, // TODO: lower selected pantograp(s) command + { "trainheating_sw:", { + user_command::heatingtoggle, + user_command::none } }, + { "signalling_sw:", { + user_command::mubrakingindicatortoggle, + user_command::none } }, + { "door_signalling_sw:", { + user_command::doorlocktoggle, + user_command::none } }, + { "nextcurrent_sw:", { + user_command::mucurrentindicatorothersourceactivate, + user_command::none } }, + { "cablight_sw:", { + user_command::interiorlighttoggle, + user_command::none } }, + { "cablightdim_sw:", { + user_command::interiorlightdimtoggle, + user_command::none } }, + { "battery_sw:", { + user_command::batterytoggle, + user_command::none } } + }; +} + +//--------------------------------------------------------------------------- diff --git a/mouseinput.h b/mouseinput.h new file mode 100644 index 00000000..95a1f194 --- /dev/null +++ b/mouseinput.h @@ -0,0 +1,60 @@ +/* +This Source Code Form is subject to the +terms of the Mozilla Public License, v. +2.0. If a copy of the MPL was not +distributed with this file, You can +obtain one at +http://mozilla.org/MPL/2.0/. +*/ + +#pragma once + +#include +#include +#include "command.h" + +class mouse_input { + +public: +// constructors + mouse_input() { default_bindings(); } + +// methods + bool + init() { return true; } + void + move( double const Mousex, double const Mousey ); + void + button( int const Button, int const Action ); + void + poll(); + +private: +// types + struct mouse_commands { + + user_command left; + user_command right; + + mouse_commands( user_command const Left, user_command const Right ): + left(Left), right(Right) + {} + }; + + typedef std::unordered_map controlcommands_map; + +// methods + void + default_bindings(); + +// members + controlcommands_map m_mousecommands; + user_command m_mousecommandleft { user_command::none }; // last if any command issued with left mouse button + user_command m_mousecommandright { user_command::none }; // last if any command issued with right mouse button + command_relay m_relay; + double m_updateaccumulator { 0.0 }; + bool m_pickmodepanning { false }; // indicates mouse is in view panning mode + glm::dvec2 m_cursorposition; // stored last mouse position, used for panning +}; + +//--------------------------------------------------------------------------- diff --git a/renderer.cpp b/renderer.cpp index bde34e81..c5739dad 100644 --- a/renderer.cpp +++ b/renderer.cpp @@ -206,8 +206,10 @@ opengl_renderer::Render_pass( rendermode const Mode ) { // TODO: run shadowmap pass before color // ::glViewport( 0, 0, Global::ScreenWidth, Global::ScreenHeight ); - auto const skydomecolour = World.Environment.m_skydome.GetAverageColor(); - ::glClearColor( skydomecolour.x, skydomecolour.y, skydomecolour.z, 0.0f ); // kolor nieba + if( World.InitPerformed() ) { + auto const skydomecolour = World.Environment.m_skydome.GetAverageColor(); + ::glClearColor( skydomecolour.x, skydomecolour.y, skydomecolour.z, 0.0f ); // kolor nieba + } ::glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); if( World.InitPerformed() ) { @@ -1972,6 +1974,7 @@ opengl_renderer::Update_Pick_Control() { ::glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 ); } #endif + m_pickcontrolitem = control; return control; } @@ -2015,6 +2018,7 @@ opengl_renderer::Update_Pick_Node() { ::glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 ); } #endif + m_picksceneryitem = node; return node; } @@ -2080,7 +2084,7 @@ opengl_renderer::Update( double const Deltatime ) { if( ( true == Global::ControlPicking ) && ( false == FreeFlyModeFlag ) ) { - m_pickcontrolitem = Update_Pick_Control(); + Update_Pick_Control(); } else { m_pickcontrolitem = nullptr; @@ -2089,7 +2093,7 @@ opengl_renderer::Update( double const Deltatime ) { if( ( true == Global::ControlPicking ) && ( true == DebugModeFlag ) && ( true == FreeFlyModeFlag ) ) { - m_picksceneryitem = Update_Pick_Node(); + Update_Pick_Node(); } else { m_picksceneryitem = nullptr; diff --git a/uilayer.cpp b/uilayer.cpp index ef753b38..e6ca85c5 100644 --- a/uilayer.cpp +++ b/uilayer.cpp @@ -143,7 +143,29 @@ ui_layer::render_progress() { float4( 8.0f / 255.0f, 160.0f / 255.0f, 8.0f / 255.0f, 1.0f ) ); } - glPopAttrib(); + if( false == m_progresstext.empty() ) { + float const screenratio = static_cast( Global::iWindowWidth ) / Global::iWindowHeight; + float const width = + ( screenratio >= (4.0f/3.0f) ? + ( 4.0f / 3.0f ) * Global::iWindowHeight : + Global::iWindowWidth ); + float const heightratio = + ( screenratio >= ( 4.0f / 3.0f ) ? + Global::iWindowHeight / 768.0 : + Global::iWindowHeight / 768.0 * screenratio / ( 4.0f / 3.0f ) ); + float const height = 768.0f * heightratio; + + ::glColor4f( 216.0f / 255.0f, 216.0f / 255.0f, 216.0f / 255.0f, 1.0f ); + auto const charsize = 9.0f; + auto const textwidth = m_progresstext.size() * charsize; + auto const textheight = 12.0f; + ::glRasterPos2f( + ( 0.5f * ( Global::iWindowWidth - width ) + origin.x * heightratio ) + ( ( size.x * heightratio - textwidth ) * 0.5f * heightratio ), + ( 0.5f * ( Global::iWindowHeight - height ) + origin.y * heightratio ) + ( charsize ) + ( ( size.y * heightratio - textheight ) * 0.5f * heightratio ) ); + print( m_progresstext ); + } + + glPopAttrib(); } void diff --git a/uilayer.h b/uilayer.h index 86ed2417..b49c0598 100644 --- a/uilayer.h +++ b/uilayer.h @@ -47,6 +47,8 @@ public: // stores operation progress void set_progress( float const Progress = 0.0f, float const Subtaskprogress = 0.0f ); + void + set_progress( std::string const &Text ) { m_progresstext = Text; } // sets the ui background texture, if any void set_background( std::string const &Filename = "" ); diff --git a/version.h b/version.h index 6ca9253b..4b87d6ad 100644 --- a/version.h +++ b/version.h @@ -1,5 +1,5 @@ #pragma once #define VERSION_MAJOR 17 -#define VERSION_MINOR 708 +#define VERSION_MINOR 710 #define VERSION_REVISION 0 From 9877b37e1f116e2ff6120b2911fe4eb9f5a8f4ee Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Wed, 12 Jul 2017 18:09:51 +0200 Subject: [PATCH 3/6] build 170712. increased amount of generic cab items, varying command repeat rate for mouse control --- EU07.cpp | 14 +-- Timer.cpp | 10 --- Timer.h | 4 - Train.cpp | 190 ++++++++++++++++++++++++++-------------- Train.h | 14 +-- World.cpp | 21 +---- World.h | 68 -------------- command.cpp | 10 +++ command.h | 14 ++- keyboardinput.cpp | 22 +++++ maszyna.vcxproj.filters | 6 ++ mouseinput.cpp | 77 +++++++++++++++- mouseinput.h | 10 ++- stdafx.h | 1 + translation.cpp | 31 +++++++ translation.h | 95 ++++++++++++++++++++ version.h | 2 +- 17 files changed, 403 insertions(+), 186 deletions(-) create mode 100644 translation.cpp create mode 100644 translation.h diff --git a/EU07.cpp b/EU07.cpp index 20b79d34..c226a225 100644 --- a/EU07.cpp +++ b/EU07.cpp @@ -68,7 +68,7 @@ namespace input { keyboard_input Keyboard; mouse_input Mouse; gamepad_input Gamepad; -glm::dvec2 mouse_pos; // stores last mouse position in control picking mode +glm::dvec2 mouse_pickmodepos; // stores last mouse position in control picking mode } @@ -144,8 +144,8 @@ void mouse_button_callback( GLFWwindow* window, int button, int action, int mods } } -void key_callback( GLFWwindow *window, int key, int scancode, int action, int mods ) -{ +void key_callback( GLFWwindow *window, int key, int scancode, int action, int mods ) { + input::Keyboard.key( key, action ); Global::shiftState = ( mods & GLFW_MOD_SHIFT ) ? true : false; @@ -159,14 +159,14 @@ void key_callback( GLFWwindow *window, int key, int scancode, int action, int mo if( Global::ControlPicking ) { // switch off - glfwGetCursorPos( window, &input::mouse_pos.x, &input::mouse_pos.y ); + glfwGetCursorPos( window, &input::mouse_pickmodepos.x, &input::mouse_pickmodepos.y ); glfwSetInputMode( window, GLFW_CURSOR, GLFW_CURSOR_DISABLED ); glfwSetCursorPos( window, 0, 0 ); } else { // enter picking mode glfwSetInputMode( window, GLFW_CURSOR, GLFW_CURSOR_NORMAL ); - glfwSetCursorPos( window, input::mouse_pos.x, input::mouse_pos.y ); + glfwSetCursorPos( window, input::mouse_pickmodepos.x, input::mouse_pickmodepos.y ); } // actually toggle the mode Global::ControlPicking = !Global::ControlPicking; @@ -183,8 +183,8 @@ void key_callback( GLFWwindow *window, int key, int scancode, int action, int mo return; } - if( action == GLFW_PRESS || action == GLFW_REPEAT ) - { + if( action == GLFW_PRESS || action == GLFW_REPEAT ) { + World.OnKeyDown( key ); switch( key ) diff --git a/Timer.cpp b/Timer.cpp index 21934834..1ddd600b 100644 --- a/Timer.cpp +++ b/Timer.cpp @@ -47,16 +47,6 @@ void SetDeltaTime(double t) DeltaTime = t; } -double GetSimulationTime() -{ - return fSimulationTime; -} - -void SetSimulationTime(double t) -{ - fSimulationTime = t; -} - bool GetSoundTimer() { // Ra: być może, by dźwięki nie modyfikowały się zbyt często, po 0.1s zeruje się ten licznik return (fSoundTimer == 0.0f); diff --git a/Timer.h b/Timer.h index 5a76ccbe..b6b58371 100644 --- a/Timer.h +++ b/Timer.h @@ -21,10 +21,6 @@ double GetfSinceStart(); void SetDeltaTime(double v); -double GetSimulationTime(); - -void SetSimulationTime(double v); - bool GetSoundTimer(); double GetFPS(); diff --git a/Train.cpp b/Train.cpp index 398cc87e..7e6a1a79 100644 --- a/Train.cpp +++ b/Train.cpp @@ -225,7 +225,17 @@ TTrain::commandhandler_map const TTrain::m_commandhandlers = { { user_command::departureannounce, &TTrain::OnCommand_departureannounce }, { user_command::hornlowactivate, &TTrain::OnCommand_hornlowactivate }, { user_command::hornhighactivate, &TTrain::OnCommand_hornhighactivate }, - { user_command::radiotoggle, &TTrain::OnCommand_radiotoggle } + { user_command::radiotoggle, &TTrain::OnCommand_radiotoggle }, + { user_command::generictoggle0, &TTrain::OnCommand_generictoggle }, + { user_command::generictoggle1, &TTrain::OnCommand_generictoggle }, + { user_command::generictoggle2, &TTrain::OnCommand_generictoggle }, + { user_command::generictoggle3, &TTrain::OnCommand_generictoggle }, + { user_command::generictoggle4, &TTrain::OnCommand_generictoggle }, + { user_command::generictoggle5, &TTrain::OnCommand_generictoggle }, + { user_command::generictoggle6, &TTrain::OnCommand_generictoggle }, + { user_command::generictoggle7, &TTrain::OnCommand_generictoggle }, + { user_command::generictoggle8, &TTrain::OnCommand_generictoggle }, + { user_command::generictoggle9, &TTrain::OnCommand_generictoggle } }; std::vector const TTrain::fPress_labels = { @@ -233,9 +243,10 @@ std::vector const TTrain::fPress_labels = { "ch1: ", "ch2: ", "ch3: ", "ch4: ", "ch5: ", "ch6: ", "ch7: ", "ch8: ", "ch9: ", "ch0: " }; -TTrain::TTrain() -{ - ActiveUniversal4 = false; +TTrain::TTrain() { +/* + Universal4Active = false; +*/ ShowNextCurrent = false; // McZapkie-240302 - przyda sie do tachometru fTachoVelocity = 0; @@ -257,7 +268,7 @@ TTrain::TTrain() bCabLightDim = false; //----- pMechSittingPosition = vector3(0, 0, 0); // ABu: 180404 - LampkaUniversal3_st = false; // ABu: 030405 + InstrumentLightActive = false; // ABu: 030405 dsbNastawnikJazdy = NULL; dsbNastawnikBocz = NULL; dsbRelay = NULL; @@ -424,7 +435,7 @@ PyObject *TTrain::GetTrainState() { PyDict_SetItemString( dict, "ca", PyGetBool( TestFlag( mvOccupied->SecuritySystem.Status, s_aware ) ) ); PyDict_SetItemString( dict, "shp", PyGetBool( TestFlag( mvOccupied->SecuritySystem.Status, s_active ) ) ); PyDict_SetItemString( dict, "pantpress", PyGetFloat( mvControlled->PantPress ) ); - PyDict_SetItemString( dict, "universal3", PyGetBool( LampkaUniversal3_st ) ); + PyDict_SetItemString( dict, "universal3", PyGetBool( InstrumentLightActive ) ); // movement data PyDict_SetItemString( dict, "velocity", PyGetFloat( mover->Vel ) ); PyDict_SetItemString( dict, "tractionforce", PyGetFloat( mover->Ft ) ); @@ -2665,7 +2676,7 @@ void TTrain::OnCommand_instrumentlighttoggle( TTrain *Train, command_data const // NOTE: the check is disabled, as we're presuming light control is present in every vehicle // TODO: proper control deviced definition for the interiors, that doesn't hinge of presence of 3d submodels - if( Train->ggUniversal3Button.SubModel == nullptr ) { + if( Train->ggInstrumentLightButton.SubModel == nullptr ) { if( Command.action == GLFW_PRESS ) { WriteLog( "Universal3 switch is missing, or wasn't defined" ); } @@ -2675,25 +2686,25 @@ void TTrain::OnCommand_instrumentlighttoggle( TTrain *Train, command_data const if( Command.action == GLFW_PRESS ) { // only reacting to press, so the switch doesn't flip back and forth if key is held down // NOTE: instrument lighting isn't fully implemented, so we have to rely on the state of the 'button' i.e. light itself - if( false == Train->LampkaUniversal3_st ) { + if( false == Train->InstrumentLightActive ) { // turn on - Train->LampkaUniversal3_st = true; + Train->InstrumentLightActive = true; // audio feedback - if( Train->ggUniversal3Button.GetValue() < 0.5 ) { + if( Train->ggInstrumentLightButton.GetValue() < 0.5 ) { Train->play_sound( Train->dsbSwitch ); } // visual feedback - Train->ggUniversal3Button.UpdateValue( 1.0 ); + Train->ggInstrumentLightButton.UpdateValue( 1.0 ); } else { //turn off - Train->LampkaUniversal3_st = false; + Train->InstrumentLightActive = false; // audio feedback - if( Train->ggUniversal3Button.GetValue() > 0.5 ) { + if( Train->ggInstrumentLightButton.GetValue() > 0.5 ) { Train->play_sound( Train->dsbSwitch ); } // visual feedback - Train->ggUniversal3Button.UpdateValue( 0.0 ); + Train->ggInstrumentLightButton.UpdateValue( 0.0 ); } } } @@ -2732,6 +2743,41 @@ void TTrain::OnCommand_heatingtoggle( TTrain *Train, command_data const &Command } } +void TTrain::OnCommand_generictoggle( TTrain *Train, command_data const &Command ) { + + auto const itemindex = static_cast( Command.command ) - static_cast( user_command::generictoggle0 ); + auto &item = Train->ggUniversals[ itemindex ]; + + if( item.SubModel == nullptr ) { + if( Command.action == GLFW_PRESS ) { + WriteLog( "Train generic item " + std::to_string( itemindex ) + " is missing, or wasn't defined" ); + } + return; + } + + if( Command.action == GLFW_PRESS ) { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + if( item.GetValue() < 0.25 ) { + // turn on + // audio feedback + if( item.GetValue() < 0.5 ) { + Train->play_sound( Train->dsbSwitch ); + } + // visual feedback + item.UpdateValue( 1.0 ); + } + else { + //turn off + // audio feedback + if( item.GetValue() > 0.5 ) { + Train->play_sound( Train->dsbSwitch ); + } + // visual feedback + item.UpdateValue( 0.0 ); + } + } +} + void TTrain::OnCommand_doorlocktoggle( TTrain *Train, command_data const &Command ) { if( Train->ggDoorSignallingButton.SubModel == nullptr ) { @@ -5193,7 +5239,6 @@ bool TTrain::Update( double const Deltatime ) } else ggMainOffButton.UpdateValue(0); -#endif /* if (cKey==Global::Keys[k_Main]) //z shiftem { ggMainOnButton.PutValue(1); @@ -5220,7 +5265,6 @@ bool TTrain::Update( double const Deltatime ) } } else */ -#ifdef EU07_USE_OLD_COMMAND_SYSTEM //---------------- // hunter-131211: czuwak przeniesiony z OnKeyPress // hunter-091012: zrobiony test czuwaka @@ -5253,7 +5297,6 @@ bool TTrain::Update( double const Deltatime ) } CAflag = false; } -#endif /* if ( Console::Pressed(Global::Keys[k_Czuwak]) ) { @@ -5292,7 +5335,6 @@ bool TTrain::Update( double const Deltatime ) } */ -#ifdef EU07_USE_OLD_COMMAND_SYSTEM if( Console::Pressed( Global::Keys[ k_Sand ] ) ) { if (mvControlled->TrainType != dt_EZT && ggSandButton.SubModel != NULL) @@ -5375,7 +5417,6 @@ bool TTrain::Update( double const Deltatime ) ggCompressorButton.PutValue(0); mvControlled->CompressorSwitch(false); } -#endif /* bez szifta if (cKey==Global::Keys[k_Converter]) //NBMX wyl przetwornicy @@ -5398,7 +5439,6 @@ bool TTrain::Update( double const Deltatime ) else */ //----------------- -#ifdef EU07_USE_OLD_COMMAND_SYSTEM if ((!FreeFlyModeFlag) && (!(DynamicObject->Mechanik ? DynamicObject->Mechanik->AIControllFlag : false))) { @@ -5422,7 +5462,6 @@ bool TTrain::Update( double const Deltatime ) else mvOccupied->BrakeReleaser(0); } // FFMF -#endif if (Console::Pressed(Global::Keys[k_Univ1])) { @@ -5435,13 +5474,11 @@ bool TTrain::Update( double const Deltatime ) ggUniversal1Button.DecValue(dt / 2); } } -#ifdef EU07_USE_OLD_COMMAND_SYSTEM if (!Console::Pressed(Global::Keys[k_SmallCompressor])) // Ra: przecieść to na zwolnienie klawisza if (DynamicObject->Mechanik ? !DynamicObject->Mechanik->AIControllFlag : false) // nie wyłączać, gdy AI mvControlled->PantCompFlag = false; // wyłączona, gdy nie trzymamy klawisza -#else /* // NOTE: disabled to allow 'prototypical' 'tricking' pantograph compressor into running unattended if( ( ( DynamicObject->Mechanik != nullptr ) @@ -5454,7 +5491,6 @@ bool TTrain::Update( double const Deltatime ) mvControlled->PantCompFlag = false; } */ -#endif if (Console::Pressed(Global::Keys[k_Univ2])) { if (!DebugModeFlag) @@ -5467,7 +5503,6 @@ bool TTrain::Update( double const Deltatime ) } } -#ifdef EU07_USE_OLD_COMMAND_SYSTEM // hunter-091012: zrobione z uwzglednieniem przelacznika swiatla if (Console::Pressed(Global::Keys[k_Univ3])) { @@ -5484,13 +5519,13 @@ bool TTrain::Update( double const Deltatime ) } else { - if (ggUniversal3Button.SubModel) + if (ggInstrumentLightButton.SubModel) { - ggUniversal3Button.PutValue(1); // hunter-131211: z UpdateValue na + ggInstrumentLightButton.PutValue(1); // hunter-131211: z UpdateValue na // PutValue - by zachowywal sie jak // pozostale przelaczniki - if (btLampkaUniversal3.Active()) - LampkaUniversal3_st = true; + if (btInstrumentLight.Active()) + InstrumentLightActive = true; } } } @@ -5507,37 +5542,37 @@ bool TTrain::Update( double const Deltatime ) } else { - if (ggUniversal3Button.SubModel) + if (ggInstrumentLightButton.SubModel) { - ggUniversal3Button.PutValue(0); // hunter-131211: z UpdateValue na + ggInstrumentLightButton.PutValue(0); // hunter-131211: z UpdateValue na // PutValue - by zachowywal sie jak // pozostale przelaczniki - if (btLampkaUniversal3.Active()) - LampkaUniversal3_st = false; + if (btInstrumentLight.Active()) + InstrumentLightActive = false; } } } } #endif // ABu030405 obsluga lampki uniwersalnej: - if (btLampkaUniversal3.Active()) // w ogóle jest - if (LampkaUniversal3_st) // załączona - switch (LampkaUniversal3_typ) + if (btInstrumentLight.Active()) // w ogóle jest + if (InstrumentLightActive) // załączona + switch (InstrumentLightType) { case 0: - btLampkaUniversal3.Turn( mvControlled->Battery || mvControlled->ConverterFlag ); + btInstrumentLight.Turn( mvControlled->Battery || mvControlled->ConverterFlag ); break; case 1: - btLampkaUniversal3.Turn(mvControlled->Mains); + btInstrumentLight.Turn(mvControlled->Mains); break; case 2: - btLampkaUniversal3.Turn(mvControlled->ConverterFlag); + btInstrumentLight.Turn(mvControlled->ConverterFlag); break; default: - btLampkaUniversal3.TurnOff(); + btInstrumentLight.TurnOff(); } else - btLampkaUniversal3.TurnOff(); + btInstrumentLight.TurnOff(); #ifdef EU07_USE_OLD_COMMAND_SYSTEM // hunter-091012: przepisanie univ4 i zrobione z uwzglednieniem przelacznika @@ -5556,7 +5591,7 @@ bool TTrain::Update( double const Deltatime ) } else { - ActiveUniversal4 = true; + Universal4Active = true; // ggUniversal4Button.UpdateValue(1); } } @@ -5574,7 +5609,7 @@ bool TTrain::Update( double const Deltatime ) } else { - ActiveUniversal4 = false; + Universal4Active = false; // ggUniversal4Button.UpdateValue(0); } } @@ -5889,18 +5924,23 @@ bool TTrain::Update( double const Deltatime ) ggHornButton.Update(); ggHornLowButton.Update(); ggHornHighButton.Update(); +/* ggUniversal1Button.Update(); ggUniversal2Button.Update(); - ggUniversal3Button.Update(); + if( Universal4Active ) { + ggUniversal4Button.PermIncValue( dt ); + } + ggUniversal4Button.Update(); +*/ + for( auto &universal : ggUniversals ) { + universal.Update(); + } // hunter-091012 + ggInstrumentLightButton.Update(); ggCabLightButton.Update(); ggCabLightDimButton.Update(); ggBatteryButton.Update(); //------ - if (ActiveUniversal4) - ggUniversal4Button.PermIncValue(dt); - - ggUniversal4Button.Update(); #ifdef EU07_USE_OLD_COMMAND_SYSTEM ggMainOffButton.UpdateValue(0); ggMainOnButton.UpdateValue(0); @@ -6460,7 +6500,9 @@ bool TTrain::InitializeCab(int NewCabNo, std::string const &asFileName) DynamicObject ->mdModel; // McZapkie-170103: szukaj elementy kabiny w glownym modelu } - ActiveUniversal4 = false; +/* + Universal4Active = false; +*/ clear_cab_controls(); } if (nullptr == DynamicObject->mdKabina) @@ -6706,14 +6748,19 @@ void TTrain::clear_cab_controls() ggHornLowButton.Clear(); ggHornHighButton.Clear(); ggNextCurrentButton.Clear(); +/* ggUniversal1Button.Clear(); ggUniversal2Button.Clear(); - ggUniversal3Button.Clear(); + ggUniversal4Button.Clear(); +*/ + for( auto &universal : ggUniversals ) { + universal.Clear(); + } + ggInstrumentLightButton.Clear(); // hunter-091012 ggCabLightButton.Clear(); ggCabLightDimButton.Clear(); //------- - ggUniversal4Button.Clear(); ggFuseButton.Clear(); ggConverterFuseButton.Clear(); ggStLinOffButton.Clear(); @@ -6772,7 +6819,7 @@ void TTrain::clear_cab_controls() btLampkaRadio.Clear(); btLampkaHamulecReczny.Clear(); btLampkaBlokadaDrzwi.Clear(); - btLampkaUniversal3.Clear(); + btInstrumentLight.Clear(); btLampkaWentZaluzje.Clear(); btLampkaOgrzewanieSkladu.Clear(11); btLampkaSHP.Clear(0); @@ -6930,8 +6977,8 @@ void TTrain::set_cab_controls() { if( true == bCabLightDim ) { ggCabLightDimButton.PutValue( 1.0 ); } - if( true == LampkaUniversal3_st ) { - ggUniversal3Button.PutValue( 1.0 ); + if( true == InstrumentLightActive ) { + ggInstrumentLightButton.PutValue( 1.0 ); } // doors // NOTE: we're relying on the cab models to have switches reversed for the rear cab(?) @@ -7073,20 +7120,20 @@ bool TTrain::initialize_button(cParser &Parser, std::string const &Label, int co { btLampkaWysRozr.Load(Parser, DynamicObject->mdKabina); } - else if (Label == "i-universal3:") + else if (Label == "i-instrumentlight:") { - btLampkaUniversal3.Load(Parser, DynamicObject->mdKabina, DynamicObject->mdModel); - LampkaUniversal3_typ = 0; + btInstrumentLight.Load(Parser, DynamicObject->mdKabina, DynamicObject->mdModel); + InstrumentLightType = 0; } - else if (Label == "i-universal3_M:") + else if (Label == "i-instrumentlight_M:") { - btLampkaUniversal3.Load(Parser, DynamicObject->mdKabina, DynamicObject->mdModel); - LampkaUniversal3_typ = 1; + btInstrumentLight.Load(Parser, DynamicObject->mdKabina, DynamicObject->mdModel); + InstrumentLightType = 1; } - else if (Label == "i-universal3_C:") + else if (Label == "i-instrumentlight_C:") { - btLampkaUniversal3.Load(Parser, DynamicObject->mdKabina, DynamicObject->mdModel); - LampkaUniversal3_typ = 2; + btInstrumentLight.Load(Parser, DynamicObject->mdKabina, DynamicObject->mdModel); + InstrumentLightType = 2; } else if (Label == "i-vent_trim:") { @@ -7279,9 +7326,20 @@ bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int con { "signalling_sw:", ggSignallingButton }, { "door_signalling_sw:", ggDoorSignallingButton }, { "nextcurrent_sw:", ggNextCurrentButton }, + { "instrumentlight_sw:", ggInstrumentLightButton }, { "cablight_sw:", ggCabLightButton }, { "cablightdim_sw:", ggCabLightDimButton }, - { "battery_sw:", ggBatteryButton } + { "battery_sw:", ggBatteryButton }, + { "universal0:", ggUniversals[ 0 ] }, + { "universal1:", ggUniversals[ 1 ] }, + { "universal2:", ggUniversals[ 2 ] }, + { "universal3:", ggUniversals[ 3 ] }, + { "universal4:", ggUniversals[ 4 ] }, + { "universal5:", ggUniversals[ 5 ] }, + { "universal6:", ggUniversals[ 6 ] }, + { "universal7:", ggUniversals[ 7 ] }, + { "universal8:", ggUniversals[ 8 ] }, + { "universal9:", ggUniversals[ 9 ] } }; auto lookup = gauges.find( Label ); if( lookup != gauges.end() ) { @@ -7292,6 +7350,7 @@ bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int con else if( Label == "mainctrlact:" ) { ggMainCtrlAct.Load( Parser, DynamicObject->mdKabina, DynamicObject->mdModel ); } +/* else if (Label == "universal1:") { ggUniversal1Button.Load(Parser, DynamicObject->mdKabina, DynamicObject->mdModel); @@ -7302,12 +7361,13 @@ bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int con } else if (Label == "universal3:") { - ggUniversal3Button.Load(Parser, DynamicObject->mdKabina, DynamicObject->mdModel); + ggInstrumentLightButton.Load(Parser, DynamicObject->mdKabina, DynamicObject->mdModel); } else if (Label == "universal4:") { ggUniversal4Button.Load(Parser, DynamicObject->mdKabina, DynamicObject->mdModel); } +*/ // SEKCJA WSKAZNIKOW else if ((Label == "tachometer:") || (Label == "tachometerb:")) { diff --git a/Train.h b/Train.h index 6daf8ac7..6d8fcef9 100644 --- a/Train.h +++ b/Train.h @@ -73,7 +73,6 @@ class TTrain { public: bool CabChange(int iDirection); - bool ActiveUniversal4; bool ShowNextCurrent; // pokaz przd w podlaczonej lokomotywie (ET41) bool InitializeCab(int NewCabNo, std::string const &asFileName); TTrain(); @@ -189,6 +188,7 @@ class TTrain static void OnCommand_hornlowactivate( TTrain *Train, command_data const &Command ); static void OnCommand_hornhighactivate( TTrain *Train, command_data const &Command ); static void OnCommand_radiotoggle( TTrain *Train, command_data const &Command ); + static void OnCommand_generictoggle( TTrain *Train, command_data const &Command ); // members TDynamicObject *DynamicObject; // przestawia zmiana pojazdu [F5] @@ -277,12 +277,16 @@ public: // reszta może by?publiczna TGauge ggHornLowButton; TGauge ggHornHighButton; TGauge ggNextCurrentButton; +/* // ABu 090305 - uniwersalne przyciski TGauge ggUniversal1Button; TGauge ggUniversal2Button; - TGauge ggUniversal3Button; TGauge ggUniversal4Button; + bool Universal4Active; +*/ + std::array ggUniversals; // NOTE: temporary arrangement until we have dynamically built control table + TGauge ggInstrumentLightButton; TGauge ggCabLightButton; // hunter-091012: przelacznik oswietlania kabiny TGauge ggCabLightDimButton; // hunter-091012: przelacznik przyciemnienia TGauge ggBatteryButton; // Stele 161228 hebelek baterii @@ -335,9 +339,9 @@ public: // reszta może by?publiczna // TButton btLampkaUnknown; TButton btLampkaOpory; TButton btLampkaWysRozr; - TButton btLampkaUniversal3; - int LampkaUniversal3_typ; // ABu 030405 - swiecenie uzaleznione od: 0-nic, 1-obw.gl, 2-przetw. - bool LampkaUniversal3_st; + TButton btInstrumentLight; + int InstrumentLightType; // ABu 030405 - swiecenie uzaleznione od: 0-nic, 1-obw.gl, 2-przetw. + bool InstrumentLightActive; TButton btLampkaWentZaluzje; // ET22 TButton btLampkaOgrzewanieSkladu; TButton btLampkaSHP; diff --git a/World.cpp b/World.cpp index 7b8120d4..209104f6 100644 --- a/World.cpp +++ b/World.cpp @@ -30,6 +30,7 @@ http://mozilla.org/MPL/2.0/. #include "Console.h" #include "color.h" #include "uilayer.h" +#include "translation.h" //--------------------------------------------------------------------------- @@ -180,20 +181,6 @@ simulation_time::julian_day() const { return JD; } -namespace locale { - -std::string -control( std::string const &Label ) { - - auto const lookup = m_controls.find( Label ); - return ( - lookup != m_controls.end() ? - lookup->second : - "" ); -} - -} - TWorld::TWorld() { // randomize(); @@ -717,8 +704,8 @@ void TWorld::OnKeyDown(int cKey) Global::iTextMode = GLFW_KEY_F1; // to wyświetlić zegar i informację } } - else if( ( cKey == GLFW_KEY_PAUSE ) && ( Global::ctrlState ) ) { - //[Ctrl]+[Break] hamowanie wszystkich pojazdów w okolicy + else if( ( cKey == GLFW_KEY_PAUSE ) && ( Global::ctrlState ) && ( Global::shiftState ) ) { + //[Ctrl]+[Break] hamowanie wszystkich pojazdów w okolicy // added shift to prevent odd issue with glfw producing pause presses on its own if (Controlled->MoverParameters->Radio) Ground.RadioStop(Camera.Pos); } @@ -1288,7 +1275,7 @@ TWorld::Update_UI() { if( ( Train != nullptr ) && ( false == FreeFlyModeFlag ) ) { if( false == DebugModeFlag ) { // in regular mode show control functions, for defined controls - UILayer.set_tooltip( locale::control( Train->GetLabel( GfxRenderer.Pick_Control() ) ) ); + UILayer.set_tooltip( locale::label_cab_control( Train->GetLabel( GfxRenderer.Pick_Control() ) ) ); } else { // in debug mode show names of submodels, to help with cab setup and/or debugging diff --git a/World.h b/World.h index 67d8d2bb..a7a26fea 100644 --- a/World.h +++ b/World.h @@ -60,74 +60,6 @@ extern simulation_time Time; } -namespace locale { - -std::string - control( std::string const &Label ); - -static std::unordered_map m_controls = { - { "mainctrl:", "master controller" }, - { "scndctrl:", "second controller" }, - { "dirkey:" , "reverser" }, - { "brakectrl:", "train brake" }, - { "localbrake:", "independent brake" }, - { "manualbrake:", "manual brake" }, - { "brakeprofile_sw:", "brake acting speed" }, - { "brakeprofileg_sw:", "brake acting speed: cargo" }, - { "brakeprofiler_sw:", "brake acting speed: rapid" }, - { "maxcurrent_sw:", "motor overload relay threshold" }, - { "main_off_bt:", "line breaker" }, - { "main_on_bt:", "line breaker" }, - { "security_reset_bt:", "alerter" }, - { "releaser_bt:", "independent brake releaser" }, - { "sand_bt:", "sandbox" }, - { "antislip_bt:", "wheelspin brake" }, - { "horn_bt:", "horn" }, - { "hornlow_bt:", "low tone horn" }, - { "hornhigh_bt:", "high tone horn" }, - { "fuse_bt:", "motor overload relay reset" }, - { "converterfuse_bt:", "converter overload relay reset" }, - { "stlinoff_bt:", "motor connectors" }, - { "door_left_sw:", "left door" }, - { "door_right_sw:", "right door" }, - { "departure_signal_bt:", "departure signal" }, - { "upperlight_sw:", "upper headlight" }, - { "leftlight_sw:", "left headlight" }, - { "rightlight_sw:", "right headlight" }, - { "dimheadlights_sw:", "headlights dimmer" }, - { "leftend_sw:", "left marker light" }, - { "rightend_sw:", "right marker light" }, - { "lights_sw:", "light pattern" }, - { "rearupperlight_sw:", "rear upper headlight" }, - { "rearleftlight_sw:", "rear left headlight" }, - { "rearrightlight_sw:", "rear right headlight" }, - { "rearleftend_sw:", "rear left marker light" }, - { "rearrightend_sw:", "rear right marker light" }, - { "compressor_sw:", "compressor" }, - { "compressorlocal_sw:", "local compressor" }, - { "converter_sw:", "converter" }, - { "converterlocal_sw:", "local converter" }, - { "converteroff_sw:", "converter" }, - { "main_sw:", "line breaker" }, - { "radio_sw:", "radio" }, - { "pantfront_sw:", "front pantograph" }, - { "pantrear_sw:", "rear pantograph" }, - { "pantfrontoff_sw:", "front pantograph" }, - { "pantrearoff_sw:", "rear pantograph" }, - { "pantalloff_sw:", "all pantographs" }, - { "pantselected_sw:", "selected pantograph" }, - { "pantselectedoff_sw:", "selected pantograph" }, - { "trainheating_sw:", "heating" }, - { "signalling_sw:", "braking indicator" }, - { "door_signalling_sw:", "door locking" }, - { "nextcurrent_sw:", "current indicator source" }, - { "cablight_sw:", "interior light" }, - { "cablightdim_sw:", "interior light dimmer" }, - { "battery_sw:", "battery" } -}; - -} - // wrapper for environment elements -- sky, sun, stars, clouds etc class world_environment { diff --git a/command.cpp b/command.cpp index 426e1873..f297c6be 100644 --- a/command.cpp +++ b/command.cpp @@ -125,6 +125,16 @@ const int k_Univ4 = 69; const int k_EndSign = 70; const int k_Active = 71; */ + { "generictoggle0", command_target::vehicle }, + { "generictoggle1", command_target::vehicle }, + { "generictoggle2", command_target::vehicle }, + { "generictoggle3", command_target::vehicle }, + { "generictoggle4", command_target::vehicle }, + { "generictoggle5", command_target::vehicle }, + { "generictoggle6", command_target::vehicle }, + { "generictoggle7", command_target::vehicle }, + { "generictoggle8", command_target::vehicle }, + { "generictoggle9", command_target::vehicle }, { "batterytoggle", command_target::vehicle } /* const int k_WalkMode = 73; diff --git a/command.h b/command.h index 5d688827..239b145e 100644 --- a/command.h +++ b/command.h @@ -120,6 +120,16 @@ const int k_Univ4 = 69; const int k_EndSign = 70; const int k_Active = 71; */ + generictoggle0, + generictoggle1, + generictoggle2, + generictoggle3, + generictoggle4, + generictoggle5, + generictoggle6, + generictoggle7, + generictoggle8, + generictoggle9, batterytoggle, /* const int k_WalkMode = 73; @@ -149,8 +159,6 @@ struct command_description { command_target target; }; -typedef std::vector commanddescription_sequence; - struct command_data { user_command command; @@ -188,6 +196,8 @@ private: // but realistically it's not like we're going to run more than one simulation at a time namespace simulation { +typedef std::vector commanddescription_sequence; + extern command_queue Commands; // TODO: add name to command map, and wrap these two into helper object extern commanddescription_sequence Commands_descriptions; diff --git a/keyboardinput.cpp b/keyboardinput.cpp index 7a2969b6..959d3648 100644 --- a/keyboardinput.cpp +++ b/keyboardinput.cpp @@ -28,6 +28,8 @@ keyboard_input::recall_bindings() { ++commandid; } std::unordered_map nametokeymap = { + { "0", GLFW_KEY_0 }, { "1", GLFW_KEY_1 }, { "2", GLFW_KEY_2 }, { "3", GLFW_KEY_3 }, { "4", GLFW_KEY_4 }, + { "5", GLFW_KEY_5 }, { "6", GLFW_KEY_6 }, { "7", GLFW_KEY_7 }, { "8", GLFW_KEY_8 }, { "9", GLFW_KEY_9 }, { "a", GLFW_KEY_A }, { "b", GLFW_KEY_B }, { "c", GLFW_KEY_C }, { "d", GLFW_KEY_D }, { "e", GLFW_KEY_E }, { "f", GLFW_KEY_F }, { "g", GLFW_KEY_G }, { "h", GLFW_KEY_H }, { "i", GLFW_KEY_I }, { "j", GLFW_KEY_J }, { "k", GLFW_KEY_K }, { "l", GLFW_KEY_L }, { "m", GLFW_KEY_M }, { "n", GLFW_KEY_N }, { "o", GLFW_KEY_O }, @@ -348,6 +350,26 @@ const int k_Univ4 = 69; const int k_EndSign = 70; const int k_Active = 71; */ + // "generictoggle0" + { GLFW_KEY_0 }, + // "generictoggle1" + { GLFW_KEY_1 }, + // "generictoggle2" + { GLFW_KEY_2 }, + // "generictoggle3" + { GLFW_KEY_3 }, + // "generictoggle4" + { GLFW_KEY_4 }, + // "generictoggle5" + { GLFW_KEY_5 }, + // "generictoggle6" + { GLFW_KEY_6 }, + // "generictoggle7" + { GLFW_KEY_7 }, + // "generictoggle8" + { GLFW_KEY_8 }, + // "generictoggle9" + { GLFW_KEY_9 }, // "batterytoggle" { GLFW_KEY_J } /* diff --git a/maszyna.vcxproj.filters b/maszyna.vcxproj.filters index a12e1e90..67cb75d1 100644 --- a/maszyna.vcxproj.filters +++ b/maszyna.vcxproj.filters @@ -228,6 +228,9 @@ Source Files\input + + Source Files + @@ -446,6 +449,9 @@ Header Files\input + + Header Files + diff --git a/mouseinput.cpp b/mouseinput.cpp index 1b99fc27..c38b64f1 100644 --- a/mouseinput.cpp +++ b/mouseinput.cpp @@ -9,6 +9,7 @@ http://mozilla.org/MPL/2.0/. #include "stdafx.h" #include "mouseinput.h" +#include "usefull.h" #include "globals.h" #include "timer.h" #include "world.h" @@ -17,6 +18,17 @@ http://mozilla.org/MPL/2.0/. extern TWorld World; +bool +mouse_input::init() { + +#ifdef _WINDOWS + DWORD systemkeyboardspeed; + ::SystemParametersInfo( SPI_GETKEYBOARDSPEED, 0, &systemkeyboardspeed, 0 ); + m_updaterate = interpolate( 0.5, 0.04, systemkeyboardspeed / 31.0 ); +#endif + return true; +} + void mouse_input::move( double Mousex, double Mousey ) { @@ -76,11 +88,13 @@ mouse_input::button( int const Button, int const Action ) { mousecommand = user_command::none; } else { - // if it's the right mouse button that got released, stop view panning + // if it's the right mouse button that got released and we had no command active, we were potentially in view panning mode; stop it if( Button == GLFW_MOUSE_BUTTON_RIGHT ) { m_pickmodepanning = false; } } + // if we were in varying command repeat rate, we can stop that now. done without any conditions, to catch some unforeseen edge cases + m_varyingpollrate = false; } else { // if not release then it's press @@ -114,6 +128,25 @@ mouse_input::button( int const Button, int const Action ) { if( mousecommand == user_command::mastercontrollerincrease ) { m_updateaccumulator -= 0.15; // extra pause on first increase of master controller } + switch( mousecommand ) { + case user_command::mastercontrollerincrease: + case user_command::mastercontrollerdecrease: + case user_command::secondcontrollerincrease: + case user_command::secondcontrollerdecrease: + case user_command::trainbrakeincrease: + case user_command::trainbrakedecrease: + case user_command::independentbrakeincrease: + case user_command::independentbrakedecrease: { + // these commands trigger varying repeat rate mode, + // which scales the rate based on the distance of the cursor from its point when the command was first issued + m_commandstartcursor = m_cursorposition; + m_varyingpollrate = true; + break; + } + default: { + break; + } + } } } else { @@ -131,11 +164,16 @@ mouse_input::poll() { m_updateaccumulator += Timer::GetDeltaRenderTime(); - if( m_updateaccumulator < 0.1 ) { + auto updaterate { m_updaterate }; + if( m_varyingpollrate ) { + updaterate /= std::max( 0.15, 2.0 * glm::length( m_cursorposition - m_commandstartcursor ) / std::max( 1, Global::ScreenHeight ) ); + } + + if( m_updateaccumulator < updaterate ) { // too early for any work return; } - m_updateaccumulator -= 0.1; + m_updateaccumulator -= updaterate; if( m_mousecommandleft != user_command::none ) { // NOTE: basic keyboard controls don't have any parameters @@ -320,6 +358,9 @@ mouse_input::default_bindings() { { "nextcurrent_sw:", { user_command::mucurrentindicatorothersourceactivate, user_command::none } }, + { "instrumentlight_sw:", { + user_command::instrumentlighttoggle, + user_command::none } }, { "cablight_sw:", { user_command::interiorlighttoggle, user_command::none } }, @@ -328,6 +369,36 @@ mouse_input::default_bindings() { user_command::none } }, { "battery_sw:", { user_command::batterytoggle, + user_command::none } }, + { "universal0:", { + user_command::generictoggle0, + user_command::none } }, + { "universal1:", { + user_command::generictoggle1, + user_command::none } }, + { "universal2:", { + user_command::generictoggle2, + user_command::none } }, + { "universal3:", { + user_command::generictoggle3, + user_command::none } }, + { "universal4:", { + user_command::generictoggle4, + user_command::none } }, + { "universal5:", { + user_command::generictoggle5, + user_command::none } }, + { "universal6:", { + user_command::generictoggle6, + user_command::none } }, + { "universal7:", { + user_command::generictoggle7, + user_command::none } }, + { "universal8:", { + user_command::generictoggle8, + user_command::none } }, + { "universal9:", { + user_command::generictoggle9, user_command::none } } }; } diff --git a/mouseinput.h b/mouseinput.h index 95a1f194..346ab4e9 100644 --- a/mouseinput.h +++ b/mouseinput.h @@ -10,7 +10,6 @@ http://mozilla.org/MPL/2.0/. #pragma once #include -#include #include "command.h" class mouse_input { @@ -21,7 +20,7 @@ public: // methods bool - init() { return true; } + init(); void move( double const Mousex, double const Mousey ); void @@ -48,13 +47,16 @@ private: default_bindings(); // members + command_relay m_relay; controlcommands_map m_mousecommands; user_command m_mousecommandleft { user_command::none }; // last if any command issued with left mouse button user_command m_mousecommandright { user_command::none }; // last if any command issued with right mouse button - command_relay m_relay; + double m_updaterate { 0.075 }; double m_updateaccumulator { 0.0 }; bool m_pickmodepanning { false }; // indicates mouse is in view panning mode - glm::dvec2 m_cursorposition; // stored last mouse position, used for panning + glm::dvec2 m_cursorposition; // stored last cursor position, used for panning + glm::dvec2 m_commandstartcursor; // helper, cursor position when the command was initiated + bool m_varyingpollrate { false }; // indicates rate of command repeats is affected by the cursor position }; //--------------------------------------------------------------------------- diff --git a/stdafx.h b/stdafx.h index 20302ae8..cca09510 100644 --- a/stdafx.h +++ b/stdafx.h @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include diff --git a/translation.cpp b/translation.cpp new file mode 100644 index 00000000..efa9efaf --- /dev/null +++ b/translation.cpp @@ -0,0 +1,31 @@ +/* +This Source Code Form is subject to the +terms of the Mozilla Public License, v. +2.0. If a copy of the MPL was not +distributed with this file, You can +obtain one at +http://mozilla.org/MPL/2.0/. +*/ +/* + MaSzyna EU07 locomotive simulator + Copyright (C) 2001-2004 Marcin Wozniak, Maciej Czapkiewicz and others +*/ + +#include "stdafx.h" +#include "translation.h" + +namespace locale { + +std::string +label_cab_control( std::string const &Label ) { + + auto const lookup = m_cabcontrols.find( Label ); + return ( + lookup != m_cabcontrols.end() ? + lookup->second : + "" ); +} + +} // namespace locale + +//--------------------------------------------------------------------------- diff --git a/translation.h b/translation.h new file mode 100644 index 00000000..8ce582e0 --- /dev/null +++ b/translation.h @@ -0,0 +1,95 @@ +/* +This Source Code Form is subject to the +terms of the Mozilla Public License, v. +2.0. If a copy of the MPL was not +distributed with this file, You can +obtain one at +http://mozilla.org/MPL/2.0/. +*/ + +#pragma once + +#include +#include + +namespace locale { + +std::string + label_cab_control( std::string const &Label ); + +static std::unordered_map m_cabcontrols = { + { "mainctrl:", "master controller" }, + { "scndctrl:", "second controller" }, + { "dirkey:" , "reverser" }, + { "brakectrl:", "train brake" }, + { "localbrake:", "independent brake" }, + { "manualbrake:", "manual brake" }, + { "brakeprofile_sw:", "brake acting speed" }, + { "brakeprofileg_sw:", "brake acting speed: cargo" }, + { "brakeprofiler_sw:", "brake acting speed: rapid" }, + { "maxcurrent_sw:", "motor overload relay threshold" }, + { "main_off_bt:", "line breaker" }, + { "main_on_bt:", "line breaker" }, + { "security_reset_bt:", "alerter" }, + { "releaser_bt:", "independent brake releaser" }, + { "sand_bt:", "sandbox" }, + { "antislip_bt:", "wheelspin brake" }, + { "horn_bt:", "horn" }, + { "hornlow_bt:", "low tone horn" }, + { "hornhigh_bt:", "high tone horn" }, + { "fuse_bt:", "motor overload relay reset" }, + { "converterfuse_bt:", "converter overload relay reset" }, + { "stlinoff_bt:", "motor connectors" }, + { "door_left_sw:", "left door" }, + { "door_right_sw:", "right door" }, + { "departure_signal_bt:", "departure signal" }, + { "upperlight_sw:", "upper headlight" }, + { "leftlight_sw:", "left headlight" }, + { "rightlight_sw:", "right headlight" }, + { "dimheadlights_sw:", "headlights dimmer" }, + { "leftend_sw:", "left marker light" }, + { "rightend_sw:", "right marker light" }, + { "lights_sw:", "light pattern" }, + { "rearupperlight_sw:", "rear upper headlight" }, + { "rearleftlight_sw:", "rear left headlight" }, + { "rearrightlight_sw:", "rear right headlight" }, + { "rearleftend_sw:", "rear left marker light" }, + { "rearrightend_sw:", "rear right marker light" }, + { "compressor_sw:", "compressor" }, + { "compressorlocal_sw:", "local compressor" }, + { "converter_sw:", "converter" }, + { "converterlocal_sw:", "local converter" }, + { "converteroff_sw:", "converter" }, + { "main_sw:", "line breaker" }, + { "radio_sw:", "radio" }, + { "pantfront_sw:", "front pantograph" }, + { "pantrear_sw:", "rear pantograph" }, + { "pantfrontoff_sw:", "front pantograph" }, + { "pantrearoff_sw:", "rear pantograph" }, + { "pantalloff_sw:", "all pantographs" }, + { "pantselected_sw:", "selected pantograph" }, + { "pantselectedoff_sw:", "selected pantograph" }, + { "trainheating_sw:", "heating" }, + { "signalling_sw:", "braking indicator" }, + { "door_signalling_sw:", "door locking" }, + { "nextcurrent_sw:", "current indicator source" }, + { "instrumentlight_sw:", "instrument light" }, + { "cablight_sw:", "interior light" }, + { "cablightdim_sw:", "interior light dimmer" }, + { "battery_sw:", "battery" }, + { "universal0:", "generic" }, + { "universal1:", "generic" }, + { "universal2:", "generic" }, + { "universal3:", "generic" }, + { "universal4:", "generic" }, + { "universal5:", "generic" }, + { "universal6:", "generic" }, + { "universal7:", "generic" }, + { "universal8:", "generic" }, + { "universal9:", "generic" } +}; + +} + +//--------------------------------------------------------------------------- + diff --git a/version.h b/version.h index 4b87d6ad..2fe8cfad 100644 --- a/version.h +++ b/version.h @@ -1,5 +1,5 @@ #pragma once #define VERSION_MAJOR 17 -#define VERSION_MINOR 710 +#define VERSION_MINOR 712 #define VERSION_REVISION 0 From 4f9000ebe2821ffc92e3aed23f5fbe5bbcf52854 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Thu, 13 Jul 2017 19:24:34 +0200 Subject: [PATCH 4/6] automatic alerter (de)activation on cab and vehicle change, minor diagnostics enhancements --- McZapkie/Mover.cpp | 3 ++ World.cpp | 108 ++++++++++++++++++++------------------------- 2 files changed, 51 insertions(+), 60 deletions(-) diff --git a/McZapkie/Mover.cpp b/McZapkie/Mover.cpp index 246575be..9c861dbc 100644 --- a/McZapkie/Mover.cpp +++ b/McZapkie/Mover.cpp @@ -2023,6 +2023,7 @@ bool TMoverParameters::CabActivisation(void) { CabNo = ActiveCab; // sterowanie jest z kabiny z obsadą DirAbsolute = ActiveDir * CabNo; + SecuritySystem.Status |= s_waiting; // activate the alerter TODO: make it part of control based cab selection SendCtrlToNext("CabActivisation", 1, CabNo); } return OK; @@ -2042,6 +2043,8 @@ bool TMoverParameters::CabDeactivisation(void) CabNo = 0; DirAbsolute = ActiveDir * CabNo; DepartureSignal = false; // nie buczeć z nieaktywnej kabiny + SecuritySystem.Status = 0; // deactivate alerter TODO: make it part of control based cab selection + SendCtrlToNext("CabActivisation", 0, ActiveCab); // CabNo==0! } return OK; diff --git a/World.cpp b/World.cpp index 209104f6..198f4ed6 100644 --- a/World.cpp +++ b/World.cpp @@ -1427,9 +1427,10 @@ TWorld::Update_UI() { // for cars other than leading unit indicate the leader uitextline1 += ", owned by " + tmp->ctOwner->OwnerName(); } + uitextline1 += "; Status: " + tmp->MoverParameters->EngineDescription( 0 ); // informacja o sprzęgach uitextline1 += - " C0:" + + "; C0:" + ( tmp->PrevConnected ? tmp->PrevConnected->GetName() + ":" + to_string( tmp->MoverParameters->Couplers[ 0 ].CouplingFlag ) : "none" ); @@ -1439,9 +1440,23 @@ TWorld::Update_UI() { tmp->NextConnected->GetName() + ":" + to_string( tmp->MoverParameters->Couplers[ 1 ].CouplingFlag ) : "none" ); - uitextline2 = "Damage status: " + tmp->MoverParameters->EngineDescription( 0 ); - - uitextline2 += "; Brake delay: "; + // equipment flags + uitextline2 = ( tmp->MoverParameters->Battery ? "B" : "." ); + uitextline2 += ( tmp->MoverParameters->Mains ? "M" : "." ); + uitextline2 += ( tmp->MoverParameters->PantRearUp ? ( tmp->MoverParameters->PantRearVolt > 0.0 ? "O" : "o" ) : "." );; + uitextline2 += ( tmp->MoverParameters->PantFrontUp ? ( tmp->MoverParameters->PantFrontVolt > 0.0 ? "P" : "p" ) : "." );; + uitextline2 += ( tmp->MoverParameters->PantPressLockActive ? "!" : ( tmp->MoverParameters->PantPressSwitchActive ? "*" : "." ) ); + uitextline2 += ( false == tmp->MoverParameters->ConverterAllowLocal ? "-" : ( tmp->MoverParameters->ConverterAllow ? ( tmp->MoverParameters->ConverterFlag ? "X" : "x" ) : "." ) ); + uitextline2 += ( tmp->MoverParameters->ConvOvldFlag ? "!" : "." ); + uitextline2 += ( false == tmp->MoverParameters->CompressorAllowLocal ? "-" : ( tmp->MoverParameters->CompressorAllow ? ( tmp->MoverParameters->CompressorFlag ? "C" : "c" ) : "." ) ); + uitextline2 += ( tmp->MoverParameters->CompressorGovernorLock ? "!" : "." ); +/* + uitextline2 += + " AnlgB: " + to_string( tmp->MoverParameters->AnPos, 1 ) + + "+" + + to_string( tmp->MoverParameters->LocalBrakePosA, 1 ) +*/ + uitextline2 += " Bdelay: "; if( ( tmp->MoverParameters->BrakeDelayFlag & bdelay_G ) == bdelay_G ) uitextline2 += "G"; if( ( tmp->MoverParameters->BrakeDelayFlag & bdelay_P ) == bdelay_P ) @@ -1451,39 +1466,22 @@ TWorld::Update_UI() { if( ( tmp->MoverParameters->BrakeDelayFlag & bdelay_M ) == bdelay_M ) uitextline2 += "+Mg"; - uitextline2 += ", BTP: " + to_string( tmp->MoverParameters->LoadFlag, 0 ); - { - uitextline2 += - "; pant: " - + to_string( tmp->MoverParameters->PantPress, 2 ) - + ( tmp->MoverParameters->bPantKurek3 ? "-ZG" : "|ZG" ); - } + uitextline2 += ", Load: " + to_string( tmp->MoverParameters->LoadFlag, 0 ); uitextline2 += - ", MED:" - + to_string( tmp->MoverParameters->LocalBrakePosA, 2 ) - + "+" - + to_string( tmp->MoverParameters->AnPos, 2 ); + "; Pant: " + + to_string( tmp->MoverParameters->PantPress, 2 ) + + ( tmp->MoverParameters->bPantKurek3 ? "-ZG" : "|ZG" ); uitextline2 += - ", Ft:" - + to_string( tmp->MoverParameters->Ft * 0.001f, 0 ); + "; Ft: " + to_string( tmp->MoverParameters->Ft * 0.001f * tmp->MoverParameters->ActiveCab, 1 ) + + ", Fb: " + to_string( tmp->MoverParameters->Fb * 0.001f, 1 ) + + ", Fr: " + to_string( tmp->MoverParameters->RunningTrack.friction, 2 ) + + ( tmp->MoverParameters->SlippingWheels ? " (!)" : "" ); uitextline2 += "; TC:" + to_string( tmp->MoverParameters->TotalCurrent, 0 ); -#ifdef EU07_USE_OLD_HVCOUPLERS - uitextline2 += - ", HV0: " - + to_string( tmp->MoverParameters->HVCouplers[ TMoverParameters::side::front ][ TMoverParameters::hvcoupler::voltage ], 0 ) - + "@" - + to_string( tmp->MoverParameters->HVCouplers[ TMoverParameters::side::front ][ TMoverParameters::hvcoupler::current ], 0 ); - uitextline2 += - ", HV1: " - + to_string( tmp->MoverParameters->HVCouplers[ TMoverParameters::side::rear ][ TMoverParameters::hvcoupler::voltage ], 0 ) - + "@" - + to_string( tmp->MoverParameters->HVCouplers[ TMoverParameters::side::rear ][ TMoverParameters::hvcoupler::current ], 0 ); -#else auto const frontcouplerhighvoltage = to_string( tmp->MoverParameters->Couplers[ TMoverParameters::side::front ].power_high.voltage, 0 ) + "@" @@ -1493,36 +1491,26 @@ TWorld::Update_UI() { + "@" + to_string( tmp->MoverParameters->Couplers[ TMoverParameters::side::rear ].power_high.current, 0 ); uitextline2 += ", HV: "; - if( tmp->MoverParameters->Couplers[ TMoverParameters::side::front ].power_high.local == false ) { - uitextline2 += - "(" + frontcouplerhighvoltage + ")-" - + ":F" + ( tmp->DirectionGet() ? "<<" : ">>" ) + "R:" - + "-(" + rearcouplerhighvoltage + ")"; - } - else { - uitextline2 += - frontcouplerhighvoltage - + ":F" + ( tmp->DirectionGet() ? "<<" : ">>" ) + "R:" - + rearcouplerhighvoltage; - } -#endif - // equipment flags - uitextline3 = ""; - uitextline3 += ( tmp->MoverParameters->Battery ? "B" : "." ); - uitextline3 += ( tmp->MoverParameters->Mains ? "M" : "." ); - uitextline3 += ( tmp->MoverParameters->PantRearUp ? ( tmp->MoverParameters->PantRearVolt > 0.0 ? "O" : "o" ) : "." );; - uitextline3 += ( tmp->MoverParameters->PantFrontUp ? ( tmp->MoverParameters->PantFrontVolt > 0.0 ? "P" : "p" ) : "." );; - uitextline3 += ( tmp->MoverParameters->PantPressLockActive ? "!" : ( tmp->MoverParameters->PantPressSwitchActive ? "*" : "." ) ); - uitextline3 += ( false == tmp->MoverParameters->ConverterAllowLocal ? "-" : ( tmp->MoverParameters->ConverterAllow ? ( tmp->MoverParameters->ConverterFlag ? "X" : "x" ) : "." ) ); - uitextline3 += ( tmp->MoverParameters->ConvOvldFlag ? "!" : "." ); - uitextline3 += ( false == tmp->MoverParameters->CompressorAllowLocal ? "-" : ( tmp->MoverParameters->CompressorAllow ? ( tmp->MoverParameters->CompressorFlag ? "C" : "c" ) : "." ) ); - uitextline3 += ( tmp->MoverParameters->CompressorGovernorLock ? "!" : "." ); + if( tmp->MoverParameters->Couplers[ TMoverParameters::side::front ].power_high.local == false ) { + uitextline2 += + "(" + frontcouplerhighvoltage + ")-" + + ":F" + ( tmp->DirectionGet() ? "<<" : ">>" ) + "R:" + + "-(" + rearcouplerhighvoltage + ")"; + } + else { + uitextline2 += + frontcouplerhighvoltage + + ":F" + ( tmp->DirectionGet() ? "<<" : ">>" ) + "R:" + + rearcouplerhighvoltage; + } uitextline3 += - " TrB: " + to_string( tmp->MoverParameters->BrakePress, 2 ) - + ", " + to_hex_str( tmp->MoverParameters->Hamulec->GetBrakeStatus(), 2 ) - + ", LcB: " + to_string( tmp->MoverParameters->LocBrakePress, 2 ) - + ", pipes: " + to_string( tmp->MoverParameters->PipePress, 2 ) + "TrB: " + to_string( tmp->MoverParameters->BrakePress, 2 ) + + ", " + to_hex_str( tmp->MoverParameters->Hamulec->GetBrakeStatus(), 2 ); + + uitextline3 += + "; LcB: " + to_string( tmp->MoverParameters->LocBrakePress, 2 ) + + "; pipes: " + to_string( tmp->MoverParameters->PipePress, 2 ) + "/" + to_string( tmp->MoverParameters->ScndPipePress, 2 ) + "/" + to_string( tmp->MoverParameters->EqvtPipePress, 2 ) + ", MT: " + to_string( tmp->MoverParameters->CompressedVolume, 3 ) @@ -1532,9 +1520,9 @@ TWorld::Update_UI() { if( tmp->MoverParameters->ManualBrakePos > 0 ) { - uitextline3 += ", manual brake on"; + uitextline3 += "; manual brake on"; } - +/* if( tmp->MoverParameters->LocalBrakePos > 0 ) { uitextline3 += ", local brake on"; @@ -1543,7 +1531,7 @@ TWorld::Update_UI() { uitextline3 += ", local brake off"; } - +*/ if( tmp->Mechanik ) { // o ile jest ktoś w środku std::string flags = "bwaccmlshhhoibsgvdp; "; // flagi AI (definicja w Driver.h) From 3a67219e306ca206a3f1e7358210ee9d6b2dd424 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Sat, 15 Jul 2017 19:27:49 +0200 Subject: [PATCH 5/6] custom sounds for cab controls configurable on per-item basis --- DynObj.cpp | 2 +- FadeSound.h | 4 +- Gauge.cpp | 190 ++++++++++++------ Gauge.h | 47 +++-- McZapkie/MOVER.h | 51 +---- McZapkie/Mover.cpp | 67 +++---- McZapkie/mctools.cpp | 182 ++--------------- McZapkie/mctools.h | 121 +++++------- Model3d.cpp | 4 +- Train.cpp | 460 ++++++++++++++++++++++++++++++++++--------- Train.h | 46 ++--- TrkFoll.cpp | 8 +- parser.h | 39 ++-- uilayer.cpp | 34 ++-- version.h | 2 +- 15 files changed, 687 insertions(+), 570 deletions(-) diff --git a/DynObj.cpp b/DynObj.cpp index a47db564..05b2ac47 100644 --- a/DynObj.cpp +++ b/DynObj.cpp @@ -1717,7 +1717,7 @@ TDynamicObject::Init(std::string Name, // nazwa pojazdu, np. "EU07-424" if (ConversionError == -8) ErrorLog("Missed file: " + BaseDir + "\\" + Type_Name + ".fiz"); Error("Cannot load dynamic object " + asName + " from:\r\n" + BaseDir + "\\" + Type_Name + - ".fiz\r\nError " + to_string(ConversionError) + " in line " + to_string(LineCount)); + ".fiz\r\nError " + to_string(ConversionError)); return 0.0; // zerowa długość to brak pojazdu } bool driveractive = (fVel != 0.0); // jeśli prędkość niezerowa, to aktywujemy ruch diff --git a/FadeSound.h b/FadeSound.h index 6ce4e1b0..97c45eb0 100644 --- a/FadeSound.h +++ b/FadeSound.h @@ -21,8 +21,8 @@ class TFadeSound fTime = 0.0f; TSoundState State = ss_Off; - public: - TFadeSound(); +public: + TFadeSound() = default; ~TFadeSound(); void Init(std::string const &Name, float fNewFade); void TurnOn(); diff --git a/Gauge.cpp b/Gauge.cpp index 3883a231..e6e6f0ec 100644 --- a/Gauge.cpp +++ b/Gauge.cpp @@ -20,31 +20,7 @@ http://mozilla.org/MPL/2.0/. #include "Timer.h" #include "logs.h" -TGauge::TGauge() -{ - eType = gt_Unknown; - fFriction = 0.0; - fDesiredValue = 0.0; - fValue = 0.0; - fOffset = 0.0; - fScale = 1.0; - fStepSize = 5; - // iChannel=-1; //kanał analogowej komunikacji zwrotnej - SubModel = NULL; -}; - -TGauge::~TGauge(){}; - -void TGauge::Clear() -{ - SubModel = NULL; - eType = gt_Unknown; - fValue = 0; - fDesiredValue = 0; -}; - -void TGauge::Init(TSubModel *NewSubModel, TGaugeType eNewType, double fNewScale, double fNewOffset, - double fNewFriction, double fNewValue) +void TGauge::Init(TSubModel *NewSubModel, TGaugeType eNewType, double fNewScale, double fNewOffset, double fNewFriction, double fNewValue) { // ustawienie parametrów animacji submodelu if (NewSubModel) { // warunek na wszelki wypadek, gdyby się submodel nie @@ -75,41 +51,107 @@ void TGauge::Init(TSubModel *NewSubModel, TGaugeType eNewType, double fNewScale, } }; -bool TGauge::Load(cParser &Parser, TModel3d *md1, TModel3d *md2, double mul) -{ - std::string str1 = Parser.getToken(false); - std::string str2 = Parser.getToken(); - Parser.getTokens( 3, false ); - double val3, val4, val5; - Parser - >> val3 - >> val4 - >> val5; - val3 *= mul; - TSubModel *sm = md1->GetFromName( str1.c_str() ); - if( val3 == 0.0 ) { - ErrorLog( "Scale of 0.0 defined for sub-model \"" + str1 + "\" in 3d model \"" + md1->NameGet() + "\". Forcing scale of 1.0 to prevent division by 0" ); - val3 = 1.0; +bool TGauge::Load(cParser &Parser, TModel3d *md1, TModel3d *md2, double mul) { + + std::string submodelname, gaugetypename; + double scale, offset, friction; + + Parser.getTokens(); + if( Parser.peek() != "{" ) { + // old fixed size config + Parser >> submodelname; + gaugetypename = Parser.getToken( true ); + Parser.getTokens( 3, false ); + Parser + >> scale + >> offset + >> friction; } - if (sm) // jeśli nie znaleziony - md2 = NULL; // informacja, że znaleziony - else if (md2) // a jest podany drugi model (np. zewnętrzny) - sm = md2->GetFromName(str1.c_str()); // to może tam będzie, co za różnica gdzie - if( sm == nullptr ) { - ErrorLog( "Failed to locate sub-model \"" + str1 + "\" in 3d model \"" + md1->NameGet() + "\"" ); + else { + // new, block type config + // TODO: rework the base part into yaml-compatible flow style mapping + cParser mappingparser( Parser.getToken( false, "}" ) ); + submodelname = mappingparser.getToken( false ); + gaugetypename = mappingparser.getToken( true ); + mappingparser.getTokens( 3, false ); + mappingparser + >> scale + >> offset + >> friction; + // new, variable length section + while( true == Load_mapping( mappingparser ) ) { + ; // all work done by while() + } } - if (str2 == "mov") - Init(sm, gt_Move, val3, val4, val5); - else if (str2 == "wip") - Init(sm, gt_Wiper, val3, val4, val5); - else if (str2 == "dgt") - Init(sm, gt_Digital, val3, val4, val5); - else - Init(sm, gt_Rotate, val3, val4, val5); + scale *= mul; + TSubModel *submodel = md1->GetFromName( submodelname.c_str() ); + if( scale == 0.0 ) { + ErrorLog( "Scale of 0.0 defined for sub-model \"" + submodelname + "\" in 3d model \"" + md1->NameGet() + "\". Forcing scale of 1.0 to prevent division by 0" ); + scale = 1.0; + } + if (submodel) // jeśli nie znaleziony + md2 = nullptr; // informacja, że znaleziony + else if (md2) // a jest podany drugi model (np. zewnętrzny) + submodel = md2->GetFromName(submodelname.c_str()); // to może tam będzie, co za różnica gdzie + if( submodel == nullptr ) { + ErrorLog( "Failed to locate sub-model \"" + submodelname + "\" in 3d model \"" + md1->NameGet() + "\"" ); + } + + std::map gaugetypes { + { "mov", gt_Move }, + { "wip", gt_Wiper }, + { "dgt", gt_Digital } + }; + auto lookup = gaugetypes.find( gaugetypename ); + auto const type = ( + lookup != gaugetypes.end() ? + lookup->second : + gt_Rotate ); + Init(submodel, type, scale, offset, friction); + return md2 != nullptr; // true, gdy podany model zewnętrzny, a w kabinie nie było }; +bool +TGauge::Load_mapping( cParser &Input ) { + + if( false == Input.getTokens( 2, true, ", " ) ) { + return false; + } + + std::string key, value; + Input + >> key + >> value; + + if( key == "soundinc:" ) { + m_soundfxincrease = ( + value != "none" ? + TSoundsManager::GetFromName( value, true ) : + nullptr ); + } + else if( key == "sounddec:" ) { + m_soundfxdecrease = ( + value != "none" ? + TSoundsManager::GetFromName( value, true ) : + nullptr ); + } + else if( key.find( "sound" ) == 0 ) { + // sounds assigned to specific gauge values, defined by key soundFoo: where Foo = value + auto const indexstart = key.find_first_of( "1234567890" ); + auto const indexend = key.find_first_not_of( "1234567890", indexstart ); + if( indexstart != std::string::npos ) { + m_soundfxvalues.emplace( + std::stoi( key.substr( indexstart, indexend - indexstart ) ), + ( value != "none" ? + TSoundsManager::GetFromName( value, true ) : + nullptr ) ); + } + } + return true; // return value marks a key: value pair was extracted, nothing about whether it's recognized +} + void TGauge::PermIncValue(double fNewDesired) { fDesiredValue = fDesiredValue + fNewDesired * fScale + fOffset; @@ -134,9 +176,34 @@ void TGauge::DecValue(double fNewDesired) fDesiredValue = 0; }; -void TGauge::UpdateValue(double fNewDesired) -{ // ustawienie wartości docelowej +// ustawienie wartości docelowej. plays provided fallback sound, if no sound was defined in the control itself +void +TGauge::UpdateValue( double fNewDesired, PSound Fallbacksound ) { + + if( static_cast( std::round( ( fDesiredValue - fOffset ) / fScale ) ) == static_cast( fNewDesired ) ) { + return; + } fDesiredValue = fNewDesired * fScale + fOffset; + // if there's any sound associated with new requested value, play it + // check value-specific table first... + auto const desiredvalue = static_cast( std::round( fNewDesired ) ); + auto const lookup = m_soundfxvalues.find( desiredvalue ); + if( lookup != m_soundfxvalues.end() ) { + play( lookup->second ); + return; + } + // ...and if there isn't any, fall back on the basic set... + auto const currentvalue = GetValue(); + if( ( currentvalue < fNewDesired ) && ( m_soundfxincrease != nullptr ) ) { + play( m_soundfxincrease ); + } + else if( ( currentvalue > fNewDesired ) && ( m_soundfxdecrease != nullptr ) ) { + play( m_soundfxdecrease ); + } + else { + // ...and if that fails too, try the provided fallback sound from legacy system + play( Fallbacksound ); + } }; void TGauge::PutValue(double fNewDesired) @@ -245,4 +312,15 @@ void TGauge::UpdateValue() } }; +void +TGauge::play( PSound Sound ) { + + if( Sound == nullptr ) { return; } + + Sound->SetCurrentPosition( 0 ); + Sound->SetVolume( DSBVOLUME_MAX ); + Sound->Play( 0, 0, 0 ); + return; +} + //--------------------------------------------------------------------------- diff --git a/Gauge.h b/Gauge.h index e2236a8d..0147a61e 100644 --- a/Gauge.h +++ b/Gauge.h @@ -10,6 +10,7 @@ http://mozilla.org/MPL/2.0/. #pragma once #include "Classes.h" +#include "sound.h" typedef enum { // typ ruchu @@ -21,35 +22,43 @@ typedef enum gt_Digital // licznik cyfrowy, np. kilometrów } TGaugeType; -class TGauge // zmienne "gg" -{ // animowany wskaźnik, mogący przyjmować wiele stanów pośrednich +// animowany wskaźnik, mogący przyjmować wiele stanów pośrednich +class TGauge { + private: - TGaugeType eType; // typ ruchu - double fFriction{ 0.0 }; // hamowanie przy zliżaniu się do zadanej wartości - double fDesiredValue{ 0.0 }; // wartość docelowa - double fValue{ 0.0 }; // wartość obecna - double fOffset{ 0.0 }; // wartość początkowa ("0") - double fScale{ 1.0 }; // wartość końcowa ("1") - double fStepSize; // nie używane + TGaugeType eType { gt_Unknown }; // typ ruchu + double fFriction { 0.0 }; // hamowanie przy zliżaniu się do zadanej wartości + double fDesiredValue { 0.0 }; // wartość docelowa + double fValue { 0.0 }; // wartość obecna + double fOffset { 0.0 }; // wartość początkowa ("0") + double fScale { 1.0 }; // wartość końcowa ("1") char cDataType; // typ zmiennej parametru: f-float, d-double, i-int - union - { // wskaźnik na parametr pokazywany przez animację + union { + // wskaźnik na parametr pokazywany przez animację float *fData; - double *dData; + double *dData { nullptr }; int *iData; }; + PSound m_soundfxincrease { nullptr }; // sound associated with increasing control's value + PSound m_soundfxdecrease { nullptr }; // sound associated with decreasing control's value + std::map m_soundfxvalues; // sounds associated with specific values +// methods + // plays specified sound + void + play( PSound Sound ); public: - TGauge(); - ~TGauge(); - void Clear(); - void Init(TSubModel *NewSubModel, TGaugeType eNewTyp, double fNewScale = 1, - double fNewOffset = 0, double fNewFriction = 0, double fNewValue = 0); - bool Load(cParser &Parser, TModel3d *md1, TModel3d *md2 = NULL, double mul = 1.0); + TGauge() = default; + ~TGauge() {} + inline + void Clear() { *this = TGauge(); } + void Init(TSubModel *NewSubModel, TGaugeType eNewTyp, double fNewScale = 1, double fNewOffset = 0, double fNewFriction = 0, double fNewValue = 0); + bool Load(cParser &Parser, TModel3d *md1, TModel3d *md2 = nullptr, double mul = 1.0); + bool Load_mapping( cParser &Input ); void PermIncValue(double fNewDesired); void IncValue(double fNewDesired); void DecValue(double fNewDesired); - void UpdateValue(double fNewDesired); + void UpdateValue(double fNewDesired, PSound Fallbacksound = nullptr ); void PutValue(double fNewDesired); double GetValue() const; void Update(); diff --git a/McZapkie/MOVER.h b/McZapkie/MOVER.h index 26c3ad7b..a21608ba 100644 --- a/McZapkie/MOVER.h +++ b/McZapkie/MOVER.h @@ -78,7 +78,8 @@ zwiekszenie nacisku przy duzych predkosciach w hamulcach Oerlikona */ #include "dumb3d.h" -using namespace Math3D; + +extern int ConversionError; const double Steel2Steel_friction = 0.15; //tarcie statyczne const double g = 9.81; //przyspieszenie ziemskie @@ -996,8 +997,8 @@ public: double FrictConst2d= 0.0; double TotalMassxg = 0.0; /*TotalMass*g*/ - vector3 vCoulpler[2]; // powtórzenie współrzędnych sprzęgów z DynObj :/ - vector3 DimHalf; // połowy rozmiarów do obliczeń geometrycznych + Math3D::vector3 vCoulpler[2]; // powtórzenie współrzędnych sprzęgów z DynObj :/ + Math3D::vector3 DimHalf; // połowy rozmiarów do obliczeń geometrycznych // int WarningSignal; //0: nie trabi, 1,2: trabi syreną o podanym numerze int WarningSignal = 0; // tymczasowo 8bit, ze względu na funkcje w MTools double fBrakeCtrlPos = -2.0; // płynna nastawa hamulca zespolonego @@ -1210,47 +1211,3 @@ private: }; extern double Distance(TLocation Loc1, TLocation Loc2, TDimension Dim1, TDimension Dim2); - -inline -std::string -extract_value( std::string const &Key, std::string const &Input ) { - - std::string value; - auto lookup = Input.find( Key + "=" ); - if( lookup != std::string::npos ) { - value = Input.substr( Input.find_first_not_of( ' ', lookup + Key.size() + 1 ) ); - lookup = value.find( ' ' ); - if( lookup != std::string::npos ) { - // trim everything past the value - value.erase( lookup ); - } - } - return value; -} - -template -bool -extract_value( Type_ &Variable, std::string const &Key, std::string const &Input, std::string const &Default ) { - - auto value = extract_value( Key, Input ); - if( false == value.empty() ) { - // set the specified variable to retrieved value - std::stringstream converter; - converter << value; - converter >> Variable; - return true; // located the variable - } - else { - // set the variable to provided default value - if( false == Default.empty() ) { - std::stringstream converter; - converter << Default; - converter >> Variable; - } - return false; // couldn't locate the variable in provided input - } -} - -template <> -bool -extract_value( bool &Variable, std::string const &Key, std::string const &Input, std::string const &Default ); diff --git a/McZapkie/Mover.cpp b/McZapkie/Mover.cpp index 9c861dbc..b32c1e07 100644 --- a/McZapkie/Mover.cpp +++ b/McZapkie/Mover.cpp @@ -13,6 +13,7 @@ http://mozilla.org/MPL/2.0/. #include "../logs.h" #include "Oerlikon_ESt.h" #include "../parser.h" +#include "mctools.h" //--------------------------------------------------------------------------- // Ra: tu należy przenosić funcje z mover.pas, które nie są z niego wywoływane. @@ -22,6 +23,8 @@ http://mozilla.org/MPL/2.0/. const double dEpsilon = 0.01; // 1cm (zależy od typu sprzęgu...) const double CouplerTune = 0.1; // skalowanie tlumiennosci +int ConversionError = 0; + std::vector const TMoverParameters::eimc_labels = { "dfic: ", "dfmax:", "p: ", "scfu: ", "cim: ", "icif: ", "Uzmax:", "Uzh: ", "DU: ", "I0: ", "fcfu: ", "F0: ", "a1: ", "Pmax: ", "Fh: ", "Ph: ", "Vh0: ", "Vh1: ", "Imax: ", "abed: ", @@ -5097,14 +5100,17 @@ bool TMoverParameters::AutoRelayCheck(void) // IminLo } // main bez samoczynnego rozruchu + if( ( MainCtrlActualPos < ( sizeof( RList ) / sizeof( TScheme ) - 1 ) ) // crude guard against running out of current fixed table + && ( ( RList[ MainCtrlActualPos ].Relay < MainCtrlPos ) + || ( RList[ MainCtrlActualPos + 1 ].Relay == MainCtrlPos ) + || ( ( TrainType == dt_ET22 ) + && ( DelayCtrlFlag ) ) ) ) { + + if( ( RList[MainCtrlPos].R == 0 ) + && ( MainCtrlPos > 0 ) + && ( MainCtrlPos != MainCtrlPosNo ) + && ( FastSerialCircuit == 1 ) ) { - if ((RList[MainCtrlActualPos].Relay < MainCtrlPos) || - (RList[MainCtrlActualPos + 1].Relay == MainCtrlPos) || - ((TrainType == dt_ET22) && (DelayCtrlFlag))) - { - if ((RList[MainCtrlPos].R == 0) && (MainCtrlPos > 0) && - (!(MainCtrlPos == MainCtrlPosNo)) && (FastSerialCircuit == 1)) - { MainCtrlActualPos++; // MainCtrlActualPos:=MainCtrlPos; //hunter-111012: // szybkie wchodzenie na bezoporowa (303E) @@ -5803,28 +5809,28 @@ std::string TMoverParameters::EngineDescription(int what) { if (TestFlag(DamageFlag, dtrain_thinwheel)) if (Power > 0.1) - outstr = "Thin wheel,"; + outstr = "Thin wheel"; else - outstr = "Load shifted,"; + outstr = "Load shifted"; if (TestFlag(DamageFlag, dtrain_wheelwear)) - outstr = "Wheel wear,"; + outstr = "Wheel wear"; if (TestFlag(DamageFlag, dtrain_bearing)) - outstr = "Bearing damaged,"; + outstr = "Bearing damaged"; if (TestFlag(DamageFlag, dtrain_coupling)) - outstr = "Coupler broken,"; + outstr = "Coupler broken"; if (TestFlag(DamageFlag, dtrain_loaddamage)) if (Power > 0.1) - outstr = "Ventilator damaged,"; + outstr = "Ventilator damaged"; else - outstr = "Load damaged,"; + outstr = "Load damaged"; if (TestFlag(DamageFlag, dtrain_loaddestroyed)) if (Power > 0.1) - outstr = "Engine damaged,"; + outstr = "Engine damaged"; else - outstr = "LOAD DESTROYED,"; + outstr = "LOAD DESTROYED"; if (TestFlag(DamageFlag, dtrain_axle)) - outstr = "Axle broken,"; + outstr = "Axle broken"; if (TestFlag(DamageFlag, dtrain_out)) outstr = "DERAILED"; if (outstr == "") @@ -6105,7 +6111,7 @@ bool TMoverParameters::readRList( std::string const &Input ) { return false; } auto idx = LISTLINE++; - if( idx >= sizeof( RList ) ) { + if( idx >= sizeof( RList ) / sizeof( TScheme ) ) { WriteLog( "Read RList: number of entries exceeded capacity of the data table" ); return false; } @@ -6127,7 +6133,7 @@ bool TMoverParameters::readDList( std::string const &line ) { cParser parser( line ); parser.getTokens( 3, false ); auto idx = LISTLINE++; - if( idx >= sizeof( RList ) ) { + if( idx >= sizeof( RList ) / sizeof( TScheme ) ) { WriteLog( "Read DList: number of entries exceeded capacity of the data table" ); return false; } @@ -6147,7 +6153,7 @@ bool TMoverParameters::readFFList( std::string const &line ) { return false; } int idx = LISTLINE++; - if( idx >= sizeof( DElist ) ) { + if( idx >= sizeof( DElist ) / sizeof( TDEScheme ) ) { WriteLog( "Read FList: number of entries exceeded capacity of the data table" ); return false; } @@ -6167,7 +6173,7 @@ bool TMoverParameters::readWWList( std::string const &line ) { return false; } int idx = LISTLINE++; - if( idx >= sizeof( DElist ) ) { + if( idx >= sizeof( DElist ) / sizeof( TDEScheme ) ) { WriteLog( "Read WWList: number of entries exceeded capacity of the data table" ); return false; } @@ -8364,22 +8370,3 @@ double TMoverParameters::ShowCurrentP(int AmpN) return current; } } - -template <> -bool -extract_value( bool &Variable, std::string const &Key, std::string const &Input, std::string const &Default ) { - - auto value = extract_value( Key, Input ); - if( false == value.empty() ) { - // set the specified variable to retrieved value - Variable = ( ToLower( value ) == "yes" ); - return true; // located the variable - } - else { - // set the variable to provided default value - if( false == Default.empty() ) { - Variable = ( ToLower( Default ) == "yes" ); - } - return false; // couldn't locate the variable in provided input - } -} diff --git a/McZapkie/mctools.cpp b/McZapkie/mctools.cpp index 42f6b17d..33744897 100644 --- a/McZapkie/mctools.cpp +++ b/McZapkie/mctools.cpp @@ -17,41 +17,9 @@ Copyright (C) 2007-2014 Maciej Cierniak /*================================================*/ -int ConversionError = 0; -int LineCount = 0; bool DebugModeFlag = false; bool FreeFlyModeFlag = false; -//std::string Ups(std::string s) -//{ -// int jatka; -// std::string swy; -// -// swy = ""; -// { -// long jatka_end = s.length() + 1; -// for (jatka = 0; jatka < jatka_end; jatka++) -// swy = swy + UpCase(s[jatka]); -// } -// return swy; -//} /*=Ups=*/ - -int Max0(int x1, int x2) -{ - if (x1 > x2) - return x1; - else - return x2; -} - -int Min0(int x1, int x2) -{ - if (x1 < x2) - return x1; - else - return x2; -} - double Max0R(double x1, double x2) { if (x1 > x2) @@ -87,13 +55,8 @@ bool TestFlag(int Flag, int Value) return false; } -bool SetFlag(int &Flag, int Value) -{ - return iSetFlag(Flag, Value); -} +bool SetFlag(int &Flag, int Value) { -bool iSetFlag(int &Flag, int Value) -{ if (Value > 0) { if ((Flag & Value) == 0) @@ -263,33 +226,13 @@ std::string to_hex_str( int const Value, int const Width ) return converter.str(); }; -int stol_def(const std::string &str, const int &DefaultValue) -{ +int stol_def(const std::string &str, const int &DefaultValue) { + int result { DefaultValue }; std::stringstream converter; converter << str; converter >> result; return result; -/* - // this function was developed iteratively on Codereview.stackexchange - // with the assistance of @Corbin - std::size_t len = str.size(); - while (std::isspace(str[len - 1])) - len--; - if (len == 0) - return DefaultValue; - errno = 0; - char *s = new char[len + 1]; - std::strncpy(s, str.c_str(), len); - char *p; - int result = strtol(s, &p, 0); - delete[] s; - if( ( *p != '\0' ) || ( errno != 0 ) ) - { - return DefaultValue; - } - return result; -*/ } std::string ToLower(std::string const &text) @@ -321,114 +264,27 @@ win1250_to_ascii( std::string &Input ) { } } -void ComputeArc(double X0, double Y0, double Xn, double Yn, double R, double L, double dL, - double &phi, double &Xout, double &Yout) -/*wylicza polozenie Xout Yout i orientacje phi punktu na elemencie dL luku*/ -{ - double dX; - double dY; - double Xc; - double Yc; - double gamma; - double alfa; - double AbsR; +template <> +bool +extract_value( bool &Variable, std::string const &Key, std::string const &Input, std::string const &Default ) { - if ((R != 0) && (L != 0)) - { - AbsR = abs(R); - dX = Xn - X0; - dY = Yn - Y0; - if (dX != 0) - gamma = atan(dY * 1.0 / dX); - else if (dY > 0) - gamma = M_PI * 1.0 / 2; - else - gamma = 3 * M_PI * 1.0 / 2; - alfa = L * 1.0 / R; - phi = gamma - (alfa + M_PI * Round(R * 1.0 / AbsR)) * 1.0 / 2; - Xc = X0 - AbsR * cos(phi); - Yc = Y0 - AbsR * sin(phi); - phi = phi + alfa * dL * 1.0 / L; - Xout = AbsR * cos(phi) + Xc; - Yout = AbsR * sin(phi) + Yc; + auto value = extract_value( Key, Input ); + if( false == value.empty() ) { + // set the specified variable to retrieved value + Variable = ( ToLower( value ) == "yes" ); + return true; // located the variable + } + else { + // set the variable to provided default value + if( false == Default.empty() ) { + Variable = ( ToLower( Default ) == "yes" ); + } + return false; // couldn't locate the variable in provided input } -} - -void ComputeALine(double X0, double Y0, double Xn, double Yn, double L, double R, double &Xout, - double &Yout) -{ - double dX; - double dY; - double gamma; - double alfa; - /* pX,pY : real;*/ - - alfa = 0; // ABu: bo nie bylo zainicjowane - dX = Xn - X0; - dY = Yn - Y0; - if (dX != 0) - gamma = atan(dY * 1.0 / dX); - else if (dY > 0) - gamma = M_PI * 1.0 / 2; - else - gamma = 3 * M_PI * 1.0 / 2; - if (R != 0) - alfa = L * 1.0 / R; - Xout = X0 + L * cos(alfa * 1.0 / 2 - gamma); - Yout = Y0 + L * sin(alfa * 1.0 / 2 - gamma); } bool FileExists( std::string const &Filename ) { - std::ifstream file( Filename ); + std::ifstream file( Filename ); return( true == file.is_open() ); } - -/* -//graficzne: - -double Xhor(double h) -{ - return h * Hstep + Xmin; -} - -double Yver(double v) -{ - return (Vsize - v) * Vstep + Ymin; -} - -long Horiz(double x) -{ - x = (x - Xmin) * 1.0 / Hstep; - if (x > -INT_MAX) - if (x < INT_MAX) - return Round(x); - else - return INT_MAX; - else - return -INT_MAX; -} - -long Vert(double Y) -{ - Y = (Y - Ymin) * 1.0 / Vstep; - if (Y > -INT_MAX) - if (Y < INT_MAX) - return Vsize - Round(Y); - else - return INT_MAX; - else - return -INT_MAX; -} -*/ - -// NOTE: this now does nothing. -void ClearPendingExceptions() -// resetuje błędy FPU, wymagane dla Trunc() -{ - ; /*?*/ /* ASM - FNCLEX - ASM END */ -} - -// END diff --git a/McZapkie/mctools.h b/McZapkie/mctools.h index c8171572..8f02ab11 100644 --- a/McZapkie/mctools.h +++ b/McZapkie/mctools.h @@ -15,48 +15,16 @@ http://mozilla.org/MPL/2.0/. #include #include #include -#include #include #include -/*Ra: te stałe nie są używane... - _FileName = ['a'..'z','A'..'Z',':','\','.','*','?','0'..'9','_','-']; - _RealNum = ['0'..'9','-','+','.','E','e']; - _Integer = ['0'..'9','-']; //Ra: to się gryzie z STLport w Builder 6 - _Plus_Int = ['0'..'9']; - _All = [' '..'ţ']; - _Delimiter= [',',';']+_EOL; - _Delimiter_Space=_Delimiter+[' ']; -*/ -static char _EOL[2] = { (char)13, (char)10 }; -static char _Spacesigns[4] = { (char)' ', (char)9, (char)13, (char)10 }; -static std::string _spacesigns = " " + (char)9 + (char)13 + (char)10; -static int const CutLeft = -1; -static int const CutRight = 1; -static int const CutBoth = 0; /*Cut_Space*/ - -extern int ConversionError; -extern int LineCount; extern bool DebugModeFlag; extern bool FreeFlyModeFlag; - -typedef unsigned long/*?*//*set of: char */ TableChar; /*MCTUTIL*/ - -/*konwersje*/ - /*funkcje matematyczne*/ -int Max0(int x1, int x2); -int Min0(int x1, int x2); - double Max0R(double x1, double x2); double Min0R(double x1, double x2); -inline int Sign(int x) -{ - return x >= 0 ? 1 : -1; -} - inline double Sign(double x) { return x >= 0 ? 1.0 : -1.0; @@ -68,7 +36,7 @@ inline long Round(double const f) //return lround(f); } -extern double Random(double a, double b); +double Random(double a, double b); inline double Random() { @@ -94,10 +62,9 @@ inline double BorlandTime() std::string Now(); /*funkcje logiczne*/ -extern bool TestFlag(int Flag, int Value); -extern bool SetFlag( int & Flag, int Value); -extern bool iSetFlag( int & Flag, int Value); -extern bool UnSetFlag(int &Flag, int Value); +bool TestFlag(int Flag, int Value); +bool SetFlag( int & Flag, int Value); +bool UnSetFlag(int &Flag, int Value); bool FuzzyLogic(double Test, double Threshold, double Probability); /*jesli Test>Threshold to losowanie*/ @@ -139,40 +106,48 @@ std::string ToUpper(std::string const &text); // replaces polish letters with basic ascii void win1250_to_ascii( std::string &Input ); -/*procedury, zmienne i funkcje graficzne*/ -void ComputeArc(double X0, double Y0, double Xn, double Yn, double R, double L, double dL, double & phi, double & Xout, double & Yout); -/*wylicza polozenie Xout Yout i orientacje phi punktu na elemencie dL luku*/ -void ComputeALine(double X0, double Y0, double Xn, double Yn, double L, double R, double & Xout, double & Yout); -/* -inline bool fileExists(const std::string &name) -{ - struct stat buffer; - return (stat(name.c_str(), &buffer) == 0); -}*/ +inline +std::string +extract_value( std::string const &Key, std::string const &Input ) { + + std::string value; + auto lookup = Input.find( Key + "=" ); + if( lookup != std::string::npos ) { + value = Input.substr( Input.find_first_not_of( ' ', lookup + Key.size() + 1 ) ); + lookup = value.find( ' ' ); + if( lookup != std::string::npos ) { + // trim everything past the value + value.erase( lookup ); + } + } + return value; +} + +template +bool +extract_value( Type_ &Variable, std::string const &Key, std::string const &Input, std::string const &Default ) { + + auto value = extract_value( Key, Input ); + if( false == value.empty() ) { + // set the specified variable to retrieved value + std::stringstream converter; + converter << value; + converter >> Variable; + return true; // located the variable + } + else { + // set the variable to provided default value + if( false == Default.empty() ) { + std::stringstream converter; + converter << Default; + converter >> Variable; + } + return false; // couldn't locate the variable in provided input + } +} + +template <> +bool +extract_value( bool &Variable, std::string const &Key, std::string const &Input, std::string const &Default ); + bool FileExists( std::string const &Filename ); -/* -extern double Xmin; -extern double Ymin; -extern double Xmax; -extern double Ymax; -extern double Xaspect; -extern double Yaspect; -extern double Hstep; -extern double Vstep; -extern int Vsize; -extern int Hsize; - - -// Converts horizontal screen coordinate into real X-coordinate. -double Xhor( double h ); - -// Converts vertical screen coordinate into real Y-coordinate. -double Yver( double v ); - -long Horiz(double x); - -long Vert(double Y); -*/ - -void ClearPendingExceptions(); - diff --git a/Model3d.cpp b/Model3d.cpp index 27614b73..b77b9329 100644 --- a/Model3d.cpp +++ b/Model3d.cpp @@ -1217,11 +1217,11 @@ TSubModel *TModel3d::GetFromName(const char *sName) if (!sName) return Root; // potrzebne do terenu z E3D if (iFlags & 0x0200) // wczytany z pliku tekstowego, wyszukiwanie rekurencyjne - return Root ? Root->GetFromName(sName) : NULL; + return Root ? Root->GetFromName(sName) : nullptr; else // wczytano z pliku binarnego, można wyszukać iteracyjnie { // for (int i=0;iGetFromName(sName) : NULL; + return Root ? Root->GetFromName(sName) : nullptr; } }; diff --git a/Train.cpp b/Train.cpp index 7e6a1a79..5f768b8e 100644 --- a/Train.cpp +++ b/Train.cpp @@ -56,14 +56,16 @@ TCab::TCab() dimm_r = dimm_g = dimm_b = 1; intlit_r = intlit_g = intlit_b = 0; intlitlow_r = intlitlow_g = intlitlow_b = 0; +/* iGaugesMax = 100; // 95 - trzeba pobierać to z pliku konfiguracyjnego ggList = new TGauge[iGaugesMax]; iGauges = 0; // na razie nie są dodane iButtonsMax = 60; // 55 - trzeba pobierać to z pliku konfiguracyjnego btList = new TButton[iButtonsMax]; iButtons = 0; +*/ } - +/* void TCab::Init(double Initx1, double Inity1, double Initz1, double Initx2, double Inity2, double Initz2, bool InitEnabled, bool InitOccupied) { @@ -76,9 +78,13 @@ void TCab::Init(double Initx1, double Inity1, double Initz1, double Initx2, doub bEnabled = InitEnabled; bOccupied = InitOccupied; } - +*/ void TCab::Load(cParser &Parser) { + // NOTE: clearing control tables here is bit of a crutch, imposed by current scheme of loading compartments anew on each cab change + ggList.clear(); + btList.clear(); + std::string token; Parser.getTokens(); Parser >> token; @@ -112,12 +118,15 @@ void TCab::Load(cParser &Parser) TCab::~TCab() { +/* delete[] ggList; delete[] btList; +*/ }; -TGauge *TCab::Gauge(int n) +TGauge &TCab::Gauge(int n) { // pobranie adresu obiektu aniomowanego ruchem +/* if (n < 0) { // rezerwacja wolnego ggList[iGauges].Clear(); @@ -126,9 +135,19 @@ TGauge *TCab::Gauge(int n) else if (n < iGauges) return ggList + n; return NULL; +*/ + if( n < 0 ) { + ggList.emplace_back(); + return ggList.back(); + } + else { + return ggList[ n ]; + } }; -TButton *TCab::Button(int n) + +TButton &TCab::Button(int n) { // pobranie adresu obiektu animowanego wyborem 1 z 2 +/* if (n < 0) { // rezerwacja wolnego return btList + iButtons++; @@ -136,10 +155,19 @@ TButton *TCab::Button(int n) else if (n < iButtons) return btList + n; return NULL; +*/ + if( n < 0 ) { + btList.emplace_back(); + return btList.back(); + } + else { + return btList[ n ]; + } }; void TCab::Update() { // odczyt parametrów i ustawienie animacji submodelom +/* int i; for (i = 0; i < iGauges; ++i) { // animacje izometryczne @@ -150,6 +178,16 @@ void TCab::Update() { // animacje dwustanowe btList[i].Update(); // odczyt parametru i wybór submodelu } +*/ + for( auto &gauge : ggList ) { + // animacje izometryczne + gauge.UpdateValue(); // odczyt parametru i przeliczenie na kąt + gauge.Update(); // ustawienie animacji + } + for( auto &button : btList ) { + // animacje dwustanowe + button.Update(); // odczyt parametru i wybór submodelu + } }; // NOTE: we're currently using universal handlers and static handler map but it may be beneficial to have these implemented on individual class instance basis @@ -519,10 +557,14 @@ void TTrain::OnCommand_mastercontrollerincrease( TTrain *Train, command_data con if( Command.action != GLFW_RELEASE ) { // on press or hold +#ifdef EU07_USE_OLD_CONTROLSOUNDS if( Train->mvControlled->IncMainCtrl( 1 ) ) { // sound feedback Train->play_sound( Train->dsbNastawnikJazdy ); } +#else + Train->mvControlled->IncMainCtrl( 1 ); +#endif } } @@ -530,10 +572,14 @@ void TTrain::OnCommand_mastercontrollerincreasefast( TTrain *Train, command_data if( Command.action != GLFW_RELEASE ) { // on press or hold +#ifdef EU07_USE_OLD_CONTROLSOUNDS if( Train->mvControlled->IncMainCtrl( 2 ) ) { // sound feedback Train->play_sound( Train->dsbNastawnikJazdy ); } +#else + Train->mvControlled->IncMainCtrl( 2 ); +#endif } } @@ -541,10 +587,14 @@ void TTrain::OnCommand_mastercontrollerdecrease( TTrain *Train, command_data con if( Command.action != GLFW_RELEASE ) { // on press or hold +#ifdef EU07_USE_OLD_CONTROLSOUNDS if( Train->mvControlled->DecMainCtrl( 1 ) ) { // sound feedback Train->play_sound( Train->dsbNastawnikJazdy ); } +#else + Train->mvControlled->DecMainCtrl( 1 ); +#endif } } @@ -552,10 +602,14 @@ void TTrain::OnCommand_mastercontrollerdecreasefast( TTrain *Train, command_data if( Command.action != GLFW_RELEASE ) { // on press or hold +#ifdef EU07_USE_OLD_CONTROLSOUNDS if( Train->mvControlled->DecMainCtrl( 2 ) ) { // sound feedback Train->play_sound( Train->dsbNastawnikJazdy ); } +#else + Train->mvControlled->DecMainCtrl( 2 ); +#endif } } @@ -568,10 +622,16 @@ void TTrain::OnCommand_secondcontrollerincrease( TTrain *Train, command_data con if( Train->mvControlled->AnPos > 1 ) Train->mvControlled->AnPos = 1; } +#ifdef EU07_USE_OLD_CONTROLSOUNDS else if( Train->mvControlled->IncScndCtrl( 1 ) ) { // sound feedback Train->play_sound( Train->dsbNastawnikBocz, Train->dsbNastawnikJazdy, DSBVOLUME_MAX, 0 ); } +#else + else { + Train->mvControlled->IncScndCtrl( 1 ); + } +#endif } } @@ -579,10 +639,14 @@ void TTrain::OnCommand_secondcontrollerincreasefast( TTrain *Train, command_data if( Command.action != GLFW_RELEASE ) { // on press or hold +#ifdef EU07_USE_OLD_CONTROLSOUNDS if( Train->mvControlled->IncScndCtrl( 2 ) ) { // sound feedback Train->play_sound( Train->dsbNastawnikBocz, Train->dsbNastawnikJazdy, DSBVOLUME_MAX, 0 ); } +#else + Train->mvControlled->IncScndCtrl( 2 ); +#endif } } @@ -592,6 +656,7 @@ void TTrain::OnCommand_notchingrelaytoggle( TTrain *Train, command_data const &C // only reacting to press, so the switch doesn't flip back and forth if key is held down if( false == Train->mvOccupied->AutoRelayFlag ) { // turn on +#ifdef EU07_USE_OLD_CONTROLSOUNDS if( Train->mvOccupied->AutoRelaySwitch( true ) ) { // audio feedback Train->play_sound( Train->dsbSwitch ); @@ -599,9 +664,13 @@ void TTrain::OnCommand_notchingrelaytoggle( TTrain *Train, command_data const &C // NOTE: there's no button for notching relay control // TBD, TODO: add notching relay control button? } +#else + Train->mvOccupied->AutoRelaySwitch( true ); +#endif } else { //turn off +#ifdef EU07_USE_OLD_CONTROLSOUNDS if( Train->mvOccupied->AutoRelaySwitch( false ) ) { // audio feedback Train->play_sound( Train->dsbSwitch ); @@ -609,6 +678,9 @@ void TTrain::OnCommand_notchingrelaytoggle( TTrain *Train, command_data const &C // NOTE: there's no button for notching relay control // TBD, TODO: add notching relay control button? } +#else + Train->mvOccupied->AutoRelaySwitch( false ); +#endif } } } @@ -625,20 +697,24 @@ void TTrain::OnCommand_mucurrentindicatorothersourceactivate( TTrain *Train, com if( Command.action == GLFW_PRESS ) { // turn on Train->ShowNextCurrent = true; +#ifdef EU07_USE_OLD_CONTROLSOUNDS // audio feedback if( Train->ggNextCurrentButton.GetValue() < 0.5 ) { Train->play_sound( Train->dsbSwitch ); } +#endif // visual feedback Train->ggNextCurrentButton.UpdateValue( 1.0 ); } else if( Command.action == GLFW_RELEASE ) { //turn off Train->ShowNextCurrent = false; +#ifdef EU07_USE_OLD_CONTROLSOUNDS // audio feedback if( Train->ggNextCurrentButton.GetValue() > 0.5 ) { Train->play_sound( Train->dsbSwitch ); } +#endif // visual feedback Train->ggNextCurrentButton.UpdateValue( 0.0 ); } @@ -653,10 +729,14 @@ void TTrain::OnCommand_secondcontrollerdecrease( TTrain *Train, command_data con if( Train->mvControlled->AnPos > 1 ) Train->mvControlled->AnPos = 1; } +#ifdef EU07_USE_OLD_CONTROLSOUNDS else if( Train->mvControlled->DecScndCtrl( 1 ) ) { // sound feedback Train->play_sound( Train->dsbNastawnikBocz, Train->dsbNastawnikJazdy, DSBVOLUME_MAX, 0 ); } +#else + Train->mvControlled->DecScndCtrl( 1 ); +#endif } } @@ -664,10 +744,14 @@ void TTrain::OnCommand_secondcontrollerdecreasefast( TTrain *Train, command_data if( Command.action != GLFW_RELEASE ) { // on press or hold +#ifdef EU07_USE_OLD_CONTROLSOUNDS if( Train->mvControlled->DecScndCtrl( 2 ) ) { // sound feedback Train->play_sound( Train->dsbNastawnikBocz, Train->dsbNastawnikJazdy, DSBVOLUME_MAX, 0 ); } +#else + Train->mvControlled->DecScndCtrl( 2 ); +#endif } } @@ -729,10 +813,12 @@ void TTrain::OnCommand_independentbrakebailoff( TTrain *Train, command_data cons if( Command.action != GLFW_RELEASE ) { // press or hold Train->mvOccupied->BrakeReleaser( 1 ); +#ifdef EU07_USE_OLD_CONTROLSOUNDS // audio feedback if( Train->ggReleaserButton.GetValue() < 0.05 ) { Train->play_sound( Train->dsbSwitch ); } +#endif // visual feedback Train->ggReleaserButton.UpdateValue( 1.0 ); } @@ -862,8 +948,8 @@ void TTrain::OnCommand_trainbrakefirstservice( TTrain *Train, command_data const // sound feedback if( ( Train->is_eztoer() ) - && ( Train->mvControlled->Mains ) - && ( Train->mvOccupied->BrakeCtrlPos != 1 ) ) { + && ( Train->mvControlled->Mains ) + && ( Train->mvOccupied->BrakeCtrlPos != 1 ) ) { Train->play_sound( Train->dsbPneumaticSwitch ); } @@ -934,10 +1020,12 @@ void TTrain::OnCommand_wheelspinbrakeactivate( TTrain *Train, command_data const if( Command.action != GLFW_RELEASE ) { // press or hold Train->mvControlled->AntiSlippingBrake(); +#ifdef EU07_USE_OLD_CONTROLSOUNDS // audio feedback if( Train->ggAntiSlipButton.GetValue() < 0.05 ) { Train->play_sound( Train->dsbSwitch ); } +#endif // visual feedback Train->ggAntiSlipButton.UpdateValue( 1.0 ); } @@ -967,8 +1055,10 @@ void TTrain::OnCommand_sandboxactivate( TTrain *Train, command_data const &Comma if( Command.action == GLFW_PRESS ) { // press Train->mvControlled->Sandbox( true ); +#ifdef EU07_USE_OLD_CONTROLSOUNDS // audio feedback Train->play_sound( Train->dsbSwitch ); +#endif // visual feedback Train->ggSandButton.UpdateValue( 1.0 ); } @@ -1025,11 +1115,13 @@ void TTrain::OnCommand_brakeactingspeedincrease( TTrain *Train, command_data con Train->mvOccupied->BrakeDelayFlag << 1 : Train->mvOccupied->BrakeDelayFlag | bdelay_M ); if( true == Train->mvOccupied->BrakeDelaySwitch( fasterbrakesetting ) ) { +#ifdef EU07_USE_OLD_CONTROLSOUNDS // audio feedback Train->play_sound( Train->dsbSwitch ); /* Train->play_sound( Train->dsbPneumaticRelay ); */ +#endif // visual feedback if( Train->ggBrakeProfileCtrl.SubModel != nullptr ) { Train->ggBrakeProfileCtrl.UpdateValue( @@ -1065,11 +1157,13 @@ void TTrain::OnCommand_brakeactingspeeddecrease( TTrain *Train, command_data con Train->mvOccupied->BrakeDelayFlag >> 1 : Train->mvOccupied->BrakeDelayFlag ^ bdelay_M ); if( true == Train->mvOccupied->BrakeDelaySwitch( slowerbrakesetting ) ) { +#ifdef EU07_USE_OLD_CONTROLSOUNDS // audio feedback Train->play_sound( Train->dsbSwitch ); /* Train->play_sound( Train->dsbPneumaticRelay ); */ +#endif // visual feedback if( Train->ggBrakeProfileCtrl.SubModel != nullptr ) { Train->ggBrakeProfileCtrl.UpdateValue( @@ -1111,20 +1205,24 @@ void TTrain::OnCommand_mubrakingindicatortoggle( TTrain *Train, command_data con if( false == Train->mvControlled->Signalling) { // turn on Train->mvControlled->Signalling = true; +#ifdef EU07_USE_OLD_CONTROLSOUNDS // audio feedback if( Train->ggSignallingButton.GetValue() < 0.5 ) { Train->play_sound( Train->dsbSwitch ); } +#endif // visual feedback Train->ggSignallingButton.UpdateValue( 1.0 ); } else { //turn off Train->mvControlled->Signalling = false; +#ifdef EU07_USE_OLD_CONTROLSOUNDS // audio feedback if( Train->ggSignallingButton.GetValue() > 0.5 ) { Train->play_sound( Train->dsbSwitch ); } +#endif // visual feedback Train->ggSignallingButton.UpdateValue( 0.0 ); } @@ -1136,8 +1234,10 @@ void TTrain::OnCommand_reverserincrease( TTrain *Train, command_data const &Comm if( Command.action == GLFW_PRESS ) { if( Train->mvOccupied->DirectionForward() ) { +#ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback Train->play_sound( Train->dsbReverserKey, Train->dsbSwitch, DSBVOLUME_MAX, 0 ); +#endif // aktualizacja skrajnych pojazdów w składzie if( ( Train->mvOccupied->ActiveDir ) && ( Train->DynamicObject->Mechanik ) ) { @@ -1153,8 +1253,10 @@ void TTrain::OnCommand_reverserdecrease( TTrain *Train, command_data const &Comm if( Command.action == GLFW_PRESS ) { if( Train->mvOccupied->DirectionBackward() ) { +#ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback Train->play_sound( Train->dsbReverserKey, Train->dsbSwitch, DSBVOLUME_MAX, 0 ); +#endif // aktualizacja skrajnych pojazdów w składzie if( ( Train->mvOccupied->ActiveDir ) && ( Train->DynamicObject->Mechanik ) ) { @@ -1181,10 +1283,12 @@ void TTrain::OnCommand_alerteracknowledge( TTrain *Train, command_data const &Co } // visual feedback Train->ggSecurityResetButton.UpdateValue( 1.0 ); +#ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggSecurityResetButton.GetValue() < 0.05 ) { Train->play_sound( Train->dsbSwitch ); } +#endif } else { // release @@ -1212,8 +1316,10 @@ void TTrain::OnCommand_batterytoggle( TTrain *Train, command_data const &Command if( Train->ggBatteryButton.SubModel ) { Train->ggBatteryButton.UpdateValue( 1 ); } +#ifdef EU07_USE_OLD_CONTROLSOUNDS // audio feedback Train->play_sound( Train->dsbSwitch ); +#endif // side-effects if( Train->mvOccupied->LightsPosNo > 0 ) { Train->SetLights(); @@ -1232,8 +1338,10 @@ void TTrain::OnCommand_batterytoggle( TTrain *Train, command_data const &Command if( Train->ggBatteryButton.SubModel ) { Train->ggBatteryButton.UpdateValue( 0 ); } +#ifdef EU07_USE_OLD_CONTROLSOUNDS // audio feedback Train->play_sound( Train->dsbSwitch ); +#endif // side-effects if( false == Train->mvControlled->ConverterFlag ) { // if there's no (low voltage) power source left, drop pantographs @@ -1254,8 +1362,10 @@ void TTrain::OnCommand_pantographtogglefront( TTrain *Train, command_data const Train->mvControlled->PantFrontSP = false; if( Train->mvControlled->PantFront( true ) ) { if( Train->mvControlled->PantFrontStart != 1 ) { +#ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback Train->play_sound( Train->dsbSwitch ); +#endif // visual feedback Train->ggPantFrontButton.UpdateValue( 1.0 ); // NOTE: currently we animate the selectable pantograph control based on standard key presses @@ -1284,8 +1394,10 @@ void TTrain::OnCommand_pantographtogglefront( TTrain *Train, command_data const Train->mvControlled->PantFrontSP = false; if( false == Train->mvControlled->PantFront( false ) ) { if( Train->mvControlled->PantFrontStart != 0 ) { +#ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback Train->play_sound( Train->dsbSwitch ); +#endif // visual feedback Train->ggPantFrontButton.UpdateValue( 0.0 ); // NOTE: currently we animate the selectable pantograph control based on standard key presses @@ -1303,17 +1415,21 @@ void TTrain::OnCommand_pantographtogglefront( TTrain *Train, command_data const else if( Command.action == GLFW_RELEASE ) { // impulse switches return automatically to neutral position if( Train->mvOccupied->PantSwitchType == "impulse" ) { +#ifdef EU07_USE_OLD_CONTROLSOUNDS if( Train->ggPantFrontButton.GetValue() > 0.35 ) { Train->play_sound( Train->dsbSwitch ); } +#endif Train->ggPantFrontButton.UpdateValue( 0.0 ); // NOTE: currently we animate the selectable pantograph control based on standard key presses // TODO: implement actual selection control, and refactor handling this control setup in a separate method Train->ggPantSelectedButton.UpdateValue( 0.0 ); // also the switch off button, in cabs which have it +#ifdef EU07_USE_OLD_CONTROLSOUNDS if( Train->ggPantFrontButtonOff.GetValue() > 0.35 ) { Train->play_sound( Train->dsbSwitch ); } +#endif if( Train->ggPantFrontButtonOff.SubModel ) { Train->ggPantFrontButtonOff.UpdateValue( 0.0 ); } @@ -1335,8 +1451,10 @@ void TTrain::OnCommand_pantographtogglerear( TTrain *Train, command_data const & Train->mvControlled->PantRearSP = false; if( Train->mvControlled->PantRear( true ) ) { if( Train->mvControlled->PantRearStart != 1 ) { +#ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback Train->play_sound( Train->dsbSwitch ); +#endif // visual feedback Train->ggPantRearButton.UpdateValue( 1.0 ); // NOTE: currently we animate the selectable pantograph control based on standard key presses @@ -1365,8 +1483,10 @@ void TTrain::OnCommand_pantographtogglerear( TTrain *Train, command_data const & Train->mvControlled->PantRearSP = false; if( false == Train->mvControlled->PantRear( false ) ) { if( Train->mvControlled->PantRearStart != 0 ) { +#ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback Train->play_sound( Train->dsbSwitch ); +#endif // visual feedback Train->ggPantRearButton.UpdateValue( 0.0 ); // NOTE: currently we animate the selectable pantograph control based on standard key presses @@ -1384,17 +1504,21 @@ void TTrain::OnCommand_pantographtogglerear( TTrain *Train, command_data const & else if( Command.action == GLFW_RELEASE ) { // impulse switches return automatically to neutral position if( Train->mvOccupied->PantSwitchType == "impulse" ) { +#ifdef EU07_USE_OLD_CONTROLSOUNDS if( Train->ggPantRearButton.GetValue() > 0.35 ) { Train->play_sound( Train->dsbSwitch ); } +#endif Train->ggPantRearButton.UpdateValue( 0.0 ); // NOTE: currently we animate the selectable pantograph control based on standard key presses // TODO: implement actual selection control, and refactor handling this control setup in a separate method Train->ggPantSelectedButton.UpdateValue( 0.0 ); // also the switch off button, in cabs which have it +#ifdef EU07_USE_OLD_CONTROLSOUNDS if( Train->ggPantRearButtonOff.GetValue() > 0.35 ) { Train->play_sound( Train->dsbSwitch ); } +#endif if( Train->ggPantRearButtonOff.SubModel ) { Train->ggPantRearButtonOff.UpdateValue( 0.0 ); } @@ -1421,14 +1545,18 @@ void TTrain::OnCommand_pantographcompressorvalvetoggle( TTrain *Train, command_d if( Train->mvControlled->bPantKurek3 == false ) { // connect pantographs with primary tank Train->mvControlled->bPantKurek3 = true; +#ifdef EU07_USE_OLD_CONTROLSOUNDS // audio feedback Train->play_sound( Train->dsbSwitch ); +#endif } else { // connect pantograps with pantograph compressor Train->mvControlled->bPantKurek3 = false; +#ifdef EU07_USE_OLD_CONTROLSOUNDS // audio feedback Train->play_sound( Train->dsbSwitch ); +#endif } } } @@ -1451,10 +1579,12 @@ void TTrain::OnCommand_pantographcompressoractivate( TTrain *Train, command_data if( Command.action != GLFW_RELEASE ) { // press or hold to activate Train->mvControlled->PantCompFlag = true; +#ifdef EU07_USE_OLD_CONTROLSOUNDS // audio feedback if( Command.action == GLFW_PRESS ) { Train->play_sound( Train->dsbSwitch ); } +#endif } else { // release to disable @@ -1481,11 +1611,13 @@ void TTrain::OnCommand_pantographlowerall( TTrain *Train, command_data const &Co // ...and rear Train->mvControlled->PantRearSP = false; Train->mvControlled->PantRear( false ); +#ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback // TODO: separate sound effect for pneumatic buttons if( Train->ggPantAllDownButton.GetValue() < 0.35 ) { Train->play_sound( Train->dsbSwitch ); } +#endif // visual feedback Train->ggPantAllDownButton.UpdateValue( 1.0 ); if( Train->ggPantSelectedDownButton.SubModel != nullptr ) { @@ -1494,6 +1626,7 @@ void TTrain::OnCommand_pantographlowerall( TTrain *Train, command_data const &Co } else if( Command.action == GLFW_RELEASE ) { // release the button +#ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback /* // NOTE: release sound disabled as this is typically pneumatic button @@ -1502,6 +1635,7 @@ void TTrain::OnCommand_pantographlowerall( TTrain *Train, command_data const &Co Train->play_sound( Train->dsbSwitch ); } */ +#endif // visual feedback Train->ggPantAllDownButton.UpdateValue( 0.0 ); if( Train->ggPantSelectedDownButton.SubModel != nullptr ) { @@ -1539,19 +1673,23 @@ void TTrain::OnCommand_linebreakertoggle( TTrain *Train, command_data const &Com } if( Train->ggMainOnButton.SubModel != nullptr ) { // two separate switches to close and break the circuit +#ifdef EU07_USE_OLD_CONTROLSOUNDS // audio feedback if( Command.action == GLFW_PRESS ) { Train->play_sound( Train->dsbSwitch ); } +#endif // visual feedback Train->ggMainOnButton.UpdateValue( 1.0 ); } else if( Train->ggMainButton.SubModel != nullptr ) { // single two-state switch +#ifdef EU07_USE_OLD_CONTROLSOUNDS // audio feedback if( Command.action == GLFW_PRESS ) { Train->play_sound( Train->dsbSwitch ); } +#endif // visual feedback Train->ggMainButton.UpdateValue( 1.0 ); } @@ -1594,10 +1732,12 @@ void TTrain::OnCommand_linebreakertoggle( TTrain *Train, command_data const &Com if( Train->ggMainOffButton.SubModel != nullptr ) { // two separate switches to close and break the circuit +#ifdef EU07_USE_OLD_CONTROLSOUNDS // audio feedback if( Command.action == GLFW_PRESS ) { Train->play_sound( Train->dsbSwitch ); } +#endif // visual feedback Train->ggMainOffButton.UpdateValue( 1.0 ); } @@ -1618,10 +1758,12 @@ void TTrain::OnCommand_linebreakertoggle( TTrain *Train, command_data const &Com else */ { +#ifdef EU07_USE_OLD_CONTROLSOUNDS // audio feedback if( Command.action == GLFW_PRESS ) { Train->play_sound( Train->dsbSwitch ); } +#endif // visual feedback Train->ggMainButton.UpdateValue( 0.0 ); } @@ -1647,20 +1789,24 @@ void TTrain::OnCommand_linebreakertoggle( TTrain *Train, command_data const &Com // for setup with two separate swiches if( Train->ggMainOnButton.SubModel != nullptr ) { Train->ggMainOnButton.UpdateValue( 0.0 ); +#ifdef EU07_USE_OLD_CONTROLSOUNDS // audio feedback if( Train->ggMainOnButton.GetValue() > 0.5 ) { Train->play_sound( Train->dsbSwitch ); } +#endif } if( Train->ggMainOffButton.SubModel != nullptr ) { Train->ggMainOffButton.UpdateValue( 0.0 ); } // and the two-state switch too, for good measure if( Train->ggMainButton.SubModel != nullptr ) { +#ifdef EU07_USE_OLD_CONTROLSOUNDS // audio feedback if( Train->ggMainButton.GetValue() > 0.5 ) { Train->play_sound( Train->dsbSwitch ); } +#endif // visual feedback Train->ggMainButton.UpdateValue( 0.0 ); } @@ -1677,10 +1823,12 @@ void TTrain::OnCommand_linebreakertoggle( TTrain *Train, command_data const &Com Train->mvControlled->CompressorSwitch( Train->ggCompressorButton.GetValue() > 0.5 ); } } +#ifdef EU07_USE_OLD_CONTROLSOUNDS // audio feedback if( Train->ggMainOnButton.GetValue() > 0.5 ) { Train->play_sound( Train->dsbSwitch ); } +#endif // visual feedback if( Train->ggMainOnButton.SubModel != nullptr ) { // setup with two separate switches @@ -1691,10 +1839,12 @@ void TTrain::OnCommand_linebreakertoggle( TTrain *Train, command_data const &Com // TODO: have proper switch type config for all switches, and put it in the cab switch descriptions, not in the .fiz if( Train->mvControlled->TrainType == dt_EZT ) { if( Train->ggMainButton.SubModel != nullptr ) { +#ifdef EU07_USE_OLD_CONTROLSOUNDS // audio feedback if( Train->ggMainButton.GetValue() > 0.5 ) { Train->play_sound( Train->dsbSwitch ); } +#endif // visual feedback Train->ggMainButton.UpdateValue( 0.0 ); } @@ -1719,10 +1869,12 @@ void TTrain::OnCommand_convertertoggle( TTrain *Train, command_data const &Comma if( ( false == Train->mvControlled->ConverterAllow ) && ( Train->ggConverterButton.GetValue() < 0.5 ) ) { // turn on +#ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggConverterButton.GetValue() < 0.5 ) { Train->play_sound( Train->dsbSwitch ); } +#endif // visual feedback Train->ggConverterButton.UpdateValue( 1.0 ); /* @@ -1750,6 +1902,7 @@ void TTrain::OnCommand_convertertoggle( TTrain *Train, command_data const &Comma } else { //turn off +#ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->mvOccupied->ConvSwitchType == "impulse" ) { if( Train->ggConverterOffButton.GetValue() < 0.5 ) { @@ -1761,6 +1914,7 @@ void TTrain::OnCommand_convertertoggle( TTrain *Train, command_data const &Comma Train->play_sound( Train->dsbSwitch ); } } +#endif // visual feedback Train->ggConverterButton.UpdateValue( 0.0 ); if( Train->ggConverterOffButton.SubModel != nullptr ) { @@ -1789,11 +1943,13 @@ void TTrain::OnCommand_convertertoggle( TTrain *Train, command_data const &Comma // on button release... if( Train->mvOccupied->ConvSwitchType == "impulse" ) { // ...return switches to start position if applicable +#ifdef EU07_USE_OLD_CONTROLSOUNDS if( ( Train->ggConverterButton.GetValue() > 0.0 ) || ( Train->ggConverterOffButton.GetValue() > 0.0 ) ) { // sound feedback Train->play_sound( Train->dsbSwitch ); } +#endif Train->ggConverterButton.UpdateValue( 0.0 ); Train->ggConverterOffButton.UpdateValue( 0.0 ); } @@ -1815,10 +1971,12 @@ void TTrain::OnCommand_convertertogglelocal( TTrain *Train, command_data const & if( ( false == Train->mvOccupied->ConverterAllowLocal ) && ( Train->ggConverterLocalButton.GetValue() < 0.5 ) ) { // turn on +#ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggConverterLocalButton.GetValue() < 0.5 ) { Train->play_sound( Train->dsbSwitch ); } +#endif // visual feedback Train->ggConverterLocalButton.UpdateValue( 1.0 ); // effect @@ -1836,10 +1994,12 @@ void TTrain::OnCommand_convertertogglelocal( TTrain *Train, command_data const & } else { //turn off +#ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggConverterLocalButton.GetValue() > 0.5 ) { Train->play_sound( Train->dsbSwitch ); } +#endif // visual feedback Train->ggConverterLocalButton.UpdateValue( 0.0 ); // effect @@ -1879,19 +2039,23 @@ void TTrain::OnCommand_converteroverloadrelayreset( TTrain *Train, command_data && ( Train->mvControlled->TrainType != dt_EZT ) ) { Train->mvControlled->ConvOvldFlag = false; } +#ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggConverterFuseButton.GetValue() < 0.5 ) { Train->play_sound( Train->dsbSwitch ); } +#endif // visual feedback Train->ggConverterFuseButton.UpdateValue( 1.0 ); } else if( Command.action == GLFW_RELEASE ) { // release +#ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggConverterFuseButton.GetValue() > 0.5 ) { Train->play_sound( Train->dsbSwitch ); } +#endif // visual feedback Train->ggConverterFuseButton.UpdateValue( 0.0 ); } @@ -1909,10 +2073,12 @@ void TTrain::OnCommand_compressortoggle( TTrain *Train, command_data const &Comm // turn on // visual feedback Train->ggCompressorButton.UpdateValue( 1.0 ); +#ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggCompressorButton.GetValue() < 0.5 ) { Train->play_sound( Train->dsbSwitch ); } +#endif // impulse type switch has no effect if there's no power // NOTE: this is most likely setup wrong, but the whole thing is smoke and mirrors anyway // (we're presuming impulse type switch for all EMUs for the time being) @@ -1925,8 +2091,10 @@ void TTrain::OnCommand_compressortoggle( TTrain *Train, command_data const &Comm else { //turn off if( true == Train->mvControlled->CompressorSwitch( false ) ) { +#ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback Train->play_sound( Train->dsbSwitch ); +#endif // NOTE: we don't have switch type definition for the compresor switch // so for the time being we have hard coded "impulse" switches for all EMUs // TODO: have proper switch type config for all switches, and put it in the cab switch descriptions, not in the .fiz @@ -1973,10 +2141,12 @@ void TTrain::OnCommand_compressortogglelocal( TTrain *Train, command_data const // only reacting to press, so the switch doesn't flip back and forth if key is held down if( false == Train->mvOccupied->CompressorAllowLocal ) { // turn on +#ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggCompressorLocalButton.GetValue() < 0.5 ) { Train->play_sound( Train->dsbSwitch ); } +#endif // visual feedback Train->ggCompressorLocalButton.UpdateValue( 1.0 ); // effect @@ -1984,10 +2154,12 @@ void TTrain::OnCommand_compressortogglelocal( TTrain *Train, command_data const } else { //turn off +#ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggCompressorLocalButton.GetValue() > 0.5 ) { Train->play_sound( Train->dsbSwitch ); } +#endif // visual feedback Train->ggCompressorLocalButton.UpdateValue( 0.0 ); // effect @@ -2027,10 +2199,12 @@ void TTrain::OnCommand_motorconnectorsopen( TTrain *Train, command_data const &C Train->mvControlled->Couplers[ 1 ].Connected->StLinSwitchOff = true; } } +#ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggStLinOffButton.GetValue() < 0.5 ) { Train->play_sound( Train->dsbSwitch ); } +#endif // visual feedback Train->ggStLinOffButton.UpdateValue( 1.0 ); // effect @@ -2074,10 +2248,12 @@ void TTrain::OnCommand_motorconnectorsopen( TTrain *Train, command_data const &C Train->mvControlled->Couplers[ 1 ].Connected->StLinSwitchOff = false; } } +#ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggStLinOffButton.GetValue() > 0.5 ) { Train->play_sound( Train->dsbSwitch ); } +#endif // visual feedback Train->ggStLinOffButton.UpdateValue( 0.0 ); } @@ -2103,10 +2279,12 @@ void TTrain::OnCommand_motorconnectorsopen( TTrain *Train, command_data const &C Train->mvControlled->Couplers[ 1 ].Connected->StLinSwitchOff = false; } } +#ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggStLinOffButton.GetValue() > 0.5 ) { Train->play_sound( Train->dsbSwitch ); } +#endif // visual feedback Train->ggStLinOffButton.UpdateValue( 0.0 ); } @@ -2123,10 +2301,14 @@ void TTrain::OnCommand_motordisconnect( TTrain *Train, command_data const &Comma } if( Command.action == GLFW_PRESS ) { +#ifdef EU07_USE_OLD_CONTROLSOUNDS if( true == Train->mvControlled->CutOffEngine() ) { // sound feedback Train->play_sound( Train->dsbSwitch ); } +#else + Train->mvControlled->CutOffEngine(); +#endif } } @@ -2139,10 +2321,12 @@ void TTrain::OnCommand_motoroverloadrelaythresholdtoggle( TTrain *Train, command if( true == Train->mvControlled->CurrentSwitch( true ) ) { // visual feedback Train->ggMaxCurrentCtrl.UpdateValue( 1.0 ); +#ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggMaxCurrentCtrl.GetValue() < 0.5 ) { Train->play_sound( Train->dsbSwitch ); } +#endif } } else { @@ -2150,10 +2334,12 @@ void TTrain::OnCommand_motoroverloadrelaythresholdtoggle( TTrain *Train, command if( true == Train->mvControlled->CurrentSwitch( false ) ) { // visual feedback Train->ggMaxCurrentCtrl.UpdateValue( 0.0 ); +#ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggMaxCurrentCtrl.GetValue() > 0.5 ) { Train->play_sound( Train->dsbSwitch ); } +#endif } } } @@ -2171,19 +2357,23 @@ void TTrain::OnCommand_motoroverloadrelayreset( TTrain *Train, command_data cons if( Command.action == GLFW_PRESS ) { // press Train->mvControlled->FuseOn(); +#ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggFuseButton.GetValue() < 0.05 ) { Train->play_sound( Train->dsbSwitch ); } +#endif // visual feedback Train->ggFuseButton.UpdateValue( 1.0 ); } else if( Command.action == GLFW_RELEASE ) { // release +#ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggFuseButton.GetValue() > 0.5 ) { Train->play_sound( Train->dsbSwitch ); } +#endif // visual feedback Train->ggFuseButton.UpdateValue( 0.0 ); } @@ -2208,20 +2398,24 @@ void TTrain::OnCommand_headlighttoggleleft( TTrain *Train, command_data const &C Train->DynamicObject->iLights[ lightsindex ] ^= TMoverParameters::light::headlight_left; // visual feedback Train->ggLeftLightButton.UpdateValue( 1.0 ); +#ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggLeftLightButton.GetValue() < 0.5 ) { Train->play_sound( Train->dsbSwitch ); } +#endif } else { //turn off Train->DynamicObject->iLights[ lightsindex ] ^= TMoverParameters::light::headlight_left; // visual feedback Train->ggLeftLightButton.UpdateValue( 0.0 ); +#ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggLeftLightButton.GetValue() > 0.5 ) { Train->play_sound( Train->dsbSwitch ); } +#endif } } } @@ -2245,20 +2439,24 @@ void TTrain::OnCommand_headlighttoggleright( TTrain *Train, command_data const & Train->DynamicObject->iLights[ lightsindex ] ^= TMoverParameters::light::headlight_right; // visual feedback Train->ggRightLightButton.UpdateValue( 1.0 ); +#ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggRightLightButton.GetValue() < 0.5 ) { Train->play_sound( Train->dsbSwitch ); } +#endif } else { //turn off Train->DynamicObject->iLights[ lightsindex ] ^= TMoverParameters::light::headlight_right; // visual feedback Train->ggRightLightButton.UpdateValue( 0.0 ); +#ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggRightLightButton.GetValue() > 0.5 ) { Train->play_sound( Train->dsbSwitch ); } +#endif } } } @@ -2282,20 +2480,24 @@ void TTrain::OnCommand_headlighttoggleupper( TTrain *Train, command_data const & Train->DynamicObject->iLights[ lightsindex ] ^= TMoverParameters::light::headlight_upper; // visual feedback Train->ggUpperLightButton.UpdateValue( 1.0 ); +#ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggUpperLightButton.GetValue() < 0.5 ) { Train->play_sound( Train->dsbSwitch ); } +#endif } else { //turn off Train->DynamicObject->iLights[ lightsindex ] ^= TMoverParameters::light::headlight_upper; // visual feedback Train->ggUpperLightButton.UpdateValue( 0.0 ); +#ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggUpperLightButton.GetValue() > 0.5 ) { Train->play_sound( Train->dsbSwitch ); } +#endif } } } @@ -2319,20 +2521,24 @@ void TTrain::OnCommand_redmarkertoggleleft( TTrain *Train, command_data const &C Train->DynamicObject->iLights[ lightsindex ] ^= TMoverParameters::light::redmarker_left; // visual feedback Train->ggLeftEndLightButton.UpdateValue( 1.0 ); +#ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggLeftEndLightButton.GetValue() < 0.5 ) { Train->play_sound( Train->dsbSwitch ); } +#endif } else { //turn off Train->DynamicObject->iLights[ lightsindex ] ^= TMoverParameters::light::redmarker_left; // visual feedback Train->ggLeftEndLightButton.UpdateValue( 0.0 ); +#ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggLeftEndLightButton.GetValue() > 0.5 ) { Train->play_sound( Train->dsbSwitch ); } +#endif } } } @@ -2356,20 +2562,24 @@ void TTrain::OnCommand_redmarkertoggleright( TTrain *Train, command_data const & Train->DynamicObject->iLights[ lightsindex ] ^= TMoverParameters::light::redmarker_right; // visual feedback Train->ggRightEndLightButton.UpdateValue( 1.0 ); +#ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggRightEndLightButton.GetValue() < 0.5 ) { Train->play_sound( Train->dsbSwitch ); } +#endif } else { //turn off Train->DynamicObject->iLights[ lightsindex ] ^= TMoverParameters::light::redmarker_right; // visual feedback Train->ggRightEndLightButton.UpdateValue( 0.0 ); +#ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggRightEndLightButton.GetValue() > 0.5 ) { Train->play_sound( Train->dsbSwitch ); } +#endif } } } @@ -2394,20 +2604,24 @@ void TTrain::OnCommand_headlighttogglerearleft( TTrain *Train, command_data cons Train->DynamicObject->iLights[ lightsindex ] ^= TMoverParameters::light::headlight_right; // visual feedback Train->ggRearLeftLightButton.UpdateValue( 1.0 ); +#ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggRearLeftLightButton.GetValue() < 0.5 ) { Train->play_sound( Train->dsbSwitch ); } +#endif } else { //turn off Train->DynamicObject->iLights[ lightsindex ] ^= TMoverParameters::light::headlight_right; // visual feedback Train->ggRearLeftLightButton.UpdateValue( 0.0 ); +#ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggRearLeftLightButton.GetValue() > 0.5 ) { Train->play_sound( Train->dsbSwitch ); } +#endif } } } @@ -2432,20 +2646,24 @@ void TTrain::OnCommand_headlighttogglerearright( TTrain *Train, command_data con Train->DynamicObject->iLights[ lightsindex ] ^= TMoverParameters::light::headlight_left; // visual feedback Train->ggRearRightLightButton.UpdateValue( 1.0 ); +#ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggRearRightLightButton.GetValue() < 0.5 ) { Train->play_sound( Train->dsbSwitch ); } +#endif } else { //turn off Train->DynamicObject->iLights[ lightsindex ] ^= TMoverParameters::light::headlight_left; // visual feedback Train->ggRearRightLightButton.UpdateValue( 0.0 ); +#ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggRearRightLightButton.GetValue() > 0.5 ) { Train->play_sound( Train->dsbSwitch ); } +#endif } } } @@ -2469,20 +2687,24 @@ void TTrain::OnCommand_headlighttogglerearupper( TTrain *Train, command_data con Train->DynamicObject->iLights[ lightsindex ] ^= TMoverParameters::light::headlight_upper; // visual feedback Train->ggRearUpperLightButton.UpdateValue( 1.0 ); +#ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggRearUpperLightButton.GetValue() < 0.5 ) { Train->play_sound( Train->dsbSwitch ); } +#endif } else { //turn off Train->DynamicObject->iLights[ lightsindex ] ^= TMoverParameters::light::headlight_upper; // visual feedback Train->ggRearUpperLightButton.UpdateValue( 0.0 ); +#ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggRearUpperLightButton.GetValue() > 0.5 ) { Train->play_sound( Train->dsbSwitch ); } +#endif } } } @@ -2507,20 +2729,24 @@ void TTrain::OnCommand_redmarkertogglerearleft( TTrain *Train, command_data cons Train->DynamicObject->iLights[ lightsindex ] ^= TMoverParameters::light::redmarker_right; // visual feedback Train->ggRearLeftEndLightButton.UpdateValue( 1.0 ); +#ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggRearLeftEndLightButton.GetValue() < 0.5 ) { Train->play_sound( Train->dsbSwitch ); } +#endif } else { //turn off Train->DynamicObject->iLights[ lightsindex ] ^= TMoverParameters::light::redmarker_right; // visual feedback Train->ggRearLeftEndLightButton.UpdateValue( 0.0 ); +#ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggRearLeftEndLightButton.GetValue() > 0.5 ) { Train->play_sound( Train->dsbSwitch ); } +#endif } } } @@ -2545,20 +2771,24 @@ void TTrain::OnCommand_redmarkertogglerearright( TTrain *Train, command_data con Train->DynamicObject->iLights[ lightsindex ] ^= TMoverParameters::light::redmarker_left; // visual feedback Train->ggRearRightEndLightButton.UpdateValue( 1.0 ); +#ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggRearRightEndLightButton.GetValue() < 0.5 ) { Train->play_sound( Train->dsbSwitch ); } +#endif } else { //turn off Train->DynamicObject->iLights[ lightsindex ] ^= TMoverParameters::light::redmarker_left; // visual feedback Train->ggRearRightEndLightButton.UpdateValue( 0.0 ); +#ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggRearRightEndLightButton.GetValue() > 0.5 ) { Train->play_sound( Train->dsbSwitch ); } +#endif } } } @@ -2579,20 +2809,24 @@ void TTrain::OnCommand_headlightsdimtoggle( TTrain *Train, command_data const &C if( false == Train->DynamicObject->DimHeadlights ) { // turn on Train->DynamicObject->DimHeadlights = true; +#ifdef EU07_USE_OLD_CONTROLSOUNDS // audio feedback if( Train->ggDimHeadlightsButton.GetValue() < 0.5 ) { Train->play_sound( Train->dsbSwitch ); } +#endif // visual feedback Train->ggDimHeadlightsButton.UpdateValue( 1.0 ); } else { //turn off Train->DynamicObject->DimHeadlights = false; +#ifdef EU07_USE_OLD_CONTROLSOUNDS // audio feedback if( Train->ggDimHeadlightsButton.GetValue() > 0.5 ) { Train->play_sound( Train->dsbSwitch ); } +#endif // visual feedback Train->ggDimHeadlightsButton.UpdateValue( 0.0 ); } @@ -2616,10 +2850,12 @@ void TTrain::OnCommand_interiorlighttoggle( TTrain *Train, command_data const &C // turn on Train->bCabLight = true; Train->btCabLight.TurnOn(); +#ifdef EU07_USE_OLD_CONTROLSOUNDS // audio feedback if( Train->ggCabLightButton.GetValue() < 0.5 ) { Train->play_sound( Train->dsbSwitch ); } +#endif // visual feedback Train->ggCabLightButton.UpdateValue( 1.0 ); } @@ -2627,10 +2863,12 @@ void TTrain::OnCommand_interiorlighttoggle( TTrain *Train, command_data const &C //turn off Train->bCabLight = false; Train->btCabLight.TurnOff(); +#ifdef EU07_USE_OLD_CONTROLSOUNDS // audio feedback if( Train->ggCabLightButton.GetValue() > 0.5 ) { Train->play_sound( Train->dsbSwitch ); } +#endif // visual feedback Train->ggCabLightButton.UpdateValue( 0.0 ); } @@ -2652,20 +2890,24 @@ void TTrain::OnCommand_interiorlightdimtoggle( TTrain *Train, command_data const if( false == Train->bCabLightDim ) { // turn on Train->bCabLightDim = true; +#ifdef EU07_USE_OLD_CONTROLSOUNDS // audio feedback if( Train->ggCabLightDimButton.GetValue() < 0.5 ) { Train->play_sound( Train->dsbSwitch ); } +#endif // visual feedback Train->ggCabLightDimButton.UpdateValue( 1.0 ); } else { //turn off Train->bCabLightDim = false; +#ifdef EU07_USE_OLD_CONTROLSOUNDS // audio feedback if( Train->ggCabLightDimButton.GetValue() > 0.5 ) { Train->play_sound( Train->dsbSwitch ); } +#endif // visual feedback Train->ggCabLightDimButton.UpdateValue( 0.0 ); } @@ -2689,20 +2931,24 @@ void TTrain::OnCommand_instrumentlighttoggle( TTrain *Train, command_data const if( false == Train->InstrumentLightActive ) { // turn on Train->InstrumentLightActive = true; +#ifdef EU07_USE_OLD_CONTROLSOUNDS // audio feedback if( Train->ggInstrumentLightButton.GetValue() < 0.5 ) { Train->play_sound( Train->dsbSwitch ); } +#endif // visual feedback Train->ggInstrumentLightButton.UpdateValue( 1.0 ); } else { //turn off Train->InstrumentLightActive = false; +#ifdef EU07_USE_OLD_CONTROLSOUNDS // audio feedback if( Train->ggInstrumentLightButton.GetValue() > 0.5 ) { Train->play_sound( Train->dsbSwitch ); } +#endif // visual feedback Train->ggInstrumentLightButton.UpdateValue( 0.0 ); } @@ -2723,20 +2969,24 @@ void TTrain::OnCommand_heatingtoggle( TTrain *Train, command_data const &Command if( false == Train->mvControlled->Heating ) { // turn on Train->mvControlled->Heating = true; +#ifdef EU07_USE_OLD_CONTROLSOUNDS // audio feedback if( Train->ggTrainHeatingButton.GetValue() < 0.5 ) { Train->play_sound( Train->dsbSwitch ); } +#endif // visual feedback Train->ggTrainHeatingButton.UpdateValue( 1.0 ); } else { //turn off Train->mvControlled->Heating = false; +#ifdef EU07_USE_OLD_CONTROLSOUNDS // audio feedback if( Train->ggTrainHeatingButton.GetValue() > 0.5 ) { Train->play_sound( Train->dsbSwitch ); } +#endif // visual feedback Train->ggTrainHeatingButton.UpdateValue( 0.0 ); } @@ -2759,19 +3009,23 @@ void TTrain::OnCommand_generictoggle( TTrain *Train, command_data const &Command // only reacting to press, so the switch doesn't flip back and forth if key is held down if( item.GetValue() < 0.25 ) { // turn on +#ifdef EU07_USE_OLD_CONTROLSOUNDS // audio feedback if( item.GetValue() < 0.5 ) { Train->play_sound( Train->dsbSwitch ); } +#endif // visual feedback item.UpdateValue( 1.0 ); } else { //turn off +#ifdef EU07_USE_OLD_CONTROLSOUNDS // audio feedback if( item.GetValue() > 0.5 ) { Train->play_sound( Train->dsbSwitch ); } +#endif // visual feedback item.UpdateValue( 0.0 ); } @@ -2794,10 +3048,12 @@ void TTrain::OnCommand_doorlocktoggle( TTrain *Train, command_data const &Comman // TODO: check wheter we really need separate flags for this Train->mvControlled->DoorSignalling = true; Train->mvOccupied->DoorBlocked = true; +#ifdef EU07_USE_OLD_CONTROLSOUNDS // audio feedback if( Train->ggDoorSignallingButton.GetValue() < 0.5 ) { Train->play_sound( Train->dsbSwitch ); } +#endif // visual feedback Train->ggDoorSignallingButton.UpdateValue( 1.0 ); } @@ -2806,10 +3062,12 @@ void TTrain::OnCommand_doorlocktoggle( TTrain *Train, command_data const &Comman // TODO: check wheter we really need separate flags for this Train->mvControlled->DoorSignalling = false; Train->mvOccupied->DoorBlocked = false; +#ifdef EU07_USE_OLD_CONTROLSOUNDS // audio feedback if( Train->ggDoorSignallingButton.GetValue() > 0.5 ) { Train->play_sound( Train->dsbSwitch ); } +#endif // visual feedback Train->ggDoorSignallingButton.UpdateValue( 0.0 ); } @@ -2831,10 +3089,12 @@ void TTrain::OnCommand_doortoggleleft( TTrain *Train, command_data const &Comman if( Train->mvOccupied->ActiveCab == 1 ) { if( Train->mvOccupied->DoorLeft( true ) ) { Train->ggDoorLeftButton.UpdateValue( 1.0 ); +#ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggDoorLeftButton.GetValue() < 0.5 ) { Train->play_sound( Train->dsbSwitch ); } +#endif Train->play_sound( Train->dsbDoorOpen ); } } @@ -2842,10 +3102,12 @@ void TTrain::OnCommand_doortoggleleft( TTrain *Train, command_data const &Comman // in the rear cab sides are reversed if( Train->mvOccupied->DoorRight( true ) ) { Train->ggDoorRightButton.UpdateValue( 1.0 ); +#ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggDoorRightButton.GetValue() < 0.5 ) { Train->play_sound( Train->dsbSwitch ); } +#endif Train->play_sound( Train->dsbDoorOpen ); } } @@ -2855,10 +3117,12 @@ void TTrain::OnCommand_doortoggleleft( TTrain *Train, command_data const &Comman if( Train->mvOccupied->ActiveCab == 1 ) { if( Train->mvOccupied->DoorLeft( false ) ) { Train->ggDoorLeftButton.UpdateValue( 0.0 ); +#ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggDoorLeftButton.GetValue() > 0.5 ) { Train->play_sound( Train->dsbSwitch ); } +#endif Train->play_sound( Train->dsbDoorClose ); } } @@ -2866,10 +3130,12 @@ void TTrain::OnCommand_doortoggleleft( TTrain *Train, command_data const &Comman // in the rear cab sides are reversed if( Train->mvOccupied->DoorRight( false ) ) { Train->ggDoorRightButton.UpdateValue( 0.0 ); +#ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggDoorRightButton.GetValue() > 0.5 ) { Train->play_sound( Train->dsbSwitch ); } +#endif Train->play_sound( Train->dsbDoorClose ); } } @@ -2892,10 +3158,12 @@ void TTrain::OnCommand_doortoggleright( TTrain *Train, command_data const &Comma if( Train->mvOccupied->ActiveCab == 1 ) { if( Train->mvOccupied->DoorRight( true ) ) { Train->ggDoorRightButton.UpdateValue( 1.0 ); +#ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggDoorRightButton.GetValue() < 0.5 ) { Train->play_sound( Train->dsbSwitch ); } +#endif Train->play_sound( Train->dsbDoorOpen ); } } @@ -2903,10 +3171,12 @@ void TTrain::OnCommand_doortoggleright( TTrain *Train, command_data const &Comma // in the rear cab sides are reversed if( Train->mvOccupied->DoorLeft( true ) ) { Train->ggDoorLeftButton.UpdateValue( 1.0 ); +#ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggDoorLeftButton.GetValue() < 0.5 ) { Train->play_sound( Train->dsbSwitch ); } +#endif Train->play_sound( Train->dsbDoorOpen ); } } @@ -2916,10 +3186,12 @@ void TTrain::OnCommand_doortoggleright( TTrain *Train, command_data const &Comma if( Train->mvOccupied->ActiveCab == 1 ) { if( Train->mvOccupied->DoorRight( false ) ) { Train->ggDoorRightButton.UpdateValue( 0.0 ); +#ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggDoorRightButton.GetValue() > 0.5 ) { Train->play_sound( Train->dsbSwitch ); } +#endif Train->play_sound( Train->dsbDoorClose ); } } @@ -2927,10 +3199,12 @@ void TTrain::OnCommand_doortoggleright( TTrain *Train, command_data const &Comma // in the rear cab sides are reversed if( Train->mvOccupied->DoorLeft( false ) ) { Train->ggDoorLeftButton.UpdateValue( 0.0 ); +#ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggDoorLeftButton.GetValue() > 0.5 ) { Train->play_sound( Train->dsbSwitch ); } +#endif Train->play_sound( Train->dsbDoorClose ); } } @@ -2952,10 +3226,12 @@ void TTrain::OnCommand_departureannounce( TTrain *Train, command_data const &Com if( false == Train->mvControlled->DepartureSignal ) { // turn on Train->mvControlled->DepartureSignal = true; +#ifdef EU07_USE_OLD_CONTROLSOUNDS // audio feedback if( Train->ggDepartureSignalButton.GetValue() < 0.5 ) { Train->play_sound( Train->dsbSwitch ); } +#endif // visual feedback Train->ggDepartureSignalButton.UpdateValue( 1.0 ); } @@ -2963,10 +3239,12 @@ void TTrain::OnCommand_departureannounce( TTrain *Train, command_data const &Com else if( Command.action == GLFW_RELEASE ) { // turn off Train->mvControlled->DepartureSignal = false; +#ifdef EU07_USE_OLD_CONTROLSOUNDS // audio feedback if( Train->ggDepartureSignalButton.GetValue() > 0.5 ) { Train->play_sound( Train->dsbSwitch ); } +#endif // visual feedback Train->ggDepartureSignalButton.UpdateValue( 0.0 ); } @@ -2993,11 +3271,13 @@ void TTrain::OnCommand_hornlowactivate( TTrain *Train, command_data const &Comma Train->mvControlled->WarningSignal &= ~2; } */ +#ifdef EU07_USE_OLD_CONTROLSOUNDS // audio feedback if( ( Train->ggHornButton.GetValue() > -0.5 ) || ( Train->ggHornLowButton.GetValue() < 0.5 ) ) { Train->play_sound( Train->dsbSwitch ); } +#endif // visual feedback Train->ggHornButton.UpdateValue( -1.0 ); Train->ggHornLowButton.UpdateValue( 1.0 ); @@ -3010,11 +3290,13 @@ void TTrain::OnCommand_hornlowactivate( TTrain *Train, command_data const &Comma Train->mvOccupied->WarningSignal &= ~( 1 | 2 ); */ Train->mvOccupied->WarningSignal &= ~1; +#ifdef EU07_USE_OLD_CONTROLSOUNDS // audio feedback if( ( Train->ggHornButton.GetValue() < -0.5 ) || ( Train->ggHornLowButton.GetValue() > 0.5 ) ) { Train->play_sound( Train->dsbSwitch ); } +#endif // visual feedback Train->ggHornButton.UpdateValue( 0.0 ); Train->ggHornLowButton.UpdateValue( 0.0 ); @@ -3042,10 +3324,12 @@ void TTrain::OnCommand_hornhighactivate( TTrain *Train, command_data const &Comm Train->mvControlled->WarningSignal &= ~1; } */ +#ifdef EU07_USE_OLD_CONTROLSOUNDS // audio feedback if( Train->ggHornButton.GetValue() < 0.5 ) { Train->play_sound( Train->dsbSwitch ); } +#endif // visual feedback Train->ggHornButton.UpdateValue( 1.0 ); Train->ggHornHighButton.UpdateValue( 1.0 ); @@ -3058,10 +3342,12 @@ void TTrain::OnCommand_hornhighactivate( TTrain *Train, command_data const &Comm Train->mvOccupied->WarningSignal &= ~( 1 | 2 ); */ Train->mvOccupied->WarningSignal &= ~2; +#ifdef EU07_USE_OLD_CONTROLSOUNDS // audio feedback if( Train->ggHornButton.GetValue() > 0.5 ) { Train->play_sound( Train->dsbSwitch ); } +#endif // visual feedback Train->ggHornButton.UpdateValue( 0.0 ); Train->ggHornHighButton.UpdateValue( 0.0 ); @@ -3085,20 +3371,24 @@ void TTrain::OnCommand_radiotoggle( TTrain *Train, command_data const &Command ) if( false == Train->mvOccupied->Radio ) { // turn on Train->mvOccupied->Radio = true; +#ifdef EU07_USE_OLD_CONTROLSOUNDS // audio feedback if( Train->ggRadioButton.GetValue() < 0.5 ) { Train->play_sound( Train->dsbSwitch ); } +#endif // visual feedback Train->ggRadioButton.UpdateValue( 1.0 ); } else { // turn off Train->mvOccupied->Radio = false; +#ifdef EU07_USE_OLD_CONTROLSOUNDS // audio feedback if( Train->ggRadioButton.GetValue() > 0.5 ) { Train->play_sound( Train->dsbSwitch ); } +#endif // visual feedback Train->ggRadioButton.UpdateValue( 0.0 ); } @@ -6452,8 +6742,7 @@ bool TTrain::InitializeCab(int NewCabNo, std::string const &asFileName) { // ABu: wstawione warunki, wczesniej tylko to: // str=Parser->GetNextSymbol().LowerCase(); - if (parse == true) - { + if (parse == true) { token = ""; parser->getTokens(); @@ -7032,9 +7321,9 @@ void TTrain::set_cab_controls() { // TODO: refactor the cabin controls into some sensible structure bool TTrain::initialize_button(cParser &Parser, std::string const &Label, int const Cabindex) { - +/* TButton *bt; // roboczy wskaźnik na obiekt animujący lampkę - +*/ // SEKCJA LAMPEK if (Label == "i-maxft:") { @@ -7250,9 +7539,9 @@ bool TTrain::initialize_button(cParser &Parser, std::string const &Label, int co else if (Label == "i-doors:") { int i = Parser.getToken() - 1; - bt = Cabine[Cabindex].Button(-1); // pierwsza wolna lampka - bt->Load(Parser, DynamicObject->mdKabina); - bt->AssignBool(bDoors[0] + 3 * i); + auto &button = Cabine[Cabindex].Button(-1); // pierwsza wolna lampka + button.Load(Parser, DynamicObject->mdKabina); + button.AssignBool(bDoors[0] + 3 * i); } else { @@ -7269,7 +7558,9 @@ bool TTrain::initialize_button(cParser &Parser, std::string const &Label, int co // TODO: refactor the cabin controls into some sensible structure bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int const Cabindex) { +/* TGauge *gg { nullptr }; // roboczy wskaźnik na obiekt animujący gałkę +*/ std::unordered_map gauges = { { "mainctrl:", ggMainCtrl }, { "scndctrl:", ggScndCtrl }, @@ -7350,73 +7641,55 @@ bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int con else if( Label == "mainctrlact:" ) { ggMainCtrlAct.Load( Parser, DynamicObject->mdKabina, DynamicObject->mdModel ); } -/* - else if (Label == "universal1:") - { - ggUniversal1Button.Load(Parser, DynamicObject->mdKabina, DynamicObject->mdModel); - } - else if (Label == "universal2:") - { - ggUniversal2Button.Load(Parser, DynamicObject->mdKabina, DynamicObject->mdModel); - } - else if (Label == "universal3:") - { - ggInstrumentLightButton.Load(Parser, DynamicObject->mdKabina, DynamicObject->mdModel); - } - else if (Label == "universal4:") - { - ggUniversal4Button.Load(Parser, DynamicObject->mdKabina, DynamicObject->mdModel); - } -*/ // SEKCJA WSKAZNIKOW else if ((Label == "tachometer:") || (Label == "tachometerb:")) { // predkosciomierz wskaźnikowy z szarpaniem - gg = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka - gg->Load(Parser, DynamicObject->mdKabina); - gg->AssignFloat(&fTachoVelocityJump); + auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka + gauge.Load(Parser, DynamicObject->mdKabina); + gauge.AssignFloat(&fTachoVelocityJump); } else if (Label == "tachometern:") { // predkosciomierz wskaźnikowy bez szarpania - gg = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka - gg->Load(Parser, DynamicObject->mdKabina); - gg->AssignFloat(&fTachoVelocity); + auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka + gauge.Load(Parser, DynamicObject->mdKabina); + gauge.AssignFloat(&fTachoVelocity); } else if (Label == "tachometerd:") { // predkosciomierz cyfrowy - gg = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka - gg->Load(Parser, DynamicObject->mdKabina); - gg->AssignFloat(&fTachoVelocity); + auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka + gauge.Load(Parser, DynamicObject->mdKabina); + gauge.AssignFloat(&fTachoVelocity); } else if ((Label == "hvcurrent1:") || (Label == "hvcurrent1b:")) { // 1szy amperomierz - gg = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka - gg->Load(Parser, DynamicObject->mdKabina); - gg->AssignFloat(fHCurrent + 1); + auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka + gauge.Load(Parser, DynamicObject->mdKabina); + gauge.AssignFloat(fHCurrent + 1); } else if ((Label == "hvcurrent2:") || (Label == "hvcurrent2b:")) { // 2gi amperomierz - gg = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka - gg->Load(Parser, DynamicObject->mdKabina); - gg->AssignFloat(fHCurrent + 2); + auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka + gauge.Load(Parser, DynamicObject->mdKabina); + gauge.AssignFloat(fHCurrent + 2); } else if ((Label == "hvcurrent3:") || (Label == "hvcurrent3b:")) { // 3ci amperomierz - gg = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałska - gg->Load(Parser, DynamicObject->mdKabina); - gg->AssignFloat(fHCurrent + 3); + auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałska + gauge.Load(Parser, DynamicObject->mdKabina); + gauge.AssignFloat(fHCurrent + 3); } else if ((Label == "hvcurrent:") || (Label == "hvcurrentb:")) { // amperomierz calkowitego pradu - gg = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka - gg->Load(Parser, DynamicObject->mdKabina); - gg->AssignFloat(fHCurrent); + auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka + gauge.Load(Parser, DynamicObject->mdKabina); + gauge.AssignFloat(fHCurrent); } else if (Label == "eimscreen:") { @@ -7424,9 +7697,9 @@ bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int con int i, j; Parser.getTokens(2, false); Parser >> i >> j; - gg = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka - gg->Load(Parser, DynamicObject->mdKabina); - gg->AssignFloat(&fEIMParams[i][j]); + auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka + gauge.Load(Parser, DynamicObject->mdKabina); + gauge.AssignFloat(&fEIMParams[i][j]); } else if (Label == "brakes:") { @@ -7434,43 +7707,43 @@ bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int con int i, j; Parser.getTokens(2, false); Parser >> i >> j; - gg = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka - gg->Load(Parser, DynamicObject->mdKabina); - gg->AssignFloat(&fPress[i - 1][j]); + auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka + gauge.Load(Parser, DynamicObject->mdKabina); + gauge.AssignFloat(&fPress[i - 1][j]); } else if ((Label == "brakepress:") || (Label == "brakepressb:")) { // manometr cylindrow hamulcowych // Ra 2014-08: przeniesione do TCab - gg = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka - gg->Load(Parser, DynamicObject->mdKabina, NULL, 0.1); - gg->AssignDouble(&mvOccupied->BrakePress); + auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka + gauge.Load(Parser, DynamicObject->mdKabina, nullptr, 0.1); + gauge.AssignDouble(&mvOccupied->BrakePress); } else if ((Label == "pipepress:") || (Label == "pipepressb:")) { // manometr przewodu hamulcowego - TGauge *gg = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka - gg->Load(Parser, DynamicObject->mdKabina, NULL, 0.1); - gg->AssignDouble(&mvOccupied->PipePress); + auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka + gauge.Load(Parser, DynamicObject->mdKabina, nullptr, 0.1); + gauge.AssignDouble(&mvOccupied->PipePress); } else if (Label == "limpipepress:") { // manometr zbiornika sterujacego zaworu maszynisty - ggZbS.Load(Parser, DynamicObject->mdKabina, NULL, 0.1); + ggZbS.Load(Parser, DynamicObject->mdKabina, nullptr, 0.1); } else if (Label == "cntrlpress:") { // manometr zbiornika kontrolnego/rorzďż˝du - gg = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka - gg->Load(Parser, DynamicObject->mdKabina, NULL, 0.1); - gg->AssignDouble(&mvControlled->PantPress); + auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka + gauge.Load(Parser, DynamicObject->mdKabina, nullptr, 0.1); + gauge.AssignDouble(&mvControlled->PantPress); } else if ((Label == "compressor:") || (Label == "compressorb:")) { // manometr sprezarki/zbiornika glownego - gg = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka - gg->Load(Parser, DynamicObject->mdKabina, NULL, 0.1); - gg->AssignDouble(&mvOccupied->Compressor); + auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka + gauge.Load(Parser, DynamicObject->mdKabina, nullptr, 0.1); + gauge.AssignDouble(&mvOccupied->Compressor); } // yB - dla drugiej sekcji else if (Label == "hvbcurrent1:") @@ -7500,12 +7773,9 @@ bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int con if (Parser.getToken() == "analog") { // McZapkie-300302: zegarek - ggClockSInd.Init(DynamicObject->mdKabina->GetFromName("ClockShand"), gt_Rotate, - 0.016666667, 0, 0); - ggClockMInd.Init(DynamicObject->mdKabina->GetFromName("ClockMhand"), gt_Rotate, - 0.016666667, 0, 0); - ggClockHInd.Init(DynamicObject->mdKabina->GetFromName("ClockHhand"), gt_Rotate, - 0.083333333, 0, 0); + ggClockSInd.Init(DynamicObject->mdKabina->GetFromName("ClockShand"), gt_Rotate, 1.0/60.0, 0, 0); + ggClockMInd.Init(DynamicObject->mdKabina->GetFromName("ClockMhand"), gt_Rotate, 1.0/60.0, 0, 0); + ggClockHInd.Init(DynamicObject->mdKabina->GetFromName("ClockHhand"), gt_Rotate, 1.0/12.0, 0, 0); } } else if (Label == "evoltage:") @@ -7516,9 +7786,9 @@ bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int con else if (Label == "hvoltage:") { // woltomierz wysokiego napiecia - gg = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka - gg->Load(Parser, DynamicObject->mdKabina); - gg->AssignFloat(&fHVoltage); + auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka + gauge.Load(Parser, DynamicObject->mdKabina); + gauge.AssignFloat(&fHVoltage); } else if (Label == "lvoltage:") { @@ -7528,29 +7798,29 @@ bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int con else if (Label == "enrot1m:") { // obrotomierz - gg = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka - gg->Load(Parser, DynamicObject->mdKabina); - gg->AssignFloat(fEngine + 1); + auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka + gauge.Load(Parser, DynamicObject->mdKabina); + gauge.AssignFloat(fEngine + 1); } // ggEnrot1m.Load(Parser,DynamicObject->mdKabina); else if (Label == "enrot2m:") { // obrotomierz - gg = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka - gg->Load(Parser, DynamicObject->mdKabina); - gg->AssignFloat(fEngine + 2); + auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka + gauge.Load(Parser, DynamicObject->mdKabina); + gauge.AssignFloat(fEngine + 2); } // ggEnrot2m.Load(Parser,DynamicObject->mdKabina); else if (Label == "enrot3m:") { // obrotomierz - gg = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka - gg->Load(Parser, DynamicObject->mdKabina); - gg->AssignFloat(fEngine + 3); + auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka + gauge.Load(Parser, DynamicObject->mdKabina); + gauge.AssignFloat(fEngine + 3); } // ggEnrot3m.Load(Parser,DynamicObject->mdKabina); else if (Label == "engageratio:") { // np. ciśnienie sterownika sprzęgła - gg = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka - gg->Load(Parser, DynamicObject->mdKabina); - gg->AssignDouble(&mvControlled->dizel_engage); + auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka + gauge.Load(Parser, DynamicObject->mdKabina); + gauge.AssignDouble(&mvControlled->dizel_engage); } // ggEngageRatio.Load(Parser,DynamicObject->mdKabina); else if (Label == "maingearstatus:") { @@ -7564,9 +7834,9 @@ bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int con else if (Label == "distcounter:") { // Ra 2014-07: licznik kilometrów - gg = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka - gg->Load(Parser, DynamicObject->mdKabina); - gg->AssignDouble(&mvControlled->DistCounter); + auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka + gauge.Load(Parser, DynamicObject->mdKabina); + gauge.AssignDouble(&mvControlled->DistCounter); } else { diff --git a/Train.h b/Train.h index 6d8fcef9..c9c9e6d2 100644 --- a/Train.h +++ b/Train.h @@ -34,8 +34,9 @@ class TCab public: TCab(); ~TCab(); - void Init(double Initx1, double Inity1, double Initz1, double Initx2, double Inity2, - double Initz2, bool InitEnabled, bool InitOccupied); +/* + void Init(double Initx1, double Inity1, double Initz1, double Initx2, double Inity2, double Initz2, bool InitEnabled, bool InitOccupied); +*/ void Load(cParser &Parser); vector3 CabPos1; vector3 CabPos2; @@ -43,17 +44,19 @@ class TCab bool bOccupied; double dimm_r, dimm_g, dimm_b; // McZapkie-120503: tlumienie swiatla double intlit_r, intlit_g, intlit_b; // McZapkie-120503: oswietlenie kabiny - double intlitlow_r, intlitlow_g, - intlitlow_b; // McZapkie-120503: przyciemnione oswietlenie kabiny + double intlitlow_r, intlitlow_g, intlitlow_b; // McZapkie-120503: przyciemnione oswietlenie kabiny private: - // bool bChangePossible; +/* TGauge *ggList; // Ra 2014-08: lista animacji macierzowych (gałek) w kabinie int iGaugesMax, iGauges; // ile miejsca w tablicy i ile jest w użyciu TButton *btList; // Ra 2014-08: lista animacji dwustanowych (lampek) w kabinie int iButtonsMax, iButtons; // ile miejsca w tablicy i ile jest w użyciu +*/ + std::vector ggList; + std::vector btList; public: - TGauge *Gauge(int n = -1); // pobranie adresu obiektu - TButton *Button(int n = -1); // pobranie adresu obiektu + TGauge &Gauge(int n = -1); // pobranie adresu obiektu + TButton &Button(int n = -1); // pobranie adresu obiektu void Update(); }; @@ -103,11 +106,9 @@ class TTrain // sets cabin controls based on current state of the vehicle // NOTE: we can get rid of this function once we have per-cab persistent state void set_cab_controls(); - // initializes a gauge matching provided label. returns: true if the label was found, false - // otherwise + // initializes a gauge matching provided label. returns: true if the label was found, false otherwise bool initialize_gauge(cParser &Parser, std::string const &Label, int const Cabindex); - // initializes a button matching provided label. returns: true if the label was found, false - // otherwise + // initializes a button matching provided label. returns: true if the label was found, false otherwise bool initialize_button(cParser &Parser, std::string const &Label, int const Cabindex); // plays specified sound, or fallback sound if the primary sound isn't presend // NOTE: temporary routine until sound system is sorted out and paired with switches @@ -209,12 +210,7 @@ public: // reszta może by?publiczna TGauge ggClockSInd; TGauge ggClockMInd; TGauge ggClockHInd; - // TGauge ggHVoltage; TGauge ggLVoltage; - // TGauge ggEnrot1m; - // TGauge ggEnrot2m; - // TGauge ggEnrot3m; - // TGauge ggEngageRatio; TGauge ggMainGearStatus; TGauge ggEngineVoltage; @@ -277,13 +273,7 @@ public: // reszta może by?publiczna TGauge ggHornLowButton; TGauge ggHornHighButton; TGauge ggNextCurrentButton; -/* - // ABu 090305 - uniwersalne przyciski - TGauge ggUniversal1Button; - TGauge ggUniversal2Button; - TGauge ggUniversal4Button; - bool Universal4Active; -*/ + std::array ggUniversals; // NOTE: temporary arrangement until we have dynamically built control table TGauge ggInstrumentLightButton; @@ -336,7 +326,6 @@ public: // reszta może by?publiczna TButton btLampkaRadio; TButton btLampkaHamowanie1zes; TButton btLampkaHamowanie2zes; - // TButton btLampkaUnknown; TButton btLampkaOpory; TButton btLampkaWysRozr; TButton btInstrumentLight; @@ -363,8 +352,6 @@ public: // reszta może by?publiczna TButton btLampkaBoczniki; TButton btLampkaMaxSila; TButton btLampkaPrzekrMaxSila; - // TButton bt; - // TButton btLampkaDoorLeft; TButton btLampkaDoorRight; TButton btLampkaDepartureSignal; @@ -439,8 +426,6 @@ public: // reszta może by?publiczna PSound dsbHasler; PSound dsbBuzzer; PSound dsbSlipAlarm; // Bombardier 011010: alarm przy poslizgu dla 181/182 - // TFadeSound sConverter; //przetwornica - // TFadeSound sSmallCompressor; //przetwornica int iCabLightFlag; // McZapkie:120503: oswietlenie kabiny (0: wyl, 1: przyciemnione, 2: pelne) bool bCabLight; // hunter-091012: czy swiatlo jest zapalone? @@ -454,11 +439,6 @@ public: // reszta może by?publiczna PSound dsbCouplerStretch; PSound dsbEN57_CouplerStretch; PSound dsbBufferClamp; - // TSubModel *smCzuwakShpOn; - // TSubModel *smCzuwakOn; - // TSubModel *smShpOn; - // TSubModel *smCzuwakShpOff; - // double fCzuwakTimer; double fBlinkTimer; float fHaslerTimer; float fConverterTimer; // hunter-261211: dla przekaznika diff --git a/TrkFoll.cpp b/TrkFoll.cpp index d610058e..77c0adf4 100644 --- a/TrkFoll.cpp +++ b/TrkFoll.cpp @@ -114,7 +114,7 @@ bool TTrackFollower::Move(double fDistance, bool bPrimary) { // omijamy cały ten blok, gdy tor nie ma on żadnych eventów (większość nie ma) if (fDistance < 0) { - if (iSetFlag(iEventFlag, -1)) // zawsze zeruje flagę sprawdzenia, jak mechanik + if (SetFlag(iEventFlag, -1)) // zawsze zeruje flagę sprawdzenia, jak mechanik // dosiądzie, to się nie wykona if (Owner->Mechanik->Primary()) // tylko dla jednego członu // if (TestFlag(iEventFlag,1)) //McZapkie-280503: wyzwalanie event tylko dla @@ -126,7 +126,7 @@ bool TTrackFollower::Move(double fDistance, bool bPrimary) // Owner->RaAxleEvent(pCurrentTrack->Event1); //Ra: dynamic zdecyduje, czy dodać do // kolejki // if (TestFlag(iEventallFlag,1)) - if (iSetFlag(iEventallFlag, + if (SetFlag(iEventallFlag, -1)) // McZapkie-280503: wyzwalanie eventall dla wszystkich pojazdow if (bPrimary && pCurrentTrack->evEventall1 && (!pCurrentTrack->evEventall1->iQueued)) @@ -136,7 +136,7 @@ bool TTrackFollower::Move(double fDistance, bool bPrimary) } else if (fDistance > 0) { - if (iSetFlag(iEventFlag, -2)) // zawsze ustawia flagę sprawdzenia, jak mechanik + if (SetFlag(iEventFlag, -2)) // zawsze ustawia flagę sprawdzenia, jak mechanik // dosiądzie, to się nie wykona if (Owner->Mechanik->Primary()) // tylko dla jednego członu // if (TestFlag(iEventFlag,2)) //sprawdzanie jest od razu w pierwszym @@ -147,7 +147,7 @@ bool TTrackFollower::Move(double fDistance, bool bPrimary) // Owner->RaAxleEvent(pCurrentTrack->Event2); //Ra: dynamic zdecyduje, czy dodać do // kolejki // if (TestFlag(iEventallFlag,2)) - if (iSetFlag(iEventallFlag, + if (SetFlag(iEventallFlag, -2)) // sprawdza i zeruje na przyszłość, true jeśli zmieni z 2 na 0 if (bPrimary && pCurrentTrack->evEventall2 && (!pCurrentTrack->evEventall2->iQueued)) diff --git a/parser.h b/parser.h index 7582c0e1..b8176c0a 100644 --- a/parser.h +++ b/parser.h @@ -33,29 +33,28 @@ class cParser //: public std::stringstream virtual ~cParser(); // methods: template - cParser& + cParser & operator>>( Type_ &Right ); template <> - cParser& + cParser & operator>>( std::string &Right ); template <> - cParser& + cParser & operator>>( bool &Right ); - template - _Output - getToken( bool const ToLower = true ) - { - getTokens( 1, ToLower ); - _Output output; - *this >> output; - return output; - }; + template + Output_ + getToken( bool const ToLower = true, const char *Break = "\n\r\t ;" ) { + getTokens( 1, ToLower, Break ); + Output_ output; + *this >> output; + return output; }; template <> bool - getToken( bool const ToLower ) { - - return ( getToken() == "true" ); - } + getToken( bool const ToLower, const char *Break ) { + auto const token = getToken( true, Break ); + return ( ( token == "true" ) + || ( token == "yes" ) + || ( token == "1" ) ); } inline void ignoreToken() { readToken(); @@ -77,7 +76,13 @@ class cParser //: public std::stringstream { return !mStream->fail(); }; - bool getTokens(unsigned int Count = 1, bool ToLower = true, const char *Break = "\n\r\t ;"); + bool getTokens(unsigned int Count = 1, bool ToLower = true, char const *Break = "\n\r\t ;"); + // returns next incoming token, if any, without removing it from the set + std::string peek() const { + return ( + false == tokens.empty() ? + tokens.front() : + "" ); } // returns percentage of file processed so far int getProgress() const; int getFullProgress() const; diff --git a/uilayer.cpp b/uilayer.cpp index e6ca85c5..0a98e41b 100644 --- a/uilayer.cpp +++ b/uilayer.cpp @@ -44,7 +44,7 @@ ui_layer::init( GLFWwindow *Window ) { DEFAULT_PITCH | FF_DONTCARE, // family and pitch "Lucida Console"); // font name ::SelectObject(hDC, font); // selects the font we want - if( true == ::wglUseFontBitmaps( hDC, 32, 96, m_fontbase ) ) { + if( TRUE == ::wglUseFontBitmaps( hDC, 32, 96, m_fontbase ) ) { // builds 96 characters starting at character 32 WriteLog( "Display Lists font used" ); //+AnsiString(glGetError()) WriteLog( "Font init OK" ); //+AnsiString(glGetError()) @@ -151,8 +151,8 @@ ui_layer::render_progress() { Global::iWindowWidth ); float const heightratio = ( screenratio >= ( 4.0f / 3.0f ) ? - Global::iWindowHeight / 768.0 : - Global::iWindowHeight / 768.0 * screenratio / ( 4.0f / 3.0f ) ); + Global::iWindowHeight / 768.f : + Global::iWindowHeight / 768.f * screenratio / ( 4.0f / 3.0f ) ); float const height = 768.0f * heightratio; ::glColor4f( 216.0f / 255.0f, 216.0f / 255.0f, 216.0f / 255.0f, 1.0f ); @@ -176,8 +176,8 @@ ui_layer::render_panels() { glPushAttrib( GL_ENABLE_BIT ); glDisable( GL_TEXTURE_2D ); - float const width = std::min( 4.0f / 3.0f, static_cast(Global::iWindowWidth) / std::max( 1, Global::iWindowHeight ) ) * Global::iWindowHeight; - float const height = Global::iWindowHeight / 768.0; + float const width = std::min( 4.f / 3.f, static_cast(Global::iWindowWidth) / std::max( 1, Global::iWindowHeight ) ) * Global::iWindowHeight; + float const height = Global::iWindowHeight / 768.f; for( auto const &panel : m_panels ) { @@ -186,8 +186,8 @@ ui_layer::render_panels() { ::glColor4fv( &line.color.x ); ::glRasterPos2f( - 0.5 * ( Global::iWindowWidth - width ) + panel->origin_x * height, - panel->origin_y * height + 20.0 * lineidx ); + 0.5f * ( Global::iWindowWidth - width ) + panel->origin_x * height, + panel->origin_y * height + 20.f * lineidx ); print( line.data ); ++lineidx; } @@ -255,14 +255,14 @@ ui_layer::quad( float4 const &Coordinates, float4 const &Color ) { float const screenratio = static_cast( Global::iWindowWidth ) / Global::iWindowHeight; float const width = - ( screenratio >= (4.0f/3.0f) ? - ( 4.0f / 3.0f ) * Global::iWindowHeight : + ( screenratio >= ( 4.f / 3.f ) ? + ( 4.f / 3.f ) * Global::iWindowHeight : Global::iWindowWidth ); float const heightratio = - ( screenratio >= ( 4.0f / 3.0f ) ? - Global::iWindowHeight / 768.0 : - Global::iWindowHeight / 768.0 * screenratio / ( 4.0f / 3.0f ) ); - float const height = 768.0f * heightratio; + ( screenratio >= ( 4.f / 3.f ) ? + Global::iWindowHeight / 768.f : + Global::iWindowHeight / 768.f * screenratio / ( 4.f / 3.f ) ); + float const height = 768.f * heightratio; /* float const heightratio = Global::iWindowHeight / 768.0f; float const height = 768.0f * heightratio; @@ -272,10 +272,10 @@ ui_layer::quad( float4 const &Coordinates, float4 const &Color ) { glBegin( GL_TRIANGLE_STRIP ); - glTexCoord2f( 0.0f, 1.0f ); glVertex2f( 0.5 * ( Global::iWindowWidth - width ) + Coordinates.x * heightratio, 0.5 * ( Global::iWindowHeight - height ) + Coordinates.y * heightratio ); - glTexCoord2f( 0.0f, 0.0f ); glVertex2f( 0.5 * ( Global::iWindowWidth - width ) + Coordinates.x * heightratio, 0.5 * ( Global::iWindowHeight - height ) + Coordinates.w * heightratio ); - glTexCoord2f( 1.0f, 1.0f ); glVertex2f( 0.5 * ( Global::iWindowWidth - width ) + Coordinates.z * heightratio, 0.5 * ( Global::iWindowHeight - height ) + Coordinates.y * heightratio ); - glTexCoord2f( 1.0f, 0.0f ); glVertex2f( 0.5 * ( Global::iWindowWidth - width ) + Coordinates.z * heightratio, 0.5 * ( Global::iWindowHeight - height ) + Coordinates.w * heightratio ); + glTexCoord2f( 0.f, 1.f ); glVertex2f( 0.5f * ( Global::iWindowWidth - width ) + Coordinates.x * heightratio, 0.5f * ( Global::iWindowHeight - height ) + Coordinates.y * heightratio ); + glTexCoord2f( 0.f, 0.f ); glVertex2f( 0.5f * ( Global::iWindowWidth - width ) + Coordinates.x * heightratio, 0.5f * ( Global::iWindowHeight - height ) + Coordinates.w * heightratio ); + glTexCoord2f( 1.f, 1.f ); glVertex2f( 0.5f * ( Global::iWindowWidth - width ) + Coordinates.z * heightratio, 0.5f * ( Global::iWindowHeight - height ) + Coordinates.y * heightratio ); + glTexCoord2f( 1.f, 0.f ); glVertex2f( 0.5f * ( Global::iWindowWidth - width ) + Coordinates.z * heightratio, 0.5f * ( Global::iWindowHeight - height ) + Coordinates.w * heightratio ); glEnd(); } diff --git a/version.h b/version.h index 2fe8cfad..53cafe07 100644 --- a/version.h +++ b/version.h @@ -1,5 +1,5 @@ #pragma once #define VERSION_MAJOR 17 -#define VERSION_MINOR 712 +#define VERSION_MINOR 714 #define VERSION_REVISION 0 From d51a4ea985a7518e3041cbc996989e839e9e3edb Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Sun, 16 Jul 2017 01:57:22 +0200 Subject: [PATCH 6/6] build 170715. custom sounds for cab lights, optional fallback on legacy sounds for controls without their own sound definitions --- Button.cpp | 158 ++++++++++++++++++------- Button.h | 75 ++++++------ Gauge.cpp | 2 +- Gauge.h | 5 +- Train.cpp | 323 ++++++++++++++++++++++++++++----------------------- renderer.cpp | 4 +- version.h | 2 +- 7 files changed, 338 insertions(+), 231 deletions(-) diff --git a/Button.cpp b/Button.cpp index b6ed1d3f..4af9a652 100644 --- a/Button.cpp +++ b/Button.cpp @@ -9,11 +9,11 @@ http://mozilla.org/MPL/2.0/. #include "stdafx.h" #include "Button.h" +#include "parser.h" +#include "Model3d.h" #include "Console.h" #include "logs.h" -//--------------------------------------------------------------------------- - TButton::TButton() { iFeedbackBit = 0; @@ -21,13 +21,11 @@ TButton::TButton() Clear(); }; -TButton::~TButton(){}; - void TButton::Clear(int i) { - pModelOn = NULL; - pModelOff = NULL; - bOn = false; + pModelOn = nullptr; + pModelOff = nullptr; + m_state = false; if (i >= 0) FeedbackBitSet(i); Update(); // kasowanie bitu Feedback, o ile jakiś ustawiony @@ -35,52 +33,134 @@ void TButton::Clear(int i) void TButton::Init(std::string const &asName, TModel3d *pModel, bool bNewOn) { - if (!pModel) - return; // nie ma w czym szukać + if( pModel == nullptr ) { return; } + pModelOn = pModel->GetFromName( (asName + "_on").c_str() ); pModelOff = pModel->GetFromName( (asName + "_off").c_str() ); - bOn = bNewOn; + m_state = bNewOn; Update(); }; -void TButton::Load(cParser &Parser, TModel3d *pModel1, TModel3d *pModel2) -{ - std::string const token = Parser.getToken(); - if (pModel1) - { // poszukiwanie submodeli w modelu - Init(token, pModel1, false); - if (pModel2) - if (!pModelOn && !pModelOff) - Init(token, pModel2, false); // może w drugim będzie (jak nie w kabinie, - // to w zewnętrznym) - } - else - { - pModelOn = NULL; - pModelOff = NULL; +void TButton::Load(cParser &Parser, TModel3d *pModel1, TModel3d *pModel2) { - ErrorLog( "Failed to locate sub-model \"" + token + "\" in 3d model \"" + pModel1->NameGet() + "\"" ); + std::string submodelname; + + Parser.getTokens(); + if( Parser.peek() != "{" ) { + // old fixed size config + Parser >> submodelname; } + else { + // new, block type config + // TODO: rework the base part into yaml-compatible flow style mapping + cParser mappingparser( Parser.getToken( false, "}" ) ); + submodelname = mappingparser.getToken( false ); + // new, variable length section + while( true == Load_mapping( mappingparser ) ) { + ; // all work done by while() + } + } + + if( pModel1 ) { + // poszukiwanie submodeli w modelu + Init( submodelname, pModel1, false ); + if( ( pModelOn != nullptr ) || ( pModelOff != nullptr ) ) { + // we got our models, bail out + return; + } + } + if( pModel2 ) { + // poszukiwanie submodeli w modelu + Init( submodelname, pModel2, false ); + if( ( pModelOn != nullptr ) || ( pModelOff != nullptr ) ) { + // we got our models, bail out + return; + } + } + // if we failed to locate even one state submodel, cry + ErrorLog( "Failed to locate sub-model \"" + submodelname + "\" in 3d model \"" + pModel1->NameGet() + "\"" ); }; -void TButton::Update() -{ - if (bData != NULL) - bOn = (*bData); - if (pModelOn) - pModelOn->iVisible = bOn; - if (pModelOff) - pModelOff->iVisible = !bOn; - if (iFeedbackBit) // jeżeli generuje informację zwrotną - { - if (bOn) // zapalenie +bool +TButton::Load_mapping( cParser &Input ) { + + if( false == Input.getTokens( 2, true, ", " ) ) { + return false; + } + + std::string key, value; + Input + >> key + >> value; + + if( key == "soundinc:" ) { + m_soundfxincrease = ( + value != "none" ? + TSoundsManager::GetFromName( value, true ) : + nullptr ); + } + else if( key == "sounddec:" ) { + m_soundfxdecrease = ( + value != "none" ? + TSoundsManager::GetFromName( value, true ) : + nullptr ); + } + return true; // return value marks a key: value pair was extracted, nothing about whether it's recognized +} + +void +TButton::Turn( bool const State ) { + + if( State != m_state ) { + + m_state = State; + play(); + Update(); + } +} + +void TButton::Update() { + + if( ( bData != nullptr ) + && ( *bData != m_state ) ) { + + m_state = ( *bData ); + play(); + } + + if( pModelOn != nullptr ) { pModelOn->iVisible = m_state; } + if( pModelOff != nullptr ) { pModelOff->iVisible = (!m_state); } + + if (iFeedbackBit) { + // jeżeli generuje informację zwrotną + if (m_state) // zapalenie Console::BitsSet(iFeedbackBit); else Console::BitsClear(iFeedbackBit); } }; -void TButton::AssignBool(bool *bValue) -{ +void TButton::AssignBool(bool const *bValue) { + bData = bValue; } + +void +TButton::play() { + + play( + m_state == true ? + m_soundfxincrease : + m_soundfxdecrease ); +} + +void +TButton::play( PSound Sound ) { + + if( Sound == nullptr ) { return; } + + Sound->SetCurrentPosition( 0 ); + Sound->SetVolume( DSBVOLUME_MAX ); + Sound->Play( 0, 0, 0 ); + return; +} diff --git a/Button.h b/Button.h index 0b79c19f..76737cd8 100644 --- a/Button.h +++ b/Button.h @@ -7,59 +7,52 @@ obtain one at http://mozilla.org/MPL/2.0/. */ -#ifndef ButtonH -#define ButtonH +#pragma once -#include -#include "Model3d.h" -#include "parser.h" +#include "Classes.h" +#include "sound.h" class TButton { // animacja dwustanowa, włącza jeden z dwóch submodeli (jednego // z nich może nie być) private: - TSubModel *pModelOn, *pModelOff; // submodel dla stanu załączonego i wyłączonego - bool bOn; - bool *bData; - int iFeedbackBit; // Ra: bit informacji zwrotnej, do wyprowadzenia na pulpit + TSubModel + *pModelOn { nullptr }, + *pModelOff { nullptr }; // submodel dla stanu załączonego i wyłączonego + bool m_state { false }; + bool const *bData { nullptr }; + int iFeedbackBit { 0 }; // Ra: bit informacji zwrotnej, do wyprowadzenia na pulpit + PSound m_soundfxincrease { nullptr }; // sound associated with increasing control's value + PSound m_soundfxdecrease { nullptr }; // sound associated with decreasing control's value +// methods + // imports member data pair from the config file + bool + Load_mapping( cParser &Input ); + // plays the sound associated with current state + void + play(); + // plays specified sound + void + play( PSound Sound ); public: TButton(); - ~TButton(); - void Clear(int i = -1); - inline void FeedbackBitSet(int i) - { - iFeedbackBit = 1 << i; - }; - inline void Turn(bool to) - { - bOn = to; - Update(); - }; - inline void TurnOn() - { - bOn = true; - Update(); - }; - inline void TurnOff() - { - bOn = false; - Update(); - }; - inline void Switch() - { - bOn = !bOn; - Update(); - }; - inline bool Active() - { - return (pModelOn) || (pModelOff); - }; + void Clear(int const i = -1); + inline void FeedbackBitSet(int const i) { + iFeedbackBit = 1 << i; }; + void Turn( bool const State ); + inline void TurnOn() { + Turn( true ); }; + inline void TurnOff() { + Turn( false ); }; + inline void Switch() { + Turn( !m_state ); }; + inline bool Active() { + return (pModelOn) || (pModelOff); }; void Update(); void Init(std::string const &asName, TModel3d *pModel, bool bNewOn = false); void Load(cParser &Parser, TModel3d *pModel1, TModel3d *pModel2 = NULL); - void AssignBool(bool *bValue); + void AssignBool(bool const *bValue); }; //--------------------------------------------------------------------------- -#endif diff --git a/Gauge.cpp b/Gauge.cpp index e6e6f0ec..125c1a1d 100644 --- a/Gauge.cpp +++ b/Gauge.cpp @@ -200,7 +200,7 @@ TGauge::UpdateValue( double fNewDesired, PSound Fallbacksound ) { else if( ( currentvalue > fNewDesired ) && ( m_soundfxdecrease != nullptr ) ) { play( m_soundfxdecrease ); } - else { + else if( Fallbacksound != nullptr ) { // ...and if that fails too, try the provided fallback sound from legacy system play( Fallbacksound ); } diff --git a/Gauge.h b/Gauge.h index 0147a61e..516294a7 100644 --- a/Gauge.h +++ b/Gauge.h @@ -43,18 +43,19 @@ class TGauge { PSound m_soundfxdecrease { nullptr }; // sound associated with decreasing control's value std::map m_soundfxvalues; // sounds associated with specific values // methods + // imports member data pair from the config file + bool + Load_mapping( cParser &Input ); // plays specified sound void play( PSound Sound ); public: TGauge() = default; - ~TGauge() {} inline void Clear() { *this = TGauge(); } void Init(TSubModel *NewSubModel, TGaugeType eNewTyp, double fNewScale = 1, double fNewOffset = 0, double fNewFriction = 0, double fNewValue = 0); bool Load(cParser &Parser, TModel3d *md1, TModel3d *md2 = nullptr, double mul = 1.0); - bool Load_mapping( cParser &Input ); void PermIncValue(double fNewDesired); void IncValue(double fNewDesired); void DecValue(double fNewDesired); diff --git a/Train.cpp b/Train.cpp index 5f768b8e..46dbb7b9 100644 --- a/Train.cpp +++ b/Train.cpp @@ -704,7 +704,7 @@ void TTrain::OnCommand_mucurrentindicatorothersourceactivate( TTrain *Train, com } #endif // visual feedback - Train->ggNextCurrentButton.UpdateValue( 1.0 ); + Train->ggNextCurrentButton.UpdateValue( 1.0, Train->dsbSwitch ); } else if( Command.action == GLFW_RELEASE ) { //turn off @@ -716,7 +716,7 @@ void TTrain::OnCommand_mucurrentindicatorothersourceactivate( TTrain *Train, com } #endif // visual feedback - Train->ggNextCurrentButton.UpdateValue( 0.0 ); + Train->ggNextCurrentButton.UpdateValue( 0.0, Train->dsbSwitch ); } } @@ -820,13 +820,13 @@ void TTrain::OnCommand_independentbrakebailoff( TTrain *Train, command_data cons } #endif // visual feedback - Train->ggReleaserButton.UpdateValue( 1.0 ); + Train->ggReleaserButton.UpdateValue( 1.0, Train->dsbSwitch ); } else { // release Train->mvOccupied->BrakeReleaser( 0 ); // visual feedback - Train->ggReleaserButton.UpdateValue( 0.0 ); + Train->ggReleaserButton.UpdateValue( 0.0, Train->dsbSwitch ); } } } @@ -1027,7 +1027,7 @@ void TTrain::OnCommand_wheelspinbrakeactivate( TTrain *Train, command_data const } #endif // visual feedback - Train->ggAntiSlipButton.UpdateValue( 1.0 ); + Train->ggAntiSlipButton.UpdateValue( 1.0, Train->dsbSwitch ); } else { // release @@ -1060,7 +1060,7 @@ void TTrain::OnCommand_sandboxactivate( TTrain *Train, command_data const &Comma Train->play_sound( Train->dsbSwitch ); #endif // visual feedback - Train->ggSandButton.UpdateValue( 1.0 ); + Train->ggSandButton.UpdateValue( 1.0, Train->dsbSwitch ); } else if( Command.action == GLFW_RELEASE) { // release @@ -1127,19 +1127,22 @@ void TTrain::OnCommand_brakeactingspeedincrease( TTrain *Train, command_data con Train->ggBrakeProfileCtrl.UpdateValue( ( ( Train->mvOccupied->BrakeDelayFlag & bdelay_R ) != 0 ? 2.0 : - Train->mvOccupied->BrakeDelayFlag - 1 ) ); + Train->mvOccupied->BrakeDelayFlag - 1 ), + Train->dsbSwitch ); } if( Train->ggBrakeProfileG.SubModel != nullptr ) { Train->ggBrakeProfileG.UpdateValue( - Train->mvOccupied->BrakeDelayFlag == bdelay_G ? + ( Train->mvOccupied->BrakeDelayFlag == bdelay_G ? 1.0 : - 0.0 ); + 0.0 ), + Train->dsbSwitch ); } if( Train->ggBrakeProfileR.SubModel != nullptr ) { Train->ggBrakeProfileR.UpdateValue( - ( Train->mvOccupied->BrakeDelayFlag & bdelay_R ) != 0 ? + ( ( Train->mvOccupied->BrakeDelayFlag & bdelay_R ) != 0 ? 1.0 : - 0.0 ); + 0.0 ), + Train->dsbSwitch ); } } } @@ -1169,19 +1172,22 @@ void TTrain::OnCommand_brakeactingspeeddecrease( TTrain *Train, command_data con Train->ggBrakeProfileCtrl.UpdateValue( ( ( Train->mvOccupied->BrakeDelayFlag & bdelay_R ) != 0 ? 2.0 : - Train->mvOccupied->BrakeDelayFlag - 1 ) ); + Train->mvOccupied->BrakeDelayFlag - 1 ), + Train->dsbSwitch ); } if( Train->ggBrakeProfileG.SubModel != nullptr ) { Train->ggBrakeProfileG.UpdateValue( - Train->mvOccupied->BrakeDelayFlag == bdelay_G ? + ( Train->mvOccupied->BrakeDelayFlag == bdelay_G ? 1.0 : - 0.0 ); + 0.0 ), + Train->dsbSwitch ); } if( Train->ggBrakeProfileR.SubModel != nullptr ) { Train->ggBrakeProfileR.UpdateValue( - ( Train->mvOccupied->BrakeDelayFlag & bdelay_R ) != 0 ? + ( ( Train->mvOccupied->BrakeDelayFlag & bdelay_R ) != 0 ? 1.0 : - 0.0 ); + 0.0 ), + Train->dsbSwitch ); } } } @@ -1212,7 +1218,7 @@ void TTrain::OnCommand_mubrakingindicatortoggle( TTrain *Train, command_data con } #endif // visual feedback - Train->ggSignallingButton.UpdateValue( 1.0 ); + Train->ggSignallingButton.UpdateValue( 1.0, Train->dsbSwitch ); } else { //turn off @@ -1224,7 +1230,7 @@ void TTrain::OnCommand_mubrakingindicatortoggle( TTrain *Train, command_data con } #endif // visual feedback - Train->ggSignallingButton.UpdateValue( 0.0 ); + Train->ggSignallingButton.UpdateValue( 0.0, Train->dsbSwitch ); } } } @@ -1282,7 +1288,7 @@ void TTrain::OnCommand_alerteracknowledge( TTrain *Train, command_data const &Co } } // visual feedback - Train->ggSecurityResetButton.UpdateValue( 1.0 ); + Train->ggSecurityResetButton.UpdateValue( 1.0, Train->dsbSwitch ); #ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggSecurityResetButton.GetValue() < 0.05 ) { @@ -1314,7 +1320,7 @@ void TTrain::OnCommand_batterytoggle( TTrain *Train, command_data const &Command if( Train->mvOccupied->BatterySwitch( true ) ) { // bateria potrzebna np. do zapalenia świateł if( Train->ggBatteryButton.SubModel ) { - Train->ggBatteryButton.UpdateValue( 1 ); + Train->ggBatteryButton.UpdateValue( 1.0, Train->dsbSwitch ); } #ifdef EU07_USE_OLD_CONTROLSOUNDS // audio feedback @@ -1336,7 +1342,7 @@ void TTrain::OnCommand_batterytoggle( TTrain *Train, command_data const &Command if( Train->mvOccupied->BatterySwitch( false ) ) { // ewentualnie zablokować z FIZ, np. w samochodach się nie odłącza akumulatora if( Train->ggBatteryButton.SubModel ) { - Train->ggBatteryButton.UpdateValue( 0 ); + Train->ggBatteryButton.UpdateValue( 0.0, Train->dsbSwitch ); } #ifdef EU07_USE_OLD_CONTROLSOUNDS // audio feedback @@ -1367,15 +1373,19 @@ void TTrain::OnCommand_pantographtogglefront( TTrain *Train, command_data const Train->play_sound( Train->dsbSwitch ); #endif // visual feedback - Train->ggPantFrontButton.UpdateValue( 1.0 ); + if( Train->ggPantFrontButton.SubModel ) + Train->ggPantFrontButton.UpdateValue( 1.0, Train->dsbSwitch ); // NOTE: currently we animate the selectable pantograph control based on standard key presses // TODO: implement actual selection control, and refactor handling this control setup in a separate method - Train->ggPantSelectedButton.UpdateValue( 1.0 ); + if( Train->ggPantSelectedButton.SubModel ) + Train->ggPantSelectedButton.UpdateValue( 1.0, Train->dsbSwitch ); // pantograph control can have two-button setup - Train->ggPantFrontButtonOff.UpdateValue( 0.0 ); + if( Train->ggPantFrontButtonOff.SubModel ) + Train->ggPantFrontButtonOff.UpdateValue( 0.0, Train->dsbSwitch ); // NOTE: currently we animate the selectable pantograph control based on standard key presses // TODO: implement actual selection control, and refactor handling this control setup in a separate method - Train->ggPantSelectedDownButton.UpdateValue( 0.0 ); + if( Train->ggPantSelectedDownButton.SubModel ) + Train->ggPantSelectedDownButton.UpdateValue( 0.0, Train->dsbSwitch ); } } } @@ -1399,15 +1409,19 @@ void TTrain::OnCommand_pantographtogglefront( TTrain *Train, command_data const Train->play_sound( Train->dsbSwitch ); #endif // visual feedback - Train->ggPantFrontButton.UpdateValue( 0.0 ); + if( Train->ggPantFrontButton.SubModel ) + Train->ggPantFrontButton.UpdateValue( 0.0, Train->dsbSwitch ); // NOTE: currently we animate the selectable pantograph control based on standard key presses // TODO: implement actual selection control, and refactor handling this control setup in a separate method - Train->ggPantSelectedButton.UpdateValue( 0.0 ); + if( Train->ggPantSelectedButton.SubModel ) + Train->ggPantSelectedButton.UpdateValue( 0.0, Train->dsbSwitch ); // pantograph control can have two-button setup - Train->ggPantFrontButtonOff.UpdateValue( 1.0 ); + if( Train->ggPantFrontButtonOff.SubModel ) + Train->ggPantFrontButtonOff.UpdateValue( 1.0, Train->dsbSwitch ); // NOTE: currently we animate the selectable pantograph control based on standard key presses // TODO: implement actual selection control, and refactor handling this control setup in a separate method - Train->ggPantSelectedDownButton.UpdateValue( 1.0 ); + if( Train->ggPantSelectedDownButton.SubModel ) + Train->ggPantSelectedDownButton.UpdateValue( 1.0, Train->dsbSwitch ); } } } @@ -1420,23 +1434,24 @@ void TTrain::OnCommand_pantographtogglefront( TTrain *Train, command_data const Train->play_sound( Train->dsbSwitch ); } #endif - Train->ggPantFrontButton.UpdateValue( 0.0 ); + if( Train->ggPantFrontButton.SubModel ) + Train->ggPantFrontButton.UpdateValue( 0.0, Train->dsbSwitch ); // NOTE: currently we animate the selectable pantograph control based on standard key presses // TODO: implement actual selection control, and refactor handling this control setup in a separate method - Train->ggPantSelectedButton.UpdateValue( 0.0 ); + if( Train->ggPantSelectedButton.SubModel ) + Train->ggPantSelectedButton.UpdateValue( 0.0, Train->dsbSwitch ); // also the switch off button, in cabs which have it #ifdef EU07_USE_OLD_CONTROLSOUNDS if( Train->ggPantFrontButtonOff.GetValue() > 0.35 ) { Train->play_sound( Train->dsbSwitch ); } #endif - if( Train->ggPantFrontButtonOff.SubModel ) { - Train->ggPantFrontButtonOff.UpdateValue( 0.0 ); - } + if( Train->ggPantFrontButtonOff.SubModel ) + Train->ggPantFrontButtonOff.UpdateValue( 0.0, Train->dsbSwitch ); if( Train->ggPantSelectedDownButton.SubModel ) { // NOTE: currently we animate the selectable pantograph control based on standard key presses // TODO: implement actual selection control, and refactor handling this control setup in a separate method - Train->ggPantSelectedDownButton.UpdateValue( 0.0 ); + Train->ggPantSelectedDownButton.UpdateValue( 0.0, Train->dsbSwitch ); } } } @@ -1456,15 +1471,19 @@ void TTrain::OnCommand_pantographtogglerear( TTrain *Train, command_data const & Train->play_sound( Train->dsbSwitch ); #endif // visual feedback - Train->ggPantRearButton.UpdateValue( 1.0 ); + if( Train->ggPantRearButton.SubModel ) + Train->ggPantRearButton.UpdateValue( 1.0, Train->dsbSwitch ); // NOTE: currently we animate the selectable pantograph control based on standard key presses // TODO: implement actual selection control, and refactor handling this control setup in a separate method - Train->ggPantSelectedButton.UpdateValue( 1.0 ); + if( Train->ggPantSelectedButton.SubModel ) + Train->ggPantSelectedButton.UpdateValue( 1.0, Train->dsbSwitch ); // pantograph control can have two-button setup - Train->ggPantRearButtonOff.UpdateValue( 0.0 ); + if( Train->ggPantRearButtonOff.SubModel ) + Train->ggPantRearButtonOff.UpdateValue( 0.0, Train->dsbSwitch ); // NOTE: currently we animate the selectable pantograph control based on standard key presses // TODO: implement actual selection control, and refactor handling this control setup in a separate method - Train->ggPantSelectedDownButton.UpdateValue( 0.0 ); + if( Train->ggPantSelectedDownButton.SubModel ) + Train->ggPantSelectedDownButton.UpdateValue( 0.0, Train->dsbSwitch ); } } } @@ -1488,15 +1507,19 @@ void TTrain::OnCommand_pantographtogglerear( TTrain *Train, command_data const & Train->play_sound( Train->dsbSwitch ); #endif // visual feedback - Train->ggPantRearButton.UpdateValue( 0.0 ); + if( Train->ggPantRearButton.SubModel ) + Train->ggPantRearButton.UpdateValue( 0.0, Train->dsbSwitch ); // NOTE: currently we animate the selectable pantograph control based on standard key presses // TODO: implement actual selection control, and refactor handling this control setup in a separate method - Train->ggPantSelectedButton.UpdateValue( 0.0 ); + if( Train->ggPantSelectedButton.SubModel ) + Train->ggPantSelectedButton.UpdateValue( 0.0, Train->dsbSwitch ); // pantograph control can have two-button setup - Train->ggPantRearButtonOff.UpdateValue( 1.0 ); + if( Train->ggPantRearButtonOff.SubModel ) + Train->ggPantRearButtonOff.UpdateValue( 1.0, Train->dsbSwitch ); // NOTE: currently we animate the selectable pantograph control based on standard key presses // TODO: implement actual selection control, and refactor handling this control setup in a separate method - Train->ggPantSelectedDownButton.UpdateValue( 1.0 ); + if( Train->ggPantSelectedDownButton.SubModel ) + Train->ggPantSelectedDownButton.UpdateValue( 1.0, Train->dsbSwitch ); } } } @@ -1509,23 +1532,24 @@ void TTrain::OnCommand_pantographtogglerear( TTrain *Train, command_data const & Train->play_sound( Train->dsbSwitch ); } #endif - Train->ggPantRearButton.UpdateValue( 0.0 ); + if( Train->ggPantRearButton.SubModel ) + Train->ggPantRearButton.UpdateValue( 0.0, Train->dsbSwitch ); // NOTE: currently we animate the selectable pantograph control based on standard key presses // TODO: implement actual selection control, and refactor handling this control setup in a separate method - Train->ggPantSelectedButton.UpdateValue( 0.0 ); + if( Train->ggPantSelectedButton.SubModel ) + Train->ggPantSelectedButton.UpdateValue( 0.0, Train->dsbSwitch ); // also the switch off button, in cabs which have it #ifdef EU07_USE_OLD_CONTROLSOUNDS if( Train->ggPantRearButtonOff.GetValue() > 0.35 ) { Train->play_sound( Train->dsbSwitch ); } #endif - if( Train->ggPantRearButtonOff.SubModel ) { - Train->ggPantRearButtonOff.UpdateValue( 0.0 ); - } + if( Train->ggPantRearButtonOff.SubModel ) + Train->ggPantRearButtonOff.UpdateValue( 0.0, Train->dsbSwitch ); if( Train->ggPantSelectedDownButton.SubModel ) { // NOTE: currently we animate the selectable pantograph control based on standard key presses // TODO: implement actual selection control, and refactor handling this control setup in a separate method - Train->ggPantSelectedDownButton.UpdateValue( 0.0 ); + Train->ggPantSelectedDownButton.UpdateValue( 0.0, Train->dsbSwitch ); } } } @@ -1619,9 +1643,10 @@ void TTrain::OnCommand_pantographlowerall( TTrain *Train, command_data const &Co } #endif // visual feedback - Train->ggPantAllDownButton.UpdateValue( 1.0 ); - if( Train->ggPantSelectedDownButton.SubModel != nullptr ) { - Train->ggPantSelectedDownButton.UpdateValue( 1.0 ); + if( Train->ggPantAllDownButton.SubModel ) + Train->ggPantAllDownButton.UpdateValue( 1.0, Train->dsbSwitch ); + if( Train->ggPantSelectedDownButton.SubModel ) { + Train->ggPantSelectedDownButton.UpdateValue( 1.0, Train->dsbSwitch ); } } else if( Command.action == GLFW_RELEASE ) { @@ -1637,8 +1662,9 @@ void TTrain::OnCommand_pantographlowerall( TTrain *Train, command_data const &Co */ #endif // visual feedback - Train->ggPantAllDownButton.UpdateValue( 0.0 ); - if( Train->ggPantSelectedDownButton.SubModel != nullptr ) { + if( Train->ggPantAllDownButton.SubModel ) + Train->ggPantAllDownButton.UpdateValue( 0.0 ); + if( Train->ggPantSelectedDownButton.SubModel ) { Train->ggPantSelectedDownButton.UpdateValue( 0.0 ); } } @@ -1680,7 +1706,7 @@ void TTrain::OnCommand_linebreakertoggle( TTrain *Train, command_data const &Com } #endif // visual feedback - Train->ggMainOnButton.UpdateValue( 1.0 ); + Train->ggMainOnButton.UpdateValue( 1.0, Train->dsbSwitch ); } else if( Train->ggMainButton.SubModel != nullptr ) { // single two-state switch @@ -1691,7 +1717,7 @@ void TTrain::OnCommand_linebreakertoggle( TTrain *Train, command_data const &Com } #endif // visual feedback - Train->ggMainButton.UpdateValue( 1.0 ); + Train->ggMainButton.UpdateValue( 1.0, Train->dsbSwitch ); } // keep track of period the button is held down, to determine when/if circuit closes if( ( ( ( Train->mvControlled->EngineType != ElectricSeriesMotor ) @@ -1739,7 +1765,7 @@ void TTrain::OnCommand_linebreakertoggle( TTrain *Train, command_data const &Com } #endif // visual feedback - Train->ggMainOffButton.UpdateValue( 1.0 ); + Train->ggMainOffButton.UpdateValue( 1.0, Train->dsbSwitch ); } else if( Train->ggMainButton.SubModel != nullptr ) { // single two-state switch @@ -1765,7 +1791,7 @@ void TTrain::OnCommand_linebreakertoggle( TTrain *Train, command_data const &Com } #endif // visual feedback - Train->ggMainButton.UpdateValue( 0.0 ); + Train->ggMainButton.UpdateValue( 0.0, Train->dsbSwitch ); } } } @@ -1788,7 +1814,7 @@ void TTrain::OnCommand_linebreakertoggle( TTrain *Train, command_data const &Com // we don't exactly know which of the two buttons was used, so reset both // for setup with two separate swiches if( Train->ggMainOnButton.SubModel != nullptr ) { - Train->ggMainOnButton.UpdateValue( 0.0 ); + Train->ggMainOnButton.UpdateValue( 0.0, Train->dsbSwitch ); #ifdef EU07_USE_OLD_CONTROLSOUNDS // audio feedback if( Train->ggMainOnButton.GetValue() > 0.5 ) { @@ -1797,7 +1823,7 @@ void TTrain::OnCommand_linebreakertoggle( TTrain *Train, command_data const &Com #endif } if( Train->ggMainOffButton.SubModel != nullptr ) { - Train->ggMainOffButton.UpdateValue( 0.0 ); + Train->ggMainOffButton.UpdateValue( 0.0, Train->dsbSwitch ); } // and the two-state switch too, for good measure if( Train->ggMainButton.SubModel != nullptr ) { @@ -1808,7 +1834,7 @@ void TTrain::OnCommand_linebreakertoggle( TTrain *Train, command_data const &Com } #endif // visual feedback - Train->ggMainButton.UpdateValue( 0.0 ); + Train->ggMainButton.UpdateValue( 0.0, Train->dsbSwitch ); } // finalize the state of the line breaker Train->m_linebreakerstate = 0; @@ -1832,7 +1858,7 @@ void TTrain::OnCommand_linebreakertoggle( TTrain *Train, command_data const &Com // visual feedback if( Train->ggMainOnButton.SubModel != nullptr ) { // setup with two separate switches - Train->ggMainOnButton.UpdateValue( 0.0 ); + Train->ggMainOnButton.UpdateValue( 0.0, Train->dsbSwitch ); } // NOTE: we don't have switch type definition for the line breaker switch // so for the time being we have hard coded "impulse" switches for all EMUs @@ -1846,7 +1872,7 @@ void TTrain::OnCommand_linebreakertoggle( TTrain *Train, command_data const &Com } #endif // visual feedback - Train->ggMainButton.UpdateValue( 0.0 ); + Train->ggMainButton.UpdateValue( 0.0, Train->dsbSwitch ); } } // finalize the state of the line breaker @@ -1876,7 +1902,7 @@ void TTrain::OnCommand_convertertoggle( TTrain *Train, command_data const &Comma } #endif // visual feedback - Train->ggConverterButton.UpdateValue( 1.0 ); + Train->ggConverterButton.UpdateValue( 1.0, Train->dsbSwitch ); /* if( ( Train->mvControlled->EnginePowerSource.SourceType != CurrentCollector ) || ( Train->mvControlled->PantRearVolt != 0.0 ) @@ -1916,9 +1942,9 @@ void TTrain::OnCommand_convertertoggle( TTrain *Train, command_data const &Comma } #endif // visual feedback - Train->ggConverterButton.UpdateValue( 0.0 ); + Train->ggConverterButton.UpdateValue( 0.0, Train->dsbSwitch ); if( Train->ggConverterOffButton.SubModel != nullptr ) { - Train->ggConverterOffButton.UpdateValue( 1.0 ); + Train->ggConverterOffButton.UpdateValue( 1.0, Train->dsbSwitch ); } if( true == Train->mvControlled->ConverterSwitch( false ) ) { // side effects @@ -1950,8 +1976,8 @@ void TTrain::OnCommand_convertertoggle( TTrain *Train, command_data const &Comma Train->play_sound( Train->dsbSwitch ); } #endif - Train->ggConverterButton.UpdateValue( 0.0 ); - Train->ggConverterOffButton.UpdateValue( 0.0 ); + Train->ggConverterButton.UpdateValue( 0.0, Train->dsbSwitch ); + Train->ggConverterOffButton.UpdateValue( 0.0, Train->dsbSwitch ); } } } @@ -1978,7 +2004,7 @@ void TTrain::OnCommand_convertertogglelocal( TTrain *Train, command_data const & } #endif // visual feedback - Train->ggConverterLocalButton.UpdateValue( 1.0 ); + Train->ggConverterLocalButton.UpdateValue( 1.0, Train->dsbSwitch ); // effect Train->mvOccupied->ConverterAllowLocal = true; /* @@ -2001,7 +2027,7 @@ void TTrain::OnCommand_convertertogglelocal( TTrain *Train, command_data const & } #endif // visual feedback - Train->ggConverterLocalButton.UpdateValue( 0.0 ); + Train->ggConverterLocalButton.UpdateValue( 0.0, Train->dsbSwitch ); // effect Train->mvOccupied->ConverterAllowLocal = false; /* @@ -2046,7 +2072,7 @@ void TTrain::OnCommand_converteroverloadrelayreset( TTrain *Train, command_data } #endif // visual feedback - Train->ggConverterFuseButton.UpdateValue( 1.0 ); + Train->ggConverterFuseButton.UpdateValue( 1.0, Train->dsbSwitch ); } else if( Command.action == GLFW_RELEASE ) { // release @@ -2057,7 +2083,7 @@ void TTrain::OnCommand_converteroverloadrelayreset( TTrain *Train, command_data } #endif // visual feedback - Train->ggConverterFuseButton.UpdateValue( 0.0 ); + Train->ggConverterFuseButton.UpdateValue( 0.0, Train->dsbSwitch ); } } @@ -2072,7 +2098,7 @@ void TTrain::OnCommand_compressortoggle( TTrain *Train, command_data const &Comm if( false == Train->mvControlled->CompressorAllow ) { // turn on // visual feedback - Train->ggCompressorButton.UpdateValue( 1.0 ); + Train->ggCompressorButton.UpdateValue( 1.0, Train->dsbSwitch ); #ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggCompressorButton.GetValue() < 0.5 ) { @@ -2104,7 +2130,7 @@ void TTrain::OnCommand_compressortoggle( TTrain *Train, command_data const &Comm // } // else { // visual feedback - Train->ggCompressorButton.UpdateValue( 0.0 ); + Train->ggCompressorButton.UpdateValue( 0.0, Train->dsbSwitch ); // } } } @@ -2148,7 +2174,7 @@ void TTrain::OnCommand_compressortogglelocal( TTrain *Train, command_data const } #endif // visual feedback - Train->ggCompressorLocalButton.UpdateValue( 1.0 ); + Train->ggCompressorLocalButton.UpdateValue( 1.0, Train->dsbSwitch ); // effect Train->mvOccupied->CompressorAllowLocal = true; } @@ -2161,7 +2187,7 @@ void TTrain::OnCommand_compressortogglelocal( TTrain *Train, command_data const } #endif // visual feedback - Train->ggCompressorLocalButton.UpdateValue( 0.0 ); + Train->ggCompressorLocalButton.UpdateValue( 0.0, Train->dsbSwitch ); // effect Train->mvOccupied->CompressorAllowLocal = false; } @@ -2206,7 +2232,7 @@ void TTrain::OnCommand_motorconnectorsopen( TTrain *Train, command_data const &C } #endif // visual feedback - Train->ggStLinOffButton.UpdateValue( 1.0 ); + Train->ggStLinOffButton.UpdateValue( 1.0, Train->dsbSwitch ); // effect if( true == Train->mvControlled->StLinFlag ) { Train->play_sound( Train->dsbRelay ); @@ -2255,7 +2281,7 @@ void TTrain::OnCommand_motorconnectorsopen( TTrain *Train, command_data const &C } #endif // visual feedback - Train->ggStLinOffButton.UpdateValue( 0.0 ); + Train->ggStLinOffButton.UpdateValue( 0.0, Train->dsbSwitch ); } } } @@ -2286,7 +2312,7 @@ void TTrain::OnCommand_motorconnectorsopen( TTrain *Train, command_data const &C } #endif // visual feedback - Train->ggStLinOffButton.UpdateValue( 0.0 ); + Train->ggStLinOffButton.UpdateValue( 0.0, Train->dsbSwitch ); } } } @@ -2320,7 +2346,7 @@ void TTrain::OnCommand_motoroverloadrelaythresholdtoggle( TTrain *Train, command // turn on if( true == Train->mvControlled->CurrentSwitch( true ) ) { // visual feedback - Train->ggMaxCurrentCtrl.UpdateValue( 1.0 ); + Train->ggMaxCurrentCtrl.UpdateValue( 1.0, Train->dsbSwitch ); #ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggMaxCurrentCtrl.GetValue() < 0.5 ) { @@ -2333,7 +2359,7 @@ void TTrain::OnCommand_motoroverloadrelaythresholdtoggle( TTrain *Train, command //turn off if( true == Train->mvControlled->CurrentSwitch( false ) ) { // visual feedback - Train->ggMaxCurrentCtrl.UpdateValue( 0.0 ); + Train->ggMaxCurrentCtrl.UpdateValue( 0.0, Train->dsbSwitch ); #ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggMaxCurrentCtrl.GetValue() > 0.5 ) { @@ -2364,7 +2390,7 @@ void TTrain::OnCommand_motoroverloadrelayreset( TTrain *Train, command_data cons } #endif // visual feedback - Train->ggFuseButton.UpdateValue( 1.0 ); + Train->ggFuseButton.UpdateValue( 1.0, Train->dsbSwitch ); } else if( Command.action == GLFW_RELEASE ) { // release @@ -2375,7 +2401,7 @@ void TTrain::OnCommand_motoroverloadrelayreset( TTrain *Train, command_data cons } #endif // visual feedback - Train->ggFuseButton.UpdateValue( 0.0 ); + Train->ggFuseButton.UpdateValue( 0.0, Train->dsbSwitch ); } } @@ -2397,7 +2423,7 @@ void TTrain::OnCommand_headlighttoggleleft( TTrain *Train, command_data const &C // turn on Train->DynamicObject->iLights[ lightsindex ] ^= TMoverParameters::light::headlight_left; // visual feedback - Train->ggLeftLightButton.UpdateValue( 1.0 ); + Train->ggLeftLightButton.UpdateValue( 1.0, Train->dsbSwitch ); #ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggLeftLightButton.GetValue() < 0.5 ) { @@ -2409,7 +2435,7 @@ void TTrain::OnCommand_headlighttoggleleft( TTrain *Train, command_data const &C //turn off Train->DynamicObject->iLights[ lightsindex ] ^= TMoverParameters::light::headlight_left; // visual feedback - Train->ggLeftLightButton.UpdateValue( 0.0 ); + Train->ggLeftLightButton.UpdateValue( 0.0, Train->dsbSwitch ); #ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggLeftLightButton.GetValue() > 0.5 ) { @@ -2438,7 +2464,7 @@ void TTrain::OnCommand_headlighttoggleright( TTrain *Train, command_data const & // turn on Train->DynamicObject->iLights[ lightsindex ] ^= TMoverParameters::light::headlight_right; // visual feedback - Train->ggRightLightButton.UpdateValue( 1.0 ); + Train->ggRightLightButton.UpdateValue( 1.0, Train->dsbSwitch ); #ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggRightLightButton.GetValue() < 0.5 ) { @@ -2450,7 +2476,7 @@ void TTrain::OnCommand_headlighttoggleright( TTrain *Train, command_data const & //turn off Train->DynamicObject->iLights[ lightsindex ] ^= TMoverParameters::light::headlight_right; // visual feedback - Train->ggRightLightButton.UpdateValue( 0.0 ); + Train->ggRightLightButton.UpdateValue( 0.0, Train->dsbSwitch ); #ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggRightLightButton.GetValue() > 0.5 ) { @@ -2479,7 +2505,7 @@ void TTrain::OnCommand_headlighttoggleupper( TTrain *Train, command_data const & // turn on Train->DynamicObject->iLights[ lightsindex ] ^= TMoverParameters::light::headlight_upper; // visual feedback - Train->ggUpperLightButton.UpdateValue( 1.0 ); + Train->ggUpperLightButton.UpdateValue( 1.0, Train->dsbSwitch ); #ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggUpperLightButton.GetValue() < 0.5 ) { @@ -2491,7 +2517,7 @@ void TTrain::OnCommand_headlighttoggleupper( TTrain *Train, command_data const & //turn off Train->DynamicObject->iLights[ lightsindex ] ^= TMoverParameters::light::headlight_upper; // visual feedback - Train->ggUpperLightButton.UpdateValue( 0.0 ); + Train->ggUpperLightButton.UpdateValue( 0.0, Train->dsbSwitch ); #ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggUpperLightButton.GetValue() > 0.5 ) { @@ -2520,7 +2546,7 @@ void TTrain::OnCommand_redmarkertoggleleft( TTrain *Train, command_data const &C // turn on Train->DynamicObject->iLights[ lightsindex ] ^= TMoverParameters::light::redmarker_left; // visual feedback - Train->ggLeftEndLightButton.UpdateValue( 1.0 ); + Train->ggLeftEndLightButton.UpdateValue( 1.0, Train->dsbSwitch ); #ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggLeftEndLightButton.GetValue() < 0.5 ) { @@ -2532,7 +2558,7 @@ void TTrain::OnCommand_redmarkertoggleleft( TTrain *Train, command_data const &C //turn off Train->DynamicObject->iLights[ lightsindex ] ^= TMoverParameters::light::redmarker_left; // visual feedback - Train->ggLeftEndLightButton.UpdateValue( 0.0 ); + Train->ggLeftEndLightButton.UpdateValue( 0.0, Train->dsbSwitch ); #ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggLeftEndLightButton.GetValue() > 0.5 ) { @@ -2561,7 +2587,7 @@ void TTrain::OnCommand_redmarkertoggleright( TTrain *Train, command_data const & // turn on Train->DynamicObject->iLights[ lightsindex ] ^= TMoverParameters::light::redmarker_right; // visual feedback - Train->ggRightEndLightButton.UpdateValue( 1.0 ); + Train->ggRightEndLightButton.UpdateValue( 1.0, Train->dsbSwitch ); #ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggRightEndLightButton.GetValue() < 0.5 ) { @@ -2573,7 +2599,7 @@ void TTrain::OnCommand_redmarkertoggleright( TTrain *Train, command_data const & //turn off Train->DynamicObject->iLights[ lightsindex ] ^= TMoverParameters::light::redmarker_right; // visual feedback - Train->ggRightEndLightButton.UpdateValue( 0.0 ); + Train->ggRightEndLightButton.UpdateValue( 0.0, Train->dsbSwitch ); #ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggRightEndLightButton.GetValue() > 0.5 ) { @@ -2603,7 +2629,7 @@ void TTrain::OnCommand_headlighttogglerearleft( TTrain *Train, command_data cons // turn on Train->DynamicObject->iLights[ lightsindex ] ^= TMoverParameters::light::headlight_right; // visual feedback - Train->ggRearLeftLightButton.UpdateValue( 1.0 ); + Train->ggRearLeftLightButton.UpdateValue( 1.0, Train->dsbSwitch ); #ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggRearLeftLightButton.GetValue() < 0.5 ) { @@ -2615,7 +2641,7 @@ void TTrain::OnCommand_headlighttogglerearleft( TTrain *Train, command_data cons //turn off Train->DynamicObject->iLights[ lightsindex ] ^= TMoverParameters::light::headlight_right; // visual feedback - Train->ggRearLeftLightButton.UpdateValue( 0.0 ); + Train->ggRearLeftLightButton.UpdateValue( 0.0, Train->dsbSwitch ); #ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggRearLeftLightButton.GetValue() > 0.5 ) { @@ -2645,7 +2671,7 @@ void TTrain::OnCommand_headlighttogglerearright( TTrain *Train, command_data con // turn on Train->DynamicObject->iLights[ lightsindex ] ^= TMoverParameters::light::headlight_left; // visual feedback - Train->ggRearRightLightButton.UpdateValue( 1.0 ); + Train->ggRearRightLightButton.UpdateValue( 1.0, Train->dsbSwitch ); #ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggRearRightLightButton.GetValue() < 0.5 ) { @@ -2657,7 +2683,7 @@ void TTrain::OnCommand_headlighttogglerearright( TTrain *Train, command_data con //turn off Train->DynamicObject->iLights[ lightsindex ] ^= TMoverParameters::light::headlight_left; // visual feedback - Train->ggRearRightLightButton.UpdateValue( 0.0 ); + Train->ggRearRightLightButton.UpdateValue( 0.0, Train->dsbSwitch ); #ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggRearRightLightButton.GetValue() > 0.5 ) { @@ -2686,7 +2712,7 @@ void TTrain::OnCommand_headlighttogglerearupper( TTrain *Train, command_data con // turn on Train->DynamicObject->iLights[ lightsindex ] ^= TMoverParameters::light::headlight_upper; // visual feedback - Train->ggRearUpperLightButton.UpdateValue( 1.0 ); + Train->ggRearUpperLightButton.UpdateValue( 1.0, Train->dsbSwitch ); #ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggRearUpperLightButton.GetValue() < 0.5 ) { @@ -2698,7 +2724,7 @@ void TTrain::OnCommand_headlighttogglerearupper( TTrain *Train, command_data con //turn off Train->DynamicObject->iLights[ lightsindex ] ^= TMoverParameters::light::headlight_upper; // visual feedback - Train->ggRearUpperLightButton.UpdateValue( 0.0 ); + Train->ggRearUpperLightButton.UpdateValue( 0.0, Train->dsbSwitch ); #ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggRearUpperLightButton.GetValue() > 0.5 ) { @@ -2728,7 +2754,7 @@ void TTrain::OnCommand_redmarkertogglerearleft( TTrain *Train, command_data cons // turn on Train->DynamicObject->iLights[ lightsindex ] ^= TMoverParameters::light::redmarker_right; // visual feedback - Train->ggRearLeftEndLightButton.UpdateValue( 1.0 ); + Train->ggRearLeftEndLightButton.UpdateValue( 1.0, Train->dsbSwitch ); #ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggRearLeftEndLightButton.GetValue() < 0.5 ) { @@ -2740,7 +2766,7 @@ void TTrain::OnCommand_redmarkertogglerearleft( TTrain *Train, command_data cons //turn off Train->DynamicObject->iLights[ lightsindex ] ^= TMoverParameters::light::redmarker_right; // visual feedback - Train->ggRearLeftEndLightButton.UpdateValue( 0.0 ); + Train->ggRearLeftEndLightButton.UpdateValue( 0.0, Train->dsbSwitch ); #ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggRearLeftEndLightButton.GetValue() > 0.5 ) { @@ -2770,7 +2796,7 @@ void TTrain::OnCommand_redmarkertogglerearright( TTrain *Train, command_data con // turn on Train->DynamicObject->iLights[ lightsindex ] ^= TMoverParameters::light::redmarker_left; // visual feedback - Train->ggRearRightEndLightButton.UpdateValue( 1.0 ); + Train->ggRearRightEndLightButton.UpdateValue( 1.0, Train->dsbSwitch ); #ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggRearRightEndLightButton.GetValue() < 0.5 ) { @@ -2782,7 +2808,7 @@ void TTrain::OnCommand_redmarkertogglerearright( TTrain *Train, command_data con //turn off Train->DynamicObject->iLights[ lightsindex ] ^= TMoverParameters::light::redmarker_left; // visual feedback - Train->ggRearRightEndLightButton.UpdateValue( 0.0 ); + Train->ggRearRightEndLightButton.UpdateValue( 0.0, Train->dsbSwitch ); #ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggRearRightEndLightButton.GetValue() > 0.5 ) { @@ -2816,7 +2842,7 @@ void TTrain::OnCommand_headlightsdimtoggle( TTrain *Train, command_data const &C } #endif // visual feedback - Train->ggDimHeadlightsButton.UpdateValue( 1.0 ); + Train->ggDimHeadlightsButton.UpdateValue( 1.0, Train->dsbSwitch ); } else { //turn off @@ -2828,7 +2854,7 @@ void TTrain::OnCommand_headlightsdimtoggle( TTrain *Train, command_data const &C } #endif // visual feedback - Train->ggDimHeadlightsButton.UpdateValue( 0.0 ); + Train->ggDimHeadlightsButton.UpdateValue( 0.0, Train->dsbSwitch ); } } } @@ -2857,7 +2883,7 @@ void TTrain::OnCommand_interiorlighttoggle( TTrain *Train, command_data const &C } #endif // visual feedback - Train->ggCabLightButton.UpdateValue( 1.0 ); + Train->ggCabLightButton.UpdateValue( 1.0, Train->dsbSwitch ); } else { //turn off @@ -2870,7 +2896,7 @@ void TTrain::OnCommand_interiorlighttoggle( TTrain *Train, command_data const &C } #endif // visual feedback - Train->ggCabLightButton.UpdateValue( 0.0 ); + Train->ggCabLightButton.UpdateValue( 0.0, Train->dsbSwitch ); } } } @@ -2897,7 +2923,7 @@ void TTrain::OnCommand_interiorlightdimtoggle( TTrain *Train, command_data const } #endif // visual feedback - Train->ggCabLightDimButton.UpdateValue( 1.0 ); + Train->ggCabLightDimButton.UpdateValue( 1.0, Train->dsbSwitch ); } else { //turn off @@ -2909,7 +2935,7 @@ void TTrain::OnCommand_interiorlightdimtoggle( TTrain *Train, command_data const } #endif // visual feedback - Train->ggCabLightDimButton.UpdateValue( 0.0 ); + Train->ggCabLightDimButton.UpdateValue( 0.0, Train->dsbSwitch ); } } } @@ -2938,7 +2964,7 @@ void TTrain::OnCommand_instrumentlighttoggle( TTrain *Train, command_data const } #endif // visual feedback - Train->ggInstrumentLightButton.UpdateValue( 1.0 ); + Train->ggInstrumentLightButton.UpdateValue( 1.0, Train->dsbSwitch ); } else { //turn off @@ -2950,7 +2976,7 @@ void TTrain::OnCommand_instrumentlighttoggle( TTrain *Train, command_data const } #endif // visual feedback - Train->ggInstrumentLightButton.UpdateValue( 0.0 ); + Train->ggInstrumentLightButton.UpdateValue( 0.0, Train->dsbSwitch ); } } } @@ -2976,7 +3002,7 @@ void TTrain::OnCommand_heatingtoggle( TTrain *Train, command_data const &Command } #endif // visual feedback - Train->ggTrainHeatingButton.UpdateValue( 1.0 ); + Train->ggTrainHeatingButton.UpdateValue( 1.0, Train->dsbSwitch ); } else { //turn off @@ -2988,7 +3014,7 @@ void TTrain::OnCommand_heatingtoggle( TTrain *Train, command_data const &Command } #endif // visual feedback - Train->ggTrainHeatingButton.UpdateValue( 0.0 ); + Train->ggTrainHeatingButton.UpdateValue( 0.0, Train->dsbSwitch ); } } } @@ -3016,7 +3042,7 @@ void TTrain::OnCommand_generictoggle( TTrain *Train, command_data const &Command } #endif // visual feedback - item.UpdateValue( 1.0 ); + item.UpdateValue( 1.0, Train->dsbSwitch ); } else { //turn off @@ -3027,7 +3053,7 @@ void TTrain::OnCommand_generictoggle( TTrain *Train, command_data const &Command } #endif // visual feedback - item.UpdateValue( 0.0 ); + item.UpdateValue( 0.0, Train->dsbSwitch ); } } } @@ -3055,7 +3081,7 @@ void TTrain::OnCommand_doorlocktoggle( TTrain *Train, command_data const &Comman } #endif // visual feedback - Train->ggDoorSignallingButton.UpdateValue( 1.0 ); + Train->ggDoorSignallingButton.UpdateValue( 1.0, Train->dsbSwitch ); } else { // turn off @@ -3069,7 +3095,7 @@ void TTrain::OnCommand_doorlocktoggle( TTrain *Train, command_data const &Comman } #endif // visual feedback - Train->ggDoorSignallingButton.UpdateValue( 0.0 ); + Train->ggDoorSignallingButton.UpdateValue( 0.0, Train->dsbSwitch ); } } } @@ -3088,7 +3114,7 @@ void TTrain::OnCommand_doortoggleleft( TTrain *Train, command_data const &Comman // open if( Train->mvOccupied->ActiveCab == 1 ) { if( Train->mvOccupied->DoorLeft( true ) ) { - Train->ggDoorLeftButton.UpdateValue( 1.0 ); + Train->ggDoorLeftButton.UpdateValue( 1.0, Train->dsbSwitch ); #ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggDoorLeftButton.GetValue() < 0.5 ) { @@ -3101,7 +3127,7 @@ void TTrain::OnCommand_doortoggleleft( TTrain *Train, command_data const &Comman else { // in the rear cab sides are reversed if( Train->mvOccupied->DoorRight( true ) ) { - Train->ggDoorRightButton.UpdateValue( 1.0 ); + Train->ggDoorRightButton.UpdateValue( 1.0, Train->dsbSwitch ); #ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggDoorRightButton.GetValue() < 0.5 ) { @@ -3116,7 +3142,7 @@ void TTrain::OnCommand_doortoggleleft( TTrain *Train, command_data const &Comman // close if( Train->mvOccupied->ActiveCab == 1 ) { if( Train->mvOccupied->DoorLeft( false ) ) { - Train->ggDoorLeftButton.UpdateValue( 0.0 ); + Train->ggDoorLeftButton.UpdateValue( 0.0, Train->dsbSwitch ); #ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggDoorLeftButton.GetValue() > 0.5 ) { @@ -3129,7 +3155,7 @@ void TTrain::OnCommand_doortoggleleft( TTrain *Train, command_data const &Comman else { // in the rear cab sides are reversed if( Train->mvOccupied->DoorRight( false ) ) { - Train->ggDoorRightButton.UpdateValue( 0.0 ); + Train->ggDoorRightButton.UpdateValue( 0.0, Train->dsbSwitch ); #ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggDoorRightButton.GetValue() > 0.5 ) { @@ -3157,7 +3183,7 @@ void TTrain::OnCommand_doortoggleright( TTrain *Train, command_data const &Comma // open if( Train->mvOccupied->ActiveCab == 1 ) { if( Train->mvOccupied->DoorRight( true ) ) { - Train->ggDoorRightButton.UpdateValue( 1.0 ); + Train->ggDoorRightButton.UpdateValue( 1.0, Train->dsbSwitch ); #ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggDoorRightButton.GetValue() < 0.5 ) { @@ -3170,7 +3196,7 @@ void TTrain::OnCommand_doortoggleright( TTrain *Train, command_data const &Comma else { // in the rear cab sides are reversed if( Train->mvOccupied->DoorLeft( true ) ) { - Train->ggDoorLeftButton.UpdateValue( 1.0 ); + Train->ggDoorLeftButton.UpdateValue( 1.0, Train->dsbSwitch ); #ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggDoorLeftButton.GetValue() < 0.5 ) { @@ -3185,7 +3211,7 @@ void TTrain::OnCommand_doortoggleright( TTrain *Train, command_data const &Comma // close if( Train->mvOccupied->ActiveCab == 1 ) { if( Train->mvOccupied->DoorRight( false ) ) { - Train->ggDoorRightButton.UpdateValue( 0.0 ); + Train->ggDoorRightButton.UpdateValue( 0.0, Train->dsbSwitch ); #ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggDoorRightButton.GetValue() > 0.5 ) { @@ -3198,7 +3224,7 @@ void TTrain::OnCommand_doortoggleright( TTrain *Train, command_data const &Comma else { // in the rear cab sides are reversed if( Train->mvOccupied->DoorLeft( false ) ) { - Train->ggDoorLeftButton.UpdateValue( 0.0 ); + Train->ggDoorLeftButton.UpdateValue( 0.0, Train->dsbSwitch ); #ifdef EU07_USE_OLD_CONTROLSOUNDS // sound feedback if( Train->ggDoorLeftButton.GetValue() > 0.5 ) { @@ -3233,7 +3259,7 @@ void TTrain::OnCommand_departureannounce( TTrain *Train, command_data const &Com } #endif // visual feedback - Train->ggDepartureSignalButton.UpdateValue( 1.0 ); + Train->ggDepartureSignalButton.UpdateValue( 1.0, Train->dsbSwitch ); } } else if( Command.action == GLFW_RELEASE ) { @@ -3246,7 +3272,7 @@ void TTrain::OnCommand_departureannounce( TTrain *Train, command_data const &Com } #endif // visual feedback - Train->ggDepartureSignalButton.UpdateValue( 0.0 ); + Train->ggDepartureSignalButton.UpdateValue( 0.0, Train->dsbSwitch ); } } @@ -3378,7 +3404,7 @@ void TTrain::OnCommand_radiotoggle( TTrain *Train, command_data const &Command ) } #endif // visual feedback - Train->ggRadioButton.UpdateValue( 1.0 ); + Train->ggRadioButton.UpdateValue( 1.0, Train->dsbSwitch ); } else { // turn off @@ -3390,7 +3416,7 @@ void TTrain::OnCommand_radiotoggle( TTrain *Train, command_data const &Command ) } #endif // visual feedback - Train->ggRadioButton.UpdateValue( 0.0 ); + Train->ggRadioButton.UpdateValue( 0.0, Train->dsbSwitch ); } } } @@ -5121,13 +5147,18 @@ bool TTrain::Update( double const Deltatime ) btLampkaED.TurnOff(); } // McZapkie-080602: obroty (albo translacje) regulatorow - if (ggMainCtrl.SubModel) - { - if (mvControlled->CoupledCtrl) + if (ggMainCtrl.SubModel) { + + if( mvControlled->CoupledCtrl ) { ggMainCtrl.UpdateValue( - double(mvControlled->MainCtrlPos + mvControlled->ScndCtrlPos)); - else - ggMainCtrl.UpdateValue(double(mvControlled->MainCtrlPos)); + double( mvControlled->MainCtrlPos + mvControlled->ScndCtrlPos ), + dsbNastawnikJazdy ); + } + else { + ggMainCtrl.UpdateValue( + double( mvControlled->MainCtrlPos ), + dsbNastawnikJazdy ); + } ggMainCtrl.Update(); } if (ggMainCtrlAct.SubModel) @@ -5139,21 +5170,23 @@ bool TTrain::Update( double const Deltatime ) ggMainCtrlAct.UpdateValue(double(mvControlled->MainCtrlActualPos)); ggMainCtrlAct.Update(); } - if (ggScndCtrl.SubModel) - { // Ra: od byte odejmowane boolean i konwertowane - // potem na double? + if (ggScndCtrl.SubModel) { + // Ra: od byte odejmowane boolean i konwertowane potem na double? ggScndCtrl.UpdateValue( - double(mvControlled->ScndCtrlPos - - ((mvControlled->TrainType == dt_ET42) && mvControlled->DynamicBrakeFlag))); + double( mvControlled->ScndCtrlPos + - ( ( mvControlled->TrainType == dt_ET42 ) && mvControlled->DynamicBrakeFlag ) ), + dsbNastawnikBocz ); ggScndCtrl.Update(); } - if (ggDirKey.SubModel) - { + if (ggDirKey.SubModel) { if (mvControlled->TrainType != dt_EZT) - ggDirKey.UpdateValue(double(mvControlled->ActiveDir)); + ggDirKey.UpdateValue( + double(mvControlled->ActiveDir), + dsbReverserKey); else - ggDirKey.UpdateValue(double(mvControlled->ActiveDir) + - double(mvControlled->Imin == mvControlled->IminHi)); + ggDirKey.UpdateValue( + double(mvControlled->ActiveDir) + double(mvControlled->Imin == mvControlled->IminHi), + dsbReverserKey); ggDirKey.Update(); } if (ggBrakeCtrl.SubModel) diff --git a/renderer.cpp b/renderer.cpp index c5739dad..97690ec0 100644 --- a/renderer.cpp +++ b/renderer.cpp @@ -346,12 +346,12 @@ opengl_renderer::Render_camera() { break; } case rendermode::shadows: { - m_renderpass.camera.position() = Global::pCameraPosition - glm::dvec3{ Global::DayLight.direction * 750.0f }; + m_renderpass.camera.position() = Global::pCameraPosition - glm::dvec3{ Global::DayLight.direction * 750.f }; m_renderpass.camera.position().y = std::max( 50.0, m_renderpass.camera.position().y ); // prevent shadow source from dipping too low viewmatrix = glm::lookAt( m_renderpass.camera.position(), glm::dvec3{ Global::pCameraPosition.x, 0.0, Global::pCameraPosition.z }, - glm::dvec3{ 0.0f, 1.0f, 0.0f } ); + glm::dvec3{ 0.f, 1.f, 0.f } ); break; } default: { diff --git a/version.h b/version.h index 53cafe07..a4437670 100644 --- a/version.h +++ b/version.h @@ -1,5 +1,5 @@ #pragma once #define VERSION_MAJOR 17 -#define VERSION_MINOR 714 +#define VERSION_MINOR 715 #define VERSION_REVISION 0