16
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-07-23 01:39:19 +02:00

Merge remote-tracking branch 'tmj-fstate/mover_in_c++' into mover_in_c++

This commit is contained in:
firleju
2017-04-28 06:15:18 +02:00
54 changed files with 6625 additions and 2965 deletions

View File

@@ -10,6 +10,7 @@ http://mozilla.org/MPL/2.0/.
#include "stdafx.h"
#include "Button.h"
#include "Console.h"
#include "logs.h"
//---------------------------------------------------------------------------
@@ -57,6 +58,8 @@ void TButton::Load(cParser &Parser, TModel3d *pModel1, TModel3d *pModel2)
{
pModelOn = NULL;
pModelOff = NULL;
ErrorLog( "Failed to locate sub-model \"" + token + "\" in 3d model \"" + pModel1->NameGet() + "\"" );
}
};

View File

@@ -15,23 +15,19 @@ http://mozilla.org/MPL/2.0/.
#include "Console.h"
#include "Timer.h"
#include "mover.h"
//---------------------------------------------------------------------------
// TViewPyramid TCamera::OrgViewPyramid;
//={vector3(-1,1,1),vector3(1,1,1),vector3(-1,-1,1),vector3(1,-1,1),vector3(0,0,0)};
const vector3 OrgCrossPos = vector3(0, -10, 0);
void TCamera::Init(vector3 NPos, vector3 NAngle)
{
pOffset = vector3(-0.0, 0, 0);
vUp = vector3(0, 1, 0);
// pOffset= vector3(-0.8,0,0);
CrossPos = OrgCrossPos;
CrossDist = 10;
Velocity = vector3(0, 0, 0);
OldVelocity = vector3(0, 0, 0);
Pitch = NAngle.x;
Yaw = NAngle.y;
Roll = NAngle.z;
@@ -54,51 +50,332 @@ void TCamera::OnCursorMove(double x, double y)
if (Type == tp_Follow) // jeżeli jazda z pojazdem
{
clamp(Pitch, -M_PI_4, M_PI_4); // ograniczenie kąta spoglądania w dół i w górę
// Fix(Yaw,-M_PI,M_PI);
}
}
void
TCamera::OnCommand( command_data const &Command ) {
double const walkspeed = 1.0;
double const runspeed = ( DebugModeFlag ? 50.0 : 7.5 );
double const speedmultiplier = ( DebugModeFlag ? 7.5 : 1.0 );
switch( Command.command ) {
case user_command::viewturn: {
OnCursorMove(
reinterpret_cast<double const &>( Command.param1 ) * 0.005 * Global::fMouseXScale / Global::ZoomFactor,
reinterpret_cast<double const &>( Command.param2 ) * -0.01 * Global::fMouseYScale / Global::ZoomFactor );
break;
}
case user_command::movevector: {
auto const movespeed =
( Type == tp_Free ?
runspeed * speedmultiplier :
walkspeed );
// left-right
double const movex = reinterpret_cast<double const &>( Command.param1 );
if( movex > 0.0 ) {
m_keys.right = true;
m_keys.left = false;
}
else if( movex < 0.0 ) {
m_keys.right = false;
m_keys.left = true;
}
else {
m_keys.right = false;
m_keys.left = false;
}
// 2/3rd of the stick range enables walk speed, past that we lerp between walk and run speed
m_moverate.x =
walkspeed
+ ( std::max( 0.0, std::abs( movex ) - 0.65 ) / 0.35 ) * ( movespeed - walkspeed );
// forward-back
double const movez = reinterpret_cast<double const &>( Command.param2 );
if( movez > 0.0 ) {
m_keys.forward = true;
m_keys.back = false;
}
else if( movez < 0.0 ) {
m_keys.forward = false;
m_keys.back = true;
}
else {
m_keys.forward = false;
m_keys.back = false;
}
m_moverate.z =
walkspeed
+ ( std::max( 0.0, std::abs( movez ) - 0.65 ) / 0.35 ) * ( movespeed - walkspeed );
break;
}
case user_command::moveforward: {
if( Command.action != GLFW_RELEASE ) {
m_keys.forward = true;
m_moverate.z =
( Type == tp_Free ?
walkspeed * speedmultiplier :
walkspeed );
}
else {
m_keys.forward = false;
}
break;
}
case user_command::moveback: {
if( Command.action != GLFW_RELEASE ) {
m_keys.back = true;
m_moverate.z =
( Type == tp_Free ?
walkspeed * speedmultiplier :
walkspeed );
}
else {
m_keys.back = false;
}
break;
}
case user_command::moveleft: {
if( Command.action != GLFW_RELEASE ) {
m_keys.left = true;
m_moverate.x =
( Type == tp_Free ?
walkspeed * speedmultiplier :
walkspeed );
}
else {
m_keys.left = false;
}
break;
}
case user_command::moveright: {
if( Command.action != GLFW_RELEASE ) {
m_keys.right = true;
m_moverate.x =
( Type == tp_Free ?
walkspeed * speedmultiplier :
walkspeed );
}
else {
m_keys.right = false;
}
break;
}
case user_command::moveup: {
if( Command.action != GLFW_RELEASE ) {
m_keys.up = true;
m_moverate.y =
( Type == tp_Free ?
walkspeed * speedmultiplier :
walkspeed );
}
else {
m_keys.up = false;
}
break;
}
case user_command::movedown: {
if( Command.action != GLFW_RELEASE ) {
m_keys.down = true;
m_moverate.y =
( Type == tp_Free ?
walkspeed * speedmultiplier :
walkspeed );
}
else {
m_keys.down = false;
}
break;
}
case user_command::moveforwardfast: {
if( Command.action != GLFW_RELEASE ) {
m_keys.forward = true;
m_moverate.z =
( Type == tp_Free ?
runspeed * speedmultiplier :
walkspeed );
}
else {
m_keys.forward = false;
}
break;
}
case user_command::movebackfast: {
if( Command.action != GLFW_RELEASE ) {
m_keys.back = true;
m_moverate.z =
( Type == tp_Free ?
runspeed * speedmultiplier :
walkspeed );
}
else {
m_keys.back = false;
}
break;
}
case user_command::moveleftfast: {
if( Command.action != GLFW_RELEASE ) {
m_keys.left = true;
m_moverate.x =
( Type == tp_Free ?
runspeed * speedmultiplier :
walkspeed );
}
else {
m_keys.left = false;
}
break;
}
case user_command::moverightfast: {
if( Command.action != GLFW_RELEASE ) {
m_keys.right = true;
m_moverate.x =
( Type == tp_Free ?
runspeed * speedmultiplier :
walkspeed );
}
else {
m_keys.right = false;
}
break;
}
case user_command::moveupfast: {
if( Command.action != GLFW_RELEASE ) {
m_keys.up = true;
m_moverate.y =
( Type == tp_Free ?
runspeed * speedmultiplier :
walkspeed );
}
else {
m_keys.up = false;
}
break;
}
case user_command::movedownfast: {
if( Command.action != GLFW_RELEASE ) {
m_keys.down = true;
m_moverate.y =
( Type == tp_Free ?
runspeed * speedmultiplier :
walkspeed );
}
else {
m_keys.down = false;
}
break;
}
}
}
void TCamera::Update()
{
// ABu: zmiana i uniezaleznienie predkosci od FPS
double a = ( Global::shiftState ? 5.00 : 1.00);
if (Global::ctrlState)
a = a * 100;
// OldVelocity=Velocity;
if (FreeFlyModeFlag == true)
Type = tp_Free;
else
Type = tp_Follow;
if (Type == tp_Free)
{
if (Console::Pressed(Global::Keys[k_MechUp]))
Velocity.y += a;
if (Console::Pressed(Global::Keys[k_MechDown]))
Velocity.y -= a;
if( FreeFlyModeFlag == true ) { Type = tp_Free; }
else { Type = tp_Follow; }
// check for sent user commands
// NOTE: this is a temporary arrangement, for the transition period from old command setup to the new one
// ultimately we'll need to track position of camera/driver for all human entities present in the scenario
command_data command;
// NOTE: currently we're only storing commands for local entity and there's no id system in place,
// so we're supplying 'default' entity id of 0
while( simulation::Commands.pop( command, static_cast<std::size_t>( command_target::entity ) | 0 ) ) {
OnCommand( command );
}
auto const deltatime = Timer::GetDeltaRenderTime(); // czas bez pauzy
#ifdef EU07_USE_OLD_COMMAND_SYSTEM
double a = 0.8; // default (walk) movement speed
if( Type == tp_Free ) {
// when not in the cab the speed modifiers are active
if( Global::shiftState ) { a = 2.5; }
if( Global::ctrlState ) { a *= 10.0; }
}
if( ( Type == tp_Free )
|| ( false == Global::ctrlState ) ) {
// ctrl is used for mirror view, so we ignore the controls when in vehicle if ctrl is pressed
if( Console::Pressed( Global::Keys[ k_MechUp ] ) )
Velocity.y = clamp( Velocity.y + a * 10.0 * deltatime, -a, a );
if( Console::Pressed( Global::Keys[ k_MechDown ] ) )
Velocity.y = clamp( Velocity.y - a * 10.0 * deltatime, -a, a );
// McZapkie-170402: poruszanie i rozgladanie we free takie samo jak w follow
if (Console::Pressed(Global::Keys[k_MechRight]))
Velocity.x += a;
if (Console::Pressed(Global::Keys[k_MechLeft]))
Velocity.x -= a;
if (Console::Pressed(Global::Keys[k_MechForward]))
Velocity.z -= a;
if (Console::Pressed(Global::Keys[k_MechBackward]))
Velocity.z += a;
// gora-dol
// if (Console::Pressed(GLFW_KEY_KP_9)) Pos.y+=0.1;
// if (Console::Pressed(GLFW_KEY_KP_3)) Pos.y-=0.1;
if( Console::Pressed( Global::Keys[ k_MechRight ] ) )
Velocity.x = clamp( Velocity.x + a * 10.0 * deltatime, -a, a );
if( Console::Pressed( Global::Keys[ k_MechLeft ] ) )
Velocity.x = clamp( Velocity.x - a * 10.0 * deltatime, -a, a );
if( Console::Pressed( Global::Keys[ k_MechForward ] ) )
Velocity.z = clamp( Velocity.z - a * 10.0 * deltatime, -a, a );
if( Console::Pressed( Global::Keys[ k_MechBackward ] ) )
Velocity.z = clamp( Velocity.z + a * 10.0 * deltatime, -a, a );
}
#else
/*
m_moverate = 0.8; // default (walk) movement speed
if( Type == tp_Free ) {
// when not in the cab the speed modifiers are active
if( Global::shiftState ) { m_moverate = 2.5; }
if( Global::ctrlState ) { m_moverate *= 10.0; }
}
*/
if( ( Type == tp_Free )
|| ( false == Global::ctrlState ) ) {
// ctrl is used for mirror view, so we ignore the controls when in vehicle if ctrl is pressed
if( m_keys.up )
Velocity.y = clamp( Velocity.y + m_moverate.y * 10.0 * deltatime, -m_moverate.y, m_moverate.y );
if( m_keys.down )
Velocity.y = clamp( Velocity.y - m_moverate.y * 10.0 * deltatime, -m_moverate.y, m_moverate.y );
// McZapkie: zeby nie hustalo przy malym FPS:
// Velocity= (Velocity+OldVelocity)/2;
// matrix4x4 mat;
// McZapkie-170402: poruszanie i rozgladanie we free takie samo jak w follow
if( m_keys.right )
Velocity.x = clamp( Velocity.x + m_moverate.x * 10.0 * deltatime, -m_moverate.x, m_moverate.x );
if( m_keys.left )
Velocity.x = clamp( Velocity.x - m_moverate.x * 10.0 * deltatime, -m_moverate.x, m_moverate.x );
if( m_keys.forward )
Velocity.z = clamp( Velocity.z - m_moverate.z * 10.0 * deltatime, -m_moverate.z, m_moverate.z );
if( m_keys.back )
Velocity.z = clamp( Velocity.z + m_moverate.z * 10.0 * deltatime, -m_moverate.z, m_moverate.z );
}
#endif
if( Type == tp_Free ) {
// free movement position update is handled here, movement while in vehicle is handled by train update
vector3 Vec = Velocity;
Vec.RotateY(Yaw);
Pos = Pos + Vec * Timer::GetDeltaRenderTime(); // czas bez pauzy
Velocity = Velocity / 2; // płynne hamowanie ruchu
// double tmp= 10*DeltaTime;
// Velocity+= -Velocity*10 * Timer::GetDeltaTime();//( tmp<1 ? tmp : 1 );
// Type= tp_Free;
Vec.RotateY( Yaw );
Pos += Vec * 5.0 * deltatime;
}
}

View File

@@ -11,6 +11,7 @@ http://mozilla.org/MPL/2.0/.
#include "dumb3d.h"
#include "dynobj.h"
#include "command.h"
using namespace Math3D;
@@ -25,7 +26,16 @@ enum TCameraType
class TCamera
{
private:
vector3 pOffset; // nie używane (zerowe)
struct keys {
bool forward{ false };
bool back{ false };
bool left{ false };
bool right{ false };
bool up{ false };
bool down{ false };
bool run{ false };
} m_keys;
glm::dvec3 m_moverate;
public: // McZapkie: potrzebuje do kiwania na boki
double Pitch;
@@ -36,7 +46,6 @@ class TCamera
vector3 LookAt; // współrzędne punktu, na który ma patrzeć
vector3 vUp;
vector3 Velocity;
vector3 OldVelocity; // lepiej usredniac zeby nie bylo rozbiezne przy malym FPS
vector3 CrossPos;
double CrossDist;
void Init(vector3 NPos, vector3 NAngle);
@@ -44,10 +53,10 @@ class TCamera
{
Pitch = Yaw = Roll = 0;
};
void OnCursorMove(double x, double y);
void OnCursorMove(double const x, double const y);
void OnCommand( command_data const &Command );
void Update();
vector3 GetDirection();
// vector3 inline GetCrossPos() { return Pos+GetDirection()*CrossDist+CrossPos; };
bool SetMatrix();
bool SetMatrix(glm::mat4 &Matrix);
void SetCabMatrix( vector3 &p );

View File

@@ -82,29 +82,14 @@ public static Int32 GetScreenSaverTimeout()
// static class member storage allocation
TKeyTrans Console::ktTable[4 * 256];
// Ra: do poprawienia
void SetLedState(unsigned char Code, bool bOn){
// Ra: bajer do migania LED-ami w klawiaturze
// NOTE: disabled for the time being
// TODO: find non Borland specific equivalent, or get rid of it
/* if (Win32Platform == VER_PLATFORM_WIN32_NT)
{
// WriteLog(AnsiString(int(GetAsyncKeyState(Code))));
if (bool(GetAsyncKeyState(Code)) != bOn)
{
keybd_event(Code, MapVirtualKey(Code, 0), KEYEVENTF_EXTENDEDKEY, 0);
keybd_event(Code, MapVirtualKey(Code, 0), KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP,
0);
}
}
else
{
TKeyboardState KBState;
GetKeyboardState(KBState);
KBState[Code] = bOn ? 1 : 0;
SetKeyboardState(KBState);
};
*/
// Ra: bajer do migania LED-ami w klawiaturze
void SetLedState( unsigned char Code, bool bOn ) {
#ifdef _WINDOWS
if( bOn != ( ::GetKeyState( Code ) != 0 ) ) {
keybd_event( Code, MapVirtualKey( Code, 0 ), KEYEVENTF_EXTENDEDKEY | 0, 0 );
keybd_event( Code, MapVirtualKey( Code, 0 ), KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0 );
}
#endif
};
//---------------------------------------------------------------------------
@@ -243,22 +228,24 @@ void Console::BitsUpdate(int mask)
switch (iMode)
{
case 1: // sterowanie światełkami klawiatury: CA/SHP+opory
if (mask & 3) // gdy SHP albo CA
SetLedState(VK_CAPITAL, (iBits & 3) != 0);
if (mask & 4) // gdy jazda na oporach
{ // Scroll Lock ma jakoś dziwnie... zmiana stanu na przeciwny
SetLedState(VK_SCROLL, true); // przyciśnięty
SetLedState(VK_SCROLL, false); // zwolniony
if( mask & 3 ) {
// gdy SHP albo CA
SetLedState( VK_CAPITAL, ( iBits & 3 ) != 0 );
}
if (mask & 4) {
// gdy jazda na oporach
SetLedState( VK_SCROLL, ( iBits & 4 ) != 0 );
++iConfig; // licznik użycia Scroll Lock
}
break;
case 2: // sterowanie światełkami klawiatury: CA+SHP
if (mask & 2) // gdy CA
SetLedState(VK_CAPITAL, (iBits & 2) != 0);
if (mask & 1) // gdy SHP
{ // Scroll Lock ma jakoś dziwnie... zmiana stanu na przeciwny
SetLedState(VK_SCROLL, true); // przyciśnięty
SetLedState(VK_SCROLL, false); // zwolniony
if( mask & 2 ) {
// gdy CA
SetLedState( VK_CAPITAL, ( iBits & 2 ) != 0 );
}
if (mask & 1) {
// gdy SHP
SetLedState( VK_SCROLL, ( iBits & 1 ) != 0 );
++iConfig; // licznik użycia Scroll Lock
}
break;

View File

@@ -826,19 +826,16 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN
{ // zaliczamy posterunek w pewnej odległości przed (choć W4 nie zasłania
// już semafora)
#if LOGSTOPS
WriteLog(pVehicle->asName + " as " + TrainParams->TrainName + ": at " +
std::to_string(GlobalTime->hh) + ":" + std::to_string(GlobalTime->mm) +
" skipped " + asNextStop); // informacja
WriteLog(
pVehicle->asName + " as " + TrainParams->TrainName
+ ": at " + std::to_string(simulation::Time.data().wHour) + ":" + std::to_string(simulation::Time.data().wMinute)
+ " skipped " + asNextStop); // informacja
#endif
fLastStopExpDist = mvOccupied->DistCounter + 0.250 +
0.001 * fLength; // przy jakim dystansie (stanie
// licznika) ma przesunąć na
// następny postój
TrainParams->UpdateMTable(
GlobalTime->hh, GlobalTime->mm, asNextStop);
// przy jakim dystansie (stanie licznika) ma przesunąć na następny postój
fLastStopExpDist = mvOccupied->DistCounter + 0.250 + 0.001 * fLength;
TrainParams->UpdateMTable( simulation::Time, asNextStop );
TrainParams->StationIndexInc(); // przejście do następnej
asNextStop =
TrainParams->NextStop(); // pobranie kolejnego miejsca zatrzymania
asNextStop = TrainParams->NextStop(); // pobranie kolejnego miejsca zatrzymania
// TableClear(); //aby od nowa sprawdziło W4 z inną nazwą już - to nie
// jest dobry pomysł
sSpeedTable[i].iFlags = 0; // nie liczy się już
@@ -933,8 +930,7 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN
// niezależne od sposobu obsługi drzwi, bo
// opóźnia również kierownika
}
if (TrainParams->UpdateMTable(
GlobalTime->hh, GlobalTime->mm, asNextStop) )
if (TrainParams->UpdateMTable( simulation::Time, asNextStop) )
{ // to się wykona tylko raz po zatrzymaniu na W4
if (TrainParams->CheckTrainLatency() < 0.0)
iDrivigFlags |= moveLate; // odnotowano spóźnienie
@@ -980,7 +976,7 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN
if (TrainParams->StationIndex < TrainParams->StationCount)
{ // jeśli są dalsze stacje, czekamy do godziny odjazdu
if (TrainParams->IsTimeToGo(GlobalTime->hh, GlobalTime->mm))
if (TrainParams->IsTimeToGo(simulation::Time.data().wHour, simulation::Time.data().wMinute))
{ // z dalszą akcją czekamy do godziny odjazdu
/* potencjalny problem z ruszaniem z w4
if (TrainParams->CheckTrainLatency() < 0)
@@ -997,10 +993,10 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN
asNextStop = TrainParams->NextStop(); // pobranie kolejnego miejsca zatrzymania
// TableClear(); //aby od nowa sprawdziło W4 z inną nazwą już - to nie jest dobry pomysł
#if LOGSTOPS
WriteLog(pVehicle->asName + " as " + TrainParams->TrainName +
": at " + std::to_string(GlobalTime->hh) + ":" +
std::to_string(GlobalTime->mm) + " next " +
asNextStop); // informacja
WriteLog(
pVehicle->asName + " as " + TrainParams->TrainName
+ ": at " + std::to_string(simulation::Time.data().wHour) + ":" + std::to_string(simulation::Time.data().wMinute)
+ " next " + asNextStop); // informacja
#endif
if (int(floor(sSpeedTable[i].evEvent->ValueGet(1))) & 1)
iDrivigFlags |= moveStopHere; // nie podjeżdżać do semafora,
@@ -1024,10 +1020,10 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN
else
{ // jeśli dojechaliśmy do końca rozkładu
#if LOGSTOPS
WriteLog(pVehicle->asName + " as " + TrainParams->TrainName +
": at " + std::to_string(GlobalTime->hh) + ":" +
std::to_string(GlobalTime->mm) +
" end of route."); // informacja
WriteLog(
pVehicle->asName + " as " + TrainParams->TrainName
+ ": at " + std::to_string(simulation::Time.data().wHour) + ":" + std::to_string(simulation::Time.data().wMinute)
+ " end of route."); // informacja
#endif
asNextStop = TrainParams->NextStop(); // informacja o końcu trasy
TrainParams->NewName("none"); // czyszczenie nieaktualnego rozkładu
@@ -2869,8 +2865,7 @@ bool TController::PutCommand(std::string NewCommand, double NewValue1, double Ne
}
else
{ // inicjacja pierwszego przystanku i pobranie jego nazwy
TrainParams->UpdateMTable(GlobalTime->hh, GlobalTime->mm,
TrainParams->NextStationName);
TrainParams->UpdateMTable( simulation::Time, TrainParams->NextStationName );
TrainParams->StationIndexInc(); // przejście do następnej
iStationStart = TrainParams->StationIndex;
asNextStop = TrainParams->NextStop();

View File

@@ -986,11 +986,8 @@ TDynamicObject * TDynamicObject::ABuFindNearestObject(TTrack *Track, TDynamicObj
return nullptr;
}
TDynamicObject * TDynamicObject::ABuScanNearestObject(TTrack *Track, double ScanDir,
double ScanDist, int &CouplNr)
{ // skanowanie toru w poszukiwaniu obiektu najblizszego
// kamerze
// double MyScanDir=ScanDir; //Moja orientacja na torze. //Ra: nie używane
TDynamicObject * TDynamicObject::ABuScanNearestObject(TTrack *Track, double ScanDir, double ScanDist, int &CouplNr)
{ // skanowanie toru w poszukiwaniu obiektu najblizszego kamerze
if (ABuGetDirection() < 0)
ScanDir = -ScanDir;
TDynamicObject *FoundedObj;
@@ -2914,11 +2911,12 @@ bool TDynamicObject::Update(double dt, double dt1)
// fragment "z EXE Kursa"
if (MoverParameters->Mains) // nie wchodzić w funkcję bez potrzeby
if ((!MoverParameters->Battery) && (Controller == Humandriver) &&
(MoverParameters->EngineType != DieselEngine) &&
(MoverParameters->EngineType != WheelsDriven))
{ // jeśli bateria wyłączona, a nie diesel ani drezyna
// reczna
if ( ( false == MoverParameters->Battery)
&& ( false == MoverParameters->ConverterFlag ) // added alternative power source. TODO: more generic power check
&& ( Controller == Humandriver)
&& ( MoverParameters->EngineType != DieselEngine )
&& ( MoverParameters->EngineType != WheelsDriven ) )
{ // jeśli bateria wyłączona, a nie diesel ani drezyna reczna
if (MoverParameters->MainSwitch(false)) // wyłączyć zasilanie
MoverParameters->EventFlag = true;
}
@@ -3291,8 +3289,7 @@ bool TDynamicObject::Update(double dt, double dt1)
if (tmpTraction.TractionVoltage == 0)
{ // to coś wyłączało dźwięk silnika w ST43!
MoverParameters->ConverterFlag = false;
MoverParameters->CompressorFlag = false; // Ra: to jest wątpliwe - wyłączenie
// sprężarki powinno być w jednym miejscu!
MoverParameters->CompressorFlag = false; // Ra: to jest wątpliwe - wyłączenie sprężarki powinno być w jednym miejscu!
}
}
}
@@ -4297,45 +4294,47 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName,
}
#else
{ // tekstura wymienna jest raczej jedynie w "dynamic\"
ReplacableSkin = Global::asCurrentTexturePath + ReplacableSkin; // skory tez z dynamic/...
std::string x = TextureTest(Global::asCurrentTexturePath + "nowhere"); // na razie prymitywnie
if (!x.empty())
m_materialdata.replacable_skins[ 4 ] = GfxRenderer.GetTextureId( Global::asCurrentTexturePath + "nowhere", "", 9 );
// ReplacableSkin = Global::asCurrentTexturePath + ReplacableSkin; // skory tez z dynamic/...
std::string nowheretexture = TextureTest(Global::asCurrentTexturePath + "nowhere"); // na razie prymitywnie
if( false == nowheretexture.empty() ) {
m_materialdata.replacable_skins[ 4 ] = GfxRenderer.GetTextureId( nowheretexture, "", 9 );
}
if (m_materialdata.multi_textures > 0)
{ // jeśli model ma 4 tekstury
m_materialdata.replacable_skins[ 1 ] = GfxRenderer.GetTextureId(
ReplacableSkin + ",1", "", Global::iDynamicFiltering);
if( m_materialdata.replacable_skins[ 1 ] )
{ // pierwsza z zestawu znaleziona
m_materialdata.replacable_skins[ 2 ] = GfxRenderer.GetTextureId(
ReplacableSkin + ",2", "", Global::iDynamicFiltering);
if( m_materialdata.replacable_skins[ 2 ] )
{
m_materialdata.multi_textures = 2; // już są dwie
m_materialdata.replacable_skins[ 3 ] = GfxRenderer.GetTextureId(
ReplacableSkin + ",3", "", Global::iDynamicFiltering);
if( m_materialdata.replacable_skins[ 3 ] )
{
m_materialdata.multi_textures = 3; // a teraz nawet trzy
m_materialdata.replacable_skins[ 4 ] = GfxRenderer.GetTextureId(
ReplacableSkin + ",4", "", Global::iDynamicFiltering);
if( m_materialdata.replacable_skins[ 4 ] )
m_materialdata.multi_textures = 4; // jak są cztery, to blokujemy podmianę tekstury
// rozkładem
}
if (m_materialdata.multi_textures > 0) {
// jeśli model ma 4 tekstury
// check for the pipe method first
if( ReplacableSkin.find( '|' ) != std::string::npos ) {
cParser nameparser( ReplacableSkin );
nameparser.getTokens( 4, true, "|" );
int skinindex = 0;
std::string texturename; nameparser >> texturename;
while( ( texturename != "" ) && ( skinindex < 4 ) ) {
m_materialdata.replacable_skins[ skinindex + 1 ] = GfxRenderer.GetTextureId( Global::asCurrentTexturePath + texturename, "" );
++skinindex;
texturename = ""; nameparser >> texturename;
}
m_materialdata.multi_textures = skinindex;
}
else
{ // zestaw nie zadziałał, próbujemy normanie
m_materialdata.multi_textures = 0;
m_materialdata.replacable_skins[ 1 ] = GfxRenderer.GetTextureId(
ReplacableSkin, "", Global::iDynamicFiltering);
else {
// otherwise try the basic approach
int skinindex = 0;
do {
texture_manager::size_type texture = GfxRenderer.GetTextureId( Global::asCurrentTexturePath + ReplacableSkin + "," + std::to_string( skinindex + 1 ), "", Global::iDynamicFiltering, true );
if( false == GfxRenderer.Texture( texture ).is_ready ) {
break;
}
m_materialdata.replacable_skins[ skinindex + 1 ] = texture;
++skinindex;
} while( skinindex < 4 );
m_materialdata.multi_textures = skinindex;
if( m_materialdata.multi_textures == 0 ) {
// zestaw nie zadziałał, próbujemy normanie
m_materialdata.replacable_skins[ 1 ] = GfxRenderer.GetTextureId( Global::asCurrentTexturePath + ReplacableSkin, "", Global::iDynamicFiltering );
}
}
}
else
m_materialdata.replacable_skins[ 1 ] = GfxRenderer.GetTextureId(
ReplacableSkin, "", Global::iDynamicFiltering);
m_materialdata.replacable_skins[ 1 ] = GfxRenderer.GetTextureId( Global::asCurrentTexturePath + ReplacableSkin, "", Global::iDynamicFiltering );
if( GfxRenderer.Texture( m_materialdata.replacable_skins[ 1 ] ).has_alpha )
m_materialdata.textures_alpha = 0x31310031; // tekstura -1 z kanałem alfa - nie renderować w cyklu nieprzezroczystych
else

View File

@@ -23,6 +23,8 @@ Stele, firleju, szociu, hunter, ZiomalCl, OLI_EU and others
#include "Globals.h"
#include "Logs.h"
#include "keyboardinput.h"
#include "gamepadinput.h"
#include "Console.h"
#include "PyInt.h"
#include "World.h"
@@ -60,6 +62,13 @@ Stele, firleju, szociu, hunter, ZiomalCl, OLI_EU and others
TWorld World;
namespace input {
keyboard_input Keyboard;
gamepad_input Gamepad;
}
#ifdef CAN_I_HAS_LIBPNG
void screenshot_save_thread( char *img )
{
@@ -113,12 +122,17 @@ void window_resize_callback(GLFWwindow *window, int w, int h)
void cursor_pos_callback(GLFWwindow *window, double x, double y)
{
input::Keyboard.mouse( x, y );
#ifdef EU07_USE_OLD_COMMAND_SYSTEM
World.OnMouseMove(x * 0.005, y * 0.01);
#endif
glfwSetCursorPos(window, 0.0, 0.0);
}
void key_callback( GLFWwindow *window, int key, int scancode, int action, int mods )
{
input::Keyboard.key( key, action );
Global::shiftState = ( mods & GLFW_MOD_SHIFT ) ? true : false;
Global::ctrlState = ( mods & GLFW_MOD_CONTROL ) ? true : false;
@@ -144,51 +158,9 @@ void key_callback( GLFWwindow *window, int key, int scancode, int action, int mo
break;
}
#endif
case GLFW_KEY_ESCAPE: {
/*
if( ( DebugModeFlag ) //[Esc] pauzuje tylko bez Debugmode
&& ( Global::iPause == 0 ) ) { // but unpausing should work always
break;
}
*/
if( Global::iPause & 1 ) // jeśli pauza startowa
Global::iPause &= ~1; // odpauzowanie, gdy po wczytaniu miało nie startować
else if( !( Global::iMultiplayer & 2 ) ) // w multiplayerze pauza nie ma sensu
if( !Global::ctrlState ) // z [Ctrl] to radiostop jest
Global::iPause ^= 2; // zmiana stanu zapauzowania
if( Global::iPause ) {// jak pauza
Global::iTextMode = GLFW_KEY_F1; // to wyświetlić zegar i informację
}
break;
}
case GLFW_KEY_F7:
if( DebugModeFlag ) {
if( Global::ctrlState ) {
// ctrl + f7 toggles static daylight
World.ToggleDaylight();
break;
}
// f7: wireframe toggle
// siatki wyświetlane tyko w trybie testowym
Global::bWireFrame = !Global::bWireFrame;
if( true == Global::bWireFrame ) {
glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
}
else {
glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
}
++Global::iReCompile; // odświeżyć siatki
// Ra: jeszcze usunąć siatki ze skompilowanych obiektów!
}
break;
default: { break; }
}
}
else if( action == GLFW_RELEASE )
{
World.OnKeyUp( key );
}
}
void focus_callback( GLFWwindow *window, int focus )
@@ -238,7 +210,11 @@ int main(int argc, char *argv[])
if (!glfwInit())
return -1;
DeleteFile("errors.txt");
#ifdef _WINDOWS
DeleteFile( "log.txt" );
DeleteFile( "errors.txt" );
_mkdir("logs");
#endif
Global::LoadIniFile("eu07.ini");
Global::InitKeys();
@@ -365,6 +341,8 @@ int main(int argc, char *argv[])
return -1;
}
input::Keyboard.init();
input::Gamepad.init();
Global::pWorld = &World; // Ra: wskaźnik potrzebny do usuwania pojazdów
if (!World.Init(window))
@@ -374,9 +352,10 @@ int main(int argc, char *argv[])
}
Console *pConsole = new Console(); // Ra: nie wiem, czy ma to sens, ale jakoś zainicjowac trzeba
/*
if( !joyGetNumDevs() )
WriteLog( "No joystick" );
*/
if( Global::iModifyTGA < 0 ) { // tylko modyfikacja TGA, bez uruchamiania symulacji
Global::iMaxTextureSize = 64; //żeby nie zamulać pamięci
World.ModifyTGA(); // rekurencyjne przeglądanie katalogów
@@ -393,7 +372,8 @@ int main(int argc, char *argv[])
&& World.Update()
&& GfxRenderer.Render())
{
glfwPollEvents();
glfwPollEvents();
input::Gamepad.poll();
}
Console::Off(); // wyłączenie konsoli (komunikacji zwrotnej)
}
@@ -403,5 +383,6 @@ int main(int argc, char *argv[])
glfwDestroyWindow(window);
glfwTerminate();
return 0;
}

View File

@@ -177,9 +177,9 @@ bool TEventLauncher::Render()
}
else
{ // jeśli nie cykliczny, to sprawdzić czas
if (GlobalTime->hh == iHour)
if (simulation::Time.data().wHour == iHour)
{
if (GlobalTime->mm == iMinute)
if (simulation::Time.data().wMinute == iMinute)
{ // zgodność czasu uruchomienia
if (UpdatedTime < 10)
{

View File

@@ -66,7 +66,7 @@ inline float3 operator/( float3 const &v, float const k )
};
inline float3 SafeNormalize(const float3 &v)
{ // bezpieczna normalizacja (wektor długości 1.0)
double l = v.Length();
auto const l = v.Length();
float3 retVal;
if (l == 0)
retVal.x = retVal.y = retVal.z = 0;
@@ -104,11 +104,11 @@ class float4
z = c;
w = d;
};
double inline float4::LengthSquared() const
float inline float4::LengthSquared() const
{
return x * x + y * y + z * z + w * w;
};
double inline float4::Length() const
float inline float4::Length() const
{
return sqrt(x * x + y * y + z * z + w * w);
};
@@ -132,26 +132,26 @@ inline float4 operator+(const float4 &v1, const float4 &v2)
{
return float4(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z, v1.w + v2.w);
};
inline float4 operator/(const float4 &v, double k)
inline float4 operator/(const float4 &v, float const k)
{
return float4(v.x / k, v.y / k, v.z / k, v.w / k);
};
inline float4 Normalize(const float4 &v)
{ // bezpieczna normalizacja (wektor długości 1.0)
double l = v.LengthSquared();
if (l == 1.0)
auto const lengthsquared = v.LengthSquared();
if (lengthsquared == 1.0)
return v;
if (l == 0.0)
if (lengthsquared == 0.0)
return float4(); // wektor zerowy, w=1
else
return v / sqrt(l); // pierwiastek liczony tylko jeśli trzeba wykonać dzielenia
return v / std::sqrt(lengthsquared); // pierwiastek liczony tylko jeśli trzeba wykonać dzielenia
};
inline
float Dot(const float4 &q1, const float4 &q2)
{ // iloczyn skalarny
return q1.x * q2.x + q1.y * q2.y + q1.z * q2.z + q1.w * q2.w;
}
inline float4 &operator*=(float4 &v1, double d)
inline float4 &operator*=(float4 &v1, float const d)
{ // mnożenie przez skalar, jaki ma sens?
v1.x *= d;
v1.y *= d;
@@ -172,7 +172,7 @@ inline float4 Slerp(const float4 &q0, const float4 &q1, float t)
new_q1.w = -new_q1.w;
cosOmega = -cosOmega;
}
double k0, k1;
float k0, k1;
if (cosOmega > 0.9999f)
{ // jeśli jesteśmy z (t) na maksimum kosinusa, to tam prawie liniowo jest
k0 = 1.0f - t;
@@ -180,9 +180,9 @@ inline float4 Slerp(const float4 &q0, const float4 &q1, float t)
}
else
{ // a w ogólnym przypadku trzeba liczyć na trygonometrię
double sinOmega = sqrt(1.0f - cosOmega * cosOmega); // sinus z jedynki tryg.
double omega = atan2(sinOmega, cosOmega); // wyznaczenie kąta
double oneOverSinOmega = 1.0f / sinOmega; // odwrotność sinusa, bo sinus w mianowniku
auto const sinOmega = std::sqrt(1.0f - cosOmega * cosOmega); // sinus z jedynki tryg.
auto const omega = std::atan2(sinOmega, cosOmega); // wyznaczenie kąta
auto const oneOverSinOmega = 1.0f / sinOmega; // odwrotność sinusa, bo sinus w mianowniku
k0 = sin((1.0f - t) * omega) * oneOverSinOmega;
k1 = sin(t * omega) * oneOverSinOmega;
}

View File

@@ -15,9 +15,10 @@ http://mozilla.org/MPL/2.0/.
#include "stdafx.h"
#include "Gauge.h"
#include "Timer.h"
#include "parser.h"
#include "Model3d.h"
#include "Timer.h"
#include "logs.h"
TGauge::TGauge()
{
@@ -86,10 +87,18 @@ bool TGauge::Load(cParser &Parser, TModel3d *md1, TModel3d *md2, double mul)
>> val5;
val3 *= mul;
TSubModel *sm = md1->GetFromName( str1.c_str() );
if( val3 == 0.0 ) {
ErrorLog( "Scale of 0.0 defined for sub-model \"" + str1 + "\" in 3d model \"" + md1->NameGet() + "\". Forcing scale of 1.0 to prevent division by 0" );
val3 = 1.0;
}
if (sm) // jeśli nie znaleziony
md2 = NULL; // informacja, że znaleziony
else if (md2) // a jest podany drugi model (np. zewnętrzny)
sm = md2->GetFromName(str1.c_str()); // to może tam będzie, co za różnica gdzie
if( sm == nullptr ) {
ErrorLog( "Failed to locate sub-model \"" + str1 + "\" in 3d model \"" + md1->NameGet() + "\"" );
}
if (str2 == "mov")
Init(sm, gt_Move, val3, val4, val5);
else if (str2 == "wip")
@@ -136,19 +145,22 @@ void TGauge::PutValue(double fNewDesired)
fValue = fDesiredValue;
};
double TGauge::GetValue() const {
// we feed value in range 0-1 so we should be getting it reported in the same range
return ( fValue - fOffset ) / fScale;
}
void TGauge::Update()
{
float dt = Timer::GetDeltaTime();
if ((fFriction > 0) && (dt < 0.5 * fFriction)) // McZapkie-281102:
// zabezpieczenie przed
// oscylacjami dla dlugich
// czasow
fValue += dt * (fDesiredValue - fValue) / fFriction;
if( ( fFriction > 0 ) && ( dt < 0.5 * fFriction ) ) {
// McZapkie-281102: zabezpieczenie przed oscylacjami dla dlugich czasow
fValue += dt * ( fDesiredValue - fValue ) / fFriction;
}
else
fValue = fDesiredValue;
if (SubModel)
{ // warunek na wszelki wypadek, gdyby się submodel nie
// podłączył
{ // warunek na wszelki wypadek, gdyby się submodel nie podłączył
TSubModel *sm;
switch (eType)
{

15
Gauge.h
View File

@@ -25,11 +25,11 @@ class TGauge // zmienne "gg"
{ // animowany wskaźnik, mogący przyjmować wiele stanów pośrednich
private:
TGaugeType eType; // typ ruchu
double fFriction; // hamowanie przy zliżaniu się do zadanej wartości
double fDesiredValue; // wartość docelowa
double fValue; // wartość obecna
double fOffset; // wartość początkowa ("0")
double fScale; // wartość końcowa ("1")
double fFriction{ 0.0 }; // hamowanie przy zliżaniu się do zadanej wartości
double fDesiredValue{ 0.0 }; // wartość docelowa
double fValue{ 0.0 }; // wartość obecna
double fOffset{ 0.0 }; // wartość początkowa ("0")
double fScale{ 1.0 }; // wartość końcowa ("1")
double fStepSize; // nie używane
char cDataType; // typ zmiennej parametru: f-float, d-double, i-int
union
@@ -51,10 +51,7 @@ class TGauge // zmienne "gg"
void DecValue(double fNewDesired);
void UpdateValue(double fNewDesired);
void PutValue(double fNewDesired);
float GetValue()
{
return fValue;
};
double GetValue() const;
void Update();
void Render();
void AssignFloat(float *fValue);

View File

@@ -80,11 +80,12 @@ double Global::pCameraRotation;
double Global::pCameraRotationDeg;
std::vector<vector3> Global::FreeCameraInit;
std::vector<vector3> Global::FreeCameraInitAngle;
double Global::fFogStart = 1700;
double Global::fFogEnd = 2000;
float Global::Background[3] = {0.2f, 0.4f, 0.33f};
GLfloat Global::AtmoColor[] = {0.423f, 0.702f, 1.0f};
GLfloat Global::FogColor[] = {0.6f, 0.7f, 0.8f};
double Global::fFogStart = 1700;
double Global::fFogEnd = 2000;
float Global::Overcast{ 0.1f }; // NOTE: all this weather stuff should be moved elsewhere
#ifdef EU07_USE_OLD_LIGHTING_MODEL
GLfloat Global::ambientDayLight[] = {0.40f, 0.40f, 0.45f, 1.0f}; // robocze
GLfloat Global::diffuseDayLight[] = {0.55f, 0.54f, 0.50f, 1.0f};
@@ -106,6 +107,7 @@ int Global::iHiddenEvents = 1; // czy łączyć eventy z torami poprzez nazwę t
// parametry użytkowe (jak komu pasuje)
int Global::Keys[MaxKeys];
bool Global::RealisticControlMode{ false };
int Global::iWindowWidth = 800;
int Global::iWindowHeight = 600;
float Global::fDistanceFactor = Global::ScreenHeight / 768.0; // baza do przeliczania odległości dla LoD
@@ -165,6 +167,7 @@ bool Global::bOldSmudge = false; // Używanie starej smugi
bool Global::bWireFrame = false;
bool Global::bSoundEnabled = true;
int Global::iWriteLogEnabled = 3; // maska bitowa: 1-zapis do pliku, 2-okienko, 4-nazwy torów
bool Global::MultipleLogs{ false };
bool Global::bManageNodes = true;
bool Global::bDecompressDDS = false; // czy programowa dekompresja DDS
@@ -373,7 +376,11 @@ void Global::ConfigParse(cParser &Parser)
Global::iWriteLogEnabled = stol_def(token,3);
}
}
else if (token == "adjustscreenfreq")
else if( token == "multiplelogs" ) {
Parser.getTokens();
Parser >> Global::MultipleLogs;
}
else if( token == "adjustscreenfreq" )
{
// McZapkie-240403 - czestotliwosc odswiezania ekranu
Parser.getTokens();

View File

@@ -166,6 +166,7 @@ class Global
public:
// double Global::tSinceStart;
static int Keys[MaxKeys];
static bool RealisticControlMode; // controls ability to steer the vehicle from outside views
static Math3D::vector3 pCameraPosition; // pozycja kamery w świecie
static double
pCameraRotation; // kierunek bezwzględny kamery w świecie: 0=północ, 90°=zachód (-azymut)
@@ -207,17 +208,16 @@ class Global
static std::string asHumanCtrlVehicle;
static void LoadIniFile(std::string asFileName);
static void InitKeys();
inline static Math3D::vector3 GetCameraPosition()
{
return pCameraPosition;
};
inline static Math3D::vector3 GetCameraPosition() { return pCameraPosition; };
static void SetCameraPosition(Math3D::vector3 pNewCameraPosition);
static void SetCameraRotation(double Yaw);
static int iWriteLogEnabled; // maska bitowa: 1-zapis do pliku, 2-okienko
static bool MultipleLogs;
// McZapkie-221002: definicja swiatla dziennego
static float Background[3];
static GLfloat AtmoColor[];
static GLfloat FogColor[];
static float Overcast;
// static bool bTimeChange;
#ifdef EU07_USE_OLD_LIGHTING_MODEL
static opengl_light AmbientLight;

View File

@@ -36,6 +36,7 @@ http://mozilla.org/MPL/2.0/.
#include "Driver.h"
#include "Console.h"
#include "Names.h"
#include "world.h"
#include "uilayer.h"
#define _PROBLEND 1
@@ -385,7 +386,7 @@ void TGroundNode::RenderAlphaVBO()
if( ( PROBLEND ) ) // sprawdza, czy w nazwie nie ma @ //Q: 13122011 - Szociu: 27012012
{
glDisable( GL_BLEND );
glAlphaFunc( GL_GREATER, 0.45f ); // im mniejsza wartość, tym większa ramka, domyślnie 0.1f
glAlphaFunc( GL_GREATER, 0.50f ); // im mniejsza wartość, tym większa ramka, domyślnie 0.1f
};
#endif
@@ -661,7 +662,7 @@ void TGroundNode::RenderAlphaDL()
if ((PROBLEND)) // sprawdza, czy w nazwie nie ma @ //Q: 13122011 - Szociu: 27012012
{
glDisable(GL_BLEND);
glAlphaFunc(GL_GREATER, 0.45f); // im mniejsza wartość, tym większa ramka, domyślnie 0.1f
glAlphaFunc(GL_GREATER, 0.50f); // im mniejsza wartość, tym większa ramka, domyślnie 0.1f
};
#endif
if (!DisplayListID) //||Global::bReCompile) //Ra: wymuszenie rekompilacji
@@ -2512,9 +2513,6 @@ void TGround::FirstInit()
WriteLog("InitEvents OK");
InitLaunchers();
WriteLog("InitLaunchers OK");
// ABu 160205: juz nie TODO :)
Mtable::GlobalTime = std::make_shared<TMTableTime>( hh, mm, srh, srm, ssh, ssm ); // McZapkie-300302: inicjacja czasu rozkladowego - TODO: czytac z trasy!
WriteLog("InitGlobalTime OK");
WriteLog("FirstInit is done");
};
@@ -2553,13 +2551,6 @@ bool TGround::Init(std::string File)
int OriginStackTop = 0;
vector3 OriginStack[OriginStackMaxDepth]; // stos zagnieżdżenia origin
// ABu: Jezeli nie ma definicji w scenerii to ustawiane ponizsze wartosci:
hh = 10; // godzina startu
mm = 30; // minuty startu
srh = 6; // godzina wschodu slonca
srm = 0; // minuty wschodu slonca
ssh = 20; // godzina zachodu slonca
ssm = 0; // minuty zachodu slonca
TGroundNode *LastNode = NULL; // do użycia w trainset
iNumNodes = 0;
token = "";
@@ -2798,16 +2789,29 @@ bool TGround::Init(std::string File)
{ // Ra: ustawienie parametrów OpenGL przeniesione do FirstInit
WriteLog("Scenery atmo definition");
parser.getTokens(3);
parser >> Global::AtmoColor[0] >> Global::AtmoColor[1] >> Global::AtmoColor[2];
parser
>> Global::AtmoColor[0]
>> Global::AtmoColor[1]
>> Global::AtmoColor[2];
parser.getTokens(2);
parser >> Global::fFogStart >> Global::fFogEnd;
parser
>> Global::fFogStart
>> Global::fFogEnd;
if (Global::fFogEnd > 0.0)
{ // ostatnie 3 parametry są opcjonalne
parser.getTokens(3);
parser >> Global::FogColor[0] >> Global::FogColor[1] >> Global::FogColor[2];
parser
>> Global::FogColor[0]
>> Global::FogColor[1]
>> Global::FogColor[2];
}
parser.getTokens();
parser >> token;
if( token != "endatmo" ) {
// optional overcast parameter
// NOTE: parameter system needs some decent replacement, but not worth the effort if we're moving to built-in editor
Global::Overcast = clamp( std::stof( token ), 0.0f, 1.0f );
}
while (token.compare("endatmo") != 0)
{ // a kolejne parametry są pomijane
parser.getTokens();
@@ -2817,47 +2821,18 @@ bool TGround::Init(std::string File)
else if (str == "time")
{
WriteLog("Scenery time definition");
char temp_in[9];
char temp_out[9];
int i, j;
parser.getTokens();
parser >> temp_in;
for (j = 0; j <= 8; j++)
temp_out[j] = ' ';
for (i = 0; temp_in[i] != ':'; i++)
temp_out[i] = temp_in[i];
hh = atoi(temp_out);
for (j = 0; j <= 8; j++)
temp_out[j] = ' ';
for (j = i + 1; j <= 8; j++)
temp_out[j - (i + 1)] = temp_in[j];
mm = atoi(temp_out);
parser >> token;
parser.getTokens();
parser >> temp_in;
for (j = 0; j <= 8; j++)
temp_out[j] = ' ';
for (i = 0; temp_in[i] != ':'; i++)
temp_out[i] = temp_in[i];
srh = atoi(temp_out);
for (j = 0; j <= 8; j++)
temp_out[j] = ' ';
for (j = i + 1; j <= 8; j++)
temp_out[j - (i + 1)] = temp_in[j];
srm = atoi(temp_out);
cParser timeparser( token );
timeparser.getTokens( 2, false, ":" );
auto &time = simulation::Time.data();
timeparser
>> time.wHour
>> time.wMinute;
// NOTE: we ignore old sunrise and sunset definitions, as they're now calculated dynamically
parser.getTokens();
parser >> temp_in;
for (j = 0; j <= 8; j++)
temp_out[j] = ' ';
for (i = 0; temp_in[i] != ':'; i++)
temp_out[i] = temp_in[i];
ssh = atoi(temp_out);
for (j = 0; j <= 8; j++)
temp_out[j] = ' ';
for (j = i + 1; j <= 8; j++)
temp_out[j - (i + 1)] = temp_in[j];
ssm = atoi(temp_out);
while (token.compare("endtime") != 0)
{
parser.getTokens();
@@ -4783,7 +4758,7 @@ TGround::Render( Math3D::vector3 const &Camera ) {
bool TGround::RenderDL(vector3 pPosition)
{ // renderowanie scenerii z Display List - faza nieprzezroczystych
glDisable(GL_BLEND);
glAlphaFunc(GL_GREATER, 0.45f); // im mniejsza wartość, tym większa ramka, domyślnie 0.1f
glAlphaFunc(GL_GREATER, 0.50f); // im mniejsza wartość, tym większa ramka, domyślnie 0.1f
++TGroundRect::iFrameNumber; // zwięszenie licznika ramek (do usuwniania nadanimacji)
CameraDirection.x = sin(Global::pCameraRotation); // wektor kierunkowy
CameraDirection.z = cos(Global::pCameraRotation);
@@ -4873,7 +4848,7 @@ bool TGround::RenderAlphaDL(vector3 pPosition)
bool TGround::RenderVBO(vector3 pPosition)
{ // renderowanie scenerii z VBO - faza nieprzezroczystych
glDisable(GL_BLEND);
glAlphaFunc(GL_GREATER, 0.45f); // im mniejsza wartość, tym większa ramka, domyślnie 0.1f
glAlphaFunc(GL_GREATER, 0.50f); // im mniejsza wartość, tym większa ramka, domyślnie 0.1f
++TGroundRect::iFrameNumber; // zwięszenie licznika ramek
CameraDirection.x = sin(Global::pCameraRotation); // wektor kierunkowy
CameraDirection.z = cos(Global::pCameraRotation);

View File

@@ -300,11 +300,7 @@ class TGround
// TGroundNode *nLastOfType[TP_LAST]; //ostatnia
TSubRect srGlobal; // zawiera obiekty globalne (na razie wyzwalacze czasowe)
int hh = 0,
mm = 0,
srh = 0,
srm = 0,
ssh = 0,
ssm = 0; // ustawienia czasu
mm = 0; // ustawienia czasu
// int tracks,tracksfar; //liczniki torów
typedef std::unordered_map<std::string, TEvent *> event_map;
event_map m_eventmap;

View File

@@ -18,6 +18,33 @@ std::ofstream comms; // lista komunikatow "comms.txt", można go wyłączyć
char endstring[10] = "\n";
std::string filename_date() {
::SYSTEMTIME st;
::GetLocalTime( &st );
char buffer[ 256 ];
sprintf( buffer,
"%d%02d%02d_%02d%02d",
st.wYear,
st.wMonth,
st.wDay,
st.wHour,
st.wMinute );
return std::string( buffer );
}
std::string filename_scenery() {
auto extension = Global::SceneryFile.rfind( '.' );
if( extension != std::string::npos ) {
return Global::SceneryFile.substr( 0, extension );
}
else {
return Global::SceneryFile;
}
}
void WriteConsoleOnly(const char *str, double value)
{
char buf[255];
@@ -57,8 +84,14 @@ void WriteLog(const char *str, bool newline)
{
if (Global::iWriteLogEnabled & 1)
{
if (!output.is_open())
output.open("log.txt", std::ios::trunc);
if( !output.is_open() ) {
std::string const filename =
( Global::MultipleLogs ?
"logs/log (" + filename_scenery() + ") " + filename_date() + ".txt" :
"log.txt" );
output.open( filename, std::ios::trunc );
}
output << str;
if (newline)
output << "\n";
@@ -72,9 +105,13 @@ void WriteLog(const char *str, bool newline)
void ErrorLog(const char *str)
{ // Ra: bezwarunkowa rejestracja poważnych błędów
if (!errors.is_open())
{
errors.open("errors.txt", std::ios::trunc);
if (!errors.is_open()) {
std::string const filename =
( Global::MultipleLogs ?
"logs/errors (" + filename_scenery() + ") " + filename_date() + ".txt" :
"errors.txt" );
errors.open( filename, std::ios::trunc );
errors << "EU07.EXE " + Global::asRelease << "\n";
}
if (str)

View File

@@ -416,37 +416,30 @@ struct TPowerParameters
struct
{
_mover__3 RHeater;
};
struct
{
_mover__2 RPowerCable;
};
struct
{
TCurrentCollector CollectorParameters;
};
struct
{
_mover__1 RAccumulator;
};
struct
{
TEngineTypes GeneratorEngine;
};
struct
{
double InputVoltage;
};
struct
{
TPowerType PowerType;
};
};
@@ -666,15 +659,24 @@ public:
double CompressorSpeed = 0.0;
/*cisnienie wlaczania, zalaczania sprezarki, wydajnosc sprezarki*/
TBrakeDelayTable BrakeDelay; /*opoznienie hamowania/odhamowania t/o*/
double AirLeakRate{ 0.01 }; // base rate of air leak from brake system components ( 0.001 = 1 l/sec )
int BrakeCtrlPosNo = 0; /*ilosc pozycji hamulca*/
/*nastawniki:*/
int MainCtrlPosNo = 0; /*ilosc pozycji nastawnika*/
int ScndCtrlPosNo = 0;
int LightsPosNo = 0; // NOTE: values higher than 0 seem to break the current code for light switches
int LightsPosNo = 0;
int LightsDefPos = 1;
bool LightsWrap = false;
int Lights[2][17]; // pozycje świateł, przód - tył, 1 .. 16
bool ScndInMain = false; /*zaleznosc bocznika od nastawnika*/
enum light {
headlight_left = 0x01,
redmarker_left = 0x02,
headlight_upper = 0x04,
headlight_right = 0x10,
redmarker_right = 0x20,
};
int ScndInMain{ 0 }; /*zaleznosc bocznika od nastawnika*/
bool MBrake = false; /*Czy jest hamulec reczny*/
double StopBrakeDecc = 0.0;
TSecuritySystem SecuritySystem;
@@ -754,7 +756,7 @@ public:
double DoorStayOpen = 0.0; /*jak dlugo otwarte w przypadku DoorCloseCtrl=2*/
bool DoorClosureWarning = false; /*czy jest ostrzeganie przed zamknieciem*/
double DoorOpenSpeed = 1.0; double DoorCloseSpeed = 1.0; /*predkosc otwierania i zamykania w j.u. */
double DoorMaxShiftL = 0.5; double DoorMaxShiftR = 0.5; double DoorMaxPlugShift = 0.5;/*szerokosc otwarcia lub kat*/
double DoorMaxShiftL = 0.5; double DoorMaxShiftR = 0.5; double DoorMaxPlugShift = 0.1;/*szerokosc otwarcia lub kat*/
int DoorOpenMethod = 2; /*sposob otwarcia - 1: przesuwne, 2: obrotowe, 3: trójelementowe*/
double PlatformSpeed = 0.25; /*szybkosc stopnia*/
double PlatformMaxShift = 0.5; /*wysuniecie stopnia*/
@@ -879,6 +881,7 @@ public:
bool FuseFlag = false; /*!o bezpiecznik nadmiarowy*/
bool ConvOvldFlag = false; /*! nadmiarowy przetwornicy i ogrzewania*/
bool StLinFlag = false; /*!o styczniki liniowe*/
bool StLinSwitchOff{ false }; // state of the button forcing motor connectors open
bool ResistorsFlag = false; /*!o jazda rezystorowa*/
double RventRot = 0.0; /*!s obroty wentylatorow rozruchowych*/
bool UnBrake = false; /*w EZT - nacisniete odhamowywanie*/
@@ -1150,6 +1153,23 @@ private:
extern double Distance(TLocation Loc1, TLocation Loc2, TDimension Dim1, TDimension Dim2);
inline
std::string
extract_value( std::string const &Key, std::string const &Input ) {
std::string value;
auto lookup = Input.find( Key + "=" );
if( lookup != std::string::npos ) {
value = Input.substr( Input.find_first_not_of( ' ', lookup + Key.size() + 1 ) );
lookup = value.find( ' ' );
if( lookup != std::string::npos ) {
// trim everything past the value
value.erase( lookup );
}
}
return value;
}
template <typename _Type>
bool
extract_value( _Type &Variable, std::string const &Key, std::string const &Input, std::string const &Default ) {
@@ -1169,23 +1189,10 @@ extract_value( _Type &Variable, std::string const &Key, std::string const &Input
converter << Default;
converter >> Variable;
}
return false; // supplied the default
return false; // couldn't locate the variable in provided input
}
}
inline
std::string
extract_value( std::string const &Key, std::string const &Input ) {
std::string value;
auto lookup = Input.find( Key + "=" );
if( lookup != std::string::npos ) {
value = Input.substr( Input.find_first_not_of( ' ', lookup + Key.size() + 1 ) );
lookup = value.find( ' ' );
if( lookup != std::string::npos ) {
// trim everything past the value
value.erase( lookup );
}
}
return value;
}
template <>
bool
extract_value( bool &Variable, std::string const &Key, std::string const &Input, std::string const &Default );

View File

@@ -129,11 +129,15 @@ double TMoverParameters::current(double n, double U)
R = RList[MainCtrlActualPos].R * Bn + CircuitRes;
if ((TrainType != dt_EZT) || (Imin != IminLo) ||
(!ScndS)) // yBARC - boczniki na szeregu poprawnie
Mn = RList[MainCtrlActualPos].Mn; // to jest wykonywane dla EU07
else
Mn = RList[MainCtrlActualPos].Mn * RList[MainCtrlActualPos].Bn;
if( ( TrainType != dt_EZT )
|| ( Imin != IminLo )
|| ( false == ScndS ) ) {
// yBARC - boczniki na szeregu poprawnie
Mn = RList[ MainCtrlActualPos ].Mn; // to jest wykonywane dla EU07
}
else {
Mn = RList[ MainCtrlActualPos ].Mn * RList[ MainCtrlActualPos ].Bn;
}
// writepaslog("#",
// "C++-----------------------------------------------------------------------------");
@@ -154,21 +158,25 @@ double TMoverParameters::current(double n, double U)
if (DynamicBrakeFlag && (!FuseFlag) && (DynamicBrakeType == dbrake_automatic) &&
ConverterFlag && Mains) // hamowanie EP09 //TUHEX
{
// TODO: zrobic bardziej uniwersalne nie tylko dla EP09
MotorCurrent =
-Max0R(MotorParam[0].fi * (Vadd / (Vadd + MotorParam[0].Isat) - MotorParam[0].fi0), 0) *
n * 2.0 / ep09resED; // TODO: zrobic bardziej uniwersalne nie tylko dla EP09
-Max0R(MotorParam[0].fi * (Vadd / (Vadd + MotorParam[0].Isat) - MotorParam[0].fi0), 0) * n * 2.0 / ep09resED;
}
else if( ( RList[ MainCtrlActualPos ].Bn == 0 )
|| ( false == StLinFlag ) ) {
// wylaczone
MotorCurrent = 0;
}
else if ((RList[MainCtrlActualPos].Bn == 0) || (!StLinFlag))
MotorCurrent = 0; // wylaczone
else
{ // wlaczone...
SP = ScndCtrlActualPos;
if (ScndCtrlActualPos < 255) // tak smiesznie bede wylaczal
{
if (ScndInMain)
if (!(RList[MainCtrlActualPos].ScndAct == 255))
SP = RList[MainCtrlActualPos].ScndAct;
if( ( ScndInMain )
&& ( RList[ MainCtrlActualPos ].ScndAct != 255 ) ) {
SP = RList[ MainCtrlActualPos ].ScndAct;
}
Rz = Mn * WindingRes + R;
@@ -212,10 +220,10 @@ double TMoverParameters::current(double n, double U)
{
if (U > 0)
MotorCurrent =
(U1 - Isf * Rz - Mn * MotorParam[SP].fi * n + sqrt(Delta)) / (2.0 * Rz);
(U1 - Isf * Rz - Mn * MotorParam[SP].fi * n + std::sqrt(Delta)) / (2.0 * Rz);
else
MotorCurrent =
(U1 - Isf * Rz - Mn * MotorParam[SP].fi * n - sqrt(Delta)) / (2.0 * Rz);
(U1 - Isf * Rz - Mn * MotorParam[SP].fi * n - std::sqrt(Delta)) / (2.0 * Rz);
}
else
MotorCurrent = 0;
@@ -676,10 +684,23 @@ bool TMoverParameters::CurrentSwitch(int direction)
if (TrainType != dt_EZT)
return (MinCurrentSwitch(direction != 0));
}
if (EngineType == DieselEngine) // dla 2Ls150
if (ShuntModeAllow)
if (ActiveDir == 0) // przed ustawieniem kierunku
// TBD, TODO: split off shunt mode toggle into a separate command? It doesn't make much sense to have these two together like that
// dla 2Ls150
if( ( EngineType == DieselEngine )
&& ( true == ShuntModeAllow )
&& ( ActiveDir == 0 ) ) {
// przed ustawieniem kierunku
ShuntMode = ( direction != 0 );
return true;
}
// for SM42/SP42
if( ( EngineType == DieselElectric )
&& ( true == ShuntModeAllow )
&& ( MainCtrlPos == 0 ) ) {
ShuntMode = ( direction != 0 );
return true;
}
return false;
};
@@ -1814,8 +1835,9 @@ bool TMoverParameters::IncScndCtrl(int CtrlSpeed)
LastRelayTime = 0;
if ((OK) && (EngineType == ElectricInductionMotor))
// NOTE: round() already adds 0.5, are the ones added here as well correct?
if ((Vmax < 250))
ScndCtrlActualPos = Round(Vel + 0.5f);
ScndCtrlActualPos = Round(Vel + 0.5);
else
ScndCtrlActualPos = Round(Vel * 1.0 / 2 + 0.5);
@@ -2031,10 +2053,12 @@ void TMoverParameters::SecuritySystemCheck(double dt)
(Battery)) // Ra: EZT ma teraz czuwak w rozrządczym
{
// CA
if (Vel >=
SecuritySystem
.AwareMinSpeed) // domyślnie predkość większa od 10% Vmax, albo podanej jawnie w FIZ
{
if( ( SecuritySystem.AwareMinSpeed > 0.0 ?
( Vel >= SecuritySystem.AwareMinSpeed ) :
( ActiveDir != 0 ) ) ) {
// domyślnie predkość większa od 10% Vmax, albo podanej jawnie w FIZ
// with defined minspeed of 0 the alerter will activate with reverser out of neutral position
// this emulates behaviour of engines like SM42
SecuritySystem.SystemTimer += dt;
if (TestFlag(SecuritySystem.SystemType, 1) &&
TestFlag(SecuritySystem.Status, s_aware)) // jeśli świeci albo miga
@@ -2819,6 +2843,8 @@ void TMoverParameters::UpdateBrakePressure(double dt)
// *************************************************************************************************
void TMoverParameters::CompressorCheck(double dt)
{
CompressedVolume = std::max( 0.0, CompressedVolume - dt * AirLeakRate * 0.1 ); // nieszczelności: 0.001=1l/s
// if (CompressorSpeed>0.0) then //ten warunek został sprawdzony przy wywołaniu funkcji
if (VeselVolume > 0)
{
@@ -2941,6 +2967,11 @@ void TMoverParameters::CompressorCheck(double dt)
// *************************************************************************************************
void TMoverParameters::UpdatePipePressure(double dt)
{
if( PipePress > 1.0 ) {
Pipe->Flow( -(PipePress)* AirLeakRate * dt );
Pipe->Act();
}
const double LBDelay = 100;
const double kL = 0.5;
//double dV;
@@ -3115,7 +3146,7 @@ void TMoverParameters::UpdatePipePressure(double dt)
// temp = (Handle as TFVel6).GetCP
temp = Handle->GetCP();
else
temp = 0;
temp = 0.0;
Hamulec->SetEPS(temp);
SendCtrlToNext("Brake", temp,
CabNo); // Ra 2014-11: na tym się wysypuje, ale nie wiem, w jakich warunkach
@@ -3124,9 +3155,9 @@ void TMoverParameters::UpdatePipePressure(double dt)
Pipe->Act();
PipePress = Pipe->P();
if ((BrakeStatus & 128) == 128) // jesli hamulec wyłączony
temp = 0; // odetnij
temp = 0.0; // odetnij
else
temp = 1; // połącz
temp = 1.0; // połącz
Pipe->Flow(temp * Hamulec->GetPF(temp * PipePress, dt, Vel) + GetDVc(dt));
if (ASBType == 128)
@@ -3138,17 +3169,17 @@ void TMoverParameters::UpdatePipePressure(double dt)
Pipe->Act();
PipePress = Pipe->P();
dpMainValve = dpMainValve / (100 * dt); // normalizacja po czasie do syczenia;
dpMainValve = dpMainValve / (100.0 * dt); // normalizacja po czasie do syczenia;
if (PipePress < -1)
if (PipePress < -1.0)
{
PipePress = -1;
Pipe->CreatePress(-1);
PipePress = -1.0;
Pipe->CreatePress(-1.0);
Pipe->Act();
}
if (CompressedVolume < 0)
CompressedVolume = 0;
if (CompressedVolume < 0.0)
CompressedVolume = 0.0;
}
// *************************************************************************************************
@@ -3157,6 +3188,11 @@ void TMoverParameters::UpdatePipePressure(double dt)
// *************************************************************************************************
void TMoverParameters::UpdateScndPipePressure(double dt)
{
if( ScndPipePress > 1.0 ) {
Pipe2->Flow( -(ScndPipePress)* AirLeakRate * dt );
Pipe2->Act();
}
const double Spz = 0.5067;
TMoverParameters *c;
double dv1, dv2, dV;
@@ -4087,106 +4123,152 @@ double TMoverParameters::TractionForce(double dt)
if ((MainCtrlPos == 0) || (ShuntMode))
ScndCtrlPos = 0;
else if (AutoRelayFlag)
switch (RelayType)
{
case 0:
{
if ((Im <= (MPTRelay[ScndCtrlPos].Iup * PosRatio)) &&
(ScndCtrlPos < ScndCtrlPosNo))
else {
if( AutoRelayFlag ) {
switch( RelayType ) {
case 0: {
if( ( Im <= ( MPTRelay[ ScndCtrlPos ].Iup * PosRatio ) ) &&
( ScndCtrlPos < ScndCtrlPosNo ) )
++ScndCtrlPos;
if ((Im >= (MPTRelay[ScndCtrlPos].Idown * PosRatio)) && (ScndCtrlPos > 0))
if( ( Im >= ( MPTRelay[ ScndCtrlPos ].Idown * PosRatio ) ) && ( ScndCtrlPos > 0 ) )
--ScndCtrlPos;
break;
}
case 1:
{
if ((MPTRelay[ScndCtrlPos].Iup < Vel) && (ScndCtrlPos < ScndCtrlPosNo))
case 1: {
if( ( MPTRelay[ ScndCtrlPos ].Iup < Vel ) && ( ScndCtrlPos < ScndCtrlPosNo ) )
++ScndCtrlPos;
if ((MPTRelay[ScndCtrlPos].Idown > Vel) && (ScndCtrlPos > 0))
if( ( MPTRelay[ ScndCtrlPos ].Idown > Vel ) && ( ScndCtrlPos > 0 ) )
--ScndCtrlPos;
break;
}
case 2:
{
if ((MPTRelay[ScndCtrlPos].Iup < Vel) && (ScndCtrlPos < ScndCtrlPosNo) &&
(EnginePower < (tmp * 0.99)))
case 2: {
if( ( MPTRelay[ ScndCtrlPos ].Iup < Vel ) && ( ScndCtrlPos < ScndCtrlPosNo ) &&
( EnginePower < ( tmp * 0.99 ) ) )
++ScndCtrlPos;
if ((MPTRelay[ScndCtrlPos].Idown < Im) && (ScndCtrlPos > 0))
if( ( MPTRelay[ ScndCtrlPos ].Idown < Im ) && ( ScndCtrlPos > 0 ) )
--ScndCtrlPos;
break;
}
case 41:
{
if ((MainCtrlPos == MainCtrlPosNo) &&
(tmpV * 3.6 > MPTRelay[ScndCtrlPos].Iup) && (ScndCtrlPos < ScndCtrlPosNo))
{
if( ( MainCtrlPos == MainCtrlPosNo )
&& ( tmpV * 3.6 > MPTRelay[ ScndCtrlPos ].Iup )
&& ( ScndCtrlPos < ScndCtrlPosNo ) ) {
++ScndCtrlPos;
enrot = enrot * 0.73;
}
if ((Im > MPTRelay[ScndCtrlPos].Idown) && (ScndCtrlPos > 0))
if( ( Im > MPTRelay[ ScndCtrlPos ].Idown )
&& ( ScndCtrlPos > 0 ) ) {
--ScndCtrlPos;
}
break;
}
case 45:
{
if ((MainCtrlPos > 11) && (ScndCtrlPos < ScndCtrlPosNo))
if ((ScndCtrlPos == 0))
if ((MPTRelay[ScndCtrlPos].Iup > Im))
if( ( MainCtrlPos >= 10 ) && ( ScndCtrlPos < ScndCtrlPosNo ) ) {
if( ScndCtrlPos == 0 ) {
if( Im < MPTRelay[ ScndCtrlPos ].Iup ) {
++ScndCtrlPos;
else if ((MPTRelay[ScndCtrlPos].Iup < Vel))
}
}
else {
if( Vel > MPTRelay[ ScndCtrlPos ].Iup ) {
++ScndCtrlPos;
}
// check for cases where the speed drops below threshold for level 2 or 3
if( ( ScndCtrlPos > 1 )
&& ( Vel < MPTRelay[ ScndCtrlPos - 1 ].Idown ) ){
--ScndCtrlPos;
}
}
}
// malenie
if ((ScndCtrlPos > 0) && (MainCtrlPos < 12))
if ((ScndCtrlPos == ScndCtrlPosNo))
if ((MPTRelay[ScndCtrlPos].Idown < Im))
if( ( ScndCtrlPos > 0 ) && ( MainCtrlPos < 10 ) ) {
if( ScndCtrlPos == 1 ) {
if( Im > MPTRelay[ ScndCtrlPos - 1 ].Idown ) {
--ScndCtrlPos;
else if ((MPTRelay[ScndCtrlPos].Idown > Vel))
}
}
else {
if( Vel < MPTRelay[ ScndCtrlPos ].Idown ) {
--ScndCtrlPos;
if ((MainCtrlPos < 11) && (ScndCtrlPos > 2))
ScndCtrlPos = 2;
if ((MainCtrlPos < 9) && (ScndCtrlPos > 0))
}
}
}
// 3rd level drops with master controller at position lower than 10...
if( MainCtrlPos < 10 ) {
ScndCtrlPos = std::min( 2, ScndCtrlPos );
}
// ...and below position 7 field shunt drops altogether
if( MainCtrlPos < 7 ) {
ScndCtrlPos = 0;
}
break;
}
case 46:
{
// wzrastanie
if ((MainCtrlPos > 9) && (ScndCtrlPos < ScndCtrlPosNo))
if ((ScndCtrlPos) % 2 == 0)
if ((MPTRelay[ScndCtrlPos].Iup > Im))
if( ( MainCtrlPos >= 10 )
&& ( ScndCtrlPos < ScndCtrlPosNo ) ) {
if( ( ScndCtrlPos ) % 2 == 0 ) {
if( ( MPTRelay[ ScndCtrlPos ].Iup > Im ) ) {
++ScndCtrlPos;
else if ((MPTRelay[ScndCtrlPos - 1].Iup > Im) &&
(MPTRelay[ScndCtrlPos].Iup < Vel))
}
}
else {
if( ( MPTRelay[ ScndCtrlPos - 1 ].Iup > Im )
&& ( MPTRelay[ ScndCtrlPos ].Iup < Vel ) ) {
++ScndCtrlPos;
}
}
}
// malenie
if ((MainCtrlPos < 10) && (ScndCtrlPos > 0))
if ((ScndCtrlPos) % 2 == 0)
if ((MPTRelay[ScndCtrlPos].Idown < Im))
if( ( MainCtrlPos < 10 )
&& ( ScndCtrlPos > 0 ) ) {
if( ( ScndCtrlPos ) % 2 == 0 ) {
if( ( MPTRelay[ ScndCtrlPos ].Idown < Im ) ) {
--ScndCtrlPos;
else if ((MPTRelay[ScndCtrlPos + 1].Idown < Im) &&
(MPTRelay[ScndCtrlPos].Idown > Vel))
}
}
else {
if( ( MPTRelay[ ScndCtrlPos + 1 ].Idown < Im )
&& ( MPTRelay[ ScndCtrlPos ].Idown > Vel ) ) {
--ScndCtrlPos;
if ((MainCtrlPos < 9) && (ScndCtrlPos > 2))
ScndCtrlPos = 2;
if ((MainCtrlPos < 6) && (ScndCtrlPos > 0))
}
}
}
if( MainCtrlPos < 10 ) {
ScndCtrlPos = std::min( 2, ScndCtrlPos );
}
if( MainCtrlPos < 7 ) {
ScndCtrlPos = 0;
}
break;
}
default: {
break;
}
} // switch RelayType
}
}
break;
} // DieselElectric
case ElectricInductionMotor:
{
if ((Mains)) // nie wchodzić w funkcję bez potrzeby
if ((abs(Voltage) < EnginePowerSource.CollectorParameters.MinV) ||
(abs(Voltage) > EnginePowerSource.CollectorParameters.MaxV + 200))
{
MainSwitch(false);
if( ( Mains ) ) {
// nie wchodzić w funkcję bez potrzeby
if( ( abs( Voltage ) < EnginePowerSource.CollectorParameters.MinV )
|| ( abs( Voltage ) > EnginePowerSource.CollectorParameters.MaxV + 200 ) ) {
MainSwitch( false );
}
tmpV = abs(nrot) * (PI * WheelDiameter) *
3.6; //*DirAbsolute*eimc[eimc_s_p]; - do przemyslenia dzialanie pp
}
tmpV = abs(nrot) * (PI * WheelDiameter) * 3.6; //*DirAbsolute*eimc[eimc_s_p]; - do przemyslenia dzialanie pp
if ((Mains))
{
@@ -4833,7 +4915,8 @@ bool TMoverParameters::AutoRelayCheck(void)
(MainCtrlActualPos == 0) && (ActiveDir != 0))
{ //^^ TODO: sprawdzic BUG, prawdopodobnie w CreateBrakeSys()
DelayCtrlFlag = true;
if (LastRelayTime >= InitialCtrlDelay)
if( (LastRelayTime >= InitialCtrlDelay)
&& ( false == StLinSwitchOff ) )
{
StLinFlag = true; // ybARC - zalaczenie stycznikow liniowych
MainCtrlActualPos = 1;
@@ -4894,48 +4977,37 @@ bool TMoverParameters::AutoRelayCheck(void)
// *************************************************************************************************
// Q: 20160713
// Podnosi / opuszcza przedni pantograf
// Podnosi / opuszcza przedni pantograf. Returns: state of the pantograph after the operation
// *************************************************************************************************
bool TMoverParameters::PantFront(bool State)
{
double pf1 = 0;
bool PF = false;
if( ( true == Battery )
|| ( true == ConverterFlag ) ) {
if ((Battery ==
true) /* and ((TrainType<>dt_ET40)or ((TrainType=dt_ET40) and (EnginePowerSource.CollectorsNo>1)))*/)
{
PF = true;
if (State == true)
pf1 = 1;
else
pf1 = 0;
if (PantFrontUp != State)
{
if( PantFrontUp != State ) {
PantFrontUp = State;
if (State == true)
{
if( State == true ) {
PantFrontStart = 0;
SendCtrlToNext("PantFront", 1, CabNo);
SendCtrlToNext( "PantFront", 1, CabNo );
}
else
{
PF = false;
else {
PantFrontStart = 1;
SendCtrlToNext("PantFront", 0, CabNo);
//{Ra: nie ma potrzeby opuszczać obydwu na raz, jak mozemy każdy osobno
// if (TrainType == dt_EZT) && (ActiveCab == 1)
// {
// PantRearUp = false;
// PantRearStart = 1;
// SendCtrlToNext("PantRear", 0, CabNo);
// }
//}
SendCtrlToNext( "PantFront", 0, CabNo );
}
}
}
else
SendCtrlToNext("PantFront", pf1, CabNo);
else {
// no power, drop the pantograph
// NOTE: this is a simplification as it should just drop on its own with loss of pressure without resupply from (dead) compressor
PantFrontStart = (
PantFrontUp ?
1 :
0 );
PantFrontUp = false;
SendCtrlToNext( "PantFront", 0, CabNo );
}
return PF;
return PantFrontUp;
}
// *************************************************************************************************
@@ -4944,35 +5016,33 @@ bool TMoverParameters::PantFront(bool State)
// *************************************************************************************************
bool TMoverParameters::PantRear(bool State)
{
double pf1;
bool PR = false;
if( ( true == Battery )
|| ( true == ConverterFlag ) ) {
if (Battery == true)
{
PR = true;
if (State == true)
pf1 = 1;
else
pf1 = 0;
if (PantRearUp != State)
{
if( PantRearUp != State ) {
PantRearUp = State;
if (State == true)
{
if( State == true ) {
PantRearStart = 0;
SendCtrlToNext("PantRear", 1, CabNo);
SendCtrlToNext( "PantRear", 1, CabNo );
}
else
{
PR = false;
else {
PantRearStart = 1;
SendCtrlToNext("PantRear", 0, CabNo);
SendCtrlToNext( "PantRear", 0, CabNo );
}
}
}
else
SendCtrlToNext("PantRear", pf1, CabNo);
else {
// no power, drop the pantograph
// NOTE: this is a simplification as it should just drop on its own with loss of pressure without resupply from (dead) compressor
PantRearStart = (
PantRearUp ?
1 :
0 );
PantRearUp = false;
SendCtrlToNext( "PantRear", 0, CabNo );
}
return PR;
return PantRearUp;
}
// *************************************************************************************************
@@ -5926,10 +5996,15 @@ bool TMoverParameters::LoadFIZ(std::string chkpath)
continue;
}
if( inputline[ 0 ] == ' ' ) {
// guard against malformed config files with leading spaces
inputline.erase( 0, inputline.find_first_not_of( ' ' ) );
}
if( inputline.length() == 0 ) {
startBPT = false;
continue;
}
// checking if table parsing should be switched off goes first...
if( issection( "END-MPT", inputline ) ) {
startBPT = false;
@@ -6422,6 +6497,11 @@ void TMoverParameters::LoadFIZ_Brake( std::string const &line ) {
lookup->second :
1;
}
if( true == extract_value( AirLeakRate, "AirLeakRate", line, "" ) ) {
// the parameter is provided in form of a multiplier, where 1.0 means the default rate of 0.001
AirLeakRate *= 0.01;
}
}
void TMoverParameters::LoadFIZ_Doors( std::string const &line ) {
@@ -6633,8 +6713,10 @@ void TMoverParameters::LoadFIZ_Cntrl( std::string const &line ) {
}
// mbpm
extract_value( MBPM, "MaxBPMass", line, "" );
// MBPM *= 1000;
if( true == extract_value( MBPM, "MaxBPMass", line, "" ) ) {
// NOTE: only convert the value from tons to kilograms if the entry is present in the config file
MBPM *= 1000.0;
}
// asbtype
std::string asb;
@@ -6891,6 +6973,9 @@ void TMoverParameters::LoadFIZ_Switches( std::string const &Input ) {
extract_value( PantSwitchType, "Pantograph", Input, "" );
extract_value( ConvSwitchType, "Converter", Input, "" );
// because people can't make up their minds whether it's "impulse" or "Impulse"...
PantSwitchType = ToLower( PantSwitchType );
ConvSwitchType = ToLower( ConvSwitchType );
}
void TMoverParameters::LoadFIZ_MotorParamTable( std::string const &Input ) {
@@ -7912,3 +7997,22 @@ double TMoverParameters::ShowCurrentP(int AmpN)
return current;
}
}
template <>
bool
extract_value( bool &Variable, std::string const &Key, std::string const &Input, std::string const &Default ) {
auto value = extract_value( Key, Input );
if( false == value.empty() ) {
// set the specified variable to retrieved value
Variable = ( ToLower( value ) == "yes" );
return true; // located the variable
}
else {
// set the variable to provided default value
if( false == Default.empty() ) {
Variable = ( ToLower( Default ) == "yes" );
}
return false; // couldn't locate the variable in provided input
}
}

View File

@@ -45,7 +45,6 @@ static int const bdelay_G = 1; //G
static int const bdelay_P = 2; //P
static int const bdelay_R = 4; //R
static int const bdelay_M = 8; //Mg
static int const bdelay_GR = 128; //G-R
/*stan hamulca*/

View File

@@ -72,23 +72,11 @@ double Min0R(double x1, double x2)
// TODO: replace with something sensible
std::string Now() {
std::time_t timenow = std::time( nullptr );
std::tm tm = *std::localtime( &timenow );
std::stringstream converter;
converter << std::put_time( &tm, "%c" );
std::time_t timenow = std::time( nullptr );
std::tm tm = *std::localtime( &timenow );
std::stringstream converter;
converter << std::put_time( &tm, "%c" );
return converter.str();
/* char buffer[ 256 ];
sprintf( buffer,
"%d-%02d-%02d %02d:%02d:%02d.%03d",
st.wYear,
st.wMonth,
st.wDay,
st.wHour,
st.wMinute,
st.wSecond,
st.wMilliseconds );
*/
}
bool TestFlag(int Flag, int Value)

View File

@@ -62,7 +62,7 @@ inline double Sign(double x)
return x >= 0 ? 1.0 : -1.0;
}
inline long Round(float f)
inline long Round(double const f)
{
return (long)(f + 0.5);
//return lround(f);

View File

@@ -313,12 +313,21 @@ int TSubModel::Load(cParser &parser, TModel3d *Model, int Pos, bool dynamic)
}
std::string discard;
parser.getTokens(13, false);
parser >> fNearAttenStart >> discard >> fNearAttenEnd >> discard >> bUseNearAtten >>
discard >> iFarAttenDecay >> discard >> fFarDecayRadius >> discard >>
fCosFalloffAngle // kąt liczony dla średnicy, a nie promienia
parser
>> fNearAttenStart
>> discard >> fNearAttenEnd
>> discard >> bUseNearAtten
>> discard >> iFarAttenDecay
>> discard >> fFarDecayRadius
>> discard >> fCosFalloffAngle // kąt liczony dla średnicy, a nie promienia
>> discard >> fCosHotspotAngle; // kąt liczony dla średnicy, a nie promienia
fCosFalloffAngle = cos(DegToRad(0.5 * fCosFalloffAngle));
fCosHotspotAngle = cos(DegToRad(0.5 * fCosHotspotAngle));
// convert conve parameters if specified in degrees
if( fCosFalloffAngle > 1.0 ) {
fCosFalloffAngle = std::cos( DegToRad( 0.5f * fCosFalloffAngle ) );
}
if( fCosHotspotAngle > 1.0 ) {
fCosHotspotAngle = std::cos( DegToRad( 0.5f * fCosHotspotAngle ) );
}
iNumVerts = 1;
/*
iFlags |= 0x4010; // rysowane w cyklu nieprzezroczystych, macierz musi zostać bez zmiany
@@ -952,29 +961,27 @@ void TSubModel::RaAnimation(TAnimType a)
glRotatef(v_Angles.z, 0.0f, 0.0f, 1.0f);
break;
case at_SecondsJump: // sekundy z przeskokiem
glRotatef(floor(GlobalTime->mr) * 6.0, 0.0, 1.0, 0.0);
glRotatef(simulation::Time.data().wSecond * 6.0, 0.0, 1.0, 0.0);
break;
case at_MinutesJump: // minuty z przeskokiem
glRotatef(GlobalTime->mm * 6.0, 0.0, 1.0, 0.0);
glRotatef(simulation::Time.data().wMinute * 6.0, 0.0, 1.0, 0.0);
break;
case at_HoursJump: // godziny skokowo 12h/360°
glRotatef(GlobalTime->hh * 30.0 * 0.5, 0.0, 1.0, 0.0);
glRotatef(simulation::Time.data().wHour * 30.0 * 0.5, 0.0, 1.0, 0.0);
break;
case at_Hours24Jump: // godziny skokowo 24h/360°
glRotatef(GlobalTime->hh * 15.0 * 0.25, 0.0, 1.0, 0.0);
glRotatef(simulation::Time.data().wHour * 15.0 * 0.25, 0.0, 1.0, 0.0);
break;
case at_Seconds: // sekundy płynnie
glRotatef(GlobalTime->mr * 6.0, 0.0, 1.0, 0.0);
glRotatef(simulation::Time.second() * 6.0, 0.0, 1.0, 0.0);
break;
case at_Minutes: // minuty płynnie
glRotatef(GlobalTime->mm * 6.0 + GlobalTime->mr * 0.1, 0.0, 1.0, 0.0);
glRotatef(simulation::Time.data().wMinute * 6.0 + simulation::Time.second() * 0.1, 0.0, 1.0, 0.0);
break;
case at_Hours: // godziny płynnie 12h/360°
// glRotatef(GlobalTime->hh*30.0+GlobalTime->mm*0.5+GlobalTime->mr/120.0,0.0,1.0,0.0);
glRotatef(2.0 * Global::fTimeAngleDeg, 0.0, 1.0, 0.0);
break;
case at_Hours24: // godziny płynnie 24h/360°
// glRotatef(GlobalTime->hh*15.0+GlobalTime->mm*0.25+GlobalTime->mr/240.0,0.0,1.0,0.0);
glRotatef(Global::fTimeAngleDeg, 0.0, 1.0, 0.0);
break;
case at_Billboard: // obrót w pionie do kamery
@@ -994,7 +1001,7 @@ void TSubModel::RaAnimation(TAnimType a)
}
break;
case at_Wind: // ruch pod wpływem wiatru (wiatr będziemy liczyć potem...)
glRotated(1.5 * sin(M_PI * GlobalTime->mr / 6.0), 0.0, 1.0, 0.0);
glRotated(1.5 * std::sin(M_PI * simulation::Time.second() / 6.0), 0.0, 1.0, 0.0);
break;
case at_Sky: // animacja nieba
glRotated(Global::fLatitudeDeg, 1.0, 0.0, 0.0); // ustawienie osi OY na północ
@@ -1642,15 +1649,21 @@ bool TModel3d::LoadFromFile(std::string const &FileName, bool dynamic)
LoadFromBinFile(asBinary, dynamic);
asBinary = ""; // wyłączenie zapisu
Init();
}
// cache the file name, in case someone wants it later
m_filename = name + ".e3d";
}
else
{
if (FileExists(name + ".t3d"))
{
LoadFromTextFile(FileName, dynamic); // wczytanie tekstowego
if (!dynamic) // pojazdy dopiero po ustawieniu animacji
Init(); // generowanie siatek i zapis E3D
}
if( !dynamic ) {
// pojazdy dopiero po ustawieniu animacji
Init(); // generowanie siatek i zapis E3D
}
// cache the file name, in case someone wants it later
m_filename = name + ".t3d";
}
}
bool const result =
Root ? (iSubModelsCount > 0) : false; // brak pliku albo problem z wczytaniem
@@ -2021,6 +2034,14 @@ void TSubModel::BinInit(TSubModel *s, float4x4 *m, float8 *v,
// so as a workaround we're doing it here manually
iFlags |= 0x20;
}
// intercept and fix hotspot values if specified in degrees and not directly
if( fCosFalloffAngle > 1.0 ) {
fCosFalloffAngle = std::cos( DegToRad( 0.5f * fCosFalloffAngle ) );
}
if( fCosHotspotAngle > 1.0 ) {
fCosHotspotAngle = std::cos( DegToRad( 0.5f * fCosHotspotAngle ) );
}
iFlags &= ~0x0200; // wczytano z pliku binarnego (nie jest właścicielem tablic)
iVboPtr = tVboPtr;

View File

@@ -342,6 +342,7 @@ private:
int *iModel; // zawartość pliku binarnego
int iSubModelsCount; // Ra: używane do tworzenia binarnych
std::string asBinary; // nazwa pod którą zapisać model binarny
std::string m_filename;
public:
inline TSubModel * GetSMRoot()
{
@@ -382,7 +383,8 @@ public:
void Init();
std::string NameGet()
{
return Root ? Root->pName : NULL;
// return Root ? Root->pName : NULL;
return m_filename;
};
int TerrainCount();
TSubModel * TerrainSquare(int n);

View File

@@ -48,6 +48,7 @@ class TRealSound
int GetStatus();
void ResetPosition();
// void FreqReset(float f=22050.0) {fFrequency=f;};
bool Empty() { return ( pSound == nullptr ); }
};
class TTextSound : public TRealSound

View File

@@ -18,7 +18,7 @@ double ResourceManager::_lastReport = 0.0f;
void ResourceManager::Register(Resource *resource)
{
_resources.push_back(resource);
_resources.emplace_back(resource);
};
void ResourceManager::Unregister(Resource *resource)

View File

@@ -401,7 +401,9 @@ void TSegment::RenderLoft(const vector6 *ShapePoints, int iNumShapePoints, doubl
jmm1 * ShapePoints[j].z + m1 * ShapePoints[j + iNumShapePoints].z, tv1);
glVertex3f(pt.x, pt.y, pt.z); // pt nie mamy gdzie zapamiętać?
}
if (p) // jeśli jest wskaźnik do tablicy
// BUG: things blow up badly in the following part in 64bit version on baltyk.scn
// TODO: sort this mess out when the time comes to reorganize spline generation
if( p ) // jeśli jest wskaźnik do tablicy
if (*p)
if (!j) // to dla pierwszego punktu
{

View File

@@ -15,12 +15,12 @@ namespace Timer
{
double DeltaTime, DeltaRenderTime;
double fFPS = 0.0f;
double fLastTime = 0.0f;
DWORD dwFrames = 0L;
double fSimulationTime = 0;
double fSoundTimer = 0;
double fSinceStart = 0;
double fFPS{ 0.0f };
double fLastTime{ 0.0f };
DWORD dwFrames{ 0 };
double fSimulationTime{ 0.0 };
double fSoundTimer{ 0.0 };
double fSinceStart{ 0.0 };
double GetTime()
{
@@ -69,15 +69,10 @@ double GetFPS()
void ResetTimers()
{
// double CurrentTime=
#if _WIN32_WINNT >= _WIN32_WINNT_VISTA
::GetTickCount64();
#else
::GetTickCount();
#endif
UpdateTimers( Global::iPause != 0 );
DeltaTime = 0.1;
DeltaRenderTime = 0;
fSoundTimer = 0;
DeltaRenderTime = 0.0;
fSoundTimer = 0.0;
};
LONGLONG fr, count, oldCount;
@@ -92,17 +87,17 @@ void UpdateTimers(bool pause)
DeltaTime = Global::fTimeSpeed * DeltaRenderTime;
fSoundTimer += DeltaTime;
if (fSoundTimer > 0.1)
fSoundTimer = 0;
fSoundTimer = 0.0;
/*
double CurrentTime= double(count)/double(fr);//GetTickCount();
DeltaTime= (CurrentTime-OldTime);
OldTime= CurrentTime;
*/
if (DeltaTime > 1)
DeltaTime = 1;
if (DeltaTime > 1.0)
DeltaTime = 1.0;
}
else
DeltaTime = 0; // wszystko stoi, bo czas nie płynie
DeltaTime = 0.0; // wszystko stoi, bo czas nie płynie
oldCount = count;
// Keep track of the time lapse and frame count

View File

@@ -7,8 +7,7 @@ obtain one at
http://mozilla.org/MPL/2.0/.
*/
#ifndef TimerH
#define TimerH
#pragma once
namespace Timer
{
@@ -36,4 +35,3 @@ void UpdateTimers(bool pause);
};
//---------------------------------------------------------------------------
#endif

View File

@@ -2521,7 +2521,7 @@ void TTrack::EnvironmentSet()
#else
switch( eEnvironment ) {
case e_canyon: {
Global::DayLight.apply_intensity( 0.5f );
Global::DayLight.apply_intensity( 0.4f );
break;
}
case e_tunnel: {

4870
Train.cpp

File diff suppressed because it is too large Load Diff

153
Train.h
View File

@@ -7,39 +7,28 @@ obtain one at
http://mozilla.org/MPL/2.0/.
*/
#ifndef TrainH
#define TrainH
#pragma once
//#include "Track.h"
//#include "TrkFoll.h"
#include "Button.h"
#include <string>
#include "DynObj.h"
#include "Button.h"
#include "Gauge.h"
#include "Model3d.h"
#include "Spring.h"
#include "mtable.h"
#include "AdvSound.h"
#include "FadeSound.h"
#include "PyInt.h"
#include "RealSound.h"
#include "Sound.h"
#include <string>
#include "command.h"
// typedef enum {st_Off, st_Starting, st_On, st_ShuttingDown} T4State;
const int maxcab = 2;
// const double fCzuwakTime= 90.0f;
const double fCzuwakBlink = 0.15;
const float fConverterPrzekaznik = 1.5f; // hunter-261211: do przekaznika nadmiarowego przetwornicy
// 0.33f
// const double fBuzzerTime= 5.0f;
const float fHaslerTime = 1.2f;
// const double fStycznTime= 0.5f;
// const double fDblClickTime= 0.2f;
class TCab
{
public:
@@ -77,52 +66,126 @@ class TTrain
bool InitializeCab(int NewCabNo, std::string const &asFileName);
TTrain();
~TTrain();
// bool Init(TTrack *Track);
// McZapkie-010302
bool Init(TDynamicObject *NewDynamicObject, bool e3d = false);
void OnKeyDown(int cKey);
void OnKeyUp(int cKey);
// bool SHP() { fShpTimer= 0; };
inline vector3 GetDirection()
{
return DynamicObject->VectorFront();
};
inline vector3 GetUp()
{
return DynamicObject->VectorUp();
};
inline vector3 GetDirection() { return DynamicObject->VectorFront(); };
inline vector3 GetUp() { return DynamicObject->VectorUp(); };
void UpdateMechPosition(double dt);
vector3 GetWorldMechPosition();
bool Update( double const Deltatime );
bool m_updated = false;
void MechStop();
void SetLights();
// virtual bool RenderAlpha();
// McZapkie-310302: ladowanie parametrow z pliku
bool LoadMMediaFile(std::string const &asFileName);
PyObject *GetTrainState();
private:
// types
typedef void( *command_handler )( TTrain *Train, command_data const &Command );
typedef std::unordered_map<user_command, command_handler> commandhandler_map;
// clears state of all cabin controls
void clear_cab_controls();
// sets cabin controls based on current state of the vehicle
// NOTE: we can get rid of this function once we have per-cab persistent state
void set_cab_controls();
// initializes a gauge matching provided label. returns: true if the label was found, false
// otherwise
bool initialize_gauge(cParser &Parser, std::string const &Label, int const Cabindex);
// initializes a button matching provided label. returns: true if the label was found, false
// otherwise
bool initialize_button(cParser &Parser, std::string const &Label, int const Cabindex);
// plays specified sound, or fallback sound if the primary sound isn't presend
// NOTE: temporary routine until sound system is sorted out and paired with switches
void play_sound( PSound Sound, int const Volume = DSBVOLUME_MAX, DWORD const Flags = 0 );
void play_sound( PSound Sound, PSound Fallbacksound, int const Volume, DWORD const Flags );
// helper, returns true for EMU with oerlikon brake
bool is_eztoer() const;
// command handlers
// NOTE: we're currently using universal handlers and static handler map but it may be beneficial to have these implemented on individual class instance basis
// TBD, TODO: consider this approach if we ever want to have customized consist behaviour to received commands, based on the consist/vehicle type or whatever
static void OnCommand_mastercontrollerincrease( TTrain *Train, command_data const &Command );
static void OnCommand_mastercontrollerincreasefast( TTrain *Train, command_data const &Command );
static void OnCommand_mastercontrollerdecrease( TTrain *Train, command_data const &Command );
static void OnCommand_mastercontrollerdecreasefast( TTrain *Train, command_data const &Command );
static void OnCommand_secondcontrollerincrease( TTrain *Train, command_data const &Command );
static void OnCommand_secondcontrollerincreasefast( TTrain *Train, command_data const &Command );
static void OnCommand_secondcontrollerdecrease( TTrain *Train, command_data const &Command );
static void OnCommand_secondcontrollerdecreasefast( TTrain *Train, command_data const &Command );
static void OnCommand_notchingrelaytoggle( TTrain *Train, command_data const &Command );
static void OnCommand_mucurrentindicatorothersourceactivate( TTrain *Train, command_data const &Command );
static void OnCommand_independentbrakeincrease( TTrain *Train, command_data const &Command );
static void OnCommand_independentbrakeincreasefast( TTrain *Train, command_data const &Command );
static void OnCommand_independentbrakedecrease( TTrain *Train, command_data const &Command );
static void OnCommand_independentbrakedecreasefast( TTrain *Train, command_data const &Command );
static void OnCommand_independentbrakebailoff( TTrain *Train, command_data const &Command );
static void OnCommand_trainbrakeincrease( TTrain *Train, command_data const &Command );
static void OnCommand_trainbrakedecrease( TTrain *Train, command_data const &Command );
static void OnCommand_trainbrakecharging( TTrain *Train, command_data const &Command );
static void OnCommand_trainbrakerelease( TTrain *Train, command_data const &Command );
static void OnCommand_trainbrakefirstservice( TTrain *Train, command_data const &Command );
static void OnCommand_trainbrakeservice( TTrain *Train, command_data const &Command );
static void OnCommand_trainbrakefullservice( TTrain *Train, command_data const &Command );
static void OnCommand_trainbrakeemergency( TTrain *Train, command_data const &Command );
static void OnCommand_wheelspinbrakeactivate( TTrain *Train, command_data const &Command );
static void OnCommand_sandboxactivate( TTrain *Train, command_data const &Command );
static void OnCommand_epbrakecontroltoggle( TTrain *Train, command_data const &Command );
static void OnCommand_brakeactingspeedincrease( TTrain *Train, command_data const &Command );
static void OnCommand_brakeactingspeeddecrease( TTrain *Train, command_data const &Command );
static void OnCommand_mubrakingindicatortoggle( TTrain *Train, command_data const &Command );
static void OnCommand_reverserincrease( TTrain *Train, command_data const &Command );
static void OnCommand_reverserdecrease( TTrain *Train, command_data const &Command );
static void OnCommand_alerteracknowledge( TTrain *Train, command_data const &Command );
static void OnCommand_batterytoggle( TTrain *Train, command_data const &Command );
static void OnCommand_pantographcompressorvalvetoggle( TTrain *Train, command_data const &Command );
static void OnCommand_pantographcompressoractivate( TTrain *Train, command_data const &Command );
static void OnCommand_pantographtogglefront( TTrain *Train, command_data const &Command );
static void OnCommand_pantographtogglerear( TTrain *Train, command_data const &Command );
static void OnCommand_pantographlowerall( TTrain *Train, command_data const &Command );
static void OnCommand_linebreakertoggle( TTrain *Train, command_data const &Command );
static void OnCommand_convertertoggle( TTrain *Train, command_data const &Command );
static void OnCommand_converteroverloadrelayreset( TTrain *Train, command_data const &Command );
static void OnCommand_compressortoggle( TTrain *Train, command_data const &Command );
static void OnCommand_motorconnectorsopen( TTrain *Train, command_data const &Command );
static void OnCommand_motordisconnect( TTrain *Train, command_data const &Command );
static void OnCommand_motoroverloadrelaythresholdtoggle( TTrain *Train, command_data const &Command );
static void OnCommand_motoroverloadrelayreset( TTrain *Train, command_data const &Command );
static void OnCommand_heatingtoggle( TTrain *Train, command_data const &Command );
static void OnCommand_headlighttoggleleft( TTrain *Train, command_data const &Command );
static void OnCommand_headlighttoggleright( TTrain *Train, command_data const &Command );
static void OnCommand_headlighttoggleupper( TTrain *Train, command_data const &Command );
static void OnCommand_redmarkertoggleleft( TTrain *Train, command_data const &Command );
static void OnCommand_redmarkertoggleright( TTrain *Train, command_data const &Command );
static void OnCommand_headlighttogglerearleft( TTrain *Train, command_data const &Command );
static void OnCommand_headlighttogglerearright( TTrain *Train, command_data const &Command );
static void OnCommand_headlighttogglerearupper( TTrain *Train, command_data const &Command );
static void OnCommand_redmarkertogglerearleft( TTrain *Train, command_data const &Command );
static void OnCommand_redmarkertogglerearright( TTrain *Train, command_data const &Command );
static void OnCommand_headlightsdimtoggle( TTrain *Train, command_data const &Command );
static void OnCommand_interiorlighttoggle( TTrain *Train, command_data const &Command );
static void OnCommand_interiorlightdimtoggle( TTrain *Train, command_data const &Command );
static void OnCommand_instrumentlighttoggle( TTrain *Train, command_data const &Command );
static void OnCommand_doorlocktoggle( TTrain *Train, command_data const &Command );
static void OnCommand_doortoggleleft( TTrain *Train, command_data const &Command );
static void OnCommand_doortoggleright( TTrain *Train, command_data const &Command );
static void OnCommand_departureannounce( TTrain *Train, command_data const &Command );
static void OnCommand_hornlowactivate( TTrain *Train, command_data const &Command );
static void OnCommand_hornhighactivate( TTrain *Train, command_data const &Command );
static void OnCommand_radiotoggle( TTrain *Train, command_data const &Command );
private: //żeby go nic z zewnątrz nie przestawiało
// members
TDynamicObject *DynamicObject; // przestawia zmiana pojazdu [F5]
private: //żeby go nic z zewnątrz nie przestawiało
TMoverParameters *mvControlled; // człon, w którym sterujemy silnikiem
TMoverParameters *mvOccupied; // człon, w którym sterujemy hamulcem
TMoverParameters *mvSecond; // drugi człon (ET40, ET41, ET42, ukrotnienia)
TMoverParameters *mvThird; // trzeci człon (SN61)
public: // reszta może by?publiczna
// AnsiString asMessage;
// helper variable, to prevent immediate switch between closing and opening line breaker circuit
int m_linebreakerstate{ 0 }; // -1: freshly open, 0: open, 1: closed, 2: freshly closed (and yes this is awful way to go about it)
static const commandhandler_map m_commandhandlers;
public: // reszta może by?publiczna
// McZapkie: definicje wskaźników
// Ra 2014-08: częsciowo przeniesione do tablicy w TCab
@@ -167,8 +230,7 @@ class TTrain
TGauge ggSandButton; // guzik piasecznicy
TGauge ggAntiSlipButton;
TGauge ggFuseButton;
TGauge ggConverterFuseButton; // hunter-261211: przycisk odblokowania
// nadmiarowego przetwornic i ogrzewania
TGauge ggConverterFuseButton; // hunter-261211: przycisk odblokowania nadmiarowego przetwornic i ogrzewania
TGauge ggStLinOffButton;
TGauge ggRadioButton;
TGauge ggUpperLightButton;
@@ -194,6 +256,8 @@ class TTrain
// ABu 090305 - syrena i prad nastepnego czlonu
TGauge ggHornButton;
TGauge ggHornLowButton;
TGauge ggHornHighButton;
TGauge ggNextCurrentButton;
// ABu 090305 - uniwersalne przyciski
TGauge ggUniversal1Button;
@@ -215,12 +279,12 @@ class TTrain
TGauge ggPantFrontButton;
TGauge ggPantRearButton;
TGauge ggPantFrontButtonOff; // EZT
TGauge ggPantRearButtonOff;
TGauge ggPantAllDownButton;
// Winger 020304 - wlacznik ogrzewania
TGauge ggTrainHeatingButton;
TGauge ggSignallingButton;
TGauge ggDoorSignallingButton;
// TModel3d *mdKabina; McZapkie-030303: to do dynobj
// TGauge ggDistCounter; //Ra 2014-07: licznik kilometrów
// TGauge ggVelocityDgt; //i od razu prędkościomierz
@@ -354,8 +418,7 @@ class TTrain
// TFadeSound sConverter; //przetwornica
// TFadeSound sSmallCompressor; //przetwornica
int iCabLightFlag; // McZapkie:120503: oswietlenie kabiny (0: wyl, 1:
// przyciemnione, 2: pelne)
int iCabLightFlag; // McZapkie:120503: oswietlenie kabiny (0: wyl, 1: przyciemnione, 2: pelne)
bool bCabLight; // hunter-091012: czy swiatlo jest zapalone?
bool bCabLightDim; // hunter-091012: czy przyciemnienie kabiny jest zapalone?
@@ -422,20 +485,10 @@ class TTrain
public:
float fPress[20][3]; // cisnienia dla wszystkich czlonow
float fEIMParams[9][10]; // parametry dla silnikow asynchronicznych
int RadioChannel()
{
return iRadioChannel;
};
inline TDynamicObject *Dynamic()
{
return DynamicObject;
};
inline TMoverParameters *Controlled()
{
return mvControlled;
};
int RadioChannel() { return iRadioChannel; };
inline TDynamicObject *Dynamic() { return DynamicObject; };
inline TMoverParameters *Controlled() { return mvControlled; };
void DynamicSet(TDynamicObject *d);
void Silence();
};
//---------------------------------------------------------------------------
#endif

619
World.cpp

File diff suppressed because it is too large Load Diff

71
World.h
View File

@@ -15,24 +15,66 @@ http://mozilla.org/MPL/2.0/.
#include "Ground.h"
#include "sky.h"
#include "sun.h"
#include "moon.h"
#include "stars.h"
#include "skydome.h"
#include "mczapkie/mover.h"
#include "renderer.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; }
int
julian_day() const;
private:
// calculates day of year from given date
int
yearday( int Day, int const Month, int const Year );
// 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 ];
};
namespace simulation {
extern simulation_time Time;
}
// wrapper for environment elements -- sky, sun, stars, clouds etc
class world_environment {
friend opengl_renderer;
public:
void init();
void update();
void render();
void time( int const Hour = -1, int const Minute = -1, int const Second = -1 );
private:
CSkyDome m_skydome;
cStars m_stars;
cSun m_sun;
cMoon m_moon;
TSky m_clouds;
};
@@ -45,13 +87,20 @@ class TWorld
void FollowView(bool wycisz = true);
void DistantView( bool const Near = false );
public:
public:
// types
// constructors
TWorld();
// destructor
~TWorld();
// methods
bool Init( GLFWwindow *w );
bool InitPerformed() { return m_init; }
GLFWwindow *window;
GLvoid glPrint(std::string const &Text);
void OnKeyDown(int cKey);
void OnKeyUp(int cKey);
// void UpdateWindow();
void OnMouseMove(double x, double y);
void OnCommandGet(DaneRozkaz *pRozkaz);
@@ -59,19 +108,14 @@ class TWorld
void TrainDelete(TDynamicObject *d = NULL);
// switches between static and dynamic daylight calculation
void ToggleDaylight();
TWorld();
~TWorld();
// double Aspect;
private:
std::string OutText1; // teksty na ekranie
std::string OutText2;
std::string OutText3;
std::string OutText4;
private:
void Update_Environment();
void Update_Camera( const double Deltatime );
void Update_UI();
void ResourceSweep();
void Render_Cab();
TCamera Camera;
TGround Ground;
world_environment Environment;
@@ -92,6 +136,7 @@ class TWorld
int tprev; // poprzedni czas
double Acc; // przyspieszenie styczne
bool m_init{ false }; // indicates whether initial update of the world was performed
public:
void ModifyTGA(std::string const &dir = "");
void CreateE3D(std::string const &dir = "", bool dyn = false);

216
command.cpp Normal file
View File

@@ -0,0 +1,216 @@
/*
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 "command.h"
#include "globals.h"
#include "logs.h"
#include "timer.h"
namespace simulation {
command_queue Commands;
commanddescription_sequence Commands_descriptions = {
{ "mastercontrollerincrease", command_target::vehicle },
{ "mastercontrollerincreasefast", command_target::vehicle },
{ "mastercontrollerdecrease", command_target::vehicle },
{ "mastercontrollerdecreasefast", command_target::vehicle },
{ "secondcontrollerincrease", command_target::vehicle },
{ "secondcontrollerincreasefast", command_target::vehicle },
{ "secondcontrollerdecrease", command_target::vehicle },
{ "secondcontrollerdecreasefast", command_target::vehicle },
{ "mucurrentindicatorothersourceactivate", command_target::vehicle },
{ "independentbrakeincrease", command_target::vehicle },
{ "independentbrakeincreasefast", command_target::vehicle },
{ "independentbrakedecrease", command_target::vehicle },
{ "independentbrakedecreasefast", command_target::vehicle },
{ "independentbrakebailoff", command_target::vehicle },
{ "trainbrakeincrease", command_target::vehicle },
{ "trainbrakedecrease", command_target::vehicle },
{ "trainbrakecharging", command_target::vehicle },
{ "trainbrakerelease", command_target::vehicle },
{ "trainbrakefirstservice", command_target::vehicle },
{ "trainbrakeservice", command_target::vehicle },
{ "trainbrakefullservice", command_target::vehicle },
{ "trainbrakeemergency", command_target::vehicle },
{ "wheelspinbrakeactivate", command_target::vehicle },
{ "sandboxactivate", command_target::vehicle },
{ "reverserincrease", command_target::vehicle },
{ "reverserdecrease", command_target::vehicle },
{ "linebreakertoggle", command_target::vehicle },
{ "convertertoggle", command_target::vehicle },
{ "converteroverloadrelayreset", command_target::vehicle },
{ "compressortoggle", command_target::vehicle },
{ "motoroverloadrelaythresholdtoggle", command_target::vehicle },
{ "motoroverloadrelayreset", command_target::vehicle },
{ "notchingrelaytoggle", command_target::vehicle },
{ "epbrakecontroltoggle", command_target::vehicle },
{ "brakeactingspeedincrease", command_target::vehicle },
{ "brakeactingspeeddecrease", command_target::vehicle },
{ "mubrakingindicatortoggle", command_target::vehicle },
{ "alerteracknowledge", command_target::vehicle },
{ "hornlowactivate", command_target::vehicle },
{ "hornhighactivate", command_target::vehicle },
{ "radiotoggle", command_target::vehicle },
/*
const int k_FailedEngineCutOff = 35;
*/
{ "viewturn", command_target::entity },
{ "movevector", command_target::entity },
{ "moveleft", command_target::entity },
{ "moveright", command_target::entity },
{ "moveforward", command_target::entity },
{ "moveback", command_target::entity },
{ "moveup", command_target::entity },
{ "movedown", command_target::entity },
{ "moveleftfast", command_target::entity },
{ "moverightfast", command_target::entity },
{ "moveforwardfast", command_target::entity },
{ "movebackfast", command_target::entity },
{ "moveupfast", command_target::entity },
{ "movedownfast", command_target::entity },
/*
const int k_CabForward = 42;
const int k_CabBackward = 43;
const int k_Couple = 44;
const int k_DeCouple = 45;
const int k_ProgramQuit = 46;
// const int k_ProgramPause= 47;
const int k_ProgramHelp = 48;
*/
{ "doortoggleleft", command_target::vehicle },
{ "doortoggleright", command_target::vehicle },
{ "departureannounce", command_target::vehicle },
{ "doorlocktoggle", command_target::vehicle },
{ "pantographcompressorvalvetoggle", command_target::vehicle },
{ "pantographcompressoractivate", command_target::vehicle },
{ "pantographtogglefront", command_target::vehicle },
{ "pantographtogglerear", command_target::vehicle },
{ "pantographlowerall", command_target::vehicle },
{ "heatingtoggle", command_target::vehicle },
/*
// const int k_FreeFlyMode= 59;
*/
{ "headlighttoggleleft", command_target::vehicle },
{ "headlighttoggleright", command_target::vehicle },
{ "headlighttoggleupper", command_target::vehicle },
{ "redmarkertoggleleft", command_target::vehicle },
{ "redmarkertoggleright", command_target::vehicle },
{ "headlighttogglerearleft", command_target::vehicle },
{ "headlighttogglerearright", command_target::vehicle },
{ "headlighttogglerearupper", command_target::vehicle },
{ "redmarkertogglerearleft", command_target::vehicle },
{ "redmarkertogglerearright", command_target::vehicle },
{ "headlightsdimtoggle", command_target::vehicle },
{ "motorconnectorsopen", command_target::vehicle },
{ "motordisconnect", command_target::vehicle },
{ "interiorlighttoggle", command_target::vehicle },
{ "interiorlightdimtoggle", command_target::vehicle },
{ "instrumentlighttoggle", command_target::vehicle },
/*
const int k_Univ1 = 66;
const int k_Univ2 = 67;
const int k_Univ3 = 68;
const int k_Univ4 = 69;
const int k_EndSign = 70;
const int k_Active = 71;
*/
{ "batterytoggle", command_target::vehicle }
/*
const int k_WalkMode = 73;
*/
};
}
// posts specified command for specified recipient
void
command_queue::push( command_data const &Command, std::size_t const Recipient ) {
auto lookup = m_commands.emplace( Recipient, commanddata_sequence() );
// recipient stack was either located or created, so we can add to it quite safely
lookup.first->second.emplace( Command );
}
// retrieves oldest posted command for specified recipient, if any. returns: true on retrieval, false if there's nothing to retrieve
bool
command_queue::pop( command_data &Command, std::size_t const Recipient ) {
auto lookup = m_commands.find( Recipient );
if( lookup == m_commands.end() ) {
// no command stack for this recipient, so no commands
return false;
}
auto &commands = lookup->second;
if( true == commands.empty() ) {
return false;
}
// we have command stack with command(s) on it, retrieve and pop the first one
Command = commands.front();
commands.pop();
return true;
}
void
command_relay::post( user_command const Command, std::uint64_t const Param1, std::uint64_t const Param2, int const Action, std::uint16_t const Recipient ) const {
auto const &command = simulation::Commands_descriptions[ static_cast<std::size_t>( Command ) ];
if( ( command.target == command_target::vehicle )
&& ( true == FreeFlyModeFlag )
&& ( ( false == DebugModeFlag )
&& ( true == Global::RealisticControlMode ) ) ) {
// in realistic control mode don't pass vehicle commands if the user isn't in one, unless we're in debug mode
return;
}
simulation::Commands.push(
command_data{
Command,
Action,
Param1,
Param2,
Timer::GetDeltaTime() },
static_cast<std::size_t>( command.target ) | Recipient );
/*
#ifdef _DEBUG
if( Action != GLFW_RELEASE ) {
// key was pressed or is still held
if( false == command.name.empty() ) {
if( false == (
( Command == user_command::moveleft )
|| ( Command == user_command::moveleftfast )
|| ( Command == user_command::moveright )
|| ( Command == user_command::moverightfast )
|| ( Command == user_command::moveforward )
|| ( Command == user_command::moveforwardfast )
|| ( Command == user_command::moveback )
|| ( Command == user_command::movebackfast )
|| ( Command == user_command::moveup )
|| ( Command == user_command::moveupfast )
|| ( Command == user_command::movedown )
|| ( Command == user_command::movedownfast )
|| ( Command == user_command::movevector )
|| ( Command == user_command::viewturn ) ) ) {
WriteLog( "Command issued: " + command.name );
}
}
}
else {
// key was released (but we don't log this)
WriteLog( "Key released: " + command.name );
}
#endif
*/
}
//---------------------------------------------------------------------------

210
command.h Normal file
View File

@@ -0,0 +1,210 @@
/*
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 <unordered_map>
#include <queue>
enum class user_command {
mastercontrollerincrease,
mastercontrollerincreasefast,
mastercontrollerdecrease,
mastercontrollerdecreasefast,
secondcontrollerincrease,
secondcontrollerincreasefast,
secondcontrollerdecrease,
secondcontrollerdecreasefast,
mucurrentindicatorothersourceactivate,
independentbrakeincrease,
independentbrakeincreasefast,
independentbrakedecrease,
independentbrakedecreasefast,
independentbrakebailoff,
trainbrakeincrease,
trainbrakedecrease,
trainbrakecharging,
trainbrakerelease,
trainbrakefirstservice,
trainbrakeservice,
trainbrakefullservice,
trainbrakeemergency,
wheelspinbrakeactivate,
sandboxactivate,
reverserincrease,
reverserdecrease,
linebreakertoggle,
convertertoggle,
converteroverloadrelayreset,
compressortoggle,
motoroverloadrelaythresholdtoggle,
motoroverloadrelayreset,
notchingrelaytoggle,
epbrakecontroltoggle,
brakeactingspeedincrease,
brakeactingspeeddecrease,
mubrakingindicatortoggle,
alerteracknowledge,
hornlowactivate,
hornhighactivate,
radiotoggle,
/*
const int k_FailedEngineCutOff = 35;
*/
viewturn,
movevector,
moveleft,
moveright,
moveforward,
moveback,
moveup,
movedown,
moveleftfast,
moverightfast,
moveforwardfast,
movebackfast,
moveupfast,
movedownfast,
/*
const int k_CabForward = 42;
const int k_CabBackward = 43;
const int k_Couple = 44;
const int k_DeCouple = 45;
const int k_ProgramQuit = 46;
// const int k_ProgramPause= 47;
const int k_ProgramHelp = 48;
*/
doortoggleleft,
doortoggleright,
departureannounce,
doorlocktoggle,
pantographcompressorvalvetoggle,
pantographcompressoractivate,
pantographtogglefront,
pantographtogglerear,
pantographlowerall,
heatingtoggle,
/*
// const int k_FreeFlyMode= 59;
*/
headlighttoggleleft,
headlighttoggleright,
headlighttoggleupper,
redmarkertoggleleft,
redmarkertoggleright,
headlighttogglerearleft,
headlighttogglerearright,
headlighttogglerearupper,
redmarkertogglerearleft,
redmarkertogglerearright,
headlightsdimtoggle,
motorconnectorsopen,
motordisconnect,
interiorlighttoggle,
interiorlightdimtoggle,
instrumentlighttoggle,
/*
const int k_Univ1 = 66;
const int k_Univ2 = 67;
const int k_Univ3 = 68;
const int k_Univ4 = 69;
const int k_EndSign = 70;
const int k_Active = 71;
*/
batterytoggle
/*
const int k_WalkMode = 73;
*/
};
enum class command_target {
userinterface,
simulation,
/*
// NOTE: there's no need for consist- and unit-specific commands at this point, but it's a possibility.
// since command targets are mutually exclusive these don't reduce ranges for individual vehicles etc
consist = 0x4000,
unit = 0x8000,
*/
// values are combined with object id. 0xffff objects of each type should be quite enough ("for everyone")
vehicle = 0x10000,
signal = 0x20000,
entity = 0x40000
};
struct command_description {
std::string name;
command_target target;
};
typedef std::vector<command_description> commanddescription_sequence;
struct command_data {
user_command command;
int action; // press, repeat or release
std::uint64_t param1;
std::uint64_t param2;
double time_delta;
};
// command_queues: collects and holds commands from input sources, for processing by their intended recipients
// NOTE: this won't scale well.
// TODO: turn it into a dispatcher and build individual command sequences into the items, where they can be examined without lookups
class command_queue {
public:
// methods
// posts specified command for specified recipient
void
push( command_data const &Command, std::size_t const Recipient );
// retrieves oldest posted command for specified recipient, if any. returns: true on retrieval, false if there's nothing to retrieve
bool
pop( command_data &Command, std::size_t const Recipient );
private:
// types
typedef std::queue<command_data> commanddata_sequence;
typedef std::unordered_map<std::size_t, commanddata_sequence> commanddatasequence_map;
// members
commanddatasequence_map m_commands;
};
// NOTE: simulation should be a (light) wrapper rather than namespace so we could potentially instance it,
// but realistically it's not like we're going to run more than one simulation at a time
namespace simulation {
extern command_queue Commands;
// TODO: add name to command map, and wrap these two into helper object
extern commanddescription_sequence Commands_descriptions;
}
// command_relay: composite class component, passes specified command to appropriate command stack
class command_relay {
public:
// constructors
// methods
// posts specified command for the specified recipient
// TODO: replace uint16_t with recipient handle, based on item id
void
post( user_command const Command, std::uint64_t const Param1, std::uint64_t const Param2, int const Action, std::uint16_t const Recipient ) const;
private:
// types
// members
};
//---------------------------------------------------------------------------

353
gamepadinput.cpp Normal file
View File

@@ -0,0 +1,353 @@
/*
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 "gamepadinput.h"
#include "logs.h"
#include "timer.h"
#include "usefull.h"
glm::vec2 circle_to_square( glm::vec2 const &Point, int const Roundness = 0 ) {
// Determine the theta angle
auto angle = std::atan2( Point.x, Point.y ) + M_PI;
glm::vec2 squared;
// Scale according to which wall we're clamping to
// X+ wall
if( angle <= M_PI_4 || angle > 7 * M_PI_4 )
squared = Point * (float)( 1.0 / std::cos( angle ) );
// Y+ wall
else if( angle > M_PI_4 && angle <= 3 * M_PI_4 )
squared = Point * (float)( 1.0 / std::sin( angle ) );
// X- wall
else if( angle > 3 * M_PI_4 && angle <= 5 * M_PI_4 )
squared = Point * (float)( -1.0 / std::cos( angle ) );
// Y- wall
else if( angle > 5 * M_PI_4 && angle <= 7 * M_PI_4 )
squared = Point * (float)( -1.0 / std::sin( angle ) );
// Early-out for a perfect square output
if( Roundness == 0 )
return squared;
// Find the inner-roundness scaling factor and LERP
auto const length = glm::length( Point );
auto const factor = std::pow( length, Roundness );
return interpolate( Point, squared, factor );
}
gamepad_input::gamepad_input() {
m_modecommands = {
{ user_command::mastercontrollerincrease, user_command::mastercontrollerdecrease },
{ user_command::trainbrakedecrease, user_command::trainbrakeincrease },
{ user_command::secondcontrollerincrease, user_command::secondcontrollerdecrease },
{ user_command::independentbrakedecrease, user_command::independentbrakeincrease }
};
}
bool
gamepad_input::init() {
// NOTE: we're only checking for joystick_1 and rely for it to stay connected throughout.
// not exactly flexible, but for quick hack it'll do
auto const name = glfwGetJoystickName( GLFW_JOYSTICK_1 );
if( name != nullptr ) {
WriteLog( "Connected gamepad: " + std::string( name ) );
m_deviceid = GLFW_JOYSTICK_1;
}
else {
// no joystick,
WriteLog( "No gamepad detected" );
m_axes.clear();
m_buttons.clear();
return false;
}
int count;
glfwGetJoystickAxes( m_deviceid, &count );
m_axes.resize( count );
glfwGetJoystickButtons( m_deviceid, &count );
m_buttons.resize( count );
return true;
}
// checks state of the controls and sends issued commands
void
gamepad_input::poll() {
if( m_deviceid == -1 ) {
// if there's no gamepad we can skip the rest
return;
}
int count; std::size_t idx = 0;
// poll button state
auto const buttons = glfwGetJoystickButtons( m_deviceid, &count );
if( count ) { // safety check in case joystick gets pulled out
for( auto &button : m_buttons ) {
if( button != buttons[ idx ] ) {
// button pressed or released, both are important
on_button(
static_cast<gamepad_button>( idx ),
( buttons[ idx ] == 1 ?
GLFW_PRESS :
GLFW_RELEASE ) );
}
else {
// otherwise we only pass info about button being held down
if( button == 1 ) {
on_button(
static_cast<gamepad_button>( idx ),
GLFW_REPEAT );
}
}
button = buttons[ idx ];
++idx;
}
}
// poll axes state
idx = 0;
glm::vec2 leftstick, rightstick, triggers;
auto const axes = glfwGetJoystickAxes( m_deviceid, &count );
if( count ) {
// safety check in case joystick gets pulled out
if( count >= 2 ) {
leftstick = glm::vec2(
( std::abs( axes[ gamepad_axes::leftstick_x ] ) > m_deadzone ?
axes[ gamepad_axes::leftstick_x ] :
0.0f ),
( std::abs( axes[ gamepad_axes::leftstick_y ] ) > m_deadzone ?
axes[ gamepad_axes::leftstick_y ] :
0.0f ) );
}
if( count >= 4 ) {
rightstick = glm::vec2(
( std::abs( axes[ gamepad_axes::rightstick_x ] ) > m_deadzone ?
axes[ gamepad_axes::rightstick_x ] :
0.0f ),
( std::abs( axes[ gamepad_axes::rightstick_y ] ) > m_deadzone ?
axes[ gamepad_axes::rightstick_y ] :
0.0f ) );
}
if( count >= 6 ) {
triggers = glm::vec2(
( axes[ gamepad_axes::lefttrigger ] > m_deadzone ?
axes[ gamepad_axes::lefttrigger ] :
0.0f ),
( axes[ gamepad_axes::righttrigger ] > m_deadzone ?
axes[ gamepad_axes::righttrigger ] :
0.0f ) );
}
}
process_axes( leftstick, rightstick, triggers );
}
void
gamepad_input::on_button( gamepad_button const Button, int const Action ) {
switch( Button ) {
// NOTE: this is rigid coupling, down the road we should support more flexible binding of functions with buttons
case gamepad_button::a:
case gamepad_button::b:
case gamepad_button::x:
case gamepad_button::y: {
if( Action == GLFW_RELEASE ) {
// TODO: send GLFW_RELEASE for whatever command could be issued by the mode active until now
// if the button was released the stick switches to control the movement
m_mode = control_mode::entity;
// zero the stick and the accumulator so the input won't bleed between modes
m_leftstick = glm::vec2();
m_modeaccumulator = 0.0f;
}
else {
// otherwise set control mode to match pressed button
m_mode = static_cast<control_mode>( Button );
}
break;
}
default: {
break;
}
}
}
void
gamepad_input::process_axes( glm::vec2 Leftstick, glm::vec2 const &Rightstick, glm::vec2 const &Triggers ) {
// right stick, look around
if( ( Rightstick.x != 0.0f ) || ( Rightstick.y != 0.0f ) ) {
// TODO: make toggles for the axis flip
auto const deltatime = Timer::GetDeltaRenderTime() * 60.0;
double const turnx = Rightstick.x * 10.0 * deltatime;
double const turny = -Rightstick.y * 10.0 * deltatime;
m_relay.post(
user_command::viewturn,
reinterpret_cast<std::uint64_t const &>( turnx ),
reinterpret_cast<std::uint64_t const &>( turny ),
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 );
}
// left stick, either movement or controls, depending on currently active mode
if( m_mode == control_mode::entity ) {
if( ( Leftstick.x != 0.0 || Leftstick.y != 0.0 )
|| ( m_leftstick.x != 0.0 || m_leftstick.y != 0.0 ) ) {
double const movex = static_cast<double>( Leftstick.x );
double const movez = static_cast<double>( Leftstick.y );
m_relay.post(
user_command::movevector,
reinterpret_cast<std::uint64_t const &>( movex ),
reinterpret_cast<std::uint64_t const &>( movez ),
GLFW_PRESS,
0 );
}
}
else {
// vehicle control modes
process_mode( Leftstick.y, 0 );
}
m_rightstick = Rightstick;
m_leftstick = Leftstick;
m_triggers = Triggers;
}
void
gamepad_input::process_axis( float const Value, float const Previousvalue, float const Multiplier, user_command Command, std::uint16_t const Recipient ) {
process_axis( Value, Previousvalue, Multiplier, Command, Command, Recipient );
}
void
gamepad_input::process_axis( float const Value, float const Previousvalue, float const Multiplier, user_command Command1, user_command Command2, std::uint16_t const Recipient ) {
user_command command{ Command1 };
if( Value * Multiplier > 0.9 ) {
command = Command2;
}
if( Value * Multiplier > 0.0f ) {
m_relay.post(
command,
0, 0,
GLFW_PRESS,
Recipient
);
}
else {
// if we had movement before but not now, report this as 'button' release
if( Previousvalue != 0.0f ) {
m_relay.post(
command, // doesn't matter which movement 'mode' we report
0, 0,
GLFW_RELEASE,
0
);
}
}
}
void
gamepad_input::process_mode( float const Value, std::uint16_t const Recipient ) {
// TODO: separate multiplier for each mode, to allow different, customizable sensitivity for each control
auto const deltatime = Timer::GetDeltaTime() * 15.0;
auto const &lookup = m_modecommands.at( static_cast<size_t>( m_mode ) );
if( Value >= 0.0f ) {
if( m_modeaccumulator < 0.0f ) {
// reset accumulator if we're going in the other direction i.e. issuing opposite control
// this also means we should indicate the previous command no longer applies
// (normally it's handled when the stick enters dead zone, but it's possible there's no actual dead zone)
m_relay.post(
lookup.second,
0, 0,
GLFW_RELEASE,
Recipient );
m_modeaccumulator = 0.0f;
}
if( Value > m_deadzone ) {
m_modeaccumulator += ( Value - m_deadzone ) / ( 1.0 - m_deadzone ) * deltatime;
// we're making sure there's always a positive charge left in the accumulator,
// to more reliably decect when the stick goes from active to dead zone, below
while( m_modeaccumulator > 1.0f ) {
// send commands if the accumulator(s) was filled
m_relay.post(
lookup.first,
0, 0,
GLFW_PRESS,
Recipient );
m_modeaccumulator -= 1.0f;
}
}
else {
// if the accumulator isn't empty it's an indicator the stick moved from active to neutral zone
// indicate it with proper RELEASE command
m_relay.post(
lookup.first,
0, 0,
GLFW_RELEASE,
Recipient );
m_modeaccumulator = 0.0f;
}
}
else {
if( m_modeaccumulator > 0.0f ) {
// reset accumulator if we're going in the other direction i.e. issuing opposite control
// this also means we should indicate the previous command no longer applies
// (normally it's handled when the stick enters dead zone, but it's possible there's no actual dead zone)
m_relay.post(
lookup.first,
0, 0,
GLFW_RELEASE,
Recipient );
m_modeaccumulator = 0.0f;
}
if( Value < m_deadzone ) {
m_modeaccumulator += ( Value + m_deadzone ) / ( 1.0 - m_deadzone ) * deltatime;
// we're making sure there's always a negative charge left in the accumulator,
// to more reliably decect when the stick goes from active to dead zone, below
while( m_modeaccumulator < -1.0f ) {
// send commands if the accumulator(s) was filled
m_relay.post(
lookup.second,
0, 0,
GLFW_PRESS,
Recipient );
m_modeaccumulator += 1.0f;
}
}
else {
// if the accumulator isn't empty it's an indicator the stick moved from active to neutral zone
// indicate it with proper RELEASE command
m_relay.post(
lookup.second,
0, 0,
GLFW_RELEASE,
Recipient );
m_modeaccumulator = 0.0f;
}
}
}
//---------------------------------------------------------------------------

86
gamepadinput.h Normal file
View File

@@ -0,0 +1,86 @@
/*
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 <vector>
#include "command.h"
class gamepad_input {
public:
// constructors
gamepad_input();
// methods
// checks state of the controls and sends issued commands
bool
init();
void
poll();
private:
// types
enum gamepad_button {
a,
b,
x,
y,
left_shoulder,
right_shoulder,
back,
start,
left_sticker,
right_sticker,
dpad_up,
dpad_right,
dpad_down,
dpad_left
};
enum gamepad_axes {
leftstick_x,
leftstick_y,
rightstick_x,
rightstick_y,
lefttrigger,
righttrigger
};
enum class control_mode {
entity = -1,
vehicle_mastercontroller,
vehicle_trainbrake,
vehicle_secondarycontroller,
vehicle_independentbrake
};
typedef std::vector<float> float_sequence;
typedef std::vector<char> char_sequence;
typedef std::vector< std::pair< user_command, user_command > > commandpair_sequence;
// methods
void on_button( gamepad_button const Button, int const Action );
void process_axes( glm::vec2 Leftstick, glm::vec2 const &Rightstick, glm::vec2 const &Triggers );
void process_axis( float const Value, float const Previousvalue, float const Multiplier, user_command Command, std::uint16_t const Recipient );
void process_axis( float const Value, float const Previousvalue, float const Multiplier, user_command Command1, user_command Command2, /*user_command Command3,*/ std::uint16_t const Recipient );
void process_mode( float const Value, std::uint16_t const Recipient );
// members
command_relay m_relay;
float_sequence m_axes;
char_sequence m_buttons;
int m_deviceid{ -1 };
control_mode m_mode{ control_mode::entity };
commandpair_sequence m_modecommands; // sets of commands issued depending on the active control mode
float m_deadzone{ 0.15f }; // TODO: allow to configure this
glm::vec2 m_leftstick;
glm::vec2 m_rightstick;
glm::vec2 m_triggers;
double m_modeaccumulator; // used to throttle command input rate for vehicle controls
};
//---------------------------------------------------------------------------

496
keyboardinput.cpp Normal file
View File

@@ -0,0 +1,496 @@
/*
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 "keyboardinput.h"
#include "logs.h"
#include "parser.h"
bool
keyboard_input::recall_bindings() {
// build helper translation tables
std::unordered_map<std::string, user_command> nametocommandmap;
std::size_t commandid = 0;
for( auto const &description : simulation::Commands_descriptions ) {
nametocommandmap.emplace(
description.name,
static_cast<user_command>( commandid ) );
++commandid;
}
std::unordered_map<std::string, int> nametokeymap = {
{ "a", GLFW_KEY_A }, { "b", GLFW_KEY_B }, { "c", GLFW_KEY_C }, { "d", GLFW_KEY_D }, { "e", GLFW_KEY_E },
{ "f", GLFW_KEY_F }, { "g", GLFW_KEY_G }, { "h", GLFW_KEY_H }, { "i", GLFW_KEY_I }, { "j", GLFW_KEY_J },
{ "k", GLFW_KEY_K }, { "l", GLFW_KEY_L }, { "m", GLFW_KEY_M }, { "n", GLFW_KEY_N }, { "o", GLFW_KEY_O },
{ "p", GLFW_KEY_P }, { "q", GLFW_KEY_Q }, { "r", GLFW_KEY_R }, { "s", GLFW_KEY_S }, { "t", GLFW_KEY_T },
{ "u", GLFW_KEY_U }, { "v", GLFW_KEY_V }, { "w", GLFW_KEY_W }, { "x", GLFW_KEY_X }, { "y", GLFW_KEY_Y }, { "z", GLFW_KEY_Z },
{ "-", GLFW_KEY_MINUS }, { "=", GLFW_KEY_EQUAL }, { "backspace", GLFW_KEY_BACKSPACE },
{ "[", GLFW_KEY_LEFT_BRACKET }, { "]", GLFW_KEY_RIGHT_BRACKET }, { "\\", GLFW_KEY_BACKSLASH },
{ ";", GLFW_KEY_SEMICOLON }, { "'", GLFW_KEY_APOSTROPHE }, { "enter", GLFW_KEY_ENTER },
{ ",", GLFW_KEY_COMMA }, { ".", GLFW_KEY_PERIOD }, { "/", GLFW_KEY_SLASH },
{ "space", GLFW_KEY_SPACE },
// numpad block
{ "num_/", GLFW_KEY_KP_DIVIDE }, { "num_*", GLFW_KEY_KP_MULTIPLY }, { "num_-", GLFW_KEY_KP_SUBTRACT },
{ "num_7", GLFW_KEY_KP_7 }, { "num_8", GLFW_KEY_KP_8 }, { "num_9", GLFW_KEY_KP_9 }, { "num_+", GLFW_KEY_KP_ADD },
{ "num_4", GLFW_KEY_KP_4 }, { "num_5", GLFW_KEY_KP_5 }, { "num_6", GLFW_KEY_KP_6 },
{ "num_1", GLFW_KEY_KP_1 }, { "num_2", GLFW_KEY_KP_2 }, { "num_3", GLFW_KEY_KP_3 }, { "num_enter", GLFW_KEY_KP_ENTER },
{ "num_0", GLFW_KEY_KP_0 }, { "num_.", GLFW_KEY_KP_DECIMAL }
};
cParser bindingparser( "eu07_input-keyboard.ini", cParser::buffer_FILE );
if( false == bindingparser.ok() ) {
return false;
}
while( true == bindingparser.getTokens( 1, true, "\n" ) ) {
std::string bindingentry;
bindingparser >> bindingentry;
cParser entryparser( bindingentry );
if( true == entryparser.getTokens( 1, true, "\n\r\t " ) ) {
std::string commandname;
entryparser >> commandname;
auto const lookup = nametocommandmap.find( commandname );
if( lookup == nametocommandmap.end() ) {
WriteLog( "Keyboard binding defined for unknown command, \"" + commandname + "\"" );
}
else {
int binding{ 0 };
while( entryparser.getTokens( 1, true, "\n\r\t " ) ) {
std::string bindingkeyname;
entryparser >> bindingkeyname;
if( bindingkeyname == "shift" ) { binding |= keymodifier::shift; }
else if( bindingkeyname == "ctrl" ) { binding |= keymodifier::control; }
else {
// regular key, convert it to glfw key code
auto const keylookup = nametokeymap.find( bindingkeyname );
if( keylookup == nametokeymap.end() ) {
WriteLog( "Keyboard binding included unrecognized key, \"" + bindingkeyname + "\"" );
}
else {
// replace any existing binding, preserve modifiers
// (protection from cases where there's more than one key listed in the entry)
binding = keylookup->second | ( binding & 0xffff0000 );
}
}
if( ( binding & 0xffff ) != 0 ) {
m_commands.at( static_cast<std::size_t>( lookup->second ) ).binding = binding;
}
}
}
}
}
bind();
return true;
}
bool
keyboard_input::key( int const Key, int const Action ) {
bool modifier( false );
if( ( Key == GLFW_KEY_LEFT_SHIFT ) || ( Key == GLFW_KEY_RIGHT_SHIFT ) ) {
// update internal state, but don't bother passing these
m_shift =
( Action == GLFW_RELEASE ?
false :
true );
modifier = true;
// whenever shift key is used it may affect currently pressed movement keys, so check and update these
}
if( ( Key == GLFW_KEY_LEFT_CONTROL ) || ( Key == GLFW_KEY_RIGHT_CONTROL ) ) {
// update internal state, but don't bother passing these
m_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;
}
if( true == update_movement( Key, Action ) ) {
// if the received key was one of movement keys, it's been handled and we don't need to bother further
return true;
}
// store key state
if( Key != -1 ) {
m_keys[ Key ] = 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 ) );
auto const lookup = m_bindings.find( key );
if( lookup == m_bindings.end() ) {
// no binding for this key
return false;
}
// NOTE: basic keyboard controls don't have any parameters
// as we haven't yet implemented either item id system or multiplayer, the 'local' controlled vehicle and entity have temporary ids of 0
// TODO: pass correct entity id once the missing systems are in place
m_relay.post( lookup->second, 0, 0, Action, 0 );
return true;
}
void
keyboard_input::mouse( double Mousex, double Mousey ) {
m_relay.post(
user_command::viewturn,
reinterpret_cast<std::uint64_t const &>( Mousex ),
reinterpret_cast<std::uint64_t const &>( Mousey ),
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 );
}
void
keyboard_input::default_bindings() {
m_commands = {
// mastercontrollerincrease
{ GLFW_KEY_KP_ADD },
// mastercontrollerincreasefast
{ GLFW_KEY_KP_ADD | keymodifier::shift },
// mastercontrollerdecrease
{ GLFW_KEY_KP_SUBTRACT },
// mastercontrollerdecreasefast
{ GLFW_KEY_KP_SUBTRACT | keymodifier::shift },
// secondcontrollerincrease
{ GLFW_KEY_KP_DIVIDE },
// secondcontrollerincreasefast
{ GLFW_KEY_KP_DIVIDE | keymodifier::shift },
// secondcontrollerdecrease
{ GLFW_KEY_KP_MULTIPLY },
// secondcontrollerdecreasefast
{ GLFW_KEY_KP_MULTIPLY | keymodifier::shift },
// 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 },
// independentbrakebailoff
{ GLFW_KEY_KP_4 },
// trainbrakeincrease
{ GLFW_KEY_KP_3 },
// trainbrakedecrease
{ GLFW_KEY_KP_9 },
// 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 },
// trainbrakeemergency
{ GLFW_KEY_KP_0 },
// wheelspinbrakeactivate,
{ GLFW_KEY_KP_ENTER },
// sandboxactivate,
{ GLFW_KEY_S },
// reverserincrease
{ GLFW_KEY_D },
// reverserdecrease
{ GLFW_KEY_R },
// linebreakertoggle
{ GLFW_KEY_M },
// convertertoggle
{ GLFW_KEY_X },
// converteroverloadrelayreset
{ GLFW_KEY_N | keymodifier::control },
// compressortoggle
{ GLFW_KEY_C },
// motoroverloadrelaythresholdtoggle
{ GLFW_KEY_F },
// motoroverloadrelayreset
{ GLFW_KEY_N },
// notchingrelaytoggle
{ GLFW_KEY_G },
// epbrakecontroltoggle
{ GLFW_KEY_Z | keymodifier::control },
// brakeactingspeedincrease
{ GLFW_KEY_B | keymodifier::shift },
// brakeactingspeeddecrease
{ GLFW_KEY_B },
// mubrakingindicatortoggle
{ GLFW_KEY_L | keymodifier::shift },
// alerteracknowledge
{ GLFW_KEY_SPACE },
// hornlowactivate
{ GLFW_KEY_A },
// hornhighactivate
{ GLFW_KEY_A | keymodifier::shift },
// radiotoggle
{ GLFW_KEY_R | keymodifier::control },
// viewturn
{ -1 },
// movevector
{ -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 },
// moveleftfast
{ -1 },
// moverightfast
{ -1 },
// moveforwardfast
{ -1 },
// movebackfast
{ -1 },
// moveupfast
{ -1 },
// movedownfast
{ -1 },
/*
const int k_CabForward = 42;
const int k_CabBackward = 43;
const int k_Couple = 44;
const int k_DeCouple = 45;
const int k_ProgramQuit = 46;
// const int k_ProgramPause= 47;
const int k_ProgramHelp = 48;
*/
// 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 },
// pantographlowerall
{ GLFW_KEY_P | keymodifier::control },
// heatingtoggle
{ GLFW_KEY_H },
/*
// const int k_FreeFlyMode= 59;
*/
// headlighttoggleleft
{ GLFW_KEY_Y },
// headlighttoggleright
{ GLFW_KEY_I },
// headlighttoggleupper
{ GLFW_KEY_U },
// redmarkertoggleleft
{ GLFW_KEY_Y | keymodifier::shift },
// redmarkertoggleright
{ GLFW_KEY_I | keymodifier::shift },
// 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 },
// headlightsdimtoggle
{ GLFW_KEY_L | keymodifier::control },
// motorconnectorsopen
{ GLFW_KEY_L },
// motordisconnect
{ GLFW_KEY_E | keymodifier::shift },
// interiorlighttoggle
{ GLFW_KEY_APOSTROPHE },
// interiorlightdimtoggle
{ GLFW_KEY_APOSTROPHE | keymodifier::control },
// instrumentlighttoggle
{ GLFW_KEY_SEMICOLON },
/*
const int k_Univ1 = 66;
const int k_Univ2 = 67;
const int k_Univ3 = 68;
const int k_Univ4 = 69;
const int k_EndSign = 70;
const int k_Active = 71;
*/
// "batterytoggle"
{ GLFW_KEY_J }
/*
const int k_WalkMode = 73;
*/
};
bind();
}
void
keyboard_input::bind() {
m_bindings.clear();
int commandcode{ 0 };
for( auto const &command : m_commands ) {
if( command.binding != -1 ) {
m_bindings.emplace(
command.binding,
static_cast<user_command>( commandcode ) );
}
++commandcode;
}
// cache movement key bindings, so we can test them faster in the input loop
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;
}
// NOTE: ugliest code ever, gg
bool
keyboard_input::update_movement( int const Key, int const Action ) {
bool shift =
( ( Key == GLFW_KEY_LEFT_SHIFT )
|| ( Key == GLFW_KEY_RIGHT_SHIFT ) );
bool movementkey =
( ( Key == m_bindingscache.forward )
|| ( Key == m_bindingscache.back )
|| ( Key == m_bindingscache.left )
|| ( Key == m_bindingscache.right )
|| ( Key == m_bindingscache.up )
|| ( Key == m_bindingscache.down ) );
if( false == ( shift || movementkey ) ) { return false; }
if( false == shift ) {
// TODO: pass correct entity id once the missing systems are in place
if( Key == m_bindingscache.forward ) {
m_keys[ Key ] = Action;
m_relay.post(
( m_shift ?
user_command::moveforwardfast :
user_command::moveforward ),
0, 0,
m_keys[ m_bindingscache.forward ],
0 );
return true;
}
else if( Key == m_bindingscache.back ) {
m_keys[ Key ] = Action;
m_relay.post(
( m_shift ?
user_command::movebackfast :
user_command::moveback ),
0, 0,
m_keys[ m_bindingscache.back ],
0 );
return true;
}
else if( Key == m_bindingscache.left ) {
m_keys[ Key ] = Action;
m_relay.post(
( m_shift ?
user_command::moveleftfast :
user_command::moveleft ),
0, 0,
m_keys[ m_bindingscache.left ],
0 );
return true;
}
else if( Key == m_bindingscache.right ) {
m_keys[ Key ] = Action;
m_relay.post(
( m_shift ?
user_command::moverightfast :
user_command::moveright ),
0, 0,
m_keys[ m_bindingscache.right ],
0 );
return true;
}
else if( Key == m_bindingscache.up ) {
m_keys[ Key ] = Action;
m_relay.post(
( m_shift ?
user_command::moveupfast :
user_command::moveup ),
0, 0,
m_keys[ m_bindingscache.up ],
0 );
return true;
}
else if( Key == m_bindingscache.down ) {
m_keys[ Key ] = Action;
m_relay.post(
( m_shift ?
user_command::movedownfast :
user_command::movedown ),
0, 0,
m_keys[ m_bindingscache.down ],
0 );
return true;
}
}
else {
// if it's not the movement keys but one of shift keys, we might potentially need to update movement state
if( m_keys[ Key ] == Action ) {
// but not if it's just repeat
return false;
}
// bit of recursion voodoo here, we fake relevant key presses so we don't have to duplicate the code from above
if( m_keys[ m_bindingscache.forward ] != GLFW_RELEASE ) { update_movement( m_bindingscache.forward, m_keys[ m_bindingscache.forward ] ); }
if( m_keys[ m_bindingscache.back ] != GLFW_RELEASE ) { update_movement( m_bindingscache.back, m_keys[ m_bindingscache.back ] ); }
if( m_keys[ m_bindingscache.left ] != GLFW_RELEASE ) { update_movement( m_bindingscache.left, m_keys[ m_bindingscache.left ] ); }
if( m_keys[ m_bindingscache.right ] != GLFW_RELEASE ) { update_movement( m_bindingscache.right, m_keys[ m_bindingscache.right ] ); }
if( m_keys[ m_bindingscache.up ] != GLFW_RELEASE ) { update_movement( m_bindingscache.up, m_keys[ m_bindingscache.up ] ); }
if( m_keys[ m_bindingscache.down ] != GLFW_RELEASE ) { update_movement( m_bindingscache.down, m_keys[ m_bindingscache.down ] ); }
}
return false;
}
//---------------------------------------------------------------------------

76
keyboardinput.h Normal file
View File

@@ -0,0 +1,76 @@
/*
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 <unordered_map>
#include <array>
#include "command.h"
class keyboard_input {
public:
// constructors
keyboard_input() { default_bindings(); }
// methods
bool
init() { return recall_bindings(); }
bool
recall_bindings();
bool
key( int const Key, int const Action );
void
mouse( double const Mousex, double const Mousey );
private:
// types
enum keymodifier : int {
shift = 0x10000,
control = 0x20000
};
struct command_setup {
int binding;
};
typedef std::vector<command_setup> commandsetup_sequence;
typedef std::unordered_map<int, user_command> usercommand_map;
struct bindings_cache {
int forward{ -1 };
int back{ -1 };
int left{ -1 };
int right{ -1 };
int up{ -1 };
int down{ -1 };
};
// methods
void
default_bindings();
void
bind();
bool
update_movement( int const Key, int const Action );
// members
commandsetup_sequence m_commands;
usercommand_map m_bindings;
command_relay m_relay;
bool m_shift{ false };
bool m_ctrl{ false };
bindings_cache m_bindingscache;
std::array<char, GLFW_KEY_LAST> m_keys;
};
//---------------------------------------------------------------------------

View File

@@ -57,8 +57,8 @@ light_array::update() {
light.direction.z = -light.direction.z;
}
// determine intensity of this light set
if( true == light.owner->MoverParameters->Battery ) {
// with battery on, the intensity depends on the state of activated switches
if( ( true == light.owner->MoverParameters->Battery ) || ( true == light.owner->MoverParameters->ConverterFlag ) ) {
// with power on, the intensity depends on the state of activated switches
auto const &lightbits = light.owner->iLights[ light.index ];
light.count = 0 +
( ( lightbits & 1 ) ? 1 : 0 ) +

View File

@@ -16,15 +16,15 @@
<Filter Include="Source Files\mczapkie">
<UniqueIdentifier>{fafd38ab-4c2a-48c8-8e66-ad0d928573b3}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\console">
<UniqueIdentifier>{2d73d7b2-5252-499c-963a-88fa3cb1af53}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\mczapkie">
<UniqueIdentifier>{36684428-8a48-435f-bca4-a24d9bfe2587}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\console">
<Filter Include="Header Files\input">
<UniqueIdentifier>{cdf75bec-91f7-413c-8b57-9e32cba49148}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\input">
<UniqueIdentifier>{2d73d7b2-5252-499c-963a-88fa3cb1af53}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="AdvSound.cpp">
@@ -157,7 +157,7 @@
<Filter>Source Files\mczapkie</Filter>
</ClCompile>
<ClCompile Include="console\LPT.cpp">
<Filter>Source Files\console</Filter>
<Filter>Source Files\input</Filter>
</ClCompile>
<ClCompile Include="mczapkie\mctools.cpp">
<Filter>Source Files\mczapkie</Filter>
@@ -169,13 +169,13 @@
<Filter>Source Files\mczapkie</Filter>
</ClCompile>
<ClCompile Include="console\PoKeys55.cpp">
<Filter>Source Files\console</Filter>
<Filter>Source Files\input</Filter>
</ClCompile>
<ClCompile Include="stdafx.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Console\MWD.cpp">
<Filter>Source Files\console</Filter>
<Filter>Source Files\input</Filter>
</ClCompile>
<ClCompile Include="Names.cpp">
<Filter>Source Files</Filter>
@@ -210,6 +210,18 @@
<ClCompile Include="openglmatrixstack.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<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>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Globals.h">
@@ -288,10 +300,10 @@
<Filter>Header Files\mczapkie</Filter>
</ClInclude>
<ClInclude Include="Console\PoKeys55.h">
<Filter>Header Files\console</Filter>
<Filter>Header Files\input</Filter>
</ClInclude>
<ClInclude Include="Console\LPT.h">
<Filter>Header Files\console</Filter>
<Filter>Header Files\input</Filter>
</ClInclude>
<ClInclude Include="RealSound.h">
<Filter>Header Files</Filter>
@@ -372,7 +384,7 @@
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Console\MWD.h">
<Filter>Header Files\console</Filter>
<Filter>Header Files\input</Filter>
</ClInclude>
<ClInclude Include="sun.h">
<Filter>Header Files</Filter>
@@ -407,6 +419,18 @@
<ClInclude Include="openglmatrixstack.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="moon.h">
<Filter>Header Files</Filter>
</ClInclude>
<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>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="maszyna.rc">

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LocalDebuggerWorkingDirectory>..\..\Projects\maszyna</LocalDebuggerWorkingDirectory>
<LocalDebuggerWorkingDirectory>..\..\..\development\maszyna</LocalDebuggerWorkingDirectory>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
@@ -9,11 +9,11 @@
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LocalDebuggerWorkingDirectory>..\..\Projects\maszyna</LocalDebuggerWorkingDirectory>
<LocalDebuggerWorkingDirectory>..\..\..\development\maszyna</LocalDebuggerWorkingDirectory>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LocalDebuggerWorkingDirectory>..\..\Projects\maszyna</LocalDebuggerWorkingDirectory>
<LocalDebuggerWorkingDirectory>..\..\..\development\maszyna</LocalDebuggerWorkingDirectory>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
<LocalDebuggerEnvironment>_NO_DEBUG_HEAP=1</LocalDebuggerEnvironment>
</PropertyGroup>
@@ -23,7 +23,7 @@
<LocalDebuggerEnvironment>_NO_DEBUG_HEAP=1</LocalDebuggerEnvironment>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LocalDebuggerWorkingDirectory>..\..\Projects\maszyna</LocalDebuggerWorkingDirectory>
<LocalDebuggerWorkingDirectory>..\..\..\development\maszyna</LocalDebuggerWorkingDirectory>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
<LocalDebuggerEnvironment>_NO_DEBUG_HEAP=1</LocalDebuggerEnvironment>
</PropertyGroup>

325
moon.cpp Normal file
View File

@@ -0,0 +1,325 @@
#include "stdafx.h"
#include "moon.h"
#include "globals.h"
#include "mtable.h"
#include "usefull.h"
#include "world.h"
//////////////////////////////////////////////////////////////////////////////////////////
// cSun -- class responsible for dynamic calculation of position and intensity of the Sun,
cMoon::cMoon() {
setLocation( 19.00f, 52.00f ); // default location roughly in centre of Poland
m_observer.press = 1013.0; // surface pressure, millibars
m_observer.temp = 15.0; // ambient dry-bulb temperature, degrees C
TIME_ZONE_INFORMATION timezoneinfo; // TODO: timezone dependant on geographic location
::GetTimeZoneInformation( &timezoneinfo );
m_observer.timezone = -timezoneinfo.Bias / 60.0f;
}
cMoon::~cMoon() { gluDeleteQuadric( moonsphere ); }
void
cMoon::init() {
moonsphere = gluNewQuadric();
gluQuadricNormals( moonsphere, GLU_SMOOTH );
// NOTE: we're calculating phase just once, because it's unlikely simulation will last a few days,
// plus a sudden texture change would be pretty jarring
phase();
}
void
cMoon::update() {
move();
Math3D::vector3 position( 0.0f, 0.0f, -2000.0f * Global::fDistanceFactor );
position.RotateX( (float)( m_body.elevref * ( M_PI / 180.0 ) ) );
position.RotateY( (float)( -m_body.hrang * ( M_PI / 180.0 ) ) );
m_position = position;
}
void
cMoon::render() {
glColor4f( 225.0f/255.0f, 225.0f/255.0f, 255.0f/255.0f, 1.f );
// debug line to locate the sun easier
Math3D::vector3 position = m_position;
glBegin( GL_LINES );
glVertex3f( position.x, position.y, position.z );
glVertex3f( position.x, 0.0f, position.z );
glEnd();
glPushMatrix();
glTranslatef( position.x, position.y, position.z );
gluSphere( moonsphere, /* (float)( Global::ScreenHeight / Global::FieldOfView ) * 0.5 * */ ( m_body.distance / 60.2666 ) * 9.037461, 12, 12 );
glPopMatrix();
}
Math3D::vector3
cMoon::getDirection() {
Math3D::vector3 position( 0.f, 0.f, -1.f );
position.RotateX( (float)( m_body.elevref * (M_PI/180.0)) );
position.RotateY( (float)( -m_body.hrang * (M_PI/180.0)) );
position.Normalize();
return position;
}
float
cMoon::getAngle() const {
return (float)m_body.elevref;
}
float cMoon::getIntensity() {
irradiance();
// NOTE: we don't have irradiance model for the moon so we cheat here
// calculating intensity of the sun instead, and returning 15% of the value,
// which roughly matches how much sunlight is reflected by the moon
// We alter the intensity further based on current phase of the moon
auto const phasefactor = 1.0f - std::abs( m_phase - 29.53f * 0.5f ) / ( 29.53 * 0.5f );
return (float)( m_body.etr/ 1399.0 ) * phasefactor * 0.15f; // arbitrary scaling factor taken from etrn value
}
void cMoon::setLocation( float const Longitude, float const Latitude ) {
// convert fraction from geographical base of 6o minutes
m_observer.longitude = (int)Longitude + (Longitude - (int)(Longitude)) * 100.0 / 60.0;
m_observer.latitude = (int)Latitude + (Latitude - (int)(Latitude)) * 100.0 / 60.0 ;
}
// sets current time, overriding one acquired from the system clock
void cMoon::setTime( int const Hour, int const Minute, int const Second ) {
m_observer.hour = clamp( Hour, -1, 23 );
m_observer.minute = clamp( Minute, -1, 59 );
m_observer.second = clamp( Second, -1, 59 );
}
void cMoon::setTemperature( float const Temperature ) {
m_observer.temp = Temperature;
}
void cMoon::setPressure( float const Pressure ) {
m_observer.press = Pressure;
}
void cMoon::move() {
static double radtodeg = 57.295779513; // converts from radians to degrees
static double degtorad = 0.0174532925; // converts from degrees to radians
SYSTEMTIME localtime = simulation::Time.data(); // time for the calculation
if( m_observer.hour >= 0 ) { localtime.wHour = m_observer.hour; }
if( m_observer.minute >= 0 ) { localtime.wMinute = m_observer.minute; }
if( m_observer.second >= 0 ) { localtime.wSecond = m_observer.second; }
double ut = localtime.wHour
+ localtime.wMinute / 60.0 // too low resolution, noticeable skips
+ localtime.wSecond / 3600.0; // good enough in normal circumstances
/*
+ localtime.wMilliseconds / 3600000.0; // for really smooth movement
*/
double daynumber = 367 * localtime.wYear
- 7 * ( localtime.wYear + ( localtime.wMonth + 9 ) / 12 ) / 4
+ 275 * localtime.wMonth / 9
+ localtime.wDay
- 730530
+ ( ut / 24.0 );
// Universal Coordinated (Greenwich standard) time
m_observer.utime = ut * 3600.0;
m_observer.utime = m_observer.utime / 3600.0 - m_observer.timezone;
// obliquity of the ecliptic
m_body.oblecl = clamp_circular( 23.4393 - 3.563e-7 * daynumber );
// moon parameters
double longascnode = clamp_circular( 125.1228 - 0.0529538083 * daynumber ); // N, degrees
double const inclination = 5.1454; // i, degrees
double const mndistance = 60.2666; // a, in earth radii
// argument of perigee
double const perigeearg = clamp_circular( 318.0634 + 0.1643573223 * daynumber ); // w, degrees
// mean anomaly
m_body.mnanom = clamp_circular( 115.3654 + 13.0649929509 * daynumber ); // M, degrees
// eccentricity
double const e = 0.054900;
// eccentric anomaly
double E0 = m_body.mnanom + radtodeg * e * std::sin( degtorad * m_body.mnanom ) * ( 1.0 + e * std::cos( degtorad * m_body.mnanom ) );
double E1 = E0 - ( E0 - radtodeg * e * std::sin( degtorad * E0 ) - m_body.mnanom ) / ( 1.0 - e * std::cos( degtorad * E0 ) );
while( std::abs( E0 - E1 ) > 0.005 ) { // arbitrary precision tolerance threshold
E0 = E1;
E1 = E0 - ( E0 - radtodeg * e * std::sin( degtorad * E0 ) - m_body.mnanom ) / ( 1.0 - e * std::cos( degtorad * E0 ) );
}
double const E = E1;
// lunar orbit plane rectangular coordinates
double const xv = mndistance * ( std::cos( degtorad * E ) - e );
double const yv = mndistance * std::sin( degtorad * E ) * std::sqrt( 1.0 - e*e );
// distance
m_body.distance = std::sqrt( xv*xv + yv*yv ); // r
// true anomaly
m_body.tranom = clamp_circular( radtodeg * std::atan2( yv, xv ) ); // v
// ecliptic rectangular coordinates
double const vpluswinrad = degtorad * ( m_body.tranom + perigeearg );
double const xeclip = m_body.distance * ( std::cos( degtorad * longascnode ) * std::cos( vpluswinrad ) - std::sin( degtorad * longascnode ) * std::sin( vpluswinrad ) * std::cos( degtorad * inclination ) );
double const yeclip = m_body.distance * ( std::sin( degtorad * longascnode ) * std::cos( vpluswinrad ) + std::cos( degtorad * longascnode ) * std::sin( vpluswinrad ) * std::cos( degtorad * inclination ) );
double const zeclip = m_body.distance * std::sin( vpluswinrad ) * std::sin( degtorad * inclination );
// ecliptic coordinates
double ecliplat = radtodeg * std::atan2( zeclip, std::sqrt( xeclip*xeclip + yeclip*yeclip ) );
m_body.eclong = clamp_circular( radtodeg * std::atan2( yeclip, xeclip ) );
// distance
m_body.distance = std::sqrt( xeclip*xeclip + yeclip*yeclip + zeclip*zeclip );
// perturbations
// NOTE: perturbation calculation can be safely disabled if we don't mind error of 1-2 degrees
// Sun's mean anomaly: Ms (already computed)
double const sunmnanom = clamp_circular( 356.0470 + 0.9856002585 * daynumber ); // M
// Sun's mean longitude: Ls (already computed)
double const sunphlong = clamp_circular( 282.9404 + 4.70935e-5 * daynumber );
double const sunmnlong = clamp_circular( sunphlong + sunmnanom ); // L = w + M
// Moon's mean anomaly: Mm (already computed)
// Moon's mean longitude: Lm = N + w + M (for the Moon)
m_body.mnlong = clamp_circular( longascnode + perigeearg + m_body.mnanom );
// Moon's mean elongation: D = Lm - Ls
double const mnelong = clamp_circular( m_body.mnlong - sunmnlong );
// Moon's argument of latitude: F = Lm - N
double const arglat = clamp_circular( m_body.mnlong - longascnode );
// longitude perturbations
double const pertevection = -1.274 * std::sin( degtorad * ( m_body.mnanom - 2.0 * mnelong ) ); // Evection
double const pertvariation = +0.658 * std::sin( degtorad * ( 2.0 * mnelong ) ); // Variation
double const pertyearlyeqt = -0.186 * std::sin( degtorad * sunmnanom ); // Yearly equation
// latitude perturbations
double const pertlat = -0.173 * std::sin( degtorad * ( arglat - 2.0 * mnelong ) );
m_body.eclong += pertevection + pertvariation + pertyearlyeqt;
ecliplat += pertlat;
// declination
m_body.declin = radtodeg * std::asin( std::sin (m_body.oblecl * degtorad) * std::sin(m_body.eclong * degtorad) );
// right ascension
double top = std::cos( degtorad * m_body.oblecl ) * std::sin( degtorad * m_body.eclong );
double bottom = std::cos( degtorad * m_body.eclong );
m_body.rascen = clamp_circular( radtodeg * std::atan2( top, bottom ) );
// Greenwich mean sidereal time
m_observer.gmst = 6.697375 + 0.0657098242 * daynumber + m_observer.utime;
m_observer.gmst -= 24.0 * (int)( m_observer.gmst / 24.0 );
if( m_observer.gmst < 0.0 ) m_observer.gmst += 24.0;
// local mean sidereal time
m_observer.lmst = m_observer.gmst * 15.0 + m_observer.longitude;
m_observer.lmst -= 360.0 * (int)( m_observer.lmst / 360.0 );
if( m_observer.lmst < 0.0 ) m_observer.lmst += 360.0;
// hour angle
m_body.hrang = m_observer.lmst - m_body.rascen;
if( m_body.hrang < -180.0 ) m_body.hrang += 360.0; // (force it between -180 and 180 degrees)
else if( m_body.hrang > 180.0 ) m_body.hrang -= 360.0;
double cz; // cosine of the solar zenith angle
double tdatcd = std::cos( degtorad * m_body.declin );
double tdatch = std::cos( degtorad * m_body.hrang );
double tdatcl = std::cos( degtorad * m_observer.latitude );
double tdatsd = std::sin( degtorad * m_body.declin );
double tdatsl = std::sin( degtorad * m_observer.latitude );
cz = tdatsd * tdatsl + tdatcd * tdatcl * tdatch;
// (watch out for the roundoff errors)
if( fabs (cz) > 1.0 ) { cz >= 0.0 ? cz = 1.0 : cz = -1.0; }
m_body.zenetr = std::acos( cz ) * radtodeg;
m_body.elevetr = 90.0 - m_body.zenetr;
refract();
}
void cMoon::refract() {
static double degtorad = 0.0174532925; // converts from degrees to radians
double prestemp; // temporary pressure/temperature correction
double refcor; // temporary refraction correction
double tanelev; // tangent of the solar elevation angle
// if the sun is near zenith, the algorithm bombs; refraction near 0.
if( m_body.elevetr > 85.0 )
refcor = 0.0;
else {
tanelev = tan( degtorad * m_body.elevetr );
if( m_body.elevetr >= 5.0 )
refcor = 58.1 / tanelev
- 0.07 / pow( tanelev, 3 )
+ 0.000086 / pow( tanelev, 5 );
else if( m_body.elevetr >= -0.575 )
refcor = 1735.0
+ m_body.elevetr * ( -518.2 + m_body.elevetr *
( 103.4 + m_body.elevetr * ( -12.79 + m_body.elevetr * 0.711 ) ) );
else
refcor = -20.774 / tanelev;
prestemp = ( m_observer.press * 283.0 ) / ( 1013.0 * ( 273.0 + m_observer.temp ) );
refcor *= prestemp / 3600.0;
}
// refracted solar elevation angle
m_body.elevref = m_body.elevetr + refcor;
// refracted solar zenith angle
m_body.zenref = 90.0 - m_body.elevref;
}
void cMoon::irradiance() {
static double radtodeg = 57.295779513; // converts from radians to degrees
static double degtorad = 0.0174532925; // converts from degrees to radians
m_body.dayang = ( simulation::Time.year_day() - 1 ) * 360.0 / 365.0;
double sd = sin( degtorad * m_body.dayang ); // sine of the day angle
double cd = cos( degtorad * m_body.dayang ); // cosine of the day angle or delination
m_body.erv = 1.000110 + 0.034221*cd + 0.001280*sd;
double d2 = 2.0 * m_body.dayang;
double c2 = cos( degtorad * d2 );
double s2 = sin( degtorad * d2 );
m_body.erv += 0.000719*c2 + 0.000077*s2;
double solcon = 1367.0; // Solar constant, 1367 W/sq m
m_body.coszen = cos( degtorad * m_body.zenref );
if( m_body.coszen > 0.0 ) {
m_body.etrn = solcon * m_body.erv;
m_body.etr = m_body.etrn * m_body.coszen;
}
else {
m_body.etrn = 0.0;
m_body.etr = 0.0;
}
}
void
cMoon::phase() {
// calculate moon's age in days from new moon
float ip = normalize( ( simulation::Time.julian_day() - 2451550.1f ) / 29.530588853f );
m_phase = ip * 29.53f;
}
// normalize values to range 0...1
float
cMoon::normalize( const float Value ) const {
float value = Value - floor( Value );
if( value < 0.f ) { ++value; }
return value;
}

106
moon.h Normal file
View File

@@ -0,0 +1,106 @@
#pragma once
#include "windows.h"
#include "GL/glew.h"
#include "GL/wglew.h"
#include "dumb3d.h"
// TODO: sun and moon share code as celestial bodies, we could make a base class out of it
class cMoon {
public:
// types:
// methods:
void init();
void update();
void render();
// returns location of the sun in the 3d scene
Math3D::vector3 getPosition() { return m_position; }
// returns vector pointing at the sun
Math3D::vector3 getDirection();
// returns current elevation above horizon
float getAngle() const;
// returns current intensity of the sun
float getIntensity();
// returns current phase of the moon
float getPhase() const { return m_phase; }
// sets current time, overriding one acquired from the system clock
void setTime( int const Hour, int const Minute, int const Second );
// sets current geographic location
void setLocation( float const Longitude, float const Latitude );
// sets ambient temperature in degrees C.
void setTemperature( float const Temperature );
// sets surface pressure in milibars
void setPressure( float const Pressure );
// constructors:
cMoon();
// deconstructor:
~cMoon();
// members:
protected:
// types:
// methods:
// calculates sun position on the sky given specified time and location
void move();
// calculates position adjustment due to refraction
void refract();
// calculates light intensity at current moment
void irradiance();
void phase();
// helper, normalize values to range 0...1
float normalize( const float Value ) const;
// members:
GLUquadricObj *moonsphere; // temporary handler for moon positioning test
struct celestialbody { // main planet parameters
double dayang; // day angle (daynum*360/year-length) degrees
double phlong; // longitude of perihelion
double mnlong; // mean longitude, degrees
double mnanom; // mean anomaly, degrees
double tranom; // true anomaly, degrees
double eclong; // ecliptic longitude, degrees.
double oblecl; // obliquity of ecliptic.
double declin; // declination--zenith angle of solar noon at equator, degrees NORTH.
double rascen; // right ascension, degrees
double hrang; // hour angle--hour of sun from solar noon, degrees WEST
double zenetr; // solar zenith angle, no atmospheric correction (= ETR)
double zenref; // solar zenith angle, deg. from zenith, refracted
double coszen; // cosine of refraction corrected solar zenith angle
double elevetr; // solar elevation, no atmospheric correction (= ETR)
double elevref; // solar elevation angle, deg. from horizon, refracted.
double distance; // distance from earth in AUs
double erv; // earth radius vector (multiplied to solar constant)
double etr; // extraterrestrial (top-of-atmosphere) W/sq m global horizontal solar irradiance
double etrn; // extraterrestrial (top-of-atmosphere) W/sq m direct normal solar irradiance
};
struct observer { // weather, time and position data in observer's location
double latitude; // latitude, degrees north (south negative)
double longitude; // longitude, degrees east (west negative)
int hour{ -1 }; // current time, used for calculation of utime. if set to -1, time for
int minute{ -1 };// calculation will be obtained from the local clock
int second{ -1 };
double utime; // universal (Greenwich) standard time
double timezone; // time zone, east (west negative). USA: Mountain = -7, Central = -6, etc.
double gmst; // Greenwich mean sidereal time, hours
double lmst; // local mean sidereal time, degrees
double temp; // ambient dry-bulb temperature, degrees C, used for refraction correction
double press; // surface pressure, millibars, used for refraction correction and ampress
};
celestialbody m_body;
observer m_observer;
Math3D::vector3 m_position;
float m_phase;
};

View File

@@ -1,7 +1,3 @@
/** @file
@brief
*/
/*
This Source Code Form is subject to the
terms of the Mozilla Public License, v.
@@ -15,9 +11,6 @@ http://mozilla.org/MPL/2.0/.
#include "mtable.h"
#include "mczapkie/mctools.h"
// using namespace Mtable;
std::shared_ptr<TMTableTime> Mtable::GlobalTime;
double CompareTime(double t1h, double t1m, double t2h, double t2m) /*roznica czasu w minutach*/
// zwraca różnicę czasu
// jeśli pierwsza jest aktualna, a druga rozkładowa, to ujemna oznacza opóżnienie
@@ -73,7 +66,12 @@ bool TTrainParameters::IsStop()
return true; // na ostatnim się zatrzymać zawsze
}
bool TTrainParameters::UpdateMTable(double hh, double mm, std::string NewName)
bool TTrainParameters::UpdateMTable( simulation_time const &Time, std::string const &NewName ) {
return UpdateMTable( Time.data().wHour, Time.data().wMinute, NewName );
}
bool TTrainParameters::UpdateMTable(double hh, double mm, std::string const &NewName)
/*odfajkowanie dojechania do stacji (NewName) i przeliczenie opóźnienia*/
{
bool OK;
@@ -138,13 +136,13 @@ std::string TTrainParameters::ShowRelation()
return "";
}
TTrainParameters::TTrainParameters(std::string NewTrainName)
TTrainParameters::TTrainParameters(std::string const &NewTrainName)
/*wstępne ustawienie parametrów rozkładu jazdy*/
{
NewName(NewTrainName);
}
void TTrainParameters::NewName(std::string NewTrainName)
void TTrainParameters::NewName(std::string const &NewTrainName)
/*wstępne ustawienie parametrów rozkładu jazdy*/
{
TrainName = NewTrainName;
@@ -519,30 +517,29 @@ bool TTrainParameters::LoadTTfile(std::string scnpath, int iPlus, double vmax)
void TMTableTime::UpdateMTableTime(double deltaT)
// dodanie czasu (deltaT) w sekundach, z przeliczeniem godziny
{
mr = mr + deltaT; // dodawanie sekund
while (mr > 60.0) // przeliczenie sekund do właściwego przedziału
mr += deltaT; // dodawanie sekund
while (mr >= 60.0) // przeliczenie sekund do właściwego przedziału
{
mr = mr - 60.0;
mr -= 60.0;
++mm;
}
while (mm > 59) // przeliczenie minut do właściwego przedziału
{
mm = mm - 60;
mm -= 60;
++hh;
}
while (hh > 23) // przeliczenie godzin do właściwego przedziału
{
hh = hh - 24;
hh -= 24;
++dd; // zwiększenie numeru dnia
}
GameTime = GameTime + deltaT;
}
bool TTrainParameters::DirectionChange()
// sprawdzenie, czy po zatrzymaniu wykonać kolejne komendy
{
if ((StationIndex > 0) && (StationIndex < StationCount)) // dla ostatniej stacji nie
if (TimeTable[StationIndex].StationWare.find("@") != std::string::npos)
if (TimeTable[StationIndex].StationWare.find('@') != std::string::npos)
return true;
return false;
}

View File

@@ -10,6 +10,7 @@ http://mozilla.org/MPL/2.0/.
#pragma once
#include <string>
#include "world.h"
namespace Mtable
{
@@ -73,9 +74,10 @@ class TTrainParameters
std::string NextStop();
bool IsStop();
bool IsTimeToGo(double hh, double mm);
bool UpdateMTable(double hh, double mm, std::string NewName);
TTrainParameters(std::string NewTrainName);
void NewName(std::string NewTrainName);
bool UpdateMTable(double hh, double mm, std::string const &NewName);
bool UpdateMTable( simulation_time const &Time, std::string const &NewName );
TTrainParameters( std::string const &NewTrainName );
void NewName(std::string const &NewTrainName);
void UpdateVelocity(int StationCount, double vActual);
bool LoadTTfile(std::string scnpath, int iPlus, double vmax);
bool DirectionChange();
@@ -86,29 +88,19 @@ class TMTableTime
{
public:
double GameTime = 0.0;
int dd = 0;
int hh = 0;
int mm = 0;
int srh = 0;
int srm = 0; /*wschod slonca*/
int ssh = 0;
int ssm = 0; /*zachod slonca*/
double mr = 0.0;
void UpdateMTableTime(double deltaT);
TMTableTime(int InitH, int InitM, int InitSRH, int InitSRM, int InitSSH, int InitSSM) :
hh( InitH ),
mm( InitM ),
srh( InitSRH ),
srm( InitSRM ),
ssh( InitSSH ),
ssm( InitSSM )
TMTableTime(int InitH, int InitM ) :
hh( InitH ),
mm( InitM )
{}
TMTableTime() = default;
};
extern std::shared_ptr<TMTableTime> GlobalTime;
}
#if !defined(NO_IMPLICIT_NAMESPACE_USE)

View File

@@ -108,6 +108,8 @@ opengl_renderer::Init( GLFWwindow *Window ) {
// preload some common textures
WriteLog( "Loading common gfx data..." );
m_glaretextureid = GetTextureId( "fx\\lightglare", szTexturePath );
m_suntextureid = GetTextureId( "fx\\sun", szTexturePath );
m_moontextureid = GetTextureId( "fx\\moon", szTexturePath );
WriteLog( "...gfx data pre-loading done" );
return true;
@@ -127,32 +129,16 @@ opengl_renderer::Render() {
std::max( 1.0f, (float)Global::ScreenWidth ) / std::max( 1.0f, (float)Global::ScreenHeight ),
0.1f * Global::ZoomFactor,
m_drawrange * Global::fDistanceFactor );
/*
glm::mat4 projection = glm::perspective(
Global::FieldOfView / Global::ZoomFactor * 0.0174532925f,
std::max( 1.0f, (float)Global::ScreenWidth ) / std::max( 1.0f, (float)Global::ScreenHeight ),
0.1f * Global::ZoomFactor,
m_drawrange * Global::fDistanceFactor );
::glLoadMatrixf( &projection[0][0] );
*/
::glMatrixMode( GL_MODELVIEW ); // Select The Modelview Matrix
::glLoadIdentity();
if( World.InitPerformed() ) {
/*
glm::mat4 modelview( 1.0f );
World.Camera.SetMatrix( modelview );
::glLoadMatrixf( &modelview[ 0 ][ 0 ] );
m_camera.update_frustum( projection, modelview );
*/
World.Camera.SetMatrix();
m_camera.update_frustum();
if( !Global::bWireFrame ) {
// bez nieba w trybie rysowania linii
World.Environment.render();
}
Render( &World.Environment );
World.Ground.Render( World.Camera.Pos );
World.Render_Cab();
@@ -167,12 +153,136 @@ opengl_renderer::Render() {
return true; // for now always succeed
}
#ifndef EU07_USE_OLD_RENDERCODE
bool
opengl_renderer::Render( world_environment *Environment ) {
if( Global::bWireFrame ) {
// bez nieba w trybie rysowania linii
return false;
}
Bind( 0 );
::glDisable( GL_LIGHTING );
::glDisable( GL_DEPTH_TEST );
::glDepthMask( GL_FALSE );
::glPushMatrix();
::glTranslatef( Global::pCameraPosition.x, Global::pCameraPosition.y, Global::pCameraPosition.z );
// setup fog
if( Global::fFogEnd > 0 ) {
// fog setup
::glFogfv( GL_FOG_COLOR, Global::FogColor );
::glFogf( GL_FOG_DENSITY, 1.0f / Global::fFogEnd );
::glEnable( GL_FOG );
}
else { ::glDisable( GL_FOG ); }
Environment->m_skydome.Render();
Environment->m_stars.render();
float const duskfactor = 1.0f - clamp( std::abs( Environment->m_sun.getAngle() ), 0.0f, 12.0f ) / 12.0f;
float3 suncolor = interpolate(
float3( 255.0f / 255.0f, 242.0f / 255.0f, 231.0f / 255.0f ),
float3( 235.0f / 255.0f, 140.0f / 255.0f, 36.0f / 255.0f ),
duskfactor );
if( DebugModeFlag == true ) {
// mark sun position for easier debugging
Environment->m_sun.render();
Environment->m_moon.render();
}
// render actual sun and moon
::glPushAttrib( GL_ENABLE_BIT | GL_CURRENT_BIT | GL_COLOR_BUFFER_BIT );
::glDisable( GL_LIGHTING );
::glDisable( GL_ALPHA_TEST );
::glEnable( GL_BLEND );
::glBlendFunc( GL_SRC_ALPHA, GL_ONE );
auto const &modelview = OpenGLMatrices.data( GL_MODELVIEW );
// sun
{
Bind( m_suntextureid );
::glColor4f( suncolor.x, suncolor.y, suncolor.z, 1.0f );
auto const sunvector = Environment->m_sun.getDirection();
auto const sunposition = modelview * glm::vec4( sunvector.x, sunvector.y, sunvector.z, 1.0f );
::glPushMatrix();
::glLoadIdentity(); // macierz jedynkowa
::glTranslatef( sunposition.x, sunposition.y, sunposition.z ); // początek układu zostaje bez zmian
float const size = 0.045f;
::glBegin( GL_TRIANGLE_STRIP );
::glTexCoord2f( 1.0f, 1.0f ); ::glVertex3f( -size, size, 0.0f );
::glTexCoord2f( 1.0f, 0.0f ); ::glVertex3f( -size, -size, 0.0f );
::glTexCoord2f( 0.0f, 1.0f ); ::glVertex3f( size, size, 0.0f );
::glTexCoord2f( 0.0f, 0.0f ); ::glVertex3f( size, -size, 0.0f );
::glEnd();
::glPopMatrix();
}
// moon
{
Bind( m_moontextureid );
float3 mooncolor( 255.0f / 255.0f, 242.0f / 255.0f, 231.0f / 255.0f );
::glColor4f( mooncolor.x, mooncolor.y, mooncolor.z, 1.0f - Global::fLuminance * 0.5f );
auto const moonvector = Environment->m_moon.getDirection();
auto const moonposition = modelview * glm::vec4( moonvector.x, moonvector.y, moonvector.z, 1.0f );
::glPushMatrix();
::glLoadIdentity(); // macierz jedynkowa
::glTranslatef( moonposition.x, moonposition.y, moonposition.z );
float const size = 0.02f; // TODO: expose distance/scale factor from the moon object
// choose the moon appearance variant, based on current moon phase
// NOTE: implementation specific, 8 variants are laid out in 3x3 arrangement
// from new moon onwards, top left to right bottom (last spot is left for future use, if any)
auto const moonphase = Environment->m_moon.getPhase();
float moonu, moonv;
if( moonphase < 1.84566f ) { moonv = 1.0f - 0.0f; moonu = 0.0f; }
else if( moonphase < 5.53699f ) { moonv = 1.0f - 0.0f; moonu = 0.333f; }
else if( moonphase < 9.22831f ) { moonv = 1.0f - 0.0f; moonu = 0.667f; }
else if( moonphase < 12.91963f ) { moonv = 1.0f - 0.333f; moonu = 0.0f; }
else if( moonphase < 16.61096f ) { moonv = 1.0f - 0.333f; moonu = 0.333f; }
else if( moonphase < 20.30228f ) { moonv = 1.0f - 0.333f; moonu = 0.667f; }
else if( moonphase < 23.99361f ) { moonv = 1.0f - 0.667f; moonu = 0.0f; }
else if( moonphase < 27.68493f ) { moonv = 1.0f - 0.667f; moonu = 0.333f; }
else { moonv = 1.0f - 0.0f; moonu = 0.0f; }
::glBegin( GL_TRIANGLE_STRIP );
::glTexCoord2f( moonu, moonv ); ::glVertex3f( -size, size, 0.0f );
::glTexCoord2f( moonu, moonv - 0.333f ); ::glVertex3f( -size, -size, 0.0f );
::glTexCoord2f( moonu + 0.333f, moonv ); ::glVertex3f( size, size, 0.0f );
::glTexCoord2f( moonu + 0.333f, moonv - 0.333f ); ::glVertex3f( size, -size, 0.0f );
::glEnd();
::glPopMatrix();
}
::glPopAttrib();
// clouds
Environment->m_clouds.Render(
interpolate( Environment->m_skydome.GetAverageColor(), suncolor, duskfactor * 0.25f )
* ( 1.0f - Global::Overcast * 0.5f ) // overcast darkens the clouds
* 2.5f ); // arbitrary adjustment factor
Global::DayLight.apply_angle();
Global::DayLight.apply_intensity();
::glPopMatrix();
::glDepthMask( GL_TRUE );
::glEnable( GL_DEPTH_TEST );
::glEnable( GL_LIGHTING );
return true;
}
bool
opengl_renderer::Render( TGround *Ground ) {
glDisable( GL_BLEND );
glAlphaFunc( GL_GREATER, 0.45f ); // im mniejsza wartość, tym większa ramka, domyślnie 0.1f
glAlphaFunc( GL_GREATER, 0.50f ); // im mniejsza wartość, tym większa ramka, domyślnie 0.1f
glEnable( GL_LIGHTING );
glColor3f( 1.0f, 1.0f, 1.0f );
@@ -209,7 +319,7 @@ opengl_renderer::Render( TDynamicObject *Dynamic ) {
// setup
TSubModel::iInstance = ( size_t )this; //żeby nie robić cudzych animacji
double squaredistance = SquareMagnitude( Global::pCameraPosition - Dynamic->vPosition ) / Global::ZoomFactor;
double squaredistance = SquareMagnitude( ( Global::pCameraPosition - Dynamic->vPosition ) / Global::ZoomFactor );
Dynamic->ABuLittleUpdate( squaredistance ); // ustawianie zmiennych submodeli dla wspólnego modelu
::glPushMatrix();
@@ -481,7 +591,7 @@ opengl_renderer::Render_Alpha( TDynamicObject *Dynamic ) {
// setup
TSubModel::iInstance = ( size_t )this; //żeby nie robić cudzych animacji
double squaredistance = SquareMagnitude( Global::pCameraPosition - Dynamic->vPosition ) / Global::ZoomFactor;
double squaredistance = SquareMagnitude( ( Global::pCameraPosition - Dynamic->vPosition ) / Global::ZoomFactor );
Dynamic->ABuLittleUpdate( squaredistance ); // ustawianie zmiennych submodeli dla wspólnego modelu
::glPushMatrix();
@@ -740,7 +850,6 @@ opengl_renderer::Render_Alpha( TSubModel *Submodel ) {
if( Submodel->iAlpha & Submodel->iFlags & 0x2F000000 )
Render_Alpha( Submodel->Next );
};
#endif
void
opengl_renderer::Update ( double const Deltatime ) {

View File

@@ -14,7 +14,7 @@ http://mozilla.org/MPL/2.0/.
#include "lightarray.h"
#include "dumb3d.h"
#include "frustum.h"
#include "ground.h"
#include "world.h"
struct opengl_light {
@@ -116,7 +116,8 @@ public:
// main draw call. returns false on error
bool
Render();
#ifndef EU07_USE_OLD_RENDERCODE
bool
Render( world_environment *Environment );
bool
Render( TGround *Ground );
bool
@@ -135,7 +136,6 @@ public:
Render_Alpha( TModel3d *Model, material_data const *Material, Math3D::vector3 const &Position, Math3D::vector3 const &Angle );
void
Render_Alpha( TSubModel *Submodel );
#endif
// maintenance jobs
void
Update( double const Deltatime);
@@ -194,6 +194,8 @@ private:
std::string m_debuginfo;
GLFWwindow *m_window{ nullptr };
texture_manager::size_type m_glaretextureid{ -1 };
texture_manager::size_type m_suntextureid{ -1 };
texture_manager::size_type m_moontextureid{ -1 };
};
extern opengl_renderer GfxRenderer;

View File

@@ -184,7 +184,7 @@ void CSkyDome::SetGammaCorrection( float const Gamma ) {
void CSkyDome::SetOvercastFactor( float const Overcast ) {
m_overcast = clamp( Overcast, 0.0f, 1.0f );
m_overcast = clamp( Overcast, 0.0f, 1.0f ) * 0.75f; // going above 0.65 makes the model go pretty bad, appearance-wise
}
void CSkyDome::GetPerez( float *Perez, float Distribution[ 5 ][ 2 ], const float Turbidity ) {
@@ -277,7 +277,7 @@ void CSkyDome::RebuildColors() {
// luminance(Y) for clear & overcast sky
float const yclear = PerezFunctionO2( perezluminance, icostheta, gamma, cosgamma2, zenithluminance );
float const yover = ( 1.0f + 2.0f * vertex.y ) / 3.0f;
float const yover = zenithluminance * ( 1.0f + 2.0f * vertex.y ) / 3.0f;
float const Y = interpolate( yclear, yover, m_overcast );
float const X = (x / y) * Y;
@@ -295,6 +295,11 @@ void CSkyDome::RebuildColors() {
colorconverter.z = 1.0f - exp( -m_expfactor * colorconverter.z );
}
// desaturate sky colour, based on overcast level
if( colorconverter.y > 0.0f ) {
colorconverter.y *= ( 1.0f - m_overcast );
}
// override the hue, based on sun height above the horizon. crude way to deal with model shortcomings
// correction begins when the sun is higher than 10 degrees above the horizon, and fully in effect at 10+15 degrees
float const degreesabovehorizon = 90.0f - m_thetasun * ( 180.0f / M_PI );
@@ -318,8 +323,8 @@ void CSkyDome::RebuildColors() {
*/
// crude correction for the times where the model breaks (late night)
// TODO: use proper night sky calculation for these times instead
if( ( color.x <= 0.0f )
&& ( color.y <= 0.0f ) ) {
if( ( color.x <= 0.05f )
&& ( color.y <= 0.05f ) ) {
// darken the sky as the sun goes deeper below the horizon
// 15:50:75 is picture-based night sky colour. it may not be accurate but looks 'right enough'
color.z = 0.75f * std::max( color.z + m_sundirection.y, 0.075f );

View File

@@ -25,6 +25,7 @@
#include <shlobj.h>
#undef NOMINMAX
#include <dbghelp.h>
#include <direct.h>
#endif
// stl
#include <cstdlib>

212
sun.cpp
View File

@@ -4,6 +4,7 @@
#include "globals.h"
#include "mtable.h"
#include "usefull.h"
#include "world.h"
//////////////////////////////////////////////////////////////////////////////////////////
// cSun -- class responsible for dynamic calculation of position and intensity of the Sun,
@@ -32,7 +33,7 @@ void
cSun::update() {
move();
Math3D::vector3 position( 0.0f, 0.0f, -2000.0f );
Math3D::vector3 position( 0.0f, 0.0f, -2000.0f * Global::fDistanceFactor );
position.RotateX( (float)( m_body.elevref * ( M_PI / 180.0 ) ) );
position.RotateY( (float)( -m_body.hrang * ( M_PI / 180.0 ) ) );
@@ -48,8 +49,6 @@ cSun::render() {
GLfloat LightPosition[]= { 10.0f, 50.0f, -5.0f, 1.0f }; // ambient
glLightfv(GL_LIGHT1, GL_POSITION, LightPosition );
*/
glDisable(GL_LIGHTING);
glDisable(GL_FOG);
glColor4f( 255.0f/255.0f, 242.0f/255.0f, 231.0f/255.0f, 1.f );
// debug line to locate the sun easier
Math3D::vector3 position = m_position;
@@ -62,8 +61,6 @@ cSun::render() {
// radius is a result of scaling true distance down to 2km -- it's scaled by equal ratio
gluSphere( sunsphere, (float)(m_body.distance * 9.359157), 12, 12 );
glPopMatrix();
glEnable(GL_FOG);
glEnable(GL_LIGHTING);
}
Math3D::vector3
@@ -115,106 +112,109 @@ void cSun::setPressure( float const Pressure ) {
void cSun::move() {
static double degrad = 57.295779513; // converts from radians to degrees
static double raddeg = 0.0174532925; // converts from degrees to radians
static double radtodeg = 57.295779513; // converts from radians to degrees
static double degtorad = 0.0174532925; // converts from degrees to radians
SYSTEMTIME localtime; // time for the calculation
time( &localtime );
SYSTEMTIME localtime = simulation::Time.data(); // time for the calculation
if( m_observer.hour >= 0 ) { localtime.wHour = m_observer.hour; }
if( m_observer.hour >= 0 ) { localtime.wHour = m_observer.hour; }
if( m_observer.minute >= 0 ) { localtime.wMinute = m_observer.minute; }
if( m_observer.second >= 0 ) { localtime.wSecond = m_observer.second; }
double ut = localtime.wHour
+ localtime.wMinute / 60.0 // too low resolution, noticeable skips
+ localtime.wSecond / 3600.0; // good enough in normal circumstances
/*
+ localtime.wMilliseconds / 3600000.0; // for really smooth movement
*/
double daynumber = 367 * localtime.wYear
- 7 * ( localtime.wYear + ( localtime.wMonth + 9 ) /12 ) / 4
+ 275 * localtime.wMonth / 9
+ localtime.wDay
- 730530
+ (ut / 24.0);
+ localtime.wMinute / 60.0 // too low resolution, noticeable skips
+ localtime.wSecond / 3600.0; // good enough in normal circumstances
/*
+ localtime.wMilliseconds / 3600000.0; // for really smooth movement
*/
double daynumber = 367 * localtime.wYear
- 7 * ( localtime.wYear + ( localtime.wMonth + 9 ) / 12 ) / 4
+ 275 * localtime.wMonth / 9
+ localtime.wDay
- 730530
+ ( ut / 24.0 );
// Universal Coordinated (Greenwich standard) time
// Universal Coordinated (Greenwich standard) time
m_observer.utime = ut * 3600.0;
m_observer.utime = m_observer.utime / 3600.0 - m_observer.timezone;
// mean longitude
m_body.mnlong = 280.460 + 0.9856474 * daynumber;
m_body.mnlong -= 360.0 * (int) ( m_body.mnlong / 360.0 ); // clamp the range to 0-360
if( m_body.mnlong < 0.0 ) m_body.mnlong += 360.0;
// mean anomaly
m_body.mnanom = 357.528 + 0.9856003 * daynumber;
m_body.mnanom -= 360.0 * (int) ( m_body.mnanom / 360.0 ); // clamp the range to 0-360
if( m_body.mnanom < 0.0 ) m_body.mnanom += 360.0;
// ecliptic longitude
m_body.eclong = m_body.mnlong
+ 1.915 * sin( m_body.mnanom * raddeg )
+ 0.020 * sin ( 2.0 * m_body.mnanom * raddeg );
m_body.eclong -= 360.0 * (int)( m_body.eclong / 360.0 );
if( m_body.eclong < 0.0 ) m_body.eclong += 360.0; // clamp the range to 0-360
// perihelion longitude
m_body.phlong = 282.9404 + 4.70935e-5 * daynumber; // w
// orbit eccentricity
double const e = 0.016709 - 1.151e-9 * daynumber;
// mean anomaly
m_body.mnanom = clamp_circular( 356.0470 + 0.9856002585 * daynumber ); // M
// obliquity of the ecliptic
m_body.ecobli = 23.439 - 4.0e-07 * daynumber;
m_body.oblecl = 23.4393 - 3.563e-7 * daynumber;
// mean longitude
m_body.mnlong = clamp_circular( m_body.phlong + m_body.mnanom ); // L = w + M
// eccentric anomaly
double const E = m_body.mnanom + radtodeg * e * std::sin( degtorad * m_body.mnanom ) * ( 1.0 + e * std::cos( degtorad * m_body.mnanom ) );
// ecliptic plane rectangular coordinates
double const xv = std::cos( degtorad * E ) - e;
double const yv = std::sin( degtorad * E ) * std::sqrt( 1.0 - e*e );
// distance
m_body.distance = std::sqrt( xv*xv + yv*yv ); // r
// true anomaly
m_body.tranom = radtodeg * std::atan2( yv, xv ); // v
// ecliptic longitude
m_body.eclong = clamp_circular( m_body.tranom + m_body.phlong ); // lon = v + w
/*
// ecliptic rectangular coordinates
double const x = m_body.distance * std::cos( degtorad * m_body.eclong );
double const y = m_body.distance * std::sin( degtorad * m_body.eclong );
double const z = 0.0;
// equatorial rectangular coordinates
double const xequat = x;
double const yequat = y * std::cos( degtorad * m_body.oblecl ) - 0.0 * std::sin( degtorad * m_body.oblecl );
double const zequat = y * std::sin( degtorad * m_body.oblecl ) + 0.0 * std::cos( degtorad * m_body.oblecl );
// declination
m_body.declin = radtodeg * std::atan2( zequat, std::sqrt( xequat*xequat + yequat*yequat ) );
// right ascension
m_body.rascen = radtodeg * std::atan2( yequat, xequat );
*/
// declination
m_body.declin = radtodeg * std::asin( std::sin( m_body.oblecl * degtorad ) * std::sin( m_body.eclong * degtorad ) );
// declination
m_body.declin = degrad * asin( sin (m_body.ecobli * raddeg) * sin (m_body.eclong * raddeg) );
// right ascension
double top = std::cos( degtorad * m_body.oblecl ) * std::sin( degtorad * m_body.eclong );
double bottom = std::cos( degtorad * m_body.eclong );
// right ascension
double top = cos ( raddeg * m_body.ecobli ) * sin ( raddeg * m_body.eclong );
double bottom = cos ( raddeg * m_body.eclong );
m_body.rascen = clamp_circular( radtodeg * std::atan2( top, bottom ) );
m_body.rascen = degrad * atan2( top, bottom );
if( m_body.rascen < 0.0 ) m_body.rascen += 360.0; // (make it a positive angle)
// Greenwich mean sidereal time
m_observer.gmst = 6.697375 + 0.0657098242 * daynumber + m_observer.utime;
// Greenwich mean sidereal time
m_observer.gmst = 6.697375 + 0.0657098242 * daynumber + m_observer.utime;
m_observer.gmst -= 24.0 * (int)( m_observer.gmst / 24.0 );
if( m_observer.gmst < 0.0 ) m_observer.gmst += 24.0;
m_observer.gmst -= 24.0 * (int)( m_observer.gmst / 24.0 );
if( m_observer.gmst < 0.0 ) m_observer.gmst += 24.0;
// local mean sidereal time
m_observer.lmst = m_observer.gmst * 15.0 + m_observer.longitude;
// local mean sidereal time
m_observer.lmst = m_observer.gmst * 15.0 + m_observer.longitude;
m_observer.lmst -= 360.0 * (int)( m_observer.lmst / 360.0 );
if( m_observer.lmst < 0.0 ) m_observer.lmst += 360.0;
m_observer.lmst -= 360.0 * (int)( m_observer.lmst / 360.0 );
if( m_observer.lmst < 0.0 ) m_observer.lmst += 360.0;
// hour angle
m_body.hrang = m_observer.lmst - m_body.rascen;
// hour angle
m_body.hrang = m_observer.lmst - m_body.rascen;
if( m_body.hrang < -180.0 ) m_body.hrang += 360.0; // (force it between -180 and 180 degrees)
if( m_body.hrang < -180.0 ) m_body.hrang += 360.0; // (force it between -180 and 180 degrees)
else if( m_body.hrang > 180.0 ) m_body.hrang -= 360.0;
double cz; // cosine of the solar zenith angle
double cz; // cosine of the solar zenith angle
double tdatcd = cos( raddeg * m_body.declin );
double tdatch = cos( raddeg * m_body.hrang );
double tdatcl = cos( raddeg * m_observer.latitude );
double tdatsd = sin( raddeg * m_body.declin );
double tdatsl = sin( raddeg * m_observer.latitude );
double tdatcd = std::cos( degtorad * m_body.declin );
double tdatch = std::cos( degtorad * m_body.hrang );
double tdatcl = std::cos( degtorad * m_observer.latitude );
double tdatsd = std::sin( degtorad * m_body.declin );
double tdatsl = std::sin( degtorad * m_observer.latitude );
cz = tdatsd * tdatsl + tdatcd * tdatcl * tdatch;
cz = tdatsd * tdatsl + tdatcd * tdatcl * tdatch;
// (watch out for the roundoff errors)
if( fabs (cz) > 1.0 ) { cz >= 0.0 ? cz = 1.0 : cz = -1.0; }
if( fabs( cz ) > 1.0 ) { cz >= 0.0 ? cz = 1.0 : cz = -1.0; }
m_body.zenetr = acos( cz ) * degrad;
m_body.elevetr = 90.0 - m_body.zenetr;
refract();
// additional calculations for proper object sizing.
// orbit eccentricity
double e = 0.016709 - 1.151e-9 * daynumber;
// eccentric anomaly
double E = m_body.mnanom + e * degrad * sin(m_body.mnanom) * ( 1.0 + e * cos(m_body.mnanom) );
double xv = cos(E) - e;
double yv = sqrt(1.0 - e*e) * sin(E);
m_body.distance = sqrt( xv*xv + yv*yv );
m_body.zenetr = std::acos( cz ) * radtodeg;
m_body.elevetr = 90.0 - m_body.zenetr;
refract();
}
void cSun::refract() {
@@ -258,10 +258,9 @@ void cSun::irradiance() {
static double degrad = 57.295779513; // converts from radians to degrees
static double raddeg = 0.0174532925; // converts from degrees to radians
SYSTEMTIME localtime; // time for the calculation
time( &localtime );
auto const &localtime = simulation::Time.data(); // time for the calculation
m_body.dayang = ( yearday( localtime.wDay, localtime.wMonth, localtime.wYear ) - 1 ) * 360.0 / 365.0;
m_body.dayang = ( simulation::Time.year_day() - 1 ) * 360.0 / 365.0;
double sd = sin( raddeg * m_body.dayang ); // sine of the day angle
double cd = cos( raddeg * m_body.dayang ); // cosine of the day angle or delination
m_body.erv = 1.000110 + 0.034221*cd + 0.001280*sd;
@@ -282,50 +281,3 @@ void cSun::irradiance() {
m_body.etr = 0.0;
}
}
int cSun::yearday( int Day, const int Month, const int Year ) {
char 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 i, leap;
leap = ( Year%4 == 0 ) && ( Year%100 != 0 ) || ( Year%400 == 0 );
for( i = 1; i < Month; ++i )
Day += daytab[ leap ][ i ];
return Day;
}
void cSun::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 + 1;
Day = Yearday - daytab[ leap ][ idx ];
}
// obtains current time for calculations
void
cSun::time( SYSTEMTIME *Time ) {
::GetLocalTime( Time );
// NOTE: we're currently using local time to determine day/month/year
if( Global::fMoveLight > 0.0 ) {
// TODO: enter scenario-defined day/month/year instead.
daymonth( Time->wDay, Time->wMonth, Time->wYear, static_cast<WORD>(Global::fMoveLight) );
}
Time->wHour = GlobalTime->hh;
Time->wMinute = GlobalTime->mm;
Time->wSecond = std::floor( GlobalTime->mr );
}

42
sun.h
View File

@@ -54,35 +54,31 @@ protected:
void refract();
// calculates light intensity at current moment
void irradiance();
// calculates day of year from given date
int yearday( int Day, int const Month, int const Year );
// calculates day and month from given day of year
void daymonth( WORD &Day, WORD &Month, WORD const Year, WORD const Yearday );
// obtains current time for calculations
void time( SYSTEMTIME *Time );
// members:
GLUquadricObj *sunsphere; // temporary handler for sun positioning test
struct celestialbody { // main planet parameters
double dayang; // day angle (daynum*360/year-length) degrees
double mnlong; // mean longitude, degrees
double mnanom; // mean anomaly, degrees
double eclong; // ecliptic longitude, degrees.
double ecobli; // obliquity of ecliptic.
double declin; // declination--zenith angle of solar noon at equator, degrees NORTH.
double rascen; // right ascension, degrees
double hrang; // hour angle--hour of sun from solar noon, degrees WEST
double zenetr; // solar zenith angle, no atmospheric correction (= ETR)
double zenref; // solar zenith angle, deg. from zenith, refracted
double coszen; // cosine of refraction corrected solar zenith angle
double elevetr; // solar elevation, no atmospheric correction (= ETR)
double elevref; // solar elevation angle, deg. from horizon, refracted.
double distance; // distance from earth in AUs
double erv; // earth radius vector (multiplied to solar constant)
double etr; // extraterrestrial (top-of-atmosphere) W/sq m global horizontal solar irradiance
double etrn; // extraterrestrial (top-of-atmosphere) W/sq m direct normal solar irradiance
double dayang; // day angle (daynum*360/year-length) degrees
double phlong; // longitude of perihelion
double mnlong; // mean longitude, degrees
double mnanom; // mean anomaly, degrees
double tranom; // true anomaly, degrees
double eclong; // ecliptic longitude, degrees.
double oblecl; // obliquity of ecliptic.
double declin; // declination--zenith angle of solar noon at equator, degrees NORTH.
double rascen; // right ascension, degrees
double hrang; // hour angle--hour of sun from solar noon, degrees WEST
double zenetr; // solar zenith angle, no atmospheric correction (= ETR)
double zenref; // solar zenith angle, deg. from zenith, refracted
double coszen; // cosine of refraction corrected solar zenith angle
double elevetr; // solar elevation, no atmospheric correction (= ETR)
double elevref; // solar elevation angle, deg. from horizon, refracted.
double distance; // distance from earth in AUs
double erv; // earth radius vector (multiplied to solar constant)
double etr; // extraterrestrial (top-of-atmosphere) W/sq m global horizontal solar irradiance
double etrn; // extraterrestrial (top-of-atmosphere) W/sq m direct normal solar irradiance
};
struct observer { // weather, time and position data in observer's location

View File

@@ -35,7 +35,8 @@ http://mozilla.org/MPL/2.0/.
#define MAKE_ID4(a,b,c,d) (((std::uint32_t)(d)<<24)|((std::uint32_t)(c)<<16)|((std::uint32_t)(b)<<8)|(std::uint32_t)(a))
template <typename _Type>
_Type clamp( _Type const Value, _Type const Min, _Type const Max ) {
_Type
clamp( _Type const Value, _Type const Min, _Type const Max ) {
_Type value = Value;
if( value < Min ) { value = Min; }
@@ -43,8 +44,20 @@ _Type clamp( _Type const Value, _Type const Min, _Type const Max ) {
return value;
}
// keeps the provided value in specified range 0-Range, as if the range was circular buffer
template <typename _Type>
_Type interpolate( _Type const First, _Type const Second, float const Factor ) {
_Type
clamp_circular( _Type Value, _Type const Range = static_cast<_Type>(360) ) {
Value -= Range * (int)( Value / Range ); // clamp the range to 0-360
if( Value < 0.0 ) Value += Range;
return Value;
}
template <typename _Type>
_Type
interpolate( _Type const First, _Type const Second, float const Factor ) {
return ( First * ( 1.0f - Factor ) ) + ( Second * Factor );
}

View File

@@ -18,7 +18,7 @@ LONG CALLBACK unhandled_handler(::EXCEPTION_POINTERS* e)
{
auto nameEnd = name + ::GetModuleFileNameA(::GetModuleHandleA(0), name, MAX_PATH);
::SYSTEMTIME t;
::GetSystemTime(&t);
::GetLocalTime(&t);
wsprintfA(nameEnd - strlen(".exe"),
"_crashdump_%4d%02d%02d_%02d%02d%02d.dmp",
t.wYear, t.wMonth, t.wDay, t.wHour, t.wMinute, t.wSecond);