mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-07-24 00:49:18 +02:00
Merge branch 'tmj-dev' into milek-dev
This commit is contained in:
@@ -414,11 +414,9 @@ void TAnimContainer::EventAssign(basic_event *ev)
|
|||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
TAnimModel::TAnimModel( scene::node_data const &Nodedata ) : basic_node( Nodedata ) {
|
TAnimModel::TAnimModel( scene::node_data const &Nodedata ) : basic_node( Nodedata ) {
|
||||||
// TODO: wrap these in a tuple and move to underlying model
|
|
||||||
for( int index = 0; index < iMaxNumLights; ++index ) {
|
m_lightcolors.fill( glm::vec3{ -1.f } );
|
||||||
LightsOn[ index ] = LightsOff[ index ] = nullptr; // normalnie nie ma
|
m_lightopacities.fill( 1.f );
|
||||||
lsLights[ index ] = ls_Off; // a jeśli są, to wyłączone
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TAnimModel::~TAnimModel()
|
TAnimModel::~TAnimModel()
|
||||||
@@ -456,7 +454,7 @@ bool TAnimModel::Init(std::string const &asName, std::string const &asReplacable
|
|||||||
bool TAnimModel::Load(cParser *parser, bool ter)
|
bool TAnimModel::Load(cParser *parser, bool ter)
|
||||||
{ // rozpoznanie wpisu modelu i ustawienie świateł
|
{ // rozpoznanie wpisu modelu i ustawienie świateł
|
||||||
std::string name = parser->getToken<std::string>();
|
std::string name = parser->getToken<std::string>();
|
||||||
std::string texture = parser->getToken<std::string>(); // tekstura (zmienia na małe)
|
std::string texture = parser->getToken<std::string>( false ); // tekstura (zmienia na małe)
|
||||||
replace_slashes( name );
|
replace_slashes( name );
|
||||||
if (!Init( name, texture ))
|
if (!Init( name, texture ))
|
||||||
{
|
{
|
||||||
@@ -499,20 +497,44 @@ bool TAnimModel::Load(cParser *parser, bool ter)
|
|||||||
if (LightsOn[i] || LightsOff[i]) // Ra: zlikwidowałem wymóg istnienia obu
|
if (LightsOn[i] || LightsOff[i]) // Ra: zlikwidowałem wymóg istnienia obu
|
||||||
iNumLights = i + 1;
|
iNumLights = i + 1;
|
||||||
|
|
||||||
if ( parser->getToken<std::string>() == "lights" )
|
std::string token;
|
||||||
{
|
do {
|
||||||
int i = 0;
|
token = parser->getToken<std::string>();
|
||||||
std::string token = parser->getToken<std::string>();
|
|
||||||
while( ( token != "" )
|
|
||||||
&& ( token != "endmodel" ) ) {
|
|
||||||
|
|
||||||
LightSet( i, std::stof( token ) ); // stan światła jest liczbą z ułamkiem
|
if( token == "lights" ) {
|
||||||
++i;
|
auto i{ 0 };
|
||||||
|
while( ( false == ( token = parser->getToken<std::string>() ).empty() )
|
||||||
|
&& ( token != "lightcolors" )
|
||||||
|
&& ( token != "endmodel" ) ) {
|
||||||
|
|
||||||
|
if( i < iNumLights ) {
|
||||||
|
// stan światła jest liczbą z ułamkiem
|
||||||
|
LightSet( i, std::stof( token ) );
|
||||||
|
}
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( token == "lightcolors" ) {
|
||||||
|
auto i{ 0 };
|
||||||
|
while( ( false == ( token = parser->getToken<std::string>() ).empty() )
|
||||||
|
&& ( token != "lights" )
|
||||||
|
&& ( token != "endmodel" ) ) {
|
||||||
|
|
||||||
|
if( ( i < iNumLights )
|
||||||
|
&& ( token != "-1" ) ) { // -1 leaves the default color intact
|
||||||
|
auto const lightcolor { std::stoi( token, 0, 16 ) };
|
||||||
|
m_lightcolors[i] = {
|
||||||
|
( ( lightcolor >> 16 ) & 0xff ) / 255.f,
|
||||||
|
( ( lightcolor >> 8 ) & 0xff ) / 255.f,
|
||||||
|
( ( lightcolor ) & 0xff ) / 255.f };
|
||||||
|
}
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while( ( false == token.empty() )
|
||||||
|
&& ( token != "endmodel" ) );
|
||||||
|
|
||||||
token = "";
|
|
||||||
parser->getTokens(); *parser >> token;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -684,6 +706,10 @@ void TAnimModel::RaPrepare()
|
|||||||
if (LightsOff[i])
|
if (LightsOff[i])
|
||||||
LightsOff[i]->iVisible = !state;
|
LightsOff[i]->iVisible = !state;
|
||||||
}
|
}
|
||||||
|
// potentially modify freespot colors
|
||||||
|
if( LightsOn[i] ) {
|
||||||
|
LightsOn[i]->SetDiffuseOverride( m_lightcolors[i], true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
TSubModel::iInstance = reinterpret_cast<std::uintptr_t>( this ); //żeby nie robić cudzych animacji
|
TSubModel::iInstance = reinterpret_cast<std::uintptr_t>( this ); //żeby nie robić cudzych animacji
|
||||||
TSubModel::pasText = &asText; // przekazanie tekstu do wyświetlacza (!!!! do przemyślenia)
|
TSubModel::pasText = &asText; // przekazanie tekstu do wyświetlacza (!!!! do przemyślenia)
|
||||||
|
|||||||
16
AnimModel.h
16
AnimModel.h
@@ -179,19 +179,19 @@ private:
|
|||||||
// members
|
// members
|
||||||
TAnimContainer *pRoot { nullptr }; // pojemniki sterujące, tylko dla aniomowanych submodeli
|
TAnimContainer *pRoot { nullptr }; // pojemniki sterujące, tylko dla aniomowanych submodeli
|
||||||
TModel3d *pModel { nullptr };
|
TModel3d *pModel { nullptr };
|
||||||
// double fBlinkTimer { 0.0 };
|
|
||||||
int iNumLights { 0 };
|
|
||||||
TSubModel *LightsOn[ iMaxNumLights ]; // Ra: te wskaźniki powinny być w ramach TModel3d
|
|
||||||
TSubModel *LightsOff[ iMaxNumLights ];
|
|
||||||
glm::vec3 vAngle; // bazowe obroty egzemplarza względem osi
|
glm::vec3 vAngle; // bazowe obroty egzemplarza względem osi
|
||||||
material_data m_materialdata;
|
material_data m_materialdata;
|
||||||
|
|
||||||
std::string asText; // tekst dla wyświetlacza znakowego
|
std::string asText; // tekst dla wyświetlacza znakowego
|
||||||
TAnimAdvanced *pAdvanced { nullptr };
|
TAnimAdvanced *pAdvanced { nullptr };
|
||||||
// TODO: wrap into a light state struct
|
// TODO: wrap into a light state struct, remove fixed element count
|
||||||
float lsLights[ iMaxNumLights ];
|
int iNumLights { 0 };
|
||||||
std::array<float, iMaxNumLights> m_lighttimers { 0.f };
|
std::array<TSubModel *, iMaxNumLights> LightsOn {}; // Ra: te wskaźniki powinny być w ramach TModel3d
|
||||||
std::array<float, iMaxNumLights> m_lightopacities { 1.f };
|
std::array<TSubModel *, iMaxNumLights> LightsOff {};
|
||||||
|
std::array<float, iMaxNumLights> lsLights {}; // ls_Off
|
||||||
|
std::array<glm::vec3, iMaxNumLights> m_lightcolors; // -1 in constructor
|
||||||
|
std::array<float, iMaxNumLights> m_lighttimers {};
|
||||||
|
std::array<float, iMaxNumLights> m_lightopacities; // {1} in constructor
|
||||||
float fOnTime { 1.f / 2 };// { 60.f / 45.f / 2 };
|
float fOnTime { 1.f / 2 };// { 60.f / 45.f / 2 };
|
||||||
float fOffTime { 1.f / 2 };// { 60.f / 45.f / 2 }; // były stałymi, teraz mogą być zmienne dla każdego egzemplarza
|
float fOffTime { 1.f / 2 };// { 60.f / 45.f / 2 }; // były stałymi, teraz mogą być zmienne dla każdego egzemplarza
|
||||||
float fTransitionTime { fOnTime * 0.9f }; // time
|
float fTransitionTime { fOnTime * 0.9f }; // time
|
||||||
|
|||||||
73
DynObj.cpp
73
DynObj.cpp
@@ -3933,6 +3933,13 @@ void TDynamicObject::RenderSounds() {
|
|||||||
|
|
||||||
if( Global.iPause != 0 ) { return; }
|
if( Global.iPause != 0 ) { return; }
|
||||||
|
|
||||||
|
if( ( m_startjoltplayed )
|
||||||
|
&& ( ( std::abs( MoverParameters->AccSVBased ) < 0.01 )
|
||||||
|
|| ( GetVelocity() < 0.01 ) ) ) {
|
||||||
|
// if the vehicle comes to a stop set the movement jolt to play when it starts moving again
|
||||||
|
m_startjoltplayed = false;
|
||||||
|
}
|
||||||
|
|
||||||
double const dt{ Timer::GetDeltaRenderTime() };
|
double const dt{ Timer::GetDeltaRenderTime() };
|
||||||
double volume{ 0.0 };
|
double volume{ 0.0 };
|
||||||
double frequency{ 1.0 };
|
double frequency{ 1.0 };
|
||||||
@@ -4103,6 +4110,10 @@ void TDynamicObject::RenderSounds() {
|
|||||||
volume = rsPisk.m_amplitudeoffset + interpolate( -1.0, 1.0, brakeforceratio ) * rsPisk.m_amplitudefactor;
|
volume = rsPisk.m_amplitudeoffset + interpolate( -1.0, 1.0, brakeforceratio ) * rsPisk.m_amplitudefactor;
|
||||||
if( volume > 0.075 ) {
|
if( volume > 0.075 ) {
|
||||||
rsPisk
|
rsPisk
|
||||||
|
.pitch(
|
||||||
|
true == rsPisk.is_combined() ?
|
||||||
|
MoverParameters->Vel * 0.01f :
|
||||||
|
rsPisk.m_frequencyoffset + rsPisk.m_frequencyfactor * 1.f )
|
||||||
.gain( volume )
|
.gain( volume )
|
||||||
.play( sound_flags::exclusive | sound_flags::looping );
|
.play( sound_flags::exclusive | sound_flags::looping );
|
||||||
}
|
}
|
||||||
@@ -4132,19 +4143,22 @@ void TDynamicObject::RenderSounds() {
|
|||||||
}
|
}
|
||||||
// NBMX sygnal odjazdu
|
// NBMX sygnal odjazdu
|
||||||
if( MoverParameters->DoorClosureWarning ) {
|
if( MoverParameters->DoorClosureWarning ) {
|
||||||
if( ( MoverParameters->DepartureSignal )
|
for( auto &door : m_doorsounds ) {
|
||||||
|
// TBD, TODO: per-location door state triggers?
|
||||||
|
if( ( MoverParameters->DepartureSignal )
|
||||||
/*
|
/*
|
||||||
|| ( ( MoverParameters->DoorCloseCtrl = control::autonomous )
|
|| ( ( MoverParameters->DoorCloseCtrl = control::autonomous )
|
||||||
&& ( ( ( false == MoverParameters->DoorLeftOpened ) && ( dDoorMoveL > 0.0 ) )
|
&& ( ( ( false == MoverParameters->DoorLeftOpened ) && ( dDoorMoveL > 0.0 ) )
|
||||||
|| ( ( false == MoverParameters->DoorRightOpened ) && ( dDoorMoveR > 0.0 ) ) ) )
|
|| ( ( false == MoverParameters->DoorRightOpened ) && ( dDoorMoveR > 0.0 ) ) ) )
|
||||||
*/
|
*/
|
||||||
) {
|
) {
|
||||||
// for the autonomous doors play the warning automatically whenever a door is closing
|
// for the autonomous doors play the warning automatically whenever a door is closing
|
||||||
// MC: pod warunkiem ze jest zdefiniowane w chk
|
// MC: pod warunkiem ze jest zdefiniowane w chk
|
||||||
sDepartureSignal.play( sound_flags::exclusive | sound_flags::looping );
|
door.sDepartureSignal.play( sound_flags::exclusive | sound_flags::looping );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
sDepartureSignal.stop();
|
door.sDepartureSignal.stop();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// NBMX Obsluga drzwi, MC: zuniwersalnione
|
// NBMX Obsluga drzwi, MC: zuniwersalnione
|
||||||
@@ -4388,6 +4402,17 @@ void TDynamicObject::RenderSounds() {
|
|||||||
rscurve.stop();
|
rscurve.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// movement start jolt
|
||||||
|
if( false == m_startjoltplayed ) {
|
||||||
|
auto const velocity { GetVelocity() };
|
||||||
|
if( ( MoverParameters->V > 0.0 ? ( MoverParameters->AccSVBased > 0.1 ) : ( MoverParameters->AccSVBased < 0.1 ) )
|
||||||
|
&& ( velocity > 1.0 )
|
||||||
|
&& ( velocity < 15.0 ) ) {
|
||||||
|
m_startjolt.play( sound_flags::exclusive );
|
||||||
|
m_startjoltplayed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// McZapkie! - to wazne - SoundFlag wystawiane jest przez moje moduly
|
// McZapkie! - to wazne - SoundFlag wystawiane jest przez moje moduly
|
||||||
// gdy zachodza pewne wydarzenia komentowane dzwiekiem.
|
// gdy zachodza pewne wydarzenia komentowane dzwiekiem.
|
||||||
if( TestFlag( MoverParameters->SoundFlag, sound::pneumatic ) ) {
|
if( TestFlag( MoverParameters->SoundFlag, sound::pneumatic ) ) {
|
||||||
@@ -5399,12 +5424,6 @@ void TDynamicObject::LoadMMediaFile( std::string const &TypeName, std::string co
|
|||||||
sHorn3.owner( this );
|
sHorn3.owner( this );
|
||||||
}
|
}
|
||||||
|
|
||||||
else if( token == "departuresignal:" ) {
|
|
||||||
// pliki z sygnalem odjazdu
|
|
||||||
sDepartureSignal.deserialize( parser, sound_type::multipart, sound_parameters::range );
|
|
||||||
sDepartureSignal.owner( this );
|
|
||||||
}
|
|
||||||
|
|
||||||
else if( token == "pantographup:" ) {
|
else if( token == "pantographup:" ) {
|
||||||
// pliki dzwiekow pantografow
|
// pliki dzwiekow pantografow
|
||||||
sound_source pantographup { sound_placement::external };
|
sound_source pantographup { sound_placement::external };
|
||||||
@@ -5456,6 +5475,19 @@ void TDynamicObject::LoadMMediaFile( std::string const &TypeName, std::string co
|
|||||||
sSmallCompressor.owner( this );
|
sSmallCompressor.owner( this );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
else if( token == "departuresignal:" ) {
|
||||||
|
// pliki z sygnalem odjazdu
|
||||||
|
sound_source soundtemplate { sound_placement::general, 25.f };
|
||||||
|
soundtemplate.deserialize( parser, sound_type::multipart, sound_parameters::range );
|
||||||
|
soundtemplate.owner( this );
|
||||||
|
for( auto &door : m_doorsounds ) {
|
||||||
|
// apply configuration to all defined doors, but preserve their individual offsets
|
||||||
|
auto const dooroffset { door.lock.offset() };
|
||||||
|
door.sDepartureSignal = soundtemplate;
|
||||||
|
door.sDepartureSignal.offset( dooroffset );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
else if( token == "dooropen:" ) {
|
else if( token == "dooropen:" ) {
|
||||||
sound_source soundtemplate { sound_placement::general, 25.f };
|
sound_source soundtemplate { sound_placement::general, 25.f };
|
||||||
soundtemplate.deserialize( parser, sound_type::single );
|
soundtemplate.deserialize( parser, sound_type::single );
|
||||||
@@ -5605,6 +5637,7 @@ void TDynamicObject::LoadMMediaFile( std::string const &TypeName, std::string co
|
|||||||
|| ( sides == "left" ) ) {
|
|| ( sides == "left" ) ) {
|
||||||
// left...
|
// left...
|
||||||
auto const location { glm::vec3 { MoverParameters->Dim.W * 0.5f, MoverParameters->Dim.H * 0.5f, offset } };
|
auto const location { glm::vec3 { MoverParameters->Dim.W * 0.5f, MoverParameters->Dim.H * 0.5f, offset } };
|
||||||
|
door.sDepartureSignal.offset( location );
|
||||||
door.rsDoorClose.offset( location );
|
door.rsDoorClose.offset( location );
|
||||||
door.rsDoorOpen.offset( location );
|
door.rsDoorOpen.offset( location );
|
||||||
door.lock.offset( location );
|
door.lock.offset( location );
|
||||||
@@ -5617,6 +5650,7 @@ void TDynamicObject::LoadMMediaFile( std::string const &TypeName, std::string co
|
|||||||
|| ( sides == "right" ) ) {
|
|| ( sides == "right" ) ) {
|
||||||
// ...and right
|
// ...and right
|
||||||
auto const location { glm::vec3 { MoverParameters->Dim.W * -0.5f, MoverParameters->Dim.H * 0.5f, offset } };
|
auto const location { glm::vec3 { MoverParameters->Dim.W * -0.5f, MoverParameters->Dim.H * 0.5f, offset } };
|
||||||
|
door.sDepartureSignal.offset( location );
|
||||||
door.rsDoorClose.offset( location );
|
door.rsDoorClose.offset( location );
|
||||||
door.rsDoorOpen.offset( location );
|
door.rsDoorOpen.offset( location );
|
||||||
door.lock.offset( location );
|
door.lock.offset( location );
|
||||||
@@ -5802,6 +5836,11 @@ void TDynamicObject::LoadMMediaFile( std::string const &TypeName, std::string co
|
|||||||
couplersounds.dsbBufferClamp_loud = bufferclash;
|
couplersounds.dsbBufferClamp_loud = bufferclash;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if( token == "startjolt:" ) {
|
||||||
|
// movement start jolt
|
||||||
|
m_startjolt.deserialize( parser, sound_type::single );
|
||||||
|
m_startjolt.owner( this );
|
||||||
|
}
|
||||||
|
|
||||||
} while( token != "" );
|
} while( token != "" );
|
||||||
|
|
||||||
|
|||||||
4
DynObj.h
4
DynObj.h
@@ -307,6 +307,7 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct door_sounds {
|
struct door_sounds {
|
||||||
|
sound_source sDepartureSignal { sound_placement::general };
|
||||||
sound_source rsDoorOpen { sound_placement::general }; // Ra: przeniesione z kabiny
|
sound_source rsDoorOpen { sound_placement::general }; // Ra: przeniesione z kabiny
|
||||||
sound_source rsDoorClose { sound_placement::general };
|
sound_source rsDoorClose { sound_placement::general };
|
||||||
sound_source lock { sound_placement::general };
|
sound_source lock { sound_placement::general };
|
||||||
@@ -427,11 +428,12 @@ private:
|
|||||||
sound_source rsSlippery { sound_placement::external, EU07_SOUND_BRAKINGCUTOFFRANGE }; // moved from cab
|
sound_source rsSlippery { sound_placement::external, EU07_SOUND_BRAKINGCUTOFFRANGE }; // moved from cab
|
||||||
sound_source sSand { sound_placement::external };
|
sound_source sSand { sound_placement::external };
|
||||||
// moving part and other external sounds
|
// moving part and other external sounds
|
||||||
|
sound_source m_startjolt { sound_placement::general }; // movement start jolt, played once on initial acceleration at slow enough speed
|
||||||
|
bool m_startjoltplayed { false };
|
||||||
std::array<coupler_sounds, 2> m_couplersounds; // always front and rear
|
std::array<coupler_sounds, 2> m_couplersounds; // always front and rear
|
||||||
std::vector<pantograph_sounds> m_pantographsounds; // typically 2 but can be less (or more?)
|
std::vector<pantograph_sounds> m_pantographsounds; // typically 2 but can be less (or more?)
|
||||||
std::vector<door_sounds> m_doorsounds; // can expect symmetrical arrangement, but don't count on it
|
std::vector<door_sounds> m_doorsounds; // can expect symmetrical arrangement, but don't count on it
|
||||||
bool m_doorlocks { false }; // sound helper, current state of door locks
|
bool m_doorlocks { false }; // sound helper, current state of door locks
|
||||||
sound_source sDepartureSignal { sound_placement::general };
|
|
||||||
sound_source sHorn1 { sound_placement::external, 5 * EU07_SOUND_RUNNINGNOISECUTOFFRANGE };
|
sound_source sHorn1 { sound_placement::external, 5 * EU07_SOUND_RUNNINGNOISECUTOFFRANGE };
|
||||||
sound_source sHorn2 { sound_placement::external, 5 * EU07_SOUND_RUNNINGNOISECUTOFFRANGE };
|
sound_source sHorn2 { sound_placement::external, 5 * EU07_SOUND_RUNNINGNOISECUTOFFRANGE };
|
||||||
sound_source sHorn3 { sound_placement::external, 5 * EU07_SOUND_RUNNINGNOISECUTOFFRANGE };
|
sound_source sHorn3 { sound_placement::external, 5 * EU07_SOUND_RUNNINGNOISECUTOFFRANGE };
|
||||||
|
|||||||
@@ -1485,7 +1485,7 @@ lights_event::deserialize_( cParser &Input, scene::scratch_data &Scratchpad ) {
|
|||||||
}
|
}
|
||||||
while( lightidx < lightcountlimit ) {
|
while( lightidx < lightcountlimit ) {
|
||||||
// HACK: mark unspecified lights with magic value
|
// HACK: mark unspecified lights with magic value
|
||||||
m_lights[ lightidx++ ] = -2.f;
|
m_lights[ lightidx++ ] = std::numeric_limits<float>::quiet_NaN();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1498,11 +1498,11 @@ lights_event::run_() {
|
|||||||
if( targetmodel == nullptr ) { continue; }
|
if( targetmodel == nullptr ) { continue; }
|
||||||
// event effect code
|
// event effect code
|
||||||
for( auto lightidx = 0; lightidx < iMaxNumLights; ++lightidx ) {
|
for( auto lightidx = 0; lightidx < iMaxNumLights; ++lightidx ) {
|
||||||
if( m_lights[ lightidx ] == -2.f ) {
|
if( std::isnan( m_lights[ lightidx ] ) ) {
|
||||||
// processed all supplied values, bail out
|
// processed all supplied values, bail out
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if( m_lights[ lightidx ] >= 0.f ) {
|
if( m_lights[ lightidx ] != -1.f ) {
|
||||||
// -1 zostawia bez zmiany
|
// -1 zostawia bez zmiany
|
||||||
targetmodel->LightSet(
|
targetmodel->LightSet(
|
||||||
lightidx,
|
lightidx,
|
||||||
@@ -1518,7 +1518,7 @@ lights_event::export_as_text_( std::ostream &Output ) const {
|
|||||||
|
|
||||||
auto lightidx{ 0 };
|
auto lightidx{ 0 };
|
||||||
while( ( lightidx < iMaxNumLights )
|
while( ( lightidx < iMaxNumLights )
|
||||||
&& ( m_lights[ lightidx ] > -2.0 ) ) {
|
&& ( false == std::isnan( m_lights[ lightidx ] ) ) ) {
|
||||||
Output << m_lights[ lightidx ] << ' ';
|
Output << m_lights[ lightidx ] << ' ';
|
||||||
++lightidx;
|
++lightidx;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4314,7 +4314,8 @@ double TMoverParameters::CouplerForce(int CouplerN, double dt)
|
|||||||
else if( ( Couplers[ CouplerN ].CouplingFlag != coupling::faux )
|
else if( ( Couplers[ CouplerN ].CouplingFlag != coupling::faux )
|
||||||
&& ( newdist > 0.001 )
|
&& ( newdist > 0.001 )
|
||||||
&& ( Couplers[ CouplerN ].Dist <= 0.001 )
|
&& ( Couplers[ CouplerN ].Dist <= 0.001 )
|
||||||
&& ( absdV > 0.005 ) ) {
|
&& ( absdV > 0.005 )
|
||||||
|
&& ( Vel > 1.0 ) ) {
|
||||||
// 090503: dzwieki pracy sprzegu
|
// 090503: dzwieki pracy sprzegu
|
||||||
SetFlag(
|
SetFlag(
|
||||||
Couplers[ CouplerN ].sounds,
|
Couplers[ CouplerN ].sounds,
|
||||||
|
|||||||
19
Model3d.cpp
19
Model3d.cpp
@@ -72,6 +72,25 @@ void TSubModel::Name(std::string const &Name)
|
|||||||
pName = Name;
|
pName = Name;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// sets rgb components of diffuse color override to specified value
|
||||||
|
void
|
||||||
|
TSubModel::SetDiffuseOverride( glm::vec3 const &Color, bool const Includechildren, bool const Includesiblings ) {
|
||||||
|
|
||||||
|
if( eType == TP_FREESPOTLIGHT ) {
|
||||||
|
DiffuseOverride = Color;
|
||||||
|
}
|
||||||
|
if( true == Includesiblings ) {
|
||||||
|
auto sibling { this };
|
||||||
|
while( ( sibling = sibling->Next ) != nullptr ) {
|
||||||
|
sibling->SetDiffuseOverride( Color, Includechildren, false ); // no need for all siblings to duplicate the work
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if( ( true == Includechildren )
|
||||||
|
&& ( Child != nullptr ) ) {
|
||||||
|
Child->SetDiffuseOverride( Color, Includechildren, true ); // node's children include child's siblings and children
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// sets visibility level (alpha component) to specified value
|
// sets visibility level (alpha component) to specified value
|
||||||
void
|
void
|
||||||
TSubModel::SetVisibilityLevel( float const Level, bool const Includechildren, bool const Includesiblings ) {
|
TSubModel::SetVisibilityLevel( float const Level, bool const Includechildren, bool const Includesiblings ) {
|
||||||
|
|||||||
@@ -106,6 +106,7 @@ private:
|
|||||||
f4Diffuse { 1.0f,1.0f,1.0f,1.0f },
|
f4Diffuse { 1.0f,1.0f,1.0f,1.0f },
|
||||||
f4Specular { 0.0f,0.0f,0.0f,1.0f },
|
f4Specular { 0.0f,0.0f,0.0f,1.0f },
|
||||||
f4Emision { 1.0f,1.0f,1.0f,1.0f };
|
f4Emision { 1.0f,1.0f,1.0f,1.0f };
|
||||||
|
glm::vec3 DiffuseOverride { -1.f };
|
||||||
normalization m_normalizenormals { normalization::none }; // indicates vectors need to be normalized due to scaling etc
|
normalization m_normalizenormals { normalization::none }; // indicates vectors need to be normalized due to scaling etc
|
||||||
float fWireSize { 0.0f }; // nie używane, ale wczytywane
|
float fWireSize { 0.0f }; // nie używane, ale wczytywane
|
||||||
float fSquareMaxDist { 10000.0f * 10000.0f };
|
float fSquareMaxDist { 10000.0f * 10000.0f };
|
||||||
@@ -195,6 +196,8 @@ public:
|
|||||||
uint32_t Flags() const { return iFlags; };
|
uint32_t Flags() const { return iFlags; };
|
||||||
void UnFlagNext() { iFlags &= 0x00FFFFFF; };
|
void UnFlagNext() { iFlags &= 0x00FFFFFF; };
|
||||||
void ColorsSet( glm::vec3 const &Ambient, glm::vec3 const &Diffuse, glm::vec3 const &Specular );
|
void ColorsSet( glm::vec3 const &Ambient, glm::vec3 const &Diffuse, glm::vec3 const &Specular );
|
||||||
|
// sets rgb components of diffuse color override to specified value
|
||||||
|
void SetDiffuseOverride( glm::vec3 const &Color, bool const Includechildren = false, bool const Includesiblings = false );
|
||||||
// sets visibility level (alpha component) to specified value
|
// sets visibility level (alpha component) to specified value
|
||||||
void SetVisibilityLevel( float const Level, bool const Includechildren = false, bool const Includesiblings = false );
|
void SetVisibilityLevel( float const Level, bool const Includechildren = false, bool const Includesiblings = false );
|
||||||
// sets light level (alpha component of illumination color) to specified value
|
// sets light level (alpha component of illumination color) to specified value
|
||||||
|
|||||||
76
PyInt.cpp
76
PyInt.cpp
@@ -31,7 +31,7 @@ void render_task::run() {
|
|||||||
if( ( outputwidth != nullptr )
|
if( ( outputwidth != nullptr )
|
||||||
&& ( outputheight != nullptr ) ) {
|
&& ( outputheight != nullptr ) ) {
|
||||||
|
|
||||||
::glBindTexture( GL_TEXTURE_2D, GfxRenderer.Texture( m_target ).id );
|
::glBindTexture( GL_TEXTURE_2D, m_target );
|
||||||
// setup texture parameters
|
// setup texture parameters
|
||||||
::glTexParameteri( GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE );
|
::glTexParameteri( GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE );
|
||||||
::glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
|
::glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
|
||||||
@@ -83,8 +83,6 @@ auto python_taskqueue::init() -> bool {
|
|||||||
PyObject *stringioclassname { nullptr };
|
PyObject *stringioclassname { nullptr };
|
||||||
PyObject *stringioobject { nullptr };
|
PyObject *stringioobject { nullptr };
|
||||||
|
|
||||||
// save a pointer to the main PyThreadState object
|
|
||||||
m_mainthread = PyThreadState_Get();
|
|
||||||
// do the setup work while we hold the lock
|
// do the setup work while we hold the lock
|
||||||
m_main = PyImport_ImportModule("__main__");
|
m_main = PyImport_ImportModule("__main__");
|
||||||
if (m_main == nullptr) {
|
if (m_main == nullptr) {
|
||||||
@@ -110,8 +108,8 @@ auto python_taskqueue::init() -> bool {
|
|||||||
|
|
||||||
if( false == run_file( "abstractscreenrenderer" ) ) { goto release_and_exit; }
|
if( false == run_file( "abstractscreenrenderer" ) ) { goto release_and_exit; }
|
||||||
|
|
||||||
// release the lock
|
// release the lock, save the state for future use
|
||||||
PyEval_ReleaseLock();
|
m_mainthread = PyEval_SaveThread();
|
||||||
|
|
||||||
WriteLog( "Python Interpreter setup complete" );
|
WriteLog( "Python Interpreter setup complete" );
|
||||||
|
|
||||||
@@ -119,12 +117,11 @@ auto python_taskqueue::init() -> bool {
|
|||||||
for( auto &worker : m_workers ) {
|
for( auto &worker : m_workers ) {
|
||||||
|
|
||||||
auto *openglcontextwindow { Application.window( -1 ) };
|
auto *openglcontextwindow { Application.window( -1 ) };
|
||||||
worker =
|
worker = std::thread(
|
||||||
std::make_unique<std::thread>(
|
&python_taskqueue::run, this,
|
||||||
&python_taskqueue::run, this,
|
openglcontextwindow, std::ref( m_tasks ), std::ref( m_condition ), std::ref( m_exit ) );
|
||||||
openglcontextwindow, std::ref( m_tasks ), std::ref( m_condition ), std::ref( m_exit ) );
|
|
||||||
|
|
||||||
if( worker == nullptr ) { return false; }
|
if( false == worker.joinable() ) { return false; }
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -140,8 +137,8 @@ void python_taskqueue::exit() {
|
|||||||
m_exit = true;
|
m_exit = true;
|
||||||
m_condition.notify_all();
|
m_condition.notify_all();
|
||||||
// let them free up their shit before we proceed
|
// let them free up their shit before we proceed
|
||||||
for( auto const &worker : m_workers ) {
|
for( auto &worker : m_workers ) {
|
||||||
worker->join();
|
worker.join();
|
||||||
}
|
}
|
||||||
// get rid of the leftover tasks
|
// get rid of the leftover tasks
|
||||||
// with the workers dead we don't have to worry about concurrent access anymore
|
// with the workers dead we don't have to worry about concurrent access anymore
|
||||||
@@ -149,8 +146,7 @@ void python_taskqueue::exit() {
|
|||||||
task->cancel();
|
task->cancel();
|
||||||
}
|
}
|
||||||
// take a bow
|
// take a bow
|
||||||
PyEval_AcquireLock();
|
acquire_lock();
|
||||||
PyThreadState_Swap( m_mainthread );
|
|
||||||
Py_Finalize();
|
Py_Finalize();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,7 +155,7 @@ auto python_taskqueue::insert( task_request const &Task ) -> bool {
|
|||||||
|
|
||||||
if( ( Task.renderer.empty() )
|
if( ( Task.renderer.empty() )
|
||||||
|| ( Task.input == nullptr )
|
|| ( Task.input == nullptr )
|
||||||
|| ( Task.target == null_handle ) ) { return false; }
|
|| ( Task.target == 0 ) ) { return false; }
|
||||||
|
|
||||||
auto *renderer { fetch_renderer( Task.renderer ) };
|
auto *renderer { fetch_renderer( Task.renderer ) };
|
||||||
if( renderer == nullptr ) { return false; }
|
if( renderer == nullptr ) { return false; }
|
||||||
@@ -173,11 +169,11 @@ auto python_taskqueue::insert( task_request const &Task ) -> bool {
|
|||||||
for( auto &task : m_tasks.data ) {
|
for( auto &task : m_tasks.data ) {
|
||||||
if( task->target() == Task.target ) {
|
if( task->target() == Task.target ) {
|
||||||
// replace pending task in the slot with the more recent one
|
// replace pending task in the slot with the more recent one
|
||||||
PyEval_AcquireLock();
|
acquire_lock();
|
||||||
{
|
{
|
||||||
task->cancel();
|
task->cancel();
|
||||||
}
|
}
|
||||||
PyEval_ReleaseLock();
|
release_lock();
|
||||||
task = newtask;
|
task = newtask;
|
||||||
newtaskinserted = true;
|
newtaskinserted = true;
|
||||||
break;
|
break;
|
||||||
@@ -211,6 +207,18 @@ auto python_taskqueue::run_file( std::string const &File, std::string const &Pat
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// acquires the python gil and sets the main thread as current
|
||||||
|
void python_taskqueue::acquire_lock() {
|
||||||
|
|
||||||
|
PyEval_RestoreThread( m_mainthread );
|
||||||
|
}
|
||||||
|
|
||||||
|
// releases the python gil and swaps the main thread out
|
||||||
|
void python_taskqueue::release_lock() {
|
||||||
|
|
||||||
|
PyEval_SaveThread();
|
||||||
|
}
|
||||||
|
|
||||||
auto python_taskqueue::fetch_renderer( std::string const Renderer ) ->PyObject * {
|
auto python_taskqueue::fetch_renderer( std::string const Renderer ) ->PyObject * {
|
||||||
|
|
||||||
auto const lookup { m_renderers.find( Renderer ) };
|
auto const lookup { m_renderers.find( Renderer ) };
|
||||||
@@ -221,17 +229,15 @@ auto python_taskqueue::fetch_renderer( std::string const Renderer ) ->PyObject *
|
|||||||
auto const path { substr_path( Renderer ) };
|
auto const path { substr_path( Renderer ) };
|
||||||
auto const file { Renderer.substr( path.size() ) };
|
auto const file { Renderer.substr( path.size() ) };
|
||||||
PyObject *renderer { nullptr };
|
PyObject *renderer { nullptr };
|
||||||
PyObject *rendererarguments { nullptr };
|
PyObject *rendererarguments { nullptr };
|
||||||
PyObject *renderername { nullptr };
|
PyObject *renderername { nullptr };
|
||||||
|
acquire_lock();
|
||||||
PyEval_AcquireLock();
|
|
||||||
|
|
||||||
if( m_main == nullptr ) {
|
|
||||||
ErrorLog( "Python Renderer: __main__ module is missing" );
|
|
||||||
goto cache_and_return;
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
{
|
||||||
|
if( m_main == nullptr ) {
|
||||||
|
ErrorLog( "Python Renderer: __main__ module is missing" );
|
||||||
|
goto cache_and_return;
|
||||||
|
}
|
||||||
|
|
||||||
if( false == run_file( file, path ) ) {
|
if( false == run_file( file, path ) ) {
|
||||||
goto cache_and_return;
|
goto cache_and_return;
|
||||||
}
|
}
|
||||||
@@ -258,7 +264,7 @@ cache_and_return:
|
|||||||
Py_DECREF( rendererarguments );
|
Py_DECREF( rendererarguments );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PyEval_ReleaseLock();
|
release_lock();
|
||||||
// cache the failures as well so we don't try again on subsequent requests
|
// cache the failures as well so we don't try again on subsequent requests
|
||||||
m_renderers.emplace( Renderer, renderer );
|
m_renderers.emplace( Renderer, renderer );
|
||||||
return renderer;
|
return renderer;
|
||||||
@@ -291,14 +297,14 @@ void python_taskqueue::run( GLFWwindow *Context, rendertask_sequence &Tasks, thr
|
|||||||
}
|
}
|
||||||
if( task != nullptr ) {
|
if( task != nullptr ) {
|
||||||
// swap in my thread state
|
// swap in my thread state
|
||||||
PyEval_AcquireLock();
|
PyEval_RestoreThread( threadstate );
|
||||||
PyThreadState_Swap( threadstate );
|
{
|
||||||
// execute python code
|
// execute python code
|
||||||
task->run();
|
task->run();
|
||||||
error();
|
error();
|
||||||
|
}
|
||||||
// clear the thread state
|
// clear the thread state
|
||||||
PyThreadState_Swap( nullptr );
|
PyEval_SaveThread();
|
||||||
PyEval_ReleaseLock();
|
|
||||||
}
|
}
|
||||||
// TBD, TODO: add some idle time between tasks in case we're on a single thread cpu?
|
// TBD, TODO: add some idle time between tasks in case we're on a single thread cpu?
|
||||||
} while( task != nullptr );
|
} while( task != nullptr );
|
||||||
|
|||||||
14
PyInt.h
14
PyInt.h
@@ -39,7 +39,7 @@ class render_task {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
// constructors
|
// constructors
|
||||||
render_task( PyObject *Renderer, PyObject *Input, texture_handle Target ) :
|
render_task( PyObject *Renderer, PyObject *Input, GLuint Target ) :
|
||||||
m_renderer( Renderer ), m_input( Input ), m_target( Target )
|
m_renderer( Renderer ), m_input( Input ), m_target( Target )
|
||||||
{}
|
{}
|
||||||
// methods
|
// methods
|
||||||
@@ -51,9 +51,11 @@ private:
|
|||||||
// members
|
// members
|
||||||
PyObject *m_renderer {nullptr};
|
PyObject *m_renderer {nullptr};
|
||||||
PyObject *m_input { nullptr };
|
PyObject *m_input { nullptr };
|
||||||
texture_handle m_target { null_handle };
|
GLuint m_target { 0 };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class python_taskqueue {
|
class python_taskqueue {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -62,7 +64,7 @@ public:
|
|||||||
|
|
||||||
std::string const &renderer;
|
std::string const &renderer;
|
||||||
PyObject *input;
|
PyObject *input;
|
||||||
texture_handle target;
|
GLuint target;
|
||||||
};
|
};
|
||||||
// constructors
|
// constructors
|
||||||
python_taskqueue() = default;
|
python_taskqueue() = default;
|
||||||
@@ -75,11 +77,15 @@ public:
|
|||||||
auto insert( task_request const &Task ) -> bool;
|
auto insert( task_request const &Task ) -> bool;
|
||||||
// executes python script stored in specified file. returns true on success
|
// executes python script stored in specified file. returns true on success
|
||||||
auto run_file( std::string const &File, std::string const &Path = "" ) -> bool;
|
auto run_file( std::string const &File, std::string const &Path = "" ) -> bool;
|
||||||
|
// acquires the python gil and sets the main thread as current
|
||||||
|
void acquire_lock();
|
||||||
|
// releases the python gil and swaps the main thread out
|
||||||
|
void release_lock();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// types
|
// types
|
||||||
static int const WORKERCOUNT { 1 };
|
static int const WORKERCOUNT { 1 };
|
||||||
using worker_array = std::array<std::unique_ptr<std::thread>, WORKERCOUNT >;
|
using worker_array = std::array<std::thread, WORKERCOUNT >;
|
||||||
using rendertask_sequence = threading::lockable< std::deque<render_task *> >;
|
using rendertask_sequence = threading::lockable< std::deque<render_task *> >;
|
||||||
// methods
|
// methods
|
||||||
auto fetch_renderer( std::string const Renderer ) -> PyObject *;
|
auto fetch_renderer( std::string const Renderer ) -> PyObject *;
|
||||||
|
|||||||
39
Segment.cpp
39
Segment.cpp
@@ -372,12 +372,10 @@ Math3D::vector3 TSegment::FastGetPoint(double const t) const
|
|||||||
interpolate( Point1, Point2, t ) );
|
interpolate( Point1, Point2, t ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TSegment::RenderLoft( gfx::vertex_array &Output, Math3D::vector3 const &Origin, const gfx::vertex_array &ShapePoints, int iNumShapePoints, double fTextureLength, double Texturescale, int iSkip, int iEnd, float fOffsetX, glm::vec3 **p, bool bRender)
|
bool TSegment::RenderLoft( gfx::vertex_array &Output, Math3D::vector3 const &Origin, const gfx::vertex_array &ShapePoints, int iNumShapePoints, double fTextureLength, double Texturescale, int iSkip, int iEnd, std::pair<float, float> fOffsetX, glm::vec3 **p, bool bRender)
|
||||||
{ // generowanie trójkątów dla odcinka trajektorii ruchu
|
{ // generowanie trójkątów dla odcinka trajektorii ruchu
|
||||||
// standardowo tworzy triangle_strip dla prostego albo ich zestaw dla łuku
|
// standardowo tworzy triangle_strip dla prostego albo ich zestaw dla łuku
|
||||||
// po modyfikacji - dla ujemnego (iNumShapePoints) w dodatkowych polach tabeli
|
// po modyfikacji - dla ujemnego (iNumShapePoints) w dodatkowych polach tabeli podany jest przekrój końcowy
|
||||||
// podany jest przekrój końcowy
|
|
||||||
// podsypka toru jest robiona za pomocą 6 punktów, szyna 12, drogi i rzeki na 3+2+3
|
|
||||||
|
|
||||||
if( fTsBuffer.empty() )
|
if( fTsBuffer.empty() )
|
||||||
return false; // prowizoryczne zabezpieczenie przed wysypem - ustalić faktyczną przyczynę
|
return false; // prowizoryczne zabezpieczenie przed wysypem - ustalić faktyczną przyczynę
|
||||||
@@ -408,8 +406,12 @@ bool TSegment::RenderLoft( gfx::vertex_array &Output, Math3D::vector3 const &Ori
|
|||||||
if( iEnd == 0 )
|
if( iEnd == 0 )
|
||||||
iEnd = iSegCount;
|
iEnd = iSegCount;
|
||||||
fEnd = fLength * double( iEnd ) / double( iSegCount );
|
fEnd = fLength * double( iEnd ) / double( iSegCount );
|
||||||
|
/*
|
||||||
m2 = s / fEnd;
|
m2 = s / fEnd;
|
||||||
jmm2 = 1.0 - m2;
|
*/
|
||||||
|
m2 = static_cast<float>( i - iSkip ) / ( iEnd - iSkip );
|
||||||
|
|
||||||
|
jmm2 = 1.f - m2;
|
||||||
|
|
||||||
while( i < iEnd ) {
|
while( i < iEnd ) {
|
||||||
|
|
||||||
@@ -417,13 +419,17 @@ bool TSegment::RenderLoft( gfx::vertex_array &Output, Math3D::vector3 const &Ori
|
|||||||
s += step; // końcowa pozycja segmentu [m]
|
s += step; // końcowa pozycja segmentu [m]
|
||||||
m1 = m2;
|
m1 = m2;
|
||||||
jmm1 = jmm2; // stara pozycja
|
jmm1 = jmm2; // stara pozycja
|
||||||
|
/*
|
||||||
m2 = s / fEnd;
|
m2 = s / fEnd;
|
||||||
jmm2 = 1.0 - m2; // nowa pozycja
|
*/
|
||||||
|
m2 = static_cast<float>( i - iSkip ) / ( iEnd - iSkip );
|
||||||
|
|
||||||
|
jmm2 = 1.f - m2; // nowa pozycja
|
||||||
if( i == iEnd ) { // gdy przekroczyliśmy koniec - stąd dziury w torach...
|
if( i == iEnd ) { // gdy przekroczyliśmy koniec - stąd dziury w torach...
|
||||||
step -= ( s - fEnd ); // jeszcze do wyliczenia mapowania potrzebny
|
step -= ( s - fEnd ); // jeszcze do wyliczenia mapowania potrzebny
|
||||||
s = fEnd;
|
s = fEnd;
|
||||||
m2 = 1.0;
|
m2 = 1.f;
|
||||||
jmm2 = 0.0;
|
jmm2 = 0.f;
|
||||||
}
|
}
|
||||||
|
|
||||||
while( tv1 < 0.0 ) {
|
while( tv1 < 0.0 ) {
|
||||||
@@ -441,11 +447,11 @@ bool TSegment::RenderLoft( gfx::vertex_array &Output, Math3D::vector3 const &Ori
|
|||||||
}
|
}
|
||||||
parallel2 = glm::normalize( parallel2 );
|
parallel2 = glm::normalize( parallel2 );
|
||||||
|
|
||||||
|
// TODO: refactor the loop, there's no need to calculate starting points for each segment when we can copy the end points of the previous one
|
||||||
if( trapez ) {
|
if( trapez ) {
|
||||||
for( int j = 0; j < iNumShapePoints; ++j ) {
|
for( int j = 0; j < iNumShapePoints; ++j ) {
|
||||||
pt = parallel1 * ( jmm1 * ( ShapePoints[ j ].position.x - fOffsetX ) + m1 * ShapePoints[ j + iNumShapePoints ].position.x ) + pos1;
|
pt = parallel1 * ( jmm1 * ( ShapePoints[ j ].position.x - fOffsetX.first ) + m1 * ( ShapePoints[ j + iNumShapePoints ].position.x - fOffsetX.second ) ) + pos1;
|
||||||
pt.y += jmm1 * ShapePoints[ j ].position.y + m1 * ShapePoints[ j + iNumShapePoints ].position.y;
|
pt.y += jmm1 * ShapePoints[ j ].position.y + m1 * ShapePoints[ j + iNumShapePoints ].position.y;
|
||||||
// pt -= Origin;
|
|
||||||
norm = ( jmm1 * ShapePoints[ j ].normal.x + m1 * ShapePoints[ j + iNumShapePoints ].normal.x ) * parallel1;
|
norm = ( jmm1 * ShapePoints[ j ].normal.x + m1 * ShapePoints[ j + iNumShapePoints ].normal.x ) * parallel1;
|
||||||
norm.y += jmm1 * ShapePoints[ j ].normal.y + m1 * ShapePoints[ j + iNumShapePoints ].normal.y;
|
norm.y += jmm1 * ShapePoints[ j ].normal.y + m1 * ShapePoints[ j + iNumShapePoints ].normal.y;
|
||||||
if( bRender ) {
|
if( bRender ) {
|
||||||
@@ -463,11 +469,10 @@ bool TSegment::RenderLoft( gfx::vertex_array &Output, Math3D::vector3 const &Ori
|
|||||||
( *p )++;
|
( *p )++;
|
||||||
} // zapamiętanie brzegu jezdni
|
} // zapamiętanie brzegu jezdni
|
||||||
// dla trapezu drugi koniec ma inne współrzędne
|
// dla trapezu drugi koniec ma inne współrzędne
|
||||||
pt = parallel2 * ( jmm2 * ( ShapePoints[ j ].position.x - fOffsetX ) + m2 * ShapePoints[ j + iNumShapePoints ].position.x ) + pos2;
|
pt = parallel2 * ( jmm2 * ( ShapePoints[ j ].position.x - fOffsetX.first ) + m2 * ( ShapePoints[ j + iNumShapePoints ].position.x - fOffsetX.second ) ) + pos2;
|
||||||
pt.y += jmm2 * ShapePoints[ j ].position.y + m2 * ShapePoints[ j + iNumShapePoints ].position.y;
|
pt.y += jmm2 * ShapePoints[ j ].position.y + m2 * ShapePoints[ j + iNumShapePoints ].position.y;
|
||||||
// pt -= Origin;
|
norm = ( jmm2 * ShapePoints[ j ].normal.x + m2 * ShapePoints[ j + iNumShapePoints ].normal.x ) * parallel2;
|
||||||
norm = ( jmm1 * ShapePoints[ j ].normal.x + m1 * ShapePoints[ j + iNumShapePoints ].normal.x ) * parallel2;
|
norm.y += jmm2 * ShapePoints[ j ].normal.y + m2 * ShapePoints[ j + iNumShapePoints ].normal.y;
|
||||||
norm.y += jmm1 * ShapePoints[ j ].normal.y + m1 * ShapePoints[ j + iNumShapePoints ].normal.y;
|
|
||||||
if( bRender ) {
|
if( bRender ) {
|
||||||
// skrzyżowania podczas łączenia siatek mogą nie renderować poboczy, ale potrzebować punktów
|
// skrzyżowania podczas łączenia siatek mogą nie renderować poboczy, ale potrzebować punktów
|
||||||
Output.emplace_back(
|
Output.emplace_back(
|
||||||
@@ -488,9 +493,8 @@ bool TSegment::RenderLoft( gfx::vertex_array &Output, Math3D::vector3 const &Ori
|
|||||||
if( bRender ) {
|
if( bRender ) {
|
||||||
for( int j = 0; j < iNumShapePoints; ++j ) {
|
for( int j = 0; j < iNumShapePoints; ++j ) {
|
||||||
//łuk z jednym profilem
|
//łuk z jednym profilem
|
||||||
pt = parallel1 * ( ShapePoints[ j ].position.x - fOffsetX ) + pos1;
|
pt = parallel1 * ( jmm1 * ( ShapePoints[ j ].position.x - fOffsetX.first ) + m1 * ( ShapePoints[ j ].position.x - fOffsetX.second ) ) + pos1;
|
||||||
pt.y += ShapePoints[ j ].position.y;
|
pt.y += ShapePoints[ j ].position.y;
|
||||||
// pt -= Origin;
|
|
||||||
norm = ShapePoints[ j ].normal.x * parallel1;
|
norm = ShapePoints[ j ].normal.x * parallel1;
|
||||||
norm.y += ShapePoints[ j ].normal.y;
|
norm.y += ShapePoints[ j ].normal.y;
|
||||||
|
|
||||||
@@ -499,9 +503,8 @@ bool TSegment::RenderLoft( gfx::vertex_array &Output, Math3D::vector3 const &Ori
|
|||||||
glm::normalize( norm ),
|
glm::normalize( norm ),
|
||||||
glm::vec2 { ShapePoints[ j ].texture.x / texturescale, tv1 } );
|
glm::vec2 { ShapePoints[ j ].texture.x / texturescale, tv1 } );
|
||||||
|
|
||||||
pt = parallel2 * ShapePoints[ j ].position.x + pos2;
|
pt = parallel2 * ( jmm2 * ( ShapePoints[ j ].position.x - fOffsetX.first ) + m2 * ( ShapePoints[ j ].position.x - fOffsetX.second ) ) + pos2;
|
||||||
pt.y += ShapePoints[ j ].position.y;
|
pt.y += ShapePoints[ j ].position.y;
|
||||||
// pt -= Origin;
|
|
||||||
norm = ShapePoints[ j ].normal.x * parallel2;
|
norm = ShapePoints[ j ].normal.x * parallel2;
|
||||||
norm.y += ShapePoints[ j ].normal.y;
|
norm.y += ShapePoints[ j ].normal.y;
|
||||||
|
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ public:
|
|||||||
r2 = fRoll2; }
|
r2 = fRoll2; }
|
||||||
|
|
||||||
bool
|
bool
|
||||||
RenderLoft( gfx::vertex_array &Output, Math3D::vector3 const &Origin, gfx::vertex_array const &ShapePoints, int iNumShapePoints, double fTextureLength, double Texturescale = 1.0, int iSkip = 0, int iEnd = 0, float fOffsetX = 0.f, glm::vec3 **p = nullptr, bool bRender = true);
|
RenderLoft( gfx::vertex_array &Output, Math3D::vector3 const &Origin, gfx::vertex_array const &ShapePoints, int iNumShapePoints, double fTextureLength, double Texturescale = 1.0, int iSkip = 0, int iEnd = 0, std::pair<float, float> fOffsetX = {0.f, 0.f}, glm::vec3 **p = nullptr, bool bRender = true );
|
||||||
/*
|
/*
|
||||||
void
|
void
|
||||||
Render();
|
Render();
|
||||||
|
|||||||
219
Texture.cpp
219
Texture.cpp
@@ -18,6 +18,7 @@ http://mozilla.org/MPL/2.0/.
|
|||||||
|
|
||||||
#include "GL/glew.h"
|
#include "GL/glew.h"
|
||||||
|
|
||||||
|
#include "application.h"
|
||||||
#include "utilities.h"
|
#include "utilities.h"
|
||||||
#include "Globals.h"
|
#include "Globals.h"
|
||||||
#include "Logs.h"
|
#include "Logs.h"
|
||||||
@@ -39,19 +40,24 @@ texture_manager::texture_manager() {
|
|||||||
void
|
void
|
||||||
opengl_texture::load() {
|
opengl_texture::load() {
|
||||||
|
|
||||||
if( name.size() < 3 ) { goto fail; }
|
if( type == "make:" ) {
|
||||||
|
// for generated texture we delay data creation until texture is bound
|
||||||
|
// this ensures the script will receive all simulation data it might potentially want
|
||||||
|
// as any binding will happen after simulation is loaded, initialized and running
|
||||||
|
// until then we supply data for a tiny 2x2 grey stub
|
||||||
|
make_stub();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
WriteLog( "Loading texture data from \"" + name + "\"", logtype::texture );
|
WriteLog( "Loading texture data from \"" + name + type + "\"", logtype::texture );
|
||||||
|
|
||||||
data_state = resource_state::loading;
|
data_state = resource_state::loading;
|
||||||
{
|
|
||||||
std::string const extension = name.substr( name.size() - 3, 3 );
|
|
||||||
|
|
||||||
if( extension == "dds" ) { load_DDS(); }
|
if( type == ".dds" ) { load_DDS(); }
|
||||||
else if( extension == "tga" ) { load_TGA(); }
|
else if( type == ".tga" ) { load_TGA(); }
|
||||||
else if( extension == "png" ) { load_PNG(); }
|
else if( type == ".png" ) { load_PNG(); }
|
||||||
else if( extension == "bmp" ) { load_BMP(); }
|
else if( type == ".bmp" ) { load_BMP(); }
|
||||||
else if( extension == "tex" ) { load_TEX(); }
|
else if( type == ".tex" ) { load_TEX(); }
|
||||||
else { goto fail; }
|
else { goto fail; }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,7 +76,7 @@ opengl_texture::load() {
|
|||||||
|
|
||||||
fail:
|
fail:
|
||||||
data_state = resource_state::failed;
|
data_state = resource_state::failed;
|
||||||
ErrorLog( "Bad texture: failed to load texture \"" + name + "\"" );
|
ErrorLog( "Bad texture: failed to load texture \"" + name + type + "\"" );
|
||||||
// NOTE: temporary workaround for texture assignment errors
|
// NOTE: temporary workaround for texture assignment errors
|
||||||
id = 0;
|
id = 0;
|
||||||
return;
|
return;
|
||||||
@@ -123,10 +129,48 @@ void opengl_texture::load_PNG()
|
|||||||
data_state = resource_state::good;
|
data_state = resource_state::good;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
opengl_texture::make_stub() {
|
||||||
|
|
||||||
|
data_width = 2;
|
||||||
|
data_height = 2;
|
||||||
|
data.resize( data_width * data_height * 3 );
|
||||||
|
std::fill( std::begin( data ), std::end( data ), static_cast<char>( 0xc0 ) );
|
||||||
|
data_mapcount = 1;
|
||||||
|
data_format = GL_RGB;
|
||||||
|
data_components = GL_RGB;
|
||||||
|
data_state = resource_state::good;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
opengl_texture::make_request() {
|
||||||
|
|
||||||
|
auto const components { Split( name, '?' ) };
|
||||||
|
auto const query { Split( components.back(), '&' ) };
|
||||||
|
|
||||||
|
PyObject *pythondictionary { nullptr };
|
||||||
|
Application.acquire_python_lock();
|
||||||
|
{
|
||||||
|
pythondictionary = PyDict_New();
|
||||||
|
if( pythondictionary != nullptr ) {
|
||||||
|
for( auto const &querypair : query ) {
|
||||||
|
auto const valuepos { querypair.find( '=' ) };
|
||||||
|
PyDict_SetItemString(
|
||||||
|
pythondictionary,
|
||||||
|
ToLower( querypair.substr( 0, valuepos ) ).c_str(),
|
||||||
|
PyGetString( querypair.substr( valuepos + 1 ).c_str() ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Application.release_python_lock();
|
||||||
|
|
||||||
|
Application.request( { ToLower( components.front() ), pythondictionary, id } );
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
opengl_texture::load_BMP() {
|
opengl_texture::load_BMP() {
|
||||||
|
|
||||||
std::ifstream file( name, std::ios::binary ); file.unsetf( std::ios::skipws );
|
std::ifstream file( name + type, std::ios::binary ); file.unsetf( std::ios::skipws );
|
||||||
|
|
||||||
BITMAPFILEHEADER header;
|
BITMAPFILEHEADER header;
|
||||||
|
|
||||||
@@ -250,7 +294,7 @@ DDSURFACEDESC2 opengl_texture::deserialize_ddsd(std::istream &s)
|
|||||||
void
|
void
|
||||||
opengl_texture::load_DDS() {
|
opengl_texture::load_DDS() {
|
||||||
|
|
||||||
std::ifstream file( name, std::ios::binary | std::ios::ate ); file.unsetf( std::ios::skipws );
|
std::ifstream file( name + type, std::ios::binary | std::ios::ate ); file.unsetf( std::ios::skipws );
|
||||||
std::size_t filesize = static_cast<size_t>(file.tellg()); // ios::ate already positioned us at the end of the file
|
std::size_t filesize = static_cast<size_t>(file.tellg()); // ios::ate already positioned us at the end of the file
|
||||||
file.seekg( 0, std::ios::beg ); // rewind the caret afterwards
|
file.seekg( 0, std::ios::beg ); // rewind the caret afterwards
|
||||||
|
|
||||||
@@ -308,12 +352,12 @@ opengl_texture::load_DDS() {
|
|||||||
data_width /= 2;
|
data_width /= 2;
|
||||||
data_height /= 2;
|
data_height /= 2;
|
||||||
--data_mapcount;
|
--data_mapcount;
|
||||||
WriteLog( "Texture size exceeds specified limits, skipping mipmap level" );
|
WriteLog( "Texture pixelcount exceeds specified limits, skipping mipmap level" );
|
||||||
};
|
};
|
||||||
|
|
||||||
if( data_mapcount <= 0 ) {
|
if( data_mapcount <= 0 ) {
|
||||||
// there's a chance we've discarded the provided mipmap(s) as too large
|
// there's a chance we've discarded the provided mipmap(s) as too large
|
||||||
WriteLog( "Texture \"" + name + "\" has no mipmaps which can fit currently set texture size limits." );
|
WriteLog( "Texture \"" + name + "\" has no mipmaps which can fit currently set texture pixelcount limits." );
|
||||||
data_state = resource_state::failed;
|
data_state = resource_state::failed;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -374,7 +418,7 @@ opengl_texture::load_DDS() {
|
|||||||
void
|
void
|
||||||
opengl_texture::load_TEX() {
|
opengl_texture::load_TEX() {
|
||||||
|
|
||||||
std::ifstream file( name, std::ios::binary ); file.unsetf( std::ios::skipws );
|
std::ifstream file( name + type, std::ios::binary ); file.unsetf( std::ios::skipws );
|
||||||
|
|
||||||
char head[ 5 ];
|
char head[ 5 ];
|
||||||
file.read( head, 4 );
|
file.read( head, 4 );
|
||||||
@@ -421,7 +465,7 @@ opengl_texture::load_TEX() {
|
|||||||
void
|
void
|
||||||
opengl_texture::load_TGA() {
|
opengl_texture::load_TGA() {
|
||||||
|
|
||||||
std::ifstream file( name, std::ios::binary ); file.unsetf( std::ios::skipws );
|
std::ifstream file( name + type, std::ios::binary ); file.unsetf( std::ios::skipws );
|
||||||
|
|
||||||
// Read the header of the TGA, compare it with the known headers for compressed and uncompressed TGAs
|
// Read the header of the TGA, compare it with the known headers for compressed and uncompressed TGAs
|
||||||
unsigned char tgaheader[ 18 ];
|
unsigned char tgaheader[ 18 ];
|
||||||
@@ -660,6 +704,12 @@ opengl_texture::create() {
|
|||||||
data = std::vector<char>();
|
data = std::vector<char>();
|
||||||
data_state = resource_state::none;
|
data_state = resource_state::none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( type == "make:" ) {
|
||||||
|
// for generated textures send a request to have the actual content of the texture generated
|
||||||
|
make_request();
|
||||||
|
}
|
||||||
|
|
||||||
is_ready = true;
|
is_ready = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -676,30 +726,36 @@ opengl_texture::release() {
|
|||||||
// if resource move is enabled we don't keep a cpu side copy after upload
|
// if resource move is enabled we don't keep a cpu side copy after upload
|
||||||
// so need to re-acquire the data before release
|
// so need to re-acquire the data before release
|
||||||
// TBD, TODO: instead of vram-ram transfer fetch the data 'normally' from the disk using worker thread
|
// TBD, TODO: instead of vram-ram transfer fetch the data 'normally' from the disk using worker thread
|
||||||
::glBindTexture( GL_TEXTURE_2D, id );
|
if( type == "make:" ) {
|
||||||
GLint datasize {};
|
// auto generated textures only store a stub
|
||||||
GLint iscompressed {};
|
make_stub();
|
||||||
::glGetTexLevelParameteriv( GL_TEXTURE_2D, 0, GL_TEXTURE_COMPRESSED, &iscompressed );
|
|
||||||
if( iscompressed == GL_TRUE ) {
|
|
||||||
// texture is compressed on the gpu side
|
|
||||||
// query texture details needed to perform the backup...
|
|
||||||
::glGetTexLevelParameteriv( GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &data_format );
|
|
||||||
::glGetTexLevelParameteriv( GL_TEXTURE_2D, 0, GL_TEXTURE_COMPRESSED_IMAGE_SIZE, &datasize );
|
|
||||||
data.resize( datasize );
|
|
||||||
// ...fetch the data...
|
|
||||||
::glGetCompressedTexImage( GL_TEXTURE_2D, 0, &data[ 0 ] );
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// for whatever reason texture didn't get compressed during upload
|
::glBindTexture( GL_TEXTURE_2D, id );
|
||||||
// fallback on plain rgba storage...
|
GLint datasize{};
|
||||||
data_format = GL_RGBA;
|
GLint iscompressed{};
|
||||||
data.resize( data_width * data_height * 4 );
|
::glGetTexLevelParameteriv( GL_TEXTURE_2D, 0, GL_TEXTURE_COMPRESSED, &iscompressed );
|
||||||
// ...fetch the data...
|
if( iscompressed == GL_TRUE ) {
|
||||||
::glGetTexImage( GL_TEXTURE_2D, 0, data_format, GL_UNSIGNED_BYTE, &data[ 0 ] );
|
// texture is compressed on the gpu side
|
||||||
|
// query texture details needed to perform the backup...
|
||||||
|
::glGetTexLevelParameteriv( GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &data_format );
|
||||||
|
::glGetTexLevelParameteriv( GL_TEXTURE_2D, 0, GL_TEXTURE_COMPRESSED_IMAGE_SIZE, &datasize );
|
||||||
|
data.resize( datasize );
|
||||||
|
// ...fetch the data...
|
||||||
|
::glGetCompressedTexImage( GL_TEXTURE_2D, 0, &data[ 0 ] );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// for whatever reason texture didn't get compressed during upload
|
||||||
|
// fallback on plain rgba storage...
|
||||||
|
data_format = GL_RGBA;
|
||||||
|
data.resize( data_width * data_height * 4 );
|
||||||
|
// ...fetch the data...
|
||||||
|
::glGetTexImage( GL_TEXTURE_2D, 0, data_format, GL_UNSIGNED_BYTE, &data[ 0 ] );
|
||||||
|
}
|
||||||
|
// ...and update texture object state
|
||||||
|
data_mapcount = 1; // we keep copy of only top mipmap level
|
||||||
|
data_state = resource_state::good;
|
||||||
}
|
}
|
||||||
// ...and update texture object state
|
|
||||||
data_mapcount = 1; // we keep copy of only top mipmap level
|
|
||||||
data_state = resource_state::good;
|
|
||||||
}
|
}
|
||||||
// release opengl resources
|
// release opengl resources
|
||||||
::glDeleteTextures( 1, &id );
|
::glDeleteTextures( 1, &id );
|
||||||
@@ -753,7 +809,7 @@ opengl_texture::downsize( GLuint const Format ) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
WriteLog( "Texture size exceeds specified limits, downsampling data" );
|
WriteLog( "Texture pixelcount exceeds specified limits, downsampling data" );
|
||||||
// trim potential odd texture sizes
|
// trim potential odd texture sizes
|
||||||
data_width -= ( data_width % 2 );
|
data_width -= ( data_width % 2 );
|
||||||
data_height -= ( data_height % 2 );
|
data_height -= ( data_height % 2 );
|
||||||
@@ -810,48 +866,77 @@ texture_manager::create( std::string Filename, bool const Loadnow ) {
|
|||||||
if( Filename.find( '|' ) != std::string::npos )
|
if( Filename.find( '|' ) != std::string::npos )
|
||||||
Filename.erase( Filename.find( '|' ) ); // po | może być nazwa kolejnej tekstury
|
Filename.erase( Filename.find( '|' ) ); // po | może być nazwa kolejnej tekstury
|
||||||
|
|
||||||
|
std::pair<std::string, std::string> locator; // resource name, resource type
|
||||||
std::string traits;
|
std::string traits;
|
||||||
auto const traitpos = Filename.find( ':' );
|
|
||||||
if( traitpos != std::string::npos ) {
|
// discern textures generated by a script
|
||||||
// po dwukropku mogą być podane dodatkowe informacje niebędące nazwą tekstury
|
// TBD: support file: for file resources?
|
||||||
if( Filename.size() > traitpos + 1 )
|
auto const isgenerated { Filename.find( "make:" ) == 0 };
|
||||||
traits = Filename.substr( traitpos + 1 );
|
// process supplied resource name
|
||||||
Filename.erase( traitpos );
|
if( isgenerated ) {
|
||||||
|
// generated resource
|
||||||
|
// scheme:(user@)path?query
|
||||||
|
|
||||||
|
// remove scheme indicator
|
||||||
|
Filename.erase( 0, Filename.find( ':' ) + 1 );
|
||||||
|
// TODO: extract traits specification from the query
|
||||||
|
// clean up slashes
|
||||||
|
erase_leading_slashes( Filename );
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
// regular file resource
|
||||||
|
// (filepath/)(#)filename.extension(:traits)
|
||||||
|
|
||||||
erase_extension( Filename );
|
// extract trait specifications
|
||||||
|
auto const traitpos = Filename.rfind( ':' );
|
||||||
if( Filename[ 0 ] == '/' ) {
|
if( traitpos != std::string::npos ) {
|
||||||
// filename can potentially begin with a slash, and we don't need it
|
// po dwukropku mogą być podane dodatkowe informacje niebędące nazwą tekstury
|
||||||
Filename.erase( 0, 1 );
|
if( Filename.size() > traitpos + 1 ) {
|
||||||
|
traits = Filename.substr( traitpos + 1 );
|
||||||
|
}
|
||||||
|
Filename.erase( traitpos );
|
||||||
|
}
|
||||||
|
// potentially trim file type indicator since we check for multiple types
|
||||||
|
erase_extension( Filename );
|
||||||
|
// clean up slashes
|
||||||
|
erase_leading_slashes( Filename );
|
||||||
|
// temporary code for legacy assets -- textures with names beginning with # are to be sharpened
|
||||||
|
if( ( Filename[ 0 ] == '#' )
|
||||||
|
|| ( Filename.find( "/#" ) != std::string::npos ) ) {
|
||||||
|
traits += '#';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// try to locate requested texture in the databank
|
// try to locate requested texture in the databank
|
||||||
auto lookup { find_in_databank( Filename ) };
|
// TBD, TODO: include trait specification in the resource id in the databank?
|
||||||
|
auto const lookup { find_in_databank( Filename ) };
|
||||||
if( lookup != npos ) {
|
if( lookup != npos ) {
|
||||||
return lookup;
|
return lookup;
|
||||||
}
|
}
|
||||||
// if we don't have the texture in the databank, check if it's on disk
|
// if the lookup fails...
|
||||||
auto const disklookup { find_on_disk( Filename ) };
|
if( isgenerated ) {
|
||||||
|
// TODO: verify presence of the generator script
|
||||||
if( true == disklookup.first.empty() ) {
|
locator.first = Filename;
|
||||||
// there's nothing matching in the databank nor on the disk, report failure
|
locator.second = "make:";
|
||||||
ErrorLog( "Bad file: failed do locate texture file \"" + Filename + "\"", logtype::file );
|
}
|
||||||
return npos;
|
else {
|
||||||
|
// ...for file resources check if it's on disk
|
||||||
|
locator = find_on_disk( Filename );
|
||||||
|
if( true == locator.first.empty() ) {
|
||||||
|
// there's nothing matching in the databank nor on the disk, report failure
|
||||||
|
ErrorLog( "Bad file: failed do locate texture file \"" + Filename + "\"", logtype::file );
|
||||||
|
return npos;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto texture = new opengl_texture();
|
auto texture = new opengl_texture();
|
||||||
texture->name = disklookup.first + disklookup.second;
|
texture->name = locator.first;
|
||||||
if( Filename.find('#') != std::string::npos ) {
|
texture->type = locator.second;
|
||||||
// temporary code for legacy assets -- textures with names beginning with # are to be sharpened
|
|
||||||
traits += '#';
|
|
||||||
}
|
|
||||||
texture->traits = traits;
|
texture->traits = traits;
|
||||||
auto const textureindex = (texture_handle)m_textures.size();
|
auto const textureindex = (texture_handle)m_textures.size();
|
||||||
m_textures.emplace_back( texture, std::chrono::steady_clock::time_point() );
|
m_textures.emplace_back( texture, std::chrono::steady_clock::time_point() );
|
||||||
m_texturemappings.emplace( disklookup.first, textureindex );
|
m_texturemappings.emplace( locator.first, textureindex );
|
||||||
|
|
||||||
WriteLog( "Created texture object for \"" + disklookup.first + disklookup.second + "\"", logtype::texture );
|
WriteLog( "Created texture object for \"" + locator.first + "\"", logtype::texture );
|
||||||
|
|
||||||
if( true == Loadnow ) {
|
if( true == Loadnow ) {
|
||||||
|
|
||||||
@@ -1009,7 +1094,7 @@ texture_manager::find_on_disk( std::string const &Texturename ) const {
|
|||||||
return (
|
return (
|
||||||
FileExists(
|
FileExists(
|
||||||
filenames,
|
filenames,
|
||||||
{ ".dds", ".tga", ".bmp", ".ext" } ) );
|
{ ".dds", ".tga", ".png", ".bmp", ".ext" } ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -46,10 +46,13 @@ struct opengl_texture {
|
|||||||
bool is_ready{ false }; // indicates the texture was processed and is ready for use
|
bool is_ready{ false }; // indicates the texture was processed and is ready for use
|
||||||
std::string traits; // requested texture attributes: wrapping modes etc
|
std::string traits; // requested texture attributes: wrapping modes etc
|
||||||
std::string name; // name of the texture source file
|
std::string name; // name of the texture source file
|
||||||
|
std::string type; // type of the texture source file
|
||||||
std::size_t size{ 0 }; // size of the texture data, in kb
|
std::size_t size{ 0 }; // size of the texture data, in kb
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// methods
|
// methods
|
||||||
|
void make_stub();
|
||||||
|
void make_request();
|
||||||
void load_BMP();
|
void load_BMP();
|
||||||
void load_PNG();
|
void load_PNG();
|
||||||
void load_DDS();
|
void load_DDS();
|
||||||
|
|||||||
408
Track.cpp
408
Track.cpp
@@ -25,6 +25,7 @@ http://mozilla.org/MPL/2.0/.
|
|||||||
#include "Timer.h"
|
#include "Timer.h"
|
||||||
#include "Logs.h"
|
#include "Logs.h"
|
||||||
#include "renderer.h"
|
#include "renderer.h"
|
||||||
|
#include "utilities.h"
|
||||||
|
|
||||||
// 101206 Ra: trapezoidalne drogi i tory
|
// 101206 Ra: trapezoidalne drogi i tory
|
||||||
// 110720 Ra: rozprucie zwrotnicy i odcinki izolowane
|
// 110720 Ra: rozprucie zwrotnicy i odcinki izolowane
|
||||||
@@ -42,6 +43,9 @@ const int iProsto3[4] = {1, -1, 2, 1}; // segmenty do jazdy prosto
|
|||||||
const int iEnds3[13] = {3, 0, 2, 1, 2, 0, -1, 1, 0, 2, 0, 3, 1}; // numer sąsiedniego toru na końcu segmentu "-1"
|
const int iEnds3[13] = {3, 0, 2, 1, 2, 0, -1, 1, 0, 2, 0, 3, 1}; // numer sąsiedniego toru na końcu segmentu "-1"
|
||||||
TIsolated *TIsolated::pRoot = NULL;
|
TIsolated *TIsolated::pRoot = NULL;
|
||||||
|
|
||||||
|
TTrack::profiles_array TTrack::m_profiles;
|
||||||
|
TTrack::profiles_map TTrack::m_profilesmap;
|
||||||
|
|
||||||
TSwitchExtension::TSwitchExtension(TTrack *owner, int const what)
|
TSwitchExtension::TSwitchExtension(TTrack *owner, int const what)
|
||||||
{ // na początku wszystko puste
|
{ // na początku wszystko puste
|
||||||
pNexts[0] = nullptr; // wskaźniki do kolejnych odcinków ruchu
|
pNexts[0] = nullptr; // wskaźniki do kolejnych odcinków ruchu
|
||||||
@@ -523,8 +527,10 @@ void TTrack::Load(cParser *parser, glm::dvec3 const &pOrigin)
|
|||||||
|
|
||||||
if (iCategoryFlag & 1)
|
if (iCategoryFlag & 1)
|
||||||
{ // zero na główce szyny
|
{ // zero na główce szyny
|
||||||
p1.y += 0.18;
|
// TODO: delay these calculations unti rail profile and thus height is known
|
||||||
p2.y += 0.18;
|
auto const railheight { 0.18 };
|
||||||
|
p1.y += railheight;
|
||||||
|
p2.y += railheight;
|
||||||
// na przechyłce doliczyć jeszcze pół przechyłki
|
// na przechyłce doliczyć jeszcze pół przechyłki
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -618,8 +624,10 @@ void TTrack::Load(cParser *parser, glm::dvec3 const &pOrigin)
|
|||||||
|
|
||||||
if (iCategoryFlag & 1)
|
if (iCategoryFlag & 1)
|
||||||
{ // zero na główce szyny
|
{ // zero na główce szyny
|
||||||
p1.y += 0.18;
|
// TODO: delay these calculations unti rail profile and thus height is known
|
||||||
p2.y += 0.18;
|
auto const railheight { 0.18 };
|
||||||
|
p1.y += railheight;
|
||||||
|
p2.y += railheight;
|
||||||
// na przechyłce doliczyć jeszcze pół przechyłki?
|
// na przechyłce doliczyć jeszcze pół przechyłki?
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -680,8 +688,10 @@ void TTrack::Load(cParser *parser, glm::dvec3 const &pOrigin)
|
|||||||
|
|
||||||
if (iCategoryFlag & 1)
|
if (iCategoryFlag & 1)
|
||||||
{ // zero na główce szyny
|
{ // zero na główce szyny
|
||||||
p3.y += 0.18;
|
// TODO: delay these calculations unti rail profile and thus height is known
|
||||||
p4.y += 0.18;
|
auto const railheight{ 0.18 };
|
||||||
|
p3.y += railheight;
|
||||||
|
p4.y += railheight;
|
||||||
// na przechyłce doliczyć jeszcze pół przechyłki?
|
// na przechyłce doliczyć jeszcze pół przechyłki?
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -877,8 +887,15 @@ void TTrack::Load(cParser *parser, glm::dvec3 const &pOrigin)
|
|||||||
SwitchExtension->m_material3 = GfxRenderer.Fetch_Material( trackbedtexture );
|
SwitchExtension->m_material3 = GfxRenderer.Fetch_Material( trackbedtexture );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if( str == "railprofile" ) {
|
||||||
|
// rail profile
|
||||||
|
auto const railprofile { parser->getToken<std::string>() };
|
||||||
|
if( iCategoryFlag == 1 ) {
|
||||||
|
m_profile1 = fetch_track_rail_profile( railprofile );
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
ErrorLog("Unknown property: \"" + str + "\" in track \"" + m_name + "\"");
|
ErrorLog("Bad track: unknown property: \"" + str + "\" defined for track \"" + m_name + "\"");
|
||||||
parser->getTokens();
|
parser->getTokens();
|
||||||
*parser >> token;
|
*parser >> token;
|
||||||
str = token;
|
str = token;
|
||||||
@@ -1010,41 +1027,6 @@ bool TTrack::AddDynamicObject(TDynamicObject *Dynamic)
|
|||||||
};
|
};
|
||||||
|
|
||||||
const int numPts = 4;
|
const int numPts = 4;
|
||||||
const int nnumPts = 12;
|
|
||||||
|
|
||||||
// szyna - vextor6(x,y,mapowanie tekstury,xn,yn,zn)
|
|
||||||
// tę wersję opracował Tolein (bez pochylenia)
|
|
||||||
// TODO: profile definitions in external files
|
|
||||||
gfx::basic_vertex const szyna[ nnumPts ] = {
|
|
||||||
{{ 0.111f, -0.180f, 0.f}, { 1.000f, 0.000f, 0.f}, {0.00f, 0.f}},
|
|
||||||
{{ 0.046f, -0.150f, 0.f}, { 0.707f, 0.707f, 0.f}, {0.15f, 0.f}},
|
|
||||||
{{ 0.044f, -0.050f, 0.f}, { 0.707f, -0.707f, 0.f}, {0.25f, 0.f}},
|
|
||||||
{{ 0.073f, -0.038f, 0.f}, { 0.707f, -0.707f, 0.f}, {0.35f, 0.f}},
|
|
||||||
{{ 0.072f, -0.010f, 0.f}, { 0.707f, 0.707f, 0.f}, {0.40f, 0.f}},
|
|
||||||
{{ 0.052f, -0.000f, 0.f}, { 0.000f, 1.000f, 0.f}, {0.45f, 0.f}},
|
|
||||||
{{ 0.020f, -0.000f, 0.f}, { 0.000f, 1.000f, 0.f}, {0.55f, 0.f}},
|
|
||||||
{{ 0.000f, -0.010f, 0.f}, {-0.707f, 0.707f, 0.f}, {0.60f, 0.f}},
|
|
||||||
{{-0.001f, -0.038f, 0.f}, {-0.707f, -0.707f, 0.f}, {0.65f, 0.f}},
|
|
||||||
{{ 0.028f, -0.050f, 0.f}, {-0.707f, -0.707f, 0.f}, {0.75f, 0.f}},
|
|
||||||
{{ 0.026f, -0.150f, 0.f}, {-0.707f, 0.707f, 0.f}, {0.85f, 0.f}},
|
|
||||||
{{-0.039f, -0.180f, 0.f}, {-1.000f, 0.000f, 0.f}, {1.00f, 0.f}} };
|
|
||||||
|
|
||||||
// iglica - vextor3(x,y,mapowanie tekstury)
|
|
||||||
// 1 mm więcej, żeby nie nachodziły tekstury?
|
|
||||||
// TODO: automatic generation from base profile TBD: reuse base profile?
|
|
||||||
gfx::basic_vertex const iglica[ nnumPts ] = {
|
|
||||||
{{ 0.010f, -0.180f, 0.f}, { 1.000f, 0.000f, 0.f}, {0.00f, 0.f}},
|
|
||||||
{{ 0.010f, -0.155f, 0.f}, { 1.000f, 0.000f, 0.f}, {0.15f, 0.f}},
|
|
||||||
{{ 0.010f, -0.070f, 0.f}, { 1.000f, 0.000f, 0.f}, {0.25f, 0.f}},
|
|
||||||
{{ 0.010f, -0.040f, 0.f}, { 1.000f, 0.000f, 0.f}, {0.35f, 0.f}},
|
|
||||||
{{ 0.010f, -0.010f, 0.f}, { 1.000f, 0.000f, 0.f}, {0.40f, 0.f}},
|
|
||||||
{{ 0.010f, -0.000f, 0.f}, { 0.707f, 0.707f, 0.f}, {0.45f, 0.f}},
|
|
||||||
{{ 0.000f, -0.000f, 0.f}, { 0.707f, 0.707f, 0.f}, {0.55f, 0.f}},
|
|
||||||
{{ 0.000f, -0.010f, 0.f}, {-1.000f, 0.000f, 0.f}, {0.60f, 0.f}},
|
|
||||||
{{ 0.000f, -0.040f, 0.f}, {-1.000f, 0.000f, 0.f}, {0.65f, 0.f}},
|
|
||||||
{{ 0.000f, -0.070f, 0.f}, {-1.000f, 0.000f, 0.f}, {0.75f, 0.f}},
|
|
||||||
{{ 0.000f, -0.155f, 0.f}, {-0.707f, 0.707f, 0.f}, {0.85f, 0.f}},
|
|
||||||
{{-0.040f, -0.180f, 0.f}, {-1.000f, 0.000f, 0.f}, {1.00f, 0.f}} };
|
|
||||||
|
|
||||||
bool TTrack::CheckDynamicObject(TDynamicObject *Dynamic)
|
bool TTrack::CheckDynamicObject(TDynamicObject *Dynamic)
|
||||||
{ // sprawdzenie, czy pojazd jest przypisany do toru
|
{ // sprawdzenie, czy pojazd jest przypisany do toru
|
||||||
@@ -1167,6 +1149,7 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) {
|
|||||||
}
|
}
|
||||||
if (m_material1)
|
if (m_material1)
|
||||||
{ // szyny - generujemy dwie, najwyżej rysować się będzie jedną
|
{ // szyny - generujemy dwie, najwyżej rysować się będzie jedną
|
||||||
|
auto const nnumPts { track_rail_profile( m_profile1.second ).size() / 2 };
|
||||||
auto const texturelength { texture_length( m_material1 ) };
|
auto const texturelength { texture_length( m_material1 ) };
|
||||||
gfx::vertex_array vertices;
|
gfx::vertex_array vertices;
|
||||||
if( ( Bank != 0 ) && ( true == Geometry1.empty() ) ) {
|
if( ( Bank != 0 ) && ( true == Geometry1.empty() ) ) {
|
||||||
@@ -1193,34 +1176,39 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) {
|
|||||||
create_track_blade_profile( rpts3, rpts4 );
|
create_track_blade_profile( rpts3, rpts4 );
|
||||||
// TODO, TBD: change all track geometry to triangles, to allow packing data in less, larger buffers
|
// TODO, TBD: change all track geometry to triangles, to allow packing data in less, larger buffers
|
||||||
auto const bladelength { static_cast<int>( std::ceil( SwitchExtension->Segments[ 0 ]->RaSegCount() * 0.65 ) ) };
|
auto const bladelength { static_cast<int>( std::ceil( SwitchExtension->Segments[ 0 ]->RaSegCount() * 0.65 ) ) };
|
||||||
|
auto const nnumPts { track_rail_profile( m_profile1.second ).size() / 2 };
|
||||||
if (SwitchExtension->RightSwitch)
|
if (SwitchExtension->RightSwitch)
|
||||||
{ // nowa wersja z SPKS, ale odwrotnie lewa/prawa
|
{ // nowa wersja z SPKS, ale odwrotnie lewa/prawa
|
||||||
gfx::vertex_array vertices;
|
gfx::vertex_array vertices;
|
||||||
if( m_material1 ) {
|
if( m_material1 ) {
|
||||||
auto const texturelength { texture_length( m_material1 ) };
|
auto const texturelength { texture_length( m_material1 ) };
|
||||||
// fixed parts
|
// left blade
|
||||||
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts2, nnumPts, texturelength );
|
// composed from two parts: transition from blade to regular rail, and regular rail
|
||||||
|
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts3, -nnumPts, texturelength, 1.0, 0, bladelength / 2, { SwitchExtension->fOffset2, SwitchExtension->fOffset2 / 2 } );
|
||||||
|
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts1, nnumPts, texturelength, 1.0, bladelength / 2, bladelength, { SwitchExtension->fOffset2 / 2, 0.f } );
|
||||||
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||||
vertices.clear();
|
vertices.clear();
|
||||||
|
// fixed parts
|
||||||
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts1, nnumPts, texturelength, 1.0, bladelength );
|
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts1, nnumPts, texturelength, 1.0, bladelength );
|
||||||
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||||
vertices.clear();
|
vertices.clear();
|
||||||
// left blade
|
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts2, nnumPts, texturelength );
|
||||||
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts3, -nnumPts, texturelength, 1.0, 0, bladelength, SwitchExtension->fOffset2 );
|
|
||||||
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||||
vertices.clear();
|
vertices.clear();
|
||||||
}
|
}
|
||||||
if( m_material2 ) {
|
if( m_material2 ) {
|
||||||
auto const texturelength { texture_length( m_material2 ) };
|
auto const texturelength { texture_length( m_material2 ) };
|
||||||
// fixed parts
|
// right blade
|
||||||
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts1, nnumPts, texturelength );
|
// composed from two parts: transition from blade to regular rail, and regular rail
|
||||||
|
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts4, -nnumPts, texturelength, 1.0, 0, bladelength / 2, { -fMaxOffset + SwitchExtension->fOffset1, ( -fMaxOffset + SwitchExtension->fOffset1 ) / 2 } );
|
||||||
|
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts2, nnumPts, texturelength, 1.0, bladelength / 2, bladelength, { ( -fMaxOffset + SwitchExtension->fOffset1 ) / 2, 0.f } );
|
||||||
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||||
vertices.clear();
|
vertices.clear();
|
||||||
|
// fixed parts
|
||||||
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts2, nnumPts, texturelength, 1.0, bladelength );
|
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts2, nnumPts, texturelength, 1.0, bladelength );
|
||||||
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||||
vertices.clear();
|
vertices.clear();
|
||||||
// right blade
|
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts1, nnumPts, texturelength );
|
||||||
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts4, -nnumPts, texturelength, 1.0, 0, bladelength, -fMaxOffset + SwitchExtension->fOffset1 );
|
|
||||||
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||||
vertices.clear();
|
vertices.clear();
|
||||||
}
|
}
|
||||||
@@ -1230,29 +1218,33 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) {
|
|||||||
gfx::vertex_array vertices;
|
gfx::vertex_array vertices;
|
||||||
if( m_material1 ) {
|
if( m_material1 ) {
|
||||||
auto const texturelength { texture_length( m_material1 ) };
|
auto const texturelength { texture_length( m_material1 ) };
|
||||||
// fixed parts
|
// right blade
|
||||||
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts1, nnumPts, texturelength ); // lewa szyna normalna cała
|
// composed from two parts: transition from blade to regular rail, and regular rail
|
||||||
|
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts4, -nnumPts, texturelength, 1.0, 0, bladelength / 2, { -SwitchExtension->fOffset2, -SwitchExtension->fOffset2 / 2 } );
|
||||||
|
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts2, nnumPts, texturelength, 1.0, bladelength / 2, bladelength, { -SwitchExtension->fOffset2 / 2, 0.f } );
|
||||||
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||||
vertices.clear();
|
vertices.clear();
|
||||||
|
// fixed parts
|
||||||
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts2, nnumPts, texturelength, 1.0, bladelength ); // prawa szyna za iglicą
|
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts2, nnumPts, texturelength, 1.0, bladelength ); // prawa szyna za iglicą
|
||||||
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||||
vertices.clear();
|
vertices.clear();
|
||||||
// right blade
|
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts1, nnumPts, texturelength ); // lewa szyna normalna cała
|
||||||
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts4, -nnumPts, texturelength, 1.0, 0, bladelength, -SwitchExtension->fOffset2 );
|
|
||||||
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||||
vertices.clear();
|
vertices.clear();
|
||||||
}
|
}
|
||||||
if( m_material2 ) {
|
if( m_material2 ) {
|
||||||
auto const texturelength { texture_length( m_material2 ) };
|
auto const texturelength { texture_length( m_material2 ) };
|
||||||
// fixed parts
|
// left blade
|
||||||
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts2, nnumPts, texturelength ); // prawa szyna normalnie cała
|
// composed from two parts: transition from blade to regular rail, and regular rail
|
||||||
|
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts3, -nnumPts, texturelength, 1.0, 0, bladelength / 2, { fMaxOffset - SwitchExtension->fOffset1, ( fMaxOffset - SwitchExtension->fOffset1 ) / 2 } );
|
||||||
|
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts1, nnumPts, texturelength, 1.0, bladelength / 2, bladelength, { ( fMaxOffset - SwitchExtension->fOffset1 ) / 2, 0.f } );
|
||||||
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||||
vertices.clear();
|
vertices.clear();
|
||||||
|
// fixed parts
|
||||||
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts1, nnumPts, texturelength, 1.0, bladelength ); // lewa szyna za iglicą
|
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts1, nnumPts, texturelength, 1.0, bladelength ); // lewa szyna za iglicą
|
||||||
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||||
vertices.clear();
|
vertices.clear();
|
||||||
// left blade
|
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts2, nnumPts, texturelength ); // prawa szyna normalnie cała
|
||||||
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts3, -nnumPts, texturelength, 1.0, 0, bladelength, fMaxOffset - SwitchExtension->fOffset1 );
|
|
||||||
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||||
vertices.clear();
|
vertices.clear();
|
||||||
}
|
}
|
||||||
@@ -1393,22 +1385,22 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) {
|
|||||||
if (SwitchExtension->iRoads == 4)
|
if (SwitchExtension->iRoads == 4)
|
||||||
{ // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony odcinka
|
{ // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony odcinka
|
||||||
if( ( fTexHeight1 >= 0.0 ) || ( side != 0.0 ) ) {
|
if( ( fTexHeight1 >= 0.0 ) || ( side != 0.0 ) ) {
|
||||||
SwitchExtension->Segments[ 2 ]->RenderLoft( vertices, m_origin, rpts2, -3, texturelength, 1.0, 0, 0, 0.0, &b, render );
|
SwitchExtension->Segments[ 2 ]->RenderLoft( vertices, m_origin, rpts2, -3, texturelength, 1.0, 0, 0, {}, &b, render );
|
||||||
if( true == render ) {
|
if( true == render ) {
|
||||||
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||||
vertices.clear();
|
vertices.clear();
|
||||||
}
|
}
|
||||||
SwitchExtension->Segments[ 3 ]->RenderLoft( vertices, m_origin, rpts2, -3, texturelength, 1.0, 0, 0, 0.0, &b, render );
|
SwitchExtension->Segments[ 3 ]->RenderLoft( vertices, m_origin, rpts2, -3, texturelength, 1.0, 0, 0, {}, &b, render );
|
||||||
if( true == render ) {
|
if( true == render ) {
|
||||||
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||||
vertices.clear();
|
vertices.clear();
|
||||||
}
|
}
|
||||||
SwitchExtension->Segments[ 4 ]->RenderLoft( vertices, m_origin, rpts2, -3, texturelength, 1.0, 0, 0, 0.0, &b, render );
|
SwitchExtension->Segments[ 4 ]->RenderLoft( vertices, m_origin, rpts2, -3, texturelength, 1.0, 0, 0, {}, &b, render );
|
||||||
if( true == render ) {
|
if( true == render ) {
|
||||||
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||||
vertices.clear();
|
vertices.clear();
|
||||||
}
|
}
|
||||||
SwitchExtension->Segments[ 5 ]->RenderLoft( vertices, m_origin, rpts2, -3, texturelength, 1.0, 0, 0, 0.0, &b, render );
|
SwitchExtension->Segments[ 5 ]->RenderLoft( vertices, m_origin, rpts2, -3, texturelength, 1.0, 0, 0, {}, &b, render );
|
||||||
if( true == render ) {
|
if( true == render ) {
|
||||||
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||||
vertices.clear();
|
vertices.clear();
|
||||||
@@ -1418,17 +1410,17 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) {
|
|||||||
else {
|
else {
|
||||||
// punkt 3 pokrywa się z punktem 1, jak w zwrotnicy; połączenie 1->2 nie musi być prostoliniowe
|
// 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 ) ) {
|
if( ( fTexHeight1 >= 0.0 ) || ( side != 0.0 ) ) {
|
||||||
SwitchExtension->Segments[ 2 ]->RenderLoft( vertices, m_origin, rpts2, -3, texturelength, 1.0, 0, 0, 0.0, &b, render ); // z P2 do P4
|
SwitchExtension->Segments[ 2 ]->RenderLoft( vertices, m_origin, rpts2, -3, texturelength, 1.0, 0, 0, {}, &b, render ); // z P2 do P4
|
||||||
if( true == render ) {
|
if( true == render ) {
|
||||||
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||||
vertices.clear();
|
vertices.clear();
|
||||||
}
|
}
|
||||||
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts2, -3, texturelength, 1.0, 0, 0, 0.0, &b, render ); // z P4 do P3=P1 (odwrócony)
|
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts2, -3, texturelength, 1.0, 0, 0, {}, &b, render ); // z P4 do P3=P1 (odwrócony)
|
||||||
if( true == render ) {
|
if( true == render ) {
|
||||||
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||||
vertices.clear();
|
vertices.clear();
|
||||||
}
|
}
|
||||||
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts2, -3, texturelength, 1.0, 0, 0, 0.0, &b, render ); // z P1 do P2
|
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts2, -3, texturelength, 1.0, 0, 0, {}, &b, render ); // z P1 do P2
|
||||||
if( true == render ) {
|
if( true == render ) {
|
||||||
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||||
vertices.clear();
|
vertices.clear();
|
||||||
@@ -1790,24 +1782,31 @@ TTrack * TTrack::RaAnimate()
|
|||||||
&& ( ( false == Geometry1.empty() )
|
&& ( ( false == Geometry1.empty() )
|
||||||
|| ( false == Geometry2.empty() ) ) ) {
|
|| ( false == Geometry2.empty() ) ) ) {
|
||||||
// iglice liczone tylko dla zwrotnic
|
// iglice liczone tylko dla zwrotnic
|
||||||
|
gfx::vertex_array rpts1, rpts2;
|
||||||
|
create_track_rail_profile( rpts1, rpts2 );
|
||||||
gfx::vertex_array rpts3, rpts4;
|
gfx::vertex_array rpts3, rpts4;
|
||||||
create_track_blade_profile( rpts3, rpts4 );
|
create_track_blade_profile( rpts3, rpts4 );
|
||||||
gfx::vertex_array vertices;
|
gfx::vertex_array vertices;
|
||||||
auto const bladelength { static_cast<int>( std::ceil( SwitchExtension->Segments[ 0 ]->RaSegCount() * 0.65 ) ) };
|
auto const bladelength { static_cast<int>( std::ceil( SwitchExtension->Segments[ 0 ]->RaSegCount() * 0.65 ) ) };
|
||||||
|
auto const nnumPts { track_rail_profile( m_profile1.second ).size() / 2 };
|
||||||
if (SwitchExtension->RightSwitch)
|
if (SwitchExtension->RightSwitch)
|
||||||
{ // nowa wersja z SPKS, ale odwrotnie lewa/prawa
|
{ // nowa wersja z SPKS, ale odwrotnie lewa/prawa
|
||||||
if( m_material1 ) {
|
if( m_material1 ) {
|
||||||
auto const texturelength { texture_length( m_material1 ) };
|
auto const texturelength { texture_length( m_material1 ) };
|
||||||
// left blade
|
// left blade
|
||||||
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts3, -nnumPts, texturelength, 1.0, 0, bladelength, SwitchExtension->fOffset2 );
|
// composed from two parts: transition from blade to regular rail, and regular rail
|
||||||
GfxRenderer.Replace( vertices, Geometry1[ 2 ] );
|
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts3, -nnumPts, texturelength, 1.0, 0, bladelength / 2, { SwitchExtension->fOffset2, SwitchExtension->fOffset2 / 2 } );
|
||||||
|
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts1, nnumPts, texturelength, 1.0, bladelength / 2, bladelength, { SwitchExtension->fOffset2 / 2, 0.f } );
|
||||||
|
GfxRenderer.Replace( vertices, Geometry1[ 0 ] );
|
||||||
vertices.clear();
|
vertices.clear();
|
||||||
}
|
}
|
||||||
if( m_material2 ) {
|
if( m_material2 ) {
|
||||||
auto const texturelength { texture_length( m_material2 ) };
|
auto const texturelength { texture_length( m_material2 ) };
|
||||||
// right blade
|
// right blade
|
||||||
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts4, -nnumPts, texturelength, 1.0, 0, bladelength, -fMaxOffset + SwitchExtension->fOffset1 );
|
// composed from two parts: transition from blade to regular rail, and regular rail
|
||||||
GfxRenderer.Replace( vertices, Geometry2[ 2 ] );
|
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts4, -nnumPts, texturelength, 1.0, 0, bladelength / 2, { -fMaxOffset + SwitchExtension->fOffset1, ( -fMaxOffset + SwitchExtension->fOffset1 ) / 2 } );
|
||||||
|
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts2, nnumPts, texturelength, 1.0, bladelength / 2, bladelength, { ( -fMaxOffset + SwitchExtension->fOffset1 ) / 2, 0.f } );
|
||||||
|
GfxRenderer.Replace( vertices, Geometry2[ 0 ] );
|
||||||
vertices.clear();
|
vertices.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1815,15 +1814,19 @@ TTrack * TTrack::RaAnimate()
|
|||||||
if( m_material1 ) {
|
if( m_material1 ) {
|
||||||
auto const texturelength { texture_length( m_material1 ) };
|
auto const texturelength { texture_length( m_material1 ) };
|
||||||
// right blade
|
// right blade
|
||||||
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts4, -nnumPts, texturelength, 1.0, 0, bladelength, -SwitchExtension->fOffset2 );
|
// composed from two parts: transition from blade to regular rail, and regular rail
|
||||||
GfxRenderer.Replace( vertices, Geometry1[ 2 ] );
|
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts4, -nnumPts, texturelength, 1.0, 0, bladelength / 2, { -SwitchExtension->fOffset2, -SwitchExtension->fOffset2 / 2 } );
|
||||||
|
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts2, nnumPts, texturelength, 1.0, bladelength / 2, bladelength, { -SwitchExtension->fOffset2 / 2, 0.f } );
|
||||||
|
GfxRenderer.Replace( vertices, Geometry1[ 0 ] );
|
||||||
vertices.clear();
|
vertices.clear();
|
||||||
}
|
}
|
||||||
if( m_material2 ) {
|
if( m_material2 ) {
|
||||||
auto const texturelength { texture_length( m_material2 ) };
|
auto const texturelength { texture_length( m_material2 ) };
|
||||||
// left blade
|
// left blade
|
||||||
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts3, -nnumPts, texturelength, 1.0, 0, bladelength, fMaxOffset - SwitchExtension->fOffset1 );
|
// composed from two parts: transition from blade to regular rail, and regular rail
|
||||||
GfxRenderer.Replace( vertices, Geometry2[ 2 ] );
|
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts3, -nnumPts, texturelength, 1.0, 0, bladelength / 2, { fMaxOffset - SwitchExtension->fOffset1, ( fMaxOffset - SwitchExtension->fOffset1 ) / 2 } );
|
||||||
|
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts1, nnumPts, texturelength, 1.0, bladelength / 2, bladelength, { ( fMaxOffset - SwitchExtension->fOffset1 ) / 2, 0.f } );
|
||||||
|
GfxRenderer.Replace( vertices, Geometry2[ 0 ] );
|
||||||
vertices.clear();
|
vertices.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2156,12 +2159,122 @@ TTrack::export_as_text_( std::ostream &Output ) const {
|
|||||||
if( fVerticalRadius != 0.f ) {
|
if( fVerticalRadius != 0.f ) {
|
||||||
Output << "vradius " << fVerticalRadius << ' ';
|
Output << "vradius " << fVerticalRadius << ' ';
|
||||||
}
|
}
|
||||||
|
if( ( eType == tt_Switch )
|
||||||
|
&& ( SwitchExtension->m_material3 != null_handle ) ) {
|
||||||
|
auto texturefile { GfxRenderer.Material( m_material2 ).name };
|
||||||
|
if( texturefile.find( szTexturePath ) == 0 ) {
|
||||||
|
// don't include 'textures/' in the path
|
||||||
|
texturefile.erase( 0, std::string{ szTexturePath }.size() );
|
||||||
|
}
|
||||||
|
Output << "trackbed " << texturefile << ' ';
|
||||||
|
}
|
||||||
// footer
|
// footer
|
||||||
Output
|
Output
|
||||||
<< "endtrack"
|
<< "endtrack"
|
||||||
<< "\n";
|
<< "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// locates specified profile in the profile database, potentially loading it from a file
|
||||||
|
// returns: pair <profile name, profile handle>
|
||||||
|
std::pair<std::string, int>
|
||||||
|
TTrack::fetch_track_rail_profile( std::string const &Profile ) {
|
||||||
|
|
||||||
|
auto const railprofilepath { std::string( szModelPath ) + "tory/railprofile_" };
|
||||||
|
auto const railkeyprefix { std::string( "rail_" ) };
|
||||||
|
|
||||||
|
if( m_profiles.empty() ) {
|
||||||
|
// ensure the default profile is always first in the database
|
||||||
|
fetch_default_profiles();
|
||||||
|
}
|
||||||
|
// try to locate specified rail profile...
|
||||||
|
auto const lookup { m_profilesmap.find( railkeyprefix + Profile ) };
|
||||||
|
if( lookup != m_profilesmap.end() ) {
|
||||||
|
// ...if it works, we're done...
|
||||||
|
return { Profile, lookup->second };
|
||||||
|
}
|
||||||
|
// ... and if it fails try to add the profile to the database from a data file
|
||||||
|
auto profilehandle { 0 }; // fallback link to default profile if loading it fails
|
||||||
|
auto profiledata { deserialize_profile( railprofilepath + Profile ) };
|
||||||
|
if( false == profiledata.empty() ) {
|
||||||
|
// if we get the profile data add it to the database and calculate a link to it
|
||||||
|
profilehandle = static_cast<int>( m_profiles.size() );
|
||||||
|
m_profiles.emplace_back( profiledata );
|
||||||
|
}
|
||||||
|
m_profilesmap.emplace( railkeyprefix + Profile, profilehandle );
|
||||||
|
return { Profile, profilehandle };
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TTrack::fetch_default_profiles() {
|
||||||
|
|
||||||
|
if( false == m_profiles.empty() ) { return; }
|
||||||
|
|
||||||
|
auto const railprofilepath { std::string( szModelPath ) + "tory/railprofile_" };
|
||||||
|
auto const railkeyprefix { std::string( "rail_" ) };
|
||||||
|
|
||||||
|
m_profiles.emplace_back( deserialize_profile( railprofilepath + "default" ) );
|
||||||
|
if( m_profiles.back().empty() ) {
|
||||||
|
// fallback to prevent utter start failure, supply legacy track profile
|
||||||
|
m_profiles.back() = {
|
||||||
|
// szyna - vextor6(x,y,mapowanie tekstury,xn,yn,zn)
|
||||||
|
// tę wersję opracował Tolein (bez pochylenia)
|
||||||
|
{{ 0.111f, -0.180f, 0.f}, { 1.000f, 0.000f, 0.f}, {0.00f, 0.f}},
|
||||||
|
{{ 0.046f, -0.150f, 0.f}, { 0.707f, 0.707f, 0.f}, {0.15f, 0.f}},
|
||||||
|
{{ 0.044f, -0.050f, 0.f}, { 0.707f, -0.707f, 0.f}, {0.25f, 0.f}},
|
||||||
|
{{ 0.073f, -0.038f, 0.f}, { 0.707f, -0.707f, 0.f}, {0.35f, 0.f}},
|
||||||
|
{{ 0.072f, -0.010f, 0.f}, { 0.707f, 0.707f, 0.f}, {0.40f, 0.f}},
|
||||||
|
{{ 0.052f, -0.000f, 0.f}, { 0.000f, 1.000f, 0.f}, {0.45f, 0.f}},
|
||||||
|
{{ 0.020f, -0.000f, 0.f}, { 0.000f, 1.000f, 0.f}, {0.55f, 0.f}},
|
||||||
|
{{ 0.000f, -0.010f, 0.f}, {-0.707f, 0.707f, 0.f}, {0.60f, 0.f}},
|
||||||
|
{{-0.001f, -0.038f, 0.f}, {-0.707f, -0.707f, 0.f}, {0.65f, 0.f}},
|
||||||
|
{{ 0.028f, -0.050f, 0.f}, {-0.707f, -0.707f, 0.f}, {0.75f, 0.f}},
|
||||||
|
{{ 0.026f, -0.150f, 0.f}, {-0.707f, 0.707f, 0.f}, {0.85f, 0.f}},
|
||||||
|
{{-0.039f, -0.180f, 0.f}, {-1.000f, 0.000f, 0.f}, {1.00f, 0.f}},
|
||||||
|
// iglica - vextor3(x,y,mapowanie tekstury)
|
||||||
|
// 1 mm więcej, żeby nie nachodziły tekstury?
|
||||||
|
{{ 0.010f, -0.180f, 0.f}, { 1.000f, 0.000f, 0.f}, {0.00f, 0.f}},
|
||||||
|
{{ 0.010f, -0.155f, 0.f}, { 1.000f, 0.000f, 0.f}, {0.15f, 0.f}},
|
||||||
|
{{ 0.010f, -0.070f, 0.f}, { 1.000f, 0.000f, 0.f}, {0.25f, 0.f}},
|
||||||
|
{{ 0.010f, -0.040f, 0.f}, { 1.000f, 0.000f, 0.f}, {0.35f, 0.f}},
|
||||||
|
{{ 0.010f, -0.010f, 0.f}, { 1.000f, 0.000f, 0.f}, {0.40f, 0.f}},
|
||||||
|
{{ 0.010f, -0.000f, 0.f}, { 0.707f, 0.707f, 0.f}, {0.45f, 0.f}},
|
||||||
|
{{ 0.000f, -0.000f, 0.f}, { 0.707f, 0.707f, 0.f}, {0.55f, 0.f}},
|
||||||
|
{{ 0.000f, -0.010f, 0.f}, {-1.000f, 0.000f, 0.f}, {0.60f, 0.f}},
|
||||||
|
{{ 0.000f, -0.040f, 0.f}, {-1.000f, 0.000f, 0.f}, {0.65f, 0.f}},
|
||||||
|
{{ 0.000f, -0.070f, 0.f}, {-1.000f, 0.000f, 0.f}, {0.75f, 0.f}},
|
||||||
|
{{ 0.000f, -0.155f, 0.f}, {-0.707f, 0.707f, 0.f}, {0.85f, 0.f}},
|
||||||
|
{{-0.040f, -0.180f, 0.f}, {-1.000f, 0.000f, 0.f}, {1.00f, 0.f}} };
|
||||||
|
}
|
||||||
|
m_profilesmap.emplace( railkeyprefix + "default", 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
gfx::vertex_array
|
||||||
|
TTrack::deserialize_profile( std::string const &Profile ) {
|
||||||
|
|
||||||
|
gfx::vertex_array profiledata;
|
||||||
|
|
||||||
|
cParser input { Profile + ".txt", cParser::buffer_FILE };
|
||||||
|
|
||||||
|
while( input.getTokens( 5, true, "\n\r\t ;,{}" ) ) {
|
||||||
|
gfx::basic_vertex vertex;
|
||||||
|
input
|
||||||
|
>> vertex.position.x
|
||||||
|
>> vertex.position.y
|
||||||
|
>> vertex.normal.x
|
||||||
|
>> vertex.normal.y
|
||||||
|
>> vertex.texture.s;
|
||||||
|
profiledata.emplace_back( vertex );
|
||||||
|
}
|
||||||
|
|
||||||
|
return profiledata;
|
||||||
|
}
|
||||||
|
|
||||||
|
gfx::vertex_array const &
|
||||||
|
TTrack::track_rail_profile( int const Profile ) {
|
||||||
|
|
||||||
|
return m_profiles[ Profile ];
|
||||||
|
}
|
||||||
|
|
||||||
float
|
float
|
||||||
TTrack::texture_length( material_handle const Material ) {
|
TTrack::texture_length( material_handle const Material ) {
|
||||||
|
|
||||||
@@ -2310,66 +2423,70 @@ TTrack::create_track_rail_profile( gfx::vertex_array &Right, gfx::vertex_array &
|
|||||||
sin2 { std::sin( roll2 ) },
|
sin2 { std::sin( roll2 ) },
|
||||||
cos2 { std::cos( roll2 ) };
|
cos2 { std::cos( roll2 ) };
|
||||||
|
|
||||||
auto const pointcount { iTrapezoid == 0 ? 12 : 24 };
|
auto const &railprofile { track_rail_profile( m_profile1.second ) };
|
||||||
Right.resize( pointcount );
|
// NOTE: rail profile defines both regular rail and switch blade profiles, so we halve total point count
|
||||||
Left.resize( pointcount );
|
auto const pointcount { railprofile.size() / 2 };
|
||||||
|
Right.resize( pointcount * ( iTrapezoid == 0 ? 1 : 2 ) );
|
||||||
|
Left.resize( pointcount * ( iTrapezoid == 0 ? 1 : 2 ) );
|
||||||
|
|
||||||
for( int i = 0; i < 12; ++i ) {
|
auto const *szyna { railprofile.data() };
|
||||||
|
|
||||||
|
for( int i = 0; i < pointcount; ++i ) {
|
||||||
|
|
||||||
Right[ i ] = {
|
Right[ i ] = {
|
||||||
// position
|
// position
|
||||||
{( fHTW + szyna[ i ].position.x ) * cos1 + szyna[ i ].position.y * sin1,
|
{( fHTW + szyna[ i ].position.x ) * cos1 + szyna[ i ].position.y * sin1,
|
||||||
-( fHTW + szyna[ i ].position.x ) * sin1 + szyna[ i ].position.y * cos1,
|
-( fHTW + szyna[ i ].position.x ) * sin1 + szyna[ i ].position.y * cos1,
|
||||||
szyna[ i ].position.z},
|
szyna[ i ].position.z},
|
||||||
// normal
|
// normal
|
||||||
{ szyna[ i ].normal.x * cos1 + szyna[ i ].normal.y * sin1,
|
{ szyna[ i ].normal.x * cos1 + szyna[ i ].normal.y * sin1,
|
||||||
-szyna[ i ].normal.x * sin1 + szyna[ i ].normal.y * cos1,
|
-szyna[ i ].normal.x * sin1 + szyna[ i ].normal.y * cos1,
|
||||||
szyna[ i ].normal.z },
|
szyna[ i ].normal.z },
|
||||||
// texture
|
// texture
|
||||||
{ szyna[ i ].texture.x,
|
{ szyna[ i ].texture.s,
|
||||||
szyna[ i ].texture.y } };
|
szyna[ i ].texture.t } };
|
||||||
|
|
||||||
Left[ 11 - i ] = {
|
Left[ pointcount - 1 - i ] = {
|
||||||
// position
|
// position
|
||||||
{(-fHTW - szyna[ i ].position.x ) * cos1 + szyna[ i ].position.y * sin1,
|
{(-fHTW - szyna[ i ].position.x ) * cos1 + szyna[ i ].position.y * sin1,
|
||||||
-(-fHTW - szyna[ i ].position.x ) * sin1 + szyna[ i ].position.y * cos1,
|
-(-fHTW - szyna[ i ].position.x ) * sin1 + szyna[ i ].position.y * cos1,
|
||||||
szyna[ i ].position.z},
|
szyna[ i ].position.z},
|
||||||
// normal
|
// normal
|
||||||
{-szyna[ i ].normal.x * cos1 + szyna[ i ].normal.y * sin1,
|
{-szyna[ i ].normal.x * cos1 + szyna[ i ].normal.y * sin1,
|
||||||
szyna[ i ].normal.x * sin1 + szyna[ i ].normal.y * cos1,
|
szyna[ i ].normal.x * sin1 + szyna[ i ].normal.y * cos1,
|
||||||
szyna[ i ].normal.z },
|
szyna[ i ].normal.z },
|
||||||
// texture
|
// texture
|
||||||
{ szyna[ i ].texture.x,
|
{ szyna[ i ].texture.s,
|
||||||
szyna[ i ].texture.y } };
|
szyna[ i ].texture.t } };
|
||||||
|
|
||||||
if( iTrapezoid == 0 ) { continue; }
|
if( iTrapezoid == 0 ) { continue; }
|
||||||
// trapez albo przechyłki, to oddzielne punkty na końcu
|
|
||||||
|
|
||||||
Right[ 12 + i ] = {
|
// trapez albo przechyłki, to oddzielne punkty na końcu
|
||||||
|
Right[ pointcount + i ] = {
|
||||||
// position
|
// position
|
||||||
{( fHTW + szyna[ i ].position.x ) * cos2 + szyna[ i ].position.y * sin2,
|
{( fHTW + szyna[ i ].position.x ) * cos2 + szyna[ i ].position.y * sin2,
|
||||||
-( fHTW + szyna[ i ].position.x ) * sin2 + szyna[ i ].position.y * cos2,
|
-( fHTW + szyna[ i ].position.x ) * sin2 + szyna[ i ].position.y * cos2,
|
||||||
szyna[ i ].position.z},
|
szyna[ i ].position.z},
|
||||||
// normal
|
// normal
|
||||||
{ szyna[ i ].normal.x * cos2 + szyna[ i ].normal.y * sin2,
|
{ szyna[ i ].normal.x * cos2 + szyna[ i ].normal.y * sin2,
|
||||||
-szyna[ i ].normal.x * sin2 + szyna[ i ].normal.y * cos2,
|
-szyna[ i ].normal.x * sin2 + szyna[ i ].normal.y * cos2,
|
||||||
szyna[ i ].normal.z },
|
szyna[ i ].normal.z },
|
||||||
// texture
|
// texture
|
||||||
{ szyna[ i ].texture.x,
|
{ szyna[ i ].texture.s,
|
||||||
szyna[ i ].texture.y } };
|
szyna[ i ].texture.t } };
|
||||||
|
|
||||||
Left[ 23 - i ] = {
|
Left[ pointcount * 2 - 1 - i ] = {
|
||||||
// position
|
// position
|
||||||
{(-fHTW - szyna[ i ].position.x ) * cos2 + szyna[ i ].position.y * sin2,
|
{(-fHTW - szyna[ i ].position.x ) * cos2 + szyna[ i ].position.y * sin2,
|
||||||
-(-fHTW - szyna[ i ].position.x ) * sin2 + szyna[ i ].position.y * cos2,
|
-(-fHTW - szyna[ i ].position.x ) * sin2 + szyna[ i ].position.y * cos2,
|
||||||
szyna[ i ].position.z},
|
szyna[ i ].position.z},
|
||||||
// normal
|
// normal
|
||||||
{-szyna[ i ].normal.x * cos2 + szyna[ i ].normal.y * sin2,
|
{-szyna[ i ].normal.x * cos2 + szyna[ i ].normal.y * sin2,
|
||||||
szyna[ i ].normal.x * sin2 + szyna[ i ].normal.y * cos2,
|
szyna[ i ].normal.x * sin2 + szyna[ i ].normal.y * cos2,
|
||||||
szyna[ i ].normal.z },
|
szyna[ i ].normal.z },
|
||||||
// texture
|
// texture
|
||||||
{ szyna[ i ].texture.x,
|
{ szyna[ i ].texture.s,
|
||||||
szyna[ i ].texture.y } };
|
szyna[ i ].texture.t } };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2397,37 +2514,43 @@ TTrack::create_track_blade_profile( gfx::vertex_array &Right, gfx::vertex_array
|
|||||||
sin2 { std::sin( roll2 ) },
|
sin2 { std::sin( roll2 ) },
|
||||||
cos2 { std::cos( roll2 ) };
|
cos2 { std::cos( roll2 ) };
|
||||||
|
|
||||||
auto const pointcount { 24 };
|
auto const &railprofile { track_rail_profile( m_profile1.second ) };
|
||||||
Right.resize( pointcount );
|
// NOTE: rail profile defines both regular rail and switch blade profiles, so we halve total point count
|
||||||
Left.resize( pointcount );
|
auto const pointcount { railprofile.size() / 2 };
|
||||||
|
|
||||||
|
Right.resize( pointcount * 2 );
|
||||||
|
Left.resize( pointcount * 2 );
|
||||||
|
|
||||||
|
auto const *szyna { railprofile.data() };
|
||||||
|
auto const *iglica { szyna + pointcount };
|
||||||
|
|
||||||
glm::vec3 const flipxvalue { -1, 1, 1 };
|
glm::vec3 const flipxvalue { -1, 1, 1 };
|
||||||
for( int i = 0; i < 12; ++i ) {
|
for( int i = 0; i < pointcount; ++i ) {
|
||||||
|
|
||||||
Right[ i ] = {
|
Right[ i ] = {
|
||||||
{+( fHTW + iglica[ i ].position.x ) * cos1 + iglica[ i ].position.y * sin1,
|
{+( fHTW + iglica[ i ].position.x ) * cos1 + iglica[ i ].position.y * sin1,
|
||||||
-( fHTW + iglica[ i ].position.x ) * sin1 + iglica[ i ].position.y * cos1,
|
-( fHTW + iglica[ i ].position.x ) * sin1 + iglica[ i ].position.y * cos1,
|
||||||
0.f},
|
0.f},
|
||||||
{iglica[ i ].normal},
|
{iglica[ i ].normal},
|
||||||
{iglica[ i ].texture.x, 0.f} };
|
{iglica[ i ].texture.s, 0.f} };
|
||||||
Right[ i + 12 ] = {
|
Right[ i + pointcount ] = {
|
||||||
{+( fHTW2 + szyna[ i ].position.x ) * cos2 + szyna[ i ].position.y * sin2,
|
{+( fHTW2 + szyna[ i ].position.x ) * cos2 + szyna[ i ].position.y * sin2,
|
||||||
-( fHTW2 + szyna[ i ].position.x ) * sin2 + iglica[ i ].position.y * cos2,
|
-( fHTW2 + szyna[ i ].position.x ) * sin2 + szyna[ i ].position.y * cos2,
|
||||||
0.f},
|
0.f},
|
||||||
{szyna[ i ].normal},
|
{szyna[ i ].normal},
|
||||||
{szyna[ i ].texture.x, 0.f} };
|
{szyna[ i ].texture.s, 0.f} };
|
||||||
Left[ 11 - i ] = {
|
Left[ pointcount - 1 - i ] = {
|
||||||
{ ( -fHTW - iglica[ i ].position.x ) * cos1 + iglica[ i ].position.y * sin1,
|
{ ( -fHTW - iglica[ i ].position.x ) * cos1 + iglica[ i ].position.y * sin1,
|
||||||
-( -fHTW - iglica[ i ].position.x ) * sin1 + iglica[ i ].position.y * cos1,
|
-( -fHTW - iglica[ i ].position.x ) * sin1 + iglica[ i ].position.y * cos1,
|
||||||
0.f},
|
0.f},
|
||||||
{iglica[ i ].normal * flipxvalue},
|
{iglica[ i ].normal * flipxvalue},
|
||||||
{iglica[ i ].texture.x, 0.f} };
|
{iglica[ i ].texture.s, 0.f} };
|
||||||
Left[ 23 - i ] = {
|
Left[ pointcount * 2 - 1 - i ] = {
|
||||||
{ ( -fHTW2 - szyna[ i ].position.x ) * cos2 + szyna[ i ].position.y * sin2,
|
{ ( -fHTW2 - szyna[ i ].position.x ) * cos2 + szyna[ i ].position.y * sin2,
|
||||||
-( -fHTW2 - szyna[ i ].position.x ) * sin2 + iglica[ i ].position.y * cos2,
|
-( -fHTW2 - szyna[ i ].position.x ) * sin2 + szyna[ i ].position.y * cos2,
|
||||||
0.f},
|
0.f},
|
||||||
{szyna[ i ].normal * flipxvalue},
|
{szyna[ i ].normal * flipxvalue},
|
||||||
{szyna[ i ].texture.x, 0.f} };
|
{szyna[ i ].texture.s, 0.f} };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2511,7 +2634,7 @@ TTrack::create_track_bed_profile( gfx::vertex_array &Output, TTrack const *Previ
|
|||||||
Output.resize( pointcount );
|
Output.resize( pointcount );
|
||||||
// potentially retrieve texture length override from the assigned material
|
// potentially retrieve texture length override from the assigned material
|
||||||
auto const texturelength { texture_length( copy_adjacent_trackbed_material() ) };
|
auto const texturelength { texture_length( copy_adjacent_trackbed_material() ) };
|
||||||
auto const railheight { 0.18f };
|
auto const railheight { std::abs( track_rail_profile( m_profile1.second ).front().position.y ) };
|
||||||
if( texturelength == 4.f ) {
|
if( texturelength == 4.f ) {
|
||||||
// stare mapowanie z różną gęstością pikseli i oddzielnymi teksturami na każdy profil
|
// stare mapowanie z różną gęstością pikseli i oddzielnymi teksturami na każdy profil
|
||||||
auto const normalx = std::cos( glm::radians( 75.f ) );
|
auto const normalx = std::cos( glm::radians( 75.f ) );
|
||||||
@@ -3065,7 +3188,7 @@ path_table::InitTracks() {
|
|||||||
auto const trackname { track->name() };
|
auto const trackname { track->name() };
|
||||||
|
|
||||||
switch (track->eType) {
|
switch (track->eType) {
|
||||||
// TODO: re-enable
|
|
||||||
case tt_Table: {
|
case tt_Table: {
|
||||||
// obrotnicę też łączymy na starcie z innymi torami
|
// obrotnicę też łączymy na starcie z innymi torami
|
||||||
// szukamy modelu o tej samej nazwie
|
// szukamy modelu o tej samej nazwie
|
||||||
@@ -3160,10 +3283,6 @@ path_table::InitTracks() {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if( Global.CreateSwitchTrackbeds ) {
|
|
||||||
// when autogenerating trackbeds, try to restore trackbeds for tracks neighbouring double slips
|
|
||||||
track->copy_adjacent_trackbed_material();
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case tt_Switch: {
|
case tt_Switch: {
|
||||||
@@ -3171,10 +3290,6 @@ path_table::InitTracks() {
|
|||||||
track->AssignForcedEvents(
|
track->AssignForcedEvents(
|
||||||
simulation::Events.FindEvent( trackname + ":forced+" ),
|
simulation::Events.FindEvent( trackname + ":forced+" ),
|
||||||
simulation::Events.FindEvent( trackname + ":forced-" ) );
|
simulation::Events.FindEvent( trackname + ":forced-" ) );
|
||||||
if( Global.CreateSwitchTrackbeds ) {
|
|
||||||
// when autogenerating trackbeds, try to restore trackbeds for tracks neighbouring double slips
|
|
||||||
track->copy_adjacent_trackbed_material();
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
@@ -3190,6 +3305,25 @@ path_table::InitTracks() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( Global.CreateSwitchTrackbeds ) {
|
||||||
|
// do this after all connections are established, otherwise missing switch connections
|
||||||
|
// may prevent us from obtaining texture data for basic track from 'across' a switch
|
||||||
|
for( auto *track : m_items ) {
|
||||||
|
// try to assign missing trackbed materials for switches and tracks neighbouring switches
|
||||||
|
switch( track->eType ) {
|
||||||
|
|
||||||
|
case tt_Normal:
|
||||||
|
case tt_Switch: {
|
||||||
|
track->copy_adjacent_trackbed_material();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} // switch
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto *isolated = TIsolated::Root();
|
auto *isolated = TIsolated::Root();
|
||||||
while( isolated ) {
|
while( isolated ) {
|
||||||
|
|
||||||
@@ -3211,6 +3345,8 @@ path_table::InitTracks() {
|
|||||||
|
|
||||||
isolated = isolated->Next();
|
isolated = isolated->Next();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TTrack::fetch_default_profiles();
|
||||||
}
|
}
|
||||||
|
|
||||||
// legacy method, sends list of occupied paths over network
|
// legacy method, sends list of occupied paths over network
|
||||||
|
|||||||
16
Track.h
16
Track.h
@@ -167,8 +167,10 @@ private:
|
|||||||
float fTexSlope = 0.9f;
|
float fTexSlope = 0.9f;
|
||||||
|
|
||||||
glm::dvec3 m_origin;
|
glm::dvec3 m_origin;
|
||||||
|
// TODO: store material names as strings, for lossless serialization and export
|
||||||
material_handle m_material1 = 0; // tekstura szyn albo nawierzchni
|
material_handle m_material1 = 0; // tekstura szyn albo nawierzchni
|
||||||
material_handle m_material2 = 0; // tekstura automatycznej podsypki albo pobocza
|
material_handle m_material2 = 0; // tekstura automatycznej podsypki albo pobocza
|
||||||
|
std::pair<std::string, int> m_profile1 {}; // profile of geometry chunks textured with texture 1
|
||||||
using geometryhandle_sequence = std::vector<gfx::geometry_handle>;
|
using geometryhandle_sequence = std::vector<gfx::geometry_handle>;
|
||||||
geometryhandle_sequence Geometry1; // geometry chunks textured with texture 1
|
geometryhandle_sequence Geometry1; // geometry chunks textured with texture 1
|
||||||
geometryhandle_sequence Geometry2; // geometry chunks textured with texture 2
|
geometryhandle_sequence Geometry2; // geometry chunks textured with texture 2
|
||||||
@@ -292,8 +294,13 @@ public:
|
|||||||
double VelocityGet();
|
double VelocityGet();
|
||||||
void ConnectionsLog();
|
void ConnectionsLog();
|
||||||
bool DoubleSlip() const;
|
bool DoubleSlip() const;
|
||||||
|
static void fetch_default_profiles();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// types
|
||||||
|
using profiles_array = std::vector<gfx::vertex_array>;
|
||||||
|
using profiles_map = std::unordered_map<std::string, int>;
|
||||||
|
// methods
|
||||||
// radius() subclass details, calculates node's bounding radius
|
// radius() subclass details, calculates node's bounding radius
|
||||||
float radius_();
|
float radius_();
|
||||||
// serialize() subclass details, sends content of the subclass to provided stream
|
// serialize() subclass details, sends content of the subclass to provided stream
|
||||||
@@ -302,6 +309,12 @@ private:
|
|||||||
void deserialize_( std::istream &Input );
|
void deserialize_( std::istream &Input );
|
||||||
// export() subclass details, sends basic content of the class in legacy (text) format to provided stream
|
// export() subclass details, sends basic content of the class in legacy (text) format to provided stream
|
||||||
void export_as_text_( std::ostream &Output ) const;
|
void export_as_text_( std::ostream &Output ) const;
|
||||||
|
// locates specified profile in the profile database, potentially loading it from a file
|
||||||
|
static std::pair<std::string, int> fetch_track_rail_profile( std::string const &Profile );
|
||||||
|
// loads content of specified file and converts it into a vertex array
|
||||||
|
static gfx::vertex_array deserialize_profile( std::string const &Profile );
|
||||||
|
// provides direct access to vertex data of specified profile
|
||||||
|
static gfx::vertex_array const & track_rail_profile( int const Profile );
|
||||||
// returns texture length for specified material
|
// returns texture length for specified material
|
||||||
float texture_length( material_handle const Material );
|
float texture_length( material_handle const Material );
|
||||||
// creates profile for a part of current path
|
// creates profile for a part of current path
|
||||||
@@ -311,6 +324,9 @@ private:
|
|||||||
void create_track_bed_profile( gfx::vertex_array &Output, TTrack const *Previous, TTrack const *Next );
|
void create_track_bed_profile( gfx::vertex_array &Output, TTrack const *Previous, TTrack const *Next );
|
||||||
void create_road_profile( gfx::vertex_array &Output, bool const Forcetransition = false );
|
void create_road_profile( gfx::vertex_array &Output, bool const Forcetransition = false );
|
||||||
void create_road_side_profile( gfx::vertex_array &Right, gfx::vertex_array &Left, gfx::vertex_array const &Road, bool const Forcetransition = false );
|
void create_road_side_profile( gfx::vertex_array &Right, gfx::vertex_array &Left, gfx::vertex_array const &Road, bool const Forcetransition = false );
|
||||||
|
// members
|
||||||
|
static profiles_array m_profiles; // shared database of path element profiles
|
||||||
|
static profiles_map m_profilesmap;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -452,11 +452,11 @@ bool TTrain::Init(TDynamicObject *NewDynamicObject, bool e3d)
|
|||||||
PyObject *TTrain::GetTrainState() {
|
PyObject *TTrain::GetTrainState() {
|
||||||
|
|
||||||
auto const *mover = DynamicObject->MoverParameters;
|
auto const *mover = DynamicObject->MoverParameters;
|
||||||
PyEval_AcquireLock();
|
Application.acquire_python_lock();
|
||||||
auto *dict = PyDict_New();
|
auto *dict = PyDict_New();
|
||||||
if( ( dict == nullptr )
|
if( ( dict == nullptr )
|
||||||
|| ( mover == nullptr ) ) {
|
|| ( mover == nullptr ) ) {
|
||||||
PyEval_ReleaseLock();
|
Application.release_python_lock();
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -586,7 +586,7 @@ PyObject *TTrain::GetTrainState() {
|
|||||||
PyDict_SetItemString( dict, "seconds", PyGetInt( simulation::Time.second() ) );
|
PyDict_SetItemString( dict, "seconds", PyGetInt( simulation::Time.second() ) );
|
||||||
PyDict_SetItemString( dict, "air_temperature", PyGetInt( Global.AirTemperature ) );
|
PyDict_SetItemString( dict, "air_temperature", PyGetInt( Global.AirTemperature ) );
|
||||||
|
|
||||||
PyEval_ReleaseLock();
|
Application.release_python_lock();
|
||||||
return dict;
|
return dict;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -6004,7 +6004,7 @@ bool TTrain::Update( double const Deltatime )
|
|||||||
&& ( false == FreeFlyModeFlag ) ) { // don't bother if we're outside
|
&& ( false == FreeFlyModeFlag ) ) { // don't bother if we're outside
|
||||||
fScreenTimer = 0.f;
|
fScreenTimer = 0.f;
|
||||||
for( auto const &screen : m_screens ) {
|
for( auto const &screen : m_screens ) {
|
||||||
Application.request( { screen.first, GetTrainState(), screen.second } );
|
Application.request( { screen.first, GetTrainState(), GfxRenderer.Texture( screen.second ).id } );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// sounds
|
// sounds
|
||||||
|
|||||||
@@ -163,12 +163,27 @@ eu07_application::run() {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// issues request for a worker thread to perform specified task. returns: true if task was scheduled
|
||||||
bool
|
bool
|
||||||
eu07_application::request( python_taskqueue::task_request const &Task ) {
|
eu07_application::request( python_taskqueue::task_request const &Task ) {
|
||||||
|
|
||||||
return m_taskqueue.insert( Task );
|
return m_taskqueue.insert( Task );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ensures the main thread holds the python gil and can safely execute python calls
|
||||||
|
void
|
||||||
|
eu07_application::acquire_python_lock() {
|
||||||
|
|
||||||
|
m_taskqueue.acquire_lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
// frees the python gil and swaps out the main thread
|
||||||
|
void
|
||||||
|
eu07_application::release_python_lock() {
|
||||||
|
|
||||||
|
m_taskqueue.release_lock();
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
eu07_application::exit() {
|
eu07_application::exit() {
|
||||||
|
|
||||||
|
|||||||
@@ -30,8 +30,15 @@ public:
|
|||||||
init( int Argc, char *Argv[] );
|
init( int Argc, char *Argv[] );
|
||||||
int
|
int
|
||||||
run();
|
run();
|
||||||
|
// issues request for a worker thread to perform specified task. returns: true if task was scheduled
|
||||||
bool
|
bool
|
||||||
request( python_taskqueue::task_request const &Task );
|
request( python_taskqueue::task_request const &Task );
|
||||||
|
// ensures the main thread holds the python gil and can safely execute python calls
|
||||||
|
void
|
||||||
|
acquire_python_lock();
|
||||||
|
// frees the python gil and swaps out the main thread
|
||||||
|
void
|
||||||
|
release_python_lock();
|
||||||
void
|
void
|
||||||
exit();
|
exit();
|
||||||
void
|
void
|
||||||
|
|||||||
84
material.cpp
84
material.cpp
@@ -117,47 +117,74 @@ material_manager::create( std::string const &Filename, bool const Loadnow ) {
|
|||||||
if( filename.find( '|' ) != std::string::npos )
|
if( filename.find( '|' ) != std::string::npos )
|
||||||
filename.erase( filename.find( '|' ) ); // po | może być nazwa kolejnej tekstury
|
filename.erase( filename.find( '|' ) ); // po | może być nazwa kolejnej tekstury
|
||||||
|
|
||||||
erase_extension( filename );
|
// discern references to textures generated by a script
|
||||||
|
// TBD: support file: for file resources?
|
||||||
|
auto const isgenerated { filename.find( "make:" ) == 0 };
|
||||||
|
|
||||||
if( filename[ 0 ] == '/' ) {
|
// process supplied resource name
|
||||||
// filename can potentially begin with a slash, and we don't need it
|
if( isgenerated ) {
|
||||||
filename.erase( 0, 1 );
|
// generated resource
|
||||||
|
// scheme:(user@)path?query
|
||||||
|
|
||||||
|
// remove scheme indicator
|
||||||
|
filename.erase( 0, filename.find(':') + 1 );
|
||||||
|
// TBD, TODO: allow shader specification as part of the query?
|
||||||
|
erase_leading_slashes( filename );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// regular file resource
|
||||||
|
// (filepath/)filename.extension
|
||||||
|
|
||||||
|
erase_extension( filename );
|
||||||
|
replace_slashes( filename );
|
||||||
|
erase_leading_slashes( filename );
|
||||||
}
|
}
|
||||||
|
|
||||||
// try to locate requested material in the databank
|
auto const databanklookup { find_in_databank( ToLower( filename ) ) };
|
||||||
auto const databanklookup { find_in_databank( filename ) };
|
|
||||||
if( databanklookup != null_handle ) {
|
if( databanklookup != null_handle ) {
|
||||||
return databanklookup;
|
return databanklookup;
|
||||||
}
|
}
|
||||||
// if this fails, try to look for it on disk
|
|
||||||
opengl_material material;
|
opengl_material material;
|
||||||
auto const disklookup { find_on_disk( filename ) };
|
material_handle materialhandle { null_handle };
|
||||||
if( false == disklookup.first.empty() ) {
|
|
||||||
cParser materialparser( disklookup.first + disklookup.second, cParser::buffer_FILE );
|
auto const locator {
|
||||||
if( false == material.deserialize( materialparser, Loadnow ) ) {
|
isgenerated ?
|
||||||
// deserialization failed but the .mat file does exist, so we give up at this point
|
std::make_pair( filename, "make:" ) :
|
||||||
return null_handle;
|
find_on_disk( filename ) };
|
||||||
|
|
||||||
|
if( ( false == isgenerated )
|
||||||
|
&& ( false == locator.first.empty() ) ) {
|
||||||
|
// try to parse located file resource
|
||||||
|
cParser materialparser( locator.first + locator.second, cParser::buffer_FILE );
|
||||||
|
if( true == material.deserialize( materialparser, Loadnow ) ) {
|
||||||
|
material.name = locator.first;
|
||||||
}
|
}
|
||||||
material.name = disklookup.first;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// if there's no .mat file, this could be legacy method of referring just to diffuse texture directly, make a material out of it in such case
|
// if there's no .mat file, this can be either autogenerated texture,
|
||||||
|
// or legacy method of referring just to diffuse texture directly.
|
||||||
|
// wrap basic material around it in either case
|
||||||
material.texture1 = GfxRenderer.Fetch_Texture( Filename, Loadnow );
|
material.texture1 = GfxRenderer.Fetch_Texture( Filename, Loadnow );
|
||||||
if( material.texture1 == null_handle ) {
|
if( material.texture1 != null_handle ) {
|
||||||
// if there's also no texture, give up
|
// use texture path and name to tell the newly created materials apart
|
||||||
return null_handle;
|
material.name = GfxRenderer.Texture( material.texture1 ).name;
|
||||||
|
material.has_alpha = GfxRenderer.Texture( material.texture1 ).has_alpha;
|
||||||
}
|
}
|
||||||
// use texture path and name to tell the newly created materials apart
|
|
||||||
filename = GfxRenderer.Texture( material.texture1 ).name;
|
|
||||||
erase_extension( filename );
|
|
||||||
material.name = filename;
|
|
||||||
material.has_alpha = GfxRenderer.Texture( material.texture1 ).has_alpha;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
material_handle handle = m_materials.size();
|
if( false == material.name.empty() ) {
|
||||||
m_materials.emplace_back( material );
|
// if we have material name it means resource was processed succesfully
|
||||||
m_materialmappings.emplace( material.name, handle );
|
materialhandle = m_materials.size();
|
||||||
return handle;
|
m_materials.emplace_back( material );
|
||||||
|
m_materialmappings.emplace( material.name, materialhandle );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// otherwise record our failure to process the resource, to speed up subsequent attempts
|
||||||
|
m_materialmappings.emplace( filename, materialhandle );
|
||||||
|
}
|
||||||
|
|
||||||
|
return materialhandle;
|
||||||
};
|
};
|
||||||
|
|
||||||
// checks whether specified material is in the material bank. returns handle to the material, or a null handle
|
// checks whether specified material is in the material bank. returns handle to the material, or a null handle
|
||||||
@@ -184,9 +211,10 @@ material_manager::find_in_databank( std::string const &Materialname ) const {
|
|||||||
std::pair<std::string, std::string>
|
std::pair<std::string, std::string>
|
||||||
material_manager::find_on_disk( std::string const &Materialname ) const {
|
material_manager::find_on_disk( std::string const &Materialname ) const {
|
||||||
|
|
||||||
|
auto const materialname { ToLower( Materialname ) };
|
||||||
return (
|
return (
|
||||||
FileExists(
|
FileExists(
|
||||||
{ Global.asCurrentTexturePath + Materialname, Materialname, szTexturePath + Materialname },
|
{ Global.asCurrentTexturePath + materialname, materialname, szTexturePath + materialname },
|
||||||
{ ".mat" } ) );
|
{ ".mat" } ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
65
renderer.cpp
65
renderer.cpp
@@ -554,7 +554,6 @@ opengl_renderer::Render_pass( rendermode const Mode ) {
|
|||||||
setup_drawing( true );
|
setup_drawing( true );
|
||||||
setup_units( true, false, false );
|
setup_units( true, false, false );
|
||||||
Render( &simulation::Environment );
|
Render( &simulation::Environment );
|
||||||
gfx::opengl_vbogeometrybank::reset();
|
|
||||||
|
|
||||||
// opaque parts...
|
// opaque parts...
|
||||||
setup_drawing( false );
|
setup_drawing( false );
|
||||||
@@ -1465,6 +1464,7 @@ opengl_renderer::Render( world_environment *Environment ) {
|
|||||||
::glPushMatrix();
|
::glPushMatrix();
|
||||||
::glScalef( 500.f, 500.f, 500.f );
|
::glScalef( 500.f, 500.f, 500.f );
|
||||||
Environment->m_skydome.Render();
|
Environment->m_skydome.Render();
|
||||||
|
gfx::opengl_vbogeometrybank::reset();
|
||||||
::glPopMatrix();
|
::glPopMatrix();
|
||||||
// stars
|
// stars
|
||||||
if( Environment->m_stars.m_stars != nullptr ) {
|
if( Environment->m_stars.m_stars != nullptr ) {
|
||||||
@@ -2606,6 +2606,11 @@ opengl_renderer::Render( TSubModel *Submodel ) {
|
|||||||
auto const unitstate = m_unitstate;
|
auto const unitstate = m_unitstate;
|
||||||
switch_units( m_unitstate.diffuse, false, false );
|
switch_units( m_unitstate.diffuse, false, false );
|
||||||
|
|
||||||
|
auto const *lightcolor {
|
||||||
|
Submodel->DiffuseOverride.r < 0.f ? // -1 indicates no override
|
||||||
|
glm::value_ptr( Submodel->f4Diffuse ) :
|
||||||
|
glm::value_ptr( Submodel->DiffuseOverride ) };
|
||||||
|
|
||||||
// main draw call
|
// main draw call
|
||||||
if( Global.Overcast > 1.f ) {
|
if( Global.Overcast > 1.f ) {
|
||||||
// fake fog halo
|
// fake fog halo
|
||||||
@@ -2614,11 +2619,12 @@ opengl_renderer::Render( TSubModel *Submodel ) {
|
|||||||
2.f, 1.f,
|
2.f, 1.f,
|
||||||
clamp<float>( Global.fFogEnd / 2000, 0.f, 1.f ) )
|
clamp<float>( Global.fFogEnd / 2000, 0.f, 1.f ) )
|
||||||
* std::max( 1.f, Global.Overcast ) };
|
* std::max( 1.f, Global.Overcast ) };
|
||||||
|
|
||||||
::glPointSize( pointsize * fogfactor );
|
::glPointSize( pointsize * fogfactor );
|
||||||
::glColor4f(
|
::glColor4f(
|
||||||
Submodel->f4Diffuse[ 0 ],
|
lightcolor[ 0 ],
|
||||||
Submodel->f4Diffuse[ 1 ],
|
lightcolor[ 1 ],
|
||||||
Submodel->f4Diffuse[ 2 ],
|
lightcolor[ 2 ],
|
||||||
Submodel->fVisible * std::min( 1.f, lightlevel ) * 0.5f );
|
Submodel->fVisible * std::min( 1.f, lightlevel ) * 0.5f );
|
||||||
::glDepthMask( GL_FALSE );
|
::glDepthMask( GL_FALSE );
|
||||||
m_geometry.draw( Submodel->m_geometry );
|
m_geometry.draw( Submodel->m_geometry );
|
||||||
@@ -2626,9 +2632,9 @@ opengl_renderer::Render( TSubModel *Submodel ) {
|
|||||||
}
|
}
|
||||||
::glPointSize( pointsize );
|
::glPointSize( pointsize );
|
||||||
::glColor4f(
|
::glColor4f(
|
||||||
Submodel->f4Diffuse[ 0 ],
|
lightcolor[ 0 ],
|
||||||
Submodel->f4Diffuse[ 1 ],
|
lightcolor[ 1 ],
|
||||||
Submodel->f4Diffuse[ 2 ],
|
lightcolor[ 2 ],
|
||||||
Submodel->fVisible * std::min( 1.f, lightlevel ) );
|
Submodel->fVisible * std::min( 1.f, lightlevel ) );
|
||||||
m_geometry.draw( Submodel->m_geometry );
|
m_geometry.draw( Submodel->m_geometry );
|
||||||
|
|
||||||
@@ -2707,30 +2713,7 @@ opengl_renderer::Render( TTrack *Track ) {
|
|||||||
++m_debugstats.drawcalls;
|
++m_debugstats.drawcalls;
|
||||||
|
|
||||||
switch( m_renderpass.draw_mode ) {
|
switch( m_renderpass.draw_mode ) {
|
||||||
case rendermode::color:
|
// single path pieces are rendererd in pick scenery mode only
|
||||||
case rendermode::reflections: {
|
|
||||||
setup_environment_light( Track->eEnvironment );
|
|
||||||
if( Track->m_material1 != 0 ) {
|
|
||||||
Bind_Material( Track->m_material1 );
|
|
||||||
m_geometry.draw( std::begin( Track->Geometry1 ), std::end( Track->Geometry1 ) );
|
|
||||||
}
|
|
||||||
if( Track->m_material2 != 0 ) {
|
|
||||||
Bind_Material( Track->m_material2 );
|
|
||||||
m_geometry.draw( std::begin( Track->Geometry2 ), std::end( Track->Geometry2 ) );
|
|
||||||
}
|
|
||||||
if( ( Track->eType == tt_Switch )
|
|
||||||
&& ( Track->SwitchExtension->m_material3 != 0 ) ) {
|
|
||||||
Bind_Material( Track->SwitchExtension->m_material3 );
|
|
||||||
m_geometry.draw( Track->SwitchExtension->Geometry3 );
|
|
||||||
}
|
|
||||||
setup_environment_light();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case rendermode::shadows: {
|
|
||||||
// shadow pass includes trackbeds but not tracks themselves due to low resolution of the map
|
|
||||||
// TODO: implement
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case rendermode::pickscenery: {
|
case rendermode::pickscenery: {
|
||||||
// add the node to the pick list
|
// add the node to the pick list
|
||||||
m_picksceneryitems.emplace_back( Track );
|
m_picksceneryitems.emplace_back( Track );
|
||||||
@@ -2750,7 +2733,6 @@ opengl_renderer::Render( TTrack *Track ) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case rendermode::pickcontrols:
|
|
||||||
default: {
|
default: {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -2845,7 +2827,7 @@ opengl_renderer::Render( scene::basic_cell::path_sequence::const_iterator First,
|
|||||||
// restore default lighting
|
// restore default lighting
|
||||||
setup_environment_light();
|
setup_environment_light();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case rendermode::shadows: {
|
case rendermode::shadows: {
|
||||||
if( ( std::abs( track->fTexHeight1 ) < 0.35f )
|
if( ( std::abs( track->fTexHeight1 ) < 0.35f )
|
||||||
@@ -3534,7 +3516,6 @@ opengl_renderer::Render_Alpha( TSubModel *Submodel ) {
|
|||||||
::glPushAttrib( GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_ENABLE_BIT );
|
::glPushAttrib( GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_ENABLE_BIT );
|
||||||
|
|
||||||
Bind_Texture( m_glaretexture );
|
Bind_Texture( m_glaretexture );
|
||||||
::glColor4f( Submodel->f4Diffuse[ 0 ], Submodel->f4Diffuse[ 1 ], Submodel->f4Diffuse[ 2 ], Submodel->fVisible * glarelevel );
|
|
||||||
::glDisable( GL_LIGHTING );
|
::glDisable( GL_LIGHTING );
|
||||||
::glDisable( GL_FOG );
|
::glDisable( GL_FOG );
|
||||||
::glDepthMask( GL_FALSE );
|
::glDepthMask( GL_FALSE );
|
||||||
@@ -3545,12 +3526,19 @@ opengl_renderer::Render_Alpha( TSubModel *Submodel ) {
|
|||||||
::glTranslatef( lightcenter.x, lightcenter.y, lightcenter.z ); // początek układu zostaje bez zmian
|
::glTranslatef( lightcenter.x, lightcenter.y, lightcenter.z ); // początek układu zostaje bez zmian
|
||||||
::glRotated( std::atan2( lightcenter.x, lightcenter.z ) * 180.0 / M_PI, 0.0, 1.0, 0.0 ); // jedynie obracamy w pionie o kąt
|
::glRotated( std::atan2( lightcenter.x, lightcenter.z ) * 180.0 / M_PI, 0.0, 1.0, 0.0 ); // jedynie obracamy w pionie o kąt
|
||||||
// disable shadows so they don't obstruct self-lit items
|
// disable shadows so they don't obstruct self-lit items
|
||||||
/*
|
|
||||||
setup_shadow_color( colors::white );
|
|
||||||
*/
|
|
||||||
auto const unitstate = m_unitstate;
|
auto const unitstate = m_unitstate;
|
||||||
switch_units( unitstate.diffuse, false, false );
|
switch_units( unitstate.diffuse, false, false );
|
||||||
|
|
||||||
|
auto const *lightcolor {
|
||||||
|
Submodel->DiffuseOverride.r < 0.f ? // -1 indicates no override
|
||||||
|
glm::value_ptr( Submodel->f4Diffuse ) :
|
||||||
|
glm::value_ptr( Submodel->DiffuseOverride ) };
|
||||||
|
::glColor4f(
|
||||||
|
lightcolor[ 0 ],
|
||||||
|
lightcolor[ 1 ],
|
||||||
|
lightcolor[ 2 ],
|
||||||
|
Submodel->fVisible * glarelevel );
|
||||||
|
|
||||||
// main draw call
|
// main draw call
|
||||||
m_geometry.draw( m_billboardgeometry );
|
m_geometry.draw( m_billboardgeometry );
|
||||||
/*
|
/*
|
||||||
@@ -3562,9 +3550,6 @@ opengl_renderer::Render_Alpha( TSubModel *Submodel ) {
|
|||||||
// ...etc instead IF we had easy access to camera's forward and right vectors. TODO: check if Camera matrix is accessible
|
// ...etc instead IF we had easy access to camera's forward and right vectors. TODO: check if Camera matrix is accessible
|
||||||
*/
|
*/
|
||||||
// post-render cleanup
|
// post-render cleanup
|
||||||
/*
|
|
||||||
setup_shadow_color( m_shadowcolor );
|
|
||||||
*/
|
|
||||||
switch_units( unitstate.diffuse, unitstate.shadows, unitstate.reflections );
|
switch_units( unitstate.diffuse, unitstate.shadows, unitstate.reflections );
|
||||||
|
|
||||||
::glPopMatrix();
|
::glPopMatrix();
|
||||||
|
|||||||
13
scene.cpp
13
scene.cpp
@@ -1157,16 +1157,21 @@ basic_region::RadioStop( glm::dvec3 const &Location ) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> switchtrackbedtextures {
|
std::vector<std::string> switchtrackbedtextures {
|
||||||
|
"rkpd34r190-tpd1",
|
||||||
|
"rkpd34r190-tpd2",
|
||||||
|
"rkpd34r190-tpd-oil2",
|
||||||
"rozkrz8r150-1pods-new",
|
"rozkrz8r150-1pods-new",
|
||||||
"rozkrz8r150-2pods-new",
|
"rozkrz8r150-2pods-new",
|
||||||
"rozkrz34r150-tpbps-new2",
|
"rozkrz34r150-tpbps-new2",
|
||||||
"rozkrz34r150-tpd1",
|
"rozkrz34r150-tpd1",
|
||||||
"rkpd34r190-tpd1",
|
"rz-1200-185",
|
||||||
"rkpd34r190-tpd2",
|
|
||||||
"rkpd34r190-tpd-oil2",
|
|
||||||
"zwr41r500",
|
"zwr41r500",
|
||||||
"zwrot-tpd-oil1",
|
"zwrot-tpd-oil1",
|
||||||
"zwrot34r300pods-new" };
|
"zwrot34r300pods",
|
||||||
|
"zwrot34r300pods-new",
|
||||||
|
"zwrot34r300pods-old",
|
||||||
|
"zwrotl65r1200pods-new",
|
||||||
|
"zwrotp65r1200pods-new" };
|
||||||
|
|
||||||
void
|
void
|
||||||
basic_region::insert( shape_node Shape, scratch_data &Scratchpad, bool const Transform ) {
|
basic_region::insert( shape_node Shape, scratch_data &Scratchpad, bool const Transform ) {
|
||||||
|
|||||||
@@ -476,6 +476,13 @@ sound_source::stop( bool const Skipend ) {
|
|||||||
void
|
void
|
||||||
sound_source::update( audio::openal_source &Source ) {
|
sound_source::update( audio::openal_source &Source ) {
|
||||||
|
|
||||||
|
if( ( m_owner != nullptr )
|
||||||
|
&& ( false == m_owner->bEnabled ) ) {
|
||||||
|
// terminate the sound if the owner is gone
|
||||||
|
// TBD, TODO: replace with a listener pattern to receive vehicle removal and cab change events and such?
|
||||||
|
m_stop = true;
|
||||||
|
}
|
||||||
|
|
||||||
if( sound( sound_id::main ).buffer != null_handle ) {
|
if( sound( sound_id::main ).buffer != null_handle ) {
|
||||||
// basic variant: single main sound, with optional bookends
|
// basic variant: single main sound, with optional bookends
|
||||||
update_basic( Source );
|
update_basic( Source );
|
||||||
|
|||||||
@@ -384,6 +384,14 @@ erase_extension( std::string &Filename ) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
erase_leading_slashes( std::string &Filename ) {
|
||||||
|
|
||||||
|
while( Filename[ 0 ] == '/' ) {
|
||||||
|
Filename.erase( 0, 1 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// potentially replaces backward slashes in provided file path with unix-compatible forward slashes
|
// potentially replaces backward slashes in provided file path with unix-compatible forward slashes
|
||||||
void
|
void
|
||||||
replace_slashes( std::string &Filename ) {
|
replace_slashes( std::string &Filename ) {
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ http://mozilla.org/MPL/2.0/.
|
|||||||
#define szModelPath "models/"
|
#define szModelPath "models/"
|
||||||
#define szDynamicPath "dynamic/"
|
#define szDynamicPath "dynamic/"
|
||||||
#define szSoundPath "sounds/"
|
#define szSoundPath "sounds/"
|
||||||
|
#define szDataPath "data/"
|
||||||
|
|
||||||
#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))
|
#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))
|
||||||
|
|
||||||
@@ -189,6 +190,10 @@ std::time_t last_modified( std::string const &Filename );
|
|||||||
bool
|
bool
|
||||||
erase_extension( std::string &Filename );
|
erase_extension( std::string &Filename );
|
||||||
|
|
||||||
|
// potentially erase leading slashes from provided file path
|
||||||
|
void
|
||||||
|
erase_leading_slashes( std::string &Filename );
|
||||||
|
|
||||||
// potentially replaces backward slashes in provided file path with unix-compatible forward slashes
|
// potentially replaces backward slashes in provided file path with unix-compatible forward slashes
|
||||||
void
|
void
|
||||||
replace_slashes( std::string &Filename );
|
replace_slashes( std::string &Filename );
|
||||||
|
|||||||
Reference in New Issue
Block a user