mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-07-22 15:09:19 +02:00
refactoring: application mode code split
This commit is contained in:
@@ -19,6 +19,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "MdlMngr.h"
|
||||
#include "simulation.h"
|
||||
#include "simulationtime.h"
|
||||
#include "event.h"
|
||||
#include "Globals.h"
|
||||
#include "Timer.h"
|
||||
#include "Logs.h"
|
||||
@@ -610,7 +611,7 @@ void TAnimModel::RaPrepare()
|
||||
if (LightsOff[i])
|
||||
LightsOff[i]->iVisible = !state;
|
||||
}
|
||||
TSubModel::iInstance = (size_t)this; //żeby nie robić cudzych animacji
|
||||
TSubModel::iInstance = reinterpret_cast<std::uintptr_t>( this ); //żeby nie robić cudzych animacji
|
||||
TSubModel::pasText = &asText; // przekazanie tekstu do wyświetlacza (!!!! do przemyślenia)
|
||||
if (pAdvanced) // jeśli jest zaawansowana animacja
|
||||
Advanced(); // wykonać co tam trzeba
|
||||
|
||||
@@ -125,7 +125,7 @@ class TAnimAdvanced
|
||||
class TAnimModel : public scene::basic_node {
|
||||
|
||||
friend opengl_renderer;
|
||||
friend ui_layer;
|
||||
friend editor_ui;
|
||||
|
||||
public:
|
||||
// constructors
|
||||
|
||||
@@ -18,16 +18,16 @@ http://mozilla.org/MPL/2.0/.
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
void TCamera::Init( Math3D::vector3 NPos, Math3D::vector3 NAngle) {
|
||||
void TCamera::Init( Math3D::vector3 const &NPos, Math3D::vector3 const &NAngle, TCameraType const NType ) {
|
||||
|
||||
vUp = Math3D::vector3(0, 1, 0);
|
||||
Velocity = Math3D::vector3(0, 0, 0);
|
||||
vUp = { 0, 1, 0 };
|
||||
Velocity = { 0, 0, 0 };
|
||||
Pitch = NAngle.x;
|
||||
Yaw = NAngle.y;
|
||||
Roll = NAngle.z;
|
||||
Pos = NPos;
|
||||
|
||||
Type = (Global.bFreeFly ? TCameraType::tp_Free : TCameraType::tp_Follow);
|
||||
Type = NType;
|
||||
};
|
||||
|
||||
void TCamera::Reset() {
|
||||
|
||||
2
Camera.h
2
Camera.h
@@ -23,7 +23,7 @@ enum class TCameraType
|
||||
class TCamera {
|
||||
|
||||
public: // McZapkie: potrzebuje do kiwania na boki
|
||||
void Init( Math3D::vector3 NPos, Math3D::vector3 NAngle);
|
||||
void Init( Math3D::vector3 const &Location, Math3D::vector3 const &Angle, TCameraType const Type );
|
||||
void Reset();
|
||||
void OnCursorMove(double const x, double const y);
|
||||
bool OnCommand( command_data const &Command );
|
||||
|
||||
@@ -28,11 +28,17 @@ class sound_source;
|
||||
class TEventLauncher;
|
||||
class TTraction; // drut
|
||||
class TTractionPowerSource; // zasilanie drutów
|
||||
class TWorld;
|
||||
class TCamera;
|
||||
class scenario_time;
|
||||
class TMoverParameters;
|
||||
class ui_layer;
|
||||
class editor_ui;
|
||||
class event_manager;
|
||||
class memory_table;
|
||||
class powergridsource_table;
|
||||
class instance_table;
|
||||
class vehicle_table;
|
||||
struct light_array;
|
||||
|
||||
namespace scene {
|
||||
struct node_data;
|
||||
|
||||
@@ -89,8 +89,7 @@ Console::Console()
|
||||
|
||||
Console::~Console()
|
||||
{
|
||||
delete PoKeys55[0];
|
||||
delete PoKeys55[1];
|
||||
Console::Off();
|
||||
};
|
||||
|
||||
void Console::ModeSet(int m, int h)
|
||||
|
||||
@@ -18,11 +18,12 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include <direct.h>
|
||||
#include "Globals.h"
|
||||
#include "Logs.h"
|
||||
#include "train.h"
|
||||
#include "mtable.h"
|
||||
#include "DynObj.h"
|
||||
#include "Event.h"
|
||||
#include "MemCell.h"
|
||||
#include "world.h"
|
||||
#include "simulation.h"
|
||||
#include "simulationtime.h"
|
||||
#include "track.h"
|
||||
#include "station.h"
|
||||
@@ -1725,7 +1726,11 @@ void TController::Activation()
|
||||
}
|
||||
if (pVehicle != old)
|
||||
{ // jeśli zmieniony został pojazd prowadzony
|
||||
Global.pWorld->CabChange(old, pVehicle); // ewentualna zmiana kabiny użytkownikowi
|
||||
if( ( simulation::Train )
|
||||
&& ( simulation::Train->Dynamic() == old ) ) {
|
||||
// ewentualna zmiana kabiny użytkownikowi
|
||||
Global.changeDynObj = pVehicle; // uruchomienie protezy
|
||||
}
|
||||
ControllingSet(); // utworzenie połączenia do sterowanego pojazdu (może się zmienić) -
|
||||
// silnikowy dla EZT
|
||||
}
|
||||
|
||||
11
DynObj.cpp
11
DynObj.cpp
@@ -16,15 +16,17 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "DynObj.h"
|
||||
|
||||
#include "simulation.h"
|
||||
#include "world.h"
|
||||
#include "train.h"
|
||||
#include "driver.h"
|
||||
#include "Globals.h"
|
||||
#include "Timer.h"
|
||||
#include "logs.h"
|
||||
#include "Console.h"
|
||||
#include "MdlMngr.h"
|
||||
#include "model3d.h"
|
||||
#include "renderer.h"
|
||||
#include "uitranscripts.h"
|
||||
#include "messaging.h"
|
||||
|
||||
// Ra: taki zapis funkcjonuje lepiej, ale może nie jest optymalny
|
||||
#define vWorldFront Math3D::vector3(0, 0, 1)
|
||||
@@ -4305,7 +4307,7 @@ void TDynamicObject::RenderSounds() {
|
||||
FreeFlyModeFlag ? true : // in external view all vehicles emit outer noise
|
||||
// Global.pWorld->train() == nullptr ? true : // (can skip this check, with no player train the external view is a given)
|
||||
ctOwner == nullptr ? true : // standalone vehicle, can't be part of user-driven train
|
||||
ctOwner != Global.pWorld->train()->Dynamic()->ctOwner ? true : // confirmed isn't a part of the user-driven train
|
||||
ctOwner != simulation::Train->Dynamic()->ctOwner ? true : // confirmed isn't a part of the user-driven train
|
||||
Global.CabWindowOpen ? true : // sticking head out we get to hear outer noise
|
||||
false ) ) {
|
||||
|
||||
@@ -6994,8 +6996,11 @@ vehicle_table::erase_disabled() {
|
||||
&& ( true == vehicle->MyTrack->RemoveDynamicObject( vehicle ) ) ) {
|
||||
vehicle->MyTrack = nullptr;
|
||||
}
|
||||
if( simulation::Train->Dynamic() == vehicle ) {
|
||||
// clear potential train binding
|
||||
Global.pWorld->TrainDelete( vehicle );
|
||||
// TBD, TODO: manually eject the driver first ?
|
||||
SafeDelete( simulation::Train );
|
||||
}
|
||||
// remove potential entries in the light array
|
||||
simulation::Lights.remove( vehicle );
|
||||
/*
|
||||
|
||||
12
Event.cpp
12
Event.cpp
@@ -17,8 +17,16 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "event.h"
|
||||
|
||||
#include "simulation.h"
|
||||
#include "world.h"
|
||||
#include "messaging.h"
|
||||
#include "globals.h"
|
||||
#include "memcell.h"
|
||||
#include "track.h"
|
||||
#include "traction.h"
|
||||
#include "tractionpower.h"
|
||||
#include "sound.h"
|
||||
#include "animmodel.h"
|
||||
#include "dynobj.h"
|
||||
#include "driver.h"
|
||||
#include "timer.h"
|
||||
#include "logs.h"
|
||||
|
||||
@@ -1207,7 +1215,7 @@ event_manager::CheckQuery() {
|
||||
}
|
||||
case 1: {
|
||||
if( m_workevent->Params[ 1 ].asdouble > 0.0 ) {
|
||||
Global.pWorld->radio_message(
|
||||
simulation::radio_message(
|
||||
m_workevent->Params[ 9 ].tsTextSound,
|
||||
static_cast<int>( m_workevent->Params[ 1 ].asdouble ) );
|
||||
}
|
||||
|
||||
@@ -14,8 +14,9 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "stdafx.h"
|
||||
#include "globals.h"
|
||||
|
||||
#include "world.h"
|
||||
#include "simulation.h"
|
||||
#include "simulationenvironment.h"
|
||||
#include "driver.h"
|
||||
#include "logs.h"
|
||||
#include "Console.h"
|
||||
#include "PyInt.h"
|
||||
@@ -94,7 +95,7 @@ global_settings::ConfigParse(cParser &Parser) {
|
||||
{ // Mczapkie-130302
|
||||
|
||||
Parser.getTokens();
|
||||
Parser >> bFreeFly;
|
||||
Parser >> FreeFlyModeFlag;
|
||||
Parser.getTokens(3, false);
|
||||
Parser >>
|
||||
FreeCameraInit[0].x,
|
||||
@@ -298,7 +299,7 @@ global_settings::ConfigParse(cParser &Parser) {
|
||||
std::tm *localtime = std::localtime(&timenow);
|
||||
fMoveLight = localtime->tm_yday + 1; // numer bieżącego dnia w roku
|
||||
}
|
||||
pWorld->compute_season( fMoveLight );
|
||||
simulation::Environment.compute_season( fMoveLight );
|
||||
}
|
||||
else if( token == "dynamiclights" ) {
|
||||
// number of dynamic lights in the scene
|
||||
|
||||
@@ -25,8 +25,8 @@ struct global_settings {
|
||||
bool altState{ false };
|
||||
std::mt19937 random_engine{ std::mt19937( static_cast<unsigned int>( std::time( NULL ) ) ) };
|
||||
TDynamicObject *changeDynObj{ nullptr };// info o zmianie pojazdu
|
||||
TWorld *pWorld{ nullptr }; // wskaźnik na świat do usuwania pojazdów
|
||||
TCamera *pCamera{ nullptr }; // parametry kamery
|
||||
TCamera *pDebugCamera{ nullptr };
|
||||
Math3D::vector3 pCameraPosition; // pozycja kamery w świecie
|
||||
Math3D::vector3 DebugCameraPosition; // pozycja kamery w świecie
|
||||
std::vector<Math3D::vector3> FreeCameraInit; // pozycje kamery
|
||||
@@ -64,7 +64,6 @@ struct global_settings {
|
||||
unsigned int DisabledLogTypes{ 0 };
|
||||
// simulation
|
||||
bool RealisticControlMode{ false }; // controls ability to steer the vehicle from outside views
|
||||
bool bFreeFly{ false };
|
||||
bool bEnableTraction{ true };
|
||||
float fFriction{ 1.f }; // mnożnik tarcia - KURS90
|
||||
bool bLiveTraction{ true };
|
||||
|
||||
@@ -1294,7 +1294,7 @@ public:
|
||||
void ComputeConstans(void);//ABu: wczesniejsze wyznaczenie stalych dla liczenia sil
|
||||
double ComputeMass(void);
|
||||
void ComputeTotalForce(double dt, double dt1, bool FullVer);
|
||||
double Adhesive(double staticfriction);
|
||||
double Adhesive(double staticfriction) const;
|
||||
double TractionForce(double dt);
|
||||
double FrictionForce(double R, int TDamage);
|
||||
double BrakeForceR(double ratio, double velocity);
|
||||
@@ -1327,8 +1327,8 @@ public:
|
||||
bool FuseOn(void); //bezpiecznik nadamiary
|
||||
bool FuseFlagCheck(void); // sprawdzanie flagi nadmiarowego
|
||||
void FuseOff(void); // wylaczenie nadmiarowego
|
||||
double ShowCurrent( int AmpN ); //pokazuje bezwgl. wartosc pradu na wybranym amperomierzu
|
||||
double ShowCurrentP(int AmpN); //pokazuje bezwgl. wartosc pradu w wybranym pojezdzie //Q 20160722
|
||||
double ShowCurrent( int AmpN ) const; //pokazuje bezwgl. wartosc pradu na wybranym amperomierzu
|
||||
double ShowCurrentP(int AmpN) const; //pokazuje bezwgl. wartosc pradu w wybranym pojezdzie //Q 20160722
|
||||
|
||||
/*!o pokazuje bezwgl. wartosc obrotow na obrotomierzu jednego z 3 pojazdow*/
|
||||
/*function ShowEngineRotation(VehN:int): integer; //Ra 2014-06: przeniesione do C++*/
|
||||
@@ -1374,7 +1374,7 @@ public:
|
||||
/*funkcje ladujace pliki opisujace pojazd*/
|
||||
bool LoadFIZ(std::string chkpath); //Q 20160717 bool LoadChkFile(std::string chkpath);
|
||||
bool CheckLocomotiveParameters( bool ReadyFlag, int Dir );
|
||||
std::string EngineDescription( int what );
|
||||
std::string EngineDescription( int what ) const;
|
||||
private:
|
||||
void LoadFIZ_Param( std::string const &line );
|
||||
void LoadFIZ_Load( std::string const &line );
|
||||
|
||||
@@ -1629,7 +1629,7 @@ void TMoverParameters::OilPumpCheck( double const Timestep ) {
|
||||
}
|
||||
|
||||
|
||||
double TMoverParameters::ShowCurrent(int AmpN)
|
||||
double TMoverParameters::ShowCurrent(int AmpN) const
|
||||
{ // Odczyt poboru prądu na podanym amperomierzu
|
||||
switch (EngineType)
|
||||
{
|
||||
@@ -4124,7 +4124,7 @@ double TMoverParameters::FrictionForce(double R, int TDamage)
|
||||
// Q: 20160713
|
||||
// Oblicza przyczepność
|
||||
// *************************************************************************************************
|
||||
double TMoverParameters::Adhesive(double staticfriction)
|
||||
double TMoverParameters::Adhesive(double staticfriction) const
|
||||
{
|
||||
double adhesion = 0.0;
|
||||
const double adh_factor = 0.25; //współczynnik określający, jak bardzo spada tarcie przy poślizgu
|
||||
@@ -6763,7 +6763,7 @@ bool TMoverParameters::ChangeOffsetH(double DeltaOffset)
|
||||
// Q: 20160713
|
||||
// Testuje zmienną (narazie tylko 0) i na podstawie uszkodzenia zwraca informację tekstową
|
||||
// *************************************************************************************************
|
||||
std::string TMoverParameters::EngineDescription(int what)
|
||||
std::string TMoverParameters::EngineDescription(int what) const
|
||||
{
|
||||
std::string outstr { "OK" };
|
||||
switch (what) {
|
||||
@@ -9599,7 +9599,7 @@ bool TMoverParameters::RunInternalCommand()
|
||||
// Q: 20160714
|
||||
// Zwraca wartość natężenia prądu na wybranym amperomierzu. Podfunkcja do ShowCurrent.
|
||||
// *************************************************************************************************
|
||||
double TMoverParameters::ShowCurrentP(int AmpN)
|
||||
double TMoverParameters::ShowCurrentP(int AmpN) const
|
||||
{
|
||||
int b, Bn;
|
||||
bool Grupowy;
|
||||
|
||||
@@ -17,6 +17,8 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "memcell.h"
|
||||
|
||||
#include "simulation.h"
|
||||
#include "driver.h"
|
||||
#include "event.h"
|
||||
#include "logs.h"
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
@@ -20,6 +20,7 @@ Copyright (C) 2001-2004 Marcin Wozniak, Maciej Czapkiewicz and others
|
||||
#include "utilities.h"
|
||||
#include "renderer.h"
|
||||
#include "Timer.h"
|
||||
#include "simulation.h"
|
||||
#include "simulationtime.h"
|
||||
#include "mtable.h"
|
||||
#include "sn_utils.h"
|
||||
@@ -28,7 +29,7 @@ Copyright (C) 2001-2004 Marcin Wozniak, Maciej Czapkiewicz and others
|
||||
using namespace Mtable;
|
||||
|
||||
float TSubModel::fSquareDist = 0.f;
|
||||
size_t TSubModel::iInstance; // numer renderowanego egzemplarza obiektu
|
||||
std::uintptr_t TSubModel::iInstance; // numer renderowanego egzemplarza obiektu
|
||||
texture_handle const *TSubModel::ReplacableSkinId = NULL;
|
||||
int TSubModel::iAlpha = 0x30300030; // maska do testowania flag tekstur wymiennych
|
||||
TModel3d *TSubModel::pRoot; // Ra: tymczasowo wskaźnik na model widoczny z submodelu
|
||||
@@ -1191,7 +1192,7 @@ TSubModel::offset( float const Geometrytestoffsetthreshold ) const {
|
||||
|
||||
if( true == TestFlag( iFlags, 0x0200 ) ) {
|
||||
// flip coordinates for t3d file which wasn't yet initialized
|
||||
if( ( false == Global.pWorld->InitPerformed() )
|
||||
if( ( false == simulation::is_ready )
|
||||
|| ( false == Vertices.empty() ) ) {
|
||||
// NOTE, HACK: results require flipping if the model wasn't yet initialized, so we're using crude method to detect possible cases
|
||||
// TODO: sort out this mess, either unify offset lookups to take place before (or after) initialization,
|
||||
|
||||
@@ -135,7 +135,7 @@ public: // chwilowo
|
||||
float3 v_TransVector { 0.0f, 0.0f, 0.0f };
|
||||
gfx::vertex_array Vertices;
|
||||
float m_boundingradius { 0 };
|
||||
size_t iAnimOwner{ 0 }; // roboczy numer egzemplarza, który ustawił animację
|
||||
std::uintptr_t iAnimOwner{ 0 }; // roboczy numer egzemplarza, który ustawił animację
|
||||
TAnimType b_aAnim{ TAnimType::at_None }; // kody animacji oddzielnie, bo zerowane
|
||||
float4x4 *mAnimMatrix{ nullptr }; // macierz do animacji kwaternionowych (należy do AnimContainer)
|
||||
TSubModel **smLetter{ nullptr }; // wskaźnik na tablicę submdeli do generoania tekstu (docelowo zapisać do E3D)
|
||||
|
||||
25
Segment.cpp
25
Segment.cpp
@@ -203,16 +203,15 @@ double TSegment::GetTFromS(double const s) const
|
||||
// initial guess for Newton's method
|
||||
double fTolerance = 0.001;
|
||||
double fRatio = s / RombergIntegral(0, 1);
|
||||
double fOmRatio = 1.0 - fRatio;
|
||||
double fTime = fOmRatio * 0 + fRatio * 1;
|
||||
int iteration = 0;
|
||||
double fTime = interpolate( 0.0, 1.0, fRatio );
|
||||
|
||||
int iteration = 0;
|
||||
double fDifference {}; // exposed for debug down the road
|
||||
do {
|
||||
double fDifference = RombergIntegral(0, fTime) - s;
|
||||
fDifference = RombergIntegral(0, fTime) - s;
|
||||
if( std::abs( fDifference ) < fTolerance ) {
|
||||
return fTime;
|
||||
}
|
||||
|
||||
fTime -= fDifference / GetFirstDerivative(fTime).Length();
|
||||
++iteration;
|
||||
}
|
||||
@@ -323,7 +322,7 @@ Math3D::vector3 TSegment::FastGetDirection(double fDistance, double fOffset)
|
||||
return (Point2 - CPointIn); // wektor na końcu jest stały
|
||||
return (FastGetPoint(t2) - FastGetPoint(t1));
|
||||
}
|
||||
|
||||
/*
|
||||
Math3D::vector3 TSegment::GetPoint(double const fDistance) const
|
||||
{ // wyliczenie współrzędnych XYZ na torze w odległości (fDistance) od Point1
|
||||
if (bCurve)
|
||||
@@ -332,13 +331,17 @@ Math3D::vector3 TSegment::GetPoint(double const fDistance) const
|
||||
// return Interpolate(t,Point1,CPointOut,CPointIn,Point2);
|
||||
return RaInterpolate(t);
|
||||
}
|
||||
else
|
||||
{ // wyliczenie dla odcinka prostego jest prostsze
|
||||
double t = fDistance / fLength; // zerowych torów nie ma
|
||||
return ((1.0 - t) * Point1 + (t)*Point2);
|
||||
else {
|
||||
// wyliczenie dla odcinka prostego jest prostsze
|
||||
return
|
||||
interpolate(
|
||||
Point1, Point2,
|
||||
clamp(
|
||||
fDistance / fLength,
|
||||
0.0, 1.0 ) );
|
||||
}
|
||||
};
|
||||
|
||||
*/
|
||||
// ustalenie pozycji osi na torze, przechyłki, pochylenia i kierunku jazdy
|
||||
void TSegment::RaPositionGet(double const fDistance, Math3D::vector3 &p, Math3D::vector3 &a) const {
|
||||
|
||||
|
||||
@@ -88,8 +88,10 @@ public:
|
||||
return CPointOut; };
|
||||
Math3D::vector3
|
||||
FastGetDirection(double const fDistance, double const fOffset);
|
||||
/*
|
||||
Math3D::vector3
|
||||
GetPoint(double const fDistance) const;
|
||||
*/
|
||||
void
|
||||
RaPositionGet(double const fDistance, Math3D::vector3 &p, Math3D::vector3 &a) const;
|
||||
Math3D::vector3
|
||||
|
||||
@@ -17,6 +17,11 @@ http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include "simulation.h"
|
||||
#include "globals.h"
|
||||
#include "event.h"
|
||||
#include "messaging.h"
|
||||
#include "dynobj.h"
|
||||
#include "animmodel.h"
|
||||
#include "track.h"
|
||||
#include "timer.h"
|
||||
#include "logs.h"
|
||||
#include "renderer.h"
|
||||
|
||||
2
Track.h
2
Track.h
@@ -128,7 +128,7 @@ class TTrack : public scene::basic_node {
|
||||
|
||||
friend opengl_renderer;
|
||||
// NOTE: temporary arrangement
|
||||
friend ui_layer;
|
||||
friend editor_ui;
|
||||
|
||||
private:
|
||||
TIsolated * pIsolated = nullptr; // obwód izolowany obsługujący zajęcia/zwolnienia grupy torów
|
||||
|
||||
@@ -17,6 +17,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include "simulation.h"
|
||||
#include "Globals.h"
|
||||
#include "tractionpower.h"
|
||||
#include "logs.h"
|
||||
#include "renderer.h"
|
||||
|
||||
|
||||
@@ -21,8 +21,10 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "camera.h"
|
||||
#include "Logs.h"
|
||||
#include "MdlMngr.h"
|
||||
#include "model3d.h"
|
||||
#include "Timer.h"
|
||||
#include "Driver.h"
|
||||
#include "dynobj.h"
|
||||
#include "mtable.h"
|
||||
#include "Console.h"
|
||||
|
||||
|
||||
@@ -18,6 +18,8 @@ http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include "simulation.h"
|
||||
#include "Globals.h"
|
||||
#include "dynobj.h"
|
||||
#include "driver.h"
|
||||
#include "Logs.h"
|
||||
|
||||
TTrackFollower::~TTrackFollower()
|
||||
|
||||
301
application.cpp
301
application.cpp
@@ -9,14 +9,13 @@ http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "application.h"
|
||||
#include "scenarioloadermode.h"
|
||||
#include "drivermode.h"
|
||||
#include "editormode.h"
|
||||
|
||||
#include "globals.h"
|
||||
#include "keyboardinput.h"
|
||||
#include "mouseinput.h"
|
||||
#include "gamepadinput.h"
|
||||
#include "console.h"
|
||||
#include "simulation.h"
|
||||
#include "world.h"
|
||||
#include "train.h"
|
||||
#include "pyint.h"
|
||||
#include "sceneeditor.h"
|
||||
#include "renderer.h"
|
||||
@@ -45,17 +44,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
|
||||
eu07_application Application;
|
||||
|
||||
namespace input {
|
||||
|
||||
gamepad_input Gamepad;
|
||||
mouse_input Mouse;
|
||||
glm::dvec2 mouse_pickmodepos; // stores last mouse position in control picking mode
|
||||
keyboard_input Keyboard;
|
||||
Console console;
|
||||
std::unique_ptr<uart_input> uart;
|
||||
user_command command; // currently issued control command, if any
|
||||
|
||||
}
|
||||
ui_layer uilayerstaticinitializer;
|
||||
|
||||
#ifdef _WIN32
|
||||
extern "C"
|
||||
@@ -71,6 +60,14 @@ extern WNDPROC BaseWindowProc;
|
||||
|
||||
// user input callbacks
|
||||
|
||||
void focus_callback( GLFWwindow *window, int focus ) {
|
||||
if( Global.bInactivePause ) // jeśli ma być pauzowanie okna w tle
|
||||
if( focus )
|
||||
Global.iPause &= ~4; // odpauzowanie, gdy jest na pierwszym planie
|
||||
else
|
||||
Global.iPause |= 4; // włączenie pauzy, gdy nieaktywy
|
||||
}
|
||||
|
||||
void window_resize_callback( GLFWwindow *window, int w, int h ) {
|
||||
// NOTE: we have two variables which basically do the same thing as we don't have dynamic fullscreen toggle
|
||||
// TBD, TODO: merge them?
|
||||
@@ -81,101 +78,23 @@ void window_resize_callback( GLFWwindow *window, int w, int h ) {
|
||||
}
|
||||
|
||||
void cursor_pos_callback( GLFWwindow *window, double x, double y ) {
|
||||
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 );
|
||||
Application.on_cursor_pos( 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 ) ) {
|
||||
// we don't care about other mouse buttons at the moment
|
||||
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 ) {
|
||||
|
||||
Global.shiftState = ( mods & GLFW_MOD_SHIFT ) ? true : false;
|
||||
Global.ctrlState = ( mods & GLFW_MOD_CONTROL ) ? true : false;
|
||||
Global.altState = ( mods & GLFW_MOD_ALT ) ? true : false;
|
||||
|
||||
// give the ui first shot at the input processing...
|
||||
if( true == UILayer.on_key( key, action ) ) { return; }
|
||||
if( true == scene::Editor.on_key( key, action ) ) { return; }
|
||||
// ...if the input is left untouched, pass it on
|
||||
input::Keyboard.key( key, action );
|
||||
|
||||
if( ( true == Global.InputMouse )
|
||||
&& ( ( key == GLFW_KEY_LEFT_ALT )
|
||||
|| ( key == GLFW_KEY_RIGHT_ALT ) ) ) {
|
||||
// if the alt key was pressed toggle control picking mode and set matching cursor behaviour
|
||||
if( action == GLFW_RELEASE ) {
|
||||
|
||||
if( Global.ControlPicking ) {
|
||||
// switch off
|
||||
Application.get_cursor_pos( input::mouse_pickmodepos.x, input::mouse_pickmodepos.y );
|
||||
Application.set_cursor( GLFW_CURSOR_DISABLED );
|
||||
Application.set_cursor_pos( 0, 0 );
|
||||
}
|
||||
else {
|
||||
// enter picking mode
|
||||
Application.set_cursor_pos( input::mouse_pickmodepos.x, input::mouse_pickmodepos.y );
|
||||
Application.set_cursor( GLFW_CURSOR_NORMAL );
|
||||
}
|
||||
// actually toggle the mode
|
||||
Global.ControlPicking = !Global.ControlPicking;
|
||||
}
|
||||
}
|
||||
|
||||
if( ( key == GLFW_KEY_LEFT_SHIFT )
|
||||
|| ( key == GLFW_KEY_LEFT_CONTROL )
|
||||
|| ( key == GLFW_KEY_LEFT_ALT )
|
||||
|| ( key == GLFW_KEY_RIGHT_SHIFT )
|
||||
|| ( key == GLFW_KEY_RIGHT_CONTROL )
|
||||
|| ( key == GLFW_KEY_RIGHT_ALT ) ) {
|
||||
// don't bother passing these
|
||||
return;
|
||||
}
|
||||
|
||||
if( action == GLFW_PRESS || action == GLFW_REPEAT ) {
|
||||
|
||||
World.OnKeyDown( key );
|
||||
|
||||
#ifdef CAN_I_HAS_LIBPNG
|
||||
switch( key ) {
|
||||
case GLFW_KEY_PRINT_SCREEN: {
|
||||
make_screenshot();
|
||||
break;
|
||||
}
|
||||
default: { break; }
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void focus_callback( GLFWwindow *window, int focus ) {
|
||||
if( Global.bInactivePause ) // jeśli ma być pauzowanie okna w tle
|
||||
if( focus )
|
||||
Global.iPause &= ~4; // odpauzowanie, gdy jest na pierwszym planie
|
||||
else
|
||||
Global.iPause |= 4; // włączenie pauzy, gdy nieaktywy
|
||||
Application.on_mouse_button( button, action, mods );
|
||||
}
|
||||
|
||||
void scroll_callback( GLFWwindow* window, double xoffset, double yoffset ) {
|
||||
|
||||
if( Global.ctrlState ) {
|
||||
// ctrl + scroll wheel adjusts fov in debug mode
|
||||
Global.FieldOfView = clamp( static_cast<float>( Global.FieldOfView - yoffset * 20.0 / Global.fFpsAverage ), 15.0f, 75.0f );
|
||||
Application.on_scroll( xoffset, yoffset );
|
||||
}
|
||||
|
||||
void key_callback( GLFWwindow *window, int key, int scancode, int action, int mods ) {
|
||||
|
||||
Application.on_key( key, scancode, action, mods );
|
||||
}
|
||||
|
||||
// public:
|
||||
@@ -190,6 +109,12 @@ eu07_application::init( int Argc, char *Argv[] ) {
|
||||
if( ( result = init_settings( Argc, Argv ) ) != 0 ) {
|
||||
return result;
|
||||
}
|
||||
|
||||
WriteLog( "Starting MaSzyna rail vehicle simulator (release: " + Global.asVersion + ")" );
|
||||
WriteLog( "For online documentation and additional files refer to: http://eu07.pl" );
|
||||
WriteLog( "Authors: Marcin_EU, McZapkie, ABu, Winger, Tolaris, nbmx, OLO_EU, Bart, Quark-t, "
|
||||
"ShaXbee, Oli_EU, youBy, KURS90, Ra, hunter, szociu, Stele, Q, firleju and others\n" );
|
||||
|
||||
if( ( result = init_glfw() ) != 0 ) {
|
||||
return result;
|
||||
}
|
||||
@@ -200,6 +125,9 @@ eu07_application::init( int Argc, char *Argv[] ) {
|
||||
if( ( result = init_audio() ) != 0 ) {
|
||||
return result;
|
||||
}
|
||||
if( ( result = init_modes() ) != 0 ) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -207,56 +135,12 @@ eu07_application::init( int Argc, char *Argv[] ) {
|
||||
int
|
||||
eu07_application::run() {
|
||||
|
||||
// HACK: prevent mouse capture before simulation starts
|
||||
Global.ControlPicking = true;
|
||||
// TODO: move input sources and their initializations to the application mode member
|
||||
input::Keyboard.init();
|
||||
input::Mouse.init();
|
||||
input::Gamepad.init();
|
||||
if( true == Global.uart_conf.enable ) {
|
||||
input::uart = std::make_unique<uart_input>();
|
||||
input::uart->init();
|
||||
}
|
||||
#ifdef _WIN32
|
||||
Console::On(); // włączenie konsoli
|
||||
#endif
|
||||
|
||||
Global.pWorld = &World; // Ra: wskaźnik potrzebny do usuwania pojazdów
|
||||
|
||||
if( false == World.Init( m_window ) ) {
|
||||
ErrorLog( "Bad init: simulation setup failed" );
|
||||
return -1;
|
||||
}
|
||||
|
||||
if( Global.iConvertModels < 0 ) {
|
||||
// generate binary files for all 3d models
|
||||
Global.iConvertModels = -Global.iConvertModels;
|
||||
World.CreateE3D( szModelPath ); // rekurencyjne przeglądanie katalogów
|
||||
World.CreateE3D( szDynamicPath, true );
|
||||
// auto-close when you're done
|
||||
WriteLog( "Binary 3d model generation completed" );
|
||||
return 0;
|
||||
}
|
||||
|
||||
set_cursor( GLFW_CURSOR_DISABLED );
|
||||
set_cursor_pos( 0, 0 );
|
||||
Global.ControlPicking = false;
|
||||
|
||||
// main application loop
|
||||
// TODO: split into parts and delegate these to application mode member
|
||||
while( ( false == glfwWindowShouldClose( m_window ) )
|
||||
&& ( true == World.Update() )
|
||||
&& ( false == m_modestack.empty() )
|
||||
&& ( true == m_modes[ m_modestack.top() ]->update() )
|
||||
&& ( true == GfxRenderer.Render() ) ) {
|
||||
glfwPollEvents();
|
||||
input::Keyboard.poll();
|
||||
if( true == Global.InputMouse ) { input::Mouse.poll(); }
|
||||
if( true == Global.InputGamepad ) { input::Gamepad.poll(); }
|
||||
if( input::uart != nullptr ) { input::uart->poll(); }
|
||||
// TODO: wrap current command in object, include other input sources
|
||||
input::command = (
|
||||
input::Mouse.command() != user_command::none ?
|
||||
input::Mouse.command() :
|
||||
input::Keyboard.command() );
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -265,9 +149,7 @@ eu07_application::run() {
|
||||
void
|
||||
eu07_application::exit() {
|
||||
|
||||
#ifdef _WIN32
|
||||
Console::Off(); // wyłączenie konsoli (komunikacji zwrotnej)
|
||||
#endif
|
||||
SafeDelete( simulation::Train );
|
||||
SafeDelete( simulation::Region );
|
||||
|
||||
glfwDestroyWindow( m_window );
|
||||
@@ -276,28 +158,103 @@ eu07_application::exit() {
|
||||
TPythonInterpreter::killInstance();
|
||||
}
|
||||
|
||||
void
|
||||
eu07_application::render_ui() {
|
||||
|
||||
if( m_modestack.empty() ) { return; }
|
||||
|
||||
m_modes[ m_modestack.top() ]->render_ui();
|
||||
}
|
||||
|
||||
bool
|
||||
eu07_application::pop_mode() {
|
||||
|
||||
if( m_modestack.empty() ) { return false; }
|
||||
|
||||
m_modes[ m_modestack.top() ]->exit();
|
||||
m_modestack.pop();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
eu07_application::push_mode( eu07_application::mode const Mode ) {
|
||||
|
||||
if( Mode >= mode::count_ ) { return false; }
|
||||
|
||||
m_modes[ Mode ]->enter();
|
||||
m_modestack.push( Mode );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
eu07_application::set_title( std::string const &Title ) {
|
||||
|
||||
glfwSetWindowTitle( m_window, Title.c_str() );
|
||||
}
|
||||
|
||||
void
|
||||
eu07_application::set_progress( float const Progress, float const Subtaskprogress ) {
|
||||
|
||||
if( m_modestack.empty() ) { return; }
|
||||
|
||||
m_modes[ m_modestack.top() ]->set_progress( Progress, Subtaskprogress );
|
||||
}
|
||||
|
||||
void
|
||||
eu07_application::set_cursor( int const Mode ) {
|
||||
|
||||
UILayer.set_cursor( Mode );
|
||||
ui_layer::set_cursor( Mode );
|
||||
}
|
||||
|
||||
void
|
||||
eu07_application::set_cursor_pos( double const X, double const Y ) {
|
||||
eu07_application::set_cursor_pos( double const Horizontal, double const Vertical ) {
|
||||
|
||||
if( m_window != nullptr ) {
|
||||
glfwSetCursorPos( m_window, X, Y );
|
||||
glfwSetCursorPos( m_window, Horizontal, Vertical );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
eu07_application::get_cursor_pos( double &X, double &Y ) const {
|
||||
eu07_application::get_cursor_pos( double &Horizontal, double &Vertical ) const {
|
||||
|
||||
if( m_window != nullptr ) {
|
||||
glfwGetCursorPos( m_window, &X, &Y );
|
||||
glfwGetCursorPos( m_window, &Horizontal, &Vertical );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
eu07_application::on_key( int const Key, int const Scancode, int const Action, int const Mods ) {
|
||||
|
||||
if( m_modestack.empty() ) { return; }
|
||||
|
||||
m_modes[ m_modestack.top() ]->on_key( Key, Scancode, Action, Mods );
|
||||
}
|
||||
|
||||
void
|
||||
eu07_application::on_cursor_pos( double const Horizontal, double const Vertical ) {
|
||||
|
||||
if( m_modestack.empty() ) { return; }
|
||||
|
||||
m_modes[ m_modestack.top() ]->on_cursor_pos( Horizontal, Vertical );
|
||||
}
|
||||
|
||||
void
|
||||
eu07_application::on_mouse_button( int const Button, int const Action, int const Mods ) {
|
||||
|
||||
if( m_modestack.empty() ) { return; }
|
||||
|
||||
m_modes[ m_modestack.top() ]->on_mouse_button( Button, Action, Mods );
|
||||
}
|
||||
|
||||
void
|
||||
eu07_application::on_scroll( double const Xoffset, double const Yoffset ) {
|
||||
|
||||
if( m_modestack.empty() ) { return; }
|
||||
|
||||
m_modes[ m_modestack.top() ]->on_scroll( Xoffset, Yoffset );
|
||||
}
|
||||
|
||||
// private:
|
||||
|
||||
void
|
||||
@@ -385,13 +342,7 @@ eu07_application::init_settings( int Argc, char *Argv[] ) {
|
||||
|
||||
std::string token { Argv[ i ] };
|
||||
|
||||
if( token == "-e3d" ) {
|
||||
Global.iConvertModels = (
|
||||
Global.iConvertModels > 0 ?
|
||||
-Global.iConvertModels :
|
||||
-7 ); // z optymalizacją, bananami i prawidłowym Opacity
|
||||
}
|
||||
else if( token == "-s" ) {
|
||||
if( token == "-s" ) {
|
||||
if( i + 1 < Argc ) {
|
||||
Global.SceneryFile = ToLower( Argv[ ++i ] );
|
||||
}
|
||||
@@ -406,7 +357,6 @@ eu07_application::init_settings( int Argc, char *Argv[] ) {
|
||||
<< "usage: " << std::string( Argv[ 0 ] )
|
||||
<< " [-s sceneryfilepath]"
|
||||
<< " [-v vehiclename]"
|
||||
<< " [-e3d]"
|
||||
<< std::endl;
|
||||
return -1;
|
||||
}
|
||||
@@ -468,7 +418,6 @@ eu07_application::init_glfw() {
|
||||
// switch off the topmost flag
|
||||
::SetWindowPos( Hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE );
|
||||
#endif
|
||||
// TBD, TODO: move the global pointer to a more appropriate place
|
||||
m_window = window;
|
||||
|
||||
return 0;
|
||||
@@ -499,7 +448,7 @@ eu07_application::init_gfx() {
|
||||
}
|
||||
|
||||
if( ( false == GfxRenderer.Init( m_window ) )
|
||||
|| ( false == UILayer.init( m_window ) ) ) {
|
||||
|| ( false == ui_layer::init( m_window ) ) ) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -515,3 +464,25 @@ eu07_application::init_audio() {
|
||||
// NOTE: lack of audio isn't deemed a failure serious enough to throw in the towel
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
eu07_application::init_modes() {
|
||||
|
||||
// NOTE: we could delay creation/initialization until transition to specific mode is requested,
|
||||
// but doing it in one go at the start saves us some error checking headache down the road
|
||||
|
||||
// create all application behaviour modes
|
||||
m_modes[ mode::scenarioloader ] = std::make_shared<scenarioloader_mode>();
|
||||
m_modes[ mode::driver ] = std::make_shared<driver_mode>();
|
||||
m_modes[ mode::editor ] = std::make_shared<editor_mode>();
|
||||
// initialize the mode objects
|
||||
for( auto &mode : m_modes ) {
|
||||
if( false == mode->init() ) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
// activate the default mode
|
||||
push_mode( mode::scenarioloader );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -7,9 +7,21 @@ obtain one at
|
||||
http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "applicationmode.h"
|
||||
|
||||
class eu07_application {
|
||||
|
||||
public:
|
||||
// types
|
||||
enum mode {
|
||||
// launcher = 0,
|
||||
scenarioloader,
|
||||
driver,
|
||||
editor,
|
||||
count_
|
||||
};
|
||||
// constructors
|
||||
eu07_application() = default;
|
||||
// methods
|
||||
@@ -19,18 +31,41 @@ public:
|
||||
run();
|
||||
void
|
||||
exit();
|
||||
void
|
||||
render_ui();
|
||||
// switches application to specified mode
|
||||
bool
|
||||
pop_mode();
|
||||
bool
|
||||
push_mode( eu07_application::mode const Mode );
|
||||
void
|
||||
set_title( std::string const &Title );
|
||||
void
|
||||
set_progress( float const Progress = 0.f, float const Subtaskprogress = 0.f );
|
||||
void
|
||||
set_cursor( int const Mode );
|
||||
void
|
||||
set_cursor_pos( double const X, double const Y );
|
||||
set_cursor_pos( double const Horizontal, double const Vertical );
|
||||
void
|
||||
get_cursor_pos( double &X, double &Y ) const;
|
||||
get_cursor_pos( double &Horizontal, double &Vertical ) const;
|
||||
// input handlers
|
||||
void
|
||||
on_key( int const Key, int const Scancode, int const Action, int const Mods );
|
||||
void
|
||||
on_cursor_pos( double const Horizontal, double const Vertical );
|
||||
void
|
||||
on_mouse_button( int const Button, int const Action, int const Mods );
|
||||
void
|
||||
on_scroll( double const Xoffset, double const Yoffset );
|
||||
inline
|
||||
GLFWwindow *
|
||||
window() {
|
||||
return m_window; }
|
||||
|
||||
private:
|
||||
// types
|
||||
using modeptr_array = std::array<std::shared_ptr<application_mode>, static_cast<std::size_t>( mode::count_ )>;
|
||||
using mode_stack = std::stack<mode>;
|
||||
// methods
|
||||
void init_debug();
|
||||
void init_files();
|
||||
@@ -39,8 +74,11 @@ private:
|
||||
void init_callbacks();
|
||||
int init_gfx();
|
||||
int init_audio();
|
||||
int init_modes();
|
||||
// members
|
||||
GLFWwindow * m_window { nullptr };
|
||||
modeptr_array m_modes { nullptr }; // collection of available application behaviour modes
|
||||
mode_stack m_modestack; // current behaviour mode
|
||||
};
|
||||
|
||||
extern eu07_application Application;
|
||||
67
applicationmode.h
Normal file
67
applicationmode.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
This Source Code Form is subject to the
|
||||
terms of the Mozilla Public License, v.
|
||||
2.0. If a copy of the MPL was not
|
||||
distributed with this file, You can
|
||||
obtain one at
|
||||
http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "uilayer.h"
|
||||
|
||||
// component implementing specific mode of application behaviour
|
||||
// base interface
|
||||
class application_mode {
|
||||
|
||||
public:
|
||||
// destructor
|
||||
virtual
|
||||
~application_mode() = default;
|
||||
// methods;
|
||||
// initializes internal data structures of the mode. returns: true on success, false otherwise
|
||||
virtual
|
||||
bool
|
||||
init() = 0;
|
||||
// mode-specific update of simulation data. returns: false on error, true otherwise
|
||||
virtual
|
||||
bool
|
||||
update() = 0;
|
||||
// draws node-specific user interface
|
||||
inline
|
||||
void
|
||||
render_ui() {
|
||||
if( m_userinterface != nullptr ) {
|
||||
m_userinterface->render(); } }
|
||||
inline
|
||||
void
|
||||
set_progress( float const Progress = 0.f, float const Subtaskprogress = 0.f ) {
|
||||
if( m_userinterface != nullptr ) {
|
||||
m_userinterface->set_progress( Progress, Subtaskprogress ); } }
|
||||
// maintenance method, called when the mode is activated
|
||||
virtual
|
||||
void
|
||||
enter() = 0;
|
||||
// maintenance method, called when the mode is deactivated
|
||||
virtual
|
||||
void
|
||||
exit() = 0;
|
||||
// input handlers
|
||||
virtual
|
||||
void
|
||||
on_key( int const Key, int const Scancode, int const Action, int const Mods ) = 0;
|
||||
virtual
|
||||
void
|
||||
on_cursor_pos( double const X, double const Y ) = 0;
|
||||
virtual
|
||||
void
|
||||
on_mouse_button( int const Button, int const Action, int const Mods ) = 0;
|
||||
virtual
|
||||
void
|
||||
on_scroll( double const Xoffset, double const Yoffset ) = 0;
|
||||
|
||||
protected:
|
||||
// members
|
||||
std::shared_ptr<ui_layer> m_userinterface;
|
||||
};
|
||||
13
combustionengine.cpp
Normal file
13
combustionengine.cpp
Normal file
@@ -0,0 +1,13 @@
|
||||
/*
|
||||
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 "combustionengine.h"
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
20
combustionengine.h
Normal file
20
combustionengine.h
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
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
|
||||
|
||||
// basic approximation of a fuel pump
|
||||
// TODO: fuel consumption, optional automatic engine start after activation
|
||||
struct fuel_pump {
|
||||
|
||||
bool is_enabled { false }; // device is allowed/requested to operate
|
||||
bool is_active { false }; // device is working
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
215
driverkeyboardinput.cpp
Normal file
215
driverkeyboardinput.cpp
Normal file
@@ -0,0 +1,215 @@
|
||||
/*
|
||||
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 "driverkeyboardinput.h"
|
||||
|
||||
bool
|
||||
driverkeyboard_input::init() {
|
||||
|
||||
default_bindings();
|
||||
|
||||
return recall_bindings();
|
||||
}
|
||||
|
||||
void
|
||||
driverkeyboard_input::default_bindings() {
|
||||
|
||||
m_bindingsetups = {
|
||||
{ user_command::aidriverenable, GLFW_KEY_Q | keymodifier::shift },
|
||||
{ user_command::aidriverdisable, GLFW_KEY_Q },
|
||||
{ user_command::mastercontrollerincrease, GLFW_KEY_KP_ADD },
|
||||
{ user_command::mastercontrollerincreasefast, GLFW_KEY_KP_ADD | keymodifier::shift },
|
||||
{ user_command::mastercontrollerdecrease, GLFW_KEY_KP_SUBTRACT },
|
||||
{ user_command::mastercontrollerdecreasefast, GLFW_KEY_KP_SUBTRACT | keymodifier::shift },
|
||||
// mastercontrollerset,
|
||||
{ user_command::secondcontrollerincrease, GLFW_KEY_KP_DIVIDE },
|
||||
{ user_command::secondcontrollerincreasefast, GLFW_KEY_KP_DIVIDE | keymodifier::shift },
|
||||
{ user_command::secondcontrollerdecrease, GLFW_KEY_KP_MULTIPLY },
|
||||
{ user_command::secondcontrollerdecreasefast, GLFW_KEY_KP_MULTIPLY | keymodifier::shift },
|
||||
// secondcontrollerset,
|
||||
{ user_command::mucurrentindicatorothersourceactivate, GLFW_KEY_Z | keymodifier::shift },
|
||||
{ user_command::independentbrakeincrease, GLFW_KEY_KP_1 },
|
||||
{ user_command::independentbrakeincreasefast, GLFW_KEY_KP_1 | keymodifier::shift },
|
||||
{ user_command::independentbrakedecrease, GLFW_KEY_KP_7 },
|
||||
{ user_command::independentbrakedecreasefast, GLFW_KEY_KP_7 | keymodifier::shift },
|
||||
// independentbrakeset,
|
||||
{ user_command::independentbrakebailoff, GLFW_KEY_KP_4 },
|
||||
{ user_command::trainbrakeincrease, GLFW_KEY_KP_3 },
|
||||
{ user_command::trainbrakedecrease, GLFW_KEY_KP_9 },
|
||||
// trainbrakeset,
|
||||
{ user_command::trainbrakecharging, GLFW_KEY_KP_DECIMAL },
|
||||
{ user_command::trainbrakerelease, GLFW_KEY_KP_6 },
|
||||
{ user_command::trainbrakefirstservice, GLFW_KEY_KP_8 },
|
||||
{ user_command::trainbrakeservice, GLFW_KEY_KP_5 },
|
||||
{ user_command::trainbrakefullservice, GLFW_KEY_KP_2 },
|
||||
{ user_command::trainbrakehandleoff, GLFW_KEY_KP_5 | keymodifier::control },
|
||||
{ user_command::trainbrakeemergency, GLFW_KEY_KP_0 },
|
||||
{ user_command::trainbrakebasepressureincrease, GLFW_KEY_KP_3 | keymodifier::control },
|
||||
{ user_command::trainbrakebasepressuredecrease, GLFW_KEY_KP_9 | keymodifier::control },
|
||||
{ user_command::trainbrakebasepressurereset, GLFW_KEY_KP_6 | keymodifier::control },
|
||||
{ user_command::trainbrakeoperationtoggle, GLFW_KEY_KP_4 | keymodifier::control },
|
||||
{ user_command::manualbrakeincrease, GLFW_KEY_KP_1 | keymodifier::control },
|
||||
{ user_command::manualbrakedecrease, GLFW_KEY_KP_7 | keymodifier::control },
|
||||
{ user_command::alarmchaintoggle, GLFW_KEY_B | keymodifier::shift | keymodifier::control },
|
||||
{ user_command::wheelspinbrakeactivate, GLFW_KEY_KP_ENTER },
|
||||
{ user_command::sandboxactivate, GLFW_KEY_S },
|
||||
{ user_command::reverserincrease, GLFW_KEY_D },
|
||||
{ user_command::reverserdecrease, GLFW_KEY_R },
|
||||
// reverserforwardhigh,
|
||||
// reverserforward,
|
||||
// reverserneutral,
|
||||
// reverserbackward,
|
||||
{ user_command::waterpumpbreakertoggle, GLFW_KEY_W | keymodifier::control },
|
||||
// waterpumpbreakerclose,
|
||||
// waterpumpbreakeropen,
|
||||
{ user_command::waterpumptoggle, GLFW_KEY_W },
|
||||
// waterpumpenable,
|
||||
// waterpumpdisable,
|
||||
{ user_command::waterheaterbreakertoggle, GLFW_KEY_W | keymodifier::control | keymodifier::shift },
|
||||
// waterheaterbreakerclose,
|
||||
// waterheaterbreakeropen,
|
||||
{ user_command::waterheatertoggle, GLFW_KEY_W | keymodifier::shift },
|
||||
// waterheaterenable,
|
||||
// waterheaterdisable,
|
||||
{ user_command::watercircuitslinktoggle, GLFW_KEY_H | keymodifier::shift },
|
||||
// watercircuitslinkenable,
|
||||
// watercircuitslinkdisable,
|
||||
{ user_command::fuelpumptoggle, GLFW_KEY_F },
|
||||
// fuelpumpenable,
|
||||
// fuelpumpdisable,
|
||||
{ user_command::oilpumptoggle, GLFW_KEY_F | keymodifier::shift },
|
||||
// oilpumpenable,
|
||||
// oilpumpdisable,
|
||||
{ user_command::linebreakertoggle, GLFW_KEY_M },
|
||||
// linebreakeropen,
|
||||
// linebreakerclose,
|
||||
{ user_command::convertertoggle, GLFW_KEY_X },
|
||||
// converterenable,
|
||||
// converterdisable,
|
||||
{ user_command::convertertogglelocal, GLFW_KEY_X | keymodifier::shift },
|
||||
{ user_command::converteroverloadrelayreset, GLFW_KEY_N | keymodifier::control },
|
||||
{ user_command::compressortoggle, GLFW_KEY_C },
|
||||
// compressorenable,
|
||||
// compressordisable,
|
||||
{ user_command::compressortogglelocal, GLFW_KEY_C | keymodifier::shift },
|
||||
{ user_command::motoroverloadrelaythresholdtoggle, GLFW_KEY_F },
|
||||
// motoroverloadrelaythresholdsetlow,
|
||||
// motoroverloadrelaythresholdsethigh,
|
||||
{ user_command::motoroverloadrelayreset, GLFW_KEY_N },
|
||||
{ user_command::notchingrelaytoggle, GLFW_KEY_G },
|
||||
{ user_command::epbrakecontroltoggle, GLFW_KEY_Z | keymodifier::control },
|
||||
{ user_command::trainbrakeoperationmodeincrease, GLFW_KEY_KP_2 | keymodifier::control },
|
||||
{ user_command::trainbrakeoperationmodedecrease, GLFW_KEY_KP_8 | keymodifier::control },
|
||||
{ user_command::brakeactingspeedincrease, GLFW_KEY_B | keymodifier::shift },
|
||||
{ user_command::brakeactingspeeddecrease, GLFW_KEY_B },
|
||||
// brakeactingspeedsetcargo,
|
||||
// brakeactingspeedsetpassenger,
|
||||
// brakeactingspeedsetrapid,
|
||||
{ user_command::brakeloadcompensationincrease, GLFW_KEY_H | keymodifier::shift | keymodifier::control },
|
||||
{ user_command::brakeloadcompensationdecrease, GLFW_KEY_H | keymodifier::control },
|
||||
{ user_command::mubrakingindicatortoggle, GLFW_KEY_L | keymodifier::shift },
|
||||
{ user_command::alerteracknowledge, GLFW_KEY_SPACE },
|
||||
{ user_command::hornlowactivate, GLFW_KEY_A },
|
||||
{ user_command::hornhighactivate, GLFW_KEY_S },
|
||||
{ user_command::whistleactivate, GLFW_KEY_Z },
|
||||
{ user_command::radiotoggle, GLFW_KEY_R | keymodifier::control },
|
||||
{ user_command::radiochannelincrease, GLFW_KEY_R | keymodifier::shift },
|
||||
{ user_command::radiochanneldecrease, GLFW_KEY_R },
|
||||
{ user_command::radiostopsend, GLFW_KEY_PAUSE | keymodifier::shift | keymodifier::control },
|
||||
{ user_command::radiostoptest, GLFW_KEY_R | keymodifier::shift | keymodifier::control },
|
||||
{ user_command::cabchangeforward, GLFW_KEY_HOME },
|
||||
{ user_command::cabchangebackward, GLFW_KEY_END },
|
||||
// viewturn,
|
||||
// movehorizontal,
|
||||
// movehorizontalfast,
|
||||
// movevertical,
|
||||
// moveverticalfast,
|
||||
{ user_command::moveleft, GLFW_KEY_LEFT },
|
||||
{ user_command::moveright, GLFW_KEY_RIGHT },
|
||||
{ user_command::moveforward, GLFW_KEY_UP },
|
||||
{ user_command::moveback, GLFW_KEY_DOWN },
|
||||
{ user_command::moveup, GLFW_KEY_PAGE_UP },
|
||||
{ user_command::movedown, GLFW_KEY_PAGE_DOWN },
|
||||
{ user_command::carcouplingincrease, GLFW_KEY_INSERT },
|
||||
{ user_command::carcouplingdisconnect, GLFW_KEY_DELETE },
|
||||
{ user_command::doortoggleleft, GLFW_KEY_COMMA },
|
||||
{ user_command::doortoggleright, GLFW_KEY_PERIOD },
|
||||
{ user_command::departureannounce, GLFW_KEY_SLASH },
|
||||
{ user_command::doorlocktoggle, GLFW_KEY_S | keymodifier::shift },
|
||||
{ user_command::pantographcompressorvalvetoggle, GLFW_KEY_V | keymodifier::control },
|
||||
{ user_command::pantographcompressoractivate, GLFW_KEY_V | keymodifier::shift },
|
||||
{ user_command::pantographtogglefront, GLFW_KEY_P },
|
||||
{ user_command::pantographtogglerear, GLFW_KEY_O },
|
||||
// pantographraisefront,
|
||||
// pantographraiserear,
|
||||
// pantographlowerfront,
|
||||
// pantographlowerrear,
|
||||
{ user_command::pantographlowerall, GLFW_KEY_P | keymodifier::control },
|
||||
{ user_command::heatingtoggle, GLFW_KEY_H },
|
||||
// heatingenable,
|
||||
// heatingdisable,
|
||||
{ user_command::lightspresetactivatenext, GLFW_KEY_T | keymodifier::shift },
|
||||
{ user_command::lightspresetactivateprevious, GLFW_KEY_T },
|
||||
{ user_command::headlighttoggleleft, GLFW_KEY_Y },
|
||||
// headlightenableleft,
|
||||
// headlightdisableleft,
|
||||
{ user_command::headlighttoggleright, GLFW_KEY_I },
|
||||
// headlightenableright,
|
||||
// headlightdisableright,
|
||||
{ user_command::headlighttoggleupper, GLFW_KEY_U },
|
||||
// headlightenableupper,
|
||||
// headlightdisableupper,
|
||||
{ user_command::redmarkertoggleleft, GLFW_KEY_Y | keymodifier::shift },
|
||||
// redmarkerenableleft,
|
||||
// redmarkerdisableleft,
|
||||
{ user_command::redmarkertoggleright, GLFW_KEY_I | keymodifier::shift },
|
||||
// redmarkerenableright,
|
||||
// redmarkerdisableright,
|
||||
{ user_command::headlighttogglerearleft, GLFW_KEY_Y | keymodifier::control },
|
||||
{ user_command::headlighttogglerearright, GLFW_KEY_I | keymodifier::control },
|
||||
{ user_command::headlighttogglerearupper, GLFW_KEY_U | keymodifier::control },
|
||||
{ user_command::redmarkertogglerearleft, GLFW_KEY_Y | keymodifier::control | keymodifier::shift },
|
||||
{ user_command::redmarkertogglerearright, GLFW_KEY_I | keymodifier::control | keymodifier::shift },
|
||||
{ user_command::redmarkerstoggle, GLFW_KEY_E | keymodifier::shift },
|
||||
{ user_command::endsignalstoggle, GLFW_KEY_E },
|
||||
{ user_command::headlightsdimtoggle, GLFW_KEY_L | keymodifier::control },
|
||||
// headlightsdimenable,
|
||||
// headlightsdimdisable,
|
||||
{ user_command::motorconnectorsopen, GLFW_KEY_L },
|
||||
// motorconnectorsclose,
|
||||
{ user_command::motordisconnect, GLFW_KEY_E | keymodifier::control },
|
||||
{ user_command::interiorlighttoggle, GLFW_KEY_APOSTROPHE },
|
||||
// interiorlightenable,
|
||||
// interiorlightdisable,
|
||||
{ user_command::interiorlightdimtoggle, GLFW_KEY_APOSTROPHE | keymodifier::control },
|
||||
// interiorlightdimenable,
|
||||
// interiorlightdimdisable,
|
||||
{ user_command::instrumentlighttoggle, GLFW_KEY_SEMICOLON },
|
||||
// instrumentlightenable,
|
||||
// instrumentlightdisable,
|
||||
{ user_command::generictoggle0, GLFW_KEY_0 },
|
||||
{ user_command::generictoggle1, GLFW_KEY_1 },
|
||||
{ user_command::generictoggle2, GLFW_KEY_2 },
|
||||
{ user_command::generictoggle3, GLFW_KEY_3 },
|
||||
{ user_command::generictoggle4, GLFW_KEY_4 },
|
||||
{ user_command::generictoggle5, GLFW_KEY_5 },
|
||||
{ user_command::generictoggle6, GLFW_KEY_6 },
|
||||
{ user_command::generictoggle7, GLFW_KEY_7 },
|
||||
{ user_command::generictoggle8, GLFW_KEY_8 },
|
||||
{ user_command::generictoggle9, GLFW_KEY_9 },
|
||||
{ user_command::batterytoggle, GLFW_KEY_J },
|
||||
// batteryenable,
|
||||
// batterydisable,
|
||||
};
|
||||
|
||||
bind();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
27
driverkeyboardinput.h
Normal file
27
driverkeyboardinput.h
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
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 "keyboardinput.h"
|
||||
|
||||
class driverkeyboard_input : public keyboard_input {
|
||||
|
||||
public:
|
||||
// methods
|
||||
bool
|
||||
init() override;
|
||||
|
||||
protected:
|
||||
// methods
|
||||
void
|
||||
default_bindings();
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
1007
drivermode.cpp
Normal file
1007
drivermode.cpp
Normal file
File diff suppressed because it is too large
Load Diff
87
drivermode.h
Normal file
87
drivermode.h
Normal file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
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 "applicationmode.h"
|
||||
|
||||
#include "driverkeyboardinput.h"
|
||||
#include "drivermouseinput.h"
|
||||
#include "gamepadinput.h"
|
||||
#include "uart.h"
|
||||
#include "console.h"
|
||||
#include "camera.h"
|
||||
#include "classes.h"
|
||||
|
||||
class driver_mode : public application_mode {
|
||||
|
||||
public:
|
||||
// constructors
|
||||
driver_mode();
|
||||
|
||||
// methods
|
||||
// initializes internal data structures of the mode. returns: true on success, false otherwise
|
||||
bool
|
||||
init() override;
|
||||
// mode-specific update of simulation data. returns: false on error, true otherwise
|
||||
bool
|
||||
update() override;
|
||||
// maintenance method, called when the mode is activated
|
||||
void
|
||||
enter() override;
|
||||
// maintenance method, called when the mode is deactivated
|
||||
void
|
||||
exit() override;
|
||||
// input handlers
|
||||
void
|
||||
on_key( int const Key, int const Scancode, int const Action, int const Mods ) override;
|
||||
void
|
||||
on_cursor_pos( double const Horizontal, double const Vertical ) override;
|
||||
void
|
||||
on_mouse_button( int const Button, int const Action, int const Mods ) override;
|
||||
void
|
||||
on_scroll( double const Xoffset, double const Yoffset ) override;
|
||||
|
||||
private:
|
||||
// types
|
||||
struct drivermode_input {
|
||||
|
||||
gamepad_input gamepad;
|
||||
mouse_input mouse;
|
||||
glm::dvec2 mouse_pickmodepos; // stores last mouse position in control picking mode
|
||||
driverkeyboard_input keyboard;
|
||||
Console console;
|
||||
std::unique_ptr<uart_input> uart;
|
||||
|
||||
bool init();
|
||||
void poll();
|
||||
};
|
||||
|
||||
// methods
|
||||
void update_camera( const double Deltatime );
|
||||
// handles vehicle change flag
|
||||
void OnKeyDown( int cKey );
|
||||
void ChangeDynamic();
|
||||
void InOutKey( bool const Near = true );
|
||||
void FollowView( bool wycisz = true );
|
||||
void DistantView( bool const Near = false );
|
||||
|
||||
// members
|
||||
drivermode_input m_input;
|
||||
std::array<TEvent *, 10> KeyEvents { nullptr }; // eventy wyzwalane z klawiaury
|
||||
TCamera Camera;
|
||||
TCamera DebugCamera;
|
||||
TDynamicObject *pDynamicNearest { nullptr }; // vehicle nearest to the active camera. TODO: move to camera
|
||||
double fTime50Hz { 0.0 }; // bufor czasu dla komunikacji z PoKeys
|
||||
double const m_primaryupdaterate { 1.0 / 100.0 };
|
||||
double const m_secondaryupdaterate { 1.0 / 50.0 };
|
||||
double m_primaryupdateaccumulator { m_secondaryupdaterate }; // keeps track of elapsed simulation time, for core fixed step routines
|
||||
double m_secondaryupdateaccumulator { m_secondaryupdaterate }; // keeps track of elapsed simulation time, for less important fixed step routines
|
||||
int iPause { 0 }; // wykrywanie zmian w zapauzowaniu
|
||||
};
|
||||
@@ -8,15 +8,15 @@ http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "mouseinput.h"
|
||||
#include "drivermouseinput.h"
|
||||
|
||||
#include "application.h"
|
||||
#include "utilities.h"
|
||||
#include "globals.h"
|
||||
#include "timer.h"
|
||||
#include "simulation.h"
|
||||
#include "world.h"
|
||||
#include "train.h"
|
||||
#include "animmodel.h"
|
||||
#include "renderer.h"
|
||||
#include "uilayer.h"
|
||||
|
||||
@@ -25,7 +25,7 @@ mouse_slider::bind( user_command const &Command ) {
|
||||
|
||||
m_command = Command;
|
||||
|
||||
auto const *train { World.train() };
|
||||
auto const *train { simulation::Train };
|
||||
TMoverParameters const *vehicle { nullptr };
|
||||
switch( m_command ) {
|
||||
case user_command::mastercontrollerset:
|
||||
@@ -184,6 +184,11 @@ mouse_input::move( double Mousex, double Mousey ) {
|
||||
void
|
||||
mouse_input::button( int const Button, int const Action ) {
|
||||
|
||||
// store key state
|
||||
if( Button >= 0 ) {
|
||||
m_buttons[ Button ] = Action;
|
||||
}
|
||||
|
||||
if( false == Global.ControlPicking ) { return; }
|
||||
|
||||
if( true == FreeFlyModeFlag ) {
|
||||
@@ -236,7 +241,7 @@ mouse_input::button( int const Button, int const Action ) {
|
||||
}
|
||||
else {
|
||||
// if not release then it's press
|
||||
auto const lookup = m_mousecommands.find( World.train()->GetLabel( GfxRenderer.Update_Pick_Control() ) );
|
||||
auto const lookup = m_mousecommands.find( simulation::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 = (
|
||||
@@ -301,6 +306,12 @@ mouse_input::button( int const Button, int const Action ) {
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
mouse_input::button( int const Button ) const {
|
||||
|
||||
return m_buttons[ Button ];
|
||||
}
|
||||
|
||||
void
|
||||
mouse_input::poll() {
|
||||
|
||||
@@ -53,6 +53,8 @@ public:
|
||||
init();
|
||||
void
|
||||
button( int const Button, int const Action );
|
||||
int
|
||||
button( int const Button ) const;
|
||||
void
|
||||
move( double const Mousex, double const Mousey );
|
||||
void
|
||||
@@ -87,6 +89,7 @@ private:
|
||||
glm::dvec2 m_cursorposition; // stored last cursor position, used for panning
|
||||
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
|
||||
std::array<int, GLFW_MOUSE_BUTTON_LAST> m_buttons;
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
904
driveruilayer.cpp
Normal file
904
driveruilayer.cpp
Normal file
@@ -0,0 +1,904 @@
|
||||
/*
|
||||
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 "driveruilayer.h"
|
||||
|
||||
#include "globals.h"
|
||||
#include "translation.h"
|
||||
#include "simulation.h"
|
||||
#include "simulationtime.h"
|
||||
#include "event.h"
|
||||
#include "camera.h"
|
||||
#include "mtable.h"
|
||||
#include "train.h"
|
||||
#include "driver.h"
|
||||
#include "animmodel.h"
|
||||
#include "dynobj.h"
|
||||
#include "model3d.h"
|
||||
#include "renderer.h"
|
||||
#include "utilities.h"
|
||||
#include "logs.h"
|
||||
|
||||
driver_ui::driver_ui() {
|
||||
|
||||
clear_texts();
|
||||
/*
|
||||
UIHeader = std::make_shared<ui_panel>( 20, 20 ); // header ui panel
|
||||
UITable = std::make_shared<ui_panel>( 20, 100 ); // schedule or scan table
|
||||
UITranscripts = std::make_shared<ui_panel>( 85, 600 ); // voice transcripts
|
||||
*/
|
||||
// make 4 empty lines for the ui header, to cut down on work down the road
|
||||
UIHeader.text_lines.emplace_back( "", Global.UITextColor );
|
||||
UIHeader.text_lines.emplace_back( "", Global.UITextColor );
|
||||
UIHeader.text_lines.emplace_back( "", Global.UITextColor );
|
||||
UIHeader.text_lines.emplace_back( "", Global.UITextColor );
|
||||
// bind the panels with ui object. maybe not the best place for this but, eh
|
||||
push_back( &UIHeader );
|
||||
push_back( &UITable );
|
||||
push_back( &UITranscripts );
|
||||
}
|
||||
|
||||
// potentially processes provided input key. returns: true if key was processed, false otherwise
|
||||
bool
|
||||
driver_ui::on_key( int const Key, int const Action ) {
|
||||
// TODO: pass the input first through an active ui element if there's any
|
||||
// if the ui element shows no interest or we don't have one, try to interpret the input yourself:
|
||||
// shared conditions
|
||||
switch( Key ) {
|
||||
|
||||
case GLFW_KEY_F1:
|
||||
case GLFW_KEY_F2:
|
||||
case GLFW_KEY_F3:
|
||||
case GLFW_KEY_F8:
|
||||
case GLFW_KEY_F9:
|
||||
case GLFW_KEY_F10:
|
||||
case GLFW_KEY_F12: { // ui mode selectors
|
||||
|
||||
if( ( true == Global.ctrlState )
|
||||
|| ( true == Global.shiftState ) ) {
|
||||
// only react to keys without modifiers
|
||||
return false;
|
||||
}
|
||||
|
||||
if( Action == GLFW_RELEASE ) { return true; } // recognized, but ignored
|
||||
/*
|
||||
EditorModeFlag = ( Key == GLFW_KEY_F11 );
|
||||
if( ( true == EditorModeFlag )
|
||||
&& ( false == Global.ControlPicking ) ) {
|
||||
set_cursor( GLFW_CURSOR_NORMAL );
|
||||
Global.ControlPicking = true;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
default: { // everything else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (Key) {
|
||||
|
||||
case GLFW_KEY_F1: {
|
||||
// basic consist info
|
||||
if( Global.iTextMode == Key ) { ++Global.iScreenMode[ Key - GLFW_KEY_F1 ]; }
|
||||
if( Global.iScreenMode[ Key - GLFW_KEY_F1 ] > 1 ) {
|
||||
// wyłączenie napisów
|
||||
Global.iTextMode = 0;
|
||||
Global.iScreenMode[ Key - GLFW_KEY_F1 ] = 0;
|
||||
}
|
||||
else {
|
||||
Global.iTextMode = Key;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
case GLFW_KEY_F2: {
|
||||
// parametry pojazdu
|
||||
if( Global.iTextMode == Key ) { ++Global.iScreenMode[ Key - GLFW_KEY_F1 ]; }
|
||||
if( Global.iScreenMode[ Key - GLFW_KEY_F1 ] > 1 ) {
|
||||
// wyłączenie napisów
|
||||
Global.iTextMode = 0;
|
||||
Global.iScreenMode[ Key - GLFW_KEY_F1 ] = 0;
|
||||
}
|
||||
else {
|
||||
Global.iTextMode = Key;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
case GLFW_KEY_F3: {
|
||||
// timetable
|
||||
if( Global.iTextMode == Key ) { ++Global.iScreenMode[ Key - GLFW_KEY_F1 ]; }
|
||||
if( Global.iScreenMode[ Key - GLFW_KEY_F1 ] > 1 ) {
|
||||
// wyłączenie napisów
|
||||
Global.iTextMode = 0;
|
||||
Global.iScreenMode[ Key - GLFW_KEY_F1 ] = 0;
|
||||
}
|
||||
else {
|
||||
Global.iTextMode = Key;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
case GLFW_KEY_F8: {
|
||||
// renderer debug data
|
||||
Global.iTextMode = Key;
|
||||
return true;
|
||||
}
|
||||
|
||||
case GLFW_KEY_F9: {
|
||||
// wersja
|
||||
Global.iTextMode = Key;
|
||||
return true;
|
||||
}
|
||||
|
||||
case GLFW_KEY_F10: {
|
||||
// quit
|
||||
if( Global.iTextMode == Key ) {
|
||||
Global.iTextMode =
|
||||
( Global.iPause && ( Key != GLFW_KEY_F1 ) ?
|
||||
GLFW_KEY_F1 :
|
||||
0 ); // wyłączenie napisów, chyba że pauza
|
||||
}
|
||||
else {
|
||||
Global.iTextMode = Key;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
/*
|
||||
case GLFW_KEY_F11: {
|
||||
// scenario inspector
|
||||
Global.iTextMode = Key;
|
||||
return true;
|
||||
}
|
||||
*/
|
||||
case GLFW_KEY_F12: {
|
||||
// coś tam jeszcze
|
||||
Global.iTextMode = Key;
|
||||
return true;
|
||||
}
|
||||
|
||||
case GLFW_KEY_Y: {
|
||||
// potentially quit
|
||||
if( Global.iTextMode != GLFW_KEY_F10 ) { return false; } // not in quit mode
|
||||
|
||||
if( Action == GLFW_RELEASE ) { return true; } // recognized, but ignored
|
||||
|
||||
glfwSetWindowShouldClose( m_window, 1 );
|
||||
return true;
|
||||
}
|
||||
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// updates state of UI elements
|
||||
void
|
||||
driver_ui::update() {
|
||||
|
||||
UITable.text_lines.clear();
|
||||
std::string uitextline1, uitextline2, uitextline3, uitextline4;
|
||||
set_tooltip( "" );
|
||||
|
||||
auto const *train { simulation::Train };
|
||||
auto const *controlled { ( train ? train->Dynamic() : nullptr ) };
|
||||
auto const *camera { Global.pCamera };
|
||||
|
||||
if( ( train != nullptr ) && ( false == FreeFlyModeFlag ) ) {
|
||||
if( false == DebugModeFlag ) {
|
||||
// in regular mode show control functions, for defined controls
|
||||
set_tooltip( locale::label_cab_control( train->GetLabel( GfxRenderer.Pick_Control() ) ) );
|
||||
}
|
||||
else {
|
||||
// in debug mode show names of submodels, to help with cab setup and/or debugging
|
||||
auto const cabcontrol = GfxRenderer.Pick_Control();
|
||||
set_tooltip( ( cabcontrol ? cabcontrol->pName : "" ) );
|
||||
}
|
||||
}
|
||||
if( ( true == Global.ControlPicking ) && ( true == FreeFlyModeFlag ) && ( true == DebugModeFlag ) ) {
|
||||
auto const scenerynode = GfxRenderer.Pick_Node();
|
||||
set_tooltip(
|
||||
( scenerynode ?
|
||||
scenerynode->name() :
|
||||
"" ) );
|
||||
}
|
||||
|
||||
switch( Global.iTextMode ) {
|
||||
|
||||
case( GLFW_KEY_F1 ) : {
|
||||
// f1, default mode: current time and timetable excerpt
|
||||
auto const &time = simulation::Time.data();
|
||||
uitextline1 =
|
||||
"Time: "
|
||||
+ to_string( time.wHour ) + ":"
|
||||
+ ( time.wMinute < 10 ? "0" : "" ) + to_string( time.wMinute ) + ":"
|
||||
+ ( time.wSecond < 10 ? "0" : "" ) + to_string( time.wSecond );
|
||||
if( Global.iPause ) {
|
||||
uitextline1 += " (paused)";
|
||||
}
|
||||
|
||||
if( ( controlled != nullptr )
|
||||
&& ( controlled->Mechanik != nullptr ) ) {
|
||||
|
||||
auto const *mover = controlled->MoverParameters;
|
||||
auto const *driver = controlled->Mechanik;
|
||||
|
||||
uitextline2 = "Throttle: " + to_string( driver->Controlling()->MainCtrlPos, 0, 2 ) + "+" + std::to_string( driver->Controlling()->ScndCtrlPos );
|
||||
if( mover->ActiveDir > 0 ) { uitextline2 += " D"; }
|
||||
else if( mover->ActiveDir < 0 ) { uitextline2 += " R"; }
|
||||
else { uitextline2 += " N"; }
|
||||
|
||||
uitextline3 = "Brakes:" + to_string( mover->fBrakeCtrlPos, 1, 5 ) + "+" + to_string( mover->LocalBrakePosA * LocalBrakePosNo, 0 ) + ( mover->SlippingWheels ? " !" : " " );
|
||||
|
||||
uitextline4 = (
|
||||
true == TestFlag( mover->SecuritySystem.Status, s_aware ) ?
|
||||
"!ALERTER! " :
|
||||
" " );
|
||||
uitextline4 += (
|
||||
true == TestFlag( mover->SecuritySystem.Status, s_active ) ?
|
||||
"!SHP! " :
|
||||
" " );
|
||||
|
||||
if( Global.iScreenMode[ Global.iTextMode - GLFW_KEY_F1 ] == 1 ) {
|
||||
// detail mode on second key press
|
||||
auto const speedlimit { static_cast<int>( std::floor( driver->VelDesired ) ) };
|
||||
uitextline2 +=
|
||||
" Speed: " + std::to_string( static_cast<int>( std::floor( mover->Vel ) ) ) + " km/h"
|
||||
+ " (limit: " + std::to_string( speedlimit ) + " km/h";
|
||||
auto const nextspeedlimit { static_cast<int>( std::floor( driver->VelNext ) ) };
|
||||
if( nextspeedlimit != speedlimit ) {
|
||||
uitextline2 +=
|
||||
", new limit: " + std::to_string( nextspeedlimit ) + " km/h"
|
||||
+ " in " + to_string( driver->ActualProximityDist * 0.001, 1 ) + " km";
|
||||
}
|
||||
uitextline2 += ")";
|
||||
auto const reverser { ( mover->ActiveDir > 0 ? 1 : -1 ) };
|
||||
auto const grade { controlled->VectorFront().y * 100 * ( controlled->DirectionGet() == reverser ? 1 : -1 ) * reverser };
|
||||
if( std::abs( grade ) >= 0.25 ) {
|
||||
uitextline2 += " Grade: " + to_string( grade, 1 ) + "%";
|
||||
}
|
||||
uitextline3 +=
|
||||
" Pressure: " + to_string( mover->BrakePress * 100.0, 2 ) + " kPa"
|
||||
+ " (train pipe: " + to_string( mover->PipePress * 100.0, 2 ) + " kPa)";
|
||||
|
||||
auto const stoptime { static_cast<int>( -1.0 * controlled->Mechanik->fStopTime ) };
|
||||
if( stoptime > 0 ) {
|
||||
uitextline4 += " Loading/unloading in progress (" + to_string( stoptime ) + ( stoptime > 1 ? " seconds" : " second" ) + " left)";
|
||||
}
|
||||
else {
|
||||
auto const trackblockdistance{ std::abs( controlled->Mechanik->TrackBlock() ) };
|
||||
if( trackblockdistance <= 75.0 ) {
|
||||
uitextline4 += " Another vehicle ahead (distance: " + to_string( trackblockdistance, 1 ) + " m)";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case( GLFW_KEY_F2 ) : {
|
||||
// timetable
|
||||
auto *vehicle {
|
||||
( FreeFlyModeFlag ?
|
||||
std::get<TDynamicObject *>( simulation::Region->find_vehicle( camera->Pos, 20, false, false ) ) :
|
||||
controlled ) }; // w trybie latania lokalizujemy wg mapy
|
||||
|
||||
if( vehicle == nullptr ) { break; }
|
||||
// if the nearest located vehicle doesn't have a direct driver, try to query its owner
|
||||
auto const owner = (
|
||||
( ( vehicle->Mechanik != nullptr ) && ( vehicle->Mechanik->Primary() ) ) ?
|
||||
vehicle->Mechanik :
|
||||
vehicle->ctOwner );
|
||||
if( owner == nullptr ){ break; }
|
||||
|
||||
auto const *table = owner->TrainTimetable();
|
||||
if( table == nullptr ) { break; }
|
||||
|
||||
auto const &time = simulation::Time.data();
|
||||
uitextline1 =
|
||||
"Time: "
|
||||
+ to_string( time.wHour ) + ":"
|
||||
+ ( time.wMinute < 10 ? "0" : "" ) + to_string( time.wMinute ) + ":"
|
||||
+ ( time.wSecond < 10 ? "0" : "" ) + to_string( time.wSecond );
|
||||
if( Global.iPause ) {
|
||||
uitextline1 += " (paused)";
|
||||
}
|
||||
|
||||
uitextline2 = Bezogonkow( owner->Relation(), true ) + " (" + Bezogonkow( owner->TrainName(), true ) + ")";
|
||||
auto const nextstation = Bezogonkow( owner->NextStop(), true );
|
||||
if( !nextstation.empty() ) {
|
||||
// jeśli jest podana relacja, to dodajemy punkt następnego zatrzymania
|
||||
uitextline3 = " -> " + nextstation;
|
||||
}
|
||||
|
||||
if( Global.iScreenMode[ Global.iTextMode - GLFW_KEY_F1 ] == 1 ) {
|
||||
|
||||
if( 0 == table->StationCount ) {
|
||||
// only bother if there's stations to list
|
||||
UITable.text_lines.emplace_back( "(no timetable)", Global.UITextColor );
|
||||
}
|
||||
else {
|
||||
// header
|
||||
UITable.text_lines.emplace_back( "+-----+------------------------------------+-------+-----+", Global.UITextColor );
|
||||
|
||||
TMTableLine const *tableline;
|
||||
for( int i = owner->iStationStart; i <= std::min( owner->iStationStart + 10, table->StationCount ); ++i ) {
|
||||
// wyświetlenie pozycji z rozkładu
|
||||
tableline = table->TimeTable + i; // linijka rozkładu
|
||||
|
||||
std::string vmax =
|
||||
" "
|
||||
+ to_string( tableline->vmax, 0 );
|
||||
vmax = vmax.substr( vmax.size() - 3, 3 ); // z wyrównaniem do prawej
|
||||
std::string const station = (
|
||||
Bezogonkow( tableline->StationName, true )
|
||||
+ " " )
|
||||
.substr( 0, 34 );
|
||||
std::string const location = (
|
||||
( tableline->km > 0.0 ?
|
||||
to_string( tableline->km, 2 ) :
|
||||
"" )
|
||||
+ " " )
|
||||
.substr( 0, 34 - tableline->StationWare.size() );
|
||||
std::string const arrival = (
|
||||
tableline->Ah >= 0 ?
|
||||
to_string( int( 100 + tableline->Ah ) ).substr( 1, 2 ) + ":" + to_string( int( 100 + tableline->Am ) ).substr( 1, 2 ) :
|
||||
" | " );
|
||||
std::string const departure = (
|
||||
tableline->Dh >= 0 ?
|
||||
to_string( int( 100 + tableline->Dh ) ).substr( 1, 2 ) + ":" + to_string( int( 100 + tableline->Dm ) ).substr( 1, 2 ) :
|
||||
" | " );
|
||||
auto const candeparture = (
|
||||
( owner->iStationStart < table->StationIndex )
|
||||
&& ( i < table->StationIndex )
|
||||
&& ( ( time.wHour * 60 + time.wMinute ) >= ( tableline->Dh * 60 + tableline->Dm ) ) );
|
||||
auto traveltime =
|
||||
" "
|
||||
+ ( i < 2 ? "" :
|
||||
tableline->Ah >= 0 ? to_string( CompareTime( table->TimeTable[ i - 1 ].Dh, table->TimeTable[ i - 1 ].Dm, tableline->Ah, tableline->Am ), 0 ) :
|
||||
to_string( std::max( 0.0, CompareTime( table->TimeTable[ i - 1 ].Dh, table->TimeTable[ i - 1 ].Dm, tableline->Dh, tableline->Dm ) - 0.5 ), 0 ) );
|
||||
traveltime = traveltime.substr( traveltime.size() - 3, 3 ); // z wyrównaniem do prawej
|
||||
|
||||
UITable.text_lines.emplace_back(
|
||||
( "| " + vmax + " | " + station + " | " + arrival + " | " + traveltime + " |" ),
|
||||
( candeparture ?
|
||||
glm::vec4( 0.0f, 1.0f, 0.0f, 1.0f ) :// czas minął i odjazd był, to nazwa stacji będzie na zielono
|
||||
Global.UITextColor ) );
|
||||
UITable.text_lines.emplace_back(
|
||||
( "| | " + location + tableline->StationWare + " | " + departure + " | |" ),
|
||||
( candeparture ?
|
||||
glm::vec4( 0.0f, 1.0f, 0.0f, 1.0f ) :// czas minął i odjazd był, to nazwa stacji będzie na zielono
|
||||
Global.UITextColor ) );
|
||||
// divider/footer
|
||||
UITable.text_lines.emplace_back( "+-----+------------------------------------+-------+-----+", Global.UITextColor );
|
||||
}
|
||||
if( owner->iStationStart + 10 < table->StationCount ) {
|
||||
// if we can't display entire timetable, add a scrolling indicator at the bottom
|
||||
UITable.text_lines.emplace_back( " ... ", Global.UITextColor );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case( GLFW_KEY_F3 ) : {
|
||||
|
||||
auto const *vehicle {
|
||||
( FreeFlyModeFlag ?
|
||||
std::get<TDynamicObject *>( simulation::Region->find_vehicle( camera->Pos, 20, false, false ) ) :
|
||||
controlled ) }; // w trybie latania lokalizujemy wg mapy
|
||||
|
||||
if( vehicle != nullptr ) {
|
||||
// jeśli domyślny ekran po pierwszym naciśnięciu
|
||||
auto const *mover { vehicle->MoverParameters };
|
||||
|
||||
uitextline1 = "Vehicle name: " + mover->Name;
|
||||
|
||||
if( ( vehicle->Mechanik == nullptr ) && ( vehicle->ctOwner ) ) {
|
||||
// for cars other than leading unit indicate the leader
|
||||
uitextline1 += ", owned by " + vehicle->ctOwner->OwnerName();
|
||||
}
|
||||
uitextline1 += "; Status: " + mover->EngineDescription( 0 );
|
||||
|
||||
// informacja o sprzęgach
|
||||
uitextline1 +=
|
||||
"; C0:" +
|
||||
( vehicle->PrevConnected ?
|
||||
vehicle->PrevConnected->name() + ":" + to_string( mover->Couplers[ 0 ].CouplingFlag ) + (
|
||||
mover->Couplers[ 0 ].CouplingFlag == 0 ?
|
||||
" (" + to_string( mover->Couplers[ 0 ].CoupleDist, 1 ) + " m)" :
|
||||
"" ) :
|
||||
"none" );
|
||||
uitextline1 +=
|
||||
" C1:" +
|
||||
( vehicle->NextConnected ?
|
||||
vehicle->NextConnected->name() + ":" + to_string( mover->Couplers[ 1 ].CouplingFlag ) + (
|
||||
mover->Couplers[ 1 ].CouplingFlag == 0 ?
|
||||
" (" + to_string( mover->Couplers[ 1 ].CoupleDist, 1 ) + " m)" :
|
||||
"" ) :
|
||||
"none" );
|
||||
|
||||
// equipment flags
|
||||
uitextline2 = ( mover->Battery ? "B" : "." );
|
||||
uitextline2 += ( mover->Mains ? "M" : "." );
|
||||
uitextline2 += ( mover->PantRearUp ? ( mover->PantRearVolt > 0.0 ? "O" : "o" ) : "." );
|
||||
uitextline2 += ( mover->PantFrontUp ? ( mover->PantFrontVolt > 0.0 ? "P" : "p" ) : "." );
|
||||
uitextline2 += ( mover->PantPressLockActive ? "!" : ( mover->PantPressSwitchActive ? "*" : "." ) );
|
||||
uitextline2 += ( mover->WaterPump.is_active ? "W" : ( false == mover->WaterPump.breaker ? "-" : ( mover->WaterPump.is_enabled ? "w" : "." ) ) );
|
||||
uitextline2 += ( true == mover->WaterHeater.is_damaged ? "!" : ( mover->WaterHeater.is_active ? "H" : ( false == mover->WaterHeater.breaker ? "-" : ( mover->WaterHeater.is_enabled ? "h" : "." ) ) ) );
|
||||
uitextline2 += ( mover->FuelPump.is_active ? "F" : ( mover->FuelPump.is_enabled ? "f" : "." ) );
|
||||
uitextline2 += ( mover->OilPump.is_active ? "O" : ( mover->OilPump.is_enabled ? "o" : "." ) );
|
||||
uitextline2 += ( false == mover->ConverterAllowLocal ? "-" : ( mover->ConverterAllow ? ( mover->ConverterFlag ? "X" : "x" ) : "." ) );
|
||||
uitextline2 += ( mover->ConvOvldFlag ? "!" : "." );
|
||||
uitextline2 += ( mover->CompressorFlag ? "C" : ( false == mover->CompressorAllowLocal ? "-" : ( ( mover->CompressorAllow || mover->CompressorStart == start_t::automatic ) ? "c" : "." ) ) );
|
||||
uitextline2 += ( mover->CompressorGovernorLock ? "!" : "." );
|
||||
|
||||
auto const *train { simulation::Train };
|
||||
if( ( train != nullptr ) && ( train->Dynamic() == vehicle ) ) {
|
||||
uitextline2 += ( mover->Radio ? " R: " : " r: " ) + std::to_string( train->RadioChannel() );
|
||||
}
|
||||
uitextline2 += " Bdelay: ";
|
||||
if( ( mover->BrakeDelayFlag & bdelay_G ) == bdelay_G )
|
||||
uitextline2 += "G";
|
||||
if( ( mover->BrakeDelayFlag & bdelay_P ) == bdelay_P )
|
||||
uitextline2 += "P";
|
||||
if( ( mover->BrakeDelayFlag & bdelay_R ) == bdelay_R )
|
||||
uitextline2 += "R";
|
||||
if( ( mover->BrakeDelayFlag & bdelay_M ) == bdelay_M )
|
||||
uitextline2 += "+Mg";
|
||||
|
||||
uitextline2 += ", Load: " + to_string( mover->Load, 0 ) + " (" + to_string( mover->LoadFlag, 0 ) + ")";
|
||||
|
||||
uitextline2 +=
|
||||
"; Pant: "
|
||||
+ to_string( mover->PantPress, 2 )
|
||||
+ ( mover->bPantKurek3 ? "-ZG" : "|ZG" );
|
||||
|
||||
uitextline2 +=
|
||||
"; Ft: " + to_string(
|
||||
mover->Ft * 0.001f * (
|
||||
mover->ActiveCab ? mover->ActiveCab :
|
||||
vehicle->ctOwner ? vehicle->ctOwner->Controlling()->ActiveCab :
|
||||
1 ), 1 )
|
||||
+ ", Fb: " + to_string( mover->Fb * 0.001f, 1 )
|
||||
+ ", Fr: " + to_string( mover->Adhesive( mover->RunningTrack.friction ), 2 )
|
||||
+ ( mover->SlippingWheels ? " (!)" : "" );
|
||||
|
||||
if( vehicle->Mechanik ) {
|
||||
uitextline2 += "; Ag: " + to_string( vehicle->Mechanik->fAccGravity, 2 ) + " (" + ( vehicle->Mechanik->fAccGravity > 0.01 ? "\\" : ( vehicle->Mechanik->fAccGravity < -0.01 ? "/" : "-" ) ) + ")";
|
||||
}
|
||||
|
||||
uitextline2 +=
|
||||
"; TC:"
|
||||
+ to_string( mover->TotalCurrent, 0 );
|
||||
auto const frontcouplerhighvoltage =
|
||||
to_string( mover->Couplers[ side::front ].power_high.voltage, 0 )
|
||||
+ "@"
|
||||
+ to_string( mover->Couplers[ side::front ].power_high.current, 0 );
|
||||
auto const rearcouplerhighvoltage =
|
||||
to_string( mover->Couplers[ side::rear ].power_high.voltage, 0 )
|
||||
+ "@"
|
||||
+ to_string( mover->Couplers[ side::rear ].power_high.current, 0 );
|
||||
uitextline2 += ", HV: ";
|
||||
if( mover->Couplers[ side::front ].power_high.local == false ) {
|
||||
uitextline2 +=
|
||||
"(" + frontcouplerhighvoltage + ")-"
|
||||
+ ":F" + ( vehicle->DirectionGet() ? "<<" : ">>" ) + "R:"
|
||||
+ "-(" + rearcouplerhighvoltage + ")";
|
||||
}
|
||||
else {
|
||||
uitextline2 +=
|
||||
frontcouplerhighvoltage
|
||||
+ ":F" + ( vehicle->DirectionGet() ? "<<" : ">>" ) + "R:"
|
||||
+ rearcouplerhighvoltage;
|
||||
}
|
||||
|
||||
uitextline3 +=
|
||||
"TrB: " + to_string( mover->BrakePress, 2 )
|
||||
+ ", " + to_hex_str( mover->Hamulec->GetBrakeStatus(), 2 );
|
||||
|
||||
uitextline3 +=
|
||||
"; LcB: " + to_string( mover->LocBrakePress, 2 )
|
||||
+ "; hat: " + to_string( mover->BrakeCtrlPos2, 2 )
|
||||
+ "; pipes: " + to_string( mover->PipePress, 2 )
|
||||
+ "/" + to_string( mover->ScndPipePress, 2 )
|
||||
+ "/" + to_string( mover->EqvtPipePress, 2 )
|
||||
+ ", MT: " + to_string( mover->CompressedVolume, 3 )
|
||||
+ ", BT: " + to_string( mover->Volume, 3 )
|
||||
+ ", CtlP: " + to_string( mover->CntrlPipePress, 3 )
|
||||
+ ", CtlT: " + to_string( mover->Hamulec->GetCRP(), 3 );
|
||||
|
||||
if( mover->ManualBrakePos > 0 ) {
|
||||
|
||||
uitextline3 += "; manual brake on";
|
||||
}
|
||||
|
||||
if( vehicle->Mechanik ) {
|
||||
// o ile jest ktoś w środku
|
||||
std::string flags = "cpapcplhhndoiefgvdpseil "; // flagi AI (definicja w Driver.h)
|
||||
for( int i = 0, j = 1; i < 23; ++i, j <<= 1 )
|
||||
if( false == ( vehicle->Mechanik->DrivigFlags() & j ) ) // jak bit ustawiony
|
||||
flags[ i ] = '.';// std::toupper( flags[ i ] ); // ^= 0x20; // to zmiana na wielką literę
|
||||
|
||||
uitextline4 = flags;
|
||||
|
||||
uitextline4 +=
|
||||
"Driver: Vd=" + to_string( vehicle->Mechanik->VelDesired, 0 )
|
||||
+ " Ad=" + to_string( vehicle->Mechanik->AccDesired, 2 )
|
||||
+ " Ah=" + to_string( vehicle->Mechanik->fAccThreshold, 2 )
|
||||
+ "@" + to_string( vehicle->Mechanik->fBrake_a0[ 0 ], 2 )
|
||||
+ "+" + to_string( vehicle->Mechanik->fBrake_a1[ 0 ], 2 )
|
||||
+ " Bd=" + to_string( vehicle->Mechanik->fBrakeDist, 0 )
|
||||
+ " Pd=" + to_string( vehicle->Mechanik->ActualProximityDist, 0 )
|
||||
+ " Vn=" + to_string( vehicle->Mechanik->VelNext, 0 )
|
||||
+ " VSl=" + to_string( vehicle->Mechanik->VelSignalLast, 0 )
|
||||
+ " VLl=" + to_string( vehicle->Mechanik->VelLimitLast, 0 )
|
||||
+ " VRd=" + to_string( vehicle->Mechanik->VelRoad, 0 )
|
||||
+ " VRst=" + to_string( vehicle->Mechanik->VelRestricted, 0 );
|
||||
|
||||
if( ( vehicle->Mechanik->VelNext == 0.0 )
|
||||
&& ( vehicle->Mechanik->eSignNext ) ) {
|
||||
// jeśli ma zapamiętany event semafora, nazwa eventu semafora
|
||||
uitextline4 += " (" + Bezogonkow( vehicle->Mechanik->eSignNext->asName ) + ")";
|
||||
}
|
||||
|
||||
// biezaca komenda dla AI
|
||||
uitextline4 += ", command: " + vehicle->Mechanik->OrderCurrent();
|
||||
}
|
||||
|
||||
if( Global.iScreenMode[ Global.iTextMode - GLFW_KEY_F1 ] == 1 ) {
|
||||
// f2 screen, track scan mode
|
||||
if( vehicle->Mechanik == nullptr ) {
|
||||
//żeby była tabelka, musi być AI
|
||||
break;
|
||||
}
|
||||
|
||||
std::size_t i = 0; std::size_t const speedtablesize = clamp( static_cast<int>( vehicle->Mechanik->TableSize() ) - 1, 0, 30 );
|
||||
do {
|
||||
std::string scanline = vehicle->Mechanik->TableText( i );
|
||||
if( scanline.empty() ) { break; }
|
||||
UITable.text_lines.emplace_back( Bezogonkow( scanline ), Global.UITextColor );
|
||||
++i;
|
||||
} while( i < speedtablesize ); // TController:iSpeedTableSize TODO: change when the table gets recoded
|
||||
}
|
||||
}
|
||||
else {
|
||||
// wyświetlenie współrzędnych w scenerii oraz kąta kamery, gdy nie mamy wskaźnika
|
||||
uitextline1 =
|
||||
"Camera position: "
|
||||
+ to_string( camera->Pos.x, 2 ) + " "
|
||||
+ to_string( camera->Pos.y, 2 ) + " "
|
||||
+ to_string( camera->Pos.z, 2 )
|
||||
+ ", azimuth: "
|
||||
+ to_string( 180.0 - glm::degrees( camera->Yaw ), 0 ) // ma być azymut, czyli 0 na północy i rośnie na wschód
|
||||
+ " "
|
||||
+ std::string( "S SEE NEN NWW SW" )
|
||||
.substr( 0 + 2 * floor( fmod( 8 + ( camera->Yaw + 0.5 * M_PI_4 ) / M_PI_4, 8 ) ), 2 );
|
||||
// current luminance level
|
||||
uitextline2 = "Light level: " + to_string( Global.fLuminance, 3 );
|
||||
if( Global.FakeLight ) { uitextline2 += "(*)"; }
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case( GLFW_KEY_F8 ) : {
|
||||
// gfx renderer data
|
||||
uitextline1 =
|
||||
"FoV: " + to_string( Global.FieldOfView / Global.ZoomFactor, 1 )
|
||||
+ ", Draw range x " + to_string( Global.fDistanceFactor, 1 )
|
||||
// + "; sectors: " + std::to_string( GfxRenderer.m_drawcount )
|
||||
// + ", FPS: " + to_string( Timer::GetFPS(), 2 );
|
||||
+ ", FPS: " + std::to_string( static_cast<int>(std::round(GfxRenderer.Framerate())) );
|
||||
if( Global.iSlowMotion ) {
|
||||
uitextline1 += " (slowmotion " + to_string( Global.iSlowMotion ) + ")";
|
||||
}
|
||||
|
||||
uitextline2 =
|
||||
std::string( "Rendering mode: " )
|
||||
+ ( Global.bUseVBO ?
|
||||
"VBO" :
|
||||
"Display Lists" )
|
||||
+ " ";
|
||||
if( false == Global.LastGLError.empty() ) {
|
||||
uitextline2 +=
|
||||
"Last openGL error: "
|
||||
+ Global.LastGLError;
|
||||
}
|
||||
// renderer stats
|
||||
uitextline3 = GfxRenderer.info_times();
|
||||
uitextline4 = GfxRenderer.info_stats();
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case( GLFW_KEY_F9 ) : {
|
||||
// informacja o wersji
|
||||
uitextline1 = "MaSzyna " + Global.asVersion; // informacja o wersji
|
||||
if( Global.iMultiplayer ) {
|
||||
uitextline1 += " (multiplayer mode is active)";
|
||||
}
|
||||
uitextline3 =
|
||||
"vehicles: " + to_string( Timer::subsystem.sim_dynamics.average(), 2 ) + " msec"
|
||||
+ " update total: " + to_string( Timer::subsystem.sim_total.average(), 2 ) + " msec";
|
||||
// current event queue
|
||||
auto const time { Timer::GetTime() };
|
||||
auto const *event { simulation::Events.begin() };
|
||||
auto eventtableindex{ 0 };
|
||||
while( ( event != nullptr )
|
||||
&& ( eventtableindex < 30 ) ) {
|
||||
|
||||
if( ( false == event->m_ignored )
|
||||
&& ( true == event->bEnabled ) ) {
|
||||
|
||||
auto const delay { " " + to_string( std::max( 0.0, event->fStartTime - time ), 1 ) };
|
||||
auto const eventline =
|
||||
"Delay: " + delay.substr( delay.length() - 6 )
|
||||
+ ", Event: " + event->asName
|
||||
+ ( event->Activator ? " (by: " + event->Activator->asName + ")" : "" )
|
||||
+ ( event->evJoined ? " (joint event)" : "" );
|
||||
|
||||
UITable.text_lines.emplace_back( eventline, Global.UITextColor );
|
||||
++eventtableindex;
|
||||
}
|
||||
event = event->evNext;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case( GLFW_KEY_F10 ) : {
|
||||
|
||||
uitextline1 = "Press [Y] key to quit / Aby zakonczyc program, przycisnij klawisz [Y].";
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case( GLFW_KEY_F12 ) : {
|
||||
// opcje włączenia i wyłączenia logowania
|
||||
uitextline1 = "[0] Debugmode " + std::string( DebugModeFlag ? "(on)" : "(off)" );
|
||||
uitextline2 = "[1] log.txt " + std::string( ( Global.iWriteLogEnabled & 1 ) ? "(on)" : "(off)" );
|
||||
uitextline3 = "[2] Console " + std::string( ( Global.iWriteLogEnabled & 2 ) ? "(on)" : "(off)" );
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
// uncovered cases, nothing to do here...
|
||||
// ... unless we're in debug mode
|
||||
if( DebugModeFlag ) {
|
||||
|
||||
auto const *vehicle {
|
||||
( FreeFlyModeFlag ?
|
||||
std::get<TDynamicObject *>( simulation::Region->find_vehicle( camera->Pos, 20, false, false ) ) :
|
||||
controlled ) }; // w trybie latania lokalizujemy wg mapy
|
||||
if( vehicle == nullptr ) {
|
||||
break;
|
||||
}
|
||||
auto const *mover { vehicle->MoverParameters };
|
||||
uitextline1 =
|
||||
"vel: " + to_string( vehicle->GetVelocity(), 2 ) + "/" + to_string( mover->nrot* M_PI * mover->WheelDiameter * 3.6, 2 )
|
||||
+ " km/h;" + ( mover->SlippingWheels ? " (!)" : " " )
|
||||
+ " dist: " + to_string( mover->DistCounter, 2 ) + " km"
|
||||
+ "; pos: [" + to_string( vehicle->GetPosition().x, 2 ) + ", " + to_string( vehicle->GetPosition().y, 2 ) + ", " + to_string( vehicle->GetPosition().z, 2 ) + "]"
|
||||
+ ", PM=" + to_string( mover->WheelFlat, 1 )
|
||||
+ " mm; enpwr=" + to_string( mover->EnginePower, 1 )
|
||||
+ "; enrot=" + to_string( mover->enrot * 60, 0 )
|
||||
+ " tmrot=" + to_string( std::abs( mover->nrot ) * mover->Transmision.Ratio * 60, 0 )
|
||||
+ "; ventrot=" + to_string( mover->RventRot * 60, 1 )
|
||||
+ "; fanrot=" + to_string( mover->dizel_heat.rpmw, 1 ) + ", " + to_string( mover->dizel_heat.rpmw2, 1 );
|
||||
|
||||
uitextline2 =
|
||||
"HamZ=" + to_string( mover->fBrakeCtrlPos, 2 )
|
||||
+ "; HamP=" + to_string( mover->LocalBrakePosA, 2 )
|
||||
+ "; NasJ=" + std::to_string( mover->MainCtrlPos ) + "(" + std::to_string( mover->MainCtrlActualPos ) + ")"
|
||||
+ ( ( mover->ShuntMode && mover->EngineType == TEngineType::DieselElectric ) ?
|
||||
"; NasB=" + to_string( mover->AnPos, 2 ) :
|
||||
"; NasB=" + std::to_string( mover->ScndCtrlPos ) + "(" + std::to_string( mover->ScndCtrlActualPos ) + ")" )
|
||||
+ "; I=" +
|
||||
( mover->TrainType == dt_EZT ?
|
||||
std::to_string( int( mover->ShowCurrent( 0 ) ) ) :
|
||||
std::to_string( int( mover->Im ) ) )
|
||||
+ "; U=" + to_string( int( mover->RunningTraction.TractionVoltage + 0.5 ) )
|
||||
+ "; R=" +
|
||||
( std::abs( mover->RunningShape.R ) > 10000.0 ?
|
||||
"~0.0" :
|
||||
to_string( mover->RunningShape.R, 1 ) )
|
||||
+ " An=" + to_string( mover->AccN, 2 ); // przyspieszenie poprzeczne
|
||||
|
||||
if( tprev != simulation::Time.data().wSecond ) {
|
||||
tprev = simulation::Time.data().wSecond;
|
||||
Acc = ( mover->Vel - VelPrev ) / 3.6;
|
||||
VelPrev = mover->Vel;
|
||||
}
|
||||
uitextline2 += "; As=" + to_string( Acc, 2 ); // przyspieszenie wzdłużne
|
||||
// uitextline2 += " eAngle=" + to_string( std::cos( mover->eAngle ), 2 );
|
||||
uitextline2 += "; oilP=" + to_string( mover->OilPump.pressure_present, 3 );
|
||||
uitextline2 += " oilT=" + to_string( mover->dizel_heat.To, 2 );
|
||||
uitextline2 += "; waterT=" + to_string( mover->dizel_heat.temperatura1, 2 );
|
||||
uitextline2 += ( mover->WaterCircuitsLink ? "-" : "|" );
|
||||
uitextline2 += to_string( mover->dizel_heat.temperatura2, 2 );
|
||||
uitextline2 += "; engineT=" + to_string( mover->dizel_heat.Ts, 2 );
|
||||
|
||||
uitextline3 =
|
||||
"cyl.ham. " + to_string( mover->BrakePress, 2 )
|
||||
+ "; prz.gl. " + to_string( mover->PipePress, 2 )
|
||||
+ "; zb.gl. " + to_string( mover->CompressedVolume, 2 )
|
||||
// youBy - drugi wezyk
|
||||
+ "; p.zas. " + to_string( mover->ScndPipePress, 2 );
|
||||
|
||||
// McZapkie: warto wiedziec w jakim stanie sa przelaczniki
|
||||
if( mover->ConvOvldFlag )
|
||||
uitextline3 += " C! ";
|
||||
else if( mover->FuseFlag )
|
||||
uitextline3 += " F! ";
|
||||
else if( !mover->Mains )
|
||||
uitextline3 += " () ";
|
||||
else {
|
||||
switch(
|
||||
mover->ActiveDir *
|
||||
( mover->Imin == mover->IminLo ?
|
||||
1 :
|
||||
2 ) ) {
|
||||
case 2: { uitextline3 += " >> "; break; }
|
||||
case 1: { uitextline3 += " -> "; break; }
|
||||
case 0: { uitextline3 += " -- "; break; }
|
||||
case -1: { uitextline3 += " <- "; break; }
|
||||
case -2: { uitextline3 += " << "; break; }
|
||||
}
|
||||
}
|
||||
// McZapkie: predkosc szlakowa
|
||||
if( mover->RunningTrack.Velmax == -1 ) {
|
||||
uitextline3 += " Vtrack=Vmax";
|
||||
}
|
||||
else {
|
||||
uitextline3 += " Vtrack " + to_string( mover->RunningTrack.Velmax, 2 );
|
||||
}
|
||||
|
||||
if( ( mover->EnginePowerSource.SourceType == TPowerSource::CurrentCollector )
|
||||
|| ( mover->TrainType == dt_EZT ) ) {
|
||||
uitextline3 +=
|
||||
"; pant. " + to_string( mover->PantPress, 2 )
|
||||
+ ( mover->bPantKurek3 ? "=" : "^" ) + "ZG";
|
||||
}
|
||||
|
||||
// McZapkie: komenda i jej parametry
|
||||
if( mover->CommandIn.Command != ( "" ) ) {
|
||||
uitextline4 =
|
||||
"C:" + mover->CommandIn.Command
|
||||
+ " V1=" + to_string( mover->CommandIn.Value1, 0 )
|
||||
+ " V2=" + to_string( mover->CommandIn.Value2, 0 );
|
||||
}
|
||||
if( ( vehicle->Mechanik )
|
||||
&& ( vehicle->Mechanik->AIControllFlag == AIdriver ) ) {
|
||||
uitextline4 +=
|
||||
"AI: Vd=" + to_string( vehicle->Mechanik->VelDesired, 0 )
|
||||
+ " ad=" + to_string(vehicle->Mechanik->AccDesired, 2)
|
||||
+ "/" + to_string(vehicle->Mechanik->AccDesired*vehicle->Mechanik->BrakeAccFactor(), 2)
|
||||
+ " atrain=" + to_string(vehicle->Mechanik->fBrake_a0[0], 2)
|
||||
+ "+" + to_string(vehicle->Mechanik->fBrake_a1[0], 2)
|
||||
+ " aS=" + to_string(vehicle->Mechanik->AbsAccS_pub, 2)
|
||||
+ " Pd=" + to_string( vehicle->Mechanik->ActualProximityDist, 0 )
|
||||
+ " Vn=" + to_string( vehicle->Mechanik->VelNext, 0 );
|
||||
}
|
||||
|
||||
// induction motor data
|
||||
if( mover->EngineType == TEngineType::ElectricInductionMotor ) {
|
||||
|
||||
UITable.text_lines.emplace_back( " eimc: eimv: press:", Global.UITextColor );
|
||||
for( int i = 0; i <= 20; ++i ) {
|
||||
|
||||
std::string parameters =
|
||||
mover->eimc_labels[ i ] + to_string( mover->eimc[ i ], 2, 9 )
|
||||
+ " | "
|
||||
+ mover->eimv_labels[ i ] + to_string( mover->eimv[ i ], 2, 9 );
|
||||
|
||||
if( i < 10 ) {
|
||||
parameters += " | " + train->fPress_labels[i] + to_string( train->fPress[ i ][ 0 ], 2, 9 );
|
||||
}
|
||||
else if( i == 12 ) {
|
||||
parameters += " med:";
|
||||
}
|
||||
else if( i >= 13 ) {
|
||||
parameters += " | " + vehicle->MED_labels[ i - 13 ] + to_string( vehicle->MED[ 0 ][ i - 13 ], 2, 9 );
|
||||
}
|
||||
|
||||
UITable.text_lines.emplace_back( parameters, Global.UITextColor );
|
||||
}
|
||||
}
|
||||
if (mover->EngineType == TEngineType::DieselEngine) {
|
||||
std::string parameters = "param value";
|
||||
UITable.text_lines.emplace_back(parameters, Global.UITextColor);
|
||||
parameters = "efill: " + to_string(mover->dizel_fill, 2, 9);
|
||||
UITable.text_lines.emplace_back(parameters, Global.UITextColor);
|
||||
parameters = "etorq: " + to_string(mover->dizel_Torque, 2, 9);
|
||||
UITable.text_lines.emplace_back(parameters, Global.UITextColor);
|
||||
parameters = "creal: " + to_string(mover->dizel_engage, 2, 9);
|
||||
UITable.text_lines.emplace_back(parameters, Global.UITextColor);
|
||||
parameters = "cdesi: " + to_string(mover->dizel_engagestate, 2, 9);
|
||||
UITable.text_lines.emplace_back(parameters, Global.UITextColor);
|
||||
parameters = "cdelt: " + to_string(mover->dizel_engagedeltaomega, 2, 9);
|
||||
UITable.text_lines.emplace_back(parameters, Global.UITextColor);
|
||||
parameters = "gears: " + to_string(mover->dizel_automaticgearstatus, 2, 9);
|
||||
UITable.text_lines.emplace_back(parameters, Global.UITextColor);
|
||||
parameters = "hydro value";
|
||||
UITable.text_lines.emplace_back(parameters, Global.UITextColor);
|
||||
parameters = "hTCnI: " + to_string(mover->hydro_TC_nIn, 2, 9);
|
||||
UITable.text_lines.emplace_back(parameters, Global.UITextColor);
|
||||
parameters = "hTCnO: " + to_string(mover->hydro_TC_nOut, 2, 9);
|
||||
UITable.text_lines.emplace_back(parameters, Global.UITextColor);
|
||||
parameters = "hTCTM: " + to_string(mover->hydro_TC_TMRatio, 2, 9);
|
||||
UITable.text_lines.emplace_back(parameters, Global.UITextColor);
|
||||
parameters = "hTCTI: " + to_string(mover->hydro_TC_TorqueIn, 2, 9);
|
||||
UITable.text_lines.emplace_back(parameters, Global.UITextColor);
|
||||
parameters = "hTCTO: " + to_string(mover->hydro_TC_TorqueOut, 2, 9);
|
||||
UITable.text_lines.emplace_back(parameters, Global.UITextColor);
|
||||
parameters = "hTCfl: " + to_string(mover->hydro_TC_Fill, 2, 9);
|
||||
UITable.text_lines.emplace_back(parameters, Global.UITextColor);
|
||||
parameters = "hTCLR: " + to_string(mover->hydro_TC_LockupRate, 2, 9);
|
||||
UITable.text_lines.emplace_back(parameters, Global.UITextColor);
|
||||
//parameters = "hTCXX: " + to_string(mover->hydro_TC_nIn, 2, 9);
|
||||
//UITable.text_lines.emplace_back(parameters, Global.UITextColor);
|
||||
}
|
||||
|
||||
} // if( DebugModeFlag && Controlled )
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef EU07_USE_OLD_UI_CODE
|
||||
if( Controlled && DebugModeFlag && !Global.iTextMode ) {
|
||||
|
||||
uitextline1 +=
|
||||
( "; d_omega " ) + to_string( Controlled->MoverParameters->dizel_engagedeltaomega, 3 );
|
||||
|
||||
if( Controlled->MoverParameters->EngineType == ElectricInductionMotor ) {
|
||||
|
||||
for( int i = 0; i <= 8; i++ ) {
|
||||
for( int j = 0; j <= 9; j++ ) {
|
||||
glRasterPos2f( 0.05f + 0.03f * i, 0.16f - 0.01f * j );
|
||||
uitextline4 = to_string( Train->fEIMParams[ i ][ j ], 2 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// update the ui header texts
|
||||
auto &headerdata = UIHeader.text_lines;
|
||||
headerdata[ 0 ].data = uitextline1;
|
||||
headerdata[ 1 ].data = uitextline2;
|
||||
headerdata[ 2 ].data = uitextline3;
|
||||
headerdata[ 3 ].data = uitextline4;
|
||||
|
||||
// stenogramy dźwięków (ukryć, gdy tabelka skanowania lub rozkład?)
|
||||
auto &transcripts = UITranscripts.text_lines;
|
||||
transcripts.clear();
|
||||
for( auto const &transcript : ui::Transcripts.aLines ) {
|
||||
|
||||
if( Global.fTimeAngleDeg >= transcript.fShow ) {
|
||||
|
||||
cParser parser( transcript.asText );
|
||||
while( true == parser.getTokens( 1, false, "|" ) ) {
|
||||
|
||||
std::string transcriptline; parser >> transcriptline;
|
||||
transcripts.emplace_back( transcriptline, glm::vec4( 1.0f, 1.0f, 0.0f, 1.0f ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
36
driveruilayer.h
Normal file
36
driveruilayer.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
This Source Code Form is subject to the
|
||||
terms of the Mozilla Public License, v.
|
||||
2.0. If a copy of the MPL was not
|
||||
distributed with this file, You can
|
||||
obtain one at
|
||||
http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "uilayer.h"
|
||||
|
||||
class driver_ui : public ui_layer {
|
||||
|
||||
public:
|
||||
// constructors
|
||||
driver_ui();
|
||||
// methods
|
||||
// potentially processes provided input key. returns: true if the input was processed, false otherwise
|
||||
bool
|
||||
on_key( int const Key, int const Action ) override;
|
||||
// updates state of UI elements
|
||||
void
|
||||
update() override;
|
||||
|
||||
private:
|
||||
// members
|
||||
ui_panel UIHeader { 20, 20 }; // header ui panel
|
||||
ui_panel UITable { 20, 100 };// schedule or scan table
|
||||
ui_panel UITranscripts { 85, 600 }; // voice transcripts
|
||||
int tprev { 0 }; // poprzedni czas
|
||||
double VelPrev { 0.0 }; // poprzednia prędkość
|
||||
double Acc { 0.0 }; // przyspieszenie styczne
|
||||
|
||||
};
|
||||
9
dumb3d.h
9
dumb3d.h
@@ -68,12 +68,13 @@ class vector3
|
||||
vector3( scalar_t X, scalar_t Y, scalar_t Z ) :
|
||||
x( X ), y( Y ), z( Z )
|
||||
{}
|
||||
vector3( glm::dvec3 const &Vector ) :
|
||||
template <typename Type_, glm::precision Precision_>
|
||||
vector3( glm::tvec3<Type_, Precision_> const &Vector ) :
|
||||
x( Vector.x ), y( Vector.y ), z( Vector.z )
|
||||
{}
|
||||
template <glm::precision Precision_>
|
||||
operator glm::tvec3<double, Precision_>() const {
|
||||
return glm::tvec3<double, Precision_>{ x, y, z }; }
|
||||
template <typename Type_, glm::precision Precision_>
|
||||
operator glm::tvec3<Type_, Precision_>() const {
|
||||
return glm::tvec3<Type_, Precision_>{ x, y, z }; }
|
||||
// The int parameter is the number of elements to copy from initArray (3 or 4)
|
||||
// explicit vector3(scalar_t* initArray, int arraySize = 3)
|
||||
// { for (int i = 0;i<arraySize;++i) e[i] = initArray[i]; }
|
||||
|
||||
37
editorkeyboardinput.cpp
Normal file
37
editorkeyboardinput.cpp
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
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 "editorkeyboardinput.h"
|
||||
|
||||
bool
|
||||
editorkeyboard_input::init() {
|
||||
|
||||
default_bindings();
|
||||
// TODO: re-enable after mode-specific binding import is in place
|
||||
// return recall_bindings();
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
editorkeyboard_input::default_bindings() {
|
||||
|
||||
m_bindingsetups = {
|
||||
{ user_command::moveleft, GLFW_KEY_LEFT },
|
||||
{ user_command::moveright, GLFW_KEY_RIGHT },
|
||||
{ user_command::moveforward, GLFW_KEY_UP },
|
||||
{ user_command::moveback, GLFW_KEY_DOWN },
|
||||
{ user_command::moveup, GLFW_KEY_PAGE_UP },
|
||||
{ user_command::movedown, GLFW_KEY_PAGE_DOWN },
|
||||
};
|
||||
|
||||
bind();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
27
editorkeyboardinput.h
Normal file
27
editorkeyboardinput.h
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
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 "keyboardinput.h"
|
||||
|
||||
class editorkeyboard_input : public keyboard_input {
|
||||
|
||||
public:
|
||||
// methods
|
||||
bool
|
||||
init() override;
|
||||
|
||||
protected:
|
||||
// methods
|
||||
void
|
||||
default_bindings() override;
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
278
editormode.cpp
Normal file
278
editormode.cpp
Normal file
@@ -0,0 +1,278 @@
|
||||
/*
|
||||
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 "editormode.h"
|
||||
#include "editoruilayer.h"
|
||||
|
||||
#include "application.h"
|
||||
#include "globals.h"
|
||||
#include "simulation.h"
|
||||
#include "simulationtime.h"
|
||||
#include "simulationenvironment.h"
|
||||
#include "timer.h"
|
||||
#include "console.h"
|
||||
#include "renderer.h"
|
||||
|
||||
bool
|
||||
editor_mode::editormode_input::init() {
|
||||
|
||||
return (
|
||||
mouse.init()
|
||||
&& keyboard.init() );
|
||||
}
|
||||
|
||||
void
|
||||
editor_mode::editormode_input::poll() {
|
||||
|
||||
keyboard.poll();
|
||||
}
|
||||
|
||||
editor_mode::editor_mode() {
|
||||
|
||||
m_userinterface = std::make_shared<editor_ui>();
|
||||
}
|
||||
|
||||
// initializes internal data structures of the mode. returns: true on success, false otherwise
|
||||
bool
|
||||
editor_mode::init() {
|
||||
|
||||
Camera.Init( {}, {}, TCameraType::tp_Free );
|
||||
|
||||
return m_input.init();
|
||||
}
|
||||
|
||||
// mode-specific update of simulation data. returns: false on error, true otherwise
|
||||
bool
|
||||
editor_mode::update() {
|
||||
|
||||
Timer::UpdateTimers( true );
|
||||
|
||||
simulation::State.update_clocks();
|
||||
simulation::Environment.update();
|
||||
|
||||
// render time routines follow:
|
||||
auto const deltarealtime = Timer::GetDeltaRenderTime(); // nie uwzględnia pauzowania ani mnożenia czasu
|
||||
|
||||
// fixed step render time routines:
|
||||
fTime50Hz += deltarealtime; // w pauzie też trzeba zliczać czas, bo przy dużym FPS będzie problem z odczytem ramek
|
||||
while( fTime50Hz >= 1.0 / 50.0 ) {
|
||||
Console::Update(); // to i tak trzeba wywoływać
|
||||
m_userinterface->update();
|
||||
// decelerate camera
|
||||
Camera.Velocity *= 0.65;
|
||||
if( std::abs( Camera.Velocity.x ) < 0.01 ) { Camera.Velocity.x = 0.0; }
|
||||
if( std::abs( Camera.Velocity.y ) < 0.01 ) { Camera.Velocity.y = 0.0; }
|
||||
if( std::abs( Camera.Velocity.z ) < 0.01 ) { Camera.Velocity.z = 0.0; }
|
||||
|
||||
fTime50Hz -= 1.0 / 50.0;
|
||||
}
|
||||
|
||||
// variable step render time routines:
|
||||
update_camera( deltarealtime );
|
||||
|
||||
simulation::Region->update_sounds();
|
||||
audio::renderer.update( deltarealtime );
|
||||
|
||||
GfxRenderer.Update( deltarealtime );
|
||||
|
||||
simulation::is_ready = true;
|
||||
|
||||
m_input.poll();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
editor_mode::update_camera( double const Deltatime ) {
|
||||
|
||||
// uwzględnienie ruchu wywołanego klawiszami
|
||||
Camera.Update();
|
||||
// reset window state, it'll be set again if applicable in a check below
|
||||
Global.CabWindowOpen = false;
|
||||
// all done, update camera position to the new value
|
||||
Global.pCameraPosition = Camera.Pos;
|
||||
}
|
||||
|
||||
// maintenance method, called when the mode is activated
|
||||
void
|
||||
editor_mode::enter() {
|
||||
|
||||
m_statebackup = { Global.pCamera, FreeFlyModeFlag, Global.ControlPicking };
|
||||
|
||||
Global.pCamera = &Camera;
|
||||
FreeFlyModeFlag = true;
|
||||
Global.ControlPicking = true;
|
||||
EditorModeFlag = true;
|
||||
|
||||
Application.set_cursor( GLFW_CURSOR_NORMAL );
|
||||
}
|
||||
|
||||
// maintenance method, called when the mode is deactivated
|
||||
void
|
||||
editor_mode::exit() {
|
||||
|
||||
EditorModeFlag = false;
|
||||
Global.ControlPicking = m_statebackup.picking;
|
||||
FreeFlyModeFlag = m_statebackup.freefly;
|
||||
Global.pCamera = m_statebackup.camera;
|
||||
|
||||
Application.set_cursor(
|
||||
( Global.ControlPicking ?
|
||||
GLFW_CURSOR_NORMAL :
|
||||
GLFW_CURSOR_DISABLED ) );
|
||||
}
|
||||
|
||||
void
|
||||
editor_mode::on_key( int const Key, int const Scancode, int const Action, int const Mods ) {
|
||||
|
||||
Global.shiftState = ( Mods & GLFW_MOD_SHIFT ) ? true : false;
|
||||
Global.ctrlState = ( Mods & GLFW_MOD_CONTROL ) ? true : false;
|
||||
Global.altState = ( Mods & GLFW_MOD_ALT ) ? true : false;
|
||||
|
||||
// give the ui first shot at the input processing...
|
||||
if( true == m_userinterface->on_key( Key, Action ) ) { return; }
|
||||
// ...if the input is left untouched, pass it on
|
||||
if( true == m_input.keyboard.key( Key, Action ) ) { return; }
|
||||
|
||||
if( Action == GLFW_RELEASE ) { return; }
|
||||
|
||||
if( ( Key == GLFW_KEY_LEFT_SHIFT )
|
||||
|| ( Key == GLFW_KEY_LEFT_CONTROL )
|
||||
|| ( Key == GLFW_KEY_LEFT_ALT )
|
||||
|| ( Key == GLFW_KEY_RIGHT_SHIFT )
|
||||
|| ( Key == GLFW_KEY_RIGHT_CONTROL )
|
||||
|| ( Key == GLFW_KEY_RIGHT_ALT ) ) {
|
||||
// don't bother passing these
|
||||
return;
|
||||
}
|
||||
|
||||
// legacy hardcoded keyboard commands
|
||||
// TODO: replace with current command system, move to input object(s)
|
||||
switch( Key ) {
|
||||
|
||||
case GLFW_KEY_F11: {
|
||||
|
||||
if( Action != GLFW_PRESS ) { break; }
|
||||
// mode switch
|
||||
// TODO: unsaved changes warning
|
||||
if( ( false == Global.ctrlState )
|
||||
&& ( false == Global.shiftState ) ) {
|
||||
Application.pop_mode();
|
||||
}
|
||||
// scenery export
|
||||
if( Global.ctrlState
|
||||
&& Global.shiftState ) {
|
||||
simulation::State.export_as_text( Global.SceneryFile );
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case GLFW_KEY_F12: {
|
||||
// quick debug mode toggle
|
||||
if( Global.ctrlState
|
||||
&& Global.shiftState ) {
|
||||
DebugModeFlag = !DebugModeFlag;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
editor_mode::on_cursor_pos( double const Horizontal, double const Vertical ) {
|
||||
|
||||
auto const mousemove { glm::dvec2{ Horizontal, Vertical } - m_input.mouse.position() };
|
||||
m_input.mouse.position( Horizontal, Vertical );
|
||||
|
||||
if( m_input.mouse.button( GLFW_MOUSE_BUTTON_LEFT ) == GLFW_RELEASE ) { return; }
|
||||
if( m_node == nullptr ) { return; }
|
||||
|
||||
if( m_takesnapshot ) {
|
||||
// take a snapshot of selected node(s)
|
||||
// TODO: implement this
|
||||
m_takesnapshot = false;
|
||||
}
|
||||
|
||||
if( mode_translation() ) {
|
||||
// move selected node
|
||||
if( mode_translation_vertical() ) {
|
||||
auto const translation { mousemove.y * -0.01f };
|
||||
m_editor.translate( m_node, translation );
|
||||
}
|
||||
else {
|
||||
auto const mouseworldposition { Camera.Pos + GfxRenderer.Mouse_Position() };
|
||||
m_editor.translate( m_node, mouseworldposition, mode_snap() );
|
||||
}
|
||||
}
|
||||
else {
|
||||
// rotate selected node
|
||||
auto const rotation { glm::vec3 { mousemove.y, mousemove.x, 0 } * 0.25f };
|
||||
auto const quantization { (
|
||||
mode_snap() ?
|
||||
15.f : // TODO: put quantization value in a variable
|
||||
0.f ) };
|
||||
m_editor.rotate( m_node, rotation, quantization );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
editor_mode::on_mouse_button( int const Button, int const Action, int const Mods ) {
|
||||
|
||||
if( Button == GLFW_MOUSE_BUTTON_LEFT ) {
|
||||
|
||||
if( Action == GLFW_PRESS ) {
|
||||
// left button press
|
||||
m_node = GfxRenderer.Update_Pick_Node();
|
||||
if( m_node ) {
|
||||
Application.set_cursor( GLFW_CURSOR_DISABLED );
|
||||
}
|
||||
dynamic_cast<editor_ui*>( m_userinterface.get() )->set_node( m_node );
|
||||
}
|
||||
else {
|
||||
// left button release
|
||||
if( m_node ) {
|
||||
Application.set_cursor( GLFW_CURSOR_NORMAL );
|
||||
}
|
||||
// prime history stack for another snapshot
|
||||
m_takesnapshot = true;
|
||||
}
|
||||
}
|
||||
|
||||
m_input.mouse.button( Button, Action );
|
||||
}
|
||||
|
||||
bool
|
||||
editor_mode::mode_translation() const {
|
||||
|
||||
return ( false == Global.altState );
|
||||
}
|
||||
|
||||
bool
|
||||
editor_mode::mode_translation_vertical() const {
|
||||
|
||||
return ( true == Global.shiftState );
|
||||
}
|
||||
|
||||
bool
|
||||
editor_mode::mode_rotation() const {
|
||||
|
||||
return ( true == Global.altState );
|
||||
}
|
||||
|
||||
bool
|
||||
editor_mode::mode_snap() const {
|
||||
|
||||
return ( true == Global.ctrlState );
|
||||
}
|
||||
84
editormode.h
Normal file
84
editormode.h
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
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 "applicationmode.h"
|
||||
#include "editormouseinput.h"
|
||||
#include "editorkeyboardinput.h"
|
||||
#include "camera.h"
|
||||
#include "sceneeditor.h"
|
||||
#include "scenenode.h"
|
||||
|
||||
class editor_mode : public application_mode {
|
||||
|
||||
public:
|
||||
// constructors
|
||||
editor_mode();
|
||||
// methods
|
||||
// initializes internal data structures of the mode. returns: true on success, false otherwise
|
||||
bool
|
||||
init() override;
|
||||
// mode-specific update of simulation data. returns: false on error, true otherwise
|
||||
bool
|
||||
update() override;
|
||||
// maintenance method, called when the mode is activated
|
||||
void
|
||||
enter() override;
|
||||
// maintenance method, called when the mode is deactivated
|
||||
void
|
||||
exit() override;
|
||||
// input handlers
|
||||
void
|
||||
on_key( int const Key, int const Scancode, int const Action, int const Mods ) override;
|
||||
void
|
||||
on_cursor_pos( double const Horizontal, double const Vertical ) override;
|
||||
void
|
||||
on_mouse_button( int const Button, int const Action, int const Mods ) override;
|
||||
void
|
||||
on_scroll( double const Xoffset, double const Yoffset ) override { ; }
|
||||
|
||||
private:
|
||||
// types
|
||||
struct editormode_input {
|
||||
|
||||
editormouse_input mouse;
|
||||
editorkeyboard_input keyboard;
|
||||
|
||||
bool init();
|
||||
void poll();
|
||||
};
|
||||
|
||||
struct state_backup {
|
||||
|
||||
TCamera *camera;
|
||||
bool freefly;
|
||||
bool picking;
|
||||
};
|
||||
// methods
|
||||
void
|
||||
update_camera( double const Deltatime );
|
||||
bool
|
||||
mode_translation() const;
|
||||
bool
|
||||
mode_translation_vertical() const;
|
||||
bool
|
||||
mode_rotation() const;
|
||||
bool
|
||||
mode_snap() const;
|
||||
// members
|
||||
editormode_input m_input;
|
||||
TCamera Camera;
|
||||
double fTime50Hz { 0.0 }; // bufor czasu dla komunikacji z PoKeys
|
||||
scene::basic_editor m_editor;
|
||||
scene::basic_node *m_node; // currently selected scene node
|
||||
bool m_takesnapshot { true }; // helper, hints whether snapshot of selected node(s) should be taken before modification
|
||||
state_backup m_statebackup; // helper, cached variables to be restored on mode exit
|
||||
|
||||
};
|
||||
55
editormouseinput.cpp
Normal file
55
editormouseinput.cpp
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
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 "editormouseinput.h"
|
||||
|
||||
bool
|
||||
editormouse_input::init() {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
editormouse_input::position( double Horizontal, double Vertical ) {
|
||||
|
||||
if( false == m_pickmodepanning ) {
|
||||
// even if the view panning isn't active we capture the cursor position in case it does get activated
|
||||
m_cursorposition.x = Horizontal;
|
||||
m_cursorposition.y = Vertical;
|
||||
return;
|
||||
}
|
||||
glm::dvec2 cursorposition { Horizontal, Vertical };
|
||||
auto const viewoffset = cursorposition - m_cursorposition;
|
||||
m_relay.post(
|
||||
user_command::viewturn,
|
||||
viewoffset.x,
|
||||
viewoffset.y,
|
||||
GLFW_PRESS,
|
||||
// as we haven't yet implemented either item id system or multiplayer, the 'local' controlled vehicle and entity have temporary ids of 0
|
||||
// TODO: pass correct entity id once the missing systems are in place
|
||||
0 );
|
||||
m_cursorposition = cursorposition;
|
||||
}
|
||||
|
||||
void
|
||||
editormouse_input::button( int const Button, int const Action ) {
|
||||
|
||||
// store key state
|
||||
if( Button >= 0 ) {
|
||||
m_buttons[ Button ] = Action;
|
||||
}
|
||||
|
||||
// right button controls panning
|
||||
if( Button == GLFW_MOUSE_BUTTON_RIGHT ) {
|
||||
m_pickmodepanning = ( Action == GLFW_PRESS );
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
44
editormouseinput.h
Normal file
44
editormouseinput.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
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 "command.h"
|
||||
|
||||
class editormouse_input {
|
||||
|
||||
public:
|
||||
// constructors
|
||||
editormouse_input() = default;
|
||||
|
||||
// methods
|
||||
bool
|
||||
init();
|
||||
void
|
||||
position( double const Horizontal, double const Vertical );
|
||||
inline
|
||||
glm::dvec2
|
||||
position() const {
|
||||
return m_cursorposition; }
|
||||
void
|
||||
button( int const Button, int const Action );
|
||||
inline
|
||||
int
|
||||
button( int const Button ) const {
|
||||
return m_buttons[ Button ]; }
|
||||
|
||||
private:
|
||||
// members
|
||||
command_relay m_relay;
|
||||
bool m_pickmodepanning { false }; // indicates mouse is in view panning mode
|
||||
glm::dvec2 m_cursorposition { 0.0 }; // stored last cursor position, used for panning
|
||||
std::array<int, GLFW_MOUSE_BUTTON_LAST> m_buttons { GLFW_RELEASE };
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
205
editoruilayer.cpp
Normal file
205
editoruilayer.cpp
Normal file
@@ -0,0 +1,205 @@
|
||||
/*
|
||||
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 "editoruilayer.h"
|
||||
|
||||
#include "globals.h"
|
||||
#include "camera.h"
|
||||
#include "animmodel.h"
|
||||
#include "track.h"
|
||||
#include "event.h"
|
||||
#include "renderer.h"
|
||||
#include "utilities.h"
|
||||
#include "logs.h"
|
||||
|
||||
editor_ui::editor_ui() {
|
||||
|
||||
clear_texts();
|
||||
/*
|
||||
UIHeader = std::make_shared<ui_panel>( 20, 20 ); // header ui panel
|
||||
*/
|
||||
// make 4 empty lines for the ui header, to cut down on work down the road
|
||||
UIHeader.text_lines.emplace_back( "", Global.UITextColor );
|
||||
UIHeader.text_lines.emplace_back( "", Global.UITextColor );
|
||||
UIHeader.text_lines.emplace_back( "", Global.UITextColor );
|
||||
UIHeader.text_lines.emplace_back( "", Global.UITextColor );
|
||||
// bind the panels with ui object. maybe not the best place for this but, eh
|
||||
push_back( &UIHeader );
|
||||
}
|
||||
|
||||
// potentially processes provided input key. returns: true if key was processed, false otherwise
|
||||
bool
|
||||
editor_ui::on_key( int const Key, int const Action ) {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// updates state of UI elements
|
||||
void
|
||||
editor_ui::update() {
|
||||
|
||||
std::string uitextline1, uitextline2, uitextline3, uitextline4;
|
||||
set_tooltip( "" );
|
||||
|
||||
auto const *camera { Global.pCamera };
|
||||
|
||||
if( ( true == Global.ControlPicking )
|
||||
&& ( true == DebugModeFlag ) ) {
|
||||
|
||||
auto const scenerynode = GfxRenderer.Pick_Node();
|
||||
set_tooltip(
|
||||
( scenerynode ?
|
||||
scenerynode->name() :
|
||||
"" ) );
|
||||
}
|
||||
|
||||
|
||||
// scenario inspector
|
||||
auto const *node { m_node };
|
||||
|
||||
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 ) + "]";
|
||||
goto update;
|
||||
}
|
||||
|
||||
uitextline1 =
|
||||
"node name: " + node->name()
|
||||
+ "; location: [" + to_string( node->location().x, 2 ) + ", " + to_string( node->location().y, 2 ) + ", " + to_string( node->location().z, 2 ) + "]"
|
||||
+ " (distance: " + to_string( glm::length( glm::dvec3{ node->location().x, 0.0, node->location().z } -glm::dvec3{ Global.pCameraPosition.x, 0.0, Global.pCameraPosition.z } ), 1 ) + " m)";
|
||||
// subclass-specific data
|
||||
// TBD, TODO: specialized data dump method in each node subclass, or data imports in the panel for provided subclass pointer?
|
||||
if( typeid( *node ) == typeid( TAnimModel ) ) {
|
||||
|
||||
auto const *subnode = static_cast<TAnimModel const *>( node );
|
||||
|
||||
uitextline2 = "angle: " + to_string( clamp_circular( subnode->vAngle.y, 360.f ), 2 ) + " deg";
|
||||
uitextline2 += "; lights: ";
|
||||
if( subnode->iNumLights > 0 ) {
|
||||
uitextline2 += '[';
|
||||
for( int lightidx = 0; lightidx < subnode->iNumLights; ++lightidx ) {
|
||||
uitextline2 += to_string( subnode->lsLights[ lightidx ] );
|
||||
if( lightidx < subnode->iNumLights - 1 ) {
|
||||
uitextline2 += ", ";
|
||||
}
|
||||
}
|
||||
uitextline2 += ']';
|
||||
}
|
||||
else {
|
||||
uitextline2 += "none";
|
||||
}
|
||||
// 3d shape
|
||||
auto modelfile { (
|
||||
( subnode->pModel != nullptr ) ?
|
||||
subnode->pModel->NameGet() :
|
||||
"none" ) };
|
||||
if( modelfile.find( szModelPath ) == 0 ) {
|
||||
// don't include 'models/' in the path
|
||||
modelfile.erase( 0, std::string{ szModelPath }.size() );
|
||||
}
|
||||
// texture
|
||||
auto texturefile { (
|
||||
( subnode->Material()->replacable_skins[ 1 ] != null_handle ) ?
|
||||
GfxRenderer.Material( subnode->Material()->replacable_skins[ 1 ] ).name :
|
||||
"none" ) };
|
||||
if( texturefile.find( szTexturePath ) == 0 ) {
|
||||
// don't include 'textures/' in the path
|
||||
texturefile.erase( 0, std::string{ szTexturePath }.size() );
|
||||
}
|
||||
uitextline3 = "mesh: " + modelfile;
|
||||
uitextline4 = "skin: " + texturefile;
|
||||
}
|
||||
else if( typeid( *node ) == typeid( TTrack ) ) {
|
||||
|
||||
auto const *subnode = static_cast<TTrack const *>( node );
|
||||
// basic attributes
|
||||
uitextline2 =
|
||||
"isolated: " + ( ( subnode->pIsolated != nullptr ) ? subnode->pIsolated->asName : "none" )
|
||||
+ "; velocity: " + to_string( subnode->SwitchExtension ? subnode->SwitchExtension->fVelocity : subnode->fVelocity )
|
||||
+ "; width: " + to_string( subnode->fTrackWidth ) + " m"
|
||||
+ "; friction: " + to_string( subnode->fFriction, 2 )
|
||||
+ "; quality: " + to_string( subnode->iQualityFlag );
|
||||
// textures
|
||||
auto texturefile { (
|
||||
( subnode->m_material1 != null_handle ) ?
|
||||
GfxRenderer.Material( subnode->m_material1 ).name :
|
||||
"none" ) };
|
||||
if( texturefile.find( szTexturePath ) == 0 ) {
|
||||
texturefile.erase( 0, std::string{ szTexturePath }.size() );
|
||||
}
|
||||
auto texturefile2{ (
|
||||
( subnode->m_material2 != null_handle ) ?
|
||||
GfxRenderer.Material( subnode->m_material2 ).name :
|
||||
"none" ) };
|
||||
if( texturefile2.find( szTexturePath ) == 0 ) {
|
||||
texturefile2.erase( 0, std::string{ szTexturePath }.size() );
|
||||
}
|
||||
uitextline2 += "; skins: [" + texturefile + ", " + texturefile2 + "]";
|
||||
// paths
|
||||
uitextline3 = "paths: ";
|
||||
for( auto const &path : subnode->m_paths ) {
|
||||
uitextline3 +=
|
||||
"["
|
||||
+ to_string( path.points[ segment_data::point::start ].x, 3 ) + ", "
|
||||
+ to_string( path.points[ segment_data::point::start ].y, 3 ) + ", "
|
||||
+ to_string( path.points[ segment_data::point::start ].z, 3 ) + "]->"
|
||||
+ "["
|
||||
+ to_string( path.points[ segment_data::point::end ].x, 3 ) + ", "
|
||||
+ to_string( path.points[ segment_data::point::end ].y, 3 ) + ", "
|
||||
+ to_string( path.points[ segment_data::point::end ].z, 3 ) + "] ";
|
||||
}
|
||||
// events
|
||||
std::vector< std::pair< std::string, TTrack::event_sequence const * > > const eventsequences {
|
||||
{ "ev0", &subnode->m_events0 }, { "ev0all", &subnode->m_events0all },
|
||||
{ "ev1", &subnode->m_events1 }, { "ev1all", &subnode->m_events1all },
|
||||
{ "ev2", &subnode->m_events2 }, { "ev2all", &subnode->m_events2all } };
|
||||
|
||||
for( auto const &eventsequence : eventsequences ) {
|
||||
|
||||
if( eventsequence.second->empty() ) { continue; }
|
||||
|
||||
uitextline4 += eventsequence.first + ": [";
|
||||
for( auto const &event : *( eventsequence.second ) ) {
|
||||
if( uitextline4.back() != '[' ) {
|
||||
uitextline4 += ", ";
|
||||
}
|
||||
if( event.second ) {
|
||||
uitextline4 += event.second->asName;
|
||||
}
|
||||
}
|
||||
uitextline4 += "] ";
|
||||
}
|
||||
|
||||
}
|
||||
else if( typeid( *node ) == typeid( TMemCell ) ) {
|
||||
|
||||
auto const *subnode = static_cast<TMemCell const *>( node );
|
||||
|
||||
uitextline2 =
|
||||
"data: [" + subnode->Text() + "]"
|
||||
+ " [" + to_string( subnode->Value1(), 2 ) + "]"
|
||||
+ " [" + to_string( subnode->Value2(), 2 ) + "]";
|
||||
uitextline3 = "track: " + ( subnode->asTrackName.empty() ? "none" : subnode->asTrackName );
|
||||
}
|
||||
|
||||
update:
|
||||
// update the ui header texts
|
||||
auto &headerdata = UIHeader.text_lines;
|
||||
headerdata[ 0 ].data = uitextline1;
|
||||
headerdata[ 1 ].data = uitextline2;
|
||||
headerdata[ 2 ].data = uitextline3;
|
||||
headerdata[ 3 ].data = uitextline4;
|
||||
}
|
||||
|
||||
void
|
||||
editor_ui::set_node( scene::basic_node * Node ) {
|
||||
|
||||
m_node = Node;
|
||||
}
|
||||
39
editoruilayer.h
Normal file
39
editoruilayer.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
This Source Code Form is subject to the
|
||||
terms of the Mozilla Public License, v.
|
||||
2.0. If a copy of the MPL was not
|
||||
distributed with this file, You can
|
||||
obtain one at
|
||||
http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "uilayer.h"
|
||||
|
||||
namespace scene {
|
||||
|
||||
class basic_node;
|
||||
|
||||
}
|
||||
|
||||
class editor_ui : public ui_layer {
|
||||
|
||||
public:
|
||||
// constructors
|
||||
editor_ui();
|
||||
// methods
|
||||
// potentially processes provided input key. returns: true if the input was processed, false otherwise
|
||||
bool
|
||||
on_key( int const Key, int const Action ) override;
|
||||
// updates state of UI elements
|
||||
void
|
||||
update() override;
|
||||
void
|
||||
set_node( scene::basic_node * Node );
|
||||
|
||||
private:
|
||||
// members
|
||||
ui_panel UIHeader { 20, 20 }; // header ui panel
|
||||
scene::basic_node * m_node { nullptr }; // currently bound scene node, if any
|
||||
};
|
||||
@@ -13,6 +13,15 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "logs.h"
|
||||
#include "parser.h"
|
||||
|
||||
namespace input {
|
||||
|
||||
std::array<char, GLFW_KEY_LAST + 1> keys { GLFW_RELEASE };
|
||||
bool key_alt;
|
||||
bool key_ctrl;
|
||||
bool key_shift;
|
||||
|
||||
}
|
||||
|
||||
bool
|
||||
keyboard_input::recall_bindings() {
|
||||
|
||||
@@ -94,7 +103,7 @@ keyboard_input::recall_bindings() {
|
||||
}
|
||||
|
||||
if( ( binding & 0xffff ) != 0 ) {
|
||||
m_commands.at( static_cast<std::size_t>( lookup->second ) ).binding = binding;
|
||||
m_bindingsetups.emplace_back( binding_setup{ lookup->second, binding } );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -113,7 +122,7 @@ keyboard_input::key( int const Key, int const Action ) {
|
||||
|
||||
if( ( Key == GLFW_KEY_LEFT_SHIFT ) || ( Key == GLFW_KEY_RIGHT_SHIFT ) ) {
|
||||
// update internal state, but don't bother passing these
|
||||
m_shift =
|
||||
input::key_shift =
|
||||
( Action == GLFW_RELEASE ?
|
||||
false :
|
||||
true );
|
||||
@@ -122,20 +131,23 @@ keyboard_input::key( int const Key, int const Action ) {
|
||||
}
|
||||
if( ( Key == GLFW_KEY_LEFT_CONTROL ) || ( Key == GLFW_KEY_RIGHT_CONTROL ) ) {
|
||||
// update internal state, but don't bother passing these
|
||||
m_ctrl =
|
||||
input::key_ctrl =
|
||||
( Action == GLFW_RELEASE ?
|
||||
false :
|
||||
true );
|
||||
modifier = true;
|
||||
}
|
||||
if( ( Key == GLFW_KEY_LEFT_ALT ) || ( Key == GLFW_KEY_RIGHT_ALT ) ) {
|
||||
// currently we have no interest in these whatsoever
|
||||
return false;
|
||||
// update internal state, but don't bother passing these
|
||||
input::key_alt =
|
||||
( Action == GLFW_RELEASE ?
|
||||
false :
|
||||
true );
|
||||
}
|
||||
|
||||
// store key state
|
||||
if( Key != -1 ) {
|
||||
m_keys[ Key ] = Action;
|
||||
input::keys[ Key ] = Action;
|
||||
}
|
||||
|
||||
if( true == is_movement_key( Key ) ) {
|
||||
@@ -146,8 +158,8 @@ keyboard_input::key( int const Key, int const Action ) {
|
||||
// include active modifiers for currently pressed key, except if the key is a modifier itself
|
||||
auto const key =
|
||||
Key
|
||||
| ( modifier ? 0 : ( m_shift ? keymodifier::shift : 0 ) )
|
||||
| ( modifier ? 0 : ( m_ctrl ? keymodifier::control : 0 ) );
|
||||
| ( modifier ? 0 : ( input::key_shift ? keymodifier::shift : 0 ) )
|
||||
| ( modifier ? 0 : ( input::key_ctrl ? keymodifier::control : 0 ) );
|
||||
|
||||
auto const lookup = m_bindings.find( key );
|
||||
if( lookup == m_bindings.end() ) {
|
||||
@@ -166,384 +178,10 @@ keyboard_input::key( int const Key, int const Action ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
keyboard_input::default_bindings() {
|
||||
|
||||
m_commands = {
|
||||
// aidriverenable
|
||||
{ GLFW_KEY_Q | keymodifier::shift },
|
||||
// aidriverdisable
|
||||
{ GLFW_KEY_Q },
|
||||
// mastercontrollerincrease
|
||||
{ GLFW_KEY_KP_ADD },
|
||||
// mastercontrollerincreasefast
|
||||
{ GLFW_KEY_KP_ADD | keymodifier::shift },
|
||||
// mastercontrollerdecrease
|
||||
{ GLFW_KEY_KP_SUBTRACT },
|
||||
// mastercontrollerdecreasefast
|
||||
{ GLFW_KEY_KP_SUBTRACT | keymodifier::shift },
|
||||
// mastercontrollerset
|
||||
{ -1 },
|
||||
// secondcontrollerincrease
|
||||
{ GLFW_KEY_KP_DIVIDE },
|
||||
// secondcontrollerincreasefast
|
||||
{ GLFW_KEY_KP_DIVIDE | keymodifier::shift },
|
||||
// secondcontrollerdecrease
|
||||
{ GLFW_KEY_KP_MULTIPLY },
|
||||
// secondcontrollerdecreasefast
|
||||
{ GLFW_KEY_KP_MULTIPLY | keymodifier::shift },
|
||||
// secondcontrollerset
|
||||
{ -1 },
|
||||
// mucurrentindicatorothersourceactivate
|
||||
{ GLFW_KEY_Z | keymodifier::shift },
|
||||
// independentbrakeincrease
|
||||
{ GLFW_KEY_KP_1 },
|
||||
// independentbrakeincreasefast
|
||||
{ GLFW_KEY_KP_1 | keymodifier::shift },
|
||||
// independentbrakedecrease
|
||||
{ GLFW_KEY_KP_7 },
|
||||
// independentbrakedecreasefast
|
||||
{ GLFW_KEY_KP_7 | keymodifier::shift },
|
||||
// independentbrakeset
|
||||
{ -1 },
|
||||
// independentbrakebailoff
|
||||
{ GLFW_KEY_KP_4 },
|
||||
// trainbrakeincrease
|
||||
{ GLFW_KEY_KP_3 },
|
||||
// trainbrakedecrease
|
||||
{ GLFW_KEY_KP_9 },
|
||||
// trainbrakeset
|
||||
{ -1 },
|
||||
// trainbrakecharging
|
||||
{ GLFW_KEY_KP_DECIMAL },
|
||||
// trainbrakerelease
|
||||
{ GLFW_KEY_KP_6 },
|
||||
// trainbrakefirstservice
|
||||
{ GLFW_KEY_KP_8 },
|
||||
// trainbrakeservice
|
||||
{ GLFW_KEY_KP_5 },
|
||||
// trainbrakefullservice
|
||||
{ GLFW_KEY_KP_2 },
|
||||
// trainbrakehandleoff
|
||||
{ GLFW_KEY_KP_5 | keymodifier::control },
|
||||
// trainbrakeemergency
|
||||
{ GLFW_KEY_KP_0 },
|
||||
// trainbrakebasepressureincrease
|
||||
{ GLFW_KEY_KP_3 | keymodifier::control },
|
||||
// trainbrakebasepressuredecrease
|
||||
{ GLFW_KEY_KP_9 | keymodifier::control },
|
||||
// trainbrakebasepressurereset
|
||||
{ GLFW_KEY_KP_6 | keymodifier::control },
|
||||
// trainbrakeoperationtoggle
|
||||
{ GLFW_KEY_KP_4 | keymodifier::control },
|
||||
// manualbrakeincrease
|
||||
{ GLFW_KEY_KP_1 | keymodifier::control },
|
||||
// manualbrakedecrease
|
||||
{ GLFW_KEY_KP_7 | keymodifier::control },
|
||||
// alarm chain toggle
|
||||
{ GLFW_KEY_B | keymodifier::shift | keymodifier::control },
|
||||
// wheelspinbrakeactivate
|
||||
{ GLFW_KEY_KP_ENTER },
|
||||
// sandboxactivate
|
||||
{ GLFW_KEY_S },
|
||||
// reverserincrease
|
||||
{ GLFW_KEY_D },
|
||||
// reverserdecrease
|
||||
{ GLFW_KEY_R },
|
||||
// reverserforwardhigh
|
||||
{ -1 },
|
||||
// reverserforward
|
||||
{ -1 },
|
||||
// reverserneutral
|
||||
{ -1 },
|
||||
// reverserbackward
|
||||
{ -1 },
|
||||
// waterpumpbreakertoggle
|
||||
{ GLFW_KEY_W | keymodifier::control },
|
||||
// waterpumpbreakerclose
|
||||
{ -1 },
|
||||
// waterpumpbreakeropen
|
||||
{ -1 },
|
||||
// waterpumptoggle
|
||||
{ GLFW_KEY_W },
|
||||
// waterpumpenable
|
||||
{ -1 },
|
||||
// waterpumpdisable
|
||||
{ -1 },
|
||||
// waterheaterbreakertoggle
|
||||
{ GLFW_KEY_W | keymodifier::control | keymodifier::shift },
|
||||
// waterheaterbreakerclose
|
||||
{ -1 },
|
||||
// waterheaterbreakeropen
|
||||
{ -1 },
|
||||
// waterheatertoggle
|
||||
{ GLFW_KEY_W | keymodifier::shift },
|
||||
// waterheaterenable
|
||||
{ -1 },
|
||||
// waterheaterdisable
|
||||
{ -1 },
|
||||
// watercircuitslinktoggle
|
||||
{ GLFW_KEY_H | keymodifier::shift },
|
||||
// watercircuitslinkenable
|
||||
{ -1 },
|
||||
// watercircuitslinkdisable
|
||||
{ -1 },
|
||||
// fuelpumptoggle
|
||||
{ GLFW_KEY_F },
|
||||
// fuelpumpenable,
|
||||
{ -1 },
|
||||
// fuelpumpdisable,
|
||||
{ -1 },
|
||||
// oilpumptoggle
|
||||
{ GLFW_KEY_F | keymodifier::shift },
|
||||
// oilpumpenable,
|
||||
{ -1 },
|
||||
// oilpumpdisable,
|
||||
{ -1 },
|
||||
// linebreakertoggle
|
||||
{ GLFW_KEY_M },
|
||||
// linebreakeropen
|
||||
{ -1 },
|
||||
// linebreakerclose
|
||||
{ -1 },
|
||||
// convertertoggle
|
||||
{ GLFW_KEY_X },
|
||||
// converterenable,
|
||||
{ -1 },
|
||||
// converterdisable,
|
||||
{ -1 },
|
||||
// convertertogglelocal
|
||||
{ GLFW_KEY_X | keymodifier::shift },
|
||||
// converteroverloadrelayreset
|
||||
{ GLFW_KEY_N | keymodifier::control },
|
||||
// compressortoggle
|
||||
{ GLFW_KEY_C },
|
||||
// compressorenable
|
||||
{ -1 },
|
||||
// compressordisable
|
||||
{ -1 },
|
||||
// compressortoggleloal
|
||||
{ GLFW_KEY_C | keymodifier::shift },
|
||||
// motoroverloadrelaythresholdtoggle
|
||||
{ GLFW_KEY_F },
|
||||
// motoroverloadrelaythresholdsetlow
|
||||
{ -1 },
|
||||
// motoroverloadrelaythresholdsethigh
|
||||
{ -1 },
|
||||
// motoroverloadrelayreset
|
||||
{ GLFW_KEY_N },
|
||||
// notchingrelaytoggle
|
||||
{ GLFW_KEY_G },
|
||||
// epbrakecontroltoggle
|
||||
{ GLFW_KEY_Z | keymodifier::control },
|
||||
// trainbrakeoperationmodeincrease
|
||||
{ GLFW_KEY_KP_2 | keymodifier::control },
|
||||
// trainbrakeoperationmodedecrease
|
||||
{ GLFW_KEY_KP_8 | keymodifier::control },
|
||||
// brakeactingspeedincrease
|
||||
{ GLFW_KEY_B | keymodifier::shift },
|
||||
// brakeactingspeeddecrease
|
||||
{ GLFW_KEY_B },
|
||||
// brakeactingspeedsetcargo
|
||||
{ -1 },
|
||||
// brakeactingspeedsetpassenger
|
||||
{ -1 },
|
||||
// brakeactingspeedsetrapid
|
||||
{ -1 },
|
||||
// brakeloadcompensationincrease
|
||||
{ GLFW_KEY_H | keymodifier::shift | keymodifier::control },
|
||||
// brakeloadcompensationdecrease
|
||||
{ GLFW_KEY_H | keymodifier::control },
|
||||
// mubrakingindicatortoggle
|
||||
{ GLFW_KEY_L | keymodifier::shift },
|
||||
// alerteracknowledge
|
||||
{ GLFW_KEY_SPACE },
|
||||
// hornlowactivate
|
||||
{ GLFW_KEY_A },
|
||||
// hornhighactivate
|
||||
{ GLFW_KEY_S },
|
||||
// whistleactivate
|
||||
{ GLFW_KEY_Z },
|
||||
// radiotoggle
|
||||
{ GLFW_KEY_R | keymodifier::control },
|
||||
// radiochannelincrease
|
||||
{ GLFW_KEY_R | keymodifier::shift },
|
||||
// radiochanneldecrease
|
||||
{ GLFW_KEY_R },
|
||||
// radiostopsend
|
||||
{ GLFW_KEY_PAUSE | keymodifier::shift | keymodifier::control },
|
||||
// radiostoptest
|
||||
{ GLFW_KEY_R | keymodifier::shift | keymodifier::control },
|
||||
// cabchangeforward
|
||||
{ GLFW_KEY_HOME },
|
||||
// cabchangebackward
|
||||
{ GLFW_KEY_END },
|
||||
// viewturn
|
||||
{ -1 },
|
||||
// movehorizontal
|
||||
{ -1 },
|
||||
// movehorizontalfast
|
||||
{ -1 },
|
||||
// movevertical
|
||||
{ -1 },
|
||||
// moveverticalfast
|
||||
{ -1 },
|
||||
// moveleft
|
||||
{ GLFW_KEY_LEFT },
|
||||
// moveright
|
||||
{ GLFW_KEY_RIGHT },
|
||||
// moveforward
|
||||
{ GLFW_KEY_UP },
|
||||
// moveback
|
||||
{ GLFW_KEY_DOWN },
|
||||
// moveup
|
||||
{ GLFW_KEY_PAGE_UP },
|
||||
// movedown
|
||||
{ GLFW_KEY_PAGE_DOWN },
|
||||
// carcouplingincrease
|
||||
{ GLFW_KEY_INSERT },
|
||||
// carcouplingdisconnect
|
||||
{ GLFW_KEY_DELETE },
|
||||
// doortoggleleft
|
||||
{ GLFW_KEY_COMMA },
|
||||
// doortoggleright
|
||||
{ GLFW_KEY_PERIOD },
|
||||
// departureannounce
|
||||
{ GLFW_KEY_SLASH },
|
||||
// doorlocktoggle
|
||||
{ GLFW_KEY_S | keymodifier::shift },
|
||||
// pantographcompressorvalvetoggle
|
||||
{ GLFW_KEY_V | keymodifier::control },
|
||||
// pantographcompressoractivate
|
||||
{ GLFW_KEY_V | keymodifier::shift },
|
||||
// pantographtogglefront
|
||||
{ GLFW_KEY_P },
|
||||
// pantographtogglerear
|
||||
{ GLFW_KEY_O },
|
||||
// pantographraisefront
|
||||
{ -1 },
|
||||
// pantographraiserear
|
||||
{ -1 },
|
||||
// pantographlowerfront
|
||||
{ -1 },
|
||||
// pantographlowerrear
|
||||
{ -1 },
|
||||
// pantographlowerall
|
||||
{ GLFW_KEY_P | keymodifier::control },
|
||||
// heatingtoggle
|
||||
{ GLFW_KEY_H },
|
||||
// heatingenable
|
||||
{ -1 },
|
||||
// heatingdisable
|
||||
{ -1 },
|
||||
// lightspresetactivatenext
|
||||
{ GLFW_KEY_T | keymodifier::shift },
|
||||
// lightspresetactivateprevious
|
||||
{ GLFW_KEY_T },
|
||||
// headlighttoggleleft
|
||||
{ GLFW_KEY_Y },
|
||||
// headlightenableleft
|
||||
{ -1 },
|
||||
// headlightdisableleft
|
||||
{ -1 },
|
||||
// headlighttoggleright
|
||||
{ GLFW_KEY_I },
|
||||
// headlightenableright
|
||||
{ -1 },
|
||||
// headlightdisableright
|
||||
{ -1 },
|
||||
// headlighttoggleupper
|
||||
{ GLFW_KEY_U },
|
||||
// headlightenableupper
|
||||
{ -1 },
|
||||
// headlightdisableupper
|
||||
{ -1 },
|
||||
// redmarkertoggleleft
|
||||
{ GLFW_KEY_Y | keymodifier::shift },
|
||||
// redmarkerenableleft
|
||||
{ -1 },
|
||||
// redmarkerdisableleft
|
||||
{ -1 },
|
||||
// redmarkertoggleright
|
||||
{ GLFW_KEY_I | keymodifier::shift },
|
||||
// redmarkerenableright
|
||||
{ -1 },
|
||||
// redmarkerdisableright
|
||||
{ -1 },
|
||||
// headlighttogglerearleft
|
||||
{ GLFW_KEY_Y | keymodifier::control },
|
||||
// headlighttogglerearright
|
||||
{ GLFW_KEY_I | keymodifier::control },
|
||||
// headlighttogglerearupper
|
||||
{ GLFW_KEY_U | keymodifier::control },
|
||||
// redmarkertogglerearleft
|
||||
{ GLFW_KEY_Y | keymodifier::control | keymodifier::shift },
|
||||
// redmarkertogglerearright
|
||||
{ GLFW_KEY_I | keymodifier::control | keymodifier::shift },
|
||||
// redmarkerstoggle
|
||||
{ GLFW_KEY_E | keymodifier::shift },
|
||||
// endsignalstoggle
|
||||
{ GLFW_KEY_E },
|
||||
// headlightsdimtoggle
|
||||
{ GLFW_KEY_L | keymodifier::control },
|
||||
// headlightsdimenable
|
||||
{ -1 },
|
||||
// headlightsdimdisable
|
||||
{ -1 },
|
||||
// motorconnectorsopen
|
||||
{ GLFW_KEY_L },
|
||||
// motorconnectorsclose
|
||||
{ -1 },
|
||||
// motordisconnect
|
||||
{ GLFW_KEY_E | keymodifier::control },
|
||||
// interiorlighttoggle
|
||||
{ GLFW_KEY_APOSTROPHE },
|
||||
// interiorlightenable
|
||||
{ -1 },
|
||||
// interiorlightdisable
|
||||
{ -1 },
|
||||
// interiorlightdimtoggle
|
||||
{ GLFW_KEY_APOSTROPHE | keymodifier::control },
|
||||
// interiorlightdimenable
|
||||
{ -1 },
|
||||
// interiorlightdimdisable
|
||||
{ -1 },
|
||||
// instrumentlighttoggle
|
||||
{ GLFW_KEY_SEMICOLON },
|
||||
// instrumentlightenable
|
||||
{ -1 },
|
||||
// instrumentlightdisable,
|
||||
{ -1 },
|
||||
// "generictoggle0"
|
||||
{ GLFW_KEY_0 },
|
||||
// "generictoggle1"
|
||||
{ GLFW_KEY_1 },
|
||||
// "generictoggle2"
|
||||
{ GLFW_KEY_2 },
|
||||
// "generictoggle3"
|
||||
{ GLFW_KEY_3 },
|
||||
// "generictoggle4"
|
||||
{ GLFW_KEY_4 },
|
||||
// "generictoggle5"
|
||||
{ GLFW_KEY_5 },
|
||||
// "generictoggle6"
|
||||
{ GLFW_KEY_6 },
|
||||
// "generictoggle7"
|
||||
{ GLFW_KEY_7 },
|
||||
// "generictoggle8"
|
||||
{ GLFW_KEY_8 },
|
||||
// "generictoggle9"
|
||||
{ GLFW_KEY_9 },
|
||||
// "batterytoggle"
|
||||
{ GLFW_KEY_J },
|
||||
// batteryenable
|
||||
{ -1 },
|
||||
// batterydisable
|
||||
{ -1 },
|
||||
};
|
||||
|
||||
bind();
|
||||
int
|
||||
keyboard_input::key( int const Key ) const {
|
||||
|
||||
return input::keys[ Key ];
|
||||
}
|
||||
|
||||
void
|
||||
@@ -551,23 +189,32 @@ keyboard_input::bind() {
|
||||
|
||||
m_bindings.clear();
|
||||
|
||||
int commandcode{ 0 };
|
||||
for( auto const &command : m_commands ) {
|
||||
for( auto const &bindingsetup : m_bindingsetups ) {
|
||||
|
||||
if( command.binding != -1 ) {
|
||||
if( bindingsetup.binding != -1 ) {
|
||||
m_bindings.emplace(
|
||||
command.binding,
|
||||
static_cast<user_command>( commandcode ) );
|
||||
bindingsetup.binding,
|
||||
bindingsetup.command );
|
||||
}
|
||||
++commandcode;
|
||||
}
|
||||
// cache movement key bindings
|
||||
m_bindingscache.forward = m_commands[ static_cast<std::size_t>( user_command::moveforward ) ].binding;
|
||||
m_bindingscache.back = m_commands[ static_cast<std::size_t>( user_command::moveback ) ].binding;
|
||||
m_bindingscache.left = m_commands[ static_cast<std::size_t>( user_command::moveleft ) ].binding;
|
||||
m_bindingscache.right = m_commands[ static_cast<std::size_t>( user_command::moveright ) ].binding;
|
||||
m_bindingscache.up = m_commands[ static_cast<std::size_t>( user_command::moveup ) ].binding;
|
||||
m_bindingscache.down = m_commands[ static_cast<std::size_t>( user_command::movedown ) ].binding;
|
||||
m_bindingscache.forward = binding( user_command::moveforward );
|
||||
m_bindingscache.back = binding( user_command::moveback );
|
||||
m_bindingscache.left = binding( user_command::moveleft );
|
||||
m_bindingscache.right = binding( user_command::moveright );
|
||||
m_bindingscache.up = binding( user_command::moveup );
|
||||
m_bindingscache.down = binding( user_command::movedown );
|
||||
}
|
||||
|
||||
int
|
||||
keyboard_input::binding( user_command const Command ) const {
|
||||
|
||||
for( auto const &binding : m_bindings ) {
|
||||
if( binding.second == Command ) {
|
||||
return binding.first;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -590,13 +237,13 @@ keyboard_input::poll() {
|
||||
glm::vec2 const movementhorizontal {
|
||||
// x-axis
|
||||
( Global.shiftState ? 1.f : 0.5f ) *
|
||||
( m_keys[ m_bindingscache.left ] != GLFW_RELEASE ? -1.f :
|
||||
m_keys[ m_bindingscache.right ] != GLFW_RELEASE ? 1.f :
|
||||
( input::keys[ m_bindingscache.left ] != GLFW_RELEASE ? -1.f :
|
||||
input::keys[ m_bindingscache.right ] != GLFW_RELEASE ? 1.f :
|
||||
0.f ),
|
||||
// z-axis
|
||||
( Global.shiftState ? 1.f : 0.5f ) *
|
||||
( m_keys[ m_bindingscache.forward ] != GLFW_RELEASE ? 1.f :
|
||||
m_keys[ m_bindingscache.back ] != GLFW_RELEASE ? -1.f :
|
||||
( input::keys[ m_bindingscache.forward ] != GLFW_RELEASE ? 1.f :
|
||||
input::keys[ m_bindingscache.back ] != GLFW_RELEASE ? -1.f :
|
||||
0.f ) };
|
||||
|
||||
if( ( movementhorizontal.x != 0.f || movementhorizontal.y != 0.f )
|
||||
@@ -616,8 +263,8 @@ keyboard_input::poll() {
|
||||
float const movementvertical {
|
||||
// y-axis
|
||||
( Global.shiftState ? 1.f : 0.5f ) *
|
||||
( m_keys[ m_bindingscache.up ] != GLFW_RELEASE ? 1.f :
|
||||
m_keys[ m_bindingscache.down ] != GLFW_RELEASE ? -1.f :
|
||||
( input::keys[ m_bindingscache.up ] != GLFW_RELEASE ? 1.f :
|
||||
input::keys[ m_bindingscache.down ] != GLFW_RELEASE ? -1.f :
|
||||
0.f ) };
|
||||
|
||||
if( ( movementvertical != 0.f )
|
||||
|
||||
@@ -13,19 +13,32 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include <array>
|
||||
#include "command.h"
|
||||
|
||||
namespace input {
|
||||
|
||||
extern std::array<char, GLFW_KEY_LAST + 1> keys;
|
||||
extern bool key_alt;
|
||||
extern bool key_ctrl;
|
||||
extern bool key_shift;
|
||||
|
||||
}
|
||||
|
||||
class keyboard_input {
|
||||
|
||||
public:
|
||||
// constructors
|
||||
keyboard_input() { default_bindings(); }
|
||||
keyboard_input() = default;
|
||||
|
||||
// destructor
|
||||
virtual ~keyboard_input() = default;
|
||||
|
||||
// methods
|
||||
virtual
|
||||
bool
|
||||
init() { return recall_bindings(); }
|
||||
bool
|
||||
recall_bindings();
|
||||
init() { return true; }
|
||||
bool
|
||||
key( int const Key, int const Action );
|
||||
int
|
||||
key( int const Key ) const;
|
||||
void
|
||||
poll();
|
||||
inline
|
||||
@@ -33,7 +46,7 @@ public:
|
||||
command() const {
|
||||
return m_command; }
|
||||
|
||||
private:
|
||||
protected:
|
||||
// types
|
||||
enum keymodifier : int {
|
||||
|
||||
@@ -41,13 +54,29 @@ private:
|
||||
control = 0x20000
|
||||
};
|
||||
|
||||
struct command_setup {
|
||||
struct binding_setup {
|
||||
|
||||
user_command command;
|
||||
int binding;
|
||||
};
|
||||
|
||||
typedef std::vector<command_setup> commandsetup_sequence;
|
||||
typedef std::unordered_map<int, user_command> usercommand_map;
|
||||
using bindingsetup_sequence = std::vector<binding_setup>;
|
||||
|
||||
// methods
|
||||
virtual
|
||||
void
|
||||
default_bindings() = 0;
|
||||
bool
|
||||
recall_bindings();
|
||||
void
|
||||
bind();
|
||||
|
||||
// members
|
||||
bindingsetup_sequence m_bindingsetups;
|
||||
|
||||
private:
|
||||
// types
|
||||
using usercommand_map = std::unordered_map<int, user_command>;
|
||||
|
||||
struct bindings_cache {
|
||||
|
||||
@@ -60,24 +89,18 @@ private:
|
||||
};
|
||||
|
||||
// methods
|
||||
void
|
||||
default_bindings();
|
||||
void
|
||||
bind();
|
||||
int
|
||||
binding( user_command const Command ) const;
|
||||
bool
|
||||
is_movement_key( int const Key ) const;
|
||||
|
||||
// members
|
||||
commandsetup_sequence m_commands;
|
||||
user_command m_command { user_command::none }; // last, if any, issued command
|
||||
usercommand_map m_bindings;
|
||||
command_relay m_relay;
|
||||
bool m_shift { false };
|
||||
bool m_ctrl { false };
|
||||
bindings_cache m_bindingscache;
|
||||
glm::vec2 m_movementhorizontal { 0.f };
|
||||
float m_movementvertical { 0.f };
|
||||
std::array<char, GLFW_KEY_LAST + 1> m_keys;
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
@@ -19,11 +19,35 @@
|
||||
<Filter Include="Header Files\mczapkie">
|
||||
<UniqueIdentifier>{36684428-8a48-435f-bca4-a24d9bfe2587}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\input">
|
||||
<UniqueIdentifier>{cdf75bec-91f7-413c-8b57-9e32cba49148}</UniqueIdentifier>
|
||||
<Filter Include="Header Files\application">
|
||||
<UniqueIdentifier>{035056ae-b8d6-4338-9d1f-514a0ce5f1e0}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\input">
|
||||
<UniqueIdentifier>{2d73d7b2-5252-499c-963a-88fa3cb1af53}</UniqueIdentifier>
|
||||
<Filter Include="Source Files\application">
|
||||
<UniqueIdentifier>{395be8b7-094b-4e4d-918e-02369cd6013b}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\application\mode_driver">
|
||||
<UniqueIdentifier>{1ea7a1f1-5728-478c-8593-b6f4eecefdbf}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\application\mode_editor">
|
||||
<UniqueIdentifier>{89843d2c-930c-4135-8575-714040f117ac}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\application\mode_scenarioloader">
|
||||
<UniqueIdentifier>{ab9c6f13-eb8f-497b-b21d-66f8c0220cf8}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\application\mode_driver">
|
||||
<UniqueIdentifier>{492181c1-fa1a-4087-be99-5d88edf66c69}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\application\mode_editor">
|
||||
<UniqueIdentifier>{e8c50720-4d83-4722-8ac9-16ea6af834b5}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\application\mode_scenarioloader">
|
||||
<UniqueIdentifier>{ecadb5ae-48aa-4811-909d-56e8a01badb2}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\application\input">
|
||||
<UniqueIdentifier>{ba04e497-9bfa-4cfd-883f-7f018ac76301}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\application\input">
|
||||
<UniqueIdentifier>{0630616b-1afe-4fb6-96d1-3755834ba8aa}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
@@ -120,27 +144,18 @@
|
||||
<ClCompile Include="TrkFoll.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="World.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="mczapkie\friction.cpp">
|
||||
<Filter>Source Files\mczapkie</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="mczapkie\hamulce.cpp">
|
||||
<Filter>Source Files\mczapkie</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="console\LPT.cpp">
|
||||
<Filter>Source Files\input</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="mczapkie\Mover.cpp">
|
||||
<Filter>Source Files\mczapkie</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="mczapkie\Oerlikon_ESt.cpp">
|
||||
<Filter>Source Files\mczapkie</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="console\PoKeys55.cpp">
|
||||
<Filter>Source Files\input</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="stdafx.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
@@ -180,21 +195,12 @@
|
||||
<ClCompile Include="moon.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="gamepadinput.cpp">
|
||||
<Filter>Source Files\input</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="keyboardinput.cpp">
|
||||
<Filter>Source Files\input</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="command.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="openglgeometrybank.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="mouseinput.cpp">
|
||||
<Filter>Source Files\input</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="translation.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
@@ -231,27 +237,72 @@
|
||||
<ClCompile Include="utilities.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="uart.cpp">
|
||||
<Filter>Source Files\input</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="station.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="stb_vorbis.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="sceneeditor.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="simulationtime.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="application.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="eu07.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="application.cpp">
|
||||
<Filter>Source Files\application</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="simulationstateserializer.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="simulationenvironment.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="sceneeditor.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="drivermode.cpp">
|
||||
<Filter>Source Files\application\mode_driver</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="driveruilayer.cpp">
|
||||
<Filter>Source Files\application\mode_driver</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="editoruilayer.cpp">
|
||||
<Filter>Source Files\application\mode_editor</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="editormode.cpp">
|
||||
<Filter>Source Files\application\mode_editor</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="scenarioloadermode.cpp">
|
||||
<Filter>Source Files\application\mode_scenarioloader</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="driverkeyboardinput.cpp">
|
||||
<Filter>Source Files\application\mode_driver</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="drivermouseinput.cpp">
|
||||
<Filter>Source Files\application\mode_driver</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="editormouseinput.cpp">
|
||||
<Filter>Source Files\application\mode_editor</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="gamepadinput.cpp">
|
||||
<Filter>Source Files\application\mode_driver</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="console\LPT.cpp">
|
||||
<Filter>Source Files\application\mode_driver</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="console\PoKeys55.cpp">
|
||||
<Filter>Source Files\application\mode_driver</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="uart.cpp">
|
||||
<Filter>Source Files\application\mode_driver</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="editorkeyboardinput.cpp">
|
||||
<Filter>Source Files\application\mode_editor</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="keyboardinput.cpp">
|
||||
<Filter>Source Files\application\input</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Globals.h">
|
||||
@@ -266,9 +317,6 @@
|
||||
<ClInclude Include="McZapkie\mover.h">
|
||||
<Filter>Header Files\mczapkie</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="World.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="dumb3d.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
@@ -317,12 +365,6 @@
|
||||
<ClInclude Include="McZapkie\friction.h">
|
||||
<Filter>Header Files\mczapkie</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Console\PoKeys55.h">
|
||||
<Filter>Header Files\input</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Console\LPT.h">
|
||||
<Filter>Header Files\input</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Segment.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
@@ -419,21 +461,12 @@
|
||||
<ClInclude Include="command.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="keyboardinput.h">
|
||||
<Filter>Header Files\input</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="gamepadinput.h">
|
||||
<Filter>Header Files\input</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="version.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="openglgeometrybank.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="mouseinput.h">
|
||||
<Filter>Header Files\input</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="translation.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
@@ -473,21 +506,72 @@
|
||||
<ClInclude Include="utilities.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="uart.h">
|
||||
<Filter>Header Files\input</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="station.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="sceneeditor.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="simulationtime.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="applicationmode.h">
|
||||
<Filter>Header Files\application</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="application.h">
|
||||
<Filter>Header Files\application</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="simulationstateserializer.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="simulationenvironment.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="sceneeditor.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="drivermode.h">
|
||||
<Filter>Header Files\application\mode_driver</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="driveruilayer.h">
|
||||
<Filter>Header Files\application\mode_driver</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="driverkeyboardinput.h">
|
||||
<Filter>Header Files\application\mode_driver</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="drivermouseinput.h">
|
||||
<Filter>Header Files\application\mode_driver</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="gamepadinput.h">
|
||||
<Filter>Header Files\application\mode_driver</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Console\LPT.h">
|
||||
<Filter>Header Files\application\mode_driver</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Console\PoKeys55.h">
|
||||
<Filter>Header Files\application\mode_driver</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="uart.h">
|
||||
<Filter>Header Files\application\mode_driver</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="editoruilayer.h">
|
||||
<Filter>Header Files\application\mode_editor</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="editormouseinput.h">
|
||||
<Filter>Header Files\application\mode_editor</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="editormode.h">
|
||||
<Filter>Header Files\application\mode_editor</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="scenarioloadermode.h">
|
||||
<Filter>Header Files\application\mode_scenarioloader</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="scenarioloaderuilayer.h">
|
||||
<Filter>Header Files\application\mode_scenarioloader</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="editorkeyboardinput.h">
|
||||
<Filter>Header Files\application\mode_editor</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="keyboardinput.h">
|
||||
<Filter>Header Files\application\input</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="maszyna.rc">
|
||||
|
||||
163
messaging.cpp
163
messaging.cpp
@@ -13,6 +13,10 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "globals.h"
|
||||
#include "application.h"
|
||||
#include "simulation.h"
|
||||
#include "simulationtime.h"
|
||||
#include "event.h"
|
||||
#include "dynobj.h"
|
||||
#include "driver.h"
|
||||
#include "mtable.h"
|
||||
#include "logs.h"
|
||||
|
||||
@@ -36,6 +40,165 @@ Navigate(std::string const &ClassName, UINT Msg, WPARAM wParam, LPARAM lParam) {
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
OnCommandGet(multiplayer::DaneRozkaz *pRozkaz)
|
||||
{ // odebranie komunikatu z serwera
|
||||
if (pRozkaz->iSygn == MAKE_ID4('E','U','0','7') )
|
||||
switch (pRozkaz->iComm)
|
||||
{
|
||||
case 0: // odesłanie identyfikatora wersji
|
||||
CommLog( Now() + " " + std::to_string(pRozkaz->iComm) + " version" + " rcvd");
|
||||
WyslijString(Global.asVersion, 0); // przedsatwienie się
|
||||
break;
|
||||
case 1: // odesłanie identyfikatora wersji
|
||||
CommLog( Now() + " " + std::to_string(pRozkaz->iComm) + " scenery" + " rcvd");
|
||||
WyslijString(Global.SceneryFile, 1); // nazwa scenerii
|
||||
break;
|
||||
case 2: {
|
||||
// event
|
||||
CommLog( Now() + " " + std::to_string( pRozkaz->iComm ) + " " +
|
||||
std::string( pRozkaz->cString + 1, (unsigned)( pRozkaz->cString[ 0 ] ) ) + " rcvd" );
|
||||
|
||||
if( Global.iMultiplayer ) {
|
||||
auto *event = simulation::Events.FindEvent( std::string( pRozkaz->cString + 1, (unsigned)( pRozkaz->cString[ 0 ] ) ) );
|
||||
if( event != nullptr ) {
|
||||
if( ( event->Type == tp_Multiple )
|
||||
|| ( event->Type == tp_Lights )
|
||||
|| ( event->evJoined != 0 ) ) {
|
||||
// tylko jawne albo niejawne Multiple
|
||||
simulation::Events.AddToQuery( event, nullptr ); // drugi parametr to dynamic wywołujący - tu brak
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 3: // rozkaz dla AI
|
||||
if (Global.iMultiplayer)
|
||||
{
|
||||
int i = int(pRozkaz->cString[8]); // długość pierwszego łańcucha (z przodu dwa floaty)
|
||||
CommLog(
|
||||
Now() + " " + to_string(pRozkaz->iComm) + " " +
|
||||
std::string(pRozkaz->cString + 11 + i, (unsigned)(pRozkaz->cString[10 + i])) +
|
||||
" rcvd");
|
||||
// nazwa pojazdu jest druga
|
||||
auto *vehicle = simulation::Vehicles.find( { pRozkaz->cString + 11 + i, (unsigned)pRozkaz->cString[ 10 + i ] } );
|
||||
if( ( vehicle != nullptr )
|
||||
&& ( vehicle->Mechanik != nullptr ) ) {
|
||||
vehicle->Mechanik->PutCommand(
|
||||
{ pRozkaz->cString + 9, static_cast<std::size_t>(i) },
|
||||
pRozkaz->fPar[0], pRozkaz->fPar[1],
|
||||
nullptr,
|
||||
stopExt ); // floaty są z przodu
|
||||
WriteLog("AI command: " + std::string(pRozkaz->cString + 9, i));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 4: // badanie zajętości toru
|
||||
{
|
||||
CommLog(Now() + " " + to_string(pRozkaz->iComm) + " " +
|
||||
std::string(pRozkaz->cString + 1, (unsigned)(pRozkaz->cString[0])) + " rcvd");
|
||||
|
||||
auto *track = simulation::Paths.find( std::string( pRozkaz->cString + 1, (unsigned)( pRozkaz->cString[ 0 ] ) ) );
|
||||
if( ( track != nullptr )
|
||||
&& ( track->IsEmpty() ) ) {
|
||||
WyslijWolny( track->name() );
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 5: // ustawienie parametrów
|
||||
{
|
||||
CommLog(Now() + " " + to_string(pRozkaz->iComm) + " params " + to_string(*pRozkaz->iPar) + " rcvd");
|
||||
if (*pRozkaz->iPar == 0) // sprawdzenie czasu
|
||||
if (*pRozkaz->iPar & 1) // ustawienie czasu
|
||||
{
|
||||
double t = pRozkaz->fPar[1];
|
||||
simulation::Time.data().wDay = std::floor(t); // niby nie powinno być dnia, ale...
|
||||
if (Global.fMoveLight >= 0)
|
||||
Global.fMoveLight = t; // trzeba by deklinację Słońca przeliczyć
|
||||
simulation::Time.data().wHour = std::floor(24 * t) - 24.0 * simulation::Time.data().wDay;
|
||||
simulation::Time.data().wMinute = std::floor(60 * 24 * t) - 60.0 * (24.0 * simulation::Time.data().wDay + simulation::Time.data().wHour);
|
||||
simulation::Time.data().wSecond = std::floor( 60 * 60 * 24 * t ) - 60.0 * ( 60.0 * ( 24.0 * simulation::Time.data().wDay + simulation::Time.data().wHour ) + simulation::Time.data().wMinute );
|
||||
}
|
||||
if (*pRozkaz->iPar & 2)
|
||||
{ // ustawienie flag zapauzowania
|
||||
Global.iPause = pRozkaz->fPar[2]; // zakładamy, że wysyłający wie, co robi
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 6: // pobranie parametrów ruchu pojazdu
|
||||
if (Global.iMultiplayer) {
|
||||
// Ra 2014-12: to ma działać również dla pojazdów bez obsady
|
||||
CommLog(
|
||||
Now() + " "
|
||||
+ to_string( pRozkaz->iComm ) + " "
|
||||
+ std::string{ pRozkaz->cString + 1, (unsigned)( pRozkaz->cString[ 0 ] ) }
|
||||
+ " rcvd" );
|
||||
if (pRozkaz->cString[0]) {
|
||||
// jeśli długość nazwy jest niezerowa szukamy pierwszego pojazdu o takiej nazwie i odsyłamy parametry ramką #7
|
||||
auto *vehicle = (
|
||||
pRozkaz->cString[ 1 ] == '*' ?
|
||||
simulation::Vehicles.find( Global.asHumanCtrlVehicle ) :
|
||||
simulation::Vehicles.find( std::string{ pRozkaz->cString + 1, (unsigned)pRozkaz->cString[ 0 ] } ) );
|
||||
if( vehicle != nullptr ) {
|
||||
WyslijNamiary( vehicle ); // wysłanie informacji o pojeździe
|
||||
}
|
||||
}
|
||||
else {
|
||||
// dla pustego wysyłamy ramki 6 z nazwami pojazdów AI (jeśli potrzebne wszystkie, to rozpoznać np. "*")
|
||||
simulation::Vehicles.DynamicList();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 8: // ponowne wysłanie informacji o zajętych odcinkach toru
|
||||
CommLog(Now() + " " + to_string(pRozkaz->iComm) + " all busy track" + " rcvd");
|
||||
simulation::Paths.TrackBusyList();
|
||||
break;
|
||||
case 9: // ponowne wysłanie informacji o zajętych odcinkach izolowanych
|
||||
CommLog(Now() + " " + to_string(pRozkaz->iComm) + " all busy isolated" + " rcvd");
|
||||
simulation::Paths.IsolatedBusyList();
|
||||
break;
|
||||
case 10: // badanie zajętości jednego odcinka izolowanego
|
||||
CommLog(Now() + " " + to_string(pRozkaz->iComm) + " " +
|
||||
std::string(pRozkaz->cString + 1, (unsigned)(pRozkaz->cString[0])) + " rcvd");
|
||||
simulation::Paths.IsolatedBusy( std::string( pRozkaz->cString + 1, (unsigned)( pRozkaz->cString[ 0 ] ) ) );
|
||||
break;
|
||||
case 11: // ustawienie parametrów ruchu pojazdu
|
||||
// Ground.IsolatedBusy(AnsiString(pRozkaz->cString+1,(unsigned)(pRozkaz->cString[0])));
|
||||
break;
|
||||
case 12: // skrocona ramka parametrow pojazdow AI (wszystkich!!)
|
||||
CommLog(Now() + " " + to_string(pRozkaz->iComm) + " obsadzone" + " rcvd");
|
||||
WyslijObsadzone();
|
||||
// Ground.IsolatedBusy(AnsiString(pRozkaz->cString+1,(unsigned)(pRozkaz->cString[0])));
|
||||
break;
|
||||
case 13: // ramka uszkodzenia i innych stanow pojazdu, np. wylaczenie CA, wlaczenie recznego itd.
|
||||
CommLog(Now() + " " + to_string(pRozkaz->iComm) + " " +
|
||||
std::string(pRozkaz->cString + 1, (unsigned)(pRozkaz->cString[0])) +
|
||||
" rcvd");
|
||||
if( pRozkaz->cString[ 1 ] ) // jeśli długość nazwy jest niezerowa
|
||||
{ // szukamy pierwszego pojazdu o takiej nazwie i odsyłamy parametry ramką #13
|
||||
auto *lookup = (
|
||||
pRozkaz->cString[ 2 ] == '*' ?
|
||||
simulation::Vehicles.find( Global.asHumanCtrlVehicle ) : // nazwa pojazdu użytkownika
|
||||
simulation::Vehicles.find( std::string( pRozkaz->cString + 2, (unsigned)pRozkaz->cString[ 1 ] ) ) ); // nazwa pojazdu
|
||||
if( lookup == nullptr ) { break; } // nothing found, nothing to do
|
||||
auto *d { lookup };
|
||||
while( d != nullptr ) {
|
||||
d->Damage( pRozkaz->cString[ 0 ] );
|
||||
d = d->Next(); // pozostałe też
|
||||
}
|
||||
d = lookup->Prev();
|
||||
while( d != nullptr ) {
|
||||
d->Damage( pRozkaz->cString[ 0 ] );
|
||||
d = d->Prev(); // w drugą stronę też
|
||||
}
|
||||
WyslijUszkodzenia( lookup->asName, lookup->MoverParameters->EngDmgFlag ); // zwrot informacji o pojeździe
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WyslijEvent(const std::string &e, const std::string &d)
|
||||
{ // Ra: jeszcze do wyczyszczenia
|
||||
|
||||
@@ -37,6 +37,8 @@ struct DaneRozkaz2 { // struktura komunikacji z EU07.EXE
|
||||
|
||||
void Navigate( std::string const &ClassName, UINT Msg, WPARAM wParam, LPARAM lParam );
|
||||
|
||||
void OnCommandGet( multiplayer::DaneRozkaz *pRozkaz );
|
||||
|
||||
void WyslijEvent( const std::string &e, const std::string &d );
|
||||
void WyslijString( const std::string &t, int n );
|
||||
void WyslijWolny( const std::string &t );
|
||||
|
||||
65
renderer.cpp
65
renderer.cpp
@@ -12,15 +12,15 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "renderer.h"
|
||||
#include "color.h"
|
||||
#include "globals.h"
|
||||
#include "camera.h"
|
||||
#include "timer.h"
|
||||
#include "simulation.h"
|
||||
#include "simulationtime.h"
|
||||
#include "world.h"
|
||||
#include "train.h"
|
||||
#include "dynobj.h"
|
||||
#include "animmodel.h"
|
||||
#include "traction.h"
|
||||
#include "uilayer.h"
|
||||
#include "application.h"
|
||||
#include "logs.h"
|
||||
#include "utilities.h"
|
||||
|
||||
@@ -128,7 +128,7 @@ opengl_renderer::Init( GLFWwindow *Window ) {
|
||||
std::vector<GLint>{ m_diffusetextureunit } :
|
||||
std::vector<GLint>{ m_normaltextureunit, m_diffusetextureunit } );
|
||||
m_textures.assign_units( m_helpertextureunit, m_shadowtextureunit, m_normaltextureunit, m_diffusetextureunit ); // TODO: add reflections unit
|
||||
UILayer.set_unit( m_diffusetextureunit );
|
||||
ui_layer::set_unit( m_diffusetextureunit );
|
||||
select_unit( m_diffusetextureunit );
|
||||
|
||||
::glDepthFunc( GL_LEQUAL );
|
||||
@@ -397,7 +397,7 @@ opengl_renderer::Render() {
|
||||
Timer::subsystem.gfx_total.start(); // note: gfx_total is actually frame total, clean this up
|
||||
Timer::subsystem.gfx_color.start();
|
||||
// fetch simulation data
|
||||
if( World.InitPerformed() ) {
|
||||
if( simulation::is_ready ) {
|
||||
m_sunlight = Global.DayLight;
|
||||
// quantize sun angle to reduce shadow crawl
|
||||
auto const quantizationstep { 0.004f };
|
||||
@@ -453,7 +453,7 @@ opengl_renderer::Render_pass( rendermode const Mode ) {
|
||||
|
||||
if( ( true == Global.RenderShadows )
|
||||
&& ( false == Global.bWireFrame )
|
||||
&& ( true == World.InitPerformed() )
|
||||
&& ( true == simulation::is_ready )
|
||||
&& ( m_shadowcolor != colors::white ) ) {
|
||||
|
||||
// run shadowmaps pass before color
|
||||
@@ -492,7 +492,7 @@ opengl_renderer::Render_pass( rendermode const Mode ) {
|
||||
}
|
||||
|
||||
if( ( true == m_environmentcubetexturesupport )
|
||||
&& ( true == World.InitPerformed() ) ) {
|
||||
&& ( true == simulation::is_ready ) ) {
|
||||
// potentially update environmental cube map
|
||||
if( true == Render_reflections() ) {
|
||||
setup_pass( m_renderpass, Mode ); // restore draw mode. TBD, TODO: render mode stack
|
||||
@@ -501,8 +501,8 @@ opengl_renderer::Render_pass( rendermode const Mode ) {
|
||||
|
||||
::glViewport( 0, 0, Global.iWindowWidth, Global.iWindowHeight );
|
||||
|
||||
if( World.InitPerformed() ) {
|
||||
auto const skydomecolour = World.Environment.m_skydome.GetAverageColor();
|
||||
if( simulation::is_ready ) {
|
||||
auto const skydomecolour = simulation::Environment.m_skydome.GetAverageColor();
|
||||
::glClearColor( skydomecolour.x, skydomecolour.y, skydomecolour.z, 0.f ); // kolor nieba
|
||||
}
|
||||
else {
|
||||
@@ -510,13 +510,13 @@ opengl_renderer::Render_pass( rendermode const Mode ) {
|
||||
}
|
||||
::glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
|
||||
|
||||
if( World.InitPerformed() ) {
|
||||
if( simulation::is_ready ) {
|
||||
// setup
|
||||
setup_matrices();
|
||||
// render
|
||||
setup_drawing( true );
|
||||
setup_units( true, false, false );
|
||||
Render( &World.Environment );
|
||||
Render( &simulation::Environment );
|
||||
// opaque parts...
|
||||
setup_drawing( false );
|
||||
setup_units( true, true, true );
|
||||
@@ -544,7 +544,7 @@ opengl_renderer::Render_pass( rendermode const Mode ) {
|
||||
setup_shadow_map( m_cabshadowtexture, m_cabshadowtexturematrix );
|
||||
// cache shadow colour in case we need to account for cab light
|
||||
auto const shadowcolor { m_shadowcolor };
|
||||
auto const *vehicle{ World.Train->Dynamic() };
|
||||
auto const *vehicle{ simulation::Train->Dynamic() };
|
||||
if( vehicle->InteriorLightLevel > 0.f ) {
|
||||
setup_shadow_color( glm::min( colors::white, shadowcolor + glm::vec4( vehicle->InteriorLight * vehicle->InteriorLightLevel, 1.f ) ) );
|
||||
}
|
||||
@@ -565,7 +565,7 @@ opengl_renderer::Render_pass( rendermode const Mode ) {
|
||||
setup_shadow_map( m_cabshadowtexture, m_cabshadowtexturematrix );
|
||||
// cache shadow colour in case we need to account for cab light
|
||||
auto const shadowcolor{ m_shadowcolor };
|
||||
auto const *vehicle{ World.Train->Dynamic() };
|
||||
auto const *vehicle{ simulation::Train->Dynamic() };
|
||||
if( vehicle->InteriorLightLevel > 0.f ) {
|
||||
setup_shadow_color( glm::min( colors::white, shadowcolor + glm::vec4( vehicle->InteriorLight * vehicle->InteriorLightLevel, 1.f ) ) );
|
||||
}
|
||||
@@ -584,13 +584,13 @@ opengl_renderer::Render_pass( rendermode const Mode ) {
|
||||
::glMatrixMode( GL_MODELVIEW );
|
||||
}
|
||||
}
|
||||
UILayer.render();
|
||||
Application.render_ui();
|
||||
break;
|
||||
}
|
||||
|
||||
case rendermode::shadows: {
|
||||
|
||||
if( World.InitPerformed() ) {
|
||||
if( simulation::is_ready ) {
|
||||
// setup
|
||||
::glEnable( GL_POLYGON_OFFSET_FILL ); // alleviate depth-fighting
|
||||
::glPolygonOffset( 1.f, 1.f );
|
||||
@@ -631,7 +631,7 @@ opengl_renderer::Render_pass( rendermode const Mode ) {
|
||||
|
||||
case rendermode::cabshadows: {
|
||||
|
||||
if( ( World.InitPerformed() )
|
||||
if( ( simulation::is_ready )
|
||||
&& ( false == FreeFlyModeFlag ) ) {
|
||||
// setup
|
||||
::glEnable( GL_POLYGON_OFFSET_FILL ); // alleviate depth-fighting
|
||||
@@ -659,8 +659,8 @@ opengl_renderer::Render_pass( rendermode const Mode ) {
|
||||
#else
|
||||
setup_units( false, false, false );
|
||||
#endif
|
||||
Render_cab( World.Train->Dynamic(), false );
|
||||
Render_cab( World.Train->Dynamic(), true );
|
||||
Render_cab( simulation::Train->Dynamic(), false );
|
||||
Render_cab( simulation::Train->Dynamic(), true );
|
||||
m_cabshadowpass = m_renderpass;
|
||||
|
||||
// post-render restore
|
||||
@@ -678,7 +678,7 @@ opengl_renderer::Render_pass( rendermode const Mode ) {
|
||||
::glClearColor( 0.f, 0.f, 0.f, 1.f );
|
||||
::glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
|
||||
|
||||
if( World.InitPerformed() ) {
|
||||
if( simulation::is_ready ) {
|
||||
|
||||
::glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE );
|
||||
// setup
|
||||
@@ -686,7 +686,7 @@ opengl_renderer::Render_pass( rendermode const Mode ) {
|
||||
// render
|
||||
setup_drawing( true );
|
||||
setup_units( true, false, false );
|
||||
Render( &World.Environment );
|
||||
Render( &simulation::Environment );
|
||||
// opaque parts...
|
||||
setup_drawing( false );
|
||||
setup_units( true, true, true );
|
||||
@@ -708,7 +708,7 @@ opengl_renderer::Render_pass( rendermode const Mode ) {
|
||||
}
|
||||
|
||||
case rendermode::pickcontrols: {
|
||||
if( World.InitPerformed() ) {
|
||||
if( simulation::is_ready ) {
|
||||
// setup
|
||||
#ifdef EU07_USE_PICKING_FRAMEBUFFER
|
||||
::glViewport( 0, 0, EU07_PICKBUFFERSIZE, EU07_PICKBUFFERSIZE );
|
||||
@@ -723,14 +723,14 @@ opengl_renderer::Render_pass( rendermode const Mode ) {
|
||||
setup_drawing( false );
|
||||
setup_units( false, false, false );
|
||||
// cab render skips translucent parts, so we can do it here
|
||||
if( World.Train != nullptr ) { Render_cab( World.Train->Dynamic() ); }
|
||||
if( simulation::Train != nullptr ) { Render_cab( simulation::Train->Dynamic() ); }
|
||||
// post-render cleanup
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case rendermode::pickscenery: {
|
||||
if( World.InitPerformed() ) {
|
||||
if( simulation::is_ready ) {
|
||||
// setup
|
||||
m_picksceneryitems.clear();
|
||||
#ifdef EU07_USE_PICKING_FRAMEBUFFER
|
||||
@@ -789,12 +789,12 @@ opengl_renderer::setup_pass( renderpass_config &Config, rendermode const Mode, f
|
||||
|
||||
Config.draw_mode = Mode;
|
||||
|
||||
if( false == World.InitPerformed() ) { return; }
|
||||
if( false == simulation::is_ready ) { return; }
|
||||
// setup draw range
|
||||
switch( Mode ) {
|
||||
case rendermode::color: { Config.draw_range = Global.BaseDrawRange; break; }
|
||||
case rendermode::shadows: { Config.draw_range = Global.BaseDrawRange * 0.5f; break; }
|
||||
case rendermode::cabshadows: { Config.draw_range = ( Global.pWorld->train()->Dynamic()->MoverParameters->ActiveCab != 0 ? 10.f : 20.f ); break; }
|
||||
case rendermode::cabshadows: { Config.draw_range = ( simulation::Train->Occupied()->ActiveCab != 0 ? 10.f : 20.f ); break; }
|
||||
case rendermode::reflections: { Config.draw_range = Global.BaseDrawRange; break; }
|
||||
case rendermode::pickcontrols: { Config.draw_range = 50.f; break; }
|
||||
case rendermode::pickscenery: { Config.draw_range = Global.BaseDrawRange * 0.5f; break; }
|
||||
@@ -811,11 +811,11 @@ opengl_renderer::setup_pass( renderpass_config &Config, rendermode const Mode, f
|
||||
// modelview
|
||||
if( ( false == DebugCameraFlag ) || ( true == Ignoredebug ) ) {
|
||||
camera.position() = Global.pCameraPosition;
|
||||
World.Camera.SetMatrix( viewmatrix );
|
||||
Global.pCamera->SetMatrix( viewmatrix );
|
||||
}
|
||||
else {
|
||||
camera.position() = Global.DebugCameraPosition;
|
||||
World.DebugCamera.SetMatrix( viewmatrix );
|
||||
Global.pDebugCamera->SetMatrix( viewmatrix );
|
||||
}
|
||||
// projection
|
||||
auto const zfar = Config.draw_range * Global.fDistanceFactor * Zfar;
|
||||
@@ -972,7 +972,7 @@ opengl_renderer::setup_pass( renderpass_config &Config, rendermode const Mode, f
|
||||
// TODO: scissor test for pick modes
|
||||
// modelview
|
||||
camera.position() = Global.pCameraPosition;
|
||||
World.Camera.SetMatrix( viewmatrix );
|
||||
Global.pCamera->SetMatrix( viewmatrix );
|
||||
// projection
|
||||
camera.projection() *=
|
||||
glm::perspective(
|
||||
@@ -1670,7 +1670,7 @@ opengl_renderer::Render( scene::basic_region *Region ) {
|
||||
Update_Lights( simulation::Lights );
|
||||
|
||||
Render( std::begin( m_sectionqueue ), std::end( m_sectionqueue ) );
|
||||
if( EditorModeFlag && FreeFlyModeFlag ) {
|
||||
if( EditorModeFlag ) {
|
||||
// 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();
|
||||
@@ -2099,7 +2099,7 @@ opengl_renderer::Render( TDynamicObject *Dynamic ) {
|
||||
++m_debugstats.dynamics;
|
||||
|
||||
// setup
|
||||
TSubModel::iInstance = ( size_t )Dynamic; //żeby nie robić cudzych animacji
|
||||
TSubModel::iInstance = reinterpret_cast<std::uintptr_t>( Dynamic ); //żeby nie robić cudzych animacji
|
||||
glm::dvec3 const originoffset = Dynamic->vPosition - m_renderpass.camera.position();
|
||||
// lod visibility ranges are defined for base (x 1.0) viewing distance. for render we adjust them for actual range multiplier and zoom
|
||||
float squaredistance;
|
||||
@@ -2201,7 +2201,7 @@ opengl_renderer::Render_cab( TDynamicObject const *Dynamic, bool const Alpha ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
TSubModel::iInstance = reinterpret_cast<std::size_t>( Dynamic );
|
||||
TSubModel::iInstance = reinterpret_cast<std::uintptr_t>( Dynamic );
|
||||
|
||||
if( ( true == FreeFlyModeFlag )
|
||||
|| ( false == Dynamic->bDisplayCab )
|
||||
@@ -3487,7 +3487,8 @@ glm::dvec3
|
||||
opengl_renderer::Update_Mouse_Position() {
|
||||
|
||||
glm::dvec2 mousepos;
|
||||
glfwGetCursorPos( m_window, &mousepos.x, &mousepos.y );
|
||||
Application.get_cursor_pos( mousepos.x, mousepos.y );
|
||||
// glfwGetCursorPos( m_window, &mousepos.x, &mousepos.y );
|
||||
mousepos.x = clamp<int>( mousepos.x, 0, Global.iWindowWidth - 1 );
|
||||
mousepos.y = clamp<int>( Global.iWindowHeight - clamp<int>( mousepos.y, 0, Global.iWindowHeight ), 0, Global.iWindowHeight - 1 ) ;
|
||||
GLfloat pointdepth;
|
||||
@@ -3550,7 +3551,7 @@ opengl_renderer::Update( double const Deltatime ) {
|
||||
}
|
||||
|
||||
if( ( true == Global.ResourceSweep )
|
||||
&& ( true == World.InitPerformed() ) ) {
|
||||
&& ( true == simulation::is_ready ) ) {
|
||||
// garbage collection
|
||||
m_geometry.update();
|
||||
m_textures.update();
|
||||
|
||||
@@ -17,7 +17,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "dumb3d.h"
|
||||
#include "frustum.h"
|
||||
#include "scene.h"
|
||||
#include "world.h"
|
||||
#include "simulationenvironment.h"
|
||||
#include "memcell.h"
|
||||
|
||||
#define EU07_USE_PICKING_FRAMEBUFFER
|
||||
|
||||
79
scenarioloadermode.cpp
Normal file
79
scenarioloadermode.cpp
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
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 "scenarioloadermode.h"
|
||||
|
||||
#include "globals.h"
|
||||
#include "simulation.h"
|
||||
#include "simulationtime.h"
|
||||
#include "timer.h"
|
||||
#include "application.h"
|
||||
#include "scenarioloaderuilayer.h"
|
||||
#include "renderer.h"
|
||||
#include "logs.h"
|
||||
|
||||
|
||||
scenarioloader_mode::scenarioloader_mode() {
|
||||
|
||||
m_userinterface = std::make_shared<scenarioloader_ui>();
|
||||
}
|
||||
|
||||
// initializes internal data structures of the mode. returns: true on success, false otherwise
|
||||
bool
|
||||
scenarioloader_mode::init() {
|
||||
// nothing to do here
|
||||
return true;
|
||||
}
|
||||
|
||||
// mode-specific update of simulation data. returns: false on error, true otherwise
|
||||
bool
|
||||
scenarioloader_mode::update() {
|
||||
|
||||
WriteLog( "\nLoading scenario..." );
|
||||
|
||||
auto timestart = std::chrono::system_clock::now();
|
||||
|
||||
if( true == simulation::State.deserialize( Global.SceneryFile ) ) {
|
||||
WriteLog( "Scenario loading time: " + std::to_string( std::chrono::duration_cast<std::chrono::seconds>( ( std::chrono::system_clock::now() - timestart ) ).count() ) + " seconds" );
|
||||
// TODO: implement and use next mode cue
|
||||
Application.pop_mode();
|
||||
Application.push_mode( eu07_application::mode::driver );
|
||||
}
|
||||
else {
|
||||
ErrorLog( "Bad init: scenario loading failed" );
|
||||
Application.pop_mode();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// maintenance method, called when the mode is activated
|
||||
void
|
||||
scenarioloader_mode::enter() {
|
||||
|
||||
// TBD: hide cursor in fullscreen mode?
|
||||
Application.set_cursor( GLFW_CURSOR_NORMAL );
|
||||
|
||||
simulation::is_ready = false;
|
||||
|
||||
m_userinterface->set_background( "logo" );
|
||||
Application.set_title( Global.AppName + " (" + Global.SceneryFile + ")" );
|
||||
m_userinterface->set_progress();
|
||||
m_userinterface->set_progress( "Loading scenery / Wczytywanie scenerii" );
|
||||
GfxRenderer.Render();
|
||||
}
|
||||
|
||||
// maintenance method, called when the mode is deactivated
|
||||
void
|
||||
scenarioloader_mode::exit() {
|
||||
|
||||
simulation::Time.init();
|
||||
simulation::Environment.init();
|
||||
}
|
||||
41
scenarioloadermode.h
Normal file
41
scenarioloadermode.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
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 "applicationmode.h"
|
||||
|
||||
class scenarioloader_mode : public application_mode {
|
||||
|
||||
public:
|
||||
// constructors
|
||||
scenarioloader_mode();
|
||||
// methods
|
||||
// initializes internal data structures of the mode. returns: true on success, false otherwise
|
||||
bool
|
||||
init() override;
|
||||
// mode-specific update of simulation data. returns: false on error, true otherwise
|
||||
bool
|
||||
update() override;
|
||||
// maintenance method, called when the mode is activated
|
||||
void
|
||||
enter() override;
|
||||
// maintenance method, called when the mode is deactivated
|
||||
void
|
||||
exit() override;
|
||||
// input handlers
|
||||
void
|
||||
on_key( int const Key, int const Scancode, int const Action, int const Mods ) override { ; }
|
||||
void
|
||||
on_cursor_pos( double const Horizontal, double const Vertical ) override { ; }
|
||||
void
|
||||
on_mouse_button( int const Button, int const Action, int const Mods ) override { ; }
|
||||
void
|
||||
on_scroll( double const Xoffset, double const Yoffset ) override { ; }
|
||||
};
|
||||
17
scenarioloaderuilayer.h
Normal file
17
scenarioloaderuilayer.h
Normal file
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
This Source Code Form is subject to the
|
||||
terms of the Mozilla Public License, v.
|
||||
2.0. If a copy of the MPL was not
|
||||
distributed with this file, You can
|
||||
obtain one at
|
||||
http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "uilayer.h"
|
||||
|
||||
class scenarioloader_ui : public ui_layer {
|
||||
|
||||
// TODO: implement mode-specific elements
|
||||
};
|
||||
@@ -12,6 +12,9 @@ http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include "simulation.h"
|
||||
#include "globals.h"
|
||||
#include "animmodel.h"
|
||||
#include "event.h"
|
||||
#include "evlaunch.h"
|
||||
#include "timer.h"
|
||||
#include "logs.h"
|
||||
#include "sn_utils.h"
|
||||
|
||||
124
sceneeditor.cpp
124
sceneeditor.cpp
@@ -13,97 +13,19 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "globals.h"
|
||||
#include "application.h"
|
||||
#include "simulation.h"
|
||||
#include "camera.h"
|
||||
#include "animmodel.h"
|
||||
#include "renderer.h"
|
||||
|
||||
namespace scene {
|
||||
|
||||
basic_editor Editor;
|
||||
|
||||
bool
|
||||
basic_editor::on_key( int const Key, int const Action ) {
|
||||
|
||||
if( false == EditorModeFlag ) { return false; }
|
||||
|
||||
if( ( Key == GLFW_KEY_LEFT_ALT )
|
||||
|| ( Key == GLFW_KEY_RIGHT_ALT ) ) {
|
||||
// intercept these while in editor mode
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
basic_editor::on_mouse_button( int const Button, int const Action ) {
|
||||
|
||||
if( false == EditorModeFlag ) { return false; }
|
||||
// TBD: automatically activate and enforce freefly mode when editor is active?
|
||||
if( false == FreeFlyModeFlag ) { 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 ) {
|
||||
Application.set_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 ) {
|
||||
Application.set_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 ) {
|
||||
basic_editor::translate( scene::basic_node *Node, glm::dvec3 const &Location, bool const Snaptoground ) {
|
||||
|
||||
auto *node { m_node }; // placeholder for operations on multiple nodes
|
||||
auto *node { Node }; // placeholder for operations on multiple nodes
|
||||
|
||||
auto location { Location };
|
||||
if( false == mode_snap() ) {
|
||||
if( false == Snaptoground ) {
|
||||
location.y = node->location().y;
|
||||
}
|
||||
|
||||
@@ -117,14 +39,14 @@ basic_editor::translate( glm::dvec3 const &Location ) {
|
||||
}
|
||||
|
||||
void
|
||||
basic_editor::translate( float const Offset ) {
|
||||
basic_editor::translate( scene::basic_node *Node, 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 location { 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
|
||||
auto *node { Node }; // placeholder for operations on multiple nodes
|
||||
|
||||
if( typeid( *node ) == typeid( TAnimModel ) ) {
|
||||
translate_instance( static_cast<TAnimModel *>( node ), offset );
|
||||
@@ -167,47 +89,29 @@ basic_editor::translate_memorycell( TMemCell *Memorycell, float const Offset ) {
|
||||
}
|
||||
|
||||
void
|
||||
basic_editor::rotate( glm::vec3 const &Angle ) {
|
||||
basic_editor::rotate( scene::basic_node *Node, glm::vec3 const &Angle, float const Quantization ) {
|
||||
|
||||
auto *node { m_node }; // placeholder for operations on multiple nodes
|
||||
auto *node { Node }; // placeholder for operations on multiple nodes
|
||||
|
||||
if( typeid( *node ) == typeid( TAnimModel ) ) {
|
||||
rotate_instance( static_cast<TAnimModel *>( node ), Angle );
|
||||
rotate_instance( static_cast<TAnimModel *>( node ), Angle, Quantization );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
basic_editor::rotate_instance( TAnimModel *Instance, glm::vec3 const &Angle ) {
|
||||
basic_editor::rotate_instance( TAnimModel *Instance, glm::vec3 const &Angle, float const Quantization ) {
|
||||
|
||||
// adjust node data
|
||||
glm::vec3 angle = glm::dvec3 { Instance->Angles() };
|
||||
angle.y = clamp_circular( angle.y + Angle.y, 360.f );
|
||||
if( mode_snap() ) {
|
||||
if( Quantization > 0.f ) {
|
||||
// TBD, TODO: adjustable quantization step
|
||||
angle.y = quantize( angle.y, 15.f );
|
||||
angle.y = quantize( angle.y, Quantization );
|
||||
}
|
||||
Instance->Angles( angle );
|
||||
// update scene
|
||||
}
|
||||
|
||||
bool
|
||||
basic_editor::mode_translation() const {
|
||||
|
||||
return ( false == Global.altState );
|
||||
}
|
||||
|
||||
bool
|
||||
basic_editor::mode_translation_vertical() const {
|
||||
|
||||
return ( true == Global.shiftState );
|
||||
}
|
||||
|
||||
bool
|
||||
basic_editor::mode_snap() const {
|
||||
|
||||
return ( true == Global.ctrlState );
|
||||
}
|
||||
|
||||
} // scene
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
@@ -13,21 +13,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
|
||||
namespace scene {
|
||||
|
||||
class basic_editor {
|
||||
|
||||
public:
|
||||
// methods
|
||||
bool
|
||||
on_key( int const Key, int const Action );
|
||||
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
|
||||
// TODO: move the snapshot to history stack
|
||||
struct node_snapshot {
|
||||
|
||||
scene::basic_node *node;
|
||||
@@ -38,19 +24,18 @@ private:
|
||||
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 );
|
||||
|
||||
inline bool operator==( node_snapshot const &Left, node_snapshot const &Right ) { return ( ( Left.node == Right.node ) && ( Left.data == Right.data ) ); }
|
||||
inline bool operator!=( node_snapshot const &Left, node_snapshot const &Right ) { return ( !( Left == Right ) ); }
|
||||
|
||||
class basic_editor {
|
||||
|
||||
public:
|
||||
// methods
|
||||
bool
|
||||
mode_translation() const;
|
||||
bool
|
||||
mode_translation_vertical() const;
|
||||
bool
|
||||
mode_snap() const;
|
||||
void
|
||||
translate( glm::dvec3 const &Location );
|
||||
translate( scene::basic_node *Node, glm::dvec3 const &Location, bool const Snaptoground );
|
||||
void
|
||||
translate( float const Offset );
|
||||
translate( scene::basic_node *Node, float const Offset );
|
||||
void
|
||||
translate_instance( TAnimModel *Instance, glm::dvec3 const &Location );
|
||||
void
|
||||
@@ -60,22 +45,11 @@ private:
|
||||
void
|
||||
translate_memorycell( TMemCell *Memorycell, float const Offset );
|
||||
void
|
||||
rotate( glm::vec3 const &Angle );
|
||||
rotate( scene::basic_node *Node, glm::vec3 const &Angle, float const Quantization );
|
||||
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 };
|
||||
|
||||
rotate_instance( TAnimModel *Instance, glm::vec3 const &Angle, float const Quantization );
|
||||
};
|
||||
|
||||
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
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
930
simulation.cpp
930
simulation.cpp
@@ -9,13 +9,20 @@ http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "simulation.h"
|
||||
#include "simulationtime.h"
|
||||
|
||||
#include "globals.h"
|
||||
#include "simulationtime.h"
|
||||
#include "uilayer.h"
|
||||
#include "renderer.h"
|
||||
#include "logs.h"
|
||||
|
||||
#include "event.h"
|
||||
#include "memcell.h"
|
||||
#include "track.h"
|
||||
#include "traction.h"
|
||||
#include "tractionpower.h"
|
||||
#include "sound.h"
|
||||
#include "animmodel.h"
|
||||
#include "dynobj.h"
|
||||
#include "lightarray.h"
|
||||
#include "scene.h"
|
||||
#include "train.h"
|
||||
|
||||
namespace simulation {
|
||||
|
||||
@@ -31,8 +38,9 @@ vehicle_table Vehicles;
|
||||
light_array Lights;
|
||||
|
||||
scene::basic_region *Region { nullptr };
|
||||
TTrain *Train { nullptr };
|
||||
|
||||
|
||||
bool is_ready { false };
|
||||
|
||||
bool
|
||||
state_manager::deserialize( std::string const &Scenariofile ) {
|
||||
@@ -63,909 +71,27 @@ state_manager::update( double const Deltatime, int Iterationcount ) {
|
||||
simulation::Vehicles.update( Deltatime, Iterationcount );
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool
|
||||
state_serializer::deserialize( std::string const &Scenariofile ) {
|
||||
|
||||
// TODO: move initialization to separate routine so we can reuse it
|
||||
SafeDelete( Region );
|
||||
Region = new scene::basic_region();
|
||||
|
||||
// TODO: check first for presence of serialized binary files
|
||||
// if this fails, fall back on the legacy text format
|
||||
scene::scratch_data importscratchpad;
|
||||
if( Scenariofile != "$.scn" ) {
|
||||
// compilation to binary file isn't supported for rainsted-created overrides
|
||||
importscratchpad.binary.terrain = Region->deserialize( Scenariofile );
|
||||
}
|
||||
// NOTE: for the time being import from text format is a given, since we don't have full binary serialization
|
||||
cParser scenarioparser( Scenariofile, cParser::buffer_FILE, Global.asCurrentSceneryPath, Global.bLoadTraction );
|
||||
|
||||
if( false == scenarioparser.ok() ) { return false; }
|
||||
|
||||
deserialize( scenarioparser, importscratchpad );
|
||||
if( ( false == importscratchpad.binary.terrain )
|
||||
&& ( Scenariofile != "$.scn" ) ) {
|
||||
// if we didn't find usable binary version of the scenario files, create them now for future use
|
||||
// as long as the scenario file wasn't rainsted-created base file override
|
||||
Region->serialize( Scenariofile );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// restores class data from provided stream
|
||||
void
|
||||
state_serializer::deserialize( cParser &Input, scene::scratch_data &Scratchpad ) {
|
||||
state_manager::update_clocks() {
|
||||
|
||||
// prepare deserialization function table
|
||||
// since all methods use the same objects, we can have simple, hard-coded binds or lambdas for the task
|
||||
using deserializefunction = void( state_serializer::*)(cParser &, scene::scratch_data &);
|
||||
std::vector<
|
||||
std::pair<
|
||||
std::string,
|
||||
deserializefunction> > functionlist = {
|
||||
{ "atmo", &state_serializer::deserialize_atmo },
|
||||
{ "camera", &state_serializer::deserialize_camera },
|
||||
{ "config", &state_serializer::deserialize_config },
|
||||
{ "description", &state_serializer::deserialize_description },
|
||||
{ "event", &state_serializer::deserialize_event },
|
||||
{ "firstinit", &state_serializer::deserialize_firstinit },
|
||||
{ "light", &state_serializer::deserialize_light },
|
||||
{ "node", &state_serializer::deserialize_node },
|
||||
{ "origin", &state_serializer::deserialize_origin },
|
||||
{ "endorigin", &state_serializer::deserialize_endorigin },
|
||||
{ "rotate", &state_serializer::deserialize_rotate },
|
||||
{ "sky", &state_serializer::deserialize_sky },
|
||||
{ "test", &state_serializer::deserialize_test },
|
||||
{ "time", &state_serializer::deserialize_time },
|
||||
{ "trainset", &state_serializer::deserialize_trainset },
|
||||
{ "endtrainset", &state_serializer::deserialize_endtrainset } };
|
||||
using deserializefunctionbind = std::function<void()>;
|
||||
std::unordered_map<
|
||||
std::string,
|
||||
deserializefunctionbind> functionmap;
|
||||
for( auto &function : functionlist ) {
|
||||
functionmap.emplace( function.first, std::bind( function.second, this, std::ref( Input ), std::ref( Scratchpad ) ) );
|
||||
}
|
||||
|
||||
// deserialize content from the provided input
|
||||
auto
|
||||
timelast { std::chrono::steady_clock::now() },
|
||||
timenow { timelast };
|
||||
std::string token { Input.getToken<std::string>() };
|
||||
while( false == token.empty() ) {
|
||||
|
||||
auto lookup = functionmap.find( token );
|
||||
if( lookup != functionmap.end() ) {
|
||||
lookup->second();
|
||||
}
|
||||
else {
|
||||
ErrorLog( "Bad scenario: unexpected token \"" + token + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( Input.Line() - 1 ) + ")" );
|
||||
}
|
||||
|
||||
timenow = std::chrono::steady_clock::now();
|
||||
if( std::chrono::duration_cast<std::chrono::milliseconds>( timenow - timelast ).count() >= 200 ) {
|
||||
timelast = timenow;
|
||||
glfwPollEvents();
|
||||
UILayer.set_progress( Input.getProgress(), Input.getFullProgress() );
|
||||
GfxRenderer.Render();
|
||||
}
|
||||
|
||||
token = Input.getToken<std::string>();
|
||||
}
|
||||
|
||||
if( false == Scratchpad.initialized ) {
|
||||
// manually perform scenario initialization
|
||||
deserialize_firstinit( Input, Scratchpad );
|
||||
}
|
||||
// Ra 2014-07: przeliczenie kąta czasu (do animacji zależnych od czasu)
|
||||
auto const &time = simulation::Time.data();
|
||||
Global.fTimeAngleDeg = time.wHour * 15.0 + time.wMinute * 0.25 + ( ( time.wSecond + 0.001 * time.wMilliseconds ) / 240.0 );
|
||||
Global.fClockAngleDeg[ 0 ] = 36.0 * ( time.wSecond % 10 ); // jednostki sekund
|
||||
Global.fClockAngleDeg[ 1 ] = 36.0 * ( time.wSecond / 10 ); // dziesiątki sekund
|
||||
Global.fClockAngleDeg[ 2 ] = 36.0 * ( time.wMinute % 10 ); // jednostki minut
|
||||
Global.fClockAngleDeg[ 3 ] = 36.0 * ( time.wMinute / 10 ); // dziesiątki minut
|
||||
Global.fClockAngleDeg[ 4 ] = 36.0 * ( time.wHour % 10 ); // jednostki godzin
|
||||
Global.fClockAngleDeg[ 5 ] = 36.0 * ( time.wHour / 10 ); // dziesiątki godzin
|
||||
}
|
||||
|
||||
// passes specified sound to all vehicles within range as a radio message broadcasted on specified channel
|
||||
void
|
||||
state_serializer::deserialize_atmo( cParser &Input, scene::scratch_data &Scratchpad ) {
|
||||
radio_message( sound_source *Message, int const Channel ) {
|
||||
|
||||
// NOTE: parameter system needs some decent replacement, but not worth the effort if we're moving to built-in editor
|
||||
// atmosphere color; legacy parameter, no longer used
|
||||
Input.getTokens( 3 );
|
||||
// fog range
|
||||
Input.getTokens( 2 );
|
||||
Input
|
||||
>> Global.fFogStart
|
||||
>> Global.fFogEnd;
|
||||
|
||||
if( Global.fFogEnd > 0.0 ) {
|
||||
// fog colour; optional legacy parameter, no longer used
|
||||
Input.getTokens( 3 );
|
||||
}
|
||||
|
||||
std::string token { Input.getToken<std::string>() };
|
||||
if( token != "endatmo" ) {
|
||||
// optional overcast parameter
|
||||
Global.Overcast = clamp( std::stof( token ), 0.f, 2.f );
|
||||
// overcast drives weather so do a calculation here
|
||||
// NOTE: ugly, clean it up when we're done with world refactoring
|
||||
Global.pWorld->compute_weather();
|
||||
}
|
||||
while( ( false == token.empty() )
|
||||
&& ( token != "endatmo" ) ) {
|
||||
// anything else left in the section has no defined meaning
|
||||
token = Input.getToken<std::string>();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
state_serializer::deserialize_camera( cParser &Input, scene::scratch_data &Scratchpad ) {
|
||||
|
||||
glm::dvec3 xyz, abc;
|
||||
int i = -1, into = -1; // do której definicji kamery wstawić
|
||||
std::string token;
|
||||
do { // opcjonalna siódma liczba określa numer kamery, a kiedyś były tylko 3
|
||||
Input.getTokens();
|
||||
Input >> token;
|
||||
switch( ++i ) { // kiedyś camera miało tylko 3 współrzędne
|
||||
case 0: { xyz.x = atof( token.c_str() ); break; }
|
||||
case 1: { xyz.y = atof( token.c_str() ); break; }
|
||||
case 2: { xyz.z = atof( token.c_str() ); break; }
|
||||
case 3: { abc.x = atof( token.c_str() ); break; }
|
||||
case 4: { abc.y = atof( token.c_str() ); break; }
|
||||
case 5: { abc.z = atof( token.c_str() ); break; }
|
||||
case 6: { into = atoi( token.c_str() ); break; } // takie sobie, bo można wpisać -1
|
||||
default: { break; }
|
||||
}
|
||||
} while( token.compare( "endcamera" ) != 0 );
|
||||
if( into < 0 )
|
||||
into = ++Global.iCameraLast;
|
||||
if( into < 10 ) { // przepisanie do odpowiedniego miejsca w tabelce
|
||||
Global.FreeCameraInit[ into ] = xyz;
|
||||
Global.FreeCameraInitAngle[ into ] =
|
||||
Math3D::vector3(
|
||||
glm::radians( abc.x ),
|
||||
glm::radians( abc.y ),
|
||||
glm::radians( abc.z ) );
|
||||
Global.iCameraLast = into; // numer ostatniej
|
||||
}
|
||||
/*
|
||||
// cleaned up version of the above.
|
||||
// NOTE: no longer supports legacy mode where some parameters were optional
|
||||
Input.getTokens( 7 );
|
||||
glm::vec3
|
||||
position,
|
||||
rotation;
|
||||
int index;
|
||||
Input
|
||||
>> position.x
|
||||
>> position.y
|
||||
>> position.z
|
||||
>> rotation.x
|
||||
>> rotation.y
|
||||
>> rotation.z
|
||||
>> index;
|
||||
|
||||
skip_until( Input, "endcamera" );
|
||||
|
||||
// TODO: finish this
|
||||
*/
|
||||
}
|
||||
|
||||
void
|
||||
state_serializer::deserialize_config( cParser &Input, scene::scratch_data &Scratchpad ) {
|
||||
|
||||
// config parameters (re)definition
|
||||
Global.ConfigParse( Input );
|
||||
}
|
||||
|
||||
void
|
||||
state_serializer::deserialize_description( cParser &Input, scene::scratch_data &Scratchpad ) {
|
||||
|
||||
// legacy section, never really used;
|
||||
skip_until( Input, "enddescription" );
|
||||
}
|
||||
|
||||
void
|
||||
state_serializer::deserialize_event( cParser &Input, scene::scratch_data &Scratchpad ) {
|
||||
|
||||
// TODO: refactor event class and its de/serialization. do offset and rotation after deserialization is done
|
||||
auto *event = new TEvent();
|
||||
Math3D::vector3 offset = (
|
||||
Scratchpad.location.offset.empty() ?
|
||||
Math3D::vector3() :
|
||||
Math3D::vector3(
|
||||
Scratchpad.location.offset.top().x,
|
||||
Scratchpad.location.offset.top().y,
|
||||
Scratchpad.location.offset.top().z ) );
|
||||
event->Load( &Input, offset );
|
||||
|
||||
if( false == simulation::Events.insert( event ) ) {
|
||||
delete event;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
state_serializer::deserialize_firstinit( cParser &Input, scene::scratch_data &Scratchpad ) {
|
||||
|
||||
if( true == Scratchpad.initialized ) { return; }
|
||||
|
||||
simulation::Paths.InitTracks();
|
||||
simulation::Traction.InitTraction();
|
||||
simulation::Events.InitEvents();
|
||||
simulation::Events.InitLaunchers();
|
||||
simulation::Memory.InitCells();
|
||||
|
||||
Scratchpad.initialized = true;
|
||||
}
|
||||
|
||||
void
|
||||
state_serializer::deserialize_light( cParser &Input, scene::scratch_data &Scratchpad ) {
|
||||
|
||||
// legacy section, no longer used nor supported;
|
||||
skip_until( Input, "endlight" );
|
||||
}
|
||||
|
||||
void
|
||||
state_serializer::deserialize_node( cParser &Input, scene::scratch_data &Scratchpad ) {
|
||||
|
||||
auto const inputline = Input.Line(); // cache in case we need to report error
|
||||
|
||||
scene::node_data nodedata;
|
||||
// common data and node type indicator
|
||||
Input.getTokens( 4 );
|
||||
Input
|
||||
>> nodedata.range_max
|
||||
>> nodedata.range_min
|
||||
>> nodedata.name
|
||||
>> nodedata.type;
|
||||
// type-based deserialization. not elegant but it'll do
|
||||
if( nodedata.type == "dynamic" ) {
|
||||
|
||||
auto *vehicle { deserialize_dynamic( Input, Scratchpad, nodedata ) };
|
||||
// vehicle import can potentially fail
|
||||
if( vehicle == nullptr ) { return; }
|
||||
|
||||
if( false == simulation::Vehicles.insert( vehicle ) ) {
|
||||
|
||||
ErrorLog( "Bad scenario: vehicle with duplicate name \"" + vehicle->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" );
|
||||
}
|
||||
|
||||
if( ( vehicle->MoverParameters->CategoryFlag == 1 ) // trains only
|
||||
&& ( ( ( vehicle->LightList( side::front ) & ( light::headlight_left | light::headlight_right | light::headlight_upper ) ) != 0 )
|
||||
|| ( ( vehicle->LightList( side::rear ) & ( light::headlight_left | light::headlight_right | light::headlight_upper ) ) != 0 ) ) ) {
|
||||
simulation::Lights.insert( vehicle );
|
||||
}
|
||||
}
|
||||
else if( nodedata.type == "track" ) {
|
||||
|
||||
auto *path { deserialize_path( Input, Scratchpad, nodedata ) };
|
||||
// duplicates of named tracks are currently experimentally allowed
|
||||
if( false == simulation::Paths.insert( path ) ) {
|
||||
ErrorLog( "Bad scenario: track with duplicate name \"" + path->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" );
|
||||
/*
|
||||
delete path;
|
||||
delete pathnode;
|
||||
*/
|
||||
}
|
||||
simulation::Region->insert_and_register( path );
|
||||
}
|
||||
else if( nodedata.type == "traction" ) {
|
||||
|
||||
auto *traction { deserialize_traction( Input, Scratchpad, nodedata ) };
|
||||
// traction loading is optional
|
||||
if( traction == nullptr ) { return; }
|
||||
|
||||
if( false == simulation::Traction.insert( traction ) ) {
|
||||
ErrorLog( "Bad scenario: traction piece with duplicate name \"" + traction->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" );
|
||||
}
|
||||
simulation::Region->insert_and_register( traction );
|
||||
}
|
||||
else if( nodedata.type == "tractionpowersource" ) {
|
||||
|
||||
auto *powersource { deserialize_tractionpowersource( Input, Scratchpad, nodedata ) };
|
||||
// traction loading is optional
|
||||
if( powersource == nullptr ) { return; }
|
||||
|
||||
if( false == simulation::Powergrid.insert( powersource ) ) {
|
||||
ErrorLog( "Bad scenario: power grid source with duplicate name \"" + powersource->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" );
|
||||
}
|
||||
/*
|
||||
// TODO: implement this
|
||||
simulation::Region.insert_powersource( powersource, Scratchpad );
|
||||
*/
|
||||
}
|
||||
else if( nodedata.type == "model" ) {
|
||||
|
||||
if( nodedata.range_min < 0.0 ) {
|
||||
// 3d terrain
|
||||
if( false == Scratchpad.binary.terrain ) {
|
||||
// if we're loading data from text .scn file convert and import
|
||||
auto *instance { deserialize_model( Input, Scratchpad, nodedata ) };
|
||||
// model import can potentially fail
|
||||
if( instance == nullptr ) { return; }
|
||||
// go through submodels, and import them as shapes
|
||||
auto const cellcount = instance->TerrainCount() + 1; // zliczenie submodeli
|
||||
for( auto i = 1; i < cellcount; ++i ) {
|
||||
auto *submodel = instance->TerrainSquare( i - 1 );
|
||||
simulation::Region->insert(
|
||||
scene::shape_node().convert( submodel ),
|
||||
Scratchpad,
|
||||
false );
|
||||
// if there's more than one group of triangles in the cell they're held as children of the primary submodel
|
||||
submodel = submodel->ChildGet();
|
||||
while( submodel != nullptr ) {
|
||||
simulation::Region->insert(
|
||||
scene::shape_node().convert( submodel ),
|
||||
Scratchpad,
|
||||
false );
|
||||
submodel = submodel->NextGet();
|
||||
}
|
||||
}
|
||||
// with the import done we can get rid of the source model
|
||||
delete instance;
|
||||
}
|
||||
else {
|
||||
// if binary terrain file was present, we already have this data
|
||||
skip_until( Input, "endmodel" );
|
||||
}
|
||||
}
|
||||
else {
|
||||
// regular instance of 3d mesh
|
||||
auto *instance { deserialize_model( Input, Scratchpad, nodedata ) };
|
||||
// model import can potentially fail
|
||||
if( instance == nullptr ) { return; }
|
||||
|
||||
if( false == simulation::Instances.insert( instance ) ) {
|
||||
ErrorLog( "Bad scenario: 3d model instance with duplicate name \"" + instance->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" );
|
||||
}
|
||||
simulation::Region->insert( instance );
|
||||
}
|
||||
}
|
||||
else if( ( nodedata.type == "triangles" )
|
||||
|| ( nodedata.type == "triangle_strip" )
|
||||
|| ( nodedata.type == "triangle_fan" ) ) {
|
||||
|
||||
if( false == Scratchpad.binary.terrain ) {
|
||||
|
||||
simulation::Region->insert(
|
||||
scene::shape_node().import(
|
||||
Input, nodedata ),
|
||||
Scratchpad,
|
||||
true );
|
||||
}
|
||||
else {
|
||||
// all shapes were already loaded from the binary version of the file
|
||||
skip_until( Input, "endtri" );
|
||||
}
|
||||
}
|
||||
else if( ( nodedata.type == "lines" )
|
||||
|| ( nodedata.type == "line_strip" )
|
||||
|| ( nodedata.type == "line_loop" ) ) {
|
||||
|
||||
if( false == Scratchpad.binary.terrain ) {
|
||||
|
||||
simulation::Region->insert(
|
||||
scene::lines_node().import(
|
||||
Input, nodedata ),
|
||||
Scratchpad );
|
||||
}
|
||||
else {
|
||||
// all lines were already loaded from the binary version of the file
|
||||
skip_until( Input, "endline" );
|
||||
}
|
||||
}
|
||||
else if( nodedata.type == "memcell" ) {
|
||||
|
||||
auto *memorycell { deserialize_memorycell( Input, Scratchpad, nodedata ) };
|
||||
if( false == simulation::Memory.insert( memorycell ) ) {
|
||||
ErrorLog( "Bad scenario: memory memorycell with duplicate name \"" + memorycell->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" );
|
||||
}
|
||||
simulation::Region->insert( memorycell );
|
||||
}
|
||||
else if( nodedata.type == "eventlauncher" ) {
|
||||
|
||||
auto *eventlauncher { deserialize_eventlauncher( Input, Scratchpad, nodedata ) };
|
||||
if( false == simulation::Events.insert( eventlauncher ) ) {
|
||||
ErrorLog( "Bad scenario: event launcher with duplicate name \"" + eventlauncher->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" );
|
||||
}
|
||||
// event launchers can be either global, or local with limited range of activation
|
||||
// each gets assigned different caretaker
|
||||
if( true == eventlauncher->IsGlobal() ) {
|
||||
simulation::Events.queue( eventlauncher );
|
||||
}
|
||||
else {
|
||||
simulation::Region->insert( eventlauncher );
|
||||
}
|
||||
}
|
||||
else if( nodedata.type == "sound" ) {
|
||||
|
||||
auto *sound { deserialize_sound( Input, Scratchpad, nodedata ) };
|
||||
if( false == simulation::Sounds.insert( sound ) ) {
|
||||
ErrorLog( "Bad scenario: sound node with duplicate name \"" + sound->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" );
|
||||
}
|
||||
simulation::Region->insert( sound );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
state_serializer::deserialize_origin( cParser &Input, scene::scratch_data &Scratchpad ) {
|
||||
|
||||
glm::dvec3 offset;
|
||||
Input.getTokens( 3 );
|
||||
Input
|
||||
>> offset.x
|
||||
>> offset.y
|
||||
>> offset.z;
|
||||
// sumowanie całkowitego przesunięcia
|
||||
Scratchpad.location.offset.emplace(
|
||||
offset + (
|
||||
Scratchpad.location.offset.empty() ?
|
||||
glm::dvec3() :
|
||||
Scratchpad.location.offset.top() ) );
|
||||
}
|
||||
|
||||
void
|
||||
state_serializer::deserialize_endorigin( cParser &Input, scene::scratch_data &Scratchpad ) {
|
||||
|
||||
if( false == Scratchpad.location.offset.empty() ) {
|
||||
Scratchpad.location.offset.pop();
|
||||
}
|
||||
else {
|
||||
ErrorLog( "Bad origin: endorigin instruction with empty origin stack in file \"" + Input.Name() + "\" (line " + std::to_string( Input.Line() - 1 ) + ")" );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
state_serializer::deserialize_rotate( cParser &Input, scene::scratch_data &Scratchpad ) {
|
||||
|
||||
Input.getTokens( 3 );
|
||||
Input
|
||||
>> Scratchpad.location.rotation.x
|
||||
>> Scratchpad.location.rotation.y
|
||||
>> Scratchpad.location.rotation.z;
|
||||
}
|
||||
|
||||
void
|
||||
state_serializer::deserialize_sky( cParser &Input, scene::scratch_data &Scratchpad ) {
|
||||
|
||||
// sky model
|
||||
Input.getTokens( 1 );
|
||||
Input
|
||||
>> Global.asSky;
|
||||
// anything else left in the section has no defined meaning
|
||||
skip_until( Input, "endsky" );
|
||||
}
|
||||
|
||||
void
|
||||
state_serializer::deserialize_test( cParser &Input, scene::scratch_data &Scratchpad ) {
|
||||
|
||||
// legacy section, no longer supported;
|
||||
skip_until( Input, "endtest" );
|
||||
}
|
||||
|
||||
void
|
||||
state_serializer::deserialize_time( cParser &Input, scene::scratch_data &Scratchpad ) {
|
||||
|
||||
// current scenario time
|
||||
cParser timeparser( Input.getToken<std::string>() );
|
||||
timeparser.getTokens( 2, false, ":" );
|
||||
auto &time = simulation::Time.data();
|
||||
timeparser
|
||||
>> time.wHour
|
||||
>> time.wMinute;
|
||||
|
||||
if( true == Global.ScenarioTimeCurrent ) {
|
||||
// calculate time shift required to match scenario time with local clock
|
||||
auto timenow = std::time( 0 );
|
||||
auto const *localtime = std::localtime( &timenow );
|
||||
Global.ScenarioTimeOffset = ( ( localtime->tm_hour * 60 + localtime->tm_min ) - ( time.wHour * 60 + time.wMinute ) ) / 60.f;
|
||||
if( Train != nullptr ) {
|
||||
Train->radio_message( Message, Channel );
|
||||
}
|
||||
|
||||
// remaining sunrise and sunset parameters are no longer used, as they're now calculated dynamically
|
||||
// anything else left in the section has no defined meaning
|
||||
skip_until( Input, "endtime" );
|
||||
}
|
||||
|
||||
void
|
||||
state_serializer::deserialize_trainset( cParser &Input, scene::scratch_data &Scratchpad ) {
|
||||
|
||||
if( true == Scratchpad.trainset.is_open ) {
|
||||
// shouldn't happen but if it does wrap up currently open trainset and report an error
|
||||
deserialize_endtrainset( Input, Scratchpad );
|
||||
ErrorLog( "Bad scenario: encountered nested trainset definitions in file \"" + Input.Name() + "\" (line " + std::to_string( Input.Line() ) + ")" );
|
||||
}
|
||||
|
||||
Scratchpad.trainset = scene::scratch_data::trainset_data();
|
||||
Scratchpad.trainset.is_open = true;
|
||||
|
||||
Input.getTokens( 4 );
|
||||
Input
|
||||
>> Scratchpad.trainset.name
|
||||
>> Scratchpad.trainset.track
|
||||
>> Scratchpad.trainset.offset
|
||||
>> Scratchpad.trainset.velocity;
|
||||
}
|
||||
|
||||
void
|
||||
state_serializer::deserialize_endtrainset( cParser &Input, scene::scratch_data &Scratchpad ) {
|
||||
|
||||
if( ( false == Scratchpad.trainset.is_open )
|
||||
|| ( true == Scratchpad.trainset.vehicles.empty() ) ) {
|
||||
// not bloody likely but we better check for it just the same
|
||||
ErrorLog( "Bad trainset: empty trainset defined in file \"" + Input.Name() + "\" (line " + std::to_string( Input.Line() - 1 ) + ")" );
|
||||
Scratchpad.trainset.is_open = false;
|
||||
return;
|
||||
}
|
||||
|
||||
std::size_t vehicleindex { 0 };
|
||||
for( auto *vehicle : Scratchpad.trainset.vehicles ) {
|
||||
// go through list of vehicles in the trainset, coupling them together and checking for potential driver
|
||||
if( ( vehicle->Mechanik != nullptr )
|
||||
&& ( vehicle->Mechanik->Primary() ) ) {
|
||||
// primary driver will receive the timetable for this trainset
|
||||
Scratchpad.trainset.driver = vehicle;
|
||||
}
|
||||
if( vehicleindex > 0 ) {
|
||||
// from second vehicle on couple it with the previous one
|
||||
Scratchpad.trainset.vehicles[ vehicleindex - 1 ]->AttachPrev(
|
||||
vehicle,
|
||||
Scratchpad.trainset.couplings[ vehicleindex - 1 ] );
|
||||
}
|
||||
++vehicleindex;
|
||||
}
|
||||
|
||||
if( Scratchpad.trainset.driver != nullptr ) {
|
||||
// if present, send timetable to the driver
|
||||
// wysłanie komendy "Timetable" ustawia odpowiedni tryb jazdy
|
||||
auto *controller = Scratchpad.trainset.driver->Mechanik;
|
||||
controller->DirectionInitial();
|
||||
controller->PutCommand(
|
||||
"Timetable:" + Scratchpad.trainset.name,
|
||||
Scratchpad.trainset.velocity,
|
||||
0,
|
||||
nullptr );
|
||||
}
|
||||
if( Scratchpad.trainset.couplings.back() == coupling::faux ) {
|
||||
// jeśli ostatni pojazd ma sprzęg 0 to założymy mu końcówki blaszane (jak AI się odpali, to sobie poprawi)
|
||||
Scratchpad.trainset.vehicles.back()->RaLightsSet( -1, light::rearendsignals );
|
||||
}
|
||||
// all done
|
||||
Scratchpad.trainset.is_open = false;
|
||||
}
|
||||
|
||||
// creates path and its wrapper, restoring class data from provided stream
|
||||
TTrack *
|
||||
state_serializer::deserialize_path( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ) {
|
||||
|
||||
// TODO: refactor track and wrapper classes and their de/serialization. do offset and rotation after deserialization is done
|
||||
auto *track = new TTrack( Nodedata );
|
||||
auto const offset { (
|
||||
Scratchpad.location.offset.empty() ?
|
||||
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;
|
||||
}
|
||||
|
||||
TTraction *
|
||||
state_serializer::deserialize_traction( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ) {
|
||||
|
||||
if( false == Global.bLoadTraction ) {
|
||||
skip_until( Input, "endtraction" );
|
||||
return nullptr;
|
||||
}
|
||||
// TODO: refactor track and wrapper classes and their de/serialization. do offset and rotation after deserialization is done
|
||||
auto *traction = new TTraction( Nodedata );
|
||||
auto offset = (
|
||||
Scratchpad.location.offset.empty() ?
|
||||
glm::dvec3() :
|
||||
Scratchpad.location.offset.top() );
|
||||
traction->Load( &Input, offset );
|
||||
|
||||
return traction;
|
||||
}
|
||||
|
||||
TTractionPowerSource *
|
||||
state_serializer::deserialize_tractionpowersource( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ) {
|
||||
|
||||
if( false == Global.bLoadTraction ) {
|
||||
skip_until( Input, "end" );
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto *powersource = new TTractionPowerSource( Nodedata );
|
||||
powersource->Load( &Input );
|
||||
// adjust location
|
||||
powersource->location( transform( powersource->location(), Scratchpad ) );
|
||||
|
||||
return powersource;
|
||||
}
|
||||
|
||||
TMemCell *
|
||||
state_serializer::deserialize_memorycell( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ) {
|
||||
|
||||
auto *memorycell = new TMemCell( Nodedata );
|
||||
memorycell->Load( &Input );
|
||||
// adjust location
|
||||
memorycell->location( transform( memorycell->location(), Scratchpad ) );
|
||||
|
||||
return memorycell;
|
||||
}
|
||||
|
||||
TEventLauncher *
|
||||
state_serializer::deserialize_eventlauncher( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ) {
|
||||
|
||||
glm::dvec3 location;
|
||||
Input.getTokens( 3 );
|
||||
Input
|
||||
>> location.x
|
||||
>> location.y
|
||||
>> location.z;
|
||||
|
||||
auto *eventlauncher = new TEventLauncher( Nodedata );
|
||||
eventlauncher->Load( &Input );
|
||||
eventlauncher->location( transform( location, Scratchpad ) );
|
||||
|
||||
return eventlauncher;
|
||||
}
|
||||
|
||||
TAnimModel *
|
||||
state_serializer::deserialize_model( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ) {
|
||||
|
||||
glm::dvec3 location;
|
||||
glm::vec3 rotation;
|
||||
Input.getTokens( 4 );
|
||||
Input
|
||||
>> location.x
|
||||
>> location.y
|
||||
>> location.z
|
||||
>> rotation.y;
|
||||
|
||||
auto *instance = new TAnimModel( Nodedata );
|
||||
instance->Angles( Scratchpad.location.rotation + rotation ); // dostosowanie do pochylania linii
|
||||
|
||||
if( instance->Load( &Input, false ) ) {
|
||||
instance->location( transform( location, Scratchpad ) );
|
||||
}
|
||||
else {
|
||||
// model nie wczytał się - ignorowanie node
|
||||
SafeDelete( instance );
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
TDynamicObject *
|
||||
state_serializer::deserialize_dynamic( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ) {
|
||||
|
||||
if( false == Scratchpad.trainset.is_open ) {
|
||||
// part of trainset data is used when loading standalone vehicles, so clear it just in case
|
||||
Scratchpad.trainset = scene::scratch_data::trainset_data();
|
||||
}
|
||||
auto const inputline { Input.Line() }; // cache in case of errors
|
||||
// basic attributes
|
||||
auto const datafolder { Input.getToken<std::string>() };
|
||||
auto const skinfile { Input.getToken<std::string>() };
|
||||
auto const mmdfile { Input.getToken<std::string>() };
|
||||
auto const pathname = (
|
||||
Scratchpad.trainset.is_open ?
|
||||
Scratchpad.trainset.track :
|
||||
Input.getToken<std::string>() );
|
||||
auto const offset { Input.getToken<double>( false ) };
|
||||
auto const drivertype { Input.getToken<std::string>() };
|
||||
auto const couplingdata = (
|
||||
Scratchpad.trainset.is_open ?
|
||||
Input.getToken<std::string>() :
|
||||
"3" );
|
||||
auto const velocity = (
|
||||
Scratchpad.trainset.is_open ?
|
||||
Scratchpad.trainset.velocity :
|
||||
Input.getToken<float>( false ) );
|
||||
// extract coupling type and optional parameters
|
||||
auto const couplingdatawithparams = couplingdata.find( '.' );
|
||||
auto coupling = (
|
||||
couplingdatawithparams != std::string::npos ?
|
||||
std::atoi( couplingdata.substr( 0, couplingdatawithparams ).c_str() ) :
|
||||
std::atoi( couplingdata.c_str() ) );
|
||||
if( coupling < 0 ) {
|
||||
// sprzęg zablokowany (pojazdy nierozłączalne przy manewrach)
|
||||
coupling = ( -coupling ) | coupling::permanent;
|
||||
}
|
||||
if( ( offset != -1.0 )
|
||||
&& ( std::abs( offset ) > 0.5 ) ) { // maksymalna odległość między sprzęgami - do przemyślenia
|
||||
// likwidacja sprzęgu, jeśli odległość zbyt duża - to powinno być uwzględniane w fizyce sprzęgów...
|
||||
coupling = coupling::faux;
|
||||
}
|
||||
auto const params = (
|
||||
couplingdatawithparams != std::string::npos ?
|
||||
couplingdata.substr( couplingdatawithparams + 1 ) :
|
||||
"" );
|
||||
// load amount and type
|
||||
auto loadcount { Input.getToken<int>( false ) };
|
||||
auto loadtype = (
|
||||
loadcount ?
|
||||
Input.getToken<std::string>() :
|
||||
"" );
|
||||
if( loadtype == "enddynamic" ) {
|
||||
// idiotoodporność: ładunek bez podanego typu nie liczy się jako ładunek
|
||||
loadcount = 0;
|
||||
loadtype = "";
|
||||
}
|
||||
|
||||
auto *path = simulation::Paths.find( pathname );
|
||||
if( path == nullptr ) {
|
||||
|
||||
ErrorLog( "Bad scenario: vehicle \"" + Nodedata.name + "\" placed on nonexistent path \"" + pathname + "\" in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" );
|
||||
skip_until( Input, "enddynamic" );
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if( ( true == Scratchpad.trainset.vehicles.empty() ) // jeśli pierwszy pojazd,
|
||||
&& ( false == path->m_events0.empty() ) // tor ma Event0
|
||||
&& ( std::abs( velocity ) <= 1.f ) // a skład stoi
|
||||
&& ( Scratchpad.trainset.offset >= 0.0 ) // ale może nie sięgać na owy tor
|
||||
&& ( Scratchpad.trainset.offset < 8.0 ) ) { // i raczej nie sięga
|
||||
// przesuwamy około pół EU07 dla wstecznej zgodności
|
||||
Scratchpad.trainset.offset = 8.0;
|
||||
}
|
||||
|
||||
auto *vehicle = new TDynamicObject();
|
||||
|
||||
auto const length =
|
||||
vehicle->Init(
|
||||
Nodedata.name,
|
||||
datafolder, skinfile, mmdfile,
|
||||
path,
|
||||
( offset == -1.0 ?
|
||||
Scratchpad.trainset.offset :
|
||||
Scratchpad.trainset.offset - offset ),
|
||||
drivertype,
|
||||
velocity,
|
||||
Scratchpad.trainset.name,
|
||||
loadcount, loadtype,
|
||||
( offset == -1.0 ),
|
||||
params );
|
||||
|
||||
if( length != 0.0 ) { // zero oznacza błąd
|
||||
// przesunięcie dla kolejnego, minus bo idziemy w stronę punktu 1
|
||||
Scratchpad.trainset.offset -= length;
|
||||
// automatically establish permanent connections for couplers which specify them in their definitions
|
||||
if( ( coupling != 0 )
|
||||
&& ( vehicle->MoverParameters->Couplers[ ( offset == -1.0 ? side::front : side::rear ) ].AllowedFlag & coupling::permanent ) ) {
|
||||
coupling |= coupling::permanent;
|
||||
}
|
||||
if( true == Scratchpad.trainset.is_open ) {
|
||||
Scratchpad.trainset.vehicles.emplace_back( vehicle );
|
||||
Scratchpad.trainset.couplings.emplace_back( coupling );
|
||||
}
|
||||
}
|
||||
else {
|
||||
if( vehicle->MyTrack != nullptr ) {
|
||||
// rare failure case where vehicle with length of 0 is added to the track,
|
||||
// treated as error code and consequently deleted, but still remains on the track
|
||||
vehicle->MyTrack->RemoveDynamicObject( vehicle );
|
||||
}
|
||||
delete vehicle;
|
||||
skip_until( Input, "enddynamic" );
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto const destination { Input.getToken<std::string>() };
|
||||
if( destination != "enddynamic" ) {
|
||||
// optional vehicle destination parameter
|
||||
vehicle->asDestination = Input.getToken<std::string>();
|
||||
skip_until( Input, "enddynamic" );
|
||||
}
|
||||
|
||||
return vehicle;
|
||||
}
|
||||
|
||||
sound_source *
|
||||
state_serializer::deserialize_sound( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ) {
|
||||
|
||||
glm::dvec3 location;
|
||||
Input.getTokens( 3 );
|
||||
Input
|
||||
>> location.x
|
||||
>> location.y
|
||||
>> location.z;
|
||||
// adjust location
|
||||
location = transform( location, Scratchpad );
|
||||
|
||||
auto *sound = new sound_source( sound_placement::external, Nodedata.range_max );
|
||||
sound->offset( location );
|
||||
sound->name( Nodedata.name );
|
||||
sound->deserialize( Input, sound_type::single );
|
||||
|
||||
skip_until( Input, "endsound" );
|
||||
|
||||
return sound;
|
||||
}
|
||||
|
||||
// skips content of stream until specified token
|
||||
void
|
||||
state_serializer::skip_until( cParser &Input, std::string const &Token ) {
|
||||
|
||||
std::string token { Input.getToken<std::string>() };
|
||||
while( ( false == token.empty() )
|
||||
&& ( token != Token ) ) {
|
||||
|
||||
token = Input.getToken<std::string>();
|
||||
}
|
||||
}
|
||||
|
||||
// transforms provided location by specifed rotation and offset
|
||||
glm::dvec3
|
||||
state_serializer::transform( glm::dvec3 Location, scene::scratch_data const &Scratchpad ) {
|
||||
|
||||
if( Scratchpad.location.rotation != glm::vec3( 0, 0, 0 ) ) {
|
||||
auto const rotation = glm::radians( Scratchpad.location.rotation );
|
||||
Location = glm::rotateY<double>( Location, rotation.y ); // Ra 2014-11: uwzględnienie rotacji
|
||||
}
|
||||
if( false == Scratchpad.location.offset.empty() ) {
|
||||
Location += Scratchpad.location.offset.top();
|
||||
}
|
||||
return Location;
|
||||
}
|
||||
|
||||
|
||||
// stores class data in specified file, in legacy (text) format
|
||||
void
|
||||
state_serializer::export_as_text( std::string const &Scenariofile ) const {
|
||||
|
||||
if( Scenariofile == "$.scn" ) {
|
||||
ErrorLog( "Bad file: scenery export not supported for file \"$.scn\"" );
|
||||
}
|
||||
else {
|
||||
WriteLog( "Scenery data export in progress..." );
|
||||
}
|
||||
|
||||
auto filename { Scenariofile };
|
||||
while( filename[ 0 ] == '$' ) {
|
||||
// trim leading $ char rainsted utility may add to the base name for modified .scn files
|
||||
filename.erase( 0, 1 );
|
||||
}
|
||||
erase_extension( filename );
|
||||
filename = Global.asCurrentSceneryPath + filename + "_export";
|
||||
|
||||
std::ofstream scmfile { filename + ".scm" };
|
||||
// tracks
|
||||
scmfile << "// paths\n";
|
||||
for( auto const *path : Paths.sequence() ) {
|
||||
path->export_as_text( scmfile );
|
||||
}
|
||||
// traction
|
||||
scmfile << "// traction\n";
|
||||
for( auto const *traction : Traction.sequence() ) {
|
||||
traction->export_as_text( scmfile );
|
||||
}
|
||||
// power grid
|
||||
scmfile << "// traction power sources\n";
|
||||
for( auto const *powersource : Powergrid.sequence() ) {
|
||||
powersource->export_as_text( scmfile );
|
||||
}
|
||||
// models
|
||||
scmfile << "// instanced models\n";
|
||||
for( auto const *instance : Instances.sequence() ) {
|
||||
instance->export_as_text( scmfile );
|
||||
}
|
||||
// sounds
|
||||
scmfile << "// sounds\n";
|
||||
Region->export_as_text( scmfile );
|
||||
|
||||
std::ofstream ctrfile { filename + ".ctr" };
|
||||
// mem cells
|
||||
ctrfile << "// memory cells\n";
|
||||
for( auto const *memorycell : Memory.sequence() ) {
|
||||
if( true == memorycell->is_exportable ) {
|
||||
memorycell->export_as_text( ctrfile );
|
||||
}
|
||||
}
|
||||
// events
|
||||
Events.export_as_text( ctrfile );
|
||||
|
||||
WriteLog( "Scenery data export done." );
|
||||
}
|
||||
|
||||
} // simulation
|
||||
|
||||
68
simulation.h
68
simulation.h
@@ -9,67 +9,11 @@ http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "parser.h"
|
||||
#include "scene.h"
|
||||
#include "event.h"
|
||||
#include "memcell.h"
|
||||
#include "evlaunch.h"
|
||||
#include "track.h"
|
||||
#include "traction.h"
|
||||
#include "tractionpower.h"
|
||||
#include "sound.h"
|
||||
#include "animmodel.h"
|
||||
#include "dynobj.h"
|
||||
#include "driver.h"
|
||||
#include "lightarray.h"
|
||||
#include "simulationstateserializer.h"
|
||||
#include "classes.h"
|
||||
|
||||
namespace simulation {
|
||||
|
||||
class state_serializer {
|
||||
|
||||
public:
|
||||
// methods
|
||||
// restores simulation data from specified file. returns: true on success, false otherwise
|
||||
bool
|
||||
deserialize( std::string const &Scenariofile );
|
||||
// stores class data in specified file, in legacy (text) format
|
||||
void
|
||||
export_as_text( std::string const &Scenariofile ) const;
|
||||
|
||||
private:
|
||||
// methods
|
||||
// restores class data from provided stream
|
||||
void deserialize( cParser &Input, scene::scratch_data &Scratchpad );
|
||||
void deserialize_atmo( cParser &Input, scene::scratch_data &Scratchpad );
|
||||
void deserialize_camera( cParser &Input, scene::scratch_data &Scratchpad );
|
||||
void deserialize_config( cParser &Input, scene::scratch_data &Scratchpad );
|
||||
void deserialize_description( cParser &Input, scene::scratch_data &Scratchpad );
|
||||
void deserialize_event( cParser &Input, scene::scratch_data &Scratchpad );
|
||||
void deserialize_firstinit( cParser &Input, scene::scratch_data &Scratchpad );
|
||||
void deserialize_light( cParser &Input, scene::scratch_data &Scratchpad );
|
||||
void deserialize_node( cParser &Input, scene::scratch_data &Scratchpad );
|
||||
void deserialize_origin( cParser &Input, scene::scratch_data &Scratchpad );
|
||||
void deserialize_endorigin( cParser &Input, scene::scratch_data &Scratchpad );
|
||||
void deserialize_rotate( cParser &Input, scene::scratch_data &Scratchpad );
|
||||
void deserialize_sky( cParser &Input, scene::scratch_data &Scratchpad );
|
||||
void deserialize_test( cParser &Input, scene::scratch_data &Scratchpad );
|
||||
void deserialize_time( cParser &Input, scene::scratch_data &Scratchpad );
|
||||
void deserialize_trainset( cParser &Input, scene::scratch_data &Scratchpad );
|
||||
void deserialize_endtrainset( cParser &Input, scene::scratch_data &Scratchpad );
|
||||
TTrack * deserialize_path( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata );
|
||||
TTraction * deserialize_traction( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata );
|
||||
TTractionPowerSource * deserialize_tractionpowersource( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata );
|
||||
TMemCell * deserialize_memorycell( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata );
|
||||
TEventLauncher * deserialize_eventlauncher( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata );
|
||||
TAnimModel * deserialize_model( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata );
|
||||
TDynamicObject * deserialize_dynamic( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata );
|
||||
sound_source * deserialize_sound( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata );
|
||||
// skips content of stream until specified token
|
||||
void skip_until( cParser &Input, std::string const &Token );
|
||||
// transforms provided location by specifed rotation and offset
|
||||
glm::dvec3 transform( glm::dvec3 Location, scene::scratch_data const &Scratchpad );
|
||||
};
|
||||
|
||||
class state_manager {
|
||||
|
||||
public:
|
||||
@@ -77,6 +21,8 @@ public:
|
||||
// legacy method, calculates changes in simulation state over specified time
|
||||
void
|
||||
update( double Deltatime, int Iterationcount );
|
||||
void
|
||||
update_clocks();
|
||||
// restores simulation data from specified file. returns: true on success, false otherwise
|
||||
bool
|
||||
deserialize( std::string const &Scenariofile );
|
||||
@@ -89,6 +35,9 @@ private:
|
||||
state_serializer m_serializer;
|
||||
};
|
||||
|
||||
// passes specified sound to all vehicles within range as a radio message broadcasted on specified channel
|
||||
void radio_message( sound_source *Message, int const Channel );
|
||||
|
||||
extern state_manager State;
|
||||
extern event_manager Events;
|
||||
extern memory_table Memory;
|
||||
@@ -101,6 +50,9 @@ extern vehicle_table Vehicles;
|
||||
extern light_array Lights;
|
||||
|
||||
extern scene::basic_region *Region;
|
||||
extern TTrain *Train;
|
||||
|
||||
extern bool is_ready;
|
||||
|
||||
} // simulation
|
||||
|
||||
|
||||
158
simulationenvironment.cpp
Normal file
158
simulationenvironment.cpp
Normal file
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
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 "simulationenvironment.h"
|
||||
|
||||
#include "globals.h"
|
||||
|
||||
namespace simulation {
|
||||
|
||||
world_environment Environment;
|
||||
|
||||
} // simulation
|
||||
|
||||
void
|
||||
world_environment::toggle_daylight() {
|
||||
|
||||
Global.FakeLight = !Global.FakeLight;
|
||||
|
||||
if( Global.FakeLight ) {
|
||||
// for fake daylight enter fixed hour
|
||||
time( 10, 30, 0 );
|
||||
}
|
||||
else {
|
||||
// local clock based calculation
|
||||
time();
|
||||
}
|
||||
}
|
||||
|
||||
// calculates current season of the year based on set simulation date
|
||||
void
|
||||
world_environment::compute_season( int const Yearday ) const {
|
||||
|
||||
using dayseasonpair = std::pair<int, std::string>;
|
||||
|
||||
std::vector<dayseasonpair> seasonsequence {
|
||||
{ 65, "winter:" },
|
||||
{ 158, "spring:" },
|
||||
{ 252, "summer:" },
|
||||
{ 341, "autumn:" },
|
||||
{ 366, "winter:" } };
|
||||
auto const lookup =
|
||||
std::lower_bound(
|
||||
std::begin( seasonsequence ), std::end( seasonsequence ),
|
||||
clamp( Yearday, 1, seasonsequence.back().first ),
|
||||
[]( dayseasonpair const &Left, const int Right ) {
|
||||
return Left.first < Right; } );
|
||||
|
||||
Global.Season = lookup->second;
|
||||
// season can affect the weather so if it changes, re-calculate weather as well
|
||||
compute_weather();
|
||||
}
|
||||
|
||||
// calculates current weather
|
||||
void
|
||||
world_environment::compute_weather() const {
|
||||
|
||||
Global.Weather = (
|
||||
Global.Overcast < 0.25 ? "clear:" :
|
||||
Global.Overcast < 1.0 ? "cloudy:" :
|
||||
( Global.Season != "winter:" ?
|
||||
"rain:" :
|
||||
"snow:" ) );
|
||||
}
|
||||
|
||||
void
|
||||
world_environment::init() {
|
||||
|
||||
m_sun.init();
|
||||
m_moon.init();
|
||||
m_stars.init();
|
||||
m_clouds.Init();
|
||||
}
|
||||
|
||||
void
|
||||
world_environment::update() {
|
||||
// move celestial bodies...
|
||||
m_sun.update();
|
||||
m_moon.update();
|
||||
// ...determine source of key light and adjust global state accordingly...
|
||||
// diffuse (sun) intensity goes down after twilight, and reaches minimum 18 degrees below horizon
|
||||
float twilightfactor = clamp( -m_sun.getAngle(), 0.0f, 18.0f ) / 18.0f;
|
||||
// NOTE: sun light receives extra padding to prevent moon from kicking in too soon
|
||||
auto const sunlightlevel = m_sun.getIntensity() + 0.05f * ( 1.f - twilightfactor );
|
||||
auto const moonlightlevel = m_moon.getIntensity() * 0.65f; // scaled down by arbitrary factor, it's pretty bright otherwise
|
||||
float keylightintensity;
|
||||
glm::vec3 keylightcolor;
|
||||
if( moonlightlevel > sunlightlevel ) {
|
||||
// rare situations when the moon is brighter than the sun, typically at night
|
||||
Global.SunAngle = m_moon.getAngle();
|
||||
Global.DayLight.position = m_moon.getDirection();
|
||||
Global.DayLight.direction = -1.0f * m_moon.getDirection();
|
||||
keylightintensity = moonlightlevel;
|
||||
// if the moon is up, it overrides the twilight
|
||||
twilightfactor = 0.0f;
|
||||
keylightcolor = glm::vec3( 255.0f / 255.0f, 242.0f / 255.0f, 202.0f / 255.0f );
|
||||
}
|
||||
else {
|
||||
// regular situation with sun as the key light
|
||||
Global.SunAngle = m_sun.getAngle();
|
||||
Global.DayLight.position = m_sun.getDirection();
|
||||
Global.DayLight.direction = -1.0f * m_sun.getDirection();
|
||||
keylightintensity = sunlightlevel;
|
||||
// include 'golden hour' effect in twilight lighting
|
||||
float const duskfactor = 1.0f - clamp( Global.SunAngle, 0.0f, 18.0f ) / 18.0f;
|
||||
keylightcolor = interpolate(
|
||||
glm::vec3( 255.0f / 255.0f, 242.0f / 255.0f, 231.0f / 255.0f ),
|
||||
glm::vec3( 235.0f / 255.0f, 140.0f / 255.0f, 36.0f / 255.0f ),
|
||||
duskfactor );
|
||||
}
|
||||
// ...update skydome to match the current sun position as well...
|
||||
m_skydome.SetOvercastFactor( Global.Overcast );
|
||||
m_skydome.Update( m_sun.getDirection() );
|
||||
// ...retrieve current sky colour and brightness...
|
||||
auto const skydomecolour = m_skydome.GetAverageColor();
|
||||
auto const skydomehsv = colors::RGBtoHSV( skydomecolour );
|
||||
// sun strength is reduced by overcast level
|
||||
keylightintensity *= ( 1.0f - std::min( 1.f, Global.Overcast ) * 0.65f );
|
||||
|
||||
// intensity combines intensity of the sun and the light reflected by the sky dome
|
||||
// it'd be more technically correct to have just the intensity of the sun here,
|
||||
// but whether it'd _look_ better is something to be tested
|
||||
auto const intensity = std::min( 1.15f * ( 0.05f + keylightintensity + skydomehsv.z ), 1.25f );
|
||||
// the impact of sun component is reduced proportionally to overcast level, as overcast increases role of ambient light
|
||||
auto const diffuselevel = interpolate( keylightintensity, intensity * ( 1.0f - twilightfactor ), 1.0f - std::min( 1.f, Global.Overcast ) * 0.75f );
|
||||
// ...update light colours and intensity.
|
||||
keylightcolor = keylightcolor * diffuselevel;
|
||||
Global.DayLight.diffuse = glm::vec4( keylightcolor, Global.DayLight.diffuse.a );
|
||||
Global.DayLight.specular = glm::vec4( keylightcolor * 0.85f, diffuselevel );
|
||||
|
||||
// tonal impact of skydome color is inversely proportional to how high the sun is above the horizon
|
||||
// (this is pure conjecture, aimed more to 'look right' than be accurate)
|
||||
float const ambienttone = clamp( 1.0f - ( Global.SunAngle / 90.0f ), 0.0f, 1.0f );
|
||||
Global.DayLight.ambient[ 0 ] = interpolate( skydomehsv.z, skydomecolour.r, ambienttone );
|
||||
Global.DayLight.ambient[ 1 ] = interpolate( skydomehsv.z, skydomecolour.g, ambienttone );
|
||||
Global.DayLight.ambient[ 2 ] = interpolate( skydomehsv.z, skydomecolour.b, ambienttone );
|
||||
|
||||
Global.fLuminance = intensity;
|
||||
|
||||
// update the fog. setting it to match the average colour of the sky dome is cheap
|
||||
// but quite effective way to make the distant items blend with background better
|
||||
// NOTE: base brightness calculation provides scaled up value, so we bring it back to 'real' one here
|
||||
Global.FogColor = m_skydome.GetAverageHorizonColor();
|
||||
}
|
||||
|
||||
void
|
||||
world_environment::time( int const Hour, int const Minute, int const Second ) {
|
||||
|
||||
m_sun.setTime( Hour, Minute, Second );
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
52
simulationenvironment.h
Normal file
52
simulationenvironment.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
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 "sky.h"
|
||||
#include "sun.h"
|
||||
#include "moon.h"
|
||||
#include "stars.h"
|
||||
#include "skydome.h"
|
||||
|
||||
class opengl_renderer;
|
||||
|
||||
// wrapper for environment elements -- sky, sun, stars, clouds etc
|
||||
class world_environment {
|
||||
|
||||
friend opengl_renderer;
|
||||
|
||||
public:
|
||||
// methods
|
||||
void init();
|
||||
void update();
|
||||
void time( int const Hour = -1, int const Minute = -1, int const Second = -1 );
|
||||
// switches between static and dynamic daylight calculation
|
||||
void toggle_daylight();
|
||||
// calculates current season of the year based on set simulation date
|
||||
void compute_season( int const Yearday ) const;
|
||||
// calculates current weather
|
||||
void compute_weather() const;
|
||||
|
||||
private:
|
||||
// members
|
||||
CSkyDome m_skydome;
|
||||
cStars m_stars;
|
||||
cSun m_sun;
|
||||
cMoon m_moon;
|
||||
TSky m_clouds;
|
||||
};
|
||||
|
||||
namespace simulation {
|
||||
|
||||
extern world_environment Environment;
|
||||
|
||||
} // simulation
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
934
simulationstateserializer.cpp
Normal file
934
simulationstateserializer.cpp
Normal file
@@ -0,0 +1,934 @@
|
||||
/*
|
||||
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 "stdafx.h"
|
||||
#include "simulationstateserializer.h"
|
||||
|
||||
#include "globals.h"
|
||||
#include "simulation.h"
|
||||
#include "simulationtime.h"
|
||||
#include "event.h"
|
||||
#include "driver.h"
|
||||
#include "dynobj.h"
|
||||
#include "animmodel.h"
|
||||
#include "tractionpower.h"
|
||||
#include "application.h"
|
||||
#include "renderer.h"
|
||||
#include "logs.h"
|
||||
|
||||
namespace simulation {
|
||||
|
||||
bool
|
||||
state_serializer::deserialize( std::string const &Scenariofile ) {
|
||||
|
||||
// TODO: move initialization to separate routine so we can reuse it
|
||||
SafeDelete( Region );
|
||||
Region = new scene::basic_region();
|
||||
|
||||
// TODO: check first for presence of serialized binary files
|
||||
// if this fails, fall back on the legacy text format
|
||||
scene::scratch_data importscratchpad;
|
||||
if( Scenariofile != "$.scn" ) {
|
||||
// compilation to binary file isn't supported for rainsted-created overrides
|
||||
importscratchpad.binary.terrain = Region->deserialize( Scenariofile );
|
||||
}
|
||||
// NOTE: for the time being import from text format is a given, since we don't have full binary serialization
|
||||
cParser scenarioparser( Scenariofile, cParser::buffer_FILE, Global.asCurrentSceneryPath, Global.bLoadTraction );
|
||||
|
||||
if( false == scenarioparser.ok() ) { return false; }
|
||||
|
||||
deserialize( scenarioparser, importscratchpad );
|
||||
if( ( false == importscratchpad.binary.terrain )
|
||||
&& ( Scenariofile != "$.scn" ) ) {
|
||||
// if we didn't find usable binary version of the scenario files, create them now for future use
|
||||
// as long as the scenario file wasn't rainsted-created base file override
|
||||
Region->serialize( Scenariofile );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// restores class data from provided stream
|
||||
void
|
||||
state_serializer::deserialize( cParser &Input, scene::scratch_data &Scratchpad ) {
|
||||
|
||||
// prepare deserialization function table
|
||||
// since all methods use the same objects, we can have simple, hard-coded binds or lambdas for the task
|
||||
using deserializefunction = void( state_serializer::*)(cParser &, scene::scratch_data &);
|
||||
std::vector<
|
||||
std::pair<
|
||||
std::string,
|
||||
deserializefunction> > functionlist = {
|
||||
{ "atmo", &state_serializer::deserialize_atmo },
|
||||
{ "camera", &state_serializer::deserialize_camera },
|
||||
{ "config", &state_serializer::deserialize_config },
|
||||
{ "description", &state_serializer::deserialize_description },
|
||||
{ "event", &state_serializer::deserialize_event },
|
||||
{ "firstinit", &state_serializer::deserialize_firstinit },
|
||||
{ "light", &state_serializer::deserialize_light },
|
||||
{ "node", &state_serializer::deserialize_node },
|
||||
{ "origin", &state_serializer::deserialize_origin },
|
||||
{ "endorigin", &state_serializer::deserialize_endorigin },
|
||||
{ "rotate", &state_serializer::deserialize_rotate },
|
||||
{ "sky", &state_serializer::deserialize_sky },
|
||||
{ "test", &state_serializer::deserialize_test },
|
||||
{ "time", &state_serializer::deserialize_time },
|
||||
{ "trainset", &state_serializer::deserialize_trainset },
|
||||
{ "endtrainset", &state_serializer::deserialize_endtrainset } };
|
||||
using deserializefunctionbind = std::function<void()>;
|
||||
std::unordered_map<
|
||||
std::string,
|
||||
deserializefunctionbind> functionmap;
|
||||
for( auto &function : functionlist ) {
|
||||
functionmap.emplace( function.first, std::bind( function.second, this, std::ref( Input ), std::ref( Scratchpad ) ) );
|
||||
}
|
||||
|
||||
// deserialize content from the provided input
|
||||
auto
|
||||
timelast { std::chrono::steady_clock::now() },
|
||||
timenow { timelast };
|
||||
std::string token { Input.getToken<std::string>() };
|
||||
while( false == token.empty() ) {
|
||||
|
||||
auto lookup = functionmap.find( token );
|
||||
if( lookup != functionmap.end() ) {
|
||||
lookup->second();
|
||||
}
|
||||
else {
|
||||
ErrorLog( "Bad scenario: unexpected token \"" + token + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( Input.Line() - 1 ) + ")" );
|
||||
}
|
||||
|
||||
timenow = std::chrono::steady_clock::now();
|
||||
if( std::chrono::duration_cast<std::chrono::milliseconds>( timenow - timelast ).count() >= 200 ) {
|
||||
timelast = timenow;
|
||||
glfwPollEvents();
|
||||
Application.set_progress( Input.getProgress(), Input.getFullProgress() );
|
||||
GfxRenderer.Render();
|
||||
}
|
||||
|
||||
token = Input.getToken<std::string>();
|
||||
}
|
||||
|
||||
if( false == Scratchpad.initialized ) {
|
||||
// manually perform scenario initialization
|
||||
deserialize_firstinit( Input, Scratchpad );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
state_serializer::deserialize_atmo( cParser &Input, scene::scratch_data &Scratchpad ) {
|
||||
|
||||
// NOTE: parameter system needs some decent replacement, but not worth the effort if we're moving to built-in editor
|
||||
// atmosphere color; legacy parameter, no longer used
|
||||
Input.getTokens( 3 );
|
||||
// fog range
|
||||
Input.getTokens( 2 );
|
||||
Input
|
||||
>> Global.fFogStart
|
||||
>> Global.fFogEnd;
|
||||
|
||||
if( Global.fFogEnd > 0.0 ) {
|
||||
// fog colour; optional legacy parameter, no longer used
|
||||
Input.getTokens( 3 );
|
||||
}
|
||||
|
||||
std::string token { Input.getToken<std::string>() };
|
||||
if( token != "endatmo" ) {
|
||||
// optional overcast parameter
|
||||
Global.Overcast = clamp( std::stof( token ), 0.f, 2.f );
|
||||
// overcast drives weather so do a calculation here
|
||||
// NOTE: ugly, clean it up when we're done with world refactoring
|
||||
simulation::Environment.compute_weather();
|
||||
}
|
||||
while( ( false == token.empty() )
|
||||
&& ( token != "endatmo" ) ) {
|
||||
// anything else left in the section has no defined meaning
|
||||
token = Input.getToken<std::string>();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
state_serializer::deserialize_camera( cParser &Input, scene::scratch_data &Scratchpad ) {
|
||||
|
||||
glm::dvec3 xyz, abc;
|
||||
int i = -1, into = -1; // do której definicji kamery wstawić
|
||||
std::string token;
|
||||
do { // opcjonalna siódma liczba określa numer kamery, a kiedyś były tylko 3
|
||||
Input.getTokens();
|
||||
Input >> token;
|
||||
switch( ++i ) { // kiedyś camera miało tylko 3 współrzędne
|
||||
case 0: { xyz.x = atof( token.c_str() ); break; }
|
||||
case 1: { xyz.y = atof( token.c_str() ); break; }
|
||||
case 2: { xyz.z = atof( token.c_str() ); break; }
|
||||
case 3: { abc.x = atof( token.c_str() ); break; }
|
||||
case 4: { abc.y = atof( token.c_str() ); break; }
|
||||
case 5: { abc.z = atof( token.c_str() ); break; }
|
||||
case 6: { into = atoi( token.c_str() ); break; } // takie sobie, bo można wpisać -1
|
||||
default: { break; }
|
||||
}
|
||||
} while( token.compare( "endcamera" ) != 0 );
|
||||
if( into < 0 )
|
||||
into = ++Global.iCameraLast;
|
||||
if( into < 10 ) { // przepisanie do odpowiedniego miejsca w tabelce
|
||||
Global.FreeCameraInit[ into ] = xyz;
|
||||
Global.FreeCameraInitAngle[ into ] =
|
||||
Math3D::vector3(
|
||||
glm::radians( abc.x ),
|
||||
glm::radians( abc.y ),
|
||||
glm::radians( abc.z ) );
|
||||
Global.iCameraLast = into; // numer ostatniej
|
||||
}
|
||||
/*
|
||||
// cleaned up version of the above.
|
||||
// NOTE: no longer supports legacy mode where some parameters were optional
|
||||
Input.getTokens( 7 );
|
||||
glm::vec3
|
||||
position,
|
||||
rotation;
|
||||
int index;
|
||||
Input
|
||||
>> position.x
|
||||
>> position.y
|
||||
>> position.z
|
||||
>> rotation.x
|
||||
>> rotation.y
|
||||
>> rotation.z
|
||||
>> index;
|
||||
|
||||
skip_until( Input, "endcamera" );
|
||||
|
||||
// TODO: finish this
|
||||
*/
|
||||
}
|
||||
|
||||
void
|
||||
state_serializer::deserialize_config( cParser &Input, scene::scratch_data &Scratchpad ) {
|
||||
|
||||
// config parameters (re)definition
|
||||
Global.ConfigParse( Input );
|
||||
}
|
||||
|
||||
void
|
||||
state_serializer::deserialize_description( cParser &Input, scene::scratch_data &Scratchpad ) {
|
||||
|
||||
// legacy section, never really used;
|
||||
skip_until( Input, "enddescription" );
|
||||
}
|
||||
|
||||
void
|
||||
state_serializer::deserialize_event( cParser &Input, scene::scratch_data &Scratchpad ) {
|
||||
|
||||
// TODO: refactor event class and its de/serialization. do offset and rotation after deserialization is done
|
||||
auto *event = new TEvent();
|
||||
Math3D::vector3 offset = (
|
||||
Scratchpad.location.offset.empty() ?
|
||||
Math3D::vector3() :
|
||||
Math3D::vector3(
|
||||
Scratchpad.location.offset.top().x,
|
||||
Scratchpad.location.offset.top().y,
|
||||
Scratchpad.location.offset.top().z ) );
|
||||
event->Load( &Input, offset );
|
||||
|
||||
if( false == simulation::Events.insert( event ) ) {
|
||||
delete event;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
state_serializer::deserialize_firstinit( cParser &Input, scene::scratch_data &Scratchpad ) {
|
||||
|
||||
if( true == Scratchpad.initialized ) { return; }
|
||||
|
||||
simulation::Paths.InitTracks();
|
||||
simulation::Traction.InitTraction();
|
||||
simulation::Events.InitEvents();
|
||||
simulation::Events.InitLaunchers();
|
||||
simulation::Memory.InitCells();
|
||||
|
||||
Scratchpad.initialized = true;
|
||||
}
|
||||
|
||||
void
|
||||
state_serializer::deserialize_light( cParser &Input, scene::scratch_data &Scratchpad ) {
|
||||
|
||||
// legacy section, no longer used nor supported;
|
||||
skip_until( Input, "endlight" );
|
||||
}
|
||||
|
||||
void
|
||||
state_serializer::deserialize_node( cParser &Input, scene::scratch_data &Scratchpad ) {
|
||||
|
||||
auto const inputline = Input.Line(); // cache in case we need to report error
|
||||
|
||||
scene::node_data nodedata;
|
||||
// common data and node type indicator
|
||||
Input.getTokens( 4 );
|
||||
Input
|
||||
>> nodedata.range_max
|
||||
>> nodedata.range_min
|
||||
>> nodedata.name
|
||||
>> nodedata.type;
|
||||
// type-based deserialization. not elegant but it'll do
|
||||
if( nodedata.type == "dynamic" ) {
|
||||
|
||||
auto *vehicle { deserialize_dynamic( Input, Scratchpad, nodedata ) };
|
||||
// vehicle import can potentially fail
|
||||
if( vehicle == nullptr ) { return; }
|
||||
|
||||
if( false == simulation::Vehicles.insert( vehicle ) ) {
|
||||
|
||||
ErrorLog( "Bad scenario: vehicle with duplicate name \"" + vehicle->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" );
|
||||
}
|
||||
|
||||
if( ( vehicle->MoverParameters->CategoryFlag == 1 ) // trains only
|
||||
&& ( ( ( vehicle->LightList( side::front ) & ( light::headlight_left | light::headlight_right | light::headlight_upper ) ) != 0 )
|
||||
|| ( ( vehicle->LightList( side::rear ) & ( light::headlight_left | light::headlight_right | light::headlight_upper ) ) != 0 ) ) ) {
|
||||
simulation::Lights.insert( vehicle );
|
||||
}
|
||||
}
|
||||
else if( nodedata.type == "track" ) {
|
||||
|
||||
auto *path { deserialize_path( Input, Scratchpad, nodedata ) };
|
||||
// duplicates of named tracks are currently experimentally allowed
|
||||
if( false == simulation::Paths.insert( path ) ) {
|
||||
ErrorLog( "Bad scenario: track with duplicate name \"" + path->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" );
|
||||
/*
|
||||
delete path;
|
||||
delete pathnode;
|
||||
*/
|
||||
}
|
||||
simulation::Region->insert_and_register( path );
|
||||
}
|
||||
else if( nodedata.type == "traction" ) {
|
||||
|
||||
auto *traction { deserialize_traction( Input, Scratchpad, nodedata ) };
|
||||
// traction loading is optional
|
||||
if( traction == nullptr ) { return; }
|
||||
|
||||
if( false == simulation::Traction.insert( traction ) ) {
|
||||
ErrorLog( "Bad scenario: traction piece with duplicate name \"" + traction->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" );
|
||||
}
|
||||
simulation::Region->insert_and_register( traction );
|
||||
}
|
||||
else if( nodedata.type == "tractionpowersource" ) {
|
||||
|
||||
auto *powersource { deserialize_tractionpowersource( Input, Scratchpad, nodedata ) };
|
||||
// traction loading is optional
|
||||
if( powersource == nullptr ) { return; }
|
||||
|
||||
if( false == simulation::Powergrid.insert( powersource ) ) {
|
||||
ErrorLog( "Bad scenario: power grid source with duplicate name \"" + powersource->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" );
|
||||
}
|
||||
/*
|
||||
// TODO: implement this
|
||||
simulation::Region.insert_powersource( powersource, Scratchpad );
|
||||
*/
|
||||
}
|
||||
else if( nodedata.type == "model" ) {
|
||||
|
||||
if( nodedata.range_min < 0.0 ) {
|
||||
// 3d terrain
|
||||
if( false == Scratchpad.binary.terrain ) {
|
||||
// if we're loading data from text .scn file convert and import
|
||||
auto *instance { deserialize_model( Input, Scratchpad, nodedata ) };
|
||||
// model import can potentially fail
|
||||
if( instance == nullptr ) { return; }
|
||||
// go through submodels, and import them as shapes
|
||||
auto const cellcount = instance->TerrainCount() + 1; // zliczenie submodeli
|
||||
for( auto i = 1; i < cellcount; ++i ) {
|
||||
auto *submodel = instance->TerrainSquare( i - 1 );
|
||||
simulation::Region->insert(
|
||||
scene::shape_node().convert( submodel ),
|
||||
Scratchpad,
|
||||
false );
|
||||
// if there's more than one group of triangles in the cell they're held as children of the primary submodel
|
||||
submodel = submodel->ChildGet();
|
||||
while( submodel != nullptr ) {
|
||||
simulation::Region->insert(
|
||||
scene::shape_node().convert( submodel ),
|
||||
Scratchpad,
|
||||
false );
|
||||
submodel = submodel->NextGet();
|
||||
}
|
||||
}
|
||||
// with the import done we can get rid of the source model
|
||||
delete instance;
|
||||
}
|
||||
else {
|
||||
// if binary terrain file was present, we already have this data
|
||||
skip_until( Input, "endmodel" );
|
||||
}
|
||||
}
|
||||
else {
|
||||
// regular instance of 3d mesh
|
||||
auto *instance { deserialize_model( Input, Scratchpad, nodedata ) };
|
||||
// model import can potentially fail
|
||||
if( instance == nullptr ) { return; }
|
||||
|
||||
if( false == simulation::Instances.insert( instance ) ) {
|
||||
ErrorLog( "Bad scenario: 3d model instance with duplicate name \"" + instance->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" );
|
||||
}
|
||||
simulation::Region->insert( instance );
|
||||
}
|
||||
}
|
||||
else if( ( nodedata.type == "triangles" )
|
||||
|| ( nodedata.type == "triangle_strip" )
|
||||
|| ( nodedata.type == "triangle_fan" ) ) {
|
||||
|
||||
if( false == Scratchpad.binary.terrain ) {
|
||||
|
||||
simulation::Region->insert(
|
||||
scene::shape_node().import(
|
||||
Input, nodedata ),
|
||||
Scratchpad,
|
||||
true );
|
||||
}
|
||||
else {
|
||||
// all shapes were already loaded from the binary version of the file
|
||||
skip_until( Input, "endtri" );
|
||||
}
|
||||
}
|
||||
else if( ( nodedata.type == "lines" )
|
||||
|| ( nodedata.type == "line_strip" )
|
||||
|| ( nodedata.type == "line_loop" ) ) {
|
||||
|
||||
if( false == Scratchpad.binary.terrain ) {
|
||||
|
||||
simulation::Region->insert(
|
||||
scene::lines_node().import(
|
||||
Input, nodedata ),
|
||||
Scratchpad );
|
||||
}
|
||||
else {
|
||||
// all lines were already loaded from the binary version of the file
|
||||
skip_until( Input, "endline" );
|
||||
}
|
||||
}
|
||||
else if( nodedata.type == "memcell" ) {
|
||||
|
||||
auto *memorycell { deserialize_memorycell( Input, Scratchpad, nodedata ) };
|
||||
if( false == simulation::Memory.insert( memorycell ) ) {
|
||||
ErrorLog( "Bad scenario: memory memorycell with duplicate name \"" + memorycell->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" );
|
||||
}
|
||||
simulation::Region->insert( memorycell );
|
||||
}
|
||||
else if( nodedata.type == "eventlauncher" ) {
|
||||
|
||||
auto *eventlauncher { deserialize_eventlauncher( Input, Scratchpad, nodedata ) };
|
||||
if( false == simulation::Events.insert( eventlauncher ) ) {
|
||||
ErrorLog( "Bad scenario: event launcher with duplicate name \"" + eventlauncher->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" );
|
||||
}
|
||||
// event launchers can be either global, or local with limited range of activation
|
||||
// each gets assigned different caretaker
|
||||
if( true == eventlauncher->IsGlobal() ) {
|
||||
simulation::Events.queue( eventlauncher );
|
||||
}
|
||||
else {
|
||||
simulation::Region->insert( eventlauncher );
|
||||
}
|
||||
}
|
||||
else if( nodedata.type == "sound" ) {
|
||||
|
||||
auto *sound { deserialize_sound( Input, Scratchpad, nodedata ) };
|
||||
if( false == simulation::Sounds.insert( sound ) ) {
|
||||
ErrorLog( "Bad scenario: sound node with duplicate name \"" + sound->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" );
|
||||
}
|
||||
simulation::Region->insert( sound );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
state_serializer::deserialize_origin( cParser &Input, scene::scratch_data &Scratchpad ) {
|
||||
|
||||
glm::dvec3 offset;
|
||||
Input.getTokens( 3 );
|
||||
Input
|
||||
>> offset.x
|
||||
>> offset.y
|
||||
>> offset.z;
|
||||
// sumowanie całkowitego przesunięcia
|
||||
Scratchpad.location.offset.emplace(
|
||||
offset + (
|
||||
Scratchpad.location.offset.empty() ?
|
||||
glm::dvec3() :
|
||||
Scratchpad.location.offset.top() ) );
|
||||
}
|
||||
|
||||
void
|
||||
state_serializer::deserialize_endorigin( cParser &Input, scene::scratch_data &Scratchpad ) {
|
||||
|
||||
if( false == Scratchpad.location.offset.empty() ) {
|
||||
Scratchpad.location.offset.pop();
|
||||
}
|
||||
else {
|
||||
ErrorLog( "Bad origin: endorigin instruction with empty origin stack in file \"" + Input.Name() + "\" (line " + std::to_string( Input.Line() - 1 ) + ")" );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
state_serializer::deserialize_rotate( cParser &Input, scene::scratch_data &Scratchpad ) {
|
||||
|
||||
Input.getTokens( 3 );
|
||||
Input
|
||||
>> Scratchpad.location.rotation.x
|
||||
>> Scratchpad.location.rotation.y
|
||||
>> Scratchpad.location.rotation.z;
|
||||
}
|
||||
|
||||
void
|
||||
state_serializer::deserialize_sky( cParser &Input, scene::scratch_data &Scratchpad ) {
|
||||
|
||||
// sky model
|
||||
Input.getTokens( 1 );
|
||||
Input
|
||||
>> Global.asSky;
|
||||
// anything else left in the section has no defined meaning
|
||||
skip_until( Input, "endsky" );
|
||||
}
|
||||
|
||||
void
|
||||
state_serializer::deserialize_test( cParser &Input, scene::scratch_data &Scratchpad ) {
|
||||
|
||||
// legacy section, no longer supported;
|
||||
skip_until( Input, "endtest" );
|
||||
}
|
||||
|
||||
void
|
||||
state_serializer::deserialize_time( cParser &Input, scene::scratch_data &Scratchpad ) {
|
||||
|
||||
// current scenario time
|
||||
cParser timeparser( Input.getToken<std::string>() );
|
||||
timeparser.getTokens( 2, false, ":" );
|
||||
auto &time = simulation::Time.data();
|
||||
timeparser
|
||||
>> time.wHour
|
||||
>> time.wMinute;
|
||||
|
||||
if( true == Global.ScenarioTimeCurrent ) {
|
||||
// calculate time shift required to match scenario time with local clock
|
||||
auto timenow = std::time( 0 );
|
||||
auto const *localtime = std::localtime( &timenow );
|
||||
Global.ScenarioTimeOffset = ( ( localtime->tm_hour * 60 + localtime->tm_min ) - ( time.wHour * 60 + time.wMinute ) ) / 60.f;
|
||||
}
|
||||
|
||||
// remaining sunrise and sunset parameters are no longer used, as they're now calculated dynamically
|
||||
// anything else left in the section has no defined meaning
|
||||
skip_until( Input, "endtime" );
|
||||
}
|
||||
|
||||
void
|
||||
state_serializer::deserialize_trainset( cParser &Input, scene::scratch_data &Scratchpad ) {
|
||||
|
||||
if( true == Scratchpad.trainset.is_open ) {
|
||||
// shouldn't happen but if it does wrap up currently open trainset and report an error
|
||||
deserialize_endtrainset( Input, Scratchpad );
|
||||
ErrorLog( "Bad scenario: encountered nested trainset definitions in file \"" + Input.Name() + "\" (line " + std::to_string( Input.Line() ) + ")" );
|
||||
}
|
||||
|
||||
Scratchpad.trainset = scene::scratch_data::trainset_data();
|
||||
Scratchpad.trainset.is_open = true;
|
||||
|
||||
Input.getTokens( 4 );
|
||||
Input
|
||||
>> Scratchpad.trainset.name
|
||||
>> Scratchpad.trainset.track
|
||||
>> Scratchpad.trainset.offset
|
||||
>> Scratchpad.trainset.velocity;
|
||||
}
|
||||
|
||||
void
|
||||
state_serializer::deserialize_endtrainset( cParser &Input, scene::scratch_data &Scratchpad ) {
|
||||
|
||||
if( ( false == Scratchpad.trainset.is_open )
|
||||
|| ( true == Scratchpad.trainset.vehicles.empty() ) ) {
|
||||
// not bloody likely but we better check for it just the same
|
||||
ErrorLog( "Bad trainset: empty trainset defined in file \"" + Input.Name() + "\" (line " + std::to_string( Input.Line() - 1 ) + ")" );
|
||||
Scratchpad.trainset.is_open = false;
|
||||
return;
|
||||
}
|
||||
|
||||
std::size_t vehicleindex { 0 };
|
||||
for( auto *vehicle : Scratchpad.trainset.vehicles ) {
|
||||
// go through list of vehicles in the trainset, coupling them together and checking for potential driver
|
||||
if( ( vehicle->Mechanik != nullptr )
|
||||
&& ( vehicle->Mechanik->Primary() ) ) {
|
||||
// primary driver will receive the timetable for this trainset
|
||||
Scratchpad.trainset.driver = vehicle;
|
||||
}
|
||||
if( vehicleindex > 0 ) {
|
||||
// from second vehicle on couple it with the previous one
|
||||
Scratchpad.trainset.vehicles[ vehicleindex - 1 ]->AttachPrev(
|
||||
vehicle,
|
||||
Scratchpad.trainset.couplings[ vehicleindex - 1 ] );
|
||||
}
|
||||
++vehicleindex;
|
||||
}
|
||||
|
||||
if( Scratchpad.trainset.driver != nullptr ) {
|
||||
// if present, send timetable to the driver
|
||||
// wysłanie komendy "Timetable" ustawia odpowiedni tryb jazdy
|
||||
auto *controller = Scratchpad.trainset.driver->Mechanik;
|
||||
controller->DirectionInitial();
|
||||
controller->PutCommand(
|
||||
"Timetable:" + Scratchpad.trainset.name,
|
||||
Scratchpad.trainset.velocity,
|
||||
0,
|
||||
nullptr );
|
||||
}
|
||||
if( Scratchpad.trainset.couplings.back() == coupling::faux ) {
|
||||
// jeśli ostatni pojazd ma sprzęg 0 to założymy mu końcówki blaszane (jak AI się odpali, to sobie poprawi)
|
||||
Scratchpad.trainset.vehicles.back()->RaLightsSet( -1, light::rearendsignals );
|
||||
}
|
||||
// all done
|
||||
Scratchpad.trainset.is_open = false;
|
||||
}
|
||||
|
||||
// creates path and its wrapper, restoring class data from provided stream
|
||||
TTrack *
|
||||
state_serializer::deserialize_path( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ) {
|
||||
|
||||
// TODO: refactor track and wrapper classes and their de/serialization. do offset and rotation after deserialization is done
|
||||
auto *track = new TTrack( Nodedata );
|
||||
auto const offset { (
|
||||
Scratchpad.location.offset.empty() ?
|
||||
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;
|
||||
}
|
||||
|
||||
TTraction *
|
||||
state_serializer::deserialize_traction( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ) {
|
||||
|
||||
if( false == Global.bLoadTraction ) {
|
||||
skip_until( Input, "endtraction" );
|
||||
return nullptr;
|
||||
}
|
||||
// TODO: refactor track and wrapper classes and their de/serialization. do offset and rotation after deserialization is done
|
||||
auto *traction = new TTraction( Nodedata );
|
||||
auto offset = (
|
||||
Scratchpad.location.offset.empty() ?
|
||||
glm::dvec3() :
|
||||
Scratchpad.location.offset.top() );
|
||||
traction->Load( &Input, offset );
|
||||
|
||||
return traction;
|
||||
}
|
||||
|
||||
TTractionPowerSource *
|
||||
state_serializer::deserialize_tractionpowersource( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ) {
|
||||
|
||||
if( false == Global.bLoadTraction ) {
|
||||
skip_until( Input, "end" );
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto *powersource = new TTractionPowerSource( Nodedata );
|
||||
powersource->Load( &Input );
|
||||
// adjust location
|
||||
powersource->location( transform( powersource->location(), Scratchpad ) );
|
||||
|
||||
return powersource;
|
||||
}
|
||||
|
||||
TMemCell *
|
||||
state_serializer::deserialize_memorycell( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ) {
|
||||
|
||||
auto *memorycell = new TMemCell( Nodedata );
|
||||
memorycell->Load( &Input );
|
||||
// adjust location
|
||||
memorycell->location( transform( memorycell->location(), Scratchpad ) );
|
||||
|
||||
return memorycell;
|
||||
}
|
||||
|
||||
TEventLauncher *
|
||||
state_serializer::deserialize_eventlauncher( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ) {
|
||||
|
||||
glm::dvec3 location;
|
||||
Input.getTokens( 3 );
|
||||
Input
|
||||
>> location.x
|
||||
>> location.y
|
||||
>> location.z;
|
||||
|
||||
auto *eventlauncher = new TEventLauncher( Nodedata );
|
||||
eventlauncher->Load( &Input );
|
||||
eventlauncher->location( transform( location, Scratchpad ) );
|
||||
|
||||
return eventlauncher;
|
||||
}
|
||||
|
||||
TAnimModel *
|
||||
state_serializer::deserialize_model( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ) {
|
||||
|
||||
glm::dvec3 location;
|
||||
glm::vec3 rotation;
|
||||
Input.getTokens( 4 );
|
||||
Input
|
||||
>> location.x
|
||||
>> location.y
|
||||
>> location.z
|
||||
>> rotation.y;
|
||||
|
||||
auto *instance = new TAnimModel( Nodedata );
|
||||
instance->Angles( Scratchpad.location.rotation + rotation ); // dostosowanie do pochylania linii
|
||||
|
||||
if( instance->Load( &Input, false ) ) {
|
||||
instance->location( transform( location, Scratchpad ) );
|
||||
}
|
||||
else {
|
||||
// model nie wczytał się - ignorowanie node
|
||||
SafeDelete( instance );
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
TDynamicObject *
|
||||
state_serializer::deserialize_dynamic( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ) {
|
||||
|
||||
if( false == Scratchpad.trainset.is_open ) {
|
||||
// part of trainset data is used when loading standalone vehicles, so clear it just in case
|
||||
Scratchpad.trainset = scene::scratch_data::trainset_data();
|
||||
}
|
||||
auto const inputline { Input.Line() }; // cache in case of errors
|
||||
// basic attributes
|
||||
auto const datafolder { Input.getToken<std::string>() };
|
||||
auto const skinfile { Input.getToken<std::string>() };
|
||||
auto const mmdfile { Input.getToken<std::string>() };
|
||||
auto const pathname = (
|
||||
Scratchpad.trainset.is_open ?
|
||||
Scratchpad.trainset.track :
|
||||
Input.getToken<std::string>() );
|
||||
auto const offset { Input.getToken<double>( false ) };
|
||||
auto const drivertype { Input.getToken<std::string>() };
|
||||
auto const couplingdata = (
|
||||
Scratchpad.trainset.is_open ?
|
||||
Input.getToken<std::string>() :
|
||||
"3" );
|
||||
auto const velocity = (
|
||||
Scratchpad.trainset.is_open ?
|
||||
Scratchpad.trainset.velocity :
|
||||
Input.getToken<float>( false ) );
|
||||
// extract coupling type and optional parameters
|
||||
auto const couplingdatawithparams = couplingdata.find( '.' );
|
||||
auto coupling = (
|
||||
couplingdatawithparams != std::string::npos ?
|
||||
std::atoi( couplingdata.substr( 0, couplingdatawithparams ).c_str() ) :
|
||||
std::atoi( couplingdata.c_str() ) );
|
||||
if( coupling < 0 ) {
|
||||
// sprzęg zablokowany (pojazdy nierozłączalne przy manewrach)
|
||||
coupling = ( -coupling ) | coupling::permanent;
|
||||
}
|
||||
if( ( offset != -1.0 )
|
||||
&& ( std::abs( offset ) > 0.5 ) ) { // maksymalna odległość między sprzęgami - do przemyślenia
|
||||
// likwidacja sprzęgu, jeśli odległość zbyt duża - to powinno być uwzględniane w fizyce sprzęgów...
|
||||
coupling = coupling::faux;
|
||||
}
|
||||
auto const params = (
|
||||
couplingdatawithparams != std::string::npos ?
|
||||
couplingdata.substr( couplingdatawithparams + 1 ) :
|
||||
"" );
|
||||
// load amount and type
|
||||
auto loadcount { Input.getToken<int>( false ) };
|
||||
auto loadtype = (
|
||||
loadcount ?
|
||||
Input.getToken<std::string>() :
|
||||
"" );
|
||||
if( loadtype == "enddynamic" ) {
|
||||
// idiotoodporność: ładunek bez podanego typu nie liczy się jako ładunek
|
||||
loadcount = 0;
|
||||
loadtype = "";
|
||||
}
|
||||
|
||||
auto *path = simulation::Paths.find( pathname );
|
||||
if( path == nullptr ) {
|
||||
|
||||
ErrorLog( "Bad scenario: vehicle \"" + Nodedata.name + "\" placed on nonexistent path \"" + pathname + "\" in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" );
|
||||
skip_until( Input, "enddynamic" );
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if( ( true == Scratchpad.trainset.vehicles.empty() ) // jeśli pierwszy pojazd,
|
||||
&& ( false == path->m_events0.empty() ) // tor ma Event0
|
||||
&& ( std::abs( velocity ) <= 1.f ) // a skład stoi
|
||||
&& ( Scratchpad.trainset.offset >= 0.0 ) // ale może nie sięgać na owy tor
|
||||
&& ( Scratchpad.trainset.offset < 8.0 ) ) { // i raczej nie sięga
|
||||
// przesuwamy około pół EU07 dla wstecznej zgodności
|
||||
Scratchpad.trainset.offset = 8.0;
|
||||
}
|
||||
|
||||
auto *vehicle = new TDynamicObject();
|
||||
|
||||
auto const length =
|
||||
vehicle->Init(
|
||||
Nodedata.name,
|
||||
datafolder, skinfile, mmdfile,
|
||||
path,
|
||||
( offset == -1.0 ?
|
||||
Scratchpad.trainset.offset :
|
||||
Scratchpad.trainset.offset - offset ),
|
||||
drivertype,
|
||||
velocity,
|
||||
Scratchpad.trainset.name,
|
||||
loadcount, loadtype,
|
||||
( offset == -1.0 ),
|
||||
params );
|
||||
|
||||
if( length != 0.0 ) { // zero oznacza błąd
|
||||
// przesunięcie dla kolejnego, minus bo idziemy w stronę punktu 1
|
||||
Scratchpad.trainset.offset -= length;
|
||||
// automatically establish permanent connections for couplers which specify them in their definitions
|
||||
if( ( coupling != 0 )
|
||||
&& ( vehicle->MoverParameters->Couplers[ ( offset == -1.0 ? side::front : side::rear ) ].AllowedFlag & coupling::permanent ) ) {
|
||||
coupling |= coupling::permanent;
|
||||
}
|
||||
if( true == Scratchpad.trainset.is_open ) {
|
||||
Scratchpad.trainset.vehicles.emplace_back( vehicle );
|
||||
Scratchpad.trainset.couplings.emplace_back( coupling );
|
||||
}
|
||||
}
|
||||
else {
|
||||
if( vehicle->MyTrack != nullptr ) {
|
||||
// rare failure case where vehicle with length of 0 is added to the track,
|
||||
// treated as error code and consequently deleted, but still remains on the track
|
||||
vehicle->MyTrack->RemoveDynamicObject( vehicle );
|
||||
}
|
||||
delete vehicle;
|
||||
skip_until( Input, "enddynamic" );
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto const destination { Input.getToken<std::string>() };
|
||||
if( destination != "enddynamic" ) {
|
||||
// optional vehicle destination parameter
|
||||
vehicle->asDestination = Input.getToken<std::string>();
|
||||
skip_until( Input, "enddynamic" );
|
||||
}
|
||||
|
||||
return vehicle;
|
||||
}
|
||||
|
||||
sound_source *
|
||||
state_serializer::deserialize_sound( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ) {
|
||||
|
||||
glm::dvec3 location;
|
||||
Input.getTokens( 3 );
|
||||
Input
|
||||
>> location.x
|
||||
>> location.y
|
||||
>> location.z;
|
||||
// adjust location
|
||||
location = transform( location, Scratchpad );
|
||||
|
||||
auto *sound = new sound_source( sound_placement::external, Nodedata.range_max );
|
||||
sound->offset( location );
|
||||
sound->name( Nodedata.name );
|
||||
sound->deserialize( Input, sound_type::single );
|
||||
|
||||
skip_until( Input, "endsound" );
|
||||
|
||||
return sound;
|
||||
}
|
||||
|
||||
// skips content of stream until specified token
|
||||
void
|
||||
state_serializer::skip_until( cParser &Input, std::string const &Token ) {
|
||||
|
||||
std::string token { Input.getToken<std::string>() };
|
||||
while( ( false == token.empty() )
|
||||
&& ( token != Token ) ) {
|
||||
|
||||
token = Input.getToken<std::string>();
|
||||
}
|
||||
}
|
||||
|
||||
// transforms provided location by specifed rotation and offset
|
||||
glm::dvec3
|
||||
state_serializer::transform( glm::dvec3 Location, scene::scratch_data const &Scratchpad ) {
|
||||
|
||||
if( Scratchpad.location.rotation != glm::vec3( 0, 0, 0 ) ) {
|
||||
auto const rotation = glm::radians( Scratchpad.location.rotation );
|
||||
Location = glm::rotateY<double>( Location, rotation.y ); // Ra 2014-11: uwzględnienie rotacji
|
||||
}
|
||||
if( false == Scratchpad.location.offset.empty() ) {
|
||||
Location += Scratchpad.location.offset.top();
|
||||
}
|
||||
return Location;
|
||||
}
|
||||
|
||||
|
||||
// stores class data in specified file, in legacy (text) format
|
||||
void
|
||||
state_serializer::export_as_text( std::string const &Scenariofile ) const {
|
||||
|
||||
if( Scenariofile == "$.scn" ) {
|
||||
ErrorLog( "Bad file: scenery export not supported for file \"$.scn\"" );
|
||||
}
|
||||
else {
|
||||
WriteLog( "Scenery data export in progress..." );
|
||||
}
|
||||
|
||||
auto filename { Scenariofile };
|
||||
while( filename[ 0 ] == '$' ) {
|
||||
// trim leading $ char rainsted utility may add to the base name for modified .scn files
|
||||
filename.erase( 0, 1 );
|
||||
}
|
||||
erase_extension( filename );
|
||||
filename = Global.asCurrentSceneryPath + filename + "_export";
|
||||
|
||||
std::ofstream scmfile { filename + ".scm" };
|
||||
// tracks
|
||||
scmfile << "// paths\n";
|
||||
for( auto const *path : Paths.sequence() ) {
|
||||
path->export_as_text( scmfile );
|
||||
}
|
||||
// traction
|
||||
scmfile << "// traction\n";
|
||||
for( auto const *traction : Traction.sequence() ) {
|
||||
traction->export_as_text( scmfile );
|
||||
}
|
||||
// power grid
|
||||
scmfile << "// traction power sources\n";
|
||||
for( auto const *powersource : Powergrid.sequence() ) {
|
||||
powersource->export_as_text( scmfile );
|
||||
}
|
||||
// models
|
||||
scmfile << "// instanced models\n";
|
||||
for( auto const *instance : Instances.sequence() ) {
|
||||
instance->export_as_text( scmfile );
|
||||
}
|
||||
// sounds
|
||||
scmfile << "// sounds\n";
|
||||
Region->export_as_text( scmfile );
|
||||
|
||||
std::ofstream ctrfile { filename + ".ctr" };
|
||||
// mem cells
|
||||
ctrfile << "// memory cells\n";
|
||||
for( auto const *memorycell : Memory.sequence() ) {
|
||||
if( true == memorycell->is_exportable ) {
|
||||
memorycell->export_as_text( ctrfile );
|
||||
}
|
||||
}
|
||||
// events
|
||||
Events.export_as_text( ctrfile );
|
||||
|
||||
WriteLog( "Scenery data export done." );
|
||||
}
|
||||
|
||||
} // simulation
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
64
simulationstateserializer.h
Normal file
64
simulationstateserializer.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
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 "parser.h"
|
||||
#include "scene.h"
|
||||
|
||||
namespace simulation {
|
||||
|
||||
class state_serializer {
|
||||
|
||||
public:
|
||||
// methods
|
||||
// restores simulation data from specified file. returns: true on success, false otherwise
|
||||
bool
|
||||
deserialize( std::string const &Scenariofile );
|
||||
// stores class data in specified file, in legacy (text) format
|
||||
void
|
||||
export_as_text( std::string const &Scenariofile ) const;
|
||||
|
||||
private:
|
||||
// methods
|
||||
// restores class data from provided stream
|
||||
void deserialize( cParser &Input, scene::scratch_data &Scratchpad );
|
||||
void deserialize_atmo( cParser &Input, scene::scratch_data &Scratchpad );
|
||||
void deserialize_camera( cParser &Input, scene::scratch_data &Scratchpad );
|
||||
void deserialize_config( cParser &Input, scene::scratch_data &Scratchpad );
|
||||
void deserialize_description( cParser &Input, scene::scratch_data &Scratchpad );
|
||||
void deserialize_event( cParser &Input, scene::scratch_data &Scratchpad );
|
||||
void deserialize_firstinit( cParser &Input, scene::scratch_data &Scratchpad );
|
||||
void deserialize_light( cParser &Input, scene::scratch_data &Scratchpad );
|
||||
void deserialize_node( cParser &Input, scene::scratch_data &Scratchpad );
|
||||
void deserialize_origin( cParser &Input, scene::scratch_data &Scratchpad );
|
||||
void deserialize_endorigin( cParser &Input, scene::scratch_data &Scratchpad );
|
||||
void deserialize_rotate( cParser &Input, scene::scratch_data &Scratchpad );
|
||||
void deserialize_sky( cParser &Input, scene::scratch_data &Scratchpad );
|
||||
void deserialize_test( cParser &Input, scene::scratch_data &Scratchpad );
|
||||
void deserialize_time( cParser &Input, scene::scratch_data &Scratchpad );
|
||||
void deserialize_trainset( cParser &Input, scene::scratch_data &Scratchpad );
|
||||
void deserialize_endtrainset( cParser &Input, scene::scratch_data &Scratchpad );
|
||||
TTrack * deserialize_path( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata );
|
||||
TTraction * deserialize_traction( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata );
|
||||
TTractionPowerSource * deserialize_tractionpowersource( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata );
|
||||
TMemCell * deserialize_memorycell( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata );
|
||||
TEventLauncher * deserialize_eventlauncher( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata );
|
||||
TAnimModel * deserialize_model( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata );
|
||||
TDynamicObject * deserialize_dynamic( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata );
|
||||
sound_source * deserialize_sound( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata );
|
||||
// skips content of stream until specified token
|
||||
void skip_until( cParser &Input, std::string const &Token );
|
||||
// transforms provided location by specifed rotation and offset
|
||||
glm::dvec3 transform( glm::dvec3 Location, scene::scratch_data const &Scratchpad );
|
||||
};
|
||||
|
||||
} // simulation
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
14
sound.cpp
14
sound.cpp
@@ -12,9 +12,9 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "sound.h"
|
||||
#include "parser.h"
|
||||
#include "globals.h"
|
||||
#include "world.h"
|
||||
#include "train.h"
|
||||
#include "dynobj.h"
|
||||
#include "simulation.h"
|
||||
|
||||
// constructors
|
||||
sound_source::sound_source( sound_placement const Placement, float const Range ) :
|
||||
@@ -910,15 +910,15 @@ sound_source::update_soundproofing() {
|
||||
int const activecab = (
|
||||
Global.CabWindowOpen ? 2 :
|
||||
FreeFlyModeFlag ? 0 :
|
||||
( Global.pWorld->train() ?
|
||||
Global.pWorld->train()->Dynamic()->MoverParameters->ActiveCab :
|
||||
( simulation::Train ?
|
||||
simulation::Train->Occupied()->ActiveCab :
|
||||
0 ) );
|
||||
// location-based gain factor:
|
||||
std::uintptr_t soundproofingstamp = reinterpret_cast<std::uintptr_t>( (
|
||||
FreeFlyModeFlag ?
|
||||
nullptr :
|
||||
( Global.pWorld->train() ?
|
||||
Global.pWorld->train()->Dynamic() :
|
||||
( simulation::Train ?
|
||||
simulation::Train->Dynamic() :
|
||||
nullptr ) ) )
|
||||
+ activecab;
|
||||
|
||||
@@ -941,7 +941,7 @@ sound_source::update_soundproofing() {
|
||||
m_properties.soundproofing = (
|
||||
soundproofingstamp == 0 ?
|
||||
EU07_SOUNDPROOFING_STRONG : // listener outside HACK: won't be true if active vehicle has open window
|
||||
( Global.pWorld->train()->Dynamic() != m_owner ?
|
||||
( simulation::Train->Dynamic() != m_owner ?
|
||||
EU07_SOUNDPROOFING_STRONG : // in another vehicle
|
||||
( activecab == 0 ?
|
||||
EU07_SOUNDPROOFING_STRONG : // listener in the engine compartment
|
||||
@@ -952,7 +952,7 @@ sound_source::update_soundproofing() {
|
||||
m_properties.soundproofing = (
|
||||
( ( soundproofingstamp == 0 ) || ( true == Global.CabWindowOpen ) ) ?
|
||||
EU07_SOUNDPROOFING_SOME : // listener outside or has a window open
|
||||
( Global.pWorld->train()->Dynamic() != m_owner ?
|
||||
( simulation::Train->Dynamic() != m_owner ?
|
||||
EU07_SOUNDPROOFING_STRONG : // in another vehicle
|
||||
( activecab == 0 ?
|
||||
EU07_SOUNDPROOFING_NONE : // listener in the engine compartment
|
||||
|
||||
4
uart.cpp
4
uart.cpp
@@ -2,7 +2,7 @@
|
||||
#include "uart.h"
|
||||
|
||||
#include "Globals.h"
|
||||
#include "World.h"
|
||||
#include "simulation.h"
|
||||
#include "Train.h"
|
||||
#include "parser.h"
|
||||
#include "Logs.h"
|
||||
@@ -130,7 +130,7 @@ void uart_input::poll()
|
||||
return;
|
||||
last_update = now;
|
||||
|
||||
auto *t = Global.pWorld->train();
|
||||
auto const *t =simulation::Train;
|
||||
if (!t)
|
||||
return;
|
||||
|
||||
|
||||
1033
uilayer.cpp
1033
uilayer.cpp
File diff suppressed because it is too large
Load Diff
56
uilayer.h
56
uilayer.h
@@ -1,4 +1,12 @@
|
||||
|
||||
/*
|
||||
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 <string>
|
||||
@@ -30,29 +38,32 @@ struct ui_panel {
|
||||
class ui_layer {
|
||||
|
||||
public:
|
||||
// parameters:
|
||||
|
||||
// constructors:
|
||||
// constructors
|
||||
ui_layer() = default;
|
||||
// destructor:
|
||||
~ui_layer();
|
||||
// destructor
|
||||
virtual ~ui_layer();
|
||||
|
||||
// methods:
|
||||
// methods
|
||||
static
|
||||
bool
|
||||
init( GLFWwindow *Window );
|
||||
// assign texturing hardware unit
|
||||
static
|
||||
void
|
||||
set_unit( GLint const Textureunit ) { m_textureunit = Textureunit; }
|
||||
// potentially processes provided input key. returns: true if the input was processed, false otherwise
|
||||
virtual
|
||||
bool
|
||||
on_key( int const Key, int const Action );
|
||||
// updates state of UI elements
|
||||
virtual
|
||||
void
|
||||
update();
|
||||
update() {}
|
||||
// draws requested UI elements
|
||||
void
|
||||
render();
|
||||
//
|
||||
static
|
||||
void
|
||||
set_cursor( int const Mode );
|
||||
// stores operation progress
|
||||
@@ -70,12 +81,15 @@ public:
|
||||
void
|
||||
clear_texts() { m_panels.clear(); }
|
||||
void
|
||||
push_back( std::shared_ptr<ui_panel> Panel ) { m_panels.emplace_back( Panel ); }
|
||||
push_back( ui_panel *Panel ) { m_panels.emplace_back( Panel ); }
|
||||
|
||||
// members:
|
||||
protected:
|
||||
// members
|
||||
static GLFWwindow *m_window;
|
||||
static bool m_cursorvisible;
|
||||
|
||||
private:
|
||||
// methods:
|
||||
// methods
|
||||
// draws background quad with specified earlier texture
|
||||
void
|
||||
render_background();
|
||||
@@ -94,11 +108,9 @@ private:
|
||||
// draws a quad between coordinates x,y and z,w with uv-coordinates spanning 0-1
|
||||
void
|
||||
quad( glm::vec4 const &Coordinates, glm::vec4 const &Color );
|
||||
|
||||
// members:
|
||||
GLFWwindow *m_window { nullptr };
|
||||
GLint m_textureunit{ GL_TEXTURE0 };
|
||||
GLuint m_fontbase { (GLuint)-1 }; // numer DL dla znaków w napisach
|
||||
// members
|
||||
static GLint m_textureunit;
|
||||
static GLuint m_fontbase; // numer DL dla znaków w napisach
|
||||
|
||||
// progress bar config. TODO: put these together into an object
|
||||
float m_progress { 0.0f }; // percentage of filled progres bar, to indicate lengthy operations.
|
||||
@@ -108,16 +120,6 @@ private:
|
||||
|
||||
texture_handle m_background { null_handle }; // path to texture used as the background. size depends on mAspect.
|
||||
GLuint m_texture { 0 };
|
||||
std::vector<std::shared_ptr<ui_panel> > m_panels;
|
||||
std::vector<ui_panel *> m_panels;
|
||||
std::string m_tooltip;
|
||||
// TODO: clean these legacy components up
|
||||
std::shared_ptr<ui_panel> UIHeader; // header ui panel
|
||||
std::shared_ptr<ui_panel> UITable; // schedule or scan table
|
||||
std::shared_ptr<ui_panel> UITranscripts; // voice transcripts
|
||||
int tprev; // poprzedni czas
|
||||
double VelPrev; // poprzednia prędkość
|
||||
double Acc; // przyspieszenie styczne
|
||||
bool m_cursorvisible { false };
|
||||
};
|
||||
|
||||
extern ui_layer UILayer;
|
||||
|
||||
@@ -281,7 +281,7 @@ std::string ToUpper(std::string const &text) {
|
||||
void
|
||||
win1250_to_ascii( std::string &Input ) {
|
||||
|
||||
std::unordered_map<char, char> charmap{
|
||||
std::unordered_map<char, char> const charmap {
|
||||
{ 165, 'A' }, { 198, 'C' }, { 202, 'E' }, { 163, 'L' }, { 209, 'N' }, { 211, 'O' }, { 140, 'S' }, { 143, 'Z' }, { 175, 'Z' },
|
||||
{ 185, 'a' }, { 230, 'c' }, { 234, 'e' }, { 179, 'l' }, { 241, 'n' }, { 243, 'o' }, { 156, 's' }, { 159, 'z' }, { 191, 'z' }
|
||||
};
|
||||
@@ -293,23 +293,33 @@ win1250_to_ascii( std::string &Input ) {
|
||||
}
|
||||
|
||||
// Ra: tymczasowe rozwiązanie kwestii zagranicznych (czeskich) napisów
|
||||
char bezogonkowo[] = "E?,?\"_++?%S<STZZ?`'\"\".--??s>stzz"
|
||||
char charsetconversiontable[] =
|
||||
"E?,?\"_++?%S<STZZ?`'\"\".--??s>stzz"
|
||||
" ^^L$A|S^CS<--RZo±,l'uP.,as>L\"lz"
|
||||
"RAAAALCCCEEEEIIDDNNOOOOxRUUUUYTB"
|
||||
"raaaalccceeeeiiddnnoooo-ruuuuyt?";
|
||||
|
||||
std::string Bezogonkow(std::string str, bool _)
|
||||
{ // wycięcie liter z ogonkami, bo OpenGL nie umie wyświetlić
|
||||
for (unsigned int i = 1; i < str.length(); ++i)
|
||||
if (str[i] & 0x80)
|
||||
str[i] = bezogonkowo[str[i] & 0x7F];
|
||||
else if (str[i] < ' ') // znaki sterujące nie są obsługiwane
|
||||
str[i] = ' ';
|
||||
else if (_)
|
||||
if (str[i] == '_') // nazwy stacji nie mogą zawierać spacji
|
||||
str[i] = ' '; // więc trzeba wyświetlać inaczej
|
||||
return str;
|
||||
};
|
||||
// wycięcie liter z ogonkami
|
||||
std::string Bezogonkow(std::string Input, bool const Underscorestospaces) {
|
||||
|
||||
char const extendedcharsetbit { static_cast<char>( 0x80 ) };
|
||||
char const space { ' ' };
|
||||
char const underscore { '_' };
|
||||
|
||||
for( auto &input : Input ) {
|
||||
if( input & extendedcharsetbit ) {
|
||||
input = charsetconversiontable[ input ^ extendedcharsetbit ];
|
||||
}
|
||||
else if( input < space ) {
|
||||
input = space;
|
||||
}
|
||||
else if( Underscorestospaces && ( input == underscore ) ) {
|
||||
input = space;
|
||||
}
|
||||
}
|
||||
|
||||
return Input;
|
||||
}
|
||||
|
||||
template <>
|
||||
bool
|
||||
|
||||
@@ -130,7 +130,7 @@ std::string ToUpper(std::string const &text);
|
||||
// replaces polish letters with basic ascii
|
||||
void win1250_to_ascii( std::string &Input );
|
||||
// TODO: unify with win1250_to_ascii()
|
||||
std::string Bezogonkow( std::string str, bool _ = false );
|
||||
std::string Bezogonkow( std::string Input, bool const Underscorestospaces = false );
|
||||
|
||||
inline
|
||||
std::string
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#define VERSION_MAJOR 18
|
||||
#define VERSION_MINOR 718
|
||||
#define VERSION_MINOR 802
|
||||
#define VERSION_REVISION 0
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "stdafx.h"
|
||||
#include "World.h"
|
||||
#include "messaging.h"
|
||||
#include "utilities.h"
|
||||
|
||||
#pragma warning (disable: 4091)
|
||||
@@ -62,7 +62,7 @@ LRESULT APIENTRY WndProc( HWND hWnd, // handle for this window
|
||||
// obsługa danych przesłanych przez program sterujący
|
||||
pDane = (PCOPYDATASTRUCT)lParam;
|
||||
if( pDane->dwData == MAKE_ID4('E', 'U', '0', '7')) // sygnatura danych
|
||||
World.OnCommandGet( ( multiplayer::DaneRozkaz *)( pDane->lpData ) );
|
||||
multiplayer::OnCommandGet( ( multiplayer::DaneRozkaz *)( pDane->lpData ) );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user