mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-03-22 15:05:03 +01:00
2619 lines
116 KiB
C++
2619 lines
116 KiB
C++
//---------------------------------------------------------------------------
|
|
/*
|
|
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;
|
|
|
|
__fastcall 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
|
|
}
|
|
__fastcall 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];
|
|
}
|
|
|
|
__fastcall TIsolated::TIsolated()
|
|
{//utworznie pustego
|
|
TIsolated("none",NULL);
|
|
};
|
|
__fastcall 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ą
|
|
};
|
|
|
|
__fastcall 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 __fastcall 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ą
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
__fastcall 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
|
|
}
|
|
|
|
__fastcall 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 __fastcall 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 __fastcall 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 __fastcall 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 __fastcall 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 __fastcall 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 __fastcall 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 __fastcall 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 __fastcall 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 __fastcall 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 __fastcall 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 __fastcall 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 __fastcall 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 __fastcall 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 __fastcall 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 __fastcall 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 __fastcall 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 __fastcall 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 __fastcall 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 __fastcall 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 __fastcall 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 __fastcall TTrack::RaAssign(TGroundNode *gn,TAnimContainer *ac)
|
|
{//Ra: wiązanie toru z modelem obrotnicy
|
|
//if (eType==tt_Table) SwitchExtension->pAnim=p;
|
|
};
|
|
void __fastcall 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 __fastcall 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 __fastcall 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 __fastcall 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 __fastcall 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 __fastcall 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 __fastcall 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 __fastcall 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 __fastcall 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 __fastcall 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 __fastcall 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 __fastcall 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 __fastcall 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 __fastcall 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 __fastcall TTrack::RadioStop()
|
|
{//przekazanie pojazdom rozkazu zatrzymania
|
|
for (int i=0;i<iNumDynamics;i++)
|
|
Dynamics[i]->RadioStop();
|
|
};
|
|
|
|
double __fastcall 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 __fastcall 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 __fastcall 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 __fastcall 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 __fastcall TTrack::MovedUp1(double dh)
|
|
{//poprawienie przechyłki wymaga wydłużenia podsypki
|
|
fTexHeight1+=dh;
|
|
};
|
|
|
|
AnsiString __fastcall TTrack::NameGet()
|
|
{//ustalenie nazwy toru
|
|
if (this)
|
|
if (pMyNode)
|
|
return pMyNode->asName;
|
|
return "none";
|
|
};
|
|
|
|
void __fastcall 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 __fastcall TTrack::VelocityGet()
|
|
{//pobranie dozwolonej prędkości podczas skanowania
|
|
return ((iDamageFlag&128)?0.0f:fVelocity); //tor uszkodzony = prędkość zerowa
|
|
};
|
|
|
|
void __fastcall 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;
|
|
};
|
|
|