From 0c062e9041ecf6503f9b80faee919eba6ee5e0c5 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Thu, 30 Aug 2018 20:41:14 +0200 Subject: [PATCH] imgui user interface implementation --- AnimModel.h | 2 +- Classes.h | 2 + Driver.cpp | 24 +- Driver.h | 18 +- Track.h | 2 +- application.cpp | 2 + drivermode.cpp | 57 ++- drivermode.h | 1 + driveruilayer.cpp | 849 +++---------------------------------- driveruilayer.h | 15 +- driveruipanels.cpp | 896 ++++++++++++++++++++++++++++++++++++++++ driveruipanels.h | 93 +++++ editormode.cpp | 3 - editoruilayer.cpp | 158 +------ editoruilayer.h | 3 +- editoruipanels.cpp | 196 +++++++++ editoruipanels.h | 24 ++ maszyna.vcxproj.filters | 27 ++ mtable.cpp | 6 +- mtable.h | 6 +- renderer.cpp | 28 +- skydome.cpp | 6 +- stdafx.h | 20 + uilayer.cpp | 194 +++++---- uilayer.h | 49 ++- 25 files changed, 1563 insertions(+), 1118 deletions(-) create mode 100644 driveruipanels.cpp create mode 100644 driveruipanels.h create mode 100644 editoruipanels.cpp create mode 100644 editoruipanels.h diff --git a/AnimModel.h b/AnimModel.h index 16f3a558..f3ddf10e 100644 --- a/AnimModel.h +++ b/AnimModel.h @@ -125,7 +125,7 @@ class TAnimAdvanced class TAnimModel : public scene::basic_node { friend opengl_renderer; - friend editor_ui; + friend itemproperties_panel; public: // constructors diff --git a/Classes.h b/Classes.h index e1c3d2b5..62faa4eb 100644 --- a/Classes.h +++ b/Classes.h @@ -33,6 +33,7 @@ class scenario_time; class TMoverParameters; class ui_layer; class editor_ui; +class itemproperties_panel; class event_manager; class memory_table; class powergridsource_table; @@ -42,6 +43,7 @@ struct light_array; namespace scene { struct node_data; +class basic_node; } namespace Mtable diff --git a/Driver.cpp b/Driver.cpp index 14a54f55..d8034036 100644 --- a/Driver.cpp +++ b/Driver.cpp @@ -321,7 +321,7 @@ bool TSpeedPos::Update() return false; }; -std::string TSpeedPos::GetName() +std::string TSpeedPos::GetName() const { if (iFlags & spTrack) // jeÅ›li tor return trTrack->name(); @@ -331,7 +331,7 @@ std::string TSpeedPos::GetName() return ""; } -std::string TSpeedPos::TableText() +std::string TSpeedPos::TableText() const { // pozycja tabelki pr?dko?ci if (iFlags & spEnabled) { // o ile pozycja istotna @@ -1639,7 +1639,7 @@ TController::~TController() CloseLog(); }; -std::string TController::Order2Str(TOrders Order) +std::string TController::Order2Str(TOrders Order) const { // zamiana kodu rozkazu na opis if (Order & Change_direction) return "Change_direction"; // może być naÅ‚ożona na innÄ… i wtedy ma priorytet @@ -1674,9 +1674,9 @@ std::string TController::Order2Str(TOrders Order) return "Undefined!"; } -std::string TController::OrderCurrent() +std::string TController::OrderCurrent() const { // pobranie aktualnego rozkazu celem wyÅ›wietlenia - return std::to_string(OrderPos) + ". " + Order2Str(OrderList[OrderPos]); + return "[" + std::to_string(OrderPos) + "] " + Order2Str(OrderList[OrderPos]); }; void TController::OrdersClear() @@ -2244,7 +2244,7 @@ void TController::SetVelocity(double NewVel, double NewVelNext, TStopReason r) VelNext = NewVelNext; // prÄ™dkość przy nastÄ™pnym obiekcie } -double TController::BrakeAccFactor() +double TController::BrakeAccFactor() const { double Factor = 1.0; if( ( ActualProximityDist > fMinProximityDist ) @@ -4916,7 +4916,7 @@ TController::UpdateSituation(double dt) { && ( pVehicles[0]->fTrackBlock < 50.0 ) ) { // crude detection of edge case, if approaching another vehicle coast slowly until min distance // this should allow to bunch up trainsets more on sidings - VelDesired = min_speed( VelDesired, 5.0 ); + VelDesired = min_speed( 5.0, VelDesired ); } else { // hamowanie tak, aby stanąć @@ -4934,7 +4934,7 @@ TController::UpdateSituation(double dt) { else { // outside of max safe range AccDesired = AccPreferred; - if( vel > min_speed( 10.0, VelDesired ) ) { + if( vel > min_speed( (ActualProximityDist > 10.0 ? 10.0 : 5.0 ), VelDesired ) ) { // allow to coast at reasonably low speed auto const brakingdistance { fBrakeDist * braking_distance_multiplier( VelNext ) }; auto const slowdowndistance { ( @@ -6026,7 +6026,7 @@ TCommandType TController::BackwardScan() return TCommandType::cm_Unknown; // nic }; -std::string TController::NextStop() +std::string TController::NextStop() const { // informacja o nastÄ™pnym zatrzymaniu, wyÅ›wietlane pod [F1] if (asNextStop == "[End of route]") return ""; // nie zawiera nazwy stacji, gdy dojechaÅ‚ do koÅ„ca @@ -6130,7 +6130,7 @@ TController::TrainTimetable() const { return TrainParams; } -std::string TController::Relation() +std::string TController::Relation() const { // zwraca relacjÄ™ pociÄ…gu return TrainParams->ShowRelation(); }; @@ -6150,7 +6150,7 @@ int TController::StationIndex() const return TrainParams->StationIndex; }; -bool TController::IsStop() +bool TController::IsStop() const { // informuje, czy jest zatrzymanie na najbliższej stacji return TrainParams->IsStop(); }; @@ -6181,7 +6181,7 @@ void TController::ControllingSet() mvControlling = pVehicle->ControlledFind()->MoverParameters; // poszukiwanie czÅ‚onu sterowanego }; -std::string TController::TableText( std::size_t const Index ) +std::string TController::TableText( std::size_t const Index ) const { // pozycja tabelki prÄ™dkoÅ›ci if( Index < sSpeedTable.size() ) { return sSpeedTable[ Index ].TableText(); diff --git a/Driver.h b/Driver.h index 6ec94085..ca01241a 100644 --- a/Driver.h +++ b/Driver.h @@ -154,8 +154,8 @@ class TSpeedPos fDist -= dist; } bool Set(TEvent *e, double d, TOrders order = Wait_for_orders); void Set(TTrack *t, double d, int f); - std::string TableText(); - std::string GetName(); + std::string TableText() const; + std::string GetName() const; bool IsProperSemaphor(TOrders order = Wait_for_orders); }; @@ -205,7 +205,7 @@ public: double fVelMax = -1.0; // maksymalna prÄ™dkość skÅ‚adu (sprawdzany każdy pojazd) public: double fBrakeDist = 0.0; // przybliżona droga hamowania - double BrakeAccFactor(); + double BrakeAccFactor() const; double fBrakeReaction = 1.0; //opóźnienie zadziaÅ‚ania hamulca - czas w s / (km/h) double fAccThreshold = 0.0; // próg opóźnienia dla zadziaÅ‚ania hamulca double AbsAccS_pub = 0.0; // próg opóźnienia dla zadziaÅ‚ania hamulca @@ -349,11 +349,11 @@ private: void OrdersClear(); void OrdersDump(); TController( bool AI, TDynamicObject *NewControll, bool InitPsyche, bool primary = true ); - std::string OrderCurrent(); + std::string OrderCurrent() const; void WaitingSet(double Seconds); private: - std::string Order2Str(TOrders Order); + std::string Order2Str(TOrders Order) const; void DirectionForward(bool forward); int OrderDirectionChange(int newdir, TMoverParameters *Vehicle); void Lights(int head, int rear); @@ -395,11 +395,11 @@ private: void TakeControl(bool yes); Mtable::TTrainParameters const * TrainTimetable() const; std::string TrainName() const; - std::string Relation(); + std::string Relation() const; int StationCount() const; int StationIndex() const; - bool IsStop(); - std::string NextStop(); + bool IsStop() const; + std::string NextStop() const; inline bool Primary() const { return ( ( iDrivigFlags & movePrimary ) != 0 ); }; @@ -411,7 +411,7 @@ private: TrackBlock() const; void MoveTo(TDynamicObject *to); void DirectionInitial(); - std::string TableText(std::size_t const Index); + std::string TableText(std::size_t const Index) const; int CrossRoute(TTrack *tr); /* void RouteSwitch(int d); diff --git a/Track.h b/Track.h index 4218ef0e..1b34b00d 100644 --- a/Track.h +++ b/Track.h @@ -128,7 +128,7 @@ class TTrack : public scene::basic_node { friend opengl_renderer; // NOTE: temporary arrangement - friend editor_ui; + friend itemproperties_panel; private: TIsolated * pIsolated = nullptr; // obwód izolowany obsÅ‚ugujÄ…cy zajÄ™cia/zwolnienia grupy torów diff --git a/application.cpp b/application.cpp index ad12acf1..4680596c 100644 --- a/application.cpp +++ b/application.cpp @@ -153,6 +153,8 @@ eu07_application::exit() { SafeDelete( simulation::Train ); SafeDelete( simulation::Region ); + ui_layer::shutdown(); + glfwDestroyWindow( m_window ); glfwTerminate(); diff --git a/drivermode.cpp b/drivermode.cpp index 0667f0a9..01bec808 100644 --- a/drivermode.cpp +++ b/drivermode.cpp @@ -327,24 +327,12 @@ driver_mode::on_key( int const Key, int const Scancode, int const Action, int co || ( Key == GLFW_KEY_RIGHT_ALT ) ) ) { // if the alt key was pressed toggle control picking mode and set matching cursor behaviour if( Action == GLFW_PRESS ) { - - if( Global.ControlPicking ) { - // switch off - Application.get_cursor_pos( m_input.mouse_pickmodepos.x, m_input.mouse_pickmodepos.y ); - Application.set_cursor( GLFW_CURSOR_DISABLED ); - Application.set_cursor_pos( 0, 0 ); - } - else { - // enter picking mode - Application.set_cursor_pos( m_input.mouse_pickmodepos.x, m_input.mouse_pickmodepos.y ); - Application.set_cursor( GLFW_CURSOR_NORMAL ); - } - // actually toggle the mode - Global.ControlPicking = !Global.ControlPicking; + // toggle picking mode + set_picking( !Global.ControlPicking ); } } - if( Action != GLFW_RELEASE ) { + if( Action == GLFW_PRESS ) { OnKeyDown( Key ); @@ -737,7 +725,7 @@ driver_mode::OnKeyDown(int cKey) { // if (cKey!=VK_F4) return; // nie sÄ… przekazywane do pojazdu wcale } - +/* if ((Global.iTextMode == GLFW_KEY_F12) ? (cKey >= '0') && (cKey <= '9') : false) { // tryb konfiguracji debugmode (przestawianie kamery już wyłączone if (!Global.shiftState) // bez [Shift] @@ -757,14 +745,21 @@ driver_mode::OnKeyDown(int cKey) { // else if (cKey=='3') Global.iWriteLogEnabled^=4; //wypisywanie nazw torów } } - else if( cKey == GLFW_KEY_ESCAPE ) { + else */ + if( cKey == GLFW_KEY_ESCAPE ) { // toggle pause - if( Global.iPause & 1 ) // jeÅ›li pauza startowa - Global.iPause &= ~1; // odpauzowanie, gdy po wczytaniu miaÅ‚o nie startować - else if( !( Global.iMultiplayer & 2 ) ) // w multiplayerze pauza nie ma sensu + if( Global.iPause & 1 ) { + // jeÅ›li pauza startowa + // odpauzowanie, gdy po wczytaniu miaÅ‚o nie startować + Global.iPause &= ~1; + } + else if( ( Global.iMultiplayer & 2 ) == 0 ) { + // w multiplayerze pauza nie ma sensu Global.iPause ^= 2; // zmiana stanu zapauzowania - if( Global.iPause ) {// jak pauza - Global.iTextMode = GLFW_KEY_F1; // to wyÅ›wietlić zegar i informacjÄ™ + if( ( Global.iPause & 2 ) + && ( false == Global.ControlPicking ) ) { + set_picking( true ); + } } } else { @@ -992,3 +987,21 @@ driver_mode::InOutKey( bool const Near ) // update window title to reflect the situation Application.set_title( Global.AppName + " (" + ( train != nullptr ? train->Occupied()->Name : "" ) + " @ " + Global.SceneryFile + ")" ); } + +void +driver_mode::set_picking( bool const Picking ) { + + if( Picking ) { + // enter picking mode + Application.set_cursor_pos( m_input.mouse_pickmodepos.x, m_input.mouse_pickmodepos.y ); + Application.set_cursor( GLFW_CURSOR_NORMAL ); + } + else { + // switch off + Application.get_cursor_pos( m_input.mouse_pickmodepos.x, m_input.mouse_pickmodepos.y ); + Application.set_cursor( GLFW_CURSOR_DISABLED ); + Application.set_cursor_pos( 0, 0 ); + } + // actually toggle the mode + Global.ControlPicking = Picking; +} diff --git a/drivermode.h b/drivermode.h index 66701ca8..297da859 100644 --- a/drivermode.h +++ b/drivermode.h @@ -73,6 +73,7 @@ private: void InOutKey( bool const Near = true ); void FollowView( bool wycisz = true ); void DistantView( bool const Near = false ); + void set_picking( bool const Picking ); // members drivermode_input m_input; diff --git a/driveruilayer.cpp b/driveruilayer.cpp index 08fb23b0..19c1bd5b 100644 --- a/driveruilayer.cpp +++ b/driveruilayer.cpp @@ -28,21 +28,18 @@ http://mozilla.org/MPL/2.0/. driver_ui::driver_ui() { - clear_texts(); -/* - UIHeader = std::make_shared( 20, 20 ); // header ui panel - UITable = std::make_shared( 20, 100 ); // schedule or scan table - UITranscripts = std::make_shared( 85, 600 ); // voice transcripts -*/ - // make 4 empty lines for the ui header, to cut down on work down the road - UIHeader.text_lines.emplace_back( "", Global.UITextColor ); - UIHeader.text_lines.emplace_back( "", Global.UITextColor ); - UIHeader.text_lines.emplace_back( "", Global.UITextColor ); - UIHeader.text_lines.emplace_back( "", Global.UITextColor ); + clear_panels(); // bind the panels with ui object. maybe not the best place for this but, eh - push_back( &UIHeader ); - push_back( &UITable ); - push_back( &UITranscripts ); + push_back( &m_aidpanel ); + push_back( &m_timetablepanel ); + push_back( &m_debugpanel ); + push_back( &m_transcriptspanel ); + + m_timetablepanel.size_min = { 435, 110 }; + m_timetablepanel.size_max = { 435, Global.iWindowHeight * 0.95 }; + + m_transcriptspanel.size_min = { 435, 85 }; + m_transcriptspanel.size_max = { Global.iWindowWidth * 0.95, Global.iWindowHeight * 0.95 }; } // potentially processes provided input key. returns: true if key was processed, false otherwise @@ -55,9 +52,6 @@ driver_ui::on_key( int const Key, int const Action ) { case GLFW_KEY_F1: case GLFW_KEY_F2: - case GLFW_KEY_F3: - case GLFW_KEY_F8: - case GLFW_KEY_F9: case GLFW_KEY_F10: case GLFW_KEY_F12: { // ui mode selectors @@ -67,15 +61,7 @@ driver_ui::on_key( int const Key, int const Action ) { return false; } - if( Action == GLFW_RELEASE ) { return true; } // recognized, but ignored -/* - EditorModeFlag = ( Key == GLFW_KEY_F11 ); - if( ( true == EditorModeFlag ) - && ( false == Global.ControlPicking ) ) { - set_cursor( GLFW_CURSOR_NORMAL ); - Global.ControlPicking = true; - } -*/ + if( Action != GLFW_PRESS ) { return true; } // recognized, but ignored } default: { // everything else @@ -87,91 +73,35 @@ driver_ui::on_key( int const Key, int const Action ) { case GLFW_KEY_F1: { // basic consist info - if( Global.iTextMode == Key ) { ++Global.iScreenMode[ Key - GLFW_KEY_F1 ]; } - if( Global.iScreenMode[ Key - GLFW_KEY_F1 ] > 1 ) { - // wyłączenie napisów - Global.iTextMode = 0; - Global.iScreenMode[ Key - GLFW_KEY_F1 ] = 0; - } - else { - Global.iTextMode = Key; - } + auto state = ( + ( m_aidpanel.is_open == false ) ? 0 : + ( m_aidpanel.is_expanded == false ) ? 1 : + 2 ); + state = clamp_circular( ++state, 3 ); + + m_aidpanel.is_open = ( state > 0 ); + m_aidpanel.is_expanded = ( state > 1 ); + return true; } case GLFW_KEY_F2: { - // parametry pojazdu - if( Global.iTextMode == Key ) { ++Global.iScreenMode[ Key - GLFW_KEY_F1 ]; } - if( Global.iScreenMode[ Key - GLFW_KEY_F1 ] > 1 ) { - // wyłączenie napisów - Global.iTextMode = 0; - Global.iScreenMode[ Key - GLFW_KEY_F1 ] = 0; - } - else { - Global.iTextMode = Key; - } - return true; - } - - case GLFW_KEY_F3: { // timetable - if( Global.iTextMode == Key ) { ++Global.iScreenMode[ Key - GLFW_KEY_F1 ]; } - if( Global.iScreenMode[ Key - GLFW_KEY_F1 ] > 1 ) { - // wyłączenie napisów - Global.iTextMode = 0; - Global.iScreenMode[ Key - GLFW_KEY_F1 ] = 0; - } - else { - Global.iTextMode = Key; - } + auto state = ( + ( m_timetablepanel.is_open == false ) ? 0 : + ( m_timetablepanel.is_expanded == false ) ? 1 : + 2 ); + state = clamp_circular( ++state, 3 ); + + m_timetablepanel.is_open = ( state > 0 ); + m_timetablepanel.is_expanded = ( state > 1 ); + return true; } - case GLFW_KEY_F8: { - // renderer debug data - Global.iTextMode = Key; - return true; - } - - case GLFW_KEY_F9: { - // wersja - Global.iTextMode = Key; - return true; - } - - case GLFW_KEY_F10: { - // quit - if( Global.iTextMode == Key ) { - Global.iTextMode = - ( Global.iPause && ( Key != GLFW_KEY_F1 ) ? - GLFW_KEY_F1 : - 0 ); // wyłączenie napisów, chyba że pauza - } - else { - Global.iTextMode = Key; - } - return true; - } -/* - case GLFW_KEY_F11: { - // scenario inspector - Global.iTextMode = Key; - return true; - } -*/ case GLFW_KEY_F12: { - // coÅ› tam jeszcze - Global.iTextMode = Key; - return true; - } - - case GLFW_KEY_Y: { - // potentially quit - if( Global.iTextMode != GLFW_KEY_F10 ) { return false; } // not in quit mode - - if( Action == GLFW_RELEASE ) { return true; } // recognized, but ignored - - glfwSetWindowShouldClose( m_window, 1 ); + // debug panel + m_debugpanel.is_open = !m_debugpanel.is_open; return true; } @@ -187,13 +117,9 @@ driver_ui::on_key( int const Key, int const Action ) { void driver_ui::update() { - UITable.text_lines.clear(); - std::string uitextline1, uitextline2, uitextline3, uitextline4; set_tooltip( "" ); auto const *train { simulation::Train }; - auto const *controlled { ( train ? train->Dynamic() : nullptr ) }; - auto const &camera { Global.pCamera }; if( ( train != nullptr ) && ( false == FreeFlyModeFlag ) ) { if( false == DebugModeFlag ) { @@ -214,691 +140,28 @@ driver_ui::update() { "" ) ); } - switch( Global.iTextMode ) { - - case( GLFW_KEY_F1 ) : { - // f1, default mode: current time and timetable excerpt - auto const &time = simulation::Time.data(); - uitextline1 = - "Time: " - + to_string( time.wHour ) + ":" - + ( time.wMinute < 10 ? "0" : "" ) + to_string( time.wMinute ) + ":" - + ( time.wSecond < 10 ? "0" : "" ) + to_string( time.wSecond ); - if( Global.iPause ) { - uitextline1 += " (paused)"; - } - - if( ( controlled != nullptr ) - && ( controlled->Mechanik != nullptr ) ) { - - auto const *mover = controlled->MoverParameters; - auto const *driver = controlled->Mechanik; - - uitextline2 = "Throttle: " + to_string( driver->Controlling()->MainCtrlPos, 0, 2 ) + "+" + std::to_string( driver->Controlling()->ScndCtrlPos ); - if( mover->ActiveDir > 0 ) { uitextline2 += " D"; } - else if( mover->ActiveDir < 0 ) { uitextline2 += " R"; } - else { uitextline2 += " N"; } - - uitextline3 = "Brakes:" + to_string( mover->fBrakeCtrlPos, 1, 5 ) + "+" + to_string( mover->LocalBrakePosA * LocalBrakePosNo, 0 ) + ( mover->SlippingWheels ? " !" : " " ); - - uitextline4 = ( - true == TestFlag( mover->SecuritySystem.Status, s_aware ) ? - "!ALERTER! " : - " " ); - uitextline4 += ( - true == TestFlag( mover->SecuritySystem.Status, s_active ) ? - "!SHP! " : - " " ); - - if( Global.iScreenMode[ Global.iTextMode - GLFW_KEY_F1 ] == 1 ) { - // detail mode on second key press - auto const speedlimit { static_cast( std::floor( driver->VelDesired ) ) }; - uitextline2 += - " Speed: " + std::to_string( static_cast( std::floor( mover->Vel ) ) ) + " km/h" - + " (limit: " + std::to_string( speedlimit ) + " km/h"; - auto const nextspeedlimit { static_cast( std::floor( driver->VelNext ) ) }; - if( nextspeedlimit != speedlimit ) { - uitextline2 += - ", new limit: " + std::to_string( nextspeedlimit ) + " km/h" - + " in " + to_string( driver->ActualProximityDist * 0.001, 1 ) + " km"; - } - uitextline2 += ")"; - auto const reverser { ( mover->ActiveDir > 0 ? 1 : -1 ) }; - auto const grade { controlled->VectorFront().y * 100 * ( controlled->DirectionGet() == reverser ? 1 : -1 ) * reverser }; - if( std::abs( grade ) >= 0.25 ) { - uitextline2 += " Grade: " + to_string( grade, 1 ) + "%"; - } - uitextline3 += - " Pressure: " + to_string( mover->BrakePress * 100.0, 2 ) + " kPa" - + " (train pipe: " + to_string( mover->PipePress * 100.0, 2 ) + " kPa)"; - - auto const stoptime { static_cast( -1.0 * controlled->Mechanik->fStopTime ) }; - if( stoptime > 0 ) { - uitextline4 += " Loading/unloading in progress (" + to_string( stoptime ) + ( stoptime > 1 ? " seconds" : " second" ) + " left)"; - } - else { - auto const trackblockdistance{ std::abs( controlled->Mechanik->TrackBlock() ) }; - if( trackblockdistance <= 75.0 ) { - uitextline4 += " Another vehicle ahead (distance: " + to_string( trackblockdistance, 1 ) + " m)"; - } - } - } - } - - break; - } - - case( GLFW_KEY_F2 ) : { - // timetable - auto *vehicle { - ( FreeFlyModeFlag ? - std::get( simulation::Region->find_vehicle( camera.Pos, 20, false, false ) ) : - controlled ) }; // w trybie latania lokalizujemy wg mapy - - if( vehicle == nullptr ) { break; } - // if the nearest located vehicle doesn't have a direct driver, try to query its owner - auto const owner = ( - ( ( vehicle->Mechanik != nullptr ) && ( vehicle->Mechanik->Primary() ) ) ? - vehicle->Mechanik : - vehicle->ctOwner ); - if( owner == nullptr ){ break; } - - auto const *table = owner->TrainTimetable(); - if( table == nullptr ) { break; } - - auto const &time = simulation::Time.data(); - uitextline1 = - "Time: " - + to_string( time.wHour ) + ":" - + ( time.wMinute < 10 ? "0" : "" ) + to_string( time.wMinute ) + ":" - + ( time.wSecond < 10 ? "0" : "" ) + to_string( time.wSecond ); - if( Global.iPause ) { - uitextline1 += " (paused)"; - } - - uitextline2 = Bezogonkow( owner->Relation(), true ) + " (" + Bezogonkow( owner->TrainName(), true ) + ")"; - auto const nextstation = Bezogonkow( owner->NextStop(), true ); - if( !nextstation.empty() ) { - // jeÅ›li jest podana relacja, to dodajemy punkt nastÄ™pnego zatrzymania - uitextline3 = " -> " + nextstation; - } - - if( Global.iScreenMode[ Global.iTextMode - GLFW_KEY_F1 ] == 1 ) { - - if( 0 == table->StationCount ) { - // only bother if there's stations to list - UITable.text_lines.emplace_back( "(no timetable)", Global.UITextColor ); - } - else { - // header - UITable.text_lines.emplace_back( "+-----+------------------------------------+-------+-----+", Global.UITextColor ); - - TMTableLine const *tableline; - for( int i = owner->iStationStart; i <= std::min( owner->iStationStart + 10, table->StationCount ); ++i ) { - // wyÅ›wietlenie pozycji z rozkÅ‚adu - tableline = table->TimeTable + i; // linijka rozkÅ‚adu - - std::string vmax = - " " - + to_string( tableline->vmax, 0 ); - vmax = vmax.substr( vmax.size() - 3, 3 ); // z wyrównaniem do prawej - std::string const station = ( - Bezogonkow( tableline->StationName, true ) - + " " ) - .substr( 0, 34 ); - std::string const location = ( - ( tableline->km > 0.0 ? - to_string( tableline->km, 2 ) : - "" ) - + " " ) - .substr( 0, 34 - tableline->StationWare.size() ); - std::string const arrival = ( - tableline->Ah >= 0 ? - to_string( int( 100 + tableline->Ah ) ).substr( 1, 2 ) + ":" + to_string( int( 100 + tableline->Am ) ).substr( 1, 2 ) : - " | " ); - std::string const departure = ( - tableline->Dh >= 0 ? - to_string( int( 100 + tableline->Dh ) ).substr( 1, 2 ) + ":" + to_string( int( 100 + tableline->Dm ) ).substr( 1, 2 ) : - " | " ); - auto const candeparture = ( - ( owner->iStationStart < table->StationIndex ) - && ( i < table->StationIndex ) - && ( ( time.wHour * 60 + time.wMinute ) >= ( tableline->Dh * 60 + tableline->Dm ) ) ); - auto traveltime = - " " - + ( i < 2 ? "" : - tableline->Ah >= 0 ? to_string( CompareTime( table->TimeTable[ i - 1 ].Dh, table->TimeTable[ i - 1 ].Dm, tableline->Ah, tableline->Am ), 0 ) : - to_string( std::max( 0.0, CompareTime( table->TimeTable[ i - 1 ].Dh, table->TimeTable[ i - 1 ].Dm, tableline->Dh, tableline->Dm ) - 0.5 ), 0 ) ); - traveltime = traveltime.substr( traveltime.size() - 3, 3 ); // z wyrównaniem do prawej - - UITable.text_lines.emplace_back( - ( "| " + vmax + " | " + station + " | " + arrival + " | " + traveltime + " |" ), - ( candeparture ? - glm::vec4( 0.0f, 1.0f, 0.0f, 1.0f ) :// czas minÄ…Å‚ i odjazd byÅ‚, to nazwa stacji bÄ™dzie na zielono - Global.UITextColor ) ); - UITable.text_lines.emplace_back( - ( "| | " + location + tableline->StationWare + " | " + departure + " | |" ), - ( candeparture ? - glm::vec4( 0.0f, 1.0f, 0.0f, 1.0f ) :// czas minÄ…Å‚ i odjazd byÅ‚, to nazwa stacji bÄ™dzie na zielono - Global.UITextColor ) ); - // divider/footer - UITable.text_lines.emplace_back( "+-----+------------------------------------+-------+-----+", Global.UITextColor ); - } - if( owner->iStationStart + 10 < table->StationCount ) { - // if we can't display entire timetable, add a scrolling indicator at the bottom - UITable.text_lines.emplace_back( " ... ", Global.UITextColor ); - } - } - } - - break; - } - - case( GLFW_KEY_F3 ) : { - - auto const *vehicle { - ( FreeFlyModeFlag ? - std::get( simulation::Region->find_vehicle( camera.Pos, 20, false, false ) ) : - controlled ) }; // w trybie latania lokalizujemy wg mapy - - if( vehicle != nullptr ) { - // jeÅ›li domyÅ›lny ekran po pierwszym naciÅ›niÄ™ciu - auto const *mover { vehicle->MoverParameters }; - - uitextline1 = "Vehicle name: " + mover->Name; - - if( ( vehicle->Mechanik == nullptr ) && ( vehicle->ctOwner ) ) { - // for cars other than leading unit indicate the leader - uitextline1 += ", owned by " + vehicle->ctOwner->OwnerName(); - } - uitextline1 += "; Status: " + mover->EngineDescription( 0 ); - - // informacja o sprzÄ™gach - uitextline1 += - "; C0:" + - ( vehicle->PrevConnected ? - vehicle->PrevConnected->name() + ":" + to_string( mover->Couplers[ 0 ].CouplingFlag ) + ( - mover->Couplers[ 0 ].CouplingFlag == 0 ? - " (" + to_string( mover->Couplers[ 0 ].CoupleDist, 1 ) + " m)" : - "" ) : - "none" ); - uitextline1 += - " C1:" + - ( vehicle->NextConnected ? - vehicle->NextConnected->name() + ":" + to_string( mover->Couplers[ 1 ].CouplingFlag ) + ( - mover->Couplers[ 1 ].CouplingFlag == 0 ? - " (" + to_string( mover->Couplers[ 1 ].CoupleDist, 1 ) + " m)" : - "" ) : - "none" ); - - // equipment flags - uitextline2 = ( mover->Battery ? "B" : "." ); - uitextline2 += ( mover->Mains ? "M" : "." ); - uitextline2 += ( mover->PantRearUp ? ( mover->PantRearVolt > 0.0 ? "O" : "o" ) : "." ); - uitextline2 += ( mover->PantFrontUp ? ( mover->PantFrontVolt > 0.0 ? "P" : "p" ) : "." ); - uitextline2 += ( mover->PantPressLockActive ? "!" : ( mover->PantPressSwitchActive ? "*" : "." ) ); - uitextline2 += ( mover->WaterPump.is_active ? "W" : ( false == mover->WaterPump.breaker ? "-" : ( mover->WaterPump.is_enabled ? "w" : "." ) ) ); - uitextline2 += ( true == mover->WaterHeater.is_damaged ? "!" : ( mover->WaterHeater.is_active ? "H" : ( false == mover->WaterHeater.breaker ? "-" : ( mover->WaterHeater.is_enabled ? "h" : "." ) ) ) ); - uitextline2 += ( mover->FuelPump.is_active ? "F" : ( mover->FuelPump.is_enabled ? "f" : "." ) ); - uitextline2 += ( mover->OilPump.is_active ? "O" : ( mover->OilPump.is_enabled ? "o" : "." ) ); - uitextline2 += ( false == mover->ConverterAllowLocal ? "-" : ( mover->ConverterAllow ? ( mover->ConverterFlag ? "X" : "x" ) : "." ) ); - uitextline2 += ( mover->ConvOvldFlag ? "!" : "." ); - uitextline2 += ( mover->CompressorFlag ? "C" : ( false == mover->CompressorAllowLocal ? "-" : ( ( mover->CompressorAllow || mover->CompressorStart == start_t::automatic ) ? "c" : "." ) ) ); - uitextline2 += ( mover->CompressorGovernorLock ? "!" : "." ); - - auto const *train { simulation::Train }; - if( ( train != nullptr ) && ( train->Dynamic() == vehicle ) ) { - uitextline2 += ( mover->Radio ? " R: " : " r: " ) + std::to_string( train->RadioChannel() ); - } - uitextline2 += " Bdelay: "; - if( ( mover->BrakeDelayFlag & bdelay_G ) == bdelay_G ) - uitextline2 += "G"; - if( ( mover->BrakeDelayFlag & bdelay_P ) == bdelay_P ) - uitextline2 += "P"; - if( ( mover->BrakeDelayFlag & bdelay_R ) == bdelay_R ) - uitextline2 += "R"; - if( ( mover->BrakeDelayFlag & bdelay_M ) == bdelay_M ) - uitextline2 += "+Mg"; - - uitextline2 += ", Load: " + to_string( mover->Load, 0 ) + " (" + to_string( mover->LoadFlag, 0 ) + ")"; - - uitextline2 += - "; Pant: " - + to_string( mover->PantPress, 2 ) - + ( mover->bPantKurek3 ? "-ZG" : "|ZG" ); - - uitextline2 += - "; Ft: " + to_string( - mover->Ft * 0.001f * ( - mover->ActiveCab ? mover->ActiveCab : - vehicle->ctOwner ? vehicle->ctOwner->Controlling()->ActiveCab : - 1 ), 1 ) - + ", Fb: " + to_string( mover->Fb * 0.001f, 1 ) - + ", Fr: " + to_string( mover->Adhesive( mover->RunningTrack.friction ), 2 ) - + ( mover->SlippingWheels ? " (!)" : "" ); - - if( vehicle->Mechanik ) { - uitextline2 += "; Ag: " + to_string( vehicle->Mechanik->fAccGravity, 2 ) + " (" + ( vehicle->Mechanik->fAccGravity > 0.01 ? "\\" : ( vehicle->Mechanik->fAccGravity < -0.01 ? "/" : "-" ) ) + ")"; - } - - uitextline2 += - "; TC:" - + to_string( mover->TotalCurrent, 0 ); - auto const frontcouplerhighvoltage = - to_string( mover->Couplers[ side::front ].power_high.voltage, 0 ) - + "@" - + to_string( mover->Couplers[ side::front ].power_high.current, 0 ); - auto const rearcouplerhighvoltage = - to_string( mover->Couplers[ side::rear ].power_high.voltage, 0 ) - + "@" - + to_string( mover->Couplers[ side::rear ].power_high.current, 0 ); - uitextline2 += ", HV: "; - if( mover->Couplers[ side::front ].power_high.local == false ) { - uitextline2 += - "(" + frontcouplerhighvoltage + ")-" - + ":F" + ( vehicle->DirectionGet() ? "<<" : ">>" ) + "R:" - + "-(" + rearcouplerhighvoltage + ")"; - } - else { - uitextline2 += - frontcouplerhighvoltage - + ":F" + ( vehicle->DirectionGet() ? "<<" : ">>" ) + "R:" - + rearcouplerhighvoltage; - } - - uitextline3 += - "TrB: " + to_string( mover->BrakePress, 2 ) - + ", " + to_hex_str( mover->Hamulec->GetBrakeStatus(), 2 ); - - uitextline3 += - "; LcB: " + to_string( mover->LocBrakePress, 2 ) - + "; hat: " + to_string( mover->BrakeCtrlPos2, 2 ) - + "; pipes: " + to_string( mover->PipePress, 2 ) - + "/" + to_string( mover->ScndPipePress, 2 ) - + "/" + to_string( mover->EqvtPipePress, 2 ) - + ", MT: " + to_string( mover->CompressedVolume, 3 ) - + ", BT: " + to_string( mover->Volume, 3 ) - + ", CtlP: " + to_string( mover->CntrlPipePress, 3 ) - + ", CtlT: " + to_string( mover->Hamulec->GetCRP(), 3 ); - - if( mover->ManualBrakePos > 0 ) { - - uitextline3 += "; manual brake on"; - } - - if( vehicle->Mechanik ) { - // o ile jest ktoÅ› w Å›rodku - std::string flags = "cpapcplhhndoiefgvdpseil "; // flagi AI (definicja w Driver.h) - for( int i = 0, j = 1; i < 23; ++i, j <<= 1 ) - if( false == ( vehicle->Mechanik->DrivigFlags() & j ) ) // jak bit ustawiony - flags[ i ] = '.';// std::toupper( flags[ i ] ); // ^= 0x20; // to zmiana na wielkÄ… literÄ™ - - uitextline4 = flags; - - uitextline4 += - "Driver: Vd=" + to_string( vehicle->Mechanik->VelDesired, 0 ) - + " Ad=" + to_string( vehicle->Mechanik->AccDesired, 2 ) - + " Ah=" + to_string( vehicle->Mechanik->fAccThreshold, 2 ) - + "@" + to_string( vehicle->Mechanik->fBrake_a0[ 0 ], 2 ) - + "+" + to_string( vehicle->Mechanik->fBrake_a1[ 0 ], 2 ) - + " Bd=" + to_string( vehicle->Mechanik->fBrakeDist, 0 ) - + " Pd=" + to_string( vehicle->Mechanik->ActualProximityDist, 0 ) - + " Vn=" + to_string( vehicle->Mechanik->VelNext, 0 ) - + " VSl=" + to_string( vehicle->Mechanik->VelSignalLast, 0 ) - + " VLl=" + to_string( vehicle->Mechanik->VelLimitLast, 0 ) - + " VRd=" + to_string( vehicle->Mechanik->VelRoad, 0 ) - + " VRst=" + to_string( vehicle->Mechanik->VelRestricted, 0 ); - - if( ( vehicle->Mechanik->VelNext == 0.0 ) - && ( vehicle->Mechanik->eSignNext ) ) { - // jeÅ›li ma zapamiÄ™tany event semafora, nazwa eventu semafora - uitextline4 += " (" + Bezogonkow( vehicle->Mechanik->eSignNext->asName ) + ")"; - } - - // biezaca komenda dla AI - uitextline4 += ", command: " + vehicle->Mechanik->OrderCurrent(); - } - - if( Global.iScreenMode[ Global.iTextMode - GLFW_KEY_F1 ] == 1 ) { - // f2 screen, track scan mode - if( vehicle->Mechanik == nullptr ) { - //żeby byÅ‚a tabelka, musi być AI - break; - } - - std::size_t i = 0; std::size_t const speedtablesize = clamp( static_cast( vehicle->Mechanik->TableSize() ) - 1, 0, 30 ); - do { - std::string scanline = vehicle->Mechanik->TableText( i ); - if( scanline.empty() ) { break; } - UITable.text_lines.emplace_back( Bezogonkow( scanline ), Global.UITextColor ); - ++i; - } while( i < speedtablesize ); // TController:iSpeedTableSize TODO: change when the table gets recoded - } - } - else { - // wyÅ›wietlenie współrzÄ™dnych w scenerii oraz kÄ…ta kamery, gdy nie mamy wskaźnika - uitextline1 = - "Camera position: " - + to_string( camera.Pos.x, 2 ) + " " - + to_string( camera.Pos.y, 2 ) + " " - + to_string( camera.Pos.z, 2 ) - + ", azimuth: " - + to_string( 180.0 - glm::degrees( camera.Yaw ), 0 ) // ma być azymut, czyli 0 na północy i roÅ›nie na wschód - + " " - + std::string( "S SEE NEN NWW SW" ) - .substr( 0 + 2 * floor( fmod( 8 + ( camera.Yaw + 0.5 * M_PI_4 ) / M_PI_4, 8 ) ), 2 ); - // current luminance level - uitextline2 = "Light level: " + to_string( Global.fLuminance, 3 ); - if( Global.FakeLight ) { uitextline2 += "(*)"; } - } - - break; - } - - case( GLFW_KEY_F8 ) : { - // gfx renderer data - uitextline1 = - "FoV: " + to_string( Global.FieldOfView / Global.ZoomFactor, 1 ) - + ", Draw range x " + to_string( Global.fDistanceFactor, 1 ) -// + "; sectors: " + std::to_string( GfxRenderer.m_drawcount ) -// + ", FPS: " + to_string( Timer::GetFPS(), 2 ); - + ", FPS: " + std::to_string( static_cast(std::round(GfxRenderer.Framerate())) ); - if( Global.iSlowMotion ) { - uitextline1 += " (slowmotion " + to_string( Global.iSlowMotion ) + ")"; - } - - uitextline2 = - std::string( "Rendering mode: " ) - + ( Global.bUseVBO ? - "VBO" : - "Display Lists" ) - + " "; - if( false == Global.LastGLError.empty() ) { - uitextline2 += - "Last openGL error: " - + Global.LastGLError; - } - // renderer stats - uitextline3 = GfxRenderer.info_times(); - uitextline4 = GfxRenderer.info_stats(); - - break; - } - - case( GLFW_KEY_F9 ) : { - // informacja o wersji - uitextline1 = "MaSzyna " + Global.asVersion; // informacja o wersji - if( Global.iMultiplayer ) { - uitextline1 += " (multiplayer mode is active)"; - } - uitextline3 = - "vehicles: " + to_string( Timer::subsystem.sim_dynamics.average(), 2 ) + " msec" - + " update total: " + to_string( Timer::subsystem.sim_total.average(), 2 ) + " msec"; - // current event queue - auto const time { Timer::GetTime() }; - auto const *event { simulation::Events.begin() }; - auto eventtableindex{ 0 }; - while( ( event != nullptr ) - && ( eventtableindex < 30 ) ) { - - if( ( false == event->m_ignored ) - && ( true == event->bEnabled ) ) { - - auto const delay { " " + to_string( std::max( 0.0, event->fStartTime - time ), 1 ) }; - auto const eventline = - "Delay: " + delay.substr( delay.length() - 6 ) - + ", Event: " + event->asName - + ( event->Activator ? " (by: " + event->Activator->asName + ")" : "" ) - + ( event->evJoined ? " (joint event)" : "" ); - - UITable.text_lines.emplace_back( eventline, Global.UITextColor ); - ++eventtableindex; - } - event = event->evNext; - } - - break; - } - - case( GLFW_KEY_F10 ) : { - - uitextline1 = "Press [Y] key to quit / Aby zakonczyc program, przycisnij klawisz [Y]."; - - break; - } - - case( GLFW_KEY_F12 ) : { - // opcje włączenia i wyłączenia logowania - uitextline1 = "[0] Debugmode " + std::string( DebugModeFlag ? "(on)" : "(off)" ); - uitextline2 = "[1] log.txt " + std::string( ( Global.iWriteLogEnabled & 1 ) ? "(on)" : "(off)" ); - uitextline3 = "[2] Console " + std::string( ( Global.iWriteLogEnabled & 2 ) ? "(on)" : "(off)" ); - - break; - } - - default: { - // uncovered cases, nothing to do here... - // ... unless we're in debug mode - if( DebugModeFlag ) { - - auto const *vehicle { - ( FreeFlyModeFlag ? - std::get( simulation::Region->find_vehicle( camera.Pos, 20, false, false ) ) : - controlled ) }; // w trybie latania lokalizujemy wg mapy - if( vehicle == nullptr ) { - break; - } - auto const *mover { vehicle->MoverParameters }; - uitextline1 = - "vel: " + to_string( vehicle->GetVelocity(), 2 ) + "/" + to_string( mover->nrot* M_PI * mover->WheelDiameter * 3.6, 2 ) - + " km/h;" + ( mover->SlippingWheels ? " (!)" : " " ) - + " dist: " + to_string( mover->DistCounter, 2 ) + " km" - + "; pos: [" + to_string( vehicle->GetPosition().x, 2 ) + ", " + to_string( vehicle->GetPosition().y, 2 ) + ", " + to_string( vehicle->GetPosition().z, 2 ) + "]" - + ", PM=" + to_string( mover->WheelFlat, 1 ) - + " mm; enpwr=" + to_string( mover->EnginePower, 1 ) - + "; enrot=" + to_string( mover->enrot * 60, 0 ) - + " tmrot=" + to_string( std::abs( mover->nrot ) * mover->Transmision.Ratio * 60, 0 ) - + "; ventrot=" + to_string( mover->RventRot * 60, 1 ) - + "; fanrot=" + to_string( mover->dizel_heat.rpmw, 1 ) + ", " + to_string( mover->dizel_heat.rpmw2, 1 ); - - uitextline2 = - "HamZ=" + to_string( mover->fBrakeCtrlPos, 2 ) - + "; HamP=" + to_string( mover->LocalBrakePosA, 2 ) - + "; NasJ=" + std::to_string( mover->MainCtrlPos ) + "(" + std::to_string( mover->MainCtrlActualPos ) + ")" - + ( ( mover->ShuntMode && mover->EngineType == TEngineType::DieselElectric ) ? - "; NasB=" + to_string( mover->AnPos, 2 ) : - "; NasB=" + std::to_string( mover->ScndCtrlPos ) + "(" + std::to_string( mover->ScndCtrlActualPos ) + ")" ) - + "; I=" + - ( mover->TrainType == dt_EZT ? - std::to_string( int( mover->ShowCurrent( 0 ) ) ) : - std::to_string( int( mover->Im ) ) ) - + "; U=" + to_string( int( mover->RunningTraction.TractionVoltage + 0.5 ) ) - + "; R=" + - ( std::abs( mover->RunningShape.R ) > 10000.0 ? - "~0.0" : - to_string( mover->RunningShape.R, 1 ) ) - + " An=" + to_string( mover->AccN, 2 ); // przyspieszenie poprzeczne - - if( tprev != simulation::Time.data().wSecond ) { - tprev = simulation::Time.data().wSecond; - Acc = ( mover->Vel - VelPrev ) / 3.6; - VelPrev = mover->Vel; - } - uitextline2 += "; As=" + to_string( Acc, 2 ); // przyspieszenie wzdÅ‚użne -// uitextline2 += " eAngle=" + to_string( std::cos( mover->eAngle ), 2 ); - uitextline2 += "; oilP=" + to_string( mover->OilPump.pressure_present, 3 ); - uitextline2 += " oilT=" + to_string( mover->dizel_heat.To, 2 ); - uitextline2 += "; waterT=" + to_string( mover->dizel_heat.temperatura1, 2 ); - uitextline2 += ( mover->WaterCircuitsLink ? "-" : "|" ); - uitextline2 += to_string( mover->dizel_heat.temperatura2, 2 ); - uitextline2 += "; engineT=" + to_string( mover->dizel_heat.Ts, 2 ); - - uitextline3 = - "cyl.ham. " + to_string( mover->BrakePress, 2 ) - + "; prz.gl. " + to_string( mover->PipePress, 2 ) - + "; zb.gl. " + to_string( mover->CompressedVolume, 2 ) - // youBy - drugi wezyk - + "; p.zas. " + to_string( mover->ScndPipePress, 2 ); - - // McZapkie: warto wiedziec w jakim stanie sa przelaczniki - if( mover->ConvOvldFlag ) - uitextline3 += " C! "; - else if( mover->FuseFlag ) - uitextline3 += " F! "; - else if( !mover->Mains ) - uitextline3 += " () "; - else { - switch( - mover->ActiveDir * - ( mover->Imin == mover->IminLo ? - 1 : - 2 ) ) { - case 2: { uitextline3 += " >> "; break; } - case 1: { uitextline3 += " -> "; break; } - case 0: { uitextline3 += " -- "; break; } - case -1: { uitextline3 += " <- "; break; } - case -2: { uitextline3 += " << "; break; } - } - } - // McZapkie: predkosc szlakowa - if( mover->RunningTrack.Velmax == -1 ) { - uitextline3 += " Vtrack=Vmax"; - } - else { - uitextline3 += " Vtrack " + to_string( mover->RunningTrack.Velmax, 2 ); - } - - if( ( mover->EnginePowerSource.SourceType == TPowerSource::CurrentCollector ) - || ( mover->TrainType == dt_EZT ) ) { - uitextline3 += - "; pant. " + to_string( mover->PantPress, 2 ) - + ( mover->bPantKurek3 ? "=" : "^" ) + "ZG"; - } - - // McZapkie: komenda i jej parametry - if( mover->CommandIn.Command != ( "" ) ) { - uitextline4 = - "C:" + mover->CommandIn.Command - + " V1=" + to_string( mover->CommandIn.Value1, 0 ) - + " V2=" + to_string( mover->CommandIn.Value2, 0 ); - } - if( ( vehicle->Mechanik ) - && ( vehicle->Mechanik->AIControllFlag == AIdriver ) ) { - uitextline4 += - "AI: Vd=" + to_string( vehicle->Mechanik->VelDesired, 0 ) - + " ad=" + to_string(vehicle->Mechanik->AccDesired, 2) - + "/" + to_string(vehicle->Mechanik->AccDesired*vehicle->Mechanik->BrakeAccFactor(), 2) - + " atrain=" + to_string(vehicle->Mechanik->fBrake_a0[0], 2) - + "+" + to_string(vehicle->Mechanik->fBrake_a1[0], 2) - + " aS=" + to_string(vehicle->Mechanik->AbsAccS_pub, 2) - + " Pd=" + to_string( vehicle->Mechanik->ActualProximityDist, 0 ) - + " Vn=" + to_string( vehicle->Mechanik->VelNext, 0 ); - } - - // induction motor data - if( mover->EngineType == TEngineType::ElectricInductionMotor ) { - - UITable.text_lines.emplace_back( " eimc: eimv: press:", Global.UITextColor ); - for( int i = 0; i <= 20; ++i ) { - - std::string parameters = - mover->eimc_labels[ i ] + to_string( mover->eimc[ i ], 2, 9 ) - + " | " - + mover->eimv_labels[ i ] + to_string( mover->eimv[ i ], 2, 9 ); - - if( i < 10 ) { - parameters += " | " + train->fPress_labels[i] + to_string( train->fPress[ i ][ 0 ], 2, 9 ); - } - else if( i == 12 ) { - parameters += " med:"; - } - else if( i >= 13 ) { - parameters += " | " + vehicle->MED_labels[ i - 13 ] + to_string( vehicle->MED[ 0 ][ i - 13 ], 2, 9 ); - } - - UITable.text_lines.emplace_back( parameters, Global.UITextColor ); - } - } - if (mover->EngineType == TEngineType::DieselEngine) { - std::string parameters = "param value"; - UITable.text_lines.emplace_back(parameters, Global.UITextColor); - parameters = "efill: " + to_string(mover->dizel_fill, 2, 9); - UITable.text_lines.emplace_back(parameters, Global.UITextColor); - parameters = "etorq: " + to_string(mover->dizel_Torque, 2, 9); - UITable.text_lines.emplace_back(parameters, Global.UITextColor); - parameters = "creal: " + to_string(mover->dizel_engage, 2, 9); - UITable.text_lines.emplace_back(parameters, Global.UITextColor); - parameters = "cdesi: " + to_string(mover->dizel_engagestate, 2, 9); - UITable.text_lines.emplace_back(parameters, Global.UITextColor); - parameters = "cdelt: " + to_string(mover->dizel_engagedeltaomega, 2, 9); - UITable.text_lines.emplace_back(parameters, Global.UITextColor); - parameters = "gears: " + to_string(mover->dizel_automaticgearstatus, 2, 9); - UITable.text_lines.emplace_back(parameters, Global.UITextColor); - parameters = "hydro value"; - UITable.text_lines.emplace_back(parameters, Global.UITextColor); - parameters = "hTCnI: " + to_string(mover->hydro_TC_nIn, 2, 9); - UITable.text_lines.emplace_back(parameters, Global.UITextColor); - parameters = "hTCnO: " + to_string(mover->hydro_TC_nOut, 2, 9); - UITable.text_lines.emplace_back(parameters, Global.UITextColor); - parameters = "hTCTM: " + to_string(mover->hydro_TC_TMRatio, 2, 9); - UITable.text_lines.emplace_back(parameters, Global.UITextColor); - parameters = "hTCTI: " + to_string(mover->hydro_TC_TorqueIn, 2, 9); - UITable.text_lines.emplace_back(parameters, Global.UITextColor); - parameters = "hTCTO: " + to_string(mover->hydro_TC_TorqueOut, 2, 9); - UITable.text_lines.emplace_back(parameters, Global.UITextColor); - parameters = "hTCfl: " + to_string(mover->hydro_TC_Fill, 2, 9); - UITable.text_lines.emplace_back(parameters, Global.UITextColor); - parameters = "hTCLR: " + to_string(mover->hydro_TC_LockupRate, 2, 9); - UITable.text_lines.emplace_back(parameters, Global.UITextColor); - //parameters = "hTCXX: " + to_string(mover->hydro_TC_nIn, 2, 9); - //UITable.text_lines.emplace_back(parameters, Global.UITextColor); - } - - } // if( DebugModeFlag && Controlled ) - - break; - } - } - -#ifdef EU07_USE_OLD_UI_CODE - if( Controlled && DebugModeFlag && !Global.iTextMode ) { - - uitextline1 += - ( "; d_omega " ) + to_string( Controlled->MoverParameters->dizel_engagedeltaomega, 3 ); - - if( Controlled->MoverParameters->EngineType == ElectricInductionMotor ) { - - for( int i = 0; i <= 8; i++ ) { - for( int j = 0; j <= 9; j++ ) { - glRasterPos2f( 0.05f + 0.03f * i, 0.16f - 0.01f * j ); - uitextline4 = to_string( Train->fEIMParams[ i ][ j ], 2 ); - } - } - } - } -#endif - - // update the ui header texts - auto &headerdata = UIHeader.text_lines; - headerdata[ 0 ].data = uitextline1; - headerdata[ 1 ].data = uitextline2; - headerdata[ 2 ].data = uitextline3; - headerdata[ 3 ].data = uitextline4; - - // stenogramy dźwiÄ™ków (ukryć, gdy tabelka skanowania lub rozkÅ‚ad?) - auto &transcripts = UITranscripts.text_lines; - transcripts.clear(); - for( auto const &transcript : ui::Transcripts.aLines ) { - - if( Global.fTimeAngleDeg >= transcript.fShow ) { - - cParser parser( transcript.asText ); - while( true == parser.getTokens( 1, false, "|" ) ) { - - std::string transcriptline; parser >> transcriptline; - transcripts.emplace_back( transcriptline, glm::vec4( 1.0f, 1.0f, 0.0f, 1.0f ) ); - } - } - } - + ui_layer::update(); +} + +// render() subclass details +void +driver_ui::render_() { + + auto const pausemask { 1 | 2 }; + if( ( Global.iPause & pausemask ) != 0 ) { + // pause/quit modal + auto const popupheader{ "Simulation Paused" }; + ImGui::OpenPopup( popupheader ); + if( ImGui::BeginPopupModal( popupheader, nullptr, ImGuiWindowFlags_AlwaysAutoResize ) ) { + if( ImGui::Button( "Resume", ImVec2( 120, 0 ) ) ) { + ImGui::CloseCurrentPopup(); + Global.iPause &= ~pausemask; + } + if( ImGui::Button( "Quit", ImVec2( 120, 0 ) ) ) { + ImGui::CloseCurrentPopup(); + glfwSetWindowShouldClose( m_window, 1 ); + } + ImGui::EndPopup(); + } + } } diff --git a/driveruilayer.h b/driveruilayer.h index 6d22e578..3ef0c638 100644 --- a/driveruilayer.h +++ b/driveruilayer.h @@ -10,6 +10,7 @@ http://mozilla.org/MPL/2.0/. #pragma once #include "uilayer.h" +#include "driveruipanels.h" class driver_ui : public ui_layer { @@ -25,12 +26,14 @@ public: update() override; private: +// methods + // render() subclass details + void + render_() override; // members - ui_panel UIHeader { 20, 20 }; // header ui panel - ui_panel UITable { 20, 100 };// schedule or scan table - ui_panel UITranscripts { 85, 600 }; // voice transcripts - int tprev { 0 }; // poprzedni czas - double VelPrev { 0.0 }; // poprzednia prÄ™dkość - double Acc { 0.0 }; // przyspieszenie styczne + drivingaid_panel m_aidpanel { "Driving Aid", true }; + timetable_panel m_timetablepanel { "Timetable", false }; + debug_panel m_debugpanel { "Debug Data", false }; + transcripts_panel m_transcriptspanel { "Transcripts", true }; // voice transcripts }; diff --git a/driveruipanels.cpp b/driveruipanels.cpp new file mode 100644 index 00000000..b677c8aa --- /dev/null +++ b/driveruipanels.cpp @@ -0,0 +1,896 @@ +/* +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 "driveruipanels.h" + +#include "globals.h" +#include "translation.h" +#include "simulation.h" +#include "simulationtime.h" +#include "event.h" +#include "camera.h" +#include "mtable.h" +#include "train.h" +#include "driver.h" +#include "animmodel.h" +#include "dynobj.h" +#include "model3d.h" +#include "renderer.h" +#include "utilities.h" +#include "logs.h" + +void +drivingaid_panel::update() { + + if( false == is_open ) { return; } + + text_lines.clear(); + + auto const *train { simulation::Train }; + auto const *controlled { ( train ? train->Dynamic() : nullptr ) }; + + if( ( controlled == nullptr ) + || ( controlled->Mechanik == nullptr ) ) { return; } + + auto const *mover = controlled->MoverParameters; + auto const *driver = controlled->Mechanik; + + { // throttle, velocity, speed limits and grade + auto textline = + "Throttle: " + to_string( driver->Controlling()->MainCtrlPos, 0, 2 ) + + "+" + std::to_string( driver->Controlling()->ScndCtrlPos ) + + " " + + ( mover->ActiveDir > 0 ? 'D' : + mover->ActiveDir < 0 ? 'R' : + 'N' ); + + if( is_expanded ) { + + auto const speedlimit { static_cast( std::floor( driver->VelDesired ) ) }; + textline += + " Speed: " + std::to_string( static_cast( std::floor( mover->Vel ) ) ) + " km/h" + + " (limit: " + std::to_string( speedlimit ) + " km/h"; + auto const nextspeedlimit { static_cast( std::floor( driver->VelNext ) ) }; + if( nextspeedlimit != speedlimit ) { + textline += + ", new limit: " + std::to_string( nextspeedlimit ) + " km/h" + + " in " + to_string( driver->ActualProximityDist * 0.001, 1 ) + " km"; + } + textline += ")"; + auto const reverser { ( mover->ActiveDir > 0 ? 1 : -1 ) }; + auto const grade { controlled->VectorFront().y * 100 * ( controlled->DirectionGet() == reverser ? 1 : -1 ) * reverser }; + if( std::abs( grade ) >= 0.25 ) { + textline += " Grade: " + to_string( grade, 1 ) + "%%"; + } + } + + text_lines.emplace_back( textline, Global.UITextColor ); + } + + { // brakes, air pressure + auto textline = + "Brakes:" + to_string( mover->fBrakeCtrlPos, 1, 5 ) + + "+" + to_string( mover->LocalBrakePosA * LocalBrakePosNo, 0 ) + + ( mover->SlippingWheels ? " !" : " " ); + if( textline.size() > 16 ) { + textline.erase( 16 ); + } + + if( is_expanded ) { + + textline += + " Pressure: " + to_string( mover->BrakePress * 100.0, 2 ) + " kPa" + + " (train pipe: " + to_string( mover->PipePress * 100.0, 2 ) + " kPa)"; + } + + text_lines.emplace_back( textline, Global.UITextColor ); + } + + { // alerter, hints + std::string textline = + ( true == TestFlag( mover->SecuritySystem.Status, s_aware ) ? + "!ALERTER! " : + " " ); + textline += + ( true == TestFlag( mover->SecuritySystem.Status, s_active ) ? + "!SHP! " : + " " ); + + if( is_expanded ) { + + auto const stoptime { static_cast( -1.0 * controlled->Mechanik->fStopTime ) }; + if( stoptime > 0 ) { + textline += " Loading/unloading in progress (" + to_string( stoptime ) + ( stoptime > 1 ? " seconds" : " second" ) + " left)"; + } + else { + auto const trackblockdistance { std::abs( controlled->Mechanik->TrackBlock() ) }; + if( trackblockdistance <= 75.0 ) { + textline += " Another vehicle ahead (distance: " + to_string( trackblockdistance, 1 ) + " m)"; + } + } + } + + text_lines.emplace_back( textline, Global.UITextColor ); + } + + auto const sizex = ( is_expanded ? 660 : 130 ); + size = { sizex, 85 }; +} + +void +timetable_panel::update() { + + if( false == is_open ) { return; } + + text_lines.clear(); + + auto const *train { simulation::Train }; + auto const *controlled { ( train ? train->Dynamic() : nullptr ) }; + auto const &camera { Global.pCamera }; + auto const &time { simulation::Time.data() }; + + { // current time + auto textline = + "Time: " + + to_string( time.wHour ) + ":" + + ( time.wMinute < 10 ? "0" : "" ) + to_string( time.wMinute ) + ":" + + ( time.wSecond < 10 ? "0" : "" ) + to_string( time.wSecond ); + + text_lines.emplace_back( textline, Global.UITextColor ); + } + + auto *vehicle { + ( FreeFlyModeFlag ? + std::get( simulation::Region->find_vehicle( camera.Pos, 20, false, false ) ) : + controlled ) }; // w trybie latania lokalizujemy wg mapy + + if( vehicle == nullptr ) { return; } + // if the nearest located vehicle doesn't have a direct driver, try to query its owner + auto const *owner = ( + ( ( vehicle->Mechanik != nullptr ) && ( vehicle->Mechanik->Primary() ) ) ? + vehicle->Mechanik : + vehicle->ctOwner ); + if( owner == nullptr ) { return; } + + auto const *table = owner->TrainTimetable(); + if( table == nullptr ) { return; } + + { // destination + auto textline = Bezogonkow( owner->Relation(), true ); + if( false == textline.empty() ) { + textline += " (" + Bezogonkow( owner->TrainName(), true ) + ")"; + } + + text_lines.emplace_back( textline, Global.UITextColor ); + } + + { // next station + auto const nextstation = Bezogonkow( owner->NextStop(), true ); + if( false == nextstation.empty() ) { + // jeÅ›li jest podana relacja, to dodajemy punkt nastÄ™pnego zatrzymania + auto textline = " -> " + nextstation; + + text_lines.emplace_back( textline, Global.UITextColor ); + } + } + + if( is_expanded ) { + + text_lines.emplace_back( "", Global.UITextColor ); + + if( 0 == table->StationCount ) { + // only bother if there's stations to list + text_lines.emplace_back( "(no timetable)", Global.UITextColor ); + } + else { + auto const readycolor { glm::vec4( 84.0f / 255.0f, 164.0f / 255.0f, 132.0f / 255.0f, 1.f ) }; + // header + text_lines.emplace_back( "+-----+------------------------------------+-------+-----+", Global.UITextColor ); + + TMTableLine const *tableline; + for( int i = owner->iStationStart; i <= table->StationCount; ++i ) { + // wyÅ›wietlenie pozycji z rozkÅ‚adu + tableline = table->TimeTable + i; // linijka rozkÅ‚adu + + std::string vmax = + " " + + to_string( tableline->vmax, 0 ); + vmax = vmax.substr( vmax.size() - 3, 3 ); // z wyrównaniem do prawej + std::string const station = ( + Bezogonkow( tableline->StationName, true ) + + " " ) + .substr( 0, 34 ); + std::string const location = ( + ( tableline->km > 0.0 ? + to_string( tableline->km, 2 ) : + "" ) + + " " ) + .substr( 0, 34 - tableline->StationWare.size() ); + std::string const arrival = ( + tableline->Ah >= 0 ? + to_string( int( 100 + tableline->Ah ) ).substr( 1, 2 ) + ":" + to_string( int( 100 + tableline->Am ) ).substr( 1, 2 ) : + " | " ); + std::string const departure = ( + tableline->Dh >= 0 ? + to_string( int( 100 + tableline->Dh ) ).substr( 1, 2 ) + ":" + to_string( int( 100 + tableline->Dm ) ).substr( 1, 2 ) : + " | " ); + auto const candeparture = ( + ( owner->iStationStart < table->StationIndex ) + && ( i < table->StationIndex ) + && ( ( time.wHour * 60 + time.wMinute ) >= ( tableline->Dh * 60 + tableline->Dm ) ) ); + auto traveltime = + " " + + ( i < 2 ? "" : + tableline->Ah >= 0 ? to_string( CompareTime( table->TimeTable[ i - 1 ].Dh, table->TimeTable[ i - 1 ].Dm, tableline->Ah, tableline->Am ), 0 ) : + to_string( std::max( 0.0, CompareTime( table->TimeTable[ i - 1 ].Dh, table->TimeTable[ i - 1 ].Dm, tableline->Dh, tableline->Dm ) - 0.5 ), 0 ) ); + traveltime = traveltime.substr( traveltime.size() - 3, 3 ); // z wyrównaniem do prawej + + text_lines.emplace_back( + ( "| " + vmax + " | " + station + " | " + arrival + " | " + traveltime + " |" ), + ( candeparture ? + readycolor :// czas minÄ…Å‚ i odjazd byÅ‚, to nazwa stacji bÄ™dzie na zielono + Global.UITextColor ) ); + text_lines.emplace_back( + ( "| | " + location + tableline->StationWare + " | " + departure + " | |" ), + ( candeparture ? + readycolor :// czas minÄ…Å‚ i odjazd byÅ‚, to nazwa stacji bÄ™dzie na zielono + Global.UITextColor ) ); + // divider/footer + text_lines.emplace_back( "+-----+------------------------------------+-------+-----+", Global.UITextColor ); + } + } + } // is_expanded +} + +void +debug_panel::update() { + + if( false == is_open ) { return; } + + // input item bindings + m_input.train = simulation::Train; + m_input.controlled = ( m_input.train ? m_input.train->Dynamic() : nullptr ); + m_input.camera = &( Global.pCamera ); + m_input.vehicle = + ( FreeFlyModeFlag ? + std::get( simulation::Region->find_vehicle( m_input.camera->Pos, 20, false, false ) ) : + m_input.controlled ); // w trybie latania lokalizujemy wg mapy + m_input.mover = + ( m_input.vehicle != nullptr ? + m_input.vehicle->MoverParameters : + nullptr ); + m_input.mechanik = ( + m_input.vehicle != nullptr ? + m_input.vehicle->Mechanik : + nullptr ); + + // header section + text_lines.clear(); + + auto textline = "Version " + Global.asVersion; + + text_lines.emplace_back( textline, Global.UITextColor ); + + // sub-sections + m_vehiclelines.clear(); + m_enginelines.clear(); + m_ailines.clear(); + m_scantablelines.clear(); + m_scenariolines.clear(); + m_eventqueuelines.clear(); + m_cameralines.clear(); + m_rendererlines.clear(); + + update_section_vehicle( m_vehiclelines ); + update_section_engine( m_enginelines ); + update_section_ai( m_ailines ); + update_section_scantable( m_scantablelines ); + update_section_scenario( m_scenariolines ); + update_section_eventqueue( m_eventqueuelines ); + update_section_camera( m_cameralines ); + update_section_renderer( m_rendererlines ); +} + +void +debug_panel::render() { + + if( false == is_open ) { return; } + + auto flags = + ImGuiWindowFlags_NoFocusOnAppearing + | ImGuiWindowFlags_NoCollapse + | ( size.x > 0 ? ImGuiWindowFlags_NoResize : 0 ); + + if( size.x > 0 ) { + ImGui::SetNextWindowSize( ImVec2( size.x, size.y ) ); + } + if( size_min.x > 0 ) { + ImGui::SetNextWindowSizeConstraints( ImVec2( size_min.x, size_min.y ), ImVec2( size_max.x, size_max.y ) ); + } + if( true == ImGui::Begin( name.c_str(), &is_open, flags ) ) { + // header section + for( auto const &line : text_lines ) { + ImGui::TextColored( ImVec4( line.color.r, line.color.g, line.color.b, line.color.a ), line.data.c_str() ); + } + // sections + ImGui::Separator(); + render_section( "Vehicle", m_vehiclelines ); + render_section( "Vehicle Engine", m_enginelines ); + render_section( "Vehicle AI", m_ailines ); + render_section( "Vehicle Scan Table", m_scantablelines ); + render_section( "Scenario", m_scenariolines ); + render_section( "Scenario Event Queue", m_eventqueuelines ); + render_section( "Camera", m_cameralines ); + render_section( "Gfx Renderer", m_rendererlines ); + // toggles + ImGui::Separator(); + ImGui::Checkbox( "Debug Mode", &DebugModeFlag ); + } + ImGui::End(); +} + +void +debug_panel::update_section_vehicle( std::vector &Output ) { + + if( m_input.vehicle == nullptr ) { return; } + if( m_input.mover == nullptr ) { return; } + + auto const &vehicle { *m_input.vehicle }; + auto const &mover { *m_input.mover }; + + // f3 data + auto textline = "Vehicle name: " + mover.Name; + + if( ( vehicle.Mechanik == nullptr ) && ( vehicle.ctOwner ) ) { + // for cars other than leading unit indicate the leader + textline += ", owned by " + vehicle.ctOwner->OwnerName(); + } + textline += "\nStatus: " + mover.EngineDescription( 0 ); + if( mover.WheelFlat > 0.01 ) { + textline += " Flat: " + to_string( mover.WheelFlat, 1 ) + " mm"; + } + + // informacja o sprzÄ™gach + textline += + "\nC0:" + + ( vehicle.PrevConnected ? + vehicle.PrevConnected->name() + ":" + to_string( mover.Couplers[ 0 ].CouplingFlag ) + ( + mover.Couplers[ 0 ].CouplingFlag == 0 ? + " (" + to_string( mover.Couplers[ 0 ].CoupleDist, 1 ) + " m)" : + "" ) : + "none" ); + textline += + " C1:" + + ( vehicle.NextConnected ? + vehicle.NextConnected->name() + ":" + to_string( mover.Couplers[ 1 ].CouplingFlag ) + ( + mover.Couplers[ 1 ].CouplingFlag == 0 ? + " (" + to_string( mover.Couplers[ 1 ].CoupleDist, 1 ) + " m)" : + "" ) : + "none" ); + + Output.emplace_back( textline, Global.UITextColor ); + + // equipment flags + textline = ( mover.Battery ? "B" : "." ); + textline += ( mover.Mains ? "M" : "." ); + textline += ( mover.PantRearUp ? ( mover.PantRearVolt > 0.0 ? "O" : "o" ) : "." ); + textline += ( mover.PantFrontUp ? ( mover.PantFrontVolt > 0.0 ? "P" : "p" ) : "." ); + textline += ( mover.PantPressLockActive ? "!" : ( mover.PantPressSwitchActive ? "*" : "." ) ); + textline += ( mover.WaterPump.is_active ? "W" : ( false == mover.WaterPump.breaker ? "-" : ( mover.WaterPump.is_enabled ? "w" : "." ) ) ); + textline += ( true == mover.WaterHeater.is_damaged ? "!" : ( mover.WaterHeater.is_active ? "H" : ( false == mover.WaterHeater.breaker ? "-" : ( mover.WaterHeater.is_enabled ? "h" : "." ) ) ) ); + textline += ( mover.FuelPump.is_active ? "F" : ( mover.FuelPump.is_enabled ? "f" : "." ) ); + textline += ( mover.OilPump.is_active ? "O" : ( mover.OilPump.is_enabled ? "o" : "." ) ); + textline += ( false == mover.ConverterAllowLocal ? "-" : ( mover.ConverterAllow ? ( mover.ConverterFlag ? "X" : "x" ) : "." ) ); + textline += ( mover.ConvOvldFlag ? "!" : "." ); + textline += ( mover.CompressorFlag ? "C" : ( false == mover.CompressorAllowLocal ? "-" : ( ( mover.CompressorAllow || mover.CompressorStart == start_t::automatic ) ? "c" : "." ) ) ); + textline += ( mover.CompressorGovernorLock ? "!" : "." ); + + if( ( m_input.train != nullptr ) && ( m_input.train->Dynamic() == m_input.vehicle ) ) { + textline += ( mover.Radio ? " R: " : " r: " ) + std::to_string( m_input.train->RadioChannel() ); + } + textline += " Bdelay: "; + if( ( mover.BrakeDelayFlag & bdelay_G ) == bdelay_G ) + textline += "G"; + if( ( mover.BrakeDelayFlag & bdelay_P ) == bdelay_P ) + textline += "P"; + if( ( mover.BrakeDelayFlag & bdelay_R ) == bdelay_R ) + textline += "R"; + if( ( mover.BrakeDelayFlag & bdelay_M ) == bdelay_M ) + textline += "+Mg"; + + textline += ", Load: " + to_string( mover.Load, 0 ) + " (" + to_string( mover.LoadFlag, 0 ) + ")"; + + textline += + "\nFt: " + to_string( + mover.Ft * 0.001f * ( + mover.ActiveCab ? mover.ActiveCab : + vehicle.ctOwner ? vehicle.ctOwner->Controlling()->ActiveCab : + 1 ), 1 ) + + ", Fb: " + to_string( mover.Fb * 0.001f, 1 ) + + ", Fr: " + to_string( mover.Adhesive( mover.RunningTrack.friction ), 2 ) + + ( mover.SlippingWheels ? " (!)" : "" ); + + textline += + "\nPant: " + + to_string( mover.PantPress, 2 ) + + ( mover.bPantKurek3 ? "-ZG" : "|ZG" ); + textline += + " TC:" + + to_string( mover.TotalCurrent, 0 ); + auto const frontcouplerhighvoltage = + to_string( mover.Couplers[ side::front ].power_high.voltage, 0 ) + + "@" + + to_string( mover.Couplers[ side::front ].power_high.current, 0 ); + auto const rearcouplerhighvoltage = + to_string( mover.Couplers[ side::rear ].power_high.voltage, 0 ) + + "@" + + to_string( mover.Couplers[ side::rear ].power_high.current, 0 ); + textline += ", HV: "; + if( mover.Couplers[ side::front ].power_high.local == false ) { + textline += + "(" + frontcouplerhighvoltage + ")-" + + ":F" + ( vehicle.DirectionGet() ? "<<" : ">>" ) + "R:" + + "-(" + rearcouplerhighvoltage + ")"; + } + else { + textline += + frontcouplerhighvoltage + + ":F" + ( vehicle.DirectionGet() ? "<<" : ">>" ) + "R:" + + rearcouplerhighvoltage; + } + + Output.emplace_back( textline, Global.UITextColor ); + + textline = + "TrB: " + to_string( mover.BrakePress, 2 ) + + ", " + to_hex_str( mover.Hamulec->GetBrakeStatus(), 2 ); + + textline += + "; LcB: " + to_string( mover.LocBrakePress, 2 ) + + "; hat: " + to_string( mover.BrakeCtrlPos2, 2 ) + + "\npipes: " + to_string( mover.PipePress, 2 ) + + "/" + to_string( mover.ScndPipePress, 2 ) + + "/" + to_string( mover.EqvtPipePress, 2 ) + + "\nMT: " + to_string( mover.CompressedVolume, 3 ) + + ", BT: " + to_string( mover.Volume, 3 ) + + ", CtlP: " + to_string( mover.CntrlPipePress, 3 ) + + ", CtlT: " + to_string( mover.Hamulec->GetCRP(), 3 ); + + if( mover.ManualBrakePos > 0 ) { + + textline += "; manual brake on"; + } + + Output.emplace_back( textline, Global.UITextColor ); + + // debug mode f1 data + textline = + "vel: " + to_string( vehicle.GetVelocity(), 2 ) + "/" + to_string( mover.nrot* M_PI * mover.WheelDiameter * 3.6, 2 ) + + " km/h;" + + " dist: " + to_string( mover.DistCounter, 2 ) + " km" + + "\npos: [" + to_string( vehicle.GetPosition().x, 2 ) + ", " + to_string( vehicle.GetPosition().y, 2 ) + ", " + to_string( vehicle.GetPosition().z, 2 ) + "]" + + "\nenpwr=" + to_string( mover.EnginePower, 1 ) + + "; enrot=" + to_string( mover.enrot * 60, 0 ) + + " tmrot=" + to_string( std::abs( mover.nrot ) * mover.Transmision.Ratio * 60, 0 ) + + "; ventrot=" + to_string( mover.RventRot * 60, 1 ) + + "; fanrot=" + to_string( mover.dizel_heat.rpmw, 1 ) + ", " + to_string( mover.dizel_heat.rpmw2, 1 ); + + Output.emplace_back( textline, Global.UITextColor ); + + textline = + "HamZ=" + to_string( mover.fBrakeCtrlPos, 2 ) + + "; HamP=" + to_string( mover.LocalBrakePosA, 2 ) + + "; NasJ=" + std::to_string( mover.MainCtrlPos ) + "(" + std::to_string( mover.MainCtrlActualPos ) + ")" + + ( ( mover.ShuntMode && mover.EngineType == TEngineType::DieselElectric ) ? + "; NasB=" + to_string( mover.AnPos, 2 ) : + "; NasB=" + std::to_string( mover.ScndCtrlPos ) + "(" + std::to_string( mover.ScndCtrlActualPos ) + ")" ) + + "\nI=" + + ( mover.TrainType == dt_EZT ? + std::to_string( int( mover.ShowCurrent( 0 ) ) ) : + std::to_string( int( mover.Im ) ) ) + + "; U=" + to_string( int( mover.RunningTraction.TractionVoltage + 0.5 ) ) + + "; R=" + + ( std::abs( mover.RunningShape.R ) > 10000.0 ? + "~0.0" : + to_string( mover.RunningShape.R, 1 ) ) + + " An=" + to_string( mover.AccN, 2 ); // przyspieszenie poprzeczne + + if( tprev != simulation::Time.data().wSecond ) { + tprev = simulation::Time.data().wSecond; + Acc = ( mover.Vel - VelPrev ) / 3.6; + VelPrev = mover.Vel; + } + textline += "; As=" + to_string( Acc, 2 ); // przyspieszenie wzdÅ‚użne + // uitextline2 += " eAngle=" + to_string( std::cos( mover.eAngle ), 2 ); + textline += "\noilP=" + to_string( mover.OilPump.pressure_present, 3 ); + textline += " oilT=" + to_string( mover.dizel_heat.To, 2 ); + textline += "; waterT=" + to_string( mover.dizel_heat.temperatura1, 2 ); + textline += ( mover.WaterCircuitsLink ? "-" : "|" ); + textline += to_string( mover.dizel_heat.temperatura2, 2 ); + textline += "; engineT=" + to_string( mover.dizel_heat.Ts, 2 ); + + Output.emplace_back( textline, Global.UITextColor ); + + textline = + "cyl.ham. " + to_string( mover.BrakePress, 2 ) + + "; prz.gl. " + to_string( mover.PipePress, 2 ) + + "; zb.gl. " + to_string( mover.CompressedVolume, 2 ) + // youBy - drugi wezyk + + "; p.zas. " + to_string( mover.ScndPipePress, 2 ); + + // McZapkie: warto wiedziec w jakim stanie sa przelaczniki + if( mover.ConvOvldFlag ) + textline += " C! "; + else if( mover.FuseFlag ) + textline += " F! "; + else if( !mover.Mains ) + textline += " () "; + else { + switch( + mover.ActiveDir * + ( mover.Imin == mover.IminLo ? + 1 : + 2 ) ) { + case 2: { textline += " >> "; break; } + case 1: { textline += " -> "; break; } + case 0: { textline += " -- "; break; } + case -1: { textline += " <- "; break; } + case -2: { textline += " << "; break; } + } + } + + Output.emplace_back( textline, Global.UITextColor ); + + // McZapkie: komenda i jej parametry + if( mover.CommandIn.Command != ( "" ) ) { + textline = + "C:" + mover.CommandIn.Command + + " V1=" + to_string( mover.CommandIn.Value1, 0 ) + + " V2=" + to_string( mover.CommandIn.Value2, 0 ); + + Output.emplace_back( textline, Global.UITextColor ); + } +} + +void +debug_panel::update_section_engine( std::vector &Output ) { + + if( m_input.train == nullptr ) { return; } + if( m_input.vehicle == nullptr ) { return; } + if( m_input.mover == nullptr ) { return; } + + auto const &train { *m_input.train }; + auto const &vehicle{ *m_input.vehicle }; + auto const &mover{ *m_input.mover }; + + // engine data + // induction motor data + if( mover.EngineType == TEngineType::ElectricInductionMotor ) { + + Output.emplace_back( " eimc: eimv: press:", Global.UITextColor ); + for( int i = 0; i <= 20; ++i ) { + + std::string parameters = + mover.eimc_labels[ i ] + to_string( mover.eimc[ i ], 2, 9 ) + + " | " + + mover.eimv_labels[ i ] + to_string( mover.eimv[ i ], 2, 9 ); + + if( i < 10 ) { + parameters += " | " + train.fPress_labels[i] + to_string( train.fPress[ i ][ 0 ], 2, 9 ); + } + else if( i == 12 ) { + parameters += " med:"; + } + else if( i >= 13 ) { + parameters += " | " + vehicle.MED_labels[ i - 13 ] + to_string( vehicle.MED[ 0 ][ i - 13 ], 2, 9 ); + } + + Output.emplace_back( parameters, Global.UITextColor ); + } + } + if ( mover.EngineType == TEngineType::DieselEngine) { + std::string parameters = "param value"; + Output.emplace_back(parameters, Global.UITextColor); + parameters = "efill: " + to_string( mover.dizel_fill, 2, 9); + Output.emplace_back(parameters, Global.UITextColor); + parameters = "etorq: " + to_string( mover.dizel_Torque, 2, 9); + Output.emplace_back(parameters, Global.UITextColor); + parameters = "creal: " + to_string( mover.dizel_engage, 2, 9); + Output.emplace_back(parameters, Global.UITextColor); + parameters = "cdesi: " + to_string( mover.dizel_engagestate, 2, 9); + Output.emplace_back(parameters, Global.UITextColor); + parameters = "cdelt: " + to_string( mover.dizel_engagedeltaomega, 2, 9); + Output.emplace_back(parameters, Global.UITextColor); + parameters = "gears: " + to_string( mover.dizel_automaticgearstatus, 2, 9); + Output.emplace_back(parameters, Global.UITextColor); + parameters = "hydro value"; + Output.emplace_back(parameters, Global.UITextColor); + parameters = "hTCnI: " + to_string( mover.hydro_TC_nIn, 2, 9); + Output.emplace_back(parameters, Global.UITextColor); + parameters = "hTCnO: " + to_string( mover.hydro_TC_nOut, 2, 9); + Output.emplace_back(parameters, Global.UITextColor); + parameters = "hTCTM: " + to_string( mover.hydro_TC_TMRatio, 2, 9); + Output.emplace_back(parameters, Global.UITextColor); + parameters = "hTCTI: " + to_string( mover.hydro_TC_TorqueIn, 2, 9); + Output.emplace_back(parameters, Global.UITextColor); + parameters = "hTCTO: " + to_string( mover.hydro_TC_TorqueOut, 2, 9); + Output.emplace_back(parameters, Global.UITextColor); + parameters = "hTCfl: " + to_string( mover.hydro_TC_Fill, 2, 9); + Output.emplace_back(parameters, Global.UITextColor); + parameters = "hTCLR: " + to_string( mover.hydro_TC_LockupRate, 2, 9); + Output.emplace_back(parameters, Global.UITextColor); + //parameters = "hTCXX: " + to_string(mover->hydro_TC_nIn, 2, 9); + //engine_lines.emplace_back(parameters, Global.UITextColor); + } +} + +void +debug_panel::update_section_ai( std::vector &Output ) { + + if( m_input.mover == nullptr ) { return; } + if( m_input.mechanik == nullptr ) { return; } + + auto const &mover{ *m_input.mover }; + auto const &mechanik{ *m_input.mechanik }; + + // biezaca komenda dla AI + auto textline = "Current order: " + mechanik.OrderCurrent(); + + Output.emplace_back( textline, Global.UITextColor ); + + if( ( mechanik.VelNext == 0.0 ) + && ( mechanik.eSignNext ) ) { + // jeÅ›li ma zapamiÄ™tany event semafora, nazwa eventu semafora + Output.emplace_back( "Current signal: " + Bezogonkow( mechanik.eSignNext->asName ), Global.UITextColor ); + } + + // distances + textline = + "Distances:\n proximity: " + to_string( mechanik.ActualProximityDist, 0 ) + + ", braking: " + to_string( mechanik.fBrakeDist, 0 ); + + Output.emplace_back( textline, Global.UITextColor ); + + // velocity factors + textline = + "Velocity:\n desired: " + to_string( mechanik.VelDesired, 0 ) + + ", next: " + to_string( mechanik.VelNext, 0 ); + + std::vector< std::pair< double, std::string > > const restrictions{ + { mechanik.VelSignalLast, "signal" }, + { mechanik.VelLimitLast, "limit" }, + { mechanik.VelRoad, "road" }, + { mechanik.VelRestricted, "restricted" }, + { mover.RunningTrack.Velmax, "track" } }; + + std::string restrictionstext; + for( auto const &restriction : restrictions ) { + if( restriction.first < 0.0 ) { continue; } + if( false == restrictionstext.empty() ) { + restrictionstext += ", "; + } + restrictionstext += + to_string( restriction.first, 0 ) + + " (" + restriction.second + ")"; + } + + if( false == restrictionstext.empty() ) { + textline += "\n restrictions: " + restrictionstext; + } + + Output.emplace_back( textline, Global.UITextColor ); + + // acceleration + textline = + "Acceleration:\n desired: " + to_string( mechanik.AccDesired, 2 ) + + ", corrected: " + to_string( mechanik.AccDesired * mechanik.BrakeAccFactor(), 2 ) + + "\n current: " + to_string( mechanik.AbsAccS_pub, 2 ) + + ", slope: " + to_string( mechanik.fAccGravity, 2 ) + " (" + ( mechanik.fAccGravity > 0.01 ? "\\" : ( mechanik.fAccGravity < -0.01 ? "/" : "-" ) ) + ")" + + "\n brake threshold: " + to_string( mechanik.fAccThreshold, 2 ) + + ", delays: " + to_string( mechanik.fBrake_a0[ 0 ], 2 ) + + "+" + to_string( mechanik.fBrake_a1[ 0 ], 2 ); + + Output.emplace_back( textline, Global.UITextColor ); + + // ai driving flags + std::vector const drivingflagnames { + "StopCloser", "StopPoint", "Active", "Press", "Connect", "Primary", "Late", "StopHere", + "StartHorn", "StartHornNow", "StartHornDone", "Oerlikons", "IncSpeed", "TrackEnd", "SwitchFound", "GuardSignal", + "Visibility", "DoorOpened", "PushPull", "SemaphorFound", "SemaphorWasElapsed", "TrainInsideStation", "SpeedLimitFound" }; + + textline = "Driving flags:"; + for( int idx = 0, flagbit = 1; idx < drivingflagnames.size(); ++idx, flagbit <<= 1 ) { + if( mechanik.DrivigFlags() & flagbit ) { + textline += "\n " + drivingflagnames[ idx ]; + } + } + + Output.emplace_back( textline, Global.UITextColor ); +} + +void +debug_panel::update_section_scantable( std::vector &Output ) { + + if( m_input.mechanik == nullptr ) { return; } + + auto const &mechanik{ *m_input.mechanik }; + + std::size_t i = 0; std::size_t const speedtablesize = clamp( static_cast( mechanik.TableSize() ) - 1, 0, 30 ); + do { + auto const scanline = mechanik.TableText( i ); + if( scanline.empty() ) { break; } + Output.emplace_back( Bezogonkow( scanline ), Global.UITextColor ); + ++i; + } while( i < speedtablesize ); + if( Output.empty() ) { + Output.emplace_back( "(no points of interest)", Global.UITextColor ); + } +} + +void +debug_panel::update_section_scenario( std::vector &Output ) { + + auto textline = + "vehicles: " + to_string( Timer::subsystem.sim_dynamics.average(), 2 ) + " msec" + + " update total: " + to_string( Timer::subsystem.sim_total.average(), 2 ) + " msec"; + + Output.emplace_back( textline, Global.UITextColor ); + // current luminance level + textline = "Light level: " + to_string( Global.fLuminance, 3 ); + if( Global.FakeLight ) { textline += "(*)"; } + + Output.emplace_back( textline, Global.UITextColor ); +} + +void +debug_panel::update_section_eventqueue( std::vector &Output ) { + + std::string textline; + + // current event queue + auto const time { Timer::GetTime() }; + auto const *event { simulation::Events.begin() }; + auto eventtableindex{ 0 }; + while( ( event != nullptr ) + && ( eventtableindex < 30 ) ) { + + if( ( false == event->m_ignored ) + && ( true == event->bEnabled ) ) { + + auto const delay { " " + to_string( std::max( 0.0, event->fStartTime - time ), 1 ) }; + textline = + "Delay: " + delay.substr( delay.length() - 6 ) + + ", Event: " + event->asName + + ( event->Activator ? " (by: " + event->Activator->asName + ")" : "" ) + + ( event->evJoined ? " (joint event)" : "" ); + + Output.emplace_back( textline, Global.UITextColor ); + ++eventtableindex; + } + event = event->evNext; + } + if( Output.empty() ) { + textline = "(no queued events)"; + Output.emplace_back( textline, Global.UITextColor ); + } +} + +void +debug_panel::update_section_camera( std::vector &Output ) { + + if( m_input.camera == nullptr ) { return; } + + auto const &camera{ *m_input.camera }; + + // camera data + auto textline = + "Position: [" + + to_string( camera.Pos.x, 2 ) + ", " + + to_string( camera.Pos.y, 2 ) + ", " + + to_string( camera.Pos.z, 2 ) + "]"; + + Output.emplace_back( textline, Global.UITextColor ); + + textline = + "Azimuth: " + + to_string( 180.0 - glm::degrees( camera.Yaw ), 0 ) // ma być azymut, czyli 0 na północy i roÅ›nie na wschód + + " " + + std::string( "S SEE NEN NWW SW" ) + .substr( 0 + 2 * floor( fmod( 8 + ( camera.Yaw + 0.5 * M_PI_4 ) / M_PI_4, 8 ) ), 2 ); + + Output.emplace_back( textline, Global.UITextColor ); +} + +void +debug_panel::update_section_renderer( std::vector &Output ) { + + // gfx renderer data + auto textline = + "FoV: " + to_string( Global.FieldOfView / Global.ZoomFactor, 1 ) + + ", Draw range x " + to_string( Global.fDistanceFactor, 1 ) +// + "; sectors: " + std::to_string( GfxRenderer.m_drawcount ) +// + ", FPS: " + to_string( Timer::GetFPS(), 2 ); + + ", FPS: " + std::to_string( static_cast(std::round(GfxRenderer.Framerate())) ); + if( Global.iSlowMotion ) { + textline += " (slowmotion " + to_string( Global.iSlowMotion ) + ")"; + } + + Output.emplace_back( textline, Global.UITextColor ); + + textline = + std::string( "Rendering mode: " ) + + ( Global.bUseVBO ? + "VBO" : + "Display Lists" ) + + " "; + if( false == Global.LastGLError.empty() ) { + textline += + "Last openGL error: " + + Global.LastGLError; + } + + Output.emplace_back( textline, Global.UITextColor ); + + // renderer stats + Output.emplace_back( GfxRenderer.info_times(), Global.UITextColor ); + Output.emplace_back( GfxRenderer.info_stats(), Global.UITextColor ); +} + +void +debug_panel::render_section( std::string const &Header, std::vector const &Lines ) { + + if( Lines.empty() ) { return; } + if( false == ImGui::CollapsingHeader( Header.c_str() ) ) { return; } + + for( auto const &line : Lines ) { + ImGui::TextColored( ImVec4( line.color.r, line.color.g, line.color.b, line.color.a ), line.data.c_str() ); + } +} + +void +transcripts_panel::update() { + + if( false == is_open ) { return; } + + text_lines.clear(); + + for( auto const &transcript : ui::Transcripts.aLines ) { + if( Global.fTimeAngleDeg >= transcript.fShow ) { + // NOTE: legacy transcript lines use | as new line mark + text_lines.emplace_back( ExchangeCharInString( transcript.asText, '|', ' ' ), colors::white ); + } + } +} + +void +transcripts_panel::render() { + + if( false == is_open ) { return; } + if( true == text_lines.empty() ) { return; } + + auto flags = + ImGuiWindowFlags_NoFocusOnAppearing + | ImGuiWindowFlags_NoCollapse + | ( size.x > 0 ? ImGuiWindowFlags_NoResize : 0 ); + + if( size.x > 0 ) { + ImGui::SetNextWindowSize( ImVec2( size.x, size.y ) ); + } + if( size_min.x > 0 ) { + ImGui::SetNextWindowSizeConstraints( ImVec2( size_min.x, size_min.y ), ImVec2( size_max.x, size_max.y ) ); + } + if( true == ImGui::Begin( name.c_str(), &is_open, flags ) ) { + // header section + for( auto const &line : text_lines ) { + ImGui::TextWrapped( line.data.c_str() ); + } + } + ImGui::End(); +} diff --git a/driveruipanels.h b/driveruipanels.h new file mode 100644 index 00000000..60315500 --- /dev/null +++ b/driveruipanels.h @@ -0,0 +1,93 @@ +/* +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 "uilayer.h" +#include "classes.h" + +class drivingaid_panel : public ui_panel { + +public: + drivingaid_panel( std::string const Name, bool const Isopen ) + : ui_panel( Name, Isopen ) + {} + + void update() override; + + bool is_expanded { false }; +}; + +class timetable_panel : public ui_panel { + +public: + timetable_panel( std::string const Name, bool const Isopen ) + : ui_panel( Name, Isopen ) {} + + void update() override; + + bool is_expanded{ false }; +}; + +class debug_panel : public ui_panel { + +public: + debug_panel( std::string const Name, bool const Isopen ) + : ui_panel( Name, Isopen ) {} + + void update() override; + void render() override; + +private: +// types + struct input_data { + TTrain const *train; + TDynamicObject const *controlled; + TCamera const *camera; + TDynamicObject const *vehicle; + TMoverParameters const *mover; + TController const *mechanik; + }; +// methods + // generate and send section data to provided output + void update_section_vehicle( std::vector &Output ); + void update_section_engine( std::vector &Output ); + void update_section_ai( std::vector &Output ); + void update_section_scantable( std::vector &Output ); + void update_section_scenario( std::vector &Output ); + void update_section_eventqueue( std::vector &Output ); + void update_section_camera( std::vector &Output ); + void update_section_renderer( std::vector &Output ); + // renders provided lines, under specified collapsing header + void render_section( std::string const &Header, std::vector const &Lines ); +// members + input_data m_input; + std::vector + m_vehiclelines, + m_enginelines, + m_ailines, + m_scantablelines, + m_cameralines, + m_scenariolines, + m_eventqueuelines, + m_rendererlines; + int tprev { 0 }; // poprzedni czas + double VelPrev { 0.0 }; // poprzednia prÄ™dkość + double Acc { 0.0 }; // przyspieszenie styczne +}; + +class transcripts_panel : public ui_panel { + +public: + transcripts_panel( std::string const Name, bool const Isopen ) + : ui_panel( Name, Isopen ) {} + + void update() override; + void render() override; +}; diff --git a/editormode.cpp b/editormode.cpp index fdcaad9b..cd376707 100644 --- a/editormode.cpp +++ b/editormode.cpp @@ -45,9 +45,6 @@ editor_mode::init() { Camera.Init( { 0, 15, 0 }, { glm::radians( -30.0 ), glm::radians( 180.0 ), 0 }, TCameraType::tp_Free ); - m_userinterface->set_progress( "Scenario editor is active. Press F11 to return to driver mode" ); - m_userinterface->set_progress( 0, 100 ); - return m_input.init(); } diff --git a/editoruilayer.cpp b/editoruilayer.cpp index 5b6df31f..2513b07b 100644 --- a/editoruilayer.cpp +++ b/editoruilayer.cpp @@ -11,27 +11,13 @@ http://mozilla.org/MPL/2.0/. #include "editoruilayer.h" #include "globals.h" -#include "camera.h" -#include "animmodel.h" -#include "track.h" -#include "event.h" #include "renderer.h" -#include "utilities.h" -#include "logs.h" editor_ui::editor_ui() { - clear_texts(); -/* - UIHeader = std::make_shared( 20, 20 ); // header ui panel -*/ - // make 4 empty lines for the ui header, to cut down on work down the road - UIHeader.text_lines.emplace_back( "", Global.UITextColor ); - UIHeader.text_lines.emplace_back( "", Global.UITextColor ); - UIHeader.text_lines.emplace_back( "", Global.UITextColor ); - UIHeader.text_lines.emplace_back( "", Global.UITextColor ); + clear_panels(); // bind the panels with ui object. maybe not the best place for this but, eh - push_back( &UIHeader ); + push_back( &m_itempropertiespanel ); } // potentially processes provided input key. returns: true if key was processed, false otherwise @@ -45,11 +31,8 @@ editor_ui::on_key( int const Key, int const Action ) { void editor_ui::update() { - std::string uitextline1, uitextline2, uitextline3, uitextline4; set_tooltip( "" ); - auto const &camera { Global.pCamera }; - if( ( true == Global.ControlPicking ) && ( true == DebugModeFlag ) ) { @@ -60,141 +43,8 @@ editor_ui::update() { "" ) ); } - // scenario inspector - auto const *node { m_node }; - - if( node == nullptr ) { - auto const mouseposition { camera.Pos + GfxRenderer.Mouse_Position() }; - uitextline1 = "mouse location: [" + to_string( mouseposition.x, 2 ) + ", " + to_string( mouseposition.y, 2 ) + ", " + to_string( mouseposition.z, 2 ) + "]"; - goto update; - } - - uitextline1 = - "node name: " + node->name() - + "; location: [" + to_string( node->location().x, 2 ) + ", " + to_string( node->location().y, 2 ) + ", " + to_string( node->location().z, 2 ) + "]" - + " (distance: " + to_string( glm::length( glm::dvec3{ node->location().x, 0.0, node->location().z } -glm::dvec3{ camera.Pos.x, 0.0, camera.Pos.z } ), 1 ) + " m)"; - // subclass-specific data - // TBD, TODO: specialized data dump method in each node subclass, or data imports in the panel for provided subclass pointer? - if( typeid( *node ) == typeid( TAnimModel ) ) { - - auto const *subnode = static_cast( node ); - - uitextline2 = "angle: " + to_string( clamp_circular( subnode->vAngle.y, 360.f ), 2 ) + " deg"; - uitextline2 += "; lights: "; - if( subnode->iNumLights > 0 ) { - uitextline2 += '['; - for( int lightidx = 0; lightidx < subnode->iNumLights; ++lightidx ) { - uitextline2 += to_string( subnode->lsLights[ lightidx ] ); - if( lightidx < subnode->iNumLights - 1 ) { - uitextline2 += ", "; - } - } - uitextline2 += ']'; - } - else { - uitextline2 += "none"; - } - // 3d shape - auto modelfile { ( - ( subnode->pModel != nullptr ) ? - subnode->pModel->NameGet() : - "none" ) }; - if( modelfile.find( szModelPath ) == 0 ) { - // don't include 'models/' in the path - modelfile.erase( 0, std::string{ szModelPath }.size() ); - } - // texture - auto texturefile { ( - ( subnode->Material()->replacable_skins[ 1 ] != null_handle ) ? - GfxRenderer.Material( subnode->Material()->replacable_skins[ 1 ] ).name : - "none" ) }; - if( texturefile.find( szTexturePath ) == 0 ) { - // don't include 'textures/' in the path - texturefile.erase( 0, std::string{ szTexturePath }.size() ); - } - uitextline3 = "mesh: " + modelfile; - uitextline4 = "skin: " + texturefile; - } - else if( typeid( *node ) == typeid( TTrack ) ) { - - auto const *subnode = static_cast( node ); - // basic attributes - uitextline2 = - "isolated: " + ( ( subnode->pIsolated != nullptr ) ? subnode->pIsolated->asName : "none" ) - + "; velocity: " + to_string( subnode->SwitchExtension ? subnode->SwitchExtension->fVelocity : subnode->fVelocity ) - + "; width: " + to_string( subnode->fTrackWidth ) + " m" - + "; friction: " + to_string( subnode->fFriction, 2 ) - + "; quality: " + to_string( subnode->iQualityFlag ); - // textures - auto texturefile { ( - ( subnode->m_material1 != null_handle ) ? - GfxRenderer.Material( subnode->m_material1 ).name : - "none" ) }; - if( texturefile.find( szTexturePath ) == 0 ) { - texturefile.erase( 0, std::string{ szTexturePath }.size() ); - } - auto texturefile2{ ( - ( subnode->m_material2 != null_handle ) ? - GfxRenderer.Material( subnode->m_material2 ).name : - "none" ) }; - if( texturefile2.find( szTexturePath ) == 0 ) { - texturefile2.erase( 0, std::string{ szTexturePath }.size() ); - } - uitextline2 += "; skins: [" + texturefile + ", " + texturefile2 + "]"; - // paths - uitextline3 = "paths: "; - for( auto const &path : subnode->m_paths ) { - uitextline3 += - "[" - + to_string( path.points[ segment_data::point::start ].x, 3 ) + ", " - + to_string( path.points[ segment_data::point::start ].y, 3 ) + ", " - + to_string( path.points[ segment_data::point::start ].z, 3 ) + "]->" - + "[" - + to_string( path.points[ segment_data::point::end ].x, 3 ) + ", " - + to_string( path.points[ segment_data::point::end ].y, 3 ) + ", " - + to_string( path.points[ segment_data::point::end ].z, 3 ) + "] "; - } - // events - std::vector< std::pair< std::string, TTrack::event_sequence const * > > const eventsequences { - { "ev0", &subnode->m_events0 }, { "ev0all", &subnode->m_events0all }, - { "ev1", &subnode->m_events1 }, { "ev1all", &subnode->m_events1all }, - { "ev2", &subnode->m_events2 }, { "ev2all", &subnode->m_events2all } }; - - for( auto const &eventsequence : eventsequences ) { - - if( eventsequence.second->empty() ) { continue; } - - uitextline4 += eventsequence.first + ": ["; - for( auto const &event : *( eventsequence.second ) ) { - if( uitextline4.back() != '[' ) { - uitextline4 += ", "; - } - if( event.second ) { - uitextline4 += event.second->asName; - } - } - uitextline4 += "] "; - } - - } - else if( typeid( *node ) == typeid( TMemCell ) ) { - - auto const *subnode = static_cast( node ); - - uitextline2 = - "data: [" + subnode->Text() + "]" - + " [" + to_string( subnode->Value1(), 2 ) + "]" - + " [" + to_string( subnode->Value2(), 2 ) + "]"; - uitextline3 = "track: " + ( subnode->asTrackName.empty() ? "none" : subnode->asTrackName ); - } - -update: - // update the ui header texts - auto &headerdata = UIHeader.text_lines; - headerdata[ 0 ].data = uitextline1; - headerdata[ 1 ].data = uitextline2; - headerdata[ 2 ].data = uitextline3; - headerdata[ 3 ].data = uitextline4; + ui_layer::update(); + m_itempropertiespanel.update( m_node ); } void diff --git a/editoruilayer.h b/editoruilayer.h index f0bafc87..95b06169 100644 --- a/editoruilayer.h +++ b/editoruilayer.h @@ -10,6 +10,7 @@ http://mozilla.org/MPL/2.0/. #pragma once #include "uilayer.h" +#include "editoruipanels.h" namespace scene { @@ -34,6 +35,6 @@ public: private: // members - ui_panel UIHeader { 20, 20 }; // header ui panel + itemproperties_panel m_itempropertiespanel { "Node Properties", true }; scene::basic_node * m_node { nullptr }; // currently bound scene node, if any }; diff --git a/editoruipanels.cpp b/editoruipanels.cpp new file mode 100644 index 00000000..fdc642a0 --- /dev/null +++ b/editoruipanels.cpp @@ -0,0 +1,196 @@ +/* +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 "editoruipanels.h" + +#include "globals.h" +#include "camera.h" +#include "animmodel.h" +#include "track.h" +#include "event.h" +#include "renderer.h" +#include "utilities.h" + +void +itemproperties_panel::update( scene::basic_node const *Node ) { + + if( false == is_open ) { return; } + + text_lines.clear(); + std::string textline; + + // scenario inspector + auto const *node { Node }; + auto const &camera { Global.pCamera }; + + if( node == nullptr ) { + auto const mouseposition { camera.Pos + GfxRenderer.Mouse_Position() }; + textline = "mouse location: [" + to_string( mouseposition.x, 2 ) + ", " + to_string( mouseposition.y, 2 ) + ", " + to_string( mouseposition.z, 2 ) + "]"; + text_lines.emplace_back( textline, Global.UITextColor ); + return; + } + + textline = + "node name: " + node->name() + + "\nlocation: [" + to_string( node->location().x, 2 ) + ", " + to_string( node->location().y, 2 ) + ", " + to_string( node->location().z, 2 ) + "]" + + " (distance: " + to_string( glm::length( glm::dvec3{ node->location().x, 0.0, node->location().z } -glm::dvec3{ camera.Pos.x, 0.0, camera.Pos.z } ), 1 ) + " m)"; + text_lines.emplace_back( textline, Global.UITextColor ); + + // subclass-specific data + // TBD, TODO: specialized data dump method in each node subclass, or data imports in the panel for provided subclass pointer? + if( typeid( *node ) == typeid( TAnimModel ) ) { + + auto const *subnode = static_cast( node ); + + textline = "angle: " + to_string( clamp_circular( subnode->vAngle.y, 360.f ), 2 ) + " deg"; + textline += "; lights: "; + if( subnode->iNumLights > 0 ) { + textline += '['; + for( int lightidx = 0; lightidx < subnode->iNumLights; ++lightidx ) { + textline += to_string( subnode->lsLights[ lightidx ] ); + if( lightidx < subnode->iNumLights - 1 ) { + textline += ", "; + } + } + textline += ']'; + } + else { + textline += "none"; + } + text_lines.emplace_back( textline, Global.UITextColor ); + + // 3d shape + auto modelfile { ( + ( subnode->pModel != nullptr ) ? + subnode->pModel->NameGet() : + "none" ) }; + if( modelfile.find( szModelPath ) == 0 ) { + // don't include 'models/' in the path + modelfile.erase( 0, std::string{ szModelPath }.size() ); + } + // texture + auto texturefile { ( + ( subnode->Material()->replacable_skins[ 1 ] != null_handle ) ? + GfxRenderer.Material( subnode->Material()->replacable_skins[ 1 ] ).name : + "none" ) }; + if( texturefile.find( szTexturePath ) == 0 ) { + // don't include 'textures/' in the path + texturefile.erase( 0, std::string{ szTexturePath }.size() ); + } + text_lines.emplace_back( "mesh: " + modelfile, Global.UITextColor ); + text_lines.emplace_back( "skin: " + texturefile, Global.UITextColor ); + } + else if( typeid( *node ) == typeid( TTrack ) ) { + + auto const *subnode = static_cast( node ); + // basic attributes + textline = + "isolated: " + ( ( subnode->pIsolated != nullptr ) ? subnode->pIsolated->asName : "none" ) + + "\nvelocity: " + to_string( subnode->SwitchExtension ? subnode->SwitchExtension->fVelocity : subnode->fVelocity ) + + "\nwidth: " + to_string( subnode->fTrackWidth ) + " m" + + "\nfriction: " + to_string( subnode->fFriction, 2 ) + + "\nquality: " + to_string( subnode->iQualityFlag ); + text_lines.emplace_back( textline, Global.UITextColor ); + // textures + auto texturefile { ( + ( subnode->m_material1 != null_handle ) ? + GfxRenderer.Material( subnode->m_material1 ).name : + "none" ) }; + if( texturefile.find( szTexturePath ) == 0 ) { + texturefile.erase( 0, std::string{ szTexturePath }.size() ); + } + auto texturefile2{ ( + ( subnode->m_material2 != null_handle ) ? + GfxRenderer.Material( subnode->m_material2 ).name : + "none" ) }; + if( texturefile2.find( szTexturePath ) == 0 ) { + texturefile2.erase( 0, std::string{ szTexturePath }.size() ); + } + textline = "skins:\n " + texturefile + "\n " + texturefile2; + text_lines.emplace_back( textline, Global.UITextColor ); + // paths + textline = "paths: "; + for( auto const &path : subnode->m_paths ) { + textline += + "\n [" + + to_string( path.points[ segment_data::point::start ].x, 3 ) + ", " + + to_string( path.points[ segment_data::point::start ].y, 3 ) + ", " + + to_string( path.points[ segment_data::point::start ].z, 3 ) + "]->" + + "[" + + to_string( path.points[ segment_data::point::end ].x, 3 ) + ", " + + to_string( path.points[ segment_data::point::end ].y, 3 ) + ", " + + to_string( path.points[ segment_data::point::end ].z, 3 ) + "] "; + } + text_lines.emplace_back( textline, Global.UITextColor ); + // events + textline.clear(); + + std::vector< std::pair< std::string, TTrack::event_sequence const * > > const eventsequences { + { "ev0", &subnode->m_events0 }, { "ev0all", &subnode->m_events0all }, + { "ev1", &subnode->m_events1 }, { "ev1all", &subnode->m_events1all }, + { "ev2", &subnode->m_events2 }, { "ev2all", &subnode->m_events2all } }; + + for( auto const &eventsequence : eventsequences ) { + + if( eventsequence.second->empty() ) { continue; } + + textline += ( textline.empty() ? "" : "\n" ) + eventsequence.first + ": ["; + for( auto const &event : *( eventsequence.second ) ) { + if( textline.back() != '[' ) { + textline += ", "; + } + textline += ( + event.second ? + event.second->asName : + event.first + " (missing)" ); + } + textline += "] "; + } + text_lines.emplace_back( textline, Global.UITextColor ); + } + else if( typeid( *node ) == typeid( TMemCell ) ) { + + auto const *subnode = static_cast( node ); + + textline = + "data: [" + subnode->Text() + "]" + + " [" + to_string( subnode->Value1(), 2 ) + "]" + + " [" + to_string( subnode->Value2(), 2 ) + "]"; + text_lines.emplace_back( textline, Global.UITextColor ); + textline = "track: " + ( subnode->asTrackName.empty() ? "none" : subnode->asTrackName ); + text_lines.emplace_back( textline, Global.UITextColor ); + } +} + +void +itemproperties_panel::render() { + + if( false == is_open ) { return; } + if( true == text_lines.empty() ) { return; } + + auto flags = + ImGuiWindowFlags_NoFocusOnAppearing + | ImGuiWindowFlags_NoCollapse + | ( size.x > 0 ? ImGuiWindowFlags_NoResize : 0 ); + + if( size.x > 0 ) { + ImGui::SetNextWindowSize( ImVec2( size.x, size.y ) ); + } + if( size_min.x > 0 ) { + ImGui::SetNextWindowSizeConstraints( ImVec2( size_min.x, size_min.y ), ImVec2( size_max.x, size_max.y ) ); + } + if( true == ImGui::Begin( name.c_str(), nullptr, flags ) ) { + // header section + for( auto const &line : text_lines ) { + ImGui::TextColored( ImVec4( line.color.r, line.color.g, line.color.b, line.color.a ), line.data.c_str() ); + } + } + ImGui::End(); +} diff --git a/editoruipanels.h b/editoruipanels.h new file mode 100644 index 00000000..2023aec1 --- /dev/null +++ b/editoruipanels.h @@ -0,0 +1,24 @@ +/* +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 "uilayer.h" +#include "classes.h" + +class itemproperties_panel : public ui_panel { + +public: + itemproperties_panel( std::string const Name, bool const Isopen ) + : ui_panel( Name, Isopen ) + {} + + void update( scene::basic_node const *Node ); + void render() override; +}; diff --git a/maszyna.vcxproj.filters b/maszyna.vcxproj.filters index 2f20ee62..b3368c08 100644 --- a/maszyna.vcxproj.filters +++ b/maszyna.vcxproj.filters @@ -49,6 +49,9 @@ {0630616b-1afe-4fb6-96d1-3755834ba8aa} + + {33f7f4ae-692b-4989-a71a-004e0d48ed4f} + @@ -306,6 +309,24 @@ Source Files + + Source Files\imgui + + + Source Files\imgui + + + Source Files\imgui + + + Source Files\imgui + + + Source Files\application\mode_driver + + + Source Files\application\mode_editor + @@ -578,6 +599,12 @@ Header Files + + Header Files\application\mode_driver + + + Header Files\application\mode_editor + diff --git a/mtable.cpp b/mtable.cpp index 1e96c458..81cfd90b 100644 --- a/mtable.cpp +++ b/mtable.cpp @@ -33,7 +33,7 @@ double TTrainParameters::WatchMTable(double DistCounter) return dist; } -std::string TTrainParameters::NextStop() +std::string TTrainParameters::NextStop() const { // pobranie nazwy nastÄ™pnego miejsca zatrzymania if (StationIndex <= StationCount) return NextStationName; // nazwa nastÄ™pnego przystanku; @@ -41,7 +41,7 @@ std::string TTrainParameters::NextStop() return "[End of route]"; //że niby koniec } -bool TTrainParameters::IsStop() +bool TTrainParameters::IsStop() const { // zapytanie, czy zatrzymywać na nastÄ™pnym punkcie rozkÅ‚adu if ((StationIndex < StationCount)) return TimeTable[StationIndex].Ah >= 0; //-1 to brak postoju @@ -129,7 +129,7 @@ bool TTrainParameters::IsTimeToGo(double hh, double mm) return false; // dalej nie jechać } -std::string TTrainParameters::ShowRelation() +std::string TTrainParameters::ShowRelation() const /*zwraca informacjÄ™ o relacji*/ { // if (Relation1=TimeTable[1].StationName) and (Relation2=TimeTable[StationCount].StationName) diff --git a/mtable.h b/mtable.h index 30adc18e..f079790c 100644 --- a/mtable.h +++ b/mtable.h @@ -69,10 +69,10 @@ class TTrainParameters int Direction; /*kierunek jazdy w/g kilometrazu*/ double CheckTrainLatency(); /*todo: str hh:mm to int i z powrotem*/ - std::string ShowRelation(); + std::string ShowRelation() const; double WatchMTable(double DistCounter); - std::string NextStop(); - bool IsStop(); + std::string NextStop() const; + bool IsStop() const; bool IsTimeToGo(double hh, double mm); bool UpdateMTable(double hh, double mm, std::string const &NewName); bool UpdateMTable( scenario_time const &Time, std::string const &NewName ); diff --git a/renderer.cpp b/renderer.cpp index eeab2f70..a1b74e29 100644 --- a/renderer.cpp +++ b/renderer.cpp @@ -409,6 +409,9 @@ opengl_renderer::Render() { m_debugstats = debug_stats(); Render_pass( rendermode::color ); Timer::subsystem.gfx_color.stop(); + // add user interface + setup_units( true, false, false ); + Application.render_ui(); Timer::subsystem.gfx_swap.start(); glfwSwapBuffers( m_window ); @@ -416,15 +419,19 @@ opengl_renderer::Render() { m_drawcount = m_cellqueue.size(); m_debugtimestext - += "frame: " + to_string( Timer::subsystem.gfx_color.average(), 2 ) + " msec (" + std::to_string( m_cellqueue.size() ) + " sectors) " - += "gpu side: " + to_string( Timer::subsystem.gfx_swap.average(), 2 ) + " msec " - += "(" + to_string( Timer::subsystem.gfx_color.average() + Timer::subsystem.gfx_swap.average(), 2 ) + " msec total)"; + += "color: " + to_string( Timer::subsystem.gfx_color.average(), 2 ) + " msec (" + std::to_string( m_cellqueue.size() ) + " sectors)\n" + += "gpu side: " + to_string( Timer::subsystem.gfx_swap.average(), 2 ) + " msec\n" + += "frame total: " + to_string( Timer::subsystem.gfx_color.average() + Timer::subsystem.gfx_swap.average(), 2 ) + " msec"; m_debugstatstext = - "drawcalls: " + to_string( m_debugstats.drawcalls ) - + "; dyn: " + to_string( m_debugstats.dynamics ) + " mod: " + to_string( m_debugstats.models ) + " sub: " + to_string( m_debugstats.submodels ) - + "; trk: " + to_string( m_debugstats.paths ) + " shp: " + to_string( m_debugstats.shapes ) - + " trc: " + to_string( m_debugstats.traction ) + " lin: " + to_string( m_debugstats.lines ); + "drawcalls: " + to_string( m_debugstats.drawcalls ) + "\n" + + " vehicles: " + to_string( m_debugstats.dynamics ) + "\n" + + " models: " + to_string( m_debugstats.models ) + "\n" + + " submodels: " + to_string( m_debugstats.submodels ) + "\n" + + " paths: " + to_string( m_debugstats.paths ) + "\n" + + " shapes: " + to_string( m_debugstats.shapes ) + "\n" + + " traction: " + to_string( m_debugstats.traction ) + "\n" + + " lines: " + to_string( m_debugstats.lines ); ++m_framestamp; @@ -463,7 +470,7 @@ opengl_renderer::Render_pass( rendermode const Mode ) { Render_pass( rendermode::cabshadows ); } Timer::subsystem.gfx_shadows.stop(); - m_debugtimestext += "shadows: " + to_string( Timer::subsystem.gfx_shadows.average(), 2 ) + " msec (" + std::to_string( m_cellqueue.size() ) + " sectors) "; + m_debugtimestext += "shadows: " + to_string( Timer::subsystem.gfx_shadows.average(), 2 ) + " msec (" + std::to_string( m_cellqueue.size() ) + " sectors)\n"; #ifdef EU07_USE_DEBUG_SHADOWMAP UILayer.set_texture( m_shadowdebugtexture ); #endif @@ -584,7 +591,6 @@ opengl_renderer::Render_pass( rendermode const Mode ) { ::glMatrixMode( GL_MODELVIEW ); } } - Application.render_ui(); break; } @@ -1413,10 +1419,6 @@ opengl_renderer::Render( world_environment *Environment ) { // skydome Environment->m_skydome.Render(); - if( true == Global.bUseVBO ) { - // skydome uses a custom vbo which could potentially confuse the main geometry system. hardly elegant but, eh - gfx::opengl_vbogeometrybank::reset(); - } // stars if( Environment->m_stars.m_stars != nullptr ) { // setup diff --git a/skydome.cpp b/skydome.cpp index a4f426ad..d36f1f10 100644 --- a/skydome.cpp +++ b/skydome.cpp @@ -118,6 +118,9 @@ void CSkyDome::Update( glm::vec3 const &Sun ) { // render skydome to screen void CSkyDome::Render() { + // cache entry state + ::glPushClientAttrib( GL_CLIENT_VERTEX_ARRAY_BIT ); + if( m_vertexbuffer == -1 ) { // build the buffers ::glGenBuffers( 1, &m_vertexbuffer ); @@ -146,8 +149,7 @@ void CSkyDome::Render() { ::glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, m_indexbuffer ); ::glDrawElements( GL_TRIANGLES, static_cast( m_indices.size() ), GL_UNSIGNED_SHORT, reinterpret_cast( 0 ) ); // cleanup - ::glDisableClientState( GL_COLOR_ARRAY ); - ::glDisableClientState( GL_VERTEX_ARRAY ); + ::glPopClientAttrib(); } bool CSkyDome::SetSunPosition( glm::vec3 const &Direction ) { diff --git a/stdafx.h b/stdafx.h index 56fb3d16..74568b22 100644 --- a/stdafx.h +++ b/stdafx.h @@ -77,13 +77,20 @@ #define GLFW_DLL #endif // _windows #endif // build_static +#ifndef __ANDROID__ #include "GL/glew.h" +#else +#include +#include +#endif #ifdef _WIN32 #include "GL/wglew.h" #endif #define GLFW_INCLUDE_GLU //m7todo: jest tu bo nie chcia³o mi siê wpychaæ do wszystkich plików +#ifndef __ANDROID__ #include +#endif #define GLM_ENABLE_EXPERIMENTAL #define GLM_FORCE_CTOR_INIT @@ -96,3 +103,16 @@ #include #include "openglmatrixstack.h" + +// imgui.h comes with its own operator new which gets wrecked by dbg_new, so we temporarily disable the latter +#ifdef _MSC_VER +#ifdef _DEBUG +#undef new +#endif // _DEBUG +#endif +#include "imgui.h" +#ifdef _MSC_VER +#ifdef _DEBUG +#define new DBG_NEW +#endif // _DEBUG +#endif diff --git a/uilayer.cpp b/uilayer.cpp index cf8f6925..817d9a49 100644 --- a/uilayer.cpp +++ b/uilayer.cpp @@ -27,61 +27,107 @@ http://mozilla.org/MPL/2.0/. #include "utilities.h" #include "logs.h" +#include "imgui_impl_glfw.h" +#include "imgui_impl_opengl2.h" + extern "C" { GLFWAPI HWND glfwGetWin32Window( GLFWwindow* window ); //m7todo: potrzebne do directsound } GLFWwindow * ui_layer::m_window { nullptr }; +ImGuiIO *ui_layer::m_imguiio { nullptr }; GLint ui_layer::m_textureunit { GL_TEXTURE0 }; -GLuint ui_layer::m_fontbase { (GLuint)-1 }; // numer DL dla znaków w napisach bool ui_layer::m_cursorvisible { true }; -ui_layer::~ui_layer() { -/* -// this should be invoked manually, or we risk trying to delete the lists after the context is gone - if( m_fontbase != -1 ) - ::glDeleteLists( m_fontbase, 96 ); -*/ +ui_panel::ui_panel( std::string const Name, bool const Isopen ) + : name( Name ), is_open( Isopen ) +{} + +void +ui_panel::render() { + + if( false == is_open ) { return; } + if( true == text_lines.empty() ) { return; } + + auto flags = + ImGuiWindowFlags_NoFocusOnAppearing + | ImGuiWindowFlags_NoCollapse + | ( size.x > 0 ? ImGuiWindowFlags_NoResize : 0 ); + + if( size.x > 0 ) { + ImGui::SetNextWindowSize( ImVec2( size.x, size.y ) ); + } + if( size_min.x > 0 ) { + ImGui::SetNextWindowSizeConstraints( ImVec2( size_min.x, size_min.y ), ImVec2( size_max.x, size_max.y ) ); + } + if( true == ImGui::Begin( name.c_str(), &is_open, flags ) ) { + for( auto const &line : text_lines ) { + ImGui::TextColored( ImVec4( line.color.r, line.color.g, line.color.b, line.color.a ), line.data.c_str() ); + } + } + ImGui::End(); } +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( m_window ) ); - font = ::CreateFont( -MulDiv( 10, ::GetDeviceCaps( hDC, LOGPIXELSY ), 72 ), // height of font - 0, // width of font - 0, // angle of escapement - 0, // orientation angle - (Global.bGlutFont ? FW_MEDIUM : FW_HEAVY), // font weight - FALSE, // italic - FALSE, // underline - FALSE, // strikeout - DEFAULT_CHARSET, // character set identifier - OUT_DEFAULT_PRECIS, // output precision - CLIP_DEFAULT_PRECIS, // clipping precision - (Global.bGlutFont ? CLEARTYPE_QUALITY : PROOF_QUALITY), // output quality - 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 ) ) { - // builds 96 characters starting at character 32 - WriteLog( "Display Lists font used" ); //+AnsiString(glGetError()) - WriteLog( "Font init OK" ); //+AnsiString(glGetError()) - Global.DLFont = true; - return true; - } - else { - ErrorLog( "Font init failed" ); -// return false; - // NOTE: we report success anyway, given some cards can't produce fonts in this manner - Global.DLFont = false; - return true; - } + + IMGUI_CHECKVERSION(); + ImGui::CreateContext(); + m_imguiio = &ImGui::GetIO(); +// m_imguiio->Fonts->AddFontFromFileTTF( "c:/windows/fonts/lucon.ttf", 13.0f ); + + ImGui_ImplGlfw_InitForOpenGL( m_window, false ); + ImGui_ImplOpenGL2_Init(); + + init_colors(); + + return true; +} + +void +ui_layer::init_colors() { + + // configure ui colours + auto *style = &ImGui::GetStyle(); + auto *colors = style->Colors; + auto const background { ImVec4( 38.0f / 255.0f, 38.0f / 255.0f, 38.0f / 255.0f, 0.65f ) }; + auto const accent { ImVec4( 44.0f / 255.0f, 88.0f / 255.0f, 72.0f / 255.0f, 0.75f ) }; + auto const itembase { ImVec4( accent.x, accent.y, accent.z, 0.35f ) }; + auto const itemhover { ImVec4( accent.x, accent.y, accent.z, 0.65f ) }; + auto const itemactive { ImVec4( accent.x, accent.y, accent.z, 0.95f ) }; + + colors[ ImGuiCol_WindowBg ] = background; + colors[ ImGuiCol_PopupBg ] = background; + colors[ ImGuiCol_FrameBg ] = itembase; + colors[ ImGuiCol_FrameBgHovered ] = itemhover; + colors[ ImGuiCol_FrameBgActive ] = itemactive; + colors[ ImGuiCol_TitleBg ] = background; + colors[ ImGuiCol_TitleBgActive ] = background; + colors[ ImGuiCol_TitleBgCollapsed ] = background; + colors[ ImGuiCol_CheckMark ] = colors[ ImGuiCol_Text ]; + colors[ ImGuiCol_Button ] = itembase; + colors[ ImGuiCol_ButtonHovered ] = itemhover; + colors[ ImGuiCol_ButtonActive ] = itemactive; + colors[ ImGuiCol_Header ] = itembase; + colors[ ImGuiCol_HeaderHovered ] = itemhover; + colors[ ImGuiCol_HeaderActive ] = itemactive; + colors[ ImGuiCol_ResizeGrip ] = itembase; + colors[ ImGuiCol_ResizeGripHovered ] = itemhover; + colors[ ImGuiCol_ResizeGripActive ] = itemactive; +} + +void +ui_layer::shutdown() { + + ImGui_ImplOpenGL2_Shutdown(); + ImGui_ImplGlfw_Shutdown(); + ImGui::DestroyContext(); } bool @@ -90,9 +136,18 @@ ui_layer::on_key( int const Key, int const Action ) { return false; } +void +ui_layer::update() { + + for( auto *panel : m_panels ) { + panel->update(); + } +} + void ui_layer::render() { + // legacy ui code glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho( 0, std::max( 1, Global.iWindowWidth ), std::max( 1, Global.iWindowHeight ), 0, -1, 1 ); @@ -120,10 +175,27 @@ ui_layer::render() { glDisable( GL_BLEND ); + glPopAttrib(); + + // imgui ui code + ::glPushClientAttrib( GL_CLIENT_VERTEX_ARRAY_BIT ); + + ::glClientActiveTexture( m_textureunit ); + ::glBindBuffer( GL_ARRAY_BUFFER, 0 ); + + ImGui_ImplOpenGL2_NewFrame(); + ImGui_ImplGlfw_NewFrame(); + ImGui::NewFrame(); + render_panels(); render_tooltip(); + // template method implementation + render_(); - glPopAttrib(); + ImGui::Render(); + ImGui_ImplOpenGL2_RenderDrawData( ImGui::GetDrawData() ); + + ::glPopClientAttrib(); } void @@ -207,30 +279,14 @@ ui_layer::render_progress() { ::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 ); } } void ui_layer::render_panels() { - if( m_panels.empty() ) { return; } - - 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 ) { - - int lineidx = 0; - for( auto const &line : panel->text_lines ) { - - ::glColor4fv( glm::value_ptr( line.color ) ); - ::glRasterPos2f( - 0.5f * ( Global.iWindowWidth - width ) + panel->origin_x * height, - panel->origin_y * height + 20.f * lineidx ); - print( line.data ); - ++lineidx; - } + for( auto *panel : m_panels ) { + panel->render(); } } @@ -240,12 +296,7 @@ ui_layer::render_tooltip() { if( m_tooltip.empty() ) { return; } if( false == m_cursorvisible ) { return; } - glm::dvec2 mousepos; - glfwGetCursorPos( m_window, &mousepos.x, &mousepos.y ); - - ::glColor4fv( glm::value_ptr( colors::white ) ); - ::glRasterPos2f( mousepos.x + 20.0f, mousepos.y + 25.0f ); - print( m_tooltip ); + ImGui::SetTooltip( m_tooltip.c_str() ); } void @@ -295,21 +346,6 @@ ui_layer::render_texture() { } } -void -ui_layer::print( std::string const &Text ) -{ - if( (false == Global.DLFont) - || (true == Text.empty()) ) - return; - - ::glPushAttrib( GL_LIST_BIT ); - - ::glListBase( m_fontbase - 32 ); - ::glCallLists( Text.size(), GL_UNSIGNED_BYTE, Text.c_str() ); - - ::glPopAttrib(); -} - void ui_layer::quad( glm::vec4 const &Coordinates, glm::vec4 const &Color ) { diff --git a/uilayer.h b/uilayer.h index d95dba3f..038e3f5a 100644 --- a/uilayer.h +++ b/uilayer.h @@ -14,25 +14,35 @@ http://mozilla.org/MPL/2.0/. // GuiLayer -- basic user interface class. draws requested information on top of openGL screen -struct ui_panel { +class ui_panel { +public: +// constructor + ui_panel( std::string const Name, bool const Isopen ); +// methods + virtual void update() {}; + virtual void render(); + // temporary access +// types struct text_line { std::string data; glm::vec4 color; - text_line( std::string const &Data, glm::vec4 const &Color): - data(Data), color(Color) + text_line( std::string const &Data, glm::vec4 const &Color) + : data(Data), color(Color) {} }; - - ui_panel( const int X, const int Y): - origin_x(X), origin_y(Y) - {} - +// members + bool is_open; + glm::ivec2 size { -1, -1 }; + glm::ivec2 size_min { -1, -1 }; + glm::ivec2 size_max { -1, -1 }; std::vector text_lines; - int origin_x; - int origin_y; + +protected: +// members + std::string name; }; class ui_layer { @@ -51,6 +61,9 @@ public: static void set_unit( GLint const Textureunit ) { m_textureunit = Textureunit; } + static + void + shutdown(); // potentially processes provided input key. returns: true if the input was processed, false otherwise virtual bool @@ -58,7 +71,7 @@ public: // updates state of UI elements virtual void - update() {} + update(); // draws requested UI elements void render(); @@ -79,17 +92,25 @@ public: void set_tooltip( std::string const &Tooltip ) { m_tooltip = Tooltip; } void - clear_texts() { m_panels.clear(); } + clear_panels() { m_panels.clear(); } void push_back( ui_panel *Panel ) { m_panels.emplace_back( Panel ); } protected: // members static GLFWwindow *m_window; + static ImGuiIO *m_imguiio; static bool m_cursorvisible; private: // methods + static + void + init_colors(); + // render() subclass details + virtual + void + render_() {}; // draws background quad with specified earlier texture void render_background(); @@ -102,15 +123,11 @@ private: render_panels(); void render_tooltip(); - // prints specified text, using display lists font - void - print( std::string const &Text ); // draws a quad between coordinates x,y and z,w with uv-coordinates spanning 0-1 void quad( glm::vec4 const &Coordinates, glm::vec4 const &Color ); // members static GLint m_textureunit; - static GLuint m_fontbase; // numer DL dla znaków 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.