refactoring: basic application code wrapper

This commit is contained in:
tmj-fstate
2018-07-14 23:44:27 +02:00
parent 12d70fe320
commit ed1e0d8a10
41 changed files with 1043 additions and 837 deletions

View File

@@ -18,6 +18,7 @@ http://mozilla.org/MPL/2.0/.
#include "renderer.h"
#include "MdlMngr.h"
#include "simulation.h"
#include "simulationtime.h"
#include "Globals.h"
#include "Timer.h"
#include "Logs.h"

View File

@@ -47,7 +47,7 @@ class TEvent;
class TAnimContainer
{ // opakowanie submodelu, określające animację egzemplarza - obsługiwane jako lista
friend class TAnimModel;
friend TAnimModel;
private:
Math3D::vector3 vRotateAngles; // dla obrotów Eulera
@@ -124,8 +124,8 @@ class TAnimAdvanced
// opakowanie modelu, określające stan egzemplarza
class TAnimModel : public scene::basic_node {
friend class opengl_renderer;
friend class ui_layer;
friend opengl_renderer;
friend ui_layer;
public:
// constructors

View File

@@ -12,6 +12,7 @@ http://mozilla.org/MPL/2.0/.
//---------------------------------------------------------------------------
// Ra: zestaw klas do robienia wskaźników, aby uporządkować nagłówki
//---------------------------------------------------------------------------
class opengl_renderer;
class TTrack; // odcinek trajektorii
class TEvent;
class TTrain; // pojazd sterowany
@@ -29,8 +30,9 @@ class TTraction; // drut
class TTractionPowerSource; // zasilanie drutów
class TWorld;
class TCamera;
class simulation_time;
class scenario_time;
class TMoverParameters;
class ui_layer;
namespace scene {
struct node_data;

View File

@@ -10,6 +10,7 @@ http://mozilla.org/MPL/2.0/.
#include "stdafx.h"
#include "Console.h"
#include "Globals.h"
#include "application.h"
#include "LPT.h"
#include "Logs.h"
#include "PoKeys55.h"
@@ -247,7 +248,7 @@ void Console::BitsUpdate(int mask)
bool Console::Pressed(int x)
{ // na razie tak - czyta się tylko klawiatura
if (glfwGetKey(Global.window, x) == GLFW_TRUE)
if (glfwGetKey(Application.window(), x) == GLFW_TRUE)
return true;
else
return false;

View File

@@ -22,10 +22,11 @@ http://mozilla.org/MPL/2.0/.
#include "DynObj.h"
#include "Event.h"
#include "MemCell.h"
#include "World.h"
#include "utilities.h"
#include "McZapkie/MOVER.h"
#include "world.h"
#include "simulationtime.h"
#include "track.h"
#include "station.h"
#include "utilities.h"
#define LOGVELOCITY 0
#define LOGORDERS 1

View File

@@ -157,7 +157,7 @@ struct material_data {
class TDynamicObject { // klasa pojazdu
friend class opengl_renderer;
friend opengl_renderer;
public:
static bool bDynamicRemove; // moved from ground

468
EU07.cpp
View File

@@ -7,8 +7,8 @@ obtain one at
http://mozilla.org/MPL/2.0/.
*/
/*
MaSzyna EU07 locomotive simulator
Copyright (C) 2001-2004 Marcin Wozniak, Maciej Czapkiewicz and others
MaSzyna EU07 locomotive simulator
Copyright (C) 2001-2004 Marcin Wozniak, Maciej Czapkiewicz and others
*/
/*
Authors:
@@ -16,475 +16,27 @@ MarcinW, McZapkie, Shaxbee, ABu, nbmx, youBy, Ra, winger, mamut, Q424,
Stele, firleju, szociu, hunter, ZiomalCl, OLI_EU and others
*/
#include "stdafx.h"
#ifdef CAN_I_HAS_LIBPNG
#include <png.h>
#endif
#include "World.h"
#include "simulation.h"
#include "sceneeditor.h"
#include "Globals.h"
#include "timer.h"
#include "Logs.h"
#include "renderer.h"
#include "uilayer.h"
#include "audiorenderer.h"
#include "keyboardinput.h"
#include "mouseinput.h"
#include "gamepadinput.h"
#include "Console.h"
#include "uart.h"
#include "PyInt.h"
#ifdef EU07_BUILD_STATIC
#pragma comment( lib, "glfw3.lib" )
#pragma comment( lib, "glew32s.lib" )
#else
#ifdef _WIN32
#pragma comment( lib, "glfw3dll.lib" )
#else
#pragma comment( lib, "glfw3.lib" )
#endif
#pragma comment( lib, "glew32.lib" )
#endif // build_static
#pragma comment( lib, "opengl32.lib" )
#pragma comment( lib, "glu32.lib" )
#pragma comment( lib, "openal32.lib")
#pragma comment( lib, "setupapi.lib" )
#pragma comment( lib, "python27.lib" )
#pragma comment( lib, "libserialport-0.lib" )
#pragma comment (lib, "dbghelp.lib")
#pragma comment (lib, "version.lib")
#ifdef CAN_I_HAS_LIBPNG
#pragma comment (lib, "libpng16.lib")
#endif
#include "application.h"
#include "logs.h"
#ifdef _MSC_VER
#pragma comment(linker, "/subsystem:windows /ENTRY:mainCRTStartup")
#endif
TWorld World;
int main( int argc, char *argv[] ) {
namespace input {
keyboard_input Keyboard;
mouse_input Mouse;
gamepad_input Gamepad;
glm::dvec2 mouse_pickmodepos; // stores last mouse position in control picking mode
std::unique_ptr<uart_input> uart;
user_command command; // currently issued control command, if any
}
#ifdef CAN_I_HAS_LIBPNG
void screenshot_save_thread( char *img )
{
png_image png;
memset(&png, 0, sizeof(png_image));
png.version = PNG_IMAGE_VERSION;
png.width = Global.iWindowWidth;
png.height = Global.iWindowHeight;
png.format = PNG_FORMAT_RGB;
char datetime[64];
time_t timer;
struct tm* tm_info;
time(&timer);
tm_info = localtime(&timer);
strftime(datetime, 64, "%Y-%m-%d_%H-%M-%S", tm_info);
uint64_t perf;
QueryPerformanceCounter((LARGE_INTEGER*)&perf);
std::string filename = "screenshots/" + std::string(datetime) +
"_" + std::to_string(perf) + ".png";
if (png_image_write_to_file(&png, filename.c_str(), 0, img, -Global.iWindowWidth * 3, nullptr) == 1)
WriteLog("saved " + filename + ".");
else
WriteLog("failed to save screenshot.");
delete[] img;
}
void make_screenshot()
{
char *img = new char[Global.iWindowWidth * Global.iWindowHeight * 3];
glReadPixels(0, 0, Global.iWindowWidth, Global.iWindowHeight, GL_RGB, GL_UNSIGNED_BYTE, (GLvoid*)img);
std::thread t(screenshot_save_thread, img);
t.detach();
}
#endif
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?
Global.iWindowWidth = w;
Global.iWindowHeight = h;
Global.fDistanceFactor = std::max( 0.5f, h / 768.0f ); // not sure if this is really something we want to use
glViewport(0, 0, w, 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 );
}
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
glfwGetCursorPos( window, &input::mouse_pickmodepos.x, &input::mouse_pickmodepos.y );
UILayer.set_cursor( GLFW_CURSOR_DISABLED );
glfwSetCursorPos( window, 0, 0 );
}
else {
// enter picking mode
glfwSetCursorPos( window, input::mouse_pickmodepos.x, input::mouse_pickmodepos.y );
UILayer.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
}
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 );
}
}
#ifdef _WIN32
extern "C"
{
GLFWAPI HWND glfwGetWin32Window(GLFWwindow* window);
}
LONG CALLBACK unhandled_handler(::EXCEPTION_POINTERS* e);
LRESULT APIENTRY WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
extern HWND Hwnd;
extern WNDPROC BaseWindowProc;
#endif
int main(int argc, char *argv[])
{
#if defined(_MSC_VER) && defined (_DEBUG)
// memory leaks
_CrtSetDbgFlag( _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG ) | _CRTDBG_LEAK_CHECK_DF );
// floating point operation errors
auto state = _clearfp();
state = _control87( 0, 0 );
// this will turn on FPE for #IND and zerodiv
state = _control87( state & ~( _EM_ZERODIVIDE | _EM_INVALID ), _MCW_EM );
#endif
#ifdef _WIN32
::SetUnhandledExceptionFilter( unhandled_handler );
#endif
if (!glfwInit())
return -1;
#ifdef _WIN32
DeleteFile( "log.txt" );
DeleteFile( "errors.txt" );
_mkdir("logs");
#endif
Global.LoadIniFile("eu07.ini");
// hunter-271211: ukrywanie konsoli
if( Global.iWriteLogEnabled & 2 )
{
AllocConsole();
SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), FOREGROUND_GREEN );
}
/*
std::string executable( argv[ 0 ] ); auto const pathend = executable.rfind( '\\' );
Global.ExecutableName =
( pathend != std::string::npos ?
executable.substr( executable.rfind( '\\' ) + 1 ) :
executable );
*/
// retrieve product version from the file's version data table
{
auto const fileversionsize = ::GetFileVersionInfoSize( argv[ 0 ], NULL );
std::vector<BYTE>fileversiondata; fileversiondata.resize( fileversionsize );
if( ::GetFileVersionInfo( argv[ 0 ], 0, fileversionsize, fileversiondata.data() ) ) {
struct lang_codepage {
WORD language;
WORD codepage;
} *langcodepage;
UINT datasize;
::VerQueryValue(
fileversiondata.data(),
TEXT( "\\VarFileInfo\\Translation" ),
(LPVOID*)&langcodepage,
&datasize );
std::string subblock; subblock.resize( 50 );
::StringCchPrintf(
&subblock[0], subblock.size(),
TEXT( "\\StringFileInfo\\%04x%04x\\ProductVersion" ),
langcodepage->language,
langcodepage->codepage );
VOID *stringdata;
if( ::VerQueryValue(
fileversiondata.data(),
subblock.data(),
&stringdata,
&datasize ) ) {
Global.asVersion = std::string( reinterpret_cast<char*>(stringdata) );
}
}
}
for (int i = 1; i < argc; ++i)
{
std::string token(argv[i]);
if (token == "-e3d") {
if (Global.iConvertModels > 0)
Global.iConvertModels = -Global.iConvertModels;
else
Global.iConvertModels = -7; // z optymalizacją, bananami i prawidłowym Opacity
}
else if (i + 1 < argc && token == "-s")
Global.SceneryFile = std::string(argv[++i]);
else if (i + 1 < argc && token == "-v")
{
std::string v(argv[++i]);
std::transform(v.begin(), v.end(), v.begin(), ::tolower);
Global.asHumanCtrlVehicle = v;
}
else
{
std::cout
<< "usage: " << std::string(argv[0])
<< " [-s sceneryfilepath]"
<< " [-v vehiclename]"
<< " [-e3d]"
<< std::endl;
return -1;
}
}
// match requested video mode to current to allow for
// fullwindow creation when resolution is the same
GLFWmonitor *monitor = glfwGetPrimaryMonitor();
const GLFWvidmode *vmode = glfwGetVideoMode(monitor);
glfwWindowHint(GLFW_RED_BITS, vmode->redBits);
glfwWindowHint(GLFW_GREEN_BITS, vmode->greenBits);
glfwWindowHint(GLFW_BLUE_BITS, vmode->blueBits);
glfwWindowHint(GLFW_REFRESH_RATE, vmode->refreshRate);
glfwWindowHint(GLFW_AUTO_ICONIFY, GLFW_FALSE);
if( Global.iMultisampling > 0 ) {
glfwWindowHint( GLFW_SAMPLES, 1 << Global.iMultisampling );
}
if (Global.bFullScreen)
{
// match screen dimensions with selected monitor, for 'borderless window' in fullscreen mode
Global.iWindowWidth = vmode->width;
Global.iWindowHeight = vmode->height;
}
GLFWwindow *window =
glfwCreateWindow(
Global.iWindowWidth,
Global.iWindowHeight,
Global.AppName.c_str(),
( Global.bFullScreen ?
monitor :
nullptr),
nullptr );
if (!window)
{
std::cout << "failed to create window" << std::endl;
return -1;
}
glfwMakeContextCurrent(window);
glfwSwapInterval(Global.VSync ? 1 : 0); //vsync
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); //capture cursor
glfwSetCursorPos(window, 0.0, 0.0);
glfwSetFramebufferSizeCallback(window, window_resize_callback);
glfwSetCursorPosCallback(window, cursor_pos_callback);
glfwSetMouseButtonCallback( window, mouse_button_callback );
glfwSetKeyCallback(window, key_callback);
glfwSetScrollCallback( window, scroll_callback );
glfwSetWindowFocusCallback(window, focus_callback);
{
int width, height;
glfwGetFramebufferSize(window, &width, &height);
window_resize_callback(window, width, height);
}
if (glewInit() != GLEW_OK)
{
std::cout << "failed to init GLEW" << std::endl;
return -1;
}
#ifdef _WIN32
// setup wrapper for base glfw window proc, to handle copydata messages
Hwnd = glfwGetWin32Window( window );
BaseWindowProc = (WNDPROC)::SetWindowLongPtr( Hwnd, GWLP_WNDPROC, (LONG_PTR)WndProc );
// switch off the topmost flag
::SetWindowPos( Hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE );
#endif
if( ( false == GfxRenderer.Init( window ) )
|| ( false == UILayer.init( window ) ) ) {
return -1;
}
if( Global.bSoundEnabled ) {
Global.bSoundEnabled &= audio::renderer.init();
}
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();
}
Global.pWorld = &World; // Ra: wskaźnik potrzebny do usuwania pojazdów
try {
if( false == World.Init( window ) ) {
ErrorLog( "Simulation setup failed" );
return -1;
auto result { Application.init( argc, argv ) };
if( result == 0 ) {
result = Application.run();
}
Application.exit();
return result;
}
catch( std::bad_alloc const &Error ) {
ErrorLog( "Critical error, memory allocation failure: " + std::string( Error.what() ) );
return -1;
}
#ifdef _WIN32
Console *pConsole = new Console(); // Ra: nie wiem, czy ma to sens, ale jakoś zainicjowac trzeba
#endif
if( Global.iConvertModels < 0 ) {
Global.iConvertModels = -Global.iConvertModels;
World.CreateE3D( szModelPath ); // rekurencyjne przeglądanie katalogów
World.CreateE3D( szDynamicPath, true );
} // po zrobieniu E3D odpalamy normalnie scenerię, by ją zobaczyć
#ifdef _WIN32
Console::On(); // włączenie konsoli
#endif
try {
while( ( false == glfwWindowShouldClose( window ) )
&& ( true == World.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() );
}
}
catch( std::bad_alloc const &Error ) {
ErrorLog( "Critical error, memory allocation failure: " + std::string( Error.what() ) );
return -1;
}
#ifdef _WIN32
Console::Off(); // wyłączenie konsoli (komunikacji zwrotnej)
SafeDelete( pConsole );
#endif
SafeDelete( simulation::Region );
glfwDestroyWindow(window);
glfwTerminate();
TPythonInterpreter::killInstance();
return 0;
}

View File

@@ -23,7 +23,7 @@ http://mozilla.org/MPL/2.0/.
#include "Timer.h"
#include "parser.h"
#include "Console.h"
#include "world.h"
#include "simulationtime.h"
#include "utilities.h"
//---------------------------------------------------------------------------

View File

@@ -20,7 +20,6 @@ struct global_settings {
// members
// data items
// TODO: take these out of the settings
GLFWwindow *window{ nullptr };
bool shiftState{ false }; //m7todo: brzydko
bool ctrlState{ false };
bool altState{ false };

View File

@@ -20,6 +20,7 @@ Copyright (C) 2001-2004 Marcin Wozniak, Maciej Czapkiewicz and others
#include "utilities.h"
#include "renderer.h"
#include "Timer.h"
#include "simulationtime.h"
#include "mtable.h"
#include "sn_utils.h"
//---------------------------------------------------------------------------

View File

@@ -55,10 +55,10 @@ class TSubModel
{ // klasa submodelu - pojedyncza siatka, punkt świetlny albo grupa punktów
//m7todo: zrobić normalną serializację
friend class opengl_renderer;
friend class TModel3d; // temporary workaround. TODO: clean up class content/hierarchy
friend class TDynamicObject; // temporary etc
friend class scene::shape_node; // temporary etc
friend opengl_renderer;
friend TModel3d; // temporary workaround. TODO: clean up class content/hierarchy
friend TDynamicObject; // temporary etc
friend scene::shape_node; // temporary etc
public:
enum normalization {
@@ -218,7 +218,7 @@ public:
class TModel3d
{
friend class opengl_renderer;
friend opengl_renderer;
private:
TSubModel *Root; // drzewo submodeli

View File

@@ -126,9 +126,9 @@ private:
// trajektoria ruchu - opakowanie
class TTrack : public scene::basic_node {
friend class opengl_renderer;
friend opengl_renderer;
// NOTE: temporary arrangement
friend class ui_layer;
friend ui_layer;
private:
TIsolated * pIsolated = nullptr; // obwód izolowany obsługujący zajęcia/zwolnienia grupy torów

View File

@@ -20,7 +20,7 @@ class TTractionPowerSource;
class TTraction : public scene::basic_node {
friend class opengl_renderer;
friend opengl_renderer;
public: // na razie
TTractionPowerSource *psPower[ 2 ] { nullptr, nullptr }; // najbliższe zasilacze z obu kierunków

View File

@@ -17,7 +17,7 @@ http://mozilla.org/MPL/2.0/.
#include "Globals.h"
#include "simulation.h"
#include "world.h"
#include "simulationtime.h"
#include "camera.h"
#include "Logs.h"
#include "MdlMngr.h"

206
World.cpp
View File

@@ -16,7 +16,9 @@ http://mozilla.org/MPL/2.0/.
#include "World.h"
#include "Globals.h"
#include "application.h"
#include "simulation.h"
#include "simulationtime.h"
#include "Logs.h"
#include "MdlMngr.h"
#include "renderer.h"
@@ -33,188 +35,13 @@ http://mozilla.org/MPL/2.0/.
//---------------------------------------------------------------------------
namespace simulation {
simulation_time Time;
basic_station Station;
}
TWorld World;
extern "C"
{
GLFWAPI HWND glfwGetWin32Window( GLFWwindow* window ); //m7todo: potrzebne do directsound
}
void
simulation_time::init() {
char monthdaycounts[ 2 ][ 13 ] = {
{ 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
{ 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } };
::memcpy( m_monthdaycounts, monthdaycounts, sizeof( monthdaycounts ) );
// potentially adjust scenario clock
auto const requestedtime { clamp_circular<int>( m_time.wHour * 60 + m_time.wMinute + Global.ScenarioTimeOffset * 60, 24 * 60 ) };
auto const requestedhour { ( requestedtime / 60 ) % 24 };
auto const requestedminute { requestedtime % 60 };
// cache requested elements, if any
::GetLocalTime( &m_time );
if( Global.fMoveLight > 0.0 ) {
// day and month of the year can be overriden by scenario setup
daymonth( m_time.wDay, m_time.wMonth, m_time.wYear, static_cast<WORD>( Global.fMoveLight ) );
}
if( requestedhour != -1 ) { m_time.wHour = static_cast<WORD>( clamp( requestedhour, 0, 23 ) ); }
if( requestedminute != -1 ) { m_time.wMinute = static_cast<WORD>( clamp( requestedminute, 0, 59 ) ); }
// if the time is taken from the local clock leave the seconds intact, otherwise set them to zero
if( ( requestedhour != -1 )
|| ( requestedminute != 1 ) ) {
m_time.wSecond = 0;
}
m_yearday = year_day( m_time.wDay, m_time.wMonth, m_time.wYear );
// calculate time zone bias
// retrieve relevant time zone info from system registry (or fall back on supplied default)
// TODO: select timezone matching defined geographic location and/or country
struct registry_time_zone_info {
long Bias;
long StandardBias;
long DaylightBias;
SYSTEMTIME StandardDate;
SYSTEMTIME DaylightDate;
} registrytimezoneinfo = { -60, 0, -60, { 0, 10, 0, 5, 3, 0, 0, 0 }, { 0, 3, 0, 5, 2, 0, 0, 0 } };
#ifdef _WIN32
TCHAR timezonekeyname[] { TEXT( "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones\\Central European Standard Time" ) };
HKEY timezonekey { NULL };
DWORD size { sizeof( registrytimezoneinfo ) };
if( ::RegOpenKeyEx( HKEY_LOCAL_MACHINE, timezonekeyname, 0, KEY_QUERY_VALUE, &timezonekey ) == ERROR_SUCCESS ) {
::RegQueryValueEx( timezonekey, "TZI", NULL, NULL, (BYTE *)&registrytimezoneinfo, &size );
}
#endif
TIME_ZONE_INFORMATION timezoneinfo { 0 };
timezoneinfo.Bias = registrytimezoneinfo.Bias;
timezoneinfo.DaylightBias = registrytimezoneinfo.DaylightBias;
timezoneinfo.DaylightDate = registrytimezoneinfo.DaylightDate;
timezoneinfo.StandardBias = registrytimezoneinfo.StandardBias;
timezoneinfo.StandardDate = registrytimezoneinfo.StandardDate;
auto zonebias { timezoneinfo.Bias };
if( m_yearday < year_day( timezoneinfo.DaylightDate.wDay, timezoneinfo.DaylightDate.wMonth, m_time.wYear ) ) {
zonebias += timezoneinfo.StandardBias;
}
else if( m_yearday < year_day( timezoneinfo.StandardDate.wDay, timezoneinfo.StandardDate.wMonth, m_time.wYear ) ) {
zonebias += timezoneinfo.DaylightBias;
}
else {
zonebias += timezoneinfo.StandardBias;
}
m_timezonebias = ( zonebias / 60.0 );
}
void
simulation_time::update( double const Deltatime ) {
m_milliseconds += ( 1000.0 * Deltatime );
while( m_milliseconds >= 1000.0 ) {
++m_time.wSecond;
m_milliseconds -= 1000.0;
}
m_time.wMilliseconds = std::floor( m_milliseconds );
while( m_time.wSecond >= 60 ) {
++m_time.wMinute;
m_time.wSecond -= 60;
}
while( m_time.wMinute >= 60 ) {
++m_time.wHour;
m_time.wMinute -= 60;
}
while( m_time.wHour >= 24 ) {
++m_time.wDay;
++m_time.wDayOfWeek;
if( m_time.wDayOfWeek >= 7 ) {
m_time.wDayOfWeek -= 7;
}
m_time.wHour -= 24;
}
int leap = ( m_time.wYear % 4 == 0 ) && ( m_time.wYear % 100 != 0 ) || ( m_time.wYear % 400 == 0 );
while( m_time.wDay > m_monthdaycounts[ leap ][ m_time.wMonth ] ) {
m_time.wDay -= m_monthdaycounts[ leap ][ m_time.wMonth ];
++m_time.wMonth;
// unlikely but we might've entered a new year
if( m_time.wMonth > 12 ) {
++m_time.wYear;
leap = ( m_time.wYear % 4 == 0 ) && ( m_time.wYear % 100 != 0 ) || ( m_time.wYear % 400 == 0 );
m_time.wMonth -= 12;
}
}
}
int
simulation_time::year_day( int Day, const int Month, const int Year ) const {
char const daytab[ 2 ][ 13 ] = {
{ 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
{ 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
};
int leap { ( Year % 4 == 0 ) && ( Year % 100 != 0 ) || ( Year % 400 == 0 ) };
for( int i = 1; i < Month; ++i )
Day += daytab[ leap ][ i ];
return Day;
}
void
simulation_time::daymonth( WORD &Day, WORD &Month, WORD const Year, WORD const Yearday ) {
WORD daytab[ 2 ][ 13 ] = {
{ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
{ 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
};
int leap = ( Year % 4 == 0 ) && ( Year % 100 != 0 ) || ( Year % 400 == 0 );
WORD idx = 1;
while( ( idx < 13 ) && ( Yearday >= daytab[ leap ][ idx ] ) ) {
++idx;
}
Month = idx;
Day = Yearday - daytab[ leap ][ idx - 1 ];
}
int
simulation_time::julian_day() const {
int yy = ( m_time.wYear < 0 ? m_time.wYear + 1 : m_time.wYear ) - std::floor( ( 12 - m_time.wMonth ) / 10.f );
int mm = m_time.wMonth + 9;
if( mm >= 12 ) { mm -= 12; }
int K1 = std::floor( 365.25 * ( yy + 4712 ) );
int K2 = std::floor( 30.6 * mm + 0.5 );
// for dates in Julian calendar
int JD = K1 + K2 + m_time.wDay + 59;
// for dates in Gregorian calendar; 2299160 is October 15th, 1582
const int gregorianswitchday = 2299160;
if( JD > gregorianswitchday ) {
int K3 = std::floor( std::floor( ( yy * 0.01 ) + 49 ) * 0.75 ) - 38;
JD -= K3;
}
return JD;
}
TWorld::TWorld()
{
Train = NULL;
@@ -254,7 +81,6 @@ bool TWorld::Init( GLFWwindow *Window ) {
auto timestart = std::chrono::system_clock::now();
window = Window;
Global.window = Window; // do WM_COPYDATA
Global.pCamera = &Camera; // Ra: wskaźnik potrzebny do likwidacji drgań
WriteLog( "\nStarting MaSzyna rail vehicle simulator (release: " + Global.asVersion + ")" );
@@ -935,7 +761,6 @@ bool TWorld::Update() {
audio::renderer.update( dt );
GfxRenderer.Update( dt );
ResourceSweep();
m_init = true;
@@ -1007,12 +832,12 @@ TWorld::Update_Camera( double const Deltatime ) {
// double modelrotate = atan2( -tempangle.x, tempangle.z );
if( ( true == Global.ctrlState )
&& ( ( glfwGetKey( Global.window, GLFW_KEY_LEFT ) == GLFW_TRUE )
|| ( glfwGetKey( Global.window, GLFW_KEY_RIGHT ) == GLFW_TRUE ) ) ) {
&& ( ( glfwGetKey( Application.window(), GLFW_KEY_LEFT ) == GLFW_TRUE )
|| ( glfwGetKey( Application.window(), GLFW_KEY_RIGHT ) == GLFW_TRUE ) ) ) {
// jeśli lusterko lewe albo prawe (bez rzucania na razie)
Global.CabWindowOpen = true;
auto const lr { glfwGetKey( Global.window, GLFW_KEY_LEFT ) == GLFW_TRUE };
auto const lr { glfwGetKey( Application.window(), GLFW_KEY_LEFT ) == GLFW_TRUE };
// Camera.Yaw powinno być wyzerowane, aby po powrocie patrzeć do przodu
Camera.Pos = Controlled->GetPosition() + Train->MirrorPosition( lr ); // pozycja lusterka
Camera.Yaw = 0; // odchylenie na bok od Camera.LookAt
@@ -1079,13 +904,6 @@ void TWorld::Update_Environment() {
Environment.update();
}
void TWorld::ResourceSweep()
{
/*
ResourceManager::Sweep( Timer::GetSimulationTime() );
*/
};
//---------------------------------------------------------------------------
void TWorld::OnCommandGet(multiplayer::DaneRozkaz *pRozkaz)
{ // odebranie komunikatu z serwera
@@ -1445,11 +1263,11 @@ TWorld::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" } };
{ 65, "winter:" },
{ 158, "spring:" },
{ 252, "summer:" },
{ 341, "autumn:" },
{ 366, "winter:" } };
auto const lookup =
std::lower_bound(
std::begin( seasonsequence ), std::end( seasonsequence ),
@@ -1457,7 +1275,7 @@ TWorld::compute_season( int const Yearday ) const {
[]( dayseasonpair const &Left, const int Right ) {
return Left.first < Right; } );
Global.Season = lookup->second + ":";
Global.Season = lookup->second;
// season can affect the weather so if it changes, re-calculate weather as well
compute_weather();
}

49
World.h
View File

@@ -20,52 +20,6 @@ http://mozilla.org/MPL/2.0/.
#include "stars.h"
#include "skydome.h"
#include "messaging.h"
#include "station.h"
// wrapper for simulation time
class simulation_time {
public:
simulation_time() { m_time.wHour = 10; m_time.wMinute = 30; }
void
init();
void
update( double const Deltatime );
SYSTEMTIME &
data() { return m_time; }
SYSTEMTIME const &
data() const { return m_time; }
double
second() const { return ( m_time.wMilliseconds * 0.001 + m_time.wSecond ); }
int
year_day() const { return m_yearday; }
// helper, calculates day of year from given date
int
year_day( int Day, int const Month, int const Year ) const;
int
julian_day() const;
double
zone_bias() const { return m_timezonebias; }
private:
// calculates day and month from given day of year
void
daymonth( WORD &Day, WORD &Month, WORD const Year, WORD const Yearday );
SYSTEMTIME m_time;
double m_milliseconds{ 0.0 };
int m_yearday;
char m_monthdaycounts[ 2 ][ 13 ];
double m_timezonebias{ 0.0 };
};
namespace simulation {
extern simulation_time Time;
extern basic_station Station; // temporary object, for station functionality tests
}
// wrapper for environment elements -- sky, sun, stars, clouds etc
class world_environment {
@@ -126,7 +80,6 @@ TWorld();
private:
void Update_Environment();
void Update_Camera( const double Deltatime );
void ResourceSweep();
// handles vehicle change flag
void ChangeDynamic();
void InOutKey( bool const Near = true );
@@ -154,5 +107,7 @@ private:
GLFWwindow *window;
};
extern TWorld World;
//---------------------------------------------------------------------------

514
application.cpp Normal file
View File

@@ -0,0 +1,514 @@
/*
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 "application.h"
#include "globals.h"
#include "keyboardinput.h"
#include "mouseinput.h"
#include "gamepadinput.h"
#include "console.h"
#include "simulation.h"
#include "world.h"
#include "pyint.h"
#include "sceneeditor.h"
#include "renderer.h"
#include "uilayer.h"
#include "logs.h"
#ifdef EU07_BUILD_STATIC
#pragma comment( lib, "glfw3.lib" )
#pragma comment( lib, "glew32s.lib" )
#else
#ifdef _WIN32
#pragma comment( lib, "glfw3dll.lib" )
#else
#pragma comment( lib, "glfw3.lib" )
#endif
#pragma comment( lib, "glew32.lib" )
#endif // build_static
#pragma comment( lib, "opengl32.lib" )
#pragma comment( lib, "glu32.lib" )
#pragma comment( lib, "openal32.lib")
#pragma comment( lib, "setupapi.lib" )
#pragma comment( lib, "python27.lib" )
#pragma comment( lib, "libserialport-0.lib" )
#pragma comment (lib, "dbghelp.lib")
#pragma comment (lib, "version.lib")
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
}
#ifdef _WIN32
extern "C"
{
GLFWAPI HWND glfwGetWin32Window( GLFWwindow* window );
}
LONG CALLBACK unhandled_handler( ::EXCEPTION_POINTERS* e );
LRESULT APIENTRY WndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
extern HWND Hwnd;
extern WNDPROC BaseWindowProc;
#endif
// user input callbacks
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?
Global.iWindowWidth = w;
Global.iWindowHeight = h;
Global.fDistanceFactor = std::max( 0.5f, h / 768.0f ); // not sure if this is really something we want to use
glViewport( 0, 0, w, 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 );
}
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
}
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 );
}
}
// public:
int
eu07_application::init( int Argc, char *Argv[] ) {
int result { 0 };
init_debug();
init_files();
if( ( result = init_settings( Argc, Argv ) ) != 0 ) {
return result;
}
if( ( result = init_glfw() ) != 0 ) {
return result;
}
init_callbacks();
if( ( result = init_gfx() ) != 0 ) {
return result;
}
if( ( result = init_audio() ) != 0 ) {
return result;
}
return result;
}
int
eu07_application::run() {
// 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 );
// main application loop
// TODO: split into parts and delegate these to application mode member
while( ( false == glfwWindowShouldClose( m_window ) )
&& ( true == World.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;
}
void
eu07_application::exit() {
#ifdef _WIN32
Console::Off(); // wyłączenie konsoli (komunikacji zwrotnej)
#endif
SafeDelete( simulation::Region );
glfwDestroyWindow( m_window );
glfwTerminate();
TPythonInterpreter::killInstance();
}
void
eu07_application::set_cursor( int const Mode ) {
UILayer.set_cursor( Mode );
}
void
eu07_application::set_cursor_pos( double const X, double const Y ) {
if( m_window != nullptr ) {
glfwSetCursorPos( m_window, X, Y );
}
}
void
eu07_application::get_cursor_pos( double &X, double &Y ) const {
if( m_window != nullptr ) {
glfwGetCursorPos( m_window, &X, &Y );
}
}
// private:
void
eu07_application::init_debug() {
#if defined(_MSC_VER) && defined (_DEBUG)
// memory leaks
_CrtSetDbgFlag( _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG ) | _CRTDBG_LEAK_CHECK_DF );
// floating point operation errors
auto state { _clearfp() };
state = _control87( 0, 0 );
// this will turn on FPE for #IND and zerodiv
state = _control87( state & ~( _EM_ZERODIVIDE | _EM_INVALID ), _MCW_EM );
#endif
#ifdef _WIN32
::SetUnhandledExceptionFilter( unhandled_handler );
#endif
}
void
eu07_application::init_files() {
#ifdef _WIN32
DeleteFile( "log.txt" );
DeleteFile( "errors.txt" );
_mkdir( "logs" );
#endif
}
int
eu07_application::init_settings( int Argc, char *Argv[] ) {
Global.LoadIniFile( "eu07.ini" );
if( ( Global.iWriteLogEnabled & 2 ) != 0 ) {
// show output console if requested
AllocConsole();
}
/*
std::string executable( argv[ 0 ] ); auto const pathend = executable.rfind( '\\' );
Global.ExecutableName =
( pathend != std::string::npos ?
executable.substr( executable.rfind( '\\' ) + 1 ) :
executable );
*/
#ifdef _WIN32
// retrieve product version from the file's version data table
{
auto const fileversionsize { ::GetFileVersionInfoSize( Argv[ 0 ], NULL ) };
std::vector<BYTE>fileversiondata; fileversiondata.resize( fileversionsize );
if( ::GetFileVersionInfo( Argv[ 0 ], 0, fileversionsize, fileversiondata.data() ) ) {
struct lang_codepage {
WORD language;
WORD codepage;
} *langcodepage;
UINT datasize;
::VerQueryValue(
fileversiondata.data(),
TEXT( "\\VarFileInfo\\Translation" ),
(LPVOID*)&langcodepage,
&datasize );
std::string subblock; subblock.resize( 50 );
::StringCchPrintf(
&subblock[0], subblock.size(),
TEXT( "\\StringFileInfo\\%04x%04x\\ProductVersion" ),
langcodepage->language,
langcodepage->codepage );
VOID *stringdata;
if( ::VerQueryValue(
fileversiondata.data(),
subblock.data(),
&stringdata,
&datasize ) ) {
Global.asVersion = std::string( reinterpret_cast<char*>(stringdata) );
}
}
}
#endif
// process command line arguments
for( int i = 1; i < Argc; ++i ) {
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( i + 1 < Argc ) {
Global.SceneryFile = Argv[ ++i ];
}
}
else if( token == "-v" ) {
if( i + 1 < Argc ) {
Global.asHumanCtrlVehicle = Argv[ ++i ];
}
}
else {
std::cout
<< "usage: " << std::string( Argv[ 0 ] )
<< " [-s sceneryfilepath]"
<< " [-v vehiclename]"
<< " [-e3d]"
<< std::endl;
return -1;
}
}
return 0;
}
int
eu07_application::init_glfw() {
if( glfwInit() == GLFW_FALSE ) {
ErrorLog( "Bad init: failed to initialize glfw" );
return -1;
}
// match requested video mode to current to allow for
// fullwindow creation when resolution is the same
auto *monitor { glfwGetPrimaryMonitor() };
auto const *vmode { glfwGetVideoMode( monitor ) };
glfwWindowHint( GLFW_RED_BITS, vmode->redBits );
glfwWindowHint( GLFW_GREEN_BITS, vmode->greenBits );
glfwWindowHint( GLFW_BLUE_BITS, vmode->blueBits );
glfwWindowHint( GLFW_REFRESH_RATE, vmode->refreshRate );
glfwWindowHint( GLFW_AUTO_ICONIFY, GLFW_FALSE );
if( Global.iMultisampling > 0 ) {
glfwWindowHint( GLFW_SAMPLES, 1 << Global.iMultisampling );
}
if( Global.bFullScreen ) {
// match screen dimensions with selected monitor, for 'borderless window' in fullscreen mode
Global.iWindowWidth = vmode->width;
Global.iWindowHeight = vmode->height;
}
auto *window {
glfwCreateWindow(
Global.iWindowWidth,
Global.iWindowHeight,
Global.AppName.c_str(),
( Global.bFullScreen ?
monitor :
nullptr ),
nullptr ) };
if( window == nullptr ) {
ErrorLog( "Bad init: failed to create glfw window" );
return -1;
}
glfwMakeContextCurrent( window );
glfwSwapInterval( Global.VSync ? 1 : 0 ); //vsync
#ifdef _WIN32
// setup wrapper for base glfw window proc, to handle copydata messages
Hwnd = glfwGetWin32Window( window );
BaseWindowProc = ( WNDPROC )::SetWindowLongPtr( Hwnd, GWLP_WNDPROC, (LONG_PTR)WndProc );
// 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;
}
void
eu07_application::init_callbacks() {
glfwSetFramebufferSizeCallback( m_window, window_resize_callback );
glfwSetCursorPosCallback( m_window, cursor_pos_callback );
glfwSetMouseButtonCallback( m_window, mouse_button_callback );
glfwSetKeyCallback( m_window, key_callback );
glfwSetScrollCallback( m_window, scroll_callback );
glfwSetWindowFocusCallback( m_window, focus_callback );
{
int width, height;
glfwGetFramebufferSize( m_window, &width, &height );
window_resize_callback( m_window, width, height );
}
}
int
eu07_application::init_gfx() {
if( glewInit() != GLEW_OK ) {
ErrorLog( "Bad init: failed to initialize glew" );
return -1;
}
if( ( false == GfxRenderer.Init( m_window ) )
|| ( false == UILayer.init( m_window ) ) ) {
return -1;
}
return 0;
}
int
eu07_application::init_audio() {
if( Global.bSoundEnabled ) {
Global.bSoundEnabled &= audio::renderer.init();
}
// NOTE: lack of audio isn't deemed a failure serious enough to throw in the towel
return 0;
}

46
application.h Normal file
View File

@@ -0,0 +1,46 @@
/*
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/.
*/
class eu07_application {
public:
// constructors
eu07_application() = default;
// methods
int
init( int Argc, char *Argv[] );
int
run();
void
exit();
void
set_cursor( int const Mode );
void
set_cursor_pos( double const X, double const Y );
void
get_cursor_pos( double &X, double &Y ) const;
inline
GLFWwindow *
window() {
return m_window; }
private:
// methods
void init_debug();
void init_files();
int init_settings( int Argc, char *Argv[] );
int init_glfw();
void init_callbacks();
int init_gfx();
int init_audio();
// members
GLFWwindow * m_window { nullptr };
};
extern eu07_application Application;

View File

@@ -13,6 +13,7 @@ http://mozilla.org/MPL/2.0/.
#include "resourcemanager.h"
#include "uitranscripts.h"
class opengl_renderer;
class sound_source;
using uint32_sequence = std::vector<std::uint32_t>;
@@ -100,7 +101,7 @@ private:
class openal_renderer {
friend class opengl_renderer;
friend opengl_renderer;
public:
// constructors

View File

@@ -12,9 +12,6 @@ http://mozilla.org/MPL/2.0/.
#include "globals.h"
#include "logs.h"
#include "parser.h"
#include "world.h"
extern TWorld World;
bool
keyboard_input::recall_bindings() {

View File

@@ -51,9 +51,6 @@
<ClCompile Include="DynObj.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="EU07.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Event.cpp">
<Filter>Source Files</Filter>
</ClCompile>
@@ -246,6 +243,15 @@
<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>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Globals.h">
@@ -476,6 +482,12 @@
<ClInclude Include="sceneeditor.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="simulationtime.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="application.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="maszyna.rc">

View File

@@ -11,6 +11,7 @@ http://mozilla.org/MPL/2.0/.
#include "messaging.h"
#include "globals.h"
#include "application.h"
#include "simulation.h"
#include "mtable.h"
#include "logs.h"
@@ -51,7 +52,7 @@ WyslijEvent(const std::string &e, const std::string &d)
cData.dwData = MAKE_ID4( 'E', 'U', '0', '7' ); // sygnatura
cData.cbData = (DWORD)(12 + i + j); // 8+dwa liczniki i dwa zera kończące
cData.lpData = &r;
Navigate( "TEU07SRK", WM_COPYDATA, (WPARAM)glfwGetWin32Window( Global.window ), (LPARAM)&cData );
Navigate( "TEU07SRK", WM_COPYDATA, (WPARAM)glfwGetWin32Window( Application.window() ), (LPARAM)&cData );
CommLog( Now() + " " + std::to_string(r.iComm) + " " + e + " sent" );
#endif
}
@@ -71,7 +72,7 @@ WyslijUszkodzenia(const std::string &t, char fl)
cData.dwData = MAKE_ID4( 'E', 'U', '0', '7' ); // sygnatura
cData.cbData = (DWORD)(11 + i); // 8+licznik i zero kończące
cData.lpData = &r;
Navigate( "TEU07SRK", WM_COPYDATA, (WPARAM)glfwGetWin32Window( Global.window ), (LPARAM)&cData );
Navigate( "TEU07SRK", WM_COPYDATA, (WPARAM)glfwGetWin32Window( Application.window() ), (LPARAM)&cData );
CommLog( Now() + " " + std::to_string(r.iComm) + " " + t + " sent");
#endif
}
@@ -90,7 +91,7 @@ WyslijString(const std::string &t, int n)
cData.dwData = MAKE_ID4( 'E', 'U', '0', '7' ); // sygnatura
cData.cbData = (DWORD)(10 + i); // 8+licznik i zero kończące
cData.lpData = &r;
Navigate( "TEU07SRK", WM_COPYDATA, (WPARAM)glfwGetWin32Window( Global.window ), (LPARAM)&cData );
Navigate( "TEU07SRK", WM_COPYDATA, (WPARAM)glfwGetWin32Window( Application.window() ), (LPARAM)&cData );
CommLog( Now() + " " + std::to_string(r.iComm) + " " + t + " sent");
#endif
}
@@ -174,7 +175,7 @@ WyslijNamiary(TDynamicObject const *Vehicle)
cData.cbData = (DWORD)(10 + i + j); // 8+licznik i zero kończące
cData.lpData = &r;
// WriteLog("Ramka gotowa");
Navigate( "TEU07SRK", WM_COPYDATA, (WPARAM)glfwGetWin32Window( Global.window ), (LPARAM)&cData );
Navigate( "TEU07SRK", WM_COPYDATA, (WPARAM)glfwGetWin32Window( Application.window() ), (LPARAM)&cData );
// WriteLog("Ramka poszla!");
CommLog( Now() + " " + std::to_string(r.iComm) + " " + Vehicle->asName + " sent");
#endif
@@ -223,7 +224,7 @@ WyslijObsadzone()
cData.cbData = 8 + 1984; // 8+licznik i zero kończące
cData.lpData = &r;
// WriteLog("Ramka gotowa");
Navigate( "TEU07SRK", WM_COPYDATA, (WPARAM)glfwGetWin32Window( Global.window ), (LPARAM)&cData );
Navigate( "TEU07SRK", WM_COPYDATA, (WPARAM)glfwGetWin32Window( Application.window() ), (LPARAM)&cData );
CommLog( Now() + " " + std::to_string(r.iComm) + " obsadzone" + " sent");
#endif
}
@@ -249,7 +250,7 @@ WyslijParam(int nr, int fl)
cData.dwData = MAKE_ID4( 'E', 'U', '0', '7' ); // sygnatura
cData.cbData = 12 + i; // 12+rozmiar danych
cData.lpData = &r;
Navigate( "TEU07SRK", WM_COPYDATA, (WPARAM)glfwGetWin32Window( Global.window ), (LPARAM)&cData );
Navigate( "TEU07SRK", WM_COPYDATA, (WPARAM)glfwGetWin32Window( Application.window() ), (LPARAM)&cData );
#endif
}

View File

@@ -4,7 +4,7 @@
#include "globals.h"
#include "mtable.h"
#include "utilities.h"
#include "world.h"
#include "simulationtime.h"
//////////////////////////////////////////////////////////////////////////////////////////
// cSun -- class responsible for dynamic calculation of position and intensity of the Sun,

View File

@@ -9,6 +9,8 @@ http://mozilla.org/MPL/2.0/.
#include "stdafx.h"
#include "mouseinput.h"
#include "application.h"
#include "utilities.h"
#include "globals.h"
#include "timer.h"
@@ -18,8 +20,6 @@ http://mozilla.org/MPL/2.0/.
#include "renderer.h"
#include "uilayer.h"
extern TWorld World;
void
mouse_slider::bind( user_command const &Command ) {
@@ -82,15 +82,14 @@ mouse_slider::bind( user_command const &Command ) {
}
}
// hide the cursor and place it in accordance with current slider value
glfwGetCursorPos( Global.window, &m_cursorposition.x, &m_cursorposition.y );
UILayer.set_cursor( GLFW_CURSOR_DISABLED );
Application.get_cursor_pos( m_cursorposition.x, m_cursorposition.y );
Application.set_cursor( GLFW_CURSOR_DISABLED );
auto const controlsize { Global.iWindowHeight * 0.75 };
auto const controledge { Global.iWindowHeight * 0.5 + controlsize * 0.5 };
auto const stepsize { controlsize / m_valuerange };
glfwSetCursorPos(
Global.window,
Application.set_cursor_pos(
Global.iWindowWidth * 0.5,
( m_analogue ?
controledge - ( 1.0 - m_value ) * controlsize :
@@ -101,8 +100,8 @@ void
mouse_slider::release() {
m_command = user_command::none;
glfwSetCursorPos( Global.window, m_cursorposition.x, m_cursorposition.y );
UILayer.set_cursor( GLFW_CURSOR_NORMAL );
Application.set_cursor_pos( m_cursorposition.x, m_cursorposition.y );
Application.set_cursor( GLFW_CURSOR_NORMAL );
}
void
@@ -525,10 +524,10 @@ mouse_input::default_bindings() {
user_command::pantographtogglerear,
user_command::none } },
{ "pantfrontoff_sw:", {
user_command::pantographtogglefront,
user_command::pantographlowerfront,
user_command::none } }, // TODO: dedicated lower pantograph commands
{ "pantrearoff_sw:", {
user_command::pantographtogglerear,
user_command::pantographlowerrear,
user_command::none } }, // TODO: dedicated lower pantograph commands
{ "pantalloff_sw:", {
user_command::pantographlowerall,

View File

@@ -11,7 +11,7 @@ http://mozilla.org/MPL/2.0/.
#include "mtable.h"
#include "globals.h"
#include "world.h"
#include "simulationtime.h"
#include "utilities.h"
double TTrainParameters::CheckTrainLatency()
@@ -49,7 +49,7 @@ bool TTrainParameters::IsStop()
return true; // na ostatnim się zatrzymać zawsze
}
bool TTrainParameters::UpdateMTable( simulation_time const &Time, std::string const &NewName ) {
bool TTrainParameters::UpdateMTable( scenario_time const &Time, std::string const &NewName ) {
return UpdateMTable( Time.data().wHour, Time.data().wMinute, NewName );
}

View File

@@ -75,7 +75,7 @@ class TTrainParameters
bool IsStop();
bool IsTimeToGo(double hh, double mm);
bool UpdateMTable(double hh, double mm, std::string const &NewName);
bool UpdateMTable( simulation_time const &Time, std::string const &NewName );
bool UpdateMTable( scenario_time const &Time, std::string const &NewName );
bool RewindTimeTable( std::string actualStationName );
TTrainParameters( std::string const &NewTrainName );
void NewName(std::string const &NewTrainName);

View File

@@ -14,6 +14,7 @@ http://mozilla.org/MPL/2.0/.
#include "globals.h"
#include "timer.h"
#include "simulation.h"
#include "simulationtime.h"
#include "world.h"
#include "train.h"
#include "dynobj.h"
@@ -24,7 +25,6 @@ http://mozilla.org/MPL/2.0/.
#include "utilities.h"
opengl_renderer GfxRenderer;
extern TWorld World;
int const EU07_PICKBUFFERSIZE { 1024 }; // size of (square) textures bound with the pick framebuffer
int const EU07_ENVIRONMENTBUFFERSIZE { 256 }; // size of (square) environmental cube map texture

View File

@@ -60,7 +60,7 @@ struct scratch_data {
// TBD, TODO: replace with quadtree scheme?
class basic_cell {
friend class opengl_renderer;
friend opengl_renderer;
public:
// constructors
@@ -198,7 +198,7 @@ private:
// basic scene partitioning structure, holds terrain geometry and collection of cells
class basic_section {
friend class opengl_renderer;
friend opengl_renderer;
public:
// constructors
@@ -302,7 +302,7 @@ private:
// top-level of scene spatial structure, holds collection of sections
class basic_region {
friend class opengl_renderer;
friend opengl_renderer;
public:
// constructors

View File

@@ -11,8 +11,8 @@ http://mozilla.org/MPL/2.0/.
#include "sceneeditor.h"
#include "globals.h"
#include "application.h"
#include "simulation.h"
#include "uilayer.h"
#include "renderer.h"
namespace scene {
@@ -47,7 +47,7 @@ basic_editor::on_mouse_button( int const Button, int const Action ) {
m_node = GfxRenderer.Update_Pick_Node();
m_nodesnapshot = { m_node };
if( m_node ) {
UILayer.set_cursor( GLFW_CURSOR_DISABLED );
Application.set_cursor( GLFW_CURSOR_DISABLED );
}
}
else {
@@ -55,7 +55,7 @@ basic_editor::on_mouse_button( int const Button, int const Action ) {
// TODO: record the current undo step on the undo stack
m_nodesnapshot = { m_node };
if( m_node ) {
UILayer.set_cursor( GLFW_CURSOR_NORMAL );
Application.set_cursor( GLFW_CURSOR_NORMAL );
}
}

View File

@@ -10,11 +10,11 @@ http://mozilla.org/MPL/2.0/.
#include "stdafx.h"
#include "simulation.h"
#include "world.h"
#include "globals.h"
#include "logs.h"
#include "simulationtime.h"
#include "uilayer.h"
#include "renderer.h"
#include "logs.h"
namespace simulation {
@@ -32,9 +32,42 @@ light_array Lights;
scene::basic_region *Region { nullptr };
bool
state_manager::deserialize( std::string const &Scenariofile ) {
return m_serializer.deserialize( Scenariofile );
}
// stores class data in specified file, in legacy (text) format
void
state_manager::export_as_text( std::string const &Scenariofile ) const {
return m_serializer.export_as_text( Scenariofile );
}
// legacy method, calculates changes in simulation state over specified time
void
state_manager::update( double const Deltatime, int Iterationcount ) {
// aktualizacja animacji krokiem FPS: dt=krok czasu [s], dt*iter=czas od ostatnich przeliczeń
if (Deltatime == 0.0) {
return;
}
auto const totaltime { Deltatime * Iterationcount };
// NOTE: we perform animations first, as they can determine factors like contact with powergrid
TAnimModel::AnimUpdate( totaltime ); // wykonanie zakolejkowanych animacji
simulation::Powergrid.update( totaltime );
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();
@@ -61,50 +94,33 @@ state_manager::deserialize( std::string const &Scenariofile ) {
return true;
}
// legacy method, calculates changes in simulation state over specified time
void
state_manager::update( double const Deltatime, int Iterationcount ) {
// aktualizacja animacji krokiem FPS: dt=krok czasu [s], dt*iter=czas od ostatnich przeliczeń
if (Deltatime == 0.0) {
// jeśli załączona jest pauza, to tylko obsłużyć ruch w kabinie trzeba
return;
}
auto const totaltime { Deltatime * Iterationcount };
// NOTE: we perform animations first, as they can determine factors like contact with powergrid
TAnimModel::AnimUpdate( totaltime ); // wykonanie zakolejkowanych animacji
simulation::Powergrid.update( totaltime );
simulation::Vehicles.update( Deltatime, Iterationcount );
}
// restores class data from provided stream
void
state_manager::deserialize( cParser &Input, scene::scratch_data &Scratchpad ) {
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_manager::*)(cParser &, scene::scratch_data &);
using deserializefunction = void( state_serializer::*)(cParser &, scene::scratch_data &);
std::vector<
std::pair<
std::string,
deserializefunction> > functionlist = {
{ "atmo", &state_manager::deserialize_atmo },
{ "camera", &state_manager::deserialize_camera },
{ "config", &state_manager::deserialize_config },
{ "description", &state_manager::deserialize_description },
{ "event", &state_manager::deserialize_event },
{ "firstinit", &state_manager::deserialize_firstinit },
{ "light", &state_manager::deserialize_light },
{ "node", &state_manager::deserialize_node },
{ "origin", &state_manager::deserialize_origin },
{ "endorigin", &state_manager::deserialize_endorigin },
{ "rotate", &state_manager::deserialize_rotate },
{ "sky", &state_manager::deserialize_sky },
{ "test", &state_manager::deserialize_test },
{ "time", &state_manager::deserialize_time },
{ "trainset", &state_manager::deserialize_trainset },
{ "endtrainset", &state_manager::deserialize_endtrainset } };
{ "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,
@@ -146,7 +162,7 @@ state_manager::deserialize( cParser &Input, scene::scratch_data &Scratchpad ) {
}
void
state_manager::deserialize_atmo( cParser &Input, scene::scratch_data &Scratchpad ) {
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
@@ -178,7 +194,7 @@ state_manager::deserialize_atmo( cParser &Input, scene::scratch_data &Scratchpad
}
void
state_manager::deserialize_camera( cParser &Input, scene::scratch_data &Scratchpad ) {
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ć
@@ -232,21 +248,21 @@ state_manager::deserialize_camera( cParser &Input, scene::scratch_data &Scratchp
}
void
state_manager::deserialize_config( cParser &Input, scene::scratch_data &Scratchpad ) {
state_serializer::deserialize_config( cParser &Input, scene::scratch_data &Scratchpad ) {
// config parameters (re)definition
Global.ConfigParse( Input );
}
void
state_manager::deserialize_description( cParser &Input, scene::scratch_data &Scratchpad ) {
state_serializer::deserialize_description( cParser &Input, scene::scratch_data &Scratchpad ) {
// legacy section, never really used;
skip_until( Input, "enddescription" );
}
void
state_manager::deserialize_event( cParser &Input, scene::scratch_data &Scratchpad ) {
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();
@@ -265,7 +281,7 @@ state_manager::deserialize_event( cParser &Input, scene::scratch_data &Scratchpa
}
void
state_manager::deserialize_firstinit( cParser &Input, scene::scratch_data &Scratchpad ) {
state_serializer::deserialize_firstinit( cParser &Input, scene::scratch_data &Scratchpad ) {
if( true == Scratchpad.initialized ) { return; }
@@ -279,14 +295,14 @@ state_manager::deserialize_firstinit( cParser &Input, scene::scratch_data &Scrat
}
void
state_manager::deserialize_light( cParser &Input, scene::scratch_data &Scratchpad ) {
state_serializer::deserialize_light( cParser &Input, scene::scratch_data &Scratchpad ) {
// legacy section, no longer used nor supported;
skip_until( Input, "endlight" );
}
void
state_manager::deserialize_node( cParser &Input, scene::scratch_data &Scratchpad ) {
state_serializer::deserialize_node( cParser &Input, scene::scratch_data &Scratchpad ) {
auto const inputline = Input.Line(); // cache in case we need to report error
@@ -469,7 +485,7 @@ state_manager::deserialize_node( cParser &Input, scene::scratch_data &Scratchpad
}
void
state_manager::deserialize_origin( cParser &Input, scene::scratch_data &Scratchpad ) {
state_serializer::deserialize_origin( cParser &Input, scene::scratch_data &Scratchpad ) {
glm::dvec3 offset;
Input.getTokens( 3 );
@@ -486,7 +502,7 @@ state_manager::deserialize_origin( cParser &Input, scene::scratch_data &Scratchp
}
void
state_manager::deserialize_endorigin( cParser &Input, scene::scratch_data &Scratchpad ) {
state_serializer::deserialize_endorigin( cParser &Input, scene::scratch_data &Scratchpad ) {
if( false == Scratchpad.location.offset.empty() ) {
Scratchpad.location.offset.pop();
@@ -497,7 +513,7 @@ state_manager::deserialize_endorigin( cParser &Input, scene::scratch_data &Scrat
}
void
state_manager::deserialize_rotate( cParser &Input, scene::scratch_data &Scratchpad ) {
state_serializer::deserialize_rotate( cParser &Input, scene::scratch_data &Scratchpad ) {
Input.getTokens( 3 );
Input
@@ -507,7 +523,7 @@ state_manager::deserialize_rotate( cParser &Input, scene::scratch_data &Scratchp
}
void
state_manager::deserialize_sky( cParser &Input, scene::scratch_data &Scratchpad ) {
state_serializer::deserialize_sky( cParser &Input, scene::scratch_data &Scratchpad ) {
// sky model
Input.getTokens( 1 );
@@ -518,14 +534,14 @@ state_manager::deserialize_sky( cParser &Input, scene::scratch_data &Scratchpad
}
void
state_manager::deserialize_test( cParser &Input, scene::scratch_data &Scratchpad ) {
state_serializer::deserialize_test( cParser &Input, scene::scratch_data &Scratchpad ) {
// legacy section, no longer supported;
skip_until( Input, "endtest" );
}
void
state_manager::deserialize_time( cParser &Input, scene::scratch_data &Scratchpad ) {
state_serializer::deserialize_time( cParser &Input, scene::scratch_data &Scratchpad ) {
// current scenario time
cParser timeparser( Input.getToken<std::string>() );
@@ -548,7 +564,7 @@ state_manager::deserialize_time( cParser &Input, scene::scratch_data &Scratchpad
}
void
state_manager::deserialize_trainset( cParser &Input, scene::scratch_data &Scratchpad ) {
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
@@ -568,7 +584,7 @@ state_manager::deserialize_trainset( cParser &Input, scene::scratch_data &Scratc
}
void
state_manager::deserialize_endtrainset( cParser &Input, scene::scratch_data &Scratchpad ) {
state_serializer::deserialize_endtrainset( cParser &Input, scene::scratch_data &Scratchpad ) {
if( ( false == Scratchpad.trainset.is_open )
|| ( true == Scratchpad.trainset.vehicles.empty() ) ) {
@@ -616,7 +632,7 @@ state_manager::deserialize_endtrainset( cParser &Input, scene::scratch_data &Scr
// creates path and its wrapper, restoring class data from provided stream
TTrack *
state_manager::deserialize_path( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ) {
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 );
@@ -633,7 +649,7 @@ state_manager::deserialize_path( cParser &Input, scene::scratch_data &Scratchpad
}
TTraction *
state_manager::deserialize_traction( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ) {
state_serializer::deserialize_traction( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ) {
if( false == Global.bLoadTraction ) {
skip_until( Input, "endtraction" );
@@ -651,7 +667,7 @@ state_manager::deserialize_traction( cParser &Input, scene::scratch_data &Scratc
}
TTractionPowerSource *
state_manager::deserialize_tractionpowersource( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ) {
state_serializer::deserialize_tractionpowersource( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ) {
if( false == Global.bLoadTraction ) {
skip_until( Input, "end" );
@@ -667,7 +683,7 @@ state_manager::deserialize_tractionpowersource( cParser &Input, scene::scratch_d
}
TMemCell *
state_manager::deserialize_memorycell( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ) {
state_serializer::deserialize_memorycell( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ) {
auto *memorycell = new TMemCell( Nodedata );
memorycell->Load( &Input );
@@ -678,7 +694,7 @@ state_manager::deserialize_memorycell( cParser &Input, scene::scratch_data &Scra
}
TEventLauncher *
state_manager::deserialize_eventlauncher( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ) {
state_serializer::deserialize_eventlauncher( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ) {
glm::dvec3 location;
Input.getTokens( 3 );
@@ -695,7 +711,7 @@ state_manager::deserialize_eventlauncher( cParser &Input, scene::scratch_data &S
}
TAnimModel *
state_manager::deserialize_model( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ) {
state_serializer::deserialize_model( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ) {
glm::dvec3 location;
glm::vec3 rotation;
@@ -721,7 +737,7 @@ state_manager::deserialize_model( cParser &Input, scene::scratch_data &Scratchpa
}
TDynamicObject *
state_manager::deserialize_dynamic( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ) {
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
@@ -846,7 +862,7 @@ state_manager::deserialize_dynamic( cParser &Input, scene::scratch_data &Scratch
}
sound_source *
state_manager::deserialize_sound( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ) {
state_serializer::deserialize_sound( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ) {
glm::dvec3 location;
Input.getTokens( 3 );
@@ -869,7 +885,7 @@ state_manager::deserialize_sound( cParser &Input, scene::scratch_data &Scratchpa
// skips content of stream until specified token
void
state_manager::skip_until( cParser &Input, std::string const &Token ) {
state_serializer::skip_until( cParser &Input, std::string const &Token ) {
std::string token { Input.getToken<std::string>() };
while( ( false == token.empty() )
@@ -881,7 +897,7 @@ state_manager::skip_until( cParser &Input, std::string const &Token ) {
// transforms provided location by specifed rotation and offset
glm::dvec3
state_manager::transform( glm::dvec3 Location, scene::scratch_data const &Scratchpad ) {
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 );
@@ -896,7 +912,7 @@ state_manager::transform( glm::dvec3 Location, scene::scratch_data const &Scratc
// stores class data in specified file, in legacy (text) format
void
state_manager::export_as_text( std::string const &Scenariofile ) const {
state_serializer::export_as_text( std::string const &Scenariofile ) const {
if( Scenariofile == "$.scn" ) {
ErrorLog( "Bad file: scenery export not supported for file \"$.scn\"" );

View File

@@ -25,15 +25,11 @@ http://mozilla.org/MPL/2.0/.
namespace simulation {
class state_manager {
class state_serializer {
public:
// types
// methods
// legacy method, calculates changes in simulation state over specified time
void
update( double Deltatime, int Iterationcount );
// 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
@@ -72,7 +68,25 @@ private:
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:
// methods
// legacy method, calculates changes in simulation state over specified time
void
update( double Deltatime, int Iterationcount );
// 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:
// members
state_serializer m_serializer;
};
extern state_manager State;

192
simulationtime.cpp Normal file
View File

@@ -0,0 +1,192 @@
/*
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 "simulationtime.h"
#include "globals.h"
#include "utilities.h"
namespace simulation {
scenario_time Time;
} // simulation
void
scenario_time::init() {
char monthdaycounts[ 2 ][ 13 ] = {
{ 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
{ 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } };
::memcpy( m_monthdaycounts, monthdaycounts, sizeof( monthdaycounts ) );
// potentially adjust scenario clock
auto const requestedtime { clamp_circular<int>( m_time.wHour * 60 + m_time.wMinute + Global.ScenarioTimeOffset * 60, 24 * 60 ) };
auto const requestedhour { ( requestedtime / 60 ) % 24 };
auto const requestedminute { requestedtime % 60 };
// cache requested elements, if any
::GetLocalTime( &m_time );
if( Global.fMoveLight > 0.0 ) {
// day and month of the year can be overriden by scenario setup
daymonth( m_time.wDay, m_time.wMonth, m_time.wYear, static_cast<WORD>( Global.fMoveLight ) );
}
if( requestedhour != -1 ) { m_time.wHour = static_cast<WORD>( clamp( requestedhour, 0, 23 ) ); }
if( requestedminute != -1 ) { m_time.wMinute = static_cast<WORD>( clamp( requestedminute, 0, 59 ) ); }
// if the time is taken from the local clock leave the seconds intact, otherwise set them to zero
if( ( requestedhour != -1 )
|| ( requestedminute != 1 ) ) {
m_time.wSecond = 0;
}
m_yearday = year_day( m_time.wDay, m_time.wMonth, m_time.wYear );
// calculate time zone bias
// retrieve relevant time zone info from system registry (or fall back on supplied default)
// TODO: select timezone matching defined geographic location and/or country
struct registry_time_zone_info {
long Bias;
long StandardBias;
long DaylightBias;
SYSTEMTIME StandardDate;
SYSTEMTIME DaylightDate;
} registrytimezoneinfo = { -60, 0, -60, { 0, 10, 0, 5, 3, 0, 0, 0 }, { 0, 3, 0, 5, 2, 0, 0, 0 } };
#ifdef _WIN32
TCHAR timezonekeyname[] { TEXT( "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones\\Central European Standard Time" ) };
HKEY timezonekey { NULL };
DWORD size { sizeof( registrytimezoneinfo ) };
if( ::RegOpenKeyEx( HKEY_LOCAL_MACHINE, timezonekeyname, 0, KEY_QUERY_VALUE, &timezonekey ) == ERROR_SUCCESS ) {
::RegQueryValueEx( timezonekey, "TZI", NULL, NULL, (BYTE *)&registrytimezoneinfo, &size );
}
#endif
TIME_ZONE_INFORMATION timezoneinfo { 0 };
timezoneinfo.Bias = registrytimezoneinfo.Bias;
timezoneinfo.DaylightBias = registrytimezoneinfo.DaylightBias;
timezoneinfo.DaylightDate = registrytimezoneinfo.DaylightDate;
timezoneinfo.StandardBias = registrytimezoneinfo.StandardBias;
timezoneinfo.StandardDate = registrytimezoneinfo.StandardDate;
auto zonebias { timezoneinfo.Bias };
if( m_yearday < year_day( timezoneinfo.DaylightDate.wDay, timezoneinfo.DaylightDate.wMonth, m_time.wYear ) ) {
zonebias += timezoneinfo.StandardBias;
}
else if( m_yearday < year_day( timezoneinfo.StandardDate.wDay, timezoneinfo.StandardDate.wMonth, m_time.wYear ) ) {
zonebias += timezoneinfo.DaylightBias;
}
else {
zonebias += timezoneinfo.StandardBias;
}
m_timezonebias = ( zonebias / 60.0 );
}
void
scenario_time::update( double const Deltatime ) {
m_milliseconds += ( 1000.0 * Deltatime );
while( m_milliseconds >= 1000.0 ) {
++m_time.wSecond;
m_milliseconds -= 1000.0;
}
m_time.wMilliseconds = std::floor( m_milliseconds );
while( m_time.wSecond >= 60 ) {
++m_time.wMinute;
m_time.wSecond -= 60;
}
while( m_time.wMinute >= 60 ) {
++m_time.wHour;
m_time.wMinute -= 60;
}
while( m_time.wHour >= 24 ) {
++m_time.wDay;
++m_time.wDayOfWeek;
if( m_time.wDayOfWeek >= 7 ) {
m_time.wDayOfWeek -= 7;
}
m_time.wHour -= 24;
}
int leap = ( m_time.wYear % 4 == 0 ) && ( m_time.wYear % 100 != 0 ) || ( m_time.wYear % 400 == 0 );
while( m_time.wDay > m_monthdaycounts[ leap ][ m_time.wMonth ] ) {
m_time.wDay -= m_monthdaycounts[ leap ][ m_time.wMonth ];
++m_time.wMonth;
// unlikely but we might've entered a new year
if( m_time.wMonth > 12 ) {
++m_time.wYear;
leap = ( m_time.wYear % 4 == 0 ) && ( m_time.wYear % 100 != 0 ) || ( m_time.wYear % 400 == 0 );
m_time.wMonth -= 12;
}
}
}
int
scenario_time::year_day( int Day, const int Month, const int Year ) const {
char const daytab[ 2 ][ 13 ] = {
{ 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
{ 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
};
int leap { ( Year % 4 == 0 ) && ( Year % 100 != 0 ) || ( Year % 400 == 0 ) };
for( int i = 1; i < Month; ++i )
Day += daytab[ leap ][ i ];
return Day;
}
void
scenario_time::daymonth( WORD &Day, WORD &Month, WORD const Year, WORD const Yearday ) {
WORD daytab[ 2 ][ 13 ] = {
{ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
{ 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
};
int leap = ( Year % 4 == 0 ) && ( Year % 100 != 0 ) || ( Year % 400 == 0 );
WORD idx = 1;
while( ( idx < 13 ) && ( Yearday >= daytab[ leap ][ idx ] ) ) {
++idx;
}
Month = idx;
Day = Yearday - daytab[ leap ][ idx - 1 ];
}
int
scenario_time::julian_day() const {
int yy = ( m_time.wYear < 0 ? m_time.wYear + 1 : m_time.wYear ) - std::floor( ( 12 - m_time.wMonth ) / 10.f );
int mm = m_time.wMonth + 9;
if( mm >= 12 ) { mm -= 12; }
int K1 = std::floor( 365.25 * ( yy + 4712 ) );
int K2 = std::floor( 30.6 * mm + 0.5 );
// for dates in Julian calendar
int JD = K1 + K2 + m_time.wDay + 59;
// for dates in Gregorian calendar; 2299160 is October 15th, 1582
const int gregorianswitchday = 2299160;
if( JD > gregorianswitchday ) {
int K3 = std::floor( std::floor( ( yy * 0.01 ) + 49 ) * 0.75 ) - 38;
JD -= K3;
}
return JD;
}
//---------------------------------------------------------------------------

66
simulationtime.h Normal file
View File

@@ -0,0 +1,66 @@
/*
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
// wrapper for scenario time
class scenario_time {
public:
scenario_time() {
m_time.wHour = 10; m_time.wMinute = 30; }
void
init();
void
update( double const Deltatime );
inline
SYSTEMTIME &
data() {
return m_time; }
inline
SYSTEMTIME const &
data() const {
return m_time; }
inline
double
second() const {
return ( m_time.wMilliseconds * 0.001 + m_time.wSecond ); }
inline
int
year_day() const {
return m_yearday; }
// helper, calculates day of year from given date
int
year_day( int Day, int const Month, int const Year ) const;
int
julian_day() const;
inline
double
zone_bias() const {
return m_timezonebias; }
private:
// calculates day and month from given day of year
void
daymonth( WORD &Day, WORD &Month, WORD const Year, WORD const Yearday );
SYSTEMTIME m_time;
double m_milliseconds{ 0.0 };
int m_yearday;
char m_monthdaycounts[ 2 ][ 13 ];
double m_timezonebias{ 0.0 };
};
namespace simulation {
extern scenario_time Time;
} // simulation
//---------------------------------------------------------------------------

2
sky.h
View File

@@ -14,7 +14,7 @@ http://mozilla.org/MPL/2.0/.
class TSky {
friend class opengl_renderer;
friend opengl_renderer;
public:
TSky() = default;

View File

@@ -8,7 +8,7 @@
class cStars {
friend class opengl_renderer;
friend opengl_renderer;
public:
// types:

View File

@@ -13,6 +13,12 @@ http://mozilla.org/MPL/2.0/.
#include "dynobj.h"
#include "mtable.h"
namespace simulation {
basic_station Station;
}
// exchanges load with consist attached to specified vehicle, operating on specified schedule
double
basic_station::update_load( TDynamicObject *First, Mtable::TTrainParameters &Schedule, int const Platform ) {

View File

@@ -19,4 +19,10 @@ public:
// exchanges load with consist attached to specified vehicle, operating on specified schedule; returns: time needed for exchange, in seconds
double
update_load( TDynamicObject *First, Mtable::TTrainParameters &Schedule, int const Platform );
};
};
namespace simulation {
extern basic_station Station; // temporary object, for station functionality tests
} // simulation

View File

@@ -4,7 +4,7 @@
#include "globals.h"
#include "mtable.h"
#include "utilities.h"
#include "world.h"
#include "simulationtime.h"
//////////////////////////////////////////////////////////////////////////////////////////
// cSun -- class responsible for dynamic calculation of position and intensity of the Sun,

View File

@@ -6,6 +6,7 @@
#include "globals.h"
#include "translation.h"
#include "simulation.h"
#include "simulationtime.h"
#include "mtable.h"
#include "train.h"
#include "sceneeditor.h"

View File

@@ -257,18 +257,24 @@ int stol_def(const std::string &str, const int &DefaultValue) {
return result;
}
std::string ToLower(std::string const &text)
{
std::string lowercase( text );
std::transform(text.begin(), text.end(), lowercase.begin(), ::tolower);
std::string ToLower(std::string const &text) {
auto lowercase { text };
std::transform(
std::begin( text ), std::end( text ),
std::begin( lowercase ),
[]( unsigned char c ) { return std::tolower( c ); } );
return lowercase;
}
std::string ToUpper(std::string const &text)
{
std::string uppercase( text );
std::transform(text.begin(), text.end(), uppercase.begin(), ::toupper);
return uppercase;
std::string ToUpper(std::string const &text) {
auto uppercase { text };
std::transform(
std::begin( text ), std::end( text ),
std::begin( uppercase ),
[]( unsigned char c ) { return std::toupper( c ); } );
return uppercase;
}
// replaces polish letters with basic ascii

View File

@@ -50,7 +50,6 @@ LONG CALLBACK unhandled_handler(::EXCEPTION_POINTERS* e)
HWND Hwnd;
WNDPROC BaseWindowProc;
PCOPYDATASTRUCT pDane;
extern TWorld World;
LRESULT APIENTRY WndProc( HWND hWnd, // handle for this window
UINT uMsg, // message for this window