mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-03-22 15:05:03 +01:00
2. Możliwość zdefiniowania koloru tła ekranu ładowania w eu07.ini. 3. Dodanie logowania ruchu ramek WM_COPYDATA do oddzielnego pliku. 4. Dodana ramka skrócona aktywnych AI. 5. Dodana ramka sterowania uszkodzeniami pojazdów. 6. Dodanie kręciołka od świateł (w tym trakcja wielokrotna). 7. Rozbudowa asynchronów, m.in. tempomat, zadawanie siły (w kN), przeciwpoślizg, czyste ED itd. 8. Dodanie animacji drtzwi odskokowo-przesuwnych. 9. Dodanie możliwości uszkadzania pojazdów (EN57). 10. Uruchomienie sprzęgu WN, zwłaszcza w asynchronach - do przejrzenia logowanie braków napięcia. 11. Wyłączanie radiostopu przez wyłączanie radia, a nie przez ruch zaworem maszynisty. 12. Usunięcie wyłącznika ciśnieniowego w EN57 (proteza, trzeba zrobić wpis na to). 13. Wstępna wersja hamowania rekuperacyjnego wraz z przechodzeniem na hamowanie oporowe. 14. Cała masa nowych zmiennych stanu dostępna dla ekranu (Pythona). 15. Nowa stara smuga z dawnego SPKSu. 16. Inne, które mogłem zapomnieć lub nie uszczegółowić. 17. Poprawione wyświetlanie haslera
5227 lines
235 KiB
C++
5227 lines
235 KiB
C++
/*
|
||
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/.
|
||
*/
|
||
|
||
/*
|
||
MaSzyna EU07 locomotive simulator
|
||
Copyright (C) 2001-2004 Marcin Wozniak and others
|
||
|
||
*/
|
||
|
||
#include "system.hpp"
|
||
#include "classes.hpp"
|
||
|
||
#include "opengl/glew.h"
|
||
#include "opengl/glut.h"
|
||
|
||
#pragma hdrstop
|
||
|
||
#include "Timer.h"
|
||
#include "Texture.h"
|
||
#include "Ground.h"
|
||
#include "Globals.h"
|
||
#include "Event.h"
|
||
#include "EvLaunch.h"
|
||
#include "TractionPower.h"
|
||
#include "Traction.h"
|
||
#include "Track.h"
|
||
#include "RealSound.h"
|
||
#include "AnimModel.h"
|
||
#include "MemCell.h"
|
||
#include "mtable.hpp"
|
||
#include "DynObj.h"
|
||
#include "Data.h"
|
||
#include "parser.h" //Tolaris-010603
|
||
#include "Driver.h"
|
||
#include "Console.h"
|
||
#include "Names.h"
|
||
|
||
#define _PROBLEND 1
|
||
//---------------------------------------------------------------------------
|
||
#pragma package(smart_init)
|
||
|
||
bool bCondition; // McZapkie: do testowania warunku na event multiple
|
||
AnsiString LogComment;
|
||
|
||
//---------------------------------------------------------------------------
|
||
// Obiekt renderuj¹cy siatkê jest sztucznie tworzonym obiektem pomocniczym,
|
||
// grupuj¹cym siatki obiektów dla danej tekstury. Obiektami sk³adowymi mog¹
|
||
// byc trójk¹ty terenu, szyny, podsypki, a tak¿e proste modele np. s³upy.
|
||
// Obiekty sk³adowe dodane s¹ do listy TSubRect::nMeshed z list¹ zrobion¹ na
|
||
// TGroundNode::nNext3, gdzie s¹ posortowane wg tekstury. Obiekty renderuj¹ce
|
||
// s¹ wpisane na listê TSubRect::nRootMesh (TGroundNode::nNext2) oraz na
|
||
// odpowiednie listy renderowania, gdzie zastêpuj¹ obiekty sk³adowe (nNext3).
|
||
// Problematyczne s¹ tory/drogi/rzeki, gdzie u¿ywane sa 2 tekstury. Dlatego
|
||
// tory s¹ zdublowane jako TP_TRACK oraz TP_DUMMYTRACK. Jeœli tekstura jest
|
||
// tylko jedna (np. zwrotnice), nie jest u¿ywany TP_DUMMYTRACK.
|
||
//---------------------------------------------------------------------------
|
||
TGroundNode::TGroundNode()
|
||
{ // nowy obiekt terenu - pusty
|
||
iType = GL_POINTS;
|
||
Vertices = NULL;
|
||
nNext = nNext2 = NULL;
|
||
pCenter = vector3(0, 0, 0);
|
||
iCount = 0; // wierzcho³ków w trójk¹cie
|
||
// iNumPts=0; //punktów w linii
|
||
TextureID = 0;
|
||
iFlags = 0; // tryb przezroczystoœci nie zbadany
|
||
DisplayListID = 0;
|
||
Pointer = NULL; // zerowanie wskaŸnika kontekstowego
|
||
bVisible = false; // czy widoczny
|
||
fSquareRadius = 10000 * 10000;
|
||
fSquareMinRadius = 0;
|
||
asName = "";
|
||
// Color= TMaterialColor(1);
|
||
// fAngle=0; //obrót dla modelu
|
||
// fLineThickness=1.0; //mm dla linii
|
||
for (int i = 0; i < 3; i++)
|
||
{
|
||
Ambient[i] = Global::whiteLight[i] * 255;
|
||
Diffuse[i] = Global::whiteLight[i] * 255;
|
||
Specular[i] = Global::noLight[i] * 255;
|
||
}
|
||
nNext3 = NULL; // nie wyœwietla innych
|
||
iVboPtr = -1; // indeks w VBO sektora (-1: nie u¿ywa VBO)
|
||
iVersion = 0; // wersja siatki
|
||
}
|
||
|
||
TGroundNode::~TGroundNode()
|
||
{
|
||
// if (iFlags&0x200) //czy obiekt zosta³ utworzony?
|
||
switch (iType)
|
||
{
|
||
case TP_MEMCELL:
|
||
SafeDelete(MemCell);
|
||
break;
|
||
case TP_EVLAUNCH:
|
||
SafeDelete(EvLaunch);
|
||
break;
|
||
case TP_TRACTION:
|
||
SafeDelete(hvTraction);
|
||
break;
|
||
case TP_TRACTIONPOWERSOURCE:
|
||
SafeDelete(psTractionPowerSource);
|
||
break;
|
||
case TP_TRACK:
|
||
SafeDelete(pTrack);
|
||
break;
|
||
case TP_DYNAMIC:
|
||
SafeDelete(DynamicObject);
|
||
break;
|
||
case TP_MODEL:
|
||
if (iFlags & 0x200) // czy model zosta³ utworzony?
|
||
delete Model;
|
||
Model = NULL;
|
||
break;
|
||
case TP_TERRAIN:
|
||
{ // pierwsze nNode zawiera model E3D, reszta to trójk¹ty
|
||
for (int i = 1; i < iCount; ++i)
|
||
nNode->Vertices =
|
||
NULL; // zerowanie wskaŸników w kolejnych elementach, bo nie s¹ do usuwania
|
||
delete[] nNode; // usuniêcie tablicy i pierwszego elementu
|
||
}
|
||
case TP_SUBMODEL: // dla formalnoœci, nie wymaga usuwania
|
||
break;
|
||
case GL_LINES:
|
||
case GL_LINE_STRIP:
|
||
case GL_LINE_LOOP:
|
||
SafeDeleteArray(Points);
|
||
break;
|
||
case GL_TRIANGLE_STRIP:
|
||
case GL_TRIANGLE_FAN:
|
||
case GL_TRIANGLES:
|
||
SafeDeleteArray(Vertices);
|
||
break;
|
||
}
|
||
}
|
||
|
||
void TGroundNode::Init(int n)
|
||
{ // utworzenie tablicy wierzcho³ków
|
||
bVisible = false;
|
||
iNumVerts = n;
|
||
Vertices = new TGroundVertex[iNumVerts];
|
||
}
|
||
|
||
TGroundNode::TGroundNode(TGroundNodeType t, int n)
|
||
{ // utworzenie obiektu
|
||
TGroundNode(); // domyœlne ustawienia
|
||
iNumVerts = n;
|
||
if (iNumVerts)
|
||
Vertices = new TGroundVertex[iNumVerts];
|
||
iType = t;
|
||
switch (iType)
|
||
{ // zale¿nie od typu
|
||
case TP_TRACK:
|
||
pTrack = new TTrack(this);
|
||
break;
|
||
}
|
||
}
|
||
|
||
void TGroundNode::InitCenter()
|
||
{ // obliczenie œrodka ciê¿koœci obiektu
|
||
for (int i = 0; i < iNumVerts; i++)
|
||
pCenter += Vertices[i].Point;
|
||
pCenter /= iNumVerts;
|
||
}
|
||
|
||
void TGroundNode::InitNormals()
|
||
{ // obliczenie wektorów normalnych
|
||
vector3 v1, v2, v3, v4, v5, n1, n2, n3, n4;
|
||
int i;
|
||
float tu, tv;
|
||
switch (iType)
|
||
{
|
||
case GL_TRIANGLE_STRIP:
|
||
v1 = Vertices[0].Point - Vertices[1].Point;
|
||
v2 = Vertices[1].Point - Vertices[2].Point;
|
||
n1 = SafeNormalize(CrossProduct(v1, v2));
|
||
if (Vertices[0].Normal == vector3(0, 0, 0))
|
||
Vertices[0].Normal = n1;
|
||
v3 = Vertices[2].Point - Vertices[3].Point;
|
||
n2 = SafeNormalize(CrossProduct(v3, v2));
|
||
if (Vertices[1].Normal == vector3(0, 0, 0))
|
||
Vertices[1].Normal = (n1 + n2) * 0.5;
|
||
|
||
for (i = 2; i < iNumVerts - 2; i += 2)
|
||
{
|
||
v4 = Vertices[i - 1].Point - Vertices[i].Point;
|
||
v5 = Vertices[i].Point - Vertices[i + 1].Point;
|
||
n3 = SafeNormalize(CrossProduct(v3, v4));
|
||
n4 = SafeNormalize(CrossProduct(v5, v4));
|
||
if (Vertices[i].Normal == vector3(0, 0, 0))
|
||
Vertices[i].Normal = (n1 + n2 + n3) / 3;
|
||
if (Vertices[i + 1].Normal == vector3(0, 0, 0))
|
||
Vertices[i + 1].Normal = (n2 + n3 + n4) / 3;
|
||
n1 = n3;
|
||
n2 = n4;
|
||
v3 = v5;
|
||
}
|
||
if (Vertices[i].Normal == vector3(0, 0, 0))
|
||
Vertices[i].Normal = (n1 + n2) / 2;
|
||
if (Vertices[i + 1].Normal == vector3(0, 0, 0))
|
||
Vertices[i + 1].Normal = n2;
|
||
break;
|
||
case GL_TRIANGLE_FAN:
|
||
|
||
break;
|
||
case GL_TRIANGLES:
|
||
for (i = 0; i < iNumVerts; i += 3)
|
||
{
|
||
v1 = Vertices[i + 0].Point - Vertices[i + 1].Point;
|
||
v2 = Vertices[i + 1].Point - Vertices[i + 2].Point;
|
||
n1 = SafeNormalize(CrossProduct(v1, v2));
|
||
if (Vertices[i + 0].Normal == vector3(0, 0, 0))
|
||
Vertices[i + 0].Normal = (n1);
|
||
if (Vertices[i + 1].Normal == vector3(0, 0, 0))
|
||
Vertices[i + 1].Normal = (n1);
|
||
if (Vertices[i + 2].Normal == vector3(0, 0, 0))
|
||
Vertices[i + 2].Normal = (n1);
|
||
tu = floor(Vertices[i + 0].tu);
|
||
tv = floor(Vertices[i + 0].tv);
|
||
Vertices[i + 1].tv -= tv;
|
||
Vertices[i + 2].tv -= tv;
|
||
Vertices[i + 0].tv -= tv;
|
||
Vertices[i + 1].tu -= tu;
|
||
Vertices[i + 2].tu -= tu;
|
||
Vertices[i + 0].tu -= tu;
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
|
||
void TGroundNode::MoveMe(vector3 pPosition)
|
||
{ // przesuwanie obiektów scenerii o wektor w celu redukcji trzêsienia
|
||
pCenter += pPosition;
|
||
switch (iType)
|
||
{
|
||
case TP_TRACTION:
|
||
hvTraction->pPoint1 += pPosition;
|
||
hvTraction->pPoint2 += pPosition;
|
||
hvTraction->pPoint3 += pPosition;
|
||
hvTraction->pPoint4 += pPosition;
|
||
hvTraction->Optimize();
|
||
break;
|
||
case TP_MODEL:
|
||
case TP_DYNAMIC:
|
||
case TP_MEMCELL:
|
||
case TP_EVLAUNCH:
|
||
break;
|
||
case TP_TRACK:
|
||
pTrack->MoveMe(pPosition);
|
||
break;
|
||
case TP_SOUND: // McZapkie - dzwiek zapetlony w zaleznosci od odleglosci
|
||
tsStaticSound->vSoundPosition += pPosition;
|
||
break;
|
||
case GL_LINES:
|
||
case GL_LINE_STRIP:
|
||
case GL_LINE_LOOP:
|
||
for (int i = 0; i < iNumPts; i++)
|
||
Points[i] += pPosition;
|
||
ResourceManager::Unregister(this);
|
||
break;
|
||
default:
|
||
for (int i = 0; i < iNumVerts; i++)
|
||
Vertices[i].Point += pPosition;
|
||
ResourceManager::Unregister(this);
|
||
}
|
||
}
|
||
|
||
void TGroundNode::RaRenderVBO()
|
||
{ // renderowanie z domyslnego bufora VBO
|
||
glColor3ub(Diffuse[0], Diffuse[1], Diffuse[2]);
|
||
if (TextureID)
|
||
glBindTexture(GL_TEXTURE_2D, TextureID); // Ustaw aktywn¹ teksturê
|
||
glDrawArrays(iType, iVboPtr, iNumVerts); // Narysuj naraz wszystkie trójk¹ty
|
||
}
|
||
|
||
void TGroundNode::RenderVBO()
|
||
{ // renderowanie obiektu z VBO - faza nieprzezroczystych
|
||
double mgn = SquareMagnitude(pCenter - Global::pCameraPosition);
|
||
if ((mgn > fSquareRadius || (mgn < fSquareMinRadius)) &&
|
||
(iType != TP_EVLAUNCH)) // McZapkie-070602: nie rysuj odleglych obiektow ale sprawdzaj
|
||
// wyzwalacz zdarzen
|
||
return;
|
||
int i, a;
|
||
switch (iType)
|
||
{
|
||
case TP_TRACTION:
|
||
return;
|
||
case TP_TRACK:
|
||
if (iNumVerts)
|
||
pTrack->RaRenderVBO(iVboPtr);
|
||
return;
|
||
case TP_MODEL:
|
||
Model->RenderVBO(&pCenter);
|
||
return;
|
||
// case TP_SOUND: //McZapkie - dzwiek zapetlony w zaleznosci od odleglosci
|
||
// if ((pStaticSound->GetStatus()&DSBSTATUS_PLAYING)==DSBPLAY_LOOPING)
|
||
// {
|
||
// pStaticSound->Play(1,DSBPLAY_LOOPING,true,pStaticSound->vSoundPosition);
|
||
// pStaticSound->AdjFreq(1.0,Timer::GetDeltaTime());
|
||
// }
|
||
// return; //Ra: TODO sprawdziæ, czy dŸwiêki nie s¹ tylko w RenderHidden
|
||
case TP_MEMCELL:
|
||
return;
|
||
case TP_EVLAUNCH:
|
||
if (EvLaunch->Render())
|
||
if ((EvLaunch->dRadius < 0) || (mgn < EvLaunch->dRadius))
|
||
{
|
||
if (Console::Pressed(VK_SHIFT) && EvLaunch->Event2 != NULL)
|
||
Global::AddToQuery(EvLaunch->Event2, NULL);
|
||
else if (EvLaunch->Event1 != NULL)
|
||
Global::AddToQuery(EvLaunch->Event1, NULL);
|
||
}
|
||
return;
|
||
case GL_LINES:
|
||
case GL_LINE_STRIP:
|
||
case GL_LINE_LOOP:
|
||
if (iNumPts)
|
||
{
|
||
float linealpha = 255000 * fLineThickness / (mgn + 1.0);
|
||
if (linealpha > 255)
|
||
linealpha = 255;
|
||
float r, g, b;
|
||
r = floor(Diffuse[0] * Global::ambientDayLight[0]); // w zaleznosci od koloru swiatla
|
||
g = floor(Diffuse[1] * Global::ambientDayLight[1]);
|
||
b = floor(Diffuse[2] * Global::ambientDayLight[2]);
|
||
glColor4ub(r, g, b, linealpha); // przezroczystosc dalekiej linii
|
||
// glDisable(GL_LIGHTING); //nie powinny œwieciæ
|
||
glDrawArrays(iType, iVboPtr, iNumPts); // rysowanie linii
|
||
// glEnable(GL_LIGHTING);
|
||
}
|
||
return;
|
||
default:
|
||
if (iVboPtr >= 0)
|
||
RaRenderVBO();
|
||
};
|
||
return;
|
||
};
|
||
|
||
void TGroundNode::RenderAlphaVBO()
|
||
{ // renderowanie obiektu z VBO - faza przezroczystych
|
||
double mgn = SquareMagnitude(pCenter - Global::pCameraPosition);
|
||
float r, g, b;
|
||
if (mgn < fSquareMinRadius)
|
||
return;
|
||
if (mgn > fSquareRadius)
|
||
return;
|
||
int i, a;
|
||
#ifdef _PROBLEND
|
||
if ((PROBLEND)) // sprawdza, czy w nazwie nie ma @ //Q: 13122011 - Szociu: 27012012
|
||
{
|
||
glDisable(GL_BLEND);
|
||
glAlphaFunc(GL_GREATER, 0.45); // im mniejsza wartoœæ, tym wiêksza ramka, domyœlnie 0.1f
|
||
};
|
||
#endif
|
||
switch (iType)
|
||
{
|
||
case TP_TRACTION:
|
||
if (bVisible)
|
||
{
|
||
#ifdef _PROBLEND
|
||
glEnable(GL_BLEND);
|
||
glAlphaFunc(GL_GREATER, 0.04);
|
||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||
#endif
|
||
hvTraction->RenderVBO(mgn, iVboPtr);
|
||
}
|
||
return;
|
||
case TP_MODEL:
|
||
#ifdef _PROBLEND
|
||
glEnable(GL_BLEND);
|
||
glAlphaFunc(GL_GREATER, 0.04);
|
||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||
#endif
|
||
Model->RenderAlphaVBO(&pCenter);
|
||
return;
|
||
case GL_LINES:
|
||
case GL_LINE_STRIP:
|
||
case GL_LINE_LOOP:
|
||
if (iNumPts)
|
||
{
|
||
float linealpha = 255000 * fLineThickness / (mgn + 1.0);
|
||
if (linealpha > 255)
|
||
linealpha = 255;
|
||
r = Diffuse[0] * Global::ambientDayLight[0]; // w zaleznosci od koloru swiatla
|
||
g = Diffuse[1] * Global::ambientDayLight[1];
|
||
b = Diffuse[2] * Global::ambientDayLight[2];
|
||
glColor4ub(r, g, b, linealpha); // przezroczystosc dalekiej linii
|
||
// glDisable(GL_LIGHTING); //nie powinny œwieciæ
|
||
glDrawArrays(iType, iVboPtr, iNumPts); // rysowanie linii
|
||
// glEnable(GL_LIGHTING);
|
||
#ifdef _PROBLEND
|
||
glEnable(GL_BLEND);
|
||
glAlphaFunc(GL_GREATER, 0.04);
|
||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||
#endif
|
||
}
|
||
#ifdef _PROBLEND
|
||
glEnable(GL_BLEND);
|
||
glAlphaFunc(GL_GREATER, 0.04);
|
||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||
#endif
|
||
return;
|
||
default:
|
||
if (iVboPtr >= 0)
|
||
{
|
||
RaRenderVBO();
|
||
#ifdef _PROBLEND
|
||
glEnable(GL_BLEND);
|
||
glAlphaFunc(GL_GREATER, 0.04);
|
||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||
#endif
|
||
return;
|
||
}
|
||
}
|
||
#ifdef _PROBLEND
|
||
glEnable(GL_BLEND);
|
||
glAlphaFunc(GL_GREATER, 0.04);
|
||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||
#endif
|
||
return;
|
||
}
|
||
|
||
void TGroundNode::Compile(bool many)
|
||
{ // tworzenie skompilowanej listy w wyœwietlaniu DL
|
||
if (!many)
|
||
{ // obs³uga pojedynczej listy
|
||
if (DisplayListID)
|
||
Release();
|
||
if (Global::bManageNodes)
|
||
{
|
||
DisplayListID = glGenLists(1);
|
||
glNewList(DisplayListID, GL_COMPILE);
|
||
iVersion = Global::iReCompile; // aktualna wersja siatek (do WireFrame)
|
||
}
|
||
}
|
||
if ((iType == GL_LINES) || (iType == GL_LINE_STRIP) || (iType == GL_LINE_LOOP))
|
||
{
|
||
#ifdef USE_VERTEX_ARRAYS
|
||
glVertexPointer(3, GL_DOUBLE, sizeof(vector3), &Points[0].x);
|
||
#endif
|
||
glBindTexture(GL_TEXTURE_2D, 0);
|
||
#ifdef USE_VERTEX_ARRAYS
|
||
glDrawArrays(iType, 0, iNumPts);
|
||
#else
|
||
glBegin(iType);
|
||
for (int i = 0; i < iNumPts; i++)
|
||
glVertex3dv(&Points[i].x);
|
||
glEnd();
|
||
#endif
|
||
}
|
||
else if (iType == GL_TRIANGLE_STRIP || iType == GL_TRIANGLE_FAN || iType == GL_TRIANGLES)
|
||
{ // jak nie linie, to trójk¹ty
|
||
TGroundNode *tri = this;
|
||
do
|
||
{ // pêtla po obiektach w grupie w celu po³¹czenia siatek
|
||
#ifdef USE_VERTEX_ARRAYS
|
||
glVertexPointer(3, GL_DOUBLE, sizeof(TGroundVertex), &tri->Vertices[0].Point.x);
|
||
glNormalPointer(GL_DOUBLE, sizeof(TGroundVertex), &tri->Vertices[0].Normal.x);
|
||
glTexCoordPointer(2, GL_FLOAT, sizeof(TGroundVertex), &tri->Vertices[0].tu);
|
||
#endif
|
||
glColor3ub(tri->Diffuse[0], tri->Diffuse[1], tri->Diffuse[2]);
|
||
glBindTexture(GL_TEXTURE_2D, Global::bWireFrame ? 0 : tri->TextureID);
|
||
#ifdef USE_VERTEX_ARRAYS
|
||
glDrawArrays(Global::bWireFrame ? GL_LINE_LOOP : tri->iType, 0, tri->iNumVerts);
|
||
#else
|
||
glBegin(Global::bWireFrame ? GL_LINE_LOOP : tri->iType);
|
||
for (int i = 0; i < tri->iNumVerts; i++)
|
||
{
|
||
glNormal3d(tri->Vertices[i].Normal.x, tri->Vertices[i].Normal.y,
|
||
tri->Vertices[i].Normal.z);
|
||
glTexCoord2f(tri->Vertices[i].tu, tri->Vertices[i].tv);
|
||
glVertex3dv(&tri->Vertices[i].Point.x);
|
||
};
|
||
glEnd();
|
||
#endif
|
||
/*
|
||
if (tri->pTriGroup) //jeœli z grupy
|
||
{tri=tri->pNext2; //nastêpny w sektorze
|
||
while (tri?!tri->pTriGroup:false) tri=tri->pNext2; //szukamy kolejnego nale¿¹cego do
|
||
grupy
|
||
}
|
||
else
|
||
*/
|
||
tri = NULL; // a jak nie, to koniec
|
||
} while (tri);
|
||
}
|
||
else if (iType == TP_MESH)
|
||
{ // grupa ze wspóln¹ tekstur¹ - wrzucanie do wspólnego Display List
|
||
if (TextureID)
|
||
glBindTexture(GL_TEXTURE_2D, TextureID); // Ustaw aktywn¹ teksturê
|
||
TGroundNode *n = nNode;
|
||
while (n ? n->TextureID == TextureID : false)
|
||
{ // wszystkie obiekty o tej samej testurze
|
||
switch (n->iType)
|
||
{ // poszczególne typy ró¿nie siê tworzy
|
||
case TP_TRACK:
|
||
case TP_DUMMYTRACK:
|
||
n->pTrack->Compile(TextureID); // dodanie trójk¹tów dla podanej tekstury
|
||
break;
|
||
}
|
||
n = n->nNext3; // nastêpny z listy
|
||
}
|
||
}
|
||
if (!many)
|
||
if (Global::bManageNodes)
|
||
glEndList();
|
||
};
|
||
|
||
void TGroundNode::Release()
|
||
{
|
||
if (DisplayListID)
|
||
glDeleteLists(DisplayListID, 1);
|
||
DisplayListID = 0;
|
||
};
|
||
|
||
void TGroundNode::RenderHidden()
|
||
{ // renderowanie obiektów niewidocznych
|
||
double mgn = SquareMagnitude(pCenter - Global::pCameraPosition);
|
||
switch (iType)
|
||
{
|
||
case TP_SOUND: // McZapkie - dzwiek zapetlony w zaleznosci od odleglosci
|
||
if ((tsStaticSound->GetStatus() & DSBSTATUS_PLAYING) == DSBPLAY_LOOPING)
|
||
{
|
||
tsStaticSound->Play(1, DSBPLAY_LOOPING, true, tsStaticSound->vSoundPosition);
|
||
tsStaticSound->AdjFreq(1.0, Timer::GetDeltaTime());
|
||
}
|
||
return;
|
||
case TP_EVLAUNCH:
|
||
if (EvLaunch->Render())
|
||
if ((EvLaunch->dRadius < 0) || (mgn < EvLaunch->dRadius))
|
||
{
|
||
WriteLog("Eventlauncher " + asName);
|
||
if (Console::Pressed(VK_SHIFT) && (EvLaunch->Event2))
|
||
Global::AddToQuery(EvLaunch->Event2, NULL);
|
||
else if (EvLaunch->Event1)
|
||
Global::AddToQuery(EvLaunch->Event1, NULL);
|
||
}
|
||
return;
|
||
}
|
||
};
|
||
|
||
void TGroundNode::RenderDL()
|
||
{ // wyœwietlanie obiektu przez Display List
|
||
switch (iType)
|
||
{ // obiekty renderowane niezale¿nie od odleg³oœci
|
||
case TP_SUBMODEL:
|
||
TSubModel::fSquareDist = 0;
|
||
return smTerrain->RenderDL();
|
||
}
|
||
// if (pTriGroup) if (pTriGroup!=this) return; //wyœwietla go inny obiekt
|
||
double mgn = SquareMagnitude(pCenter - Global::pCameraPosition);
|
||
if ((mgn > fSquareRadius) || (mgn < fSquareMinRadius)) // McZapkie-070602: nie rysuj odleglych
|
||
// obiektow ale sprawdzaj wyzwalacz
|
||
// zdarzen
|
||
return;
|
||
int i, a;
|
||
switch (iType)
|
||
{
|
||
case TP_TRACK:
|
||
return pTrack->Render();
|
||
case TP_MODEL:
|
||
return Model->RenderDL(&pCenter);
|
||
}
|
||
// TODO: sprawdzic czy jest potrzebny warunek fLineThickness < 0
|
||
// if ((iNumVerts&&(iFlags&0x10))||(iNumPts&&(fLineThickness<0)))
|
||
if ((iFlags & 0x10) || (fLineThickness < 0))
|
||
{
|
||
if (!DisplayListID || (iVersion != Global::iReCompile)) // Ra: wymuszenie rekompilacji
|
||
{
|
||
Compile();
|
||
if (Global::bManageNodes)
|
||
ResourceManager::Register(this);
|
||
};
|
||
|
||
if ((iType == GL_LINES) || (iType == GL_LINE_STRIP) || (iType == GL_LINE_LOOP))
|
||
// if (iNumPts)
|
||
{ // wszelkie linie s¹ rysowane na samym koñcu
|
||
float r, g, b;
|
||
r = Diffuse[0] * Global::ambientDayLight[0]; // w zaleznosci od koloru swiatla
|
||
g = Diffuse[1] * Global::ambientDayLight[1];
|
||
b = Diffuse[2] * Global::ambientDayLight[2];
|
||
glColor4ub(r, g, b, 1.0);
|
||
glCallList(DisplayListID);
|
||
// glColor4fv(Diffuse); //przywrócenie koloru
|
||
// glColor3ub(Diffuse[0],Diffuse[1],Diffuse[2]);
|
||
}
|
||
// GL_TRIANGLE etc
|
||
else
|
||
glCallList(DisplayListID);
|
||
SetLastUsage(Timer::GetSimulationTime());
|
||
};
|
||
};
|
||
|
||
void TGroundNode::RenderAlphaDL()
|
||
{
|
||
// SPOSOB NA POZBYCIE SIE RAMKI DOOKOLA TEXTURY ALPHA DLA OBIEKTOW ZAGNIEZDZONYCH W SCN JAKO
|
||
// NODE
|
||
|
||
// W GROUND.H dajemy do klasy TGroundNode zmienna bool PROBLEND to samo robimy w klasie TGround
|
||
// nastepnie podczas wczytywania textury dla TRIANGLES w TGround::AddGroundNode
|
||
// sprawdzamy czy w nazwie jest @ i wg tego
|
||
// ustawiamy PROBLEND na true dla wlasnie wczytywanego trojkata (kazdy trojkat jest osobnym
|
||
// nodem)
|
||
// nastepnie podczas renderowania w bool TGroundNode::RenderAlpha()
|
||
// na poczatku ustawiamy standardowe GL_GREATER = 0.04
|
||
// pozniej sprawdzamy czy jest wlaczony PROBLEND dla aktualnie renderowanego noda TRIANGLE,
|
||
// wlasciwie dla kazdego node'a
|
||
// i jezeli tak to odpowiedni GL_GREATER w przeciwnym wypadku standardowy 0.04
|
||
|
||
// if (pTriGroup) if (pTriGroup!=this) return; //wyœwietla go inny obiekt
|
||
double mgn = SquareMagnitude(pCenter - Global::pCameraPosition);
|
||
float r, g, b;
|
||
if (mgn < fSquareMinRadius)
|
||
return;
|
||
if (mgn > fSquareRadius)
|
||
return;
|
||
int i, a;
|
||
switch (iType)
|
||
{
|
||
case TP_TRACTION:
|
||
if (bVisible)
|
||
hvTraction->RenderDL(mgn);
|
||
return;
|
||
case TP_MODEL:
|
||
Model->RenderAlphaDL(&pCenter);
|
||
return;
|
||
case TP_TRACK:
|
||
// pTrack->RenderAlpha();
|
||
return;
|
||
};
|
||
|
||
// TODO: sprawdzic czy jest potrzebny warunek fLineThickness < 0
|
||
if ((iNumVerts && (iFlags & 0x20)) || (iNumPts && (fLineThickness > 0)))
|
||
{
|
||
#ifdef _PROBLEND
|
||
if ((PROBLEND)) // sprawdza, czy w nazwie nie ma @ //Q: 13122011 - Szociu: 27012012
|
||
{
|
||
glDisable(GL_BLEND);
|
||
glAlphaFunc(GL_GREATER, 0.45); // im mniejsza wartoœæ, tym wiêksza ramka, domyœlnie 0.1f
|
||
};
|
||
#endif
|
||
if (!DisplayListID) //||Global::bReCompile) //Ra: wymuszenie rekompilacji
|
||
{
|
||
Compile();
|
||
if (Global::bManageNodes)
|
||
ResourceManager::Register(this);
|
||
};
|
||
|
||
// GL_LINE, GL_LINE_STRIP, GL_LINE_LOOP
|
||
if (iNumPts)
|
||
{
|
||
float linealpha = 255000 * fLineThickness / (mgn + 1.0);
|
||
if (linealpha > 255)
|
||
linealpha = 255;
|
||
r = Diffuse[0] * Global::ambientDayLight[0]; // w zaleznosci od koloru swiatla
|
||
g = Diffuse[1] * Global::ambientDayLight[1];
|
||
b = Diffuse[2] * Global::ambientDayLight[2];
|
||
glColor4ub(r, g, b, linealpha); // przezroczystosc dalekiej linii
|
||
glCallList(DisplayListID);
|
||
}
|
||
// GL_TRIANGLE etc
|
||
else
|
||
glCallList(DisplayListID);
|
||
SetLastUsage(Timer::GetSimulationTime());
|
||
};
|
||
#ifdef _PROBLEND
|
||
if ((PROBLEND)) // sprawdza, czy w nazwie nie ma @ //Q: 13122011 - Szociu: 27012012
|
||
{
|
||
glEnable(GL_BLEND);
|
||
glAlphaFunc(GL_GREATER, 0.04);
|
||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||
};
|
||
#endif
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
//------------------ Podstawowy pojemnik terenu - sektor -----------------------
|
||
//------------------------------------------------------------------------------
|
||
TSubRect::TSubRect()
|
||
{
|
||
nRootNode = NULL; // lista wszystkich obiektów jest pusta
|
||
nRenderHidden = nRenderRect = nRenderRectAlpha = nRender = nRenderMixed = nRenderAlpha =
|
||
nRenderWires = NULL;
|
||
tTrackAnim = NULL; // nic nie animujemy
|
||
tTracks = NULL; // nie ma jeszcze torów
|
||
nRootMesh = nMeshed = NULL; // te listy te¿ s¹ puste
|
||
iNodeCount = 0; // licznik obiektów
|
||
iTracks = 0; // licznik torów
|
||
}
|
||
TSubRect::~TSubRect()
|
||
{
|
||
if (Global::bManageNodes) // Ra: tu siê coœ sypie
|
||
ResourceManager::Unregister(this); // wyrejestrowanie ze sprz¹tacza
|
||
// TODO: usun¹æ obiekty z listy (nRootMesh), bo s¹ one tworzone dla sektora
|
||
}
|
||
|
||
void TSubRect::NodeAdd(TGroundNode *Node)
|
||
{ // przyczepienie obiektu do sektora, wstêpna kwalifikacja na listy renderowania
|
||
if (!this)
|
||
return; // zabezpiecznie przed obiektami przekraczaj¹cymi obszar roboczy
|
||
// Ra: sortowanie obiektów na listy renderowania:
|
||
// nRenderHidden - lista obiektów niewidocznych, "renderowanych" równie¿ z ty³u
|
||
// nRenderRect - lista grup renderowanych z sektora
|
||
// nRenderRectAlpha - lista grup renderowanych z sektora z przezroczystoœci¹
|
||
// nRender - lista grup renderowanych z w³asnych VBO albo DL
|
||
// nRenderAlpha - lista grup renderowanych z w³asnych VBO albo DL z przezroczystoœci¹
|
||
// nRenderWires - lista grup renderowanych z w³asnych VBO albo DL - druty i linie
|
||
// nMeshed - obiekty do pogrupowania wg tekstur
|
||
GLuint t; // pomocniczy kod tekstury
|
||
switch (Node->iType)
|
||
{
|
||
case TP_SOUND: // te obiekty s¹ sprawdzanie niezale¿nie od kierunku patrzenia
|
||
case TP_EVLAUNCH:
|
||
Node->nNext3 = nRenderHidden;
|
||
nRenderHidden = Node; // do listy koniecznych
|
||
break;
|
||
case TP_TRACK: // TODO: tory z cieniem (tunel, canyon) te¿ daæ bez ³¹czenia?
|
||
++iTracks; // jeden tor wiêcej
|
||
Node->pTrack->RaOwnerSet(this); // do którego sektora ma zg³aszaæ animacjê
|
||
// if (Global::bUseVBO?false:!Node->pTrack->IsGroupable())
|
||
if (Global::bUseVBO ? true :
|
||
!Node->pTrack->IsGroupable()) // TODO: tymczasowo dla VBO wy³¹czone
|
||
RaNodeAdd(
|
||
Node); // tory ruchome nie s¹ grupowane przy Display Lists (wymagaj¹ odœwie¿ania DL)
|
||
else
|
||
{ // tory nieruchome mog¹ byæ pogrupowane wg tekstury, przy VBO wszystkie
|
||
Node->TextureID = Node->pTrack->TextureGet(0); // pobranie tekstury do sortowania
|
||
t = Node->pTrack->TextureGet(1);
|
||
if (Node->TextureID) // je¿eli jest pierwsza
|
||
{
|
||
if (t && (Node->TextureID != t))
|
||
{ // jeœli s¹ dwie ró¿ne tekstury, dodajemy drugi obiekt dla danego toru
|
||
TGroundNode *n = new TGroundNode();
|
||
n->iType = TP_DUMMYTRACK; // obiekt renderuj¹cy siatki dla tekstury
|
||
n->TextureID = t;
|
||
n->pTrack = Node->pTrack; // wskazuje na ten sam tor
|
||
n->pCenter = Node->pCenter;
|
||
n->fSquareRadius = Node->fSquareRadius;
|
||
n->fSquareMinRadius = Node->fSquareMinRadius;
|
||
n->iFlags = Node->iFlags;
|
||
n->nNext2 = nRootMesh;
|
||
nRootMesh = n; // podczepienie do listy, ¿eby usun¹æ na koñcu
|
||
n->nNext3 = nMeshed;
|
||
nMeshed = n;
|
||
}
|
||
}
|
||
else
|
||
Node->TextureID = t; // jest tylko druga tekstura
|
||
if (Node->TextureID)
|
||
{
|
||
Node->nNext3 = nMeshed;
|
||
nMeshed = Node;
|
||
} // do podzielenia potem
|
||
}
|
||
break;
|
||
case GL_TRIANGLE_STRIP:
|
||
case GL_TRIANGLE_FAN:
|
||
case GL_TRIANGLES:
|
||
// Node->nNext3=nMeshed; nMeshed=Node; //do podzielenia potem
|
||
if (Node->iFlags & 0x20) // czy jest przezroczyste?
|
||
{
|
||
Node->nNext3 = nRenderRectAlpha;
|
||
nRenderRectAlpha = Node;
|
||
} // DL: do przezroczystych z sektora
|
||
else if (Global::bUseVBO)
|
||
{
|
||
Node->nNext3 = nRenderRect;
|
||
nRenderRect = Node;
|
||
} // VBO: do nieprzezroczystych z sektora
|
||
else
|
||
{
|
||
Node->nNext3 = nRender;
|
||
nRender = Node;
|
||
} // DL: do nieprzezroczystych wszelakich
|
||
/*
|
||
//Ra: na razie wy³¹czone do testów VBO
|
||
//if
|
||
((Node->iType==GL_TRIANGLE_STRIP)||(Node->iType==GL_TRIANGLE_FAN)||(Node->iType==GL_TRIANGLES))
|
||
if (Node->fSquareMinRadius==0.0) //znikaj¹ce z bliska nie mog¹ byæ optymalizowane
|
||
if (Node->fSquareRadius>=160000.0) //tak od 400m to ju¿ normalne trójk¹ty musz¹ byæ
|
||
//if (Node->iFlags&0x10) //i nieprzezroczysty
|
||
{if (pTriGroup) //je¿eli by³ ju¿ jakiœ grupuj¹cy
|
||
{if (pTriGroup->fSquareRadius>Node->fSquareRadius) //i mia³ wiêkszy zasiêg
|
||
Node->fSquareRadius=pTriGroup->fSquareRadius; //zwiêkszenie zakresu widocznoœci
|
||
grupuj¹cego
|
||
pTriGroup->pTriGroup=Node; //poprzedniemu doczepiamy nowy
|
||
}
|
||
Node->pTriGroup=Node; //nowy lider ma siê sam wyœwietlaæ - wskaŸnik na siebie
|
||
pTriGroup=Node; //zapamiêtanie lidera
|
||
}
|
||
*/
|
||
break;
|
||
case TP_TRACTION:
|
||
case GL_LINES:
|
||
case GL_LINE_STRIP:
|
||
case GL_LINE_LOOP: // te renderowane na koñcu, ¿eby nie ³apa³y koloru nieba
|
||
Node->nNext3 = nRenderWires;
|
||
nRenderWires = Node; // lista drutów
|
||
break;
|
||
case TP_MODEL: // modele zawsze wyœwietlane z w³asnego VBO
|
||
// jeœli model jest prosty, mo¿na próbowaæ zrobiæ wspóln¹ siatkê (s³upy)
|
||
if ((Node->iFlags & 0x20200020) == 0) // czy brak przezroczystoœci?
|
||
{
|
||
Node->nNext3 = nRender;
|
||
nRender = Node;
|
||
} // do nieprzezroczystych
|
||
else if ((Node->iFlags & 0x10100010) == 0) // czy brak nieprzezroczystoœci?
|
||
{
|
||
Node->nNext3 = nRenderAlpha;
|
||
nRenderAlpha = Node;
|
||
} // do przezroczystych
|
||
else // jak i take i takie, to bêdzie dwa razy renderowane...
|
||
{
|
||
Node->nNext3 = nRenderMixed;
|
||
nRenderMixed = Node;
|
||
} // do mieszanych
|
||
// Node->nNext3=nMeshed; //dopisanie do listy sortowania
|
||
// nMeshed=Node;
|
||
break;
|
||
case TP_MEMCELL:
|
||
case TP_TRACTIONPOWERSOURCE: // a te w ogóle pomijamy
|
||
// case TP_ISOLATED: //lista torów w obwodzie izolowanym - na razie ignorowana
|
||
break;
|
||
case TP_DYNAMIC:
|
||
return; // tych nie dopisujemy wcale
|
||
}
|
||
Node->nNext2 = nRootNode; // dopisanie do ogólnej listy
|
||
nRootNode = Node;
|
||
++iNodeCount; // licznik obiektów
|
||
}
|
||
|
||
void TSubRect::RaNodeAdd(TGroundNode *Node)
|
||
{ // finalna kwalifikacja na listy renderowania, jeœli nie obs³ugiwane grupowo
|
||
switch (Node->iType)
|
||
{
|
||
case TP_TRACK:
|
||
if (Global::bUseVBO)
|
||
{
|
||
Node->nNext3 = nRenderRect;
|
||
nRenderRect = Node;
|
||
} // VBO: do nieprzezroczystych z sektora
|
||
else
|
||
{
|
||
Node->nNext3 = nRender;
|
||
nRender = Node;
|
||
} // DL: do nieprzezroczystych
|
||
break;
|
||
case GL_TRIANGLE_STRIP:
|
||
case GL_TRIANGLE_FAN:
|
||
case GL_TRIANGLES:
|
||
if (Node->iFlags & 0x20) // czy jest przezroczyste?
|
||
{
|
||
Node->nNext3 = nRenderRectAlpha;
|
||
nRenderRectAlpha = Node;
|
||
} // DL: do przezroczystych z sektora
|
||
else if (Global::bUseVBO)
|
||
{
|
||
Node->nNext3 = nRenderRect;
|
||
nRenderRect = Node;
|
||
} // VBO: do nieprzezroczystych z sektora
|
||
else
|
||
{
|
||
Node->nNext3 = nRender;
|
||
nRender = Node;
|
||
} // DL: do nieprzezroczystych wszelakich
|
||
break;
|
||
case TP_MODEL: // modele zawsze wyœwietlane z w³asnego VBO
|
||
if ((Node->iFlags & 0x20200020) == 0) // czy brak przezroczystoœci?
|
||
{
|
||
Node->nNext3 = nRender;
|
||
nRender = Node;
|
||
} // do nieprzezroczystych
|
||
else if ((Node->iFlags & 0x10100010) == 0) // czy brak nieprzezroczystoœci?
|
||
{
|
||
Node->nNext3 = nRenderAlpha;
|
||
nRenderAlpha = Node;
|
||
} // do przezroczystych
|
||
else // jak i take i takie, to bêdzie dwa razy renderowane...
|
||
{
|
||
Node->nNext3 = nRenderMixed;
|
||
nRenderMixed = Node;
|
||
} // do mieszanych
|
||
break;
|
||
case TP_MESH: // grupa ze wspóln¹ tekstur¹
|
||
//{Node->nNext3=nRenderRect; nRenderRect=Node;} //do nieprzezroczystych z sektora
|
||
{
|
||
Node->nNext3 = nRender;
|
||
nRender = Node;
|
||
} // do nieprzezroczystych
|
||
break;
|
||
case TP_SUBMODEL: // submodele terenu w kwadracie kilometrowym id¹ do nRootMesh
|
||
// WriteLog("nRootMesh was "+AnsiString(nRootMesh?"not null ":"null
|
||
// ")+IntToHex(int(this),8));
|
||
Node->nNext3 = nRootMesh; // przy VBO musi byæ inaczej
|
||
nRootMesh = Node;
|
||
break;
|
||
}
|
||
}
|
||
|
||
void TSubRect::Sort()
|
||
{ // przygotowanie sektora do renderowania
|
||
TGroundNode **n0, *n1, *n2; // wskaŸniki robocze
|
||
delete[] tTracks; // usuniêcie listy
|
||
tTracks =
|
||
iTracks ? new TTrack *[iTracks] : NULL; // tworzenie tabeli torów do renderowania pojazdów
|
||
if (tTracks)
|
||
{ // wype³nianie tabeli torów
|
||
int i = 0;
|
||
for (n1 = nRootNode; n1; n1 = n1->nNext2) // kolejne obiekty z sektora
|
||
if (n1->iType == TP_TRACK)
|
||
tTracks[i++] = n1->pTrack;
|
||
}
|
||
// sortowanie obiektów w sektorze na listy renderowania
|
||
if (!nMeshed)
|
||
return; // nie ma nic do sortowania
|
||
bool sorted = false;
|
||
while (!sorted)
|
||
{ // sortowanie b¹belkowe obiektów wg tekstury
|
||
sorted = true; // zak³adamy posortowanie
|
||
n0 = &nMeshed; // wskaŸnik niezbêdny do zamieniania obiektów
|
||
n1 = nMeshed; // lista obiektów przetwarzanych na statyczne siatki
|
||
while (n1)
|
||
{ // sprawdzanie stanu posortowania obiektów i ewentualne zamiany
|
||
n2 = n1->nNext3; // kolejny z tej listy
|
||
if (n2) // jeœli istnieje
|
||
if (n1->TextureID > n2->TextureID)
|
||
{ // zamiana elementów miejscami
|
||
*n0 = n2; // drugi bêdzie na pocz¹tku
|
||
n1->nNext3 = n2->nNext3; // ten zza drugiego bêdzie za pierwszym
|
||
n2->nNext3 = n1; // a za drugim bêdzie pierwszy
|
||
sorted = false; // potrzebny kolejny przebieg
|
||
}
|
||
n0 = &(n1->nNext3);
|
||
n1 = n2;
|
||
};
|
||
}
|
||
// wyrzucenie z listy obiektów pojedynczych (nie ma z czym ich grupowaæ)
|
||
// nawet jak s¹ pojedyncze, to i tak lepiej, aby by³y w jednym Display List
|
||
/*
|
||
else
|
||
{//dodanie do zwyk³ej listy renderowania i usuniêcie z grupowego
|
||
*n0=n2; //drugi bêdzie na pocz¹tku
|
||
RaNodeAdd(n1); //nie ma go z czym zgrupowaæ; (n1->nNext3) zostanie nadpisane
|
||
n1=n2; //potrzebne do ustawienia (n0)
|
||
}
|
||
*/
|
||
//...
|
||
// przegl¹danie listy i tworzenie obiektów renderuj¹cych dla danej tekstury
|
||
GLuint t = 0; // pomocniczy kod tekstury
|
||
n1 = nMeshed; // lista obiektów przetwarzanych na statyczne siatki
|
||
while (n1)
|
||
{ // dla ka¿dej tekstury powinny istnieæ co najmniej dwa obiekty, ale dla DL nie ma to znaczenia
|
||
if (t < n1->TextureID) // jeœli (n1) ma inn¹ teksturê ni¿ poprzednie
|
||
{ // mo¿na zrobiæ obiekt renderuj¹cy
|
||
t = n1->TextureID;
|
||
n2 = new TGroundNode();
|
||
n2->nNext2 = nRootMesh;
|
||
nRootMesh = n2; // podczepienie na pocz¹tku listy
|
||
nRootMesh->iType = TP_MESH; // obiekt renderuj¹cy siatki dla tekstury
|
||
nRootMesh->TextureID = t;
|
||
nRootMesh->nNode = n1; // pierwszy element z listy
|
||
nRootMesh->pCenter = n1->pCenter;
|
||
nRootMesh->fSquareRadius = 1e8; // widaæ bez ograniczeñ
|
||
nRootMesh->fSquareMinRadius = 0.0;
|
||
nRootMesh->iFlags = 0x10;
|
||
RaNodeAdd(nRootMesh); // dodanie do odpowiedniej listy renderowania
|
||
}
|
||
n1 = n1->nNext3; // kolejny z tej listy
|
||
};
|
||
}
|
||
|
||
TTrack *__fastcall TSubRect::FindTrack(vector3 *Point, int &iConnection, TTrack *Exclude)
|
||
{ // szukanie toru, którego koniec jest najbli¿szy (*Point)
|
||
TTrack *Track;
|
||
for (int i = 0; i < iTracks; ++i)
|
||
if (tTracks[i] != Exclude) // mo¿na u¿yæ tabelê torów, bo jest mniejsza
|
||
{
|
||
iConnection = tTracks[i]->TestPoint(Point);
|
||
if (iConnection >= 0)
|
||
return tTracks[i]; // szukanie TGroundNode nie jest potrzebne
|
||
}
|
||
/*
|
||
TGroundNode *Current;
|
||
for (Current=nRootNode;Current;Current=Current->Next)
|
||
if ((Current->iType==TP_TRACK)&&(Current->pTrack!=Exclude)) //mo¿na u¿yæ tabelê torów
|
||
{
|
||
iConnection=Current->pTrack->TestPoint(Point);
|
||
if (iConnection>=0) return Current;
|
||
}
|
||
*/
|
||
return NULL;
|
||
};
|
||
|
||
bool TSubRect::RaTrackAnimAdd(TTrack *t)
|
||
{ // aktywacja animacji torów w VBO (zwrotnica, obrotnica)
|
||
if (m_nVertexCount < 0)
|
||
return true; // nie ma animacji, gdy nie widaæ
|
||
if (tTrackAnim)
|
||
tTrackAnim->RaAnimListAdd(t);
|
||
else
|
||
tTrackAnim = t;
|
||
return false; // bêdzie animowane...
|
||
}
|
||
|
||
void TSubRect::RaAnimate()
|
||
{ // wykonanie animacji
|
||
if (!tTrackAnim)
|
||
return; // nie ma nic do animowania
|
||
if (Global::bUseVBO)
|
||
{ // odœwie¿enie VBO sektora
|
||
if (Global::bOpenGL_1_5) // modyfikacje VBO s¹ dostêpne od OpenGL 1.5
|
||
glBindBufferARB(GL_ARRAY_BUFFER_ARB, m_nVBOVertices);
|
||
else // dla OpenGL 1.4 z GL_ARB_vertex_buffer_object odœwie¿enie ca³ego sektora
|
||
Release(); // opró¿nienie VBO sektora, aby siê odœwie¿y³ z nowymi ustawieniami
|
||
}
|
||
tTrackAnim = tTrackAnim->RaAnimate(); // przeliczenie animacji kolejnego
|
||
};
|
||
|
||
TTraction *__fastcall TSubRect::FindTraction(vector3 *Point, int &iConnection, TTraction *Exclude)
|
||
{ // szukanie przês³a w sektorze, którego koniec jest najbli¿szy (*Point)
|
||
TGroundNode *Current;
|
||
for (Current = nRenderWires; Current; Current = Current->nNext3)
|
||
if ((Current->iType == TP_TRACTION) && (Current->hvTraction != Exclude))
|
||
{
|
||
iConnection = Current->hvTraction->TestPoint(Point);
|
||
if (iConnection >= 0)
|
||
return Current->hvTraction;
|
||
}
|
||
return NULL;
|
||
};
|
||
|
||
void TSubRect::LoadNodes()
|
||
{ // utworzenie siatek VBO dla wszystkich node w sektorze
|
||
if (m_nVertexCount >= 0)
|
||
return; // obiekty by³y ju¿ sprawdzone
|
||
m_nVertexCount = 0; //-1 oznacza, ¿e nie sprawdzono listy obiektów
|
||
if (!nRootNode)
|
||
return;
|
||
TGroundNode *n = nRootNode;
|
||
while (n)
|
||
{
|
||
switch (n->iType)
|
||
{
|
||
case GL_TRIANGLE_STRIP:
|
||
case GL_TRIANGLE_FAN:
|
||
case GL_TRIANGLES:
|
||
n->iVboPtr = m_nVertexCount; // nowy pocz¹tek
|
||
m_nVertexCount += n->iNumVerts;
|
||
break;
|
||
case GL_LINES:
|
||
case GL_LINE_STRIP:
|
||
case GL_LINE_LOOP:
|
||
n->iVboPtr = m_nVertexCount; // nowy pocz¹tek
|
||
m_nVertexCount +=
|
||
n->iNumPts; // miejsce w tablicach normalnych i teksturowania siê zmarnuje...
|
||
break;
|
||
case TP_TRACK:
|
||
n->iVboPtr = m_nVertexCount; // nowy pocz¹tek
|
||
n->iNumVerts = n->pTrack->RaArrayPrepare(); // zliczenie wierzcho³ków
|
||
m_nVertexCount += n->iNumVerts;
|
||
break;
|
||
case TP_TRACTION:
|
||
n->iVboPtr = m_nVertexCount; // nowy pocz¹tek
|
||
n->iNumVerts = n->hvTraction->RaArrayPrepare(); // zliczenie wierzcho³ków
|
||
m_nVertexCount += n->iNumVerts;
|
||
break;
|
||
}
|
||
n = n->nNext2; // nastêpny z sektora
|
||
}
|
||
if (!m_nVertexCount)
|
||
return; // jeœli nie ma obiektów do wyœwietlenia z VBO, to koniec
|
||
if (Global::bUseVBO)
|
||
{ // tylko liczenie wierzcho³ów, gdy nie ma VBO
|
||
MakeArray(m_nVertexCount);
|
||
n = nRootNode;
|
||
int i;
|
||
while (n)
|
||
{
|
||
if (n->iVboPtr >= 0)
|
||
switch (n->iType)
|
||
{
|
||
case GL_TRIANGLE_STRIP:
|
||
case GL_TRIANGLE_FAN:
|
||
case GL_TRIANGLES:
|
||
for (i = 0; i < n->iNumVerts; ++i)
|
||
{ // Ra: trójk¹ty mo¿na od razu wczytywaæ do takich tablic... to mo¿e poczekaæ
|
||
m_pVNT[n->iVboPtr + i].x = n->Vertices[i].Point.x;
|
||
m_pVNT[n->iVboPtr + i].y = n->Vertices[i].Point.y;
|
||
m_pVNT[n->iVboPtr + i].z = n->Vertices[i].Point.z;
|
||
m_pVNT[n->iVboPtr + i].nx = n->Vertices[i].Normal.x;
|
||
m_pVNT[n->iVboPtr + i].ny = n->Vertices[i].Normal.y;
|
||
m_pVNT[n->iVboPtr + i].nz = n->Vertices[i].Normal.z;
|
||
m_pVNT[n->iVboPtr + i].u = n->Vertices[i].tu;
|
||
m_pVNT[n->iVboPtr + i].v = n->Vertices[i].tv;
|
||
}
|
||
break;
|
||
case GL_LINES:
|
||
case GL_LINE_STRIP:
|
||
case GL_LINE_LOOP:
|
||
for (i = 0; i < n->iNumPts; ++i)
|
||
{
|
||
m_pVNT[n->iVboPtr + i].x = n->Points[i].x;
|
||
m_pVNT[n->iVboPtr + i].y = n->Points[i].y;
|
||
m_pVNT[n->iVboPtr + i].z = n->Points[i].z;
|
||
// miejsce w tablicach normalnych i teksturowania siê marnuje...
|
||
}
|
||
break;
|
||
case TP_TRACK:
|
||
if (n->iNumVerts) // bo tory zabezpieczaj¹ce s¹ niewidoczne
|
||
n->pTrack->RaArrayFill(m_pVNT + n->iVboPtr, m_pVNT);
|
||
break;
|
||
case TP_TRACTION:
|
||
if (n->iNumVerts) // druty mog¹ byæ niewidoczne...?
|
||
n->hvTraction->RaArrayFill(m_pVNT + n->iVboPtr);
|
||
break;
|
||
}
|
||
n = n->nNext2; // nastêpny z sektora
|
||
}
|
||
BuildVBOs();
|
||
}
|
||
if (Global::bManageNodes)
|
||
ResourceManager::Register(this); // dodanie do automatu zwalniaj¹cego pamiêæ
|
||
}
|
||
|
||
bool TSubRect::StartVBO()
|
||
{ // pocz¹tek rysowania elementów z VBO w sektorze
|
||
SetLastUsage(Timer::GetSimulationTime()); // te z ty³u bêd¹ niepotrzebnie zwalniane
|
||
return CMesh::StartVBO();
|
||
};
|
||
|
||
void TSubRect::Release()
|
||
{ // wirtualne zwolnienie zasobów przez sprz¹tacz albo destruktor
|
||
if (Global::bUseVBO)
|
||
CMesh::Clear(); // usuwanie buforów
|
||
};
|
||
|
||
void TSubRect::RenderDL()
|
||
{ // renderowanie nieprzezroczystych (DL)
|
||
TGroundNode *node;
|
||
RaAnimate(); // przeliczenia animacji torów w sektorze
|
||
for (node = nRender; node; node = node->nNext3)
|
||
node->RenderDL(); // nieprzezroczyste obiekty (oprócz pojazdów)
|
||
for (node = nRenderMixed; node; node = node->nNext3)
|
||
node->RenderDL(); // nieprzezroczyste z mieszanych modeli
|
||
for (int j = 0; j < iTracks; ++j)
|
||
tTracks[j]->RenderDyn(); // nieprzezroczyste fragmenty pojazdów na torach
|
||
};
|
||
|
||
void TSubRect::RenderAlphaDL()
|
||
{ // renderowanie przezroczystych modeli oraz pojazdów (DL)
|
||
TGroundNode *node;
|
||
for (node = nRenderMixed; node; node = node->nNext3)
|
||
node->RenderAlphaDL(); // przezroczyste z mieszanych modeli
|
||
for (node = nRenderAlpha; node; node = node->nNext3)
|
||
node->RenderAlphaDL(); // przezroczyste modele
|
||
// for (node=tmp->nRender;node;node=node->nNext3)
|
||
// if (node->iType==TP_TRACK)
|
||
// node->pTrack->RenderAlpha(); //przezroczyste fragmenty pojazdów na torach
|
||
for (int j = 0; j < iTracks; ++j)
|
||
tTracks[j]->RenderDynAlpha(); // przezroczyste fragmenty pojazdów na torach
|
||
};
|
||
|
||
void TSubRect::RenderVBO()
|
||
{ // renderowanie nieprzezroczystych (VBO)
|
||
TGroundNode *node;
|
||
RaAnimate(); // przeliczenia animacji torów w sektorze
|
||
LoadNodes(); // czemu tutaj?
|
||
if (StartVBO())
|
||
{
|
||
for (node = nRenderRect; node; node = node->nNext3)
|
||
if (node->iVboPtr >= 0)
|
||
node->RenderVBO(); // nieprzezroczyste obiekty terenu
|
||
EndVBO();
|
||
}
|
||
for (node = nRender; node; node = node->nNext3)
|
||
node->RenderVBO(); // nieprzezroczyste obiekty (oprócz pojazdów)
|
||
for (node = nRenderMixed; node; node = node->nNext3)
|
||
node->RenderVBO(); // nieprzezroczyste z mieszanych modeli
|
||
for (int j = 0; j < iTracks; ++j)
|
||
tTracks[j]->RenderDyn(); // nieprzezroczyste fragmenty pojazdów na torach
|
||
};
|
||
|
||
void TSubRect::RenderAlphaVBO()
|
||
{ // renderowanie przezroczystych modeli oraz pojazdów (VBO)
|
||
TGroundNode *node;
|
||
for (node = nRenderMixed; node; node = node->nNext3)
|
||
node->RenderAlphaVBO(); // przezroczyste z mieszanych modeli
|
||
for (node = nRenderAlpha; node; node = node->nNext3)
|
||
node->RenderAlphaVBO(); // przezroczyste modele
|
||
// for (node=tmp->nRender;node;node=node->nNext3)
|
||
// if (node->iType==TP_TRACK)
|
||
// node->pTrack->RenderAlpha(); //przezroczyste fragmenty pojazdów na torach
|
||
for (int j = 0; j < iTracks; ++j)
|
||
tTracks[j]->RenderDynAlpha(); // przezroczyste fragmenty pojazdów na torach
|
||
};
|
||
|
||
void TSubRect::RenderSounds()
|
||
{ // aktualizacja dŸwiêków w pojazdach sektora (sektor mo¿e nie byæ wyœwietlany)
|
||
for (int j = 0; j < iTracks; ++j)
|
||
tTracks[j]->RenderDynSounds(); // dŸwiêki pojazdów id¹ niezale¿nie od wyœwietlania
|
||
};
|
||
//---------------------------------------------------------------------------
|
||
//------------------ Kwadrat kilometrowy ------------------------------------
|
||
//---------------------------------------------------------------------------
|
||
int TGroundRect::iFrameNumber = 0; // licznik wyœwietlanych klatek
|
||
|
||
TGroundRect::TGroundRect()
|
||
{
|
||
pSubRects = NULL;
|
||
nTerrain = NULL;
|
||
};
|
||
|
||
TGroundRect::~TGroundRect()
|
||
{
|
||
SafeDeleteArray(pSubRects);
|
||
};
|
||
|
||
void TGroundRect::RenderDL()
|
||
{ // renderowanie kwadratu kilometrowego (DL), jeœli jeszcze nie zrobione
|
||
if (iLastDisplay != iFrameNumber)
|
||
{ // tylko jezeli dany kwadrat nie by³ jeszcze renderowany
|
||
// for (TGroundNode* node=pRender;node;node=node->pNext3)
|
||
// node->Render(); //nieprzezroczyste trójk¹ty kwadratu kilometrowego
|
||
if (nRender)
|
||
{ //³¹czenie trójk¹tów w jedn¹ listê - trochê wioska
|
||
if (!nRender->DisplayListID || (nRender->iVersion != Global::iReCompile))
|
||
{ // je¿eli nie skompilowany, kompilujemy wszystkie trójk¹ty w jeden
|
||
nRender->fSquareRadius = 5000.0 * 5000.0; // aby agregat nigdy nie znika³
|
||
nRender->DisplayListID = glGenLists(1);
|
||
glNewList(nRender->DisplayListID, GL_COMPILE);
|
||
nRender->iVersion = Global::iReCompile; // aktualna wersja siatek
|
||
for (TGroundNode *node = nRender; node; node = node->nNext3) // nastêpny tej grupy
|
||
node->Compile(true);
|
||
glEndList();
|
||
}
|
||
nRender->RenderDL(); // nieprzezroczyste trójk¹ty kwadratu kilometrowego
|
||
}
|
||
if (nRootMesh)
|
||
nRootMesh->RenderDL();
|
||
iLastDisplay = iFrameNumber; // drugi raz nie potrzeba
|
||
}
|
||
};
|
||
|
||
void TGroundRect::RenderVBO()
|
||
{ // renderowanie kwadratu kilometrowego (VBO), jeœli jeszcze nie zrobione
|
||
if (iLastDisplay != iFrameNumber)
|
||
{ // tylko jezeli dany kwadrat nie by³ jeszcze renderowany
|
||
LoadNodes(); // ewentualne tworzenie siatek
|
||
if (StartVBO())
|
||
{
|
||
for (TGroundNode *node = nRenderRect; node; node = node->nNext3) // nastêpny tej grupy
|
||
node->RaRenderVBO(); // nieprzezroczyste trójk¹ty kwadratu kilometrowego
|
||
EndVBO();
|
||
iLastDisplay = iFrameNumber;
|
||
}
|
||
if (nTerrain)
|
||
nTerrain->smTerrain->iVisible = iFrameNumber; // ma siê wyœwietliæ w tej ramce
|
||
}
|
||
};
|
||
|
||
//---------------------------------------------------------------------------
|
||
//---------------------------------------------------------------------------
|
||
//---------------------------------------------------------------------------
|
||
|
||
void TGround::MoveGroundNode(vector3 pPosition)
|
||
{ // Ra: to wymaga gruntownej reformy
|
||
/*
|
||
TGroundNode *Current;
|
||
for (Current=RootNode;Current!=NULL;Current=Current->Next)
|
||
Current->MoveMe(pPosition);
|
||
|
||
TGroundRect *Rectx=new TGroundRect; //kwadrat kilometrowy
|
||
for(int i=0;i<iNumRects;i++)
|
||
for(int j=0;j<iNumRects;j++)
|
||
Rects[i][j]=*Rectx; //kopiowanie zawartoœci do ka¿dego kwadratu
|
||
delete Rectx;
|
||
for (Current=RootNode;Current!=NULL;Current=Current->Next)
|
||
{//roz³o¿enie obiektów na mapie
|
||
if (Current->iType!=TP_DYNAMIC)
|
||
{//pojazdów to w ogóle nie dotyczy
|
||
if ((Current->iType!=GL_TRIANGLES)&&(Current->iType!=GL_TRIANGLE_STRIP)?true //~czy trójk¹t?
|
||
:(Current->iFlags&0x20)?true //~czy teksturê ma nieprzezroczyst¹?
|
||
//:(Current->iNumVerts!=3)?true //~czy tylko jeden trójk¹t?
|
||
:(Current->fSquareMinRadius!=0.0)?true //~czy widoczny z bliska?
|
||
:(Current->fSquareRadius<=90000.0)) //~czy widoczny z daleka?
|
||
GetSubRect(Current->pCenter.x,Current->pCenter.z)->AddNode(Current);
|
||
else //dodajemy do kwadratu kilometrowego
|
||
GetRect(Current->pCenter.x,Current->pCenter.z)->AddNode(Current);
|
||
}
|
||
}
|
||
for (Current=RootDynamic;Current!=NULL;Current=Current->Next)
|
||
{
|
||
Current->pCenter+=pPosition;
|
||
Current->DynamicObject->UpdatePos();
|
||
}
|
||
for (Current=RootDynamic;Current!=NULL;Current=Current->Next)
|
||
Current->DynamicObject->MoverParameters->Physic_ReActivation();
|
||
*/
|
||
}
|
||
|
||
TGround::TGround()
|
||
{
|
||
// RootNode=NULL;
|
||
nRootDynamic = NULL;
|
||
QueryRootEvent = NULL;
|
||
tmpEvent = NULL;
|
||
tmp2Event = NULL;
|
||
OldQRE = NULL;
|
||
RootEvent = NULL;
|
||
iNumNodes = 0;
|
||
// pTrain=NULL;
|
||
Global::pGround = this;
|
||
bInitDone = false; // Ra: ¿eby nie robi³o dwa razy FirstInit
|
||
for (int i = 0; i < TP_LAST; i++)
|
||
nRootOfType[i] = NULL; // zerowanie tablic wyszukiwania
|
||
bDynamicRemove = false; // na razie nic do usuniêcia
|
||
sTracks = new TNames(); // nazwy torów - na razie tak
|
||
}
|
||
|
||
TGround::~TGround()
|
||
{
|
||
Free();
|
||
}
|
||
|
||
void TGround::Free()
|
||
{
|
||
TEvent *tmp;
|
||
for (TEvent *Current = RootEvent; Current;)
|
||
{
|
||
tmp = Current;
|
||
Current = Current->evNext2;
|
||
delete tmp;
|
||
}
|
||
TGroundNode *tmpn;
|
||
for (int i = 0; i < TP_LAST; ++i)
|
||
{
|
||
for (TGroundNode *Current = nRootOfType[i]; Current;)
|
||
{
|
||
tmpn = Current;
|
||
Current = Current->nNext;
|
||
delete tmpn;
|
||
}
|
||
nRootOfType[i] = NULL;
|
||
}
|
||
for (TGroundNode *Current = nRootDynamic; Current;)
|
||
{
|
||
tmpn = Current;
|
||
Current = Current->nNext;
|
||
delete tmpn;
|
||
}
|
||
iNumNodes = 0;
|
||
// RootNode=NULL;
|
||
nRootDynamic = NULL;
|
||
delete sTracks;
|
||
}
|
||
|
||
TGroundNode *__fastcall TGround::DynamicFindAny(AnsiString asNameToFind)
|
||
{ // wyszukanie pojazdu o podanej nazwie, szukanie po wszystkich (u¿yæ drzewa!)
|
||
for (TGroundNode *Current = nRootDynamic; Current; Current = Current->nNext)
|
||
if ((Current->asName == asNameToFind))
|
||
return Current;
|
||
return NULL;
|
||
};
|
||
|
||
TGroundNode *__fastcall TGround::DynamicFind(AnsiString asNameToFind)
|
||
{ // wyszukanie pojazdu z obsad¹ o podanej nazwie (u¿yæ drzewa!)
|
||
for (TGroundNode *Current = nRootDynamic; Current; Current = Current->nNext)
|
||
if (Current->DynamicObject->Mechanik)
|
||
if ((Current->asName == asNameToFind))
|
||
return Current;
|
||
return NULL;
|
||
};
|
||
|
||
void TGround::DynamicList(bool all)
|
||
{ // odes³anie nazw pojazdów dostêpnych na scenerii (nazwy, szczególnie wagonów, mog¹ siê
|
||
// powtarzaæ!)
|
||
for (TGroundNode *Current = nRootDynamic; Current; Current = Current->nNext)
|
||
if (all || Current->DynamicObject->Mechanik)
|
||
WyslijString(Current->asName, 6); // same nazwy pojazdów
|
||
WyslijString("none", 6); // informacja o koñcu listy
|
||
};
|
||
|
||
TGroundNode *__fastcall TGround::FindGroundNode(AnsiString asNameToFind, TGroundNodeType iNodeType)
|
||
{ // wyszukiwanie obiektu o podanej nazwie i konkretnym typie
|
||
if ((iNodeType == TP_TRACK) || (iNodeType == TP_MEMCELL) || (iNodeType == TP_MODEL))
|
||
{ // wyszukiwanie w drzewie binarnym
|
||
return (TGroundNode *)sTracks->Find(iNodeType, asNameToFind.c_str());
|
||
}
|
||
// standardowe wyszukiwanie liniowe
|
||
TGroundNode *Current;
|
||
for (Current = nRootOfType[iNodeType]; Current; Current = Current->nNext)
|
||
if (Current->asName == asNameToFind)
|
||
return Current;
|
||
return NULL;
|
||
}
|
||
|
||
double fTrainSetVel = 0;
|
||
double fTrainSetDir = 0;
|
||
double fTrainSetDist = 0; // odleg³oœæ sk³adu od punktu 1 w stronê punktu 2
|
||
AnsiString asTrainSetTrack = "";
|
||
int iTrainSetConnection = 0;
|
||
bool bTrainSet = false;
|
||
AnsiString asTrainName = "";
|
||
int iTrainSetWehicleNumber = 0;
|
||
TGroundNode *nTrainSetNode = NULL; // poprzedni pojazd do ³¹czenia
|
||
TGroundNode *nTrainSetDriver = NULL; // pojazd, któremu zostanie wys³any rozk³ad
|
||
|
||
TGroundVertex TempVerts[10000]; // tu wczytywane s¹ trójk¹ty
|
||
Byte TempConnectionType[200]; // Ra: sprzêgi w sk³adzie; ujemne, gdy odwrotnie
|
||
|
||
void TGround::RaTriangleDivider(TGroundNode *node)
|
||
{ // tworzy dodatkowe trójk¹ty i zmiejsza podany
|
||
// to jest wywo³ywane przy wczytywaniu trójk¹tów
|
||
// dodatkowe trójk¹ty s¹ dodawane do g³ównej listy trójk¹tów
|
||
// podzia³ trójk¹tów na sektory i kwadraty jest dokonywany póŸniej w FirstInit
|
||
if (node->iType != GL_TRIANGLES)
|
||
return; // tylko pojedyncze trójk¹ty
|
||
if (node->iNumVerts != 3)
|
||
return; // tylko gdy jeden trójk¹t
|
||
double x0 = 1000.0 * floor(0.001 * node->pCenter.x) - 200.0;
|
||
double x1 = x0 + 1400.0;
|
||
double z0 = 1000.0 * floor(0.001 * node->pCenter.z) - 200.0;
|
||
double z1 = z0 + 1400.0;
|
||
if ((node->Vertices[0].Point.x >= x0) && (node->Vertices[0].Point.x <= x1) &&
|
||
(node->Vertices[0].Point.z >= z0) && (node->Vertices[0].Point.z <= z1) &&
|
||
(node->Vertices[1].Point.x >= x0) && (node->Vertices[1].Point.x <= x1) &&
|
||
(node->Vertices[1].Point.z >= z0) && (node->Vertices[1].Point.z <= z1) &&
|
||
(node->Vertices[2].Point.x >= x0) && (node->Vertices[2].Point.x <= x1) &&
|
||
(node->Vertices[2].Point.z >= z0) && (node->Vertices[2].Point.z <= z1))
|
||
return; // trójk¹t wystaj¹cy mniej ni¿ 200m z kw. kilometrowego jest do przyjêcia
|
||
// Ra: przerobiæ na dzielenie na 2 trójk¹ty, podzia³ w przeciêciu z siatk¹ kilometrow¹
|
||
// Ra: i z rekurencj¹ bêdzie dzieliæ trzy trójk¹ty, jeœli bêdzie taka potrzeba
|
||
int divide = -1; // bok do podzielenia: 0=AB, 1=BC, 2=CA; +4=podzia³ po OZ; +8 na x1/z1
|
||
double min = 0, mul; // jeœli przechodzi przez oœ, iloczyn bêdzie ujemny
|
||
x0 += 200.0;
|
||
x1 -= 200.0; // przestawienie na siatkê
|
||
z0 += 200.0;
|
||
z1 -= 200.0;
|
||
mul = (node->Vertices[0].Point.x - x0) * (node->Vertices[1].Point.x - x0); // AB na wschodzie
|
||
if (mul < min)
|
||
min = mul, divide = 0;
|
||
mul = (node->Vertices[1].Point.x - x0) * (node->Vertices[2].Point.x - x0); // BC na wschodzie
|
||
if (mul < min)
|
||
min = mul, divide = 1;
|
||
mul = (node->Vertices[2].Point.x - x0) * (node->Vertices[0].Point.x - x0); // CA na wschodzie
|
||
if (mul < min)
|
||
min = mul, divide = 2;
|
||
mul = (node->Vertices[0].Point.x - x1) * (node->Vertices[1].Point.x - x1); // AB na zachodzie
|
||
if (mul < min)
|
||
min = mul, divide = 8;
|
||
mul = (node->Vertices[1].Point.x - x1) * (node->Vertices[2].Point.x - x1); // BC na zachodzie
|
||
if (mul < min)
|
||
min = mul, divide = 9;
|
||
mul = (node->Vertices[2].Point.x - x1) * (node->Vertices[0].Point.x - x1); // CA na zachodzie
|
||
if (mul < min)
|
||
min = mul, divide = 10;
|
||
mul = (node->Vertices[0].Point.z - z0) * (node->Vertices[1].Point.z - z0); // AB na po³udniu
|
||
if (mul < min)
|
||
min = mul, divide = 4;
|
||
mul = (node->Vertices[1].Point.z - z0) * (node->Vertices[2].Point.z - z0); // BC na po³udniu
|
||
if (mul < min)
|
||
min = mul, divide = 5;
|
||
mul = (node->Vertices[2].Point.z - z0) * (node->Vertices[0].Point.z - z0); // CA na po³udniu
|
||
if (mul < min)
|
||
min = mul, divide = 6;
|
||
mul = (node->Vertices[0].Point.z - z1) * (node->Vertices[1].Point.z - z1); // AB na pó³nocy
|
||
if (mul < min)
|
||
min = mul, divide = 12;
|
||
mul = (node->Vertices[1].Point.z - z1) * (node->Vertices[2].Point.z - z1); // BC na pó³nocy
|
||
if (mul < min)
|
||
min = mul, divide = 13;
|
||
mul = (node->Vertices[2].Point.z - z1) * (node->Vertices[0].Point.z - z1); // CA na pó³nocy
|
||
if (mul < min)
|
||
divide = 14;
|
||
// tworzymy jeden dodatkowy trójk¹t, dziel¹c jeden bok na przeciêciu siatki kilometrowej
|
||
TGroundNode *ntri; // wskaŸnik na nowy trójk¹t
|
||
ntri = new TGroundNode(); // a ten jest nowy
|
||
ntri->iType = GL_TRIANGLES; // kopiowanie parametrów, przyda³by siê konstruktor kopiuj¹cy
|
||
ntri->Init(3);
|
||
ntri->TextureID = node->TextureID;
|
||
ntri->iFlags = node->iFlags;
|
||
for (int j = 0; j < 4; ++j)
|
||
{
|
||
ntri->Ambient[j] = node->Ambient[j];
|
||
ntri->Diffuse[j] = node->Diffuse[j];
|
||
ntri->Specular[j] = node->Specular[j];
|
||
}
|
||
ntri->asName = node->asName;
|
||
ntri->fSquareRadius = node->fSquareRadius;
|
||
ntri->fSquareMinRadius = node->fSquareMinRadius;
|
||
ntri->bVisible = node->bVisible; // a s¹ jakieœ niewidoczne?
|
||
ntri->nNext = nRootOfType[GL_TRIANGLES];
|
||
nRootOfType[GL_TRIANGLES] = ntri; // dopisanie z przodu do listy
|
||
iNumNodes++;
|
||
switch (divide & 3)
|
||
{ // podzielenie jednego z boków, powstaje wierzcho³ek D
|
||
case 0: // podzia³ AB (0-1) -> ADC i DBC
|
||
ntri->Vertices[2] = node->Vertices[2]; // wierzcho³ek C jest wspólny
|
||
ntri->Vertices[1] = node->Vertices[1]; // wierzcho³ek B przechodzi do nowego
|
||
// node->Vertices[1].HalfSet(node->Vertices[0],node->Vertices[1]); //na razie D tak
|
||
if (divide & 4)
|
||
node->Vertices[1].SetByZ(node->Vertices[0], node->Vertices[1], divide & 8 ? z1 : z0);
|
||
else
|
||
node->Vertices[1].SetByX(node->Vertices[0], node->Vertices[1], divide & 8 ? x1 : x0);
|
||
ntri->Vertices[0] = node->Vertices[1]; // wierzcho³ek D jest wspólny
|
||
break;
|
||
case 1: // podzia³ BC (1-2) -> ABD i ADC
|
||
ntri->Vertices[0] = node->Vertices[0]; // wierzcho³ek A jest wspólny
|
||
ntri->Vertices[2] = node->Vertices[2]; // wierzcho³ek C przechodzi do nowego
|
||
// node->Vertices[2].HalfSet(node->Vertices[1],node->Vertices[2]); //na razie D tak
|
||
if (divide & 4)
|
||
node->Vertices[2].SetByZ(node->Vertices[1], node->Vertices[2], divide & 8 ? z1 : z0);
|
||
else
|
||
node->Vertices[2].SetByX(node->Vertices[1], node->Vertices[2], divide & 8 ? x1 : x0);
|
||
ntri->Vertices[1] = node->Vertices[2]; // wierzcho³ek D jest wspólny
|
||
break;
|
||
case 2: // podzia³ CA (2-0) -> ABD i DBC
|
||
ntri->Vertices[1] = node->Vertices[1]; // wierzcho³ek B jest wspólny
|
||
ntri->Vertices[2] = node->Vertices[2]; // wierzcho³ek C przechodzi do nowego
|
||
// node->Vertices[2].HalfSet(node->Vertices[2],node->Vertices[0]); //na razie D tak
|
||
if (divide & 4)
|
||
node->Vertices[2].SetByZ(node->Vertices[2], node->Vertices[0], divide & 8 ? z1 : z0);
|
||
else
|
||
node->Vertices[2].SetByX(node->Vertices[2], node->Vertices[0], divide & 8 ? x1 : x0);
|
||
ntri->Vertices[0] = node->Vertices[2]; // wierzcho³ek D jest wspólny
|
||
break;
|
||
}
|
||
// przeliczenie œrodków ciê¿koœci obu
|
||
node->pCenter =
|
||
(node->Vertices[0].Point + node->Vertices[1].Point + node->Vertices[2].Point) / 3.0;
|
||
ntri->pCenter =
|
||
(ntri->Vertices[0].Point + ntri->Vertices[1].Point + ntri->Vertices[2].Point) / 3.0;
|
||
RaTriangleDivider(node); // rekurencja, bo nawet na TD raz nie wystarczy
|
||
RaTriangleDivider(ntri);
|
||
};
|
||
|
||
TGroundNode *__fastcall TGround::AddGroundNode(cParser *parser)
|
||
{ // wczytanie wpisu typu "node"
|
||
// parser->LoadTraction=Global::bLoadTraction; //Ra: tu nie potrzeba powtarzaæ
|
||
AnsiString str, str1, str2, str3, str4, Skin, DriverType, asNodeName;
|
||
int nv, ti, i, n;
|
||
double tf, r, rmin, tf1, tf2, tf3, tf4, l, dist, mgn;
|
||
int int1, int2;
|
||
bool bError = false, curve;
|
||
vector3 pt, front, up, left, pos, tv;
|
||
matrix4x4 mat2, mat1, mat;
|
||
GLuint TexID;
|
||
TGroundNode *tmp1;
|
||
TTrack *Track;
|
||
TTextSound *tmpsound;
|
||
std::string token;
|
||
parser->getTokens(2);
|
||
*parser >> r >> rmin;
|
||
parser->getTokens();
|
||
*parser >> token;
|
||
asNodeName = AnsiString(token.c_str());
|
||
parser->getTokens();
|
||
*parser >> token;
|
||
str = AnsiString(token.c_str());
|
||
TGroundNode *tmp, *tmp2;
|
||
tmp = new TGroundNode();
|
||
tmp->asName = (asNodeName == AnsiString("none") ? AnsiString("") : asNodeName);
|
||
if (r >= 0)
|
||
tmp->fSquareRadius = r * r;
|
||
tmp->fSquareMinRadius = rmin * rmin;
|
||
if (str == "triangles")
|
||
tmp->iType = GL_TRIANGLES;
|
||
else if (str == "triangle_strip")
|
||
tmp->iType = GL_TRIANGLE_STRIP;
|
||
else if (str == "triangle_fan")
|
||
tmp->iType = GL_TRIANGLE_FAN;
|
||
else if (str == "lines")
|
||
tmp->iType = GL_LINES;
|
||
else if (str == "line_strip")
|
||
tmp->iType = GL_LINE_STRIP;
|
||
else if (str == "line_loop")
|
||
tmp->iType = GL_LINE_LOOP;
|
||
else if (str == "model")
|
||
tmp->iType = TP_MODEL;
|
||
// else if (str=="terrain") tmp->iType=TP_TERRAIN; //tymczasowo do odwo³ania
|
||
else if (str == "dynamic")
|
||
tmp->iType = TP_DYNAMIC;
|
||
else if (str == "sound")
|
||
tmp->iType = TP_SOUND;
|
||
else if (str == "track")
|
||
tmp->iType = TP_TRACK;
|
||
else if (str == "memcell")
|
||
tmp->iType = TP_MEMCELL;
|
||
else if (str == "eventlauncher")
|
||
tmp->iType = TP_EVLAUNCH;
|
||
else if (str == "traction")
|
||
tmp->iType = TP_TRACTION;
|
||
else if (str == "tractionpowersource")
|
||
tmp->iType = TP_TRACTIONPOWERSOURCE;
|
||
// else if (str=="isolated") tmp->iType=TP_ISOLATED;
|
||
else
|
||
bError = true;
|
||
// WriteLog("-> node "+str+" "+tmp->asName);
|
||
if (bError)
|
||
{
|
||
Error(AnsiString("Scene parse error near " + str).c_str());
|
||
for (int i = 0; i < 60; ++i)
|
||
{ // Ra: skopiowanie dalszej czêœci do logu - taka prowizorka, lepsza ni¿ nic
|
||
parser->getTokens(); // pobranie linijki tekstu nie dzia³a
|
||
*parser >> token;
|
||
WriteLog(token.c_str());
|
||
}
|
||
// if (tmp==RootNode) RootNode=NULL;
|
||
delete tmp;
|
||
return NULL;
|
||
}
|
||
switch (tmp->iType)
|
||
{
|
||
case TP_TRACTION:
|
||
tmp->hvTraction = new TTraction();
|
||
parser->getTokens();
|
||
*parser >> token;
|
||
tmp->hvTraction->asPowerSupplyName = AnsiString(token.c_str()); // nazwa zasilacza
|
||
parser->getTokens(3);
|
||
*parser >> tmp->hvTraction->NominalVoltage >> tmp->hvTraction->MaxCurrent >>
|
||
tmp->hvTraction->fResistivity;
|
||
if (tmp->hvTraction->fResistivity == 0.01) // tyle jest w sceneriach [om/km]
|
||
tmp->hvTraction->fResistivity = 0.075; // taka sensowniejsza wartoϾ za
|
||
// http://www.ikolej.pl/fileadmin/user_upload/Seminaria_IK/13_05_07_Prezentacja_Kruczek.pdf
|
||
tmp->hvTraction->fResistivity *= 0.001; // teraz [om/m]
|
||
parser->getTokens();
|
||
*parser >> token;
|
||
// Ra 2014-02: a tutaj damy symbol sieci i jej budowê, np.:
|
||
// SKB70-C, CuCd70-2C, KB95-2C, C95-C, C95-2C, YC95-2C, YpC95-2C, YC120-2C
|
||
// YpC120-2C, YzC120-2C, YwsC120-2C, YC150-C150, YC150-2C150, C150-C150
|
||
// C120-2C, 2C120-2C, 2C120-2C-1, 2C120-2C-2, 2C120-2C-3, 2C120-2C-4
|
||
if (token.compare("none") == 0)
|
||
tmp->hvTraction->Material = 0;
|
||
else if (token.compare("al") == 0)
|
||
tmp->hvTraction->Material = 2; // 1=aluminiowa, rysuje siê na czarno
|
||
else
|
||
tmp->hvTraction->Material = 1; // 1=miedziana, rysuje siê na zielono albo czerwono
|
||
parser->getTokens();
|
||
*parser >> tmp->hvTraction->WireThickness;
|
||
parser->getTokens();
|
||
*parser >> tmp->hvTraction->DamageFlag;
|
||
parser->getTokens(3);
|
||
*parser >> tmp->hvTraction->pPoint1.x >> tmp->hvTraction->pPoint1.y >>
|
||
tmp->hvTraction->pPoint1.z;
|
||
tmp->hvTraction->pPoint1 += pOrigin;
|
||
parser->getTokens(3);
|
||
*parser >> tmp->hvTraction->pPoint2.x >> tmp->hvTraction->pPoint2.y >>
|
||
tmp->hvTraction->pPoint2.z;
|
||
tmp->hvTraction->pPoint2 += pOrigin;
|
||
parser->getTokens(3);
|
||
*parser >> tmp->hvTraction->pPoint3.x >> tmp->hvTraction->pPoint3.y >>
|
||
tmp->hvTraction->pPoint3.z;
|
||
tmp->hvTraction->pPoint3 += pOrigin;
|
||
parser->getTokens(3);
|
||
*parser >> tmp->hvTraction->pPoint4.x >> tmp->hvTraction->pPoint4.y >>
|
||
tmp->hvTraction->pPoint4.z;
|
||
tmp->hvTraction->pPoint4 += pOrigin;
|
||
parser->getTokens();
|
||
*parser >> tf1;
|
||
tmp->hvTraction->fHeightDifference =
|
||
(tmp->hvTraction->pPoint3.y - tmp->hvTraction->pPoint1.y + tmp->hvTraction->pPoint4.y -
|
||
tmp->hvTraction->pPoint2.y) *
|
||
0.5f -
|
||
tf1;
|
||
parser->getTokens();
|
||
*parser >> tf1;
|
||
if (tf1 > 0)
|
||
tmp->hvTraction->iNumSections =
|
||
(tmp->hvTraction->pPoint1 - tmp->hvTraction->pPoint2).Length() / tf1;
|
||
else
|
||
tmp->hvTraction->iNumSections = 0;
|
||
parser->getTokens();
|
||
*parser >> tmp->hvTraction->Wires;
|
||
parser->getTokens();
|
||
*parser >> tmp->hvTraction->WireOffset;
|
||
parser->getTokens();
|
||
*parser >> token;
|
||
tmp->bVisible = (token.compare("vis") == 0);
|
||
parser->getTokens();
|
||
*parser >> token;
|
||
if (token.compare("parallel") == 0)
|
||
{ // jawne wskazanie innego przês³a, na które mo¿e przestawiæ siê pantograf
|
||
parser->getTokens();
|
||
*parser >> token; // wypada³o by to zapamiêtaæ...
|
||
tmp->hvTraction->asParallel = AnsiString(token.c_str());
|
||
parser->getTokens();
|
||
*parser >> token; // a tu ju¿ powinien byæ koniec
|
||
}
|
||
if (token.compare("endtraction") != 0)
|
||
Error("ENDTRACTION delimiter missing! " + str2 + " found instead.");
|
||
tmp->hvTraction->Init(); // przeliczenie parametrów
|
||
// if (Global::bLoadTraction)
|
||
// tmp->hvTraction->Optimize(); //generowanie DL dla wszystkiego przy wczytywaniu?
|
||
tmp->pCenter = (tmp->hvTraction->pPoint2 + tmp->hvTraction->pPoint1) * 0.5f;
|
||
// if (!Global::bLoadTraction) SafeDelete(tmp); //Ra: tak byæ nie mo¿e, bo NULL to b³¹d
|
||
break;
|
||
case TP_TRACTIONPOWERSOURCE:
|
||
parser->getTokens(3);
|
||
*parser >> tmp->pCenter.x >> tmp->pCenter.y >> tmp->pCenter.z;
|
||
tmp->pCenter += pOrigin;
|
||
tmp->psTractionPowerSource = new TTractionPowerSource();
|
||
tmp->psTractionPowerSource->gMyNode =
|
||
tmp; // Ra 2015-03: znowu prowizorka, aby mieæ nazwê do logowania
|
||
tmp->psTractionPowerSource->Load(parser);
|
||
break;
|
||
case TP_MEMCELL:
|
||
parser->getTokens(3);
|
||
*parser >> tmp->pCenter.x >> tmp->pCenter.y >> tmp->pCenter.z;
|
||
tmp->pCenter.RotateY(aRotate.y / 180.0 * M_PI); // Ra 2014-11: uwzglêdnienie rotacji
|
||
tmp->pCenter += pOrigin;
|
||
tmp->MemCell = new TMemCell(&tmp->pCenter);
|
||
tmp->MemCell->Load(parser);
|
||
if (!tmp->asName.IsEmpty()) // jest pusta gdy "none"
|
||
{ // dodanie do wyszukiwarki
|
||
if (sTracks->Update(TP_MEMCELL, tmp->asName.c_str(),
|
||
tmp)) // najpierw sprawdziæ, czy ju¿ jest
|
||
{ // przy zdublowaniu wskaŸnik zostanie podmieniony w drzewku na póŸniejszy (zgodnoœæ
|
||
// wsteczna)
|
||
ErrorLog("Duplicated memcell: " + tmp->asName); // to zg³aszaæ duplikat
|
||
}
|
||
else
|
||
sTracks->Add(TP_MEMCELL, tmp->asName.c_str(), tmp); // nazwa jest unikalna
|
||
}
|
||
break;
|
||
case TP_EVLAUNCH:
|
||
parser->getTokens(3);
|
||
*parser >> tmp->pCenter.x >> tmp->pCenter.y >> tmp->pCenter.z;
|
||
tmp->pCenter.RotateY(aRotate.y / 180.0 * M_PI); // Ra 2014-11: uwzglêdnienie rotacji
|
||
tmp->pCenter += pOrigin;
|
||
tmp->EvLaunch = new TEventLauncher();
|
||
tmp->EvLaunch->Load(parser);
|
||
break;
|
||
case TP_TRACK:
|
||
tmp->pTrack = new TTrack(tmp);
|
||
if (Global::iWriteLogEnabled & 4)
|
||
if (!tmp->asName.IsEmpty())
|
||
WriteLog(tmp->asName.c_str());
|
||
tmp->pTrack->Load(parser, pOrigin,
|
||
tmp->asName); // w nazwie mo¿e byæ nazwa odcinka izolowanego
|
||
if (!tmp->asName.IsEmpty()) // jest pusta gdy "none"
|
||
{ // dodanie do wyszukiwarki
|
||
if (sTracks->Update(TP_TRACK, tmp->asName.c_str(),
|
||
tmp)) // najpierw sprawdziæ, czy ju¿ jest
|
||
{ // przy zdublowaniu wskaŸnik zostanie podmieniony w drzewku na póŸniejszy (zgodnoœæ
|
||
// wsteczna)
|
||
if (tmp->pTrack->iCategoryFlag & 1) // jeœli jest zdublowany tor kolejowy
|
||
ErrorLog("Duplicated track: " + tmp->asName); // to zg³aszaæ duplikat
|
||
}
|
||
else
|
||
sTracks->Add(TP_TRACK, tmp->asName.c_str(), tmp); // nazwa jest unikalna
|
||
}
|
||
tmp->pCenter = (tmp->pTrack->CurrentSegment()->FastGetPoint_0() +
|
||
tmp->pTrack->CurrentSegment()->FastGetPoint(0.5) +
|
||
tmp->pTrack->CurrentSegment()->FastGetPoint_1()) /
|
||
3.0;
|
||
break;
|
||
case TP_SOUND:
|
||
tmp->tsStaticSound = new TTextSound;
|
||
parser->getTokens(3);
|
||
*parser >> tmp->pCenter.x >> tmp->pCenter.y >> tmp->pCenter.z;
|
||
tmp->pCenter.RotateY(aRotate.y / 180.0 * M_PI); // Ra 2014-11: uwzglêdnienie rotacji
|
||
tmp->pCenter += pOrigin;
|
||
parser->getTokens();
|
||
*parser >> token;
|
||
str = AnsiString(token.c_str());
|
||
tmp->tsStaticSound->Init(str.c_str(), sqrt(tmp->fSquareRadius), tmp->pCenter.x,
|
||
tmp->pCenter.y, tmp->pCenter.z, false, rmin);
|
||
if (rmin < 0.0)
|
||
rmin =
|
||
0.0; // przywrócenie poprawnej wartoœci, jeœli s³u¿y³a do wy³¹czenia efektu Dopplera
|
||
|
||
// tmp->pDirectSoundBuffer=TSoundsManager::GetFromName(str.c_str());
|
||
// tmp->iState=(Parser->GetNextSymbol().LowerCase()=="loop"?DSBPLAY_LOOPING:0);
|
||
parser->getTokens();
|
||
*parser >> token;
|
||
break;
|
||
case TP_DYNAMIC:
|
||
tmp->DynamicObject = new TDynamicObject();
|
||
// tmp->DynamicObject->Load(Parser);
|
||
parser->getTokens();
|
||
*parser >> token;
|
||
str1 = AnsiString(token.c_str()); // katalog
|
||
// McZapkie: doszedl parametr ze zmienialna skora
|
||
parser->getTokens();
|
||
*parser >> token;
|
||
Skin = AnsiString(token.c_str()); // tekstura wymienna
|
||
parser->getTokens();
|
||
*parser >> token;
|
||
str3 = AnsiString(token.c_str()); // McZapkie-131102: model w MMD
|
||
if (bTrainSet)
|
||
{ // jeœli pojazd jest umieszczony w sk³adzie
|
||
str = asTrainSetTrack;
|
||
parser->getTokens();
|
||
*parser >> tf1; // Ra: -1 oznacza odwrotne wstawienie, normalnie w sk³adzie 0
|
||
parser->getTokens();
|
||
*parser >> token;
|
||
DriverType = AnsiString(token.c_str()); // McZapkie:010303 - w przyszlosci rozne
|
||
// konfiguracje mechanik/pomocnik itp
|
||
tf3 = fTrainSetVel; // prêdkoœæ
|
||
parser->getTokens();
|
||
*parser >> token;
|
||
str4 = AnsiString(token.c_str());
|
||
int2 = str4.Pos("."); // yB: wykorzystuje tutaj zmienna, ktora potem bedzie ladunkiem
|
||
if (int2 > 0) // yB: jesli znalazl kropke, to ja przetwarza jako parametry
|
||
{
|
||
int dlugosc = str4.Length();
|
||
int1 = str4.SubString(1, int2 - 1).ToInt(); // niech sprzegiem bedzie do kropki cos
|
||
str4 = str4.SubString(int2 + 1, dlugosc - int2);
|
||
}
|
||
else
|
||
{
|
||
int1 = str4.ToInt();
|
||
str4 = "";
|
||
}
|
||
int2 = 0; // zeruje po wykorzystaniu
|
||
// *parser >> int1; //yB: nastawy i takie tam TUTAJ!!!!!
|
||
if (int1 < 0)
|
||
int1 = (-int1) |
|
||
ctrain_depot; // sprzêg zablokowany (pojazdy nieroz³¹czalne przy manewrach)
|
||
if (tf1 != -1.0)
|
||
if (fabs(tf1) > 0.5) // maksymalna odleg³oœæ miêdzy sprzêgami - do przemyœlenia
|
||
int1 = 0; // likwidacja sprzêgu, jeœli odleg³oœæ zbyt du¿a - to powinno byæ
|
||
// uwzglêdniane w fizyce sprzêgów...
|
||
TempConnectionType[iTrainSetWehicleNumber] = int1; // wartoϾ dodatnia
|
||
}
|
||
else
|
||
{ // pojazd wstawiony luzem
|
||
fTrainSetDist = 0; // zerowanie dodatkowego przesuniêcia
|
||
asTrainName = ""; // puste oznacza jazdê pojedynczego bez rozk³adu, "none" jest dla
|
||
// sk³adu (trainset)
|
||
parser->getTokens();
|
||
*parser >> token;
|
||
str = AnsiString(token.c_str()); // track
|
||
parser->getTokens();
|
||
*parser >> tf1; // Ra: -1 oznacza odwrotne wstawienie
|
||
parser->getTokens();
|
||
*parser >> token;
|
||
DriverType = AnsiString(token.c_str()); // McZapkie:010303: obsada
|
||
parser->getTokens();
|
||
*parser >>
|
||
tf3; // prêdkoœæ, niektórzy wpisuj¹ tu "3" jako sprzêg, ¿eby nie by³o tabliczki
|
||
iTrainSetWehicleNumber = 0;
|
||
TempConnectionType[iTrainSetWehicleNumber] = 3; // likwidacja tabliczki na koñcu?
|
||
}
|
||
parser->getTokens();
|
||
*parser >> int2; // iloœæ ³adunku
|
||
if (int2 > 0)
|
||
{ // je¿eli ³adunku jest wiêcej ni¿ 0, to rozpoznajemy jego typ
|
||
parser->getTokens();
|
||
*parser >> token;
|
||
str2 = AnsiString(token.c_str()); // LoadType
|
||
if (str2 == AnsiString("enddynamic")) // idiotoodpornoœæ: ³adunek bez podanego typu
|
||
{
|
||
str2 = "";
|
||
int2 = 0; // iloœæ bez typu siê nie liczy jako ³adunek
|
||
}
|
||
}
|
||
else
|
||
str2 = ""; // brak ladunku
|
||
|
||
tmp1 = FindGroundNode(str, TP_TRACK); // poszukiwanie toru
|
||
if (tmp1 ? tmp1->pTrack != NULL : false)
|
||
{ // jeœli tor znaleziony
|
||
Track = tmp1->pTrack;
|
||
if (!iTrainSetWehicleNumber) // jeœli pierwszy pojazd
|
||
if (Track->evEvent0) // jeœli tor ma Event0
|
||
if (fabs(fTrainSetVel) <= 1.0) // a sk³ad stoi
|
||
if (fTrainSetDist >= 0.0) // ale mo¿e nie siêgaæ na owy tor
|
||
if (fTrainSetDist < 8.0) // i raczej nie siêga
|
||
fTrainSetDist =
|
||
8.0; // przesuwamy oko³o pó³ EU07 dla wstecznej zgodnoœci
|
||
// WriteLog("Dynamic shift: "+AnsiString(fTrainSetDist));
|
||
/* //Ra: to jednak robi du¿e problemy - przesuniêcie w dynamic jest przesuniêciem do
|
||
ty³u, odwrotnie ni¿ w trainset
|
||
if (!iTrainSetWehicleNumber) //dla pierwszego jest to przesuniêcie (ujemne = do
|
||
ty³u)
|
||
if (tf1!=-1.0) //-1 wyj¹tkowo oznacza odwrócenie
|
||
tf1=-tf1; //a dla kolejnych odleg³oœæ miêdzy sprzêgami (ujemne = wbite)
|
||
*/
|
||
tf3 = tmp->DynamicObject->Init(asNodeName, str1, Skin, str3, Track,
|
||
(tf1 == -1.0 ? fTrainSetDist : fTrainSetDist - tf1),
|
||
DriverType, tf3, asTrainName, int2, str2, (tf1 == -1.0),
|
||
str4);
|
||
if (tf3 != 0.0) // zero oznacza b³¹d
|
||
{
|
||
fTrainSetDist -=
|
||
tf3; // przesuniêcie dla kolejnego, minus bo idziemy w stronê punktu 1
|
||
tmp->pCenter = tmp->DynamicObject->GetPosition();
|
||
if (TempConnectionType[iTrainSetWehicleNumber]) // jeœli jest sprzêg
|
||
if (tmp->DynamicObject->MoverParameters->Couplers[tf1 == -1.0 ? 0 : 1]
|
||
.AllowedFlag &
|
||
ctrain_depot) // jesli zablokowany
|
||
TempConnectionType[iTrainSetWehicleNumber] |= ctrain_depot; // bêdzie
|
||
// blokada
|
||
iTrainSetWehicleNumber++;
|
||
}
|
||
else
|
||
{ // LastNode=NULL;
|
||
delete tmp;
|
||
tmp = NULL; // nie mo¿e byæ tu return, bo trzeba pomin¹æ jeszcze enddynamic
|
||
}
|
||
}
|
||
else
|
||
{ // gdy tor nie znaleziony
|
||
ErrorLog("Missed track: dynamic placed on \"" + tmp->DynamicObject->asTrack + "\"");
|
||
delete tmp;
|
||
tmp = NULL; // nie mo¿e byæ tu return, bo trzeba pomin¹æ jeszcze enddynamic
|
||
}
|
||
parser->getTokens();
|
||
*parser >> token;
|
||
if (token.compare("destination") == 0)
|
||
{ // dok¹d wagon ma jechaæ, uwzglêdniane przy manewrach
|
||
parser->getTokens();
|
||
*parser >> token;
|
||
if (tmp)
|
||
tmp->DynamicObject->asDestination = AnsiString(token.c_str());
|
||
*parser >> token;
|
||
}
|
||
if (token.compare("enddynamic") != 0)
|
||
Error("enddynamic statement missing");
|
||
break;
|
||
case TP_MODEL:
|
||
if (rmin < 0)
|
||
{
|
||
tmp->iType = TP_TERRAIN;
|
||
tmp->fSquareMinRadius = 0; // to w ogóle potrzebne?
|
||
}
|
||
parser->getTokens(3);
|
||
*parser >> tmp->pCenter.x >> tmp->pCenter.y >> tmp->pCenter.z;
|
||
parser->getTokens();
|
||
*parser >> tf1;
|
||
// OlO_EU&KAKISH-030103: obracanie punktow zaczepien w modelu
|
||
tmp->pCenter.RotateY(aRotate.y / 180.0 * M_PI);
|
||
// McZapkie-260402: model tez ma wspolrzedne wzgledne
|
||
tmp->pCenter += pOrigin;
|
||
// tmp->fAngle+=aRotate.y; // /180*M_PI
|
||
/*
|
||
if (tmp->iType==TP_MODEL)
|
||
{//jeœli standardowy model
|
||
*/
|
||
tmp->Model = new TAnimModel();
|
||
tmp->Model->RaAnglesSet(aRotate.x, tf1 + aRotate.y,
|
||
aRotate.z); // dostosowanie do pochylania linii
|
||
if (tmp->Model->Load(
|
||
parser, tmp->iType == TP_TERRAIN)) // wczytanie modelu, tekstury i stanu œwiate³...
|
||
tmp->iFlags =
|
||
tmp->Model->Flags() | 0x200; // ustalenie, czy przezroczysty; flaga usuwania
|
||
else if (tmp->iType != TP_TERRAIN)
|
||
{ // model nie wczyta³ siê - ignorowanie node
|
||
delete tmp;
|
||
tmp = NULL; // nie mo¿e byæ tu return
|
||
break; // nie mo¿e byæ tu return?
|
||
}
|
||
/*
|
||
}
|
||
else if (tmp->iType==TP_TERRAIN)
|
||
{//nie potrzeba nak³adki animuj¹cej submodele
|
||
*parser >> token;
|
||
tmp->pModel3D=TModelsManager::GetModel(token.c_str(),false);
|
||
do //Ra: z tym to trochê bez sensu jest
|
||
{parser->getTokens();
|
||
*parser >> token;
|
||
str=AnsiString(token.c_str());
|
||
} while (str!="endterrains");
|
||
}
|
||
*/
|
||
if (tmp->iType == TP_TERRAIN)
|
||
{ // jeœli model jest terenem, trzeba utworzyæ dodatkowe obiekty
|
||
// po wczytaniu model ma ju¿ utworzone DL albo VBO
|
||
Global::pTerrainCompact = tmp->Model; // istnieje co najmniej jeden obiekt terenu
|
||
tmp->iCount = Global::pTerrainCompact->TerrainCount() + 1; // zliczenie submodeli
|
||
tmp->nNode = new TGroundNode[tmp->iCount]; // sztuczne node dla kwadratów
|
||
tmp->nNode[0].iType = TP_MODEL; // pierwszy zawiera model (dla delete)
|
||
tmp->nNode[0].Model = Global::pTerrainCompact;
|
||
tmp->nNode[0].iFlags = 0x200; // nie wyœwietlany, ale usuwany
|
||
for (i = 1; i < tmp->iCount; ++i)
|
||
{ // a reszta to submodele
|
||
tmp->nNode[i].iType = TP_SUBMODEL; //
|
||
tmp->nNode[i].smTerrain = Global::pTerrainCompact->TerrainSquare(i - 1);
|
||
tmp->nNode[i].iFlags = 0x10; // nieprzezroczyste; nie usuwany
|
||
tmp->nNode[i].bVisible = true;
|
||
tmp->nNode[i].pCenter = tmp->pCenter; // nie przesuwamy w inne miejsce
|
||
// tmp->nNode[i].asName=
|
||
}
|
||
}
|
||
else if (!tmp->asName.IsEmpty()) // jest pusta gdy "none"
|
||
{ // dodanie do wyszukiwarki
|
||
if (sTracks->Update(TP_MODEL, tmp->asName.c_str(),
|
||
tmp)) // najpierw sprawdziæ, czy ju¿ jest
|
||
{ // przy zdublowaniu wskaŸnik zostanie podmieniony w drzewku na póŸniejszy (zgodnoœæ
|
||
// wsteczna)
|
||
ErrorLog("Duplicated model: " + tmp->asName); // to zg³aszaæ duplikat
|
||
}
|
||
else
|
||
sTracks->Add(TP_MODEL, tmp->asName.c_str(), tmp); // nazwa jest unikalna
|
||
}
|
||
// str=Parser->GetNextSymbol().LowerCase();
|
||
break;
|
||
// case TP_GEOMETRY :
|
||
case GL_TRIANGLES:
|
||
case GL_TRIANGLE_STRIP:
|
||
case GL_TRIANGLE_FAN:
|
||
parser->getTokens();
|
||
*parser >> token;
|
||
// McZapkie-050702: opcjonalne wczytywanie parametrow materialu (ambient,diffuse,specular)
|
||
if (token.compare("material") == 0)
|
||
{
|
||
parser->getTokens();
|
||
*parser >> token;
|
||
while (token.compare("endmaterial") != 0)
|
||
{
|
||
if (token.compare("ambient:") == 0)
|
||
{
|
||
parser->getTokens();
|
||
*parser >> tmp->Ambient[0];
|
||
parser->getTokens();
|
||
*parser >> tmp->Ambient[1];
|
||
parser->getTokens();
|
||
*parser >> tmp->Ambient[2];
|
||
}
|
||
else if (token.compare("diffuse:") == 0)
|
||
{ // Ra: coœ jest nie tak, bo w jednej linijce nie dzia³a
|
||
parser->getTokens();
|
||
*parser >> tmp->Diffuse[0];
|
||
parser->getTokens();
|
||
*parser >> tmp->Diffuse[1];
|
||
parser->getTokens();
|
||
*parser >> tmp->Diffuse[2];
|
||
}
|
||
else if (token.compare("specular:") == 0)
|
||
{
|
||
parser->getTokens();
|
||
*parser >> tmp->Specular[0];
|
||
parser->getTokens();
|
||
*parser >> tmp->Specular[1];
|
||
parser->getTokens();
|
||
*parser >> tmp->Specular[2];
|
||
}
|
||
else
|
||
Error("Scene material failure!");
|
||
parser->getTokens();
|
||
*parser >> token;
|
||
}
|
||
}
|
||
if (token.compare("endmaterial") == 0)
|
||
{
|
||
parser->getTokens();
|
||
*parser >> token;
|
||
}
|
||
str = AnsiString(token.c_str());
|
||
#ifdef _PROBLEND
|
||
// PROBLEND Q: 13122011 - Szociu: 27012012
|
||
PROBLEND = true; // domyslnie uruchomione nowe wyœwietlanie
|
||
tmp->PROBLEND = true; // odwolanie do tgroundnode, bo rendering jest w tej klasie
|
||
if (str.Pos("@") > 0) // sprawdza, czy w nazwie tekstury jest znak "@"
|
||
{
|
||
PROBLEND = false; // jeœli jest, wyswietla po staremu
|
||
tmp->PROBLEND = false;
|
||
}
|
||
#endif
|
||
tmp->TextureID = TTexturesManager::GetTextureID(szTexturePath, szSceneryPath, str.c_str());
|
||
tmp->iFlags = TTexturesManager::GetAlpha(tmp->TextureID) ? 0x220 : 0x210; // z usuwaniem
|
||
if (((tmp->iType == GL_TRIANGLES) && (tmp->iFlags & 0x10)) ?
|
||
Global::pTerrainCompact->TerrainLoaded() :
|
||
false)
|
||
{ // jeœli jest tekstura nieprzezroczysta, a teren za³adowany, to pomijamy trójk¹ty
|
||
do
|
||
{ // pomijanie trójk¹tów
|
||
parser->getTokens();
|
||
*parser >> token;
|
||
} while (token.compare("endtri") != 0);
|
||
// delete tmp; //nie ma co tego trzymaæ
|
||
// tmp=NULL; //to jest b³¹d
|
||
}
|
||
else
|
||
{
|
||
i = 0;
|
||
do
|
||
{
|
||
if (i < 9999) // 3333 trójk¹ty
|
||
{ // liczba wierzcho³ków nie jest nieograniczona
|
||
parser->getTokens(3);
|
||
*parser >> TempVerts[i].Point.x >> TempVerts[i].Point.y >> TempVerts[i].Point.z;
|
||
parser->getTokens(3);
|
||
*parser >> TempVerts[i].Normal.x >> TempVerts[i].Normal.y >>
|
||
TempVerts[i].Normal.z;
|
||
/*
|
||
str=Parser->GetNextSymbol().LowerCase();
|
||
if (str==AnsiString("x"))
|
||
TempVerts[i].tu=(TempVerts[i].Point.x+Parser->GetNextSymbol().ToDouble())/Parser->GetNextSymbol().ToDouble();
|
||
else
|
||
if (str==AnsiString("y"))
|
||
TempVerts[i].tu=(TempVerts[i].Point.y+Parser->GetNextSymbol().ToDouble())/Parser->GetNextSymbol().ToDouble();
|
||
else
|
||
if (str==AnsiString("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==AnsiString("x"))
|
||
TempVerts[i].tv=(TempVerts[i].Point.x+Parser->GetNextSymbol().ToDouble())/Parser->GetNextSymbol().ToDouble();
|
||
else
|
||
if (str==AnsiString("y"))
|
||
TempVerts[i].tv=(TempVerts[i].Point.y+Parser->GetNextSymbol().ToDouble())/Parser->GetNextSymbol().ToDouble();
|
||
else
|
||
if (str==AnsiString("z"))
|
||
TempVerts[i].tv=(TempVerts[i].Point.z+Parser->GetNextSymbol().ToDouble())/Parser->GetNextSymbol().ToDouble();
|
||
else
|
||
TempVerts[i].tv=str.ToDouble();;
|
||
*/
|
||
parser->getTokens(2);
|
||
*parser >> TempVerts[i].tu >> TempVerts[i].tv;
|
||
|
||
// 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;
|
||
}
|
||
else if (i == 9999)
|
||
ErrorLog("Bad triangles: too many verices");
|
||
i++;
|
||
parser->getTokens();
|
||
*parser >> token;
|
||
|
||
// }
|
||
|
||
} while (token.compare("endtri") != 0);
|
||
nv = i;
|
||
tmp->Init(nv); // utworzenie tablicy wierzcho³ków
|
||
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;
|
||
RaTriangleDivider(tmp); // Ra: dzielenie trójk¹tów jest teraz ca³kiem wydajne
|
||
} // koniec wczytywania trójk¹tów
|
||
break;
|
||
case GL_LINES:
|
||
case GL_LINE_STRIP:
|
||
case GL_LINE_LOOP:
|
||
parser->getTokens(3);
|
||
*parser >> tmp->Diffuse[0] >> tmp->Diffuse[1] >> tmp->Diffuse[2];
|
||
// tmp->Diffuse[0]=Parser->GetNextSymbol().ToDouble()/255;
|
||
// tmp->Diffuse[1]=Parser->GetNextSymbol().ToDouble()/255;
|
||
// tmp->Diffuse[2]=Parser->GetNextSymbol().ToDouble()/255;
|
||
parser->getTokens();
|
||
*parser >> tmp->fLineThickness;
|
||
i = 0;
|
||
parser->getTokens();
|
||
*parser >> token;
|
||
do
|
||
{
|
||
str = AnsiString(token.c_str());
|
||
TempVerts[i].Point.x = str.ToDouble();
|
||
parser->getTokens(2);
|
||
*parser >> TempVerts[i].Point.y >> TempVerts[i].Point.z;
|
||
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].Point += pOrigin;
|
||
tmp->pCenter += TempVerts[i].Point;
|
||
i++;
|
||
parser->getTokens();
|
||
*parser >> token;
|
||
} while (token.compare("endline") != 0);
|
||
nv = i;
|
||
// tmp->Init(nv);
|
||
tmp->Points = new vector3[nv];
|
||
tmp->iNumPts = nv;
|
||
tmp->pCenter /= (nv > 0 ? nv : 1);
|
||
for (int i = 0; i < nv; i++)
|
||
tmp->Points[i] = TempVerts[i].Point;
|
||
break;
|
||
}
|
||
return tmp;
|
||
}
|
||
|
||
TSubRect *__fastcall TGround::FastGetSubRect(int iCol, int iRow)
|
||
{
|
||
int br, bc, sr, sc;
|
||
br = iRow / iNumSubRects;
|
||
bc = iCol / iNumSubRects;
|
||
sr = iRow - br * iNumSubRects;
|
||
sc = iCol - bc * iNumSubRects;
|
||
if ((br < 0) || (bc < 0) || (br >= iNumRects) || (bc >= iNumRects))
|
||
return NULL;
|
||
return (Rects[br][bc].FastGetRect(sc, sr));
|
||
}
|
||
|
||
TSubRect *__fastcall TGround::GetSubRect(int iCol, int iRow)
|
||
{ // znalezienie ma³ego kwadratu mapy
|
||
int br, bc, sr, sc;
|
||
br = iRow / iNumSubRects; // wspó³rzêdne kwadratu kilometrowego
|
||
bc = iCol / iNumSubRects;
|
||
sr = iRow - br * iNumSubRects; // wspó³rzêdne wzglêne ma³ego kwadratu
|
||
sc = iCol - bc * iNumSubRects;
|
||
if ((br < 0) || (bc < 0) || (br >= iNumRects) || (bc >= iNumRects))
|
||
return NULL; // jeœli poza map¹
|
||
return (Rects[br][bc].SafeGetRect(sc, sr)); // pobranie ma³ego kwadratu
|
||
}
|
||
|
||
TEvent *__fastcall TGround::FindEvent(const AnsiString &asEventName)
|
||
{
|
||
return (TEvent *)sTracks->Find(0, asEventName.c_str()); // wyszukiwanie w drzewie
|
||
/* //powolna wyszukiwarka
|
||
for (TEvent *Current=RootEvent;Current;Current=Current->Next2)
|
||
{
|
||
if (Current->asName==asEventName)
|
||
return Current;
|
||
}
|
||
return NULL;
|
||
*/
|
||
}
|
||
|
||
TEvent *__fastcall TGround::FindEventScan(const AnsiString &asEventName)
|
||
{ // wyszukanie eventu z opcj¹ utworzenia niejawnego dla komórek skanowanych
|
||
TEvent *e = (TEvent *)sTracks->Find(0, asEventName.c_str()); // wyszukiwanie w drzewie eventów
|
||
if (e)
|
||
return e; // jak istnieje, to w porz¹dku
|
||
if (asEventName.SubString(asEventName.Length() - 4, 5) ==
|
||
":scan") // jeszcze mo¿e byæ event niejawny
|
||
{ // no to szukamy komórki pamiêci o nazwie zawartej w evencie
|
||
AnsiString n = asEventName.SubString(1, asEventName.Length() - 5); // do dwukropka
|
||
if (sTracks->Find(TP_MEMCELL, n.c_str())) // jeœli jest takowa komórka pamiêci
|
||
e = new TEvent(n); // utworzenie niejawnego eventu jej odczytu
|
||
}
|
||
return e; // utworzony albo siê nie uda³o
|
||
}
|
||
|
||
void TGround::FirstInit()
|
||
{ // ustalanie zale¿noœci na scenerii przed wczytaniem pojazdów
|
||
if (bInitDone)
|
||
return; // Ra: ¿eby nie robi³o siê dwa razy
|
||
bInitDone = true;
|
||
WriteLog("InitNormals");
|
||
int i, j;
|
||
for (i = 0; i < TP_LAST; ++i)
|
||
{
|
||
for (TGroundNode *Current = nRootOfType[i]; Current; Current = Current->nNext)
|
||
{
|
||
Current->InitNormals();
|
||
if (Current->iType != TP_DYNAMIC)
|
||
{ // pojazdów w ogóle nie dotyczy dodawanie do mapy
|
||
if (i == TP_EVLAUNCH ? Current->EvLaunch->IsGlobal() : false)
|
||
srGlobal.NodeAdd(Current); // dodanie do globalnego obiektu
|
||
else if (i == TP_TERRAIN)
|
||
{ // specjalne przetwarzanie terenu wczytanego z pliku E3D
|
||
AnsiString xxxzzz; // nazwa kwadratu
|
||
TGroundRect *gr;
|
||
for (j = 1; j < Current->iCount; ++j)
|
||
{ // od 1 do koñca s¹ zestawy trójk¹tów
|
||
xxxzzz = AnsiString(Current->nNode[j].smTerrain->pName); // pobranie nazwy
|
||
gr = GetRect(1000 * (xxxzzz.SubString(1, 3).ToIntDef(0) - 500),
|
||
1000 * (xxxzzz.SubString(4, 3).ToIntDef(0) - 500));
|
||
if (Global::bUseVBO)
|
||
gr->nTerrain = Current->nNode + j; // zapamiêtanie
|
||
else
|
||
gr->RaNodeAdd(&Current->nNode[j]);
|
||
}
|
||
}
|
||
// else if
|
||
// ((Current->iType!=GL_TRIANGLES)&&(Current->iType!=GL_TRIANGLE_STRIP)?true
|
||
// //~czy trójk¹t?
|
||
else if ((Current->iType != GL_TRIANGLES) ?
|
||
true //~czy trójk¹t?
|
||
:
|
||
(Current->iFlags & 0x20) ?
|
||
true //~czy teksturê ma nieprzezroczyst¹?
|
||
:
|
||
(Current->fSquareMinRadius != 0.0) ?
|
||
true //~czy widoczny z bliska?
|
||
:
|
||
(Current->fSquareRadius <= 90000.0)) //~czy widoczny z daleka?
|
||
GetSubRect(Current->pCenter.x, Current->pCenter.z)->NodeAdd(Current);
|
||
else // dodajemy do kwadratu kilometrowego
|
||
GetRect(Current->pCenter.x, Current->pCenter.z)->NodeAdd(Current);
|
||
}
|
||
// if (Current->iType!=TP_DYNAMIC)
|
||
// GetSubRect(Current->pCenter.x,Current->pCenter.z)->AddNode(Current);
|
||
}
|
||
}
|
||
for (i = 0; i < iNumRects; ++i)
|
||
for (j = 0; j < iNumRects; ++j)
|
||
Rects[i][j].Optimize(); // optymalizacja obiektów w sektorach
|
||
WriteLog("InitNormals OK");
|
||
WriteLog("InitTracks");
|
||
InitTracks(); //³¹czenie odcinków ze sob¹ i przyklejanie eventów
|
||
WriteLog("InitTracks OK");
|
||
WriteLog("InitTraction");
|
||
InitTraction(); //³¹czenie drutów ze sob¹
|
||
WriteLog("InitTraction OK");
|
||
WriteLog("InitEvents");
|
||
InitEvents();
|
||
WriteLog("InitEvents OK");
|
||
WriteLog("InitLaunchers");
|
||
InitLaunchers();
|
||
WriteLog("InitLaunchers OK");
|
||
WriteLog("InitGlobalTime");
|
||
// ABu 160205: juz nie TODO :)
|
||
GlobalTime = new TMTableTime(
|
||
hh, mm, srh, srm, ssh,
|
||
ssm); // McZapkie-300302: inicjacja czasu rozkladowego - TODO: czytac z trasy!
|
||
WriteLog("InitGlobalTime OK");
|
||
// jeszcze ustawienie pogody, gdyby nie by³o w scenerii wpisów
|
||
glClearColor(Global::AtmoColor[0], Global::AtmoColor[1], Global::AtmoColor[2],
|
||
0.0); // Background Color
|
||
if (Global::fFogEnd > 0)
|
||
{
|
||
glFogi(GL_FOG_MODE, GL_LINEAR);
|
||
glFogfv(GL_FOG_COLOR, Global::FogColor); // set fog color
|
||
glFogf(GL_FOG_START, Global::fFogStart); // fog start depth
|
||
glFogf(GL_FOG_END, Global::fFogEnd); // fog end depth
|
||
glEnable(GL_FOG);
|
||
}
|
||
else
|
||
glDisable(GL_FOG);
|
||
glDisable(GL_LIGHTING);
|
||
glLightfv(GL_LIGHT0, GL_POSITION, Global::lightPos); // daylight position
|
||
glLightfv(GL_LIGHT0, GL_AMBIENT, Global::ambientDayLight); // kolor wszechobceny
|
||
glLightfv(GL_LIGHT0, GL_DIFFUSE, Global::diffuseDayLight); // kolor padaj¹cy
|
||
glLightfv(GL_LIGHT0, GL_SPECULAR, Global::specularDayLight); // kolor odbity
|
||
// musi byæ tutaj, bo wczeœniej nie mieliœmy wartoœci œwiat³a
|
||
if (Global::fMoveLight >= 0.0) // albo tak, albo niech ustala minimum ciemnoœci w nocy
|
||
{
|
||
Global::fLuminance = // obliczenie luminacji "œwiat³a w ciemnoœci"
|
||
+0.150 * Global::ambientDayLight[0] // R
|
||
+ 0.295 * Global::ambientDayLight[1] // G
|
||
+ 0.055 * Global::ambientDayLight[2]; // B
|
||
if (Global::fLuminance > 0.1) // jeœli mia³o by byæ za jasno
|
||
for (int i = 0; i < 3; i++)
|
||
Global::ambientDayLight[i] *=
|
||
0.1 / Global::fLuminance; // ograniczenie jasnoœci w nocy
|
||
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, Global::ambientDayLight);
|
||
}
|
||
else if (Global::bDoubleAmbient) // Ra: wczeœniej by³o ambient dawane na obydwa œwiat³a
|
||
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, Global::ambientDayLight);
|
||
glEnable(GL_LIGHTING);
|
||
WriteLog("FirstInit is done");
|
||
};
|
||
|
||
bool TGround::Init(AnsiString asFile, HDC hDC)
|
||
{ // g³ówne wczytywanie scenerii
|
||
if (asFile.LowerCase().SubString(1, 7) == "scenery")
|
||
asFile.Delete(1, 8); // Ra: usuniêcie niepotrzebnych znaków - zgodnoœæ wstecz z 2003
|
||
WriteLog("Loading scenery from " + asFile);
|
||
Global::pGround = this;
|
||
// pTrain=NULL;
|
||
pOrigin = aRotate = vector3(0, 0, 0); // zerowanie przesuniêcia i obrotu
|
||
AnsiString str = "";
|
||
// TFileStream *fs;
|
||
// int size;
|
||
std::string subpath = Global::asCurrentSceneryPath.c_str(); // "scenery/";
|
||
cParser parser(asFile.c_str(), cParser::buffer_FILE, subpath, Global::bLoadTraction);
|
||
std::string token;
|
||
|
||
/*
|
||
TFileStream *fs;
|
||
fs=new TFileStream(asFile , fmOpenRead | fmShareCompat );
|
||
AnsiString str="";
|
||
int size=fs->Size;
|
||
str.SetLength(size);
|
||
fs->Read(str.c_str(),size);
|
||
str+="";
|
||
delete fs;
|
||
TQueryParserComp *Parser;
|
||
Parser=new TQueryParserComp(NULL);
|
||
Parser->TextToParse=str;
|
||
// Parser->LoadStringToParse(asFile);
|
||
Parser->First();
|
||
AnsiString Token,asFileName;
|
||
*/
|
||
const int OriginStackMaxDepth = 100; // rozmiar stosu dla zagnie¿d¿enia origin
|
||
int OriginStackTop = 0;
|
||
vector3 OriginStack[OriginStackMaxDepth]; // stos zagnie¿d¿enia origin
|
||
|
||
double tf;
|
||
int ParamCount, ParamPos;
|
||
|
||
// ABu: Jezeli nie ma definicji w scenerii to ustawiane ponizsze wartosci:
|
||
hh = 10; // godzina startu
|
||
mm = 30; // minuty startu
|
||
srh = 6; // godzina wschodu slonca
|
||
srm = 0; // minuty wschodu slonca
|
||
ssh = 20; // godzina zachodu slonca
|
||
ssm = 0; // minuty zachodu slonca
|
||
TGroundNode *LastNode = NULL; // do u¿ycia w trainset
|
||
iNumNodes = 0;
|
||
token = "";
|
||
parser.getTokens();
|
||
parser >> token;
|
||
int refresh = 0;
|
||
|
||
while (token != "") //(!Parser->EndOfFile)
|
||
{
|
||
if (refresh == 50)
|
||
{ // SwapBuffers(hDC); //Ra: bez ogranicznika za bardzo spowalnia :( a u niektórych miga
|
||
refresh = 0;
|
||
Global::DoEvents();
|
||
}
|
||
else
|
||
++refresh;
|
||
str = AnsiString(token.c_str());
|
||
if (str == AnsiString("node"))
|
||
{
|
||
LastNode = AddGroundNode(&parser); // rozpoznanie wêz³a
|
||
if (LastNode)
|
||
{ // je¿eli przetworzony poprawnie
|
||
if (LastNode->iType == GL_TRIANGLES)
|
||
{
|
||
if (!LastNode->Vertices)
|
||
SafeDelete(LastNode); // usuwamy nieprzezroczyste trójk¹ty terenu
|
||
}
|
||
else if (Global::bLoadTraction ? false : LastNode->iType == TP_TRACTION)
|
||
SafeDelete(LastNode); // usuwamy druty, jeœli wy³¹czone
|
||
if (LastNode) // dopiero na koniec dopisujemy do tablic
|
||
if (LastNode->iType != TP_DYNAMIC)
|
||
{ // jeœli nie jest pojazdem
|
||
LastNode->nNext = nRootOfType[LastNode->iType]; // ostatni dodany do³¹czamy
|
||
// na koñcu nowego
|
||
nRootOfType[LastNode->iType] =
|
||
LastNode; // ustawienie nowego na pocz¹tku listy
|
||
iNumNodes++;
|
||
}
|
||
else
|
||
{ // jeœli jest pojazdem
|
||
// if (!bInitDone) FirstInit(); //jeœli nie by³o w scenerii
|
||
if (LastNode->DynamicObject->Mechanik) // ale mo¿e byæ pasa¿er
|
||
if (LastNode->DynamicObject->Mechanik
|
||
->Primary()) // jeœli jest g³ównym (pasa¿er nie jest)
|
||
nTrainSetDriver =
|
||
LastNode; // pojazd, któremu zostanie wys³any rozk³ad
|
||
LastNode->nNext = nRootDynamic;
|
||
nRootDynamic = LastNode; // dopisanie z przodu do listy
|
||
// if (bTrainSet && (LastNode?(LastNode->iType==TP_DYNAMIC):false))
|
||
if (nTrainSetNode) // je¿eli istnieje wczeœniejszy TP_DYNAMIC
|
||
nTrainSetNode->DynamicObject->AttachPrev(
|
||
LastNode->DynamicObject,
|
||
TempConnectionType[iTrainSetWehicleNumber - 2]);
|
||
nTrainSetNode = LastNode; // ostatnio wczytany
|
||
if (TempConnectionType[iTrainSetWehicleNumber - 1] ==
|
||
0) // jeœli sprzêg jest zerowy, to wys³aæ rozk³ad do sk³adu
|
||
{ // powinien te¿ tu wchodziæ, gdy pojazd bez trainset
|
||
if (nTrainSetDriver) // pojazd, któremu zostanie wys³any rozk³ad
|
||
{ // wys³anie komendy "Timetable" ustawia odpowiedni tryb jazdy
|
||
nTrainSetDriver->DynamicObject->Mechanik->DirectionInitial();
|
||
nTrainSetDriver->DynamicObject->Mechanik->PutCommand(
|
||
"Timetable:" + asTrainName, fTrainSetVel, 0, NULL);
|
||
nTrainSetDriver =
|
||
NULL; // a przy "endtrainset" ju¿ wtedy nie potrzeba
|
||
}
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
Error("Scene parse error near " + AnsiString(token.c_str()));
|
||
// break;
|
||
}
|
||
}
|
||
else if (str == AnsiString("trainset"))
|
||
{
|
||
iTrainSetWehicleNumber = 0;
|
||
nTrainSetNode = NULL;
|
||
nTrainSetDriver = NULL; // pojazd, któremu zostanie wys³any rozk³ad
|
||
bTrainSet = true;
|
||
parser.getTokens();
|
||
parser >> token;
|
||
asTrainName = AnsiString(token.c_str()); // McZapkie: rodzaj+nazwa pociagu w SRJP
|
||
parser.getTokens();
|
||
parser >> token;
|
||
asTrainSetTrack = AnsiString(token.c_str()); //œcie¿ka startowa
|
||
parser.getTokens(2);
|
||
parser >> fTrainSetDist >> fTrainSetVel; // przesuniêcie i prêdkoœæ
|
||
}
|
||
else if (str == AnsiString("endtrainset"))
|
||
{ // McZapkie-110103: sygnaly konca pociagu ale tylko dla pociagow rozkladowych
|
||
if (nTrainSetNode) // trainset bez dynamic siê sypa³
|
||
{ // powinien te¿ tu wchodziæ, gdy pojazd bez trainset
|
||
if (nTrainSetDriver) // pojazd, któremu zostanie wys³any rozk³ad
|
||
{ // wys³anie komendy "Timetable" ustawia odpowiedni tryb jazdy
|
||
nTrainSetDriver->DynamicObject->Mechanik->DirectionInitial();
|
||
nTrainSetDriver->DynamicObject->Mechanik->PutCommand("Timetable:" + asTrainName,
|
||
fTrainSetVel, 0, NULL);
|
||
}
|
||
}
|
||
if (LastNode) // ostatni wczytany obiekt
|
||
if (LastNode->iType ==
|
||
TP_DYNAMIC) // o ile jest pojazdem (na ogó³ jest, ale kto wie...)
|
||
if (iTrainSetWehicleNumber ? !TempConnectionType[iTrainSetWehicleNumber - 1] :
|
||
false) // jeœli ostatni pojazd ma sprzêg 0
|
||
LastNode->DynamicObject->RaLightsSet(-1, 2 + 32 + 64); // to za³o¿ymy mu
|
||
// koñcówki blaszane
|
||
// (jak AI siê
|
||
// odpali, to sobie
|
||
// poprawi)
|
||
bTrainSet = false;
|
||
fTrainSetVel = 0;
|
||
// iTrainSetConnection=0;
|
||
nTrainSetNode = nTrainSetDriver = NULL;
|
||
iTrainSetWehicleNumber = 0;
|
||
}
|
||
else if (str == AnsiString("event"))
|
||
{
|
||
TEvent *tmp = new TEvent();
|
||
tmp->Load(&parser, &pOrigin);
|
||
if (tmp->Type == tp_Unknown)
|
||
delete tmp;
|
||
else
|
||
{ // najpierw sprawdzamy, czy nie ma, a potem dopisujemy
|
||
TEvent *found = FindEvent(tmp->asName);
|
||
if (found)
|
||
{ // jeœli znaleziony duplikat
|
||
int i = tmp->asName.Length();
|
||
if (tmp->asName[1] == '#') // zawsze jeden znak co najmniej jest
|
||
{
|
||
delete tmp;
|
||
tmp = NULL;
|
||
} // utylizacja duplikatu z krzy¿ykiem
|
||
else if (i > 8 ? tmp->asName.SubString(1, 9) == "lineinfo:" :
|
||
false) // tymczasowo wyj¹tki
|
||
{
|
||
delete tmp;
|
||
tmp = NULL;
|
||
} // tymczasowa utylizacja duplikatów W5
|
||
else if (i > 8 ? tmp->asName.SubString(i - 7, 8) == "_warning" :
|
||
false) // tymczasowo wyj¹tki
|
||
{
|
||
delete tmp;
|
||
tmp = NULL;
|
||
} // tymczasowa utylizacja duplikatu z tr¹bieniem
|
||
else if (i > 4 ? tmp->asName.SubString(i - 3, 4) == "_shp" :
|
||
false) // nie podlegaj¹ logowaniu
|
||
{
|
||
delete tmp;
|
||
tmp = NULL;
|
||
} // tymczasowa utylizacja duplikatu SHP
|
||
if (tmp) // jeœli nie zosta³ zutylizowany
|
||
if (Global::bJoinEvents)
|
||
found->Append(tmp); // doczepka (taki wirtualny multiple bez warunków)
|
||
else
|
||
{
|
||
ErrorLog("Duplicated event: " + tmp->asName);
|
||
found->Append(tmp); // doczepka (taki wirtualny multiple bez warunków)
|
||
found->Type = tp_Ignored; // dezaktywacja pierwotnego - taka proteza na
|
||
// wsteczn¹ zgodnoœæ
|
||
// SafeDelete(tmp); //bezlitoœnie usuwamy wszelkie duplikaty, ¿eby nie
|
||
// zaœmiecaæ drzewka
|
||
}
|
||
}
|
||
if (tmp)
|
||
{ // jeœli nie duplikat
|
||
tmp->evNext2 = RootEvent; // lista wszystkich eventów (m.in. do InitEvents)
|
||
RootEvent = tmp;
|
||
if (!found)
|
||
{ // jeœli nazwa wyst¹pi³a, to do kolejki i wyszukiwarki dodawany jest tylko
|
||
// pierwszy
|
||
if (RootEvent->Type != tp_Ignored)
|
||
if (RootEvent->asName.Pos(
|
||
"onstart")) // event uruchamiany automatycznie po starcie
|
||
AddToQuery(RootEvent, NULL); // dodanie do kolejki
|
||
sTracks->Add(0, tmp->asName.c_str(), tmp); // dodanie do wyszukiwarki
|
||
}
|
||
}
|
||
}
|
||
}
|
||
// else
|
||
// if (str==AnsiString("include")) //Tolaris to zrobil wewnatrz parsera
|
||
// {
|
||
// Include(Parser);
|
||
// }
|
||
else if (str == AnsiString("rotate"))
|
||
{
|
||
// parser.getTokens(3);
|
||
// parser >> aRotate.x >> aRotate.y >> aRotate.z; //Ra: to potrafi dawaæ b³êdne
|
||
// rezultaty
|
||
parser.getTokens();
|
||
parser >> aRotate.x;
|
||
parser.getTokens();
|
||
parser >> aRotate.y;
|
||
parser.getTokens();
|
||
parser >> aRotate.z;
|
||
// WriteLog("*** rotate "+AnsiString(aRotate.x)+" "+AnsiString(aRotate.y)+"
|
||
// "+AnsiString(aRotate.z));
|
||
}
|
||
else if (str == AnsiString("origin"))
|
||
{
|
||
// str=Parser->GetNextSymbol().LowerCase();
|
||
// if (str=="begin")
|
||
{
|
||
if (OriginStackTop >= OriginStackMaxDepth - 1)
|
||
{
|
||
MessageBox(0, AnsiString("Origin stack overflow ").c_str(), "Error", MB_OK);
|
||
break;
|
||
}
|
||
parser.getTokens(3);
|
||
parser >> OriginStack[OriginStackTop].x >> OriginStack[OriginStackTop].y >>
|
||
OriginStack[OriginStackTop].z;
|
||
pOrigin += OriginStack[OriginStackTop]; // sumowanie ca³kowitego przesuniêcia
|
||
OriginStackTop++; // zwiêkszenie wskaŸnika stosu
|
||
}
|
||
}
|
||
else if (str == AnsiString("endorigin"))
|
||
{
|
||
// else
|
||
// if (str=="end")
|
||
{
|
||
if (OriginStackTop <= 0)
|
||
{
|
||
MessageBox(0, AnsiString("Origin stack underflow ").c_str(), "Error", MB_OK);
|
||
break;
|
||
}
|
||
|
||
OriginStackTop--; // zmniejszenie wskaŸnika stosu
|
||
pOrigin -= OriginStack[OriginStackTop];
|
||
}
|
||
}
|
||
else if (str == AnsiString("atmo")) // TODO: uporzadkowac gdzie maja byc parametry mgly!
|
||
{ // Ra: ustawienie parametrów OpenGL przeniesione do FirstInit
|
||
WriteLog("Scenery atmo definition");
|
||
parser.getTokens(3);
|
||
parser >> Global::AtmoColor[0] >> Global::AtmoColor[1] >> Global::AtmoColor[2];
|
||
parser.getTokens(2);
|
||
parser >> Global::fFogStart >> Global::fFogEnd;
|
||
if (Global::fFogEnd > 0.0)
|
||
{ // ostatnie 3 parametry s¹ opcjonalne
|
||
parser.getTokens(3);
|
||
parser >> Global::FogColor[0] >> Global::FogColor[1] >> Global::FogColor[2];
|
||
}
|
||
parser.getTokens();
|
||
parser >> token;
|
||
while (token.compare("endatmo") != 0)
|
||
{ // a kolejne parametry s¹ pomijane
|
||
parser.getTokens();
|
||
parser >> token;
|
||
}
|
||
}
|
||
else if (str == AnsiString("time"))
|
||
{
|
||
WriteLog("Scenery time definition");
|
||
char temp_in[9];
|
||
char temp_out[9];
|
||
int i, j;
|
||
parser.getTokens();
|
||
parser >> temp_in;
|
||
for (j = 0; j <= 8; j++)
|
||
temp_out[j] = ' ';
|
||
for (i = 0; temp_in[i] != ':'; i++)
|
||
temp_out[i] = temp_in[i];
|
||
hh = atoi(temp_out);
|
||
for (j = 0; j <= 8; j++)
|
||
temp_out[j] = ' ';
|
||
for (j = i + 1; j <= 8; j++)
|
||
temp_out[j - (i + 1)] = temp_in[j];
|
||
mm = atoi(temp_out);
|
||
|
||
parser.getTokens();
|
||
parser >> temp_in;
|
||
for (j = 0; j <= 8; j++)
|
||
temp_out[j] = ' ';
|
||
for (i = 0; temp_in[i] != ':'; i++)
|
||
temp_out[i] = temp_in[i];
|
||
srh = atoi(temp_out);
|
||
for (j = 0; j <= 8; j++)
|
||
temp_out[j] = ' ';
|
||
for (j = i + 1; j <= 8; j++)
|
||
temp_out[j - (i + 1)] = temp_in[j];
|
||
srm = atoi(temp_out);
|
||
|
||
parser.getTokens();
|
||
parser >> temp_in;
|
||
for (j = 0; j <= 8; j++)
|
||
temp_out[j] = ' ';
|
||
for (i = 0; temp_in[i] != ':'; i++)
|
||
temp_out[i] = temp_in[i];
|
||
ssh = atoi(temp_out);
|
||
for (j = 0; j <= 8; j++)
|
||
temp_out[j] = ' ';
|
||
for (j = i + 1; j <= 8; j++)
|
||
temp_out[j - (i + 1)] = temp_in[j];
|
||
ssm = atoi(temp_out);
|
||
while (token.compare("endtime") != 0)
|
||
{
|
||
parser.getTokens();
|
||
parser >> token;
|
||
}
|
||
}
|
||
else if (str == AnsiString("light"))
|
||
{ // Ra: ustawianie œwiat³a przeniesione do FirstInit
|
||
WriteLog("Scenery light definition");
|
||
vector3 lp;
|
||
parser.getTokens();
|
||
parser >> lp.x;
|
||
parser.getTokens();
|
||
parser >> lp.y;
|
||
parser.getTokens();
|
||
parser >> lp.z;
|
||
lp = Normalize(lp); // kierunek padania
|
||
Global::lightPos[0] = lp.x; // daylight position
|
||
Global::lightPos[1] = lp.y;
|
||
Global::lightPos[2] = lp.z;
|
||
parser.getTokens();
|
||
parser >> Global::ambientDayLight[0]; // kolor wszechobceny
|
||
parser.getTokens();
|
||
parser >> Global::ambientDayLight[1];
|
||
parser.getTokens();
|
||
parser >> Global::ambientDayLight[2];
|
||
|
||
parser.getTokens();
|
||
parser >> Global::diffuseDayLight[0]; // kolor padaj¹cy
|
||
parser.getTokens();
|
||
parser >> Global::diffuseDayLight[1];
|
||
parser.getTokens();
|
||
parser >> Global::diffuseDayLight[2];
|
||
|
||
parser.getTokens();
|
||
parser >> Global::specularDayLight[0]; // kolor odbity
|
||
parser.getTokens();
|
||
parser >> Global::specularDayLight[1];
|
||
parser.getTokens();
|
||
parser >> Global::specularDayLight[2];
|
||
|
||
do
|
||
{
|
||
parser.getTokens();
|
||
parser >> token;
|
||
} while (token.compare("endlight") != 0);
|
||
}
|
||
else if (str == AnsiString("camera"))
|
||
{
|
||
vector3 xyz, abc;
|
||
xyz = abc = vector3(0, 0, 0); // wartoœci domyœlne, bo nie wszystie musz¹ byæ
|
||
int i = -1, into = -1; // do której definicji kamery wstawiæ
|
||
WriteLog("Scenery camera definition");
|
||
do
|
||
{ // opcjonalna siódma liczba okreœla numer kamery, a kiedyœ by³y tylko 3
|
||
parser.getTokens();
|
||
parser >> token;
|
||
switch (++i)
|
||
{ // kiedyœ camera mia³o tylko 3 wspó³rzêdne
|
||
case 0:
|
||
xyz.x = atof(token.c_str());
|
||
break;
|
||
case 1:
|
||
xyz.y = atof(token.c_str());
|
||
break;
|
||
case 2:
|
||
xyz.z = atof(token.c_str());
|
||
break;
|
||
case 3:
|
||
abc.x = atof(token.c_str());
|
||
break;
|
||
case 4:
|
||
abc.y = atof(token.c_str());
|
||
break;
|
||
case 5:
|
||
abc.z = atof(token.c_str());
|
||
break;
|
||
case 6:
|
||
into = atoi(token.c_str()); // takie sobie, bo mo¿na wpisaæ -1
|
||
}
|
||
} while (token.compare("endcamera") != 0);
|
||
if (into < 0)
|
||
into = ++Global::iCameraLast;
|
||
if ((into >= 0) && (into < 10))
|
||
{ // przepisanie do odpowiedniego miejsca w tabelce
|
||
Global::pFreeCameraInit[into] = xyz;
|
||
abc.x = DegToRad(abc.x);
|
||
abc.y = DegToRad(abc.y);
|
||
abc.z = DegToRad(abc.z);
|
||
Global::pFreeCameraInitAngle[into] = abc;
|
||
Global::iCameraLast = into; // numer ostatniej
|
||
}
|
||
}
|
||
else if (str == AnsiString("sky"))
|
||
{ // youBy - niebo z pliku
|
||
WriteLog("Scenery sky definition");
|
||
parser.getTokens();
|
||
parser >> token;
|
||
AnsiString SkyTemp;
|
||
SkyTemp = AnsiString(token.c_str());
|
||
if (Global::asSky == "1")
|
||
Global::asSky = SkyTemp;
|
||
do
|
||
{ // po¿arcie dodatkowych parametrów
|
||
parser.getTokens();
|
||
parser >> token;
|
||
} while (token.compare("endsky") != 0);
|
||
WriteLog(Global::asSky.c_str());
|
||
}
|
||
else if (str == AnsiString("firstinit"))
|
||
FirstInit();
|
||
else if (str == AnsiString("description"))
|
||
{
|
||
do
|
||
{
|
||
parser.getTokens();
|
||
parser >> token;
|
||
} while (token.compare("enddescription") != 0);
|
||
}
|
||
else if (str == AnsiString("test"))
|
||
{ // wypisywanie treœci po przetworzeniu
|
||
WriteLog("---> Parser test:");
|
||
do
|
||
{
|
||
parser.getTokens();
|
||
parser >> token;
|
||
WriteLog(token.c_str());
|
||
} while (token.compare("endtest") != 0);
|
||
WriteLog("---> End of parser test.");
|
||
}
|
||
else if (str == AnsiString("config"))
|
||
{ // mo¿liwoœæ przedefiniowania parametrów w scenerii
|
||
Global::ConfigParse(NULL, &parser); // parsowanie dodatkowych ustawieñ
|
||
}
|
||
else if (str != AnsiString(""))
|
||
{ // pomijanie od nierozpoznanej komendy do jej zakoñczenia
|
||
if ((token.length() > 2) && (atof(token.c_str()) == 0.0))
|
||
{ // jeœli nie liczba, to spróbowaæ pomin¹æ komendê
|
||
WriteLog(AnsiString("Unrecognized command: " + str));
|
||
str = "end" + str;
|
||
do
|
||
{
|
||
parser.getTokens();
|
||
token = "";
|
||
parser >> token;
|
||
} while ((token != "") && (token.compare(str.c_str()) != 0));
|
||
}
|
||
else // jak liczba to na pewno b³¹d
|
||
Error(AnsiString("Unrecognized command: " + str));
|
||
}
|
||
else if (str == AnsiString(""))
|
||
break;
|
||
|
||
// LastNode=NULL;
|
||
|
||
token = "";
|
||
parser.getTokens();
|
||
parser >> token;
|
||
}
|
||
|
||
delete parser;
|
||
sTracks->Sort(TP_TRACK); // finalne sortowanie drzewa torów
|
||
sTracks->Sort(TP_MEMCELL); // finalne sortowanie drzewa komórek pamiêci
|
||
sTracks->Sort(TP_MODEL); // finalne sortowanie drzewa modeli
|
||
sTracks->Sort(0); // finalne sortowanie drzewa eventów
|
||
if (!bInitDone)
|
||
FirstInit(); // jeœli nie by³o w scenerii
|
||
if (Global::pTerrainCompact)
|
||
TerrainWrite(); // Ra: teraz mo¿na zapisaæ teren w jednym pliku
|
||
Global::iPause &= ~0x10; // koniec pauzy wczytywania
|
||
return true;
|
||
}
|
||
|
||
bool TGround::InitEvents()
|
||
{ //³¹czenie eventów z pozosta³ymi obiektami
|
||
TGroundNode *tmp, *trk;
|
||
char buff[255];
|
||
int i;
|
||
for (TEvent *Current = RootEvent; Current; Current = Current->evNext2)
|
||
{
|
||
switch (Current->Type)
|
||
{
|
||
case tp_AddValues: // sumowanie wartoœci
|
||
case tp_UpdateValues: // zmiana wartoœci
|
||
tmp = FindGroundNode(Current->asNodeName,
|
||
TP_MEMCELL); // nazwa komórki powi¹zanej z eventem
|
||
if (tmp)
|
||
{ // McZapkie-100302
|
||
if (Current->iFlags & (conditional_trackoccupied | conditional_trackfree))
|
||
{ // jeœli chodzi o zajetosc toru (tor mo¿e byæ inny, ni¿ wpisany w komórce)
|
||
trk = FindGroundNode(Current->asNodeName,
|
||
TP_TRACK); // nazwa toru ta sama, co nazwa komórki
|
||
if (trk)
|
||
Current->Params[9].asTrack = trk->pTrack;
|
||
if (!Current->Params[9].asTrack)
|
||
ErrorLog("Bad event: track \"" + AnsiString(Current->asNodeName) +
|
||
"\" does not exists in \"" + Current->asName + "\"");
|
||
}
|
||
Current->Params[4].nGroundNode = tmp;
|
||
Current->Params[5].asMemCell = tmp->MemCell; // komórka do aktualizacji
|
||
if (Current->iFlags & (conditional_memcompare))
|
||
Current->Params[9].asMemCell = tmp->MemCell; // komórka do badania warunku
|
||
if (!tmp->MemCell->asTrackName
|
||
.IsEmpty()) // tor powi¹zany z komórk¹ powi¹zan¹ z eventem
|
||
{ // tu potrzebujemy wskaŸnik do komórki w (tmp)
|
||
trk = FindGroundNode(tmp->MemCell->asTrackName, TP_TRACK);
|
||
if (trk)
|
||
Current->Params[6].asTrack = trk->pTrack;
|
||
else
|
||
ErrorLog("Bad memcell: track \"" + tmp->MemCell->asTrackName +
|
||
"\" not exists in memcell \"" + tmp->asName + "\"");
|
||
}
|
||
else
|
||
Current->Params[6].asTrack = NULL;
|
||
}
|
||
else
|
||
{ // nie ma komórki, to nie bêdzie dzia³a³ poprawnie
|
||
Current->Type = tp_Ignored; // deaktywacja
|
||
ErrorLog("Bad event: \"" + Current->asName + "\" cannot find memcell \"" +
|
||
Current->asNodeName + "\"");
|
||
}
|
||
break;
|
||
case tp_LogValues: // skojarzenie z memcell
|
||
if (Current->asNodeName.IsEmpty())
|
||
{ // brak skojarzenia daje logowanie wszystkich
|
||
Current->Params[9].asMemCell = NULL;
|
||
break;
|
||
}
|
||
case tp_GetValues:
|
||
case tp_WhoIs:
|
||
tmp = FindGroundNode(Current->asNodeName, TP_MEMCELL);
|
||
if (tmp)
|
||
{
|
||
Current->Params[8].nGroundNode = tmp;
|
||
Current->Params[9].asMemCell = tmp->MemCell;
|
||
if (Current->Type == tp_GetValues) // jeœli odczyt komórki
|
||
if (tmp->MemCell->IsVelocity()) // a komórka zawiera komendê SetVelocity albo
|
||
// ShuntVelocity
|
||
Current->bEnabled = false; // to event nie bêdzie dodawany do kolejki
|
||
}
|
||
else
|
||
{ // nie ma komórki, to nie bêdzie dzia³a³ poprawnie
|
||
Current->Type = tp_Ignored; // deaktywacja
|
||
ErrorLog("Bad event: \"" + Current->asName + "\" cannot find memcell \"" +
|
||
Current->asNodeName + "\"");
|
||
}
|
||
break;
|
||
case tp_CopyValues: // skopiowanie komórki do innej
|
||
tmp = FindGroundNode(Current->asNodeName, TP_MEMCELL); // komórka docelowa
|
||
if (tmp)
|
||
{
|
||
Current->Params[4].nGroundNode = tmp;
|
||
Current->Params[5].asMemCell = tmp->MemCell; // komórka docelowa
|
||
if (!tmp->MemCell->asTrackName
|
||
.IsEmpty()) // tor powi¹zany z komórk¹ powi¹zan¹ z eventem
|
||
{ // tu potrzebujemy wskaŸnik do komórki w (tmp)
|
||
trk = FindGroundNode(tmp->MemCell->asTrackName, TP_TRACK);
|
||
if (trk)
|
||
Current->Params[6].asTrack = trk->pTrack;
|
||
else
|
||
ErrorLog("Bad memcell: track \"" + tmp->MemCell->asTrackName +
|
||
"\" not exists in memcell \"" + tmp->asName + "\"");
|
||
}
|
||
else
|
||
Current->Params[6].asTrack = NULL;
|
||
}
|
||
else
|
||
ErrorLog("Bad copyvalues: event \"" + Current->asName +
|
||
"\" cannot find memcell \"" + Current->asNodeName + "\"");
|
||
strcpy(
|
||
buff,
|
||
Current->Params[9].asText); // skopiowanie nazwy drugiej komórki do bufora roboczego
|
||
SafeDeleteArray(Current->Params[9].asText); // usuniêcie nazwy komórki
|
||
tmp = FindGroundNode(buff, TP_MEMCELL); // komórka Ÿód³owa
|
||
if (tmp)
|
||
{
|
||
Current->Params[8].nGroundNode = tmp;
|
||
Current->Params[9].asMemCell = tmp->MemCell; // komórka Ÿród³owa
|
||
}
|
||
else
|
||
ErrorLog("Bad copyvalues: event \"" + Current->asName +
|
||
"\" cannot find memcell \"" + AnsiString(buff) + "\"");
|
||
break;
|
||
case tp_Animation: // animacja modelu
|
||
tmp = FindGroundNode(Current->asNodeName, TP_MODEL); // egzemplarza modelu do animowania
|
||
if (tmp)
|
||
{
|
||
strcpy(
|
||
buff,
|
||
Current->Params[9].asText); // skopiowanie nazwy submodelu do bufora roboczego
|
||
SafeDeleteArray(Current->Params[9].asText); // usuniêcie nazwy submodelu
|
||
if (Current->Params[0].asInt == 4)
|
||
Current->Params[9].asModel = tmp->Model; // model dla ca³omodelowych animacji
|
||
else
|
||
{ // standardowo przypisanie submodelu
|
||
Current->Params[9].asAnimContainer = tmp->Model->GetContainer(buff); // submodel
|
||
if (Current->Params[9].asAnimContainer)
|
||
{
|
||
Current->Params[9].asAnimContainer->WillBeAnimated(); // oflagowanie
|
||
// animacji
|
||
if (!Current->Params[9]
|
||
.asAnimContainer->Event()) // nie szukaæ, gdy znaleziony
|
||
Current->Params[9].asAnimContainer->EventAssign(
|
||
FindEvent(Current->asNodeName + "." + AnsiString(buff) + ":done"));
|
||
}
|
||
}
|
||
}
|
||
else
|
||
ErrorLog("Bad animation: event \"" + Current->asName + "\" cannot find model \"" +
|
||
Current->asNodeName + "\"");
|
||
Current->asNodeName = "";
|
||
break;
|
||
case tp_Lights: // zmiana œwiete³ modelu
|
||
tmp = FindGroundNode(Current->asNodeName, TP_MODEL);
|
||
if (tmp)
|
||
Current->Params[9].asModel = tmp->Model;
|
||
else
|
||
ErrorLog("Bad lights: event \"" + Current->asName + "\" cannot find model \"" +
|
||
Current->asNodeName + "\"");
|
||
Current->asNodeName = "";
|
||
break;
|
||
case tp_Visible: // ukrycie albo przywrócenie obiektu
|
||
tmp = FindGroundNode(Current->asNodeName, TP_MODEL); // najpierw model
|
||
if (!tmp)
|
||
tmp = FindGroundNode(Current->asNodeName, TP_TRACTION); // mo¿e druty?
|
||
if (!tmp)
|
||
tmp = FindGroundNode(Current->asNodeName, TP_TRACK); // albo tory?
|
||
if (tmp)
|
||
Current->Params[9].nGroundNode = tmp;
|
||
else
|
||
ErrorLog("Bad visibility: event \"" + Current->asName + "\" cannot find model \"" +
|
||
Current->asNodeName + "\"");
|
||
Current->asNodeName = "";
|
||
break;
|
||
case tp_Switch: // prze³o¿enie zwrotnicy albo zmiana stanu obrotnicy
|
||
tmp = FindGroundNode(Current->asNodeName, TP_TRACK);
|
||
if (tmp)
|
||
{ // dowi¹zanie toru
|
||
if (!tmp->pTrack->iAction) // jeœli nie jest zwrotnic¹ ani obrotnic¹
|
||
tmp->pTrack->iAction |= 0x100; // to bêdzie siê zmienia³ stan uszkodzenia
|
||
Current->Params[9].asTrack = tmp->pTrack;
|
||
if (!Current->Params[0].asInt) // jeœli prze³¹cza do stanu 0
|
||
if (Current->Params[2].asdouble >=
|
||
0.0) // jeœli jest zdefiniowany dodatkowy ruch iglic
|
||
Current->Params[9].asTrack->Switch(
|
||
0, Current->Params[1].asdouble,
|
||
Current->Params[2].asdouble); // przes³anie parametrów
|
||
}
|
||
else
|
||
ErrorLog("Bad switch: event \"" + Current->asName + "\" cannot find track \"" +
|
||
Current->asNodeName + "\"");
|
||
Current->asNodeName = "";
|
||
break;
|
||
case tp_Sound: // odtworzenie dŸwiêku
|
||
tmp = FindGroundNode(Current->asNodeName, TP_SOUND);
|
||
if (tmp)
|
||
Current->Params[9].tsTextSound = tmp->tsStaticSound;
|
||
else
|
||
ErrorLog("Bad sound: event \"" + Current->asName +
|
||
"\" cannot find static sound \"" + Current->asNodeName + "\"");
|
||
Current->asNodeName = "";
|
||
break;
|
||
case tp_TrackVel: // ustawienie prêdkoœci na torze
|
||
if (!Current->asNodeName.IsEmpty())
|
||
{
|
||
tmp = FindGroundNode(Current->asNodeName, TP_TRACK);
|
||
if (tmp)
|
||
{
|
||
tmp->pTrack->iAction |=
|
||
0x200; // flaga zmiany prêdkoœci toru jest istotna dla skanowania
|
||
Current->Params[9].asTrack = tmp->pTrack;
|
||
}
|
||
else
|
||
ErrorLog("Bad velocity: event \"" + Current->asName +
|
||
"\" cannot find track \"" + Current->asNodeName + "\"");
|
||
}
|
||
Current->asNodeName = "";
|
||
break;
|
||
case tp_DynVel: // komunikacja z pojazdem o konkretnej nazwie
|
||
if (Current->asNodeName == "activator")
|
||
Current->Params[9].asDynamic = NULL;
|
||
else
|
||
{
|
||
tmp = FindGroundNode(Current->asNodeName, TP_DYNAMIC);
|
||
if (tmp)
|
||
Current->Params[9].asDynamic = tmp->DynamicObject;
|
||
else
|
||
Error("Event \"" + Current->asName + "\" cannot find dynamic \"" +
|
||
Current->asNodeName + "\"");
|
||
}
|
||
Current->asNodeName = "";
|
||
break;
|
||
case tp_Multiple:
|
||
if (Current->Params[9].asText != NULL)
|
||
{ // przepisanie nazwy do bufora
|
||
strcpy(buff, Current->Params[9].asText);
|
||
SafeDeleteArray(Current->Params[9].asText);
|
||
Current->Params[9].asPointer = NULL; // zerowanie wskaŸnika, aby wykryæ brak obeiktu
|
||
}
|
||
else
|
||
buff[0] = '\0';
|
||
if (Current->iFlags & (conditional_trackoccupied | conditional_trackfree))
|
||
{ // jeœli chodzi o zajetosc toru
|
||
tmp = FindGroundNode(buff, TP_TRACK);
|
||
if (tmp)
|
||
Current->Params[9].asTrack = tmp->pTrack;
|
||
if (!Current->Params[9].asTrack)
|
||
{
|
||
ErrorLog(AnsiString("Bad event: Track \"") + AnsiString(buff) +
|
||
"\" does not exist in \"" + Current->asName + "\"");
|
||
Current->iFlags &=
|
||
~(conditional_trackoccupied | conditional_trackfree); // zerowanie flag
|
||
}
|
||
}
|
||
else if (Current->iFlags &
|
||
(conditional_memstring | conditional_memval1 | conditional_memval2))
|
||
{ // jeœli chodzi o komorke pamieciow¹
|
||
tmp = FindGroundNode(buff, TP_MEMCELL);
|
||
if (tmp)
|
||
Current->Params[9].asMemCell = tmp->MemCell;
|
||
if (!Current->Params[9].asMemCell)
|
||
{
|
||
ErrorLog(AnsiString("Bad event: MemCell \"") + AnsiString(buff) +
|
||
AnsiString("\" does not exist in \"" + Current->asName + "\""));
|
||
Current->iFlags &=
|
||
~(conditional_memstring | conditional_memval1 | conditional_memval2);
|
||
}
|
||
}
|
||
for (i = 0; i < 8; i++)
|
||
{
|
||
if (Current->Params[i].asText != NULL)
|
||
{
|
||
strcpy(buff, Current->Params[i].asText);
|
||
SafeDeleteArray(Current->Params[i].asText);
|
||
Current->Params[i].asEvent = FindEvent(buff);
|
||
if (!Current->Params[i].asEvent) // Ra: tylko w logu informacja o braku
|
||
if (AnsiString(Current->Params[i].asText).SubString(1, 5) != "none_")
|
||
{
|
||
WriteLog(AnsiString("Event \"") + AnsiString(buff) +
|
||
AnsiString("\" does not exist"));
|
||
ErrorLog("Missed event: " + AnsiString(buff) + " in multiple " +
|
||
Current->asName);
|
||
}
|
||
}
|
||
}
|
||
break;
|
||
case tp_Voltage: // zmiana napiêcia w zasilaczu (TractionPowerSource)
|
||
if (!Current->asNodeName.IsEmpty())
|
||
{
|
||
tmp = FindGroundNode(Current->asNodeName,
|
||
TP_TRACTIONPOWERSOURCE); // pod³¹czenie zasilacza
|
||
if (tmp)
|
||
Current->Params[9].psPower = tmp->psTractionPowerSource;
|
||
else
|
||
ErrorLog("Bad voltage: event \"" + Current->asName +
|
||
"\" cannot find power source \"" + Current->asNodeName + "\"");
|
||
}
|
||
Current->asNodeName = "";
|
||
break;
|
||
case tp_Message: // wyœwietlenie komunikatu
|
||
break;
|
||
}
|
||
if (Current->fDelay < 0)
|
||
AddToQuery(Current, NULL);
|
||
}
|
||
for (TGroundNode *Current = nRootOfType[TP_MEMCELL]; Current; Current = Current->nNext)
|
||
{ // Ra: eventy komórek pamiêci, wykonywane po wys³aniu komendy do zatrzymanego pojazdu
|
||
Current->MemCell->AssignEvents(FindEvent(Current->asName + ":sent"));
|
||
}
|
||
return true;
|
||
}
|
||
|
||
void TGround::InitTracks()
|
||
{ //³¹czenie torów ze sob¹ i z eventami
|
||
TGroundNode *Current, *Model;
|
||
TTrack *tmp; // znaleziony tor
|
||
TTrack *Track;
|
||
int iConnection, state;
|
||
AnsiString name;
|
||
// tracks=tracksfar=0;
|
||
for (Current = nRootOfType[TP_TRACK]; Current; Current = Current->nNext)
|
||
{
|
||
Track = Current->pTrack;
|
||
if (Global::iHiddenEvents & 1)
|
||
if (!Current->asName.IsEmpty())
|
||
{ // jeœli podana jest nazwa torów, mo¿na szukaæ eventów skojarzonych przez nazwê
|
||
if (Track->asEvent0Name.IsEmpty())
|
||
if (FindEvent(Current->asName + ":event0"))
|
||
Track->asEvent0Name = Current->asName + ":event0";
|
||
if (Track->asEvent1Name.IsEmpty())
|
||
if (FindEvent(Current->asName + ":event1"))
|
||
Track->asEvent1Name = Current->asName + ":event1";
|
||
if (Track->asEvent2Name.IsEmpty())
|
||
if (FindEvent(Current->asName + ":event2"))
|
||
Track->asEvent2Name = Current->asName + ":event2";
|
||
|
||
if (Track->asEventall0Name.IsEmpty())
|
||
if (FindEvent(Current->asName + ":eventall0"))
|
||
Track->asEventall0Name = Current->asName + ":eventall0";
|
||
if (Track->asEventall1Name.IsEmpty())
|
||
if (FindEvent(Current->asName + ":eventall1"))
|
||
Track->asEventall1Name = Current->asName + ":eventall1";
|
||
if (Track->asEventall2Name.IsEmpty())
|
||
if (FindEvent(Current->asName + ":eventall2"))
|
||
Track->asEventall2Name = Current->asName + ":eventall2";
|
||
}
|
||
Track->AssignEvents(
|
||
Track->asEvent0Name.IsEmpty() ? NULL : FindEvent(Track->asEvent0Name),
|
||
Track->asEvent1Name.IsEmpty() ? NULL : FindEventScan(Track->asEvent1Name),
|
||
Track->asEvent2Name.IsEmpty() ? NULL : FindEventScan(Track->asEvent2Name));
|
||
Track->AssignallEvents(
|
||
Track->asEventall0Name.IsEmpty() ? NULL : FindEvent(Track->asEventall0Name),
|
||
Track->asEventall1Name.IsEmpty() ? NULL : FindEvent(Track->asEventall1Name),
|
||
Track->asEventall2Name.IsEmpty() ? NULL :
|
||
FindEvent(Track->asEventall2Name)); // MC-280503
|
||
switch (Track->eType)
|
||
{
|
||
case tt_Table: // obrotnicê te¿ ³¹czymy na starcie z innymi torami
|
||
Model = FindGroundNode(Current->asName, TP_MODEL); // szukamy modelu o tej samej nazwie
|
||
// if (tmp) //mamy model, trzeba zapamiêtaæ wskaŸnik do jego animacji
|
||
{ // jak coœ pójdzie Ÿle, to robimy z tego normalny tor
|
||
// Track->ModelAssign(tmp->Model->GetContainer(NULL)); //wi¹zanie toru z modelem
|
||
// obrotnicy
|
||
Track->RaAssign(
|
||
Current, Model ? Model->Model : NULL, FindEvent(Current->asName + ":done"),
|
||
FindEvent(Current->asName + ":joined")); // wi¹zanie toru z modelem obrotnicy
|
||
// break; //jednak po³¹czê z s¹siednim, jak ma siê wysypywaæ null track
|
||
}
|
||
if (!Model) // jak nie ma modelu
|
||
break; // to pewnie jest wykolejnica, a ta jest domyœlnie zamkniêta i wykoleja
|
||
case tt_Normal: // tylko proste s¹ pod³¹czane do rozjazdów, st¹d dwa rozjazdy siê nie
|
||
// po³¹cz¹ ze sob¹
|
||
if (Track->CurrentPrev() == NULL) // tylko jeœli jeszcze nie pod³¹czony
|
||
{
|
||
tmp = FindTrack(Track->CurrentSegment()->FastGetPoint_0(), iConnection, Current);
|
||
switch (iConnection)
|
||
{
|
||
case -1: // Ra: pierwsza koncepcja zawijania samochodów i statków
|
||
// if ((Track->iCategoryFlag&1)==0) //jeœli nie jest torem szynowym
|
||
// Track->ConnectPrevPrev(Track,0); //³¹czenie koñca odcinka do samego siebie
|
||
break;
|
||
case 0:
|
||
Track->ConnectPrevPrev(tmp, 0);
|
||
break;
|
||
case 1:
|
||
Track->ConnectPrevNext(tmp, 1);
|
||
break;
|
||
case 2:
|
||
Track->ConnectPrevPrev(tmp, 0); // do Point1 pierwszego
|
||
tmp->SetConnections(0); // zapamiêtanie ustawieñ w Segmencie
|
||
break;
|
||
case 3:
|
||
Track->ConnectPrevNext(tmp, 1); // do Point2 pierwszego
|
||
tmp->SetConnections(0); // zapamiêtanie ustawieñ w Segmencie
|
||
break;
|
||
case 4:
|
||
tmp->Switch(1);
|
||
Track->ConnectPrevPrev(tmp, 2); // do Point1 drugiego
|
||
tmp->SetConnections(1); // robi te¿ Switch(0)
|
||
tmp->Switch(0);
|
||
break;
|
||
case 5:
|
||
tmp->Switch(1);
|
||
Track->ConnectPrevNext(tmp, 3); // do Point2 drugiego
|
||
tmp->SetConnections(1); // robi te¿ Switch(0)
|
||
tmp->Switch(0);
|
||
break;
|
||
}
|
||
}
|
||
if (Track->CurrentNext() == NULL) // tylko jeœli jeszcze nie pod³¹czony
|
||
{
|
||
tmp = FindTrack(Track->CurrentSegment()->FastGetPoint_1(), iConnection, Current);
|
||
switch (iConnection)
|
||
{
|
||
case -1: // Ra: pierwsza koncepcja zawijania samochodów i statków
|
||
// if ((Track->iCategoryFlag&1)==0) //jeœli nie jest torem szynowym
|
||
// Track->ConnectNextNext(Track,1); //³¹czenie koñca odcinka do samego siebie
|
||
break;
|
||
case 0:
|
||
Track->ConnectNextPrev(tmp, 0);
|
||
break;
|
||
case 1:
|
||
Track->ConnectNextNext(tmp, 1);
|
||
break;
|
||
case 2:
|
||
Track->ConnectNextPrev(tmp, 0);
|
||
tmp->SetConnections(0); // zapamiêtanie ustawieñ w Segmencie
|
||
break;
|
||
case 3:
|
||
Track->ConnectNextNext(tmp, 1);
|
||
tmp->SetConnections(0); // zapamiêtanie ustawieñ w Segmencie
|
||
break;
|
||
case 4:
|
||
tmp->Switch(1);
|
||
Track->ConnectNextPrev(tmp, 2);
|
||
tmp->SetConnections(1); // robi te¿ Switch(0)
|
||
// tmp->Switch(0);
|
||
break;
|
||
case 5:
|
||
tmp->Switch(1);
|
||
Track->ConnectNextNext(tmp, 3);
|
||
tmp->SetConnections(1); // robi te¿ Switch(0)
|
||
// tmp->Switch(0);
|
||
break;
|
||
}
|
||
}
|
||
break;
|
||
case tt_Switch: // dla rozjazdów szukamy eventów sygnalizacji rozprucia
|
||
Track->AssignForcedEvents(FindEvent(Current->asName + ":forced+"),
|
||
FindEvent(Current->asName + ":forced-"));
|
||
break;
|
||
}
|
||
name = Track->IsolatedName(); // pobranie nazwy odcinka izolowanego
|
||
if (!name.IsEmpty()) // jeœli zosta³a zwrócona nazwa
|
||
Track->IsolatedEventsAssign(FindEvent(name + ":busy"), FindEvent(name + ":free"));
|
||
if (Current->asName.SubString(1, 1) ==
|
||
"*") // mo¿liwy portal, jeœli nie pod³¹czony od striny 1
|
||
if (!Track->CurrentPrev() && Track->CurrentNext())
|
||
Track->iCategoryFlag |= 0x100; // ustawienie flagi portalu
|
||
}
|
||
// WriteLog("Total "+AnsiString(tracks)+", far "+AnsiString(tracksfar));
|
||
TIsolated *p = TIsolated::Root();
|
||
while (p)
|
||
{ // jeœli siê znajdzie, to podaæ wskaŸnik
|
||
Current = FindGroundNode(p->asName, TP_MEMCELL); // czy jest komóka o odpowiedniej nazwie
|
||
if (Current)
|
||
p->pMemCell = Current->MemCell; // przypisanie powi¹zanej komórki
|
||
else
|
||
{ // utworzenie automatycznej komórki
|
||
Current = new TGroundNode(); // to nie musi mieæ nazwy, nazwa w wyszukiwarce wystarczy
|
||
// Current->asName=p->asName; //mazwa identyczna, jak nazwa odcinka izolowanego
|
||
Current->MemCell = new TMemCell(NULL); // nowa komórka
|
||
sTracks->Add(TP_MEMCELL, p->asName.c_str(), Current); // dodanie do wyszukiwarki
|
||
Current->nNext =
|
||
nRootOfType[TP_MEMCELL]; // to nie powinno tutaj byæ, bo robi siê œmietnik
|
||
nRootOfType[TP_MEMCELL] = Current;
|
||
iNumNodes++;
|
||
p->pMemCell = Current->MemCell; // wskaŸnik komóki przekazany do odcinka izolowanego
|
||
}
|
||
p = p->Next();
|
||
}
|
||
// for (Current=nRootOfType[TP_TRACK];Current;Current=Current->nNext)
|
||
// if (Current->pTrack->eType==tt_Cross)
|
||
// Current->pTrack->ConnectionsLog(); //zalogowanie informacji o po³¹czeniach
|
||
}
|
||
|
||
void TGround::InitTraction()
|
||
{ //³¹czenie drutów ze sob¹ oraz z torami i eventami
|
||
TGroundNode *nCurrent, *nTemp;
|
||
TTraction *tmp; // znalezione przês³o
|
||
TTraction *Traction;
|
||
int iConnection;
|
||
AnsiString name;
|
||
for (nCurrent = nRootOfType[TP_TRACTION]; nCurrent; nCurrent = nCurrent->nNext)
|
||
{ // pod³¹czenie do zasilacza, ¿eby mo¿na by³o sumowaæ pr¹d kilku pojazdów
|
||
// a jednoczeœnie z jednego miejsca zmieniaæ napiêcie eventem
|
||
// wykonywane najpierw, ¿eby mo¿na by³o logowaæ pod³¹czenie 2 zasilaczy do jednego drutu
|
||
// izolator zawieszony na przêœle jest ma byæ osobnym odcinkiem drutu o d³ugoœci ok. 1m,
|
||
// pod³¹czonym do zasilacza o nazwie "*" (gwiazka); "none" nie bêdzie odpowiednie
|
||
Traction = nCurrent->hvTraction;
|
||
nTemp = FindGroundNode(Traction->asPowerSupplyName, TP_TRACTIONPOWERSOURCE);
|
||
if (nTemp) // jak zasilacz znaleziony
|
||
Traction->PowerSet(nTemp->psTractionPowerSource); // to pod³¹czyæ do przês³a
|
||
else if (Traction->asPowerSupplyName != "*") // gwiazdka dla przês³a z izolatorem
|
||
if (Traction->asPowerSupplyName != "none") // dopuszczamy na razie brak pod³¹czenia?
|
||
{ // logowanie b³êdu i utworzenie zasilacza o domyœlnej zawartoœci
|
||
ErrorLog("Missed TractionPowerSource: " + Traction->asPowerSupplyName);
|
||
nTemp = new TGroundNode();
|
||
nTemp->iType = TP_TRACTIONPOWERSOURCE;
|
||
nTemp->asName = Traction->asPowerSupplyName;
|
||
nTemp->psTractionPowerSource = new TTractionPowerSource();
|
||
nTemp->psTractionPowerSource->Init(Traction->NominalVoltage, Traction->MaxCurrent);
|
||
nTemp->nNext = nRootOfType[nTemp->iType]; // ostatni dodany do³¹czamy na koñcu
|
||
// nowego
|
||
nRootOfType[nTemp->iType] = nTemp; // ustawienie nowego na pocz¹tku listy
|
||
iNumNodes++;
|
||
}
|
||
}
|
||
for (nCurrent = nRootOfType[TP_TRACTION]; nCurrent; nCurrent = nCurrent->nNext)
|
||
{
|
||
Traction = nCurrent->hvTraction;
|
||
if (!Traction->hvNext[0]) // tylko jeœli jeszcze nie pod³¹czony
|
||
{
|
||
tmp = FindTraction(&Traction->pPoint1, iConnection, nCurrent);
|
||
switch (iConnection)
|
||
{
|
||
case 0:
|
||
Traction->Connect(0, tmp, 0);
|
||
break;
|
||
case 1:
|
||
Traction->Connect(0, tmp, 1);
|
||
break;
|
||
}
|
||
if (Traction->hvNext[0]) // jeœli zosta³ pod³¹czony
|
||
if (Traction->psSection && tmp->psSection) // tylko przês³o z izolatorem mo¿e nie
|
||
// mieæ zasilania, bo ma 2, trzeba
|
||
// sprawdzaæ s¹siednie
|
||
if (Traction->psSection !=
|
||
tmp->psSection) // po³¹czone odcinki maj¹ ró¿ne zasilacze
|
||
{ // to mo¿e byæ albo pod³¹czenie podstacji lub kabiny sekcyjnej do sekcji, albo
|
||
// b³¹d
|
||
if (Traction->psSection->bSection && !tmp->psSection->bSection)
|
||
{ //(tmp->psSection) jest podstacj¹, a (Traction->psSection) nazw¹ sekcji
|
||
tmp->PowerSet(Traction->psSection); // zast¹pienie wskazaniem sekcji
|
||
}
|
||
else if (!Traction->psSection->bSection && tmp->psSection->bSection)
|
||
{ //(Traction->psSection) jest podstacj¹, a (tmp->psSection) nazw¹ sekcji
|
||
Traction->PowerSet(tmp->psSection); // zast¹pienie wskazaniem sekcji
|
||
}
|
||
else // jeœli obie to sekcje albo obie podstacje, to bêdzie b³¹d
|
||
ErrorLog("Bad power: at " +
|
||
FloatToStrF(Traction->pPoint1.x, ffFixed, 6, 2) + " " +
|
||
FloatToStrF(Traction->pPoint1.y, ffFixed, 6, 2) + " " +
|
||
FloatToStrF(Traction->pPoint1.z, ffFixed, 6, 2));
|
||
}
|
||
}
|
||
if (!Traction->hvNext[1]) // tylko jeœli jeszcze nie pod³¹czony
|
||
{
|
||
tmp = FindTraction(&Traction->pPoint2, iConnection, nCurrent);
|
||
switch (iConnection)
|
||
{
|
||
case 0:
|
||
Traction->Connect(1, tmp, 0);
|
||
break;
|
||
case 1:
|
||
Traction->Connect(1, tmp, 1);
|
||
break;
|
||
}
|
||
if (Traction->hvNext[1]) // jeœli zosta³ pod³¹czony
|
||
if (Traction->psSection && tmp->psSection) // tylko przês³o z izolatorem mo¿e nie
|
||
// mieæ zasilania, bo ma 2, trzeba
|
||
// sprawdzaæ s¹siednie
|
||
if (Traction->psSection != tmp->psSection)
|
||
{ // to mo¿e byæ albo pod³¹czenie podstacji lub kabiny sekcyjnej do sekcji, albo
|
||
// b³¹d
|
||
if (Traction->psSection->bSection && !tmp->psSection->bSection)
|
||
{ //(tmp->psSection) jest podstacj¹, a (Traction->psSection) nazw¹ sekcji
|
||
tmp->PowerSet(Traction->psSection); // zast¹pienie wskazaniem sekcji
|
||
}
|
||
else if (!Traction->psSection->bSection && tmp->psSection->bSection)
|
||
{ //(Traction->psSection) jest podstacj¹, a (tmp->psSection) nazw¹ sekcji
|
||
Traction->PowerSet(tmp->psSection); // zast¹pienie wskazaniem sekcji
|
||
}
|
||
else // jeœli obie to sekcje albo obie podstacje, to bêdzie b³¹d
|
||
ErrorLog("Bad power: at " +
|
||
FloatToStrF(Traction->pPoint2.x, ffFixed, 6, 2) + " " +
|
||
FloatToStrF(Traction->pPoint2.y, ffFixed, 6, 2) + " " +
|
||
FloatToStrF(Traction->pPoint2.z, ffFixed, 6, 2));
|
||
}
|
||
}
|
||
}
|
||
iConnection = 0; // teraz bêdzie licznikiem koñców
|
||
for (nCurrent = nRootOfType[TP_TRACTION]; nCurrent; nCurrent = nCurrent->nNext)
|
||
{ // operacje maj¹ce na celu wykrywanie bie¿ni wspólnych i ³¹czenie przêse³ napr¹¿ania
|
||
if (nCurrent->hvTraction->WhereIs()) // oznakowanie przedostatnich przêse³
|
||
{ // poszukiwanie bie¿ni wspólnej dla przedostatnich przêse³, równie¿ w celu po³¹czenia
|
||
// zasilania
|
||
// to siê nie sprawdza, bo po³¹czyæ siê mog¹ dwa niezasilane odcinki jako najbli¿sze
|
||
// sobie
|
||
// nCurrent->hvTraction->hvParallel=TractionNearestFind(nCurrent->pCenter,0,nCurrent);
|
||
// //szukanie najbli¿szego przês³a
|
||
// trzeba by zliczaæ koñce, a potem wpisaæ je do tablicy, aby sukcesywnie pod³¹czaæ do
|
||
// zasilaczy
|
||
nCurrent->hvTraction->iTries = 5; // oznaczanie koñcowych
|
||
++iConnection;
|
||
}
|
||
if (nCurrent->hvTraction->fResistance[0] == 0.0)
|
||
{
|
||
nCurrent->hvTraction
|
||
->ResistanceCalc(); // obliczanie przêse³ w segmencie z bezpoœrednim zasilaniem
|
||
// ErrorLog("Section "+nCurrent->hvTraction->asPowerSupplyName+" connected"); //jako
|
||
// niby b³¹d bêdzie bardziej widoczne
|
||
nCurrent->hvTraction->iTries = 0; // nie potrzeba mu szukaæ zasilania
|
||
}
|
||
// if (!Traction->hvParallel) //jeszcze utworzyæ pêtle z bie¿ni wspólnych
|
||
}
|
||
int zg = 0; // zgodnoœæ kierunku przêse³, tymczasowo iterator do tabeli koñców
|
||
TGroundNode **nEnds = new TGroundNode *[iConnection]; // koñców jest ok. 10 razy mniej ni¿
|
||
// wszystkich przêse³ (Quark: 216)
|
||
for (nCurrent = nRootOfType[TP_TRACTION]; nCurrent; nCurrent = nCurrent->nNext)
|
||
{ //³¹czenie bie¿ni wspólnych, w tym oznaczanie niepodanych jawnie
|
||
Traction = nCurrent->hvTraction;
|
||
if (!Traction->asParallel.IsEmpty()) // bêdzie wskaŸnik na inne przês³o
|
||
if ((Traction->asParallel == "none") ||
|
||
(Traction->asParallel == "*")) // jeœli nieokreœlone
|
||
Traction->iLast =
|
||
2; // jakby przedostatni - niech po prostu szuka (iLast ju¿ przeliczone)
|
||
else if (!Traction->hvParallel) // jeœli jeszcze nie zosta³ w³¹czony w kó³ko
|
||
{
|
||
nTemp = FindGroundNode(Traction->asParallel, TP_TRACTION);
|
||
if (nTemp)
|
||
{ // o ile zostanie znalezione przês³o o takiej nazwie
|
||
if (!nTemp->hvTraction
|
||
->hvParallel) // jeœli tamten jeszcze nie ma wskaŸnika bie¿ni wspólnej
|
||
Traction->hvParallel =
|
||
nTemp->hvTraction; // wpisaæ siebie i dalej daæ mu wskaŸnik zwrotny
|
||
else // a jak ma, to albo do³¹czyæ siê do kó³eczka
|
||
Traction->hvParallel =
|
||
nTemp->hvTraction->hvParallel; // przj¹æ dotychczasowy wskaŸnik od niego
|
||
nTemp->hvTraction->hvParallel =
|
||
Traction; // i na koniec ustawienie wskaŸnika zwrotnego
|
||
}
|
||
if (!Traction->hvParallel)
|
||
ErrorLog("Missed overhead: " + Traction->asParallel); // logowanie braku
|
||
}
|
||
if (Traction->iTries > 0) // jeœli zaznaczony do pod³¹czenia
|
||
// if (!nCurrent->hvTraction->psPower[0]||!nCurrent->hvTraction->psPower[1])
|
||
if (zg < iConnection) // zabezpieczenie
|
||
nEnds[zg++] = nCurrent; // wype³nianie tabeli koñców w celu szukania im po³¹czeñ
|
||
}
|
||
while (zg < iConnection)
|
||
nEnds[zg++] = NULL; // zape³nienie do koñca tablicy, jeœli by jakieœ koñce wypad³y
|
||
zg = 1; // nieefektywny przebieg koñczy ³¹czenie
|
||
while (zg)
|
||
{ // ustalenie zastêpczej rezystancji dla ka¿dego przês³a
|
||
zg = 0; // flaga pod³¹czonych przêse³ koñcowych: -1=puste wskaŸniki, 0=coœ zosta³o,
|
||
// 1=wykonano ³¹czenie
|
||
for (int i = 0; i < iConnection; ++i)
|
||
if (nEnds[i]) // za³atwione bêdziemy zerowaæ
|
||
{ // ka¿dy przebieg to próba pod³¹czenia koñca segmentu naprê¿ania do innego zasilanego
|
||
// przês³a
|
||
if (nEnds[i]->hvTraction->hvNext[0])
|
||
{ // jeœli koñcowy ma ci¹g dalszy od strony 0 (Point1), szukamy odcinka najbli¿szego
|
||
// do Point2
|
||
if (TractionNearestFind(nEnds[i]->hvTraction->pPoint2, 0,
|
||
nEnds[i])) // poszukiwanie przês³a
|
||
{
|
||
nEnds[i] = NULL;
|
||
zg = 1; // jak coœ zosta³o pod³¹czone, to mo¿e zasilanie gdzieœ dodatkowo
|
||
// dotrze
|
||
}
|
||
}
|
||
else if (nEnds[i]->hvTraction->hvNext[1])
|
||
{ // jeœli koñcowy ma ci¹g dalszy od strony 1 (Point2), szukamy odcinka najbli¿szego
|
||
// do Point1
|
||
if (TractionNearestFind(nEnds[i]->hvTraction->pPoint1, 1,
|
||
nEnds[i])) // poszukiwanie przês³a
|
||
{
|
||
nEnds[i] = NULL;
|
||
zg = 1; // jak coœ zosta³o pod³¹czone, to mo¿e zasilanie gdzieœ dodatkowo
|
||
// dotrze
|
||
}
|
||
}
|
||
else
|
||
{ // gdy koniec jest samotny, to na razie nie zostanie pod³¹czony (nie powinno
|
||
// takich byæ)
|
||
nEnds[i] = NULL;
|
||
}
|
||
}
|
||
}
|
||
delete[] nEnds; // nie potrzebne ju¿
|
||
};
|
||
|
||
void TGround::TrackJoin(TGroundNode *Current)
|
||
{ // wyszukiwanie s¹siednich torów do pod³¹czenia (wydzielone na u¿ytek obrotnicy)
|
||
TTrack *Track = Current->pTrack;
|
||
TTrack *tmp;
|
||
int iConnection;
|
||
if (!Track->CurrentPrev())
|
||
{
|
||
tmp = FindTrack(Track->CurrentSegment()->FastGetPoint_0(), iConnection,
|
||
Current); // Current do pominiêcia
|
||
switch (iConnection)
|
||
{
|
||
case 0:
|
||
Track->ConnectPrevPrev(tmp, 0);
|
||
break;
|
||
case 1:
|
||
Track->ConnectPrevNext(tmp, 1);
|
||
break;
|
||
}
|
||
}
|
||
if (!Track->CurrentNext())
|
||
{
|
||
tmp = FindTrack(Track->CurrentSegment()->FastGetPoint_1(), iConnection, Current);
|
||
switch (iConnection)
|
||
{
|
||
case 0:
|
||
Track->ConnectNextPrev(tmp, 0);
|
||
break;
|
||
case 1:
|
||
Track->ConnectNextNext(tmp, 1);
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
// McZapkie-070602: wyzwalacze zdarzen
|
||
bool TGround::InitLaunchers()
|
||
{
|
||
TGroundNode *Current, *tmp;
|
||
TEventLauncher *EventLauncher;
|
||
int i;
|
||
for (Current = nRootOfType[TP_EVLAUNCH]; Current; Current = Current->nNext)
|
||
{
|
||
EventLauncher = Current->EvLaunch;
|
||
if (EventLauncher->iCheckMask != 0)
|
||
if (EventLauncher->asMemCellName != AnsiString("none"))
|
||
{ // jeœli jest powi¹zana komórka pamiêci
|
||
tmp = FindGroundNode(EventLauncher->asMemCellName, TP_MEMCELL);
|
||
if (tmp)
|
||
EventLauncher->MemCell = tmp->MemCell; // jeœli znaleziona, dopisaæ
|
||
else
|
||
MessageBox(0, "Cannot find Memory Cell for Event Launcher", "Error", MB_OK);
|
||
}
|
||
else
|
||
EventLauncher->MemCell = NULL;
|
||
EventLauncher->Event1 = (EventLauncher->asEvent1Name != AnsiString("none")) ?
|
||
FindEvent(EventLauncher->asEvent1Name) :
|
||
NULL;
|
||
EventLauncher->Event2 = (EventLauncher->asEvent2Name != AnsiString("none")) ?
|
||
FindEvent(EventLauncher->asEvent2Name) :
|
||
NULL;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
TTrack *__fastcall TGround::FindTrack(vector3 Point, int &iConnection, TGroundNode *Exclude)
|
||
{ // wyszukiwanie innego toru koñcz¹cego siê w (Point)
|
||
TTrack *Track;
|
||
TGroundNode *Current;
|
||
TTrack *tmp;
|
||
iConnection = -1;
|
||
TSubRect *sr;
|
||
// najpierw szukamy w okolicznych segmentach
|
||
int c = GetColFromX(Point.x);
|
||
int r = GetRowFromZ(Point.z);
|
||
if ((sr = FastGetSubRect(c, r)) != NULL) // 75% torów jest w tym samym sektorze
|
||
if ((tmp = sr->FindTrack(&Point, iConnection, Exclude->pTrack)) != NULL)
|
||
return tmp;
|
||
int i, x, y;
|
||
for (i = 1; i < 9;
|
||
++i) // sektory w kolejnoœci odleg³oœci, 4 jest tu wystarczaj¹ce, 9 na wszelki wypadek
|
||
{ // niemal wszystkie pod³¹czone tory znajduj¹ siê w s¹siednich 8 sektorach
|
||
x = SectorOrder[i].x;
|
||
y = SectorOrder[i].y;
|
||
if ((sr = FastGetSubRect(c + y, r + x)) != NULL)
|
||
if ((tmp = sr->FindTrack(&Point, iConnection, Exclude->pTrack)) != NULL)
|
||
return tmp;
|
||
if (x)
|
||
if ((sr = FastGetSubRect(c + y, r - x)) != NULL)
|
||
if ((tmp = sr->FindTrack(&Point, iConnection, Exclude->pTrack)) != NULL)
|
||
return tmp;
|
||
if (y)
|
||
if ((sr = FastGetSubRect(c - y, r + x)) != NULL)
|
||
if ((tmp = sr->FindTrack(&Point, iConnection, Exclude->pTrack)) != NULL)
|
||
return tmp;
|
||
if ((sr = FastGetSubRect(c - y, r - x)) != NULL)
|
||
if ((tmp = sr->FindTrack(&Point, iConnection, Exclude->pTrack)) != NULL)
|
||
return tmp;
|
||
}
|
||
#if 0
|
||
//wyszukiwanie czo³gowe (po wszystkich jak leci) - nie ma chyba sensu
|
||
for (Current=nRootOfType[TP_TRACK];Current;Current=Current->Next)
|
||
{
|
||
if ((Current->iType==TP_TRACK) && (Current!=Exclude))
|
||
{
|
||
iConnection=Current->pTrack->TestPoint(&Point);
|
||
if (iConnection>=0) return Current->pTrack;
|
||
}
|
||
}
|
||
#endif
|
||
return NULL;
|
||
}
|
||
|
||
TTraction *__fastcall TGround::FindTraction(vector3 *Point, int &iConnection, TGroundNode *Exclude)
|
||
{ // wyszukiwanie innego przês³a koñcz¹cego siê w (Point)
|
||
TTraction *Traction;
|
||
TGroundNode *Current;
|
||
TTraction *tmp;
|
||
iConnection = -1;
|
||
TSubRect *sr;
|
||
// najpierw szukamy w okolicznych segmentach
|
||
int c = GetColFromX(Point->x);
|
||
int r = GetRowFromZ(Point->z);
|
||
if ((sr = FastGetSubRect(c, r)) != NULL) // wiêkszoœæ bêdzie w tym samym sektorze
|
||
if ((tmp = sr->FindTraction(Point, iConnection, Exclude->hvTraction)) != NULL)
|
||
return tmp;
|
||
int i, x, y;
|
||
for (i = 1; i < 9;
|
||
++i) // sektory w kolejnoœci odleg³oœci, 4 jest tu wystarczaj¹ce, 9 na wszelki wypadek
|
||
{ // wszystkie przês³a powinny zostaæ znajdowaæ siê w s¹siednich 8 sektorach
|
||
x = SectorOrder[i].x;
|
||
y = SectorOrder[i].y;
|
||
if ((sr = FastGetSubRect(c + y, r + x)) != NULL)
|
||
if ((tmp = sr->FindTraction(Point, iConnection, Exclude->hvTraction)) != NULL)
|
||
return tmp;
|
||
if (x & y)
|
||
{
|
||
if ((sr = FastGetSubRect(c + y, r - x)) != NULL)
|
||
if ((tmp = sr->FindTraction(Point, iConnection, Exclude->hvTraction)) != NULL)
|
||
return tmp;
|
||
if ((sr = FastGetSubRect(c - y, r + x)) != NULL)
|
||
if ((tmp = sr->FindTraction(Point, iConnection, Exclude->hvTraction)) != NULL)
|
||
return tmp;
|
||
}
|
||
if ((sr = FastGetSubRect(c - y, r - x)) != NULL)
|
||
if ((tmp = sr->FindTraction(Point, iConnection, Exclude->hvTraction)) != NULL)
|
||
return tmp;
|
||
}
|
||
return NULL;
|
||
};
|
||
|
||
TTraction *__fastcall TGround::TractionNearestFind(vector3 &p, int dir, TGroundNode *n)
|
||
{ // wyszukanie najbli¿szego do (p) przês³a o tej samej nazwie sekcji (ale innego ni¿ pod³¹czone)
|
||
// oraz zasilanego z kierunku (dir)
|
||
TGroundNode *nCurrent, *nBest = NULL;
|
||
int i, j, k, zg;
|
||
double d, dist = 200.0 * 200.0; //[m] odleg³oœæ graniczna
|
||
// najpierw szukamy w okolicznych segmentach
|
||
int c = GetColFromX(n->pCenter.x);
|
||
int r = GetRowFromZ(n->pCenter.z);
|
||
TSubRect *sr;
|
||
for (i = -1; i <= 1; ++i) // przegl¹damy 9 najbli¿szych sektorów
|
||
for (j = -1; j <= 1; ++j) //
|
||
if ((sr = FastGetSubRect(c + i, r + j)) != NULL) // o ile w ogóle sektor jest
|
||
for (nCurrent = sr->nRenderWires; nCurrent; nCurrent = nCurrent->nNext3)
|
||
if (nCurrent->iType == TP_TRACTION)
|
||
if (nCurrent->hvTraction->psSection ==
|
||
n->hvTraction->psSection) // jeœli ta sama sekcja
|
||
if (nCurrent != n) // ale nie jest tym samym
|
||
if (nCurrent->hvTraction !=
|
||
n->hvTraction
|
||
->hvNext[0]) // ale nie jest bezpoœrednio pod³¹czonym
|
||
if (nCurrent->hvTraction != n->hvTraction->hvNext[1])
|
||
if (nCurrent->hvTraction->psPower
|
||
[k = (DotProduct(
|
||
n->hvTraction->vParametric,
|
||
nCurrent->hvTraction->vParametric) >= 0 ?
|
||
dir ^ 1 :
|
||
dir)]) // ma zasilanie z odpowiedniej
|
||
// strony
|
||
if (nCurrent->hvTraction->fResistance[k] >=
|
||
0.0) //¿eby siê nie propagowa³y jakieœ ujemne
|
||
{ // znaleziony kandydat do po³¹czenia
|
||
d = SquareMagnitude(
|
||
p -
|
||
nCurrent
|
||
->pCenter); // kwadrat odleg³oœci œrodków
|
||
if (dist > d)
|
||
{ // zapamiêtanie nowego najbli¿szego
|
||
dist = d; // nowy rekord odleg³oœci
|
||
nBest = nCurrent;
|
||
zg = k; // z którego koñca braæ wskaŸnik
|
||
// zasilacza
|
||
}
|
||
}
|
||
if (nBest) // jak znalezione przês³o z zasilaniem, to pod³¹czenie "równoleg³e"
|
||
{
|
||
n->hvTraction->ResistanceCalc(dir, nBest->hvTraction->fResistance[zg],
|
||
nBest->hvTraction->psPower[zg]);
|
||
// testowo skrzywienie przês³a tak, aby pokazaæ sk¹d ma zasilanie
|
||
// if (dir) //1 gdy ci¹g dalszy jest od strony Point2
|
||
// n->hvTraction->pPoint3=0.25*(nBest->pCenter+3*(zg?nBest->hvTraction->pPoint4:nBest->hvTraction->pPoint3));
|
||
// else
|
||
// n->hvTraction->pPoint4=0.25*(nBest->pCenter+3*(zg?nBest->hvTraction->pPoint4:nBest->hvTraction->pPoint3));
|
||
}
|
||
return (nBest ? nBest->hvTraction : NULL);
|
||
};
|
||
|
||
bool TGround::AddToQuery(TEvent *Event, TDynamicObject *Node)
|
||
{
|
||
if (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 = Node;
|
||
if (Event->Type == tp_AddValues ? (Event->fDelay == 0.0) : false)
|
||
{ // 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 (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);
|
||
if (Event->Params[6].asTrack)
|
||
{ // McZapkie-100302 - updatevalues oprocz zmiany wartosci robi putcommand dla
|
||
// wszystkich 'dynamic' na danym torze
|
||
for (int i = 0; i < Event->Params[6].asTrack->iNumDynamics; ++i)
|
||
Event->Params[5].asMemCell->PutCommand(
|
||
Event->Params[6].asTrack->Dynamics[i]->Mechanik,
|
||
&Event->Params[4].nGroundNode->pCenter);
|
||
if (DebugModeFlag)
|
||
WriteLog("EVENT EXECUTED: AddValues & Track command - " +
|
||
AnsiString(Event->Params[0].asText) + " " +
|
||
AnsiString(Event->Params[1].asdouble) + " " +
|
||
AnsiString(Event->Params[2].asdouble));
|
||
}
|
||
else if (DebugModeFlag)
|
||
WriteLog("EVENT EXECUTED: AddValues - " +
|
||
AnsiString(Event->Params[0].asText) + " " +
|
||
AnsiString(Event->Params[1].asdouble) + " " +
|
||
AnsiString(Event->Params[2].asdouble));
|
||
}
|
||
Event =
|
||
Event
|
||
->evJoined; // jeœli jest kolejny o takiej samej nazwie, to idzie do kolejki
|
||
}
|
||
if (Event)
|
||
{ // standardowe dodanie do kolejki
|
||
WriteLog("EVENT ADDED TO QUEUE: " + Event->asName +
|
||
(Node ? AnsiString(" by " + Node->asName) : AnsiString("")));
|
||
Event->fStartTime =
|
||
fabs(Event->fDelay) + Timer::GetTime(); // czas od uruchomienia scenerii
|
||
if (Event->fRandomDelay > 0.0)
|
||
Event->fStartTime += Event->fRandomDelay * random(10000) *
|
||
0.0001; // doliczenie losowego czasu opóŸnienia
|
||
++Event->iQueued; // zabezpieczenie przed podwójnym dodaniem do kolejki
|
||
if (QueryRootEvent ? Event->fStartTime >= QueryRootEvent->fStartTime : false)
|
||
QueryRootEvent->AddToQuery(Event); // dodanie gdzieœ w œrodku
|
||
else
|
||
{ // dodanie z przodu: albo nic nie ma, albo ma byæ wykonany szybciej ni¿ pierwszy
|
||
Event->evNext = QueryRootEvent;
|
||
QueryRootEvent = Event;
|
||
}
|
||
}
|
||
}
|
||
return true;
|
||
}
|
||
|
||
bool TGround::EventConditon(TEvent *e)
|
||
{ // sprawdzenie spelnienia warunków dla eventu
|
||
if (e->iFlags <= update_only)
|
||
return true; // bezwarunkowo
|
||
if (e->iFlags & conditional_trackoccupied)
|
||
return (!e->Params[9].asTrack->IsEmpty());
|
||
else if (e->iFlags & conditional_trackfree)
|
||
return (e->Params[9].asTrack->IsEmpty());
|
||
else if (e->iFlags & conditional_propability)
|
||
{
|
||
double rprobability = 1.0 * rand() / RAND_MAX;
|
||
WriteLog("Random integer: " + CurrToStr(rprobability) + "/" +
|
||
CurrToStr(e->Params[10].asdouble));
|
||
return (e->Params[10].asdouble > rprobability);
|
||
}
|
||
else if (e->iFlags & conditional_memcompare)
|
||
{ // porównanie wartoœci
|
||
if (tmpEvent->Params[9].asMemCell->Compare(e->Params[10].asText, e->Params[11].asdouble,
|
||
e->Params[12].asdouble, e->iFlags))
|
||
return true;
|
||
else if (Global::iWriteLogEnabled && DebugModeFlag)
|
||
{ // nie zgadza siê, wiêc sprawdzmy, co
|
||
LogComment = e->Params[9].asMemCell->Text() + AnsiString(" ") +
|
||
FloatToStrF(e->Params[9].asMemCell->Value1(), ffFixed, 8, 2) + " " +
|
||
FloatToStrF(tmpEvent->Params[9].asMemCell->Value2(), ffFixed, 8, 2) +
|
||
" != ";
|
||
if (TestFlag(e->iFlags, conditional_memstring))
|
||
LogComment += AnsiString(tmpEvent->Params[10].asText);
|
||
else
|
||
LogComment += "*";
|
||
if (TestFlag(tmpEvent->iFlags, conditional_memval1))
|
||
LogComment += " " + FloatToStrF(tmpEvent->Params[11].asdouble, ffFixed, 8, 2);
|
||
else
|
||
LogComment += " *";
|
||
if (TestFlag(tmpEvent->iFlags, conditional_memval2))
|
||
LogComment += " " + FloatToStrF(tmpEvent->Params[12].asdouble, ffFixed, 8, 2);
|
||
else
|
||
LogComment += " *";
|
||
WriteLog(LogComment.c_str());
|
||
}
|
||
}
|
||
return false;
|
||
};
|
||
|
||
bool TGround::CheckQuery()
|
||
{ // sprawdzenie kolejki eventów oraz wykonanie tych, którym czas min¹³
|
||
TLocation loc;
|
||
int i;
|
||
/* //Ra: to w ogóle jakiœ chory kod jest; wygl¹da jak wyszukanie eventu z najlepszym czasem
|
||
Double evtime,evlowesttime; //Ra: co to za typ?
|
||
//evlowesttime=1000000;
|
||
if (QueryRootEvent)
|
||
{
|
||
OldQRE=QueryRootEvent;
|
||
tmpEvent=QueryRootEvent;
|
||
}
|
||
if (QueryRootEvent)
|
||
{
|
||
for (i=0;i<90;++i)
|
||
{
|
||
evtime=((tmpEvent->fStartTime)-(Timer::GetTime())); //pobranie wartoœci zmiennej
|
||
if (evtime<evlowesttime)
|
||
{
|
||
evlowesttime=evtime;
|
||
tmp2Event=tmpEvent;
|
||
}
|
||
if (tmpEvent->Next)
|
||
tmpEvent=tmpEvent->Next;
|
||
else
|
||
i=100;
|
||
}
|
||
if (OldQRE!=tmp2Event)
|
||
{
|
||
QueryRootEvent->AddToQuery(QueryRootEvent);
|
||
QueryRootEvent=tmp2Event;
|
||
}
|
||
}
|
||
*/
|
||
/*
|
||
if (QueryRootEvent)
|
||
{//wypisanie kolejki
|
||
tmpEvent=QueryRootEvent;
|
||
WriteLog("--> Event queue:");
|
||
while (tmpEvent)
|
||
{
|
||
WriteLog(tmpEvent->asName+" "+AnsiString(tmpEvent->fStartTime));
|
||
tmpEvent=tmpEvent->Next;
|
||
}
|
||
}
|
||
*/
|
||
while (QueryRootEvent ? QueryRootEvent->fStartTime < Timer::GetTime() : false)
|
||
{ // eventy s¹ posortowana wg czasu wykonania
|
||
tmpEvent = QueryRootEvent; // wyjêcie eventu z kolejki
|
||
if (QueryRootEvent->evJoined) // jeœli jest kolejny o takiej samej nazwie
|
||
{ // to teraz on bêdzie nastêpny do wykonania
|
||
QueryRootEvent = QueryRootEvent->evJoined; // nastêpny bêdzie ten doczepiony
|
||
QueryRootEvent->evNext = tmpEvent->evNext; // pamiêtaj¹c o nastêpnym z kolejki
|
||
QueryRootEvent->fStartTime =
|
||
tmpEvent->fStartTime; // czas musi byæ ten sam, bo nie jest aktualizowany
|
||
QueryRootEvent->Activator = tmpEvent->Activator; // pojazd aktywuj¹cy
|
||
// w sumie mo¿na by go dodaæ normalnie do kolejki, ale trzeba te po³¹czone posortowaæ wg
|
||
// czasu wykonania
|
||
}
|
||
else // a jak nazwa jest unikalna, to kolejka idzie dalej
|
||
QueryRootEvent = QueryRootEvent->evNext; // NULL w skrajnym przypadku
|
||
if (tmpEvent->bEnabled)
|
||
{ // w zasadzie te wy³¹czone s¹ skanowane i nie powinny siê nigdy w kolejce znaleŸæ
|
||
WriteLog("EVENT LAUNCHED: " + tmpEvent->asName +
|
||
(tmpEvent->Activator ? AnsiString(" by " + tmpEvent->Activator->asName) :
|
||
AnsiString("")));
|
||
switch (tmpEvent->Type)
|
||
{
|
||
case tp_CopyValues: // skopiowanie wartoœci z innej komórki
|
||
tmpEvent->Params[5].asMemCell->UpdateValues(
|
||
tmpEvent->Params[9].asMemCell->Text(), tmpEvent->Params[9].asMemCell->Value1(),
|
||
tmpEvent->Params[9].asMemCell->Value2(),
|
||
tmpEvent->iFlags // flagi okreœlaj¹, co ma byæ skopiowane
|
||
);
|
||
// break; //¿eby siê wys³a³o do torów i nie by³o potrzeby na AddValues * 0 0
|
||
case tp_AddValues: // ró¿ni siê jedn¹ flag¹ od UpdateValues
|
||
case tp_UpdateValues:
|
||
if (EventConditon(tmpEvent))
|
||
{ // teraz mog¹ byæ warunki do tych eventów
|
||
if (tmpEvent->Type != tp_CopyValues) // dla CopyValues zrobi³o siê wczeœniej
|
||
tmpEvent->Params[5].asMemCell->UpdateValues(
|
||
tmpEvent->Params[0].asText, tmpEvent->Params[1].asdouble,
|
||
tmpEvent->Params[2].asdouble, tmpEvent->iFlags);
|
||
if (tmpEvent->Params[6].asTrack)
|
||
{ // McZapkie-100302 - updatevalues oprocz zmiany wartosci robi putcommand dla
|
||
// wszystkich 'dynamic' na danym torze
|
||
for (int i = 0; i < tmpEvent->Params[6].asTrack->iNumDynamics; ++i)
|
||
tmpEvent->Params[5].asMemCell->PutCommand(
|
||
tmpEvent->Params[6].asTrack->Dynamics[i]->Mechanik,
|
||
&tmpEvent->Params[4].nGroundNode->pCenter);
|
||
if (DebugModeFlag)
|
||
WriteLog("Type: UpdateValues & Track command - " +
|
||
AnsiString(tmpEvent->Params[0].asText) + " " +
|
||
AnsiString(tmpEvent->Params[1].asdouble) + " " +
|
||
AnsiString(tmpEvent->Params[2].asdouble));
|
||
}
|
||
else if (DebugModeFlag)
|
||
WriteLog("Type: UpdateValues - " + AnsiString(tmpEvent->Params[0].asText) +
|
||
" " + AnsiString(tmpEvent->Params[1].asdouble) + " " +
|
||
AnsiString(tmpEvent->Params[2].asdouble));
|
||
}
|
||
break;
|
||
case tp_GetValues:
|
||
if (tmpEvent->Activator)
|
||
{
|
||
// loc.X= -tmpEvent->Params[8].nGroundNode->pCenter.x;
|
||
// loc.Y= tmpEvent->Params[8].nGroundNode->pCenter.z;
|
||
// loc.Z= tmpEvent->Params[8].nGroundNode->pCenter.y;
|
||
if (Global::iMultiplayer) // potwierdzenie wykonania dla serwera (odczyt
|
||
// semafora ju¿ tak nie dzia³a)
|
||
WyslijEvent(tmpEvent->asName, tmpEvent->Activator->GetName());
|
||
// tmpEvent->Params[9].asMemCell->PutCommand(tmpEvent->Activator->Mechanik,loc);
|
||
tmpEvent->Params[9].asMemCell->PutCommand(
|
||
tmpEvent->Activator->Mechanik, &tmpEvent->Params[8].nGroundNode->pCenter);
|
||
}
|
||
WriteLog("Type: GetValues");
|
||
break;
|
||
case tp_PutValues:
|
||
if (tmpEvent->Activator)
|
||
{
|
||
loc.X =
|
||
-tmpEvent->Params[3].asdouble; // zamiana, bo fizyka ma inaczej ni¿ sceneria
|
||
loc.Y = tmpEvent->Params[5].asdouble;
|
||
loc.Z = tmpEvent->Params[4].asdouble;
|
||
if (tmpEvent->Activator->Mechanik) // przekazanie rozkazu do AI
|
||
tmpEvent->Activator->Mechanik->PutCommand(
|
||
tmpEvent->Params[0].asText, tmpEvent->Params[1].asdouble,
|
||
tmpEvent->Params[2].asdouble, loc);
|
||
else
|
||
{ // przekazanie do pojazdu
|
||
tmpEvent->Activator->MoverParameters->PutCommand(
|
||
tmpEvent->Params[0].asText, tmpEvent->Params[1].asdouble,
|
||
tmpEvent->Params[2].asdouble, loc);
|
||
}
|
||
}
|
||
WriteLog("Type: PutValues");
|
||
break;
|
||
case tp_Lights:
|
||
if (tmpEvent->Params[9].asModel)
|
||
for (i = 0; i < iMaxNumLights; i++)
|
||
if (tmpEvent->Params[i].asdouble >= 0) //-1 zostawia bez zmiany
|
||
tmpEvent->Params[9].asModel->LightSet(
|
||
i, tmpEvent->Params[i].asdouble); // teraz te¿ u³amek
|
||
break;
|
||
case tp_Visible:
|
||
if (tmpEvent->Params[9].nGroundNode)
|
||
tmpEvent->Params[9].nGroundNode->bVisible = (tmpEvent->Params[i].asInt > 0);
|
||
break;
|
||
case tp_Velocity:
|
||
Error("Not implemented yet :(");
|
||
break;
|
||
case tp_Exit:
|
||
MessageBox(0, tmpEvent->asNodeName.c_str(), " THE END ", MB_OK);
|
||
Global::iTextMode = -1; // wy³¹czenie takie samo jak sekwencja F10 -> Y
|
||
return false;
|
||
case tp_Sound:
|
||
switch (tmpEvent->Params[0].asInt)
|
||
{ // trzy mo¿liwe przypadki:
|
||
case 0:
|
||
tmpEvent->Params[9].tsTextSound->Stop();
|
||
break;
|
||
case 1:
|
||
tmpEvent->Params[9].tsTextSound->Play(
|
||
1, 0, true, tmpEvent->Params[9].tsTextSound->vSoundPosition);
|
||
break;
|
||
case -1:
|
||
tmpEvent->Params[9].tsTextSound->Play(
|
||
1, DSBPLAY_LOOPING, true, tmpEvent->Params[9].tsTextSound->vSoundPosition);
|
||
break;
|
||
}
|
||
break;
|
||
case tp_Disable:
|
||
Error("Not implemented yet :(");
|
||
break;
|
||
case tp_Animation: // Marcin: dorobic translacje - Ra: dorobi³em ;-)
|
||
if (tmpEvent->Params[0].asInt == 1)
|
||
tmpEvent->Params[9].asAnimContainer->SetRotateAnim(
|
||
vector3(tmpEvent->Params[1].asdouble, tmpEvent->Params[2].asdouble,
|
||
tmpEvent->Params[3].asdouble),
|
||
tmpEvent->Params[4].asdouble);
|
||
else if (tmpEvent->Params[0].asInt == 2)
|
||
tmpEvent->Params[9].asAnimContainer->SetTranslateAnim(
|
||
vector3(tmpEvent->Params[1].asdouble, tmpEvent->Params[2].asdouble,
|
||
tmpEvent->Params[3].asdouble),
|
||
tmpEvent->Params[4].asdouble);
|
||
else if (tmpEvent->Params[0].asInt == 4)
|
||
tmpEvent->Params[9].asModel->AnimationVND(
|
||
tmpEvent->Params[8].asPointer,
|
||
tmpEvent->Params[1].asdouble, // tu mog¹ byæ dodatkowe parametry, np. od-do
|
||
tmpEvent->Params[2].asdouble, tmpEvent->Params[3].asdouble,
|
||
tmpEvent->Params[4].asdouble);
|
||
break;
|
||
case tp_Switch:
|
||
if (tmpEvent->Params[9].asTrack)
|
||
tmpEvent->Params[9].asTrack->Switch(tmpEvent->Params[0].asInt,
|
||
tmpEvent->Params[1].asdouble,
|
||
tmpEvent->Params[2].asdouble);
|
||
if (Global::iMultiplayer) // dajemy znaæ do serwera o prze³o¿eniu
|
||
WyslijEvent(tmpEvent->asName, ""); // wys³anie nazwy eventu prze³¹czajacego
|
||
// Ra: bardziej by siê przyda³a nazwa toru, ale nie ma do niej st¹d dostêpu
|
||
break;
|
||
case tp_TrackVel:
|
||
if (tmpEvent->Params[9].asTrack)
|
||
{ // prêdkoœæ na zwrotnicy mo¿e byæ ograniczona z góry we wpisie, wiêkszej siê nie
|
||
// ustawi eventem
|
||
WriteLog("type: TrackVel");
|
||
// WriteLog("Vel: ",tmpEvent->Params[0].asdouble);
|
||
tmpEvent->Params[9].asTrack->VelocitySet(tmpEvent->Params[0].asdouble);
|
||
if (DebugModeFlag) // wyœwietlana jest ta faktycznie ustawiona
|
||
WriteLog("vel: ", tmpEvent->Params[9].asTrack->VelocityGet());
|
||
}
|
||
break;
|
||
case tp_DynVel:
|
||
Error("Event \"DynVel\" is obsolete");
|
||
break;
|
||
case tp_Multiple:
|
||
{
|
||
bCondition = EventConditon(tmpEvent);
|
||
if (bCondition || (tmpEvent->iFlags &
|
||
conditional_anyelse)) // warunek spelniony albo by³o u¿yte else
|
||
{
|
||
WriteLog("Multiple passed");
|
||
for (i = 0; i < 8; ++i)
|
||
{ // dodawane do kolejki w kolejnoœci zapisania
|
||
if (tmpEvent->Params[i].asEvent)
|
||
if (bCondition != bool(tmpEvent->iFlags & (conditional_else << i)))
|
||
{
|
||
if (tmpEvent->Params[i].asEvent != tmpEvent)
|
||
AddToQuery(tmpEvent->Params[i].asEvent,
|
||
tmpEvent->Activator); // normalnie dodaæ
|
||
else // jeœli ma byæ rekurencja
|
||
if (tmpEvent->fDelay >=
|
||
5.0) // to musi mieæ sensowny okres powtarzania
|
||
if (tmpEvent->iQueued < 2)
|
||
{ // trzeba zrobiæ wyj¹tek, aby event móg³ siê sam dodaæ do
|
||
// kolejki, raz ju¿ jest, ale bêdzie usuniêty
|
||
// pêtla eventowa mo¿e byæ uruchomiona wiele razy, ale tylko
|
||
// pierwsze uruchomienie zadzia³a
|
||
tmpEvent->iQueued =
|
||
0; // tymczasowo, aby by³ ponownie dodany do kolejki
|
||
AddToQuery(tmpEvent, tmpEvent->Activator);
|
||
tmpEvent->iQueued =
|
||
2; // kolejny raz ju¿ absolutnie nie dodawaæ
|
||
}
|
||
}
|
||
}
|
||
if (Global::iMultiplayer) // dajemy znaæ do serwera o wykonaniu
|
||
if ((tmpEvent->iFlags & conditional_anyelse) ==
|
||
0) // jednoznaczne tylko, gdy nie by³o else
|
||
{
|
||
if (tmpEvent->Activator)
|
||
WyslijEvent(tmpEvent->asName, tmpEvent->Activator->GetName());
|
||
else
|
||
WyslijEvent(tmpEvent->asName, "");
|
||
}
|
||
}
|
||
}
|
||
break;
|
||
case tp_WhoIs: // pobranie nazwy poci¹gu do komórki pamiêci
|
||
if (tmpEvent->iFlags & update_load)
|
||
{ // jeœli pytanie o ³adunek
|
||
if (tmpEvent->iFlags & update_memadd) // jeœli typ pojazdu
|
||
tmpEvent->Params[9].asMemCell->UpdateValues(
|
||
tmpEvent->Activator->MoverParameters->TypeName.c_str(), // typ pojazdu
|
||
0, // na razie nic
|
||
0, // na razie nic
|
||
tmpEvent->iFlags &
|
||
(update_memstring | update_memval1 | update_memval2));
|
||
else // jeœli parametry ³adunku
|
||
tmpEvent->Params[9].asMemCell->UpdateValues(
|
||
tmpEvent->Activator->MoverParameters->LoadType != "" ?
|
||
tmpEvent->Activator->MoverParameters->LoadType.c_str() :
|
||
"none", // nazwa ³adunku
|
||
tmpEvent->Activator->MoverParameters->Load, // aktualna iloϾ
|
||
tmpEvent->Activator->MoverParameters->MaxLoad, // maksymalna iloϾ
|
||
tmpEvent->iFlags &
|
||
(update_memstring | update_memval1 | update_memval2));
|
||
}
|
||
else if (tmpEvent->iFlags & update_memadd)
|
||
{ // jeœli miejsce docelowe pojazdu
|
||
tmpEvent->Params[9].asMemCell->UpdateValues(
|
||
tmpEvent->Activator->asDestination.c_str(), // adres docelowy
|
||
tmpEvent->Activator->DirectionGet(), // kierunek pojazdu wzglêdem czo³a
|
||
// sk³adu (1=zgodny,-1=przeciwny)
|
||
tmpEvent->Activator->MoverParameters
|
||
->Power, // moc pojazdu silnikowego: 0 dla wagonu
|
||
tmpEvent->iFlags & (update_memstring | update_memval1 | update_memval2));
|
||
}
|
||
else if (tmpEvent->Activator->Mechanik)
|
||
if (tmpEvent->Activator->Mechanik->Primary())
|
||
{ // tylko jeœli ktoœ tam siedzi - nie powinno dotyczyæ pasa¿era!
|
||
tmpEvent->Params[9].asMemCell->UpdateValues(
|
||
tmpEvent->Activator->Mechanik->TrainName().c_str(),
|
||
tmpEvent->Activator->Mechanik->StationCount() -
|
||
tmpEvent->Activator->Mechanik
|
||
->StationIndex(), // ile przystanków do koñca
|
||
tmpEvent->Activator->Mechanik->IsStop() ? 1 :
|
||
0, // 1, gdy ma tu zatrzymanie
|
||
tmpEvent->iFlags);
|
||
WriteLog("Train detected: " + tmpEvent->Activator->Mechanik->TrainName());
|
||
}
|
||
break;
|
||
case tp_LogValues: // zapisanie zawartoœci komórki pamiêci do logu
|
||
if (tmpEvent->Params[9].asMemCell) // jeœli by³a podana nazwa komórki
|
||
WriteLog("Memcell \"" + tmpEvent->asNodeName + "\": " +
|
||
tmpEvent->Params[9].asMemCell->Text() + " " +
|
||
tmpEvent->Params[9].asMemCell->Value1() + " " +
|
||
tmpEvent->Params[9].asMemCell->Value2());
|
||
else // lista wszystkich
|
||
for (TGroundNode *Current = nRootOfType[TP_MEMCELL]; Current;
|
||
Current = Current->nNext)
|
||
WriteLog("Memcell \"" + Current->asName + "\": " +
|
||
Current->MemCell->Text() + " " + Current->MemCell->Value1() + " " +
|
||
Current->MemCell->Value2());
|
||
break;
|
||
case tp_Voltage: // zmiana napiêcia w zasilaczu (TractionPowerSource)
|
||
if (tmpEvent->Params[9].psPower)
|
||
{ // na razie takie chamskie ustawienie napiêcia zasilania
|
||
WriteLog("type: Voltage");
|
||
tmpEvent->Params[9].psPower->VoltageSet(tmpEvent->Params[0].asdouble);
|
||
}
|
||
case tp_Friction: // zmiana tarcia na scenerii
|
||
{ // na razie takie chamskie ustawienie napiêcia zasilania
|
||
WriteLog("type: Friction");
|
||
Global::fFriction = (tmpEvent->Params[0].asdouble);
|
||
}
|
||
break;
|
||
case tp_Message: // wyœwietlenie komunikatu
|
||
break;
|
||
} // switch (tmpEvent->Type)
|
||
} // if (tmpEvent->bEnabled)
|
||
--tmpEvent->iQueued; // teraz moze byæ ponownie dodany do kolejki
|
||
/*
|
||
if (QueryRootEvent->eJoined) //jeœli jest kolejny o takiej samej nazwie
|
||
{//to teraz jego dajemy do wykonania
|
||
QueryRootEvent->eJoined->Next=QueryRootEvent->Next; //pamiêtaj¹c o nastêpnym z kolejki
|
||
QueryRootEvent->eJoined->fStartTime=QueryRootEvent->fStartTime; //czas musi byæ ten sam,
|
||
bo nie jest aktualizowany
|
||
//QueryRootEvent->fStartTime=0;
|
||
QueryRootEvent=QueryRootEvent->eJoined; //a wykonaæ ten doczepiony
|
||
}
|
||
else
|
||
{//a jak nazwa jest unikalna, to kolejka idzie dalej
|
||
//QueryRootEvent->fStartTime=0;
|
||
QueryRootEvent=QueryRootEvent->Next; //NULL w skrajnym przypadku
|
||
}
|
||
*/
|
||
} // while
|
||
return true;
|
||
}
|
||
|
||
void TGround::OpenGLUpdate(HDC hDC)
|
||
{
|
||
SwapBuffers(hDC); // swap buffers (double buffering)
|
||
};
|
||
|
||
void TGround::UpdatePhys(double dt, int iter)
|
||
{ // aktualizacja fizyki sta³ym krokiem: dt=krok czasu [s], dt*iter=czas od ostatnich przeliczeñ
|
||
for (TGroundNode *Current = nRootOfType[TP_TRACTIONPOWERSOURCE]; Current;
|
||
Current = Current->nNext)
|
||
Current->psTractionPowerSource->Update(dt * iter); // zerowanie sumy pr¹dów
|
||
};
|
||
|
||
bool TGround::Update(double dt, int iter)
|
||
{ // aktualizacja animacji krokiem FPS: dt=krok czasu [s], dt*iter=czas od ostatnich przeliczeñ
|
||
if (dt == 0.0)
|
||
{ // jeœli za³¹czona jest pauza, to tylko obs³u¿yæ ruch w kabinie trzeba
|
||
return true;
|
||
}
|
||
// Ra: w zasadzie to trzeba by utworzyæ oddzieln¹ listê taboru do liczenia fizyki
|
||
// na któr¹ by siê zapisywa³y wszystkie pojazdy bêd¹ce w ruchu
|
||
// pojazdy stoj¹ce nie potrzebuj¹ aktualizacji, chyba ¿e np. ktoœ im zmieni nastawê hamulca
|
||
// oddzieln¹ listê mo¿na by zrobiæ na pojazdy z napêdem, najlepiej posortowan¹ wg typu napêdu
|
||
if (iter > 1) // ABu: ponizsze wykonujemy tylko jesli wiecej niz jedna iteracja
|
||
{ // pierwsza iteracja i wyznaczenie stalych:
|
||
for (TGroundNode *Current = nRootDynamic; Current; Current = Current->nNext)
|
||
{ //
|
||
Current->DynamicObject->MoverParameters->ComputeConstans();
|
||
Current->DynamicObject->CoupleDist();
|
||
Current->DynamicObject->UpdateForce(dt, dt, false);
|
||
}
|
||
for (TGroundNode *Current = nRootDynamic; Current; Current = Current->nNext)
|
||
Current->DynamicObject->FastUpdate(dt);
|
||
// pozostale iteracje
|
||
for (int i = 1; i < (iter - 1); ++i) // jeœli iter==5, to wykona siê 3 razy
|
||
{
|
||
for (TGroundNode *Current = nRootDynamic; Current; Current = Current->nNext)
|
||
Current->DynamicObject->UpdateForce(dt, dt, false);
|
||
for (TGroundNode *Current = nRootDynamic; Current; Current = Current->nNext)
|
||
Current->DynamicObject->FastUpdate(dt);
|
||
}
|
||
// ABu 200205: a to robimy tylko raz, bo nie potrzeba wiêcej
|
||
// Winger 180204 - pantografy
|
||
double dt1 = dt * iter; // ca³kowity czas
|
||
UpdatePhys(dt1, 1);
|
||
TAnimModel::AnimUpdate(dt1); // wykonanie zakolejkowanych animacji
|
||
for (TGroundNode *Current = nRootDynamic; Current; Current = Current->nNext)
|
||
{ // Ra: zmieniæ warunek na sprawdzanie pantografów w jednej zmiennej: czy pantografy i czy
|
||
// podniesione
|
||
if (Current->DynamicObject->MoverParameters->EnginePowerSource.SourceType ==
|
||
CurrentCollector)
|
||
GetTraction(Current->DynamicObject); // poszukiwanie drutu dla pantografów
|
||
Current->DynamicObject->UpdateForce(dt, dt1, true); //,true);
|
||
}
|
||
for (TGroundNode *Current = nRootDynamic; Current; Current = Current->nNext)
|
||
Current->DynamicObject->Update(dt, dt1); // Ra 2015-01: tylko tu przelicza sieæ
|
||
// trakcyjn¹
|
||
}
|
||
else
|
||
{ // jezeli jest tylko jedna iteracja
|
||
UpdatePhys(dt, 1);
|
||
TAnimModel::AnimUpdate(dt); // wykonanie zakolejkowanych animacji
|
||
for (TGroundNode *Current = nRootDynamic; Current; Current = Current->nNext)
|
||
{
|
||
if (Current->DynamicObject->MoverParameters->EnginePowerSource.SourceType ==
|
||
CurrentCollector)
|
||
GetTraction(Current->DynamicObject);
|
||
Current->DynamicObject->MoverParameters->ComputeConstans();
|
||
Current->DynamicObject->CoupleDist();
|
||
Current->DynamicObject->UpdateForce(dt, dt, true); //,true);
|
||
}
|
||
for (TGroundNode *Current = nRootDynamic; Current; Current = Current->nNext)
|
||
Current->DynamicObject->Update(dt, dt); // Ra 2015-01: tylko tu przelicza sieæ trakcyjn¹
|
||
}
|
||
if (bDynamicRemove)
|
||
{ // jeœli jest coœ do usuniêcia z listy, to trzeba na koñcu
|
||
for (TGroundNode *Current = nRootDynamic; Current; Current = Current->nNext)
|
||
if (!Current->DynamicObject->bEnabled)
|
||
{
|
||
DynamicRemove(Current->DynamicObject); // usuniêcie tego i pod³¹czonych
|
||
Current = nRootDynamic; // sprawdzanie listy od pocz¹tku
|
||
}
|
||
bDynamicRemove = false; // na razie koniec
|
||
}
|
||
return true;
|
||
};
|
||
|
||
// Winger 170204 - szukanie trakcji nad pantografami
|
||
bool TGround::GetTraction(TDynamicObject *model)
|
||
{ // aktualizacja drutu zasilaj¹cego dla ka¿dego pantografu, ¿eby odczytaæ napiêcie
|
||
// jeœli pojazd siê nie porusza, to nie ma sensu przeliczaæ tego wiêcej ni¿ raz
|
||
double fRaParam; // parametr równania parametrycznego odcinka drutu
|
||
double fVertical; // odleg³oœæ w pionie; musi byæ w zasiêgu ruchu "pionowego" pantografu
|
||
double fHorizontal; // odleg³oœæ w bok; powinna byæ mniejsza ni¿ pó³ szerokoœci pantografu
|
||
vector3 vLeft, vUp, vFront, dwys;
|
||
vector3 pant0;
|
||
vector3 vParam; // wspó³czynniki równania parametrycznego drutu
|
||
vector3 vStyk; // punkt przebicia drutu przez p³aszczyznê ruchu pantografu
|
||
vector3 vGdzie; // wektor po³o¿enia drutu wzglêdem pojazdu
|
||
vFront = model->VectorFront(); // wektor normalny dla p³aszczyzny ruchu pantografu
|
||
vUp = model->VectorUp(); // wektor pionu pud³a (pochylony od pionu na przechy³ce)
|
||
vLeft = model->VectorLeft(); // wektor odleg³oœci w bok (odchylony od poziomu na przechy³ce)
|
||
dwys = model->GetPosition(); // wspó³rzêdne œrodka pojazdu
|
||
TAnimPant *p; // wskaŸnik do obiektu danych pantografu
|
||
for (int k = 0; k < model->iAnimType[ANIM_PANTS]; ++k)
|
||
{ // pêtla po pantografach
|
||
p = model->pants[k].fParamPants;
|
||
if (k ? model->MoverParameters->PantRearUp : model->MoverParameters->PantFrontUp)
|
||
{ // jeœli pantograf podniesiony
|
||
pant0 = dwys + (vLeft * p->vPos.z) + (vUp * p->vPos.y) + (vFront * p->vPos.x);
|
||
if (p->hvPowerWire)
|
||
{ // je¿eli znamy drut z poprzedniego przebiegu
|
||
int n = 30; //¿eby siê nie zapêtli³
|
||
while (p->hvPowerWire)
|
||
{ // powtarzane a¿ do znalezienia odpowiedniego odcinka na liœcie dwukierunkowej
|
||
// obliczamy wyraz wolny równania p³aszczyzny (to miejsce nie jest odpowienie)
|
||
vParam = p->hvPowerWire->vParametric; // wspó³czynniki równania parametrycznego
|
||
fRaParam = -DotProduct(pant0, vFront);
|
||
// podstawiamy równanie parametryczne drutu do równania p³aszczyzny pantografu
|
||
// vFront.x*(t1x+t*vParam.x)+vFront.y*(t1y+t*vParam.y)+vFront.z*(t1z+t*vParam.z)+fRaDist=0;
|
||
fRaParam = -(DotProduct(p->hvPowerWire->pPoint1, vFront) + fRaParam) /
|
||
DotProduct(vParam, vFront);
|
||
if (fRaParam <
|
||
-0.001) // histereza rzêdu 7cm na 70m typowego przês³a daje 1 promil
|
||
p->hvPowerWire = p->hvPowerWire->hvNext[0];
|
||
else if (fRaParam > 1.001)
|
||
p->hvPowerWire = p->hvPowerWire->hvNext[1];
|
||
else if (p->hvPowerWire->iLast & 3)
|
||
{ // dla ostatniego i przedostatniego przês³a wymuszamy szukanie innego
|
||
p->hvPowerWire = NULL; // nie to, ¿e nie ma, ale trzeba sprawdziæ inne
|
||
// p->fHorizontal=fHorizontal; //zapamiêtanie po³o¿enia drutu
|
||
break;
|
||
}
|
||
else if (p->hvPowerWire->hvParallel)
|
||
{ // jeœli przês³o tworzy bie¿niê wspóln¹, to trzeba sprawdziæ pozosta³e
|
||
p->hvPowerWire = NULL; // nie to, ¿e nie ma, ale trzeba sprawdziæ inne
|
||
// p->fHorizontal=fHorizontal; //zapamiêtanie po³o¿enia drutu
|
||
break; // tymczasowo dla bie¿ni wspólnych poszukiwanie po ca³oœci
|
||
}
|
||
else
|
||
{ // jeœli t jest w przedziale, wyznaczyæ odleg³oœæ wzd³u¿ wektorów vUp i vLeft
|
||
vStyk = p->hvPowerWire->pPoint1 + fRaParam * vParam; // punkt styku
|
||
// p³aszczyzny z drutem
|
||
// (dla generatora ³uku
|
||
// el.)
|
||
vGdzie = vStyk - pant0; // wektor
|
||
// odleg³oœæ w pionie musi byæ w zasiêgu ruchu "pionowego" pantografu
|
||
fVertical = DotProduct(
|
||
vGdzie, vUp); // musi siê mieœciæ w przedziale ruchu pantografu
|
||
// odleg³oœæ w bok powinna byæ mniejsza ni¿ pó³ szerokoœci pantografu
|
||
fHorizontal = fabs(DotProduct(vGdzie, vLeft)) -
|
||
p->fWidth; // to siê musi mieœciæ w przedziale zale¿nym od
|
||
// szerokoœci pantografu
|
||
// jeœli w pionie albo w bok jest za daleko, to dany drut jest nieu¿yteczny
|
||
if (fHorizontal > 0) // 0.635 dla AKP-1 AKP-4E
|
||
{ // drut wyszed³ poza zakres roboczy, ale jeszcze jest nabie¿nik -
|
||
// pantograf siê unosi bez utraty pr¹du
|
||
if (fHorizontal > p->fWidthExtra) // czy wyszed³ za nabie¿nik
|
||
{
|
||
p->hvPowerWire = NULL; // dotychczasowy drut nie liczy siê
|
||
// p->fHorizontal=fHorizontal; //zapamiêtanie po³o¿enia drutu
|
||
}
|
||
else
|
||
{ // problem jest, gdy nowy drut jest wy¿ej, wtedy pantograf od³¹cza siê
|
||
// od starego, a na podniesienie do nowego potrzebuje czasu
|
||
p->PantTraction =
|
||
fVertical +
|
||
0.15 * fHorizontal / p->fWidthExtra; // na razie liniowo na
|
||
// nabie¿niku, dok³adnoœæ
|
||
// poprawi siê póŸniej
|
||
// p->fHorizontal=fHorizontal; //zapamiêtanie po³o¿enia drutu
|
||
}
|
||
}
|
||
else
|
||
{ // po wyselekcjonowaniu drutu, przypisaæ go do toru, ¿eby nie trzeba by³o
|
||
// szukaæ
|
||
// dla 3 koñcowych przêse³ sprawdziæ wszystkie dostêpne przês³a
|
||
// bo mog¹ byæ umieszczone równolegle nad torem - po³¹czyæ w pierœcieñ
|
||
// najlepiej, jakby odcinki równoleg³e by³y oznaczone we wpisach
|
||
// WriteLog("Drut: "+AnsiString(fHorizontal)+" "+AnsiString(fVertical));
|
||
p->PantTraction = fVertical;
|
||
// p->fHorizontal=fHorizontal; //zapamiêtanie po³o¿enia drutu
|
||
break; // koniec pêtli, aktualny drut pasuje
|
||
}
|
||
}
|
||
if (--n <= 0) // coœ za d³ugo to szukanie trwa
|
||
p->hvPowerWire = NULL;
|
||
}
|
||
}
|
||
if (!p->hvPowerWire) // else nie, bo móg³ zostaæ wyrzucony
|
||
{ // poszukiwanie po okolicznych sektorach
|
||
int c = GetColFromX(dwys.x) + 1;
|
||
int r = GetRowFromZ(dwys.z) + 1;
|
||
TSubRect *tmp;
|
||
TGroundNode *node;
|
||
p->PantTraction = 5.0; // taka za du¿a wartoœæ
|
||
for (int j = r - 2; j <= r; j++)
|
||
for (int i = c - 2; i <= c; i++)
|
||
{ // poszukiwanie po najbli¿szych sektorach niewiele da przy wiêkszym
|
||
// zagêszczeniu
|
||
tmp = FastGetSubRect(i, j);
|
||
if (tmp)
|
||
{ // dany sektor mo¿e nie mieæ nic w œrodku
|
||
for (node = tmp->nRenderWires; node;
|
||
node = node->nNext3) // nastêpny z grupy
|
||
if (node->iType ==
|
||
TP_TRACTION) // w grupie tej s¹ druty oraz inne linie
|
||
{
|
||
vParam =
|
||
node->hvTraction
|
||
->vParametric; // wspó³czynniki równania parametrycznego
|
||
fRaParam = -DotProduct(pant0, vFront);
|
||
fRaParam = -(DotProduct(node->hvTraction->pPoint1, vFront) +
|
||
fRaParam) /
|
||
DotProduct(vParam, vFront);
|
||
if ((fRaParam >= -0.001) ? (fRaParam <= 1.001) : false)
|
||
{ // jeœli tylko jest w przedziale, wyznaczyæ odleg³oœæ wzd³u¿
|
||
// wektorów vUp i vLeft
|
||
vStyk = node->hvTraction->pPoint1 +
|
||
fRaParam * vParam; // punkt styku p³aszczyzny z
|
||
// drutem (dla generatora ³uku
|
||
// el.)
|
||
vGdzie = vStyk - pant0; // wektor
|
||
fVertical = DotProduct(
|
||
vGdzie,
|
||
vUp); // musi siê mieœciæ w przedziale ruchu pantografu
|
||
if (fVertical >= 0.0) // jeœli ponad pantografem (bo mo¿e
|
||
// ³apaæ druty spod wiaduktu)
|
||
if (Global::bEnableTraction ?
|
||
fVertical < p->PantWys - 0.15 :
|
||
false) // jeœli drut jest ni¿ej ni¿ 15cm pod
|
||
// œlizgiem
|
||
{ // prze³¹czamy w tryb po³amania, o ile jedzie;
|
||
// (bEnableTraction) aby da³o siê jeŸdziæ na
|
||
// koœlawych
|
||
// sceneriach
|
||
fHorizontal = fabs(DotProduct(vGdzie, vLeft)) -
|
||
p->fWidth; // i do tego jeszcze
|
||
// wejdzie pod œlizg
|
||
if (fHorizontal <= 0.0) // 0.635 dla AKP-1 AKP-4E
|
||
{
|
||
p->PantWys =
|
||
-1.0; // ujemna liczba oznacza po³amanie
|
||
p->hvPowerWire = NULL; // bo inaczej siê zasila
|
||
// w nieskoñczonoœæ z
|
||
// po³amanego
|
||
// p->fHorizontal=fHorizontal; //zapamiêtanie
|
||
// po³o¿enia drutu
|
||
if (model->MoverParameters->EnginePowerSource
|
||
.CollectorParameters.CollectorsNo >
|
||
0) // liczba pantografów
|
||
--model->MoverParameters->EnginePowerSource
|
||
.CollectorParameters
|
||
.CollectorsNo; // teraz bêdzie
|
||
// mniejsza
|
||
if (DebugModeFlag)
|
||
ErrorLog(
|
||
"Pant. break: at " +
|
||
FloatToStrF(pant0.x, ffFixed, 7, 2) +
|
||
" " +
|
||
FloatToStrF(pant0.y, ffFixed, 7, 2) +
|
||
" " +
|
||
FloatToStrF(pant0.z, ffFixed, 7, 2));
|
||
}
|
||
}
|
||
else if (fVertical < p->PantTraction) // ale ni¿ej, ni¿
|
||
// poprzednio
|
||
// znaleziony
|
||
{
|
||
fHorizontal =
|
||
fabs(DotProduct(vGdzie, vLeft)) - p->fWidth;
|
||
if (fHorizontal <= 0.0) // 0.635 dla AKP-1 AKP-4E
|
||
{ // to siê musi mieœciæ w przedziale zaleznym od
|
||
// szerokoœci pantografu
|
||
p->hvPowerWire =
|
||
node->hvTraction; // jakiœ znaleziony
|
||
p->PantTraction =
|
||
fVertical; // zapamiêtanie nowej wysokoœci
|
||
// p->fHorizontal=fHorizontal; //zapamiêtanie
|
||
// po³o¿enia drutu
|
||
}
|
||
else if (fHorizontal <
|
||
p->fWidthExtra) // czy zmieœci³ siê w
|
||
// zakresie nabie¿nika?
|
||
{ // problem jest, gdy nowy drut jest wy¿ej, wtedy
|
||
// pantograf od³¹cza siê od starego, a na
|
||
// podniesienie do nowego potrzebuje czasu
|
||
fVertical +=
|
||
0.15 * fHorizontal /
|
||
p->fWidthExtra; // korekta wysokoœci o
|
||
// nabie¿nik - drut nad
|
||
// nabie¿nikiem jest
|
||
// geometrycznie jakby nieco
|
||
// wy¿ej
|
||
if (fVertical <
|
||
p->PantTraction) // gdy po korekcie jest
|
||
// ni¿ej, ni¿ poprzednio
|
||
// znaleziony
|
||
{ // gdyby to wystarczy³o, to mo¿emy go uznaæ
|
||
p->hvPowerWire =
|
||
node->hvTraction; // mo¿e byæ
|
||
p->PantTraction =
|
||
fVertical; // na razie liniowo na
|
||
// nabie¿niku, dok³adnoœæ
|
||
// poprawi siê póŸniej
|
||
// p->fHorizontal=fHorizontal;
|
||
// //zapamiêtanie po³o¿enia drutu
|
||
}
|
||
}
|
||
}
|
||
} // warunek na parametr drutu <0;1>
|
||
} // pêtla po drutach
|
||
} // sektor istnieje
|
||
} // pêtla po sektorach
|
||
} // koniec poszukiwania w sektorach
|
||
if (!p->hvPowerWire) // jeœli drut nie znaleziony
|
||
if (!Global::bLiveTraction) // ale mo¿na oszukiwaæ
|
||
model->pants[k].fParamPants->PantTraction = 1.4; // to dajemy coœ tam dla picu
|
||
} // koniec obs³ugi podniesionego
|
||
else
|
||
p->hvPowerWire = NULL; // pantograf opuszczony
|
||
}
|
||
// if (model->fWahaczeAmp<model->MoverParameters->DistCounter)
|
||
//{//nieu¿ywana normalnie zmienna ogranicza powtórzone logowania
|
||
// model->fWahaczeAmp=model->MoverParameters->DistCounter;
|
||
// ErrorLog(FloatToStrF(1000.0*model->MoverParameters->DistCounter,ffFixed,7,3)+","+FloatToStrF(p->PantTraction,ffFixed,7,3)+","+FloatToStrF(p->fHorizontal,ffFixed,7,3)+","+FloatToStrF(p->PantWys,ffFixed,7,3)+","+AnsiString(p->hvPowerWire?1:0));
|
||
// //
|
||
// if (p->fHorizontal>1.0)
|
||
//{
|
||
// //Global::iPause|=1; //zapauzowanie symulacji
|
||
// Global::fTimeSpeed=1; //spowolnienie czasu do obejrzenia pantografu
|
||
// return true; //³apacz
|
||
//}
|
||
//}
|
||
return true;
|
||
};
|
||
|
||
bool TGround::RenderDL(vector3 pPosition)
|
||
{ // renderowanie scenerii z Display List - faza nieprzezroczystych
|
||
glDisable(GL_BLEND);
|
||
glAlphaFunc(GL_GREATER, 0.45); // im mniejsza wartoœæ, tym wiêksza ramka, domyœlnie 0.1f
|
||
++TGroundRect::iFrameNumber; // zwiêszenie licznika ramek (do usuwniania nadanimacji)
|
||
CameraDirection.x = sin(Global::pCameraRotation); // wektor kierunkowy
|
||
CameraDirection.z = cos(Global::pCameraRotation);
|
||
int tr, tc;
|
||
TGroundNode *node;
|
||
glColor3f(1.0f, 1.0f, 1.0f);
|
||
glEnable(GL_LIGHTING);
|
||
int n = 2 * iNumSubRects; //(2*==2km) promieñ wyœwietlanej mapy w sektorach
|
||
int c = GetColFromX(pPosition.x);
|
||
int r = GetRowFromZ(pPosition.z);
|
||
TSubRect *tmp;
|
||
for (node = srGlobal.nRenderHidden; node; node = node->nNext3)
|
||
node->RenderHidden(); // rednerowanie globalnych (nie za czêsto?)
|
||
int i, j, k;
|
||
// renderowanie czo³gowe dla obiektów aktywnych a niewidocznych
|
||
for (j = r - n; j <= r + n; j++)
|
||
for (i = c - n; i <= c + n; i++)
|
||
if ((tmp = FastGetSubRect(i, j)) != NULL)
|
||
{
|
||
tmp->LoadNodes(); // oznaczanie aktywnych sektorów
|
||
for (node = tmp->nRenderHidden; node; node = node->nNext3)
|
||
node->RenderHidden();
|
||
tmp->RenderSounds(); // jeszcze dŸwiêki pojazdów by siê przyda³y, równie¿
|
||
// niewidocznych
|
||
}
|
||
// renderowanie progresywne - zale¿ne od FPS oraz kierunku patrzenia
|
||
iRendered = 0; // iloœæ renderowanych sektorów
|
||
vector3 direction;
|
||
for (k = 0; k < Global::iSegmentsRendered; ++k) // sektory w kolejnoœci odleg³oœci
|
||
{ // przerobione na u¿ycie SectorOrder
|
||
i = SectorOrder[k].x; // na starcie oba >=0
|
||
j = SectorOrder[k].y;
|
||
do
|
||
{
|
||
if (j <= 0)
|
||
i = -i; // pierwszy przebieg: j<=0, i>=0; drugi: j>=0, i<=0; trzeci: j<=0, i<=0
|
||
// czwarty: j>=0, i>=0;
|
||
j = -j; // i oraz j musi byæ zmienione wczeœniej, ¿eby continue dzia³a³o
|
||
direction = vector3(i, 0, j); // wektor od kamery do danego sektora
|
||
if (LengthSquared3(direction) > 5) // te blisko s¹ zawsze wyœwietlane
|
||
{
|
||
direction = SafeNormalize(direction); // normalizacja
|
||
if (CameraDirection.x * direction.x + CameraDirection.z * direction.z < 0.55)
|
||
continue; // pomijanie sektorów poza k¹tem patrzenia
|
||
}
|
||
Rects[(i + c) / iNumSubRects][(j + r) / iNumSubRects]
|
||
.RenderDL(); // kwadrat kilometrowy nie zawsze, bo szkoda FPS
|
||
if ((tmp = FastGetSubRect(i + c, j + r)) != NULL)
|
||
if (tmp->iNodeCount) // o ile s¹ jakieœ obiekty, bo po co puste sektory przelatywaæ
|
||
pRendered[iRendered++] = tmp; // tworzenie listy sektorów do renderowania
|
||
} while ((i < 0) || (j < 0)); // s¹ 4 przypadki, oprócz i=j=0
|
||
}
|
||
for (i = 0; i < iRendered; i++)
|
||
pRendered[i]->RenderDL(); // renderowanie nieprzezroczystych
|
||
return true;
|
||
}
|
||
|
||
bool TGround::RenderAlphaDL(vector3 pPosition)
|
||
{ // renderowanie scenerii z Display List - faza przezroczystych
|
||
glEnable(GL_BLEND);
|
||
glAlphaFunc(GL_GREATER, 0.04); // im mniejsza wartoœæ, tym wiêksza ramka, domyœlnie 0.1f
|
||
TGroundNode *node;
|
||
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
|
||
TSubRect *tmp;
|
||
// Ra: renderowanie progresywne - zale¿ne od FPS oraz kierunku patrzenia
|
||
int i;
|
||
for (i = iRendered - 1; i >= 0; --i) // od najdalszych
|
||
{ // przezroczyste trójk¹ty w oddzielnym cyklu przed modelami
|
||
tmp = pRendered[i];
|
||
for (node = tmp->nRenderRectAlpha; node; node = node->nNext3)
|
||
node->RenderAlphaDL(); // przezroczyste modele
|
||
}
|
||
for (i = iRendered - 1; i >= 0; --i) // od najdalszych
|
||
{ // renderowanie przezroczystych modeli oraz pojazdów
|
||
pRendered[i]->RenderAlphaDL();
|
||
}
|
||
glDisable(GL_LIGHTING); // linie nie powinny œwieciæ
|
||
for (i = iRendered - 1; i >= 0; --i) // od najdalszych
|
||
{ // druty na koñcu, ¿eby siê nie robi³y bia³e plamy na tle lasu
|
||
tmp = pRendered[i];
|
||
for (node = tmp->nRenderWires; node; node = node->nNext3)
|
||
node->RenderAlphaDL(); // druty
|
||
}
|
||
return true;
|
||
}
|
||
|
||
bool TGround::RenderVBO(vector3 pPosition)
|
||
{ // renderowanie scenerii z VBO - faza nieprzezroczystych
|
||
glDisable(GL_BLEND);
|
||
glAlphaFunc(GL_GREATER, 0.45); // im mniejsza wartoœæ, tym wiêksza ramka, domyœlnie 0.1f
|
||
++TGroundRect::iFrameNumber; // zwiêszenie licznika ramek
|
||
CameraDirection.x = sin(Global::pCameraRotation); // wektor kierunkowy
|
||
CameraDirection.z = cos(Global::pCameraRotation);
|
||
int tr, tc;
|
||
TGroundNode *node;
|
||
glColor3f(1.0f, 1.0f, 1.0f);
|
||
glEnable(GL_LIGHTING);
|
||
int n = 2 * iNumSubRects; //(2*==2km) promieñ wyœwietlanej mapy w sektorach
|
||
int c = GetColFromX(pPosition.x);
|
||
int r = GetRowFromZ(pPosition.z);
|
||
TSubRect *tmp;
|
||
for (node = srGlobal.nRenderHidden; node; node = node->nNext3)
|
||
node->RenderHidden(); // rednerowanie globalnych (nie za czêsto?)
|
||
int i, j, k;
|
||
// renderowanie czo³gowe dla obiektów aktywnych a niewidocznych
|
||
for (j = r - n; j <= r + n; j++)
|
||
for (i = c - n; i <= c + n; i++)
|
||
{
|
||
if ((tmp = FastGetSubRect(i, j)) != NULL)
|
||
{
|
||
for (node = tmp->nRenderHidden; node; node = node->nNext3)
|
||
node->RenderHidden();
|
||
tmp->RenderSounds(); // jeszcze dŸwiêki pojazdów by siê przyda³y, równie¿
|
||
// niewidocznych
|
||
}
|
||
}
|
||
// renderowanie progresywne - zale¿ne od FPS oraz kierunku patrzenia
|
||
iRendered = 0; // iloœæ renderowanych sektorów
|
||
vector3 direction;
|
||
for (k = 0; k < Global::iSegmentsRendered; ++k) // sektory w kolejnoœci odleg³oœci
|
||
{ // przerobione na u¿ycie SectorOrder
|
||
i = SectorOrder[k].x; // na starcie oba >=0
|
||
j = SectorOrder[k].y;
|
||
do
|
||
{
|
||
if (j <= 0)
|
||
i = -i; // pierwszy przebieg: j<=0, i>=0; drugi: j>=0, i<=0; trzeci: j<=0, i<=0
|
||
// czwarty: j>=0, i>=0;
|
||
j = -j; // i oraz j musi byæ zmienione wczeœniej, ¿eby continue dzia³a³o
|
||
direction = vector3(i, 0, j); // wektor od kamery do danego sektora
|
||
if (LengthSquared3(direction) > 5) // te blisko s¹ zawsze wyœwietlane
|
||
{
|
||
direction = SafeNormalize(direction); // normalizacja
|
||
if (CameraDirection.x * direction.x + CameraDirection.z * direction.z < 0.55)
|
||
continue; // pomijanie sektorów poza k¹tem patrzenia
|
||
}
|
||
Rects[(i + c) / iNumSubRects][(j + r) / iNumSubRects]
|
||
.RenderVBO(); // kwadrat kilometrowy nie zawsze, bo szkoda FPS
|
||
if ((tmp = FastGetSubRect(i + c, j + r)) != NULL)
|
||
if (tmp->iNodeCount) // je¿eli s¹ jakieœ obiekty, bo po co puste sektory przelatywaæ
|
||
pRendered[iRendered++] = tmp; // tworzenie listy sektorów do renderowania
|
||
} while ((i < 0) || (j < 0)); // s¹ 4 przypadki, oprócz i=j=0
|
||
}
|
||
// dodaæ rednerowanie terenu z E3D - jedno VBO jest u¿ywane dla ca³ego modelu, chyba ¿e jest ich
|
||
// wiêcej
|
||
if (Global::pTerrainCompact)
|
||
Global::pTerrainCompact->TerrainRenderVBO(TGroundRect::iFrameNumber);
|
||
for (i = 0; i < iRendered; i++)
|
||
{ // renderowanie nieprzezroczystych
|
||
pRendered[i]->RenderVBO();
|
||
}
|
||
return true;
|
||
}
|
||
|
||
bool TGround::RenderAlphaVBO(vector3 pPosition)
|
||
{ // renderowanie scenerii z VBO - faza przezroczystych
|
||
glEnable(GL_BLEND);
|
||
glAlphaFunc(GL_GREATER, 0.04); // im mniejsza wartoœæ, tym wiêksza ramka, domyœlnie 0.1f
|
||
TGroundNode *node;
|
||
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
|
||
TSubRect *tmp;
|
||
int i;
|
||
for (i = iRendered - 1; i >= 0; --i) // od najdalszych
|
||
{ // renderowanie przezroczystych trójk¹tów sektora
|
||
tmp = pRendered[i];
|
||
tmp->LoadNodes(); // ewentualne tworzenie siatek
|
||
if (tmp->StartVBO())
|
||
{
|
||
for (node = tmp->nRenderRectAlpha; node; node = node->nNext3)
|
||
if (node->iVboPtr >= 0)
|
||
node->RenderAlphaVBO(); // nieprzezroczyste obiekty terenu
|
||
tmp->EndVBO();
|
||
}
|
||
}
|
||
for (i = iRendered - 1; i >= 0; --i) // od najdalszych
|
||
pRendered[i]->RenderAlphaVBO(); // przezroczyste modeli oraz pojazdy
|
||
glDisable(GL_LIGHTING); // linie nie powinny œwieciæ
|
||
for (i = iRendered - 1; i >= 0; --i) // od najdalszych
|
||
{ // druty na koñcu, ¿eby siê nie robi³y bia³e plamy na tle lasu
|
||
tmp = pRendered[i];
|
||
if (tmp->StartVBO())
|
||
{
|
||
for (node = tmp->nRenderWires; node; node = node->nNext3)
|
||
node->RenderAlphaVBO(); // przezroczyste modele
|
||
tmp->EndVBO();
|
||
}
|
||
}
|
||
return true;
|
||
};
|
||
|
||
//---------------------------------------------------------------------------
|
||
void TGround::Navigate(String ClassName, UINT Msg, WPARAM wParam, LPARAM lParam)
|
||
{ // wys³anie komunikatu do steruj¹cego
|
||
HWND h = FindWindow(ClassName.c_str(), 0); // mo¿na by to zapamiêtaæ
|
||
if (h == 0)
|
||
h = FindWindow(0, ClassName.c_str()); // mo¿na by to zapamiêtaæ
|
||
SendMessage(h, Msg, wParam, lParam);
|
||
};
|
||
//--------------------------------
|
||
void TGround::WyslijEvent(const AnsiString &e, const AnsiString &d)
|
||
{ // Ra: jeszcze do wyczyszczenia
|
||
DaneRozkaz r;
|
||
r.iSygn = 'EU07';
|
||
r.iComm = 2; // 2 - event
|
||
int i = e.Length(), j = d.Length();
|
||
r.cString[0] = char(i);
|
||
strcpy(r.cString + 1, e.c_str()); // zakoñczony zerem
|
||
r.cString[i + 2] = char(j); // licznik po zerze koñcz¹cym
|
||
strcpy(r.cString + 3 + i, d.c_str()); // zakoñczony zerem
|
||
COPYDATASTRUCT cData;
|
||
cData.dwData = 'EU07'; // sygnatura
|
||
cData.cbData = 12 + i + j; // 8+dwa liczniki i dwa zera koñcz¹ce
|
||
cData.lpData = &r;
|
||
Navigate("TEU07SRK", WM_COPYDATA, (WPARAM)Global::hWnd, (LPARAM)&cData);
|
||
CommLog(AnsiString(Now()) + " " + IntToStr(r.iComm) + " " + e + " sent");
|
||
};
|
||
//---------------------------------------------------------------------------
|
||
void TGround::WyslijUszkodzenia(const AnsiString &t, char fl)
|
||
{ // wys³anie informacji w postaci pojedynczego tekstu
|
||
DaneRozkaz r;
|
||
r.iSygn = 'EU07';
|
||
r.iComm = 13; // numer komunikatu
|
||
int i = t.Length();
|
||
r.cString[0] = char(fl);
|
||
r.cString[1] = char(i);
|
||
strcpy(r.cString + 2, t.c_str()); // z zerem koñcz¹cym
|
||
COPYDATASTRUCT cData;
|
||
cData.dwData = 'EU07'; // sygnatura
|
||
cData.cbData = 11 + i; // 8+licznik i zero koñcz¹ce
|
||
cData.lpData = &r;
|
||
Navigate("TEU07SRK", WM_COPYDATA, (WPARAM)Global::hWnd, (LPARAM)&cData);
|
||
CommLog(AnsiString(Now()) + " " + IntToStr(r.iComm) + " " + t + " sent");
|
||
};
|
||
//---------------------------------------------------------------------------
|
||
void TGround::WyslijString(const AnsiString &t, int n)
|
||
{ // wys³anie informacji w postaci pojedynczego tekstu
|
||
DaneRozkaz r;
|
||
r.iSygn = 'EU07';
|
||
r.iComm = n; // numer komunikatu
|
||
int i = t.Length();
|
||
r.cString[0] = char(i);
|
||
strcpy(r.cString + 1, t.c_str()); // z zerem koñcz¹cym
|
||
COPYDATASTRUCT cData;
|
||
cData.dwData = 'EU07'; // sygnatura
|
||
cData.cbData = 10 + i; // 8+licznik i zero koñcz¹ce
|
||
cData.lpData = &r;
|
||
Navigate("TEU07SRK", WM_COPYDATA, (WPARAM)Global::hWnd, (LPARAM)&cData);
|
||
CommLog(AnsiString(Now()) + " " + IntToStr(r.iComm) + " " + t + " sent");
|
||
};
|
||
//---------------------------------------------------------------------------
|
||
void TGround::WyslijWolny(const AnsiString &t)
|
||
{ // Ra: jeszcze do wyczyszczenia
|
||
WyslijString(t, 4); // tor wolny
|
||
};
|
||
//--------------------------------
|
||
void TGround::WyslijNamiary(TGroundNode *t)
|
||
{ // wys³anie informacji o pojeŸdzie - (float), d³ugoœæ ramki bêdzie zwiêkszana w miarê potrzeby
|
||
// WriteLog("Wysylam pojazd");
|
||
DaneRozkaz r;
|
||
r.iSygn = 'EU07';
|
||
r.iComm = 7; // 7 - dane pojazdu
|
||
int i = 32, j = t->asName.Length();
|
||
r.iPar[0] = i; // iloϾ danych liczbowych
|
||
r.fPar[1] = Global::fTimeAngleDeg / 360.0; // aktualny czas (1.0=doba)
|
||
r.fPar[2] = t->DynamicObject->MoverParameters->Loc.X; // pozycja X
|
||
r.fPar[3] = t->DynamicObject->MoverParameters->Loc.Y; // pozycja Y
|
||
r.fPar[4] = t->DynamicObject->MoverParameters->Loc.Z; // pozycja Z
|
||
r.fPar[5] = t->DynamicObject->MoverParameters->V; // prêdkoœæ ruchu X
|
||
r.fPar[6] = t->DynamicObject->MoverParameters->nrot * M_PI *
|
||
t->DynamicObject->MoverParameters->WheelDiameter; // prêdkoœæ obrotowa kó£
|
||
r.fPar[7] = 0; // prêdkoœæ ruchu Z
|
||
r.fPar[8] = t->DynamicObject->MoverParameters->AccS; // przyspieszenie X
|
||
r.fPar[9] = t->DynamicObject->MoverParameters->AccN; // przyspieszenie Y //na razie nie
|
||
r.fPar[10] = t->DynamicObject->MoverParameters->AccV; // przyspieszenie Z
|
||
r.fPar[11] = t->DynamicObject->MoverParameters->DistCounter; // przejechana odleg³oœæ w km
|
||
r.fPar[12] = t->DynamicObject->MoverParameters->PipePress; // ciœnienie w PG
|
||
r.fPar[13] = t->DynamicObject->MoverParameters->ScndPipePress; // ciœnienie w PZ
|
||
r.fPar[14] = t->DynamicObject->MoverParameters->BrakePress; // ciœnienie w CH
|
||
r.fPar[15] = t->DynamicObject->MoverParameters->Compressor; // ciœnienie w ZG
|
||
r.fPar[16] = t->DynamicObject->MoverParameters->Itot; // Pr¹d ca³kowity
|
||
r.iPar[17] = t->DynamicObject->MoverParameters->MainCtrlPos; // Pozycja NJ
|
||
r.iPar[18] = t->DynamicObject->MoverParameters->ScndCtrlPos; // Pozycja NB
|
||
r.iPar[19] = t->DynamicObject->MoverParameters->MainCtrlActualPos; // Pozycja jezdna
|
||
r.iPar[20] = t->DynamicObject->MoverParameters->ScndCtrlActualPos; // Pozycja bocznikowania
|
||
r.iPar[21] = t->DynamicObject->MoverParameters->ScndCtrlActualPos; // Pozycja bocznikowania
|
||
r.iPar[22] = t->DynamicObject->MoverParameters->ResistorsFlag * 1 +
|
||
t->DynamicObject->MoverParameters->ConverterFlag * 2 +
|
||
+t->DynamicObject->MoverParameters->CompressorFlag * 4 +
|
||
t->DynamicObject->MoverParameters->Mains * 8 +
|
||
+t->DynamicObject->MoverParameters->DoorLeftOpened * 16 +
|
||
t->DynamicObject->MoverParameters->DoorRightOpened * 32 +
|
||
+t->DynamicObject->MoverParameters->FuseFlag * 64 +
|
||
t->DynamicObject->MoverParameters->DepartureSignal * 128;
|
||
// WriteLog("Zapisalem stare");
|
||
// WriteLog("Mam patykow "+IntToStr(t->DynamicObject->iAnimType[ANIM_PANTS]));
|
||
for (int p = 0; p < 4; p++)
|
||
{
|
||
// WriteLog("Probuje pant "+IntToStr(p));
|
||
if (p < t->DynamicObject->iAnimType[ANIM_PANTS])
|
||
{
|
||
r.fPar[23 + p] = t->DynamicObject->pants[p].fParamPants->PantWys; // stan pantografów 4
|
||
// WriteLog("Zapisalem pant "+IntToStr(p));
|
||
}
|
||
else
|
||
{
|
||
r.fPar[23 + p] = -2;
|
||
// WriteLog("Nie mam pant "+IntToStr(p));
|
||
}
|
||
}
|
||
// WriteLog("Zapisalem pantografy");
|
||
for (int p = 0; p < 3; p++)
|
||
r.fPar[27 + p] =
|
||
t->DynamicObject->MoverParameters->ShowCurrent(p + 1); // amperomierze kolejnych grup
|
||
// WriteLog("zapisalem prady");
|
||
r.iPar[30] = t->DynamicObject->MoverParameters->WarningSignal; // trabienie
|
||
r.fPar[31] = t->DynamicObject->MoverParameters->RunningTraction.TractionVoltage; // napiecie WN
|
||
// WriteLog("Parametry gotowe");
|
||
i <<= 2; // iloœæ bajtów
|
||
r.cString[i] = char(j); // na koñcu nazwa, ¿eby jakoœ zidentyfikowaæ
|
||
strcpy(r.cString + i + 1, t->asName.c_str()); // zakoñczony zerem
|
||
COPYDATASTRUCT cData;
|
||
cData.dwData = 'EU07'; // sygnatura
|
||
cData.cbData = 10 + i + j; // 8+licznik i zero koñcz¹ce
|
||
cData.lpData = &r;
|
||
// WriteLog("Ramka gotowa");
|
||
Navigate("TEU07SRK", WM_COPYDATA, (WPARAM)Global::hWnd, (LPARAM)&cData);
|
||
// WriteLog("Ramka poszla!");
|
||
CommLog(AnsiString(Now()) + " " + IntToStr(r.iComm) + " " + t->asName + " sent");
|
||
};
|
||
//
|
||
void TGround::WyslijObsadzone()
|
||
{ // wys³anie informacji o pojeŸdzie
|
||
DaneRozkaz2 r;
|
||
r.iSygn = 'EU07';
|
||
r.iComm = 12; // kod 12
|
||
for (int i; i<1984; i++) r.cString[i] = 0;
|
||
|
||
int i = 0;
|
||
for (TGroundNode *Current = nRootDynamic; Current; Current = Current->nNext)
|
||
if (Current->DynamicObject->Mechanik)
|
||
{
|
||
strcpy(r.cString + 64 * i, Current->DynamicObject->asName.c_str());
|
||
r.fPar[16 * i + 4] = Current->DynamicObject->GetPosition().x;
|
||
r.fPar[16 * i + 5] = Current->DynamicObject->GetPosition().y;
|
||
r.fPar[16 * i + 6] = Current->DynamicObject->GetPosition().z;
|
||
r.iPar[16 * i + 7] = Current->DynamicObject->Mechanik->GetAction();
|
||
strcpy(r.cString + 64 * i + 32, Current->DynamicObject->GetTrack()->IsolatedName().c_str());
|
||
strcpy(r.cString + 64 * i + 48, Current->DynamicObject->Mechanik->Timetable()->TrainName.c_str());
|
||
i++;
|
||
if (i>30) break;
|
||
}
|
||
while (i <= 30)
|
||
{
|
||
strcpy(r.cString + 64 * i, AnsiString("none").c_str());
|
||
r.fPar[16 * i + 4] = 1;
|
||
r.fPar[16 * i + 5] = 2;
|
||
r.fPar[16 * i + 6] = 3;
|
||
r.iPar[16 * i + 7] = 0;
|
||
strcpy(r.cString + 64 * i + 32, AnsiString("none").c_str());
|
||
strcpy(r.cString + 64 * i + 48, AnsiString("none").c_str());
|
||
i++;
|
||
}
|
||
|
||
COPYDATASTRUCT cData;
|
||
cData.dwData = 'EU07'; // sygnatura
|
||
cData.cbData = 8 + 1984; // 8+licznik i zero koñcz¹ce
|
||
cData.lpData = &r;
|
||
// WriteLog("Ramka gotowa");
|
||
Navigate("TEU07SRK", WM_COPYDATA, (WPARAM)Global::hWnd, (LPARAM)&cData);
|
||
CommLog(AnsiString(Now()) + " " + IntToStr(r.iComm) + " obsadzone" + " sent");
|
||
}
|
||
|
||
//--------------------------------
|
||
void TGround::WyslijParam(int nr, int fl)
|
||
{ // wys³anie parametrów symulacji w ramce (nr) z flagami (fl)
|
||
DaneRozkaz r;
|
||
r.iSygn = 'EU07';
|
||
r.iComm = nr; // zwykle 5
|
||
r.iPar[0] = fl; // flagi istotnoœci kolejnych parametrów
|
||
int i = 0; // domyœlnie brak danych
|
||
switch (nr)
|
||
{ // mo¿na tym przesy³aæ ró¿ne zestawy parametrów
|
||
case 5: // czas i pauza
|
||
r.fPar[1] = Global::fTimeAngleDeg / 360.0; // aktualny czas (1.0=doba)
|
||
r.iPar[2] = Global::iPause; // stan zapauzowania
|
||
i = 8; // dwa parametry po 4 bajty ka¿dy
|
||
break;
|
||
}
|
||
COPYDATASTRUCT cData;
|
||
cData.dwData = 'EU07'; // sygnatura
|
||
cData.cbData = 12 + i; // 12+rozmiar danych
|
||
cData.lpData = &r;
|
||
Navigate("TEU07SRK", WM_COPYDATA, (WPARAM)Global::hWnd, (LPARAM)&cData);
|
||
};
|
||
//---------------------------------------------------------------------------
|
||
//---------------------------------------------------------------------------
|
||
//---------------------------------------------------------------------------
|
||
void TGround::RadioStop(vector3 pPosition)
|
||
{ // zatrzymanie poci¹gów w okolicy
|
||
TGroundNode *node;
|
||
TSubRect *tmp;
|
||
int c = GetColFromX(pPosition.x);
|
||
int r = GetRowFromZ(pPosition.z);
|
||
int i, j;
|
||
int n = 2 * iNumSubRects; // przegl¹danie czo³gowe okolicznych torów w kwadracie 4km×4km
|
||
for (j = r - n; j <= r + n; j++)
|
||
for (i = c - n; i <= c + n; i++)
|
||
if ((tmp = FastGetSubRect(i, j)) != NULL)
|
||
for (node = tmp->nRootNode; node != NULL; node = node->nNext2)
|
||
if (node->iType == TP_TRACK)
|
||
node->pTrack->RadioStop(); // przekazanie do ka¿dego toru w ka¿dym segmencie
|
||
};
|
||
|
||
TDynamicObject *__fastcall TGround::DynamicNearest(vector3 pPosition, double distance, bool mech)
|
||
{ // wyszukanie pojazdu najbli¿szego wzglêdem (pPosition)
|
||
TGroundNode *node;
|
||
TSubRect *tmp;
|
||
TDynamicObject *dyn = NULL;
|
||
int c = GetColFromX(pPosition.x);
|
||
int r = GetRowFromZ(pPosition.z);
|
||
int i, j, k;
|
||
double sqm = distance * distance, sqd; // maksymalny promien poszukiwañ do kwadratu
|
||
for (j = r - 1; j <= r + 1; j++) // plus dwa zewnêtrzne sektory, ³¹cznie 9
|
||
for (i = c - 1; i <= c + 1; i++)
|
||
if ((tmp = FastGetSubRect(i, j)) != NULL)
|
||
for (node = tmp->nRootNode; node; node = node->nNext2) // nastêpny z sektora
|
||
if (node->iType == TP_TRACK) // Ra: przebudowaæ na u¿ycie tabeli torów?
|
||
for (k = 0; k < node->pTrack->iNumDynamics; k++)
|
||
if (mech ? (node->pTrack->Dynamics[k]->Mechanik != NULL) :
|
||
true) // czy ma mieæ obsadê
|
||
if ((sqd = SquareMagnitude(
|
||
node->pTrack->Dynamics[k]->GetPosition() - pPosition)) <
|
||
sqm)
|
||
{
|
||
sqm = sqd; // nowa odleg³oœæ
|
||
dyn = node->pTrack->Dynamics[k]; // nowy lider
|
||
}
|
||
return dyn;
|
||
};
|
||
TDynamicObject *__fastcall TGround::CouplerNearest(vector3 pPosition, double distance, bool mech)
|
||
{ // wyszukanie pojazdu, którego sprzêg jest najbli¿ej wzglêdem (pPosition)
|
||
TGroundNode *node;
|
||
TSubRect *tmp;
|
||
TDynamicObject *dyn = NULL;
|
||
int c = GetColFromX(pPosition.x);
|
||
int r = GetRowFromZ(pPosition.z);
|
||
int i, j, k;
|
||
double sqm = distance * distance, sqd; // maksymalny promien poszukiwañ do kwadratu
|
||
for (j = r - 1; j <= r + 1; j++) // plus dwa zewnêtrzne sektory, ³¹cznie 9
|
||
for (i = c - 1; i <= c + 1; i++)
|
||
if ((tmp = FastGetSubRect(i, j)) != NULL)
|
||
for (node = tmp->nRootNode; node; node = node->nNext2) // nastêpny z sektora
|
||
if (node->iType == TP_TRACK) // Ra: przebudowaæ na u¿ycie tabeli torów?
|
||
for (k = 0; k < node->pTrack->iNumDynamics; k++)
|
||
if (mech ? (node->pTrack->Dynamics[k]->Mechanik != NULL) :
|
||
true) // czy ma mieæ obsadê
|
||
{
|
||
if ((sqd = SquareMagnitude(
|
||
node->pTrack->Dynamics[k]->HeadPosition() - pPosition)) <
|
||
sqm)
|
||
{
|
||
sqm = sqd; // nowa odleg³oœæ
|
||
dyn = node->pTrack->Dynamics[k]; // nowy lider
|
||
}
|
||
if ((sqd = SquareMagnitude(
|
||
node->pTrack->Dynamics[k]->RearPosition() - pPosition)) <
|
||
sqm)
|
||
{
|
||
sqm = sqd; // nowa odleg³oœæ
|
||
dyn = node->pTrack->Dynamics[k]; // nowy lider
|
||
}
|
||
}
|
||
return dyn;
|
||
};
|
||
//---------------------------------------------------------------------------
|
||
void TGround::DynamicRemove(TDynamicObject *dyn)
|
||
{ // Ra: usuniêcie pojazdów ze scenerii (gdy dojad¹ na koniec i nie sa potrzebne)
|
||
TDynamicObject *d = dyn->Prev();
|
||
if (d) // jeœli coœ jest z przodu
|
||
DynamicRemove(d); // zaczynamy od tego z przodu
|
||
else
|
||
{ // jeœli mamy ju¿ tego na pocz¹tku
|
||
TGroundNode **n, *node;
|
||
d = dyn; // od pierwszego
|
||
while (d)
|
||
{
|
||
if (d->MyTrack)
|
||
d->MyTrack->RemoveDynamicObject(d); // usuniêcie z toru o ile nie usuniêty
|
||
n = &nRootDynamic; // lista pojazdów od pocz¹tku
|
||
// node=NULL; //nie znalezione
|
||
while (*n ? (*n)->DynamicObject != d : false)
|
||
{ // usuwanie z listy pojazdów
|
||
n = &((*n)->nNext); // sprawdzenie kolejnego pojazdu na liœcie
|
||
}
|
||
if ((*n)->DynamicObject == d)
|
||
{ // jeœli znaleziony
|
||
node = (*n); // zapamiêtanie wêz³a, aby go usun¹æ
|
||
(*n) = node->nNext; // pominiêcie na liœcie
|
||
Global::TrainDelete(d);
|
||
d = d->Next(); // przejœcie do kolejnego pojazdu, póki jeszcze jest
|
||
delete node; // usuwanie fizyczne z pamiêci
|
||
}
|
||
else
|
||
d = NULL; // coœ nie tak!
|
||
}
|
||
}
|
||
};
|
||
|
||
//---------------------------------------------------------------------------
|
||
void TGround::TerrainRead(const AnsiString &f){
|
||
// Ra: wczytanie trójk¹tów terenu z pliku E3D
|
||
};
|
||
|
||
//---------------------------------------------------------------------------
|
||
void TGround::TerrainWrite()
|
||
{ // Ra: zapisywanie trójk¹tów terenu do pliku E3D
|
||
if (Global::pTerrainCompact->TerrainLoaded())
|
||
return; // jeœli zosta³o wczytane, to nie ma co dalej robiæ
|
||
if (Global::asTerrainModel.IsEmpty())
|
||
return;
|
||
// Trójk¹ty s¹ zapisywane kwadratami kilometrowymi.
|
||
// Kwadrat 500500 jest na œrodku (od 0.0 do 1000.0 na OX oraz OZ).
|
||
// Ewentualnie w numerowaniu kwadratów uwzglêdnic wpis //$g.
|
||
// Trójk¹ty s¹ grupowane w submodele wg tekstury.
|
||
// Triangle_strip oraz triangle_fan s¹ rozpisywane na pojedyncze trójk¹ty,
|
||
// chyba ¿e dla danej tekstury wychodzi tylko jeden submodel.
|
||
TModel3d *m = new TModel3d(); // wirtualny model roboczy z oddzielnymi submodelami
|
||
TSubModel *sk; // wskaŸnik roboczy na submodel kwadratu
|
||
TSubModel *st; // wskaŸnik roboczy na submodel tekstury
|
||
// Zliczamy kwadraty z trójk¹tami, iloœæ tekstur oraz wierzcho³ków.
|
||
// Iloœæ kwadratów i iloœæ tekstur okreœli iloœæ submodeli.
|
||
// int sub=0; //ca³kowita iloœæ submodeli
|
||
// int ver=0; //ca³kowita iloœæ wierzcho³ków
|
||
int i, j, k; // indeksy w pêtli
|
||
TGroundNode *Current;
|
||
float8 *ver; // trójk¹ty
|
||
TSubModel::iInstance = 0; // pozycja w tabeli wierzcho³ków liczona narastaj¹co
|
||
for (i = 0; i < iNumRects; ++i) // pêtla po wszystkich kwadratach kilometrowych
|
||
for (j = 0; j < iNumRects; ++j)
|
||
if (Rects[i][j].iNodeCount)
|
||
{ // o ile s¹ jakieœ trójk¹ty w œrodku
|
||
sk = new TSubModel(); // nowy submodel dla kawadratu
|
||
// numer kwadratu XXXZZZ, przy czym X jest ujemne - XXX roœnie na wschód, ZZZ roœnie
|
||
// na pó³noc
|
||
sk->NameSet(AnsiString(1000 * (500 + i - iNumRects / 2) + (500 + j - iNumRects / 2))
|
||
.c_str()); // nazwa=numer kwadratu
|
||
m->AddTo(NULL, sk); // dodanie submodelu dla kwadratu
|
||
for (Current = Rects[i][j].nRootNode; Current; Current = Current->nNext2)
|
||
if (Current->TextureID)
|
||
switch (Current->iType)
|
||
{ // pêtla po trójk¹tach - zliczanie wierzcho³ków, dodaje submodel dla
|
||
// ka¿dej tekstury
|
||
case GL_TRIANGLES:
|
||
Current->iVboPtr = sk->TriangleAdd(
|
||
m, Current->TextureID,
|
||
Current->iNumVerts); // zwiêkszenie iloœci trójk¹tów w submodelu
|
||
m->iNumVerts +=
|
||
Current->iNumVerts; // zwiêkszenie ca³kowitej iloœci wierzcho³ków
|
||
break;
|
||
case GL_TRIANGLE_STRIP: // na razie nie, bo trzeba przerabiaæ na pojedyncze
|
||
// trójk¹ty
|
||
break;
|
||
case GL_TRIANGLE_FAN: // na razie nie, bo trzeba przerabiaæ na pojedyncze
|
||
// trójk¹ty
|
||
break;
|
||
}
|
||
for (Current = Rects[i][j].nRootNode; Current; Current = Current->nNext2)
|
||
if (Current->TextureID)
|
||
switch (Current->iType)
|
||
{ // pêtla po trójk¹tach - dopisywanie wierzcho³ków
|
||
case GL_TRIANGLES:
|
||
// ver=sk->TrianglePtr(TTexturesManager::GetName(Current->TextureID).c_str(),Current->iNumVerts);
|
||
// //wskaŸnik na pocz¹tek
|
||
ver = sk->TrianglePtr(Current->TextureID, Current->iVboPtr,
|
||
Current->Ambient, Current->Diffuse,
|
||
Current->Specular); // wskaŸnik na pocz¹tek
|
||
// WriteLog("Zapis "+AnsiString(Current->iNumVerts)+" trójk¹tów w
|
||
// ("+AnsiString(i)+","+AnsiString(j)+") od
|
||
// "+AnsiString(Current->iVboPtr)+" dla
|
||
// "+AnsiString(Current->TextureID));
|
||
Current->iVboPtr = -1; // bo to by³o tymczasowo u¿ywane
|
||
for (k = 0; k < Current->iNumVerts; ++k)
|
||
{ // przepisanie wspó³rzêdnych
|
||
ver[k].Point.x = Current->Vertices[k].Point.x;
|
||
ver[k].Point.y = Current->Vertices[k].Point.y;
|
||
ver[k].Point.z = Current->Vertices[k].Point.z;
|
||
ver[k].Normal.x = Current->Vertices[k].Normal.x;
|
||
ver[k].Normal.y = Current->Vertices[k].Normal.y;
|
||
ver[k].Normal.z = Current->Vertices[k].Normal.z;
|
||
ver[k].tu = Current->Vertices[k].tu;
|
||
ver[k].tv = Current->Vertices[k].tv;
|
||
}
|
||
break;
|
||
case GL_TRIANGLE_STRIP: // na razie nie, bo trzeba przerabiaæ na pojedyncze
|
||
// trójk¹ty
|
||
break;
|
||
case GL_TRIANGLE_FAN: // na razie nie, bo trzeba przerabiaæ na pojedyncze
|
||
// trójk¹ty
|
||
break;
|
||
}
|
||
}
|
||
m->SaveToBinFile(AnsiString("models\\" + Global::asTerrainModel).c_str());
|
||
};
|
||
//---------------------------------------------------------------------------
|
||
|
||
void TGround::TrackBusyList()
|
||
{ // wys³anie informacji o wszystkich zajêtych odcinkach
|
||
TGroundNode *Current;
|
||
TTrack *Track;
|
||
AnsiString name;
|
||
for (Current = nRootOfType[TP_TRACK]; Current; Current = Current->nNext)
|
||
if (!Current->asName.IsEmpty()) // musi byæ nazwa
|
||
if (Current->pTrack->iNumDynamics) // osi to chyba nie ma jak policzyæ
|
||
WyslijString(Current->asName, 8); // zajêty
|
||
};
|
||
//---------------------------------------------------------------------------
|
||
|
||
void TGround::IsolatedBusyList()
|
||
{ // wys³anie informacji o wszystkich odcinkach izolowanych
|
||
TIsolated *Current;
|
||
for (Current = TIsolated::Root(); Current; Current = Current->Next())
|
||
if (Current->Busy()) // sprawdŸ zajêtoœæ
|
||
WyslijString(Current->asName, 11); // zajêty
|
||
else
|
||
WyslijString(Current->asName, 10); // wolny
|
||
WyslijString("none", 10); // informacja o koñcu listy
|
||
};
|
||
//---------------------------------------------------------------------------
|
||
|
||
void TGround::IsolatedBusy(const AnsiString t)
|
||
{ // wys³anie informacji o odcinku izolowanym (t)
|
||
// Ra 2014-06: do wyszukania u¿yæ drzewka nazw
|
||
TIsolated *Current;
|
||
for (Current = TIsolated::Root(); Current; Current = Current->Next())
|
||
if (Current->asName == t) // wyszukiwanie odcinka o nazwie (t)
|
||
if (Current->Busy()) // sprawdŸ zajetoœæ
|
||
{
|
||
WyslijString(Current->asName, 11); // zajêty
|
||
return; // nie sprawdzaj dalszych
|
||
}
|
||
WyslijString(t, 10); // wolny
|
||
};
|
||
//---------------------------------------------------------------------------
|
||
|
||
void TGround::Silence(vector3 gdzie)
|
||
{ // wyciszenie wszystkiego w sektorach przed przeniesieniem kamery z (gdzie)
|
||
int tr, tc;
|
||
TGroundNode *node;
|
||
int n = 2 * iNumSubRects; //(2*==2km) promieñ wyœwietlanej mapy w sektorach
|
||
int c = GetColFromX(gdzie.x); // sektory wg dotychczasowej pozycji kamery
|
||
int r = GetRowFromZ(gdzie.z);
|
||
TSubRect *tmp;
|
||
int i, j, k;
|
||
// renderowanie czo³gowe dla obiektów aktywnych a niewidocznych
|
||
for (j = r - n; j <= r + n; j++)
|
||
for (i = c - n; i <= c + n; i++)
|
||
if ((tmp = FastGetSubRect(i, j)) != NULL)
|
||
{ // tylko dŸwiêki interesuj¹
|
||
for (node = tmp->nRenderHidden; node; node = node->nNext3)
|
||
node->RenderHidden();
|
||
tmp->RenderSounds(); // dŸwiêki pojazdów by siê przyda³o wy³¹czyæ
|
||
}
|
||
};
|
||
//---------------------------------------------------------------------------
|