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

Merge branch 'tmj-dev' into milek-dev

This commit is contained in:
milek7
2018-06-30 18:45:58 +02:00
37 changed files with 672 additions and 498 deletions

View File

@@ -551,7 +551,7 @@ void TAnimModel::RaAnimate( unsigned int const Framestamp ) {
// Ra 2F1I: to by można pomijać dla modeli bez animacji, których jest większość
TAnimContainer *pCurrent;
for (pCurrent = pRoot; pCurrent != NULL; pCurrent = pCurrent->pNext)
for (pCurrent = pRoot; pCurrent != nullptr; pCurrent = pCurrent->pNext)
if (!pCurrent->evDone) // jeśli jest bez eventu
pCurrent->UpdateModel(); // przeliczenie animacji każdego submodelu
// if () //tylko dla modeli z IK !!!!

View File

@@ -125,6 +125,7 @@ class TAnimAdvanced
class TAnimModel : public scene::basic_node {
friend class opengl_renderer;
friend class ui_layer;
public:
// constructors
@@ -151,7 +152,7 @@ public:
return &m_materialdata; }
inline
TModel3d *
Model() {
Model() const {
return pModel; }
// members
static TAnimContainer *acAnimList; // lista animacji z eventem, które muszą być przeliczane również bez wyświetlania

View File

@@ -520,7 +520,7 @@ void TController::TableTraceRoute(double fDistance, TDynamicObject *pVehicle)
pTrack = lastspeedpoint.trTrack;
assert( pTrack != nullptr );
// flaga ustawiona, gdy Point2 toru jest blizej
fLastDir = lastspeedpoint.iFlags & spReverse ? -1.0 : 1.0;
fLastDir = ( ( ( lastspeedpoint.iFlags & spReverse ) != 0 ) ? -1.0 : 1.0 );
fCurrentDistance = lastspeedpoint.fDist; // aktualna odleglosc do jego Point1
fTrackLength = pTrack->Length();
}
@@ -858,6 +858,35 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN
} // koniec obsługi przelotu na W4
else {
// zatrzymanie na W4
if ( ( false == sSpeedTable[i].bMoved )
&& ( ( OrderCurrentGet() & ( Obey_train | Shunt ) ) != 0 ) ) {
// potentially shift the stop point in accordance with its defined parameters
/*
// https://rainsted.com/pl/Wersja/18.2.133#Okr.C4.99gi_dla_W4_i_W32
Pierwszy parametr ujemny - preferowane zatrzymanie czoła składu (np. przed przejściem).
Pierwszy parametr dodatni - preferowane zatrzymanie środka składu (np. przy wiacie, przejściu podziemnym).
Drugi parametr ujemny - wskazanie zatrzymania dla krótszych składów (W32).
Drugi paramer dodatni - długość peronu (W4).
*/
auto L = 0.0;
auto Par1 = sSpeedTable[i].evEvent->ValueGet(1);
auto Par2 = sSpeedTable[i].evEvent->ValueGet(2);
if ((Par2 >= 0) || (fLength < -Par2)) { //użyj tego W4
if (Par1 < 0) {
L = -Par1;
}
else {
//środek
L = Par1 - fMinProximityDist - fLength * 0.5;
}
L = std::max(0.0, std::min(L, std::abs(Par2) - fMinProximityDist - fLength));
sSpeedTable[i].UpdateDistance(L);
sSpeedTable[i].bMoved = true;
}
else {
sSpeedTable[i].iFlags = 0;
}
}
isatpassengerstop = (
// Ra 2F1I: odległość plus długość pociągu musi być mniejsza od długości
// peronu, chyba że pociąg jest dłuższy, to wtedy minimalna.
@@ -866,7 +895,7 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN
( iDrivigFlags & moveStopCloser ) ?
( sSpeedTable[ i ].fDist + fLength ) <=
std::max(
sSpeedTable[ i ].evEvent->ValueGet( 2 ),
std::abs( sSpeedTable[ i ].evEvent->ValueGet( 2 ) ),
2.0 * fMaxProximityDist + fLength ) : // fmaxproximitydist typically equals ~50 m
sSpeedTable[ i ].fDist < d_to_next_sem );
@@ -969,7 +998,7 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN
// NOTE: this calculation is expected to run after completing loading/unloading
AutoRewident(); // nastawianie hamulca do jazdy pociągowej
if( int( floor( sSpeedTable[ i ].evEvent->ValueGet( 1 ) ) ) & 1 ) {
if( static_cast<int>( std::floor( std::abs( sSpeedTable[ i ].evEvent->ValueGet( 1 ) ) ) ) % 2 ) {
// nie podjeżdżać do semafora, jeśli droga nie jest wolna
iDrivigFlags |= moveStopHere;
}
@@ -1201,26 +1230,29 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN
sSpeedTable[ i ].iFlags = 0;
}
}
else if (go == cm_Unknown) // jeśli jeszcze nie ma komendy
if (v != 0.0) // komenda jest tylko gdy ma jechać, bo stoi na podstawie
// tabelki
{ // jeśli nie było komendy wcześniej - pierwsza się liczy - ustawianie
// VelSignal
else if( go == cm_Unknown ) {
// jeśli jeszcze nie ma komendy
// komenda jest tylko gdy ma jechać, bo stoi na podstawietabelki
if( v != 0.0 ) {
// jeśli nie było komendy wcześniej - pierwsza się liczy - ustawianie VelSignal
go = cm_ShuntVelocity; // w trybie pociągowym tylko jeśli włącza
// tryb manewrowy (v!=0.0)
// Ra 2014-06: (VelSignal) nie może być tu ustawiane, bo Tm może być
// daleko
// VelSignal=v; //nie do końca tak, to jest druga prędkość
if (VelSignal == 0.0)
VelSignal = v; // aby stojący ruszył
if (sSpeedTable[i].fDist < 0.0) // jeśli przejechany
{
VelSignal = v; //!!! ustawienie, gdy przejechany jest lepsze niż
// wcale, ale to jeszcze nie to
sSpeedTable[i].iFlags =
0; // to można usunąć (nie mogą być usuwane w skanowaniu)
if( VelSignal == 0.0 ) {
// aby stojący ruszył
VelSignal = v;
}
if( sSpeedTable[ i ].fDist < 0.0 ) {
// jeśli przejechany
//!!! ustawienie, gdy przejechany jest lepsze niż wcale, ale to jeszcze nie to
VelSignal = v;
// to można usunąć (nie mogą być usuwane w skanowaniu)
sSpeedTable[ i ].iFlags = 0;
}
}
}
}
else if( !( sSpeedTable[ i ].iFlags & spSectionVel ) ) {
//jeśli jakiś event pasywny ale nie ograniczenie
@@ -1285,7 +1317,7 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN
&& ( true == TestFlag( sSpeedTable[ i ].iFlags, ( spEnabled | spEvent | spPassengerStopPoint ) ) )
&& ( false == isatpassengerstop ) ) {
// ma podjechać bliżej - czy na pewno w tym miejscu taki warunek?
a = ( iDrivigFlags & moveStopCloser ?
a = ( ( ( iDrivigFlags & moveStopCloser ) != 0 ) ?
fAcc :
0.0 );
}
@@ -2699,65 +2731,69 @@ bool TController::IncSpeed()
if (!mvControlling->FuseFlag) //&&mvControlling->StLinFlag) //yBARC
if ((mvControlling->MainCtrlPos == 0) ||
(mvControlling->StLinFlag)) // youBy polecił dodać 2012-09-08 v367
// na pozycji 0 przejdzie, a na pozostałych będzie czekać, aż się załączą liniowe
// (zgaśnie DelayCtrlFlag)
if (Ready || (iDrivigFlags & movePress))
{
bool scndctrl = ((mvOccupied->Vel <= 30) ||
(mvControlling->Imax > mvControlling->ImaxLo) ||
(fVoltage + fVoltage <
mvControlling->EnginePowerSource.CollectorParameters.MinV +
mvControlling->EnginePowerSource.CollectorParameters.MaxV) ||
(mvControlling->MainCtrlPos == mvControlling->MainCtrlPosNo));
scndctrl = ((scndctrl) && (mvControlling->MainCtrlPos > 1) && (mvControlling->RList[mvControlling->MainCtrlActualPos].R < 0.01)&& (mvControlling->ScndCtrlPos != mvControlling->ScndCtrlPosNo));
double Vs = 99999;
if((mvControlling->MainCtrlPos != mvControlling->MainCtrlPosNo)||(mvControlling->ScndCtrlPos!=mvControlling->ScndCtrlPosNo))
Vs = ESMVelocity(!scndctrl);
// na pozycji 0 przejdzie, a na pozostałych będzie czekać, aż się załączą liniowe (zgaśnie DelayCtrlFlag)
if (Ready || (iDrivigFlags & movePress)) {
// use series mode to build up speed, when high threshold is set for motor overload relay or if the power station is heavily burdened
auto const useseriesmodevoltage { 0.85 * mvControlling->EnginePowerSource.CollectorParameters.MaxV };
auto const useseriesmode = (
( mvOccupied->Vel <= ( ( mvOccupied->BrakeDelayFlag & bdelay_G ) != 0 ? 35 : 25 ) + ( mvControlling->ScndCtrlPos == 0 ? 0 : 5 ) )
|| ( mvControlling->Imax > mvControlling->ImaxLo )
|| ( fVoltage < useseriesmodevoltage ) );
if ((fabs(mvControlling->Im) <
(fReady < 0.4 ? mvControlling->Imin : mvControlling->IminLo))||(mvControlling->Vel>Vs))
{ // Ra: wywalał nadmiarowy, bo Im może być ujemne; jak nie odhamowany, to nie
// przesadzać z prądem
if ((mvOccupied->Vel <= 30) ||
(mvControlling->Imax > mvControlling->ImaxLo) ||
(fVoltage + fVoltage <
mvControlling->EnginePowerSource.CollectorParameters.MinV +
mvControlling->EnginePowerSource.CollectorParameters.MaxV))
{ // bocznik na szeregowej przy ciezkich bruttach albo przy wysokim rozruchu
// pod górę albo przy niskim napięciu
if (mvControlling->MainCtrlPos ?
mvControlling->RList[mvControlling->MainCtrlPos].R > 0.0 :
true) // oporowa
{
OK = (mvControlling->DelayCtrlFlag ?
true :
mvControlling->IncMainCtrl(1)); // kręcimy nastawnik jazdy
if ((OK) &&
(mvControlling->MainCtrlPos ==
1)) // czekaj na 1 pozycji, zanim się nie włączą liniowe
iDrivigFlags |= moveIncSpeed;
else
iDrivigFlags &= ~moveIncSpeed; // usunięcie flagi czekania
}
else // jeśli bezoporowa (z wyjątekiem 0)
OK = false; // to dać bocznik
}
else
{ // przekroczone 30km/h, można wejść na jazdę równoległą
if (mvControlling->ScndCtrlPos) // jeśli ustawiony bocznik
if (mvControlling->MainCtrlPos <
mvControlling->MainCtrlPosNo - 1) // a nie jest ostatnia pozycja
mvControlling->DecScndCtrl(2); // to bocznik na zero po chamsku
// (ktoś miał to poprawić...)
OK = mvControlling->IncMainCtrl(1);
}
if ((mvControlling->MainCtrlPos > 2) &&
(mvControlling->Im == 0)) // brak prądu na dalszych pozycjach
Need_TryAgain = true; // nie załączona lokomotywa albo wywalił
// nadmiarowy
else if (!OK) // nie da się wrzucić kolejnej pozycji
OK = mvControlling->IncScndCtrl(1); // to dać bocznik
auto const scndctrl = (
( mvControlling->StLinFlag )
&& ( mvControlling->RList[ mvControlling->MainCtrlActualPos ].R < 0.01 )
&& ( useseriesmode ?
mvControlling->RList[ mvControlling->MainCtrlActualPos ].Bn == 1 :
mvControlling->RList[ mvControlling->MainCtrlActualPos ].Bn > 1 ) );
double Vs = 99999;
if( scndctrl ?
( mvControlling->ScndCtrlPos < mvControlling->ScndCtrlPosNo ) :
( mvControlling->MainCtrlPos < mvControlling->MainCtrlPosNo ) ) {
Vs = ESMVelocity( !scndctrl );
}
if( ( std::abs( mvControlling->Im ) < ( fReady < 0.4 ? mvControlling->Imin : mvControlling->IminLo ) )
|| ( mvControlling->Vel > Vs ) ) {
// Ra: wywalał nadmiarowy, bo Im może być ujemne; jak nie odhamowany, to nie przesadzać z prądem
if( scndctrl ) {
// to dać bocznik
// engage the shuntfield only if there's sufficient power margin to draw from
OK = (
fVoltage > useseriesmodevoltage + 0.0125 * mvControlling->EnginePowerSource.CollectorParameters.MaxV ?
mvControlling->IncScndCtrl( 1 ) :
false );
}
else {
// jeśli ustawiony bocznik to bocznik na zero po chamsku
if( mvControlling->ScndCtrlPos ) {
mvControlling->DecScndCtrl( 2 );
}
// kręcimy nastawnik jazdy
OK = (
mvControlling->DelayCtrlFlag ?
true :
mvControlling->IncMainCtrl( 1 ) );
// czekaj na 1 pozycji, zanim się nie włączą liniowe
if( true == mvControlling->StLinFlag ) {
iDrivigFlags |= moveIncSpeed;
}
else {
iDrivigFlags &= ~moveIncSpeed;
}
if( ( mvControlling->Im == 0 )
&& ( mvControlling->MainCtrlPos > 2 ) ) {
// brak prądu na dalszych pozycjach
// nie załączona lokomotywa albo wywalił nadmiarowy
Need_TryAgain = true;
}
}
}
else {
OK = false;
}
}
mvControlling->AutoRelayCheck(); // sprawdzenie logiki sterowania
break;
@@ -2943,11 +2979,8 @@ void TController::SpeedSet()
break;
case ElectricSeriesMotor:
if( ( false == mvControlling->StLinFlag )
&& ( false == mvControlling->DelayCtrlFlag )
&& ( 0 == ( iDrivigFlags & moveIncSpeed ) ) ) // styczniki liniowe rozłączone yBARC
{
// if (iDrivigFlags&moveIncSpeed) {} //jeśli czeka na załączenie liniowych
// else
&& ( false == mvControlling->DelayCtrlFlag ) ) {
// styczniki liniowe rozłączone yBARC
while( DecSpeed() )
; // zerowanie napędu
}
@@ -3820,6 +3853,28 @@ TController::UpdateSituation(double dt) {
}
}
}
if( fVoltage < 0.8 * mvControlling->EnginePowerSource.CollectorParameters.MaxV ) {
// if the power station is heavily burdened try to reduce the load
switch( mvControlling->EngineType ) {
case ElectricSeriesMotor: {
if( mvControlling->RList[ mvControlling->MainCtrlPos ].Bn > 1 ) {
// limit yourself to series mode
if( mvControlling->ScndCtrlPos ) {
mvControlling->DecScndCtrl( 2 );
}
while( ( mvControlling->RList[ mvControlling->MainCtrlPos ].Bn > 1 )
&& ( mvControlling->DecMainCtrl( 1 ) ) ) {
; // all work is performed in the header
}
}
break;
}
default: {
break;
}
}
}
}
else {
if( ( IdleTime > 45.0 )
@@ -4574,14 +4629,14 @@ TController::UpdateSituation(double dt) {
else {
// jeśli oba jadą, to przyhamuj lekko i ogranicz prędkość
if( vehicle->fTrackBlock < (
mvOccupied->CategoryFlag & 2 ?
( mvOccupied->CategoryFlag & 2 ) ?
fMaxProximityDist + 0.5 * vel : // cars
2.0 * fMaxProximityDist + 2.0 * vel ) ) { //others
// jak tamten jedzie wolniej a jest w drodze hamowania
AccPreferred = std::min( -0.9, AccPreferred );
VelNext = min_speed( std::round( k ) - 5.0, VelDesired );
if( vehicle->fTrackBlock <= (
mvOccupied->CategoryFlag & 2 ?
( mvOccupied->CategoryFlag & 2 ) ?
fMaxProximityDist : // cars
2.0 * fMaxProximityDist ) ) { //others
// try to force speed change if obstacle is really close
@@ -4647,22 +4702,13 @@ TController::UpdateSituation(double dt) {
VelDesired,
TrainParams->TTVmax );
}
if( ( ( iDrivigFlags & moveStopHere ) != 0 )
&& ( vel < 0.01 )
&& ( SemNextIndex != -1 )
&& ( SemNextIndex < sSpeedTable.size() ) // BUG: index can point at non-existing slot. investigate reason(s)
&& ( sSpeedTable[ SemNextIndex ].fVelNext == 0.0 ) ) {
// don't depart if told to wait at passenger stop until allowed to by the signal
VelDesired = 0.0;
}
}
if( ( OrderCurrentGet() & ( Shunt | Obey_train ) ) != 0 ) {
// w Connect nie, bo moveStopHere odnosi się do stanu po połączeniu
if( ( ( iDrivigFlags & moveStopHere ) != 0 )
&& ( vel < 0.01 )
&& ( VelSignal == 0.0 ) ) {
&& ( VelSignalNext == 0.0 ) ) {
// jeśli ma czekać na wolną drogę, stoi a wyjazdu nie ma, to ma stać
VelDesired = 0.0;
}
@@ -4825,7 +4871,7 @@ TController::UpdateSituation(double dt) {
else {
// jeśli daleko jechać nie można
if( ActualProximityDist > (
mvOccupied->CategoryFlag & 2 ?
( mvOccupied->CategoryFlag & 2 ) ?
fMinProximityDist : // cars
fMaxProximityDist ) ) { // trains and others
// ale ma kawałek do sygnalizatora
@@ -5133,7 +5179,7 @@ TController::UpdateSituation(double dt) {
VelDesired - fVelMinus ) ) {
// ...jeśli prędkość w kierunku czoła jest mniejsza od dozwolonej o margines
if( ( ActualProximityDist > (
mvOccupied->CategoryFlag & 2 ?
( mvOccupied->CategoryFlag & 2 ) ?
fMinProximityDist : // cars are allowed to move within min proximity distance
fMaxProximityDist ) ? // other vehicle types keep wider margin
true :

View File

@@ -131,6 +131,7 @@ class TSpeedPos
// zwrotnicy,32-minięty,64=koniec,128=łuk
// 0x100=event,0x200=manewrowa,0x400=przystanek,0x800=SBL,0x1000=wysłana komenda,0x2000=W5
// 0x4000=semafor,0x10000=zatkanie
bool bMoved{ false }; // czy przesunięty (dotyczy punktu zatrzymania w peronie)
Math3D::vector3 vPos; // współrzędne XYZ do liczenia odległości
struct
{

166
Event.cpp
View File

@@ -39,7 +39,6 @@ TEvent::~TEvent() {
switch (Type)
{ // sprzątanie
case tp_Multiple:
// SafeDeleteArray(Params[9].asText); //nie usuwać - nazwa obiektu powiązanego zamieniana na wskaźnik
if (iFlags & conditional_memstring) // o ile jest łańcuch do porównania w memcompare
SafeDeleteArray(Params[10].asText);
break;
@@ -68,12 +67,6 @@ void TEvent::Conditions(cParser *parser, std::string s)
if (s == "condition")
{ // jesli nie "endevent"
std::string token, str;
if (!asNodeName.empty())
{ // podczepienie łańcucha, jeśli nie jest pusty
// BUG: source of a memory leak -- the array never gets deleted. fix the destructor
Params[9].asText = new char[asNodeName.size() + 1]; // usuwane i zamieniane na wskaźnik
strcpy(Params[9].asText, asNodeName.c_str());
}
parser->getTokens();
*parser >> token;
str = token;
@@ -986,75 +979,76 @@ event_manager::FindEvent( std::string const &Name ) {
// legacy method, inserts specified event in the event query
bool
event_manager::AddToQuery( TEvent *Event, TDynamicObject *Owner, double delay ) {
event_manager::AddToQuery( TEvent *Event, TDynamicObject const *Owner, double delay ) {
if( true == Event->bEnabled ) {
// jeśli może być dodany do kolejki (nie używany w skanowaniu)
if( !Event->iQueued ) // jeśli nie dodany jeszcze do kolejki
{ // kolejka eventów jest posortowana względem (fStartTime)
Event->Activator = Owner;
if( ( Event->Type == tp_AddValues )
&& ( Event->fDelay == 0.0 ) ) {
// eventy AddValues trzeba wykonywać natychmiastowo, inaczej kolejka może zgubić jakieś dodawanie
// Ra: kopiowanie wykonania tu jest bez sensu, lepiej by było wydzielić funkcję
// wykonującą eventy i ją wywołać
if( ( false == Event->m_ignored )
&& ( true == EventConditon( Event ) ) ) { // teraz mogą być warunki do tych eventów
if( false == Event->bEnabled ) { return false; }
if( Event->iQueued != 0 ) { return false; }
// jeśli może być dodany do kolejki (nie używany w skanowaniu)
// jeśli nie dodany jeszcze do kolejki
// kolejka eventów jest posortowana względem (fStartTime)
Event->Activator = Owner;
if( ( Event->Type == tp_AddValues )
&& ( Event->fDelay == 0.0 ) ) {
// eventy AddValues trzeba wykonywać natychmiastowo, inaczej kolejka może zgubić jakieś dodawanie
// Ra: kopiowanie wykonania tu jest bez sensu, lepiej by było wydzielić funkcję
// wykonującą eventy i ją wywołać
if( ( false == Event->m_ignored )
&& ( true == EventConditon( Event ) ) ) { // teraz mogą być warunki do tych eventów
Event->Params[ 5 ].asMemCell->UpdateValues(
Event->Params[ 0 ].asText, Event->Params[ 1 ].asdouble,
Event->Params[ 2 ].asdouble, Event->iFlags );
Event->Params[ 5 ].asMemCell->UpdateValues(
Event->Params[ 0 ].asText, Event->Params[ 1 ].asdouble,
Event->Params[ 2 ].asdouble, Event->iFlags );
if( Event->Params[ 6 ].asTrack ) { // McZapkie-100302 - updatevalues oprocz zmiany wartosci robi putcommand dla
// wszystkich 'dynamic' na danym torze
for( auto dynamic : Event->Params[ 6 ].asTrack->Dynamics ) {
Event->Params[ 5 ].asMemCell->PutCommand(
dynamic->Mechanik,
Event->Params[ 4 ].asLocation );
}
//if (DebugModeFlag)
WriteLog(
"EVENT EXECUTED" + ( Owner ? ( " by " + Owner->asName ) : "" ) + ": AddValues & Track command - ["
+ std::string{ Event->Params[ 0 ].asText } + "] ["
+ to_string( Event->Params[ 1 ].asdouble, 2 ) + "] ["
+ to_string( Event->Params[ 2 ].asdouble, 2 ) + " ]" );
}
//else if (DebugModeFlag)
WriteLog(
"EVENT EXECUTED" + ( Owner ? ( " by " + Owner->asName ) : "" ) + ": AddValues - ["
+ std::string( Event->Params[ 0 ].asText ) + "] ["
+ to_string( Event->Params[ 1 ].asdouble, 2 ) + "] ["
+ to_string( Event->Params[ 2 ].asdouble, 2 ) + "]" );
}
// jeśli jest kolejny o takiej samej nazwie, to idzie do kolejki (and if there's no joint event it'll be set to null and processing will end here)
do {
Event = Event->evJoined;
// NOTE: we could've received a new event from joint event above, so we need to check conditions just in case and discard the bad events
// TODO: refactor this arrangement, it's hardly optimal
} while( ( Event != nullptr )
&& ( ( false == Event->bEnabled )
|| ( Event->iQueued > 0 ) ) );
}
if( ( Event != nullptr )
&& ( false == Event->m_ignored ) ) {
// standardowe dodanie do kolejki
++Event->iQueued; // zabezpieczenie przed podwójnym dodaniem do kolejki
WriteLog( "EVENT ADDED TO QUEUE" + ( Owner ? ( " by " + Owner->asName ) : "" ) + ": " + Event->asName );
Event->fStartTime = delay + std::abs( Event->fDelay ) + Timer::GetTime(); // czas od uruchomienia scenerii
if( Event->fRandomDelay > 0.0 ) {
// doliczenie losowego czasu opóźnienia
Event->fStartTime += Event->fRandomDelay * Random( 10000 ) * 0.0001;
}
if( QueryRootEvent != nullptr ) {
TEvent::AddToQuery( Event, QueryRootEvent );
}
else {
QueryRootEvent = Event;
QueryRootEvent->evNext = nullptr;
if( Event->Params[ 6 ].asTrack ) {
// McZapkie-100302 - updatevalues oprocz zmiany wartosci robi putcommand dla wszystkich 'dynamic' na danym torze
for( auto dynamic : Event->Params[ 6 ].asTrack->Dynamics ) {
Event->Params[ 5 ].asMemCell->PutCommand(
dynamic->Mechanik,
Event->Params[ 4 ].asLocation );
}
//if (DebugModeFlag)
WriteLog(
"EVENT EXECUTED" + ( Owner ? ( " by " + Owner->asName ) : "" ) + ": AddValues & Track command - ["
+ std::string{ Event->Params[ 0 ].asText } + "] ["
+ to_string( Event->Params[ 1 ].asdouble, 2 ) + "] ["
+ to_string( Event->Params[ 2 ].asdouble, 2 ) + " ]" );
}
//else if (DebugModeFlag)
WriteLog(
"EVENT EXECUTED" + ( Owner ? ( " by " + Owner->asName ) : "" ) + ": AddValues - ["
+ std::string( Event->Params[ 0 ].asText ) + "] ["
+ to_string( Event->Params[ 1 ].asdouble, 2 ) + "] ["
+ to_string( Event->Params[ 2 ].asdouble, 2 ) + "]" );
}
// jeśli jest kolejny o takiej samej nazwie, to idzie do kolejki (and if there's no joint event it'll be set to null and processing will end here)
do {
Event = Event->evJoined;
// NOTE: we could've received a new event from joint event above, so we need to check conditions just in case and discard the bad events
// TODO: refactor this arrangement, it's hardly optimal
} while( ( Event != nullptr )
&& ( ( false == Event->bEnabled )
|| ( Event->iQueued > 0 ) ) );
}
if( ( Event != nullptr )
&& ( false == Event->m_ignored ) ) {
// standardowe dodanie do kolejki
++Event->iQueued; // zabezpieczenie przed podwójnym dodaniem do kolejki
WriteLog( "EVENT ADDED TO QUEUE" + ( Owner ? ( " by " + Owner->asName ) : "" ) + ": " + Event->asName );
Event->fStartTime = delay + std::abs( Event->fDelay ) + Timer::GetTime(); // czas od uruchomienia scenerii
if( Event->fRandomDelay > 0.0 ) {
// doliczenie losowego czasu opóźnienia
Event->fStartTime += Event->fRandomDelay * Random( 10000 ) * 0.0001;
}
if( QueryRootEvent != nullptr ) {
TEvent::AddToQuery( Event, QueryRootEvent );
}
else {
QueryRootEvent = Event;
QueryRootEvent->evNext = nullptr;
}
}
return true;
}
@@ -1666,26 +1660,22 @@ event_manager::InitEvents() {
break;
}
case tp_Multiple: {
std::string cellastext;
if( event->Params[ 9 ].asText != nullptr ) { // przepisanie nazwy do bufora
cellastext = event->Params[ 9 ].asText;
SafeDeleteArray( event->Params[ 9 ].asText );
event->Params[ 9 ].asPointer = nullptr; // zerowanie wskaźnika, aby wykryć brak obeiktu
}
if( event->iFlags & ( conditional_trackoccupied | conditional_trackfree ) ) {
// jeśli chodzi o zajetosc toru
event->Params[ 9 ].asTrack = simulation::Paths.find( cellastext );
if( event->Params[ 9 ].asTrack == nullptr ) {
ErrorLog( "Bad event: multi-event \"" + event->asName + "\" cannot find track \"" + cellastext + "\"" );
event->iFlags &= ~( conditional_trackoccupied | conditional_trackfree ); // zerowanie flag
if( false == event->asNodeName.empty() ) {
if( event->iFlags & ( conditional_trackoccupied | conditional_trackfree ) ) {
// jeśli chodzi o zajetosc toru
event->Params[ 9 ].asTrack = simulation::Paths.find( event->asNodeName );
if( event->Params[ 9 ].asTrack == nullptr ) {
ErrorLog( "Bad event: multi-event \"" + event->asName + "\" cannot find track \"" + event->asNodeName + "\"" );
event->iFlags &= ~( conditional_trackoccupied | conditional_trackfree ); // zerowanie flag
}
}
}
else if( event->iFlags & ( conditional_memstring | conditional_memval1 | conditional_memval2 ) ) {
// jeśli chodzi o komorke pamieciową
event->Params[ 9 ].asMemCell = simulation::Memory.find( cellastext );
if( event->Params[ 9 ].asMemCell == nullptr ) {
ErrorLog( "Bad event: multi-event \"" + event->asName + "\" cannot find memory cell \"" + cellastext + "\"" );
event->iFlags &= ~( conditional_memstring | conditional_memval1 | conditional_memval2 );
else if( event->iFlags & ( conditional_memstring | conditional_memval1 | conditional_memval2 ) ) {
// jeśli chodzi o komorke pamieciową
event->Params[ 9 ].asMemCell = simulation::Memory.find( event->asNodeName );
if( event->Params[ 9 ].asMemCell == nullptr ) {
ErrorLog( "Bad event: multi-event \"" + event->asName + "\" cannot find memory cell \"" + event->asNodeName + "\"" );
event->iFlags &= ~( conditional_memstring | conditional_memval1 | conditional_memval2 );
}
}
}
for( auto &childevent : event->m_children ) {

View File

@@ -105,7 +105,7 @@ public:
TEventType Type = tp_Unknown;
double fStartTime = 0.0;
double fDelay = 0.0;
TDynamicObject *Activator = nullptr;
TDynamicObject const *Activator = nullptr;
TParam Params[13]; // McZapkie-070502 //Ra: zamienić to na union/struct
unsigned int iFlags = 0; // zamiast Params[8] z flagami warunku
@@ -122,6 +122,8 @@ private:
class event_manager {
public:
// constructors
event_manager() = default;
// destructor
~event_manager();
// methods
@@ -147,7 +149,7 @@ public:
FindEvent( std::string const &Name );
// legacy method, inserts specified event in the event query
bool
AddToQuery( TEvent *Event, TDynamicObject *Owner, double delay = 0.0 );
AddToQuery( TEvent *Event, TDynamicObject const *Owner, double delay = 0.0 );
// legacy method, executes queued events
bool
CheckQuery();

View File

@@ -36,16 +36,6 @@ std::vector<std::string> const TMoverParameters::eimv_labels = {
"Fful:"
};
inline long Trunc(float f)
{
return (long)f;
}
inline long ROUND(float f)
{
return Trunc(f + 0.5f);
}
inline double square(double val) // SQR() zle liczylo w current() ...
{
return val * val;
@@ -293,10 +283,10 @@ TMoverParameters::TMoverParameters(double VelInitial, std::string TypeNameInit,
int Cab) ://: T_MoverParameters(VelInitial, TypeNameInit,
//NameInit, LoadInitial, LoadTypeInitial, Cab)
TypeName( TypeNameInit ),
Name( NameInit ),
ActiveCab( Cab ),
LoadType( LoadTypeInitial ),
Load( LoadInitial ),
Name( NameInit )
LoadType( LoadTypeInitial )
{
WriteLog(
"------------------------------------------------------");
@@ -1577,9 +1567,10 @@ void TMoverParameters::WaterHeaterCheck( double const Timestep ) {
WaterHeater.is_active = false;
}
WaterHeater.is_damaged |= (
( true == WaterHeater.is_active )
&& ( false == WaterPump.is_active ) );
WaterHeater.is_damaged = (
( true == WaterHeater.is_damaged )
|| ( ( true == WaterHeater.is_active )
&& ( false == WaterPump.is_active ) ) );
}
// fuel pump status update
@@ -1711,19 +1702,12 @@ bool TMoverParameters::IncMainCtrl(int CtrlSpeed)
// szybkie przejœcie na bezoporow¹
if( TrainType == dt_ET40 ) {
break; // this means ET40 won't react at all to fast acceleration command. should it issue just IncMainCtrl(1) instead?
}
}
while( ( RList[ MainCtrlPos ].R > 0.0 )
&& IncMainCtrl( 1 ) ) {
// all work is done in the loop header
;
}
// OK:=true ; {takie chamskie, potem poprawie} <-Ra: kto mia³ to poprawiæ i po co?
if( ActiveDir < 0 ) {
while( ( RList[ MainCtrlPos ].Bn > 1 )
&& IncMainCtrl( 1 ) ) {
--MainCtrlPos;
}
}
OK = false; // shouldn't this be part of the loop above?
// if (TrainType=dt_ET40) then
// while Abs (Im)>IminHi do
@@ -1749,14 +1733,6 @@ bool TMoverParameters::IncMainCtrl(int CtrlSpeed)
}
}
}
if( ActiveDir < 0 ) {
if( ( TrainType != dt_PseudoDiesel )
&& ( RList[ MainCtrlPos ].Bn > 1 ) ) {
// blokada wejścia na równoległą podczas jazdy do tyłu
--MainCtrlPos;
OK = false;
}
}
//
// if (TrainType == "et40")
// if (Abs(Im) > IminHi)
@@ -1765,15 +1741,14 @@ bool TMoverParameters::IncMainCtrl(int CtrlSpeed)
// OK = false;
// }
//}
}
}
if( ( TrainType == dt_ET42 ) && ( true == DynamicBrakeFlag ) ) {
if( MainCtrlPos > 20 ) {
MainCtrlPos = 20;
if( ( TrainType == dt_ET42 ) && ( true == DynamicBrakeFlag ) ) {
if( MainCtrlPos > 20 ) {
MainCtrlPos = 20;
OK = false;
}
}
// return OK;
}
break;
}
@@ -2863,7 +2838,6 @@ bool TMoverParameters::IncLocalBrakeLevel(int CtrlSpeed)
while ((LocalBrakePos < LocalBrakePosNo) && (CtrlSpeed > 0))
{
LocalBrakePos++;
// LocalBrakePosA = static_cast<double>(LocalBrakePos) / LocalBrakePosNo; // temporary hack until i figure out how this element is supposed to work
CtrlSpeed--;
}
IBL = true;
@@ -2887,7 +2861,6 @@ bool TMoverParameters::DecLocalBrakeLevel(int CtrlSpeed)
while ((CtrlSpeed > 0) && (LocalBrakePos > 0))
{
LocalBrakePos--;
// LocalBrakePosA = static_cast<double>( LocalBrakePos ) / LocalBrakePosNo; // temporary hack until i figure out how this element is supposed to work
CtrlSpeed--;
}
DBL = true;
@@ -2909,7 +2882,6 @@ bool TMoverParameters::IncLocalBrakeLevelFAST(void)
if (LocalBrakePos < LocalBrakePosNo)
{
LocalBrakePos = LocalBrakePosNo;
// LocalBrakePosA = static_cast<double>( LocalBrakePos ) / LocalBrakePosNo; // temporary hack until i figure out how this element is supposed to work
ILBLF = true;
}
else
@@ -2928,7 +2900,6 @@ bool TMoverParameters::DecLocalBrakeLevelFAST(void)
if (LocalBrakePos > 0)
{
LocalBrakePos = 0;
// LocalBrakePosA = static_cast<double>( LocalBrakePos ) / LocalBrakePosNo; // temporary hack until i figure out how this element is supposed to work
DLBLF = true;
}
else
@@ -5091,7 +5062,7 @@ double TMoverParameters::TractionForce( double dt ) {
Hamulec->SetED(0);
// (Hamulec as TLSt).SetLBP(LocBrakePress);
if ((PosRatio > dizel_fill))
tmp = 1;
tmp = 4;
else
tmp = 4; // szybkie malenie, powolne wzrastanie
}
@@ -5100,7 +5071,7 @@ double TMoverParameters::TractionForce( double dt ) {
// TODO: gather these in single place so they can be resolved together
if( ( SlippingWheels ) ) {
PosRatio = 0;
tmp = 9;
tmp = 10;
Sandbox( true, range::unit );
} // przeciwposlizg
else {
@@ -5108,7 +5079,7 @@ double TMoverParameters::TractionForce( double dt ) {
Sandbox( false, range::unit );
}
dizel_fill += Max0R(Min0R(PosRatio - dizel_fill, 0.1), -0.1) * 2 *
dizel_fill += Max0R(Min0R(PosRatio - dizel_fill, 0.02), -0.02) * 12 *
(tmp /*2{+4*byte(PosRatio<dizel_fill)*/) *
dt; // wartość zadana/procent czegoś
@@ -5986,16 +5957,19 @@ bool TMoverParameters::dizel_AutoGearCheck(void)
if (MotorParam[ScndCtrlActualPos].AutoSwitch &&
(dizel_automaticgearstatus == 0)) // sprawdz czy zmienic biegi
{
if ((Vel > MotorParam[ScndCtrlActualPos].mfi) &&
(ScndCtrlActualPos < ScndCtrlPosNo))
{
dizel_automaticgearstatus = 1;
OK = true;
if( Vel > MotorParam[ ScndCtrlActualPos ].mfi ) {
// shift up
if( ScndCtrlActualPos < ScndCtrlPosNo ) {
dizel_automaticgearstatus = 1;
OK = true;
}
}
else if ((Vel < MotorParam[ScndCtrlActualPos].fi) && (ScndCtrlActualPos > 0))
{
dizel_automaticgearstatus = -1;
OK = true;
else if( Vel < MotorParam[ ScndCtrlActualPos ].fi ) {
// shift down
if( ScndCtrlActualPos > 0 ) {
dizel_automaticgearstatus = -1;
OK = true;
}
}
}
}
@@ -6466,7 +6440,7 @@ void TMoverParameters::dizel_Heat( double const dt ) {
auto const zaluzje2 { ( dizel_heat.zaluzje2 ? 1 : 0 ) };
// auxiliary water circuit heat transfer values
auto const kf2 { kurek07 * ( ( dizel_heat.kw * ( 0.3 + 0.7 * zaluzje2 ) ) * dizel_heat.rpmw2 + ( dizel_heat.kv * ( 0.3 + 0.7 * zaluzje2 ) * Vel / 3.6 ) ) + 2 };
auto const dTs2 { ( ( dizel_heat.kfs * ( 0.3 ) * ( dizel_heat.To - dizel_heat.Tsr2 ) ) ) / ( gw2 * Cw ) };
auto const dTs2 { ( ( dizel_heat.kfo2 * ( dizel_heat.To - dizel_heat.Tsr2 ) ) ) / ( gw2 * Cw ) };
// przy otwartym kurku B ma³y obieg jest dogrzewany przez du¿y - stosujemy przy korzystaniu z podgrzewacza oraz w zimie
auto const Qch2 { -kf2 * ( dizel_heat.Tsr2 - dizel_heat.Te ) + ( 80 * ( true == WaterCircuitsLink ? 1 : 0 ) * ( dizel_heat.Twy - dizel_heat.Tsr2 ) ) };
auto const dTch2 { Qch2 / ( gw2 * Cw ) };
@@ -6923,41 +6897,11 @@ bool startDLIST, startFFLIST, startWWLIST;
bool startLIGHTSLIST;
int LISTLINE;
// *************************************************************************************************
// Q: 20160717
// *************************************************************************************************
size_t Pos(std::string str_find, std::string in)
{
size_t pos = in.find(str_find);
return (pos != std::string::npos ? pos+1 : 0);
}
/*
// *************************************************************************************************
// Q: 20160717
// *************************************************************************************************
bool issection(std::string const &name)
{
sectionname = name;
if (xline.compare(0, name.size(), name) == 0)
{
lastsectionname = name;
return true;
}
else
return false;
}
*/
bool issection( std::string const &Name, std::string const &Input ) {
return ( Input.compare( 0, Name.size(), Name ) == 0 );
}
int MARKERROR(int code, std::string type, std::string msg)
{
WriteLog(msg);
return code;
}
int s2NPW(std::string s)
{ // wylicza ilosc osi napednych z opisu ukladu osi
const char A = 64;
@@ -9175,9 +9119,7 @@ bool TMoverParameters::SendCtrlToNext( std::string const CtrlCommand, double con
// jakiejś zmiany (np. IncMainCtrl) lepiej wywołać funkcję, czy od razu wysłać komendę.
bool TMoverParameters::RunCommand( std::string Command, double CValue1, double CValue2, int const Couplertype )
{
bool OK;
std::string testload;
OK = false;
bool OK { false };
if (Command == "MainCtrl")
{
@@ -9602,29 +9544,37 @@ bool TMoverParameters::RunCommand( std::string Command, double CValue1, double C
OK = true; // true, gdy można usunąć komendę
}
/*naladunek/rozladunek*/
else if (Pos("Load=", Command) == 1)
else if ( issection( "Load=", Command ) )
{
OK = false; // będzie powtarzane aż się załaduje
if ((Vel == 0) && (MaxLoad > 0) &&
(Load < MaxLoad * (1.0 + OverLoadFactor))) // czy można ładowac?
if (Distance(Loc, CommandIn.Location, Dim, Dim) < 10) // ten peron/rampa
{
testload = ToLower(DUE(Command));
if (Pos(testload, LoadAccepted) > 0) // nazwa jest obecna w CHK
OK = LoadingDone(Min0R(CValue2, LoadSpeed), testload); // zmienia LoadStatus
}
if( ( Vel < 0.01 )
&& ( MaxLoad > 0 )
&& ( Load < MaxLoad * ( 1.0 + OverLoadFactor ) ) ) {
// czy można ładowac?
if( Distance( Loc, CommandIn.Location, Dim, Dim ) < 10 ) {
// ten peron/rampa
auto const testload { ToLower( extract_value( "Load", Command ) ) };
if( LoadAccepted.find( testload ) != std::string::npos ) // nazwa jest obecna w CHK
OK = LoadingDone( Min0R( CValue2, LoadSpeed ), testload ); // zmienia LoadStatus
}
}
// if OK then LoadStatus:=0; //nie udalo sie w ogole albo juz skonczone
}
else if (Pos("UnLoad=", Command) == 1)
else if( issection( "UnLoad=", Command ) )
{
OK = false; // będzie powtarzane aż się rozładuje
if ((Vel == 0) && (Load > 0)) // czy jest co rozladowac?
if (Distance(Loc, CommandIn.Location, Dim, Dim) < 10) // ten peron
{
testload = DUE(Command); // zgodność nazwy ładunku z CHK
if (LoadType == testload) /*mozna to rozladowac*/
OK = LoadingDone(-Min0R(CValue2, LoadSpeed), testload);
}
if( ( Vel < 0.01 )
&& ( Load > 0 ) ) {
// czy jest co rozladowac?
if( Distance( Loc, CommandIn.Location, Dim, Dim ) < 10 ) {
// ten peron
auto const testload { ToLower( extract_value( "UnLoad", Command ) ) }; // zgodność nazwy ładunku z CHK
if( LoadType == testload ) {
/*mozna to rozladowac*/
OK = LoadingDone( -Min0R( CValue2, LoadSpeed ), testload );
}
}
}
// if OK then LoadStatus:=0;
}
else if (Command == "SpeedCntrl")

View File

@@ -155,6 +155,7 @@ public:
static float fSquareDist;
static TModel3d *pRoot;
static std::string *pasText; // tekst dla wyświetlacza (!!!! do przemyślenia)
TSubModel() = default;
~TSubModel();
int Load(cParser &Parser, TModel3d *Model, /*int Pos,*/ bool dynamic);
void ChildAdd(TSubModel *SubModel);

View File

@@ -29,6 +29,9 @@ void UpdateTimers(bool pause);
class stopwatch {
public:
// constructors
stopwatch() = default;
// methods
void
start() {
m_start = std::chrono::steady_clock::now(); }
@@ -40,6 +43,7 @@ public:
return m_accumulator / 20.f;}
private:
// members
std::chrono::time_point<std::chrono::steady_clock> m_start { std::chrono::steady_clock::now() };
float m_accumulator { 1000.f / 30.f * 20.f }; // 20 last samples, initial 'neutral' rate of 30 fps
};

View File

@@ -924,6 +924,25 @@ bool TTrack::AssignForcedEvents(TEvent *NewEventPlus, TEvent *NewEventMinus)
return false;
};
void TTrack::QueueEvents( event_sequence const &Events, TDynamicObject const *Owner ) {
for( auto const &event : Events ) {
if( event.second != nullptr ) {
simulation::Events.AddToQuery( event.second, Owner );
}
}
}
void TTrack::QueueEvents( event_sequence const &Events, TDynamicObject const *Owner, double const Delaylimit ) {
for( auto const &event : Events ) {
if( ( event.second != nullptr )
&& ( event.second->fDelay <= Delaylimit) ) {
simulation::Events.AddToQuery( event.second, Owner );
}
}
}
std::string TTrack::IsolatedName()
{ // podaje nazwę odcinka izolowanego, jesli nie ma on jeszcze przypisanych zdarzeń
if (pIsolated)
@@ -1191,7 +1210,7 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) {
{ szyna[ i ].texture.x,
szyna[ i ].texture.y } };
if( false == iTrapezoid ) { continue; }
if( iTrapezoid == 0 ) { continue; }
// trapez albo przechyłki, to oddzielne punkty na końcu
rpts1[ 12 + i ] = {

View File

@@ -127,6 +127,8 @@ private:
class TTrack : public scene::basic_node {
friend class opengl_renderer;
// NOTE: temporary arrangement
friend class ui_layer;
private:
TIsolated * pIsolated = nullptr; // obwód izolowany obsługujący zajęcia/zwolnienia grupy torów
@@ -247,6 +249,8 @@ public:
void Load(cParser *parser, Math3D::vector3 pOrigin);
bool AssignEvents();
bool AssignForcedEvents(TEvent *NewEventPlus, TEvent *NewEventMinus);
void QueueEvents( event_sequence const &Events, TDynamicObject const *Owner );
void QueueEvents( event_sequence const &Events, TDynamicObject const *Owner, double const Delaylimit );
bool CheckDynamicObject(TDynamicObject *Dynamic);
bool AddDynamicObject(TDynamicObject *Dynamic);
bool RemoveDynamicObject(TDynamicObject *Dynamic);

View File

@@ -924,7 +924,12 @@ void TTrain::OnCommand_independentbrakedecreasefast( TTrain *Train, command_data
}
void TTrain::OnCommand_independentbrakeset( TTrain *Train, command_data const &Command ) {
Train->mvControlled->LocalBrakePosA = (
clamp(
reinterpret_cast<double const &>( Command.param1 ),
0.0, 1.0 ) );
/*
Train->mvControlled->LocalBrakePos = (
std::round(
interpolate<double>(
@@ -933,6 +938,7 @@ void TTrain::OnCommand_independentbrakeset( TTrain *Train, command_data const &C
clamp(
reinterpret_cast<double const &>( Command.param1 ),
0.0, 1.0 ) ) ) );
*/
}
void TTrain::OnCommand_independentbrakebailoff( TTrain *Train, command_data const &Command ) {
@@ -5174,7 +5180,8 @@ bool TTrain::Update( double const Deltatime )
}
else
#endif
ggLocalBrake.UpdateValue(double(mvOccupied->LocalBrakePos));
// standardowa prodedura z kranem powiązanym z klawiaturą
ggLocalBrake.UpdateValue( std::max<double>( mvOccupied->LocalBrakePos, mvOccupied->LocalBrakePosA * LocalBrakePosNo ) );
ggLocalBrake.Update();
}
if (ggManualBrake.SubModel != nullptr) {
@@ -5650,7 +5657,7 @@ TTrain::update_sounds( double const Deltatime ) {
m_radiostop.stop();
}
if( fTachoCount > 3.f ) {
if( fTachoCount >= 3.f ) {
auto const frequency { (
true == dsbHasler.is_combined() ?
fTachoVelocity * 0.01 :
@@ -6355,6 +6362,7 @@ void TTrain::clear_cab_controls()
ggRadioTest.Clear();
ggDoorLeftButton.Clear();
ggDoorRightButton.Clear();
ggTrainHeatingButton.Clear();
ggDepartureSignalButton.Clear();
ggCompressorButton.Clear();
ggConverterButton.Clear();

View File

@@ -109,19 +109,9 @@ bool TTrackFollower::Move(double fDistance, bool bPrimary)
if( ( Owner->Mechanik != nullptr )
&& ( Owner->Mechanik->Primary() ) ) {
// tylko dla jednego członu
for( auto &event : pCurrentTrack->m_events0 ) {
if( ( event.second != nullptr )
&& ( event.second->iQueued == 0 ) ) {
simulation::Events.AddToQuery( event.second, Owner );
}
}
}
for( auto &event : pCurrentTrack->m_events0all ) {
if( ( event.second != nullptr )
&& ( event.second->iQueued == 0 ) ) {
simulation::Events.AddToQuery( event.second, Owner );
}
pCurrentTrack->QueueEvents( pCurrentTrack->m_events0, Owner );
}
pCurrentTrack->QueueEvents( pCurrentTrack->m_events0all, Owner );
}
else if (fDistance < 0) {
// event1, eventall1
@@ -132,26 +122,14 @@ bool TTrackFollower::Move(double fDistance, bool bPrimary)
// tylko dla jednego członu
// McZapkie-280503: wyzwalanie event tylko dla pojazdow z obsada
if( true == bPrimary ) {
for( auto &event : pCurrentTrack->m_events1 ) {
if( ( event.second != nullptr )
&& ( event.second->iQueued == 0 ) ) {
// dodanie do kolejki
simulation::Events.AddToQuery( event.second, Owner );
}
}
pCurrentTrack->QueueEvents( pCurrentTrack->m_events1, Owner );
}
}
}
if( SetFlag( iEventallFlag, -1 ) ) {
// McZapkie-280503: wyzwalanie eventall dla wszystkich pojazdow
if( true == bPrimary ) {
for( auto &event : pCurrentTrack->m_events1all ) {
if( ( event.second != nullptr )
&& ( event.second->iQueued == 0 ) ) {
// dodanie do kolejki
simulation::Events.AddToQuery( event.second, Owner );
}
}
pCurrentTrack->QueueEvents( pCurrentTrack->m_events1all, Owner );
}
}
}
@@ -163,26 +141,14 @@ bool TTrackFollower::Move(double fDistance, bool bPrimary)
&& ( Owner->Mechanik->Primary() ) ) {
// tylko dla jednego członu
if( true == bPrimary ) {
for( auto &event : pCurrentTrack->m_events2 ) {
if( ( event.second != nullptr )
&& ( event.second->iQueued == 0 ) ) {
// dodanie do kolejki
simulation::Events.AddToQuery( event.second, Owner );
}
}
pCurrentTrack->QueueEvents( pCurrentTrack->m_events2, Owner );
}
}
}
if( SetFlag( iEventallFlag, -2 ) ) {
// sprawdza i zeruje na przyszłość, true jeśli zmieni z 2 na 0
if( true == bPrimary ) {
for( auto &event : pCurrentTrack->m_events2all ) {
if( ( event.second != nullptr )
&& ( event.second->iQueued == 0 ) ) {
// dodanie do kolejki
simulation::Events.AddToQuery( event.second, Owner );
}
}
pCurrentTrack->QueueEvents( pCurrentTrack->m_events2all, Owner );
}
}
}
@@ -279,34 +245,13 @@ bool TTrackFollower::Move(double fDistance, bool bPrimary)
{ // tylko gdy początkowe ustawienie, dodajemy eventy stania do kolejki
if (Owner->MoverParameters->ActiveCab != 0) {
for( auto &event : pCurrentTrack->m_events1 ) {
if( ( event.second != nullptr )
&& ( event.second->fDelay <= -1.0 ) ) {
simulation::Events.AddToQuery( event.second, Owner );
}
}
for( auto &event : pCurrentTrack->m_events2 ) {
if( ( event.second != nullptr )
&& ( event.second->fDelay <= -1.0 ) ) {
simulation::Events.AddToQuery( event.second, Owner );
}
}
}
for( auto &event : pCurrentTrack->m_events1all ) {
if( ( event.second != nullptr )
&& ( event.second->fDelay <= -1.0 ) ) {
simulation::Events.AddToQuery( event.second, Owner );
}
}
for( auto &event : pCurrentTrack->m_events2all ) {
if( ( event.second != nullptr )
&& ( event.second->fDelay <= -1.0 ) ) {
simulation::Events.AddToQuery( event.second, Owner );
}
pCurrentTrack->QueueEvents( pCurrentTrack->m_events1, Owner, -1.0 );
pCurrentTrack->QueueEvents( pCurrentTrack->m_events2, Owner, -1.0 );
}
pCurrentTrack->QueueEvents( pCurrentTrack->m_events1all, Owner, -1.0 );
pCurrentTrack->QueueEvents( pCurrentTrack->m_events2all, Owner, -1.0 );
}
fCurrentDistance = s;
// fDistance=0;
return ComputatePosition(); // przeliczenie XYZ, true o ile nie wyjechał na NULL
}
}

View File

@@ -13,49 +13,50 @@ http://mozilla.org/MPL/2.0/.
#include "Classes.h"
#include "Segment.h"
class TTrackFollower
{ // oś poruszająca się po torze
private:
TTrack *pCurrentTrack = nullptr; // na którym torze siê znajduje
std::shared_ptr<TSegment> pCurrentSegment; // zwrotnice mog¹ mieæ dwa segmenty
double fCurrentDistance = 0.0; // przesuniêcie wzglêdem Point1 w stronê Point2
double fDirection = 1.0; // ustawienie wzglêdem toru: -1.0 albo 1.0, mno¿one przez dystans // jest przodem do Point2
bool ComputatePosition(); // przeliczenie pozycji na torze
TDynamicObject *Owner = nullptr; // pojazd posiadający
int iEventFlag = 0; // McZapkie-020602: informacja o tym czy wyzwalac zdarzenie: 0,1,2,3
int iEventallFlag = 0;
int iSegment = 0; // który segment toru jest używany (żeby nie przeskakiwało po przestawieniu
// zwrotnicy pod taborem)
public:
double fOffsetH = 0.0; // Ra: odległość środka osi od osi toru (dla samochodów) - użyć do wężykowania
Math3D::vector3 pPosition; // współrzędne XYZ w układzie scenerii
Math3D::vector3 vAngles; // x:przechyłka, y:pochylenie, z:kierunek w planie (w radianach)
// oś poruszająca się po torze
class TTrackFollower {
public:
// constructors
TTrackFollower() = default;
// destructor
~TTrackFollower();
// methods
TTrack * SetCurrentTrack(TTrack *pTrack, int end);
bool Move(double fDistance, bool bPrimary);
inline TTrack * GetTrack() const
{
return pCurrentTrack;
};
inline double GetRoll()
{
return vAngles.x;
}; // przechyłka policzona przy ustalaniu pozycji
inline TTrack * GetTrack() const {
return pCurrentTrack; };
// przechyłka policzona przy ustalaniu pozycji
inline double GetRoll() {
return vAngles.x; };
//{return pCurrentSegment->GetRoll(fCurrentDistance)*fDirection;}; //zamiast liczyć można pobrać
inline double GetDirection() const
{
return fDirection;
}; // zwrot na torze
inline double GetTranslation() const
{
return fCurrentDistance;
}; // ABu-030403
// zwrot na torze
inline double GetDirection() const {
return fDirection; };
// ABu-030403
inline double GetTranslation() const {
return fCurrentDistance; };
// inline double GetLength(vector3 p1, vector3 cp1, vector3 cp2, vector3 p2)
//{ return pCurrentSegment->ComputeLength(p1,cp1,cp2,p2); };
// inline double GetRadius(double L, double d); //McZapkie-150503
bool Init(TTrack *pTrack, TDynamicObject *NewOwner, double fDir);
void Render(float fNr);
// members
double fOffsetH = 0.0; // Ra: odległość środka osi od osi toru (dla samochodów) - użyć do wężykowania
Math3D::vector3 pPosition; // współrzędne XYZ w układzie scenerii
Math3D::vector3 vAngles; // x:przechyłka, y:pochylenie, z:kierunek w planie (w radianach)
private:
// methods
bool ComputatePosition(); // przeliczenie pozycji na torze
// members
TTrack *pCurrentTrack = nullptr; // na którym torze siê znajduje
std::shared_ptr<TSegment> pCurrentSegment; // zwrotnice mog¹ mieæ dwa segmenty
double fCurrentDistance = 0.0; // przesuniêcie wzglêdem Point1 w stronê Point2
double fDirection = 1.0; // ustawienie wzglêdem toru: -1.0 albo 1.0, mno¿one przez dystans // jest przodem do Point2
TDynamicObject *Owner = nullptr; // pojazd posiadający
int iEventFlag = 0; // McZapkie-020602: informacja o tym czy wyzwalac zdarzenie: 0,1,2,3
int iEventallFlag = 0;
int iSegment = 0; // który segment toru jest używany (żeby nie przeskakiwało po przestawieniu zwrotnicy pod taborem)
};
//---------------------------------------------------------------------------
#endif

View File

@@ -74,6 +74,12 @@ simulation_time::init() {
m_time.wMinute = tms->tm_min;
m_time.wSecond = tms->tm_sec;
m_time.wMilliseconds = ts.tv_nsec / 1000000;
/*
time_t local = mktime(localtime(&ts.tv_sec));
time_t utc = mktime(gmtime(&ts.tv_sec));
m_timezonebias = (double)(local - utc) / 3600.0f;
*/
#elif _WIN32
::GetLocalTime( &m_time );
#endif
@@ -92,6 +98,30 @@ simulation_time::init() {
}
m_yearday = year_day( m_time.wDay, m_time.wMonth, m_time.wYear );
// calculate time zone bias
// retrieve relevant time zone info from system registry (or fall back on supplied default)
// TODO: select timezone matching defined geographic location and/or country
struct registry_time_zone_info {
long Bias;
long StandardBias;
long DaylightBias;
SYSTEMTIME StandardDate;
SYSTEMTIME DaylightDate;
} timezoneinfo = { -60, 0, -60, { 0, 10, 0, 5, 3, 0, 0, 0 }, { 0, 3, 0, 5, 2, 0, 0, 0 } };
auto zonebias { timezoneinfo.Bias };
if( m_yearday < year_day( timezoneinfo.DaylightDate.wDay, timezoneinfo.DaylightDate.wMonth, m_time.wYear ) ) {
zonebias += timezoneinfo.StandardBias;
}
else if( m_yearday < year_day( timezoneinfo.StandardDate.wDay, timezoneinfo.StandardDate.wMonth, m_time.wYear ) ) {
zonebias += timezoneinfo.DaylightBias;
}
else {
zonebias += timezoneinfo.StandardBias;
}
m_timezonebias = ( zonebias / 60.0 );
}
void
@@ -216,15 +246,14 @@ void TWorld::TrainDelete(TDynamicObject *d)
if (Train)
if (Train->Dynamic() != d)
return; // nie tego usuwać
#ifdef EU07_SCENERY_EDITOR
if( ( Train->DynamicObject )
&& ( Train->DynamicObject->Mechanik ) ) {
/*
if( ( Train->Dynamic() )
&& ( Train->Dynamic()->Mechanik ) ) {
// likwidacja kabiny wymaga przejęcia przez AI
Train->DynamicObject->Mechanik->TakeControl( true );
Train->Dynamic()->Mechanik->TakeControl( true );
}
#endif
delete Train; // i nie ma czym sterować
Train = NULL;
*/
SafeDelete( Train ); // i nie ma czym sterować
Controlled = NULL; // tego też już nie ma
mvControlled = NULL;
};

View File

@@ -44,6 +44,8 @@ public:
year_day( int Day, int const Month, int const Year ) const;
int
julian_day() const;
double
zone_bias() const { return m_timezonebias; }
private:
// calculates day and month from given day of year
@@ -54,6 +56,7 @@ private:
double m_milliseconds{ 0.0 };
int m_yearday;
char m_monthdaycounts[ 2 ][ 13 ];
double m_timezonebias{ 0.0 };
};
namespace simulation {

View File

@@ -53,7 +53,8 @@ struct openal_source {
bool is_looping { false };
sound_properties properties;
sync_state sync { sync_state::good };
// constructors
openal_source() = default;
// methods
template <class Iterator_>
openal_source &
@@ -102,6 +103,8 @@ class openal_renderer {
friend class opengl_renderer;
public:
// constructors
openal_renderer() = default;
// destructor
~openal_renderer();
// methods

View File

@@ -24,7 +24,7 @@ class cFrustum {
public:
// constructors:
cFrustum() = default;
// methods:
// update the frustum to match current view orientation
void

2
lua.h
View File

@@ -17,5 +17,5 @@ public:
void interpret(std::string file);
typedef void (*eventhandler_t)(TEvent*, TDynamicObject*);
typedef void (*eventhandler_t)(TEvent*, const TDynamicObject*);
};

View File

@@ -9,18 +9,6 @@ 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
#ifdef _WIN32
TIME_ZONE_INFORMATION timezoneinfo; // TODO: timezone dependant on geographic location
::GetTimeZoneInformation( &timezoneinfo );
m_observer.timezone = -timezoneinfo.Bias / 60.0f;
#elif __linux__
timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
time_t local = mktime(localtime(&ts.tv_sec));
time_t utc = mktime(gmtime(&ts.tv_sec));
m_observer.timezone = (local - utc) / 3600.0f;
#endif
}
cMoon::~cMoon() { gluDeleteQuadric( moonsphere ); }
@@ -28,16 +16,20 @@ cMoon::~cMoon() { gluDeleteQuadric( moonsphere ); }
void
cMoon::init() {
moonsphere = gluNewQuadric();
gluQuadricNormals( moonsphere, GLU_SMOOTH );
m_observer.timezone = -1.0 * simulation::Time.zone_bias();
// 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();
moonsphere = gluNewQuadric();
gluQuadricNormals( moonsphere, GLU_SMOOTH );
}
void
cMoon::update() {
m_observer.temp = Global.AirTemperature;
move();
glm::vec3 position( 0.f, 0.f, -1.f );
position = glm::rotateX( position, glm::radians( static_cast<float>( m_body.elevref ) ) );
@@ -121,7 +113,7 @@ void cMoon::move() {
if( m_observer.minute >= 0 ) { localtime.wMinute = m_observer.minute; }
if( m_observer.second >= 0 ) { localtime.wSecond = m_observer.second; }
double ut =
double localut =
localtime.wHour
+ localtime.wMinute / 60.0 // too low resolution, noticeable skips
+ localtime.wSecond / 3600.0; // good enough in normal circumstances
@@ -134,11 +126,10 @@ void cMoon::move() {
+ 275 * localtime.wMonth / 9
+ localtime.wDay
- 730530
+ ( ut / 24.0 );
+ ( localut / 24.0 );
// Universal Coordinated (Greenwich standard) time
m_observer.utime = ut * 3600.0;
m_observer.utime = m_observer.utime / 3600.0 - m_observer.timezone;
m_observer.utime = localut - m_observer.timezone;
// obliquity of the ecliptic
m_body.oblecl = clamp_circular( 23.4393 - 3.563e-7 * daynumber );

View File

@@ -75,7 +75,7 @@ mouse_input::button( int const Button, int const Action ) {
if( true == FreeFlyModeFlag ) {
// world editor controls
// currently we only handle view panning in this mode
// TODO: separate behaviour when the scenery editor is active and in 'regular' free fly mode
if( Action == GLFW_RELEASE ) {
// if it's the right mouse button that got released we were potentially in view panning mode; stop it
if( Button == GLFW_MOUSE_BUTTON_RIGHT ) {
@@ -84,6 +84,19 @@ mouse_input::button( int const Button, int const Action ) {
}
else {
// button press
if( Button == GLFW_MOUSE_BUTTON_LEFT ) {
// the left button selects scene node
// further behaviour can vary depending on whether we're in editor mode
auto const *node { GfxRenderer.Update_Pick_Node() };
if( true == EditorModeFlag ) {
// NOTE: until we have proper editor object in place we set the current node manually
editor::Node = node;
}
else {
// launch on_click event associated with to the node
// TODO: implement
}
}
if( Button == GLFW_MOUSE_BUTTON_RIGHT ) {
// the right button activates mouse panning mode
m_pickmodepanning = true;

View File

@@ -266,6 +266,8 @@ typedef geometry_handle geometrybank_handle;
class geometrybank_manager {
public:
// constructors
geometrybank_manager() = default;
// methods:
// performs a resource sweep
void update();

View File

@@ -1826,15 +1826,6 @@ opengl_renderer::Render( cell_sequence::iterator First, cell_sequence::iterator
// tracks
// TODO: update after path node refactoring
Render( std::begin( cell->m_paths ), std::end( cell->m_paths ) );
#ifdef EU07_SCENERY_EDITOR
// TODO: re-implement
// memcells
if( EditorModeFlag ) {
for( auto const memcell : Groundsubcell->m_memcells ) {
Render( memcell );
}
}
#endif
#ifdef EU07_USE_DEBUG_CULLING
// debug
::glLineWidth( 2.f );
@@ -1904,16 +1895,7 @@ opengl_renderer::Render( cell_sequence::iterator First, cell_sequence::iterator
::glColor3fv( glm::value_ptr( pick_color( m_picksceneryitems.size() + 1 ) ) );
Render( path );
}
#ifdef EU07_SCENERY_EDITOR
// memcells
// TODO: re-implement
if( EditorModeFlag ) {
for( auto const memcell : Groundsubcell->m_memcells ) {
::glColor3fv( glm::value_ptr( pick_color( m_picksceneryitems.size() + 1 ) ) );
Render( memcell );
}
}
#endif
// post-render cleanup
::glPopMatrix();
@@ -1944,6 +1926,17 @@ opengl_renderer::Render( cell_sequence::iterator First, cell_sequence::iterator
Render( dynamic );
}
}
// memcells
if( ( EditorModeFlag )
&& ( DebugModeFlag ) ) {
::glPushAttrib( GL_ENABLE_BIT );
::glDisable( GL_TEXTURE_2D );
::glColor3f( 0.36f, 0.75f, 0.35f );
for( auto const *memorycell : cell->m_memorycells ) {
Render( memorycell );
}
::glPopAttrib();
}
break;
}
case rendermode::pickscenery: {
@@ -1953,6 +1946,14 @@ opengl_renderer::Render( cell_sequence::iterator First, cell_sequence::iterator
::glColor3fv( glm::value_ptr( pick_color( m_picksceneryitems.size() + 1 ) ) );
Render( instance );
}
// memcells
if( ( EditorModeFlag )
&& ( DebugModeFlag ) ) {
for( auto const *memorycell : cell->m_memorycells ) {
::glColor3fv( glm::value_ptr( pick_color( m_picksceneryitems.size() + 1 ) ) );
Render( memorycell );
}
}
// vehicles aren't included in scenery picking for the time being
break;
}
@@ -2774,25 +2775,22 @@ opengl_renderer::Render( scene::basic_cell::path_sequence::const_iterator First,
}
void
opengl_renderer::Render( TMemCell *Memcell ) {
opengl_renderer::Render( TMemCell const *Memcell ) {
::glPushMatrix();
auto const position = Memcell->location() - m_renderpass.camera.position();
::glTranslated( position.x, position.y + 0.5, position.z );
switch( m_renderpass.draw_mode ) {
case rendermode::color: {
::glPushAttrib( GL_ENABLE_BIT );
::glDisable( GL_TEXTURE_2D );
::glColor3f( 0.36f, 0.75f, 0.35f );
case rendermode::color:
case rendermode::shadows: {
::gluSphere( m_quadric, 0.35, 4, 2 );
::glPopAttrib();
break;
}
case rendermode::shadows:
case rendermode::pickscenery: {
// add the node to the pick list
m_picksceneryitems.emplace_back( Memcell );
::gluSphere( m_quadric, 0.35, 4, 2 );
break;
}

View File

@@ -52,6 +52,8 @@ struct opengl_technique {
class opengl_camera {
public:
// constructors
opengl_camera() = default;
// methods:
inline
void
@@ -113,10 +115,10 @@ class opengl_renderer {
public:
// types
// constructors
opengl_renderer() = default;
// destructor
~opengl_renderer() { gluDeleteQuadric( m_quadric ); }
// methods
bool
Init( GLFWwindow *Window );
@@ -287,7 +289,7 @@ private:
bool
Render_cab( TDynamicObject const *Dynamic, bool const Alpha = false );
void
Render( TMemCell *Memcell );
Render( TMemCell const *Memcell );
void
Render_Alpha( scene::basic_region *Region );
void

View File

@@ -124,7 +124,6 @@ basic_cell::update_events() {
void
basic_cell::update_sounds() {
auto const deltatime = Timer::GetDeltaRenderTime();
for( auto *sound : m_sounds ) {
sound->play_event();
}
@@ -361,6 +360,7 @@ basic_cell::insert( sound_source *Sound ) {
m_active = true;
m_sounds.emplace_back( Sound );
// NOTE: sound sources are virtual 'points' hence they don't ever expand cell range
}
// adds provided sound instance to the cell
@@ -374,6 +374,16 @@ basic_cell::insert( TEventLauncher *Launcher ) {
enclose_area( Launcher );
}
// adds provided memory cell to the cell
void
basic_cell::insert( TMemCell *Memorycell ) {
m_active = true;
m_memorycells.emplace_back( Memorycell );
// NOTE: memory cells are virtual 'points' hence they don't ever expand cell range
}
// registers provided path in the lookup directory of the cell
void
basic_cell::register_end( TTrack *Path ) {
@@ -1133,7 +1143,6 @@ basic_region::insert_lines( lines_node Lines, scratch_data &Scratchpad ) {
// inserts provided track in the region
void
basic_region::insert_path( TTrack *Path, const scratch_data &Scratchpad ) {
// NOTE: bounding area isn't present/filled until track class and wrapper refactoring is done
auto location = Path->location();
@@ -1155,7 +1164,6 @@ basic_region::insert_path( TTrack *Path, const scratch_data &Scratchpad ) {
// inserts provided track in the region
void
basic_region::insert_traction( TTraction *Traction, scratch_data &Scratchpad ) {
// NOTE: bounding area isn't present/filled until track class and wrapper refactoring is done
auto location = Traction->location();
@@ -1177,7 +1185,6 @@ basic_region::insert_traction( TTraction *Traction, scratch_data &Scratchpad ) {
// inserts provided instance of 3d model in the region
void
basic_region::insert_instance( TAnimModel *Instance, scratch_data &Scratchpad ) {
// NOTE: bounding area isn't present/filled until track class and wrapper refactoring is done
auto location = Instance->location();
@@ -1210,7 +1217,6 @@ basic_region::insert_sound( sound_source *Sound, scratch_data &Scratchpad ) {
// inserts provided event launcher in the region
void
basic_region::insert_launcher( TEventLauncher *Launcher, scratch_data &Scratchpad ) {
// NOTE: bounding area isn't present/filled until track class and wrapper refactoring is done
auto location = Launcher->location();
@@ -1224,6 +1230,22 @@ basic_region::insert_launcher( TEventLauncher *Launcher, scratch_data &Scratchpa
}
}
// inserts provided memory cell in the region
void
basic_region::insert_memorycell( TMemCell *Memorycell, scratch_data &Scratchpad ) {
// NOTE: bounding area isn't present/filled until track class and wrapper refactoring is done
auto location = Memorycell->location();
if( point_inside( location ) ) {
// NOTE: nodes placed outside of region boundaries are discarded
section( location ).insert( Memorycell );
}
else {
// tracks are guaranteed to hava a name so we can skip the check
ErrorLog( "Bad scenario: memory cell \"" + Memorycell->name() + "\" placed in location outside region bounds (" + to_string( location ) + ")" );
}
}
// find a vehicle located neares to specified location, within specified radius, optionally discarding vehicles without drivers
std::tuple<TDynamicObject *, float>
basic_region::find_vehicle( glm::dvec3 const &Point, float const Radius, bool const Onlycontrolled, bool const Findbycoupler ) {

12
scene.h
View File

@@ -64,6 +64,8 @@ class basic_cell {
friend class ::opengl_renderer;
public:
// constructors
basic_cell() = default;
// methods
// legacy method, finds and assigns traction piece to specified pantograph of provided vehicle
void
@@ -113,6 +115,9 @@ public:
// adds provided event launcher to the cell
void
insert( TEventLauncher *Launcher );
// adds provided memory cell to the cell
void
insert( TMemCell *Memorycell );
// registers provided path in the lookup directory of the cell
void
register_end( TTrack *Path );
@@ -150,6 +155,7 @@ private:
using instance_sequence = std::vector<TAnimModel *>;
using sound_sequence = std::vector<sound_source *>;
using eventlauncher_sequence = std::vector<TEventLauncher *>;
using memorycell_sequence = std::vector<TMemCell *>;
// methods
void
enclose_area( scene::basic_node *Node );
@@ -166,6 +172,7 @@ private:
traction_sequence m_traction;
sound_sequence m_sounds;
eventlauncher_sequence m_eventlaunchers;
memorycell_sequence m_memorycells;
// search helpers
struct lookup_data {
path_sequence paths;
@@ -183,6 +190,8 @@ class basic_section {
friend class ::opengl_renderer;
public:
// constructors
basic_section() = default;
// methods
// legacy method, finds and assigns traction piece to specified pantograph of provided vehicle
void
@@ -325,6 +334,9 @@ public:
// inserts provided event launcher in the region
void
insert_launcher( TEventLauncher *Launcher, scratch_data &Scratchpad );
// inserts provided memory cell in the region
void
insert_memorycell( TMemCell *Memorycell, scratch_data &Scratchpad );
// find a vehicle located nearest to specified point, within specified radius. reurns: located vehicle and distance
std::tuple<TDynamicObject *, float>
find_vehicle( glm::dvec3 const &Point, float const Radius, bool const Onlycontrolled, bool const Findbycoupler );

View File

@@ -759,4 +759,11 @@ basic_node::radius_() {
}
} // scene
namespace editor {
scene::basic_node const *Node { nullptr }; // temporary helper, currently selected scene node
} // editor
//---------------------------------------------------------------------------

View File

@@ -381,4 +381,10 @@ basic_node::visible() const {
} // scene
namespace editor {
extern scene::basic_node const *Node; // temporary helper, currently selected scene node
} // editor
//---------------------------------------------------------------------------

View File

@@ -450,10 +450,7 @@ state_manager::deserialize_node( cParser &Input, scene::scratch_data &Scratchpad
if( false == simulation::Memory.insert( memorycell ) ) {
ErrorLog( "Bad scenario: memory memorycell with duplicate name \"" + memorycell->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" );
}
/*
// TODO: implement this
simulation::Region.insert_memorycell( memorycell, Scratchpad );
*/
simulation::Region->insert_memorycell( memorycell, Scratchpad );
}
else if( nodedata.type == "eventlauncher" ) {

8
sky.h
View File

@@ -16,11 +16,13 @@ class TSky {
friend class opengl_renderer;
public:
TSky() = default;
void Init();
private:
TModel3d *mdCloud { nullptr };
public:
void Init();
};
//---------------------------------------------------------------------------

View File

@@ -467,7 +467,7 @@ float
sound_source::compute_combined_point() const {
return (
m_properties.pitch < 1.1f ?
m_properties.pitch <= 1.f ?
// most sounds use 0-1 value range, we clamp these to 0-99 to allow more intuitive sound definition in .mmd files
clamp( m_properties.pitch, 0.f, 0.99f ) :
std::max( 0.f, m_properties.pitch )

View File

@@ -16,7 +16,7 @@ public:
// methods:
void init();
// constructors:
cStars() = default;
// deconstructor:
// members:

23
sun.cpp
View File

@@ -20,25 +20,17 @@ cSun::~cSun() { gluDeleteQuadric( sunsphere ); }
void
cSun::init() {
m_observer.timezone = -1.0 * simulation::Time.zone_bias();
sunsphere = gluNewQuadric();
gluQuadricNormals( sunsphere, GLU_SMOOTH );
#ifdef _WIN32
TIME_ZONE_INFORMATION timezoneinfo; // TODO: timezone dependant on geographic location
::GetTimeZoneInformation( &timezoneinfo );
m_observer.timezone = -timezoneinfo.Bias / 60.0f;
#elif __linux__
timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
time_t local = mktime(localtime(&ts.tv_sec));
time_t utc = mktime(gmtime(&ts.tv_sec));
m_observer.timezone = (local - utc) / 3600.0f;
#endif
}
void
cSun::update() {
m_observer.temp = Global.AirTemperature;
move();
glm::vec3 position( 0.f, 0.f, -1.f );
position = glm::rotateX( position, glm::radians( static_cast<float>( m_body.elevref ) ) );
@@ -131,7 +123,7 @@ void cSun::move() {
if( m_observer.minute >= 0 ) { localtime.wMinute = m_observer.minute; }
if( m_observer.second >= 0 ) { localtime.wSecond = m_observer.second; }
double ut =
double localut =
localtime.wHour
+ localtime.wMinute / 60.0 // too low resolution, noticeable skips
+ localtime.wSecond / 3600.0; // good enough in normal circumstances
@@ -144,11 +136,10 @@ void cSun::move() {
+ 275 * localtime.wMonth / 9
+ localtime.wDay
- 730530
+ ( ut / 24.0 );
+ ( localut / 24.0 );
// Universal Coordinated (Greenwich standard) time
m_observer.utime = ut * 3600.0;
m_observer.utime = m_observer.utime / 3600.0 - m_observer.timezone;
m_observer.utime = localut - m_observer.timezone;
// perihelion longitude
m_body.phlong = 282.9404 + 4.70935e-5 * daynumber; // w
// orbit eccentricity

View File

@@ -266,6 +266,8 @@ ui_layer::update() {
"" ) );
}
EditorModeFlag = ( Global.iTextMode == GLFW_KEY_F11 );
switch( Global.iTextMode ) {
case( GLFW_KEY_F1 ) : {
@@ -689,19 +691,7 @@ ui_layer::update() {
uitextline3 =
"vehicles: " + to_string( Timer::subsystem.sim_dynamics.average(), 2 ) + " msec"
+ " update total: " + to_string( Timer::subsystem.sim_total.average(), 2 ) + " msec";
break;
}
case( GLFW_KEY_F10 ) : {
uitextline1 = "Press [Y] key to quit / Aby zakonczyc program, przycisnij klawisz [Y].";
break;
}
case( GLFW_KEY_F11 ): {
// scenario inspector
// current event queue
auto const time { Timer::GetTime() };
auto const *event { simulation::Events.begin() };
auto eventtableindex{ 0 };
@@ -727,6 +717,139 @@ ui_layer::update() {
break;
}
case( GLFW_KEY_F10 ) : {
uitextline1 = "Press [Y] key to quit / Aby zakonczyc program, przycisnij klawisz [Y].";
break;
}
case( GLFW_KEY_F11 ): {
// scenario inspector
auto const *node { editor::Node };
if( node == nullptr ) { break; }
uitextline1 =
"Node name: " + node->name()
+ "; location: [" + to_string( node->location().x, 2 ) + ", " + to_string( node->location().y, 2 ) + ", " + to_string( node->location().z, 2 ) + "]"
+ " (distance: " + to_string( glm::length( glm::dvec3{ node->location().x, 0.0, node->location().z } -glm::dvec3{ Global.pCameraPosition.x, 0.0, Global.pCameraPosition.z } ), 1 ) + " m)";
// subclass-specific data
// TBD, TODO: specialized data dump method in each node subclass, or data imports in the panel for provided subclass pointer?
if( typeid( *node ) == typeid( TAnimModel ) ) {
auto const *subnode = static_cast<TAnimModel const *>( node );
uitextline2 = "angle: " + to_string( clamp_circular( subnode->vAngle.y, 360.0 ), 2 ) + " deg";
uitextline2 += "; lights: ";
if( subnode->iNumLights > 0 ) {
uitextline2 += '[';
for( int lightidx = 0; lightidx < subnode->iNumLights; ++lightidx ) {
uitextline2 += to_string( subnode->lsLights[ lightidx ] );
if( lightidx < subnode->iNumLights - 1 ) {
uitextline2 += ", ";
}
}
uitextline2 += ']';
}
else {
uitextline2 += "none";
}
// 3d shape
auto modelfile { (
subnode->pModel ?
subnode->pModel->NameGet() :
"none" ) };
if( modelfile.find( szModelPath ) == 0 ) {
// don't include 'models/' in the path
modelfile.erase( 0, std::string{ szModelPath }.size() );
}
// texture
auto texturefile { (
subnode->Material()->replacable_skins[ 1 ] != null_handle ?
GfxRenderer.Material( subnode->Material()->replacable_skins[ 1 ] ).name :
"none" ) };
if( texturefile.find( szTexturePath ) == 0 ) {
// don't include 'textures/' in the path
texturefile.erase( 0, std::string{ szTexturePath }.size() );
}
uitextline3 = "mesh: " + modelfile;
uitextline4 = "skin: " + texturefile;
}
else if( typeid( *node ) == typeid( TTrack ) ) {
auto const *subnode = static_cast<TTrack const *>( node );
// basic attributes
uitextline2 =
"isolated: " + ( subnode->pIsolated ? subnode->pIsolated->asName : "none" )
+ "; velocity: " + to_string( subnode->SwitchExtension ? subnode->SwitchExtension->fVelocity : subnode->fVelocity )
+ "; width: " + to_string( subnode->fTrackWidth ) + " m"
+ "; friction: " + to_string( subnode->fFriction, 2 )
+ "; quality: " + to_string( subnode->iQualityFlag );
// textures
auto texturefile { (
subnode->m_material1 != null_handle ?
GfxRenderer.Material( subnode->m_material1 ).name :
"none" ) };
if( texturefile.find( szTexturePath ) == 0 ) {
texturefile.erase( 0, std::string{ szTexturePath }.size() );
}
auto texturefile2{ (
subnode->m_material2 != null_handle ?
GfxRenderer.Material( subnode->m_material2 ).name :
"none" ) };
if( texturefile2.find( szTexturePath ) == 0 ) {
texturefile2.erase( 0, std::string{ szTexturePath }.size() );
}
uitextline2 += "; skins: [" + texturefile + ", " + texturefile2 + "]";
// paths
uitextline3 = "paths: ";
for( auto const &path : subnode->m_paths ) {
uitextline3 +=
"["
+ to_string( path.points[ segment_data::point::start ].x, 3 ) + ", "
+ to_string( path.points[ segment_data::point::start ].y, 3 ) + ", "
+ to_string( path.points[ segment_data::point::start ].z, 3 ) + "]->"
+ "["
+ to_string( path.points[ segment_data::point::end ].x, 3 ) + ", "
+ to_string( path.points[ segment_data::point::end ].y, 3 ) + ", "
+ to_string( path.points[ segment_data::point::end ].z, 3 ) + "] ";
}
// events
std::vector< std::pair< std::string, TTrack::event_sequence const * > > const eventsequences {
{ "ev0", &subnode->m_events0 }, { "ev0all", &subnode->m_events0all },
{ "ev1", &subnode->m_events1 }, { "ev1all", &subnode->m_events1all },
{ "ev2", &subnode->m_events2 }, { "ev2all", &subnode->m_events2all } };
for( auto const &eventsequence : eventsequences ) {
if( eventsequence.second->empty() ) { continue; }
uitextline4 += eventsequence.first + ": [";
for( auto const &event : *( eventsequence.second ) ) {
if( uitextline4.back() != '[' ) {
uitextline4 += ", ";
}
if( event.second ) {
uitextline4 += event.second->asName;
}
}
uitextline4 += "] ";
}
}
else if( typeid( *node ) == typeid( TMemCell ) ) {
auto const *subnode = static_cast<TMemCell const *>( node );
uitextline2 =
"data: [" + subnode->Text() + "]"
+ " [" + to_string( subnode->Value1(), 2 ) + "]"
+ " [" + to_string( subnode->Value2(), 2 ) + "]";
uitextline3 = "track: " + ( subnode->asTrackName.empty() ? "none" : subnode->asTrackName );
}
break;
}
case( GLFW_KEY_F12 ) : {
// opcje włączenia i wyłączenia logowania
uitextline1 = "[0] Debugmode " + std::string( DebugModeFlag ? "(on)" : "(off)" );

View File

@@ -9,8 +9,8 @@ struct ui_panel {
struct text_line {
glm::vec4 color;
std::string data;
glm::vec4 color;
text_line( std::string const &Data, glm::vec4 const &Color):
data(Data), color(Color)
@@ -33,7 +33,7 @@ public:
// parameters:
// constructors:
ui_layer() = default;
// destructor:
~ui_layer();

View File

@@ -19,13 +19,14 @@ struct TTranscript {
class TTranscripts {
public:
// constructors
TTranscripts() = default;
// methods
void AddLine( std::string const &txt, float show, float hide, bool it );
// dodanie tekstów, długość dźwięku, czy istotne
void Add( std::string const &txt, bool background = false );
// usuwanie niepotrzebnych (ok. 10 razy na sekundę)
void Update();
// members
std::deque<TTranscript> aLines;

View File

@@ -1 +1 @@
#define VERSION_INFO "M7 16.06.2018/2, based on tmj ef5811e6"
#define VERSION_INFO "M7 27.06.2018, based on tmj 30e31cd"