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

Merge branch 'mover_in_c++' of https://github.com/tmj-fstate/maszyna into mover_in_c++

This commit is contained in:
VB
2017-03-07 20:52:46 +01:00
19 changed files with 159 additions and 525 deletions

View File

@@ -460,7 +460,7 @@ bool TAnimModel::Init(std::string const &asName, std::string const &asReplacable
iTexAlpha = 0x30300030; iTexAlpha = 0x30300030;
} }
// przezroczystych // przezroczystych
return (Init(TModelsManager::GetModel(asName.c_str()))); return (Init(TModelsManager::GetModel(asName)));
} }
bool TAnimModel::Load(cParser *parser, bool ter) bool TAnimModel::Load(cParser *parser, bool ter)

View File

@@ -1,17 +0,0 @@
/*
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 <vcl.h>
#pragma hdrstop
#include "Classes.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)

View File

@@ -2441,8 +2441,8 @@ bool TController::IncSpeed()
if (tsGuardSignal->GetStatus() & DSBSTATUS_PLAYING) // jeśli gada, to nie jedziemy if (tsGuardSignal->GetStatus() & DSBSTATUS_PLAYING) // jeśli gada, to nie jedziemy
return false; return false;
bool OK = true; bool OK = true;
if ((iDrivigFlags & moveDoorOpened) if ( ( iDrivigFlags & moveDoorOpened )
&&(mvOccupied->Vel > 0.1)) // added velocity threshold to prevent door shuffle on stop && ( VelDesired > 0.0 ) ) // to prevent door shuffle on stop
Doors(false); // zamykanie drzwi - tutaj wykonuje tylko AI (zmienia fActionTime) Doors(false); // zamykanie drzwi - tutaj wykonuje tylko AI (zmienia fActionTime)
if (fActionTime < 0.0) // gdy jest nakaz poczekać z jazdą, to nie ruszać if (fActionTime < 0.0) // gdy jest nakaz poczekać z jazdą, to nie ruszać
return false; return false;

View File

@@ -55,6 +55,25 @@ void TEventLauncher::Init()
{ {
} }
// encodes expected key in a short, where low byte represents the actual key,
// and the high byte holds modifiers: 0x1 = shift, 0x2 = ctrl, 0x4 = alt
int vk_to_glfw_key( int const Keycode ) {
#ifdef _WINDOWS
auto const code = VkKeyScan( Keycode );
char key = code & 0xff;
char shiftstate = ( code & 0xff00 ) >> 8;
if( (key >= 'A') && (key <= 'Z') ) {
key = GLFW_KEY_A + key - 'A';
}
else if( ( key >= '0' ) && ( key <= '9' ) ) {
key = GLFW_KEY_0 + key - '0';
}
return key + ( shiftstate << 8 );
#endif
}
bool TEventLauncher::Load(cParser *parser) bool TEventLauncher::Load(cParser *parser)
{ // wczytanie wyzwalacza zdarzeń { // wczytanie wyzwalacza zdarzeń
std::string token; std::string token;
@@ -66,10 +85,10 @@ bool TEventLauncher::Load(cParser *parser)
*parser >> token; *parser >> token;
if (token != "none") if (token != "none")
{ {
if (token.size() == 1) if( token.size() == 1 )
iKey = VkKeyScan(token[0]); // jeden znak jest konwertowany na kod klawisza iKey = vk_to_glfw_key( token[ 0 ] );
else else
iKey = stol_def(token,0); // a jak więcej, to jakby numer klawisza jest iKey = vk_to_glfw_key(stol_def( token, 0 )); // a jak więcej, to jakby numer klawisza jest
} }
parser->getTokens(); parser->getTokens();
*parser >> DeltaTime; *parser >> DeltaTime;
@@ -145,7 +164,20 @@ bool TEventLauncher::Render()
bool bCond = false; bool bCond = false;
if (iKey != 0) if (iKey != 0)
{ {
bCond = (Console::Pressed(iKey)); // czy klawisz wciśnięty if( Global::bActive ) {
// tylko jeśli okno jest aktywne
if( iKey > 255 ) {
// key and modifier
auto const modifier = ( iKey & 0xff00 ) >> 8;
bCond = ( Console::Pressed( iKey & 0xff ) )
&& ( modifier & 1 ? Global::shiftState : true )
&& ( modifier & 2 ? Global::ctrlState : true );
}
else {
// just key
bCond = ( Console::Pressed( iKey & 0xff ) ); // czy klawisz wciśnięty
}
}
} }
if (DeltaTime > 0) if (DeltaTime > 0)
{ {

View File

@@ -1,52 +0,0 @@
/*
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 <vcl.h>
#pragma hdrstop
#include "Forth.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
/* Ra: Forth jest prostym językiem programowania, funkcjonującym na dosyć
niskim poziomie. Może być zarówno interpretowany jak i kompilowany, co
pozwala szybko działać skompilowanym programom, jak również wykonywać
polecenia wprowadzane z klawiatury. Za pomocą zdefiniowanych kompilatorów
można definiować nowe funkcje, można również tworzyć nowe struktury jezyka,
np. wykraczające poza dotychczasową składnię. Prostota i wydajność są okupione
nieco specyficzną składnią, wynikającą z użycia stosu do obliczeń (tzw. odwrotna
notacja polska).
Forth ma być używany jako:
1. Alternatywna postać eventów. Dotychczasowe eventy w sceneriach mogą być
traktowane jako funkcje języka Forth. Jednocześnie można uzyskać uelastycznienie
składni, poprzez np. połączenie w jednym wpisie różnych typów eventów wraz z
dodaniem warunków dostępnych tylko dla Multiple. Również można będzie używać
wyrażeń języka Forth, czyli dokonywać obliczeń.
2. Jako docelowa postać schematów obwodów Ladder Diagram. Można zrobić tak, by
program źródłowy w Forth (przy pewnych ograniczeniach) był wyświetlany graficznie
jako Ladder Diagram. Jednocześnie graficzne modyfikacje schematu można by
przełożyć na postać tekstową Forth i skompilować na kod niskiego poziomu.
3. Jako algorytm funkcjonowania AI, możliwy do zaprogramowania na zewnątzr EXE.
Każdy użytkownik będzie mógł swój własny styl jazdy.
4. Jako algorytm sterowania ruchem (zależności na stacji).
5. Jako AI stacji, zarządzające ruchem na stacji zależnie w czasie rzeczywistym.
Względem pierwotnego języka Forth, użyty tutaj będzie miał pewne odstępstwa:
1. Operacje na liczbach czterobajtowych float. Należy we własnym zakresie dbać
o zgodność użytych funkcji z typem argumentu na stosie.
2. Jedynym typem całkowitym jest czterobajtowy int.
3. Do wyszukiwania obiektów w scenerii po nazwie (torów, eventów), używane jest
drzewo zamiast listy.
Wpisy w scenerii, przetwarzane jako komendy Forth, nie mogą używać średnika jako
separatora słów. Uniemożliwia to używanie średnika jako słowa.
*/

17
Forth.h
View File

@@ -1,17 +0,0 @@
/*
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/.
*/
#ifndef ForthH
#define ForthH
//---------------------------------------------------------------------------
class Forth
{ // klasa obsługi języka
};
#endif

127
Geom.cpp
View File

@@ -1,127 +0,0 @@
/*
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 "system.hpp"
#include "classes.hpp"
#include <gl/gl.h>
#include <gl/glu.h>
#include "GL/glut.h"
#pragma hdrstop
#include "Texture.h"
#include "usefull.h"
#include "Globals.h"
#include "Geom.h"
TGeometry::TGeometry()
{
}
TGeometry::~TGeometry()
{
}
bool TGeometry::Init()
{
}
vector3 TGeometry::Load(TQueryParserComp *Parser)
{
str = Parser->GetNextSymbol().LowerCase();
tmp->TextureID = TTexturesManager::GetTextureID(str.c_str());
i = 0;
do
{
tf = Parser->GetNextSymbol().ToDouble();
TempVerts[i].Point.x = tf;
tf = Parser->GetNextSymbol().ToDouble();
TempVerts[i].Point.y = tf;
tf = Parser->GetNextSymbol().ToDouble();
TempVerts[i].Point.z = tf;
tf = Parser->GetNextSymbol().ToDouble();
TempVerts[i].Normal.x = tf;
tf = Parser->GetNextSymbol().ToDouble();
TempVerts[i].Normal.y = tf;
tf = Parser->GetNextSymbol().ToDouble();
TempVerts[i].Normal.z = tf;
str = Parser->GetNextSymbol().LowerCase();
if (str == "x")
TempVerts[i].tu = (TempVerts[i].Point.x + Parser->GetNextSymbol().ToDouble()) /
Parser->GetNextSymbol().ToDouble();
else if (str == "y")
TempVerts[i].tu = (TempVerts[i].Point.y + Parser->GetNextSymbol().ToDouble()) /
Parser->GetNextSymbol().ToDouble();
else if (str == "z")
TempVerts[i].tu = (TempVerts[i].Point.z + Parser->GetNextSymbol().ToDouble()) /
Parser->GetNextSymbol().ToDouble();
else
TempVerts[i].tu = str.ToDouble();
;
str = Parser->GetNextSymbol().LowerCase();
if (str == "x")
TempVerts[i].tv = (TempVerts[i].Point.x + Parser->GetNextSymbol().ToDouble()) /
Parser->GetNextSymbol().ToDouble();
else if (str == "y")
TempVerts[i].tv = (TempVerts[i].Point.y + Parser->GetNextSymbol().ToDouble()) /
Parser->GetNextSymbol().ToDouble();
else if (str == "z")
TempVerts[i].tv = (TempVerts[i].Point.z + Parser->GetNextSymbol().ToDouble()) /
Parser->GetNextSymbol().ToDouble();
else
TempVerts[i].tv = str.ToDouble();
;
// tf= Parser->GetNextSymbol().ToDouble();
// TempVerts[i].tu= tf;
// tf= Parser->GetNextSymbol().ToDouble();
// TempVerts[i].tv= tf;
TempVerts[i].Point.RotateZ(aRotate.z / 180 * M_PI);
TempVerts[i].Point.RotateX(aRotate.x / 180 * M_PI);
TempVerts[i].Point.RotateY(aRotate.y / 180 * M_PI);
TempVerts[i].Normal.RotateZ(aRotate.z / 180 * M_PI);
TempVerts[i].Normal.RotateX(aRotate.x / 180 * M_PI);
TempVerts[i].Normal.RotateY(aRotate.y / 180 * M_PI);
TempVerts[i].Point += pOrigin;
tmp->pCenter += TempVerts[i].Point;
i++;
// }
} while (Parser->GetNextSymbol().LowerCase() != "endtri");
nv = i;
tmp->Init(nv);
tmp->pCenter /= (nv > 0 ? nv : 1);
// memcpy(tmp->Vertices,TempVerts,nv*sizeof(TGroundVertex));
r = 0;
for (int i = 0; i < nv; i++)
{
tmp->Vertices[i] = TempVerts[i];
tf = SquareMagnitude(tmp->Vertices[i].Point - tmp->pCenter);
if (tf > r)
r = tf;
}
// tmp->fSquareRadius= 2000*2000+r;
tmp->fSquareRadius += r;
}
bool TGeometry::Render()
{
}
//---------------------------------------------------------------------------
#pragma package(smart_init)

46
Geom.h
View File

@@ -1,46 +0,0 @@
/*
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/.
*/
#ifndef GeomH
#define GeomH
#include <gl/gl.h>
#include "QueryParserComp.hpp"
struct TGeomVertex
{
vector3 Point;
vector3 Normal;
double tu, tv;
};
class TGeometry
{
private:
GLuint iType;
union
{
int iNumVerts;
int iNumPts;
};
GLuint TextureID;
TMaterialColor Ambient;
TMaterialColor Diffuse;
TMaterialColor Specular;
public:
TGeometry();
~TGeometry();
bool Init();
vector3 Load(TQueryParserComp *Parser);
bool Render();
};
//---------------------------------------------------------------------------
#endif

View File

@@ -88,8 +88,8 @@ TTranscripts Global::tranTexts; // obiekt obsługujący stenogramy dźwięków n
vector3 Global::pCameraPosition; vector3 Global::pCameraPosition;
double Global::pCameraRotation; double Global::pCameraRotation;
double Global::pCameraRotationDeg; double Global::pCameraRotationDeg;
vector3 Global::pFreeCameraInit[10]; std::vector<vector3> Global::FreeCameraInit;
vector3 Global::pFreeCameraInitAngle[10]; std::vector<vector3> Global::FreeCameraInitAngle;
double Global::fFogStart = 1700; double Global::fFogStart = 1700;
double Global::fFogEnd = 2000; double Global::fFogEnd = 2000;
float Global::Background[3] = {0.2f, 0.4f, 0.33f}; float Global::Background[3] = {0.2f, 0.4f, 0.33f};
@@ -238,11 +238,15 @@ std::string Global::GetNextSymbol()
void Global::LoadIniFile(std::string asFileName) void Global::LoadIniFile(std::string asFileName)
{ {
/*
for (int i = 0; i < 10; ++i) for (int i = 0; i < 10; ++i)
{ // zerowanie pozycji kamer { // zerowanie pozycji kamer
pFreeCameraInit[i] = vector3(0, 0, 0); // współrzędne w scenerii pFreeCameraInit[i] = vector3(0, 0, 0); // współrzędne w scenerii
pFreeCameraInitAngle[i] = vector3(0, 0, 0); // kąty obrotu w radianach pFreeCameraInitAngle[i] = vector3(0, 0, 0); // kąty obrotu w radianach
} }
*/
FreeCameraInit.resize( 10 );
FreeCameraInitAngle.resize( 10 );
cParser parser(asFileName, cParser::buffer_FILE); cParser parser(asFileName, cParser::buffer_FILE);
ConfigParse(parser); ConfigParse(parser);
}; };
@@ -320,8 +324,10 @@ void Global::ConfigParse(cParser &Parser)
Parser.getTokens(); Parser.getTokens();
Parser >> Global::bFreeFly; Parser >> Global::bFreeFly;
Parser.getTokens(3, false); Parser.getTokens(3, false);
Parser >> Global::pFreeCameraInit[0].x, Global::pFreeCameraInit[0].y, Parser >>
Global::pFreeCameraInit[0].z; Global::FreeCameraInit[0].x,
Global::FreeCameraInit[0].y,
Global::FreeCameraInit[0].z;
} }
else if (token == "wireframe") else if (token == "wireframe")
{ {

View File

@@ -13,7 +13,7 @@ http://mozilla.org/MPL/2.0/.
#include <Windows.h> #include <Windows.h>
#include "renderer.h" #include "renderer.h"
#include <GLFW/glfw3.h> #include <GLFW/glfw3.h>
#include "GL/glew.h" #include <GL/glew.h>
#include "dumb3d.h" #include "dumb3d.h"
// definicje klawiszy // definicje klawiszy
@@ -170,8 +170,8 @@ class Global
static double static double
pCameraRotation; // kierunek bezwzględny kamery w świecie: 0=północ, 90°=zachód (-azymut) pCameraRotation; // kierunek bezwzględny kamery w świecie: 0=północ, 90°=zachód (-azymut)
static double pCameraRotationDeg; // w stopniach, dla animacji billboard static double pCameraRotationDeg; // w stopniach, dla animacji billboard
static Math3D::vector3 pFreeCameraInit[10]; // pozycje kamery static std::vector<Math3D::vector3> FreeCameraInit; // pozycje kamery
static Math3D::vector3 pFreeCameraInitAngle[10]; static std::vector<Math3D::vector3> FreeCameraInitAngle;
static int iWindowWidth; static int iWindowWidth;
static int iWindowHeight; static int iWindowHeight;
static float fDistanceFactor; static float fDistanceFactor;

View File

@@ -1977,7 +1977,8 @@ TGroundNode * TGround::AddGroundNode(cParser *parser)
if( tmp->DynamicObject->MoverParameters->LightPowerSource.SourceType != TPowerSource::NotDefined ) { if( tmp->DynamicObject->MoverParameters->LightPowerSource.SourceType != TPowerSource::NotDefined ) {
// if the vehicle has defined light source, it can (potentially) emit light, so add it to the light array // if the vehicle has defined light source, it can (potentially) emit light, so add it to the light array
*/ */
if( tmp->DynamicObject->MoverParameters->SecuritySystem.SystemType != 0 ) { if( ( tmp != nullptr )
&& ( tmp->DynamicObject->MoverParameters->SecuritySystem.SystemType != 0 ) ) {
// we check for presence of security system, as a way to determine whether the vehicle is a controllable engine // we check for presence of security system, as a way to determine whether the vehicle is a controllable engine
// NOTE: this isn't 100% precise, e.g. middle EZT module comes with security system, while it has no lights // NOTE: this isn't 100% precise, e.g. middle EZT module comes with security system, while it has no lights
m_lights.insert( tmp->DynamicObject ); m_lights.insert( tmp->DynamicObject );
@@ -2955,11 +2956,12 @@ bool TGround::Init(std::string File)
into = ++Global::iCameraLast; into = ++Global::iCameraLast;
if ((into >= 0) && (into < 10)) if ((into >= 0) && (into < 10))
{ // przepisanie do odpowiedniego miejsca w tabelce { // przepisanie do odpowiedniego miejsca w tabelce
Global::pFreeCameraInit[into] = xyz; Global::FreeCameraInit[ into ] = xyz;
abc.x = DegToRad(abc.x); Global::FreeCameraInitAngle[ into ] =
abc.y = DegToRad(abc.y); Math3D::vector3(
abc.z = DegToRad(abc.z); DegToRad( abc.x ),
Global::pFreeCameraInitAngle[into] = abc; DegToRad( abc.y ),
DegToRad( abc.z ) );
Global::iCameraLast = into; // numer ostatniej Global::iCameraLast = into; // numer ostatniej
} }
} }
@@ -4002,6 +4004,7 @@ bool TGround::EventConditon(TEvent *e)
{ // sprawdzenie spelnienia warunków dla eventu { // sprawdzenie spelnienia warunków dla eventu
if (e->iFlags <= update_only) if (e->iFlags <= update_only)
return true; // bezwarunkowo return true; // bezwarunkowo
if (e->iFlags & conditional_trackoccupied) if (e->iFlags & conditional_trackoccupied)
return (!e->Params[9].asTrack->IsEmpty()); return (!e->Params[9].asTrack->IsEmpty());
else if (e->iFlags & conditional_trackfree) else if (e->iFlags & conditional_trackfree)
@@ -4015,6 +4018,11 @@ bool TGround::EventConditon(TEvent *e)
} }
else if (e->iFlags & conditional_memcompare) else if (e->iFlags & conditional_memcompare)
{ // porównanie wartości { // porównanie wartości
if( nullptr == e->Params[9].asMemCell ) {
ErrorLog( "Event " + e->asName + " trying conditional_memcompare with nonexistent memcell" );
return true; // though this is technically error, we report success to maintain backward compatibility
}
if (tmpEvent->Params[9].asMemCell->Compare(e->Params[10].asText, e->Params[11].asdouble, if (tmpEvent->Params[9].asMemCell->Compare(e->Params[10].asText, e->Params[11].asdouble,
e->Params[12].asdouble, e->iFlags)) e->Params[12].asdouble, e->iFlags))
{ //logowanie spełnionych warunków { //logowanie spełnionych warunków
@@ -5084,7 +5092,7 @@ void TGround::WyslijString(const std::string &t, int n)
r.cString[0] = char(i); r.cString[0] = char(i);
strcpy(r.cString + 1, t.c_str()); // z zerem kończącym strcpy(r.cString + 1, t.c_str()); // z zerem kończącym
COPYDATASTRUCT cData; COPYDATASTRUCT cData;
cData.dwData = 'EU07'; // sygnatura cData.dwData = MAKE_ID4( 'E', 'U', '0', '7' ); // sygnatura
cData.cbData = (DWORD)(10 + i); // 8+licznik i zero kończące cData.cbData = (DWORD)(10 + i); // 8+licznik i zero kończące
cData.lpData = &r; cData.lpData = &r;
Navigate( "TEU07SRK", WM_COPYDATA, (WPARAM)glfwGetWin32Window( Global::window ), (LPARAM)&cData ); Navigate( "TEU07SRK", WM_COPYDATA, (WPARAM)glfwGetWin32Window( Global::window ), (LPARAM)&cData );
@@ -5163,7 +5171,7 @@ void TGround::WyslijNamiary(TGroundNode *t)
r.cString[i] = char(j); // na końcu nazwa, żeby jakoś zidentyfikować r.cString[i] = char(j); // na końcu nazwa, żeby jakoś zidentyfikować
strcpy(r.cString + i + 1, t->asName.c_str()); // zakończony zerem strcpy(r.cString + i + 1, t->asName.c_str()); // zakończony zerem
COPYDATASTRUCT cData; COPYDATASTRUCT cData;
cData.dwData = 'EU07'; // sygnatura cData.dwData = MAKE_ID4( 'E', 'U', '0', '7' ); // sygnatura
cData.cbData = (DWORD)(10 + i + j); // 8+licznik i zero kończące cData.cbData = (DWORD)(10 + i + j); // 8+licznik i zero kończące
cData.lpData = &r; cData.lpData = &r;
// WriteLog("Ramka gotowa"); // WriteLog("Ramka gotowa");

View File

@@ -3814,10 +3814,13 @@ double TMoverParameters::TractionForce(double dt)
} }
eAngle += enrot * dt; eAngle += enrot * dt;
if( eAngle > M_PI * 2.0 )
eAngle = std::fmod( eAngle, M_PI * 2.0 );
/*
while (eAngle > M_PI * 2.0) while (eAngle > M_PI * 2.0)
// eAngle = Pirazy2 - eAngle; <- ABu: a nie czasem tak, jak nizej? // eAngle = Pirazy2 - eAngle; <- ABu: a nie czasem tak, jak nizej?
eAngle -= M_PI * 2.0; eAngle -= M_PI * 2.0;
*/
// hunter-091012: przeniesione z if ActiveDir<>0 (zeby po zejsciu z kierunku dalej spadala // hunter-091012: przeniesione z if ActiveDir<>0 (zeby po zejsciu z kierunku dalej spadala
// predkosc wentylatorow) // predkosc wentylatorow)
if (EngineType == ElectricSeriesMotor) if (EngineType == ElectricSeriesMotor)

View File

@@ -90,7 +90,7 @@ double PFVa( double PH, double PL, double const S, double LIM, double const DP )
LIM = LIM + 1; LIM = LIM + 1;
PH = PH + 1; // wyzsze cisnienie absolutne PH = PH + 1; // wyzsze cisnienie absolutne
PL = PL + 1; // nizsze cisnienie absolutne PL = PL + 1; // nizsze cisnienie absolutne
double sg = PL / PH; // bezwymiarowy stosunek cisnien double sg = std::min( 1.0, PL / PH ); // bezwymiarowy stosunek cisnien. NOTE: sg is capped at 1 to prevent calculations from going awry. TODO, TBD: log these as errors?
double FM = PH * 197 * S; // najwyzszy mozliwy przeplyw, wraz z kierunkiem double FM = PH * 197 * S; // najwyzszy mozliwy przeplyw, wraz z kierunkiem
if ((LIM - PL) < DP) if ((LIM - PL) < DP)
FM = FM * (LIM - PL) / DP; // jesli jestesmy przy nastawieniu, to zawor sie przymyka FM = FM * (LIM - PL) / DP; // jesli jestesmy przy nastawieniu, to zawor sie przymyka

View File

@@ -2015,7 +2015,8 @@ void TSubModel::BinInit(TSubModel *s, float4x4 *m, float8 *v,
if (pTexture.find_last_of("/\\") == std::string::npos) if (pTexture.find_last_of("/\\") == std::string::npos)
pTexture.insert(0, Global::asCurrentTexturePath); pTexture.insert(0, Global::asCurrentTexturePath);
TextureID = GfxRenderer.GetTextureId(pTexture, szTexturePath); TextureID = GfxRenderer.GetTextureId(pTexture, szTexturePath);
} iFlags |= (GfxRenderer.Texture(TextureID).has_alpha ? 0x20 : 0x10); // 0x10-nieprzezroczysta, 0x20-przezroczysta
}
else else
TextureID = iTexture; TextureID = iTexture;
b_aAnim = b_Anim; // skopiowanie animacji do drugiego cyklu b_aAnim = b_Anim; // skopiowanie animacji do drugiego cyklu
@@ -2029,7 +2030,7 @@ void TSubModel::BinInit(TSubModel *s, float4x4 *m, float8 *v,
void TModel3d::LoadFromBinFile(std::string const &FileName, bool dynamic) void TModel3d::LoadFromBinFile(std::string const &FileName, bool dynamic)
{ // wczytanie modelu z pliku binarnego { // wczytanie modelu z pliku binarnego
WriteLog("loading e3d model " + FileName + " .."); WriteLog("Loading binary format 3d model data from \"" + FileName + "\"...");
std::ifstream file(FileName, std::ios::binary); std::ifstream file(FileName, std::ios::binary);
@@ -2042,12 +2043,12 @@ void TModel3d::LoadFromBinFile(std::string const &FileName, bool dynamic)
deserialize(file, size, dynamic); deserialize(file, size, dynamic);
file.close(); file.close();
WriteLog("..done."); WriteLog("Finished loading 3d model data from \"" + FileName + "\"");
}; };
void TModel3d::LoadFromTextFile(std::string const &FileName, bool dynamic) void TModel3d::LoadFromTextFile(std::string const &FileName, bool dynamic)
{ // wczytanie submodelu z pliku tekstowego { // wczytanie submodelu z pliku tekstowego
WriteLog("Loading - text model: " + FileName); WriteLog("Loading text format 3d model data from \"" + FileName + "\"...");
iFlags |= 0x0200; // wczytano z pliku tekstowego (właścicielami tablic są submodle) iFlags |= 0x0200; // wczytano z pliku tekstowego (właścicielami tablic są submodle)
cParser parser(FileName, cParser::buffer_FILE); // Ra: tu powinno być "models\\"... cParser parser(FileName, cParser::buffer_FILE); // Ra: tu powinno być "models\\"...
TSubModel *SubModel; TSubModel *SubModel;

View File

@@ -1,151 +0,0 @@
// Borland C++ Builder
// Copyright (c) 1995, 1999 by Borland International
// All rights reserved
// (DO NOT EDIT: machine generated header) 'QueryParserComp.pas' rev: 5.00
#ifndef QueryParserCompHPP
#define QueryParserCompHPP
#pragma delphiheader begin
#pragma option push -w-
#pragma option push -Vx
#include <SysUtils.hpp> // Pascal unit
#include <Classes.hpp> // Pascal unit
#include <SysInit.hpp> // Pascal unit
#include <System.hpp> // Pascal unit
//-- user supplied -----------------------------------------------------------
namespace Queryparsercomp
{
//-- type declarations -------------------------------------------------------
#pragma option push -b-
enum TTokenType { ttString, ttSymbol, ttComment, ttDelimiter, ttSpecialChar, ttStatementDelimiter, ttCommentedSymbol,
ttCommentDelimiter };
#pragma option pop
typedef Set<char, 0, 255> TSetOfChar;
typedef AnsiString TComment[2];
#pragma option push -b-
enum TCharacterType { ctSymbol, ctBeginComment, ctEndComment, ctDelimiter, ctString, ctSpecialChar }
;
#pragma option pop
#pragma option push -b-
enum QueryParserComp__1 { cmt1, cmt2, cmt3 };
#pragma option pop
typedef Set<QueryParserComp__1, cmt1, cmt3> TCommentType;
typedef AnsiString QueryParserComp__2[3][2];
typedef void __fastcall (__closure *TEndOfStatement)(System::TObject* Sender, AnsiString SQLStatement
);
class DELPHICLASS TQueryParserComp;
class PASCALIMPLEMENTATION TQueryParserComp : public Classes::TComponent
{
typedef Classes::TComponent inherited;
private:
Classes::TStringStream* FStream;
bool FEOF;
AnsiString FToken;
TTokenType FTokenType;
bool FComment;
bool FString;
bool FWasString;
TCommentType FCommentType;
AnsiString FStringDelimiters;
AnsiString FLastStringDelimiterFound;
int FSymbolsCount;
AnsiString FSpecialCharacters;
bool FRemoveStrDelimiter;
AnsiString FStringToParse;
int FGoPosition;
TEndOfStatement FOnStatementDelimiter;
bool FCountFromStatement;
Classes::TStringList* FStatementDelimiters;
char FStringDelimiter;
bool FGenerateOnStmtDelimiter;
void __fastcall Init(void);
void __fastcall SetStringToParse(AnsiString AStringToParse);
bool __fastcall StatementDelimiter(void);
bool __fastcall CheckForBeginComment(void);
bool __fastcall CheckForEndComment(char Character);
TCharacterType __fastcall CharacterType(char Character);
bool __fastcall CheckCharcterType(char Character);
bool __fastcall StringDelimiter(char Character);
bool __fastcall SpecialCharacter(char Character);
void __fastcall RemoveStringDelimiter(AnsiString &Source);
void __fastcall SetDelimiterType(AnsiString Source);
void __fastcall SetToken(void);
void __fastcall SetSD(Classes::TStringList* ASD);
void __fastcall SetSpecialCharacters(AnsiString ASpecialCharacters);
void __fastcall SetStringDelimiters(AnsiString AStringDelimiters);
protected:
DYNAMIC void __fastcall DoStatementDelimiter(void);
public:
__fastcall virtual TQueryParserComp(Classes::TComponent* AOwner);
__fastcall virtual ~TQueryParserComp(void);
void __fastcall LoadStringToParse(AnsiString FileName);
void __fastcall First(void);
void __fastcall FirstToken(void);
void __fastcall NextToken(void);
AnsiString __fastcall GetNextSymbol();
__property bool EndOfFile = {read=FEOF, nodefault};
__property bool Comment = {read=FComment, nodefault};
__property AnsiString Token = {read=FToken};
__property TTokenType TokenType = {read=FTokenType, nodefault};
__property char CurrentStringDelimiter = {read=FStringDelimiter, nodefault};
__property int SymbolsCount = {read=FSymbolsCount, default=0};
__property Classes::TStringStream* StringStream = {read=FStream};
__published:
__property bool IsEOFStmtDelimiter = {read=FGenerateOnStmtDelimiter, write=FGenerateOnStmtDelimiter
, nodefault};
__property AnsiString StringDelimiters = {read=FStringDelimiters, write=SetStringDelimiters};
__property AnsiString SpecialCharacters = {read=FSpecialCharacters, write=SetSpecialCharacters};
__property bool RemoveStrDelimiter = {read=FRemoveStrDelimiter, write=FRemoveStrDelimiter, nodefault
};
__property bool CountFromStatement = {read=FCountFromStatement, write=FCountFromStatement, nodefault
};
__property AnsiString TextToParse = {read=FStringToParse, write=SetStringToParse};
__property Classes::TStringList* StatementDelimiters = {read=FStatementDelimiters, write=SetSD};
__property TEndOfStatement OnStatementDelimiter = {read=FOnStatementDelimiter, write=FOnStatementDelimiter
};
};
//-- var, const, procedure ---------------------------------------------------
extern PACKAGE System::ResourceString _sTextNotSet;
#define Queryparsercomp_sTextNotSet System::LoadResourceString(&Queryparsercomp::_sTextNotSet)
extern PACKAGE System::ResourceString _sIllegalSpecialChar;
#define Queryparsercomp_sIllegalSpecialChar System::LoadResourceString(&Queryparsercomp::_sIllegalSpecialChar)
extern PACKAGE System::ResourceString _sIllegalStringChar;
#define Queryparsercomp_sIllegalStringChar System::LoadResourceString(&Queryparsercomp::_sIllegalStringChar)
static const char CR = '\xd';
static const char LF = '\xa';
static const char TAB = '\x9';
#define CRLF "\r\n"
extern PACKAGE TSetOfChar Delimiters;
extern PACKAGE AnsiString Comments[3][2];
extern PACKAGE void __fastcall Register(void);
} /* namespace Queryparsercomp */
#if !defined(NO_IMPLICIT_NAMESPACE_USE)
using namespace Queryparsercomp;
#endif
#pragma option pop // -w-
#pragma option pop // -Vx
#pragma delphiheader end.
//-- end unit ----------------------------------------------------------------
#endif // QueryParserComp

151
Train.cpp
View File

@@ -2382,7 +2382,7 @@ if
{ {
// McZapkie: poruszanie sie po kabinie, w updatemechpos zawarte sa wiezy // McZapkie: poruszanie sie po kabinie, w updatemechpos zawarte sa wiezy
auto step = 1.5f; auto step = 1.0f;
auto const camerayaw = Global::pCamera->Yaw; auto const camerayaw = Global::pCamera->Yaw;
Math3D::vector3 direction( 0.0f, 0.0f, step ); Math3D::vector3 direction( 0.0f, 0.0f, step );
direction.RotateY( camerayaw ); direction.RotateY( camerayaw );
@@ -2499,6 +2499,7 @@ void TTrain::OnKeyUp(int cKey)
} }
}; };
// cab movement update, fixed step part
void TTrain::UpdateMechPosition(double dt) void TTrain::UpdateMechPosition(double dt)
{ // Ra: mechanik powinien być { // Ra: mechanik powinien być
// telepany niezależnie od pozycji // telepany niezależnie od pozycji
@@ -2512,123 +2513,111 @@ void TTrain::UpdateMechPosition(double dt)
// - na postoju horyzont prosto, kabina skosem // - na postoju horyzont prosto, kabina skosem
// - przy szybkiej jeździe kabina prosto, horyzont pochylony // - przy szybkiej jeździe kabina prosto, horyzont pochylony
vector3 pNewMechPosition;
Math3D::vector3 shake; Math3D::vector3 shake;
// McZapkie: najpierw policzę pozycję w/m kabiny // McZapkie: najpierw policzę pozycję w/m kabiny
// ABu: rzucamy kabina tylko przy duzym FPS! // ABu: rzucamy kabina tylko przy duzym FPS!
// Mala histereza, zeby bez przerwy nie przelaczalo przy FPS~17 // Mala histereza, zeby bez przerwy nie przelaczalo przy FPS~17
// Granice mozna ustalic doswiadczalnie. Ja proponuje 14:20 // Granice mozna ustalic doswiadczalnie. Ja proponuje 14:20
double const iVel = std::min(DynamicObject->GetVelocity(), 150.0); double const iVel = std::min( DynamicObject->GetVelocity(), 150.0 );
if (!Global::iSlowMotion // musi być pełna prędkość if( !Global::iSlowMotion // musi być pełna prędkość
&& (pMechOffset.y < 4.0)) // Ra 15-01: przy oglądaniu pantografu bujanie przeszkadza && ( pMechOffset.y < 4.0 ) ) // Ra 15-01: przy oglądaniu pantografu bujanie przeszkadza
{ {
if( iVel > 0.0 ) { if( iVel > 0.5 ) {
// acceleration-driven base shake // acceleration-driven base shake
shake += 1.25 * MechSpring.ComputateForces( shake += 1.25 * MechSpring.ComputateForces(
vector3( vector3(
-mvControlled->AccN * dt * 5.0, // highlight side sway -mvControlled->AccN * dt * 5.0, // highlight side sway
mvControlled->AccV * dt, mvControlled->AccV * dt,
-mvControlled->AccS * dt * 1.25 ), // accent acceleration/deceleration -mvControlled->AccS * dt * 1.25 ), // accent acceleration/deceleration
pMechShake ); pMechShake );
if( Random( iVel ) > 25.0 ) { if( Random( iVel ) > 25.0 ) {
// extra shake at increased velocity // extra shake at increased velocity
shake += MechSpring.ComputateForces( shake += MechSpring.ComputateForces(
vector3( vector3(
( Random( iVel * 2 ) - iVel ) / ( ( iVel * 2 ) * 4 ) * fMechSpringX, ( Random( iVel * 2 ) - iVel ) / ( ( iVel * 2 ) * 4 ) * fMechSpringX,
( Random( iVel * 2 ) - iVel ) / ( ( iVel * 2 ) * 4 ) * fMechSpringY, ( Random( iVel * 2 ) - iVel ) / ( ( iVel * 2 ) * 4 ) * fMechSpringY,
( Random( iVel * 2 ) - iVel ) / ( ( iVel * 2 ) * 4 ) * fMechSpringZ ), ( Random( iVel * 2 ) - iVel ) / ( ( iVel * 2 ) * 4 ) * fMechSpringZ )
* 1.25,
pMechShake ); pMechShake );
// * (( 200 - DynamicObject->MyTrack->iQualityFlag ) * 0.0075 ); // scale to 75-150% based on track quality // * (( 200 - DynamicObject->MyTrack->iQualityFlag ) * 0.0075 ); // scale to 75-150% based on track quality
} }
// shake *= 1.25; // shake *= 0.85;
} }
vMechVelocity -= (shake + vMechVelocity * 100) * (fMechSpringX + fMechSpringY + fMechSpringZ) / (200); vMechVelocity -= ( shake + vMechVelocity * 100 ) * ( fMechSpringX + fMechSpringY + fMechSpringZ ) / ( 200 );
// vMechVelocity -= vMechVelocity * iVel * dt; // shake *= 0.95 * dt; // shake damping
// shake *= 0.95 * dt; // shake damping
// McZapkie: // McZapkie:
pMechShake += vMechVelocity * dt; pMechShake += vMechVelocity * dt;
// Ra 2015-01: dotychczasowe rzucanie // Ra 2015-01: dotychczasowe rzucanie
pMechOffset += vMechMovement * dt; pMechOffset += vMechMovement * dt;
if ((pMechShake.y > fMechMaxSpring) || (pMechShake.y < -fMechMaxSpring)) if( ( pMechShake.y > fMechMaxSpring ) || ( pMechShake.y < -fMechMaxSpring ) )
vMechVelocity.y = -vMechVelocity.y; vMechVelocity.y = -vMechVelocity.y;
// ABu011104: 5*pMechShake.y, zeby ladnie pudlem rzucalo :) // ABu011104: 5*pMechShake.y, zeby ladnie pudlem rzucalo :)
pNewMechPosition = pMechOffset + vector3(1.5 * pMechShake.x, 2.0 * pMechShake.y, 1.5 * pMechShake.z); pMechPosition = pMechOffset + vector3( 1.5 * pMechShake.x, 2.0 * pMechShake.y, 1.5 * pMechShake.z );
// vMechMovement = 0.5 * vMechMovement; vMechMovement = 0.5 * vMechMovement;
} }
else else { // hamowanie rzucania przy spadku FPS
{ // hamowanie rzucania przy spadku FPS pMechShake -= pMechShake * std::min( dt, 1.0 ); // po tym chyba potrafią zostać jakieś ułamki, które powodują zjazd
pMechShake -= pMechShake * std::min(dt, 1.0); // po tym chyba potrafią zostać jakieś ułamki, które powodują zjazd
pMechOffset += vMechMovement * dt; pMechOffset += vMechMovement * dt;
vMechVelocity.y -= vMechVelocity.y * 50.0 * dt; vMechVelocity.y = 0.5 * vMechVelocity.y;
pNewMechPosition = pMechOffset + vector3(pMechShake.x, 5 * pMechShake.y, pMechShake.z); pMechPosition = pMechOffset + vector3( pMechShake.x, 5 * pMechShake.y, pMechShake.z );
// vMechMovement = 0.5 * vMechMovement; vMechMovement = 0.5 * vMechMovement;
} }
// numer kabiny (-1: kabina B) // numer kabiny (-1: kabina B)
if (DynamicObject->Mechanik) // może nie być? if( DynamicObject->Mechanik ) // może nie być?
if (DynamicObject->Mechanik->AIControllFlag) // jeśli prowadzi AI if( DynamicObject->Mechanik->AIControllFlag ) // jeśli prowadzi AI
{ // Ra: przesiadka, jeśli AI zmieniło kabinę (a człon?)... { // Ra: przesiadka, jeśli AI zmieniło kabinę (a człon?)...
if (iCabn != (DynamicObject->MoverParameters->ActiveCab == -1 ? if( iCabn != ( DynamicObject->MoverParameters->ActiveCab == -1 ?
2 : 2 :
DynamicObject->MoverParameters->ActiveCab)) DynamicObject->MoverParameters->ActiveCab ) )
InitializeCab(DynamicObject->MoverParameters->ActiveCab, InitializeCab( DynamicObject->MoverParameters->ActiveCab,
DynamicObject->asBaseDir + DynamicObject->MoverParameters->TypeName + DynamicObject->asBaseDir + DynamicObject->MoverParameters->TypeName +
".mmd"); ".mmd" );
} }
iCabn = (DynamicObject->MoverParameters->ActiveCab == -1 ? iCabn = ( DynamicObject->MoverParameters->ActiveCab == -1 ?
2 : 2 :
DynamicObject->MoverParameters->ActiveCab); DynamicObject->MoverParameters->ActiveCab );
if (!DebugModeFlag) if( !DebugModeFlag ) { // sprawdzaj więzy //Ra: nie tu!
{ // sprawdzaj więzy //Ra: nie tu! if( pMechPosition.x < Cabine[ iCabn ].CabPos1.x )
if (pNewMechPosition.x < Cabine[iCabn].CabPos1.x) pMechPosition.x = Cabine[ iCabn ].CabPos1.x;
pNewMechPosition.x = Cabine[iCabn].CabPos1.x; if( pMechPosition.x > Cabine[ iCabn ].CabPos2.x )
if (pNewMechPosition.x > Cabine[iCabn].CabPos2.x) pMechPosition.x = Cabine[ iCabn ].CabPos2.x;
pNewMechPosition.x = Cabine[iCabn].CabPos2.x; if( pMechPosition.z < Cabine[ iCabn ].CabPos1.z )
if (pNewMechPosition.z < Cabine[iCabn].CabPos1.z) pMechPosition.z = Cabine[ iCabn ].CabPos1.z;
pNewMechPosition.z = Cabine[iCabn].CabPos1.z; if( pMechPosition.z > Cabine[ iCabn ].CabPos2.z )
if (pNewMechPosition.z > Cabine[iCabn].CabPos2.z) pMechPosition.z = Cabine[ iCabn ].CabPos2.z;
pNewMechPosition.z = Cabine[iCabn].CabPos2.z; if( pMechPosition.y > Cabine[ iCabn ].CabPos1.y + 1.8 )
if (pNewMechPosition.y > Cabine[iCabn].CabPos1.y + 1.8) pMechPosition.y = Cabine[ iCabn ].CabPos1.y + 1.8;
pNewMechPosition.y = Cabine[iCabn].CabPos1.y + 1.8; if( pMechPosition.y < Cabine[ iCabn ].CabPos1.y + 0.5 )
if (pNewMechPosition.y < Cabine[iCabn].CabPos1.y + 0.5) pMechPosition.y = Cabine[ iCabn ].CabPos2.y + 0.5;
pNewMechPosition.y = Cabine[iCabn].CabPos2.y + 0.5;
if (pMechOffset.x < Cabine[iCabn].CabPos1.x) if( pMechOffset.x < Cabine[ iCabn ].CabPos1.x )
pMechOffset.x = Cabine[iCabn].CabPos1.x; pMechOffset.x = Cabine[ iCabn ].CabPos1.x;
if (pMechOffset.x > Cabine[iCabn].CabPos2.x) if( pMechOffset.x > Cabine[ iCabn ].CabPos2.x )
pMechOffset.x = Cabine[iCabn].CabPos2.x; pMechOffset.x = Cabine[ iCabn ].CabPos2.x;
if (pMechOffset.z < Cabine[iCabn].CabPos1.z) if( pMechOffset.z < Cabine[ iCabn ].CabPos1.z )
pMechOffset.z = Cabine[iCabn].CabPos1.z; pMechOffset.z = Cabine[ iCabn ].CabPos1.z;
if (pMechOffset.z > Cabine[iCabn].CabPos2.z) if( pMechOffset.z > Cabine[ iCabn ].CabPos2.z )
pMechOffset.z = Cabine[iCabn].CabPos2.z; pMechOffset.z = Cabine[ iCabn ].CabPos2.z;
if (pMechOffset.y > Cabine[iCabn].CabPos1.y + 1.8) if( pMechOffset.y > Cabine[ iCabn ].CabPos1.y + 1.8 )
pMechOffset.y = Cabine[iCabn].CabPos1.y + 1.8; pMechOffset.y = Cabine[ iCabn ].CabPos1.y + 1.8;
if (pMechOffset.y < Cabine[iCabn].CabPos1.y + 0.5) if( pMechOffset.y < Cabine[ iCabn ].CabPos1.y + 0.5 )
pMechOffset.y = Cabine[iCabn].CabPos2.y + 0.5; pMechOffset.y = Cabine[ iCabn ].CabPos2.y + 0.5;
} }
pMechPosition = DynamicObject->mMatrix *
pNewMechPosition; // położenie względem środka pojazdu w układzie scenerii
pMechPosition += DynamicObject->GetPosition();
// framerate-independent speed reduction that doesn't break at high framerates...
Math3D::vector3 movementslowdown = vMechMovement * 35 * dt;
if( movementslowdown.LengthSquared() >= vMechMovement.LengthSquared() ) {
// if the reduction vector exceeds speed movement we're running at low fps,
// fallback on the old behaviour
vMechMovement *= 0.5;
}
else {
vMechMovement -= movementslowdown;
if( vMechMovement.LengthSquared() < 0.01 ) {
vMechMovement = Math3D::vector3();
}
}
}; };
// returns position of the mechanic in the scene coordinates
vector3
TTrain::GetWorldMechPosition() {
vector3 position = DynamicObject->mMatrix *pMechPosition; // położenie względem środka pojazdu w układzie scenerii
position += DynamicObject->GetPosition();
return position;
}
bool TTrain::Update( double const Deltatime ) bool TTrain::Update( double const Deltatime )
{ {
DWORD stat; DWORD stat;

View File

@@ -94,6 +94,7 @@ class TTrain
return DynamicObject->VectorUp(); return DynamicObject->VectorUp();
}; };
void UpdateMechPosition(double dt); void UpdateMechPosition(double dt);
vector3 GetWorldMechPosition();
bool Update( double const Deltatime ); bool Update( double const Deltatime );
bool m_updated = false; bool m_updated = false;
void MechStop(); void MechStop();

View File

@@ -59,12 +59,13 @@ opengl_renderer::Update_Lights( light_array const &Lights ) {
renderlight->set_position( scenelight.position ); renderlight->set_position( scenelight.position );
renderlight->direction = scenelight.direction; renderlight->direction = scenelight.direction;
renderlight->diffuse[ 0 ] = scenelight.color.x; auto const luminance = Global::fLuminance; // TODO: adjust this based on location, e.g. for tunnels
renderlight->diffuse[ 1 ] = scenelight.color.y; renderlight->diffuse[ 0 ] = std::max( 0.0, scenelight.color.x - luminance );
renderlight->diffuse[ 2 ] = scenelight.color.z; renderlight->diffuse[ 1 ] = std::max( 0.0, scenelight.color.y - luminance );
renderlight->ambient[ 0 ] = scenelight.color.x * scenelight.intensity; renderlight->diffuse[ 2 ] = std::max( 0.0, scenelight.color.z - luminance );
renderlight->ambient[ 1 ] = scenelight.color.y * scenelight.intensity; renderlight->ambient[ 0 ] = std::max( 0.0, scenelight.color.x * scenelight.intensity - luminance);
renderlight->ambient[ 2 ] = scenelight.color.z * scenelight.intensity; renderlight->ambient[ 1 ] = std::max( 0.0, scenelight.color.y * scenelight.intensity - luminance );
renderlight->ambient[ 2 ] = std::max( 0.0, scenelight.color.z * scenelight.intensity - luminance );
::glLightf( renderlight->id, GL_LINEAR_ATTENUATION, (0.25f * scenelight.count) / std::pow( scenelight.count, 2 ) ); ::glLightf( renderlight->id, GL_LINEAR_ATTENUATION, (0.25f * scenelight.count) / std::pow( scenelight.count, 2 ) );
::glEnable( renderlight->id ); ::glEnable( renderlight->id );

View File

@@ -18,11 +18,14 @@
#endif // _DEBUG #endif // _DEBUG
#endif #endif
// operating system // operating system
#ifdef _WINDOWS
#include "targetver.h" #include "targetver.h"
#define NOMINMAX #define NOMINMAX
#include <windows.h> #include <windows.h>
#include <shlobj.h> #include <shlobj.h>
#undef NOMINMAX #undef NOMINMAX
#include <dbghelp.h>
#endif
// stl // stl
#include <cstdlib> #include <cstdlib>
#include <cassert> #include <cassert>