diff --git a/AnimModel.cpp b/AnimModel.cpp
index d1917a75..4676c08a 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 e901f1c5..fb109893 100644
--- a/AnimModel.h
+++ b/AnimModel.h
@@ -138,11 +138,8 @@ public:
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 @@ public:
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 @@ private:
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 b58901f7..6e4f51ed 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 9a70d438..3ac8b33b 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 ff276ba6..281a8b38 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 999925d2..c9bf882f 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 83487d50..f545ca57 100644
--- a/EvLaunch.h
+++ b/EvLaunch.h
@@ -24,6 +24,7 @@ public:
// 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 d4e76a93..c6a0cecc 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 fff1b605..5d117c14 100644
--- a/Segment.cpp
+++ b/Segment.cpp
@@ -18,23 +18,8 @@ http://mozilla.org/MPL/2.0/.
//---------------------------------------------------------------------------
-// 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 538f3a33..9410a2f7 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 a1404217..fc2b4347 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 4348d210..0f54aa4b 100644
--- a/Track.h
+++ b/Track.h
@@ -170,20 +170,7 @@ public:
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 @@ public:
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 a155e5a7..5356c4d5 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 9c66e203..84f19a08 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 c55d40ec..4bfceae0 100644
--- a/mouseinput.cpp
+++ b/mouseinput.cpp
@@ -12,6 +12,7 @@ http://mozilla.org/MPL/2.0/.
#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;
+ // 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( ( node == nullptr )
+ || ( typeid( *node ) != typeid( TAnimModel ) ) ) {
+ return;
+ }
+ simulation::Region->on_click( static_cast( node ) );
}
}
- 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
- 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( 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,60 +119,57 @@ 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 ff9c77eb..e87cdc42 100644
--- a/mouseinput.h
+++ b/mouseinput.h
@@ -21,10 +21,10 @@ public:
// 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 @@ private:
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 63720686..42be7b0e 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 88405377..3db03799 100644
--- a/renderer.h
+++ b/renderer.h
@@ -167,13 +167,17 @@ public:
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 @@ private:
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 @@ private:
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 @@ private:
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 @@ private:
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 9b6312ec..4586f442 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 1e0ab86d..1b7be690 100644
--- a/scene.h
+++ b/scene.h
@@ -66,6 +66,9 @@ public:
// 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 @@ public:
// 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 @@ private:
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 @@ public:
// 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 @@ public:
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 @@ public:
// 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 @@ public:
// 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 00000000..fec5381a
--- /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 00000000..74f96d4a
--- /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 5022a795..67efa435 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 eb986dba..915c60c7 100644
--- a/scenenode.h
+++ b/scenenode.h
@@ -316,6 +316,8 @@ public:
// 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 39d06723..39ab215b 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 f54ca2c3..d0f98db6 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 af1deec4..bd8207b2 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 3bd9f9e8..21dedce9 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 995460b1..13967e6c 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