mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-03-22 15:05:03 +01:00
vehicle visualization config file parameters, vehicle attachments support, axle clatter fix, disabled vehicles smoke fix
This commit is contained in:
16
Driver.cpp
16
Driver.cpp
@@ -1784,8 +1784,7 @@ void TController::OrdersClear()
|
||||
|
||||
void TController::Activation()
|
||||
{ // umieszczenie obsady w odpowiednim członie, wykonywane wyłącznie gdy steruje AI
|
||||
iDirection = iDirectionOrder; // kierunek (względem sprzęgów pojazdu z AI) właśnie został
|
||||
// ustalony (zmieniony)
|
||||
iDirection = iDirectionOrder; // kierunek (względem sprzęgów pojazdu z AI) właśnie został ustalony (zmieniony)
|
||||
if (iDirection)
|
||||
{ // jeśli jest ustalony kierunek
|
||||
TDynamicObject *old = pVehicle, *d = pVehicle; // w tym siedzi AI
|
||||
@@ -1794,7 +1793,7 @@ void TController::Activation()
|
||||
ZeroSpeed();
|
||||
ZeroDirection();
|
||||
mvOccupied->SpringBrakeActivate(true);
|
||||
if (TestFlag(d->MoverParameters->Couplers[iDirectionOrder < 0 ? 1 : 0].CouplingFlag, ctrain_controll)) {
|
||||
if (TestFlag(d->MoverParameters->Couplers[iDirectionOrder < 0 ? end::rear : end::front].CouplingFlag, ctrain_controll)) {
|
||||
mvControlling->MainSwitch( false); // dezaktywacja czuwaka, jeśli przejście do innego członu
|
||||
mvOccupied->DecLocalBrakeLevel(LocalBrakePosNo); // zwolnienie hamulca w opuszczanym pojeździe
|
||||
// mvOccupied->BrakeLevelSet((mvOccupied->BrakeHandle==FVel6)?4:-2); //odcięcie na
|
||||
@@ -1806,20 +1805,17 @@ void TController::Activation()
|
||||
mvOccupied->ActiveCab = mvOccupied->CabNo; // użytkownik moze zmienić ActiveCab wychodząc
|
||||
mvOccupied->CabDeactivisation(); // tak jest w Train.cpp
|
||||
// przejście AI na drugą stronę EN57, ET41 itp.
|
||||
while (TestFlag(d->MoverParameters->Couplers[iDirection < 0 ? 1 : 0].CouplingFlag, ctrain_controll))
|
||||
while (TestFlag(d->MoverParameters->Couplers[iDirection < 0 ? end::rear : end::front].CouplingFlag, ctrain_controll))
|
||||
{ // jeśli pojazd z przodu jest ukrotniony, to przechodzimy do niego
|
||||
d = iDirection * d->DirectionGet() < 0 ? d->Next() :
|
||||
d->Prev(); // przechodzimy do następnego członu
|
||||
if (d)
|
||||
{
|
||||
drugi = d->Mechanik; // zapamiętanie tego, co ewentualnie tam siedzi, żeby w razie
|
||||
// dwóch zamienić miejscami
|
||||
drugi = d->Mechanik; // zapamiętanie tego, co ewentualnie tam siedzi, żeby w razie dwóch zamienić miejscami
|
||||
d->Mechanik = this; // na razie bilokacja
|
||||
d->MoverParameters->SetInternalCommand(
|
||||
"", 0, 0); // usunięcie ewentualnie zalegającej komendy (Change_direction?)
|
||||
d->MoverParameters->SetInternalCommand("", 0, 0); // usunięcie ewentualnie zalegającej komendy (Change_direction?)
|
||||
if (d->DirectionGet() != pVehicle->DirectionGet()) // jeśli są przeciwne do siebie
|
||||
iDirection = -iDirection; // to będziemy jechać w drugą stronę względem
|
||||
// zasiedzianego pojazdu
|
||||
iDirection = -iDirection; // to będziemy jechać w drugą stronę względem zasiedzianego pojazdu
|
||||
pVehicle->Mechanik = drugi; // wsadzamy tego, co ewentualnie był (podwójna trakcja)
|
||||
pVehicle->MoverParameters->CabNo = 0; // wyłączanie kabin po drodze
|
||||
pVehicle->MoverParameters->ActiveCab = 0; // i zaznaczenie, że nie ma tam nikogo
|
||||
|
||||
139
DynObj.cpp
139
DynObj.cpp
@@ -2009,12 +2009,18 @@ TDynamicObject::Init(std::string Name, // nazwa pojazdu, np. "EU07-424"
|
||||
smBuforPrawy[ i ]->WillBeAnimated();
|
||||
}
|
||||
}
|
||||
for( auto &axle : m_axlesounds ) {
|
||||
// wyszukiwanie osi (0 jest na końcu, dlatego dodajemy długość?)
|
||||
axle.distance = (
|
||||
Reversed ?
|
||||
-axle.offset :
|
||||
( axle.offset + MoverParameters->Dim.L ) ) + fDist;
|
||||
if( Track->fSoundDistance > 0.f ) {
|
||||
for( auto &axle : m_axlesounds ) {
|
||||
// wyszukiwanie osi (0 jest na końcu, dlatego dodajemy długość?)
|
||||
axle.distance =
|
||||
clamp_circular<double>(
|
||||
( Reversed ?
|
||||
-axle.offset :
|
||||
axle.offset )
|
||||
- 0.5 * MoverParameters->Dim.L
|
||||
+ fDist,
|
||||
Track->fSoundDistance );
|
||||
}
|
||||
}
|
||||
// McZapkie-250202 end.
|
||||
Track->AddDynamicObject(this); // wstawiamy do toru na pozycję 0, a potem przesuniemy
|
||||
@@ -3155,12 +3161,19 @@ bool TDynamicObject::Update(double dt, double dt1)
|
||||
if( MyTrack->fSoundDistance != -1 ) {
|
||||
|
||||
if( MyTrack->fSoundDistance != dRailLength ) {
|
||||
dRailLength = MyTrack->fSoundDistance;
|
||||
for( auto &axle : m_axlesounds ) {
|
||||
axle.distance = axle.offset + MoverParameters->Dim.L;
|
||||
if( dRailLength > 0.0 ) {
|
||||
for( auto &axle : m_axlesounds ) {
|
||||
axle.distance =
|
||||
clamp_circular<double>(
|
||||
axle.distance - dRailLength
|
||||
+ axle.offset
|
||||
/* - 0.5 * MoverParameters->Dim.L */,
|
||||
MyTrack->fSoundDistance );
|
||||
}
|
||||
}
|
||||
dRailLength = MyTrack->fSoundDistance;
|
||||
}
|
||||
if( dRailLength != -1 ) {
|
||||
if( dRailLength > 0.0 ) {
|
||||
if( MoverParameters->Vel > 0 ) {
|
||||
// TODO: track quality and/or environment factors as separate subroutine
|
||||
auto volume =
|
||||
@@ -3182,35 +3195,37 @@ bool TDynamicObject::Update(double dt, double dt1)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
auto axleindex { 0 };
|
||||
for( auto &axle : m_axlesounds ) {
|
||||
axle.distance -= dDOMoveLen * Sign( dDOMoveLen );
|
||||
if( axle.distance < 0 ) {
|
||||
axle.distance += dRailLength;
|
||||
if( MoverParameters->Vel > 2.5 ) {
|
||||
// NOTE: for combined clatter sound we supply 1/100th of actual value, as the sound module converts does the opposite, converting received (typically) 0-1 values to 0-100 range
|
||||
auto const frequency = (
|
||||
true == axle.clatter.is_combined() ?
|
||||
MoverParameters->Vel * 0.01 :
|
||||
1.0 );
|
||||
axle.clatter
|
||||
.pitch( frequency )
|
||||
.gain( volume )
|
||||
.play();
|
||||
// crude bump simulation, drop down on even axles, move back up on the odd ones
|
||||
MoverParameters->AccVert +=
|
||||
interpolate(
|
||||
0.01, 0.05,
|
||||
clamp(
|
||||
GetVelocity() / ( 1 + MoverParameters->Vmax ),
|
||||
0.0, 1.0 ) )
|
||||
* ( ( axleindex % 2 ) != 0 ?
|
||||
1 :
|
||||
-1 );
|
||||
if( dRailLength > 0.0 ) {
|
||||
auto axleindex { 0 };
|
||||
for( auto &axle : m_axlesounds ) {
|
||||
axle.distance += dDOMoveLen * DirectionGet();
|
||||
if( ( axle.distance < 0 )
|
||||
|| ( axle.distance > dRailLength ) ) {
|
||||
axle.distance = clamp_circular( axle.distance, dRailLength );
|
||||
if( MoverParameters->Vel > 0.1 ) {
|
||||
// NOTE: for combined clatter sound we supply 1/100th of actual value, as the sound module converts does the opposite, converting received (typically) 0-1 values to 0-100 range
|
||||
auto const frequency = (
|
||||
true == axle.clatter.is_combined() ?
|
||||
MoverParameters->Vel * 0.01 :
|
||||
1.0 );
|
||||
axle.clatter
|
||||
.pitch( frequency )
|
||||
.gain( volume )
|
||||
.play();
|
||||
// crude bump simulation, drop down on even axles, move back up on the odd ones
|
||||
MoverParameters->AccVert +=
|
||||
interpolate(
|
||||
0.01, 0.05,
|
||||
clamp(
|
||||
GetVelocity() / ( 1 + MoverParameters->Vmax ),
|
||||
0.0, 1.0 ) )
|
||||
* ( ( axleindex % 2 ) != 0 ?
|
||||
1 :
|
||||
-1 );
|
||||
}
|
||||
}
|
||||
++axleindex;
|
||||
}
|
||||
++axleindex;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4268,11 +4283,24 @@ void TDynamicObject::LoadMMediaFile( std::string const &TypeName, std::string co
|
||||
std::string asAnimName;
|
||||
bool Stop_InternalData = false;
|
||||
pants = NULL; // wskaźnik pierwszego obiektu animującego dla pantografów
|
||||
cParser parser( TypeName + ".mmd", cParser::buffer_FILE, asBaseDir );
|
||||
if( false == parser.ok() ) {
|
||||
ErrorLog( "Failed to load appearance data for vehicle " + MoverParameters->Name );
|
||||
return;
|
||||
{
|
||||
// preliminary check whether the file exists
|
||||
cParser parser( TypeName + ".mmd", cParser::buffer_FILE, asBaseDir );
|
||||
if( false == parser.ok() ) {
|
||||
ErrorLog( "Failed to load appearance data for vehicle " + MoverParameters->Name );
|
||||
return;
|
||||
}
|
||||
}
|
||||
// use #include wrapper to access the appearance data file
|
||||
// this allows us to provide the file content with user-defined parameters
|
||||
cParser parser(
|
||||
"include " + TypeName + ".mmd"
|
||||
+ " " + asName // (p1)
|
||||
+ " " + TypeName // (p2)
|
||||
+ " " + ReplacableSkin // (p3)
|
||||
+ " end",
|
||||
cParser::buffer_TEXT,
|
||||
asBaseDir );
|
||||
std::string token;
|
||||
do {
|
||||
token = "";
|
||||
@@ -4430,15 +4458,30 @@ void TDynamicObject::LoadMMediaFile( std::string const &TypeName, std::string co
|
||||
parser.getTokens();
|
||||
parser >> asModel;
|
||||
replace_slashes( asModel );
|
||||
if( asModel[ 0 ] == '/' ) {
|
||||
// filename can potentially begin with a slash, and we don't need it
|
||||
asModel.erase( 0, 1 );
|
||||
}
|
||||
erase_leading_slashes( asModel );
|
||||
asModel = asBaseDir + asModel; // McZapkie-200702 - dynamics maja swoje modele w dynamic/basedir
|
||||
Global.asCurrentTexturePath = asBaseDir; // biezaca sciezka do tekstur to dynamic/...
|
||||
mdLowPolyInt = TModelsManager::GetModel(asModel, true);
|
||||
}
|
||||
|
||||
else if(token == "attachments:") {
|
||||
// additional 3d models attached to main body
|
||||
// content provided as a series of values together enclosed in "{}"
|
||||
// each value is a name of additional 3d model
|
||||
// value can be optionally set of values enclosed in "[]" in which case one value will be picked randomly
|
||||
// TBD: reconsider something more yaml-compliant and/or ability to define offset and rotation
|
||||
while( ( ( token = parser.getToken<std::string>() ) != "" )
|
||||
&& ( token != "}" ) ) {
|
||||
auto attachmentmodelname { deserialize_random_set( parser ) };
|
||||
replace_slashes( attachmentmodelname );
|
||||
Global.asCurrentTexturePath = asBaseDir; // biezaca sciezka do tekstur to dynamic/...
|
||||
auto *attachmentmodel { TModelsManager::GetModel( asBaseDir + attachmentmodelname, true ) };
|
||||
if( attachmentmodel != nullptr ) {
|
||||
mdAttachments.emplace_back( attachmentmodel );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if(token == "loads:") {
|
||||
// default load visualization models overrides
|
||||
// content provided as "key: value" pairs together enclosed in "{}"
|
||||
@@ -4982,18 +5025,18 @@ void TDynamicObject::LoadMMediaFile( std::string const &TypeName, std::string co
|
||||
// add another axle entry to the list
|
||||
axle_sounds axle {
|
||||
0,
|
||||
std::atof( token.c_str() ),
|
||||
std::atof( token.c_str() ) * -1.0, // for axle locations negative value means ahead of centre but vehicle faces +Z in 'its' space
|
||||
{ sound_placement::external, static_cast<float>( dSDist ) } };
|
||||
axle.clatter.deserialize( parser, sound_type::single );
|
||||
axle.clatter.owner( this );
|
||||
axle.clatter.offset( { 0, 0, -axle.offset } ); // vehicle faces +Z in 'its' space, for axle locations negative value means ahead of centre
|
||||
axle.clatter.offset( { 0, 0, axle.offset } );
|
||||
m_axlesounds.emplace_back( axle );
|
||||
}
|
||||
// arrange the axles in case they're listed out of order
|
||||
std::sort(
|
||||
std::begin( m_axlesounds ), std::end( m_axlesounds ),
|
||||
[]( axle_sounds const &Left, axle_sounds const &Right ) {
|
||||
return ( Left.offset < Right.offset ); } );
|
||||
return ( Left.offset > Right.offset ); } );
|
||||
}
|
||||
|
||||
else if( ( token == "engine:" )
|
||||
|
||||
1
DynObj.h
1
DynObj.h
@@ -200,6 +200,7 @@ public:
|
||||
TModel3d *mdLowPolyInt; // ABu 010305: wnetrze lowpoly
|
||||
std::array<TSubModel *, 3> LowPolyIntCabs {}; // pointers to low fidelity version of individual driver cabs
|
||||
bool JointCabs{ false }; // flag for vehicles with multiple virtual 'cabs' sharing location and 3d model(s)
|
||||
std::vector<TModel3d *> mdAttachments; // additional models attached to main body
|
||||
struct destination_data {
|
||||
TSubModel *sign { nullptr }; // submodel mapped with replacable texture -4
|
||||
bool has_light { false }; // the submodel was originally configured with self-illumination attribute
|
||||
|
||||
42
EvLaunch.cpp
42
EvLaunch.cpp
@@ -78,25 +78,6 @@ bool TEventLauncher::Load(cParser *parser)
|
||||
}
|
||||
parser->getTokens();
|
||||
*parser >> DeltaTime;
|
||||
if (DeltaTime < 0)
|
||||
DeltaTime = -DeltaTime; // dla ujemnego zmieniamy na dodatni
|
||||
else if (DeltaTime > 0)
|
||||
{ // wartość dodatnia oznacza wyzwalanie o określonej godzinie
|
||||
iMinute = int(DeltaTime) % 100; // minuty są najmłodszymi cyframi dziesietnymi
|
||||
iHour = int(DeltaTime - iMinute) / 100; // godzina to setki
|
||||
DeltaTime = 0; // bez powtórzeń
|
||||
// potentially shift the provided time by requested offset
|
||||
auto const timeoffset { static_cast<int>( Global.ScenarioTimeOffset * 60 ) };
|
||||
if( timeoffset != 0 ) {
|
||||
auto const adjustedtime { clamp_circular( iHour * 60 + iMinute + timeoffset, 24 * 60 ) };
|
||||
iHour = ( adjustedtime / 60 ) % 24;
|
||||
iMinute = adjustedtime % 60;
|
||||
}
|
||||
WriteLog(
|
||||
"EventLauncher at "
|
||||
+ std::to_string( iHour ) + ":"
|
||||
+ ( iMinute < 10 ? "0" : "" ) + to_string( iMinute ) ); // wyświetlenie czasu
|
||||
}
|
||||
parser->getTokens();
|
||||
*parser >> token;
|
||||
asEvent1Name = token; // pierwszy event
|
||||
@@ -145,6 +126,29 @@ bool TEventLauncher::Load(cParser *parser)
|
||||
parser->getTokens(); // słowo zamykające
|
||||
*parser >> token;
|
||||
}
|
||||
|
||||
if( DeltaTime < 0 )
|
||||
DeltaTime = -DeltaTime; // dla ujemnego zmieniamy na dodatni
|
||||
else if( DeltaTime > 0 ) { // wartość dodatnia oznacza wyzwalanie o określonej godzinie
|
||||
iMinute = int( DeltaTime ) % 100; // minuty są najmłodszymi cyframi dziesietnymi
|
||||
iHour = int( DeltaTime - iMinute ) / 100; // godzina to setki
|
||||
DeltaTime = 0; // bez powtórzeń
|
||||
// potentially shift the provided time by requested offset
|
||||
auto const timeoffset{ static_cast<int>( Global.ScenarioTimeOffset * 60 ) };
|
||||
if( timeoffset != 0 ) {
|
||||
auto const adjustedtime{ clamp_circular( iHour * 60 + iMinute + timeoffset, 24 * 60 ) };
|
||||
iHour = ( adjustedtime / 60 ) % 24;
|
||||
iMinute = adjustedtime % 60;
|
||||
}
|
||||
|
||||
WriteLog(
|
||||
"EventLauncher at "
|
||||
+ std::to_string( iHour ) + ":"
|
||||
+ ( iMinute < 10 ? "0" : "" ) + to_string( iMinute )
|
||||
+ " (" + asEvent1Name
|
||||
+ ( asEvent2Name != "none" ? " / " + asEvent2Name : "" )
|
||||
+ ")" ); // wyświetlenie czasu
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -244,7 +244,7 @@ bool TTrackFollower::Move(double fDistance, bool bPrimary)
|
||||
{ // gdy zostaje na tym samym torze (przesuwanie już nie zmienia toru)
|
||||
if (bPrimary)
|
||||
{ // tylko gdy początkowe ustawienie, dodajemy eventy stania do kolejki
|
||||
if (Owner->MoverParameters->CabNo != 0) {
|
||||
if (Owner->MoverParameters->ActiveCab != 0) {
|
||||
|
||||
pCurrentTrack->QueueEvents( pCurrentTrack->m_events1, Owner, -1.0 );
|
||||
pCurrentTrack->QueueEvents( pCurrentTrack->m_events2, Owner, -1.0 );
|
||||
|
||||
@@ -44,6 +44,7 @@ drivingaid_panel::update() {
|
||||
|
||||
auto const *mover = controlled->MoverParameters;
|
||||
auto const *driver = controlled->Mechanik;
|
||||
auto const *owner = ( controlled->ctOwner != nullptr ? controlled->ctOwner : controlled->Mechanik );
|
||||
|
||||
{ // throttle, velocity, speed limits and grade
|
||||
std::string expandedtext;
|
||||
@@ -60,8 +61,8 @@ drivingaid_panel::update() {
|
||||
gradetext = m_buffer.data();
|
||||
}
|
||||
// next speed limit
|
||||
auto const speedlimit { static_cast<int>( std::floor( driver->VelDesired ) ) };
|
||||
auto const nextspeedlimit { static_cast<int>( std::floor( driver->VelNext ) ) };
|
||||
auto const speedlimit { static_cast<int>( std::floor( owner->VelDesired ) ) };
|
||||
auto const nextspeedlimit { static_cast<int>( std::floor( owner->VelNext ) ) };
|
||||
std::string nextspeedlimittext;
|
||||
if( nextspeedlimit != speedlimit ) {
|
||||
std::snprintf(
|
||||
@@ -117,7 +118,7 @@ drivingaid_panel::update() {
|
||||
{ // alerter, hints
|
||||
std::string expandedtext;
|
||||
if( is_expanded ) {
|
||||
auto const stoptime { static_cast<int>( std::ceil( -1.0 * controlled->Mechanik->fStopTime ) ) };
|
||||
auto const stoptime { static_cast<int>( std::ceil( -1.0 * owner->fStopTime ) ) };
|
||||
if( stoptime > 0 ) {
|
||||
std::snprintf(
|
||||
m_buffer.data(), m_buffer.size(),
|
||||
@@ -126,7 +127,7 @@ drivingaid_panel::update() {
|
||||
expandedtext = m_buffer.data();
|
||||
}
|
||||
else {
|
||||
auto const trackblockdistance{ std::abs( controlled->Mechanik->TrackBlock() ) };
|
||||
auto const trackblockdistance{ std::abs( owner->TrackBlock() ) };
|
||||
if( trackblockdistance <= 75.0 ) {
|
||||
std::snprintf(
|
||||
m_buffer.data(), m_buffer.size(),
|
||||
|
||||
6
parser.h
6
parser.h
@@ -50,20 +50,24 @@ class cParser //: public std::stringstream
|
||||
bool
|
||||
expectToken( std::string const &Value ) {
|
||||
return readToken() == Value; };
|
||||
inline
|
||||
bool
|
||||
eof() {
|
||||
return mStream->eof(); };
|
||||
inline
|
||||
bool
|
||||
ok() {
|
||||
return !mStream->fail(); };
|
||||
return ( !mStream->fail() ); };
|
||||
cParser &
|
||||
autoclear( bool const Autoclear );
|
||||
inline
|
||||
bool
|
||||
autoclear() const {
|
||||
return m_autoclear; }
|
||||
bool
|
||||
getTokens( unsigned int Count = 1, bool ToLower = true, char const *Break = "\n\r\t ;" );
|
||||
// returns next incoming token, if any, without removing it from the set
|
||||
inline
|
||||
std::string
|
||||
peek() const {
|
||||
return (
|
||||
|
||||
@@ -167,10 +167,16 @@ smoke_source::update( double const Timedelta, bool const Onlydespawn ) {
|
||||
std::min<float>(
|
||||
m_spawncount + ( m_spawnrate * Timedelta * Global.SmokeFidelity ),
|
||||
m_max_particles ) );
|
||||
// HACK: don't spawn particles in tunnels, to prevent smoke clipping through 'terrain' outside
|
||||
if( ( m_ownertype == owner_type::vehicle )
|
||||
&& ( m_owner.vehicle->RaTrackGet()->eEnvironment == e_tunnel ) ) {
|
||||
// consider special spawn rate cases
|
||||
if( m_ownertype == owner_type::vehicle ) {
|
||||
// HACK: don't spawn particles in tunnels, to prevent smoke clipping through 'terrain' outside
|
||||
if( m_owner.vehicle->RaTrackGet()->eEnvironment == e_tunnel ) {
|
||||
m_spawncount = 0.f;
|
||||
}
|
||||
if( false == m_owner.vehicle->bEnabled ) {
|
||||
// don't spawn particles for vehicles which left the scenario
|
||||
m_spawncount = 0.f;
|
||||
}
|
||||
}
|
||||
// update spawned particles
|
||||
for( auto particleiterator { std::begin( m_particles ) }; particleiterator != std::end( m_particles ); ++particleiterator ) {
|
||||
|
||||
30
renderer.cpp
30
renderer.cpp
@@ -2393,8 +2393,13 @@ opengl_renderer::Render( TDynamicObject *Dynamic ) {
|
||||
}
|
||||
}
|
||||
if( Dynamic->mdModel ) {
|
||||
// main model
|
||||
Render( Dynamic->mdModel, Dynamic->Material(), squaredistance );
|
||||
}
|
||||
// optional attached models
|
||||
for( auto *attachment : Dynamic->mdAttachments ) {
|
||||
Render( attachment, Dynamic->Material(), squaredistance );
|
||||
}
|
||||
// post-render cleanup
|
||||
m_renderspecular = false;
|
||||
if( Dynamic->fShade > 0.0f ) {
|
||||
@@ -2411,10 +2416,18 @@ opengl_renderer::Render( TDynamicObject *Dynamic ) {
|
||||
Render( Dynamic->mdLowPolyInt, Dynamic->Material(), squaredistance );
|
||||
// }
|
||||
}
|
||||
if( Dynamic->mdModel )
|
||||
if( Dynamic->mdModel ) {
|
||||
// main model
|
||||
Render( Dynamic->mdModel, Dynamic->Material(), squaredistance );
|
||||
if( Dynamic->mdLoad ) // renderowanie nieprzezroczystego ładunku
|
||||
}
|
||||
// optional attached models
|
||||
for( auto *attachment : Dynamic->mdAttachments ) {
|
||||
Render( attachment, Dynamic->Material(), squaredistance );
|
||||
}
|
||||
if( Dynamic->mdLoad ) {
|
||||
// renderowanie nieprzezroczystego ładunku
|
||||
Render( Dynamic->mdLoad, Dynamic->Material(), squaredistance, { 0.f, Dynamic->LoadOffset, 0.f }, {} );
|
||||
}
|
||||
// post-render cleanup
|
||||
break;
|
||||
}
|
||||
@@ -3523,11 +3536,18 @@ opengl_renderer::Render_Alpha( TDynamicObject *Dynamic ) {
|
||||
// }
|
||||
}
|
||||
|
||||
if( Dynamic->mdModel )
|
||||
if( Dynamic->mdModel ) {
|
||||
// main model
|
||||
Render_Alpha( Dynamic->mdModel, Dynamic->Material(), squaredistance );
|
||||
|
||||
if( Dynamic->mdLoad ) // renderowanie nieprzezroczystego ładunku
|
||||
}
|
||||
// optional attached models
|
||||
for( auto *attachment : Dynamic->mdAttachments ) {
|
||||
Render_Alpha( attachment, Dynamic->Material(), squaredistance );
|
||||
}
|
||||
if( Dynamic->mdLoad ) {
|
||||
// renderowanie nieprzezroczystego ładunku
|
||||
Render_Alpha( Dynamic->mdLoad, Dynamic->Material(), squaredistance, { 0.f, Dynamic->LoadOffset, 0.f }, {} );
|
||||
}
|
||||
|
||||
// post-render cleanup
|
||||
m_renderspecular = false;
|
||||
|
||||
Reference in New Issue
Block a user