From ff1a85fe5d450c352882733493c8f82d1a73b88e Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Sun, 8 Jul 2018 23:18:27 +0200 Subject: [PATCH] build 180708. model instance position and rotation adjustment in scenery editor, support for event launcher activation with mouse click, minor refactoring --- AnimModel.cpp | 6 +- AnimModel.h | 13 +++- Camera.cpp | 6 -- Camera.h | 1 - EU07.cpp | 21 ++--- EvLaunch.cpp | 53 +++++++------ EvLaunch.h | 1 + Event.cpp | 2 +- Segment.cpp | 17 +---- Segment.h | 2 +- Track.cpp | 4 +- Track.h | 17 +---- Traction.cpp | 11 --- maszyna.vcxproj.filters | 9 +++ mouseinput.cpp | 138 +++++++++++++++------------------ mouseinput.h | 6 +- renderer.cpp | 60 +++++++++++---- renderer.h | 24 +++--- scene.cpp | 106 +++++++++++++++++++++++--- scene.h | 28 ++++++- sceneeditor.cpp | 165 ++++++++++++++++++++++++++++++++++++++++ sceneeditor.h | 73 ++++++++++++++++++ scenenode.cpp | 14 ++-- scenenode.h | 8 +- simulation.cpp | 14 ++-- uilayer.cpp | 17 +++-- utilities.cpp | 17 ++++- utilities.h | 4 + version.h | 2 +- 29 files changed, 601 insertions(+), 238 deletions(-) create mode 100644 sceneeditor.cpp create mode 100644 sceneeditor.h diff --git a/AnimModel.cpp b/AnimModel.cpp index d1917a758..4676c08ac 100644 --- a/AnimModel.cpp +++ b/AnimModel.cpp @@ -419,7 +419,7 @@ TAnimModel::TAnimModel( scene::node_data const &Nodedata ) : basic_node( Nodedat TAnimModel::~TAnimModel() { - delete pAdvanced; // nie ma zaawansowanej animacji + SafeDelete(pAdvanced); // nie ma zaawansowanej animacji SafeDelete(pRoot); } @@ -630,10 +630,6 @@ int TAnimModel::Flags() //--------------------------------------------------------------------------- -bool TAnimModel::TerrainLoaded() -{ // zliczanie kwadratów kilometrowych (główna linia po Next) do tworznia tablicy - return (this ? pModel != NULL : false); -}; int TAnimModel::TerrainCount() { // zliczanie kwadratów kilometrowych (główna linia po Next) do tworznia tablicy return pModel ? pModel->TerrainCount() : 0; diff --git a/AnimModel.h b/AnimModel.h index e901f1c51..fb109893c 100644 --- a/AnimModel.h +++ b/AnimModel.h @@ -138,11 +138,8 @@ class TAnimModel : public scene::basic_node { bool Load(cParser *parser, bool ter = false); TAnimContainer * AddContainer(std::string const &Name); TAnimContainer * GetContainer(std::string const &Name = ""); - void RaAnglesSet( glm::vec3 Angles ) { - vAngle = { Angles }; }; void LightSet( int const n, float const v ); void AnimationVND( void *pData, double a, double b, double c, double d ); - bool TerrainLoaded(); int TerrainCount(); TSubModel * TerrainSquare(int n); int Flags(); @@ -154,6 +151,14 @@ class TAnimModel : public scene::basic_node { TModel3d * Model() const { return pModel; } + inline + void + Angles( glm::vec3 const &Angles ) { + vAngle = Angles; } + inline + glm::vec3 + Angles() const { + return vAngle; } // members static TAnimContainer *acAnimList; // lista animacji z eventem, które muszą być przeliczane również bez wyświetlania @@ -178,7 +183,7 @@ class TAnimModel : public scene::basic_node { int iNumLights { 0 }; TSubModel *LightsOn[ iMaxNumLights ]; // Ra: te wskaźniki powinny być w ramach TModel3d TSubModel *LightsOff[ iMaxNumLights ]; - Math3D::vector3 vAngle; // bazowe obroty egzemplarza względem osi + glm::vec3 vAngle; // bazowe obroty egzemplarza względem osi material_data m_materialdata; std::string asText; // tekst dla wyświetlacza znakowego diff --git a/Camera.cpp b/Camera.cpp index b58901f7e..6e4f51ed2 100644 --- a/Camera.cpp +++ b/Camera.cpp @@ -237,9 +237,3 @@ void TCamera::RaLook() m_rotationoffsets.x = 0.0; } }; - -void TCamera::Stop() -{ // wyłącznie bezwładnego ruchu po powrocie do kabiny - Type = tp_Follow; - Velocity = Math3D::vector3(0, 0, 0); -}; diff --git a/Camera.h b/Camera.h index 9a70d438d..3ac8b33b2 100644 --- a/Camera.h +++ b/Camera.h @@ -31,7 +31,6 @@ class TCamera { Math3D::vector3 GetDirection(); bool SetMatrix(glm::dmat4 &Matrix); void RaLook(); - void Stop(); TCameraType Type; double Pitch; diff --git a/EU07.cpp b/EU07.cpp index ff276ba67..281a8b385 100644 --- a/EU07.cpp +++ b/EU07.cpp @@ -22,6 +22,7 @@ Stele, firleju, szociu, hunter, ZiomalCl, OLI_EU and others #include "World.h" #include "simulation.h" +#include "sceneeditor.h" #include "Globals.h" #include "timer.h" #include "Logs.h" @@ -127,23 +128,25 @@ void window_resize_callback(GLFWwindow *window, int w, int h) void cursor_pos_callback(GLFWwindow *window, double x, double y) { - input::Mouse.move( x, y ); - - if( true == Global.ControlPicking ) { - glfwSetCursorPos( window, x, y ); - } - else { + if( false == Global.ControlPicking ) { glfwSetCursorPos( window, 0, 0 ); } + + // give the potential event recipient a shot at it, in the virtual z order + if( true == scene::Editor.on_mouse_move( x, y ) ) { return; } + input::Mouse.move( x, y ); } void mouse_button_callback( GLFWwindow* window, int button, int action, int mods ) { - if( ( button == GLFW_MOUSE_BUTTON_LEFT ) - || ( button == GLFW_MOUSE_BUTTON_RIGHT ) ) { + if( ( button != GLFW_MOUSE_BUTTON_LEFT ) + && ( button != GLFW_MOUSE_BUTTON_RIGHT ) ) { // we don't care about other mouse buttons at the moment - input::Mouse.button( button, action ); + return; } + // give the potential event recipient a shot at it, in the virtual z order + if( true == scene::Editor.on_mouse_button( button, action ) ) { return; } + input::Mouse.button( button, action ); } void key_callback( GLFWwindow *window, int key, int scancode, int action, int mods ) { diff --git a/EvLaunch.cpp b/EvLaunch.cpp index 999925d25..c9bf882f2 100644 --- a/EvLaunch.cpp +++ b/EvLaunch.cpp @@ -135,10 +135,11 @@ bool TEventLauncher::Load(cParser *parser) return true; } -bool TEventLauncher::check_conditions() -{ //"renderowanie" wyzwalacza +bool TEventLauncher::check_activation() { + auto bCond { false }; - if (iKey != 0) { + + if( iKey != 0 ) { if( iKey > 255 ) { // key and modifier auto const modifier = ( iKey & 0xff00 ) >> 8; @@ -151,37 +152,45 @@ bool TEventLauncher::check_conditions() bCond = ( Console::Pressed( iKey & 0xff ) ); // czy klawisz wciśnięty } } - if (DeltaTime > 0) - { - if (UpdatedTime > DeltaTime) - { + if( DeltaTime > 0 ) { + if( UpdatedTime > DeltaTime ) { UpdatedTime = 0; // naliczanie od nowa bCond = true; } - else - UpdatedTime += Timer::GetDeltaTime(); // aktualizacja naliczania czasu + else { + // aktualizacja naliczania czasu + UpdatedTime += Timer::GetDeltaTime(); + } } - else - { // jeśli nie cykliczny, to sprawdzić czas - if (simulation::Time.data().wHour == iHour) - { - if (simulation::Time.data().wMinute == iMinute) - { // zgodność czasu uruchomienia - if (UpdatedTime < 10) - { + else { + // jeśli nie cykliczny, to sprawdzić czas + if( simulation::Time.data().wHour == iHour ) { + if( simulation::Time.data().wMinute == iMinute ) { + // zgodność czasu uruchomienia + if( UpdatedTime < 10 ) { UpdatedTime = 20; // czas do kolejnego wyzwolenia? bCond = true; } } } - else + else { UpdatedTime = 1; + } } - if (bCond) // jeśli spełniony został warunek - { - if ((iCheckMask != 0) && MemCell) // sprawdzanie warunku na komórce pamięci - bCond = MemCell->Compare(szText, fVal1, fVal2, iCheckMask); + + return bCond; +} + +bool TEventLauncher::check_conditions() { + + auto bCond { true }; + + if( ( iCheckMask != 0 ) + && ( MemCell != nullptr ) ) { + // sprawdzanie warunku na komórce pamięci + bCond = MemCell->Compare( szText, fVal1, fVal2, iCheckMask ); } + return bCond; // sprawdzanie dRadius w Ground.cpp } diff --git a/EvLaunch.h b/EvLaunch.h index 83487d50c..f545ca57c 100644 --- a/EvLaunch.h +++ b/EvLaunch.h @@ -24,6 +24,7 @@ class TEventLauncher : public scene::basic_node { // methods bool Load( cParser *parser ); + bool check_activation(); // checks conditions associated with the event. returns: true if the conditions are met bool check_conditions(); bool IsGlobal() const; diff --git a/Event.cpp b/Event.cpp index d4e76a937..c6a0cecc5 100644 --- a/Event.cpp +++ b/Event.cpp @@ -894,7 +894,7 @@ event_manager::update() { // test list of global events for possible new additions to the queue for( auto *launcher : m_launcherqueue ) { - if( true == launcher->check_conditions() ) { + if( true == ( launcher->check_activation() && launcher->check_conditions() ) ) { // NOTE: we're presuming global events aren't going to use event2 WriteLog( "Eventlauncher " + launcher->name() ); if( launcher->Event1 ) { diff --git a/Segment.cpp b/Segment.cpp index fff1b605a..5d117c14b 100644 --- a/Segment.cpp +++ b/Segment.cpp @@ -18,23 +18,8 @@ obtain one at //--------------------------------------------------------------------------- -// helper, restores content of a 3d vector from provided input stream -// TODO: review and clean up the helper routines, there's likely some redundant ones -Math3D::vector3 LoadPoint( cParser &Input ) { - // pobranie współrzędnych punktu - Input.getTokens( 3 ); - Math3D::vector3 point; - Input - >> point.x - >> point.y - >> point.z; - - return point; -} - - void -segment_data::deserialize( cParser &Input, Math3D::vector3 const &Offset ) { +segment_data::deserialize( cParser &Input, glm::dvec3 const &Offset ) { points[ segment_data::point::start ] = LoadPoint( Input ) + Offset; Input.getTokens(); diff --git a/Segment.h b/Segment.h index 538f3a33b..9410a2f7c 100644 --- a/Segment.h +++ b/Segment.h @@ -29,7 +29,7 @@ struct segment_data { // constructors segment_data() = default; // methods - void deserialize( cParser &Input, Math3D::vector3 const &Offset ); + void deserialize( cParser &Input, glm::dvec3 const &Offset ); }; class TSegment diff --git a/Track.cpp b/Track.cpp index a14042176..fc2b4347c 100644 --- a/Track.cpp +++ b/Track.cpp @@ -343,7 +343,7 @@ void TTrack::ConnectNextNext(TTrack *pTrack, int typ) } } -void TTrack::Load(cParser *parser, Math3D::vector3 pOrigin) +void TTrack::Load(cParser *parser, glm::dvec3 const &pOrigin) { // pobranie obiektu trajektorii ruchu Math3D::vector3 pt, vec, p1, p2, cp1, cp2, p3, p4, cp3, cp4; // dodatkowe punkty potrzebne do skrzyżowań double a1, a2, r1, r2, r3, r4; @@ -862,7 +862,7 @@ void TTrack::Load(cParser *parser, Math3D::vector3 pOrigin) } // calculate path location - m_area.center = ( glm::dvec3{ ( + location( { ( CurrentSegment()->FastGetPoint_0() + CurrentSegment()->FastGetPoint( 0.5 ) + CurrentSegment()->FastGetPoint_1() ) diff --git a/Track.h b/Track.h index 4348d2100..0f54aa4b3 100644 --- a/Track.h +++ b/Track.h @@ -170,20 +170,7 @@ class TTrack : public scene::basic_node { m_events1, m_events2; bool m_events { false }; // Ra: flaga informująca o obecności eventów -/* - TEvent *evEventall0 = nullptr; // McZapkie-140302: wyzwalany gdy pojazd stoi - TEvent *evEventall1 = nullptr; - TEvent *evEventall2 = nullptr; - TEvent *evEvent0 = nullptr; // McZapkie-280503: wyzwalany tylko gdy headdriver - TEvent *evEvent1 = nullptr; - TEvent *evEvent2 = nullptr; - std::string asEventall0Name; // nazwy eventów - std::string asEventall1Name; - std::string asEventall2Name; - std::string asEvent0Name; - std::string asEvent1Name; - std::string asEvent2Name; -*/ + int iNextDirection = 0; // 0:Point1, 1:Point2, 3:do odchylonego na zwrotnicy int iPrevDirection = 0; // domyślnie wirtualne odcinki dołączamy stroną od Point1 TTrackType eType = tt_Normal; // domyślnie zwykły @@ -246,7 +233,7 @@ class TTrack : public scene::basic_node { SwitchExtension != nullptr ? SwitchExtension->iRoads - 1 : 1 ); } - void Load(cParser *parser, Math3D::vector3 pOrigin); + void Load(cParser *parser, glm::dvec3 const &pOrigin); bool AssignEvents(); bool AssignForcedEvents(TEvent *NewEventPlus, TEvent *NewEventMinus); void QueueEvents( event_sequence const &Events, TDynamicObject const *Owner ); diff --git a/Traction.cpp b/Traction.cpp index a155e5a76..5356c4d5f 100644 --- a/Traction.cpp +++ b/Traction.cpp @@ -91,17 +91,6 @@ jawnie nazwę sekcji, ewentualnie nazwę zasilacza (zostanie zastąpiona wskazan sekcji z sąsiedniego przęsła). */ -glm::dvec3 LoadPoint( cParser &Input ) { - // pobranie współrzędnych punktu - glm::dvec3 point; - Input.getTokens( 3 ); - Input - >> point.x - >> point.y - >> point.z; - return point; -} - TTraction::TTraction( scene::node_data const &Nodedata ) : basic_node( Nodedata ) {} void diff --git a/maszyna.vcxproj.filters b/maszyna.vcxproj.filters index 9c66e2038..84f19a08c 100644 --- a/maszyna.vcxproj.filters +++ b/maszyna.vcxproj.filters @@ -240,6 +240,12 @@ Source Files + + Source Files + + + Source Files + @@ -467,6 +473,9 @@ Header Files + + Header Files + diff --git a/mouseinput.cpp b/mouseinput.cpp index c55d40eca..4bfceae0f 100644 --- a/mouseinput.cpp +++ b/mouseinput.cpp @@ -12,6 +12,7 @@ obtain one at #include "utilities.h" #include "globals.h" #include "timer.h" +#include "simulation.h" #include "world.h" #include "train.h" #include "renderer.h" @@ -74,33 +75,21 @@ mouse_input::button( int const Button, int const Action ) { if( false == Global.ControlPicking ) { return; } if( true == FreeFlyModeFlag ) { - // world editor controls - // TODO: separate behaviour when the scenery editor is active and in 'regular' free fly mode - if( Action == GLFW_RELEASE ) { - // if it's the right mouse button that got released we were potentially in view panning mode; stop it - if( Button == GLFW_MOUSE_BUTTON_RIGHT ) { - m_pickmodepanning = false; - } - } - else { - // button press - if( Button == GLFW_MOUSE_BUTTON_LEFT ) { - // the left button selects scene node - // further behaviour can vary depending on whether we're in editor mode + // freefly mode + // left mouse button launches on_click event associated with to the node + if( Button == GLFW_MOUSE_BUTTON_LEFT ) { + if( Action == GLFW_PRESS ) { auto const *node { GfxRenderer.Update_Pick_Node() }; - if( true == EditorModeFlag ) { - // NOTE: until we have proper editor object in place we set the current node manually - editor::Node = node; - } - else { - // launch on_click event associated with to the node - // TODO: implement + if( ( node == nullptr ) + || ( typeid( *node ) != typeid( TAnimModel ) ) ) { + return; } + simulation::Region->on_click( static_cast( node ) ); } - if( Button == GLFW_MOUSE_BUTTON_RIGHT ) { - // the right button activates mouse panning mode - m_pickmodepanning = true; - } + } + // right button controls panning + if( Button == GLFW_MOUSE_BUTTON_RIGHT ) { + m_pickmodepanning = ( Action == GLFW_PRESS ); } } else { @@ -130,62 +119,59 @@ mouse_input::button( int const Button, int const Action ) { } else { // if not release then it's press - auto train = World.train(); - if( train != nullptr ) { - auto lookup = m_mousecommands.find( train->GetLabel( GfxRenderer.Update_Pick_Control() ) ); - if( lookup != m_mousecommands.end() ) { - mousecommand = ( - Button == GLFW_MOUSE_BUTTON_LEFT ? - lookup->second.left : - lookup->second.right - ); - if( mousecommand != user_command::none ) { - // check manually for commands which have 'fast' variants launched with shift modifier - if( Global.shiftState ) { - switch( mousecommand ) { - case user_command::mastercontrollerincrease: { mousecommand = user_command::mastercontrollerincreasefast; break; } - case user_command::mastercontrollerdecrease: { mousecommand = user_command::mastercontrollerdecreasefast; break; } - case user_command::secondcontrollerincrease: { mousecommand = user_command::secondcontrollerincreasefast; break; } - case user_command::secondcontrollerdecrease: { mousecommand = user_command::secondcontrollerdecreasefast; break; } - case user_command::independentbrakeincrease: { mousecommand = user_command::independentbrakeincreasefast; break; } - case user_command::independentbrakedecrease: { mousecommand = user_command::independentbrakedecreasefast; break; } - default: { break; } - } - } - // NOTE: basic keyboard controls don't have any parameters - // as we haven't yet implemented either item id system or multiplayer, the 'local' controlled vehicle and entity have temporary ids of 0 - // TODO: pass correct entity id once the missing systems are in place - m_relay.post( mousecommand, 0, 0, Action, 0 ); - m_updateaccumulator = -0.25; // prevent potential command repeat right after issuing one - - switch( mousecommand ) { - case user_command::mastercontrollerincrease: - case user_command::mastercontrollerdecrease: - case user_command::secondcontrollerincrease: - case user_command::secondcontrollerdecrease: - case user_command::trainbrakeincrease: - case user_command::trainbrakedecrease: - case user_command::independentbrakeincrease: - case user_command::independentbrakedecrease: { - // these commands trigger varying repeat rate mode, - // which scales the rate based on the distance of the cursor from its point when the command was first issued - m_commandstartcursor = m_cursorposition; - m_varyingpollrate = true; - break; - } - default: { - break; - } - } + auto const lookup = m_mousecommands.find( World.train()->GetLabel( GfxRenderer.Update_Pick_Control() ) ); + if( lookup != m_mousecommands.end() ) { + // if the recognized element under the cursor has a command associated with the pressed button, notify the recipient + mousecommand = ( + Button == GLFW_MOUSE_BUTTON_LEFT ? + lookup->second.left : + lookup->second.right + ); + if( mousecommand == user_command::none ) { return; } + // check manually for commands which have 'fast' variants launched with shift modifier + if( Global.shiftState ) { + switch( mousecommand ) { + case user_command::mastercontrollerincrease: { mousecommand = user_command::mastercontrollerincreasefast; break; } + case user_command::mastercontrollerdecrease: { mousecommand = user_command::mastercontrollerdecreasefast; break; } + case user_command::secondcontrollerincrease: { mousecommand = user_command::secondcontrollerincreasefast; break; } + case user_command::secondcontrollerdecrease: { mousecommand = user_command::secondcontrollerdecreasefast; break; } + case user_command::independentbrakeincrease: { mousecommand = user_command::independentbrakeincreasefast; break; } + case user_command::independentbrakedecrease: { mousecommand = user_command::independentbrakedecreasefast; break; } + default: { break; } } } - else { - // if we don't have any recognized element under the cursor and the right button was pressed, enter view panning mode - if( Button == GLFW_MOUSE_BUTTON_RIGHT ) { - m_pickmodepanning = true; + // NOTE: basic keyboard controls don't have any parameters + // NOTE: as we haven't yet implemented either item id system or multiplayer, the 'local' controlled vehicle and entity have temporary ids of 0 + // TODO: pass correct entity id once the missing systems are in place + m_relay.post( mousecommand, 0, 0, Action, 0 ); + m_updateaccumulator = -0.25; // prevent potential command repeat right after issuing one + + switch( mousecommand ) { + case user_command::mastercontrollerincrease: + case user_command::mastercontrollerdecrease: + case user_command::secondcontrollerincrease: + case user_command::secondcontrollerdecrease: + case user_command::trainbrakeincrease: + case user_command::trainbrakedecrease: + case user_command::independentbrakeincrease: + case user_command::independentbrakedecrease: { + // these commands trigger varying repeat rate mode, + // which scales the rate based on the distance of the cursor from its point when the command was first issued + m_varyingpollrateorigin = m_cursorposition; + m_varyingpollrate = true; + break; + } + default: { + break; } } } + else { + // if we don't have any recognized element under the cursor and the right button was pressed, enter view panning mode + if( Button == GLFW_MOUSE_BUTTON_RIGHT ) { + m_pickmodepanning = true; + } + } } } } @@ -197,7 +183,7 @@ mouse_input::poll() { auto updaterate { m_updaterate }; if( m_varyingpollrate ) { - updaterate /= std::max( 0.15, 2.0 * glm::length( m_cursorposition - m_commandstartcursor ) / std::max( 1, Global.iWindowHeight ) ); + updaterate /= std::max( 0.15, 2.0 * glm::length( m_cursorposition - m_varyingpollrateorigin ) / std::max( 1, Global.iWindowHeight ) ); } while( m_updateaccumulator > updaterate ) { diff --git a/mouseinput.h b/mouseinput.h index ff9c77eb3..e87cdc42d 100644 --- a/mouseinput.h +++ b/mouseinput.h @@ -21,10 +21,10 @@ class mouse_input { // methods bool init(); - void - move( double const Mousex, double const Mousey ); void button( int const Button, int const Action ); + void + move( double const Mousex, double const Mousey ); void poll(); @@ -52,8 +52,8 @@ class mouse_input { double m_updateaccumulator { 0.0 }; bool m_pickmodepanning { false }; // indicates mouse is in view panning mode glm::dvec2 m_cursorposition; // stored last cursor position, used for panning - glm::dvec2 m_commandstartcursor; // helper, cursor position when the command was initiated bool m_varyingpollrate { false }; // indicates rate of command repeats is affected by the cursor position + glm::dvec2 m_varyingpollrateorigin; // helper, cursor position when the command was initiated }; //--------------------------------------------------------------------------- diff --git a/renderer.cpp b/renderer.cpp index 63720686b..42be7b0ed 100644 --- a/renderer.cpp +++ b/renderer.cpp @@ -449,6 +449,8 @@ opengl_renderer::Render_pass( rendermode const Mode ) { case rendermode::color: { + m_colorpass = m_renderpass; + if( ( true == Global.RenderShadows ) && ( false == Global.bWireFrame ) && ( true == World.InitPerformed() ) @@ -1668,6 +1670,11 @@ opengl_renderer::Render( scene::basic_region *Region ) { Update_Lights( simulation::Lights ); Render( std::begin( m_sectionqueue ), std::end( m_sectionqueue ) ); + if( EditorModeFlag && FreeFlyModeFlag && Global.ControlPicking ) { + // when editor mode is active calculate world position of the cursor + // at this stage the z-buffer is filled with only ground geometry + Update_Mouse_Position(); + } // draw queue is filled while rendering sections Render( std::begin( m_cellqueue ), std::end( m_cellqueue ) ); break; @@ -1912,7 +1919,7 @@ opengl_renderer::Render( cell_sequence::iterator First, cell_sequence::iterator ::glPushAttrib( GL_ENABLE_BIT ); ::glDisable( GL_TEXTURE_2D ); ::glColor3f( 0.36f, 0.75f, 0.35f ); - for( auto const *memorycell : cell->m_memorycells ) { + for( auto *memorycell : cell->m_memorycells ) { Render( memorycell ); } ::glPopAttrib(); @@ -1929,7 +1936,7 @@ opengl_renderer::Render( cell_sequence::iterator First, cell_sequence::iterator // memcells if( ( EditorModeFlag ) && ( DebugModeFlag ) ) { - for( auto const *memorycell : cell->m_memorycells ) { + for( auto *memorycell : cell->m_memorycells ) { ::glColor3fv( glm::value_ptr( pick_color( m_picksceneryitems.size() + 1 ) ) ); Render( memorycell ); } @@ -2310,16 +2317,16 @@ opengl_renderer::Render( TModel3d *Model, material_data const *Material, float c } bool -opengl_renderer::Render( TModel3d *Model, material_data const *Material, float const Squaredistance, Math3D::vector3 const &Position, Math3D::vector3 const &Angle ) { +opengl_renderer::Render( TModel3d *Model, material_data const *Material, float const Squaredistance, Math3D::vector3 const &Position, glm::vec3 const &Angle ) { ::glPushMatrix(); ::glTranslated( Position.x, Position.y, Position.z ); if( Angle.y != 0.0 ) - ::glRotated( Angle.y, 0.0, 1.0, 0.0 ); + ::glRotatef( Angle.y, 0.f, 1.f, 0.f ); if( Angle.x != 0.0 ) - ::glRotated( Angle.x, 1.0, 0.0, 0.0 ); + ::glRotatef( Angle.x, 1.f, 0.f, 0.f ); if( Angle.z != 0.0 ) - ::glRotated( Angle.z, 0.0, 0.0, 1.0 ); + ::glRotatef( Angle.z, 0.f, 0.f, 1.f ); auto const result = Render( Model, Material, Squaredistance ); @@ -2755,7 +2762,7 @@ opengl_renderer::Render( scene::basic_cell::path_sequence::const_iterator First, } void -opengl_renderer::Render( TMemCell const *Memcell ) { +opengl_renderer::Render( TMemCell *Memcell ) { ::glPushMatrix(); auto const position = Memcell->location() - m_renderpass.camera.position(); @@ -3129,16 +3136,16 @@ opengl_renderer::Render_Alpha( TModel3d *Model, material_data const *Material, f } bool -opengl_renderer::Render_Alpha( TModel3d *Model, material_data const *Material, float const Squaredistance, Math3D::vector3 const &Position, Math3D::vector3 const &Angle ) { +opengl_renderer::Render_Alpha( TModel3d *Model, material_data const *Material, float const Squaredistance, Math3D::vector3 const &Position, glm::vec3 const &Angle ) { ::glPushMatrix(); ::glTranslated( Position.x, Position.y, Position.z ); if( Angle.y != 0.0 ) - ::glRotated( Angle.y, 0.0, 1.0, 0.0 ); + ::glRotatef( Angle.y, 0.f, 1.f, 0.f ); if( Angle.x != 0.0 ) - ::glRotated( Angle.x, 1.0, 0.0, 0.0 ); + ::glRotatef( Angle.x, 1.f, 0.f, 0.f ); if( Angle.z != 0.0 ) - ::glRotated( Angle.z, 0.0, 0.0, 1.0 ); + ::glRotatef( Angle.z, 0.f, 0.f, 1.f ); auto const result = Render_Alpha( Model, Material, Squaredistance ); // position is effectively camera offset @@ -3379,7 +3386,7 @@ opengl_renderer::Render_Alpha( TSubModel *Submodel ) { // utility methods -TSubModel const * +TSubModel * opengl_renderer::Update_Pick_Control() { #ifdef EU07_USE_PICKING_FRAMEBUFFER @@ -3412,7 +3419,7 @@ opengl_renderer::Update_Pick_Control() { unsigned char pickreadout[4]; ::glReadPixels( pickbufferpos.x, pickbufferpos.y, 1, 1, GL_BGRA, GL_UNSIGNED_BYTE, pickreadout ); auto const controlindex = pick_index( glm::ivec3{ pickreadout[ 2 ], pickreadout[ 1 ], pickreadout[ 0 ] } ); - TSubModel const *control { nullptr }; + TSubModel *control { nullptr }; if( ( controlindex > 0 ) && ( controlindex <= m_pickcontrolsitems.size() ) ) { control = m_pickcontrolsitems[ controlindex - 1 ]; @@ -3426,7 +3433,7 @@ opengl_renderer::Update_Pick_Control() { return control; } -scene::basic_node const * +scene::basic_node * opengl_renderer::Update_Pick_Node() { #ifdef EU07_USE_PICKING_FRAMEBUFFER @@ -3461,7 +3468,7 @@ opengl_renderer::Update_Pick_Node() { unsigned char pickreadout[4]; ::glReadPixels( pickbufferpos.x, pickbufferpos.y, 1, 1, GL_BGRA, GL_UNSIGNED_BYTE, pickreadout ); auto const nodeindex = pick_index( glm::ivec3{ pickreadout[ 2 ], pickreadout[ 1 ], pickreadout[ 0 ] } ); - scene::basic_node const *node { nullptr }; + scene::basic_node *node { nullptr }; if( ( nodeindex > 0 ) && ( nodeindex <= m_picksceneryitems.size() ) ) { node = m_picksceneryitems[ nodeindex - 1 ]; @@ -3475,6 +3482,29 @@ opengl_renderer::Update_Pick_Node() { return node; } +// converts provided screen coordinates to world coordinates of most recent color pass +glm::dvec3 +opengl_renderer::Update_Mouse_Position() { + + glm::dvec2 mousepos; + glfwGetCursorPos( m_window, &mousepos.x, &mousepos.y ); + mousepos.x = clamp( mousepos.x, 0, Global.iWindowWidth - 1 ); + mousepos.y = clamp( Global.iWindowHeight - clamp( mousepos.y, 0, Global.iWindowHeight ), 0, Global.iWindowHeight - 1 ) ; + GLfloat pointdepth; + ::glReadPixels( mousepos.x, mousepos.y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &pointdepth ); + + if( pointdepth < 1.0 ) { + m_worldmousecoordinates = + glm::unProject( + glm::vec3{ mousepos, pointdepth }, + glm::mat4{ glm::mat3{ m_colorpass.camera.modelview() } }, + m_colorpass.camera.projection(), + glm::vec4{ 0, 0, Global.iWindowWidth, Global.iWindowHeight } ); + } + + return m_colorpass.camera.position() + glm::dvec3{ m_worldmousecoordinates }; +} + void opengl_renderer::Update( double const Deltatime ) { diff --git a/renderer.h b/renderer.h index 884053776..3db03799e 100644 --- a/renderer.h +++ b/renderer.h @@ -167,13 +167,17 @@ class opengl_renderer { Pick_Control() const { return m_pickcontrolitem; } scene::basic_node const * Pick_Node() const { return m_picksceneryitem; } + glm::dvec3 + Mouse_Position() const { return m_worldmousecoordinates; } // maintenance methods void Update( double const Deltatime ); - TSubModel const * + TSubModel * Update_Pick_Control(); - scene::basic_node const * + scene::basic_node * Update_Pick_Node(); + glm::dvec3 + Update_Mouse_Position(); // debug methods std::string const & info_times() const; @@ -277,7 +281,7 @@ class opengl_renderer { bool Render( TDynamicObject *Dynamic ); bool - Render( TModel3d *Model, material_data const *Material, float const Squaredistance, Math3D::vector3 const &Position, Math3D::vector3 const &Angle ); + Render( TModel3d *Model, material_data const *Material, float const Squaredistance, Math3D::vector3 const &Position, glm::vec3 const &Angle ); bool Render( TModel3d *Model, material_data const *Material, float const Squaredistance ); void @@ -289,7 +293,7 @@ class opengl_renderer { bool Render_cab( TDynamicObject const *Dynamic, bool const Alpha = false ); void - Render( TMemCell const *Memcell ); + Render( TMemCell *Memcell ); void Render_Alpha( scene::basic_region *Region ); void @@ -303,7 +307,7 @@ class opengl_renderer { bool Render_Alpha( TDynamicObject *Dynamic ); bool - Render_Alpha( TModel3d *Model, material_data const *Material, float const Squaredistance, Math3D::vector3 const &Position, Math3D::vector3 const &Angle ); + Render_Alpha( TModel3d *Model, material_data const *Material, float const Squaredistance, Math3D::vector3 const &Position, glm::vec3 const &Angle ); bool Render_Alpha( TModel3d *Model, material_data const *Material, float const Squaredistance ); void @@ -386,12 +390,14 @@ class opengl_renderer { renderpass_config m_renderpass; // parameters for current render pass section_sequence m_sectionqueue; // list of sections in current render pass cell_sequence m_cellqueue; + renderpass_config m_colorpass; // parametrs of most recent color pass renderpass_config m_shadowpass; // parametrs of most recent shadowmap pass renderpass_config m_cabshadowpass; // parameters of most recent cab shadowmap pass - std::vector m_pickcontrolsitems; - TSubModel const *m_pickcontrolitem { nullptr }; - std::vector m_picksceneryitems; - scene::basic_node const *m_picksceneryitem { nullptr }; + std::vector m_pickcontrolsitems; + TSubModel *m_pickcontrolitem { nullptr }; + std::vector m_picksceneryitems; + scene::basic_node *m_picksceneryitem { nullptr }; + glm::vec3 m_worldmousecoordinates { 0.f }; #ifdef EU07_USE_DEBUG_CAMERA renderpass_config m_worldcamera; // debug item #endif diff --git a/scene.cpp b/scene.cpp index 9b6312ecd..4586f442d 100644 --- a/scene.cpp +++ b/scene.cpp @@ -22,6 +22,19 @@ namespace scene { std::string const EU07_FILEEXTENSION_REGION { ".sbt" }; std::uint32_t const EU07_FILEVERSION_REGION { MAKE_ID4( 'S', 'B', 'T', 1 ) }; +// potentially activates event handler with the same name as provided node, and within handler activation range +void +basic_cell::on_click( TAnimModel const *Instance ) { + + for( auto *launcher : m_eventlaunchers ) { + if( ( launcher->name() == Instance->name() ) + && ( glm::length2( launcher->location() - Instance->location() ) < launcher->dRadius ) + && ( true == launcher->check_conditions() ) ) { + launch_event( launcher ); + } + } +} + // legacy method, finds and assigns traction piece to specified pantograph of provided vehicle void basic_cell::update_traction( TDynamicObject *Vehicle, int const Pantographindex ) { @@ -105,17 +118,10 @@ basic_cell::update_events() { // event launchers for( auto *launcher : m_eventlaunchers ) { - if( ( true == launcher->check_conditions() ) + if( ( true == ( launcher->check_activation() && launcher->check_conditions() ) ) && ( SquareMagnitude( launcher->location() - Global.pCameraPosition ) < launcher->dRadius ) ) { - WriteLog( "Eventlauncher " + launcher->name() ); - if( ( true == Global.shiftState ) - && ( launcher->Event2 != nullptr ) ) { - simulation::Events.AddToQuery( launcher->Event2, nullptr ); - } - else if( launcher->Event1 ) { - simulation::Events.AddToQuery( launcher->Event1, nullptr ); - } + launch_event( launcher ); } } } @@ -384,6 +390,38 @@ basic_cell::insert( TMemCell *Memorycell ) { // NOTE: memory cells are virtual 'points' hence they don't ever expand cell range } +// removes provided model instance from the cell +void +basic_cell::erase( TAnimModel *Instance ) { + + auto const flags = Instance->Flags(); + auto alpha = + ( Instance->Material() != nullptr ? + Instance->Material()->textures_alpha : + 0x30300030 ); + + if( alpha & flags & 0x2F2F002F ) { + // instance has translucent pieces + m_instancetranslucent.erase( + std::remove_if( + std::begin( m_instancetranslucent ), std::end( m_instancetranslucent ), + [=]( TAnimModel *instance ) { + return instance == Instance; } ), + std::end( m_instancetranslucent ) ); + } + alpha ^= 0x0F0F000F; // odwrócenie flag tekstur, aby wyłapać nieprzezroczyste + if( alpha & flags & 0x1F1F001F ) { + // instance has opaque pieces + m_instancesopaque.erase( + std::remove_if( + std::begin( m_instancesopaque ), std::end( m_instancesopaque ), + [=]( TAnimModel *instance ) { + return instance == Instance; } ), + std::end( m_instancesopaque ) ); + } + // TODO: update cell bounding area +} + // registers provided path in the lookup directory of the cell void basic_cell::register_end( TTrack *Path ) { @@ -549,6 +587,20 @@ basic_cell::create_geometry( gfx::geometrybank_handle const &Bank ) { m_geometrycreated = true; // helper for legacy animation code, get rid of it after refactoring } +// executes event assigned to specified launcher +void +basic_cell::launch_event( TEventLauncher *Launcher ) { + + WriteLog( "Eventlauncher " + Launcher->name() ); + if( ( true == Global.shiftState ) + && ( Launcher->Event2 != nullptr ) ) { + simulation::Events.AddToQuery( Launcher->Event2, nullptr ); + } + else if( Launcher->Event1 ) { + simulation::Events.AddToQuery( Launcher->Event1, nullptr ); + } +} + // adjusts cell bounding area to enclose specified node void basic_cell::enclose_area( scene::basic_node *Node ) { @@ -560,6 +612,13 @@ basic_cell::enclose_area( scene::basic_node *Node ) { +// potentially activates event handler with the same name as provided node, and within handler activation range +void +basic_section::on_click( TAnimModel const *Instance ) { + + cell( Instance->location() ).on_click( Instance ); +} + // legacy method, finds and assigns traction piece(s) to pantographs of provided vehicle void basic_section::update_traction( TDynamicObject *Vehicle, int const Pantographindex ) { @@ -856,6 +915,19 @@ basic_region::~basic_region() { for( auto *section : m_sections ) { if( section != nullptr ) { delete section; } } } +// potentially activates event handler with the same name as provided node, and within handler activation range +void +basic_region::on_click( TAnimModel const *Instance ) { + + if( Instance->name().empty() || ( Instance->name() == "none" ) ) { return; } + + auto const location { Instance->location() }; + + if( point_inside( location ) ) { + section( location ).on_click( Instance ); + } +} + // legacy method, polls event launchers around camera void basic_region::update_events() { @@ -1185,8 +1257,8 @@ basic_region::insert_traction( TTraction *Traction, scratch_data &Scratchpad ) { // inserts provided instance of 3d model in the region void basic_region::insert_instance( TAnimModel *Instance, scratch_data &Scratchpad ) { - // NOTE: bounding area isn't present/filled until track class and wrapper refactoring is done - auto location = Instance->location(); + + auto const location { Instance->location() }; if( point_inside( location ) ) { // NOTE: nodes placed outside of region boundaries are discarded @@ -1198,6 +1270,18 @@ basic_region::insert_instance( TAnimModel *Instance, scratch_data &Scratchpad ) } } +// removes specified instance of 3d model from the region +void +basic_region::erase_instance( TAnimModel *Instance ) { + + auto const location { Instance->location() }; + + if( point_inside( location ) ) { + // NOTE: nodes placed outside of region boundaries are discarded + section( location ).erase( Instance ); + } +} + // inserts provided sound in the region void basic_region::insert_sound( sound_source *Sound, scratch_data &Scratchpad ) { diff --git a/scene.h b/scene.h index 1e0ab86dd..1b7be690c 100644 --- a/scene.h +++ b/scene.h @@ -66,6 +66,9 @@ class basic_cell { // constructors basic_cell() = default; // methods + // potentially activates event handler with the same name as provided node, and within handler activation range + void + on_click( TAnimModel const *Instance ); // legacy method, finds and assigns traction piece to specified pantograph of provided vehicle void update_traction( TDynamicObject *Vehicle, int const Pantographindex ); @@ -123,6 +126,9 @@ class basic_cell { // registers provided traction piece in the lookup directory of the cell void register_end( TTraction *Traction ); + // removes provided model instance from the cell + void + erase( TAnimModel *Instance ); // find a vehicle located nearest to specified point, within specified radius. reurns: located vehicle and distance std::tuple find( glm::dvec3 const &Point, float const Radius, bool const Onlycontrolled, bool const Findbycoupler ) const; @@ -157,6 +163,8 @@ class basic_cell { using eventlauncher_sequence = std::vector; using memorycell_sequence = std::vector; // methods + void + launch_event( TEventLauncher *Launcher ); void enclose_area( scene::basic_node *Node ); // members @@ -193,7 +201,10 @@ class basic_section { // constructors basic_section() = default; // methods -// legacy method, finds and assigns traction piece to specified pantograph of provided vehicle + // potentially activates event handler with the same name as provided node, and within handler activation range + void + on_click( TAnimModel const *Instance ); + // legacy method, finds and assigns traction piece to specified pantograph of provided vehicle void update_traction( TDynamicObject *Vehicle, int const Pantographindex ); // legacy method, updates sounds and polls event launchers within radius around specified point @@ -230,6 +241,13 @@ class basic_section { m_area.radius = std::max( m_area.radius, static_cast( glm::length( m_area.center - targetcell.area().center ) + targetcell.area().radius ) ); } + // erases provided node from the section + template + void + erase( Type_ *Node ) { + auto &targetcell { cell( Node->location() ) }; + // TODO: re-calculate bounding area after removal + targetcell.erase( Node ); } // registers provided node in the lookup directory of the section enclosing specified point template void @@ -289,7 +307,10 @@ class basic_region { // destructor ~basic_region(); // methods -// legacy method, finds and assigns traction piece to specified pantograph of provided vehicle + // potentially activates event handler with the same name as provided node, and within handler activation range + void + on_click( TAnimModel const *Instance ); + // legacy method, finds and assigns traction piece to specified pantograph of provided vehicle void update_traction( TDynamicObject *Vehicle, int const Pantographindex ); // legacy method, polls event launchers around camera @@ -337,6 +358,9 @@ class basic_region { // inserts provided memory cell in the region void insert_memorycell( TMemCell *Memorycell, scratch_data &Scratchpad ); + // removes specified instance of 3d model from the region + void + erase_instance( TAnimModel *Instance ); // find a vehicle located nearest to specified point, within specified radius. reurns: located vehicle and distance std::tuple find_vehicle( glm::dvec3 const &Point, float const Radius, bool const Onlycontrolled, bool const Findbycoupler ); diff --git a/sceneeditor.cpp b/sceneeditor.cpp new file mode 100644 index 000000000..fec5381a0 --- /dev/null +++ b/sceneeditor.cpp @@ -0,0 +1,165 @@ +/* +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 "sceneeditor.h" + +#include "globals.h" +#include "simulation.h" +#include "renderer.h" + +namespace scene { + +basic_editor Editor; + +bool +basic_editor::on_mouse_button( int const Button, int const Action ) { + + if( false == EditorModeFlag ) { return false; } + // TBD: automatically activate and enforce picking mode and/or freefly mode when editor is active? + if( false == FreeFlyModeFlag ) { return false; } + if( false == Global.ControlPicking ) { return false; } + + if( Button == GLFW_MOUSE_BUTTON_LEFT ) { + + if( Action == GLFW_PRESS ) { + + m_node = GfxRenderer.Update_Pick_Node(); + m_nodesnapshot = { m_node }; + if( m_node ) { + glfwSetInputMode( Global.window, GLFW_CURSOR, GLFW_CURSOR_DISABLED ); + } + } + else { + // left button release + // TODO: record the current undo step on the undo stack + m_nodesnapshot = { m_node }; + if( m_node ) { + glfwSetInputMode( Global.window, GLFW_CURSOR, GLFW_CURSOR_NORMAL ); + } + } + + m_mouseleftbuttondown = ( Action == GLFW_PRESS ); + + return ( m_node != nullptr ); + } + + return false; +} + +bool +basic_editor::on_mouse_move( double const Mousex, double const Mousey ) { + + auto const mousemove { glm::dvec2{ Mousex, Mousey } - m_mouseposition }; + m_mouseposition = { Mousex, Mousey }; + + if( false == EditorModeFlag ) { return false; } + if( false == m_mouseleftbuttondown ) { return false; } + if( m_node == nullptr ) { return false; } + + if( mode_translation() ) { + // move selected node + if( mode_translation_vertical() ) { + auto const translation { mousemove.y * -0.01f }; + translate( translation ); + } + else { + auto const mouseworldposition{ Global.pCamera->Pos + GfxRenderer.Mouse_Position() }; + translate( mouseworldposition ); + } + } + else { + // rotate selected node + auto const rotation { glm::vec3 { mousemove.y, mousemove.x, 0 } * 0.25f }; + rotate( rotation ); + } + + return true; +} + +void +basic_editor::translate( glm::dvec3 const &Location ) { + + auto *node { m_node }; // placeholder for operations on multiple nodes + + auto location { Location }; + + if( typeid( *node ) == typeid( TAnimModel ) ) { + // TBD, TODO: don't modify y coordinate if snap-to-ground mode is active? +// location.y = node->location().y; + translate_instance( static_cast( node ), location ); + } +} + +void +basic_editor::translate( float const Offset ) { + + // NOTE: offset scaling is calculated early so the same multiplier can be applied to potential whole group + auto location { m_node->location() }; + auto const distance { glm::length( location - glm::dvec3{ Global.pCamera->Pos } ) }; + auto const offset { Offset * std::max( 1.0, distance * 0.01 ) }; + + auto *node { m_node }; // placeholder for operations on multiple nodes + + if( typeid( *node ) == typeid( TAnimModel ) ) { + translate_instance( static_cast( node ), offset ); + } +} + +void +basic_editor::translate_instance( TAnimModel *Instance, glm::dvec3 const &Location ) { + + simulation::Region->erase_instance( Instance ); + Instance->location( Location ); + simulation::Region->insert_instance( Instance, scene::scratch_data() ); +} + +void +basic_editor::translate_instance( TAnimModel *Instance, float const Offset ) { + + auto location { Instance->location() }; + location.y += Offset; + Instance->location( location ); +} + +void +basic_editor::rotate( glm::vec3 const &Angle ) { + + auto *node { m_node }; // placeholder for operations on multiple nodes + + if( typeid( *node ) == typeid( TAnimModel ) ) { + rotate_instance( static_cast( node ), Angle ); + } +} + +void +basic_editor::rotate_instance( TAnimModel *Instance, glm::vec3 const &Angle ) { + + // adjust node data + glm::vec3 angle = glm::dvec3 { Instance->Angles() }; + angle.y = clamp_circular( angle.y + Angle.y, 360.f ); + Instance->Angles( angle ); + // update scene +} + +bool +basic_editor::mode_translation() const { + + return ( false == Global.ctrlState ); +} + +bool +basic_editor::mode_translation_vertical() const { + + return ( true == Global.shiftState ); +} + +} // scene + +//--------------------------------------------------------------------------- diff --git a/sceneeditor.h b/sceneeditor.h new file mode 100644 index 000000000..74f96d4a6 --- /dev/null +++ b/sceneeditor.h @@ -0,0 +1,73 @@ +/* +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 "scenenode.h" + +namespace scene { + +class basic_editor { + +public: +// methods + bool + on_mouse_button( int const Button, int const Action ); + bool + on_mouse_move( double const Mousex, double const Mousey ); + scene::basic_node const * + node() const { + return m_node; } +private: +// types + struct node_snapshot { + + scene::basic_node *node; + std::string data; + + node_snapshot( scene::basic_node *Node ) : + node( Node ) { + if( Node != nullptr ) { + Node->export_as_text( data ); } }; + }; + friend bool operator==( basic_editor::node_snapshot const &Left, basic_editor::node_snapshot const &Right ); + friend bool operator!=( basic_editor::node_snapshot const &Left, basic_editor::node_snapshot const &Right ); +// methods + bool + mode_translation() const; + bool + mode_translation_vertical() const; + void + translate( glm::dvec3 const &Location ); + void + translate( float const Offset ); + void + translate_instance( TAnimModel *Instance, glm::dvec3 const &Location ); + void + translate_instance( TAnimModel *Instance, float const Offset ); + void + rotate( glm::vec3 const &Angle ); + void + rotate_instance( TAnimModel *Instance, glm::vec3 const &Angle ); +// members + scene::basic_node *m_node; // temporary helper, currently selected scene node + node_snapshot m_nodesnapshot { nullptr }; // currently selected scene node in its pre-modified state + glm::dvec2 m_mouseposition { 0.0 }; + bool m_mouseleftbuttondown { false }; + +}; + +inline bool operator==( basic_editor::node_snapshot const &Left, basic_editor::node_snapshot const &Right ) { return ( ( Left.node == Right.node ) && ( Left.data == Right.data ) ); } +inline bool operator!=( basic_editor::node_snapshot const &Left, basic_editor::node_snapshot const &Right ) { return ( !( Left == Right ) ); } + +extern basic_editor Editor; + +} // scene + +//--------------------------------------------------------------------------- diff --git a/scenenode.cpp b/scenenode.cpp index 5022a795c..67efa4351 100644 --- a/scenenode.cpp +++ b/scenenode.cpp @@ -743,6 +743,14 @@ basic_node::export_as_text( std::ostream &Output ) const { export_as_text_( Output ); } +void +basic_node::export_as_text( std::string &Output ) const { + + std::stringstream converter; + export_as_text( converter ); + Output += converter.str(); +} + float const & basic_node::radius() { @@ -763,10 +771,4 @@ basic_node::radius_() { } // scene -namespace editor { - -scene::basic_node const *Node { nullptr }; // temporary helper, currently selected scene node - -} // editor - //--------------------------------------------------------------------------- diff --git a/scenenode.h b/scenenode.h index eb986dba8..915c60c7e 100644 --- a/scenenode.h +++ b/scenenode.h @@ -316,6 +316,8 @@ struct basic_node { // sends basic content of the class in legacy (text) format to provided stream void export_as_text( std::ostream &Output ) const; + void + export_as_text( std::string &Output ) const; std::string const & name() const; void @@ -381,10 +383,4 @@ basic_node::visible() const { } // scene -namespace editor { - -extern scene::basic_node const *Node; // temporary helper, currently selected scene node - -} // editor - //--------------------------------------------------------------------------- diff --git a/simulation.cpp b/simulation.cpp index 39d067232..39ab215b7 100644 --- a/simulation.cpp +++ b/simulation.cpp @@ -620,13 +620,13 @@ state_manager::deserialize_path( cParser &Input, scene::scratch_data &Scratchpad // TODO: refactor track and wrapper classes and their de/serialization. do offset and rotation after deserialization is done auto *track = new TTrack( Nodedata ); - Math3D::vector3 offset = ( + auto const offset { ( Scratchpad.location.offset.empty() ? - Math3D::vector3() : - Math3D::vector3( - Scratchpad.location.offset.top().x, - Scratchpad.location.offset.top().y, - Scratchpad.location.offset.top().z ) ); + glm::dvec3 { 0.0 } : + glm::dvec3 { + Scratchpad.location.offset.top().x, + Scratchpad.location.offset.top().y, + Scratchpad.location.offset.top().z } ) }; track->Load( &Input, offset ); return track; @@ -707,7 +707,7 @@ state_manager::deserialize_model( cParser &Input, scene::scratch_data &Scratchpa >> rotation.y; auto *instance = new TAnimModel( Nodedata ); - instance->RaAnglesSet( Scratchpad.location.rotation + rotation ); // dostosowanie do pochylania linii + instance->Angles( Scratchpad.location.rotation + rotation ); // dostosowanie do pochylania linii if( instance->Load( &Input, false ) ) { instance->location( transform( location, Scratchpad ) ); diff --git a/uilayer.cpp b/uilayer.cpp index f54ca2c31..d0f98db69 100644 --- a/uilayer.cpp +++ b/uilayer.cpp @@ -2,17 +2,14 @@ #include "stdafx.h" #include "uilayer.h" -#include "uitranscripts.h" #include "globals.h" #include "translation.h" #include "simulation.h" #include "mtable.h" #include "train.h" -#include "dynobj.h" -#include "model3d.h" +#include "sceneeditor.h" #include "renderer.h" -#include "timer.h" #include "utilities.h" #include "logs.h" @@ -710,12 +707,16 @@ ui_layer::update() { case( GLFW_KEY_F11 ): { // scenario inspector - auto const *node { editor::Node }; + auto const *node { scene::Editor.node() }; - if( node == nullptr ) { break; } + if( node == nullptr ) { + auto const mouseposition { Global.pCamera->Pos + GfxRenderer.Mouse_Position() }; + uitextline1 = "mouse location: [" + to_string( mouseposition.x, 2 ) + ", " + to_string( mouseposition.y, 2 ) + ", " + to_string( mouseposition.z, 2 ) + "]"; + break; + } uitextline1 = - "Node name: " + node->name() + "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{ Global.pCameraPosition.x, 0.0, Global.pCameraPosition.z } ), 1 ) + " m)"; // subclass-specific data @@ -724,7 +725,7 @@ ui_layer::update() { auto const *subnode = static_cast( node ); - uitextline2 = "angle: " + to_string( clamp_circular( subnode->vAngle.y, 360.0 ), 2 ) + " deg"; + uitextline2 = "angle: " + to_string( clamp_circular( subnode->vAngle.y, 360.f ), 2 ) + " deg"; uitextline2 += "; lights: "; if( subnode->iNumLights > 0 ) { uitextline2 += '['; diff --git a/utilities.cpp b/utilities.cpp index af1deec4c..bd8207b2d 100644 --- a/utilities.cpp +++ b/utilities.cpp @@ -25,10 +25,11 @@ Copyright (C) 2007-2014 Maciej Cierniak #include "utilities.h" #include "globals.h" +#include "parser.h" bool DebugModeFlag = false; bool FreeFlyModeFlag = false; -bool EditorModeFlag = true; +bool EditorModeFlag = false; bool DebugCameraFlag = false; double Max0R(double x1, double x2) @@ -387,3 +388,17 @@ substr_path( std::string const &Filename ) { Filename.substr( 0, Filename.rfind( '/' ) + 1 ) : "" ); } + +// helper, restores content of a 3d vector from provided input stream +// TODO: review and clean up the helper routines, there's likely some redundant ones +glm::dvec3 LoadPoint( cParser &Input ) { + // pobranie współrzędnych punktu + Input.getTokens( 3 ); + glm::dvec3 point; + Input + >> point.x + >> point.y + >> point.z; + + return point; +} diff --git a/utilities.h b/utilities.h index 3bd9f9e80..21dedce90 100644 --- a/utilities.h +++ b/utilities.h @@ -300,4 +300,8 @@ nearest_segment_point( VecType_ const &Segmentstart, VecType_ const &Segmentend, return c1 / c2; } +class cParser; + +glm::dvec3 LoadPoint( cParser &Input ); + //--------------------------------------------------------------------------- diff --git a/version.h b/version.h index 995460b1c..13967e6ca 100644 --- a/version.h +++ b/version.h @@ -1,5 +1,5 @@ #pragma once #define VERSION_MAJOR 18 -#define VERSION_MINOR 629 +#define VERSION_MINOR 708 #define VERSION_REVISION 0