mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-03-22 15:05:03 +01:00
3197 lines
154 KiB
C++
3197 lines
154 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
|
|
|
|
*/
|
|
|
|
// nagłówki identyczne w każdym pliku...
|
|
#pragma hdrstop
|
|
|
|
#include "Track.h"
|
|
#include "Usefull.h"
|
|
#include "Texture.h"
|
|
#include "Timer.h"
|
|
#include "Globals.h"
|
|
#include "Ground.h"
|
|
#include "parser.h"
|
|
#include "Mover.h"
|
|
#include "DynObj.h"
|
|
#include "AnimModel.h"
|
|
#include "MemCell.h"
|
|
#include "Event.h"
|
|
|
|
#pragma package(smart_init)
|
|
|
|
// 101206 Ra: trapezoidalne drogi i tory
|
|
// 110720 Ra: rozprucie zwrotnicy i odcinki izolowane
|
|
|
|
static const double fMaxOffset = 0.1; // double(0.1f)==0.100000001490116
|
|
// const int NextMask[4]={0,1,0,1}; //tor następny dla stanów 0, 1, 2, 3
|
|
// const int PrevMask[4]={0,0,1,1}; //tor poprzedni dla stanów 0, 1, 2, 3
|
|
const int iLewo4[4] = {5, 3, 4, 6}; // segmenty (1..6) do skręcania w lewo
|
|
const int iPrawo4[4] = {-4, -6, -3, -5}; // segmenty (1..6) do skręcania w prawo
|
|
const int iProsto4[4] = {1, -1, 2, -2}; // segmenty (1..6) do jazdy prosto
|
|
const int iEnds4[13] = {3, 0, 2, 1, 2, 0, -1,
|
|
1, 3, 2, 0, 3, 1}; // numer sąsiedniego toru na końcu segmentu "-1"
|
|
const int iLewo3[4] = {1, 3, 2, 1}; // segmenty do skręcania w lewo
|
|
const int iPrawo3[4] = {-2, -1, -3, -2}; // segmenty do skręcania w prawo
|
|
const int iProsto3[4] = {1, -1, 2, 1}; // segmenty do jazdy prosto
|
|
const int iEnds3[13] = {3, 0, 2, 1, 2, 0, -1,
|
|
1, 0, 2, 0, 3, 1}; // numer sąsiedniego toru na końcu segmentu "-1"
|
|
TIsolated *TIsolated::pRoot = NULL;
|
|
|
|
TSwitchExtension::TSwitchExtension(TTrack *owner, int what)
|
|
{ // na początku wszystko puste
|
|
CurrentIndex = 0;
|
|
pNexts[0] = NULL; // wskaźniki do kolejnych odcinków ruchu
|
|
pNexts[1] = NULL;
|
|
pPrevs[0] = NULL;
|
|
pPrevs[1] = NULL;
|
|
fOffsetSpeed = 0.1; // prędkość liniowa iglic
|
|
fOffsetDelay = 0.05; // dodatkowy ruch drugiej iglicy po zablokowaniu pierwszej na opornicy
|
|
fOffset1 = fOffset = fDesiredOffset = -fOffsetDelay; // położenie zasadnicze
|
|
fOffset2 = 0.0; // w zasadniczym wewnętrzna iglica dolega
|
|
pOwner = NULL;
|
|
pNextAnim = NULL;
|
|
bMovement = false; // nie potrzeba przeliczać fOffset1
|
|
Segments[0] = new TSegment(owner); // z punktu 1 do 2
|
|
Segments[1] = new TSegment(
|
|
owner); // z punktu 3 do 4 (1=3 dla zwrotnic; odwrócony dla skrzyżowań, ewentualnie 1=4)
|
|
Segments[2] = (what >= 3) ?
|
|
new TSegment(owner) :
|
|
NULL; // z punktu 2 do 4 skrzyżowanie od góry: wersja "-1":
|
|
Segments[3] = (what >= 4) ? new TSegment(owner) :
|
|
NULL; // z punktu 4 do 1 1 1=4 0 0=3
|
|
Segments[4] =
|
|
(what >= 5) ? new TSegment(owner) : NULL; // z punktu 1 do 3 4 x 3 3 3 x 2 2
|
|
Segments[5] = (what >= 6) ? new TSegment(owner) :
|
|
NULL; // z punktu 3 do 2 2 2 1 1
|
|
evPlus = evMinus = NULL;
|
|
fVelocity = -1.0; // maksymalne ograniczenie prędkości (ustawianej eventem)
|
|
vTrans = vector3(0, 0, 0); // docelowa translacja przesuwnicy
|
|
}
|
|
TSwitchExtension::~TSwitchExtension()
|
|
{ // nie ma nic do usuwania
|
|
// delete Segments[0];
|
|
// delete Segments[1];
|
|
delete Segments[2];
|
|
delete Segments[3];
|
|
delete Segments[4];
|
|
delete Segments[5];
|
|
}
|
|
|
|
TIsolated::TIsolated()
|
|
{ // utworznie pustego
|
|
TIsolated("none", NULL);
|
|
};
|
|
|
|
TIsolated::TIsolated(const AnsiString &n, TIsolated *i)
|
|
{ // utworznie obwodu izolowanego
|
|
asName = n;
|
|
pNext = i;
|
|
iAxles = 0;
|
|
evBusy = evFree = NULL;
|
|
pMemCell = NULL; // podpiąć istniejącą albo utworzyć pustą
|
|
};
|
|
|
|
TIsolated::~TIsolated(){// usuwanie
|
|
/*
|
|
TIsolated *p=pRoot;
|
|
while (pRoot)
|
|
{
|
|
p=pRoot;
|
|
p->pNext=NULL;
|
|
delete p;
|
|
}
|
|
*/
|
|
};
|
|
|
|
TIsolated *__fastcall TIsolated::Find(const AnsiString &n)
|
|
{ // znalezienie obiektu albo utworzenie nowego
|
|
TIsolated *p = pRoot;
|
|
while (p)
|
|
{ // jeśli się znajdzie, to podać wskaźnik
|
|
if (p->asName == n)
|
|
return p;
|
|
p = p->pNext;
|
|
}
|
|
pRoot = new TIsolated(n, pRoot);
|
|
return pRoot;
|
|
};
|
|
|
|
void TIsolated::Modify(int i, TDynamicObject *o)
|
|
{ // dodanie lub odjęcie osi
|
|
if (iAxles)
|
|
{ // grupa zajęta
|
|
iAxles += i;
|
|
if (!iAxles)
|
|
{ // jeśli po zmianie nie ma żadnej osi na odcinku izolowanym
|
|
if (evFree)
|
|
Global::AddToQuery(evFree, o); // dodanie zwolnienia do kolejki
|
|
if (Global::iMultiplayer) // jeśli multiplayer
|
|
Global::pGround->WyslijString(asName, 10); // wysłanie pakietu o zwolnieniu
|
|
if (pMemCell) // w powiązanej komórce
|
|
pMemCell->UpdateValues(NULL, 0, int(pMemCell->Value2()) & ~0xFF,
|
|
update_memval2); //"zerujemy" ostatnią wartość
|
|
}
|
|
}
|
|
else
|
|
{ // grupa była wolna
|
|
iAxles += i;
|
|
if (iAxles)
|
|
{
|
|
if (evBusy)
|
|
Global::AddToQuery(evBusy, o); // dodanie zajętości do kolejki
|
|
if (Global::iMultiplayer) // jeśli multiplayer
|
|
Global::pGround->WyslijString(asName, 11); // wysłanie pakietu o zajęciu
|
|
if (pMemCell) // w powiązanej komórce
|
|
pMemCell->UpdateValues(NULL, 0, int(pMemCell->Value2()) | 1,
|
|
update_memval2); // zmieniamy ostatnią wartość na nieparzystą
|
|
}
|
|
}
|
|
};
|
|
|
|
TTrack::TTrack(TGroundNode *g)
|
|
{ // tworzenie nowego odcinka ruchu
|
|
trNext = trPrev = NULL; // sąsiednie
|
|
Segment = NULL; // dane odcinka
|
|
SwitchExtension = NULL; // dodatkowe parametry zwrotnicy i obrotnicy
|
|
TextureID1 = 0; // tekstura szyny
|
|
fTexLength = 4.0; // powtarzanie tekstury
|
|
TextureID2 = 0; // tekstura podsypki albo drugiego toru zwrotnicy
|
|
fTexHeight1 = 0.6; // nowy profil podsypki ;)
|
|
fTexWidth = 0.9;
|
|
fTexSlope = 0.9;
|
|
eType = tt_Normal; // domyślnie zwykły
|
|
iCategoryFlag = 1; // 1-tor, 2-droga, 4-rzeka, 8-samolot?
|
|
fTrackWidth = 1.435; // rozstaw toru, szerokość nawierzchni
|
|
fFriction = 0.15; // współczynnik tarcia
|
|
fSoundDistance = -1;
|
|
iQualityFlag = 20;
|
|
iDamageFlag = 0;
|
|
eEnvironment = e_flat;
|
|
bVisible = true;
|
|
iEvents = 0; // Ra: flaga informująca o obecności eventów
|
|
evEvent0 = NULL;
|
|
evEvent1 = NULL;
|
|
evEvent2 = NULL;
|
|
evEventall0 = NULL;
|
|
evEventall1 = NULL;
|
|
evEventall2 = NULL;
|
|
fVelocity = -1; // ograniczenie prędkości
|
|
fTrackLength = 100.0;
|
|
fRadius = 0; // promień wybranego toru zwrotnicy
|
|
fRadiusTable[0] = 0; // dwa promienie nawet dla prostego
|
|
fRadiusTable[1] = 0;
|
|
iNumDynamics = 0;
|
|
ScannedFlag = false;
|
|
DisplayListID = 0;
|
|
iTrapezoid = 0; // parametry kształtu: 0-standard, 1-przechyłka, 2-trapez, 3-oba
|
|
hvOverhead = NULL; // drut zasilający, najbliższy Point1 toru
|
|
fTexRatio1 =
|
|
1.0; // proporcja boków tekstury nawierzchni (żeby zaoszczędzić na rozmiarach tekstur...)
|
|
fTexRatio2 =
|
|
1.0; // proporcja boków tekstury chodnika (żeby zaoszczędzić na rozmiarach tekstur...)
|
|
iPrevDirection = 0; // domyślnie wirtualne odcinki dołączamy stroną od Point1
|
|
iNextDirection = 0;
|
|
pIsolated = NULL;
|
|
pMyNode = g; // Ra: proteza, żeby tor znał swoją nazwę TODO: odziedziczyć TTrack z TGroundNode
|
|
iAction = 0; // normalnie może być pomijany podczas skanowania
|
|
fOverhead = -1.0; // można normalnie pobierać prąd (0 dla jazdy bezprądowej po danym odcinku
|
|
nFouling[0] = NULL; // ukres albo kozioł od strony Point1
|
|
nFouling[1] = NULL; // ukres albo kozioł od strony Point2
|
|
trColides = NULL; // tor kolizyjny, na którym trzeba sprawdzać pojazdy pod kątem zderzenia
|
|
}
|
|
|
|
TTrack::~TTrack()
|
|
{ // likwidacja odcinka
|
|
if (eType == tt_Normal)
|
|
delete Segment; // dla zwrotnic nie usuwać tego (kopiowany)
|
|
else
|
|
{ // usuwanie dodatkowych danych dla niezwykłych odcinków
|
|
if (eType == tt_Cross)
|
|
delete SwitchExtension->vPoints; // skrzyżowanie może mieć punkty
|
|
SafeDelete(SwitchExtension);
|
|
}
|
|
}
|
|
|
|
void TTrack::Init()
|
|
{ // tworzenie pomocniczych danych
|
|
switch (eType)
|
|
{
|
|
case tt_Switch:
|
|
SwitchExtension = new TSwitchExtension(this, 2); // na wprost i na bok
|
|
break;
|
|
case tt_Cross: // tylko dla skrzyżowania dróg
|
|
SwitchExtension = new TSwitchExtension(this, 6); // 6 połączeń
|
|
SwitchExtension->vPoints = NULL; // brak tablicy punktów
|
|
SwitchExtension->iPoints = 0;
|
|
SwitchExtension->bPoints = false; // tablica punktów nie wypełniona
|
|
SwitchExtension->iRoads = 4; // domyślnie 4
|
|
break;
|
|
case tt_Normal:
|
|
Segment = new TSegment(this);
|
|
break;
|
|
case tt_Table: // oba potrzebne
|
|
SwitchExtension = new TSwitchExtension(this, 1); // kopia oryginalnego toru
|
|
Segment = new TSegment(this);
|
|
break;
|
|
}
|
|
}
|
|
|
|
TTrack *__fastcall TTrack::Create400m(int what, double dx)
|
|
{ // tworzenie toru do wstawiania taboru podczas konwersji na E3D
|
|
TGroundNode *tmp = new TGroundNode(TP_TRACK); // node
|
|
TTrack *trk = tmp->pTrack;
|
|
trk->bVisible = false; // nie potrzeba pokazywać, zresztą i tak nie ma tekstur
|
|
trk->iCategoryFlag = what; // taki sam typ plus informacja, że dodatkowy
|
|
trk->Init(); // utworzenie segmentu
|
|
trk->Segment->Init(vector3(-dx, 0, 0), vector3(-dx, 0, 400), 0, 0, 0); // prosty
|
|
tmp->pCenter = vector3(-dx, 0, 200); //środek, aby się mogło wyświetlić
|
|
TSubRect *r = Global::pGround->GetSubRect(tmp->pCenter.x, tmp->pCenter.z);
|
|
r->NodeAdd(tmp); // dodanie toru do segmentu
|
|
r->Sort(); //żeby wyświetlał tabor z dodanego toru
|
|
r->Release(); // usunięcie skompilowanych zasobów
|
|
return trk;
|
|
};
|
|
|
|
TTrack *__fastcall TTrack::NullCreate(int dir)
|
|
{ // tworzenie toru wykolejającego od strony (dir), albo pętli dla samochodów
|
|
TGroundNode *tmp = new TGroundNode(TP_TRACK), *tmp2 = NULL; // node
|
|
TTrack *trk = tmp->pTrack; // tor; UWAGA! obrotnica może generować duże ilości tego
|
|
// tmp->iType=TP_TRACK;
|
|
// TTrack* trk=new TTrack(tmp); //tor; UWAGA! obrotnica może generować duże ilości tego
|
|
// tmp->pTrack=trk;
|
|
trk->bVisible = false; // nie potrzeba pokazywać, zresztą i tak nie ma tekstur
|
|
// trk->iTrapezoid=1; //są przechyłki do uwzględniania w rysowaniu
|
|
trk->iCategoryFlag = (iCategoryFlag & 15) | 0x80; // taki sam typ plus informacja, że dodatkowy
|
|
double r1, r2;
|
|
Segment->GetRolls(r1, r2); // pobranie przechyłek na początku toru
|
|
vector3 p1, cv1, cv2, p2; // będziem tworzyć trajektorię lotu
|
|
if (iCategoryFlag & 1)
|
|
{ // tylko dla kolei
|
|
trk->iDamageFlag = 128; // wykolejenie
|
|
trk->fVelocity = 0.0; // koniec jazdy
|
|
trk->Init(); // utworzenie segmentu
|
|
switch (dir)
|
|
{ //łączenie z nowym torem
|
|
case 0:
|
|
p1 = Segment->FastGetPoint_0();
|
|
p2 = p1 - 450.0 * Normalize(Segment->GetDirection1());
|
|
trk->Segment->Init(p1, p2, 5, -RadToDeg(r1),
|
|
70.0); // bo prosty, kontrolne wyliczane przy zmiennej przechyłce
|
|
ConnectPrevPrev(trk, 0);
|
|
break;
|
|
case 1:
|
|
p1 = Segment->FastGetPoint_1();
|
|
p2 = p1 - 450.0 * Normalize(Segment->GetDirection2());
|
|
trk->Segment->Init(p1, p2, 5, RadToDeg(r2),
|
|
70.0); // bo prosty, kontrolne wyliczane przy zmiennej przechyłce
|
|
ConnectNextPrev(trk, 0);
|
|
break;
|
|
case 3: // na razie nie możliwe
|
|
p1 = SwitchExtension->Segments[1]->FastGetPoint_1(); // koniec toru drugiego zwrotnicy
|
|
p2 = p1 -
|
|
450.0 *
|
|
Normalize(
|
|
SwitchExtension->Segments[1]->GetDirection2()); // przedłużenie na wprost
|
|
trk->Segment->Init(p1, p2, 5, RadToDeg(r2),
|
|
70.0); // bo prosty, kontrolne wyliczane przy zmiennej przechyłce
|
|
ConnectNextPrev(trk, 0);
|
|
// trk->ConnectPrevNext(trk,dir);
|
|
SetConnections(1); // skopiowanie połączeń
|
|
Switch(1); // bo się przełączy na 0, a to coś chce się przecież wykoleić na bok
|
|
break; // do drugiego zwrotnicy... nie zadziała?
|
|
}
|
|
}
|
|
else
|
|
{ // tworznie pętelki dla samochodów
|
|
trk->fVelocity = 20.0; // zawracanie powoli
|
|
trk->fRadius = 20.0; // promień, aby się dodawało do tabelki prędkości i liczyło narastająco
|
|
trk->Init(); // utworzenie segmentu
|
|
tmp2 = new TGroundNode(TP_TRACK); // drugi odcinek do zapętlenia
|
|
TTrack *trk2 = tmp2->pTrack;
|
|
trk2->iCategoryFlag =
|
|
(iCategoryFlag & 15) | 0x80; // taki sam typ plus informacja, że dodatkowy
|
|
trk2->bVisible = false;
|
|
trk2->fVelocity = 20.0; // zawracanie powoli
|
|
trk2->fRadius = 20.0; // promień, aby się dodawało do tabelki prędkości i liczyło
|
|
// narastająco
|
|
trk2->Init(); // utworzenie segmentu
|
|
switch (dir)
|
|
{ //łączenie z nowym torem
|
|
case 0:
|
|
p1 = Segment->FastGetPoint_0();
|
|
cv1 = -20.0 * Normalize(Segment->GetDirection1()); // pierwszy wektor kontrolny
|
|
p2 = p1 + cv1 + cv1; // 40m
|
|
trk->Segment->Init(p1, p1 + cv1, p2 + vector3(-cv1.z, cv1.y, cv1.x), p2, 2,
|
|
-RadToDeg(r1),
|
|
0.0); // bo prosty, kontrolne wyliczane przy zmiennej przechyłce
|
|
ConnectPrevPrev(trk, 0);
|
|
trk2->Segment->Init(p1, p1 + cv1, p2 + vector3(cv1.z, cv1.y, -cv1.x), p2, 2,
|
|
-RadToDeg(r1),
|
|
0.0); // bo prosty, kontrolne wyliczane przy zmiennej przechyłce
|
|
trk2->iPrevDirection = 0; // zwrotnie do tego samego odcinka
|
|
break;
|
|
case 1:
|
|
p1 = Segment->FastGetPoint_1();
|
|
cv1 = -20.0 * Normalize(Segment->GetDirection2()); // pierwszy wektor kontrolny
|
|
p2 = p1 + cv1 + cv1;
|
|
trk->Segment->Init(p1, p1 + cv1, p2 + vector3(-cv1.z, cv1.y, cv1.x), p2, 2,
|
|
RadToDeg(r2),
|
|
0.0); // bo prosty, kontrolne wyliczane przy zmiennej przechyłce
|
|
ConnectNextPrev(trk, 0);
|
|
trk2->Segment->Init(p1, p1 + cv1, p2 + vector3(cv1.z, cv1.y, -cv1.x), p2, 2,
|
|
RadToDeg(r2),
|
|
0.0); // bo prosty, kontrolne wyliczane przy zmiennej przechyłce
|
|
trk2->iPrevDirection = 1; // zwrotnie do tego samego odcinka
|
|
break;
|
|
}
|
|
trk2->trPrev = this;
|
|
trk->ConnectNextNext(trk2, 1); // połączenie dwóch dodatkowych odcinków punktami 2
|
|
tmp2->pCenter = (0.5 * (p1 + p2)); //środek, aby się mogło wyświetlić
|
|
}
|
|
// trzeba jeszcze dodać do odpowiedniego segmentu, aby się renderowały z niego pojazdy
|
|
tmp->pCenter = (0.5 * (p1 + p2)); //środek, aby się mogło wyświetlić
|
|
if (tmp2)
|
|
tmp2->pCenter = tmp->pCenter; // ten sam środek jest
|
|
// Ra: to poniżej to porażka, ale na razie się nie da inaczej
|
|
TSubRect *r = Global::pGround->GetSubRect(tmp->pCenter.x, tmp->pCenter.z);
|
|
r->NodeAdd(tmp); // dodanie toru do segmentu
|
|
if (tmp2)
|
|
r->NodeAdd(tmp2); // drugiego też
|
|
r->Sort(); //żeby wyświetlał tabor z dodanego toru
|
|
r->Release(); // usunięcie skompilowanych zasobów
|
|
return trk;
|
|
};
|
|
|
|
void TTrack::ConnectPrevPrev(TTrack *pTrack, int typ)
|
|
{ //łączenie torów - Point1 własny do Point1 cudzego
|
|
if (pTrack)
|
|
{ //(pTrack) może być zwrotnicą, a (this) tylko zwykłym odcinkiem
|
|
trPrev = pTrack;
|
|
iPrevDirection = ((pTrack->eType == tt_Switch) ? 0 : (typ & 2));
|
|
pTrack->trPrev = this;
|
|
pTrack->iPrevDirection = 0;
|
|
}
|
|
}
|
|
void TTrack::ConnectPrevNext(TTrack *pTrack, int typ)
|
|
{ //łaczenie torów - Point1 własny do Point2 cudzego
|
|
if (pTrack)
|
|
{
|
|
trPrev = pTrack;
|
|
iPrevDirection = typ | 1; // 1:zwykły lub pierwszy zwrotnicy, 3:drugi zwrotnicy
|
|
pTrack->trNext = this;
|
|
pTrack->iNextDirection = 0;
|
|
if (bVisible)
|
|
if (pTrack->bVisible)
|
|
if (eType == tt_Normal) // jeśli łączone są dwa normalne
|
|
if (pTrack->eType == tt_Normal)
|
|
if ((fTrackWidth !=
|
|
pTrack->fTrackWidth) // Ra: jeśli kolejny ma inne wymiary
|
|
||
|
|
(fTexHeight1 != pTrack->fTexHeight1) ||
|
|
(fTexWidth != pTrack->fTexWidth) || (fTexSlope != pTrack->fTexSlope))
|
|
pTrack->iTrapezoid |= 2; // to rysujemy potworka
|
|
}
|
|
}
|
|
void TTrack::ConnectNextPrev(TTrack *pTrack, int typ)
|
|
{ //łaczenie torów - Point2 własny do Point1 cudzego
|
|
if (pTrack)
|
|
{
|
|
trNext = pTrack;
|
|
iNextDirection = ((pTrack->eType == tt_Switch) ? 0 : (typ & 2));
|
|
pTrack->trPrev = this;
|
|
pTrack->iPrevDirection = 1;
|
|
if (bVisible)
|
|
if (pTrack->bVisible)
|
|
if (eType == tt_Normal) // jeśli łączone są dwa normalne
|
|
if (pTrack->eType == tt_Normal)
|
|
if ((fTrackWidth !=
|
|
pTrack->fTrackWidth) // Ra: jeśli kolejny ma inne wymiary
|
|
||
|
|
(fTexHeight1 != pTrack->fTexHeight1) ||
|
|
(fTexWidth != pTrack->fTexWidth) || (fTexSlope != pTrack->fTexSlope))
|
|
iTrapezoid |= 2; // to rysujemy potworka
|
|
}
|
|
}
|
|
void TTrack::ConnectNextNext(TTrack *pTrack, int typ)
|
|
{ //łaczenie torów - Point2 własny do Point2 cudzego
|
|
if (pTrack)
|
|
{
|
|
trNext = pTrack;
|
|
iNextDirection = typ | 1; // 1:zwykły lub pierwszy zwrotnicy, 3:drugi zwrotnicy
|
|
pTrack->trNext = this;
|
|
pTrack->iNextDirection = 1;
|
|
}
|
|
}
|
|
|
|
vector3 MakeCPoint(vector3 p, double d, double a1, double a2)
|
|
{
|
|
vector3 cp = vector3(0, 0, 1);
|
|
cp.RotateX(DegToRad(a2));
|
|
cp.RotateY(DegToRad(a1));
|
|
cp = cp * d + p;
|
|
return cp;
|
|
}
|
|
|
|
vector3 LoadPoint(cParser *parser)
|
|
{ // pobranie współrzędnych punktu
|
|
vector3 p;
|
|
std::string token;
|
|
parser->getTokens(3);
|
|
*parser >> p.x >> p.y >> p.z;
|
|
return p;
|
|
}
|
|
|
|
void TTrack::Load(cParser *parser, vector3 pOrigin, AnsiString name)
|
|
{ // pobranie obiektu trajektorii ruchu
|
|
vector3 pt, vec, p1, p2, cp1, cp2, p3, p4, cp3, cp4; // dodatkowe punkty potrzebne do skrzyżowań
|
|
double a1, a2, r1, r2, r3, r4, d1, d2, a;
|
|
AnsiString str;
|
|
bool bCurve;
|
|
int i; //,state; //Ra: teraz już nie ma początkowego stanu zwrotnicy we wpisie
|
|
std::string token;
|
|
|
|
parser->getTokens();
|
|
*parser >> token;
|
|
str = AnsiString(token.c_str()); // typ toru
|
|
|
|
if (str == "normal")
|
|
{
|
|
eType = tt_Normal;
|
|
iCategoryFlag = 1;
|
|
}
|
|
else if (str == "switch")
|
|
{
|
|
eType = tt_Switch;
|
|
iCategoryFlag = 1;
|
|
}
|
|
else if (str == "turn")
|
|
{ // Ra: to jest obrotnica
|
|
eType = tt_Table;
|
|
iCategoryFlag = 1;
|
|
}
|
|
else if (str == "table")
|
|
{ // Ra: obrotnica, przesuwnica albo wywrotnica
|
|
eType = tt_Table;
|
|
iCategoryFlag = 1;
|
|
}
|
|
else if (str == "road")
|
|
{
|
|
eType = tt_Normal;
|
|
iCategoryFlag = 2;
|
|
}
|
|
else if (str == "cross")
|
|
{ // Ra: to będzie skrzyżowanie dróg
|
|
eType = tt_Cross;
|
|
iCategoryFlag = 2;
|
|
}
|
|
else if (str == "river")
|
|
{
|
|
eType = tt_Normal;
|
|
iCategoryFlag = 4;
|
|
}
|
|
else if (str == "tributary")
|
|
{
|
|
eType = tt_Tributary;
|
|
iCategoryFlag = 4;
|
|
}
|
|
else
|
|
eType = tt_Unknown;
|
|
if (Global::iWriteLogEnabled & 4)
|
|
WriteLog(str.c_str());
|
|
parser->getTokens(4);
|
|
*parser >> fTrackLength >> fTrackWidth >> fFriction >> fSoundDistance;
|
|
// fTrackLength=Parser->GetNextSymbol().ToDouble(); //track length
|
|
// 100502
|
|
// fTrackWidth=Parser->GetNextSymbol().ToDouble(); //track width
|
|
// fFriction=Parser->GetNextSymbol().ToDouble(); //friction coeff.
|
|
// fSoundDistance=Parser->GetNextSymbol().ToDouble(); //snd
|
|
fTrackWidth2 = fTrackWidth; // rozstaw/szerokość w punkcie 2, na razie taka sama
|
|
parser->getTokens(2);
|
|
*parser >> iQualityFlag >> iDamageFlag;
|
|
// iQualityFlag=Parser->GetNextSymbol().ToInt(); //McZapkie: qualityflag
|
|
// iDamageFlag=Parser->GetNextSymbol().ToInt(); //damage
|
|
if (iDamageFlag & 128)
|
|
iAction |= 0x80; // flaga wykolejania z powodu uszkodzenia
|
|
parser->getTokens();
|
|
*parser >> token;
|
|
str = AnsiString(token.c_str()); // environment
|
|
if (str == "flat")
|
|
eEnvironment = e_flat;
|
|
else if (str == "mountains" || str == "mountain")
|
|
eEnvironment = e_mountains;
|
|
else if (str == "canyon")
|
|
eEnvironment = e_canyon;
|
|
else if (str == "tunnel")
|
|
eEnvironment = e_tunnel;
|
|
else if (str == "bridge")
|
|
eEnvironment = e_bridge;
|
|
else if (str == "bank")
|
|
eEnvironment = e_bank;
|
|
else
|
|
{
|
|
eEnvironment = e_unknown;
|
|
Error("Unknown track environment: \"" + str + "\"");
|
|
}
|
|
parser->getTokens();
|
|
*parser >> token;
|
|
bVisible = (token.compare("vis") == 0); // visible
|
|
if (bVisible)
|
|
{
|
|
parser->getTokens();
|
|
*parser >> token;
|
|
str = AnsiString(token.c_str()); // railtex
|
|
TextureID1 = (str == "none" ? 0 : TTexturesManager::GetTextureID(
|
|
szTexturePath, szSceneryPath, str.c_str(),
|
|
(iCategoryFlag & 1) ? Global::iRailProFiltering :
|
|
Global::iBallastFiltering));
|
|
parser->getTokens();
|
|
*parser >> fTexLength; // tex tile length
|
|
if (fTexLength < 0.01)
|
|
fTexLength = 4; // Ra: zabezpiecznie przed zawieszeniem
|
|
parser->getTokens();
|
|
*parser >> token;
|
|
str = AnsiString(token.c_str()); // sub || railtex
|
|
TextureID2 = (str == "none" ? 0 : TTexturesManager::GetTextureID(
|
|
szTexturePath, szSceneryPath, str.c_str(),
|
|
(eType == tt_Normal) ? Global::iBallastFiltering :
|
|
Global::iRailProFiltering));
|
|
parser->getTokens(3);
|
|
*parser >> fTexHeight1 >> fTexWidth >> fTexSlope;
|
|
// fTexHeight=Parser->GetNextSymbol().ToDouble(); //tex sub height
|
|
// fTexWidth=Parser->GetNextSymbol().ToDouble(); //tex sub width
|
|
// fTexSlope=Parser->GetNextSymbol().ToDouble(); //tex sub slope width
|
|
if (iCategoryFlag & 4)
|
|
fTexHeight1 = -fTexHeight1; // rzeki mają wysokość odwrotnie niż drogi
|
|
}
|
|
else if (Global::iWriteLogEnabled & 4)
|
|
WriteLog("unvis");
|
|
Init(); // ustawia SwitchExtension
|
|
double segsize = 5.0; // długość odcinka segmentowania
|
|
switch (eType)
|
|
{ // Ra: łuki segmentowane co 5m albo 314-kątem foremnym
|
|
case tt_Table: // obrotnica jest prawie jak zwykły tor
|
|
iAction |= 2; // flaga zmiany położenia typu obrotnica
|
|
case tt_Normal:
|
|
p1 = LoadPoint(parser) + pOrigin; // pobranie współrzędnych P1
|
|
parser->getTokens();
|
|
*parser >> r1; // pobranie przechyłki w P1
|
|
cp1 = LoadPoint(parser); // pobranie współrzędnych punktów kontrolnych
|
|
cp2 = LoadPoint(parser);
|
|
p2 = LoadPoint(parser) + pOrigin; // pobranie współrzędnych P2
|
|
parser->getTokens(2);
|
|
*parser >> r2 >> fRadius; // pobranie przechyłki w P1 i promienia
|
|
fRadius = fabs(fRadius); // we wpisie może być ujemny
|
|
if (iCategoryFlag & 1)
|
|
{ // zero na główce szyny
|
|
p1.y += 0.18;
|
|
p2.y += 0.18;
|
|
// na przechyłce doliczyć jeszcze pół przechyłki
|
|
}
|
|
if (fRadius != 0) // gdy podany promień
|
|
segsize = Min0R(5.0, 0.2 + fabs(fRadius) * 0.02); // do 250m - 5, potem 1 co 50m
|
|
|
|
if ((((p1 + p1 + p2) / 3.0 - p1 - cp1).Length() < 0.02) ||
|
|
(((p1 + p2 + p2) / 3.0 - p2 + cp1).Length() < 0.02))
|
|
cp1 = cp2 = vector3(0, 0, 0); //"prostowanie" prostych z kontrolnymi, dokładność 2cm
|
|
|
|
if ((cp1 == vector3(0, 0, 0)) &&
|
|
(cp2 == vector3(0, 0, 0))) // Ra: hm, czasem dla prostego są podane...
|
|
Segment->Init(p1, p2, segsize, r1,
|
|
r2); // gdy prosty, kontrolne wyliczane przy zmiennej przechyłce
|
|
else
|
|
Segment->Init(p1, cp1 + p1, cp2 + p2, p2, segsize, r1,
|
|
r2); // gdy łuk (ustawia bCurve=true)
|
|
if ((r1 != 0) || (r2 != 0))
|
|
iTrapezoid = 1; // są przechyłki do uwzględniania w rysowaniu
|
|
if (eType == tt_Table) // obrotnica ma doklejkę
|
|
{ // SwitchExtension=new TSwitchExtension(this,1); //dodatkowe zmienne dla obrotnicy
|
|
SwitchExtension->Segments[0]->Init(p1, p2, segsize); // kopia oryginalnego toru
|
|
}
|
|
else if (iCategoryFlag & 2)
|
|
if (TextureID1 && fTexLength)
|
|
{ // dla drogi trzeba ustalić proporcje boków nawierzchni
|
|
float w, h;
|
|
glBindTexture(GL_TEXTURE_2D, TextureID1);
|
|
glGetTexLevelParameterfv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &w);
|
|
glGetTexLevelParameterfv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &h);
|
|
if (h != 0.0)
|
|
fTexRatio1 = w / h; // proporcja boków
|
|
glBindTexture(GL_TEXTURE_2D, TextureID2);
|
|
glGetTexLevelParameterfv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &w);
|
|
glGetTexLevelParameterfv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &h);
|
|
if (h != 0.0)
|
|
fTexRatio2 = w / h; // proporcja boków
|
|
}
|
|
break;
|
|
|
|
case tt_Cross: // skrzyżowanie dróg - 4 punkty z wektorami kontrolnymi
|
|
segsize = 1.0; // specjalne segmentowanie ze względu na małe promienie
|
|
case tt_Tributary: // dopływ
|
|
case tt_Switch: // zwrotnica
|
|
iAction |= 1; // flaga zmiany położenia typu zwrotnica lub skrzyżowanie dróg
|
|
// problemy z animacją iglic powstaje, gdzy odcinek prosty ma zmienną przechyłkę
|
|
// wtedy dzieli się na dodatkowe odcinki (po 0.2m, bo R=0) i animację diabli biorą
|
|
// Ra: na razie nie podejmuję się przerabiania iglic
|
|
|
|
// SwitchExtension=new TSwitchExtension(this,eType==tt_Cross?6:2); //zwrotnica ma doklejkę
|
|
|
|
p1 = LoadPoint(parser) + pOrigin; // pobranie współrzędnych P1
|
|
parser->getTokens();
|
|
*parser >> r1;
|
|
cp1 = LoadPoint(parser);
|
|
cp2 = LoadPoint(parser);
|
|
p2 = LoadPoint(parser) + pOrigin; // pobranie współrzędnych P2
|
|
parser->getTokens(2);
|
|
*parser >> r2 >> fRadiusTable[0];
|
|
fRadiusTable[0] = fabs(fRadiusTable[0]); // we wpisie może być ujemny
|
|
if (iCategoryFlag & 1)
|
|
{ // zero na główce szyny
|
|
p1.y += 0.18;
|
|
p2.y += 0.18;
|
|
// na przechyłce doliczyć jeszcze pół przechyłki?
|
|
}
|
|
if (fRadiusTable[0] > 0)
|
|
segsize = Min0R(5.0, 0.2 + fRadiusTable[0] * 0.02);
|
|
else if (eType != tt_Cross) // dla skrzyżowań muszą być podane kontrolne
|
|
{ // jak promień zerowy, to przeliczamy punkty kontrolne
|
|
cp1 = (p1 + p1 + p2) / 3.0 - p1; // jak jest prosty, to się zoptymalizuje
|
|
cp2 = (p1 + p2 + p2) / 3.0 - p2;
|
|
segsize = 5.0;
|
|
} // ułomny prosty
|
|
if (!(cp1 == vector3(0, 0, 0)) && !(cp2 == vector3(0, 0, 0)))
|
|
SwitchExtension->Segments[0]->Init(p1, p1 + cp1, p2 + cp2, p2, segsize, r1, r2);
|
|
else
|
|
SwitchExtension->Segments[0]->Init(p1, p2, segsize, r1, r2);
|
|
|
|
p3 = LoadPoint(parser) + pOrigin; // pobranie współrzędnych P3
|
|
parser->getTokens();
|
|
*parser >> r3;
|
|
cp3 = LoadPoint(parser);
|
|
cp4 = LoadPoint(parser);
|
|
p4 = LoadPoint(parser) + pOrigin; // pobranie współrzędnych P4
|
|
parser->getTokens(2);
|
|
*parser >> r4 >> fRadiusTable[1];
|
|
fRadiusTable[1] = fabs(fRadiusTable[1]); // we wpisie może być ujemny
|
|
if (iCategoryFlag & 1)
|
|
{ // zero na główce szyny
|
|
p3.y += 0.18;
|
|
p4.y += 0.18;
|
|
// na przechyłce doliczyć jeszcze pół przechyłki?
|
|
}
|
|
|
|
if (fRadiusTable[1] > 0)
|
|
segsize = Min0R(5.0, 0.2 + fRadiusTable[1] * 0.02);
|
|
else if (eType != tt_Cross) // dla skrzyżowań muszą być podane kontrolne
|
|
{ // jak promień zerowy, to przeliczamy punkty kontrolne
|
|
cp3 = (p3 + p3 + p4) / 3.0 - p3; // jak jest prosty, to się zoptymalizuje
|
|
cp4 = (p3 + p4 + p4) / 3.0 - p4;
|
|
segsize = 5.0;
|
|
} // ułomny prosty
|
|
|
|
if (!(cp3 == vector3(0, 0, 0)) && !(cp4 == vector3(0, 0, 0)))
|
|
{ // dla skrzyżowania dróg dać odwrotnie końce, żeby brzegi generować lewym
|
|
if (eType != tt_Cross)
|
|
SwitchExtension->Segments[1]->Init(p3, p3 + cp3, p4 + cp4, p4, segsize, r3, r4);
|
|
else
|
|
SwitchExtension->Segments[1]->Init(p4, p4 + cp4, p3 + cp3, p3, segsize, r4,
|
|
r3); // odwrócony
|
|
}
|
|
else
|
|
SwitchExtension->Segments[1]->Init(p3, p4, segsize, r3, r4);
|
|
if (eType == tt_Cross)
|
|
{ // Ra 2014-07: dla skrzyżowań będą dodatkowe segmenty
|
|
SwitchExtension->Segments[2]->Init(p2, cp2 + p2, cp4 + p4, p4, segsize, r2,
|
|
r4); // z punktu 2 do 4
|
|
if (LengthSquared3(p3 - p1) <
|
|
0.01) // gdy mniej niż 10cm, to mamy skrzyżowanie trzech dróg
|
|
SwitchExtension->iRoads = 3;
|
|
else // dla 4 dróg będą dodatkowe 3 segmenty
|
|
{
|
|
SwitchExtension->Segments[3]->Init(p4, p4 + cp4, p1 + cp1, p1, segsize, r4,
|
|
r1); // z punktu 4 do 1
|
|
SwitchExtension->Segments[4]->Init(p1, p1 + cp1, p3 + cp3, p3, segsize, r1,
|
|
r3); // z punktu 1 do 3
|
|
SwitchExtension->Segments[5]->Init(p3, p3 + cp3, p2 + cp2, p2, segsize, r3,
|
|
r2); // z punktu 3 do 2
|
|
}
|
|
}
|
|
|
|
Switch(0); // na stałe w położeniu 0 - nie ma początkowego stanu zwrotnicy we wpisie
|
|
|
|
// Ra: zamienić później na iloczyn wektorowy
|
|
{
|
|
vector3 v1, v2;
|
|
double a1, a2;
|
|
v1 = SwitchExtension->Segments[0]->FastGetPoint_1() -
|
|
SwitchExtension->Segments[0]->FastGetPoint_0();
|
|
v2 = SwitchExtension->Segments[1]->FastGetPoint_1() -
|
|
SwitchExtension->Segments[1]->FastGetPoint_0();
|
|
a1 = atan2(v1.x, v1.z);
|
|
a2 = atan2(v2.x, v2.z);
|
|
a2 = a2 - a1;
|
|
while (a2 > M_PI)
|
|
a2 = a2 - 2 * M_PI;
|
|
while (a2 < -M_PI)
|
|
a2 = a2 + 2 * M_PI;
|
|
SwitchExtension->RightSwitch = a2 < 0; // lustrzany układ OXY...
|
|
}
|
|
break;
|
|
}
|
|
parser->getTokens();
|
|
*parser >> token;
|
|
str = AnsiString(token.c_str());
|
|
while (str != "endtrack")
|
|
{
|
|
if (str == "event0")
|
|
{
|
|
parser->getTokens();
|
|
*parser >> token;
|
|
asEvent0Name = AnsiString(token.c_str());
|
|
}
|
|
else if (str == "event1")
|
|
{
|
|
parser->getTokens();
|
|
*parser >> token;
|
|
asEvent1Name = AnsiString(token.c_str());
|
|
}
|
|
else if (str == "event2")
|
|
{
|
|
parser->getTokens();
|
|
*parser >> token;
|
|
asEvent2Name = AnsiString(token.c_str());
|
|
}
|
|
else if (str == "eventall0")
|
|
{
|
|
parser->getTokens();
|
|
*parser >> token;
|
|
asEventall0Name = AnsiString(token.c_str());
|
|
}
|
|
else if (str == "eventall1")
|
|
{
|
|
parser->getTokens();
|
|
*parser >> token;
|
|
asEventall1Name = AnsiString(token.c_str());
|
|
}
|
|
else if (str == "eventall2")
|
|
{
|
|
parser->getTokens();
|
|
*parser >> token;
|
|
asEventall2Name = AnsiString(token.c_str());
|
|
}
|
|
else if (str == "velocity")
|
|
{
|
|
parser->getTokens();
|
|
*parser >> fVelocity; //*0.28; McZapkie-010602
|
|
if (SwitchExtension) // jeśli tor ruchomy
|
|
if (fabs(fVelocity) >= 1.0) //żeby zero nie ograniczało dożywotnio
|
|
SwitchExtension->fVelocity = fVelocity; // zapamiętanie głównego ograniczenia; a
|
|
// np. -40 ogranicza tylko na bok
|
|
}
|
|
else if (str == "isolated")
|
|
{ // obwód izolowany, do którego tor należy
|
|
parser->getTokens();
|
|
*parser >> token;
|
|
pIsolated = TIsolated::Find(AnsiString(token.c_str()));
|
|
}
|
|
else if (str == "angle1")
|
|
{ // kąt ścięcia końca od strony 1
|
|
parser->getTokens();
|
|
*parser >> a1;
|
|
Segment->AngleSet(0, a1);
|
|
}
|
|
else if (str == "angle2")
|
|
{ // kąt ścięcia końca od strony 2
|
|
parser->getTokens();
|
|
*parser >> a2;
|
|
Segment->AngleSet(1, a2);
|
|
}
|
|
else if (str == "fouling1")
|
|
{ // wskazanie modelu ukresu w kierunku 1
|
|
parser->getTokens();
|
|
*parser >> token;
|
|
// nFouling[0]=
|
|
}
|
|
else if (str == "fouling2")
|
|
{ // wskazanie modelu ukresu w kierunku 2
|
|
parser->getTokens();
|
|
*parser >> token;
|
|
// nFouling[1]=
|
|
}
|
|
else if (str == "overhead")
|
|
{ // informacja o stanie sieci: 0-jazda bezprądowa, >0-z opuszczonym i ograniczeniem
|
|
// prędkości
|
|
parser->getTokens();
|
|
*parser >> fOverhead;
|
|
if (fOverhead > 0.0)
|
|
iAction |= 0x40; // flaga opuszczenia pantografu (tor uwzględniany w skanowaniu jako
|
|
// ograniczenie dla pantografujących)
|
|
}
|
|
else if (str == "colides")
|
|
{ // informacja o stanie sieci: 0-jazda bezprądowa, >0-z opuszczonym i ograniczeniem
|
|
// prędkości
|
|
parser->getTokens();
|
|
*parser >> token;
|
|
// trColides=; //tor kolizyjny, na którym trzeba sprawdzać pojazdy pod kątem zderzenia
|
|
}
|
|
else
|
|
ErrorLog("Unknown property: \"" + str + "\" in track \"" + name + "\"");
|
|
parser->getTokens();
|
|
*parser >> token;
|
|
str = AnsiString(token.c_str());
|
|
}
|
|
// alternatywny zapis nazwy odcinka izolowanego - po znaku "@" w nazwie toru
|
|
if (!pIsolated)
|
|
if ((i = name.Pos("@")) > 0)
|
|
if (i < name.Length()) // nie może być puste
|
|
{
|
|
pIsolated = TIsolated::Find(name.SubString(i + 1, name.Length()));
|
|
name = name.SubString(1, i - 1); // usunięcie z nazwy
|
|
}
|
|
}
|
|
|
|
bool TTrack::AssignEvents(TEvent *NewEvent0, TEvent *NewEvent1, TEvent *NewEvent2)
|
|
{
|
|
bool bError = false;
|
|
if (!evEvent0)
|
|
{
|
|
if (NewEvent0)
|
|
{
|
|
evEvent0 = NewEvent0;
|
|
asEvent0Name = "";
|
|
iEvents |= 1; // sumaryczna informacja o eventach
|
|
}
|
|
else
|
|
{
|
|
if (!asEvent0Name.IsEmpty())
|
|
{
|
|
ErrorLog(AnsiString("Bad track: Event0 \"") + asEvent0Name +
|
|
AnsiString("\" does not exist"));
|
|
bError = true;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ErrorLog(
|
|
AnsiString("Bad track: Event0 cannot be assigned to track, track already has one"));
|
|
bError = true;
|
|
}
|
|
if (!evEvent1)
|
|
{
|
|
if (NewEvent1)
|
|
{
|
|
evEvent1 = NewEvent1;
|
|
asEvent1Name = "";
|
|
iEvents |= 2; // sumaryczna informacja o eventach
|
|
}
|
|
else if (!asEvent1Name.IsEmpty())
|
|
{ // Ra: tylko w logu informacja
|
|
ErrorLog(AnsiString("Bad track: Event1 \"") + asEvent1Name +
|
|
AnsiString("\" does not exist").c_str());
|
|
bError = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ErrorLog(
|
|
AnsiString("Bad track: Event1 cannot be assigned to track, track already has one"));
|
|
bError = true;
|
|
}
|
|
if (!evEvent2)
|
|
{
|
|
if (NewEvent2)
|
|
{
|
|
evEvent2 = NewEvent2;
|
|
asEvent2Name = "";
|
|
iEvents |= 4; // sumaryczna informacja o eventach
|
|
}
|
|
else if (!asEvent2Name.IsEmpty())
|
|
{ // Ra: tylko w logu informacja
|
|
ErrorLog(AnsiString("Bad track: Event2 \"") + asEvent2Name +
|
|
AnsiString("\" does not exist"));
|
|
bError = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ErrorLog(
|
|
AnsiString("Bad track: Event2 cannot be assigned to track, track already has one"));
|
|
bError = true;
|
|
}
|
|
return !bError;
|
|
}
|
|
|
|
bool TTrack::AssignallEvents(TEvent *NewEvent0, TEvent *NewEvent1, TEvent *NewEvent2)
|
|
{
|
|
bool bError = false;
|
|
if (!evEventall0)
|
|
{
|
|
if (NewEvent0)
|
|
{
|
|
evEventall0 = NewEvent0;
|
|
asEventall0Name = "";
|
|
iEvents |= 8; // sumaryczna informacja o eventach
|
|
}
|
|
else
|
|
{
|
|
if (!asEvent0Name.IsEmpty())
|
|
{
|
|
Error(AnsiString("Eventall0 \"") + asEventall0Name +
|
|
AnsiString("\" does not exist"));
|
|
bError = true;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Error(AnsiString("Eventall0 cannot be assigned to track, track already has one"));
|
|
bError = true;
|
|
}
|
|
if (!evEventall1)
|
|
{
|
|
if (NewEvent1)
|
|
{
|
|
evEventall1 = NewEvent1;
|
|
asEventall1Name = "";
|
|
iEvents |= 16; // sumaryczna informacja o eventach
|
|
}
|
|
else
|
|
{
|
|
if (!asEvent0Name.IsEmpty())
|
|
{ // Ra: tylko w logu informacja
|
|
WriteLog(AnsiString("Eventall1 \"") + asEventall1Name +
|
|
AnsiString("\" does not exist"));
|
|
bError = true;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Error(AnsiString("Eventall1 cannot be assigned to track, track already has one"));
|
|
bError = true;
|
|
}
|
|
if (!evEventall2)
|
|
{
|
|
if (NewEvent2)
|
|
{
|
|
evEventall2 = NewEvent2;
|
|
asEventall2Name = "";
|
|
iEvents |= 32; // sumaryczna informacja o eventach
|
|
}
|
|
else
|
|
{
|
|
if (!asEvent0Name.IsEmpty())
|
|
{ // Ra: tylko w logu informacja
|
|
WriteLog(AnsiString("Eventall2 \"") + asEventall2Name +
|
|
AnsiString("\" does not exist"));
|
|
bError = true;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Error(AnsiString("Eventall2 cannot be assigned to track, track already has one"));
|
|
bError = true;
|
|
}
|
|
return !bError;
|
|
}
|
|
|
|
bool TTrack::AssignForcedEvents(TEvent *NewEventPlus, TEvent *NewEventMinus)
|
|
{ // ustawienie eventów sygnalizacji rozprucia
|
|
if (SwitchExtension)
|
|
{
|
|
if (NewEventPlus)
|
|
SwitchExtension->evPlus = NewEventPlus;
|
|
if (NewEventMinus)
|
|
SwitchExtension->evMinus = NewEventMinus;
|
|
return true;
|
|
}
|
|
return false;
|
|
};
|
|
|
|
AnsiString TTrack::IsolatedName()
|
|
{ // podaje nazwę odcinka izolowanego, jesli nie ma on jeszcze przypisanych zdarzeń
|
|
if (pIsolated)
|
|
if (!pIsolated->evBusy && !pIsolated->evFree)
|
|
return pIsolated->asName;
|
|
return "";
|
|
};
|
|
|
|
bool TTrack::IsolatedEventsAssign(TEvent *busy, TEvent *free)
|
|
{ // ustawia zdarzenia dla odcinka izolowanego
|
|
if (pIsolated)
|
|
{
|
|
if (busy)
|
|
pIsolated->evBusy = busy;
|
|
if (free)
|
|
pIsolated->evFree = free;
|
|
return true;
|
|
}
|
|
return false;
|
|
};
|
|
|
|
// ABu: przeniesione z Track.h i poprawione!!!
|
|
bool TTrack::AddDynamicObject(TDynamicObject *Dynamic)
|
|
{ // dodanie pojazdu do trajektorii
|
|
// Ra: tymczasowo wysyłanie informacji o zajętości konkretnego toru
|
|
// Ra: usunąć po upowszechnieniu się odcinków izolowanych
|
|
if (iCategoryFlag & 0x100) // jeśli usuwaczek
|
|
{
|
|
Dynamic->MyTrack = NULL; // trzeba by to uzależnić od kierunku ruchu...
|
|
return true;
|
|
}
|
|
if (Global::iMultiplayer) // jeśli multiplayer
|
|
if (!iNumDynamics) // pierwszy zajmujący
|
|
if (pMyNode->asName != "none")
|
|
Global::pGround->WyslijString(pMyNode->asName,
|
|
8); // przekazanie informacji o zajętości toru
|
|
if (iNumDynamics < iMaxNumDynamics)
|
|
{ // jeśli jest miejsce, dajemy na koniec
|
|
Dynamics[iNumDynamics++] = Dynamic;
|
|
Dynamic->MyTrack = this; // ABu: na ktorym torze jesteśmy
|
|
if (Dynamic->iOverheadMask) // jeśli ma pantografy
|
|
Dynamic->OverheadTrack(
|
|
fOverhead); // przekazanie informacji o jeździe bezprądowej na tym odcinku toru
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
Error("Too many dynamics on track " + pMyNode->asName);
|
|
return false;
|
|
}
|
|
};
|
|
|
|
void TTrack::MoveMe(vector3 pPosition)
|
|
{ // to nie jest używane
|
|
if (SwitchExtension)
|
|
{
|
|
SwitchExtension->Segments[0]->MoveMe(1 * pPosition);
|
|
SwitchExtension->Segments[1]->MoveMe(1 * pPosition);
|
|
SwitchExtension->Segments[2]->MoveMe(3 * pPosition); // Ra: 3 razy?
|
|
SwitchExtension->Segments[3]->MoveMe(4 * pPosition);
|
|
}
|
|
else
|
|
{
|
|
Segment->MoveMe(pPosition);
|
|
};
|
|
ResourceManager::Unregister(this);
|
|
};
|
|
|
|
const int numPts = 4;
|
|
const int nnumPts = 12;
|
|
/*
|
|
const vector6 szyna[nnumPts]= //szyna - vextor6(x,y,mapowanie tekstury,xn,yn,zn)
|
|
{pierwotna szyna, opracował youBy, zmiany w celu uzyskania symetrii
|
|
vector6( 0.111,-0.180,0.00, 1.000, 0.000,0.000),
|
|
vector6( 0.045,-0.155,0.15, 0.707, 0.707,0.000),
|
|
vector6( 0.045,-0.070,0.25, 0.707,-0.707,0.000),
|
|
vector6( 0.071,-0.040,0.35, 0.707,-0.707,0.000), //albo tu 0.073
|
|
vector6( 0.072,-0.010,0.40, 0.707, 0.707,0.000),
|
|
vector6( 0.052,-0.000,0.45, 0.000, 1.000,0.000),
|
|
vector6( 0.020,-0.000,0.55, 0.000, 1.000,0.000),
|
|
vector6( 0.000,-0.010,0.60,-0.707, 0.707,0.000),
|
|
vector6( 0.001,-0.040,0.65,-0.707,-0.707,0.000), //albo tu -0.001
|
|
vector6( 0.027,-0.070,0.75,-0.707,-0.707,0.000), //albo zostanie asymetryczna
|
|
vector6( 0.027,-0.155,0.85,-0.707, 0.707,0.000),
|
|
vector6(-0.039,-0.180,1.00,-1.000, 0.000,0.000)
|
|
};
|
|
*/
|
|
const vector6 szyna[nnumPts] = // szyna - vextor6(x,y,mapowanie tekstury,xn,yn,zn)
|
|
{ // tę wersję opracował Tolein (bez pochylenia)
|
|
vector6(0.111, -0.180, 0.00, 1.000, 0.000, 0.000),
|
|
vector6(0.046, -0.150, 0.15, 0.707, 0.707, 0.000),
|
|
vector6(0.044, -0.050, 0.25, 0.707, -0.707, 0.000),
|
|
vector6(0.073, -0.038, 0.35, 0.707, -0.707, 0.000),
|
|
vector6(0.072, -0.010, 0.40, 0.707, 0.707, 0.000),
|
|
vector6(0.052, -0.000, 0.45, 0.000, 1.000, 0.000),
|
|
vector6(0.020, -0.000, 0.55, 0.000, 1.000, 0.000),
|
|
vector6(0.000, -0.010, 0.60, -0.707, 0.707, 0.000),
|
|
vector6(-0.001, -0.038, 0.65, -0.707, -0.707, 0.000),
|
|
vector6(0.028, -0.050, 0.75, -0.707, -0.707, 0.000),
|
|
vector6(0.026, -0.150, 0.85, -0.707, 0.707, 0.000),
|
|
vector6(-0.039, -0.180, 1.00, -1.000, 0.000, 0.000)};
|
|
|
|
const vector6 iglica[nnumPts] = // iglica - vextor3(x,y,mapowanie tekstury)
|
|
{
|
|
vector6(0.010, -0.180, 0.00, 1.000, 0.000, 0.000),
|
|
vector6(0.010, -0.155, 0.15, 1.000, 0.000, 0.000),
|
|
vector6(0.010, -0.070, 0.25, 1.000, 0.000, 0.000),
|
|
vector6(0.010, -0.040, 0.35, 1.000, 0.000, 0.000),
|
|
vector6(0.010, -0.010, 0.40, 1.000, 0.000, 0.000),
|
|
vector6(0.010, -0.000, 0.45, 0.707, 0.707, 0.000),
|
|
vector6(0.000, -0.000, 0.55, 0.707, 0.707, 0.000),
|
|
vector6(0.000, -0.010, 0.60, -1.000, 0.000, 0.000),
|
|
vector6(0.000, -0.040, 0.65, -1.000, 0.000, 0.000),
|
|
vector6(0.000, -0.070, 0.75, -1.000, 0.000, 0.000),
|
|
vector6(0.000, -0.155, 0.85, -0.707, 0.707, 0.000),
|
|
vector6(-0.040, -0.180, 1.00, -1.000, 0.000,
|
|
0.000) // 1mm więcej, żeby nie nachodziły tekstury?
|
|
};
|
|
|
|
void TTrack::Compile(GLuint tex)
|
|
{ // generowanie treści dla Display Lists - model proceduralny
|
|
if (!tex)
|
|
{ // jeśli nie podana tekstura, to każdy tor ma wlasne DL
|
|
if (DisplayListID)
|
|
Release(); // zwolnienie zasobów w celu ponownego utworzenia
|
|
if (Global::bManageNodes)
|
|
{
|
|
DisplayListID = glGenLists(1); // otwarcie nowej listy
|
|
glNewList(DisplayListID, GL_COMPILE);
|
|
};
|
|
}
|
|
glColor3f(1.0f, 1.0f, 1.0f); // to tutaj potrzebne?
|
|
// Ra: nie zmieniamy oświetlenia przy kompilowaniu, ponieważ ono się zmienia w czasie!
|
|
// trochę podliczonych zmiennych, co się potem przydadzą
|
|
double fHTW = 0.5 * fabs(fTrackWidth); // połowa szerokości
|
|
double side = fabs(fTexWidth); // szerokść podsypki na zewnątrz szyny albo pobocza
|
|
double slop = fabs(fTexSlope); // szerokość pochylenia
|
|
double rozp = fHTW + side + slop; // brzeg zewnętrzny
|
|
double hypot1 = hypot(slop, fTexHeight1); // rozmiar pochylenia do liczenia normalnych
|
|
if (hypot1 == 0.0)
|
|
hypot1 = 1.0;
|
|
vector3 normal1 = vector3(fTexSlope / hypot1, fTexHeight1 / hypot1, 0.0); // wektor normalny
|
|
double fHTW2, side2, slop2, rozp2, fTexHeight2, hypot2;
|
|
vector3 normal2;
|
|
if (iTrapezoid & 2) // ten bit oznacza, że istnieje odpowiednie pNext
|
|
{ // Ra: jest OK
|
|
fHTW2 = 0.5 * fabs(trNext->fTrackWidth); // połowa rozstawu/nawierzchni
|
|
side2 = fabs(trNext->fTexWidth);
|
|
slop2 = fabs(trNext->fTexSlope);
|
|
rozp2 = fHTW2 + side2 + slop2; // szerokość podstawy
|
|
fTexHeight2 = trNext->fTexHeight1;
|
|
hypot2 = hypot(slop2, fTexHeight2);
|
|
if (hypot2 == 0.0)
|
|
hypot2 = 1.0;
|
|
normal2 = vector3(trNext->fTexSlope / hypot2, fTexHeight2 / hypot2, 0.0);
|
|
}
|
|
else // gdy nie ma następnego albo jest nieodpowiednim końcem podpięty
|
|
{
|
|
fHTW2 = fHTW;
|
|
side2 = side;
|
|
slop2 = slop;
|
|
rozp2 = rozp;
|
|
fTexHeight2 = fTexHeight1;
|
|
hypot2 = hypot1;
|
|
normal2 = normal1;
|
|
}
|
|
double roll1, roll2;
|
|
switch (iCategoryFlag & 15)
|
|
{
|
|
case 1: // tor
|
|
{
|
|
Segment->GetRolls(roll1, roll2);
|
|
double sin1 = sin(roll1), cos1 = cos(roll1), sin2 = sin(roll2), cos2 = cos(roll2);
|
|
// zwykla szyna: //Ra: czemu główki są asymetryczne na wysokości 0.140?
|
|
vector6 rpts1[24], rpts2[24], rpts3[24], rpts4[24];
|
|
int i;
|
|
for (i = 0; i < 12; ++i)
|
|
{
|
|
rpts1[i] = vector6((fHTW + szyna[i].x) * cos1 + szyna[i].y * sin1,
|
|
-(fHTW + szyna[i].x) * sin1 + szyna[i].y * cos1, szyna[i].z,
|
|
+szyna[i].n.x * cos1 + szyna[i].n.y * sin1,
|
|
-szyna[i].n.x * sin1 + szyna[i].n.y * cos1, 0.0);
|
|
rpts2[11 - i] = vector6((-fHTW - szyna[i].x) * cos1 + szyna[i].y * sin1,
|
|
-(-fHTW - szyna[i].x) * sin1 + szyna[i].y * cos1, szyna[i].z,
|
|
-szyna[i].n.x * cos1 + szyna[i].n.y * sin1,
|
|
+szyna[i].n.x * sin1 + szyna[i].n.y * cos1, 0.0);
|
|
}
|
|
if (iTrapezoid) // jak trapez albo przechyłki, to oddzielne punkty na końcu
|
|
for (i = 0; i < 12; ++i)
|
|
{
|
|
rpts1[12 + i] = vector6((fHTW2 + szyna[i].x) * cos2 + szyna[i].y * sin2,
|
|
-(fHTW2 + szyna[i].x) * sin2 + szyna[i].y * cos2,
|
|
szyna[i].z, +szyna[i].n.x * cos2 + szyna[i].n.y * sin2,
|
|
-szyna[i].n.x * sin2 + szyna[i].n.y * cos2, 0.0);
|
|
rpts2[23 - i] = vector6((-fHTW2 - szyna[i].x) * cos2 + szyna[i].y * sin2,
|
|
-(-fHTW2 - szyna[i].x) * sin2 + szyna[i].y * cos2,
|
|
szyna[i].z, -szyna[i].n.x * cos2 + szyna[i].n.y * sin2,
|
|
+szyna[i].n.x * sin2 + szyna[i].n.y * cos2, 0.0);
|
|
}
|
|
switch (eType) // dalej zależnie od typu
|
|
{
|
|
case tt_Table: // obrotnica jak zwykły tor, animacja wykonywana w RaAnimate(), tutaj tylko
|
|
// regeneracja siatek
|
|
case tt_Normal:
|
|
if (TextureID2)
|
|
if (tex ? TextureID2 == tex : true) // jeśli pasuje do grupy (tex)
|
|
{ // podsypka z podkładami jest tylko dla zwykłego toru
|
|
vector6
|
|
bpts1[8]; // punkty głównej płaszczyzny nie przydają się do robienia boków
|
|
if (fTexLength ==
|
|
4.0) // jeśli stare mapowanie na profil 0.2 0.5 1.1 (również 6-9-9/noil)
|
|
{ // stare mapowanie z różną gęstością pikseli i oddzielnymi teksturami na każdy
|
|
// profil
|
|
if (iTrapezoid) // trapez albo przechyłki
|
|
{ // podsypka z podkladami trapezowata
|
|
// ewentualnie poprawić mapowanie, żeby środek mapował się na
|
|
// 1.435/4.671 ((0.3464,0.6536)
|
|
// bo się tekstury podsypki rozjeżdżają po zmianie proporcji profilu
|
|
bpts1[0] = vector6(rozp, -fTexHeight1 - 0.18, 0.00, normal1.x,
|
|
-normal1.y, 0.0); // lewy brzeg
|
|
bpts1[1] = vector6((fHTW + side) * cos1, -(fHTW + side) * sin1 - 0.18,
|
|
0.33, 0.0, 1.0, 0.0); // krawędź załamania
|
|
bpts1[2] =
|
|
vector6(-bpts1[1].x, +(fHTW + side) * sin1 - 0.18, 0.67, -normal1.x,
|
|
-normal1.y, 0.0); // prawy brzeg początku symetrycznie
|
|
bpts1[3] = vector6(-rozp, -fTexHeight1 - 0.18, 1.00, -normal1.x,
|
|
-normal1.y, 0.0); // prawy skos
|
|
// przekrój końcowy
|
|
bpts1[4] = vector6(rozp2, -fTexHeight2 - 0.18, 0.00, normal2.x,
|
|
-normal2.y, 0.0); // lewy brzeg
|
|
bpts1[5] =
|
|
vector6((fHTW2 + side2) * cos2, -(fHTW2 + side2) * sin2 - 0.18,
|
|
0.33, 0.0, 1.0, 0.0); // krawędź załamania
|
|
bpts1[6] = vector6(-bpts1[5].x, +(fHTW2 + side2) * sin2 - 0.18, 0.67,
|
|
0.0, 1.0, 0.0); // prawy brzeg początku symetrycznie
|
|
bpts1[7] = vector6(-rozp2, -fTexHeight2 - 0.18, 1.00, -normal2.x,
|
|
-normal2.y, 0.0); // prawy skos
|
|
}
|
|
else
|
|
{
|
|
bpts1[0] = vector6(rozp, -fTexHeight1 - 0.18, 0.0, +normal1.x,
|
|
-normal1.y, 0.0); // lewy brzeg
|
|
bpts1[1] = vector6(fHTW + side, -0.18, 0.33, +normal1.x, -normal1.y,
|
|
0.0); // krawędź załamania
|
|
bpts1[2] = vector6(-fHTW - side, -0.18, 0.67, -normal1.x, -normal1.y,
|
|
0.0); // druga
|
|
bpts1[3] = vector6(-rozp, -fTexHeight1 - 0.18, 1.0, -normal1.x,
|
|
-normal1.y, 0.0); // prawy skos
|
|
}
|
|
}
|
|
else
|
|
{ // mapowanie proporcjonalne do powierzchni, rozmiar w poprzek określa
|
|
// fTexLength
|
|
double max = fTexRatio2 * fTexLength; // szerokość proporcjonalna do
|
|
// długości
|
|
double map11 =
|
|
max > 0.0 ? (fHTW + side) / max : 0.25; // załamanie od strony 1
|
|
double map12 =
|
|
max > 0.0 ? (fHTW + side + hypot1) / max : 0.5; // brzeg od strony 1
|
|
if (iTrapezoid) // trapez albo przechyłki
|
|
{ // podsypka z podkladami trapezowata
|
|
double map21 =
|
|
max > 0.0 ? (fHTW2 + side2) / max : 0.25; // załamanie od strony 2
|
|
double map22 = max > 0.0 ? (fHTW2 + side2 + hypot2) / max :
|
|
0.5; // brzeg od strony 2
|
|
// ewentualnie poprawić mapowanie, żeby środek mapował się na
|
|
// 1.435/4.671 ((0.3464,0.6536)
|
|
// bo się tekstury podsypki rozjeżdżają po zmianie proporcji profilu
|
|
bpts1[0] = vector6(rozp, -fTexHeight1 - 0.18, 0.5 - map12, normal1.x,
|
|
-normal1.y, 0.0); // lewy brzeg
|
|
bpts1[1] = vector6((fHTW + side) * cos1, -(fHTW + side) * sin1 - 0.18,
|
|
0.5 - map11, 0.0, 1.0, 0.0); // krawędź załamania
|
|
bpts1[2] =
|
|
vector6(-bpts1[1].x, +(fHTW + side) * sin1 - 0.18, 0.5 + map11, 0.0,
|
|
1.0, 0.0); // prawy brzeg początku symetrycznie
|
|
bpts1[3] = vector6(-rozp, -fTexHeight1 - 0.18, 0.5 + map12, -normal1.x,
|
|
-normal1.y, 0.0); // prawy skos
|
|
// przekrój końcowy
|
|
bpts1[4] = vector6(rozp2, -fTexHeight2 - 0.18, 0.5 - map22, normal2.x,
|
|
-normal2.y, 0.0); // lewy brzeg
|
|
bpts1[5] =
|
|
vector6((fHTW2 + side2) * cos2, -(fHTW2 + side2) * sin2 - 0.18,
|
|
0.5 - map21, 0.0, 1.0, 0.0); // krawędź załamania
|
|
bpts1[6] =
|
|
vector6(-bpts1[5].x, +(fHTW2 + side2) * sin2 - 0.18, 0.5 + map21,
|
|
0.0, 1.0, 0.0); // prawy brzeg początku symetrycznie
|
|
bpts1[7] = vector6(-rozp2, -fTexHeight2 - 0.18, 0.5 + map22, -normal2.x,
|
|
-normal2.y, 0.0); // prawy skos
|
|
}
|
|
else
|
|
{
|
|
bpts1[0] = vector6(rozp, -fTexHeight1 - 0.18, 0.5 - map12, +normal1.x,
|
|
-normal1.y, 0.0); // lewy brzeg
|
|
bpts1[1] = vector6(fHTW + side, -0.18, 0.5 - map11, +normal1.x,
|
|
-normal1.y, 0.0); // krawędź załamania
|
|
bpts1[2] = vector6(-fHTW - side, -0.18, 0.5 + map11, -normal1.x,
|
|
-normal1.y, 0.0); // druga
|
|
bpts1[3] = vector6(-rozp, -fTexHeight1 - 0.18, 0.5 + map12, -normal1.x,
|
|
-normal1.y, 0.0); // prawy skos
|
|
}
|
|
}
|
|
if (!tex)
|
|
glBindTexture(GL_TEXTURE_2D, TextureID2);
|
|
Segment->RenderLoft(bpts1, iTrapezoid ? -4 : 4, fTexLength);
|
|
}
|
|
if (TextureID1)
|
|
if (tex ? TextureID1 == tex : true) // jeśli pasuje do grupy (tex)
|
|
{ // szyny
|
|
if (!tex)
|
|
glBindTexture(GL_TEXTURE_2D, TextureID1);
|
|
Segment->RenderLoft(rpts1, iTrapezoid ? -nnumPts : nnumPts, fTexLength);
|
|
Segment->RenderLoft(rpts2, iTrapezoid ? -nnumPts : nnumPts, fTexLength);
|
|
}
|
|
break;
|
|
case tt_Switch: // dla zwrotnicy dwa razy szyny
|
|
if (TextureID1) // zwrotnice nie są grupowane, aby prościej było je animować
|
|
{ // iglice liczone tylko dla zwrotnic
|
|
// Ra: TODO: oddzielna animacja każdej iglicy, opór na docisku
|
|
vector6 rpts3[24], rpts4[24];
|
|
for (i = 0; i < 12; ++i)
|
|
{
|
|
rpts3[i] = vector6((fHTW + iglica[i].x) * cos1 + iglica[i].y * sin1,
|
|
-(fHTW + iglica[i].x) * sin1 + iglica[i].y * cos1,
|
|
iglica[i].z, +iglica[i].n.x * cos1 + iglica[i].n.y * sin1,
|
|
-iglica[i].n.x * sin1 + iglica[i].n.y * cos1, 0.0);
|
|
rpts4[11 - i] =
|
|
vector6((-fHTW - iglica[i].x) * cos1 + iglica[i].y * sin1,
|
|
-(-fHTW - iglica[i].x) * sin1 + iglica[i].y * cos1, iglica[i].z,
|
|
-iglica[i].n.x * cos1 + iglica[i].n.y * sin1,
|
|
+iglica[i].n.x * sin1 + iglica[i].n.y * cos1, 0.0);
|
|
}
|
|
if (iTrapezoid) // trapez albo przechyłki, to oddzielne punkty na końcu
|
|
for (i = 0; i < 12; ++i)
|
|
{
|
|
rpts3[12 + i] =
|
|
vector6((fHTW2 + iglica[i].x) * cos2 + iglica[i].y * sin2,
|
|
-(fHTW2 + iglica[i].x) * sin2 + iglica[i].y * cos2, iglica[i].z,
|
|
+iglica[i].n.x * cos2 + iglica[i].n.y * sin2,
|
|
-iglica[i].n.x * sin2 + iglica[i].n.y * cos2, 0.0);
|
|
rpts4[23 - i] =
|
|
vector6((-fHTW2 - iglica[i].x) * cos2 + iglica[i].y * sin2,
|
|
-(-fHTW2 - iglica[i].x) * sin2 + iglica[i].y * cos2,
|
|
iglica[i].z, -iglica[i].n.x * cos2 + iglica[i].n.y * sin2,
|
|
+iglica[i].n.x * sin2 + iglica[i].n.y * cos2, 0.0);
|
|
}
|
|
// McZapkie-130302 - poprawione rysowanie szyn
|
|
if (SwitchExtension->RightSwitch)
|
|
{ // zwrotnica prawa
|
|
glBindTexture(GL_TEXTURE_2D, TextureID1);
|
|
SwitchExtension->Segments[0]->RenderLoft(rpts1, nnumPts, fTexLength,
|
|
2); // prawa szyna za iglicą
|
|
SwitchExtension->Segments[0]->RenderSwitchRail(
|
|
rpts1, rpts3, nnumPts, fTexLength, 2,
|
|
SwitchExtension->fOffset2); // prawa iglica
|
|
SwitchExtension->Segments[0]->RenderLoft(
|
|
rpts2, nnumPts, fTexLength); // lewa szyna normalnie cała
|
|
if (TextureID2 != TextureID1) // nie wiadomo, czy OpenGL to optymalizuje
|
|
glBindTexture(GL_TEXTURE_2D, TextureID2);
|
|
SwitchExtension->Segments[1]->RenderLoft(
|
|
rpts1, nnumPts, fTexLength); // prawa szyna normalna cała
|
|
SwitchExtension->Segments[1]->RenderLoft(rpts2, nnumPts, fTexLength,
|
|
2); // lewa szyna za iglicą
|
|
SwitchExtension->Segments[1]->RenderSwitchRail(
|
|
rpts2, rpts4, nnumPts, fTexLength, 2,
|
|
-fMaxOffset + SwitchExtension->fOffset1); // lewa iglica
|
|
}
|
|
else
|
|
{ // lewa kiedyś działała lepiej niż prawa
|
|
glBindTexture(GL_TEXTURE_2D, TextureID1);
|
|
SwitchExtension->Segments[0]->RenderLoft(
|
|
rpts1, nnumPts, fTexLength); // prawa szyna normalna cała
|
|
SwitchExtension->Segments[0]->RenderLoft(rpts2, nnumPts, fTexLength,
|
|
2); // lewa szyna za iglicą
|
|
SwitchExtension->Segments[0]->RenderSwitchRail(
|
|
rpts2, rpts4, nnumPts, fTexLength, 2,
|
|
-SwitchExtension->fOffset2); // lewa iglica
|
|
if (TextureID2 != TextureID1) // nie wiadomo, czy OpenGL to optymalizuje
|
|
glBindTexture(GL_TEXTURE_2D, TextureID2);
|
|
SwitchExtension->Segments[1]->RenderLoft(rpts1, nnumPts, fTexLength,
|
|
2); // prawa szyna za iglicą
|
|
SwitchExtension->Segments[1]->RenderSwitchRail(
|
|
rpts1, rpts3, nnumPts, fTexLength, 2,
|
|
fMaxOffset - SwitchExtension->fOffset1); // prawa iglica
|
|
SwitchExtension->Segments[1]->RenderLoft(
|
|
rpts2, nnumPts, fTexLength); // lewa szyna normalnie cała
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
} // koniec obsługi torów
|
|
break;
|
|
case 2: // McZapkie-260302 - droga - rendering
|
|
// McZapkie:240702-zmieniony zakres widzialnosci
|
|
switch (eType) // dalej zależnie od typu
|
|
{
|
|
case tt_Normal: // drogi proste, bo skrzyżowania osobno
|
|
{
|
|
vector6 bpts1[4]; // punkty głównej płaszczyzny przydają się do robienia boków
|
|
if (TextureID1 || TextureID2) // punkty się przydadzą, nawet jeśli nawierzchni nie ma
|
|
{ // double max=2.0*(fHTW>fHTW2?fHTW:fHTW2); //z szerszej strony jest 100%
|
|
double max = fTexRatio1 * fTexLength; // test: szerokość proporcjonalna do długości
|
|
double map1 = max > 0.0 ? fHTW / max : 0.5; // obcięcie tekstury od strony 1
|
|
double map2 = max > 0.0 ? fHTW2 / max : 0.5; // obcięcie tekstury od strony 2
|
|
if (iTrapezoid) // trapez albo przechyłki
|
|
{ // nawierzchnia trapezowata
|
|
Segment->GetRolls(roll1, roll2);
|
|
bpts1[0] = vector6(fHTW * cos(roll1), -fHTW * sin(roll1), 0.5 - map1,
|
|
sin(roll1), cos(roll1), 0.0); // lewy brzeg początku
|
|
bpts1[1] = vector6(-bpts1[0].x, -bpts1[0].y, 0.5 + map1, -sin(roll1),
|
|
cos(roll1), 0.0); // prawy brzeg początku symetrycznie
|
|
bpts1[2] = vector6(fHTW2 * cos(roll2), -fHTW2 * sin(roll2), 0.5 - map2,
|
|
sin(roll2), cos(roll2), 0.0); // lewy brzeg końca
|
|
bpts1[3] = vector6(-bpts1[2].x, -bpts1[2].y, 0.5 + map2, -sin(roll2),
|
|
cos(roll2), 0.0); // prawy brzeg początku symetrycznie
|
|
}
|
|
else
|
|
{
|
|
bpts1[0] = vector6(fHTW, 0.0, 0.5 - map1, 0.0, 1.0, 0.0);
|
|
bpts1[1] = vector6(-fHTW, 0.0, 0.5 + map1, 0.0, 1.0, 0.0);
|
|
}
|
|
}
|
|
if (TextureID1) // jeśli podana była tekstura, generujemy trójkąty
|
|
if (tex ? TextureID1 == tex : true) // jeśli pasuje do grupy (tex)
|
|
{ // tworzenie trójkątów nawierzchni szosy
|
|
if (!tex)
|
|
glBindTexture(GL_TEXTURE_2D, TextureID1);
|
|
Segment->RenderLoft(bpts1, iTrapezoid ? -2 : 2, fTexLength);
|
|
}
|
|
if (TextureID2)
|
|
if (tex ? TextureID2 == tex : true) // jeśli pasuje do grupy (tex)
|
|
{ // pobocze drogi - poziome przy przechyłce (a może krawężnik i chodnik zrobić jak
|
|
// w Midtown Madness 2?)
|
|
if (!tex)
|
|
glBindTexture(GL_TEXTURE_2D, TextureID2);
|
|
vector6 rpts1[6],
|
|
rpts2[6]; // współrzędne przekroju i mapowania dla prawej i lewej strony
|
|
if (fTexHeight1 >= 0.0)
|
|
{ // standardowo: od zewnątrz pochylenie, a od wewnątrz poziomo
|
|
rpts1[0] = vector6(rozp, -fTexHeight1, 0.0); // lewy brzeg podstawy
|
|
rpts1[1] =
|
|
vector6(bpts1[0].x + side, bpts1[0].y, 0.5); // lewa krawędź załamania
|
|
rpts1[2] = vector6(bpts1[0].x, bpts1[0].y,
|
|
1.0); // lewy brzeg pobocza (mapowanie może być inne
|
|
rpts2[0] = vector6(bpts1[1].x, bpts1[1].y, 1.0); // prawy brzeg pobocza
|
|
rpts2[1] =
|
|
vector6(bpts1[1].x - side, bpts1[1].y, 0.5); // prawa krawędź załamania
|
|
rpts2[2] = vector6(-rozp, -fTexHeight1, 0.0); // prawy brzeg podstawy
|
|
if (iTrapezoid) // trapez albo przechyłki
|
|
{ // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony
|
|
// odcinka
|
|
rpts1[3] =
|
|
vector6(rozp2, -fTexHeight2, 0.0); // lewy brzeg lewego pobocza
|
|
rpts1[4] =
|
|
vector6(bpts1[2].x + side2, bpts1[2].y, 0.5); // krawędź załamania
|
|
rpts1[5] = vector6(bpts1[2].x, bpts1[2].y, 1.0); // brzeg pobocza
|
|
rpts2[3] = vector6(bpts1[3].x, bpts1[3].y, 1.0);
|
|
rpts2[4] = vector6(bpts1[3].x - side2, bpts1[3].y, 0.5);
|
|
rpts2[5] =
|
|
vector6(-rozp2, -fTexHeight2, 0.0); // prawy brzeg prawego pobocza
|
|
}
|
|
}
|
|
else
|
|
{ // wersja dla chodnika: skos 1:3.75, każdy chodnik innej szerokości
|
|
// mapowanie propocjonalne do szerokości chodnika
|
|
// krawężnik jest mapowany od 31/64 do 32/64 lewy i od 32/64 do 33/64 prawy
|
|
double d =
|
|
-fTexHeight1 / 3.75; // krawężnik o wysokości 150mm jest pochylony 40mm
|
|
double max =
|
|
fTexRatio2 * fTexLength; // test: szerokość proporcjonalna do długości
|
|
double map1l = max > 0.0 ?
|
|
side / max :
|
|
0.484375; // obcięcie tekstury od lewej strony punktu 1
|
|
double map1r = max > 0.0 ?
|
|
slop / max :
|
|
0.484375; // obcięcie tekstury od prawej strony punktu 1
|
|
rpts1[0] = vector6(bpts1[0].x + slop, bpts1[0].y - fTexHeight1,
|
|
0.515625 + map1r); // prawy brzeg prawego chodnika
|
|
rpts1[1] = vector6(bpts1[0].x + d, bpts1[0].y - fTexHeight1,
|
|
0.515625); // prawy krawężnik u góry
|
|
rpts1[2] = vector6(bpts1[0].x, bpts1[0].y,
|
|
0.515625 - d / 2.56); // prawy krawężnik u dołu
|
|
rpts2[0] = vector6(bpts1[1].x, bpts1[1].y,
|
|
0.484375 + d / 2.56); // lewy krawężnik u dołu
|
|
rpts2[1] = vector6(bpts1[1].x - d, bpts1[1].y - fTexHeight1,
|
|
0.484375); // lewy krawężnik u góry
|
|
rpts2[2] = vector6(bpts1[1].x - side, bpts1[1].y - fTexHeight1,
|
|
0.484375 - map1l); // lewy brzeg lewego chodnika
|
|
if (iTrapezoid) // trapez albo przechyłki
|
|
{ // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony
|
|
// odcinka
|
|
slop2 = fabs((iTrapezoid & 2) ? slop2 :
|
|
slop); // szerokość chodnika po prawej
|
|
double map2l =
|
|
max > 0.0 ? side2 / max :
|
|
0.484375; // obcięcie tekstury od lewej strony punktu 2
|
|
double map2r =
|
|
max > 0.0 ? slop2 / max :
|
|
0.484375; // obcięcie tekstury od prawej strony punktu 2
|
|
rpts1[3] = vector6(bpts1[2].x + slop2, bpts1[2].y - fTexHeight2,
|
|
0.515625 + map2r); // prawy brzeg prawego chodnika
|
|
rpts1[4] = vector6(bpts1[2].x + d, bpts1[2].y - fTexHeight2,
|
|
0.515625); // prawy krawężnik u góry
|
|
rpts1[5] = vector6(bpts1[2].x, bpts1[2].y,
|
|
0.515625 - d / 2.56); // prawy krawężnik u dołu
|
|
rpts2[3] = vector6(bpts1[3].x, bpts1[3].y,
|
|
0.484375 + d / 2.56); // lewy krawężnik u dołu
|
|
rpts2[4] = vector6(bpts1[3].x - d, bpts1[3].y - fTexHeight2,
|
|
0.484375); // lewy krawężnik u góry
|
|
rpts2[5] = vector6(bpts1[3].x - side2, bpts1[3].y - fTexHeight2,
|
|
0.484375 - map2l); // lewy brzeg lewego chodnika
|
|
}
|
|
}
|
|
if (iTrapezoid) // trapez albo przechyłki
|
|
{ // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony
|
|
// odcinka
|
|
if ((fTexHeight1 >= 0.0) ? true : (slop != 0.0))
|
|
Segment->RenderLoft(rpts1, -3, fTexLength); // tylko jeśli jest z prawej
|
|
if ((fTexHeight1 >= 0.0) ? true : (side != 0.0))
|
|
Segment->RenderLoft(rpts2, -3, fTexLength); // tylko jeśli jest z lewej
|
|
}
|
|
else
|
|
{ // pobocza zwykłe, brak przechyłki
|
|
if ((fTexHeight1 >= 0.0) ? true : (slop != 0.0))
|
|
Segment->RenderLoft(rpts1, 3, fTexLength);
|
|
if ((fTexHeight1 >= 0.0) ? true : (side != 0.0))
|
|
Segment->RenderLoft(rpts2, 3, fTexLength);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case tt_Cross: // skrzyżowanie dróg rysujemy inaczej
|
|
{ // ustalenie współrzędnych środka - przecięcie Point1-Point2 z CV4-Point4
|
|
double a[4]; // kąty osi ulic wchodzących
|
|
vector3 p[4]; // punkty się przydadzą do obliczeń
|
|
// na razie połowa odległości pomiędzy Point1 i Point2, potem się dopracuje
|
|
a[0] = a[1] = 0.5; // parametr do poszukiwania przecięcia łuków
|
|
// modyfikować a[0] i a[1] tak, aby trafić na przecięcie odcinka 34
|
|
p[0] = SwitchExtension->Segments[0]->FastGetPoint(
|
|
a[0]); // współrzędne środka pierwszego odcinka
|
|
p[1] = SwitchExtension->Segments[1]->FastGetPoint(a[1]); //-//- drugiego
|
|
// p[2]=p[1]-p[0]; //jeśli różne od zera, przeliczyć a[0] i a[1] i wyznaczyć nowe punkty
|
|
vector3 oxz = p[0]; // punkt mapowania środka tekstury skrzyżowania
|
|
p[0] = SwitchExtension->Segments[0]
|
|
->GetDirection1(); // Point1 - pobranie wektorów kontrolnych
|
|
p[1] = SwitchExtension->Segments[1]->GetDirection2(); // Point3 (bo zamienione)
|
|
p[2] = SwitchExtension->Segments[0]->GetDirection2(); // Point2
|
|
p[3] = SwitchExtension->Segments[1]->GetDirection1(); // Point4 (bo zamienione)
|
|
a[0] = atan2(-p[0].x, p[0].z); // kąty stycznych osi dróg
|
|
a[1] = atan2(-p[1].x, p[1].z);
|
|
a[2] = atan2(-p[2].x, p[2].z);
|
|
a[3] = atan2(-p[3].x, p[3].z);
|
|
p[0] = SwitchExtension->Segments[0]
|
|
->FastGetPoint_0(); // Point1 - pobranie współrzędnych końców
|
|
p[1] = SwitchExtension->Segments[1]->FastGetPoint_1(); // Point3
|
|
p[2] = SwitchExtension->Segments[0]->FastGetPoint_1(); // Point2
|
|
p[3] = SwitchExtension->Segments[1]
|
|
->FastGetPoint_0(); // Point4 - przy trzech drogach pokrywa się z Point1
|
|
// 2014-07: na początek rysować brzegi jak dla łuków
|
|
// punkty brzegu nawierzchni uzyskujemy podczas renderowania boków (bez sensu, ale
|
|
// najszybciej było zrobić)
|
|
int i, j; // ile punktów (może byc różna ilość punktów między drogami)
|
|
if (!SwitchExtension->vPoints)
|
|
{ // jeśli tablica punktów nie jest jeszcze utworzona, zliczamy punkty i tworzymy ją
|
|
if (SwitchExtension->iRoads == 3) // mogą być tylko 3 drogi zamiast 4
|
|
SwitchExtension->iPoints = 5 + SwitchExtension->Segments[0]->RaSegCount() +
|
|
SwitchExtension->Segments[1]->RaSegCount() +
|
|
SwitchExtension->Segments[2]->RaSegCount();
|
|
else
|
|
SwitchExtension->iPoints =
|
|
5 + SwitchExtension->Segments[2]->RaSegCount() +
|
|
SwitchExtension->Segments[3]->RaSegCount() +
|
|
SwitchExtension->Segments[4]->RaSegCount() +
|
|
SwitchExtension->Segments[5]->RaSegCount(); // mogą być tylko 3 drogi
|
|
SwitchExtension->vPoints =
|
|
new vector3[SwitchExtension->iPoints]; // tablica utworzona z zapasem, ale nie
|
|
// wypełniona współrzędnymi
|
|
}
|
|
vector3 *b =
|
|
SwitchExtension->bPoints ?
|
|
NULL :
|
|
SwitchExtension
|
|
->vPoints; // zmienna robocza, NULL gdy tablica punktów już jest wypełniona
|
|
vector6 bpts1[4]; // punkty głównej płaszczyzny przydają się do robienia boków
|
|
if (TextureID1 || TextureID2) // punkty się przydadzą, nawet jeśli nawierzchni nie ma
|
|
{ // double max=2.0*(fHTW>fHTW2?fHTW:fHTW2); //z szerszej strony jest 100%
|
|
double max = fTexRatio1 * fTexLength; // test: szerokość proporcjonalna do długości
|
|
double map1 = max > 0.0 ? fHTW / max : 0.5; // obcięcie tekstury od strony 1
|
|
double map2 = max > 0.0 ? fHTW2 / max : 0.5; // obcięcie tekstury od strony 2
|
|
// if (iTrapezoid) //trapez albo przechyłki
|
|
{ // nawierzchnia trapezowata
|
|
Segment->GetRolls(roll1, roll2);
|
|
bpts1[0] = vector6(fHTW * cos(roll1), -fHTW * sin(roll1), 0.5 - map1,
|
|
sin(roll1), cos(roll1), 0.0); // lewy brzeg początku
|
|
bpts1[1] = vector6(-bpts1[0].x, -bpts1[0].y, 0.5 + map1, -sin(roll1),
|
|
cos(roll1), 0.0); // prawy brzeg początku symetrycznie
|
|
bpts1[2] = vector6(fHTW2 * cos(roll2), -fHTW2 * sin(roll2), 0.5 - map2,
|
|
sin(roll2), cos(roll2), 0.0); // lewy brzeg końca
|
|
bpts1[3] = vector6(-bpts1[2].x, -bpts1[2].y, 0.5 + map2, -sin(roll2),
|
|
cos(roll2), 0.0); // prawy brzeg początku symetrycznie
|
|
}
|
|
}
|
|
// najpierw renderowanie poboczy i zapamiętywanie punktów
|
|
// problem ze skrzyżowaniami jest taki, że teren chce się pogrupować wg tekstur, ale
|
|
// zaczyna od nawierzchni
|
|
// sama nawierzchnia nie wypełni tablicy punktów, bo potrzebne są pobocza
|
|
// ale pobocza renderują się później, więc nawierzchnia nie załapuje się na renderowanie
|
|
// w swoim czasie
|
|
// if (TextureID2)
|
|
// if (tex?TextureID2==tex:true) //jeśli pasuje do grupy (tex)
|
|
{ // pobocze drogi - poziome przy przechyłce (a może krawężnik i chodnik zrobić jak w
|
|
// Midtown Madness 2?)
|
|
if (TextureID2)
|
|
if (!tex)
|
|
glBindTexture(GL_TEXTURE_2D, TextureID2);
|
|
vector6 rpts1[6],
|
|
rpts2[6]; // współrzędne przekroju i mapowania dla prawej i lewej strony
|
|
// Ra 2014-07: trzeba to przerobić na pętlę i pobierać profile (przynajmniej 2..4) z
|
|
// sąsiednich dróg
|
|
if (fTexHeight1 >= 0.0)
|
|
{ // standardowo: od zewnątrz pochylenie, a od wewnątrz poziomo
|
|
rpts1[0] = vector6(rozp, -fTexHeight1, 0.0); // lewy brzeg podstawy
|
|
rpts1[1] = vector6(bpts1[0].x + side, bpts1[0].y, 0.5); // lewa krawędź
|
|
// załamania
|
|
rpts1[2] = vector6(bpts1[0].x, bpts1[0].y,
|
|
1.0); // lewy brzeg pobocza (mapowanie może być inne
|
|
rpts2[0] = vector6(bpts1[1].x, bpts1[1].y, 1.0); // prawy brzeg pobocza
|
|
rpts2[1] =
|
|
vector6(bpts1[1].x - side, bpts1[1].y, 0.5); // prawa krawędź załamania
|
|
rpts2[2] = vector6(-rozp, -fTexHeight1, 0.0); // prawy brzeg podstawy
|
|
// if (iTrapezoid) //trapez albo przechyłki
|
|
{ // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony
|
|
// odcinka
|
|
rpts1[3] = vector6(rozp2, -fTexHeight2, 0.0); // lewy brzeg lewego pobocza
|
|
rpts1[4] = vector6(bpts1[2].x + side2, bpts1[2].y, 0.5); // krawędź
|
|
// załamania
|
|
rpts1[5] = vector6(bpts1[2].x, bpts1[2].y, 1.0); // brzeg pobocza
|
|
rpts2[3] = vector6(bpts1[3].x, bpts1[3].y, 1.0);
|
|
rpts2[4] = vector6(bpts1[3].x - side2, bpts1[3].y, 0.5);
|
|
rpts2[5] = vector6(-rozp2, -fTexHeight2, 0.0); // prawy brzeg prawego
|
|
// pobocza
|
|
}
|
|
}
|
|
else
|
|
{ // wersja dla chodnika: skos 1:3.75, każdy chodnik innej szerokości
|
|
// mapowanie propocjonalne do szerokości chodnika
|
|
// krawężnik jest mapowany od 31/64 do 32/64 lewy i od 32/64 do 33/64 prawy
|
|
double d =
|
|
-fTexHeight1 / 3.75; // krawężnik o wysokości 150mm jest pochylony 40mm
|
|
double max =
|
|
fTexRatio2 * fTexLength; // test: szerokość proporcjonalna do długości
|
|
double map1l = max > 0.0 ?
|
|
side / max :
|
|
0.484375; // obcięcie tekstury od lewej strony punktu 1
|
|
double map1r = max > 0.0 ?
|
|
slop / max :
|
|
0.484375; // obcięcie tekstury od prawej strony punktu 1
|
|
rpts1[0] = vector6(bpts1[0].x + slop, bpts1[0].y - fTexHeight1,
|
|
0.515625 + map1r); // prawy brzeg prawego chodnika
|
|
rpts1[1] = vector6(bpts1[0].x + d, bpts1[0].y - fTexHeight1,
|
|
0.515625); // prawy krawężnik u góry
|
|
rpts1[2] = vector6(bpts1[0].x, bpts1[0].y,
|
|
0.515625 - d / 2.56); // prawy krawężnik u dołu
|
|
rpts2[0] = vector6(bpts1[1].x, bpts1[1].y,
|
|
0.484375 + d / 2.56); // lewy krawężnik u dołu
|
|
rpts2[1] = vector6(bpts1[1].x - d, bpts1[1].y - fTexHeight1,
|
|
0.484375); // lewy krawężnik u góry
|
|
rpts2[2] = vector6(bpts1[1].x - side, bpts1[1].y - fTexHeight1,
|
|
0.484375 - map1l); // lewy brzeg lewego chodnika
|
|
// if (iTrapezoid) //trapez albo przechyłki
|
|
{ // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony
|
|
// odcinka
|
|
slop2 =
|
|
fabs((iTrapezoid & 2) ? slop2 : slop); // szerokość chodnika po prawej
|
|
double map2l = max > 0.0 ?
|
|
side2 / max :
|
|
0.484375; // obcięcie tekstury od lewej strony punktu 2
|
|
double map2r = max > 0.0 ?
|
|
slop2 / max :
|
|
0.484375; // obcięcie tekstury od prawej strony punktu 2
|
|
rpts1[3] = vector6(bpts1[2].x + slop2, bpts1[2].y - fTexHeight2,
|
|
0.515625 + map2r); // prawy brzeg prawego chodnika
|
|
rpts1[4] = vector6(bpts1[2].x + d, bpts1[2].y - fTexHeight2,
|
|
0.515625); // prawy krawężnik u góry
|
|
rpts1[5] = vector6(bpts1[2].x, bpts1[2].y,
|
|
0.515625 - d / 2.56); // prawy krawężnik u dołu
|
|
rpts2[3] = vector6(bpts1[3].x, bpts1[3].y,
|
|
0.484375 + d / 2.56); // lewy krawężnik u dołu
|
|
rpts2[4] = vector6(bpts1[3].x - d, bpts1[3].y - fTexHeight2,
|
|
0.484375); // lewy krawężnik u góry
|
|
rpts2[5] = vector6(bpts1[3].x - side2, bpts1[3].y - fTexHeight2,
|
|
0.484375 - map2l); // lewy brzeg lewego chodnika
|
|
}
|
|
}
|
|
bool render = TextureID2 ? (tex ? TextureID2 == tex : true) :
|
|
false; // renderować nie trzeba, ale trzeba wyznaczyć
|
|
// punkty brzegowe nawierzchni
|
|
// if (iTrapezoid) //trapez albo przechyłki
|
|
if (SwitchExtension->iRoads == 4)
|
|
{ // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony odcinka
|
|
if ((fTexHeight1 >= 0.0) ? true : (side != 0.0))
|
|
SwitchExtension->Segments[2]->RenderLoft(
|
|
rpts2, -3, fTexLength, 0, 1, &b, render); // tylko jeśli jest z lewej
|
|
if ((fTexHeight1 >= 0.0) ? true : (side != 0.0))
|
|
SwitchExtension->Segments[3]->RenderLoft(
|
|
rpts2, -3, fTexLength, 0, 1, &b, render); // tylko jeśli jest z lewej
|
|
if ((fTexHeight1 >= 0.0) ? true : (side != 0.0))
|
|
SwitchExtension->Segments[4]->RenderLoft(
|
|
rpts2, -3, fTexLength, 0, 1, &b, render); // tylko jeśli jest z lewej
|
|
if ((fTexHeight1 >= 0.0) ? true : (side != 0.0))
|
|
SwitchExtension->Segments[5]->RenderLoft(
|
|
rpts2, -3, fTexLength, 0, 1, &b, render); // tylko jeśli jest z lewej
|
|
}
|
|
else // to będzie ewentualnie dla prostego na skrzyżowaniu trzech dróg
|
|
{ // punkt 3 pokrywa się z punktem 1, jak w zwrotnicy; połączenie 1->2 nie musi być
|
|
// prostoliniowe
|
|
if ((fTexHeight1 >= 0.0) ? true : (side != 0.0)) // OK
|
|
SwitchExtension->Segments[2]->RenderLoft(rpts2, -3, fTexLength, 0, 1, &b,
|
|
render); // z P2 do P4
|
|
if ((fTexHeight1 >= 0.0) ? true : (side != 0.0)) // OK
|
|
SwitchExtension->Segments[1]->RenderLoft(
|
|
rpts2, -3, fTexLength, 0, 1, &b, render); // z P4 do P3=P1 (odwrócony)
|
|
if ((fTexHeight1 >= 0.0) ? true : (side != 0.0)) // OK
|
|
SwitchExtension->Segments[0]->RenderLoft(rpts2, -3, fTexLength, 0, 1, &b,
|
|
render); // z P1 do P2
|
|
/*
|
|
if ((fTexHeight1>=0.0)?true:(slop!=0.0))
|
|
Segment->RenderLoft(rpts1,3,fTexLength);
|
|
if ((fTexHeight1>=0.0)?true:(side!=0.0))
|
|
Segment->RenderLoft(rpts2,3,fTexLength);
|
|
*/
|
|
}
|
|
}
|
|
// renderowanie nawierzchni na końcu
|
|
double sina0 = sin(a[0]), cosa0 = cos(a[0]);
|
|
double u, v;
|
|
if (!SwitchExtension->bPoints) // jeśli tablica nie wypełniona
|
|
if (b) // ale jest wskaźnik do tablicy - może nie być?
|
|
{ // coś się gubi w obliczeniach na wskaźnikach
|
|
i = (int((void *)(b)) - int((void *)(SwitchExtension->vPoints))) /
|
|
sizeof(vector3); // ustalenie liczby punktów, bo mogło wyjść inaczej niż
|
|
// policzone z góry
|
|
if (i > 0)
|
|
{ // jeśli zostało to właśnie utworzone
|
|
if (SwitchExtension->iPoints > i) // jeśli wyszło mniej niż było miejsca
|
|
SwitchExtension->iPoints = i; // domknięcie wachlarza
|
|
else
|
|
--SwitchExtension->iPoints; // jak tutaj wejdzie, to błąd jest - zrobić
|
|
// miejsce na powtórzenie pierwszego punktu
|
|
// na końcu
|
|
SwitchExtension->vPoints[SwitchExtension->iPoints++] =
|
|
SwitchExtension->vPoints[0];
|
|
SwitchExtension->bPoints = true; // tablica punktów została wypełniona
|
|
}
|
|
}
|
|
if (TextureID1) // jeśli podana tekstura nawierzchni
|
|
if (tex ? TextureID1 == tex : true) // jeśli pasuje do grupy (tex)
|
|
{
|
|
if (!tex)
|
|
glBindTexture(GL_TEXTURE_2D, TextureID1);
|
|
glBegin(GL_TRIANGLE_FAN); // takie kółeczko będzie
|
|
glNormal3f(0, 1, 0);
|
|
glTexCoord2f(0.5, 0.5); //środek tekstury na środku skrzyżowania
|
|
glVertex3f(oxz.x, oxz.y, oxz.z);
|
|
for (i = SwitchExtension->iPoints - 1; i >= 0; --i)
|
|
// for (i=0;i<SwitchExtension->iPoints;++i)
|
|
{
|
|
glNormal3f(0, 1, 0);
|
|
u = (SwitchExtension->vPoints[i].x - oxz.x) /
|
|
fTexLength; // mapowanie we współrzędnych scenerii
|
|
v = (SwitchExtension->vPoints[i].z - oxz.z) / (fTexRatio1 * fTexLength);
|
|
glTexCoord2f(cosa0 * u + sina0 * v + 0.5, -sina0 * u + cosa0 * v + 0.5);
|
|
glVertex3f(SwitchExtension->vPoints[i].x, SwitchExtension->vPoints[i].y,
|
|
SwitchExtension->vPoints[i].z);
|
|
}
|
|
glEnd();
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case 4: // McZapkie-260302 - rzeka- rendering
|
|
// Ra: rzeki na razie bez zmian, przechyłki na pewno nie mają
|
|
// Ra: przemyśleć wyrównanie u góry trawą do czworoboku
|
|
vector6 bpts1[numPts] = {vector6(fHTW, 0.0, 0.0), vector6(fHTW, 0.2, 0.33),
|
|
vector6(-fHTW, 0.0, 0.67), vector6(-fHTW, 0.0, 1.0)};
|
|
// Ra: dziwnie ten kształt wygląda
|
|
if (TextureID1)
|
|
if (tex ? TextureID1 == tex : true) // jeśli pasuje do grupy (tex)
|
|
{
|
|
if (!tex)
|
|
glBindTexture(GL_TEXTURE_2D, TextureID1);
|
|
Segment->RenderLoft(bpts1, numPts, fTexLength);
|
|
}
|
|
if (TextureID2)
|
|
if (tex ? TextureID2 == tex : true) // jeśli pasuje do grupy (tex)
|
|
{ // brzegi rzeki prawie jak pobocze derogi, tylko inny znak ma wysokość
|
|
// znak jest zmieniany przy wczytywaniu, więc tu musi byc minus fTexHeight
|
|
vector6 rpts1[3] = {vector6(rozp, -fTexHeight1, 0.0),
|
|
vector6(fHTW + side, 0.0, 0.5), vector6(fHTW, 0.0, 1.0)};
|
|
vector6 rpts2[3] = {vector6(-fHTW, 0.0, 1.0), vector6(-fHTW - side, 0.0, 0.5),
|
|
vector6(-rozp, -fTexHeight1, 0.0)}; // Ra: po kiego 0.1?
|
|
if (!tex)
|
|
glBindTexture(GL_TEXTURE_2D, TextureID2); // brzeg rzeki
|
|
Segment->RenderLoft(rpts1, 3, fTexLength);
|
|
Segment->RenderLoft(rpts2, 3, fTexLength);
|
|
}
|
|
break;
|
|
}
|
|
if (!tex)
|
|
if (Global::bManageNodes)
|
|
glEndList();
|
|
};
|
|
|
|
void TTrack::Release()
|
|
{
|
|
if (DisplayListID)
|
|
glDeleteLists(DisplayListID, 1);
|
|
DisplayListID = 0;
|
|
};
|
|
|
|
void TTrack::Render()
|
|
{
|
|
if (bVisible) // Ra: tory są renderowane sektorami i nie ma sensu każdorazowo liczyć odległości
|
|
{
|
|
if (!DisplayListID)
|
|
{
|
|
Compile();
|
|
if (Global::bManageNodes)
|
|
ResourceManager::Register(this);
|
|
};
|
|
SetLastUsage(Timer::GetSimulationTime());
|
|
EnvironmentSet(); // oświetlenie nie może być skompilowane, bo może się zmieniać z czasem
|
|
glCallList(DisplayListID);
|
|
EnvironmentReset(); // ustawienie oświetlenia na zwykłe
|
|
if (InMovement())
|
|
Release(); // zwrotnica w trakcie animacji do odrysowania
|
|
};
|
|
//#ifdef _DEBUG
|
|
#if 0
|
|
if (DebugModeFlag && ScannedFlag) //McZapkie-230702
|
|
//if (iNumDynamics) //będzie kreska na zajętym torze
|
|
{
|
|
vector3 pos1,pos2,pos3;
|
|
glDisable(GL_DEPTH_TEST);
|
|
glDisable(GL_LIGHTING);
|
|
glColor3ub(255,0,0);
|
|
glBindTexture(GL_TEXTURE_2D,0);
|
|
glBegin(GL_LINE_STRIP);
|
|
pos1=Segment->FastGetPoint_0();
|
|
pos2=Segment->FastGetPoint(0.5);
|
|
pos3=Segment->FastGetPoint_1();
|
|
glVertex3f(pos1.x,pos1.y,pos1.z);
|
|
glVertex3f(pos2.x,pos2.y+10,pos2.z);
|
|
glVertex3f(pos3.x,pos3.y,pos3.z);
|
|
glEnd();
|
|
glEnable(GL_LIGHTING);
|
|
glEnable(GL_DEPTH_TEST);
|
|
ScannedFlag=false;
|
|
}
|
|
#endif
|
|
// glLightfv(GL_LIGHT0,GL_AMBIENT,Global::ambientDayLight);
|
|
// glLightfv(GL_LIGHT0,GL_DIFFUSE,Global::diffuseDayLight);
|
|
// glLightfv(GL_LIGHT0,GL_SPECULAR,Global::specularDayLight);
|
|
};
|
|
|
|
bool TTrack::CheckDynamicObject(TDynamicObject *Dynamic)
|
|
{ // sprawdzenie, czy pojazd jest przypisany do toru
|
|
for (int i = 0; i < iNumDynamics; i++)
|
|
if (Dynamic == Dynamics[i])
|
|
return true;
|
|
return false;
|
|
};
|
|
|
|
bool TTrack::RemoveDynamicObject(TDynamicObject *Dynamic)
|
|
{ // usunięcie pojazdu z listy przypisanych do toru
|
|
for (int i = 0; i < iNumDynamics; i++)
|
|
{ // sprawdzanie wszystkich po kolei
|
|
if (Dynamic == Dynamics[i])
|
|
{ // znaleziony, przepisanie następnych, żeby dziur nie było
|
|
--iNumDynamics;
|
|
for (i; i < iNumDynamics; i++)
|
|
Dynamics[i] = Dynamics[i + 1];
|
|
if (Global::iMultiplayer) // jeśli multiplayer
|
|
if (!iNumDynamics) // jeśli już nie ma żadnego
|
|
if (pMyNode->asName != "none")
|
|
Global::pGround->WyslijString(
|
|
pMyNode->asName, 9); // przekazanie informacji o zwolnieniu toru
|
|
return true;
|
|
}
|
|
}
|
|
Error("Cannot remove dynamic from track");
|
|
return false;
|
|
}
|
|
|
|
bool TTrack::InMovement()
|
|
{ // tory animowane (zwrotnica, obrotnica) mają SwitchExtension
|
|
if (SwitchExtension)
|
|
{
|
|
if (eType == tt_Switch)
|
|
return SwitchExtension->bMovement; // ze zwrotnicą łatwiej
|
|
if (eType == tt_Table)
|
|
if (SwitchExtension->pModel)
|
|
{
|
|
if (!SwitchExtension->CurrentIndex)
|
|
return false; // 0=zablokowana się nie animuje
|
|
// trzeba każdorazowo porównywać z kątem modelu
|
|
TAnimContainer *ac =
|
|
SwitchExtension->pModel ? SwitchExtension->pModel->GetContainer(NULL) : NULL;
|
|
return ac ?
|
|
(ac->AngleGet() != SwitchExtension->fOffset) ||
|
|
!(ac->TransGet() == SwitchExtension->vTrans) :
|
|
false;
|
|
// return true; //jeśli jest taki obiekt
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
void TTrack::RaAssign(TGroundNode *gn, TAnimContainer *ac){
|
|
// Ra: wiązanie toru z modelem obrotnicy
|
|
// if (eType==tt_Table) SwitchExtension->pAnim=p;
|
|
};
|
|
void TTrack::RaAssign(TGroundNode *gn, TAnimModel *am, TEvent *done, TEvent *joined)
|
|
{ // Ra: wiązanie toru z modelem obrotnicy
|
|
if (eType == tt_Table)
|
|
{
|
|
SwitchExtension->pModel = am;
|
|
SwitchExtension->pMyNode = gn;
|
|
SwitchExtension->evMinus = done; // event zakończenia animacji (zadanie nowej przedłuża)
|
|
SwitchExtension->evPlus =
|
|
joined; // event potwierdzenia połączenia (gdy nie znajdzie, to się nie połączy)
|
|
if (am)
|
|
if (am->GetContainer(NULL)) // może nie być?
|
|
am->GetContainer(NULL)->EventAssign(done); // zdarzenie zakończenia animacji
|
|
}
|
|
};
|
|
|
|
int TTrack::RaArrayPrepare()
|
|
{ // przygotowanie tablic do skopiowania do VBO (zliczanie wierzchołków)
|
|
if (bVisible) // o ile w ogóle widać
|
|
switch (iCategoryFlag & 15)
|
|
{
|
|
case 1: // tor
|
|
if (eType == tt_Switch) // dla zwrotnicy tylko szyny
|
|
return 48 * ((TextureID1 ? SwitchExtension->Segments[0]->RaSegCount() : 0) +
|
|
(TextureID2 ? SwitchExtension->Segments[1]->RaSegCount() : 0));
|
|
else // dla toru podsypka plus szyny
|
|
return (Segment->RaSegCount()) * ((TextureID1 ? 48 : 0) + (TextureID2 ? 8 : 0));
|
|
case 2: // droga
|
|
if (eType == tt_Cross) // tylko dla skrzyżowania dróg
|
|
{ // specjalny sposób obliczania liczby wierzchołków w skrzyżowaniu
|
|
// int n=0; //wierzchołki wewnętrzne do generowania nawierzchni
|
|
// int b=0; //wierzchołki do generowania boków
|
|
if (fTexHeight1 >= 0) // jeśli fTexHeight1<0, to są chodniki i może któregoś nie być
|
|
{ // normalne pobocze, na razie się składa z
|
|
return (Segment->RaSegCount()) * ((TextureID1 ? 4 : 0) + (TextureID2 ? 12 : 0));
|
|
}
|
|
else
|
|
return (Segment->RaSegCount()) *
|
|
((TextureID1 ? 4 : 0) +
|
|
(TextureID2 ? (fTexWidth != 0.0 ? 6 : 0) + (fTexSlope != 0.0 ? 6 : 0) :
|
|
0));
|
|
}
|
|
else // standardowo dla zwykłej drogi
|
|
if (fTexHeight1 >= 0) // jeśli fTexHeight1<0, to są chodniki i może któregoś nie być
|
|
return (Segment->RaSegCount()) *
|
|
((TextureID1 ? 4 : 0) + (TextureID2 ? 12 : 0)); // może nie być poziomego!
|
|
else
|
|
return (Segment->RaSegCount()) *
|
|
((TextureID1 ? 4 : 0) +
|
|
(TextureID2 ? (fTexWidth != 0.0 ? 6 : 0) + (fTexSlope != 0.0 ? 6 : 0) : 0));
|
|
case 4: // rzeki do przemyślenia
|
|
return (Segment->RaSegCount()) * ((TextureID1 ? 4 : 0) + (TextureID2 ? 12 : 0));
|
|
}
|
|
return 0;
|
|
};
|
|
|
|
void TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start)
|
|
{ // wypełnianie tablic VBO
|
|
// Ra: trzeba rozdzielić szyny od podsypki, aby móc grupować wg tekstur
|
|
double fHTW = 0.5 * fabs(fTrackWidth);
|
|
double side = fabs(fTexWidth); // szerokść podsypki na zewnątrz szyny albo pobocza
|
|
double slop = fabs(fTexSlope); // brzeg zewnętrzny
|
|
double rozp = fHTW + side + slop; // brzeg zewnętrzny
|
|
double hypot1 = hypot(slop, fTexHeight1); // rozmiar pochylenia do liczenia normalnych
|
|
if (hypot1 == 0.0)
|
|
hypot1 = 1.0;
|
|
vector3 normal1 = vector3(fTexSlope / hypot1, fTexHeight1 / hypot1, 0.0); // wektor normalny
|
|
double fHTW2, side2, slop2, rozp2, fTexHeight2, hypot2;
|
|
vector3 normal2;
|
|
if (iTrapezoid & 2) // ten bit oznacza, że istnieje odpowiednie pNext
|
|
{ // Ra: jest OK
|
|
fHTW2 = 0.5 * fabs(trNext->fTrackWidth); // połowa rozstawu/nawierzchni
|
|
side2 = fabs(trNext->fTexWidth);
|
|
slop2 = fabs(trNext->fTexSlope); // nie jest używane później
|
|
rozp2 = fHTW2 + side2 + slop2;
|
|
fTexHeight2 = trNext->fTexHeight1;
|
|
hypot2 = hypot(slop2, fTexHeight2);
|
|
if (hypot2 == 0.0)
|
|
hypot2 = 1.0;
|
|
normal2 = vector3(trNext->fTexSlope / hypot2, fTexHeight2 / hypot2, 0.0);
|
|
}
|
|
else // gdy nie ma następnego albo jest nieodpowiednim końcem podpięty
|
|
{
|
|
fHTW2 = fHTW;
|
|
side2 = side;
|
|
slop2 = slop;
|
|
rozp2 = rozp;
|
|
fTexHeight2 = fTexHeight1;
|
|
hypot2 = hypot1;
|
|
normal2 = normal1;
|
|
}
|
|
double roll1, roll2;
|
|
switch (iCategoryFlag & 15)
|
|
{
|
|
case 1: // tor
|
|
{
|
|
if (Segment)
|
|
Segment->GetRolls(roll1, roll2);
|
|
else
|
|
roll1 = roll2 = 0.0; // dla zwrotnic
|
|
double sin1 = sin(roll1), cos1 = cos(roll1), sin2 = sin(roll2), cos2 = cos(roll2);
|
|
// zwykla szyna: //Ra: czemu główki są asymetryczne na wysokości 0.140?
|
|
vector6 rpts1[24], rpts2[24], rpts3[24], rpts4[24];
|
|
int i;
|
|
for (i = 0; i < 12; ++i)
|
|
{
|
|
rpts1[i] = vector6((fHTW + szyna[i].x) * cos1 + szyna[i].y * sin1,
|
|
-(fHTW + szyna[i].x) * sin1 + szyna[i].y * cos1, szyna[i].z,
|
|
+szyna[i].n.x * cos1 + szyna[i].n.y * sin1,
|
|
-szyna[i].n.x * sin1 + szyna[i].n.y * cos1, 0.0);
|
|
rpts2[11 - i] = vector6((-fHTW - szyna[i].x) * cos1 + szyna[i].y * sin1,
|
|
-(-fHTW - szyna[i].x) * sin1 + szyna[i].y * cos1, szyna[i].z,
|
|
-szyna[i].n.x * cos1 + szyna[i].n.y * sin1,
|
|
+szyna[i].n.x * sin1 + szyna[i].n.y * cos1, 0.0);
|
|
}
|
|
if (iTrapezoid) // trapez albo przechyłki, to oddzielne punkty na końcu
|
|
for (i = 0; i < 12; ++i)
|
|
{
|
|
rpts1[12 + i] = vector6((fHTW2 + szyna[i].x) * cos2 + szyna[i].y * sin2,
|
|
-(fHTW2 + szyna[i].x) * sin2 + szyna[i].y * cos2,
|
|
szyna[i].z, +szyna[i].n.x * cos2 + szyna[i].n.y * sin2,
|
|
-szyna[i].n.x * sin2 + szyna[i].n.y * cos2, 0.0);
|
|
rpts2[23 - i] = vector6((-fHTW2 - szyna[i].x) * cos2 + szyna[i].y * sin2,
|
|
-(-fHTW2 - szyna[i].x) * sin2 + szyna[i].y * cos2,
|
|
szyna[i].z, -szyna[i].n.x * cos2 + szyna[i].n.y * sin2,
|
|
+szyna[i].n.x * sin2 + szyna[i].n.y * cos2, 0.0);
|
|
}
|
|
switch (eType) // dalej zależnie od typu
|
|
{
|
|
case tt_Table: // obrotnica jak zwykły tor, tylko animacja dochodzi
|
|
SwitchExtension->iLeftVBO = Vert - Start; // indeks toru obrotnicy
|
|
case tt_Normal:
|
|
if (TextureID2)
|
|
{ // podsypka z podkładami jest tylko dla zwykłego toru
|
|
vector6 bpts1[8]; // punkty głównej płaszczyzny nie przydają się do robienia boków
|
|
if (fTexLength == 4.0) // jeśli stare mapowanie
|
|
{ // stare mapowanie z różną gęstością pikseli i oddzielnymi teksturami na każdy
|
|
// profil
|
|
if (iTrapezoid) // trapez albo przechyłki
|
|
{ // podsypka z podkladami trapezowata
|
|
// ewentualnie poprawić mapowanie, żeby środek mapował się na 1.435/4.671
|
|
// ((0.3464,0.6536)
|
|
// bo się tekstury podsypki rozjeżdżają po zmianie proporcji profilu
|
|
bpts1[0] = vector6(rozp, -fTexHeight1 - 0.18, 0.00, -0.707, 0.707,
|
|
0.0); // lewy brzeg
|
|
bpts1[1] = vector6((fHTW + side) * cos1, -(fHTW + side) * sin1 - 0.18, 0.33,
|
|
-0.707, 0.707, 0.0); // krawędź załamania
|
|
bpts1[2] = vector6(-bpts1[1].x, +(fHTW + side) * sin1 - 0.18, 0.67, 0.707,
|
|
0.707, 0.0); // prawy brzeg początku symetrycznie
|
|
bpts1[3] = vector6(-rozp, -fTexHeight1 - 0.18, 1.00, 0.707, 0.707,
|
|
0.0); // prawy skos
|
|
// końcowy przekrój
|
|
bpts1[4] = vector6(rozp2, -fTexHeight2 - 0.18, 0.00, -0.707, 0.707,
|
|
0.0); // lewy brzeg
|
|
bpts1[5] = vector6((fHTW2 + side2) * cos2, -(fHTW2 + side2) * sin2 - 0.18,
|
|
0.33, -0.707, 0.707, 0.0); // krawędź załamania
|
|
bpts1[6] = vector6(-bpts1[5].x, +(fHTW2 + side2) * sin2 - 0.18, 0.67, 0.707,
|
|
0.707, 0.0); // prawy brzeg początku symetrycznie
|
|
bpts1[7] = vector6(-rozp2, -fTexHeight2 - 0.18, 1.00, 0.707, 0.707,
|
|
0.0); // prawy skos
|
|
}
|
|
else
|
|
{
|
|
bpts1[0] = vector6(rozp, -fTexHeight1 - 0.18, 0.0, -0.707, 0.707,
|
|
0.0); // lewy brzeg
|
|
bpts1[1] = vector6(fHTW + side, -0.18, 0.33, -0.707, 0.707,
|
|
0.0); // krawędź załamania
|
|
bpts1[2] = vector6(-fHTW - side, -0.18, 0.67, 0.707, 0.707, 0.0); // druga
|
|
bpts1[3] = vector6(-rozp, -fTexHeight1 - 0.18, 1.0, 0.707, 0.707,
|
|
0.0); // prawy skos
|
|
}
|
|
}
|
|
else
|
|
{ // mapowanie proporcjonalne do powierzchni, rozmiar w poprzek określa fTexLength
|
|
double max = fTexRatio2 * fTexLength; // szerokość proporcjonalna do długości
|
|
double map11 = max > 0.0 ? (fHTW + side) / max : 0.25; // załamanie od strony 1
|
|
double map12 =
|
|
max > 0.0 ? (fHTW + side + hypot1) / max : 0.5; // brzeg od strony 1
|
|
if (iTrapezoid) // trapez albo przechyłki
|
|
{ // podsypka z podkladami trapezowata
|
|
double map21 =
|
|
max > 0.0 ? (fHTW2 + side2) / max : 0.25; // załamanie od strony 2
|
|
double map22 =
|
|
max > 0.0 ? (fHTW2 + side2 + hypot2) / max : 0.5; // brzeg od strony 2
|
|
// ewentualnie poprawić mapowanie, żeby środek mapował się na 1.435/4.671
|
|
// ((0.3464,0.6536)
|
|
// bo się tekstury podsypki rozjeżdżają po zmianie proporcji profilu
|
|
bpts1[0] = vector6(rozp, -fTexHeight1 - 0.18, 0.5 - map12, normal1.x,
|
|
-normal1.y, 0.0); // lewy brzeg
|
|
bpts1[1] = vector6((fHTW + side) * cos1, -(fHTW + side) * sin1 - 0.18,
|
|
0.5 - map11, 0.0, 1.0, 0.0); // krawędź załamania
|
|
bpts1[2] = vector6(-bpts1[1].x, +(fHTW + side) * sin1 - 0.18, 0.5 + map11,
|
|
0.0, 1.0, 0.0); // prawy brzeg początku symetrycznie
|
|
bpts1[3] = vector6(-rozp, -fTexHeight1 - 0.18, 0.5 + map12, -normal1.x,
|
|
-normal1.y, 0.0); // prawy skos
|
|
// przekrój końcowy
|
|
bpts1[4] = vector6(rozp2, -fTexHeight2 - 0.18, 0.5 - map22, normal2.x,
|
|
-normal2.y, 0.0); // lewy brzeg
|
|
bpts1[5] = vector6((fHTW2 + side2) * cos2, -(fHTW2 + side2) * sin2 - 0.18,
|
|
0.5 - map21, 0.0, 1.0, 0.0); // krawędź załamania
|
|
bpts1[6] = vector6(-bpts1[5].x, +(fHTW2 + side2) * sin2 - 0.18, 0.5 + map21,
|
|
0.0, 1.0, 0.0); // prawy brzeg początku symetrycznie
|
|
bpts1[7] = vector6(-rozp2, -fTexHeight2 - 0.18, 0.5 + map22, -normal2.x,
|
|
-normal2.y, 0.0); // prawy skos
|
|
}
|
|
else
|
|
{
|
|
bpts1[0] = vector6(rozp, -fTexHeight1 - 0.18, 0.5 - map12, +normal1.x,
|
|
-normal1.y, 0.0); // lewy brzeg
|
|
bpts1[1] = vector6(fHTW + side, -0.18, 0.5 - map11, +normal1.x, -normal1.y,
|
|
0.0); // krawędź załamania
|
|
bpts1[2] = vector6(-fHTW - side, -0.18, 0.5 + map11, -normal1.x, -normal1.y,
|
|
0.0); // druga
|
|
bpts1[3] = vector6(-rozp, -fTexHeight1 - 0.18, 0.5 + map12, -normal1.x,
|
|
-normal1.y, 0.0); // prawy skos
|
|
}
|
|
}
|
|
Segment->RaRenderLoft(Vert, bpts1, iTrapezoid ? -4 : 4, fTexLength);
|
|
}
|
|
if (TextureID1)
|
|
{ // szyny - generujemy dwie, najwyżej rysować się będzie jedną
|
|
Segment->RaRenderLoft(Vert, rpts1, iTrapezoid ? -nnumPts : nnumPts, fTexLength);
|
|
Segment->RaRenderLoft(Vert, rpts2, iTrapezoid ? -nnumPts : nnumPts, fTexLength);
|
|
}
|
|
break;
|
|
case tt_Switch: // dla zwrotnicy dwa razy szyny
|
|
if (TextureID1) // Ra: !!!! tu jest do poprawienia
|
|
{ // iglice liczone tylko dla zwrotnic
|
|
vector6 rpts3[24], rpts4[24];
|
|
for (i = 0; i < 12; ++i)
|
|
{
|
|
rpts3[i] =
|
|
vector6(+(fHTW + iglica[i].x) * cos1 + iglica[i].y * sin1,
|
|
-(+fHTW + iglica[i].x) * sin1 + iglica[i].y * cos1, iglica[i].z);
|
|
rpts3[i + 12] =
|
|
vector6(+(fHTW2 + szyna[i].x) * cos2 + szyna[i].y * sin2,
|
|
-(+fHTW2 + szyna[i].x) * sin2 + iglica[i].y * cos2, szyna[i].z);
|
|
rpts4[11 - i] =
|
|
vector6((-fHTW - iglica[i].x) * cos1 + iglica[i].y * sin1,
|
|
-(-fHTW - iglica[i].x) * sin1 + iglica[i].y * cos1, iglica[i].z);
|
|
rpts4[23 - i] =
|
|
vector6((-fHTW2 - szyna[i].x) * cos2 + szyna[i].y * sin2,
|
|
-(-fHTW2 - szyna[i].x) * sin2 + iglica[i].y * cos2, szyna[i].z);
|
|
}
|
|
if (SwitchExtension->RightSwitch)
|
|
{ // nowa wersja z SPKS, ale odwrotnie lewa/prawa
|
|
SwitchExtension->iLeftVBO = Vert - Start; // indeks lewej iglicy
|
|
SwitchExtension->Segments[0]->RaRenderLoft(Vert, rpts3, -nnumPts, fTexLength, 0,
|
|
2, SwitchExtension->fOffset2);
|
|
SwitchExtension->Segments[0]->RaRenderLoft(Vert, rpts1, nnumPts, fTexLength, 2);
|
|
SwitchExtension->Segments[0]->RaRenderLoft(Vert, rpts2, nnumPts, fTexLength);
|
|
SwitchExtension->Segments[1]->RaRenderLoft(Vert, rpts1, nnumPts, fTexLength);
|
|
SwitchExtension->iRightVBO = Vert - Start; // indeks prawej iglicy
|
|
SwitchExtension->Segments[1]->RaRenderLoft(Vert, rpts4, -nnumPts, fTexLength, 0,
|
|
2, -fMaxOffset +
|
|
SwitchExtension->fOffset1);
|
|
SwitchExtension->Segments[1]->RaRenderLoft(Vert, rpts2, nnumPts, fTexLength, 2);
|
|
}
|
|
else
|
|
{ // lewa działa lepiej niż prawa
|
|
SwitchExtension->Segments[0]->RaRenderLoft(
|
|
Vert, rpts1, nnumPts, fTexLength); // lewa szyna normalna cała
|
|
SwitchExtension->iLeftVBO = Vert - Start; // indeks lewej iglicy
|
|
SwitchExtension->Segments[0]->RaRenderLoft(
|
|
Vert, rpts4, -nnumPts, fTexLength, 0, 2,
|
|
-SwitchExtension->fOffset2); // prawa iglica
|
|
SwitchExtension->Segments[0]->RaRenderLoft(Vert, rpts2, nnumPts, fTexLength,
|
|
2); // prawa szyna za iglicą
|
|
SwitchExtension->iRightVBO = Vert - Start; // indeks prawej iglicy
|
|
SwitchExtension->Segments[1]->RaRenderLoft(
|
|
Vert, rpts3, -nnumPts, fTexLength, 0, 2,
|
|
fMaxOffset - SwitchExtension->fOffset1); // lewa iglica
|
|
SwitchExtension->Segments[1]->RaRenderLoft(Vert, rpts1, nnumPts, fTexLength,
|
|
2); // lewa szyna za iglicą
|
|
SwitchExtension->Segments[1]->RaRenderLoft(
|
|
Vert, rpts2, nnumPts, fTexLength); // prawa szyna normalnie cała
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
} // koniec obsługi torów
|
|
break;
|
|
case 2: // McZapkie-260302 - droga - rendering
|
|
switch (eType) // dalej zależnie od typu
|
|
{
|
|
case tt_Normal: // drogi proste, bo skrzyżowania osobno
|
|
{
|
|
vector6 bpts1[4]; // punkty głównej płaszczyzny przydają się do robienia boków
|
|
if (TextureID1 || TextureID2) // punkty się przydadzą, nawet jeśli nawierzchni nie ma
|
|
{ // double max=2.0*(fHTW>fHTW2?fHTW:fHTW2); //z szerszej strony jest 100%
|
|
double max = (iCategoryFlag & 4) ?
|
|
0.0 :
|
|
fTexLength; // test: szerokość dróg proporcjonalna do długości
|
|
double map1 = max > 0.0 ? fHTW / max : 0.5; // obcięcie tekstury od strony 1
|
|
double map2 = max > 0.0 ? fHTW2 / max : 0.5; // obcięcie tekstury od strony 2
|
|
if (iTrapezoid) // trapez albo przechyłki
|
|
{ // nawierzchnia trapezowata
|
|
Segment->GetRolls(roll1, roll2);
|
|
bpts1[0] = vector6(fHTW * cos(roll1), -fHTW * sin(roll1),
|
|
0.5 - map1); // lewy brzeg początku
|
|
bpts1[1] = vector6(-bpts1[0].x, -bpts1[0].y,
|
|
0.5 + map1); // prawy brzeg początku symetrycznie
|
|
bpts1[2] = vector6(fHTW2 * cos(roll2), -fHTW2 * sin(roll2),
|
|
0.5 - map2); // lewy brzeg końca
|
|
bpts1[3] = vector6(-bpts1[2].x, -bpts1[2].y,
|
|
0.5 + map2); // prawy brzeg początku symetrycznie
|
|
}
|
|
else
|
|
{
|
|
bpts1[0] = vector6(fHTW, 0.0, 0.5 - map1); // zawsze standardowe mapowanie
|
|
bpts1[1] = vector6(-fHTW, 0.0, 0.5 + map1);
|
|
}
|
|
}
|
|
if (TextureID1) // jeśli podana była tekstura, generujemy trójkąty
|
|
{ // tworzenie trójkątów nawierzchni szosy
|
|
Segment->RaRenderLoft(Vert, bpts1, iTrapezoid ? -2 : 2, fTexLength);
|
|
}
|
|
if (TextureID2)
|
|
{ // pobocze drogi - poziome przy przechyłce (a może krawężnik i chodnik zrobić jak w
|
|
// Midtown Madness 2?)
|
|
vector6 rpts1[6],
|
|
rpts2[6]; // współrzędne przekroju i mapowania dla prawej i lewej strony
|
|
if (fTexHeight1 >= 0.0)
|
|
{ // standardowo: od zewnątrz pochylenie, a od wewnątrz poziomo
|
|
rpts1[0] = vector6(rozp, -fTexHeight1, 0.0); // lewy brzeg podstawy
|
|
rpts1[1] =
|
|
vector6(bpts1[0].x + side, bpts1[0].y, 0.5), // lewa krawędź załamania
|
|
rpts1[2] = vector6(bpts1[0].x, bpts1[0].y,
|
|
1.0); // lewy brzeg pobocza (mapowanie może być inne
|
|
rpts2[0] = vector6(bpts1[1].x, bpts1[1].y, 1.0); // prawy brzeg pobocza
|
|
rpts2[1] =
|
|
vector6(bpts1[1].x - side, bpts1[1].y, 0.5); // prawa krawędź załamania
|
|
rpts2[2] = vector6(-rozp, -fTexHeight1, 0.0); // prawy brzeg podstawy
|
|
if (iTrapezoid) // trapez albo przechyłki
|
|
{ // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony
|
|
// odcinka
|
|
rpts1[3] = vector6(rozp2, -fTexHeight2, 0.0); // lewy brzeg lewego pobocza
|
|
rpts1[4] = vector6(bpts1[2].x + side2, bpts1[2].y, 0.5); // krawędź
|
|
// załamania
|
|
rpts1[5] = vector6(bpts1[2].x, bpts1[2].y, 1.0); // brzeg pobocza
|
|
rpts2[3] = vector6(bpts1[3].x, bpts1[3].y, 1.0);
|
|
rpts2[4] = vector6(bpts1[3].x - side2, bpts1[3].y, 0.5);
|
|
rpts2[5] = vector6(-rozp2, -fTexHeight2, 0.0); // prawy brzeg prawego
|
|
// pobocza
|
|
Segment->RaRenderLoft(Vert, rpts1, -3, fTexLength);
|
|
Segment->RaRenderLoft(Vert, rpts2, -3, fTexLength);
|
|
}
|
|
else
|
|
{ // pobocza zwykłe, brak przechyłki
|
|
Segment->RaRenderLoft(Vert, rpts1, 3, fTexLength);
|
|
Segment->RaRenderLoft(Vert, rpts2, 3, fTexLength);
|
|
}
|
|
}
|
|
else
|
|
{ // wersja dla chodnika: skos 1:3.75, każdy chodnik innej szerokości
|
|
// mapowanie propocjonalne do szerokości chodnika
|
|
// krawężnik jest mapowany od 31/64 do 32/64 lewy i od 32/64 do 33/64 prawy
|
|
double d =
|
|
-fTexHeight1 / 3.75; // krawężnik o wysokości 150mm jest pochylony 40mm
|
|
double max =
|
|
fTexRatio2 * fTexLength; // test: szerokość proporcjonalna do długości
|
|
double map1l = max > 0.0 ?
|
|
side / max :
|
|
0.484375; // obcięcie tekstury od lewej strony punktu 1
|
|
double map1r = max > 0.0 ?
|
|
slop / max :
|
|
0.484375; // obcięcie tekstury od prawej strony punktu 1
|
|
double h1r = (slop > d) ? -fTexHeight1 : 0;
|
|
double h1l = (side > d) ? -fTexHeight1 : 0;
|
|
rpts1[0] = vector6(bpts1[0].x + slop, bpts1[0].y + h1r,
|
|
0.515625 + map1r); // prawy brzeg prawego chodnika
|
|
rpts1[1] = vector6(bpts1[0].x + d, bpts1[0].y + h1r,
|
|
0.515625); // prawy krawężnik u góry
|
|
rpts1[2] = vector6(bpts1[0].x, bpts1[0].y,
|
|
0.515625 - d / 2.56); // prawy krawężnik u dołu
|
|
rpts2[0] = vector6(bpts1[1].x, bpts1[1].y,
|
|
0.484375 + d / 2.56); // lewy krawężnik u dołu
|
|
rpts2[1] = vector6(bpts1[1].x - d, bpts1[1].y + h1l,
|
|
0.484375); // lewy krawężnik u góry
|
|
rpts2[2] = vector6(bpts1[1].x - side, bpts1[1].y + h1l,
|
|
0.484375 - map1l); // lewy brzeg lewego chodnika
|
|
if (iTrapezoid) // trapez albo przechyłki
|
|
{ // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony
|
|
// odcinka
|
|
slop2 =
|
|
fabs((iTrapezoid & 2) ? slop2 : slop); // szerokość chodnika po prawej
|
|
double map2l = max > 0.0 ?
|
|
side2 / max :
|
|
0.484375; // obcięcie tekstury od lewej strony punktu 2
|
|
double map2r = max > 0.0 ?
|
|
slop2 / max :
|
|
0.484375; // obcięcie tekstury od prawej strony punktu 2
|
|
double h2r = (slop2 > d) ? -fTexHeight2 : 0;
|
|
double h2l = (side2 > d) ? -fTexHeight2 : 0;
|
|
rpts1[3] = vector6(bpts1[2].x + slop2, bpts1[2].y + h2r,
|
|
0.515625 + map2r); // prawy brzeg prawego chodnika
|
|
rpts1[4] = vector6(bpts1[2].x + d, bpts1[2].y + h2r,
|
|
0.515625); // prawy krawężnik u góry
|
|
rpts1[5] = vector6(bpts1[2].x, bpts1[2].y,
|
|
0.515625 - d / 2.56); // prawy krawężnik u dołu
|
|
rpts2[3] = vector6(bpts1[3].x, bpts1[3].y,
|
|
0.484375 + d / 2.56); // lewy krawężnik u dołu
|
|
rpts2[4] = vector6(bpts1[3].x - d, bpts1[3].y + h2l,
|
|
0.484375); // lewy krawężnik u góry
|
|
rpts2[5] = vector6(bpts1[3].x - side2, bpts1[3].y + h2l,
|
|
0.484375 - map2l); // lewy brzeg lewego chodnika
|
|
if (slop != 0.0)
|
|
Segment->RaRenderLoft(Vert, rpts1, -3, fTexLength);
|
|
if (side != 0.0)
|
|
Segment->RaRenderLoft(Vert, rpts2, -3, fTexLength);
|
|
}
|
|
else
|
|
{ // pobocza zwykłe, brak przechyłki
|
|
if (slop != 0.0)
|
|
Segment->RaRenderLoft(Vert, rpts1, 3, fTexLength);
|
|
if (side != 0.0)
|
|
Segment->RaRenderLoft(Vert, rpts2, 3, fTexLength);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case 4: // Ra: rzeki na razie jak drogi, przechyłki na pewno nie mają
|
|
switch (eType) // dalej zależnie od typu
|
|
{
|
|
case tt_Normal: // drogi proste, bo skrzyżowania osobno
|
|
{
|
|
vector6 bpts1[4]; // punkty głównej płaszczyzny przydają się do robienia boków
|
|
if (TextureID1 || TextureID2) // punkty się przydadzą, nawet jeśli nawierzchni nie ma
|
|
{ // double max=2.0*(fHTW>fHTW2?fHTW:fHTW2); //z szerszej strony jest 100%
|
|
double max = (iCategoryFlag & 4) ?
|
|
0.0 :
|
|
fTexLength; // test: szerokość dróg proporcjonalna do długości
|
|
double map1 = max > 0.0 ? fHTW / max : 0.5; // obcięcie tekstury od strony 1
|
|
double map2 = max > 0.0 ? fHTW2 / max : 0.5; // obcięcie tekstury od strony 2
|
|
if (iTrapezoid) // trapez albo przechyłki
|
|
{ // nawierzchnia trapezowata
|
|
Segment->GetRolls(roll1, roll2);
|
|
bpts1[0] = vector6(fHTW * cos(roll1), -fHTW * sin(roll1),
|
|
0.5 - map1); // lewy brzeg początku
|
|
bpts1[1] = vector6(-bpts1[0].x, -bpts1[0].y,
|
|
0.5 + map1); // prawy brzeg początku symetrycznie
|
|
bpts1[2] = vector6(fHTW2 * cos(roll2), -fHTW2 * sin(roll2),
|
|
0.5 - map2); // lewy brzeg końca
|
|
bpts1[3] = vector6(-bpts1[2].x, -bpts1[2].y,
|
|
0.5 + map2); // prawy brzeg początku symetrycznie
|
|
}
|
|
else
|
|
{
|
|
bpts1[0] = vector6(fHTW, 0.0, 0.5 - map1); // zawsze standardowe mapowanie
|
|
bpts1[1] = vector6(-fHTW, 0.0, 0.5 + map1);
|
|
}
|
|
}
|
|
if (TextureID1) // jeśli podana była tekstura, generujemy trójkąty
|
|
{ // tworzenie trójkątów nawierzchni szosy
|
|
Segment->RaRenderLoft(Vert, bpts1, iTrapezoid ? -2 : 2, fTexLength);
|
|
}
|
|
if (TextureID2)
|
|
{ // pobocze drogi - poziome przy przechyłce (a może krawężnik i chodnik zrobić jak w
|
|
// Midtown Madness 2?)
|
|
vector6 rpts1[6],
|
|
rpts2[6]; // współrzędne przekroju i mapowania dla prawej i lewej strony
|
|
rpts1[0] = vector6(rozp, -fTexHeight1, 0.0); // lewy brzeg podstawy
|
|
rpts1[1] = vector6(bpts1[0].x + side, bpts1[0].y, 0.5), // lewa krawędź załamania
|
|
rpts1[2] = vector6(bpts1[0].x, bpts1[0].y,
|
|
1.0); // lewy brzeg pobocza (mapowanie może być inne
|
|
rpts2[0] = vector6(bpts1[1].x, bpts1[1].y, 1.0); // prawy brzeg pobocza
|
|
rpts2[1] = vector6(bpts1[1].x - side, bpts1[1].y, 0.5); // prawa krawędź załamania
|
|
rpts2[2] = vector6(-rozp, -fTexHeight1, 0.0); // prawy brzeg podstawy
|
|
if (iTrapezoid) // trapez albo przechyłki
|
|
{ // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony odcinka
|
|
rpts1[3] = vector6(rozp2, -fTexHeight2, 0.0); // lewy brzeg lewego pobocza
|
|
rpts1[4] = vector6(bpts1[2].x + side2, bpts1[2].y, 0.5); // krawędź załamania
|
|
rpts1[5] = vector6(bpts1[2].x, bpts1[2].y, 1.0); // brzeg pobocza
|
|
rpts2[3] = vector6(bpts1[3].x, bpts1[3].y, 1.0);
|
|
rpts2[4] = vector6(bpts1[3].x - side2, bpts1[3].y, 0.5);
|
|
rpts2[5] = vector6(-rozp2, -fTexHeight2, 0.0); // prawy brzeg prawego pobocza
|
|
Segment->RaRenderLoft(Vert, rpts1, -3, fTexLength);
|
|
Segment->RaRenderLoft(Vert, rpts2, -3, fTexLength);
|
|
}
|
|
else
|
|
{ // pobocza zwykłe, brak przechyłki
|
|
Segment->RaRenderLoft(Vert, rpts1, 3, fTexLength);
|
|
Segment->RaRenderLoft(Vert, rpts2, 3, fTexLength);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
};
|
|
|
|
void TTrack::RaRenderVBO(int iPtr)
|
|
{ // renderowanie z użyciem VBO
|
|
// Ra 2014-07: trzeba wymienić GL_TRIANGLE_STRIP na GL_TRIANGLES i renderować trójkąty sektora
|
|
// dla kolejnych tekstur!
|
|
EnvironmentSet();
|
|
int seg;
|
|
int i;
|
|
switch (iCategoryFlag & 15)
|
|
{
|
|
case 1: // tor
|
|
if (eType == tt_Switch) // dla zwrotnicy tylko szyny
|
|
{
|
|
if (TextureID1)
|
|
if ((seg = SwitchExtension->Segments[0]->RaSegCount()) > 0)
|
|
{
|
|
glBindTexture(GL_TEXTURE_2D, TextureID1); // szyny +
|
|
for (i = 0; i < seg; ++i)
|
|
glDrawArrays(GL_TRIANGLE_STRIP, iPtr + 24 * i, 24);
|
|
iPtr += 24 * seg; // pominięcie lewej szyny
|
|
for (i = 0; i < seg; ++i)
|
|
glDrawArrays(GL_TRIANGLE_STRIP, iPtr + 24 * i, 24);
|
|
iPtr += 24 * seg; // pominięcie prawej szyny
|
|
}
|
|
if (TextureID2)
|
|
if ((seg = SwitchExtension->Segments[1]->RaSegCount()) > 0)
|
|
{
|
|
glBindTexture(GL_TEXTURE_2D, TextureID2); // szyny -
|
|
for (i = 0; i < seg; ++i)
|
|
glDrawArrays(GL_TRIANGLE_STRIP, iPtr + 24 * i, 24);
|
|
iPtr += 24 * seg; // pominięcie lewej szyny
|
|
for (i = 0; i < seg; ++i)
|
|
glDrawArrays(GL_TRIANGLE_STRIP, iPtr + 24 * i, 24);
|
|
}
|
|
}
|
|
else // dla toru podsypka plus szyny
|
|
{
|
|
if ((seg = Segment->RaSegCount()) > 0)
|
|
{
|
|
if (TextureID2)
|
|
{
|
|
glBindTexture(GL_TEXTURE_2D, TextureID2); // podsypka
|
|
for (i = 0; i < seg; ++i)
|
|
glDrawArrays(GL_TRIANGLE_STRIP, iPtr + 8 * i, 8);
|
|
iPtr += 8 * seg; // pominięcie podsypki
|
|
}
|
|
if (TextureID1)
|
|
{
|
|
glBindTexture(GL_TEXTURE_2D, TextureID1); // szyny
|
|
for (i = 0; i < seg; ++i)
|
|
glDrawArrays(GL_TRIANGLE_STRIP, iPtr + 24 * i, 24);
|
|
iPtr += 24 * seg; // pominięcie lewej szyny
|
|
for (i = 0; i < seg; ++i)
|
|
glDrawArrays(GL_TRIANGLE_STRIP, iPtr + 24 * i, 24);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case 2: // droga
|
|
if ((seg = Segment->RaSegCount()) > 0)
|
|
{
|
|
if (TextureID1)
|
|
{
|
|
glBindTexture(GL_TEXTURE_2D, TextureID1); // nawierzchnia
|
|
for (i = 0; i < seg; ++i)
|
|
{
|
|
glDrawArrays(GL_TRIANGLE_STRIP, iPtr, 4);
|
|
iPtr += 4;
|
|
}
|
|
}
|
|
if (TextureID2)
|
|
{
|
|
glBindTexture(GL_TEXTURE_2D, TextureID2); // pobocze
|
|
if (fTexHeight1 >= 0.0)
|
|
{ // normalna droga z poboczem
|
|
for (i = 0; i < seg; ++i)
|
|
glDrawArrays(GL_TRIANGLE_STRIP, iPtr + 6 * i, 6);
|
|
iPtr += 6 * seg; // pominięcie lewego pobocza
|
|
for (i = 0; i < seg; ++i)
|
|
glDrawArrays(GL_TRIANGLE_STRIP, iPtr + 6 * i, 6);
|
|
}
|
|
else
|
|
{ // z chodnikami o różnych szerokociach
|
|
if (fTexWidth != 0.0)
|
|
{
|
|
for (i = 0; i < seg; ++i)
|
|
glDrawArrays(GL_TRIANGLE_STRIP, iPtr + 6 * i, 6);
|
|
iPtr += 6 * seg; // pominięcie lewego pobocza
|
|
}
|
|
if (fTexSlope != 0.0)
|
|
for (i = 0; i < seg; ++i)
|
|
glDrawArrays(GL_TRIANGLE_STRIP, iPtr + 6 * i, 6);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case 4: // rzeki - jeszcze do przemyślenia
|
|
if ((seg = Segment->RaSegCount()) > 0)
|
|
{
|
|
if (TextureID1)
|
|
{
|
|
glBindTexture(GL_TEXTURE_2D, TextureID1); // nawierzchnia
|
|
for (i = 0; i < seg; ++i)
|
|
{
|
|
glDrawArrays(GL_TRIANGLE_STRIP, iPtr, 4);
|
|
iPtr += 4;
|
|
}
|
|
}
|
|
if (TextureID2)
|
|
{
|
|
glBindTexture(GL_TEXTURE_2D, TextureID2); // pobocze
|
|
for (i = 0; i < seg; ++i)
|
|
glDrawArrays(GL_TRIANGLE_STRIP, iPtr + 6 * i, 6);
|
|
iPtr += 6 * seg; // pominięcie lewego pobocza
|
|
for (i = 0; i < seg; ++i)
|
|
glDrawArrays(GL_TRIANGLE_STRIP, iPtr + 6 * i, 6);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
EnvironmentReset();
|
|
};
|
|
|
|
void TTrack::EnvironmentSet()
|
|
{ // ustawienie zmienionego światła
|
|
glColor3f(1.0f, 1.0f, 1.0f); // Ra: potrzebne to?
|
|
if (eEnvironment)
|
|
{ // McZapkie-310702: zmiana oswietlenia w tunelu, wykopie
|
|
GLfloat ambientLight[4] = {0.5f, 0.5f, 0.5f, 1.0f};
|
|
GLfloat diffuseLight[4] = {0.5f, 0.5f, 0.5f, 1.0f};
|
|
GLfloat specularLight[4] = {0.5f, 0.5f, 0.5f, 1.0f};
|
|
switch (eEnvironment)
|
|
{ // modyfikacje oświetlenia zależnie od środowiska
|
|
case e_canyon:
|
|
for (int li = 0; li < 3; li++)
|
|
{
|
|
// ambientLight[li]= Global::ambientDayLight[li]*0.8; //0.7
|
|
diffuseLight[li] = Global::diffuseDayLight[li] * 0.4; // 0.3
|
|
specularLight[li] = Global::specularDayLight[li] * 0.5; // 0.4
|
|
}
|
|
// glLightfv(GL_LIGHT0,GL_AMBIENT,ambientLight);
|
|
glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseLight);
|
|
glLightfv(GL_LIGHT0, GL_SPECULAR, specularLight);
|
|
break;
|
|
case e_tunnel:
|
|
for (int li = 0; li < 3; li++)
|
|
{
|
|
ambientLight[li] = Global::ambientDayLight[li] * 0.2;
|
|
diffuseLight[li] = Global::diffuseDayLight[li] * 0.1;
|
|
specularLight[li] = Global::specularDayLight[li] * 0.2;
|
|
}
|
|
glLightfv(GL_LIGHT0, GL_AMBIENT, ambientLight);
|
|
glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseLight);
|
|
glLightfv(GL_LIGHT0, GL_SPECULAR, specularLight);
|
|
break;
|
|
}
|
|
}
|
|
};
|
|
|
|
void TTrack::EnvironmentReset()
|
|
{ // przywrócenie domyślnego światła
|
|
switch (eEnvironment)
|
|
{ // przywrócenie globalnych ustawień światła, o ile było zmienione
|
|
case e_canyon: // wykop
|
|
case e_tunnel: // tunel
|
|
glLightfv(GL_LIGHT0, GL_AMBIENT, Global::ambientDayLight);
|
|
glLightfv(GL_LIGHT0, GL_DIFFUSE, Global::diffuseDayLight);
|
|
glLightfv(GL_LIGHT0, GL_SPECULAR, Global::specularDayLight);
|
|
}
|
|
};
|
|
|
|
void TTrack::RenderDyn()
|
|
{ // renderowanie nieprzezroczystych fragmentów pojazdów
|
|
if (!iNumDynamics)
|
|
return; // po co kombinować, jeśli nie ma pojazdów?
|
|
// EnvironmentSet(); //Ra: pojazdy sobie same teraz liczą cienie
|
|
for (int i = 0; i < iNumDynamics; i++)
|
|
Dynamics[i]->Render(); // sam sprawdza, czy VBO; zmienia kontekst VBO!
|
|
// EnvironmentReset();
|
|
};
|
|
|
|
void TTrack::RenderDynAlpha()
|
|
{ // renderowanie przezroczystych fragmentów pojazdów
|
|
if (!iNumDynamics)
|
|
return; // po co kombinować, jeśli nie ma pojazdów?
|
|
// EnvironmentSet(); //Ra: pojazdy sobie same teraz liczą cienie
|
|
for (int i = 0; i < iNumDynamics; i++)
|
|
Dynamics[i]->RenderAlpha(); // sam sprawdza, czy VBO; zmienia kontekst VBO!
|
|
// EnvironmentReset();
|
|
};
|
|
|
|
void TTrack::RenderDynSounds()
|
|
{ // odtwarzanie dźwięków pojazdów jest niezależne od ich wyświetlania
|
|
for (int i = 0; i < iNumDynamics; i++)
|
|
Dynamics[i]->RenderSounds();
|
|
};
|
|
//---------------------------------------------------------------------------
|
|
bool TTrack::SetConnections(int i)
|
|
{ // przepisanie aktualnych połączeń toru do odpowiedniego segmentu
|
|
if (SwitchExtension)
|
|
{
|
|
SwitchExtension->pNexts[i] = trNext;
|
|
SwitchExtension->pPrevs[i] = trPrev;
|
|
SwitchExtension->iNextDirection[i] = iNextDirection;
|
|
SwitchExtension->iPrevDirection[i] = iPrevDirection;
|
|
if (eType == tt_Switch)
|
|
{ // zwrotnica jest wyłącznie w punkcie 1, więc tor od strony Prev jest zawsze ten sam
|
|
SwitchExtension->pPrevs[i ^ 1] = trPrev;
|
|
SwitchExtension->iPrevDirection[i ^ 1] = iPrevDirection;
|
|
}
|
|
else if (eType == tt_Cross)
|
|
if (SwitchExtension->iRoads == 3)
|
|
{
|
|
}
|
|
if (i)
|
|
Switch(0); // po przypisaniu w punkcie 4 włączyć stan zasadniczy
|
|
return true;
|
|
}
|
|
Error("Cannot set connections");
|
|
return false;
|
|
}
|
|
|
|
bool TTrack::Switch(int i, double t, double d)
|
|
{ // przełączenie torów z uruchomieniem animacji
|
|
if (SwitchExtension) // tory przełączalne mają doklejkę
|
|
if (eType == tt_Switch)
|
|
{ // przekładanie zwrotnicy jak zwykle
|
|
if (t > 0.0) // prędkość liniowa ruchu iglic
|
|
SwitchExtension->fOffsetSpeed = t; // prędkość łatwiej zgrać z animacją modelu
|
|
if (d >= 0.0) // dodatkowy ruch drugiej iglicy (zamknięcie nastawnicze)
|
|
SwitchExtension->fOffsetDelay = d;
|
|
i &= 1; // ograniczenie błędów !!!!
|
|
SwitchExtension->fDesiredOffset =
|
|
i ? fMaxOffset + SwitchExtension->fOffsetDelay : -SwitchExtension->fOffsetDelay;
|
|
SwitchExtension->CurrentIndex = i;
|
|
Segment = SwitchExtension->Segments[i]; // wybranie aktywnej drogi - potrzebne to?
|
|
trNext = SwitchExtension->pNexts[i]; // przełączenie końców
|
|
trPrev = SwitchExtension->pPrevs[i];
|
|
iNextDirection = SwitchExtension->iNextDirection[i];
|
|
iPrevDirection = SwitchExtension->iPrevDirection[i];
|
|
fRadius = fRadiusTable[i]; // McZapkie: wybor promienia toru
|
|
if (SwitchExtension->fVelocity <=
|
|
-2) //-1 oznacza maksymalną prędkość, a dalsze ujemne to ograniczenie na bok
|
|
fVelocity = i ? -SwitchExtension->fVelocity : -1;
|
|
if (SwitchExtension->pOwner ? SwitchExtension->pOwner->RaTrackAnimAdd(this) :
|
|
true) // jeśli nie dodane do animacji
|
|
{ // nie ma się co bawić
|
|
SwitchExtension->fOffset = SwitchExtension->fDesiredOffset;
|
|
RaAnimate(); // przeliczenie położenia iglic; czy zadziała na niewyświetlanym
|
|
// sektorze w VBO?
|
|
}
|
|
return true;
|
|
}
|
|
else if (eType == tt_Table)
|
|
{ // blokowanie (0, szukanie torów) lub odblokowanie (1, rozłączenie) obrotnicy
|
|
if (i)
|
|
{ // 0: rozłączenie sąsiednich torów od obrotnicy
|
|
if (trPrev) // jeśli jest tor od Point1 obrotnicy
|
|
if (iPrevDirection) // 0:dołączony Point1, 1:dołączony Point2
|
|
trPrev->trNext = NULL; // rozłączamy od Point2
|
|
else
|
|
trPrev->trPrev = NULL; // rozłączamy od Point1
|
|
if (trNext) // jeśli jest tor od Point2 obrotnicy
|
|
if (iNextDirection) // 0:dołączony Point1, 1:dołączony Point2
|
|
trNext->trNext = NULL; // rozłączamy od Point2
|
|
else
|
|
trNext->trPrev = NULL; // rozłączamy od Point1
|
|
trNext = trPrev =
|
|
NULL; // na końcu rozłączamy obrotnicę (wkaźniki do sąsiadów już niepotrzebne)
|
|
fVelocity = 0.0; // AI, nie ruszaj się!
|
|
if (SwitchExtension->pOwner)
|
|
SwitchExtension->pOwner->RaTrackAnimAdd(this); // dodanie do listy animacyjnej
|
|
}
|
|
else
|
|
{ // 1: ustalenie finalnego położenia (gdy nie było animacji)
|
|
RaAnimate(); // ostatni etap animowania
|
|
// zablokowanie pozycji i połączenie do sąsiednich torów
|
|
Global::pGround->TrackJoin(SwitchExtension->pMyNode);
|
|
if (trNext || trPrev)
|
|
{
|
|
fVelocity = 6.0; // jazda dozwolona
|
|
if (trPrev)
|
|
if (trPrev->fVelocity ==
|
|
0.0) // ustawienie 0 da możliwość zatrzymania AI na obrotnicy
|
|
trPrev->VelocitySet(6.0); // odblokowanie dołączonego toru do jazdy
|
|
if (trNext)
|
|
if (trNext->fVelocity == 0.0)
|
|
trNext->VelocitySet(6.0);
|
|
if (SwitchExtension->evPlus) // w starych sceneriach może nie być
|
|
Global::AddToQuery(SwitchExtension->evPlus,
|
|
NULL); // potwierdzenie wykonania (np. odpala WZ)
|
|
}
|
|
}
|
|
SwitchExtension->CurrentIndex = i; // zapamiętanie stanu zablokowania
|
|
return true;
|
|
}
|
|
else if (eType == tt_Cross)
|
|
{ // to jest przydatne tylko do łączenia odcinków
|
|
i &= 1;
|
|
SwitchExtension->CurrentIndex = i;
|
|
Segment = SwitchExtension->Segments[i]; // wybranie aktywnej drogi - potrzebne to?
|
|
trNext = SwitchExtension->pNexts[i]; // przełączenie końców
|
|
trPrev = SwitchExtension->pPrevs[i];
|
|
iNextDirection = SwitchExtension->iNextDirection[i];
|
|
iPrevDirection = SwitchExtension->iPrevDirection[i];
|
|
return true;
|
|
}
|
|
if (iCategoryFlag == 1)
|
|
iDamageFlag = (iDamageFlag & 127) + 128 * (i & 1); // przełączanie wykolejenia
|
|
else
|
|
Error("Cannot switch normal track");
|
|
return false;
|
|
};
|
|
|
|
bool TTrack::SwitchForced(int i, TDynamicObject *o)
|
|
{ // rozprucie rozjazdu
|
|
if (SwitchExtension)
|
|
if (eType == tt_Switch)
|
|
{ //
|
|
if (i != SwitchExtension->CurrentIndex)
|
|
{
|
|
switch (i)
|
|
{
|
|
case 0:
|
|
if (SwitchExtension->evPlus)
|
|
Global::AddToQuery(SwitchExtension->evPlus, o); // dodanie do kolejki
|
|
break;
|
|
case 1:
|
|
if (SwitchExtension->evMinus)
|
|
Global::AddToQuery(SwitchExtension->evMinus, o); // dodanie do kolejki
|
|
break;
|
|
}
|
|
Switch(i); // jeśli się tu nie przełączy, to każdy pojazd powtórzy event rozrprucia
|
|
}
|
|
}
|
|
else if (eType == tt_Cross)
|
|
{ // ustawienie wskaźnika na wskazany segment
|
|
Segment = SwitchExtension->Segments[i];
|
|
}
|
|
return true;
|
|
};
|
|
|
|
int TTrack::CrossSegment(int from, int into)
|
|
{ // ustawienie wskaźnika na segement w pożądanym kierunku (into) od strony (from)
|
|
// zwraca kod segmentu, z kierunkiem jazdy jako znakiem ±
|
|
int i = 0;
|
|
switch (into)
|
|
{
|
|
case 0: // stop
|
|
// WriteLog("Crossing from P"+AnsiString(from+1)+" into stop on "+pMyNode->asName);
|
|
break;
|
|
case 1: // left
|
|
// WriteLog("Crossing from P"+AnsiString(from+1)+" to left on "+pMyNode->asName);
|
|
i = (SwitchExtension->iRoads == 4) ? iLewo4[from] : iLewo3[from];
|
|
break;
|
|
case 2: // right
|
|
// WriteLog("Crossing from P"+AnsiString(from+1)+" to right on "+pMyNode->asName);
|
|
i = (SwitchExtension->iRoads == 4) ? iPrawo4[from] : iPrawo3[from];
|
|
break;
|
|
case 3: // stright
|
|
// WriteLog("Crossing from P"+AnsiString(from+1)+" to straight on "+pMyNode->asName);
|
|
i = (SwitchExtension->iRoads == 4) ? iProsto4[from] : iProsto3[from];
|
|
break;
|
|
}
|
|
if (i)
|
|
{
|
|
Segment = SwitchExtension->Segments[abs(i) - 1];
|
|
// WriteLog("Selected segment: "+AnsiString(abs(i)-1));
|
|
}
|
|
return i;
|
|
};
|
|
|
|
void TTrack::RaAnimListAdd(TTrack *t)
|
|
{ // dodanie toru do listy animacyjnej
|
|
if (SwitchExtension)
|
|
{
|
|
if (t == this)
|
|
return; // siebie nie dodajemy drugi raz do listy
|
|
if (!t->SwitchExtension)
|
|
return; // nie podlega animacji
|
|
if (SwitchExtension->pNextAnim)
|
|
{
|
|
if (SwitchExtension->pNextAnim == t)
|
|
return; // gdy już taki jest
|
|
else
|
|
SwitchExtension->pNextAnim->RaAnimListAdd(t);
|
|
}
|
|
else
|
|
{
|
|
SwitchExtension->pNextAnim = t;
|
|
t->SwitchExtension->pNextAnim = NULL; // nowo dodawany nie może mieć ogona
|
|
}
|
|
}
|
|
};
|
|
|
|
TTrack *__fastcall TTrack::RaAnimate()
|
|
{ // wykonanie rekurencyjne animacji, wywoływane przed wyświetleniem sektora
|
|
// zwraca wskaźnik toru wymagającego dalszej animacji
|
|
if (SwitchExtension->pNextAnim)
|
|
SwitchExtension->pNextAnim = SwitchExtension->pNextAnim->RaAnimate();
|
|
bool m = true; // animacja trwa
|
|
if (eType == tt_Switch) // dla zwrotnicy tylko szyny
|
|
{
|
|
double v = SwitchExtension->fDesiredOffset - SwitchExtension->fOffset; // kierunek
|
|
SwitchExtension->fOffset += sign(v) * Timer::GetDeltaTime() * SwitchExtension->fOffsetSpeed;
|
|
// Ra: trzeba dać to do klasy...
|
|
SwitchExtension->fOffset1 = SwitchExtension->fOffset;
|
|
SwitchExtension->fOffset2 = SwitchExtension->fOffset;
|
|
if (SwitchExtension->fOffset1 >= fMaxOffset)
|
|
SwitchExtension->fOffset1 = fMaxOffset; // ograniczenie animacji zewnętrznej iglicy
|
|
if (SwitchExtension->fOffset2 <= 0.00)
|
|
SwitchExtension->fOffset2 = 0.0; // ograniczenie animacji wewnętrznej iglicy
|
|
if (v < 0)
|
|
{ // jak na pierwszy z torów
|
|
if (SwitchExtension->fOffset <= SwitchExtension->fDesiredOffset)
|
|
{
|
|
SwitchExtension->fOffset = SwitchExtension->fDesiredOffset;
|
|
m = false; // koniec animacji
|
|
}
|
|
}
|
|
else
|
|
{ // jak na drugi z torów
|
|
if (SwitchExtension->fOffset >= SwitchExtension->fDesiredOffset)
|
|
{
|
|
SwitchExtension->fOffset = SwitchExtension->fDesiredOffset;
|
|
m = false; // koniec animacji
|
|
}
|
|
}
|
|
if (Global::bUseVBO)
|
|
{ // dla OpenGL 1.4 odświeży się cały sektor, w późniejszych poprawiamy fragment
|
|
if (Global::bOpenGL_1_5) // dla OpenGL 1.4 to się nie wykona poprawnie
|
|
if (TextureID1) // Ra: !!!! tu jest do poprawienia
|
|
{ // iglice liczone tylko dla zwrotnic
|
|
vector6 rpts3[24], rpts4[24];
|
|
double fHTW = 0.5 * fabs(fTrackWidth);
|
|
double fHTW2 = fHTW; // Ra: na razie niech tak będzie
|
|
double cos1 = 1.0, sin1 = 0.0, cos2 = 1.0, sin2 = 0.0; // Ra: ...
|
|
for (int i = 0; i < 12; ++i)
|
|
{
|
|
rpts3[i] =
|
|
vector6((fHTW + iglica[i].x) * cos1 + iglica[i].y * sin1,
|
|
-(fHTW + iglica[i].x) * sin1 + iglica[i].y * cos1, iglica[i].z);
|
|
rpts3[i + 12] =
|
|
vector6((fHTW2 + szyna[i].x) * cos2 + szyna[i].y * sin2,
|
|
-(fHTW2 + szyna[i].x) * sin2 + iglica[i].y * cos2, szyna[i].z);
|
|
rpts4[11 - i] = vector6((-fHTW - iglica[i].x) * cos1 + iglica[i].y * sin1,
|
|
-(-fHTW - iglica[i].x) * sin1 + iglica[i].y * cos1,
|
|
iglica[i].z);
|
|
rpts4[23 - i] =
|
|
vector6((-fHTW2 - szyna[i].x) * cos2 + szyna[i].y * sin2,
|
|
-(-fHTW2 - szyna[i].x) * sin2 + iglica[i].y * cos2, szyna[i].z);
|
|
}
|
|
CVertNormTex Vert[2 * 2 * 12]; // na razie 2 segmenty
|
|
CVertNormTex *v = Vert; // bo RaAnimate() modyfikuje wskaźnik
|
|
glGetBufferSubData(
|
|
GL_ARRAY_BUFFER, SwitchExtension->iLeftVBO * sizeof(CVertNormTex),
|
|
2 * 2 * 12 * sizeof(CVertNormTex), &Vert); // pobranie fragmentu bufora VBO
|
|
if (SwitchExtension->RightSwitch)
|
|
{ // nowa wersja z SPKS, ale odwrotnie lewa/prawa
|
|
SwitchExtension->Segments[0]->RaAnimate(v, rpts3, -nnumPts, fTexLength, 0,
|
|
2, SwitchExtension->fOffset2);
|
|
glBufferSubData(GL_ARRAY_BUFFER,
|
|
SwitchExtension->iLeftVBO * sizeof(CVertNormTex),
|
|
2 * 2 * 12 * sizeof(CVertNormTex),
|
|
&Vert); // wysłanie fragmentu bufora VBO
|
|
v = Vert;
|
|
glGetBufferSubData(GL_ARRAY_BUFFER,
|
|
SwitchExtension->iRightVBO * sizeof(CVertNormTex),
|
|
2 * 2 * 12 * sizeof(CVertNormTex),
|
|
&Vert); // pobranie fragmentu bufora VBO
|
|
SwitchExtension->Segments[1]->RaAnimate(v, rpts4, -nnumPts, fTexLength, 0,
|
|
2, -fMaxOffset +
|
|
SwitchExtension->fOffset1);
|
|
}
|
|
else
|
|
{ // oryginalnie lewa działała lepiej niż prawa
|
|
SwitchExtension->Segments[0]->RaAnimate(
|
|
v, rpts4, -nnumPts, fTexLength, 0, 2,
|
|
-SwitchExtension->fOffset2); // prawa iglica
|
|
glBufferSubData(GL_ARRAY_BUFFER,
|
|
SwitchExtension->iLeftVBO * sizeof(CVertNormTex),
|
|
2 * 2 * 12 * sizeof(CVertNormTex),
|
|
&Vert); // wysłanie fragmentu bufora VBO
|
|
v = Vert;
|
|
glGetBufferSubData(GL_ARRAY_BUFFER,
|
|
SwitchExtension->iRightVBO * sizeof(CVertNormTex),
|
|
2 * 2 * 12 * sizeof(CVertNormTex),
|
|
&Vert); // pobranie fragmentu bufora VBO
|
|
SwitchExtension->Segments[1]->RaAnimate(
|
|
v, rpts3, -nnumPts, fTexLength, 0, 2,
|
|
fMaxOffset - SwitchExtension->fOffset1); // lewa iglica
|
|
}
|
|
glBufferSubData(
|
|
GL_ARRAY_BUFFER, SwitchExtension->iRightVBO * sizeof(CVertNormTex),
|
|
2 * 2 * 12 * sizeof(CVertNormTex), &Vert); // wysłanie fragmentu bufora VBO
|
|
}
|
|
}
|
|
else // gdy Display List
|
|
Release(); // niszczenie skompilowanej listy, aby się wygenerowała nowa
|
|
}
|
|
else if (eType == tt_Table) // dla obrotnicy - szyny i podsypka
|
|
{
|
|
if (SwitchExtension->pModel &&
|
|
SwitchExtension->CurrentIndex) // 0=zablokowana się nie animuje
|
|
{ // trzeba każdorazowo porównywać z kątem modelu
|
|
// SwitchExtension->fOffset1=SwitchExtension->pAnim?SwitchExtension->pAnim->AngleGet():0.0;
|
|
// //pobranie kąta z modelu
|
|
TAnimContainer *ac = SwitchExtension->pModel ?
|
|
SwitchExtension->pModel->GetContainer(NULL) :
|
|
NULL; // pobranie głównego submodelu
|
|
// if (ac) ac->EventAssign(SwitchExtension->evMinus); //event zakończenia animacji,
|
|
// trochę bez sensu tutaj
|
|
if (ac)
|
|
if ((ac->AngleGet() != SwitchExtension->fOffset) ||
|
|
!(ac->TransGet() ==
|
|
SwitchExtension->vTrans)) // czy przemieściło się od ostatniego sprawdzania
|
|
{
|
|
double hlen = 0.5 * SwitchExtension->Segments[0]->GetLength(); // połowa
|
|
// długości
|
|
SwitchExtension->fOffset = ac->AngleGet(); // pobranie kąta z submodelu
|
|
double sina = -hlen * sin(DegToRad(SwitchExtension->fOffset)),
|
|
cosa = -hlen * cos(DegToRad(SwitchExtension->fOffset));
|
|
SwitchExtension->vTrans = ac->TransGet();
|
|
vector3 middle =
|
|
SwitchExtension->pMyNode->pCenter +
|
|
SwitchExtension->vTrans; // SwitchExtension->Segments[0]->FastGetPoint(0.5);
|
|
Segment->Init(middle + vector3(sina, 0.0, cosa),
|
|
middle - vector3(sina, 0.0, cosa), 5.0); // nowy odcinek
|
|
for (int i = 0; i < iNumDynamics; i++)
|
|
Dynamics[i]->Move(0.000001); // minimalny ruch, aby przeliczyć pozycję i
|
|
// kąty
|
|
if (Global::bUseVBO)
|
|
{ // dla OpenGL 1.4 odświeży się cały sektor, w późniejszych poprawiamy fragment
|
|
// aktualizacja pojazdów na torze
|
|
if (Global::bOpenGL_1_5) // dla OpenGL 1.4 to się nie wykona poprawnie
|
|
{
|
|
int size =
|
|
RaArrayPrepare(); // wielkość tabeli potrzebna dla tej obrotnicy
|
|
CVertNormTex *Vert = new CVertNormTex[size]; // bufor roboczy
|
|
// CVertNormTex *v=Vert; //zmieniane przez
|
|
RaArrayFill(Vert,
|
|
Vert -
|
|
SwitchExtension
|
|
->iLeftVBO); // iLeftVBO powinno zostać niezmienione
|
|
glBufferSubData(
|
|
GL_ARRAY_BUFFER, SwitchExtension->iLeftVBO * sizeof(CVertNormTex),
|
|
size * sizeof(CVertNormTex), Vert); // wysłanie fragmentu bufora VBO
|
|
}
|
|
}
|
|
else // gdy Display List
|
|
Release(); // niszczenie skompilowanej listy, aby się wygenerowała nowa
|
|
} // animacja trwa nadal
|
|
}
|
|
else
|
|
m = false; // koniec animacji albo w ogóle nie połączone z modelem
|
|
}
|
|
return m ? this : SwitchExtension->pNextAnim; // zwraca obiekt do dalszej animacji
|
|
};
|
|
//---------------------------------------------------------------------------
|
|
void TTrack::RadioStop()
|
|
{ // przekazanie pojazdom rozkazu zatrzymania
|
|
for (int i = 0; i < iNumDynamics; i++)
|
|
Dynamics[i]->RadioStop();
|
|
};
|
|
|
|
double TTrack::WidthTotal()
|
|
{ // szerokość z poboczem
|
|
if (iCategoryFlag & 2) // jesli droga
|
|
if (fTexHeight1 >= 0.0) // i ma boki zagięte w dół (chodnik jest w górę)
|
|
return 2.0 * fabs(fTexWidth) +
|
|
0.5 * fabs(fTrackWidth + fTrackWidth2); // dodajemy pobocze
|
|
return 0.5 * fabs(fTrackWidth + fTrackWidth2); // a tak tylko zwykła średnia szerokość
|
|
};
|
|
|
|
bool TTrack::IsGroupable()
|
|
{ // czy wyświetlanie toru może być zgrupwane z innymi
|
|
if ((eType == tt_Switch) || (eType == tt_Table))
|
|
return false; // tory ruchome nie są grupowane
|
|
if ((eEnvironment == e_canyon) || (eEnvironment == e_tunnel))
|
|
return false; // tory ze zmianą światła
|
|
return true;
|
|
};
|
|
|
|
bool Equal(vector3 v1, vector3 *v2)
|
|
{ // sprawdzenie odległości punktów
|
|
// Ra: powinno być do 100cm wzdłuż toru i ze 2cm w poprzek (na prostej może nie być długiego
|
|
// kawałka)
|
|
// Ra: z automatycznie dodawanym stukiem, jeśli dziura jest większa niż 2mm.
|
|
if (fabs(v1.x - v2->x) > 0.02)
|
|
return false; // sześcian zamiast kuli
|
|
if (fabs(v1.z - v2->z) > 0.02)
|
|
return false;
|
|
if (fabs(v1.y - v2->y) > 0.02)
|
|
return false;
|
|
return true;
|
|
// return (SquareMagnitude(v1-*v2)<0.00012); //0.011^2=0.00012
|
|
};
|
|
|
|
int TTrack::TestPoint(vector3 *Point)
|
|
{ // sprawdzanie, czy tory można połączyć
|
|
switch (eType)
|
|
{
|
|
case tt_Normal: // zwykły odcinek
|
|
if (trPrev == NULL)
|
|
if (Equal(Segment->FastGetPoint_0(), Point))
|
|
return 0;
|
|
if (trNext == NULL)
|
|
if (Equal(Segment->FastGetPoint_1(), Point))
|
|
return 1;
|
|
break;
|
|
case tt_Switch: // zwrotnica
|
|
{
|
|
int state = GetSwitchState(); // po co?
|
|
// Ra: TODO: jak się zmieni na bezpośrednie odwołania do segmentow zwrotnicy,
|
|
// to się wykoleja, ponieważ trNext zależy od przełożenia
|
|
Switch(0);
|
|
if (trPrev == NULL)
|
|
// if (Equal(SwitchExtension->Segments[0]->FastGetPoint_0(),Point))
|
|
if (Equal(Segment->FastGetPoint_0(), Point))
|
|
{
|
|
Switch(state);
|
|
return 2;
|
|
}
|
|
if (trNext == NULL)
|
|
// if (Equal(SwitchExtension->Segments[0]->FastGetPoint_1(),Point))
|
|
if (Equal(Segment->FastGetPoint_1(), Point))
|
|
{
|
|
Switch(state);
|
|
return 3;
|
|
}
|
|
Switch(1); // można by się pozbyć tego przełączania
|
|
if (trPrev == NULL) // Ra: z tym chyba nie potrzeba łączyć
|
|
// if (Equal(SwitchExtension->Segments[1]->FastGetPoint_0(),Point))
|
|
if (Equal(Segment->FastGetPoint_0(), Point))
|
|
{
|
|
Switch(state); // Switch(0);
|
|
return 4;
|
|
}
|
|
if (trNext == NULL) // TODO: to zależy od przełożenia zwrotnicy
|
|
// if (Equal(SwitchExtension->Segments[1]->FastGetPoint_1(),Point))
|
|
if (Equal(Segment->FastGetPoint_1(), Point))
|
|
{
|
|
Switch(state); // Switch(0);
|
|
return 5;
|
|
}
|
|
Switch(state);
|
|
}
|
|
break;
|
|
case tt_Cross: // skrzyżowanie dróg
|
|
// if (trPrev==NULL)
|
|
if (Equal(SwitchExtension->Segments[0]->FastGetPoint_0(), Point))
|
|
return 2;
|
|
// if (trNext==NULL)
|
|
if (Equal(SwitchExtension->Segments[0]->FastGetPoint_1(), Point))
|
|
return 3;
|
|
// if (trPrev==NULL)
|
|
if (Equal(SwitchExtension->Segments[1]->FastGetPoint_0(), Point))
|
|
return 4;
|
|
// if (trNext==NULL)
|
|
if (Equal(SwitchExtension->Segments[1]->FastGetPoint_1(), Point))
|
|
return 5;
|
|
break;
|
|
}
|
|
return -1;
|
|
};
|
|
|
|
void TTrack::MovedUp1(double dh)
|
|
{ // poprawienie przechyłki wymaga wydłużenia podsypki
|
|
fTexHeight1 += dh;
|
|
};
|
|
|
|
AnsiString TTrack::NameGet()
|
|
{ // ustalenie nazwy toru
|
|
if (this)
|
|
if (pMyNode)
|
|
return pMyNode->asName;
|
|
return "none";
|
|
};
|
|
|
|
void TTrack::VelocitySet(float v)
|
|
{ // ustawienie prędkości z ograniczeniem do pierwotnej wartości (zapisanej w scenerii)
|
|
if (SwitchExtension ? SwitchExtension->fVelocity >= 0.0 : false)
|
|
{ // zwrotnica może mieć odgórne ograniczenie, nieprzeskakiwalne eventem
|
|
if (v > SwitchExtension->fVelocity ? true : v < 0.0)
|
|
return void(fVelocity =
|
|
SwitchExtension->fVelocity); // maksymalnie tyle, ile było we wpisie
|
|
}
|
|
fVelocity = v; // nie ma ograniczenia
|
|
};
|
|
|
|
float TTrack::VelocityGet()
|
|
{ // pobranie dozwolonej prędkości podczas skanowania
|
|
return ((iDamageFlag & 128) ? 0.0f : fVelocity); // tor uszkodzony = prędkość zerowa
|
|
};
|
|
|
|
void TTrack::ConnectionsLog()
|
|
{ // wypisanie informacji o połączeniach
|
|
int i;
|
|
WriteLog("--> tt_Cross named " + pMyNode->asName);
|
|
if (eType == tt_Cross)
|
|
for (i = 0; i < 2; ++i)
|
|
{
|
|
if (SwitchExtension->pPrevs[i])
|
|
WriteLog("Point " + AnsiString(i + i + 1) + " -> track " +
|
|
SwitchExtension->pPrevs[i]->pMyNode->asName + ":" +
|
|
AnsiString(int(SwitchExtension->iPrevDirection[i])));
|
|
if (SwitchExtension->pNexts[i])
|
|
WriteLog("Point " + AnsiString(i + i + 2) + " -> track " +
|
|
SwitchExtension->pNexts[i]->pMyNode->asName + ":" +
|
|
AnsiString(int(SwitchExtension->iNextDirection[i])));
|
|
}
|
|
};
|
|
|
|
TTrack *__fastcall TTrack::Neightbour(int s, double &d)
|
|
{ // zwraca wskaźnik na sąsiedni tor, w kierunku określonym znakiem (s), odwraca (d) w razie
|
|
// niezgodności kierunku torów
|
|
TTrack *t; // nie zmieniamy kierunku (d), jeśli nie ma toru dalej
|
|
if (eType != tt_Cross)
|
|
{ // jeszcze trzeba sprawdzić zgodność
|
|
t = (s > 0) ? trNext : trPrev;
|
|
if (t) // o ile jest na co przejść, zmieniamy znak kierunku na nowym torze
|
|
if (t->eType == tt_Cross)
|
|
{ // jeśli wjazd na skrzyżowanie, trzeba ustalić segment, bo od tego zależy zmiana
|
|
// kierunku (d)
|
|
// if (r) //gdy nie podano (r), to nie zmieniać (d)
|
|
// if (s*t->CrossSegment(((s>0)?iNextDirection:iPrevDirection),r)<0)
|
|
// d=-d;
|
|
}
|
|
else
|
|
{
|
|
if ((s > 0) ? iNextDirection : !iPrevDirection)
|
|
d = -d; // następuje zmiana kierunku wózka albo kierunku skanowania
|
|
// s=((s>0)?iNextDirection:iPrevDirection)?-1:1; //kierunek toru po zmianie
|
|
}
|
|
return (t); // zwrotnica ma odpowiednio ustawione (trNext)
|
|
}
|
|
switch ((SwitchExtension->iRoads == 4) ? iEnds4[s + 6] :
|
|
iEnds3[s + 6]) // numer końca 0..3, -1 to błąd
|
|
{ // zjazd ze skrzyżowania
|
|
case 0:
|
|
if (SwitchExtension->pPrevs[0])
|
|
if ((s > 0) == SwitchExtension->iPrevDirection[0])
|
|
d = -d;
|
|
return SwitchExtension->pPrevs[0];
|
|
case 1:
|
|
if (SwitchExtension->pNexts[0])
|
|
if ((s > 0) == SwitchExtension->iNextDirection[0])
|
|
d = -d;
|
|
return SwitchExtension->pNexts[0];
|
|
case 2:
|
|
if (SwitchExtension->pPrevs[1])
|
|
if ((s > 0) == SwitchExtension->iPrevDirection[1])
|
|
d = -d;
|
|
return SwitchExtension->pPrevs[1];
|
|
case 3:
|
|
if (SwitchExtension->pNexts[1])
|
|
if ((s > 0) == SwitchExtension->iNextDirection[1])
|
|
d = -d;
|
|
return SwitchExtension->pNexts[1];
|
|
}
|
|
return NULL;
|
|
};
|