17
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-10-22 16:43:21 +02:00

Merge remote-tracking branch 'tmj-fstate/mover_in_c++' into mover_in_c++

This commit is contained in:
firleju
2017-06-02 17:16:03 +02:00
54 changed files with 1864 additions and 3239 deletions

View File

@@ -411,13 +411,7 @@ TAnimModel::TAnimModel()
pModel = NULL;
iNumLights = 0;
fBlinkTimer = 0;
#ifdef EU07_USE_OLD_RENDERCODE
ReplacableSkinId[ 0 ] = 0;
ReplacableSkinId[ 1 ] = 0;
ReplacableSkinId[ 2 ] = 0;
ReplacableSkinId[ 3 ] = 0;
ReplacableSkinId[ 4 ] = 0;
#endif
for (int i = 0; i < iMaxNumLights; i++)
{
LightsOn[i] = LightsOff[i] = NULL; // normalnie nie ma
@@ -443,28 +437,7 @@ bool TAnimModel::Init(TModel3d *pNewModel)
pModel = pNewModel;
return (pModel != NULL);
}
#ifdef EU07_USE_OLD_RENDERCODE
bool TAnimModel::Init(std::string const &asName, std::string const &asReplacableTexture)
{
if (asReplacableTexture.substr(0, 1) ==
"*") // od gwiazdki zaczynają się teksty na wyświetlaczach
asText = asReplacableTexture.substr(1, asReplacableTexture.length() - 1); // zapamiętanie tekstu
else if (asReplacableTexture != "none")
ReplacableSkinId[1] =
GfxRenderer.GetTextureId( asReplacableTexture, "" );
if( ( ReplacableSkinId[ 1 ] != 0 )
&& ( GfxRenderer.Texture( ReplacableSkinId[ 1 ] ).has_alpha ) ) {
// tekstura z kanałem alfa - nie renderować w cyklu nieprzezroczystych
iTexAlpha = 0x31310031;
}
else{
// tekstura nieprzezroczysta - nie renderować w cyklu
iTexAlpha = 0x30300030;
}
// przezroczystych
return (Init(TModelsManager::GetModel(asName)));
}
#else
bool TAnimModel::Init(std::string const &asName, std::string const &asReplacableTexture)
{
if (asReplacableTexture.substr(0, 1) ==
@@ -485,7 +458,6 @@ bool TAnimModel::Init(std::string const &asName, std::string const &asReplacable
// przezroczystych
return (Init(TModelsManager::GetModel(asName)));
}
#endif
bool TAnimModel::Load(cParser *parser, bool ter)
{ // rozpoznanie wpisu modelu i ustawienie świateł
@@ -622,111 +594,29 @@ void TAnimModel::RaPrepare()
// for (pCurrent=pRoot;pCurrent!=NULL;pCurrent=pCurrent->pNext) //albo osobny łańcuch
// pCurrent->UpdateModelIK(); //przeliczenie odwrotnej kinematyki
}
/*
void TAnimModel::RenderVBO(vector3 pPosition, double fAngle)
{ // sprawdza światła i rekurencyjnie renderuje TModel3d
RaAnimate(); // jednorazowe przeliczenie animacji
RaPrepare();
if (pModel) // renderowanie rekurencyjne submodeli
pModel->RaRender(pPosition, fAngle, ReplacableSkinId, iTexAlpha);
}
void TAnimModel::RenderAlphaVBO(vector3 pPosition, double fAngle)
{
RaPrepare();
if (pModel) // renderowanie rekurencyjne submodeli
pModel->RaRenderAlpha(pPosition, fAngle, ReplacableSkinId, iTexAlpha);
};
void TAnimModel::RenderDL(vector3 pPosition, double fAngle)
{
RaAnimate(); // jednorazowe przeliczenie animacji
RaPrepare();
if (pModel) // renderowanie rekurencyjne submodeli
pModel->Render(pPosition, fAngle, ReplacableSkinId, iTexAlpha);
}
void TAnimModel::RenderAlphaDL(vector3 pPosition, double fAngle)
{
RaPrepare();
if (pModel)
pModel->RenderAlpha(pPosition, fAngle, ReplacableSkinId, iTexAlpha);
};
*/
#ifdef EU07_USE_OLD_RENDERCODE
int TAnimModel::Flags()
{ // informacja dla TGround, czy ma być w Render, RenderAlpha, czy RenderMixed
int i = pModel ? pModel->Flags() : 0; // pobranie flag całego modelu
if (ReplacableSkinId[1] > 0) // jeśli ma wymienną teksturę 0
i |= (i & 0x01010001) * ((iTexAlpha & 1) ? 0x20 : 0x10);
// if (ReplacableSkinId[2]>0) //jeśli ma wymienną teksturę 1
// i|=(i&0x02020002)*((iTexAlpha&1)?0x10:0x08);
// if (ReplacableSkinId[3]>0) //jeśli ma wymienną teksturę 2
// i|=(i&0x04040004)*((iTexAlpha&1)?0x08:0x04);
// if (ReplacableSkinId[4]>0) //jeśli ma wymienną teksturę 3
// i|=(i&0x08080008)*((iTexAlpha&1)?0x04:0x02);
return i;
};
#else
int TAnimModel::Flags()
{ // informacja dla TGround, czy ma być w Render, RenderAlpha, czy RenderMixed
int i = pModel ? pModel->Flags() : 0; // pobranie flag całego modelu
if( m_materialdata.replacable_skins[ 1 ] > 0 ) // jeśli ma wymienną teksturę 0
i |= (i & 0x01010001) * ((m_materialdata.textures_alpha & 1) ? 0x20 : 0x10);
// if (ReplacableSkinId[2]>0) //jeśli ma wymienną teksturę 1
// i|=(i&0x02020002)*((iTexAlpha&1)?0x10:0x08);
// if (ReplacableSkinId[3]>0) //jeśli ma wymienną teksturę 2
// i|=(i&0x04040004)*((iTexAlpha&1)?0x08:0x04);
// if (ReplacableSkinId[4]>0) //jeśli ma wymienną teksturę 3
// i|=(i&0x08080008)*((iTexAlpha&1)?0x04:0x02);
return i;
};
#endif
//-----------------------------------------------------------------------------
// 2011-03-16 cztery nowe funkcje renderowania z możliwością pochylania obiektów
// 2011-03-16 funkcje renderowania z możliwością pochylania obiektów
//-----------------------------------------------------------------------------
#ifdef EU07_USE_OLD_RENDERCODE
void TAnimModel::RenderDL(vector3 *vPosition)
{
void TAnimModel::Render( vector3 const &Position ) {
RaAnimate(); // jednorazowe przeliczenie animacji
RaPrepare();
if( pModel ) // renderowanie rekurencyjne submodeli
pModel->Render(vPosition, &vAngle, ReplacableSkinId, iTexAlpha);
GfxRenderer.Render( pModel, Material(), Position, vAngle );
};
void TAnimModel::RenderAlphaDL(vector3 *vPosition)
{
RaPrepare();
if (pModel) // renderowanie rekurencyjne submodeli
pModel->RenderAlpha(vPosition, &vAngle, ReplacableSkinId, iTexAlpha);
};
void TAnimModel::RenderVBO(vector3 *vPosition)
{
RaAnimate(); // jednorazowe przeliczenie animacji
RaPrepare();
if (pModel) // renderowanie rekurencyjne submodeli
pModel->RaRender( vPosition, &vAngle, Material()->replacable_skins, Material()->textures_alpha );
};
void TAnimModel::RenderAlphaVBO(vector3 *vPosition)
{
RaPrepare();
if (pModel) // renderowanie rekurencyjne submodeli
pModel->RaRenderAlpha( vPosition, &vAngle, Material()->replacable_skins, Material()->textures_alpha );
};
#else
void TAnimModel::Render( vector3 *vPosition ) {
RaAnimate(); // jednorazowe przeliczenie animacji
void TAnimModel::RenderAlpha( vector3 const &Position ) {
RaPrepare();
if( pModel ) // renderowanie rekurencyjne submodeli
GfxRenderer.Render( pModel, Material(), *vPosition, vAngle );
GfxRenderer.Render_Alpha( pModel, Material(), Position, vAngle );
};
void TAnimModel::RenderAlpha( vector3 *vPosition ) {
RaPrepare();
if( pModel ) // renderowanie rekurencyjne submodeli
GfxRenderer.Render_Alpha( pModel, Material(), *vPosition, vAngle );
};
#endif
//---------------------------------------------------------------------------
bool TAnimModel::TerrainLoaded()
@@ -901,13 +791,8 @@ void TAnimModel::LightSet(int n, float v)
void TAnimModel::AnimUpdate(double dt)
{ // wykonanie zakolejkowanych animacji, nawet gdy modele nie są aktualnie wyświetlane
TAnimContainer *p = TAnimModel::acAnimList;
while (p)
{ // jeśli w ogóle jest co animować
// if ((*p)->fTranslateSpeed==0.0)
// if ((*p)->fRotateSpeed==0.0)
// {//jak się naanimował, to usunąć z listy
// *p=(*p)->ListRemove(); //zwraca wskaźnik do kolejnego z listy
// }
while( p ) {
p->UpdateModel();
p = p->acAnimNext; // na razie bez usuwania z listy, bo głównie obrotnica na nią wchodzi
}

View File

@@ -12,8 +12,7 @@ http://mozilla.org/MPL/2.0/.
*/
#ifndef AnimModelH
#define AnimModelH
#pragma once
#include "Model3d.h"
#include "Texture.h"
@@ -139,11 +138,7 @@ class TAnimModel
TSubModel *LightsOn[iMaxNumLights]; // Ra: te wskaźniki powinny być w ramach TModel3d
TSubModel *LightsOff[iMaxNumLights];
vector3 vAngle; // bazowe obroty egzemplarza względem osi
#ifdef EU07_USE_OLD_RENDERCODE
int iTexAlpha; //żeby nie sprawdzać za każdym razem, dla 4 wymiennych tekstur
#else
material_data m_materialdata;
#endif
std::string asText; // tekst dla wyświetlacza znakowego
TAnimAdvanced *pAdvanced;
@@ -155,14 +150,9 @@ class TAnimModel
void RaAnimate(); // przeliczenie animacji egzemplarza
void RaPrepare(); // ustawienie animacji egzemplarza na wzorcu
public:
#ifdef EU07_USE_OLD_RENDERCODE
texture_manager::size_type ReplacableSkinId[5]; // McZapkie-020802: zmienialne skory
#endif
static TAnimContainer *acAnimList; // lista animacji z eventem, które muszą być przeliczane również bez wyświetlania
#ifndef EU07_USE_OLD_RENDERCODE
inline
material_data const *Material() const { return &m_materialdata; }
#endif
TAnimModel();
~TAnimModel();
@@ -171,20 +161,8 @@ class TAnimModel
bool Load(cParser *parser, bool ter = false);
TAnimContainer * AddContainer(char *pName);
TAnimContainer * GetContainer(char *pName);
/* void RenderDL(vector3 pPosition = vector3(0, 0, 0), double fAngle = 0);
void RenderAlphaDL(vector3 pPosition = vector3(0, 0, 0), double fAngle = 0);
void RenderVBO(vector3 pPosition = vector3(0, 0, 0), double fAngle = 0);
void RenderAlphaVBO(vector3 pPosition = vector3(0, 0, 0), double fAngle = 0);
*/
#ifdef EU07_USE_OLD_RENDERCODE
void RenderDL( vector3 *vPosition );
void RenderAlphaDL(vector3 *vPosition);
void RenderVBO(vector3 *vPosition);
void RenderAlphaVBO(vector3 *vPosition);
#else
void Render( vector3 *vPosition );
void RenderAlpha( vector3 *vPosition );
#endif
void Render( vector3 const &Position );
void RenderAlpha( vector3 const &Position );
int Flags();
void RaAnglesSet(double a, double b, double c)
{
@@ -201,6 +179,4 @@ class TAnimModel
static void AnimUpdate(double dt);
};
//---------------------------------------------------------------------------
#endif

View File

@@ -410,21 +410,21 @@ bool TCamera::SetMatrix()
return true;
}
bool TCamera::SetMatrix( glm::mat4 &Matrix ) {
bool TCamera::SetMatrix( glm::dmat4 &Matrix ) {
Matrix = glm::rotate( Matrix, (float)-Roll, glm::vec3( 0.0f, 0.0f, 1.0f ) ); // po wyłączeniu tego kręci się pojazd, a sceneria nie
Matrix = glm::rotate( Matrix, (float)-Pitch, glm::vec3( 1.0f, 0.0f, 0.0f ) );
Matrix = glm::rotate( Matrix, (float)-Yaw, glm::vec3( 0.0f, 1.0f, 0.0f ) ); // w zewnętrznym widoku: kierunek patrzenia
Matrix = glm::rotate( Matrix, -Roll, glm::dvec3( 0.0, 0.0, 1.0 ) ); // po wyłączeniu tego kręci się pojazd, a sceneria nie
Matrix = glm::rotate( Matrix, -Pitch, glm::dvec3( 1.0, 0.0, 0.0 ) );
Matrix = glm::rotate( Matrix, -Yaw, glm::dvec3( 0.0, 1.0, 0.0 ) ); // w zewnętrznym widoku: kierunek patrzenia
if( Type == tp_Follow ) {
Matrix *= glm::lookAt(
glm::vec3( Pos.x, Pos.y, Pos.z ),
glm::vec3( LookAt.x, LookAt.y, LookAt.z ),
glm::vec3( vUp.x, vUp.y, vUp.z ) );
glm::dvec3( Pos.x, Pos.y, Pos.z ),
glm::dvec3( LookAt.x, LookAt.y, LookAt.z ),
glm::dvec3( vUp.x, vUp.y, vUp.z ) );
}
else {
Matrix = glm::translate( Matrix, glm::vec3( -Pos.x, -Pos.y, -Pos.z ) ); // nie zmienia kierunku patrzenia
Matrix = glm::translate( Matrix, glm::dvec3( -Pos.x, -Pos.y, -Pos.z ) ); // nie zmienia kierunku patrzenia
}
Global::SetCameraPosition( Pos ); // było +pOffset

View File

@@ -58,7 +58,7 @@ class TCamera
void Update();
vector3 GetDirection();
bool SetMatrix();
bool SetMatrix(glm::mat4 &Matrix);
bool SetMatrix(glm::dmat4 &Matrix);
void SetCabMatrix( vector3 &p );
void RaLook();
void Stop();

View File

@@ -469,6 +469,16 @@ void TController::TableTraceRoute(double fDistance, TDynamicObject *pVehicle)
}
else {
if( iTableDirection == 0 ) { return; }
// NOTE: provisory fix for BUG: sempahor indices no longer matching table size
// TODO: find and really fix the reason it happens
if( ( SemNextIndex != -1 )
&& ( SemNextIndex >= sSpeedTable.size() ) ) {
SemNextIndex = -1;
}
if( ( SemNextStopIndex != -1 )
&& ( SemNextStopIndex >= sSpeedTable.size() ) ) {
SemNextStopIndex = -1;
}
// kontynuacja skanowania od ostatnio sprawdzonego toru (w ostatniej pozycji zawsze jest tor)
if( ( SemNextStopIndex != -1 )
&& ( sSpeedTable[SemNextStopIndex].fVelNext < 1.0 ) ) {
@@ -512,11 +522,6 @@ void TController::TableTraceRoute(double fDistance, TDynamicObject *pVehicle)
return;
}
#ifdef EU07_USE_OLD_SPEEDTABLE
// jak coś się znajdzie, zostanie wpisane w tę pozycję, którą właśnie odczytano
--iLast;
#endif
while (fCurrentDistance < fDistance)
{
if (pTrack != tLast) // ostatni zapisany w tabelce nie był jeszcze sprawdzony
@@ -869,8 +874,9 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN
// if (p7&3) //żeby jeszcze poczekał chwilę, zanim zamknie
// WaitingSet(10); //10 sekund (wziąć z rozkładu????)
}
if (fStopTime > -5) // na końcu rozkładu się ustawia 60s i tu by było skrócenie
WaitingSet(10); // 10 sekund (wziąć z rozkładu????) - czekanie
if( fStopTime > -5 ) // na końcu rozkładu się ustawia 60s i tu by było skrócenie
WaitingSet( 15.0 + Random( 15.0 ) ); // 10 sekund (wziąć z rozkładu????) - czekanie
// niezależne od sposobu obsługi drzwi, bo opóźnia również kierownika
}
if (TrainParams->UpdateMTable( simulation::Time, asNextStop) )
@@ -980,11 +986,10 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN
sSpeedTable[i].fVelNext = -1; // można jechać za W4
fLastStopExpDist = -1.0f; // nie ma rozkładu, nie ma usuwania stacji
WaitingSet(60); // tak ze 2 minuty, aż wszyscy wysiądą
JumpToNextOrder(); // wykonanie kolejnego rozkazu (Change_direction
// albo Shunt)
iDrivigFlags |= moveStopHere | moveStartHorn; // ma się nie ruszać
// aż do momentu
// podania sygnału
// wykonanie kolejnego rozkazu (Change_direction albo Shunt)
JumpToNextOrder();
// ma się nie ruszać aż do momentu podania sygnału
iDrivigFlags |= moveStopHere | moveStartHorn;
continue; // nie analizować prędkości
} // koniec obsługi ostatniej stacji
} // if (MoverParameters->Vel==0.0)
@@ -1340,7 +1345,6 @@ void TController::TablePurger()
// we can only update pointers safely after new table is finalized, so record their indices until then
for( std::size_t idx = 0; idx < sSpeedTable.size() - 1; ++idx ) {
// cache placement of semaphors in the new table, if we encounter them
// NOTE: we rely on the semaphor actually getting added in the next step rather than skipped, but it's a pretty safe bet
if( idx == SemNextIndex ) {
SemNextIndex = trimmedtable.size();
}
@@ -1351,6 +1355,13 @@ void TController::TablePurger()
if( ( 0 == ( speedpoint.iFlags & spEnabled ) )
|| ( ( speedpoint.iFlags & ( spElapsed | spTrack | spCurve | spSwitch ) == ( spElapsed | spTrack | spCurve ) )
&& ( speedpoint.fVelNext < 0.0 ) ) ) {
// if the trimmed point happens to be currently active semaphor we need to invalidate their placements
if( idx == SemNextIndex ) {
SemNextIndex = -1;
}
if( idx == SemNextStopIndex ) {
SemNextStopIndex = -1;
}
continue;
}
// we're left with useful speed point record we should copy
@@ -2246,76 +2257,79 @@ bool TController::ReleaseEngine()
bool TController::IncBrake()
{ // zwiększenie hamowania
bool OK = false;
switch (mvOccupied->BrakeSystem)
{
case Individual:
if (mvOccupied->LocalBrake == ManualBrake)
OK = mvOccupied->IncManualBrakeLevel( 1 + static_cast<int>( std::floor( 0.5 + std::fabs(AccDesired))) );
else
OK = mvOccupied->IncLocalBrakeLevel( std::floor( 1.5 + std::abs( AccDesired ) ) );
break;
case Pneumatic:
// NOTE: can't perform just test whether connected vehicle == nullptr, due to virtual couplers formed with nearby vehicles
if ((mvOccupied->Couplers[0].CouplingFlag == 0) &&
(mvOccupied->Couplers[1].CouplingFlag == 0))
OK = mvOccupied->IncLocalBrakeLevel(
1 + static_cast<int>( std::floor( 0.5 + std::fabs(AccDesired))) ); // hamowanie lokalnym bo luzem jedzie
else
{
if (mvOccupied->BrakeCtrlPos + 1 == mvOccupied->BrakeCtrlPosNo)
{
if (AccDesired < -1.5) // hamowanie nagle
OK = mvOccupied->IncBrakeLevel();
else
OK = false;
switch( mvOccupied->BrakeSystem ) {
case Individual: {
if( mvOccupied->LocalBrake == ManualBrake ) {
OK = mvOccupied->IncManualBrakeLevel( 1 + static_cast<int>( std::floor( 0.5 + std::fabs( AccDesired ) ) ) );
}
else {
OK = mvOccupied->IncLocalBrakeLevel( std::floor( 1.5 + std::abs( AccDesired ) ) );
}
break;
}
case Pneumatic: {
// NOTE: can't perform just test whether connected vehicle == nullptr, due to virtual couplers formed with nearby vehicles
bool standalone{ true };
if( ( mvOccupied->TrainType == dt_ET41 )
|| ( mvOccupied->TrainType == dt_ET42 ) ) {
// NOTE: we're doing simplified checks full of presuptions here.
// they'll break if someone does strange thing like turning around the second unit
if( ( mvOccupied->Couplers[ 1 ].CouplingFlag & coupling::permanent )
&& ( mvOccupied->Couplers[ 1 ].Connected->Couplers[ 1 ].CouplingFlag > 0 ) ) {
standalone = false;
}
if( ( mvOccupied->Couplers[ 0 ].CouplingFlag & coupling::permanent )
&& ( mvOccupied->Couplers[ 0 ].Connected->Couplers[ 0 ].CouplingFlag > 0 ) ) {
standalone = false;
}
}
else {
standalone =
( ( mvOccupied->Couplers[ 0 ].CouplingFlag == 0 )
&& ( mvOccupied->Couplers[ 1 ].CouplingFlag == 0 ) );
}
if( true == standalone ) {
OK = mvOccupied->IncLocalBrakeLevel(
1 + static_cast<int>( std::floor( 0.5 + std::fabs( AccDesired ) ) ) ); // hamowanie lokalnym bo luzem jedzie
}
else {
if( mvOccupied->BrakeCtrlPos + 1 == mvOccupied->BrakeCtrlPosNo ) {
if( AccDesired < -1.5 ) // hamowanie nagle
OK = mvOccupied->IncBrakeLevel();
else
OK = false;
}
else {
// dodane dla towarowego
if( mvOccupied->BrakeDelayFlag == bdelay_G ?
-AccDesired * 6.6 > std::min( 2, mvOccupied->BrakeCtrlPos ) :
true ) {
OK = mvOccupied->IncBrakeLevel();
}
else
OK = false;
}
}
if( mvOccupied->BrakeCtrlPos > 0 ) {
mvOccupied->BrakeReleaser( 0 );
}
break;
}
case ElectroPneumatic: {
if( mvOccupied->EngineType == ElectricInductionMotor ) {
OK = mvOccupied->IncLocalBrakeLevel( 1 );
}
else if( mvOccupied->fBrakeCtrlPos != mvOccupied->Handle->GetPos( bh_EPB ) ) {
mvOccupied->BrakeLevelSet( mvOccupied->Handle->GetPos( bh_EPB ) );
if( mvOccupied->Handle->GetPos( bh_EPR ) - mvOccupied->Handle->GetPos( bh_EPN ) < 0.1 )
mvOccupied->SwitchEPBrake( 1 ); // to nie chce działać
OK = true;
}
else
{
/*
if (AccDesired>-0.2) and ((Vel<20) or (Vel-VelNext<10)))
begin
if BrakeCtrlPos>0)
OK:=IncBrakeLevel
else;
OK:=IncLocalBrakeLevel(1); //finezyjne hamowanie lokalnym
end
else
*/
// dodane dla towarowego
if (mvOccupied->BrakeDelayFlag == bdelay_G ?
-AccDesired * 6.6 > std::min(2, mvOccupied->BrakeCtrlPos) :
true)
{
OK = mvOccupied->IncBrakeLevel();
}
else
OK = false;
}
OK = false;
break;
}
if (mvOccupied->BrakeCtrlPos > 0)
mvOccupied->BrakeReleaser(0);
break;
case ElectroPneumatic:
if (mvOccupied->EngineType == ElectricInductionMotor)
{
OK = mvOccupied->IncLocalBrakeLevel(1);
}
else if (mvOccupied->fBrakeCtrlPos != mvOccupied->Handle->GetPos(bh_EPB))
{
mvOccupied->BrakeLevelSet(mvOccupied->Handle->GetPos(bh_EPB));
if (mvOccupied->Handle->GetPos(bh_EPR) - mvOccupied->Handle->GetPos(bh_EPN) < 0.1)
mvOccupied->SwitchEPBrake(1); // to nie chce działać
OK = true;
}
else
OK = false;
// if (mvOccupied->BrakeCtrlPos<mvOccupied->BrakeCtrlPosNo)
// if
// (mvOccupied->BrakePressureTable[mvOccupied->BrakeCtrlPos+1+2].BrakeType==ElectroPneumatic)
// //+2 to indeks Pascala
// OK=mvOccupied->IncBrakeLevel();
// else
// OK=false;
default: { break; }
}
return OK;
}
@@ -3367,8 +3381,8 @@ bool TController::UpdateSituation(double dt)
}
ElapsedTime += dt;
WaitingTime += dt;
fBrakeTime -=
dt; // wpisana wartość jest zmniejszana do 0, gdy ujemna należy zmienić nastawę hamulca
// wpisana wartość jest zmniejszana do 0, gdy ujemna należy zmienić nastawę hamulca
fBrakeTime -= dt;
fStopTime += dt; // zliczanie czasu postoju, nie ruszy dopóki ujemne
fActionTime += dt; // czas używany przy regulacji prędkości i zamykaniu drzwi
if (WriteLogFlag)
@@ -3386,7 +3400,7 @@ bool TController::UpdateSituation(double dt)
LastUpdatedTime = LastUpdatedTime + dt;
}
// Ra: skanowanie również dla prowadzonego ręcznie, aby podpowiedzieć prędkość
if ((LastReactionTime > Min0R(ReactionTime, 2.0)))
if ((LastReactionTime > std::min(ReactionTime, 2.0)))
{
// Ra: nie wiem czemu ReactionTime potrafi dostać 12 sekund, to jest przegięcie, bo przeżyna
// STÓJ
@@ -3431,18 +3445,48 @@ bool TController::UpdateSituation(double dt)
if (AIControllFlag)
{ // tu bedzie logika sterowania
if (mvOccupied->CommandIn.Command != "")
if (!mvOccupied->RunInternalCommand()) // rozpoznaj komende bo lokomotywa jej nie
// rozpoznaje
if( !mvOccupied->RunInternalCommand() ) {
// rozpoznaj komende bo lokomotywa jej nie rozpoznaje
RecognizeCommand(); // samo czyta komendę wstawioną do pojazdu?
if (mvOccupied->SecuritySystem.Status > 1) // jak zadziałało CA/SHP
if (!mvOccupied->SecuritySystemReset()) // to skasuj
// if
// ((TestFlag(mvOccupied->SecuritySystem.Status,s_ebrake))&&(mvOccupied->BrakeCtrlPos==0)&&(AccDesired>0.0))
if ((TestFlag(mvOccupied->SecuritySystem.Status, s_SHPebrake) ||
TestFlag(mvOccupied->SecuritySystem.Status, s_CAebrake)) &&
(mvOccupied->BrakeCtrlPos == 0) && (AccDesired > 0.0))
mvOccupied->BrakeLevelSet(
0); //!!! hm, może po prostu normalnie sterować hamulcem?
}
if( mvOccupied->SecuritySystem.Status > 1 ) {
// jak zadziałało CA/SHP
if( !mvOccupied->SecuritySystemReset() ) { // to skasuj
if( ( mvOccupied->BrakeCtrlPos == 0 )
&& ( AccDesired > 0.0 )
&& ( ( TestFlag( mvOccupied->SecuritySystem.Status, s_SHPebrake ) )
|| ( TestFlag( mvOccupied->SecuritySystem.Status, s_CAebrake ) ) ) ) {
//!!! hm, może po prostu normalnie sterować hamulcem?
mvOccupied->BrakeLevelSet( 0 );
}
}
}
// basic emergency stop handling, while at it
if( ( true == mvOccupied->EmergencyBrakeFlag ) // radio-stop
&& ( mvOccupied->Vel < 0.01 ) // and actual stop
&& ( true == mvOccupied->Radio ) ) { // and we didn't touch the radio yet
// turning off the radio should reset the flag, during security system check
if( m_radiocontroltime > 2.5 ) {
// arbitrary 2.5 sec delay between stop and disabling the radio
mvOccupied->Radio = false;
m_radiocontroltime = 0.0;
}
else {
m_radiocontroltime += LastReactionTime;
}
}
if( ( false == mvOccupied->Radio )
&& ( false == mvOccupied->EmergencyBrakeFlag ) ) {
// otherwise if it's safe to do so, turn the radio back on
if( m_radiocontroltime > 5.0 ) {
// arbitrary 5 sec delay before switching radio back on
mvOccupied->Radio = true;
m_radiocontroltime = 0.0;
}
else {
m_radiocontroltime += LastReactionTime;
}
}
}
switch (OrderList[OrderPos])
{ // ustalenie prędkości przy doczepianiu i odczepianiu, dystansów w pozostałych przypadkach
@@ -4139,6 +4183,7 @@ bool TController::UpdateSituation(double dt)
->TTVmax); // jesli nie spozniony to nie przekraczać rozkladowej
if (VelDesired > 0.0)
if( ( ( SemNextIndex != -1 )
&& ( SemNextIndex < sSpeedTable.size() ) // BUG: index can point at non-existing slot. investigate reason(s)
&& ( sSpeedTable[SemNextIndex].fVelNext != 0.0 ) )
|| ( ( iDrivigFlags & moveStopHere ) == 0 ) )
{ // jeśli można jechać, to odpalić dźwięk kierownika oraz zamknąć drzwi w

View File

@@ -201,8 +201,7 @@ class TController
public:
double fLastStopExpDist = -1.0; // odległość wygasania ostateniego przystanku
double ReactionTime = 0.0; // czas reakcji Ra: czego i na co? świadomości AI
double fBrakeTime = 0.0; // wpisana wartość jest zmniejszana do 0, gdy ujemna należy zmienić nastawę
// hamulca
double fBrakeTime = 0.0; // wpisana wartość jest zmniejszana do 0, gdy ujemna należy zmienić nastawę hamulca
private:
double fReady = 0.0; // poziom odhamowania wagonów
bool Ready = false; // ABu: stan gotowosci do odjazdu - sprawdzenie odhamowania wagonow
@@ -211,6 +210,7 @@ class TController
double deltalog = 0.05; // przyrost czasu
double LastReactionTime = 0.0;
double fActionTime = 0.0; // czas używany przy regulacji prędkości i zamykaniu drzwi
double m_radiocontroltime{ 0.0 }; // timer used to control speed of radio operations
TAction eAction = actSleep; // aktualny stan
bool HelpMeFlag = false; // wystawiane True jesli cos niedobrego sie dzieje
public:

View File

@@ -1531,14 +1531,6 @@ TDynamicObject::TDynamicObject()
//}
mdModel = NULL;
mdKabina = NULL;
#ifdef EU07_USE_OLD_RENDERCODE
ReplacableSkinID[ 0 ] = 0;
ReplacableSkinID[ 1 ] = 0;
ReplacableSkinID[ 2 ] = 0;
ReplacableSkinID[ 3 ] = 0;
ReplacableSkinID[ 4 ] = 0;
iAlpha = 0x30300030; // tak gdy tekstury wymienne nie mają przezroczystości
#endif
// smWiazary[0]=smWiazary[1]=NULL;
smWahacze[0] = smWahacze[1] = smWahacze[2] = smWahacze[3] = NULL;
fWahaczeAmp = 0;
@@ -1879,8 +1871,7 @@ TDynamicObject::Init(std::string Name, // nazwa pojazdu, np. "EU07-424"
{ // McZapkie-040602: jeśli coś siedzi w pojeździe
if (Name == Global::asHumanCtrlVehicle) // jeśli pojazd wybrany do prowadzenia
{
if (DebugModeFlag ? false : MoverParameters->EngineType !=
Dumb) // jak nie Debugmode i nie jest dumbem
if ( MoverParameters->EngineType != Dumb)
Controller = Humandriver; // wsadzamy tam sterującego
else // w przeciwnym razie trzeba włączyć pokazywanie kabiny
bDisplayCab = true;
@@ -2481,10 +2472,15 @@ bool TDynamicObject::Update(double dt, double dt1)
}
else {
if( MoverParameters->PantPress >= 4.6 ) {
// prime the pressure switch
MoverParameters->PantPressSwitchActive = true;
// turn off the subsystems lock
MoverParameters->PantPressLockActive = false;
// NOTE: we require active low power source to prime the pressure switch
// this is a work-around for potential isssues caused by the switch activating on otherwise idle vehicles, but should check whether it's accurate
if( ( true == MoverParameters->Battery )
|| ( true == MoverParameters->ConverterFlag ) ) {
// prime the pressure switch
MoverParameters->PantPressSwitchActive = true;
// turn off the subsystems lock
MoverParameters->PantPressLockActive = false;
}
if( MoverParameters->PantPress >= 4.8 ) {
// Winger - automatyczne wylaczanie malej sprezarki
@@ -3564,262 +3560,6 @@ void TDynamicObject::TurnOff()
btMechanik1.TurnOff();
btMechanik2.TurnOff();
};
#ifdef EU07_USE_OLD_RENDERCODE
void TDynamicObject::Render()
{ // rysowanie elementów nieprzezroczystych
// youBy - sprawdzamy, czy jest sens renderowac
if (GfxRenderer.Visible(this))
{
TSubModel::iInstance = (size_t)this; //żeby nie robić cudzych animacji
// AnsiString asLoadName="";
double ObjSqrDist = SquareMagnitude(Global::pCameraPosition - vPosition) / Global::ZoomFactor;
ABuLittleUpdate(ObjSqrDist); // ustawianie zmiennych submodeli dla wspólnego modelu
// Cone(vCoulpler[0],modelRot.z,0);
// Cone(vCoulpler[1],modelRot.z,1);
// ActualTrack= GetTrack(); //McZapkie-240702
#if RENDER_CONE
{ // Ra: testowe renderowanie pozycji wózków w postaci ostrosłupów, wymaga
// GLUT32.DLL
double dir = RadToDeg(atan2(vLeft.z, vLeft.x));
Axle0.Render(0);
Axle1.Render(1); // bogieRot[0]
// if (PrevConnected) //renderowanie połączenia
}
#endif
glPushMatrix();
// vector3 pos= vPosition;
// double ObjDist= SquareMagnitude(Global::pCameraPosition-pos);
if (this == Global::pUserDynamic)
{ // specjalne ustawienie, aby nie trzęsło
#ifdef EU07_USE_OLD_LIGHTING_MODEL
if (Global::bSmudge)
{ // jak jest widoczna smuga, to pojazd renderować po
// wyrenderowaniu smugi
glPopMatrix(); // a to trzeba zebrać przed wyjściem
return;
}
#endif
// if (Global::pWorld->) //tu trzeba by ustawić animacje na modelu
// zewnętrznym
glLoadIdentity(); // zacząć od macierzy jedynkowej
Global::pCamera->SetCabMatrix(vPosition); // specjalne ustawienie kamery
}
else
glTranslated(vPosition.x, vPosition.y,
vPosition.z); // standardowe przesunięcie względem początku scenerii
glMultMatrixd(mMatrix.getArray());
#ifdef EU07_USE_OLD_LIGHTING_MODEL
if (fShade > 0.0)
{ // Ra: 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};
// trochę problem z ambientem w wykopie...
for (int li = 0; li < 3; li++)
{
ambientLight[li] = Global::ambientDayLight[li] * fShade;
diffuseLight[li] = Global::diffuseDayLight[li] * fShade;
specularLight[li] = Global::specularDayLight[li] * fShade;
}
glLightfv(GL_LIGHT0, GL_AMBIENT, ambientLight);
glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseLight);
glLightfv(GL_LIGHT0, GL_SPECULAR, specularLight);
}
#else
if( fShade > 0.0f ) {
// change light level based on light level of the occupied track
Global::DayLight.apply_intensity( fShade );
}
#endif
if (Global::bUseVBO)
{ // wersja VBO
if (mdLowPolyInt)
if (FreeFlyModeFlag ? true : !mdKabina || !bDisplayCab)
mdLowPolyInt->RaRender(ObjSqrDist, ReplacableSkinID, iAlpha);
mdModel->RaRender(ObjSqrDist, ReplacableSkinID, iAlpha);
if (mdLoad) // renderowanie nieprzezroczystego ładunku
mdLoad->RaRender(ObjSqrDist, ReplacableSkinID, iAlpha);
}
else
{ // wersja Display Lists
if( mdLowPolyInt ) {
// low poly interior
if( FreeFlyModeFlag ? true : !mdKabina || !bDisplayCab ) {
// enable cab light if needed
if( InteriorLightLevel > 0.0f ) {
// crude way to light the cabin, until we have something more complete in place
auto const cablight = InteriorLight * InteriorLightLevel;
::glLightModelfv( GL_LIGHT_MODEL_AMBIENT, &cablight.x );
}
mdLowPolyInt->Render( ObjSqrDist, ReplacableSkinID, iAlpha );
if( InteriorLightLevel > 0.0f ) {
// reset the overall ambient
GLfloat ambient[] = { 0.0f, 0.0f, 0.0f, 1.0f };
::glLightModelfv( GL_LIGHT_MODEL_AMBIENT, ambient );
}
}
}
mdModel->Render(ObjSqrDist, ReplacableSkinID, iAlpha);
if (mdLoad) // renderowanie nieprzezroczystego ładunku
mdLoad->Render(ObjSqrDist, ReplacableSkinID, iAlpha);
}
// Ra: czy ta kabina tu ma sens?
// Ra: czy nie renderuje się dwukrotnie?
// Ra: dlaczego jest zablokowana w przezroczystych?
if (mdKabina) // jeśli ma model kabiny
if ((mdKabina != mdModel) && bDisplayCab && FreeFlyModeFlag)
{ // rendering kabiny gdy jest oddzielnym modelem i
// ma byc wyswietlana
// ABu: tylko w trybie FreeFly, zwykly tryb w world.cpp
// Ra: świetła są ustawione dla zewnętrza danego pojazdu
#ifdef EU07_USE_OLD_LIGHTING_MODEL
// TODO: re-mplement this
// oswietlenie kabiny
GLfloat ambientCabLight[4] = {0.5f, 0.5f, 0.5f, 1.0f};
GLfloat diffuseCabLight[4] = {0.5f, 0.5f, 0.5f, 1.0f};
GLfloat specularCabLight[4] = {0.5f, 0.5f, 0.5f, 1.0f};
for (int li = 0; li < 3; li++)
{
ambientCabLight[li] = Global::ambientDayLight[li] * 0.9;
diffuseCabLight[li] = Global::diffuseDayLight[li] * 0.5;
specularCabLight[li] = Global::specularDayLight[li] * 0.5;
}
switch (MyTrack->eEnvironment)
{
case e_canyon:
{
for (int li = 0; li < 3; li++)
{
diffuseCabLight[li] *= 0.6f;
specularCabLight[li] *= 0.7f;
}
}
break;
case e_tunnel:
{
for (int li = 0; li < 3; li++)
{
ambientCabLight[li] *= 0.3f;
diffuseCabLight[li] *= 0.1f;
specularCabLight[li] *= 0.2f;
}
}
break;
}
glLightfv(GL_LIGHT0, GL_AMBIENT, ambientCabLight);
glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseCabLight);
glLightfv(GL_LIGHT0, GL_SPECULAR, specularCabLight);
#endif
if (Global::bUseVBO)
mdKabina->RaRender(ObjSqrDist, 0);
else
mdKabina->Render(ObjSqrDist, 0);
#ifdef EU07_USE_OLD_LIGHTING_MODEL
glLightfv(GL_LIGHT0, GL_AMBIENT, Global::ambientDayLight);
glLightfv(GL_LIGHT0, GL_DIFFUSE, Global::diffuseDayLight);
glLightfv(GL_LIGHT0, GL_SPECULAR, Global::specularDayLight);
#endif
}
#ifdef EU07_USE_OLD_LIGHTING_MODEL
if( fShade != 0.0 ) // tylko jeśli było zmieniane
{ // przywrócenie standardowego oświetlenia
glLightfv(GL_LIGHT0, GL_AMBIENT, Global::ambientDayLight);
glLightfv(GL_LIGHT0, GL_DIFFUSE, Global::diffuseDayLight);
glLightfv(GL_LIGHT0, GL_SPECULAR, Global::specularDayLight);
}
#else
if( fShade > 0.0f ) {
// restore regular light level
Global::DayLight.apply_intensity();
}
#endif
glPopMatrix();
if (btnOn)
TurnOff(); // przywrócenie domyślnych pozycji submodeli
} // yB - koniec mieszania z grafika
};
void TDynamicObject::RenderAlpha()
{ // rysowanie elementów półprzezroczystych
if (renderme)
{
TSubModel::iInstance = (size_t)this; //żeby nie robić cudzych animacji
double ObjSqrDist = SquareMagnitude(Global::pCameraPosition - vPosition);
ABuLittleUpdate(ObjSqrDist); // ustawianie zmiennych submodeli dla wspólnego modelu
glPushMatrix();
if (this == Global::pUserDynamic)
{ // specjalne ustawienie, aby nie trzęsło
glPopMatrix(); // to trzeba zebrać przed wyściem
return;
glLoadIdentity(); // zacząć od macierzy jedynkowej
Global::pCamera->SetCabMatrix(vPosition); // specjalne ustawienie kamery
}
else
glTranslated(vPosition.x, vPosition.y,
vPosition.z); // standardowe przesunięcie względem początku scenerii
glMultMatrixd(mMatrix.getArray());
#ifdef EU07_USE_OLD_LIGHTING_MODEL
// TODO: re-implement this
if (fShade > 0.0)
{ // Ra: 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};
// trochę problem z ambientem w wykopie...
for (int li = 0; li < 3; li++)
{
ambientLight[li] = Global::ambientDayLight[li] * fShade;
diffuseLight[li] = Global::diffuseDayLight[li] * fShade;
specularLight[li] = Global::specularDayLight[li] * fShade;
}
glLightfv(GL_LIGHT0, GL_AMBIENT, ambientLight);
glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseLight);
glLightfv(GL_LIGHT0, GL_SPECULAR, specularLight);
}
#endif
if (Global::bUseVBO)
{ // wersja VBO
if (mdLowPolyInt)
if (FreeFlyModeFlag ? true : !mdKabina || !bDisplayCab)
mdLowPolyInt->RaRenderAlpha(ObjSqrDist, ReplacableSkinID, iAlpha);
mdModel->RaRenderAlpha(ObjSqrDist, ReplacableSkinID, iAlpha);
if (mdLoad)
mdLoad->RaRenderAlpha(ObjSqrDist, ReplacableSkinID, iAlpha);
}
else
{ // wersja Display Lists
if (mdLowPolyInt)
if (FreeFlyModeFlag ? true : !mdKabina || !bDisplayCab)
mdLowPolyInt->RenderAlpha(ObjSqrDist, ReplacableSkinID, iAlpha);
mdModel->RenderAlpha(ObjSqrDist, ReplacableSkinID, iAlpha);
if (mdLoad)
mdLoad->RenderAlpha(ObjSqrDist, ReplacableSkinID, iAlpha);
}
#ifdef EU07_USE_OLD_LIGHTING_MODEL
// TODO: re-implement this
if (fShade != 0.0) // tylko jeśli było zmieniane
{ // przywrócenie standardowego oświetlenia
glLightfv(GL_LIGHT0, GL_AMBIENT, Global::ambientDayLight);
glLightfv(GL_LIGHT0, GL_DIFFUSE, Global::diffuseDayLight);
glLightfv(GL_LIGHT0, GL_SPECULAR, Global::specularDayLight);
}
#endif
glPopMatrix();
if (btnOn)
TurnOff(); // przywrócenie domyślnych pozycji submodeli
}
return;
} // koniec renderalpha
#endif
void TDynamicObject::RenderSounds()
{ // przeliczanie dźwięków, bo będzie słychać bez wyświetlania sektora z pojazdem
@@ -4211,26 +3951,6 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName,
if( token == "models:") {
// modele i podmodele
#ifdef EU07_USE_OLD_RENDERCODE
iMultiTex = 0; // czy jest wiele tekstur wymiennych?
parser.getTokens();
parser >> asModel;
if( asModel[asModel.size() - 1] == '#' ) // Ra 2015-01: nie podoba mi siê to
{ // model wymaga wielu tekstur wymiennych
iMultiTex = 1;
asModel.erase( asModel.length() - 1 );
}
std::size_t i = asModel.find( ',' );
if ( i != std::string::npos )
{ // Ra 2015-01: może szukać przecinka w nazwie modelu, a po przecinku była by liczba tekstur?
if (i < asModel.length())
iMultiTex = asModel[i + 1] - '0';
if (iMultiTex < 0)
iMultiTex = 0;
else if (iMultiTex > 1)
iMultiTex = 1; // na razie ustawiamy na 1
}
#else
m_materialdata.multi_textures = 0; // czy jest wiele tekstur wymiennych?
parser.getTokens();
parser >> asModel;
@@ -4246,71 +3966,13 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName,
m_materialdata.multi_textures = asModel[i + 1] - '0';
m_materialdata.multi_textures = clamp( m_materialdata.multi_textures, 0, 1 ); // na razie ustawiamy na 1
}
#endif
asModel = BaseDir + asModel; // McZapkie 2002-07-20: dynamics maja swoje
// modele w dynamics/basedir
Global::asCurrentTexturePath = BaseDir; // biezaca sciezka do tekstur to dynamic/...
mdModel = TModelsManager::GetModel(asModel, true);
assert( mdModel != nullptr ); // TODO: handle this more gracefully than all going to shit
if (ReplacableSkin != "none")
#ifdef EU07_USE_OLD_RENDERCODE
{ // tekstura wymienna jest raczej jedynie w "dynamic\"
ReplacableSkin =
Global::asCurrentTexturePath + ReplacableSkin; // skory tez z dynamic/...
std::string x = TextureTest(Global::asCurrentTexturePath + "nowhere"); // na razie prymitywnie
if (!x.empty())
ReplacableSkinID[4] = GfxRenderer.GetTextureId( Global::asCurrentTexturePath + "nowhere", "", 9);
if (iMultiTex > 0)
{ // jeśli model ma 4 tekstury
ReplacableSkinID[1] = GfxRenderer.GetTextureId(
ReplacableSkin + ",1", "", Global::iDynamicFiltering);
if (ReplacableSkinID[1])
{ // pierwsza z zestawu znaleziona
ReplacableSkinID[2] = GfxRenderer.GetTextureId(
ReplacableSkin + ",2", "", Global::iDynamicFiltering);
if (ReplacableSkinID[2])
{
iMultiTex = 2; // już są dwie
ReplacableSkinID[3] = GfxRenderer.GetTextureId(
ReplacableSkin + ",3", "", Global::iDynamicFiltering);
if (ReplacableSkinID[3])
{
iMultiTex = 3; // a teraz nawet trzy
ReplacableSkinID[4] = GfxRenderer.GetTextureId(
ReplacableSkin + ",4", "", Global::iDynamicFiltering);
if (ReplacableSkinID[4])
iMultiTex = 4; // jak są cztery, to blokujemy podmianę tekstury rozkładem
}
}
}
else
{ // zestaw nie zadziałał, próbujemy normanie
iMultiTex = 0;
ReplacableSkinID[1] = GfxRenderer.GetTextureId(
ReplacableSkin, "", Global::iDynamicFiltering);
}
}
else
ReplacableSkinID[1] = GfxRenderer.GetTextureId(
ReplacableSkin, "", Global::iDynamicFiltering);
if (GfxRenderer.Texture(ReplacableSkinID[1]).has_alpha)
iAlpha = 0x31310031; // tekstura -1 z kanałem alfa - nie renderować w cyklu nieprzezroczystych
else
iAlpha = 0x30300030; // wszystkie tekstury nieprzezroczyste - nie renderować w cyklu przezroczystych
if (ReplacableSkinID[2])
if (GfxRenderer.Texture(ReplacableSkinID[2]).has_alpha)
iAlpha |= 0x02020002; // tekstura -2 z kanałem alfa - nie renderować w cyklu nieprzezroczystych
if (ReplacableSkinID[3])
if (GfxRenderer.Texture(ReplacableSkinID[3]).has_alpha)
iAlpha |= 0x04040004; // tekstura -3 z kanałem alfa - nie renderować w cyklu nieprzezroczystych
if (ReplacableSkinID[4])
if (GfxRenderer.Texture(ReplacableSkinID[4]).has_alpha)
iAlpha |= 0x08080008; // tekstura -4 z kanałem alfa - nie renderować w cyklu nieprzezroczystych
}
#else
{ // tekstura wymienna jest raczej jedynie w "dynamic\"
// ReplacableSkin = Global::asCurrentTexturePath + ReplacableSkin; // skory tez z dynamic/...
{
std::string nowheretexture = TextureTest(Global::asCurrentTexturePath + "nowhere"); // na razie prymitywnie
if( false == nowheretexture.empty() ) {
m_materialdata.replacable_skins[ 4 ] = GfxRenderer.GetTextureId( nowheretexture, "", 9 );
@@ -4365,7 +4027,6 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName,
if( GfxRenderer.Texture( m_materialdata.replacable_skins[ 4 ] ).has_alpha )
m_materialdata.textures_alpha |= 0x08080008; // tekstura -4 z kanałem alfa - nie renderować w cyklu nieprzezroczystych
}
#endif
if (!MoverParameters->LoadAccepted.empty())
// if (MoverParameters->LoadAccepted!=AnsiString("")); // &&
// MoverParameters->LoadType!=AnsiString("passengers"))
@@ -5072,7 +4733,7 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName,
// plik z przyspieszaczem (upust po zlapaniu hamowania)
// sBrakeAcc.Init(str.c_str(),Parser->GetNextSymbol().ToDouble(),GetPosition().x,GetPosition().y,GetPosition().z,true);
parser.getTokens( 1, false ); parser >> token;
sBrakeAcc = TSoundsManager::GetFromName( token.c_str(), true );
sBrakeAcc = TSoundsManager::GetFromName( token, true );
bBrakeAcc = true;
// sBrakeAcc.AM=1.0;
// sBrakeAcc.AA=0.0;
@@ -5577,22 +5238,27 @@ TDynamicObject * TDynamicObject::ControlledFind()
// jeździć dobrze
// również hamowanie wykonuje się zaworem w członie, a nie w silnikowym...
TDynamicObject *d = this; // zaczynamy od aktualnego
if (d->MoverParameters->TrainType & dt_EZT) // na razie dotyczy to EZT
if (d->NextConnected ? d->MoverParameters->Couplers[1].AllowedFlag & ctrain_depot : false)
{ // gdy jest człon od sprzęgu 1, a sprzęg łączony
// warsztatowo (powiedzmy)
if ((d->MoverParameters->Power < 1.0) && (d->NextConnected->MoverParameters->Power >
1.0)) // my nie mamy mocy, ale ten drugi ma
if( d->MoverParameters->TrainType & dt_EZT ) {
// na razie dotyczy to EZT
if( ( d->NextConnected != nullptr )
&& ( true == TestFlag( d->MoverParameters->Couplers[ 1 ].AllowedFlag, coupling::permanent ) ) ) {
// gdy jest człon od sprzęgu 1, a sprzęg łączony warsztatowo (powiedzmy)
if( ( d->MoverParameters->Power < 1.0 )
&& ( d->NextConnected->MoverParameters->Power > 1.0 ) ) {
// my nie mamy mocy, ale ten drugi ma
d = d->NextConnected; // będziemy sterować tym z mocą
}
}
else if (d->PrevConnected ? d->MoverParameters->Couplers[0].AllowedFlag & ctrain_depot :
false)
{ // gdy jest człon od sprzęgu 0, a sprzęg łączony
// warsztatowo (powiedzmy)
if ((d->MoverParameters->Power < 1.0) && (d->PrevConnected->MoverParameters->Power >
1.0)) // my nie mamy mocy, ale ten drugi ma
else if( ( d->PrevConnected != nullptr )
&& ( true == TestFlag( d->MoverParameters->Couplers[ 0 ].AllowedFlag, coupling::permanent ) ) ) {
// gdy jest człon od sprzęgu 0, a sprzęg łączony warsztatowo (powiedzmy)
if( ( d->MoverParameters->Power < 1.0 )
&& ( d->PrevConnected->MoverParameters->Power > 1.0 ) ) {
// my nie mamy mocy, ale ten drugi ma
d = d->PrevConnected; // będziemy sterować tym z mocą
}
}
}
return d;
};
//---------------------------------------------------------------------------
@@ -5656,62 +5322,16 @@ std::string TDynamicObject::TextureTest(std::string const &name)
return ""; // nie znaleziona
};
#ifdef EU07_USE_OLD_RENDERCODE
void TDynamicObject::DestinationSet(std::string to, std::string numer)
{ // ustawienie stacji
// docelowej oraz wymiennej
// tekstury 4, jeśli
// istnieje plik
// w zasadzie, to każdy wagon mógłby mieć inną stację docelową
// zwłaszcza w towarowych, pod kątem zautomatyzowania maewrów albo pracy górki
// ale to jeszcze potrwa, zanim będzie możliwe, na razie można wpisać stację z
// rozkładu
if (abs(iMultiTex) >= 4)
return; // jak są 4 tekstury wymienne, to nie zmieniać rozkładem
numer = Global::Bezogonkow(numer);
asDestination = to;
to = Global::Bezogonkow(to); // do szukania pliku obcinamy ogonki
std::string x = TextureTest(asBaseDir + numer + "@" + MoverParameters->TypeName);
if (!x.empty())
{
ReplacableSkinID[4] = GfxRenderer.GetTextureId( x, "", 9); // rozmywania 0,1,4,5 nie nadają się
return;
}
x = TextureTest(asBaseDir + numer );
if (!x.empty())
{
ReplacableSkinID[4] = GfxRenderer.GetTextureId( x, "", 9); // rozmywania 0,1,4,5 nie nadają się
return;
}
if (to.empty())
to = "nowhere";
x = TextureTest(asBaseDir + to + "@" + MoverParameters->TypeName); // w pierwszej kolejności z nazwą FIZ/MMD
if (!x.empty())
{
ReplacableSkinID[4] = GfxRenderer.GetTextureId( x, "", 9); // rozmywania 0,1,4,5 nie nadają się
return;
}
x = TextureTest(asBaseDir + to); // na razie prymitywnie
if (!x.empty())
ReplacableSkinID[4] = GfxRenderer.GetTextureId( x, "", 9); // rozmywania 0,1,4,5 nie nadają się
else
{
x = TextureTest(asBaseDir + "nowhere"); // jak nie znalazł dedykowanej, to niech daje nowhere
if (!x.empty())
ReplacableSkinID[4] = GfxRenderer.GetTextureId( x, "", 9);
}
// Ra 2015-01: żeby zalogować błąd, trzeba by mieć pewność, że model używa
// tekstury nr 4
};
#else
void TDynamicObject::DestinationSet(std::string to, std::string numer)
{ // ustawienie stacji docelowej oraz wymiennej tekstury 4, jeśli istnieje plik
// w zasadzie, to każdy wagon mógłby mieć inną stację docelową
// zwłaszcza w towarowych, pod kątem zautomatyzowania maewrów albo pracy górki
// ale to jeszcze potrwa, zanim będzie możliwe, na razie można wpisać stację z
// rozkładu
if( std::abs( m_materialdata.multi_textures ) >= 4 )
return; // jak są 4 tekstury wymienne, to nie zmieniać rozkładem
if( std::abs( m_materialdata.multi_textures ) >= 4 ) {
// jak są 4 tekstury wymienne, to nie zmieniać rozkładem
return;
}
numer = Global::Bezogonkow(numer);
asDestination = to;
to = Global::Bezogonkow(to); // do szukania pliku obcinamy ogonki
@@ -5744,10 +5364,8 @@ void TDynamicObject::DestinationSet(std::string to, std::string numer)
if (!x.empty())
m_materialdata.replacable_skins[ 4 ] = GfxRenderer.GetTextureId( x, "", 9 );
}
// Ra 2015-01: żeby zalogować błąd, trzeba by mieć pewność, że model używa
// tekstury nr 4
// Ra 2015-01: żeby zalogować błąd, trzeba by mieć pewność, że model używa tekstury nr 4
};
#endif
void TDynamicObject::OverheadTrack(float o)
{ // ewentualne wymuszanie jazdy

View File

@@ -137,11 +137,8 @@ class TAnim
void Parovoz(); // wykonanie obliczeń animacji
};
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
#ifndef EU07_USE_OLD_RENDERCODE
// parameters for the material object, as currently used by various simulator models
struct material_data {
@@ -153,7 +150,6 @@ struct material_data {
::SecureZeroMemory( replacable_skins, sizeof( replacable_skins ) );
}
};
#endif
class TDynamicObject { // klasa pojazdu
@@ -200,15 +196,11 @@ public: // modele składowe pojazdu
float fShade; // zacienienie: 0:normalnie, -1:w ciemności, +1:dodatkowe światło (brak koloru?)
private: // zmienne i metody do animacji submodeli; Ra: sprzatam animacje w pojeździe
#ifndef EU07_USE_OLD_RENDERCODE
material_data m_materialdata;
#endif
public:
#ifndef EU07_USE_OLD_RENDERCODE
inline
material_data const *Material() const { return &m_materialdata; }
#endif
material_data const *Material() const { return &m_materialdata; }
// tymczasowo udostępnione do wyszukiwania drutu
int iAnimType[ ANIM_TYPES ]; // 0-osie,1-drzwi,2-obracane,3-zderzaki,4-wózki,5-pantografy,6-tłoki
private:
@@ -421,11 +413,6 @@ public: // modele składowe pojazdu
int iCabs; // maski bitowe modeli kabin
TTrack *MyTrack; // McZapkie-030303: tor na ktorym stoi, ABu
std::string asBaseDir;
#ifdef EU07_USE_OLD_RENDERCODE
texture_manager::size_type ReplacableSkinID[5]; // McZapkie:zmienialne nadwozie
int iAlpha; // maska przezroczystości tekstur
int iMultiTex; //<0 tekstury wskazane wpisem, >0 tekstury z przecinkami, =0 jedna
#endif
int iOverheadMask; // maska przydzielana przez AI pojazdom posiadającym pantograf, aby wymuszały
// jazdę bezprądową
TTractionParam tmpTraction;
@@ -444,10 +431,6 @@ public: // modele składowe pojazdu
bool FastUpdate(double dt);
void Move(double fDistance);
void FastMove(double fDistance);
#ifdef EU07_USE_OLD_RENDERCODE
void Render();
void RenderAlpha();
#endif
void RenderSounds();
inline vector3 GetPosition() const
{

View File

@@ -9,7 +9,6 @@ http://mozilla.org/MPL/2.0/.
/*
MaSzyna EU07 locomotive simulator
Copyright (C) 2001-2004 Marcin Wozniak, Maciej Czapkiewicz and others
*/
/*
Authors:
@@ -383,9 +382,15 @@ int main(int argc, char *argv[])
input::Gamepad.init();
Global::pWorld = &World; // Ra: wskaźnik potrzebny do usuwania pojazdów
if (!World.Init(window))
{
ErrorLog( "Failed to init TWorld" );
try {
if( false == World.Init( window ) ) {
ErrorLog( "Failed to init TWorld" );
return -1;
}
}
catch( std::bad_alloc const &Error ) {
ErrorLog( "Critical error, memory allocation failure: " + std::string( Error.what() ) );
return -1;
}
@@ -406,13 +411,23 @@ int main(int argc, char *argv[])
} // po zrobieniu E3D odpalamy normalnie scenerię, by ją zobaczyć
Console::On(); // włączenie konsoli
while (!glfwWindowShouldClose(window)
&& World.Update()
&& GfxRenderer.Render())
{
glfwPollEvents();
input::Gamepad.poll();
try {
while( ( false == glfwWindowShouldClose( window ) )
&& ( true == World.Update() )
&& ( true == GfxRenderer.Render() ) ) {
glfwPollEvents();
if( true == Global::InputGamepad ) {
input::Gamepad.poll();
}
}
}
catch( std::bad_alloc const &Error ) {
ErrorLog( "Critical error, memory allocation failure: " + std::string( Error.what() ) );
return -1;
}
Console::Off(); // wyłączenie konsoli (komunikacji zwrotnej)
}

View File

@@ -610,14 +610,32 @@ void TEvent::Load(cParser *parser, vector3 *org)
}
};
void TEvent::AddToQuery(TEvent *e)
{ // dodanie eventu do kolejki
if (evNext ? (e->fStartTime >= evNext->fStartTime) : false)
evNext->AddToQuery(e); // sortowanie wg czasu
else
{ // dodanie z przodu
e->evNext = evNext;
evNext = e;
void TEvent::AddToQuery( TEvent *Event, TEvent *&Start ) {
TEvent *target( Start );
TEvent *previous( nullptr );
while( ( Event->fStartTime >= target->fStartTime )
&& ( target->evNext != nullptr ) ) {
previous = target;
target = target->evNext;
}
// the new event will be either before or after the one we located
if( Event->fStartTime >= target->fStartTime ) {
assert( target->evNext == nullptr );
target->evNext = Event;
// if we have resurrected event land at the end of list, the link from previous run could potentially "add" unwanted events to the queue
Event->evNext = nullptr;
}
else {
if( previous != nullptr ) {
previous->evNext = Event;
Event->evNext = target;
}
else {
// special case, we're inserting our event before the provided start point
Event->evNext = Start;
Start = Event;
}
}
}

View File

@@ -105,7 +105,7 @@ class TEvent // zmienne: ev*
~TEvent();
void Init();
void Load(cParser *parser, vector3 *org);
void AddToQuery(TEvent *e);
static void AddToQuery( TEvent *Event, TEvent *&Start );
std::string CommandGet();
TCommandType Command();
double ValueGet(int n);

View File

@@ -25,7 +25,7 @@ void TFadeSound::Free()
{
}
void TFadeSound::Init(char *Name, float fNewFade)
void TFadeSound::Init(std::string const &Name, float fNewFade)
{
Sound = TSoundsManager::GetFromName(Name, false);
if (Sound)

View File

@@ -24,7 +24,7 @@ class TFadeSound
public:
TFadeSound();
~TFadeSound();
void Init(char *Name, float fNewFade);
void Init(std::string const &Name, float fNewFade);
void TurnOn();
void TurnOff();
bool Playing()

View File

@@ -83,17 +83,8 @@ GLfloat Global::FogColor[] = {0.6f, 0.7f, 0.8f};
double Global::fFogStart = 1700;
double Global::fFogEnd = 2000;
float Global::Overcast{ 0.1f }; // NOTE: all this weather stuff should be moved elsewhere
#ifdef EU07_USE_OLD_LIGHTING_MODEL
GLfloat Global::ambientDayLight[] = {0.40f, 0.40f, 0.45f, 1.0f}; // robocze
GLfloat Global::diffuseDayLight[] = {0.55f, 0.54f, 0.50f, 1.0f};
GLfloat Global::specularDayLight[] = {0.95f, 0.94f, 0.90f, 1.0f};
GLfloat Global::ambientLight[] = {0.80f, 0.80f, 0.85f, 1.0f}; // stałe
GLfloat Global::diffuseLight[] = {0.85f, 0.85f, 0.80f, 1.0f};
GLfloat Global::specularLight[] = {0.95f, 0.94f, 0.90f, 1.0f};
#else
opengl_light Global::DayLight;
int Global::DynamicLightCount{ 3 };
#endif
GLfloat Global::whiteLight[] = {1.00f, 1.00f, 1.00f, 1.0f};
GLfloat Global::noLight[] = {0.00f, 0.00f, 0.00f, 1.0f};
GLfloat Global::darkLight[] = {0.03f, 0.03f, 0.03f, 1.0f}; //śladowe
@@ -110,6 +101,7 @@ int Global::iWindowHeight = 600;
float Global::fDistanceFactor = Global::ScreenHeight / 768.0; // baza do przeliczania odległości dla LoD
int Global::iFeedbackMode = 1; // tryb pracy informacji zwrotnej
int Global::iFeedbackPort = 0; // dodatkowy adres dla informacji zwrotnych
bool Global::InputGamepad{ true };
bool Global::bFreeFly = false;
bool Global::bFullScreen = false;
bool Global::VSync{ false };
@@ -801,6 +793,11 @@ void Global::ConfigParse(cParser &Parser)
>> Global::Background[1] // g
>> Global::Background[2]; // b
}
else if( token == "input.gamepad" ) {
// czy grupować eventy o tych samych nazwach
Parser.getTokens();
Parser >> Global::InputGamepad;
}
// maciek001: ustawienia MWD
else if (token == "mwdmasterenable") { // główne włączenie maszyny!
Parser.getTokens();

View File

@@ -221,20 +221,11 @@ class Global
static GLfloat FogColor[];
static float Overcast;
// static bool bTimeChange;
#ifdef EU07_USE_OLD_LIGHTING_MODEL
static opengl_light AmbientLight;
static GLfloat ambientDayLight[];
static GLfloat diffuseDayLight[];
static GLfloat specularDayLight[];
static GLfloat ambientLight[];
static GLfloat diffuseLight[];
static GLfloat specularLight[];
#else
// TODO: put these things in the renderer
static opengl_light DayLight;
static int DynamicLightCount;
#endif
static GLfloat whiteLight[];
static GLfloat noLight[];
static GLfloat darkLight[];
@@ -255,6 +246,7 @@ class Global
static std::string LastGLError;
static int iFeedbackMode; // tryb pracy informacji zwrotnej
static int iFeedbackPort; // dodatkowy adres dla informacji zwrotnych
static bool InputGamepad; // whether gamepad support is enabled
static double fLuminance; // jasność światła do automatycznego zapalania
static float SunAngle; // angle of the sun relative to horizon
static int iMultiplayer; // blokada działania niektórych eventów na rzecz kominikacji
@@ -287,7 +279,6 @@ class Global
static int iKeyLast; // ostatnio naciśnięty klawisz w celu logowania
static int iPause; // globalna pauza ruchu: b0=start,b1=klawisz,b2=tło,b3=lagi,b4=wczytywanie
static bool bActive; // czy jest aktywnym oknem
static void BindTexture(GLuint t);
static int iConvertModels; // tworzenie plików binarnych
static int iErorrCounter; // licznik sprawdzań do śledzenia błędów OpenGL
static bool bInactivePause; // automatyczna pauza, gdy okno nieaktywne

File diff suppressed because it is too large Load Diff

View File

@@ -122,19 +122,20 @@ public:
TGroundNode *nNode; // obiekt renderujący grupowo ma tu wskaźnik na listę obiektów
};
std::string asName; // nazwa (nie zawsze ma znaczenie)
vector3 pCenter; // współrzędne środka do przydzielenia sektora
vector3 m_rootposition; // position of the ground (sub)rectangle holding the node, in the 3d world
// visualization-related data
// TODO: wrap these in a struct, when cleaning objects up
union
{
int iNumVerts; // dla trójkątów
int iNumPts; // dla linii
int iCount; // dla terenu
// int iState; //Ra: nie używane - dźwięki zapętlone
};
vector3 pCenter; // współrzędne środka do przydzielenia sektora
double fLineThickness; // McZapkie-120702: grubosc linii
double fSquareRadius; // kwadrat widoczności do
double fSquareMinRadius; // kwadrat widoczności od
// TGroundNode *nMeshGroup; //Ra: obiekt grupujący trójkąty w TSubRect dla tekstury
int iVersion; // wersja siatki (do wykonania rekompilacji)
// union ?
GLuint DisplayListID; // numer siatki DisplayLists
@@ -144,6 +145,7 @@ public:
int iFlags; // tryb przezroczystości: 0x10-nieprz.,0x20-przezroczysty,0x30-mieszany
int Ambient[4], Diffuse[4], Specular[4]; // oświetlenie
bool bVisible;
TGroundNode *nNext; // lista wszystkich w scenerii, ostatni na początku
TGroundNode *nNext2; // lista obiektów w sektorze
TGroundNode *nNext3; // lista obiektów renderowanych we wspólnym cyklu
@@ -154,8 +156,6 @@ public:
void InitCenter(); // obliczenie współrzędnych środka
void InitNormals();
void MoveMe(vector3 pPosition); // przesuwanie (nie działa)
// bool Disable();
inline TGroundNode * Find(const std::string &asNameToFind, TGroundNodeType iNodeType)
{ // wyszukiwanie czołgowe z typem
@@ -166,7 +166,7 @@ public:
return NULL;
};
void Compile(bool many = false);
void Compile(Math3D::vector3 const &Origin, bool const Multiple = false);
void Release();
void RenderHidden(); // obsługa dźwięków i wyzwalaczy zdarzeń
@@ -177,7 +177,7 @@ public:
struct bounding_area {
float3 center; // mid point of the rectangle
glm::vec3 center; // mid point of the rectangle
float radius{ 0.0f }; // radius of the bounding sphere
};
@@ -192,8 +192,8 @@ class TSubRect : public Resource, public CMesh
TGroundNode *nRootMesh = nullptr; // obiekty renderujące wg tekstury (wtórne, lista po nNext2)
TGroundNode *nMeshed = nullptr; // lista obiektów dla których istnieją obiekty renderujące grupowo
public:
TGroundNode * nRootNode = nullptr; // wszystkie obiekty w sektorze, z wyjątkiem renderujących i pojazdów (nNext2)
TGroundNode * nRenderHidden = nullptr; // lista obiektów niewidocznych, "renderowanych" również z tyłu (nNext3)
TGroundNode *nRootNode = nullptr; // wszystkie obiekty w sektorze, z wyjątkiem renderujących i pojazdów (nNext2)
TGroundNode *nRenderHidden = nullptr; // lista obiektów niewidocznych, "renderowanych" również z tyłu (nNext3)
TGroundNode *nRenderRect = nullptr; // z poziomu sektora - nieprzezroczyste (nNext3)
TGroundNode *nRenderRectAlpha = nullptr; // z poziomu sektora - przezroczyste (nNext3)
TGroundNode *nRenderWires = nullptr; // z poziomu sektora - druty i inne linie (nNext3)
@@ -217,11 +217,6 @@ class TSubRect : public Resource, public CMesh
bool StartVBO(); // ustwienie VBO sektora dla (nRenderRect), (nRenderRectAlpha) i (nRenderWires)
bool RaTrackAnimAdd(TTrack *t); // zgłoszenie toru do animacji
void RaAnimate(); // przeliczenie animacji torów
void RenderDL(); // renderowanie nieprzezroczystych w Display Lists
void RenderAlphaDL(); // renderowanie przezroczystych w Display Lists
// (McZapkie-131202)
void RenderVBO(); // renderowanie nieprzezroczystych z własnego VBO
void RenderAlphaVBO(); // renderowanie przezroczystych z (własnego) VBO
void RenderSounds(); // dźwięki pojazdów z niewidocznych sektorów
};
@@ -238,6 +233,8 @@ class TGroundRect : public TSubRect
{ // kwadrat kilometrowy
// obiekty o niewielkiej ilości wierzchołków będą renderowane stąd
// Ra: 2012-02 doszły submodele terenu
friend class opengl_renderer;
private:
int iLastDisplay; // numer klatki w której był ostatnio wyświetlany
TSubRect *pSubRects{ nullptr };
@@ -264,8 +261,6 @@ class TGroundRect : public TSubRect
for (int i = iNumSubRects * iNumSubRects - 1; i >= 0; --i)
pSubRects[i].Sort(); // optymalizacja obiektów w sektorach
};
void RenderDL();
void RenderVBO();
};
class TGround
@@ -279,9 +274,7 @@ class TGround
TGroundRect Rects[iNumRects][iNumRects]; // mapa kwadratów kilometrowych
TEvent *RootEvent = nullptr; // lista zdarzeń
TEvent *QueryRootEvent = nullptr,
*tmpEvent = nullptr,
*tmp2Event = nullptr,
*OldQRE = nullptr;
*tmpEvent = nullptr;
TSubRect *pRendered[1500]; // lista renderowanych sektorów
int iNumNodes = 0;
vector3 pOrigin;
@@ -341,16 +334,15 @@ class TGround
{
return &Rects[GetColFromX(x) / iNumSubRects][GetRowFromZ(z) / iNumSubRects];
};
TSubRect * GetSubRect( int iCol, int iRow );
TSubRect * GetSubRect(double x, double z)
{
return GetSubRect(GetColFromX(x), GetRowFromZ(z));
};
TSubRect * FastGetSubRect(double x, double z)
{
return FastGetSubRect(GetColFromX(x), GetRowFromZ(z));
TSubRect * FastGetSubRect( int iCol, int iRow );
TSubRect * FastGetSubRect( double x, double z ) {
return FastGetSubRect( GetColFromX( x ), GetRowFromZ( z ) );
};
TSubRect * GetSubRect(int iCol, int iRow);
TSubRect * FastGetSubRect(int iCol, int iRow);
int GetRowFromZ(double z)
{
return (int)(z / fSubRectSize + fHalfTotalNumSubRects);

View File

@@ -847,12 +847,14 @@ public:
bool CompressorFlag = false; /*!o czy wlaczona sprezarka*/
bool PantCompFlag = false; /*!o czy wlaczona sprezarka pantografow*/
bool CompressorAllow = false; /*! zezwolenie na uruchomienie sprezarki NBMX*/
bool CompressorAllowLocal{ true }; // local device state override (most units don't have this fitted so it's set to true not to intefere)
bool CompressorGovernorLock{ false }; // indicates whether compressor pressure switch was activated due to reaching cut-out pressure
// TODO converter parameters, for when we start cleaning up mover parameters
start ConverterStart{ manual }; // whether converter is started manually, or by other means
float ConverterStartDelay{ 0.0f }; // delay (in seconds) before the converter is started, once its activation conditions are met
double ConverterStartDelayTimer{ 0.0 }; // helper, for tracking whether converter start delay passed
bool ConverterAllow = false; /*zezwolenie na prace przetwornicy NBMX*/
bool ConverterAllowLocal{ true }; // local device state override (most units don't have this fitted so it's set to true not to intefere)
bool ConverterFlag = false; /*! czy wlaczona przetwornica NBMX*/
int BrakeCtrlPos = -2; /*nastawa hamulca zespolonego*/
@@ -978,8 +980,10 @@ public:
int PantRearStart = 0;
double PantFrontVolt = 0.0; //pantograf pod napieciem? 'Winger 160404
double PantRearVolt = 0.0;
// TODO: move these switch types where they belong, cabin definition
std::string PantSwitchType;
std::string ConvSwitchType;
std::string StLinSwitchType;
bool Heating = false; //ogrzewanie 'Winger 020304
int DoubleTr = 1; //trakcja ukrotniona - przedni pojazd 'Winger 160304

View File

@@ -1565,6 +1565,7 @@ double TMoverParameters::ShowEngineRotation(int VehN)
void TMoverParameters::ConverterCheck( double const Timestep ) {
// TODO: move other converter checks here, to have it all in one place for potential device object
if( ( ConverterAllow )
&& ( ConverterAllowLocal )
&& ( false == PantPressLockActive )
&& ( Mains ) ) {
// delay timer can be optionally configured, and is set anew whenever converter goes off
@@ -3018,7 +3019,7 @@ void TMoverParameters::CompressorCheck(double dt)
if (MaxCompressor - MinCompressor < 0.0001)
{
// if (Mains && (MainCtrlPos > 1))
if (CompressorAllow && Mains && (MainCtrlPos > 0))
if (CompressorAllow && CompressorAllowLocal && Mains && (MainCtrlPos > 0))
{
if (Compressor < MaxCompressor)
if ((EngineType == DieselElectric) && (CompressorPower > 0))
@@ -3048,8 +3049,10 @@ void TMoverParameters::CompressorCheck(double dt)
{ // zasilanie sprężarki w członie ra z członu silnikowego (sprzęg 1)
if (Couplers[1].Connected != NULL)
CompressorFlag =
(Couplers[1].Connected->CompressorAllow &&
Couplers[1].Connected->ConverterFlag && Couplers[1].Connected->Mains);
( Couplers[ 1 ].Connected->CompressorAllow
&& Couplers[ 1 ].Connected->CompressorAllowLocal
&& Couplers[ 1 ].Connected->Mains
&& Couplers[ 1 ].Connected->ConverterFlag );
else
CompressorFlag = false; // bez tamtego członu nie zadziała
}
@@ -3057,62 +3060,116 @@ void TMoverParameters::CompressorCheck(double dt)
{ // zasilanie sprężarki w członie ra z członu silnikowego (sprzęg 1)
if (Couplers[0].Connected != NULL)
CompressorFlag =
(Couplers[0].Connected->CompressorAllow &&
Couplers[0].Connected->ConverterFlag && Couplers[0].Connected->Mains);
( Couplers[ 0 ].Connected->CompressorAllow
&& Couplers[ 0 ].Connected->CompressorAllowLocal
&& Couplers[ 0 ].Connected->Mains
&& Couplers[ 0 ].Connected->ConverterFlag );
else
CompressorFlag = false; // bez tamtego członu nie zadziała
}
else
CompressorFlag = (CompressorAllow) &&
((ConverterFlag) || (CompressorPower == 0)) && (Mains);
CompressorFlag =
( ( CompressorAllow )
&& ( CompressorAllowLocal )
&& ( Mains )
&& ( ( ConverterFlag )
|| ( CompressorPower == 0 ) ) );
if( Compressor > MaxCompressor ) {
// wyłącznik ciśnieniowy jest niezależny od sposobu zasilania
CompressorFlag = false;
CompressorGovernorLock = true; // prevent manual activation until the pressure goes below cut-in level
}
}
else // jeśli nie załączona
if( ( ( Compressor < MinCompressor )
|| ( ( Compressor < MaxCompressor )
&& ( false == CompressorGovernorLock ) ) )
&& (LastSwitchingTime > CtrlDelay) ) {
// załączenie przy małym ciśnieniu
// jeśli nie załączona, a ciśnienie za małe
// or if the switch is on and the pressure isn't maxed
if( CompressorPower == 5 ) // jeśli zasilanie z następnego członu
{ // zasilanie sprężarki w członie ra z członu silnikowego (sprzęg 1)
if (Couplers[1].Connected != NULL)
CompressorFlag =
(Couplers[1].Connected->CompressorAllow &&
Couplers[1].Connected->ConverterFlag && Couplers[1].Connected->Mains);
else
CompressorFlag = false; // bez tamtego członu nie zadziała
}
else if (CompressorPower == 4) // jeśli zasilanie z poprzedniego członu
{ // zasilanie sprężarki w członie ra z członu silnikowego (sprzęg 1)
if (Couplers[0].Connected != NULL)
CompressorFlag =
(Couplers[0].Connected->CompressorAllow &&
Couplers[0].Connected->ConverterFlag && Couplers[0].Connected->Mains);
else
CompressorFlag = false; // bez tamtego członu nie zadziała
}
else
CompressorFlag = (CompressorAllow) &&
((ConverterFlag) || (CompressorPower == 0)) && (Mains);
if( CompressorFlag ) {
// jeśli została załączona
LastSwitchingTime = 0; // to trzeba ograniczyć ponowne włączenie
if( Compressor < MinCompressor ) {
// if the activation took place at pressure below the cut-in level, we can reset compressor governor
CompressorGovernorLock = false;
if( ( TrainType == dt_ET41 )
|| ( TrainType == dt_ET42 ) ) {
// for these multi-unit engines compressors turn off whenever any of them was affected by the governor
// NOTE: this is crude implementation, TODO: re-implement when a more elegant/flexible system is in place
if( ( Couplers[ 1 ].Connected != nullptr )
&& ( true == TestFlag( Couplers[ 1 ].CouplingFlag, coupling::permanent ) ) ) {
// the first unit isn't allowed to start its compressor until second unit can start its own as well
CompressorFlag &= ( Couplers[ 1 ].Connected->CompressorGovernorLock == false );
}
if( ( Couplers[ 0 ].Connected != nullptr )
&& ( true == TestFlag( Couplers[ 0 ].CouplingFlag, coupling::permanent ) ) ) {
// the second unit isn't allowed to start its compressor until first unit can start its own as well
CompressorFlag &= ( Couplers[ 0 ].Connected->CompressorGovernorLock == false );
}
}
}
// for b:=0 to 1 do //z Megapacka
// with Couplers[b] do
// if TestFlag(CouplingFlag,ctrain_scndpneumatic) then
// Connected.CompressorFlag:=CompressorFlag;
else {
// jeśli nie załączona
if( Compressor < MinCompressor ) {
// if the pressure drops below the cut-in level, we can reset compressor governor
CompressorGovernorLock = false;
}
if( ( ( Compressor < MinCompressor )
|| ( ( Compressor < MaxCompressor )
&& ( false == CompressorGovernorLock ) ) )
&& ( LastSwitchingTime > CtrlDelay ) ) {
// załączenie przy małym ciśnieniu
// jeśli nie załączona, a ciśnienie za małe
// or if the switch is on and the pressure isn't maxed
if( CompressorPower == 5 ) // jeśli zasilanie z następnego członu
{ // zasilanie sprężarki w członie ra z członu silnikowego (sprzęg 1)
if( Couplers[ 1 ].Connected != nullptr ) {
CompressorFlag =
( Couplers[ 1 ].Connected->CompressorAllow
&& Couplers[ 1 ].Connected->CompressorAllowLocal
&& Couplers[ 1 ].Connected->Mains
&& Couplers[ 1 ].Connected->ConverterFlag );
}
else {
CompressorFlag = false; // bez tamtego członu nie zadziała
}
}
else if( CompressorPower == 4 ) // jeśli zasilanie z poprzedniego członu
{ // zasilanie sprężarki w członie ra z członu silnikowego (sprzęg 1)
if( Couplers[ 0 ].Connected != nullptr ) {
CompressorFlag =
( Couplers[ 0 ].Connected->CompressorAllow
&& Couplers[ 0 ].Connected->CompressorAllowLocal
&& Couplers[ 0 ].Connected->Mains
&& Couplers[ 0 ].Connected->ConverterFlag );
}
else {
CompressorFlag = false; // bez tamtego członu nie zadziała
}
}
else {
CompressorFlag =
( ( CompressorAllow )
&& ( CompressorAllowLocal )
&& ( Mains )
&& ( ( ConverterFlag )
|| ( CompressorPower == 0 ) ) );
}
// NOTE: crude way to enforce simultaneous activation of compressors in multi-unit setups
// TODO: replace this with a more universal activation system down the road
if( ( TrainType == dt_ET41 )
|| ( TrainType == dt_ET42 ) ) {
if( ( Couplers[1].Connected != nullptr )
&& ( true == TestFlag( Couplers[ 1 ].CouplingFlag, coupling::permanent ) ) ) {
// the first unit isn't allowed to start its compressor until second unit can start its own as well
CompressorFlag &= ( Couplers[ 1 ].Connected->CompressorGovernorLock == false );
}
if( ( Couplers[ 0 ].Connected != nullptr )
&& ( true == TestFlag( Couplers[ 0 ].CouplingFlag, coupling::permanent ) ) ) {
// the second unit isn't allowed to start its compressor until first unit can start its own as well
CompressorFlag &= ( Couplers[ 0 ].Connected->CompressorGovernorLock == false );
}
}
if( CompressorFlag ) {
// jeśli została załączona
LastSwitchingTime = 0; // to trzeba ograniczyć ponowne włączenie
}
}
}
if (CompressorFlag)
if ((EngineType == DieselElectric) && (CompressorPower > 0))
CompressedVolume += dt * CompressorSpeed * (2.0 * MaxCompressor - Compressor) /
@@ -3628,7 +3685,8 @@ void TMoverParameters::ComputeTotalForce(double dt, double dt1, bool FullVer)
else
FTrain = 0;
Fb = BrakeForce(RunningTrack);
if( std::max( std::abs( FTrain ), Fb ) > TotalMassxg * Adhesive( RunningTrack.friction ) ) // poslizg
if( ( Vel > 0.001 ) // crude trap, to prevent braked stationary vehicles from passing fb > mass * adhesive test
&& ( std::max( std::abs( FTrain ), Fb ) > TotalMassxg * Adhesive( RunningTrack.friction ) ) ) // poslizg
{
SlippingWheels = true;
}
@@ -7255,9 +7313,11 @@ void TMoverParameters::LoadFIZ_Switches( std::string const &Input ) {
extract_value( PantSwitchType, "Pantograph", Input, "" );
extract_value( ConvSwitchType, "Converter", Input, "" );
extract_value( StLinSwitchType, "MotorConnectors", Input, "" );
// because people can't make up their minds whether it's "impulse" or "Impulse"...
PantSwitchType = ToLower( PantSwitchType );
ConvSwitchType = ToLower( ConvSwitchType );
StLinSwitchType = ToLower( StLinSwitchType );
}
void TMoverParameters::LoadFIZ_MotorParamTable( std::string const &Input ) {

View File

@@ -144,98 +144,6 @@ bool FuzzyLogicAI(double Test, double Threshold, double Probability)
return false;
}
std::string ReadWord(std::ifstream &infile)
{
std::string s = "";
char c;
bool nextword = false;
while ((!infile.eof()) && (!nextword))
{
infile.get(c);
if (_spacesigns.find(c) != std::string::npos)
if (s != "")
nextword = true;
if (_spacesigns.find(c) == std::string::npos)
s += c;
}
return s;
}
std::string TrimSpace(std::string &s)
{
/*int ii;
switch (Just)
{
case CutLeft:
{
ii = 0;
while ((ii < s.length()) && (s[ii + 1] == (char)" "))
++ii;
s = s.substr(ii + 1, s.length() - ii);
}
case CutRight:
{
ii = s.length();
while ((ii > 0) && (s[ii] == (char)" "))
--ii;
s = s.substr(0, ii);
}
case CutBoth:
{
s = TrimSpace(s, CutLeft);
s = TrimSpace(s, CutRight);
}
}
return s;*/
if (s.empty())
return "";
size_t first = s.find_first_not_of(' ');
if (first == std::string::npos)
return "";
size_t last = s.find_last_not_of(' ');
return s.substr(first, (last - first + 1));
}
char* TrimAndReduceSpaces(const char* s)
{ // redukuje spacje pomiedzy znakami do jednej
char* tmp = nullptr;
if (s)
{
tmp = _strdup(s);
char* from = tmp + strspn(tmp, " ");
char* to = tmp;
do if ((*to = *from++) == ' ')
from += strspn(from, " ");
while (*to++);
while (*--to == ' ')
*to = '\0';
}
return tmp;
}
std::string ExtractKeyWord(std::string InS, std::string KeyWord)
{
std::string s;
InS = InS + " ";
std::size_t kwp = InS.find(KeyWord);
if (kwp != std::string::npos)
{
s = InS.substr(kwp, InS.length());
//s = Copy(InS, kwp, length(InS));
s = s.substr(0, s.find_first_of(" "));
//s = Copy(s, 1, Pos(" ", s) - 1);
}
else
s = "";
return s;
}
std::string DUE(std::string s) /*Delete Before Equal sign*/
{
//DUE = Copy(s, Pos("=", s) + 1, length(s));
@@ -473,8 +381,7 @@ void ComputeALine(double X0, double Y0, double Xn, double Yn, double L, double R
bool FileExists( std::string const &Filename ) {
std::ifstream file( Filename );
if( file.is_open() == false ) { return false; }
else { return true; }
return( true == file.is_open() );
}
/*

View File

@@ -105,11 +105,6 @@ bool FuzzyLogicAI(double Test, double Threshold, double Probability);
/*to samo ale zawsze niezaleznie od DebugFlag*/
/*operacje na stringach*/
std::string ReadWord( std::ifstream& infile); /*czyta slowo z wiersza pliku tekstowego*/
//std::string Ups(std::string s);
//std::string TrimSpace(std::string &s);
//char* TrimAndReduceSpaces(const char* s);
//std::string ExtractKeyWord(std::string InS, std::string KeyWord); /*wyciaga slowo kluczowe i lancuch do pierwszej spacji*/
std::string DUE(std::string s); /*Delete Until Equal sign*/
std::string DWE(std::string s); /*Delete While Equal sign*/
std::string ExchangeCharInString(std::string const &s, const char &aim, const char &target); // zamienia jeden znak na drugi

View File

@@ -56,7 +56,8 @@ void TModelsManager::Init()
*/
void TModelsManager::Free()
{
SafeDeleteArray(Models);
delete[] Models;
Models = nullptr;
}
TModel3d * TModelsManager::LoadModel(std::string const &Name, bool dynamic)

View File

@@ -14,16 +14,12 @@ http://mozilla.org/MPL/2.0/.
class TMdlContainer
{
friend class TModelsManager;
TMdlContainer()
{
Model = NULL;
};
~TMdlContainer()
{
SafeDelete(Model);
delete Model;
};
TModel3d * LoadModel(std::string const &NewName, bool dynamic);
TModel3d *Model;
TModel3d *Model{ nullptr };
std::string Name;
};

View File

@@ -1036,421 +1036,6 @@ void TSubModel::RaAnimation(TAnimType a)
}
};
#ifdef EU07_USE_OLD_RENDERCODE
void TSubModel::RenderDL()
{ // główna procedura renderowania przez DL
if( ( iVisible )
&& ( fSquareDist >= (fSquareMinDist / Global::fDistanceFactor) )
&& ( fSquareDist <= (fSquareMaxDist * Global::fDistanceFactor) ) )
{
if (iFlags & 0xC000)
{
glPushMatrix();
if (fMatrix)
glMultMatrixf(fMatrix->readArray());
if (b_Anim)
RaAnimation(b_Anim);
}
if (eType < TP_ROTATOR)
{ // renderowanie obiektów OpenGL
if (iAlpha & iFlags & 0x1F) // rysuj gdy element nieprzezroczysty
{
if (TextureID < 0) // && (ReplacableSkinId!=0))
{ // zmienialne skóry
GfxRenderer.Bind(ReplacableSkinId[-TextureID]);
// TexAlpha=!(iAlpha&1); //zmiana tylko w przypadku wymienej tekstury
}
else
GfxRenderer.Bind(TextureID); // również 0
if (Global::fLuminance < fLight)
{
glMaterialfv(GL_FRONT, GL_EMISSION, f4Diffuse); // zeby swiecilo na kolorowo
glCallList(uiDisplayList); // tylko dla siatki
glMaterialfv(GL_FRONT, GL_EMISSION, emm2);
}
else
glCallList(uiDisplayList); // tylko dla siatki
}
}
else if (eType == TP_FREESPOTLIGHT)
{ // wersja DL
matrix4x4 mat; // macierz opisuje układ renderowania względem kamery
glGetDoublev(GL_MODELVIEW_MATRIX, mat.getArray());
// kąt między kierunkiem światła a współrzędnymi kamery
vector3 gdzie = mat * vector3(0, 0, 0); // pozycja punktu świecącego względem kamery
fCosViewAngle = DotProduct(Normalize(mat * vector3(0, 0, 1) - gdzie), Normalize(gdzie));
if (fCosViewAngle > fCosFalloffAngle) // kąt większy niż maksymalny stożek swiatła
{
double Distdimm = 1.0;
if (fCosViewAngle <
fCosHotspotAngle) // zmniejszona jasność między Hotspot a Falloff
if (fCosFalloffAngle < fCosHotspotAngle)
Distdimm = 1.0 -
(fCosHotspotAngle - fCosViewAngle) /
(fCosHotspotAngle - fCosFalloffAngle);
glColor3f(f4Diffuse[0] * Distdimm, f4Diffuse[1] * Distdimm,
f4Diffuse[2] * Distdimm);
/* TODO: poprawic to zeby dzialalo
if (iFarAttenDecay>0)
switch (iFarAttenDecay)
{
case 1:
Distdimm=fFarDecayRadius/(1+sqrt(fSquareDist));
//dorobic od kata
break;
case 2:
Distdimm=fFarDecayRadius/(1+fSquareDist);
//dorobic od kata
break;
}
if (Distdimm>1)
Distdimm=1;
glColor3f(Diffuse[0]*Distdimm,Diffuse[1]*Distdimm,Diffuse[2]*Distdimm);
*/
// glPopMatrix();
// return;
glCallList(uiDisplayList); // wyświetlenie warunkowe
}
}
else if (eType == TP_STARS)
{
// glDisable(GL_LIGHTING); //Tolaris-030603: bo mu punkty swiecace sie
// blendowaly
if (Global::fLuminance < fLight)
{
glMaterialfv(GL_FRONT, GL_EMISSION, f4Diffuse); // zeby swiecilo na kolorowo
glCallList(uiDisplayList); // narysuj naraz wszystkie punkty z DL
glMaterialfv(GL_FRONT, GL_EMISSION, emm2);
}
}
if (Child != NULL)
if (iAlpha & iFlags & 0x001F0000)
Child->RenderDL();
if (iFlags & 0xC000)
glPopMatrix();
}
if (b_Anim < at_SecondsJump)
b_Anim = at_None; // wyłączenie animacji dla kolejnego użycia subm
if (Next)
if (iAlpha & iFlags & 0x1F000000)
Next->RenderDL(); // dalsze rekurencyjnie
}; // Render
void TSubModel::RenderAlphaDL()
{ // renderowanie przezroczystych przez DL
if( ( iVisible )
&& ( fSquareDist >= (fSquareMinDist / Global::fDistanceFactor) )
&& ( fSquareDist <= (fSquareMaxDist * Global::fDistanceFactor) ) )
{
if (iFlags & 0xC000)
{
glPushMatrix();
if (fMatrix)
glMultMatrixf(fMatrix->readArray());
if (b_aAnim)
RaAnimation(b_aAnim);
}
if (eType < TP_ROTATOR)
{ // renderowanie obiektów OpenGL
if (iAlpha & iFlags & 0x2F) // rysuj gdy element przezroczysty
{
if (TextureID < 0) // && (ReplacableSkinId!=0))
{ // zmienialne skóry
GfxRenderer.Bind(ReplacableSkinId[-TextureID]);
// TexAlpha=iAlpha&1; //zmiana tylko w przypadku wymienej tekstury
}
else
GfxRenderer.Bind(TextureID); // również 0
if (Global::fLuminance < fLight)
{
glMaterialfv(GL_FRONT, GL_EMISSION, f4Diffuse); // zeby swiecilo na kolorowo
glCallList(uiDisplayList); // tylko dla siatki
glMaterialfv(GL_FRONT, GL_EMISSION, emm2);
}
else
glCallList(uiDisplayList); // tylko dla siatki
}
}
else if (eType == TP_FREESPOTLIGHT)
{
// dorobić aureolę!
}
if (Child != NULL)
if (eType == TP_TEXT)
{ // tekst renderujemy w specjalny sposób, zamiast
// submodeli z łańcucha Child
int i, j = (int)pasText->size();
TSubModel *p;
if (!smLetter)
{ // jeśli nie ma tablicy, to ją stworzyć; miejsce
// nieodpowiednie, ale tymczasowo
// może być
smLetter = new TSubModel *[256]; // tablica wskaźników submodeli dla
// wyświetlania tekstu
ZeroMemory(smLetter, 256 * sizeof(TSubModel *)); // wypełnianie zerami
p = Child;
while (p)
{
smLetter[p->pName[0]] = p;
p = p->Next; // kolejny znak
}
}
for (i = 1; i <= j; ++i)
{
p = smLetter[(*pasText)[i]]; // znak do wyświetlenia
if (p)
{ // na razie tylko jako przezroczyste
p->RenderAlphaDL();
if (p->fMatrix)
glMultMatrixf(p->fMatrix->readArray()); // przesuwanie widoku
}
}
}
else if (iAlpha & iFlags & 0x002F0000)
Child->RenderAlphaDL();
if (iFlags & 0xC000)
glPopMatrix();
}
if (b_aAnim < at_SecondsJump)
b_aAnim = at_None; // wyłączenie animacji dla kolejnego użycia submodelu
if (Next != NULL)
if (iAlpha & iFlags & 0x2F000000)
Next->RenderAlphaDL();
}; // RenderAlpha
void TSubModel::RenderVBO()
{ // główna procedura renderowania przez VBO
if( ( iVisible )
&& ( fSquareDist >= (fSquareMinDist / Global::fDistanceFactor) )
&& ( fSquareDist <= (fSquareMaxDist * Global::fDistanceFactor) ) )
{
if (iFlags & 0xC000)
{
glPushMatrix();
if (fMatrix)
glMultMatrixf(fMatrix->readArray());
if (b_Anim)
RaAnimation(b_Anim);
}
if (eType < TP_ROTATOR)
{ // renderowanie obiektów OpenGL
if (iAlpha & iFlags & 0x1F) // rysuj gdy element nieprzezroczysty
{
if (TextureID < 0) // && (ReplacableSkinId!=0))
{ // zmienialne skóry
GfxRenderer.Bind(ReplacableSkinId[-TextureID]);
// TexAlpha=!(iAlpha&1); //zmiana tylko w przypadku wymienej tekstury
}
else
GfxRenderer.Bind(TextureID); // również 0
glColor3fv(f4Diffuse); // McZapkie-240702: zamiast ub
// glMaterialfv(GL_FRONT,GL_AMBIENT_AND_DIFFUSE,f4Diffuse); //to samo,
// co glColor
if (Global::fLuminance < fLight)
{
glMaterialfv(GL_FRONT, GL_EMISSION, f4Diffuse); // zeby swiecilo na kolorowo
glDrawArrays(eType, iVboPtr,
iNumVerts); // narysuj naraz wszystkie trójkąty z VBO
glMaterialfv(GL_FRONT, GL_EMISSION, emm2);
}
else
glDrawArrays(eType, iVboPtr,
iNumVerts); // narysuj naraz wszystkie trójkąty z VBO
}
}
else if (eType == TP_FREESPOTLIGHT)
{ // wersja VBO
/*
matrix4x4 mat; // macierz opisuje układ renderowania względem kamery
glGetDoublev(GL_MODELVIEW_MATRIX, mat.getArray());
*/
matrix4x4 mat; mat.OpenGL_Matrix( OpenGLMatrices.data_array( GL_MODELVIEW ) );
// kąt między kierunkiem światła a współrzędnymi kamery
vector3 gdzie = mat * vector3(0, 0, 0); // pozycja punktu świecącego względem kamery
fCosViewAngle = DotProduct(Normalize(mat * vector3(0, 0, 1) - gdzie), Normalize(gdzie));
if (fCosViewAngle > fCosFalloffAngle) // kąt większy niż maksymalny stożek swiatła
{
double Distdimm = 1.0;
if (fCosViewAngle <
fCosHotspotAngle) // zmniejszona jasność między Hotspot a Falloff
if (fCosFalloffAngle < fCosHotspotAngle)
Distdimm = 1.0 -
(fCosHotspotAngle - fCosViewAngle) /
(fCosHotspotAngle - fCosFalloffAngle);
/* TODO: poprawic to zeby dzialalo
2- Inverse (Applies inverse decay. The formula is luminance=R0/R, where
R0 is
the radial source of the light if no attenuation is
used, or the Near End
value of the light if Attenuation is used. R is the
radial distance of the
illuminated surface from R0.)
3- Inverse Square (Applies inverse-square decay. The formula for this is
(R0/R)^2.
This is actually the "real-world" decay of light, but
you might find it too dim
in the world of computer graphics.)
<light>.DecayRadius -- The distance over which the decay occurs.
if (iFarAttenDecay>0)
switch (iFarAttenDecay)
{
case 1:
Distdimm=fFarDecayRadius/(1+sqrt(fSquareDist));
//dorobic od kata
break;
case 2:
Distdimm=fFarDecayRadius/(1+fSquareDist);
//dorobic od kata
break;
}
if (Distdimm>1)
Distdimm=1;
*/
GfxRenderer.Bind(0); // nie teksturować
// glColor3f(f4Diffuse[0],f4Diffuse[1],f4Diffuse[2]);
// glColorMaterial(GL_FRONT,GL_EMISSION);
float color[4] = { (float)(f4Diffuse[0] * Distdimm), (float)(f4Diffuse[1] * Distdimm),
(float)(f4Diffuse[2] * Distdimm), 0 };
// glColor3f(f4Diffuse[0]*Distdimm,f4Diffuse[1]*Distdimm,f4Diffuse[2]*Distdimm);
glColorMaterial(GL_FRONT, GL_EMISSION);
glDisable(GL_LIGHTING); // Tolaris-030603: bo mu punkty swiecace sie
// blendowaly
glColor3fv(color); // inaczej są białe
glMaterialfv(GL_FRONT, GL_EMISSION, color);
glDrawArrays(GL_POINTS, iVboPtr, iNumVerts); // narysuj wierzchołek z
// VBO
glEnable(GL_LIGHTING);
glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE); // co ma ustawiać glColor
glMaterialfv(GL_FRONT, GL_EMISSION, emm2); // bez tego słupy się świecą
}
}
else if (eType == TP_STARS)
{
// glDisable(GL_LIGHTING); //Tolaris-030603: bo mu punkty swiecace sie
// blendowaly
if (Global::fLuminance < fLight)
{ // Ra: pewnie można by to zrobić
// lepiej, bez powtarzania StartVBO()
pRoot->EndVBO(); // Ra: to też nie jest zbyt ładne
if (pRoot->StartColorVBO())
{ // wyświetlanie kolorowych punktów zamiast
// trójkątów
GfxRenderer.Bind(0); // tekstury nie ma
glColorMaterial(GL_FRONT, GL_EMISSION);
glDisable(GL_LIGHTING); // Tolaris-030603: bo mu punkty swiecace sie
// blendowaly
// glMaterialfv(GL_FRONT,GL_EMISSION,f4Diffuse); //zeby swiecilo na
// kolorowo
glDrawArrays(GL_POINTS, iVboPtr,
iNumVerts); // narysuj naraz wszystkie punkty z VBO
glEnable(GL_LIGHTING);
glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
// glMaterialfv(GL_FRONT,GL_EMISSION,emm2);
pRoot->EndVBO();
pRoot->StartVBO();
}
}
}
/*Ra: tu coś jest bez sensu...
else
{
glBindTexture(GL_TEXTURE_2D, 0);
// if (eType==smt_FreeSpotLight)
// {
// if (iFarAttenDecay==0)
// glColor3f(Diffuse[0],Diffuse[1],Diffuse[2]);
// }
// else
//TODO: poprawic zeby dzialalo
glColor3f(f4Diffuse[0],f4Diffuse[1],f4Diffuse[2]);
glColorMaterial(GL_FRONT,GL_EMISSION);
glDisable(GL_LIGHTING); //Tolaris-030603: bo mu punkty
swiecace sie blendowaly
//glBegin(GL_POINTS);
glDrawArrays(GL_POINTS,iVboPtr,iNumVerts); //narysuj
wierzchołek z VBO
// glVertex3f(0,0,0);
//glEnd();
glEnable(GL_LIGHTING);
glColorMaterial(GL_FRONT,GL_AMBIENT_AND_DIFFUSE);
glMaterialfv(GL_FRONT,GL_EMISSION,emm2);
//glEndList();
}
*/
if (Child != NULL)
if (iAlpha & iFlags & 0x001F0000)
Child->RenderVBO();
if (iFlags & 0xC000)
glPopMatrix();
}
if (b_Anim < at_SecondsJump)
b_Anim = at_None; // wyłączenie animacji dla kolejnego użycia submodelu
if (Next)
if (iAlpha & iFlags & 0x1F000000)
Next->RenderVBO(); // dalsze rekurencyjnie
}; // RaRender
void TSubModel::RenderAlphaVBO()
{ // renderowanie przezroczystych przez VBO
if( ( iVisible )
&& ( fSquareDist >= (fSquareMinDist / Global::fDistanceFactor) )
&& ( fSquareDist <= (fSquareMaxDist * Global::fDistanceFactor) ) )
{
if (iFlags & 0xC000)
{
glPushMatrix(); // zapamiętanie matrycy
if (fMatrix)
glMultMatrixf(fMatrix->readArray());
if (b_aAnim)
RaAnimation(b_aAnim);
}
glColor3fv(f4Diffuse);
if (eType < TP_ROTATOR)
{ // renderowanie obiektów OpenGL
if (iAlpha & iFlags & 0x2F) // rysuj gdy element przezroczysty
{
if (TextureID < 0) // && (ReplacableSkinId!=0))
{ // zmienialne skory
GfxRenderer.Bind(ReplacableSkinId[-TextureID]);
// TexAlpha=iAlpha&1; //zmiana tylko w przypadku wymienej tekstury
}
else
GfxRenderer.Bind(TextureID); // również 0
if (Global::fLuminance < fLight)
{
glMaterialfv(GL_FRONT, GL_EMISSION, f4Diffuse); // zeby swiecilo na kolorowo
glDrawArrays(eType, iVboPtr,
iNumVerts); // narysuj naraz wszystkie trójkąty z VBO
glMaterialfv(GL_FRONT, GL_EMISSION, emm2);
}
else
glDrawArrays(eType, iVboPtr,
iNumVerts); // narysuj naraz wszystkie trójkąty z VBO
}
}
else if (eType == TP_FREESPOTLIGHT)
{
// dorobić aureolę!
}
if (Child)
if (iAlpha & iFlags & 0x002F0000)
Child->RenderAlphaVBO();
if (iFlags & 0xC000)
glPopMatrix();
}
if (b_aAnim < at_SecondsJump)
b_aAnim = at_None; // wyłączenie animacji dla kolejnego użycia submodelu
if (Next)
if (iAlpha & iFlags & 0x2F000000)
Next->RenderAlphaVBO();
}; // RaRenderAlpha
#endif
//---------------------------------------------------------------------------
void TSubModel::RaArrayFill(CVertNormTex *Vert)
@@ -1577,8 +1162,12 @@ TModel3d::~TModel3d()
}
else
{ // wczytano z pliku binarnego (jest właścicielem tablic)
m_pVNT = NULL; // nie usuwać tego, bo wskazuje na iModel
Root = NULL;
#ifdef EU07_USE_OLD_VERTEXBUFFER
m_pVNT = nullptr; // nie usuwać tego, bo wskazuje na iModel
#else
m_pVNT.clear();
#endif
Root = nullptr;
delete[] iModel; // usuwamy cały wczytany plik i to wystarczy
}
// później się jeszcze usuwa obiekt z którego dziedziczymy tabelę VBO
@@ -1801,7 +1390,11 @@ void TModel3d::SaveToBinFile(char const *FileName)
transforms[i].serialize_float32(s);
MakeArray(iNumVerts);
Root->RaArrayFill(m_pVNT);
#ifdef EU07_USE_OLD_VERTEXBUFFER
Root->RaArrayFill(m_pVNT);
#else
Root->RaArrayFill( m_pVNT.data() );
#endif
sn_utils::ls_uint32(s, MAKE_ID4('V', 'N', 'T', '0'));
sn_utils::ls_uint32(s, 8 + iNumVerts * 32);
for (size_t i = 0; i < (size_t)iNumVerts; i++)
@@ -1886,7 +1479,11 @@ void TSubModel::deserialize(std::istream &s)
void TModel3d::deserialize(std::istream &s, size_t size, bool dynamic)
{
m_pVNT = nullptr;
#ifdef EU07_USE_OLD_VERTEXBUFFER
m_pVNT = nullptr;
#else
m_pVNT.clear();
#endif
Root = nullptr;
float4x4 *tm = nullptr;
@@ -1900,13 +1497,22 @@ void TModel3d::deserialize(std::istream &s, size_t size, bool dynamic)
if (type == MAKE_ID4('V', 'N', 'T', '0'))
{
if (m_pVNT != nullptr)
#ifdef EU07_USE_OLD_VERTEXBUFFER
if (m_pVNT != nullptr)
#else
if( false == m_pVNT.empty() )
#endif
throw std::runtime_error("e3d: duplicated VNT chunk");
size_t vt_cnt = size / 32;
iNumVerts = (int)vt_cnt;
m_nVertexCount = (int)vt_cnt;
m_pVNT = new CVertNormTex[vt_cnt];
#ifdef EU07_USE_OLD_VERTEXBUFFER
assert( m_pVNT == nullptr );
m_pVNT = new CVertNormTex[vt_cnt];
#else
m_pVNT.resize( vt_cnt );
#endif
for (size_t i = 0; i < vt_cnt; i++)
m_pVNT[i].deserialize(s);
}
@@ -1967,12 +1573,20 @@ void TModel3d::deserialize(std::istream &s, size_t size, bool dynamic)
if (!Root)
throw std::runtime_error("e3d: no submodels");
if (!m_pVNT)
#ifdef EU07_USE_OLD_VERTEXBUFFER
if (!m_pVNT)
#else
if(m_pVNT.empty() )
#endif
throw std::runtime_error("e3d: no vertices");
for (size_t i = 0; (int)i < iSubModelsCount; i++)
{
Root[i].BinInit(Root, tm, (float8*)m_pVNT, &Textures, &Names, dynamic);
#ifdef EU07_USE_OLD_VERTEXBUFFER
Root[i].BinInit(Root, tm, (float8*)m_pVNT, &Textures, &Names, dynamic);
#else
Root[ i ].BinInit( Root, tm, (float8*)m_pVNT.data(), &Textures, &Names, dynamic );
#endif
if (Root[i].ChildGet())
Root[i].ChildGet()->Parent = &Root[i];
@@ -2151,11 +1765,18 @@ void TModel3d::Init()
*/
if (Global::bUseVBO)
{
if (!m_pVNT) // jeśli nie ma jeszcze tablicy (wczytano z pliku
// tekstowego)
#ifdef EU07_USE_OLD_VERTEXBUFFER
if (!m_pVNT) // jeśli nie ma jeszcze tablicy (wczytano z pliku tekstowego)
#else
if( m_pVNT.empty() )
#endif
{ // tworzenie tymczasowej tablicy z wierzchołkami całego modelu
MakeArray(iNumVerts); // tworzenie tablic dla VBO
Root->RaArrayFill(m_pVNT); // wypełnianie tablicy
#ifdef EU07_USE_OLD_VERTEXBUFFER
Root->RaArrayFill(m_pVNT); // wypełnianie tablicy
#else
Root->RaArrayFill( m_pVNT.data() ); // wypełnianie tablicy
#endif
BuildVBOs(); // tworzenie VBO i usuwanie tablicy z pamięci
}
else
@@ -2176,140 +1797,6 @@ void TModel3d::BreakHierarhy()
Error("Not implemented yet :(");
};
#ifdef EU07_USE_OLD_RENDERCODE
void TModel3d::Render(double fSquareDistance, texture_manager::size_type *ReplacableSkinId, int iAlpha)
{
iAlpha ^= 0x0F0F000F; // odwrócenie flag tekstur, aby wyłapać nieprzezroczyste
if (iAlpha & iFlags & 0x1F1F001F) // czy w ogóle jest co robić w tym cyklu?
{
TSubModel::fSquareDist = fSquareDistance; // zmienna globalna!
Root->ReplacableSet(ReplacableSkinId, iAlpha);
Root->RenderDL();
}
};
void TModel3d::RenderAlpha(double fSquareDistance, texture_manager::size_type *ReplacableSkinId, int iAlpha)
{
if (iAlpha & iFlags & 0x2F2F002F)
{
TSubModel::fSquareDist = fSquareDistance; // zmienna globalna!
Root->ReplacableSet(ReplacableSkinId, iAlpha);
Root->RenderAlphaDL();
}
};
void TModel3d::RaRender(double fSquareDistance, texture_manager::size_type const *ReplacableSkinId, int iAlpha)
{ // renderowanie specjalne, np. kabiny
iAlpha ^= 0x0F0F000F; // odwrócenie flag tekstur, aby wyłapać nieprzezroczyste
if (iAlpha & iFlags & 0x1F1F001F) // czy w ogóle jest co robić w tym cyklu?
{
TSubModel::fSquareDist = fSquareDistance; // zmienna globalna!
if (StartVBO())
{ // odwrócenie flag, aby wyłapać nieprzezroczyste
Root->ReplacableSet(ReplacableSkinId, iAlpha);
Root->pRoot = this;
Root->RenderVBO();
EndVBO();
}
}
};
void TModel3d::RaRenderAlpha(double fSquareDistance, texture_manager::size_type const *ReplacableSkinId, int iAlpha)
{ // renderowanie specjalne, np. kabiny
if (iAlpha & iFlags & 0x2F2F002F) // czy w ogóle jest co robić w tym cyklu?
{
TSubModel::fSquareDist = fSquareDistance; // zmienna globalna!
if (StartVBO())
{
Root->ReplacableSet(ReplacableSkinId, iAlpha);
Root->RenderAlphaVBO();
EndVBO();
}
}
};
#endif
//-----------------------------------------------------------------------------
// 2011-03-16 cztery nowe funkcje renderowania z możliwością pochylania obiektów
//-----------------------------------------------------------------------------
#ifdef EU07_USE_OLD_RENDERCODE
void TModel3d::Render(vector3 *vPosition, vector3 *vAngle, texture_manager::size_type *ReplacableSkinId, int iAlpha)
{ // nieprzezroczyste, Display List
glPushMatrix();
glTranslated(vPosition->x, vPosition->y, vPosition->z);
if (vAngle->y != 0.0)
glRotated(vAngle->y, 0.0, 1.0, 0.0);
if (vAngle->x != 0.0)
glRotated(vAngle->x, 1.0, 0.0, 0.0);
if (vAngle->z != 0.0)
glRotated(vAngle->z, 0.0, 0.0, 1.0);
TSubModel::fSquareDist =
SquareMagnitude(*vPosition - Global::GetCameraPosition()); // zmienna globalna!
// odwrócenie flag, aby wyłapać nieprzezroczyste
Root->ReplacableSet(ReplacableSkinId, iAlpha ^ 0x0F0F000F);
Root->RenderDL();
glPopMatrix();
};
void TModel3d::RenderAlpha(vector3 *vPosition, vector3 *vAngle, texture_manager::size_type *ReplacableSkinId,
int iAlpha)
{ // przezroczyste, Display List
glPushMatrix();
glTranslated(vPosition->x, vPosition->y, vPosition->z);
if (vAngle->y != 0.0)
glRotated(vAngle->y, 0.0, 1.0, 0.0);
if (vAngle->x != 0.0)
glRotated(vAngle->x, 1.0, 0.0, 0.0);
if (vAngle->z != 0.0)
glRotated(vAngle->z, 0.0, 0.0, 1.0);
TSubModel::fSquareDist =
SquareMagnitude(*vPosition - Global::GetCameraPosition()); // zmienna globalna!
Root->ReplacableSet(ReplacableSkinId, iAlpha);
Root->RenderAlphaDL();
glPopMatrix();
};
void TModel3d::RaRender(vector3 *vPosition, vector3 *vAngle, texture_manager::size_type const *ReplacableSkinId, int iAlpha)
{ // nieprzezroczyste, VBO
glPushMatrix();
glTranslated(vPosition->x, vPosition->y, vPosition->z);
if (vAngle->y != 0.0)
glRotated(vAngle->y, 0.0, 1.0, 0.0);
if (vAngle->x != 0.0)
glRotated(vAngle->x, 1.0, 0.0, 0.0);
if (vAngle->z != 0.0)
glRotated(vAngle->z, 0.0, 0.0, 1.0);
TSubModel::fSquareDist =
SquareMagnitude(*vPosition - Global::GetCameraPosition()); // zmienna globalna!
if (StartVBO())
{ // odwrócenie flag, aby wyłapać nieprzezroczyste
Root->ReplacableSet(ReplacableSkinId, iAlpha ^ 0x0F0F000F);
Root->RenderVBO();
EndVBO();
}
glPopMatrix();
};
void TModel3d::RaRenderAlpha(vector3 *vPosition, vector3 *vAngle, texture_manager::size_type const *ReplacableSkinId,
int iAlpha)
{ // przezroczyste, VBO
glPushMatrix();
glTranslated(vPosition->x, vPosition->y, vPosition->z);
if (vAngle->y != 0.0)
glRotated(vAngle->y, 0.0, 1.0, 0.0);
if (vAngle->x != 0.0)
glRotated(vAngle->x, 1.0, 0.0, 0.0);
if (vAngle->z != 0.0)
glRotated(vAngle->z, 0.0, 0.0, 1.0);
TSubModel::fSquareDist =
SquareMagnitude(*vPosition - Global::GetCameraPosition()); // zmienna globalna!
if (StartVBO())
{
Root->ReplacableSet(ReplacableSkinId, iAlpha);
Root->RenderAlphaVBO();
EndVBO();
}
glPopMatrix();
};
#endif
//-----------------------------------------------------------------------------
// 2012-02 funkcje do tworzenia terenu z E3D
//-----------------------------------------------------------------------------
@@ -2341,6 +1828,8 @@ TSubModel *TModel3d::TerrainSquare(int n)
void TModel3d::TerrainRenderVBO(int n)
{ // renderowanie terenu z VBO
glPushMatrix();
::glTranslated( -Global::pCameraPosition.x, -Global::pCameraPosition.y, -Global::pCameraPosition.z );
// glTranslated(vPosition->x,vPosition->y,vPosition->z);
// if (vAngle->y!=0.0) glRotated(vAngle->y,0.0,1.0,0.0);
// if (vAngle->x!=0.0) glRotated(vAngle->x,1.0,0.0,0.0);

View File

@@ -255,12 +255,6 @@ public:
void SetRotateIK1(float3 vNewAngles);
TSubModel * GetFromName(std::string const &search, bool i = true);
TSubModel * GetFromName(char const *search, bool i = true);
#ifdef EU07_USE_OLD_RENDERCODE
void RenderDL();
void RenderAlphaDL();
void RenderVBO();
void RenderAlphaVBO();
#endif
// inline matrix4x4* GetMatrix() {return dMatrix;};
inline float4x4 * GetMatrix()
{
@@ -361,20 +355,6 @@ public:
bool LoadFromFile(std::string const &FileName, bool dynamic);
void SaveToBinFile(char const *FileName);
void BreakHierarhy();
// renderowanie specjalne
#ifdef EU07_USE_OLD_RENDERCODE
void Render(double fSquareDistance, texture_manager::size_type *ReplacableSkinId = NULL, int iAlpha = 0x30300030);
void RenderAlpha(double fSquareDistance, texture_manager::size_type *ReplacableSkinId = NULL, int iAlpha = 0x30300030);
#endif
void RaRender(double fSquareDistance, texture_manager::size_type const *ReplacableSkinId = NULL, int iAlpha = 0x30300030);
void RaRenderAlpha(double fSquareDistance, texture_manager::size_type const *ReplacableSkinId = NULL, int iAlpha = 0x30300030);
// trzy kąty obrotu
#ifdef EU07_USE_OLD_RENDERCODE
void Render( vector3 *vPosition, vector3 *vAngle, texture_manager::size_type *ReplacableSkinId = NULL, int iAlpha = 0x30300030 );
void RenderAlpha(vector3 *vPosition, vector3 *vAngle, texture_manager::size_type *ReplacableSkinId = NULL, int iAlpha = 0x30300030);
#endif
void RaRender(vector3 *vPosition, vector3 *vAngle, texture_manager::size_type const *ReplacableSkinId = NULL, int iAlpha = 0x30300030);
void RaRenderAlpha(vector3 *vPosition, vector3 *vAngle, texture_manager::size_type const *ReplacableSkinId = NULL, int iAlpha = 0x30300030);
// inline int GetSubModelsCount() { return (SubModelsCount); };
int Flags() const
{

View File

@@ -40,7 +40,7 @@ void TRealSound::Init(std::string const &SoundName, double DistanceAttenuation,
bool Dynamic, bool freqmod, double rmin)
{
// Nazwa=SoundName; //to tak raczej nie zadziała, (SoundName) jest tymczasowe
pSound = TSoundsManager::GetFromName(SoundName.c_str(), Dynamic, &fFrequency);
pSound = TSoundsManager::GetFromName(SoundName, Dynamic, &fFrequency);
if (pSound)
{
if (freqmod)
@@ -48,8 +48,7 @@ void TRealSound::Init(std::string const &SoundName, double DistanceAttenuation,
{ // dla modulowanych nie może być zmiany mnożnika, bo częstotliwość w nagłówku byłą
// ignorowana, a mogła być inna niż 22050
fFrequency = 22050.0;
ErrorLog("Bad sound: " + std::string(SoundName) +
", as modulated, should have 22.05kHz in header");
ErrorLog("Bad sound: " + SoundName + ", as modulated, should have 22.05kHz in header");
}
AM = 1.0;
pSound->SetVolume(DSBVOLUME_MIN);
@@ -57,7 +56,7 @@ void TRealSound::Init(std::string const &SoundName, double DistanceAttenuation,
else
{ // nie ma dźwięku, to jest wysyp
AM = 0;
ErrorLog("Missed sound: " + std::string(SoundName));
ErrorLog("Missed sound: " + SoundName);
}
if (DistanceAttenuation > 0.0)
{
@@ -268,26 +267,8 @@ void TTextSound::Play(double Volume, int Looping, bool ListenerInside, vector3 N
{ // jeśli ma powiązany tekst
DWORD stat;
pSound->GetStatus(&stat);
if (!(stat & DSBSTATUS_PLAYING)) // jeśli nie jest aktualnie odgrywany
{
/*
std::string t( asText );
size_t i;
do
{ // na razie zrobione jakkolwiek, docelowo przenieść teksty do tablicy nazw
i = t.find('\r'); // znak nowej linii
if( i == std::string::npos ) {
Global::tranTexts.Add( t, fTime, true );
}
else
{
Global::tranTexts.Add(t.substr(0, i), fTime, true);
t.erase(0, i + 1);
while (t.empty() ? false : (unsigned char)(t[1]) < 33)
t.erase(0, 1);
}
} while (i != std::string::npos);
*/
if (!(stat & DSBSTATUS_PLAYING)) {
// jeśli nie jest aktualnie odgrywany
Global::tranTexts.Add( asText, fTime, true );
}
}

View File

@@ -114,28 +114,30 @@ bool TSegment::Init(vector3 &NewPoint1, vector3 NewCPointOut, vector3 NewCPointI
{
ErrorLog( "Bad geometry (zero length) for spline \"" + pOwner->NameGet() + "\" at " + Where( Point1 ) );
// MessageBox(0,"Length<=0","TSegment::Init",MB_OK);
fLength = 0.01; // crude workaround TODO: fix this properly
/*
return false; // zerowe nie mogą być
*/
}
if( ( pOwner->eType == tt_Switch )
&& ( fStep * 3.0 > fLength ) ) {
// NOTE: a workaround for too short switches (less than 3 segments) messing up animation/generation of blades
fStep = fLength / 3.0;
}
fStoop = std::atan2((Point2.y - Point1.y), fLength); // pochylenie toru prostego, żeby nie liczyć wielokrotnie
SafeDeleteArray(fTsBuffer);
if( ( bCurve ) && ( fStep > 0 ) ) {
if( fStep > 0 ) { // Ra: prosty dostanie podział, jak ma różną przechyłkę na końcach
double s = 0;
int i = 0;
iSegCount = static_cast<int>( std::ceil( fLength / fStep )); // potrzebne do VBO
// fStep=fLength/(double)(iSegCount-1); //wyrównanie podziału
fTsBuffer = new double[ iSegCount + 1 ];
fTsBuffer[ 0 ] = 0; /* TODO : fix fTsBuffer */
while( s < fLength ) {
i++;
s += fStep;
if( s > fLength )
s = fLength;
fTsBuffer[ i ] = GetTFromS( s );
}
}
iSegCount = static_cast<int>( std::ceil( fLength / fStep ) ); // potrzebne do VBO
fStep = fLength / iSegCount; // update step to equalize size of individual pieces
fTsBuffer = new double[ iSegCount + 1 ];
fTsBuffer[ 0 ] = 0.0;
for( int i = 1; i < iSegCount; ++i ) {
fTsBuffer[ i ] = GetTFromS( i * fStep );
}
fTsBuffer[ iSegCount ] = 1.0;
return true;
}
@@ -317,14 +319,16 @@ vector3 TSegment::FastGetPoint(double t)
return (bCurve ? RaInterpolate(t) : ((1.0 - t) * Point1 + (t)*Point2));
}
void TSegment::RenderLoft( CVertNormTex* &Output, const vector6 *ShapePoints, int iNumShapePoints, double fTextureLength, double Texturescale, int iSkip, int iEnd, double fOffsetX, bool Onlypositions, vector3 **p, bool bRender)
int TSegment::RenderLoft( CVertNormTex* &Output, Math3D::vector3 const &Origin, const vector6 *ShapePoints, int iNumShapePoints, double fTextureLength, double Texturescale, int iSkip, int iEnd, double fOffsetX, vector3 **p, bool bRender)
{ // generowanie trójkątów dla odcinka trajektorii ruchu
// standardowo tworzy triangle_strip dla prostego albo ich zestaw dla łuku
// po modyfikacji - dla ujemnego (iNumShapePoints) w dodatkowych polach tabeli
// podany jest przekrój końcowy
// podsypka toru jest robiona za pomocą 6 punktów, szyna 12, drogi i rzeki na 3+2+3
int vertexcount{ 0 };
if( !fTsBuffer )
return; // prowizoryczne zabezpieczenie przed wysypem - ustalić faktyczną przyczynę
return vertexcount; // prowizoryczne zabezpieczenie przed wysypem - ustalić faktyczną przyczynę
vector3 pos1, pos2, dir, parallel1, parallel2, pt, norm;
double s, step, fOffset, tv1, tv2, t, fEnd;
@@ -348,6 +352,7 @@ void TSegment::RenderLoft( CVertNormTex* &Output, const vector6 *ShapePoints, in
fEnd = fLength * double( iEnd ) / double( iSegCount );
m2 = s / fEnd;
jmm2 = 1.0 - m2;
while( i < iEnd ) {
++i; // kolejny punkt łamanej
@@ -363,12 +368,10 @@ void TSegment::RenderLoft( CVertNormTex* &Output, const vector6 *ShapePoints, in
jmm2 = 0.0;
}
if( false == Onlypositions ) {
while( tv1 < 0.0 ) {
tv1 += 1.0;
}
tv2 = tv1 - step / fTextureLength; // mapowanie na końcu segmentu
while( tv1 < 0.0 ) {
tv1 += 1.0;
}
tv2 = tv1 - step / fTextureLength; // mapowanie na końcu segmentu
t = fTsBuffer[ i ]; // szybsze od GetTFromS(s);
pos2 = FastGetPoint( t );
@@ -384,32 +387,28 @@ void TSegment::RenderLoft( CVertNormTex* &Output, const vector6 *ShapePoints, in
for( int j = 0; j < iNumShapePoints; ++j ) {
pt = parallel1 * ( jmm1 * ( ShapePoints[ j ].x - fOffsetX ) + m1 * ShapePoints[ j + iNumShapePoints ].x ) + pos1;
pt.y += jmm1 * ShapePoints[ j ].y + m1 * ShapePoints[ j + iNumShapePoints ].y;
if( false == Onlypositions ) {
norm = ( jmm1 * ShapePoints[ j ].n.x + m1 * ShapePoints[ j + iNumShapePoints ].n.x ) * parallel1;
norm.y += jmm1 * ShapePoints[ j ].n.y + m1 * ShapePoints[ j + iNumShapePoints ].n.y;
}
pt -= Origin;
norm = ( jmm1 * ShapePoints[ j ].n.x + m1 * ShapePoints[ j + iNumShapePoints ].n.x ) * parallel1;
norm.y += jmm1 * ShapePoints[ j ].n.y + m1 * ShapePoints[ j + iNumShapePoints ].n.y;
if( bRender ) { // skrzyżowania podczas łączenia siatek mogą nie renderować poboczy, ale potrzebować punktów
if( Output == nullptr ) {
// immediate mode
if( false == Onlypositions ) {
::glNormal3f( norm.x, norm.y, norm.z );
::glTexCoord2f( (jmm1 * ShapePoints[ j ].z + m1 * ShapePoints[ j + iNumShapePoints ].z) / Texturescale, tv1 );
}
::glNormal3f( norm.x, norm.y, norm.z );
::glTexCoord2f( (jmm1 * ShapePoints[ j ].z + m1 * ShapePoints[ j + iNumShapePoints ].z) / Texturescale, tv1 );
::glVertex3f( pt.x, pt.y, pt.z ); // pt nie mamy gdzie zapamiętać?
}
else {
Output->x = pt.x;
Output->y = pt.y;
Output->z = pt.z;
if( false == Onlypositions ) {
Output->nx = norm.x;
Output->ny = norm.y;
Output->nz = norm.z;
Output->u = (jmm1 * ShapePoints[ j ].z + m1 * ShapePoints[ j + iNumShapePoints ].z) / Texturescale;
Output->v = tv1;
}
Output->nx = norm.x;
Output->ny = norm.y;
Output->nz = norm.z;
Output->u = (jmm1 * ShapePoints[ j ].z + m1 * ShapePoints[ j + iNumShapePoints ].z) / Texturescale;
Output->v = tv1;
++Output;
}
++vertexcount;
}
if( p ) // jeśli jest wskaźnik do tablicy
if( *p )
@@ -421,32 +420,28 @@ void TSegment::RenderLoft( CVertNormTex* &Output, const vector6 *ShapePoints, in
// dla trapezu drugi koniec ma inne współrzędne
pt = parallel2 * ( jmm2 * ( ShapePoints[ j ].x - fOffsetX ) + m2 * ShapePoints[ j + iNumShapePoints ].x ) + pos2;
pt.y += jmm2 * ShapePoints[ j ].y + m2 * ShapePoints[ j + iNumShapePoints ].y;
if( false == Onlypositions ) {
norm = ( jmm1 * ShapePoints[ j ].n.x + m1 * ShapePoints[ j + iNumShapePoints ].n.x ) * parallel2;
norm.y += jmm1 * ShapePoints[ j ].n.y + m1 * ShapePoints[ j + iNumShapePoints ].n.y;
}
pt -= Origin;
norm = ( jmm1 * ShapePoints[ j ].n.x + m1 * ShapePoints[ j + iNumShapePoints ].n.x ) * parallel2;
norm.y += jmm1 * ShapePoints[ j ].n.y + m1 * ShapePoints[ j + iNumShapePoints ].n.y;
if( bRender ) { // skrzyżowania podczas łączenia siatek mogą nie renderować poboczy, ale potrzebować punktów
if( Output == nullptr ) {
// immediate mode
if( false == Onlypositions ) {
::glNormal3f( norm.x, norm.y, norm.z );
::glTexCoord2f( (jmm2 * ShapePoints[ j ].z + m2 * ShapePoints[ j + iNumShapePoints ].z) / Texturescale, tv2 );
}
::glNormal3f( norm.x, norm.y, norm.z );
::glTexCoord2f( (jmm2 * ShapePoints[ j ].z + m2 * ShapePoints[ j + iNumShapePoints ].z) / Texturescale, tv2 );
::glVertex3f( pt.x, pt.y, pt.z );
}
else {
Output->x = pt.x;
Output->y = pt.y;
Output->z = pt.z;
if( false == Onlypositions ) {
Output->nx = norm.x;
Output->ny = norm.y;
Output->nz = norm.z;
Output->u = (jmm2 * ShapePoints[ j ].z + m2 * ShapePoints[ j + iNumShapePoints ].z) / Texturescale;
Output->v = tv2;
}
Output->nx = norm.x;
Output->ny = norm.y;
Output->nz = norm.z;
Output->u = (jmm2 * ShapePoints[ j ].z + m2 * ShapePoints[ j + iNumShapePoints ].z) / Texturescale;
Output->v = tv2;
++Output;
}
++vertexcount;
}
if( p ) // jeśli jest wskaźnik do tablicy
if( *p )
@@ -458,61 +453,56 @@ void TSegment::RenderLoft( CVertNormTex* &Output, const vector6 *ShapePoints, in
}
}
else {
for( int j = 0; j < iNumShapePoints; ++j ) {
//łuk z jednym profilem
pt = parallel1 * ( ShapePoints[ j ].x - fOffsetX ) + pos1;
pt.y += ShapePoints[ j ].y;
if( false == Onlypositions ) {
if( bRender ) {
for( int j = 0; j < iNumShapePoints; ++j ) {
//łuk z jednym profilem
pt = parallel1 * ( ShapePoints[ j ].x - fOffsetX ) + pos1;
pt.y += ShapePoints[ j ].y;
pt -= Origin;
norm = ShapePoints[ j ].n.x * parallel1;
norm.y += ShapePoints[ j ].n.y;
}
if( Output == nullptr ) {
// immediate mode
if( false == Onlypositions ) {
if( Output == nullptr ) {
// immediate mode
::glNormal3f( norm.x, norm.y, norm.z );
::glTexCoord2f( ShapePoints[ j ].z / Texturescale, tv1 );
::glVertex3f( pt.x, pt.y, pt.z ); // punkt na początku odcinka
}
::glVertex3f( pt.x, pt.y, pt.z ); // punkt na początku odcinka
}
else {
Output->x = pt.x;
Output->y = pt.y;
Output->z = pt.z;
if( false == Onlypositions ) {
else {
Output->x = pt.x;
Output->y = pt.y;
Output->z = pt.z;
Output->nx = norm.x;
Output->ny = norm.y;
Output->nz = norm.z;
Output->u = ShapePoints[ j ].z / Texturescale;
Output->v = tv1;
++Output;
}
++Output;
}
pt = parallel2 * ShapePoints[ j ].x + pos2;
pt.y += ShapePoints[ j ].y;
if( false == Onlypositions ) {
++vertexcount;
pt = parallel2 * ShapePoints[ j ].x + pos2;
pt.y += ShapePoints[ j ].y;
pt -= Origin;
norm = ShapePoints[ j ].n.x * parallel2;
norm.y += ShapePoints[ j ].n.y;
}
if( Output == nullptr ) {
// immediate mode
if( false == Onlypositions ) {
if( Output == nullptr ) {
// immediate mode
::glNormal3f( norm.x, norm.y, norm.z );
::glTexCoord2f( ShapePoints[ j ].z / Texturescale, tv2 );
::glVertex3f( pt.x, pt.y, pt.z ); // punkt na końcu odcinka
}
::glVertex3f( pt.x, pt.y, pt.z ); // punkt na końcu odcinka
}
else {
Output->x = pt.x;
Output->y = pt.y;
Output->z = pt.z;
if( false == Onlypositions ) {
else {
Output->x = pt.x;
Output->y = pt.y;
Output->z = pt.z;
Output->nx = norm.x;
Output->ny = norm.y;
Output->nz = norm.z;
Output->u = ShapePoints[ j ].z / Texturescale;
Output->v = tv2;
++Output;
}
++Output;
++vertexcount;
}
}
}
@@ -522,10 +512,10 @@ void TSegment::RenderLoft( CVertNormTex* &Output, const vector6 *ShapePoints, in
}
pos1 = pos2;
parallel1 = parallel2;
if( false == Onlypositions ) {
tv1 = tv2;
}
tv1 = tv2;
}
return vertexcount;
};
void TSegment::Render()

View File

@@ -113,7 +113,7 @@ class TSegment
r1 = fRoll1;
r2 = fRoll2;
}
void RenderLoft( CVertNormTex* &Output, const vector6 *ShapePoints, int iNumShapePoints, double fTextureLength, double Texturescale = 1.0, int iSkip = 0, int iEnd = 0, double fOffsetX = 0.0, bool Onlypositions = false, vector3 **p = nullptr, bool bRender = true);
int RenderLoft( CVertNormTex* &Output, Math3D::vector3 const &Origin, vector6 const *ShapePoints, int iNumShapePoints, double fTextureLength, double Texturescale = 1.0, int iSkip = 0, int iEnd = 0, double fOffsetX = 0.0, vector3 **p = nullptr, bool bRender = true);
void Render();
inline double GetLength()
{

116
Sound.cpp
View File

@@ -14,7 +14,7 @@ http://mozilla.org/MPL/2.0/.
#include "Usefull.h"
#include "mczapkie/mctools.h"
#include "WavRead.h"
//#define SAFE_DELETE(p) { if(p) { delete (p); (p)=NULL; } }
#define SAFE_RELEASE(p) \
{ \
if (p) \
@@ -24,43 +24,31 @@ http://mozilla.org/MPL/2.0/.
} \
}
char Directory[] = "sounds\\";
LPDIRECTSOUND TSoundsManager::pDS;
LPDIRECTSOUNDNOTIFY TSoundsManager::pDSNotify;
int TSoundsManager::Count = 0;
TSoundContainer *TSoundsManager::First = NULL;
TSoundContainer::TSoundContainer(LPDIRECTSOUND pDS, const char *Directory, const char *strFileName,
int NConcurrent)
TSoundContainer::TSoundContainer(LPDIRECTSOUND pDS, std::string const &Directory, std::string const &Filename, int NConcurrent)
{ // wczytanie pliku dźwiękowego
int hr = 111;
DSBuffer = NULL; // na początek, gdyby uruchomić dźwięków się nie udało
DSBuffer = nullptr; // na początek, gdyby uruchomić dźwięków się nie udało
Concurrent = NConcurrent;
Oldest = 0;
// strcpy(Name, strFileName);
strcpy(Name, Directory);
strcat(Name, strFileName);
CWaveSoundRead *pWaveSoundRead;
m_name = Directory + Filename;
// Create a new wave file class
pWaveSoundRead = new CWaveSoundRead();
std::shared_ptr<CWaveSoundRead> pWaveSoundRead = std::make_shared<CWaveSoundRead>();
// Load the wave file
if (FAILED(pWaveSoundRead->Open(Name)))
if (FAILED(pWaveSoundRead->Open(strdup(strFileName))))
{
// SetFileUI( hDlg, TEXT("Bad wave file.") );
ErrorLog( "Missed sound: " + std::string( strFileName ) );
return;
}
if( ( FAILED( pWaveSoundRead->Open( m_name ) ) )
&& ( FAILED( pWaveSoundRead->Open( Filename ) ) ) ) {
ErrorLog( "Missed sound: " + Filename );
return;
}
strcpy(Name, ToLower(strFileName).c_str());
m_name = ToLower( Filename );
// Set up the direct sound buffer, and only request the flags needed
// since each requires some overhead and limits if the buffer can
@@ -133,27 +121,10 @@ TSoundContainer::TSoundContainer(LPDIRECTSOUND pDS, const char *Directory, const
// We dont need the wav file data buffer anymore, so delete it
delete[] pbWavData;
delete pWaveSoundRead;
DSBuffers.push(DSBuffer);
/*
for (int i=1; i<Concurrent; i++)
{
if( FAILED( hr= pDS->DuplicateSoundBuffer(pDSBuffer[0],&(pDSBuffer[i]))))
{
Concurrent= i;
break;
};
};*/
};
TSoundContainer::~TSoundContainer()
{
// for (int i=Concurrent-1; i>=0; i--)
// SAFE_RELEASE( pDSBuffer[i] );
// free(pDSBuffer);
while (!DSBuffers.empty())
{
SAFE_RELEASE(DSBuffers.top());
@@ -185,84 +156,51 @@ void TSoundsManager::Free()
SAFE_RELEASE(pDS);
};
TSoundContainer * TSoundsManager::LoadFromFile(const char *Dir, const char *Name, int Concurrent)
TSoundContainer * TSoundsManager::LoadFromFile( std::string const &Dir, std::string const &Filename, int Concurrent)
{
TSoundContainer *Tmp = First;
First = new TSoundContainer(pDS, Dir, Name, Concurrent);
First->Next = Tmp;
TSoundContainer *tmp = First;
First = new TSoundContainer(pDS, Dir, Filename, Concurrent);
First->Next = tmp;
Count++;
return First; // albo NULL, jak nie wyjdzie (na razie zawsze wychodzi)
};
void TSoundsManager::LoadSounds(char *Directory)
{ // wczytanie wszystkich plików z katalogu - mało elastyczne
WIN32_FIND_DATA FindFileData;
HANDLE handle = FindFirstFile("sounds\\*.wav", &FindFileData);
if (handle != INVALID_HANDLE_VALUE)
do
{
LoadFromFile(Directory, FindFileData.cFileName, 1);
} while (FindNextFile(handle, &FindFileData));
FindClose(handle);
};
LPDIRECTSOUNDBUFFER TSoundsManager::GetFromName(const char *Name, bool Dynamic, float *fSamplingRate)
LPDIRECTSOUNDBUFFER TSoundsManager::GetFromName(std::string const &Name, bool Dynamic, float *fSamplingRate)
{ // wyszukanie dźwięku w pamięci albo wczytanie z pliku
std::string name{ ToLower(Name) };
std::string file;
if (Dynamic)
{ // próba wczytania z katalogu pojazdu
file = Global::asCurrentDynamicPath + Name;
file = Global::asCurrentDynamicPath + name;
if (FileExists(file))
Name = file.c_str(); // nowa nazwa
name = file; // nowa nazwa
else
Dynamic = false; // wczytanie z "sounds/"
}
TSoundContainer *Next = First;
for (int i = 0; i < Count; i++)
{
if (strcmp(Name, Next->Name) == 0)
{
if( name == Next->m_name ) {
if (fSamplingRate)
*fSamplingRate = Next->fSamplingRate; // częstotliwość
return (Next->GetUnique(pDS));
// DSBuffers.
/*
Next->pDSBuffer[Next->Oldest]->Stop();
Next->pDSBuffer[Next->Oldest]->SetCurrentPosition(0);
if (Next->Oldest<Next->Concurrent-1)
{
Next->Oldest++;
return (Next->pDSBuffer[Next->Oldest-1]);
}
else
{
Next->Oldest= 0;
return (Next->pDSBuffer[Next->Concurrent-1]);
};
/* for (int j=0; j<Next->Concurrent; j++)
{
Next->pDSBuffer[j]->GetStatus(&dwStatus);
if ((dwStatus & DSBSTATUS_PLAYING) != DSBSTATUS_PLAYING)
return (Next->pDSBuffer[j]);
} */
}
else
Next = Next->Next;
};
if (Dynamic) // wczytanie z katalogu pojazdu
Next = LoadFromFile("", Name, 1);
Next = LoadFromFile("", name, 1);
else
Next = LoadFromFile(Directory, Name, 1);
Next = LoadFromFile(szSoundPath, name, 1);
if (Next)
{ //
if (fSamplingRate)
*fSamplingRate = Next->fSamplingRate; // częstotliwość
return Next->GetUnique(pDS);
}
ErrorLog("Missed sound: " + std::string(Name) );
return (NULL);
ErrorLog("Missed sound: " + Name );
return (nullptr);
};
void TSoundsManager::RestoreAll()
@@ -299,10 +237,6 @@ void TSoundsManager::RestoreAll()
};
};
// void TSoundsManager::Init(char *Name, int Concurrent)
// TSoundsManager::TSoundsManager(HWND hWnd)
// void TSoundsManager::Init(HWND hWnd, char *NDirectory)
void TSoundsManager::Init(HWND hWnd)
{

38
Sound.h
View File

@@ -7,56 +7,44 @@ obtain one at
http://mozilla.org/MPL/2.0/.
*/
#ifndef SoundH
#define SoundH
#pragma once
#include <stack>
#include <dsound.h>
typedef LPDIRECTSOUNDBUFFER PSound;
// inline Playing(PSound Sound)
//{
//}
class TSoundContainer
{
public:
public:
int Concurrent;
int Oldest;
char Name[80];
std::string m_name;
LPDIRECTSOUNDBUFFER DSBuffer;
float fSamplingRate; // częstotliwość odczytana z pliku
int iBitsPerSample; // ile bitów na próbkę
TSoundContainer *Next;
std::stack<LPDIRECTSOUNDBUFFER> DSBuffers;
LPDIRECTSOUNDBUFFER GetUnique(LPDIRECTSOUND pDS);
TSoundContainer(LPDIRECTSOUND pDS, const char *Directory, const char *strFileName, int NConcurrent);
TSoundContainer(LPDIRECTSOUND pDS, std::string const &Directory, std::string const &Filename, int NConcurrent);
~TSoundContainer();
LPDIRECTSOUNDBUFFER GetUnique( LPDIRECTSOUND pDS );
};
class TSoundsManager
{
private:
private:
static LPDIRECTSOUND pDS;
static LPDIRECTSOUNDNOTIFY pDSNotify;
// static char Directory[80];
static int Count;
static TSoundContainer *First;
static TSoundContainer * LoadFromFile(const char *Dir, const char *Name, int Concurrent);
static int Count;
public:
// TSoundsManager(HWND hWnd);
// static void Init(HWND hWnd, char *NDirectory);
static void Init(HWND hWnd);
static TSoundContainer * LoadFromFile( std::string const &Directory, std::string const &FileName, int Concurrent);
public:
~TSoundsManager();
static void Init( HWND hWnd );
static void Free();
static void Init(char *Name, int Concurrent);
static void LoadSounds(char *Directory);
static LPDIRECTSOUNDBUFFER GetFromName(const char *Name, bool Dynamic, float *fSamplingRate = NULL);
static LPDIRECTSOUNDBUFFER GetFromName( std::string const &Name, bool Dynamic, float *fSamplingRate = NULL );
static void RestoreAll();
};
//---------------------------------------------------------------------------
#endif

395
Track.cpp
View File

@@ -198,7 +198,7 @@ TTrack * TTrack::Create400m(int what, double dx)
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
trk->Segment->Init(vector3(-dx, 0, 0), vector3(-dx, 0, 400), 10.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
@@ -405,8 +405,7 @@ void TTrack::Load(cParser *parser, vector3 pOrigin, std::string name)
std::string token;
parser->getTokens();
*parser >> token;
str = token; // typ toru
*parser >> str; // typ toru
if (str == "normal")
{
@@ -460,8 +459,7 @@ void TTrack::Load(cParser *parser, vector3 pOrigin, std::string name)
if (iDamageFlag & 128)
iAction |= 0x80; // flaga wykolejania z powodu uszkodzenia
parser->getTokens();
*parser >> token;
str = token; // environment
*parser >> str; // environment
if (str == "flat")
eEnvironment = e_flat;
else if (str == "mountains" || str == "mountain")
@@ -477,7 +475,7 @@ void TTrack::Load(cParser *parser, vector3 pOrigin, std::string name)
else
{
eEnvironment = e_unknown;
Error("Unknown track environment: \"" + str + "\"");
Error( "Unknown track environment: \"" + str + "\"" );
}
parser->getTokens();
*parser >> token;
@@ -485,8 +483,7 @@ void TTrack::Load(cParser *parser, vector3 pOrigin, std::string name)
if (bVisible)
{
parser->getTokens();
*parser >> token;
str = token; // railtex
*parser >> str; // railtex
TextureID1 = (str == "none" ? 0 : GfxRenderer.GetTextureId(
str, szTexturePath,
(iCategoryFlag & 1) ? Global::iRailProFiltering :
@@ -496,8 +493,7 @@ void TTrack::Load(cParser *parser, vector3 pOrigin, std::string name)
if (fTexLength < 0.01)
fTexLength = 4; // Ra: zabezpiecznie przed zawieszeniem
parser->getTokens();
*parser >> token;
str = token; // sub || railtex
*parser >> str; // sub || railtex
TextureID2 = (str == "none" ? 0 : GfxRenderer.GetTextureId(
str, szTexturePath,
(eType == tt_Normal) ? Global::iBallastFiltering :
@@ -532,7 +528,7 @@ void TTrack::Load(cParser *parser, vector3 pOrigin, std::string name)
// 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
segsize = clamp( 0.2 + std::fabs( fRadius ) * 0.02, 2.0, 10.0 );
else
segsize = 10.0; // for straights, 10m per segment works good enough
@@ -595,13 +591,14 @@ void TTrack::Load(cParser *parser, vector3 pOrigin, std::string name)
// na przechyłce doliczyć jeszcze pół przechyłki?
}
if (fRadiusTable[0] > 0)
segsize = Min0R(5.0, 0.2 + fRadiusTable[0] * 0.02);
segsize = clamp( 0.2 + fRadiusTable[0] * 0.02, 2.0, 5.0 );
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
@@ -624,7 +621,8 @@ void TTrack::Load(cParser *parser, vector3 pOrigin, std::string name)
}
if (fRadiusTable[1] > 0)
segsize = Min0R(5.0, 0.2 + fRadiusTable[1] * 0.02);
segsize = clamp( 0.2 + fRadiusTable[ 1 ] * 0.02, 2.0, 5.0 );
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
@@ -641,6 +639,7 @@ void TTrack::Load(cParser *parser, vector3 pOrigin, std::string name)
}
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
@@ -1091,6 +1090,9 @@ void TTrack::Compile(GLuint tex)
hypot2 = hypot1;
normal2 = normal1;
}
auto const origin = pMyNode->m_rootposition;
double roll1, roll2;
switch (iCategoryFlag & 15)
{
@@ -1217,19 +1219,19 @@ void TTrack::Compile(GLuint tex)
}
if (!tex)
GfxRenderer.Bind( TextureID2 );
Segment->RenderLoft( immediate, bpts1, iTrapezoid ? -4 : 4, fTexLength);
Segment->RenderLoft( immediate, origin, bpts1, iTrapezoid ? -4 : 4, fTexLength);
}
if (TextureID1)
if (tex ? TextureID1 == tex : true) // jeśli pasuje do grupy (tex)
{ // szyny
if (!tex)
GfxRenderer.Bind( TextureID1 );
Segment->RenderLoft( immediate, rpts1, iTrapezoid ? -nnumPts : nnumPts, fTexLength);
Segment->RenderLoft( immediate, rpts2, iTrapezoid ? -nnumPts : nnumPts, fTexLength);
Segment->RenderLoft( immediate, origin, rpts1, iTrapezoid ? -nnumPts : nnumPts, fTexLength);
Segment->RenderLoft( immediate, origin, 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ć
if (TextureID1 || TextureID2) // 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];
@@ -1251,27 +1253,34 @@ void TTrack::Compile(GLuint tex)
// McZapkie-130302 - poprawione rysowanie szyn
if (SwitchExtension->RightSwitch)
{ // zwrotnica prawa
GfxRenderer.Bind( TextureID1 );
SwitchExtension->Segments[0]->RenderLoft( immediate, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, SwitchExtension->fOffset2); // prawa iglica
SwitchExtension->Segments[0]->RenderLoft( immediate, rpts1, nnumPts, fTexLength, 1.0, 2); // prawa szyna za iglicą
SwitchExtension->Segments[0]->RenderLoft( immediate, rpts2, nnumPts, fTexLength); // lewa szyna normalnie cała
if (TextureID2 != TextureID1) // nie wiadomo, czy OpenGL to optymalizuje
if( TextureID1 ) {
GfxRenderer.Bind( TextureID1 );
SwitchExtension->Segments[ 0 ]->RenderLoft( immediate, origin, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, SwitchExtension->fOffset2 ); // prawa iglica
SwitchExtension->Segments[ 0 ]->RenderLoft( immediate, origin, rpts1, nnumPts, fTexLength, 1.0, 2 ); // prawa szyna za iglicą
SwitchExtension->Segments[ 0 ]->RenderLoft( immediate, origin, rpts2, nnumPts, fTexLength ); // lewa szyna normalnie cała
}
if( TextureID2 ) {
GfxRenderer.Bind( TextureID2 );
SwitchExtension->Segments[1]->RenderLoft( immediate, rpts1, nnumPts, fTexLength); // prawa szyna normalna cała
SwitchExtension->Segments[1]->RenderLoft( immediate, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -fMaxOffset + SwitchExtension->fOffset1); // lewa iglica
SwitchExtension->Segments[1]->RenderLoft( immediate, rpts2, nnumPts, fTexLength, 1.0, 2); // lewa szyna za iglicą
SwitchExtension->Segments[ 1 ]->RenderLoft( immediate, origin, rpts1, nnumPts, fTexLength ); // prawa szyna normalna cała
SwitchExtension->Segments[ 1 ]->RenderLoft( immediate, origin, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -fMaxOffset + SwitchExtension->fOffset1 ); // lewa iglica
SwitchExtension->Segments[ 1 ]->RenderLoft( immediate, origin, rpts2, nnumPts, fTexLength, 1.0, 2 ); // lewa szyna za iglicą
}
}
else
{ // lewa kiedyś działała lepiej niż prawa
GfxRenderer.Bind( TextureID1 );
SwitchExtension->Segments[0]->RenderLoft( immediate, rpts1, nnumPts, fTexLength); // prawa szyna normalna cała
SwitchExtension->Segments[0]->RenderLoft( immediate, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -SwitchExtension->fOffset2); // lewa iglica
SwitchExtension->Segments[0]->RenderLoft( immediate, rpts2, nnumPts, fTexLength, 1.0, 2); // lewa szyna za iglicą
if (TextureID2 != TextureID1) // nie wiadomo, czy OpenGL to optymalizuje
if( TextureID1 ) {
GfxRenderer.Bind( TextureID1 );
SwitchExtension->Segments[ 0 ]->RenderLoft( immediate, origin, rpts1, nnumPts, fTexLength ); // prawa szyna normalna cała
SwitchExtension->Segments[ 0 ]->RenderLoft( immediate, origin, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -SwitchExtension->fOffset2 ); // lewa iglica
SwitchExtension->Segments[ 0 ]->RenderLoft( immediate, origin, rpts2, nnumPts, fTexLength, 1.0, 2 ); // lewa szyna za iglicą
}
if( TextureID2 ) {
// nie wiadomo, czy OpenGL to optymalizuje
GfxRenderer.Bind( TextureID2 );
SwitchExtension->Segments[1]->RenderLoft( immediate, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, fMaxOffset - SwitchExtension->fOffset1); // prawa iglica
SwitchExtension->Segments[1]->RenderLoft( immediate, rpts1, nnumPts, fTexLength, 1.0, 2); // prawa szyna za iglicą
SwitchExtension->Segments[1]->RenderLoft( immediate, rpts2, nnumPts, fTexLength); // lewa szyna normalnie cała
SwitchExtension->Segments[ 1 ]->RenderLoft( immediate, origin, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, fMaxOffset - SwitchExtension->fOffset1 ); // prawa iglica
SwitchExtension->Segments[ 1 ]->RenderLoft( immediate, origin, rpts1, nnumPts, fTexLength, 1.0, 2 ); // prawa szyna za iglicą
SwitchExtension->Segments[ 1 ]->RenderLoft( immediate, origin, rpts2, nnumPts, fTexLength ); // lewa szyna normalnie cała
}
}
}
break;
@@ -1309,7 +1318,7 @@ void TTrack::Compile(GLuint tex)
{ // tworzenie trójkątów nawierzchni szosy
if (!tex)
GfxRenderer.Bind( TextureID1 );
Segment->RenderLoft( immediate, bpts1, iTrapezoid ? -2 : 2, fTexLength);
Segment->RenderLoft( immediate, origin, bpts1, iTrapezoid ? -2 : 2, fTexLength);
}
if (TextureID2)
if (tex ? TextureID2 == tex : true) // jeśli pasuje do grupy (tex)
@@ -1393,16 +1402,16 @@ void TTrack::Compile(GLuint tex)
{ // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony
// odcinka
if ((fTexHeight1 >= 0.0) ? true : (slop != 0.0))
Segment->RenderLoft( immediate, rpts1, -3, fTexLength); // tylko jeśli jest z prawej
Segment->RenderLoft( immediate, origin, rpts1, -3, fTexLength); // tylko jeśli jest z prawej
if ((fTexHeight1 >= 0.0) ? true : (side != 0.0))
Segment->RenderLoft( immediate, rpts2, -3, fTexLength); // tylko jeśli jest z lewej
Segment->RenderLoft( immediate, origin, 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( immediate, rpts1, 3, fTexLength);
Segment->RenderLoft( immediate, origin, rpts1, 3, fTexLength);
if ((fTexHeight1 >= 0.0) ? true : (side != 0.0))
Segment->RenderLoft( immediate, rpts2, 3, fTexLength);
Segment->RenderLoft( immediate, origin, rpts2, 3, fTexLength);
}
}
break;
@@ -1438,19 +1447,19 @@ void TTrack::Compile(GLuint tex)
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();
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->Segments[ 2 ]->RaSegCount()
+ SwitchExtension->Segments[ 3 ]->RaSegCount()
+ SwitchExtension->Segments[ 4 ]->RaSegCount()
+ SwitchExtension->Segments[ 5 ]->RaSegCount();
}
// tablica utworzona z zapasem, ale nie wypełniona współrzędnymi
SwitchExtension->vPoints = new vector3[SwitchExtension->iPoints];
SwitchExtension->vPoints = new vector3[ SwitchExtension->iPoints + SwitchExtension->iRoads ];
}
vector3 *b =
SwitchExtension->bPoints ?
@@ -1545,58 +1554,62 @@ void TTrack::Compile(GLuint tex)
if (SwitchExtension->iRoads == 4)
{ // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony odcinka
if( ( fTexHeight1 >= 0.0 ) || ( side != 0.0 ) ) {
SwitchExtension->Segments[ 2 ]->RenderLoft( immediate, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, false, &b, render );
SwitchExtension->Segments[ 3 ]->RenderLoft( immediate, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, false, &b, render );
SwitchExtension->Segments[ 4 ]->RenderLoft( immediate, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, false, &b, render );
SwitchExtension->Segments[ 5 ]->RenderLoft( immediate, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, false, &b, render );
SwitchExtension->Segments[ 2 ]->RenderLoft( immediate, origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render );
SwitchExtension->Segments[ 3 ]->RenderLoft( immediate, origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render );
SwitchExtension->Segments[ 4 ]->RenderLoft( immediate, origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render );
SwitchExtension->Segments[ 5 ]->RenderLoft( immediate, origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render );
}
}
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 ) || ( side != 0.0 ) ) {
SwitchExtension->Segments[ 2 ]->RenderLoft( immediate, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, false, &b, render ); // z P2 do P4
SwitchExtension->Segments[ 1 ]->RenderLoft( immediate, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, false, &b, render ); // z P4 do P3=P1 (odwrócony)
SwitchExtension->Segments[ 0 ]->RenderLoft( immediate, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, false, &b, render ); // z P1 do P2
SwitchExtension->Segments[ 2 ]->RenderLoft( immediate, origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render ); // z P2 do P4
SwitchExtension->Segments[ 1 ]->RenderLoft( immediate, origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render ); // z P4 do P3=P1 (odwrócony)
SwitchExtension->Segments[ 0 ]->RenderLoft( immediate, origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render ); // z P1 do P2
}
}
}
// 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
// ustalenie liczby punktów, bo mogło wyjść inaczej niż
i = (int)(((size_t)(b)) - ((size_t)(SwitchExtension->vPoints))) / sizeof(vector3);
// 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 {
// jak tutaj wejdzie, to błąd jest - zrobić miejsce na powtórzenie pierwszego punktu na końcu
--SwitchExtension->iPoints;
}
SwitchExtension->vPoints[SwitchExtension->iPoints++] = SwitchExtension->vPoints[0];
SwitchExtension->bPoints = true; // tablica punktów została wypełniona
}
}
if( ( false == SwitchExtension->bPoints ) // jeśli tablica nie wypełniona
&& ( b != nullptr ) ) {
SwitchExtension->bPoints = true; // tablica punktów została wypełniona
}
if (TextureID1) // jeśli podana tekstura nawierzchni
if ( (tex == TextureID1) || (tex == 0) ) // jeśli pasuje do grupy (tex)
{
if (!tex)
GfxRenderer.Bind( TextureID1 );
glBegin(GL_TRIANGLE_FAN); // takie kółeczko będzie
// we start with a vertex in the middle...
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)
glVertex3f(
oxz.x - origin.x,
oxz.y - origin.y,
oxz.z - origin.z );
// ...and add one extra vertex to close the fan...
glNormal3f( 0, 1, 0 );
// mapowanie we współrzędnych scenerii
u = ( SwitchExtension->vPoints[ 0 ].x - oxz.x + origin.x ) / fTexLength;
v = ( SwitchExtension->vPoints[ 0 ].z - oxz.z + origin.z ) / ( fTexRatio1 * fTexLength );
glTexCoord2f(
cosa0 * u + sina0 * v + 0.5,
-sina0 * u + cosa0 * v + 0.5 );
glVertex3f(
SwitchExtension->vPoints[ 0 ].x,
SwitchExtension->vPoints[ 0 ].y,
SwitchExtension->vPoints[ 0 ].z );
for ( i = SwitchExtension->iPoints + SwitchExtension->iRoads - 1; i >= 0; --i )
{
glNormal3f(0, 1, 0);
// mapowanie we współrzędnych scenerii
u = (SwitchExtension->vPoints[i].x - oxz.x) / fTexLength;
v = (SwitchExtension->vPoints[i].z - oxz.z) / (fTexRatio1 * fTexLength);
u = (SwitchExtension->vPoints[i].x - oxz.x + origin.x) / fTexLength;
v = (SwitchExtension->vPoints[i].z - oxz.z + origin.z) / (fTexRatio1 * fTexLength);
glTexCoord2f(
cosa0 * u + sina0 * v + 0.5,
-sina0 * u + cosa0 * v + 0.5);
@@ -1622,7 +1635,7 @@ void TTrack::Compile(GLuint tex)
{
if (!tex)
GfxRenderer.Bind( TextureID1 );
Segment->RenderLoft( immediate, bpts1, numPts, fTexLength);
Segment->RenderLoft( immediate, origin, bpts1, numPts, fTexLength);
}
if (TextureID2)
if (tex ? TextureID2 == tex : true) // jeśli pasuje do grupy (tex)
@@ -1634,8 +1647,8 @@ void TTrack::Compile(GLuint tex)
vector6(-rozp, -fTexHeight1, 0.0)}; // Ra: po kiego 0.1?
if (!tex)
GfxRenderer.Bind( TextureID2 ); // brzeg rzeki
Segment->RenderLoft( immediate, rpts1, 3, fTexLength);
Segment->RenderLoft( immediate, rpts2, 3, fTexLength);
Segment->RenderLoft( immediate, origin, rpts1, 3, fTexLength );
Segment->RenderLoft( immediate, origin, rpts2, 3, fTexLength );
}
break;
}
@@ -1779,31 +1792,33 @@ int TTrack::RaArrayPrepare()
if( SwitchExtension->iRoads == 3 ) {
// mogą być tylko 3 drogi zamiast 4
SwitchExtension->iPoints =
5
+ SwitchExtension->Segments[ 0 ]->RaSegCount()
SwitchExtension->Segments[ 0 ]->RaSegCount()
+ SwitchExtension->Segments[ 1 ]->RaSegCount()
+ SwitchExtension->Segments[ 2 ]->RaSegCount();
}
else {
SwitchExtension->iPoints =
5
+ SwitchExtension->Segments[ 2 ]->RaSegCount()
SwitchExtension->Segments[ 2 ]->RaSegCount()
+ SwitchExtension->Segments[ 3 ]->RaSegCount()
+ SwitchExtension->Segments[ 4 ]->RaSegCount()
+ SwitchExtension->Segments[ 5 ]->RaSegCount();
}
/*
if (fTexHeight1 >= 0) {
// normalne pobocze, na razie się składa z
return SwitchExtension->iPoints * ((TextureID1 ? 1 : 0) + (TextureID2 ? 12 : 0));
return ( ( TextureID1 ? SwitchExtension->iPoints + SwitchExtension->iRoads + 2 : 0 ) + ( TextureID2 ? SwitchExtension->iPoints * 12 : 0 ) );
}
else {
// jeśli fTexHeight1<0, to są chodniki i może któregoś nie być
return SwitchExtension->iPoints * ((TextureID1 ? 1 : 0) + (TextureID2 ? 6 : 0 ));
return ( ( TextureID1 ? SwitchExtension->iPoints + SwitchExtension->iRoads + 2 : 0 ) + ( TextureID2 ? SwitchExtension->iPoints * 6 : 0 ) );
}
*/
// each sub-segment covers only one side of the road, so it has points for single sideroad, if any
return ( ( TextureID1 ? SwitchExtension->iPoints + SwitchExtension->iRoads + 2 : 0 ) + ( TextureID2 ? SwitchExtension->iPoints * 6 : 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()) *
return ( Segment->RaSegCount()) *
((TextureID1 ? 4 : 0) + (TextureID2 ? 12 : 0)); // może nie być poziomego!
else
return (Segment->RaSegCount()) *
@@ -1815,7 +1830,7 @@ int TTrack::RaArrayPrepare()
return 0;
};
void TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start)
void TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start, int const Vertexcount)
{ // wypełnianie tablic VBO
// Ra: trzeba rozdzielić szyny od podsypki, aby móc grupować wg tekstur
double fHTW = 0.5 * fabs(fTrackWidth);
@@ -1850,6 +1865,9 @@ void TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start)
hypot2 = hypot1;
normal2 = normal1;
}
auto const origin = pMyNode->m_rootposition;
double roll1, roll2;
switch (iCategoryFlag & 15)
{
@@ -1951,16 +1969,16 @@ void TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start)
bpts1[3] = vector6(-rozp, -fTexHeight1 - 0.18, 0.5 + map12, -normal1.x, -normal1.y, 0.0); // prawy skos
}
}
Segment->RenderLoft(Vert, bpts1, iTrapezoid ? -4 : 4, fTexLength);
Segment->RenderLoft(Vert, origin, bpts1, iTrapezoid ? -4 : 4, fTexLength);
}
if (TextureID1)
{ // szyny - generujemy dwie, najwyżej rysować się będzie jedną
Segment->RenderLoft(Vert, rpts1, iTrapezoid ? -nnumPts : nnumPts, fTexLength);
Segment->RenderLoft(Vert, rpts2, iTrapezoid ? -nnumPts : nnumPts, fTexLength);
Segment->RenderLoft(Vert, origin, rpts1, iTrapezoid ? -nnumPts : nnumPts, fTexLength);
Segment->RenderLoft(Vert, origin, rpts2, iTrapezoid ? -nnumPts : nnumPts, fTexLength);
}
break;
case tt_Switch: // dla zwrotnicy dwa razy szyny
if (TextureID1) // Ra: !!!! tu jest do poprawienia
if( TextureID1 || TextureID2 )
{ // iglice liczone tylko dla zwrotnic
vector6 rpts3[24], rpts4[24];
for (i = 0; i < 12; ++i)
@@ -1980,27 +1998,34 @@ void TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start)
}
if (SwitchExtension->RightSwitch)
{ // nowa wersja z SPKS, ale odwrotnie lewa/prawa
SwitchExtension->Segments[0]->RenderLoft( Vert, rpts2, nnumPts, fTexLength);
SwitchExtension->Segments[0]->RenderLoft( Vert, rpts1, nnumPts, fTexLength, 1.0, 2 );
SwitchExtension->iLeftVBO = Vert - Start; // indeks lewej iglicy
SwitchExtension->Segments[0]->RenderLoft( Vert, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, SwitchExtension->fOffset2 );
if( TextureID1 ) {
SwitchExtension->Segments[ 0 ]->RenderLoft( Vert, origin, rpts2, nnumPts, fTexLength );
SwitchExtension->Segments[ 0 ]->RenderLoft( Vert, origin, rpts1, nnumPts, fTexLength, 1.0, 2 );
SwitchExtension->iRightVBO = Vert - Start; // indeks prawej iglicy
SwitchExtension->Segments[1]->RenderLoft( Vert, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -fMaxOffset + SwitchExtension->fOffset1 );
SwitchExtension->Segments[1]->RenderLoft( Vert, rpts2, nnumPts, fTexLength, 1.0, 2 );
SwitchExtension->Segments[1]->RenderLoft( Vert, rpts1, nnumPts, fTexLength );
SwitchExtension->iLeftVBO = Vert - Start; // indeks lewej iglicy
SwitchExtension->Segments[ 0 ]->RenderLoft( Vert, origin, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, SwitchExtension->fOffset2 );
}
if( TextureID2 ) {
SwitchExtension->iRightVBO = Vert - Start; // indeks prawej iglicy
SwitchExtension->Segments[ 1 ]->RenderLoft( Vert, origin, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -fMaxOffset + SwitchExtension->fOffset1 );
SwitchExtension->Segments[ 1 ]->RenderLoft( Vert, origin, rpts2, nnumPts, fTexLength, 1.0, 2 );
SwitchExtension->Segments[ 1 ]->RenderLoft( Vert, origin, rpts1, nnumPts, fTexLength );
}
}
else
{ // lewa działa lepiej niż prawa
SwitchExtension->Segments[0]->RenderLoft( Vert, rpts1, nnumPts, fTexLength); // lewa szyna normalna cała
SwitchExtension->Segments[0]->RenderLoft( Vert, rpts2, nnumPts, fTexLength, 1.0, 2 ); // prawa szyna za iglicą
SwitchExtension->iLeftVBO = Vert - Start; // indeks lewej iglicy
SwitchExtension->Segments[0]->RenderLoft( Vert, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -SwitchExtension->fOffset2); // prawa iglica
SwitchExtension->iRightVBO = Vert - Start; // indeks prawej iglicy
SwitchExtension->Segments[1]->RenderLoft( Vert, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, fMaxOffset - SwitchExtension->fOffset1); // lewa iglica
SwitchExtension->Segments[1]->RenderLoft( Vert, rpts1, nnumPts, fTexLength, 1.0, 2); // lewa szyna za iglicą
SwitchExtension->Segments[1]->RenderLoft( Vert, rpts2, nnumPts, fTexLength); // prawa szyna normalnie cała
if( TextureID1 ) {
SwitchExtension->Segments[ 0 ]->RenderLoft( Vert, origin, rpts1, nnumPts, fTexLength ); // lewa szyna normalna cała
SwitchExtension->Segments[ 0 ]->RenderLoft( Vert, origin, rpts2, nnumPts, fTexLength, 1.0, 2 ); // prawa szyna za iglicą
SwitchExtension->iLeftVBO = Vert - Start; // indeks lewej iglicy
SwitchExtension->Segments[ 0 ]->RenderLoft( Vert, origin, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -SwitchExtension->fOffset2 ); // prawa iglica
}
if( TextureID2 ) {
SwitchExtension->iRightVBO = Vert - Start; // indeks prawej iglicy
SwitchExtension->Segments[ 1 ]->RenderLoft( Vert, origin, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, fMaxOffset - SwitchExtension->fOffset1 ); // lewa iglica
SwitchExtension->Segments[ 1 ]->RenderLoft( Vert, origin, rpts1, nnumPts, fTexLength, 1.0, 2 ); // lewa szyna za iglicą
SwitchExtension->Segments[ 1 ]->RenderLoft( Vert, origin, rpts2, nnumPts, fTexLength ); // prawa szyna normalnie cała
}
}
}
break;
@@ -2034,7 +2059,7 @@ void TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start)
}
if (TextureID1) // jeśli podana była tekstura, generujemy trójkąty
{ // tworzenie trójkątów nawierzchni szosy
Segment->RenderLoft(Vert, bpts1, iTrapezoid ? -2 : 2, fTexLength);
Segment->RenderLoft(Vert, origin, 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?)
@@ -2114,18 +2139,22 @@ void TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start)
if( iTrapezoid ) // trapez albo przechyłki
{ // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony
// odcinka
if( ( fTexHeight1 >= 0.0 ) || ( slop != 0.0 ) )
Segment->RenderLoft( Vert, rpts1, -3, fTexLength ); // tylko jeśli jest z prawej
if( ( fTexHeight1 >= 0.0 ) || ( side != 0.0 ) )
Segment->RenderLoft( Vert, rpts2, -3, fTexLength ); // tylko jeśli jest z lewej
}
else { // pobocza zwykłe, brak przechyłki
if( ( fTexHeight1 >= 0.0 ) || ( slop != 0.0 ) )
Segment->RenderLoft( Vert, rpts1, 3, fTexLength );
if( ( fTexHeight1 >= 0.0 ) || ( side != 0.0 ) )
Segment->RenderLoft( Vert, rpts2, 3, fTexLength );
if( ( fTexHeight1 >= 0.0 ) || ( slop != 0.0 ) ) {
Segment->RenderLoft( Vert, origin, rpts1, -3, fTexLength ); // tylko jeśli jest z prawej
}
if( ( fTexHeight1 >= 0.0 ) || ( side != 0.0 ) ) {
Segment->RenderLoft( Vert, origin, rpts2, -3, fTexLength ); // tylko jeśli jest z lewej
}
}
else { // pobocza zwykłe, brak przechyłki
if( ( fTexHeight1 >= 0.0 ) || ( slop != 0.0 ) ) {
Segment->RenderLoft( Vert, origin, rpts1, 3, fTexLength );
}
if( ( fTexHeight1 >= 0.0 ) || ( side != 0.0 ) ) {
Segment->RenderLoft( Vert, origin, rpts2, 3, fTexLength );
}
}
}
break;
}
case tt_Cross: // skrzyżowanie dróg rysujemy inaczej
@@ -2156,24 +2185,9 @@ void TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start)
int i; // 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();
}
// tablica utworzona z zapasem, ale nie wypełniona współrzędnymi
SwitchExtension->vPoints = new vector3[SwitchExtension->iPoints];
// points were already counted during preparation stage
// we'll need to add couple extra points for the complete fan we'll build
SwitchExtension->vPoints = new vector3[SwitchExtension->iPoints + SwitchExtension->iRoads];
}
vector3 *b =
SwitchExtension->bPoints ?
@@ -2262,56 +2276,63 @@ void TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start)
if (SwitchExtension->iRoads == 4)
{ // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony odcinka
if( ( fTexHeight1 >= 0.0 ) || ( side != 0.0 ) ) {
SwitchExtension->Segments[ 2 ]->RenderLoft( Vert, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, false, &b, render );
SwitchExtension->Segments[ 3 ]->RenderLoft( Vert, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, false, &b, render );
SwitchExtension->Segments[ 4 ]->RenderLoft( Vert, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, false, &b, render );
SwitchExtension->Segments[ 5 ]->RenderLoft( Vert, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, false, &b, render );
SwitchExtension->Segments[ 2 ]->RenderLoft( Vert, origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render );
SwitchExtension->Segments[ 3 ]->RenderLoft( Vert, origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render );
SwitchExtension->Segments[ 4 ]->RenderLoft( Vert, origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render );
SwitchExtension->Segments[ 5 ]->RenderLoft( Vert, origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render );
}
}
else {
// punkt 3 pokrywa się z punktem 1, jak w zwrotnicy; połączenie 1->2 nie musi być prostoliniowe
if( ( fTexHeight1 >= 0.0 ) || ( side != 0.0 ) ) {
SwitchExtension->Segments[ 2 ]->RenderLoft( Vert, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, false, &b, render ); // z P2 do P4
SwitchExtension->Segments[ 1 ]->RenderLoft( Vert, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, false, &b, render ); // z P4 do P3=P1 (odwrócony)
SwitchExtension->Segments[ 0 ]->RenderLoft( Vert, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, false, &b, render ); // z P1 do P2
SwitchExtension->Segments[ 2 ]->RenderLoft( Vert, origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render ); // z P2 do P4
SwitchExtension->Segments[ 1 ]->RenderLoft( Vert, origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render ); // z P4 do P3=P1 (odwrócony)
SwitchExtension->Segments[ 0 ]->RenderLoft( Vert, origin, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, &b, render ); // z P1 do P2
}
}
}
// 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
// ustalenie liczby punktów, bo mogło wyjść inaczej niż policzone z góry
i = (int)(((size_t)(b)) - ((size_t)(SwitchExtension->vPoints))) / sizeof(vector3);
if (i > 0)
{ // jeśli zostało to właśnie utworzone
SwitchExtension->iPoints = std::min( SwitchExtension->iPoints - 2, i );
SwitchExtension->vPoints[SwitchExtension->iPoints++] = SwitchExtension->vPoints[0];
++SwitchExtension->iPoints; // we'll add one extra point in the middle
SwitchExtension->bPoints = true; // tablica punktów została wypełniona
}
}
if( ( false == SwitchExtension->bPoints ) // jeśli tablica nie wypełniona
&& ( b != nullptr ) ) {
SwitchExtension->bPoints = true; // tablica punktów została wypełniona
}
if (TextureID1) {
// jeśli podana tekstura nawierzchni
// jeśli podana tekstura nawierzchni
// we start with a vertex in the middle...
Vert->nx = 0.0;
Vert->ny = 1.0;
Vert->nz = 0.0;
Vert->u = 0.5;
Vert->v = 0.5;
Vert->x = oxz.x;
Vert->y = oxz.y;
Vert->z = oxz.z;
Vert->x = oxz.x - origin.x;
Vert->y = oxz.y - origin.y;
Vert->z = oxz.z - origin.z;
++Vert;
for (i = SwitchExtension->iPoints - 2; i >= 0; --i)
// ...and add one extra vertex to close the fan...
Vert->nx = 0.0;
Vert->ny = 1.0;
Vert->nz = 0.0;
// mapowanie we współrzędnych scenerii
u = ( SwitchExtension->vPoints[ 0 ].x - oxz.x + origin.x ) / fTexLength;
v = ( SwitchExtension->vPoints[ 0 ].z - oxz.z + origin.z ) / ( fTexRatio1 * fTexLength );
Vert->u = cosa0 * u + sina0 * v + 0.5;
Vert->v = -sina0 * u + cosa0 * v + 0.5;
Vert->x = SwitchExtension->vPoints[ 0 ].x;
Vert->y = SwitchExtension->vPoints[ 0 ].y;
Vert->z = SwitchExtension->vPoints[ 0 ].z;
++Vert;
// ...then draw the precalculated rest
for (i = SwitchExtension->iPoints + SwitchExtension->iRoads - 1; i >= 0; --i)
{
Vert->nx = 0.0;
Vert->ny = 1.0;
Vert->nz = 0.0;
// mapowanie we współrzędnych scenerii
u = (SwitchExtension->vPoints[i].x - oxz.x) / fTexLength;
v = (SwitchExtension->vPoints[i].z - oxz.z) / (fTexRatio1 * fTexLength);
u = (SwitchExtension->vPoints[i].x - oxz.x + origin.x ) / fTexLength;
v = (SwitchExtension->vPoints[i].z - oxz.z + origin.z ) / (fTexRatio1 * fTexLength);
Vert->u = cosa0 * u + sina0 * v + 0.5;
Vert->v = -sina0 * u + cosa0 * v + 0.5;
Vert->x = SwitchExtension->vPoints[ i ].x;
@@ -2321,8 +2342,8 @@ void TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start)
}
}
break;
}
}
} // tt_cross
} // road
break;
case 4: // Ra: rzeki na razie jak drogi, przechyłki na pewno nie mają
switch (eType) // dalej zależnie od typu
@@ -2357,7 +2378,7 @@ void TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start)
}
if (TextureID1) // jeśli podana była tekstura, generujemy trójkąty
{ // tworzenie trójkątów nawierzchni szosy
Segment->RenderLoft(Vert, bpts1, iTrapezoid ? -2 : 2, fTexLength);
Segment->RenderLoft(Vert, origin, bpts1, iTrapezoid ? -2 : 2, fTexLength);
}
if (TextureID2)
{ // pobocze drogi - poziome przy przechyłce (a może krawężnik i chodnik zrobić jak w
@@ -2379,19 +2400,20 @@ void TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start)
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->RenderLoft(Vert, rpts1, -3, fTexLength);
Segment->RenderLoft(Vert, rpts2, -3, fTexLength);
Segment->RenderLoft(Vert, origin, rpts1, -3, fTexLength);
Segment->RenderLoft(Vert, origin, rpts2, -3, fTexLength);
}
else
{ // pobocza zwykłe, brak przechyłki
Segment->RenderLoft(Vert, rpts1, 3, fTexLength);
Segment->RenderLoft(Vert, rpts2, 3, fTexLength);
Segment->RenderLoft(Vert, origin, rpts1, 3, fTexLength);
Segment->RenderLoft(Vert, origin, rpts2, 3, fTexLength);
}
}
}
}
break;
}
return;
};
void TTrack::RaRenderVBO( int iPtr ) { // renderowanie z użyciem VBO
@@ -2405,12 +2427,12 @@ void TTrack::RaRenderVBO( int iPtr ) { // renderowanie z użyciem VBO
if( eType == tt_Switch ) // dla zwrotnicy tylko szyny
{
int const bladesegmentcount = 2;
if( TextureID1 )
if( TextureID1 ) {
if( ( seg = SwitchExtension->Segments[ 0 ]->RaSegCount() ) > 0 ) {
GfxRenderer.Bind( TextureID1 ); // szyny +
::glDrawArrays( GL_TRIANGLE_STRIP, iPtr, 24 * seg );
iPtr += 24 * seg;
::glDrawArrays( GL_TRIANGLE_STRIP, iPtr, 24 * (seg - bladesegmentcount) );
::glDrawArrays( GL_TRIANGLE_STRIP, iPtr, 24 * ( seg - bladesegmentcount ) );
// NOTE: due to way blades bend need to render each segment separately, or some unwanted edges may show
iPtr += 24 * ( seg - bladesegmentcount );
for( int i = 0; i < bladesegmentcount; ++i ) {
@@ -2418,7 +2440,8 @@ void TTrack::RaRenderVBO( int iPtr ) { // renderowanie z użyciem VBO
iPtr += 24;
}
}
if( TextureID2 )
}
if( TextureID2 ) {
if( ( seg = SwitchExtension->Segments[ 1 ]->RaSegCount() ) > 0 ) {
GfxRenderer.Bind( TextureID2 );
// NOTE: due to way blades bend need to render each segment separately, or some unwanted edges may show
@@ -2431,6 +2454,7 @@ void TTrack::RaRenderVBO( int iPtr ) { // renderowanie z użyciem VBO
::glDrawArrays( GL_TRIANGLE_STRIP, iPtr, 24 * seg );
iPtr += 24 * seg;
}
}
}
else // dla toru podsypka plus szyny
{
@@ -2513,7 +2537,7 @@ void TTrack::RaRenderVBO( int iPtr ) { // renderowanie z użyciem VBO
if( TextureID1 ) {
// roads
GfxRenderer.Bind( TextureID1 );
::glDrawArrays( GL_TRIANGLE_FAN, iPtr, SwitchExtension->iPoints );
::glDrawArrays( GL_TRIANGLE_FAN, iPtr, SwitchExtension->iPoints + SwitchExtension->iRoads + 2 );
iPtr += SwitchExtension->iPoints;
}
}
@@ -2581,11 +2605,7 @@ void TTrack::RenderDyn()
{ // renderowanie nieprzezroczystych fragmentów pojazdów
for( auto dynamic : Dynamics ) {
// sam sprawdza, czy VBO; zmienia kontekst VBO!
#ifdef EU07_USE_OLD_RENDERCODE
dynamic->Render();
#else
GfxRenderer.Render( dynamic );
#endif
}
};
@@ -2593,11 +2613,7 @@ void TTrack::RenderDynAlpha()
{ // renderowanie przezroczystych fragmentów pojazdów
for( auto dynamic : Dynamics ) {
// sam sprawdza, czy VBO; zmienia kontekst VBO!
#ifdef EU07_USE_OLD_RENDERCODE
dynamic->RenderAlpha();
#else
GfxRenderer.Render_Alpha( dynamic );
#endif
}
};
@@ -2870,19 +2886,22 @@ TTrack * TTrack::RaAnimate(GLuint const Vertexbuffer)
// fetch current blade geometry
std::vector<CVertNormTex> bladesbuffer; bladesbuffer.resize( 2 * 2 * 24 ); // 2 blades, 2 segments each
/*
::glGetBufferSubData(
GL_ARRAY_BUFFER,
SwitchExtension->iLeftVBO * sizeof( CVertNormTex ),
bladesbuffer.size() * sizeof( CVertNormTex ),
bladesbuffer.data() );
*/
auto bladevertices = bladesbuffer.data();
auto const origin = pMyNode->m_rootposition;
if( SwitchExtension->RightSwitch ) { // nowa wersja z SPKS, ale odwrotnie lewa/prawa
SwitchExtension->Segments[ 0 ]->RenderLoft( bladevertices, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, SwitchExtension->fOffset2, true );
SwitchExtension->Segments[ 1 ]->RenderLoft( bladevertices, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -fMaxOffset + SwitchExtension->fOffset1, true );
SwitchExtension->Segments[ 0 ]->RenderLoft( bladevertices, origin, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, SwitchExtension->fOffset2 /*, true*/ );
SwitchExtension->Segments[ 1 ]->RenderLoft( bladevertices, origin, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -fMaxOffset + SwitchExtension->fOffset1 /*, true*/ );
}
else {
SwitchExtension->Segments[ 0 ]->RenderLoft( bladevertices, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -SwitchExtension->fOffset2, true ); // prawa iglica
SwitchExtension->Segments[ 1 ]->RenderLoft( bladevertices, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, fMaxOffset - SwitchExtension->fOffset1, true ); // lewa iglica
SwitchExtension->Segments[ 0 ]->RenderLoft( bladevertices, origin, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -SwitchExtension->fOffset2 /*, true*/ ); // prawa iglica
SwitchExtension->Segments[ 1 ]->RenderLoft( bladevertices, origin, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, fMaxOffset - SwitchExtension->fOffset1 /*, true*/ ); // lewa iglica
}
// push back updated geometry
::glBufferSubData(
@@ -2936,8 +2955,8 @@ TTrack * TTrack::RaAnimate(GLuint const Vertexbuffer)
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(
RaArrayFill(Vert, Vert - SwitchExtension->iLeftVBO, size); // iLeftVBO powinno zostać niezmienione
::glBufferSubData(
GL_ARRAY_BUFFER, SwitchExtension->iLeftVBO * sizeof(CVertNormTex),
size * sizeof(CVertNormTex), Vert); // wysłanie fragmentu bufora VBO
}

View File

@@ -240,7 +240,7 @@ class TTrack : public Resource
void Render(); // renderowanie z Display Lists
int RaArrayPrepare(); // zliczanie rozmiaru dla VBO sektroa
void RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start); // wypełnianie VBO
void RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start, int const Vertexcount); // wypełnianie VBO
void RaRenderVBO(int iPtr); // renderowanie z VBO sektora
void RenderDyn(); // renderowanie nieprzezroczystych pojazdów (oba tryby)
void RenderDynAlpha(); // renderowanie przezroczystych pojazdów (oba tryby)

View File

@@ -109,7 +109,7 @@ TTraction::~TTraction()
glDeleteLists(uiDisplayList, 1);
}
void TTraction::Optimize()
void TTraction::Optimize( Math3D::vector3 const &Origin )
{
if (Global::bUseVBO)
return;
@@ -125,13 +125,13 @@ void TTraction::Optimize()
// Przewoz jezdny 1 'Marcin
glBegin(GL_LINE_STRIP);
glVertex3f(
pPoint1.x - (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset,
pPoint1.y,
pPoint1.z - (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset);
pPoint1.x - (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset - Origin.x,
pPoint1.y - Origin.y,
pPoint1.z - (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset - Origin.z);
glVertex3f(
pPoint2.x - (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset,
pPoint2.y,
pPoint2.z - (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset);
pPoint2.x - (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset - Origin.x,
pPoint2.y - Origin.y,
pPoint2.z - (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset - Origin.z );
glEnd();
// Nie wiem co 'Marcin
Math3D::vector3 pt1, pt2, pt3, pt4, v1, v2;
@@ -147,29 +147,39 @@ void TTraction::Optimize()
if (Wires > 1)
{
glBegin(GL_LINE_STRIP);
glVertex3f(pPoint3.x, pPoint3.y, pPoint3.z);
glVertex3f(
pPoint3.x - Origin.x,
pPoint3.y - Origin.y,
pPoint3.z - Origin.z );
for (int i = 0; i < iNumSections - 1; ++i)
{
pt3 = pPoint3 + v1 * f;
t = (1 - std::fabs(f - mid) * 2);
if ((Wires < 4) || ((i != 0) && (i != iNumSections - 2)))
glVertex3f(
pt3.x,
pt3.y - std::sqrt(t) * fHeightDifference,
pt3.z);
pt3.x - Origin.x,
pt3.y - std::sqrt(t) * fHeightDifference - Origin.y,
pt3.z - Origin.z );
f += step;
}
glVertex3f(pPoint4.x, pPoint4.y, pPoint4.z);
glVertex3f(
pPoint4.x - Origin.x,
pPoint4.y - Origin.y,
pPoint4.z - Origin.z );
glEnd();
}
// Drugi przewod jezdny 'Winger
if (Wires > 2)
{
glBegin(GL_LINE_STRIP);
glVertex3f(pPoint1.x + (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset, pPoint1.y,
pPoint1.z + (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset);
glVertex3f(pPoint2.x + (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset, pPoint2.y,
pPoint2.z + (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset);
glVertex3f(
pPoint1.x + (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset - Origin.x,
pPoint1.y - Origin.y,
pPoint1.z + (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset - Origin.z );
glVertex3f(
pPoint2.x + (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset - Origin.x,
pPoint2.y - Origin.y,
pPoint2.z + (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset - Origin.z );
glEnd();
}
@@ -178,22 +188,29 @@ void TTraction::Optimize()
if (Wires == 4)
{
glBegin(GL_LINE_STRIP);
glVertex3f(pPoint3.x, pPoint3.y - 0.65f * fHeightDifference, pPoint3.z);
glVertex3f(
pPoint3.x - Origin.x,
pPoint3.y - 0.65f * fHeightDifference - Origin.y,
pPoint3.z - Origin.z );
for (int i = 0; i < iNumSections - 1; ++i)
{
pt3 = pPoint3 + v1 * f;
t = (1 - std::fabs(f - mid) * 2);
glVertex3f(
pt3.x,
pt3.x - Origin.x,
pt3.y - std::sqrt( t ) * fHeightDifference - (
( ( i == 0 )
|| ( i == iNumSections - 2 ) ) ?
0.25f * fHeightDifference :
0.05 ),
pt3.z);
0.05 )
- Origin.y,
pt3.z - Origin.z );
f += step;
}
glVertex3f(pPoint4.x, pPoint4.y - 0.65f * fHeightDifference, pPoint4.z);
glVertex3f(
pPoint4.x - Origin.x,
pPoint4.y - 0.65f * fHeightDifference - Origin.y,
pPoint4.z - Origin.z );
glEnd();
}
@@ -214,35 +231,35 @@ void TTraction::Optimize()
if ((i % 2) == 0)
{
glVertex3f(
pt3.x,
pt3.y - std::sqrt(t) * fHeightDifference - ((i == 0) || (i == iNumSections - 2) ? flo : flo1),
pt3.z);
pt3.x - Origin.x,
pt3.y - std::sqrt(t) * fHeightDifference - ((i == 0) || (i == iNumSections - 2) ? flo : flo1) - Origin.y,
pt3.z - Origin.z );
glVertex3f(
pt4.x - (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset,
pt4.y,
pt4.z - (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset);
pt4.x - (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset - Origin.x,
pt4.y - Origin.y,
pt4.z - (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset - Origin.z );
}
else
{
glVertex3f(
pt3.x,
pt3.y - std::sqrt(t) * fHeightDifference - ((i == 0) || (i == iNumSections - 2) ? flo : flo1),
pt3.z);
pt3.x - Origin.x,
pt3.y - std::sqrt(t) * fHeightDifference - ((i == 0) || (i == iNumSections - 2) ? flo : flo1) - Origin.y,
pt3.z - Origin.z );
glVertex3f(
pt4.x + (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset,
pt4.y,
pt4.z + (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset);
pt4.x + (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset - Origin.x,
pt4.y - Origin.y,
pt4.z + (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset - Origin.z );
}
if ((Wires == 4) && ((i == 1) || (i == iNumSections - 3)))
{
glVertex3f(
pt3.x,
pt3.y - std::sqrt(t) * fHeightDifference - 0.05,
pt3.z);
pt3.x - Origin.x,
pt3.y - std::sqrt(t) * fHeightDifference - 0.05 - Origin.y,
pt3.z - Origin.z );
glVertex3f(
pt3.x,
pt3.y - std::sqrt(t) * fHeightDifference,
pt3.z);
pt3.x - Origin.x,
pt3.y - std::sqrt(t) * fHeightDifference - Origin.y,
pt3.z - Origin.z );
}
f += step;
}
@@ -258,7 +275,7 @@ void TTraction::InitCenter(vector3 Angles, vector3 pOrigin)
fSquaredRadius= SquareMagnitude((pPoint2-pPoint1)*0.5f);
} */
void TTraction::RenderDL(float mgn) // McZapkie: mgn to odleglosc od obserwatora
void TTraction::RenderDL(float mgn, Math3D::vector3 const &Origin ) // McZapkie: mgn to odleglosc od obserwatora
{
// McZapkie: ustalanie przezroczystosci i koloru linii:
if( Wires != 0 && !TestFlag( DamageFlag, 128 ) ) // rysuj jesli sa druty i nie zerwana
@@ -281,7 +298,7 @@ void TTraction::RenderDL(float mgn) // McZapkie: mgn to odleglosc od obserwatora
::glColor4f( red, green, blue, linealpha );
// draw code
if (!uiDisplayList)
Optimize(); // generowanie DL w miarę potrzeby
Optimize( Origin ); // generowanie DL w miarę potrzeby
::glCallList(uiDisplayList);
// cleanup
::glLineWidth(1.0);
@@ -324,20 +341,24 @@ int TTraction::RaArrayPrepare()
return iLines;
};
void TTraction::RaArrayFill(CVertNormTex *Vert)
int TTraction::RaArrayFill(CVertNormTex *Vert, Math3D::vector3 const &Origin)
{ // wypełnianie tablic VBO
int debugvertexcount{ 0 };
double ddp = std::hypot(pPoint2.x - pPoint1.x, pPoint2.z - pPoint1.z);
if (Wires == 2)
WireOffset = 0;
// jezdny
Vert->x = pPoint1.x - ( pPoint2.z / ddp - pPoint1.z / ddp ) * WireOffset;
Vert->y = pPoint1.y;
Vert->z = pPoint1.z - ( -pPoint2.x / ddp + pPoint1.x / ddp ) * WireOffset;
Vert->x = pPoint1.x - ( pPoint2.z / ddp - pPoint1.z / ddp ) * WireOffset - Origin.x;
Vert->y = pPoint1.y - Origin.y;
Vert->z = pPoint1.z - ( -pPoint2.x / ddp + pPoint1.x / ddp ) * WireOffset - Origin.z;
++Vert;
Vert->x = pPoint2.x - ( pPoint2.z / ddp - pPoint1.z / ddp ) * WireOffset;
Vert->y = pPoint2.y;
Vert->z = pPoint2.z - ( -pPoint2.x / ddp + pPoint1.x / ddp ) * WireOffset;
++debugvertexcount;
Vert->x = pPoint2.x - ( pPoint2.z / ddp - pPoint1.z / ddp ) * WireOffset - Origin.x;
Vert->y = pPoint2.y - Origin.y;
Vert->z = pPoint2.z - ( -pPoint2.x / ddp + pPoint1.x / ddp ) * WireOffset - Origin.z;
++Vert;
++debugvertexcount;
// Nie wiem co 'Marcin
Math3D::vector3 pt1, pt2, pt3, pt4, v1, v2;
v1 = pPoint4 - pPoint3;
@@ -351,10 +372,11 @@ void TTraction::RaArrayFill(CVertNormTex *Vert)
// Przewod nosny 'Marcin
if (Wires > 1)
{ // lina nośna w kawałkach
Vert->x = pPoint3.x;
Vert->y = pPoint3.y;
Vert->z = pPoint3.z;
Vert->x = pPoint3.x - Origin.x;
Vert->y = pPoint3.y - Origin.y;
Vert->z = pPoint3.z - Origin.z;
++Vert;
++debugvertexcount;
for (int i = 0; i < iNumSections - 1; ++i)
{
pt3 = pPoint3 + v1 * f;
@@ -362,54 +384,63 @@ void TTraction::RaArrayFill(CVertNormTex *Vert)
if( ( Wires < 4 )
|| ( ( i != 0 )
&& ( i != iNumSections - 2 ) ) ) {
Vert->x = pt3.x;
Vert->y = pt3.y - std::sqrt( t ) * fHeightDifference;
Vert->z = pt3.z;
Vert->x = pt3.x - Origin.x;
Vert->y = pt3.y - std::sqrt( t ) * fHeightDifference - Origin.y;
Vert->z = pt3.z - Origin.z;
++Vert;
++debugvertexcount;
}
f += step;
}
Vert->x = pPoint4.x;
Vert->y = pPoint4.y;
Vert->z = pPoint4.z;
Vert->x = pPoint4.x - Origin.x;
Vert->y = pPoint4.y - Origin.y;
Vert->z = pPoint4.z - Origin.z;
++Vert;
++debugvertexcount;
}
// Drugi przewod jezdny 'Winger
if (Wires > 2)
{
Vert->x = pPoint1.x + (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset;
Vert->y = pPoint1.y;
Vert->z = pPoint1.z + (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset;
Vert->x = pPoint1.x + (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset - Origin.x;
Vert->y = pPoint1.y - Origin.y;
Vert->z = pPoint1.z + (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset - Origin.z;
++Vert;
Vert->x = pPoint2.x + (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset;
Vert->y = pPoint2.y;
Vert->z = pPoint2.z + (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset;
++debugvertexcount;
Vert->x = pPoint2.x + (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset - Origin.x;
Vert->y = pPoint2.y - Origin.y;
Vert->z = pPoint2.z + (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset - Origin.z;
++Vert;
++debugvertexcount;
}
f = step;
if( Wires == 4 ) {
Vert->x = pPoint3.x;
Vert->y = pPoint3.y - 0.65f * fHeightDifference;
Vert->z = pPoint3.z;
Vert->x = pPoint3.x - Origin.x;
Vert->y = pPoint3.y - 0.65f * fHeightDifference - Origin.y;
Vert->z = pPoint3.z - Origin.z;
++Vert;
++debugvertexcount;
for( int i = 0; i < iNumSections - 1; ++i ) {
pt3 = pPoint3 + v1 * f;
t = ( 1 - std::fabs( f - mid ) * 2 );
Vert->x = pt3.x;
Vert->x = pt3.x - Origin.x;
Vert->y = pt3.y - std::sqrt( t ) * fHeightDifference - (
( ( i == 0 )
|| ( i == iNumSections - 2 ) ) ?
0.25f * fHeightDifference :
0.05 );
Vert->z = pt3.z;
0.05 )
- Origin.y;
Vert->z = pt3.z - Origin.z;
++Vert;
++debugvertexcount;
f += step;
}
Vert->x = pPoint4.x;
Vert->y = pPoint4.y - 0.65f * fHeightDifference;
Vert->z = pPoint4.z;
Vert->x = pPoint4.x - Origin.x;
Vert->y = pPoint4.y - 0.65f * fHeightDifference - Origin.y;
Vert->z = pPoint4.z - Origin.z;
++Vert;
++debugvertexcount;
}
f = step;
@@ -426,40 +457,47 @@ void TTraction::RaArrayFill(CVertNormTex *Vert)
t = (1 - std::fabs(f - mid) * 2);
if( ( i % 2 ) == 0 ) {
Vert->x = pt3.x;
Vert->y = pt3.y - std::sqrt( t ) * fHeightDifference - ( ( i == 0 ) || ( i == iNumSections - 2 ) ? flo : flo1 );
Vert->z = pt3.z;
Vert->x = pt3.x - Origin.x;
Vert->y = pt3.y - std::sqrt( t ) * fHeightDifference - ( ( i == 0 ) || ( i == iNumSections - 2 ) ? flo : flo1 ) - Origin.y;
Vert->z = pt3.z - Origin.z;
++Vert;
Vert->x = pt4.x - ( pPoint2.z / ddp - pPoint1.z / ddp ) * WireOffset;
Vert->y = pt4.y;
Vert->z = pt4.z - ( -pPoint2.x / ddp + pPoint1.x / ddp ) * WireOffset;
++debugvertexcount;
Vert->x = pt4.x - ( pPoint2.z / ddp - pPoint1.z / ddp ) * WireOffset - Origin.x;
Vert->y = pt4.y - Origin.y;
Vert->z = pt4.z - ( -pPoint2.x / ddp + pPoint1.x / ddp ) * WireOffset - Origin.z;
++Vert;
++debugvertexcount;
}
else {
Vert->x = pt3.x;
Vert->y = pt3.y - std::sqrt( t ) * fHeightDifference - ( ( i == 0 ) || ( i == iNumSections - 2 ) ? flo : flo1 );
Vert->z = pt3.z;
Vert->x = pt3.x - Origin.x;
Vert->y = pt3.y - std::sqrt( t ) * fHeightDifference - ( ( i == 0 ) || ( i == iNumSections - 2 ) ? flo : flo1 ) - Origin.y;
Vert->z = pt3.z - Origin.z;
++Vert;
Vert->x = pt4.x + ( pPoint2.z / ddp - pPoint1.z / ddp ) * WireOffset;
Vert->y = pt4.y;
Vert->z = pt4.z + ( -pPoint2.x / ddp + pPoint1.x / ddp ) * WireOffset;
++debugvertexcount;
Vert->x = pt4.x + ( pPoint2.z / ddp - pPoint1.z / ddp ) * WireOffset - Origin.x;
Vert->y = pt4.y - Origin.y;
Vert->z = pt4.z + ( -pPoint2.x / ddp + pPoint1.x / ddp ) * WireOffset - Origin.z;
++Vert;
++debugvertexcount;
}
if( ( ( Wires == 4 )
&& ( ( i == 1 )
|| ( i == iNumSections - 3 ) ) ) ) {
Vert->x = pt3.x;
Vert->y = pt3.y - std::sqrt( t ) * fHeightDifference - 0.05;
Vert->z = pt3.z;
Vert->x = pt3.x - Origin.x;
Vert->y = pt3.y - std::sqrt( t ) * fHeightDifference - 0.05 - Origin.y;
Vert->z = pt3.z - Origin.z;
++Vert;
Vert->x = pt3.x;
Vert->y = pt3.y - std::sqrt( t ) * fHeightDifference;
Vert->z = pt3.z;
++debugvertexcount;
Vert->x = pt3.x - Origin.x;
Vert->y = pt3.y - std::sqrt( t ) * fHeightDifference - Origin.y;
Vert->z = pt3.z - Origin.z;
++Vert;
++debugvertexcount;
}
f += step;
}
}
return debugvertexcount;
};
void TTraction::RenderVBO(float mgn, int iPtr)

View File

@@ -56,7 +56,7 @@ class TTraction
int iTries = 0;
int PowerState{ 0 }; // type of incoming power, if any
void Optimize();
void Optimize( Math3D::vector3 const &Origin );
TTraction();
~TTraction();
@@ -66,9 +66,9 @@ class TTraction
// { return TNode::Hit(x,z,hitPoint,hitDirection); };
// virtual bool Move(double dx, double dy, double dz) { return false; };
// virtual void SelectedRender();
void RenderDL(float mgn);
void RenderDL(float mgn, Math3D::vector3 const &Origin );
int RaArrayPrepare();
void RaArrayFill(CVertNormTex *Vert);
int RaArrayFill( CVertNormTex *Vert, Math3D::vector3 const &Origin );
void RenderVBO(float mgn, int iPtr);
int TestPoint(Math3D::vector3 *Point);
void Connect(int my, TTraction *with, int to);

307
Train.cpp
View File

@@ -175,8 +175,10 @@ TTrain::commandhandler_map const TTrain::m_commandhandlers = {
{ user_command::pantographlowerall, &TTrain::OnCommand_pantographlowerall },
{ user_command::linebreakertoggle, &TTrain::OnCommand_linebreakertoggle },
{ user_command::convertertoggle, &TTrain::OnCommand_convertertoggle },
{ user_command::convertertogglelocal, &TTrain::OnCommand_convertertogglelocal },
{ user_command::converteroverloadrelayreset, &TTrain::OnCommand_converteroverloadrelayreset },
{ user_command::compressortoggle, &TTrain::OnCommand_compressortoggle },
{ user_command::compressortogglelocal, &TTrain::OnCommand_compressortogglelocal },
{ user_command::motorconnectorsopen, &TTrain::OnCommand_motorconnectorsopen },
{ user_command::motordisconnect, &TTrain::OnCommand_motordisconnect },
{ user_command::motoroverloadrelaythresholdtoggle, &TTrain::OnCommand_motoroverloadrelaythresholdtoggle },
@@ -1727,6 +1729,69 @@ void TTrain::OnCommand_convertertoggle( TTrain *Train, command_data const &Comma
}
}
void TTrain::OnCommand_convertertogglelocal( TTrain *Train, command_data const &Command ) {
if( Train->mvOccupied->ConverterStart == start::automatic ) {
// let the automatic thing do its automatic thing...
return;
}
if( Train->ggConverterLocalButton.SubModel == nullptr ) {
return;
}
if( Command.action == GLFW_PRESS ) {
// only reacting to press, so the switch doesn't flip back and forth if key is held down
if( ( false == Train->mvOccupied->ConverterAllowLocal )
&& ( Train->ggConverterLocalButton.GetValue() < 0.5 ) ) {
// turn on
// sound feedback
if( Train->ggConverterLocalButton.GetValue() < 0.5 ) {
Train->play_sound( Train->dsbSwitch );
}
// visual feedback
Train->ggConverterLocalButton.UpdateValue( 1.0 );
// effect
Train->mvOccupied->ConverterAllowLocal = true;
/*
if( true == Train->mvControlled->ConverterSwitch( true, range::local ) ) {
// side effects
// control the compressor, if it's paired with the converter
if( Train->mvControlled->CompressorPower == 2 ) {
// hunter-091012: tak jest poprawnie
Train->mvControlled->CompressorSwitch( true, range::local );
}
}
*/
}
else {
//turn off
// sound feedback
if( Train->ggConverterLocalButton.GetValue() > 0.5 ) {
Train->play_sound( Train->dsbSwitch );
}
// visual feedback
Train->ggConverterLocalButton.UpdateValue( 0.0 );
// effect
Train->mvOccupied->ConverterAllowLocal = false;
/*
if( true == Train->mvControlled->ConverterSwitch( false, range::local ) ) {
// side effects
// control the compressor, if it's paired with the converter
if( Train->mvControlled->CompressorPower == 2 ) {
// hunter-091012: tak jest poprawnie
Train->mvControlled->CompressorSwitch( false, range::local );
}
// if there's no (low voltage) power source left, drop pantographs
if( false == Train->mvControlled->Battery ) {
Train->mvControlled->PantFront( false, range::local );
Train->mvControlled->PantRear( false, range::local );
}
}
*/
}
}
}
void TTrain::OnCommand_converteroverloadrelayreset( TTrain *Train, command_data const &Command ) {
if( Train->ggConverterFuseButton.SubModel == nullptr ) {
@@ -1824,6 +1889,42 @@ void TTrain::OnCommand_compressortoggle( TTrain *Train, command_data const &Comm
*/
}
void TTrain::OnCommand_compressortogglelocal( TTrain *Train, command_data const &Command ) {
if( Train->mvOccupied->CompressorPower >= 2 ) {
return;
}
if( Train->ggCompressorLocalButton.SubModel == nullptr ) {
return;
}
if( Command.action == GLFW_PRESS ) {
// only reacting to press, so the switch doesn't flip back and forth if key is held down
if( false == Train->mvOccupied->CompressorAllowLocal ) {
// turn on
// sound feedback
if( Train->ggCompressorLocalButton.GetValue() < 0.5 ) {
Train->play_sound( Train->dsbSwitch );
}
// visual feedback
Train->ggCompressorLocalButton.UpdateValue( 1.0 );
// effect
Train->mvOccupied->CompressorAllowLocal = true;
}
else {
//turn off
// sound feedback
if( Train->ggCompressorLocalButton.GetValue() > 0.5 ) {
Train->play_sound( Train->dsbSwitch );
}
// visual feedback
Train->ggCompressorLocalButton.UpdateValue( 0.0 );
// effect
Train->mvOccupied->CompressorAllowLocal = false;
}
}
}
void TTrain::OnCommand_motorconnectorsopen( TTrain *Train, command_data const &Command ) {
// TODO: don't rely on presense of 3d model to determine presence of the switch
@@ -1833,31 +1934,111 @@ void TTrain::OnCommand_motorconnectorsopen( TTrain *Train, command_data const &C
}
return;
}
if( Command.action != GLFW_RELEASE ) {
// button works while it's held down
if( true == Train->mvControlled->StLinFlag ) {
// NOTE: because we don't have modeled actual circuits this is a simplification of the real mechanics
// namely, pressing the button will flip it in the entire unit, which isn't exactly physically possible
if( Command.action == GLFW_PRESS ) {
// button works while it's held down but we can only pay attention to initial press
if( false == Train->mvControlled->StLinSwitchOff ) {
// open the connectors
Train->mvControlled->StLinSwitchOff = true;
if( ( Train->mvControlled->TrainType == dt_ET41 )
|| ( Train->mvControlled->TrainType == dt_ET42 ) ) {
// crude implementation of the butto affecting entire unit for multi-unit engines
// TODO: rework it into part of standard command propagation system
if( ( Train->mvControlled->Couplers[ 0 ].Connected != nullptr )
&& ( true == TestFlag( Train->mvControlled->Couplers[ 0 ].CouplingFlag, coupling::permanent ) ) ) {
// the first unit isn't allowed to start its compressor until second unit can start its own as well
Train->mvControlled->Couplers[ 0 ].Connected->StLinSwitchOff = true;
}
if( ( Train->mvControlled->Couplers[ 1 ].Connected != nullptr )
&& ( true == TestFlag( Train->mvControlled->Couplers[ 1 ].CouplingFlag, coupling::permanent ) ) ) {
// the first unit isn't allowed to start its compressor until second unit can start its own as well
Train->mvControlled->Couplers[ 1 ].Connected->StLinSwitchOff = true;
}
}
// sound feedback
if( Train->ggStLinOffButton.GetValue() < 0.5 ) {
Train->play_sound( Train->dsbSwitch );
}
// visual feedback
Train->ggStLinOffButton.UpdateValue( 1.0 );
// effect
if( true == Train->mvControlled->StLinFlag ) {
Train->play_sound( Train->dsbRelay );
}
// yBARC - zmienione na przeciwne, bo true to zalaczone
Train->mvControlled->StLinFlag = false;
Train->play_sound( Train->dsbRelay );
if( ( Train->mvControlled->TrainType == dt_ET41 )
|| ( Train->mvControlled->TrainType == dt_ET42 ) ) {
// crude implementation of the butto affecting entire unit for multi-unit engines
// TODO: rework it into part of standard command propagation system
if( ( Train->mvControlled->Couplers[ 0 ].Connected != nullptr )
&& ( true == TestFlag( Train->mvControlled->Couplers[ 0 ].CouplingFlag, coupling::permanent ) ) ) {
// the first unit isn't allowed to start its compressor until second unit can start its own as well
Train->mvControlled->Couplers[ 0 ].Connected->StLinFlag = false;
}
if( ( Train->mvControlled->Couplers[ 1 ].Connected != nullptr )
&& ( true == TestFlag( Train->mvControlled->Couplers[ 1 ].CouplingFlag, coupling::permanent ) ) ) {
// the first unit isn't allowed to start its compressor until second unit can start its own as well
Train->mvControlled->Couplers[ 1 ].Connected->StLinFlag = false;
}
}
}
Train->mvControlled->StLinSwitchOff = true;
// sound feedback
if( Train->ggStLinOffButton.GetValue() < 0.05 ) {
Train->play_sound( Train->dsbSwitch );
else {
if( Train->mvControlled->StLinSwitchType == "toggle" ) {
// default type of button (impulse) has only one effect on press, but the toggle type can toggle the state
Train->mvControlled->StLinSwitchOff = false;
if( ( Train->mvControlled->TrainType == dt_ET41 )
|| ( Train->mvControlled->TrainType == dt_ET42 ) ) {
// crude implementation of the butto affecting entire unit for multi-unit engines
// TODO: rework it into part of standard command propagation system
if( ( Train->mvControlled->Couplers[ 0 ].Connected != nullptr )
&& ( true == TestFlag( Train->mvControlled->Couplers[ 0 ].CouplingFlag, coupling::permanent ) ) ) {
// the first unit isn't allowed to start its compressor until second unit can start its own as well
Train->mvControlled->Couplers[ 0 ].Connected->StLinSwitchOff = false;
}
if( ( Train->mvControlled->Couplers[ 1 ].Connected != nullptr )
&& ( true == TestFlag( Train->mvControlled->Couplers[ 1 ].CouplingFlag, coupling::permanent ) ) ) {
// the first unit isn't allowed to start its compressor until second unit can start its own as well
Train->mvControlled->Couplers[ 1 ].Connected->StLinSwitchOff = false;
}
}
// sound feedback
if( Train->ggStLinOffButton.GetValue() > 0.5 ) {
Train->play_sound( Train->dsbSwitch );
}
// visual feedback
Train->ggStLinOffButton.UpdateValue( 0.0 );
}
}
// visual feedback
Train->ggStLinOffButton.UpdateValue( 1.0 );
}
else {
else if( Command.action == GLFW_RELEASE ) {
// button released
Train->mvControlled->StLinSwitchOff = false;
// sound feedback
if( Train->ggStLinOffButton.GetValue() > 0.5 ) {
Train->play_sound( Train->dsbSwitch );
if( Train->mvControlled->StLinSwitchType != "toggle" ) {
// default button type (impulse) works on button release
Train->mvControlled->StLinSwitchOff = false;
if( ( Train->mvControlled->TrainType == dt_ET41 )
|| ( Train->mvControlled->TrainType == dt_ET42 ) ) {
// crude implementation of the butto affecting entire unit for multi-unit engines
// TODO: rework it into part of standard command propagation system
if( ( Train->mvControlled->Couplers[ 0 ].Connected != nullptr )
&& ( true == TestFlag( Train->mvControlled->Couplers[ 0 ].CouplingFlag, coupling::permanent ) ) ) {
// the first unit isn't allowed to start its compressor until second unit can start its own as well
Train->mvControlled->Couplers[ 0 ].Connected->StLinSwitchOff = false;
}
if( ( Train->mvControlled->Couplers[ 1 ].Connected != nullptr )
&& ( true == TestFlag( Train->mvControlled->Couplers[ 1 ].CouplingFlag, coupling::permanent ) ) ) {
// the first unit isn't allowed to start its compressor until second unit can start its own as well
Train->mvControlled->Couplers[ 1 ].Connected->StLinSwitchOff = false;
}
}
// sound feedback
if( Train->ggStLinOffButton.GetValue() > 0.5 ) {
Train->play_sound( Train->dsbSwitch );
}
// visual feedback
Train->ggStLinOffButton.UpdateValue( 0.0 );
}
// visual feedback
Train->ggStLinOffButton.UpdateValue( 0.0 );
}
}
@@ -2700,10 +2881,12 @@ void TTrain::OnCommand_hornlowactivate( TTrain *Train, command_data const &Comma
if( false == TestFlag( Train->mvOccupied->WarningSignal, 1 ) ) {
// turn on
Train->mvOccupied->WarningSignal |= 1;
/*
if( true == TestFlag( Train->mvOccupied->WarningSignal, 2 ) ) {
// low and high horn are treated as mutually exclusive
Train->mvControlled->WarningSignal &= ~2;
}
*/
// audio feedback
if( ( Train->ggHornButton.GetValue() > -0.5 )
|| ( Train->ggHornLowButton.GetValue() < 0.5 ) ) {
@@ -2716,8 +2899,11 @@ void TTrain::OnCommand_hornlowactivate( TTrain *Train, command_data const &Comma
}
else if( Command.action == GLFW_RELEASE ) {
// turn off
/*
// NOTE: we turn off both low and high horn, due to unreliability of release event when shift key is involved
Train->mvOccupied->WarningSignal &= ~( 1 | 2 );
*/
Train->mvOccupied->WarningSignal &= ~1;
// audio feedback
if( ( Train->ggHornButton.GetValue() < -0.5 )
|| ( Train->ggHornLowButton.GetValue() > 0.5 ) ) {
@@ -2744,10 +2930,12 @@ void TTrain::OnCommand_hornhighactivate( TTrain *Train, command_data const &Comm
if( false == TestFlag( Train->mvOccupied->WarningSignal, 2 ) ) {
// turn on
Train->mvOccupied->WarningSignal |= 2;
/*
if( true == TestFlag( Train->mvOccupied->WarningSignal, 1 ) ) {
// low and high horn are treated as mutually exclusive
Train->mvControlled->WarningSignal &= ~1;
}
*/
// audio feedback
if( Train->ggHornButton.GetValue() < 0.5 ) {
Train->play_sound( Train->dsbSwitch );
@@ -2759,8 +2947,11 @@ void TTrain::OnCommand_hornhighactivate( TTrain *Train, command_data const &Comm
}
else if( Command.action == GLFW_RELEASE ) {
// turn off
/*
// NOTE: we turn off both low and high horn, due to unreliability of release event when shift key is involved
Train->mvOccupied->WarningSignal &= ~( 1 | 2 );
*/
Train->mvOccupied->WarningSignal &= ~2;
// audio feedback
if( Train->ggHornButton.GetValue() > 0.5 ) {
Train->play_sound( Train->dsbSwitch );
@@ -4674,9 +4865,11 @@ bool TTrain::Update( double const Deltatime )
ggDepartureSignalButton.Update();
// NBMX dzwignia sprezarki
ggCompressorButton.Update();
ggCompressorLocalButton.Update();
ggMainButton.Update();
ggRadioButton.Update();
ggConverterButton.Update();
ggConverterLocalButton.Update();
ggConverterOffButton.Update();
#ifdef EU07_USE_OLD_COMMAND_SYSTEM
@@ -5820,6 +6013,8 @@ bool TTrain::LoadMMediaFile(std::string const &asFileName)
// NOTE: yaml-style comments are disabled until conflict in use of # is resolved
// parser.addCommentStyle( "#", "\n" );
//Wartości domyślne by nie wysypywało przy wybrakowanych mmd @240816 Stele
// NOTE: should be no longer needed as safety checks were added,
// but leaving the defaults for the sake of incomplete mmd files
dsbPneumaticSwitch = TSoundsManager::GetFromName("silence1.wav", true);
dsbBufferClamp = TSoundsManager::GetFromName("en57_bufferclamp.wav", true);
dsbCouplerDetach = TSoundsManager::GetFromName("couplerdetach.wav", true);
@@ -5847,67 +6042,67 @@ bool TTrain::LoadMMediaFile(std::string const &asFileName)
{
// nastawnik:
dsbNastawnikJazdy =
TSoundsManager::GetFromName(parser.getToken<std::string>().c_str(), true);
TSoundsManager::GetFromName(parser.getToken<std::string>(), true);
}
else if (token == "ctrlscnd:")
{
// hunter-081211: nastawnik bocznikowania
dsbNastawnikBocz =
TSoundsManager::GetFromName(parser.getToken<std::string>().c_str(), true);
TSoundsManager::GetFromName(parser.getToken<std::string>(), true);
}
else if (token == "reverserkey:")
{
// hunter-131211: dzwiek kierunkowego
dsbReverserKey =
TSoundsManager::GetFromName(parser.getToken<std::string>().c_str(), true);
TSoundsManager::GetFromName(parser.getToken<std::string>(), true);
}
else if (token == "buzzer:")
{
// bzyczek shp:
dsbBuzzer =
TSoundsManager::GetFromName(parser.getToken<std::string>().c_str(), true);
TSoundsManager::GetFromName(parser.getToken<std::string>(), true);
}
else if (token == "slipalarm:")
{
// Bombardier 011010: alarm przy poslizgu:
dsbSlipAlarm =
TSoundsManager::GetFromName(parser.getToken<std::string>().c_str(), true);
TSoundsManager::GetFromName(parser.getToken<std::string>(), true);
}
else if (token == "tachoclock:")
{
// cykanie rejestratora:
dsbHasler =
TSoundsManager::GetFromName(parser.getToken<std::string>().c_str(), true);
TSoundsManager::GetFromName(parser.getToken<std::string>(), true);
}
else if (token == "switch:")
{
// przelaczniki:
dsbSwitch =
TSoundsManager::GetFromName(parser.getToken<std::string>().c_str(), true);
TSoundsManager::GetFromName(parser.getToken<std::string>(), true);
}
else if (token == "pneumaticswitch:")
{
// stycznik EP:
dsbPneumaticSwitch =
TSoundsManager::GetFromName(parser.getToken<std::string>().c_str(), true);
TSoundsManager::GetFromName(parser.getToken<std::string>(), true);
}
else if (token == "wejscie_na_bezoporow:")
{
// hunter-111211: wydzielenie wejscia na bezoporowa i na drugi uklad do pliku
dsbWejscie_na_bezoporow =
TSoundsManager::GetFromName(parser.getToken<std::string>().c_str(), true);
TSoundsManager::GetFromName(parser.getToken<std::string>(), true);
}
else if (token == "wejscie_na_drugi_uklad:")
{
dsbWejscie_na_drugi_uklad =
TSoundsManager::GetFromName(parser.getToken<std::string>().c_str(), true);
TSoundsManager::GetFromName(parser.getToken<std::string>(), true);
}
else if (token == "relay:")
{
// styczniki itp:
dsbRelay =
TSoundsManager::GetFromName(parser.getToken<std::string>().c_str(), true);
TSoundsManager::GetFromName(parser.getToken<std::string>(), true);
if (!dsbWejscie_na_bezoporow)
{ // hunter-111211: domyslne, gdy brak
dsbWejscie_na_bezoporow =
@@ -5923,39 +6118,37 @@ bool TTrain::LoadMMediaFile(std::string const &asFileName)
{
// wylaczniki pneumatyczne:
dsbPneumaticRelay =
TSoundsManager::GetFromName(parser.getToken<std::string>().c_str(), true);
TSoundsManager::GetFromName(parser.getToken<std::string>(), true);
}
else if (token == "couplerattach:")
{
// laczenie:
dsbCouplerAttach =
TSoundsManager::GetFromName(parser.getToken<std::string>().c_str(), true);
TSoundsManager::GetFromName(parser.getToken<std::string>(), true);
}
else if (token == "couplerstretch:")
{
// laczenie:
dsbCouplerStretch = TSoundsManager::GetFromName(
parser.getToken<std::string>().c_str(),
true); // McZapkie-090503: PROWIZORKA!!! "en57_couplerstretch.wav"
dsbCouplerStretch =
TSoundsManager::GetFromName(parser.getToken<std::string>(), true);
}
else if (token == "couplerdetach:")
{
// rozlaczanie:
dsbCouplerDetach =
TSoundsManager::GetFromName(parser.getToken<std::string>().c_str(), true);
TSoundsManager::GetFromName(parser.getToken<std::string>(), true);
}
else if (token == "bufferclamp:")
{
// laczenie:
dsbBufferClamp = TSoundsManager::GetFromName(
parser.getToken<std::string>().c_str(),
true); // McZapkie-090503: PROWIZORKA!!! "en57_bufferclamp.wav"
dsbBufferClamp =
TSoundsManager::GetFromName(parser.getToken<std::string>(), true);
}
else if (token == "ignition:")
{
// odpalanie silnika
dsbDieselIgnition =
TSoundsManager::GetFromName(parser.getToken<std::string>().c_str(), true);
TSoundsManager::GetFromName(parser.getToken<std::string>(), true);
}
else if (token == "brakesound:")
{
@@ -6073,25 +6266,25 @@ bool TTrain::LoadMMediaFile(std::string const &asFileName)
{
// podniesienie patyka:
dsbPantUp =
TSoundsManager::GetFromName(parser.getToken<std::string>().c_str(), true);
TSoundsManager::GetFromName(parser.getToken<std::string>(), true);
}
else if (token == "pantographdown:")
{
// podniesienie patyka:
dsbPantDown =
TSoundsManager::GetFromName(parser.getToken<std::string>().c_str(), true);
TSoundsManager::GetFromName(parser.getToken<std::string>(), true);
}
else if (token == "doorclose:")
{
// zamkniecie drzwi:
dsbDoorClose =
TSoundsManager::GetFromName(parser.getToken<std::string>().c_str(), true);
TSoundsManager::GetFromName(parser.getToken<std::string>(), true);
}
else if (token == "dooropen:")
{
// otwarcie drzwi:
dsbDoorOpen =
TSoundsManager::GetFromName(parser.getToken<std::string>().c_str(), true);
TSoundsManager::GetFromName(parser.getToken<std::string>(), true);
}
} while (token != "");
@@ -6604,6 +6797,11 @@ void TTrain::set_cab_controls() {
if( true == mvOccupied->Battery ) {
ggBatteryButton.PutValue( 1.0 );
}
// motor connectors
ggStLinOffButton.PutValue(
( mvControlled->StLinSwitchOff ?
1.0 :
0.0 ) );
// radio
if( true == mvOccupied->Radio ) {
ggRadioButton.PutValue( 1.0 );
@@ -6636,10 +6834,19 @@ void TTrain::set_cab_controls() {
1.0 :
0.0 );
}
ggConverterLocalButton.PutValue(
mvControlled->ConverterAllowLocal ?
1.0 :
0.0 );
// compressor
if( true == mvControlled->CompressorAllow ) {
ggCompressorButton.PutValue( 1.0 );
}
ggCompressorButton.PutValue(
mvControlled->CompressorAllow ?
1.0 :
0.0 );
ggCompressorLocalButton.PutValue(
mvControlled->CompressorAllowLocal ?
1.0 :
0.0 );
// motor overload relay threshold / shunt mode
if( mvControlled->Imax == mvControlled->ImaxHi ) {
ggMaxCurrentCtrl.PutValue( 1.0 );
@@ -7175,11 +7382,19 @@ bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int con
// sprezarka
ggCompressorButton.Load(Parser, DynamicObject->mdKabina);
}
else if( Label == "compressorlocal_sw:" ) {
// sprezarka
ggCompressorLocalButton.Load( Parser, DynamicObject->mdKabina );
}
else if (Label == "converter_sw:")
{
// przetwornica
ggConverterButton.Load(Parser, DynamicObject->mdKabina);
}
else if( Label == "converterlocal_sw:" ) {
// przetwornica
ggConverterLocalButton.Load( Parser, DynamicObject->mdKabina );
}
else if (Label == "converteroff_sw:")
{
// przetwornica wyl

View File

@@ -146,8 +146,10 @@ class TTrain
static void OnCommand_pantographlowerall( TTrain *Train, command_data const &Command );
static void OnCommand_linebreakertoggle( TTrain *Train, command_data const &Command );
static void OnCommand_convertertoggle( TTrain *Train, command_data const &Command );
static void OnCommand_convertertogglelocal( TTrain *Train, command_data const &Command );
static void OnCommand_converteroverloadrelayreset( TTrain *Train, command_data const &Command );
static void OnCommand_compressortoggle( TTrain *Train, command_data const &Command );
static void OnCommand_compressortogglelocal( TTrain *Train, command_data const &Command );
static void OnCommand_motorconnectorsopen( TTrain *Train, command_data const &Command );
static void OnCommand_motordisconnect( TTrain *Train, command_data const &Command );
static void OnCommand_motoroverloadrelaythresholdtoggle( TTrain *Train, command_data const &Command );
@@ -251,7 +253,9 @@ public: // reszta może by?publiczna
TGauge ggIgnitionKey;
TGauge ggCompressorButton;
TGauge ggCompressorLocalButton; // controls only compressor of its own unit (et42-specific)
TGauge ggConverterButton;
TGauge ggConverterLocalButton; // controls only converter of its own unit (et42-specific)
TGauge ggConverterOffButton;
// ABu 090305 - syrena i prad nastepnego czlonu

20
VBO.cpp
View File

@@ -44,7 +44,9 @@ void CVertNormTex::serialize(std::ostream &s)
CMesh::CMesh()
{ // utworzenie pustego obiektu
#ifdef EU07_USE_OLD_VERTEXBUFFER
m_pVNT = nullptr;
#endif
m_nVertexCount = -1;
m_nVBOVertices = 0; // nie zarezerwowane
};
@@ -57,7 +59,13 @@ CMesh::~CMesh()
void CMesh::MakeArray(int n)
{ // tworzenie tablic
m_nVertexCount = n;
#ifdef EU07_USE_OLD_VERTEXBUFFER
assert( m_pVNT == nullptr );
m_pVNT = new CVertNormTex[m_nVertexCount]; // przydzielenie pamięci dla tablicy
#else
m_pVNT.clear();
m_pVNT.resize( m_nVertexCount );
#endif
};
void CMesh::BuildVBOs(bool del)
@@ -65,11 +73,19 @@ void CMesh::BuildVBOs(bool del)
// pobierz numer VBO oraz ustaw go jako aktywny
glGenBuffers(1, &m_nVBOVertices); // pobierz numer
glBindBuffer(GL_ARRAY_BUFFER, m_nVBOVertices); // ustaw bufor jako aktualny
#ifdef EU07_USE_OLD_VERTEXBUFFER
glBufferData(GL_ARRAY_BUFFER, m_nVertexCount * sizeof(CVertNormTex), m_pVNT, GL_STATIC_DRAW);
#else
glBufferData( GL_ARRAY_BUFFER, m_nVertexCount * sizeof( CVertNormTex ), m_pVNT.data(), GL_STATIC_DRAW );
#endif
// WriteLog("Assigned VBO number "+AnsiString(m_nVBOVertices)+", vertices:
// "+AnsiString(m_nVertexCount));
#ifdef EU07_USE_OLD_VERTEXBUFFER
if (del)
SafeDeleteArray(m_pVNT); // wierzchołki już się nie przydadzą
#else
m_pVNT.clear();
#endif
};
void CMesh::Clear()
@@ -82,7 +98,11 @@ void CMesh::Clear()
}
m_nVBOVertices = 0;
m_nVertexCount = -1; // do ponownego zliczenia
#ifdef EU07_USE_OLD_VERTEXBUFFER
SafeDeleteArray(m_pVNT); // usuwanie tablic, gdy były użyte do Vertex Array
#else
m_pVNT.clear();
#endif
};
bool CMesh::StartVBO()

7
VBO.h
View File

@@ -9,6 +9,9 @@ http://mozilla.org/MPL/2.0/.
#ifndef VBOH
#define VBOH
#define EU07_USE_OLD_VERTEXBUFFER
//---------------------------------------------------------------------------
class CVertNormTex
{
@@ -30,7 +33,11 @@ class CMesh
{ // wsparcie dla VBO
public:
int m_nVertexCount; // liczba wierzchołków
#ifdef EU07_USE_OLD_VERTEXBUFFER
CVertNormTex *m_pVNT;
#else
std::vector<CVertNormTex> m_pVNT;
#endif
unsigned int m_nVBOVertices; // numer VBO z wierzchołkami
CMesh();
~CMesh();

606
World.cpp
View File

@@ -375,11 +375,12 @@ bool TWorld::Init( GLFWwindow *Window ) {
WriteLog( "Load time: " +
std::to_string( std::chrono::duration_cast<std::chrono::seconds>(( std::chrono::system_clock::now() - timestart )).count() )
+ " seconds");
/*
if (DebugModeFlag) // w Debugmode automatyczne włączenie AI
if (Train)
if (Train->Dynamic()->Mechanik)
Train->Dynamic()->Mechanik->TakeControl(true);
*/
UILayer.set_progress();
UILayer.set_background( "" );
UILayer.clear_texts();
@@ -905,43 +906,52 @@ void TWorld::DistantView( bool const Near )
Camera.RaLook(); // jednorazowe przestawienie kamery
};
void TWorld::FollowView(bool wycisz)
{ // ustawienie śledzenia pojazdu
// ustawienie śledzenia pojazdu
void TWorld::FollowView(bool wycisz) {
Camera.Reset(); // likwidacja obrotów - patrzy horyzontalnie na południe
if (Controlled) // jest pojazd do prowadzenia?
{
vector3 camStara =
Camera.Pos; // przestawianie kamery jest bez sensu: do przerobienia na potem
// Controlled->ABuSetModelShake(vector3(0,0,0));
Ground.Silence( Camera.Pos ); // wyciszenie dźwięków z poprzedniej pozycji
if (FreeFlyModeFlag)
{ // jeżeli poza kabiną, przestawiamy w jej okolicę - OK
if (Train)
Train->Dynamic()->ABuSetModelShake(
vector3(0, 0, 0)); // wyłączenie trzęsienia na siłę?
// Camera.Pos=Train->pMechPosition+Normalize(Train->GetDirection())*20;
if( Train ) {
// wyłączenie trzęsienia na siłę?
Train->Dynamic()->ABuSetModelShake( vector3() );
}
DistantView(); // przestawienie kamery
//żeby nie bylo numerów z 'fruwajacym' lokiem - konsekwencja bujania pudła
Global::SetCameraPosition(
Camera.Pos); // tu ustawić nową, bo od niej liczą się odległości
Ground.Silence(camStara); // wyciszenie dźwięków z poprzedniej pozycji
// tu ustawić nową, bo od niej liczą się odległości
Global::SetCameraPosition( Camera.Pos );
}
else if (Train)
{ // korekcja ustawienia w kabinie - OK
vector3 camStara = Camera.Pos; // przestawianie kamery jest bez sensu: do przerobienia na potem
// Ra: czy to tu jest potrzebne, bo przelicza się kawałek dalej?
Camera.Pos = Train->pMechPosition; // Train.GetPosition1();
if( wycisz ) {
// wyciszenie dźwięków z poprzedniej pozycji
// trzymanie prawego w kabinie daje marny efekt
Ground.Silence( Camera.Pos );
}
Camera.Pos = Train->pMechPosition;
Camera.Roll = std::atan(Train->pMechShake.x * Train->fMechRoll); // hustanie kamery na boki
Camera.Pitch -= 0.5 * std::atan(Train->vMechVelocity.z * Train->fMechPitch); // hustanie kamery przod tyl
if (Train->Dynamic()->MoverParameters->ActiveCab == 0)
Camera.LookAt = Train->pMechPosition + Train->GetDirection() * 5.0;
else // patrz w strone wlasciwej kabiny
Camera.LookAt = Train->pMechPosition + Train->GetDirection() * 5.0 * Train->Dynamic()->MoverParameters->ActiveCab;
Train->pMechOffset.x = Train->pMechSittingPosition.x;
Train->pMechOffset.y = Train->pMechSittingPosition.y;
Train->pMechOffset.z = Train->pMechSittingPosition.z;
if( Train->Dynamic()->MoverParameters->ActiveCab == 0 ) {
Camera.LookAt =
Train->pMechPosition
+ Train->GetDirection() * 5.0;
}
else {
// patrz w strone wlasciwej kabiny
Camera.LookAt =
Train->pMechPosition
+ Train->GetDirection() * 5.0 * Train->Dynamic()->MoverParameters->ActiveCab;
}
Train->pMechOffset = Train->pMechSittingPosition;
Global::SetCameraPosition( Train->Dynamic() ->GetPosition()); // tu ustawić nową, bo od niej liczą się odległości
if (wycisz) // trzymanie prawego w kabinie daje marny efekt
Ground.Silence(camStara); // wyciszenie dźwięków z poprzedniej pozycji
}
}
else
@@ -1238,105 +1248,7 @@ TWorld::Update_Camera( double const Deltatime ) {
void TWorld::Update_Environment() {
#ifdef EU07_USE_OLD_LIGHTING_MODEL
if( Global::fMoveLight < 0.0 ) {
return;
}
// double a=Global::fTimeAngleDeg/180.0*M_PI-M_PI; //kąt godzinny w radianach
double a = fmod( Global::fTimeAngleDeg, 360.0 ) / 180.0 * M_PI -
M_PI; // kąt godzinny w radianach
//(a) jest traktowane jako czas miejscowy, nie uwzględniający stref czasowych ani czasu
// letniego
// aby wyznaczyć strefę czasową, trzeba uwzględnić południk miejscowy
// aby uwzględnić czas letni, trzeba sprawdzić dzień roku
double L = Global::fLatitudeDeg / 180.0 * M_PI; // szerokość geograficzna
double H = asin( cos( L ) * cos( Global::fSunDeclination ) * cos( a ) +
sin( L ) * sin( Global::fSunDeclination ) ); // kąt ponad horyzontem
// double A=asin(cos(d)*sin(M_PI-a)/cos(H));
// Declination=((0.322003-22.971*cos(t)-0.357898*cos(2*t)-0.14398*cos(3*t)+3.94638*sin(t)+0.019334*sin(2*t)+0.05928*sin(3*t)))*Pi/180
// Altitude=asin(sin(Declination)*sin(latitude)+cos(Declination)*cos(latitude)*cos((15*(time-12))*(Pi/180)));
// Azimuth=(acos((cos(latitude)*sin(Declination)-cos(Declination)*sin(latitude)*cos((15*(time-12))*(Pi/180)))/cos(Altitude)));
// double A=acos(cos(L)*sin(d)-cos(d)*sin(L)*cos(M_PI-a)/cos(H));
// dAzimuth = atan2(-sin( dHourAngle ),tan( dDeclination )*dCos_Latitude -
// dSin_Latitude*dCos_HourAngle );
double A = atan2( sin( a ), tan( Global::fSunDeclination ) * cos( L ) - sin( L ) * cos( a ) );
vector3 lp = vector3( sin( A ), tan( H ), cos( A ) );
lp = Normalize( lp ); // przeliczenie na wektor długości 1.0
Global::lightPos[ 0 ] = (float)lp.x;
Global::lightPos[ 1 ] = (float)lp.y;
Global::lightPos[ 2 ] = (float)lp.z;
glLightfv( GL_LIGHT0, GL_POSITION, Global::lightPos ); // daylight position
if( H > 0 ) { // słońce ponad horyzontem
Global::ambientDayLight[ 0 ] = Global::ambientLight[ 0 ];
Global::ambientDayLight[ 1 ] = Global::ambientLight[ 1 ];
Global::ambientDayLight[ 2 ] = Global::ambientLight[ 2 ];
if( H > 0.02 ) // ponad 1.146° zaczynają się cienie
{
Global::diffuseDayLight[ 0 ] =
Global::diffuseLight[ 0 ]; // od wschodu do zachodu maksimum ???
Global::diffuseDayLight[ 1 ] = Global::diffuseLight[ 1 ];
Global::diffuseDayLight[ 2 ] = Global::diffuseLight[ 2 ];
Global::specularDayLight[ 0 ] = Global::specularLight[ 0 ]; // podobnie specular
Global::specularDayLight[ 1 ] = Global::specularLight[ 1 ];
Global::specularDayLight[ 2 ] = Global::specularLight[ 2 ];
}
else {
Global::diffuseDayLight[ 0 ] =
50 * H * Global::diffuseLight[ 0 ]; // wschód albo zachód
Global::diffuseDayLight[ 1 ] = 50 * H * Global::diffuseLight[ 1 ];
Global::diffuseDayLight[ 2 ] = 50 * H * Global::diffuseLight[ 2 ];
Global::specularDayLight[ 0 ] =
50 * H * Global::specularLight[ 0 ]; // podobnie specular
Global::specularDayLight[ 1 ] = 50 * H * Global::specularLight[ 1 ];
Global::specularDayLight[ 2 ] = 50 * H * Global::specularLight[ 2 ];
}
}
else { // słońce pod horyzontem
GLfloat lum = 3.1831 * ( H > -0.314159 ? 0.314159 + H :
0.0 ); // po zachodzie ambient się ściemnia
Global::ambientDayLight[ 0 ] = lum * Global::ambientLight[ 0 ];
Global::ambientDayLight[ 1 ] = lum * Global::ambientLight[ 1 ];
Global::ambientDayLight[ 2 ] = lum * Global::ambientLight[ 2 ];
Global::diffuseDayLight[ 0 ] =
Global::noLight[ 0 ]; // od zachodu do wschodu nie ma diffuse
Global::diffuseDayLight[ 1 ] = Global::noLight[ 1 ];
Global::diffuseDayLight[ 2 ] = Global::noLight[ 2 ];
Global::specularDayLight[ 0 ] = Global::noLight[ 0 ]; // ani specular
Global::specularDayLight[ 1 ] = Global::noLight[ 1 ];
Global::specularDayLight[ 2 ] = Global::noLight[ 2 ];
}
// Calculate sky colour according to time of day.
// GLfloat sin_t = sin(PI * time_of_day / 12.0);
// back_red = 0.3 * (1.0 - sin_t);
// back_green = 0.9 * sin_t;
// back_blue = sin_t + 0.4, 1.0;
// aktualizacja świateł
glLightfv( GL_LIGHT0, GL_AMBIENT, Global::ambientDayLight );
glLightfv( GL_LIGHT0, GL_DIFFUSE, Global::diffuseDayLight );
glLightfv( GL_LIGHT0, GL_SPECULAR, Global::specularDayLight );
Global::fLuminance = // to posłuży również do zapalania latarń
+0.150 * ( Global::diffuseDayLight[ 0 ] + Global::ambientDayLight[ 0 ] ) // R
+ 0.295 * ( Global::diffuseDayLight[ 1 ] + Global::ambientDayLight[ 1 ] ) // G
+ 0.055 * ( Global::diffuseDayLight[ 2 ] + Global::ambientDayLight[ 2 ] ); // B
vector3 sky = vector3( Global::AtmoColor[ 0 ], Global::AtmoColor[ 1 ], Global::AtmoColor[ 2 ] );
if( Global::fLuminance < 0.25 ) { // przyspieszenie zachodu/wschodu
sky *= 4.0 * Global::fLuminance; // nocny kolor nieba
GLfloat fog[ 3 ];
fog[ 0 ] = Global::FogColor[ 0 ] * 4.0 * Global::fLuminance;
fog[ 1 ] = Global::FogColor[ 1 ] * 4.0 * Global::fLuminance;
fog[ 2 ] = Global::FogColor[ 2 ] * 4.0 * Global::fLuminance;
glFogfv( GL_FOG_COLOR, fog ); // nocny kolor mgły
}
else {
glFogfv( GL_FOG_COLOR, Global::FogColor ); // kolor mgły
}
#else
Environment.update();
#endif
}
void TWorld::ResourceSweep()
@@ -1363,11 +1275,9 @@ TWorld::Render_Cab() {
// ABu: Rendering kabiny jako ostatniej, zeby bylo widac przez szyby, tylko w widoku ze srodka
return;
}
::glEnable( GL_LIGHTING ); // po renderowaniu drutów może być to wyłączone. TODO: have the wires render take care of its own shit
/*
// ABu: Rendering kabiny jako ostatniej, zeby bylo widac przez szyby, tylko w widoku ze srodka
if( ( Train->Dynamic()->mdKabina != Train->Dynamic()->mdModel ) &&
Train->Dynamic()->bDisplayCab && !FreeFlyModeFlag ) {
*/
glPushMatrix();
vector3 pos = dynamic->GetPosition(); // wszpółrzędne pojazdu z kabiną
// glTranslatef(pos.x,pos.y,pos.z); //przesunięcie o wektor (tak było i trzęsło)
@@ -1376,247 +1286,28 @@ TWorld::Render_Cab() {
glLoadIdentity(); // zacząć od macierzy jedynkowej
Camera.SetCabMatrix( pos ); // widok z kamery po przesunięciu
glMultMatrixd( dynamic->mMatrix.getArray() ); // ta macierz nie ma przesunięcia
/*
//*yB: moje smuuugi 1
if( Global::bSmudge ) { // Ra: uwzględniłem zacienienie pojazdu przy zapalaniu smug
// 1. warunek na smugę wyznaczyc wcześniej
// 2. jeśli smuga włączona, nie renderować pojazdu użytkownika w DynObj
// 3. jeśli smuga właczona, wyrenderować pojazd użytkownia po dodaniu smugi do sceny
auto const &frontlights = Train->Controlled()->iLights[ 0 ];
float frontlightstrength = 0.f +
( ( frontlights & 1 ) ? 0.3f : 0.f ) +
( ( frontlights & 4 ) ? 0.3f : 0.f ) +
( ( frontlights & 16 ) ? 0.3f : 0.f );
frontlightstrength = std::max( frontlightstrength - Global::fLuminance, 0.0 );
auto const &rearlights = Train->Controlled()->iLights[ 1 ];
float rearlightstrength = 0.f +
( ( rearlights & 1 ) ? 0.3f : 0.f ) +
( ( rearlights & 4 ) ? 0.3f : 0.f ) +
( ( rearlights & 16 ) ? 0.3f : 0.f );
rearlightstrength = std::max( rearlightstrength - Global::fLuminance, 0.0 );
if( ( Train->Controlled()->Battery ) // trochę na skróty z tą baterią
&& ( ( frontlightstrength > 0.f )
|| ( rearlightstrength > 0.f ) ) ) {
if( Global::bOldSmudge == true ) {
glBlendFunc( GL_SRC_ALPHA, GL_ONE );
// glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_DST_COLOR);
// glBlendFunc(GL_SRC_ALPHA_SATURATE,GL_ONE);
glDisable( GL_DEPTH_TEST );
glDisable( GL_LIGHTING );
glDisable( GL_FOG );
GfxRenderer.Bind( light ); // Select our texture
glBegin( GL_QUADS );
float fSmudge =
dynamic->MoverParameters->DimHalf.y + 7; // gdzie zaczynać smugę
if( frontlightstrength > 0.f ) { // wystarczy jeden zapalony z przodu
glColor4f( 1.0f, 1.0f, 1.0f, 0.5f * frontlightstrength );
glTexCoord2f( 0, 0 );
glVertex3f( 15.0, 0.0, +fSmudge ); // rysowanie względem położenia modelu
glTexCoord2f( 1, 0 );
glVertex3f( -15.0, 0.0, +fSmudge );
glTexCoord2f( 1, 1 );
glVertex3f( -15.0, 2.5, 250.0 );
glTexCoord2f( 0, 1 );
glVertex3f( 15.0, 2.5, 250.0 );
}
if( rearlightstrength > 0.f ) { // wystarczy jeden zapalony z tyłu
glColor4f( 1.0f, 1.0f, 1.0f, 0.5f * rearlightstrength );
glTexCoord2f( 0, 0 );
glVertex3f( -15.0, 0.0, -fSmudge );
glTexCoord2f( 1, 0 );
glVertex3f( 15.0, 0.0, -fSmudge );
glTexCoord2f( 1, 1 );
glVertex3f( 15.0, 2.5, -250.0 );
glTexCoord2f( 0, 1 );
glVertex3f( -15.0, 2.5, -250.0 );
}
glEnd();
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
glEnable( GL_DEPTH_TEST );
// glEnable(GL_LIGHTING); //i tak się włączy potem
glEnable( GL_FOG );
}
else {
glBlendFunc( GL_DST_COLOR, GL_ONE );
glDepthFunc( GL_GEQUAL );
glAlphaFunc( GL_GREATER, 0.004 );
// glDisable(GL_DEPTH_TEST);
glDisable( GL_LIGHTING );
glDisable( GL_FOG );
//glColor4f(0.15f, 0.15f, 0.15f, 0.25f);
GfxRenderer.Bind( light ); // Select our texture
//float ddl = (0.15*Global::diffuseDayLight[0]+0.295*Global::diffuseDayLight[1]+0.055*Global::diffuseDayLight[2]); //0.24:0
glBegin( GL_QUADS );
float fSmudge = dynamic->MoverParameters->DimHalf.y + 7; // gdzie zaczynać smugę
if( frontlightstrength > 0.f ) {
// wystarczy jeden zapalony z przodu
for( int i = 15; i <= 35; i++ ) {
float z = i * i * i * 0.01f;//25/4;
//float C = (36 - i*0.5)*0.005*(1.5 - sqrt(ddl));
float C = ( 36 - i*0.5 )*0.005*sqrt( ( 1 / sqrt( Global::fLuminance + 0.015 ) ) - 1 ) * frontlightstrength;
glColor4f( C, C, C, 1.0f );// *frontlightstrength );
glTexCoord2f( 0, 0 ); glVertex3f( -10 / 2 - 2 * i / 4, 6.0 + 0.3*z, 13 + 1.7*z / 3 );
glTexCoord2f( 1, 0 ); glVertex3f( 10 / 2 + 2 * i / 4, 6.0 + 0.3*z, 13 + 1.7*z / 3 );
glTexCoord2f( 1, 1 ); glVertex3f( 10 / 2 + 2 * i / 4, -5.0 - 0.5*z, 13 + 1.7*z / 3 );
glTexCoord2f( 0, 1 ); glVertex3f( -10 / 2 - 2 * i / 4, -5.0 - 0.5*z, 13 + 1.7*z / 3 );
}
}
if( rearlightstrength > 0.f ) {
// wystarczy jeden zapalony z tyłu
for( int i = 15; i <= 35; i++ ) {
float z = i * i * i * 0.01f;//25/4;
float C = ( 36 - i*0.5 )*0.005*sqrt( ( 1 / sqrt( Global::fLuminance + 0.015 ) ) - 1 ) * rearlightstrength;
glColor4f( C, C, C, 1.0f );// *rearlightstrength );
glTexCoord2f( 0, 0 ); glVertex3f( 10 / 2 + 2 * i / 4, 6.0 + 0.3*z, -13 - 1.7*z / 3 );
glTexCoord2f( 1, 0 ); glVertex3f( -10 / 2 - 2 * i / 4, 6.0 + 0.3*z, -13 - 1.7*z / 3 );
glTexCoord2f( 1, 1 ); glVertex3f( -10 / 2 - 2 * i / 4, -5.0 - 0.5*z, -13 - 1.7*z / 3 );
glTexCoord2f( 0, 1 ); glVertex3f( 10 / 2 + 2 * i / 4, -5.0 - 0.5*z, -13 - 1.7*z / 3 );
}
}
glEnd();
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
// glEnable(GL_DEPTH_TEST);
glAlphaFunc( GL_GREATER, 0.04 );
glDepthFunc( GL_LEQUAL );
glEnable( GL_LIGHTING ); //i tak się włączy potem
glEnable( GL_FOG );
}
}
glEnable( GL_LIGHTING ); // po renderowaniu smugi jest to wyłączone
// Ra: pojazd użytkownika należało by renderować po smudze, aby go nie rozświetlała
Global::bSmudge = false; // aby model użytkownika się teraz wyrenderował
dynamic->Render();
dynamic->RenderAlpha(); // przezroczyste fragmenty pojazdów na torach
} // yB: moje smuuugi 1 - koniec
else
*/ glEnable( GL_LIGHTING ); // po renderowaniu drutów może być to wyłączone. TODO: have the wires render take care of its own shit
*/
::glPushMatrix();
auto const originoffset = dynamic->GetPosition() - Global::pCameraPosition;
::glTranslated( originoffset.x, originoffset.y, originoffset.z );
::glMultMatrixd( dynamic->mMatrix.getArray() );
if( dynamic->mdKabina ) // bo mogła zniknąć przy przechodzeniu do innego pojazdu
{
#ifdef EU07_USE_OLD_LIGHTING_MODEL
// oswietlenie kabiny
GLfloat ambientCabLight[ 4 ] = { 0.5f, 0.5f, 0.5f, 1.0f };
GLfloat diffuseCabLight[ 4 ] = { 0.5f, 0.5f, 0.5f, 1.0f };
GLfloat specularCabLight[ 4 ] = { 0.5f, 0.5f, 0.5f, 1.0f };
for( int li = 0; li < 3; li++ ) { // przyciemnienie standardowe
ambientCabLight[ li ] = Global::ambientDayLight[ li ] * 0.9;
diffuseCabLight[ li ] = Global::diffuseDayLight[ li ] * 0.5;
specularCabLight[ li ] = Global::specularDayLight[ li ] * 0.5;
}
switch( dynamic->MyTrack->eEnvironment ) { // wpływ świetła zewnętrznego
case e_canyon:
{
for( int li = 0; li < 3; li++ ) {
diffuseCabLight[ li ] *= 0.6;
specularCabLight[ li ] *= 0.7;
}
}
break;
case e_tunnel:
{
for( int li = 0; li < 3; li++ ) {
ambientCabLight[ li ] *= 0.3;
diffuseCabLight[ li ] *= 0.1;
specularCabLight[ li ] *= 0.2;
}
}
break;
}
switch( Train->iCabLightFlag ) // Ra: uzeleżnic od napięcia w obwodzie sterowania
{ // hunter-091012: uzaleznienie jasnosci od przetwornicy
case 0: //światło wewnętrzne zgaszone
break;
case 1: //światło wewnętrzne przygaszone (255 216 176)
if( dynamic->MoverParameters->ConverterFlag ==
true ) // jasnosc dla zalaczonej przetwornicy
{
ambientCabLight[ 0 ] = Max0R( 0.700, ambientCabLight[ 0 ] ) * 0.75; // R
ambientCabLight[ 1 ] = Max0R( 0.593, ambientCabLight[ 1 ] ) * 0.75; // G
ambientCabLight[ 2 ] = Max0R( 0.483, ambientCabLight[ 2 ] ) * 0.75; // B
for( int i = 0; i < 3; i++ )
if( ambientCabLight[ i ] <= ( Global::ambientDayLight[ i ] * 0.9 ) )
ambientCabLight[ i ] = Global::ambientDayLight[ i ] * 0.9;
}
else {
ambientCabLight[ 0 ] = Max0R( 0.700, ambientCabLight[ 0 ] ) * 0.375; // R
ambientCabLight[ 1 ] = Max0R( 0.593, ambientCabLight[ 1 ] ) * 0.375; // G
ambientCabLight[ 2 ] = Max0R( 0.483, ambientCabLight[ 2 ] ) * 0.375; // B
for( int i = 0; i < 3; i++ )
if( ambientCabLight[ i ] <= ( Global::ambientDayLight[ i ] * 0.9 ) )
ambientCabLight[ i ] = Global::ambientDayLight[ i ] * 0.9;
}
break;
case 2: //światło wewnętrzne zapalone (255 216 176)
if( dynamic->MoverParameters->ConverterFlag ==
true ) // jasnosc dla zalaczonej przetwornicy
{
ambientCabLight[ 0 ] = Max0R( 1.000, ambientCabLight[ 0 ] ); // R
ambientCabLight[ 1 ] = Max0R( 0.847, ambientCabLight[ 1 ] ); // G
ambientCabLight[ 2 ] = Max0R( 0.690, ambientCabLight[ 2 ] ); // B
for( int i = 0; i < 3; i++ )
if( ambientCabLight[ i ] <= ( Global::ambientDayLight[ i ] * 0.9 ) )
ambientCabLight[ i ] = Global::ambientDayLight[ i ] * 0.9;
}
else {
ambientCabLight[ 0 ] = Max0R( 1.000, ambientCabLight[ 0 ] ) * 0.5; // R
ambientCabLight[ 1 ] = Max0R( 0.847, ambientCabLight[ 1 ] ) * 0.5; // G
ambientCabLight[ 2 ] = Max0R( 0.690, ambientCabLight[ 2 ] ) * 0.5; // B
for( int i = 0; i < 3; i++ )
if( ambientCabLight[ i ] <= ( Global::ambientDayLight[ i ] * 0.9 ) )
ambientCabLight[ i ] = Global::ambientDayLight[ i ] * 0.9;
}
break;
}
glLightfv( GL_LIGHT0, GL_AMBIENT, ambientCabLight );
glLightfv( GL_LIGHT0, GL_DIFFUSE, diffuseCabLight );
glLightfv( GL_LIGHT0, GL_SPECULAR, specularCabLight );
#else
// setup
if( dynamic->fShade > 0.0f ) {
// change light level based on light level of the occupied track
Global::DayLight.apply_intensity( dynamic->fShade );
}
if( dynamic->InteriorLightLevel > 0.0f ) {
// crude way to light the cabin, until we have something more complete in place
auto const cablight = dynamic->InteriorLight * dynamic->InteriorLightLevel;
::glLightModelfv( GL_LIGHT_MODEL_AMBIENT, &cablight.x );
}
#endif
#ifdef EU07_USE_OLD_RENDERCODE
if( Global::bUseVBO ) {
// renderowanie z użyciem VBO. NOTE: needs update, and eventual merge into single render path down the road
dynamic->mdKabina->RaRender( 0.0, dynamic->Material()->replacable_skins, dynamic->Material()->textures_alpha );
dynamic->mdKabina->RaRenderAlpha( 0.0, dynamic->Material()->replacable_skins, dynamic->Material()->textures_alpha );
}
else {
// renderowanie z Display List
dynamic->mdKabina->Render( 0.0, dynamic->ReplacableSkinID, dynamic->iAlpha );
dynamic->mdKabina->RenderAlpha( 0.0, dynamic->ReplacableSkinID, dynamic->iAlpha );
}
#else
// render
GfxRenderer.Render( dynamic->mdKabina, dynamic->Material(), 0.0 );
GfxRenderer.Render_Alpha( dynamic->mdKabina, dynamic->Material(), 0.0 );
#endif
#ifdef EU07_USE_OLD_LIGHTING_MODEL
// przywrócenie standardowych, bo zawsze są zmieniane
glLightfv( GL_LIGHT0, GL_AMBIENT, Global::ambientDayLight );
glLightfv( GL_LIGHT0, GL_DIFFUSE, Global::diffuseDayLight );
glLightfv( GL_LIGHT0, GL_SPECULAR, Global::specularDayLight );
#else
// post-render restore
if( dynamic->fShade > 0.0f ) {
// change light level based on light level of the occupied track
Global::DayLight.apply_intensity();
@@ -1626,7 +1317,6 @@ TWorld::Render_Cab() {
GLfloat ambient[] = { 0.0f, 0.0f, 0.0f, 1.0f };
::glLightModelfv( GL_LIGHT_MODEL_AMBIENT, ambient );
}
#endif
}
glPopMatrix();
}
@@ -1748,11 +1438,9 @@ TWorld::Update_UI() {
Global::Bezogonkow( "| " + station + " | " + arrival + " | " + departure + " | " + vmax + " | " + tableline->StationWare, true ),
( ( owner->iStationStart < table->StationIndex )
&& ( i < table->StationIndex )
&& ( time.wHour >= tableline->Dh )
&& ( time.wMinute >= tableline->Dm ) ?
&& ( ( time.wHour * 60 + time.wMinute ) >= ( tableline->Dh * 60 + tableline->Dm ) ) ?
float4( 0.0f, 1.0f, 0.0f, 1.0f ) :// czas minął i odjazd był, to nazwa stacji będzie na zielono
Global::UITextColor )
);
Global::UITextColor ) );
// divider/footer
UITable->text_lines.emplace_back( "+----------------------------+-------+-------+-----+", Global::UITextColor );
}
@@ -1864,9 +1552,9 @@ TWorld::Update_UI() {
uitextline3 += ( tmp->MoverParameters->PantRearUp ? ( tmp->MoverParameters->PantRearVolt > 0.0 ? "O" : "o" ) : "." );;
uitextline3 += ( tmp->MoverParameters->PantFrontUp ? ( tmp->MoverParameters->PantFrontVolt > 0.0 ? "P" : "p" ) : "." );;
uitextline3 += ( tmp->MoverParameters->PantPressLockActive ? "!" : ( tmp->MoverParameters->PantPressSwitchActive ? "*" : "." ) );
uitextline3 += ( tmp->MoverParameters->ConverterAllow ? ( tmp->MoverParameters->ConverterFlag ? "X" : "x" ) : "." );
uitextline3 += ( false == tmp->MoverParameters->ConverterAllowLocal ? "-" : ( tmp->MoverParameters->ConverterAllow ? ( tmp->MoverParameters->ConverterFlag ? "X" : "x" ) : "." ) );
uitextline3 += ( tmp->MoverParameters->ConvOvldFlag ? "!" : "." );
uitextline3 += ( tmp->MoverParameters->CompressorAllow ? ( tmp->MoverParameters->CompressorFlag ? "C" : "c" ) : "." );
uitextline3 += ( false == tmp->MoverParameters->CompressorAllowLocal ? "-" : ( tmp->MoverParameters->CompressorAllow ? ( tmp->MoverParameters->CompressorFlag ? "C" : "c" ) : "." ) );
uitextline3 += ( tmp->MoverParameters->CompressorGovernorLock ? "!" : "." );
uitextline3 +=
@@ -2385,103 +2073,119 @@ void TWorld::ModifyTGA(const std::string &dir)
}
*/
};
//---------------------------------------------------------------------------
std::string last; // zmienne używane w rekurencji
double shift = 0;
void TWorld::CreateE3D(std::string const &dir, bool dyn)
void TWorld::CreateE3D(std::string const &Path, bool Dynamic)
{ // rekurencyjna generowanie plików E3D
/* TODO: remove Borland file access stuff
TTrack *trk;
double at;
TSearchRec sr;
if (FindFirst(dir + "*.*", faDirectory | faArchive, sr) == 0)
{
do
{
if (sr.Name[1] != '.')
if ((sr.Attr & faDirectory)) // jeśli katalog, to rekurencja
CreateE3D(dir + sr.Name + "\\", dyn);
else if (dyn)
{
if (sr.Name.LowerCase().SubString(sr.Name.Length() - 3, 4) == ".mmd")
{
// konwersja pojazdów będzie ułomna, bo nie poustawiają się animacje na
// submodelach określonych w MMD
// TModelsManager::GetModel(AnsiString(dir+sr.Name).c_str(),true);
if (last != dir)
{ // utworzenie toru dla danego pojazdu
last = dir;
trk = TTrack::Create400m(1, shift);
shift += 10.0; // następny tor będzie deczko dalej, aby nie zabić FPS
at = 400.0;
// if (shift>1000) break; //bezpiecznik
std::string last; // zmienne używane w rekurencji
TTrack *trk{ nullptr };
double at{ 0.0 };
double shift{ 0.0 };
#ifdef _WINDOWS
std::string searchpattern( "*.*" );
::WIN32_FIND_DATA filedata;
::HANDLE search = ::FindFirstFile( ( Path + searchpattern ).c_str(), &filedata );
if( search == INVALID_HANDLE_VALUE ) { return; } // if nothing to do, bail out
do {
std::string filename = filedata.cFileName;
if( filedata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) {
// launch recursive search for sub-directories...
if( filename == "." ) { continue; }
if( filename == ".." ) { continue; }
CreateE3D( Path + filename + "\\", Dynamic );
}
else {
// process the file
if( filename.size() < 4 ) { continue; }
std::string const filetype = ToLower( filename.substr( filename.size() - 4, 4 ) );
if( filetype == ".mmd" ) {
if( false == Dynamic ) { continue; }
// konwersja pojazdów będzie ułomna, bo nie poustawiają się animacje na submodelach określonych w MMD
if( last != Path ) { // utworzenie toru dla danego pojazdu
last = Path;
trk = TTrack::Create400m( 1, shift );
shift += 10.0; // następny tor będzie deczko dalej, aby nie zabić FPS
at = 400.0;
}
TGroundNode *tmp = new TGroundNode();
tmp->DynamicObject = new TDynamicObject();
at -= tmp->DynamicObject->Init(
"",
Path.substr( 8, Path.size() - 9 ), // skip leading "dynamic/" and trailing slash
"none",
filename.substr( 0, filename.size() - 4 ),
trk,
at,
"nobody", 0.0, "none", 0.0, "", false, "" );
// po wczytaniu CHK zrobić pętlę po ładunkach, aby każdy z nich skonwertować
cParser loadparser( tmp->DynamicObject->MoverParameters->LoadAccepted ); // typy ładunków
std::string loadname;
loadparser.getTokens( 1, true, "," ); loadparser >> loadname;
while( loadname != "" ) {
if( ( true == FileExists( Path + loadname + ".t3d" ) )
&& ( false == FileExists( Path + loadname + ".e3d" ) ) ) {
// a nie ma jeszcze odpowiednika binarnego
at -= tmp->DynamicObject->Init(
"",
Path.substr( 8, Path.size() - 9 ), // skip leading "dynamic/" and trailing slash
"none",
filename.substr( 0, filename.size() - 4 ),
trk,
at,
"nobody", 0.0, "none", 1.0, loadname, false, "" );
}
TGroundNode *tmp = new TGroundNode();
tmp->DynamicObject = new TDynamicObject();
// Global::asCurrentTexturePath=dir; //pojazdy mają tekstury we własnych
// katalogach
at -= tmp->DynamicObject->Init(
"", string((dir.SubString(9, dir.Length() - 9)).c_str()), "none",
string(sr.Name.SubString(1, sr.Name.Length() - 4).c_str()), trk, at, "nobody", 0.0,
"none", 0.0, "", false, "");
// po wczytaniu CHK zrobić pętlę po ładunkach, aby każdy z nich skonwertować
AnsiString loads, load;
loads = AnsiString(tmp->DynamicObject->MoverParameters->LoadAccepted.c_str()); // typy ładunków
if (!loads.IsEmpty())
{
loads += ","; // przecinek na końcu
int i = loads.Pos(",");
while (i > 1)
{ // wypadało by sprawdzić, czy T3D ładunku jest
load = loads.SubString(1, i - 1);
if (FileExists(dir + load + ".t3d")) // o ile jest plik ładunku, bo
// inaczej nie ma to sensu
if (!FileExists(
dir + load +
".e3d")) // a nie ma jeszcze odpowiednika binarnego
at -= tmp->DynamicObject->Init(
"", dir.SubString(9, dir.Length() - 9).c_str(), "none",
sr.Name.SubString(1, sr.Name.Length() - 4).c_str(), trk, at,
"nobody", 0.0, "none", 1.0, load.c_str(), false, "");
loads.Delete(1, i); // usunięcie z następującym przecinkiem
i = loads.Pos(",");
}
}
if (tmp->DynamicObject->iCabs)
{ // jeśli ma jakąkolwiek kabinę
delete Train;
Train = new TTrain();
if (tmp->DynamicObject->iCabs & 1)
{
tmp->DynamicObject->MoverParameters->ActiveCab = 1;
Train->Init(tmp->DynamicObject, true);
}
if (tmp->DynamicObject->iCabs & 4)
{
tmp->DynamicObject->MoverParameters->ActiveCab = -1;
Train->Init(tmp->DynamicObject, true);
}
if (tmp->DynamicObject->iCabs & 2)
{
tmp->DynamicObject->MoverParameters->ActiveCab = 0;
Train->Init(tmp->DynamicObject, true);
}
}
Global::asCurrentTexturePath =
(szTexturePath); // z powrotem defaultowa sciezka do tekstur
loadname = "";
loadparser.getTokens( 1, true, "," ); loadparser >> loadname;
}
if( tmp->DynamicObject->iCabs ) { // jeśli ma jakąkolwiek kabinę
delete Train;
Train = new TTrain();
if( tmp->DynamicObject->iCabs & 1 ) {
tmp->DynamicObject->MoverParameters->ActiveCab = 1;
Train->Init( tmp->DynamicObject, true );
}
if( tmp->DynamicObject->iCabs & 4 ) {
tmp->DynamicObject->MoverParameters->ActiveCab = -1;
Train->Init( tmp->DynamicObject, true );
}
if( tmp->DynamicObject->iCabs & 2 ) {
tmp->DynamicObject->MoverParameters->ActiveCab = 0;
Train->Init( tmp->DynamicObject, true );
}
}
else if (sr.Name.LowerCase().SubString(sr.Name.Length() - 3, 4) == ".t3d")
{ // z modelami jest prościej
Global::asCurrentTexturePath = dir.c_str();
TModelsManager::GetModel(AnsiString(dir + sr.Name).c_str(), false);
}
} while (FindNext(sr) == 0);
FindClose(sr);
}
*/
// z powrotem defaultowa sciezka do tekstur
Global::asCurrentTexturePath = ( szTexturePath );
}
else if( filetype == ".t3d" ) {
// z modelami jest prościej
Global::asCurrentTexturePath = Path;
TModelsManager::GetModel( Path + filename, false );
}
}
} while( ::FindNextFile( search, &filedata ) );
// all done, clean up
::FindClose( search );
#endif
};
//---------------------------------------------------------------------------
void TWorld::CabChange(TDynamicObject *old, TDynamicObject *now)
{ // ewentualna zmiana kabiny użytkownikowi

View File

@@ -47,8 +47,10 @@ commanddescription_sequence Commands_descriptions = {
{ "reverserdecrease", command_target::vehicle },
{ "linebreakertoggle", command_target::vehicle },
{ "convertertoggle", command_target::vehicle },
{ "convertertogglelocal", command_target::vehicle },
{ "converteroverloadrelayreset", command_target::vehicle },
{ "compressortoggle", command_target::vehicle },
{ "compressortogglelocal", command_target::vehicle },
{ "motoroverloadrelaythresholdtoggle", command_target::vehicle },
{ "motoroverloadrelayreset", command_target::vehicle },
{ "notchingrelaytoggle", command_target::vehicle },

View File

@@ -42,8 +42,10 @@ enum class user_command {
reverserdecrease,
linebreakertoggle,
convertertoggle,
convertertogglelocal,
converteroverloadrelayreset,
compressortoggle,
compressortogglelocal,
motoroverloadrelaythresholdtoggle,
motoroverloadrelayreset,
notchingrelaytoggle,

View File

@@ -27,6 +27,9 @@ public:
calculate(glm::mat4 const &Projection, glm::mat4 const &Modelview);
// returns true if specified point is inside of the frustum
inline
bool
point_inside( glm::vec3 const &Point ) const { return point_inside( Point.x, Point.y, Point.z ); }
inline
bool
point_inside( float3 const &Point ) const { return point_inside( Point.x, Point.y, Point.z ); }
inline
@@ -36,6 +39,9 @@ public:
point_inside( float const X, float const Y, float const Z ) const;
// tests if the sphere is in frustum, returns the distance between origin and sphere centre
inline
float
sphere_inside( glm::vec3 const &Center, float const Radius ) const { return sphere_inside( Center.x, Center.y, Center.z, Radius ); }
inline
float
sphere_inside( float3 const &Center, float const Radius ) const { return sphere_inside( Center.x, Center.y, Center.z, Radius ); }
inline
@@ -45,6 +51,9 @@ public:
sphere_inside( float const X, float const Y, float const Z, float const Radius ) const;
// returns true if specified cube is inside of the frustum. Size = half of the length
inline
bool
cube_inside( glm::vec3 const &Center, float const Size ) const { return cube_inside( Center.x, Center.y, Center.z, Size ); }
inline
bool
cube_inside( float3 const &Center, float const Size ) const { return cube_inside( Center.x, Center.y, Center.z, Size ); }
inline

View File

@@ -228,10 +228,14 @@ keyboard_input::default_bindings() {
{ GLFW_KEY_M },
// convertertoggle
{ GLFW_KEY_X },
// convertertogglelocal
{ GLFW_KEY_X | keymodifier::shift },
// converteroverloadrelayreset
{ GLFW_KEY_N | keymodifier::control },
// compressortoggle
{ GLFW_KEY_C },
// compressortoggleloal
{ GLFW_KEY_C | keymodifier::shift },
// motoroverloadrelaythresholdtoggle
{ GLFW_KEY_F },
// motoroverloadrelayreset

View File

@@ -70,7 +70,7 @@ private:
bool m_shift{ false };
bool m_ctrl{ false };
bindings_cache m_bindingscache;
std::array<char, GLFW_KEY_LAST> m_keys;
std::array<char, GLFW_KEY_LAST + 1> m_keys;
};
//---------------------------------------------------------------------------

View File

@@ -3,6 +3,8 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LocalDebuggerWorkingDirectory>..\..\..\development\maszyna</LocalDebuggerWorkingDirectory>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
<LocalDebuggerCommandArguments>
</LocalDebuggerCommandArguments>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LocalDebuggerWorkingDirectory>..\..\Projects\maszyna</LocalDebuggerWorkingDirectory>

View File

@@ -82,9 +82,9 @@ typedef std::vector<opengl_stack> openglstack_array;
public:
// constructors:
opengl_matrices() {
m_stacks.emplace_back(); // projection
m_stacks.emplace_back(); // modelview
}
m_stacks.emplace_back(); // projection
m_stacks.emplace_back(); // modelview
}
// methods:
void

View File

@@ -142,9 +142,16 @@ opengl_renderer::Render() {
::glLoadIdentity();
if( World.InitPerformed() ) {
/*
World.Camera.SetMatrix();
m_camera.update_frustum();
*/
glm::dmat4 worldcamera;
World.Camera.SetMatrix( worldcamera );
m_camera.update_frustum( OpenGLMatrices.data( GL_PROJECTION ), worldcamera );
// frustum tests are performed in 'world space' but after we set up frustum
// we no longer need camera translation, only rotation
::glMultMatrixd( glm::value_ptr( glm::dmat4( glm::dmat3( worldcamera ))));
Render( &World.Environment );
Render( &World.Ground );
@@ -178,11 +185,12 @@ opengl_renderer::Render( world_environment *Environment ) {
/*
::glTranslatef( Global::pCameraPosition.x, Global::pCameraPosition.y, Global::pCameraPosition.z );
*/
/*
glm::mat4 worldcamera;
World.Camera.SetMatrix( worldcamera );
glLoadIdentity();
glMultMatrixf( glm::value_ptr( glm::mat4( glm::mat3( worldcamera ) ) ) );
*/
// setup fog
if( Global::fFogEnd > 0 ) {
// fog setup
@@ -294,12 +302,16 @@ opengl_renderer::Render( world_environment *Environment ) {
bool
opengl_renderer::Render( TGround *Ground ) {
/*
glDisable( GL_BLEND );
glAlphaFunc( GL_GREATER, 0.50f ); // im mniejsza wartość, tym większa ramka, domyślnie 0.1f
glEnable( GL_LIGHTING );
glColor3f( 1.0f, 1.0f, 1.0f );
::glEnable( GL_LIGHTING );
::glDisable( GL_BLEND );
::glAlphaFunc( GL_GREATER, 0.50f ); // im mniejsza wartość, tym większa ramka, domyślnie 0.1f
::glColor3f( 1.0f, 1.0f, 1.0f );
++TGroundRect::iFrameNumber; // zwięszenie licznika ramek (do usuwniania nadanimacji)
Update_Lights( Ground->m_lights );
/*
glm::vec3 const cameraposition( Global::pCameraPosition.x, Global::pCameraPosition.y, Global::pCameraPosition.z );
int const camerax = static_cast<int>( std::floor( cameraposition.x / 1000.0f ) + iNumRects / 2 );
int const cameraz = static_cast<int>( std::floor( cameraposition.z / 1000.0f ) + iNumRects / 2 );
@@ -310,22 +322,13 @@ opengl_renderer::Render( TGround *Ground ) {
for( int column = originx; column <= originx + segmentcount; ++column ) {
for( int row = originz; row <= originz + segmentcount; ++row ) {
auto &rectangle = Ground->Rects[ column ][ row ];
if( m_camera.visible( rectangle.m_area ) ) {
rectangle.RenderDL();
auto *rectangle = &Ground->Rects[ column ][ row ];
if( m_camera.visible( rectangle->m_area ) ) {
Render( rectangle );
}
}
}
*/
::glEnable( GL_LIGHTING );
::glDisable( GL_BLEND );
::glAlphaFunc( GL_GREATER, 0.50f ); // im mniejsza wartość, tym większa ramka, domyślnie 0.1f
::glColor3f( 1.0f, 1.0f, 1.0f );
++TGroundRect::iFrameNumber; // zwięszenie licznika ramek (do usuwniania nadanimacji)
Update_Lights( Ground->m_lights );
Ground->CameraDirection.x = std::sin( Global::pCameraRotation ); // wektor kierunkowy
Ground->CameraDirection.z = std::cos( Global::pCameraRotation );
TGroundNode *node;
@@ -354,6 +357,16 @@ opengl_renderer::Render( TGround *Ground ) {
}
}
// renderowanie progresywne - zależne od FPS oraz kierunku patrzenia
// pre-calculate camera view span
double const fieldofviewcosine =
std::cos(
std::max(
// vertical...
Global::FieldOfView / Global::ZoomFactor,
// ...or horizontal, whichever is bigger
Global::FieldOfView / Global::ZoomFactor
* std::max( 1.0f, (float)Global::ScreenWidth ) / std::max( 1.0f, (float)Global::ScreenHeight ) ) );
Ground->iRendered = 0; // ilość renderowanych sektorów
Math3D::vector3 direction;
for( k = 0; k < Global::iSegmentsRendered; ++k ) // sektory w kolejności odległości
@@ -369,18 +382,12 @@ opengl_renderer::Render( TGround *Ground ) {
if( Math3D::LengthSquared3( direction ) > 5 ) // te blisko są zawsze wyświetlane
{
direction = Math3D::SafeNormalize( direction ); // normalizacja
if( Ground->CameraDirection.x * direction.x + Ground->CameraDirection.z * direction.z < 0.55 )
if( Ground->CameraDirection.x * direction.x + Ground->CameraDirection.z * direction.z < 0.5 )
continue; // pomijanie sektorów poza kątem patrzenia
}
// kwadrat kilometrowy nie zawsze, bo szkoda FPS
if( Global::bUseVBO ) {
// vbo render path
Ground->Rects[ ( i + c ) / iNumSubRects ][ ( j + r ) / iNumSubRects ].RenderVBO();
}
else {
// display list render path
Ground->Rects[ ( i + c ) / iNumSubRects ][ ( j + r ) / iNumSubRects ].RenderDL();
}
Render( &Ground->Rects[ ( i + c ) / iNumSubRects ][ ( j + r ) / iNumSubRects ] );
if( ( tmp = Ground->FastGetSubRect( i + c, j + r ) ) != nullptr ) {
if( tmp->iNodeCount ) {
// o ile są jakieś obiekty, bo po co puste sektory przelatywać
@@ -389,29 +396,149 @@ opengl_renderer::Render( TGround *Ground ) {
}
} while( ( i < 0 ) || ( j < 0 ) ); // są 4 przypadki, oprócz i=j=0
}
// dodać renderowanie terenu z E3D - jedno VBO jest używane dla całego modelu, chyba że jest ich więcej
if( Global::bUseVBO ) {
if( Global::pTerrainCompact ) {
Global::pTerrainCompact->TerrainRenderVBO( TGroundRect::iFrameNumber );
}
}
// renderowanie nieprzezroczystych
for( i = 0; i < Ground->iRendered; ++i ) {
if( Global::bUseVBO ) {
// vbo render path
Ground->pRendered[ i ]->RenderVBO();
}
else {
// display list render path
Ground->pRendered[ i ]->RenderDL();
}
Render( Ground->pRendered[ i ] );
}
// regular render takes care of all solid geometry present in the scene, thus we can launch alpha parts render here
return Render_Alpha( Ground );
}
// TODO: unify ground render code, until then old version is in place
#define EU07_USE_OLD_RENDERCODE
bool
opengl_renderer::Render( TGroundRect *Groundcell ) {
::glPushMatrix();
auto const &cellorigin = Groundcell->m_area.center;
// TODO: unify all math objects
auto const originoffset = Math3D::vector3( cellorigin.x, cellorigin.y, cellorigin.z ) - Global::pCameraPosition;
::glTranslated( originoffset.x, originoffset.y, originoffset.z );
bool result{ false }; // will be true if we do any rendering
// TODO: unify render paths
if( Global::bUseVBO ) {
if ( Groundcell->iLastDisplay != Groundcell->iFrameNumber)
{ // tylko jezeli dany kwadrat nie był jeszcze renderowany
Groundcell->LoadNodes(); // ewentualne tworzenie siatek
if ( Groundcell->nRenderRect && Groundcell->StartVBO())
{
for (TGroundNode *node = Groundcell->nRenderRect; node; node = node->nNext3) // następny tej grupy
#ifdef EU07_USE_OLD_RENDERCODE
node->RaRenderVBO(); // nieprzezroczyste trójkąty kwadratu kilometrowego
#else
Render( node ); // nieprzezroczyste trójkąty kwadratu kilometrowego
#endif
Groundcell->EndVBO();
Groundcell->iLastDisplay = Groundcell->iFrameNumber;
result = true;
}
if ( Groundcell->nTerrain)
Groundcell->nTerrain->smTerrain->iVisible = Groundcell->iFrameNumber; // ma się wyświetlić w tej ramce
}
::glPopMatrix();
}
else {
#ifdef EU07_USE_OLD_RENDERCODE
if (Groundcell->iLastDisplay != Groundcell->iFrameNumber)
{ // tylko jezeli dany kwadrat nie był jeszcze renderowany
// for (TGroundNode* node=pRender;node;node=node->pNext3)
// node->Render(); //nieprzezroczyste trójkąty kwadratu kilometrowego
if ( Groundcell->nRender)
{ //łączenie trójkątów w jedną listę - trochę wioska
if (!Groundcell->nRender->DisplayListID || ( Groundcell->nRender->iVersion != Global::iReCompile))
{ // jeżeli nie skompilowany, kompilujemy wszystkie trójkąty w jeden
Groundcell->nRender->fSquareRadius = 5000.0 * 5000.0; // aby agregat nigdy nie znikał
Groundcell->nRender->DisplayListID = glGenLists(1);
glNewList( Groundcell->nRender->DisplayListID, GL_COMPILE);
Groundcell->nRender->iVersion = Global::iReCompile; // aktualna wersja siatek
auto const origin = Math3D::vector3( Groundcell->m_area.center.x, Groundcell->m_area.center.y, Groundcell->m_area.center.z );
for (TGroundNode *node = Groundcell->nRender; node; node = node->nNext3) // następny tej grupy
node->Compile(origin, true);
glEndList();
}
Render( Groundcell->nRender ); // nieprzezroczyste trójkąty kwadratu kilometrowego
}
// submodels geometry is world-centric, so at least for the time being we need to pop the stack early
::glPopMatrix();
if( Groundcell->nRootMesh ) {
Render( Groundcell->nRootMesh );
}
Groundcell->iLastDisplay = Groundcell->iFrameNumber; // drugi raz nie potrzeba
result = true;
}
else {
::glPopMatrix();
}
#else
if( iLastDisplay != iFrameNumber ) { // tylko jezeli dany kwadrat nie był jeszcze renderowany
LoadNodes(); // ewentualne tworzenie siatek
if( nRenderRect ) {
for( TGroundNode *node = nRenderRect; node; node = node->nNext3 ) // następny tej grupy
Render( node ); // nieprzezroczyste trójkąty kwadratu kilometrowego
}
if( nRootMesh )
Render( nRootMesh );
iLastDisplay = iFrameNumber;
}
#endif
}
return result;
}
#undef EU07_USE_OLD_RENDERCODE
bool
opengl_renderer::Render( TSubRect *Groundsubcell ) {
Groundsubcell->RaAnimate(); // przeliczenia animacji torów w sektorze
TGroundNode *node;
// nieprzezroczyste obiekty terenu
if( Global::bUseVBO ) {
// vbo render path
if( Groundsubcell->StartVBO() ) {
for( node = Groundsubcell->nRenderRect; node; node = node->nNext3 ) {
if( node->iVboPtr >= 0 ) {
Render( node );
}
}
Groundsubcell->EndVBO();
}
}
else {
// display list render path
for( node = Groundsubcell->nRenderRect; node; node = node->nNext3 ) {
Render( node ); // nieprzezroczyste obiekty terenu
}
}
// nieprzezroczyste obiekty (oprócz pojazdów)
for( node = Groundsubcell->nRender; node; node = node->nNext3 )
Render( node );
// nieprzezroczyste z mieszanych modeli
for( node = Groundsubcell->nRenderMixed; node; node = node->nNext3 )
Render( node );
// nieprzezroczyste fragmenty pojazdów na torach
for( int j = 0; j < Groundsubcell->iTracks; ++j )
Groundsubcell->tTracks[ j ]->RenderDyn();
#ifdef EU07_SCENERY_EDITOR
// memcells
if( DebugModeFlag ) {
for( auto const memcell : m_memcells ) {
memcell->RenderDL();
}
}
#endif
return true;
}
bool
@@ -422,8 +549,12 @@ opengl_renderer::Render( TGroundNode *Node ) {
switch (Node->iType)
{ // obiekty renderowane niezależnie od odległości
case TP_SUBMODEL:
::glPushMatrix();
auto const originoffset = Node->pCenter - Global::pCameraPosition;
::glTranslated( originoffset.x, originoffset.y, originoffset.z );
TSubModel::fSquareDist = 0;
Render( Node->smTerrain );
::glPopMatrix();
return true;
}
@@ -436,22 +567,30 @@ opengl_renderer::Render( TGroundNode *Node ) {
switch (Node->iType)
{
case TP_TRACK: {
if( Global::bUseVBO && ( Node->iNumVerts <= 0 ) ) {
return false;
}
// setup
::glPushMatrix();
auto const originoffset = Node->m_rootposition - Global::pCameraPosition;
::glTranslated( originoffset.x, originoffset.y, originoffset.z );
// TODO: unify the render code after generic buffers are in place
if( Global::bUseVBO ) {
if( Node->iNumVerts ) {
Node->pTrack->RaRenderVBO( Node->iVboPtr );
}
else {
return false;
}
// vbo render path
Node->pTrack->RaRenderVBO( Node->iVboPtr );
}
else {
// display list render path
Node->pTrack->Render();
}
// post-render cleanup
::glPopMatrix();
return true;
}
case TP_MODEL: {
Node->Model->Render( &Node->pCenter );
Node->Model->Render( Node->pCenter - Global::pCameraPosition );
return true;
}
case TP_MEMCELL: {
@@ -468,7 +607,7 @@ opengl_renderer::Render( TGroundNode *Node ) {
// additional setup for display lists
if( ( Node->DisplayListID == 0 )
|| ( Node->iVersion != Global::iReCompile ) ) { // Ra: wymuszenie rekompilacji
Node->Compile();
Node->Compile(Node->m_rootposition);
if( Global::bManageNodes )
ResourceManager::Register( Node );
};
@@ -492,11 +631,16 @@ opengl_renderer::Render( TGroundNode *Node ) {
// render
// TODO: unify the render code after generic buffers are in place
if( Global::bUseVBO ) {
::glPushMatrix();
auto const originoffset = Node->m_rootposition - Global::pCameraPosition;
::glTranslated( originoffset.x, originoffset.y, originoffset.z );
::glDrawArrays( Node->iType, Node->iVboPtr, Node->iNumPts );
::glPopMatrix();
}
else {
::glCallList( Node->DisplayListID );
}
// post-render cleanup
return true;
}
else {
@@ -505,6 +649,11 @@ opengl_renderer::Render( TGroundNode *Node ) {
}
else {
// GL_TRIANGLE etc
if( ( Global::bUseVBO ?
Node->iVboPtr < 0 :
Node->DisplayListID == 0 ) ) {
return false;
}
// setup
::glColor3ub(
static_cast<GLubyte>( Node->Diffuse[ 0 ] ),
@@ -517,22 +666,17 @@ opengl_renderer::Render( TGroundNode *Node ) {
// TODO: unify the render code after generic buffers are in place
if( Global::bUseVBO ) {
// vbo render path
if( Node->iVboPtr >= 0 ) {
::glDrawArrays( Node->iType, Node->iVboPtr, Node->iNumVerts );
}
else {
return false;
}
::glPushMatrix();
auto const originoffset = Node->m_rootposition - Global::pCameraPosition;
::glTranslated( originoffset.x, originoffset.y, originoffset.z );
::glDrawArrays( Node->iType, Node->iVboPtr, Node->iNumVerts );
::glPopMatrix();
}
else {
// display list render path
if( Node->DisplayListID != 0 ) {
::glCallList( Node->DisplayListID );
}
else {
return false;
}
::glCallList( Node->DisplayListID );
}
// post-render cleanup
return true;
}
}
@@ -550,11 +694,11 @@ opengl_renderer::Render( TDynamicObject *Dynamic ) {
// setup
TSubModel::iInstance = ( size_t )this; //żeby nie robić cudzych animacji
double squaredistance = SquareMagnitude( ( Global::pCameraPosition - Dynamic->vPosition ) / Global::ZoomFactor );
auto const originoffset = Dynamic->vPosition - Global::pCameraPosition;
double const squaredistance = SquareMagnitude( originoffset / Global::ZoomFactor );
Dynamic->ABuLittleUpdate( squaredistance ); // ustawianie zmiennych submodeli dla wspólnego modelu
::glPushMatrix();
/*
if( Dynamic == Global::pUserDynamic ) {
//specjalne ustawienie, aby nie trzęsło
//tu trzeba by ustawić animacje na modelu zewnętrznym
@@ -563,7 +707,8 @@ opengl_renderer::Render( TDynamicObject *Dynamic ) {
}
else
::glTranslated( Dynamic->vPosition.x, Dynamic->vPosition.y, Dynamic->vPosition.z ); // standardowe przesunięcie względem początku scenerii
*/
::glTranslated( originoffset.x, originoffset.y, originoffset.z );
::glMultMatrixd( Dynamic->mMatrix.getArray() );
if( Dynamic->fShade > 0.0f ) {
@@ -666,7 +811,8 @@ opengl_renderer::Render( TModel3d *Model, material_data const *Material, Math3D:
if( Angle.z != 0.0 )
::glRotated( Angle.z, 0.0, 0.0, 1.0 );
auto const result = Render( Model, Material, SquareMagnitude( Position - Global::GetCameraPosition() ) );
// auto const result = Render( Model, Material, SquareMagnitude( Position / Global::ZoomFactor ) ); // position is effectively camera offset
auto const result = Render( Model, Material, SquareMagnitude( Position ) ); // position is effectively camera offset
::glPopMatrix();
@@ -864,14 +1010,7 @@ opengl_renderer::Render_Alpha( TGround *Ground ) {
}
for( int i = Ground->iRendered - 1; i >= 0; --i ) // od najdalszych
{ // renderowanie przezroczystych modeli oraz pojazdów
if( Global::bUseVBO ) {
// vbo render path
Ground->pRendered[ i ]->RenderAlphaVBO();
}
else {
// display list render path
Ground->pRendered[ i ]->RenderAlphaDL();
}
Render_Alpha( Ground->pRendered[ i ] );
}
::glDisable( GL_LIGHTING ); // linie nie powinny świecić
@@ -899,6 +1038,20 @@ opengl_renderer::Render_Alpha( TGround *Ground ) {
return true;
}
bool
opengl_renderer::Render_Alpha( TSubRect *Groundsubcell ) {
TGroundNode *node;
for( node = Groundsubcell->nRenderMixed; node; node = node->nNext3 )
Render_Alpha( node ); // przezroczyste z mieszanych modeli
for( node = Groundsubcell->nRenderAlpha; node; node = node->nNext3 )
Render_Alpha( node ); // przezroczyste modele
for( int j = 0; j < Groundsubcell->iTracks; ++j )
Groundsubcell->tTracks[ j ]->RenderDynAlpha(); // przezroczyste fragmenty pojazdów na torach
return true;
}
// NOTE: legacy render system switch
#define _PROBLEND
@@ -932,12 +1085,19 @@ opengl_renderer::Render_Alpha( TGroundNode *Node ) {
case TP_TRACTION: {
// TODO: unify the render code after generic buffers are in place
if( Node->bVisible ) {
// setup
::glPushMatrix();
auto const originoffset = Node->m_rootposition - Global::pCameraPosition;
::glTranslated( originoffset.x, originoffset.y, originoffset.z );
// render
if( Global::bUseVBO ) {
Node->hvTraction->RenderVBO( distancesquared, Node->iVboPtr );
}
else {
Node->hvTraction->RenderDL( distancesquared );
Node->hvTraction->RenderDL( distancesquared, Node->m_rootposition );
}
// post-render cleanup
::glPopMatrix();
return true;
}
else {
@@ -945,7 +1105,7 @@ opengl_renderer::Render_Alpha( TGroundNode *Node ) {
}
}
case TP_MODEL: {
Node->Model->RenderAlpha( &Node->pCenter );
Node->Model->RenderAlpha( Node->pCenter - Global::pCameraPosition );
return true;
}
}
@@ -966,7 +1126,7 @@ opengl_renderer::Render_Alpha( TGroundNode *Node ) {
// additional setup for display lists
if( ( Node->DisplayListID == 0 )
|| ( Node->iVersion != Global::iReCompile ) ) { // Ra: wymuszenie rekompilacji
Node->Compile();
Node->Compile(Node->m_rootposition);
if( Global::bManageNodes )
ResourceManager::Register( Node );
};
@@ -980,6 +1140,9 @@ opengl_renderer::Render_Alpha( TGroundNode *Node ) {
// wszelkie linie są rysowane na samym końcu
if( Node->iNumPts ) {
// setup
::glPushMatrix();
auto const originoffset = Node->m_rootposition - Global::pCameraPosition;
::glTranslated( originoffset.x, originoffset.y, originoffset.z );
// w zaleznosci od koloru swiatla
::glColor4ub(
static_cast<GLubyte>( std::floor( Node->Diffuse[ 0 ] * Global::DayLight.ambient[ 0 ] ) ),
@@ -997,12 +1160,18 @@ opengl_renderer::Render_Alpha( TGroundNode *Node ) {
else {
::glCallList( Node->DisplayListID );
}
// post-render cleanup
::glPopMatrix();
result = true;
}
}
else {
// GL_TRIANGLE etc
// setup
::glPushMatrix();
auto const originoffset = Node->m_rootposition - Global::pCameraPosition;
::glTranslated( originoffset.x, originoffset.y, originoffset.z );
::glColor3ub(
static_cast<GLubyte>( Node->Diffuse[ 0 ] ),
static_cast<GLubyte>( Node->Diffuse[ 1 ] ),
@@ -1024,8 +1193,10 @@ opengl_renderer::Render_Alpha( TGroundNode *Node ) {
::glCallList( Node->DisplayListID );
result = true;
}
// post-render cleanup
::glPopMatrix();
}
// post-render cleanup
#ifdef _PROBLEND
if( ( Node->PROBLEND ) ) // sprawdza, czy w nazwie nie ma @ //Q: 13122011 - Szociu: 27012012
{
@@ -1049,17 +1220,19 @@ opengl_renderer::Render_Alpha( TDynamicObject *Dynamic ) {
// setup
TSubModel::iInstance = ( size_t )this; //żeby nie robić cudzych animacji
double squaredistance = SquareMagnitude( ( Global::pCameraPosition - Dynamic->vPosition ) / Global::ZoomFactor );
auto const originoffset = Dynamic->vPosition - Global::pCameraPosition;
double const squaredistance = SquareMagnitude( originoffset / Global::ZoomFactor );
Dynamic->ABuLittleUpdate( squaredistance ); // ustawianie zmiennych submodeli dla wspólnego modelu
::glPushMatrix();
/*
if( Dynamic == Global::pUserDynamic ) { // specjalne ustawienie, aby nie trzęsło
::glLoadIdentity(); // zacząć od macierzy jedynkowej
Global::pCamera->SetCabMatrix( Dynamic->vPosition ); // specjalne ustawienie kamery
}
else
::glTranslated( Dynamic->vPosition.x, Dynamic->vPosition.y, Dynamic->vPosition.z ); // standardowe przesunięcie względem początku scenerii
*/
::glTranslated( originoffset.x, originoffset.y, originoffset.z );
::glMultMatrixd( Dynamic->mMatrix.getArray() );
if( Dynamic->fShade > 0.0f ) {
@@ -1161,7 +1334,8 @@ opengl_renderer::Render_Alpha( TModel3d *Model, material_data const *Material, M
if( Angle.z != 0.0 )
::glRotated( Angle.z, 0.0, 0.0, 1.0 );
auto const result = Render_Alpha( Model, Material, SquareMagnitude( Position - Global::GetCameraPosition() ) );
// auto const result = Render_Alpha( Model, Material, SquareMagnitude( Position / Global::ZoomFactor ) ); // position is effectively camera offset
auto const result = Render_Alpha( Model, Material, SquareMagnitude( Position ) ); // position is effectively camera offset
::glPopMatrix();
@@ -1400,7 +1574,7 @@ opengl_renderer::Update_Lights( light_array const &Lights ) {
continue;
}
// if the light passed tests so far, it's good enough
renderlight->set_position( scenelight.position );
renderlight->set_position( scenelight.position - Global::pCameraPosition );
renderlight->direction = scenelight.direction;
auto luminance = Global::fLuminance; // TODO: adjust this based on location, e.g. for tunnels

View File

@@ -94,7 +94,7 @@ public:
update_frustum() { m_frustum.calculate(); }
inline
void
update_frustum(glm::mat4 &Projection, glm::mat4 &Modelview) { m_frustum.calculate(Projection, Modelview); }
update_frustum(glm::mat4 const &Projection, glm::mat4 const &Modelview) { m_frustum.calculate(Projection, Modelview); }
bool
visible( bounding_area const &Area ) const;
bool
@@ -124,6 +124,10 @@ public:
Render( world_environment *Environment );
bool
Render( TGround *Ground );
bool
Render( TGroundRect *Groundcell );
bool
Render( TSubRect *Groundsubcell );
bool
Render( TGroundNode *Node );
bool
@@ -138,6 +142,8 @@ public:
Render( TMemCell *Memcell );
bool
Render_Alpha( TGround *Ground );
bool
Render_Alpha( TSubRect *Groundsubcell );
bool
Render_Alpha( TGroundNode *Node );
bool

27
sky.cpp
View File

@@ -31,39 +31,18 @@ void TSky::Render( float3 const &Tint )
{
if (mdCloud)
{ // jeśli jest model nieba
#ifdef EU07_USE_OLD_LIGHTING_MODEL
// TODO: re-implement this
glLightfv(GL_LIGHT0, GL_POSITION, lightPos);
#else
// setup
::glEnable( GL_LIGHTING );
GfxRenderer.Disable_Lights();
::glLightModelfv( GL_LIGHT_MODEL_AMBIENT, &Tint.x );
#endif
#ifdef EU07_USE_OLD_RENDERCODE
if( Global::bUseVBO )
{ // renderowanie z VBO
mdCloud->RaRender( 100, 0 );
mdCloud->RaRenderAlpha(100, 0);
}
else
{ // renderowanie z Display List
mdCloud->Render(100, 0);
mdCloud->RenderAlpha(100, 0);
}
#else
// render
GfxRenderer.Render( mdCloud, nullptr, 100.0 );
GfxRenderer.Render_Alpha( mdCloud, nullptr, 100.0 );
#endif
#ifdef EU07_USE_OLD_LIGHTING_MODEL
glPopMatrix();
// TODO: re-implement this
glLightfv(GL_LIGHT0, GL_POSITION, Global::lightPos);
#else
// post-render cleanup
GLfloat noambient[] = { 0.0f, 0.0f, 0.0f, 1.0f };
::glLightModelfv( GL_LIGHT_MODEL_AMBIENT, noambient );
::glEnable( GL_LIGHT0 ); // other lights will be enabled during lights update
::glDisable( GL_LIGHTING );
#endif
}
};

View File

@@ -14,23 +14,16 @@ cStars::init() {
void
cStars::render() {
// setup
::glPushMatrix();
::glRotatef( m_latitude, 1.0f, 0.0f, 0.0f ); // ustawienie osi OY na północ
::glRotatef( -std::fmod( (float)Global::fTimeAngleDeg, 360.0f ), 0.0f, 1.0f, 0.0f ); // obrót dobowy osi OX
::glPointSize( 2.0f );
#ifdef EU07_USE_OLD_RENDERCODE
if( Global::bUseVBO ) {
m_stars.RaRender( 1.0, 0 );
}
else {
m_stars.Render( 1.0 );
}
#else
// render
GfxRenderer.Render( &m_stars, nullptr, 1.0 );
#endif
// post-render cleanup
::glPointSize( 3.0f );
::glPopMatrix();

View File

@@ -11,17 +11,6 @@ http://mozilla.org/MPL/2.0/.
#include "stdafx.h"
#define SafeDelete(a) \
{ \
delete (a); \
a = nullptr; \
}
#define SafeDeleteArray(a) \
{ \
delete[](a); \
a = nullptr; \
}
#define sign(x) ((x) < 0 ? -1 : ((x) > 0 ? 1 : 0))
#define DegToRad(a) ((M_PI / 180.0) * (a)) //(a) w nawiasie, bo może być dodawaniem
@@ -31,9 +20,22 @@ http://mozilla.org/MPL/2.0/.
#define asSceneryPath std::string("scenery\\")
#define szSceneryPath "scenery\\"
#define szTexturePath "textures\\"
#define szSoundPath "sounds\\"
#define MAKE_ID4(a,b,c,d) (((std::uint32_t)(d)<<24)|((std::uint32_t)(c)<<16)|((std::uint32_t)(b)<<8)|(std::uint32_t)(a))
template <typename _Type>
void SafeDelete( _Type &Pointer ) {
delete Pointer;
Pointer = nullptr;
}
template <typename _Type>
void SafeDeleteArray( _Type &Pointer ) {
delete[] Pointer;
Pointer = nullptr;
}
template <typename _Type>
_Type
clamp( _Type const Value, _Type const Min, _Type const Max ) {

View File

@@ -1,5 +1,5 @@
#pragma once
#define VERSION_MAJOR 17
#define VERSION_MINOR 517
#define VERSION_MINOR 602
#define VERSION_REVISION 0

View File

@@ -17,26 +17,7 @@ http://mozilla.org/MPL/2.0/.
//-----------------------------------------------------------------------------
#include "stdafx.h"
#include "WavRead.h"
//-----------------------------------------------------------------------------
// Defines, constants, and global variables
//-----------------------------------------------------------------------------
#define SAFE_DELETE(p) \
{ \
if (p) \
{ \
delete (p); \
(p) = NULL; \
} \
}
#define SAFE_RELEASE(p) \
{ \
if (p) \
{ \
(p)->Release(); \
(p) = NULL; \
} \
}
#include "usefull.h"
//-----------------------------------------------------------------------------
// Name: ReadMMIO()
@@ -122,13 +103,13 @@ HRESULT ReadMMIO(HMMIO hmmioIn, MMCKINFO *pckInRIFF, WAVEFORMATEX **ppwfxInfo)
// so the data can be easily read with WaveReadFile. Returns 0 if
// successful, the error code if not.
//-----------------------------------------------------------------------------
HRESULT WaveOpenFile(CHAR *strFileName, HMMIO *phmmioIn, WAVEFORMATEX **ppwfxInfo,
HRESULT WaveOpenFile( std::string const &Filename, HMMIO *phmmioIn, WAVEFORMATEX **ppwfxInfo,
MMCKINFO *pckInRIFF)
{
HRESULT hr;
HMMIO hmmioIn = NULL;
if (NULL == (hmmioIn = mmioOpen(strFileName, NULL, MMIO_ALLOCBUF | MMIO_READ)))
if (NULL == (hmmioIn = mmioOpen(const_cast<char*>(Filename.c_str()), NULL, MMIO_ALLOCBUF | MMIO_READ)))
return E_FAIL;
if (FAILED(hr = ReadMMIO(hmmioIn, pckInRIFF, ppwfxInfo)))
@@ -228,20 +209,20 @@ CWaveSoundRead::CWaveSoundRead()
CWaveSoundRead::~CWaveSoundRead()
{
Close();
SAFE_DELETE(m_pwfx);
SafeDelete(m_pwfx);
}
//-----------------------------------------------------------------------------
// Name: Open()
// Desc: Opens a wave file for reading
//-----------------------------------------------------------------------------
HRESULT CWaveSoundRead::Open(CHAR *strFilename)
HRESULT CWaveSoundRead::Open(std::string const &Filename)
{
SAFE_DELETE(m_pwfx);
SafeDelete(m_pwfx);
HRESULT hr;
if (FAILED(hr = WaveOpenFile(strFilename, &m_hmmioIn, &m_pwfx, &m_ckInRiff)))
if (FAILED(hr = WaveOpenFile(Filename, &m_hmmioIn, &m_pwfx, &m_ckInRiff)))
return hr;
if (FAILED(hr = Reset()))
@@ -276,6 +257,8 @@ HRESULT CWaveSoundRead::Read(UINT nSizeToRead, BYTE *pbData, UINT *pnSizeRead)
//-----------------------------------------------------------------------------
HRESULT CWaveSoundRead::Close()
{
mmioClose(m_hmmioIn, 0);
if( m_hmmioIn != NULL ) {
mmioClose( m_hmmioIn, 0 );
}
return S_OK;
}

View File

@@ -15,12 +15,12 @@ http://mozilla.org/MPL/2.0/.
//
// Copyright (c) 1999 Microsoft Corp. All rights reserved.
//-----------------------------------------------------------------------------
#ifndef WAVE_READ_H
#define WAVE_READ_H
#pragma once
#include <mmsystem.h>
#include <string>
HRESULT WaveOpenFile(CHAR *strFileName, HMMIO *phmmioIn, WAVEFORMATEX **ppwfxInfo,
HRESULT WaveOpenFile(std::string const &Filename, HMMIO *phmmioIn, WAVEFORMATEX **ppwfxInfo,
MMCKINFO *pckInRIFF);
HRESULT WaveStartDataRead(HMMIO *phmmioIn, MMCKINFO *pckIn, MMCKINFO *pckInRIFF);
HRESULT WaveReadFile(HMMIO hmmioIn, UINT cbRead, BYTE *pbDest, MMCKINFO *pckIn, UINT *cbActualRead);
@@ -33,7 +33,7 @@ class CWaveSoundRead
{
public:
WAVEFORMATEX *m_pwfx; // Pointer to WAVEFORMATEX structure
HMMIO m_hmmioIn; // MM I/O handle for the WAVE
HMMIO m_hmmioIn{ NULL }; // MM I/O handle for the WAVE
MMCKINFO m_ckIn; // Multimedia RIFF chunk
MMCKINFO m_ckInRiff; // Use in opening a WAVE file
@@ -41,10 +41,8 @@ class CWaveSoundRead
CWaveSoundRead();
~CWaveSoundRead();
HRESULT Open(CHAR *strFilename);
HRESULT Open(std::string const &Filename);
HRESULT Reset();
HRESULT Read(UINT nSizeToRead, BYTE *pbData, UINT *pnSizeRead);
HRESULT Close();
};
#endif WAVE_READ_H