16
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-07-23 06:19:18 +02:00

cab textures size limit, generic cab controls return type support, minor bug fixes

This commit is contained in:
tmj-fstate
2019-11-23 17:09:24 +01:00
parent e3dbaf9096
commit e3cc06af23
16 changed files with 416 additions and 112 deletions

View File

@@ -4592,7 +4592,7 @@ TController::UpdateSituation(double dt) {
}
// uśrednione napięcie sieci: przy spadku poniżej wartości minimalnej opóźnić rozruch o losowy czas
fVoltage = 0.5 * (fVoltage + mvControlling->PantographVoltage);
fVoltage = 0.5 * (fVoltage + std::max( mvControlling->GetAnyTrainsetVoltage(), mvControlling->PantographVoltage ) );
if( fVoltage < mvControlling->EnginePowerSource.CollectorParameters.MinV ) {
// gdy rozłączenie WS z powodu niskiego napięcia
if( fActionTime >= 0 ) {

View File

@@ -4185,9 +4185,9 @@ void TDynamicObject::RenderSounds() {
&& ( MoverParameters->Vel > 5.0 ) ) {
// scale volume with curve radius and vehicle speed
volume =
MoverParameters->AccN * MoverParameters->AccN
MoverParameters->AccN // * MoverParameters->AccN
* interpolate(
0.0, 1.0,
0.5, 1.0,
clamp(
MoverParameters->Vel / 40.0,
0.0, 1.0 ) )

View File

@@ -293,15 +293,23 @@ global_settings::ConfigParse(cParser &Parser) {
Parser.getTokens(1, false);
int size;
Parser >> size;
if (size <= 64) { iMaxTextureSize = 64; }
else if (size <= 128) { iMaxTextureSize = 128; }
else if (size <= 256) { iMaxTextureSize = 256; }
else if (size <= 512) { iMaxTextureSize = 512; }
else if (size <= 1024) { iMaxTextureSize = 1024; }
else if (size <= 2048) { iMaxTextureSize = 2048; }
else if (size <= 4096) { iMaxTextureSize = 4096; }
else if (size <= 8192) { iMaxTextureSize = 8192; }
else { iMaxTextureSize = 16384; }
auto p2size { 64 }; // start with 64px
while( (p2size <= 16384 ) && ( p2size <= size ) ) {
iMaxTextureSize = p2size;
p2size = p2size << 1;
}
}
else if (token == "maxcabtexturesize")
{
// wymuszenie przeskalowania tekstur
Parser.getTokens( 1, false );
int size;
Parser >> size;
auto p2size { 64 }; // start with 64px
while( ( p2size <= 16384 ) && ( p2size <= size ) ) {
iMaxCabTextureSize = p2size;
p2size = p2size << 1;
}
}
else if (token == "movelight")
{

View File

@@ -53,6 +53,7 @@ struct global_settings {
std::string asCurrentSceneryPath{ "scenery/" };
std::string asCurrentTexturePath{ szTexturePath };
std::string asCurrentDynamicPath;
int CurrentMaxTextureSize{ 4096 };
bool GfxFramebufferSRGB { true };
// settings
// filesystem
@@ -129,6 +130,7 @@ struct global_settings {
float AnisotropicFiltering{ 8.f }; // requested level of anisotropic filtering. TODO: move it to renderer object
float FieldOfView{ 45.f }; // vertical field of view for the camera. TODO: move it to the renderer
GLint iMaxTextureSize{ 4096 }; // maksymalny rozmiar tekstury
GLint iMaxCabTextureSize{ 4096 }; // largest allowed texture in vehicle cab
int iMultisampling{ 2 }; // tryb antyaliasingu: 0=brak,1=2px,2=4px,3=8px,4=16px
bool bSmoothTraction{ true }; // wygładzanie drutów starym sposobem
float SplineFidelity{ 1.f }; // determines segment size during conversion of splines to geometry

View File

@@ -1544,7 +1544,7 @@ public:
bool RunInternalCommand();
void PutCommand(std::string NewCommand, double NewValue1, double NewValue2, const TLocation &NewLocation);
bool CabActivisation(void);
bool CabDeactivisation(void);
bool CabDeactivisation( bool const Force = false );
/*! funkcje zwiekszajace/zmniejszajace nastawniki*/
/*! glowny nastawnik:*/

View File

@@ -1728,7 +1728,7 @@ void TMoverParameters::HeatingCheck( double const Timestep ) {
break;
}
case TPowerSource::Main: {
voltage = ( true == Mains ? PantographVoltage : 0.0 );
voltage = ( true == Mains ? std::max( GetAnyTrainsetVoltage(), PantographVoltage ) : 0.0 );
break;
}
default: {
@@ -2355,11 +2355,11 @@ bool TMoverParameters::CabActivisation(void)
// Q: 20160710
// wyłączenie rozrządu
// *************************************************************************************************
bool TMoverParameters::CabDeactivisation(void)
bool TMoverParameters::CabDeactivisation( bool const Force )
{
bool OK = false;
OK = (CabNo == ActiveCab); // o ile obsada jest w kabinie ze sterowaniem
OK = Force || (CabNo == ActiveCab); // o ile obsada jest w kabinie ze sterowaniem
if (OK)
{
CabNo = 0;
@@ -3736,7 +3736,7 @@ void TMoverParameters::CompressorCheck(double dt)
if( CompressorPower == 2 ) {
CompressorAllow = ConverterAllow;
}
// TODO: clean up compressor CompressorFlag state code, large parts are cloned and an utter mess
if (MaxCompressorF - MinCompressorF < 0.0001) {
// TODO: investigate purpose of this branch and whether it can be removed as it duplicates later code
if( ( true == CompressorAllow )
@@ -3802,10 +3802,9 @@ void TMoverParameters::CompressorCheck(double dt)
CompressorFlag = (
( ( CompressorAllow ) || ( CompressorStart == start_t::automatic ) )
&& ( CompressorAllowLocal )
&& ( Mains )
&& ( ( ConverterFlag )
|| ( CompressorPower == 0 )
|| ( CompressorPower == 3 ) ) );
&& ( CompressorPower == 0 ? Mains :
CompressorPower == 3 ? Mains :
ConverterFlag ) );
if( Compressor > MaxCompressorF ) {
// wyłącznik ciśnieniowy jest niezależny od sposobu zasilania
@@ -3878,10 +3877,9 @@ void TMoverParameters::CompressorCheck(double dt)
CompressorFlag = (
( ( CompressorAllow ) || ( CompressorStart == start_t::automatic ) )
&& ( CompressorAllowLocal )
&& ( Mains )
&& ( ( ConverterFlag )
|| ( CompressorPower == 0 )
|| ( CompressorPower == 3 ) ) );
&& ( CompressorPower == 0 ? Mains :
CompressorPower == 3 ? Mains :
ConverterFlag ) );
}
// NOTE: crude way to enforce simultaneous activation of compressors in multi-unit setups

View File

@@ -473,7 +473,7 @@ opengl_texture::load_DDS() {
int blockSize = ( data_format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT ? 8 : 16 );
int offset = 0;
while( ( data_width > Global.iMaxTextureSize ) || ( data_height > Global.iMaxTextureSize ) ) {
while( ( data_width > Global.CurrentMaxTextureSize ) || ( data_height > Global.CurrentMaxTextureSize ) ) {
// pomijanie zbyt dużych mipmap, jeśli wymagane jest ograniczenie rozmiaru
offset += ( ( data_width + 3 ) / 4 ) * ( ( data_height + 3 ) / 4 ) * blockSize;
data_width /= 2;
@@ -714,7 +714,7 @@ opengl_texture::load_TGA() {
}
downsize( GL_BGRA );
if( ( data_width > Global.iMaxTextureSize ) || ( data_height > Global.iMaxTextureSize ) ) {
if( ( data_width > Global.CurrentMaxTextureSize ) || ( data_height > Global.CurrentMaxTextureSize ) ) {
// for non-square textures there's currently possibility the scaling routine will have to abort
// before it gets all work done
data_state = resource_state::failed;
@@ -1054,7 +1054,7 @@ opengl_texture::set_filtering() const {
void
opengl_texture::downsize( GLuint const Format ) {
while( ( data_width > Global.iMaxTextureSize ) || ( data_height > Global.iMaxTextureSize ) ) {
while( ( data_width > Global.CurrentMaxTextureSize ) || ( data_height > Global.CurrentMaxTextureSize ) ) {
// scale down the base texture, if it's larger than allowed maximum
// NOTE: scaling is uniform along both axes, meaning non-square textures can drop below the maximum
// TODO: replace with proper scaling function once we have image middleware in place

View File

@@ -439,8 +439,15 @@ TTrain::TTrain() {
bool TTrain::Init(TDynamicObject *NewDynamicObject, bool e3d)
{ // powiązanie ręcznego sterowania kabiną z pojazdem
if( NewDynamicObject->Mechanik == nullptr ) {
/*
ErrorLog( "Bad config: can't take control of inactive vehicle \"" + NewDynamicObject->asName + "\"" );
return false;
*/
auto const activecab { (
NewDynamicObject->MoverParameters->ActiveCab > 0 ? "1" :
NewDynamicObject->MoverParameters->ActiveCab < 0 ? "2" :
"p" ) };
NewDynamicObject->create_controller( activecab, NewDynamicObject->ctOwner != nullptr );
}
DynamicSet(NewDynamicObject);
@@ -452,11 +459,20 @@ bool TTrain::Init(TDynamicObject *NewDynamicObject, bool e3d)
fMainRelayTimer = 0; // Hunter, do k...y nędzy, ustawiaj wartości początkowe zmiennych!
if( false == LoadMMediaFile( DynamicObject->asBaseDir + DynamicObject->MoverParameters->TypeName + ".mmd" ) ) {
iCabn = (
mvOccupied->ActiveCab < 0 ? 0 :
mvOccupied->ActiveCab > 0 ? 1 :
2 );
{
Global.CurrentMaxTextureSize = Global.iMaxCabTextureSize;
auto const result{ LoadMMediaFile( DynamicObject->asBaseDir + DynamicObject->MoverParameters->TypeName + ".mmd" ) };
Global.CurrentMaxTextureSize = Global.iMaxTextureSize;
if( false == result ) {
return false;
}
}
iCabn = 0;
// Ra: taka proteza - przesłanie kierunku do członów connected
if (mvControlled->ActiveDir > 0)
{ // było do przodu
@@ -4434,8 +4450,17 @@ void TTrain::OnCommand_generictoggle( TTrain *Train, command_data const &Command
return;
}
*/
if( Command.action == GLFW_PRESS ) {
// only reacting to press, so the switch doesn't flip back and forth if key is held down
if( item.type() == TGaugeType::push ) {
// impulse switch
// turn on
// visual feedback
item.UpdateValue( 1.0 );
}
else {
// two-state switch
if( item.GetDesiredValue() < 0.5 ) {
// turn on
// visual feedback
@@ -4447,6 +4472,16 @@ void TTrain::OnCommand_generictoggle( TTrain *Train, command_data const &Command
item.UpdateValue( 0.0 );
}
}
}
else if( Command.action == GLFW_RELEASE ) {
if( item.type() == TGaugeType::push ) {
// impulse switch
// turn off
// visual feedback
item.UpdateValue( 0.0 );
}
}
}
void TTrain::OnCommand_springbraketoggle(TTrain *Train, command_data const &Command) {

View File

@@ -15,6 +15,8 @@ http://mozilla.org/MPL/2.0/.
#include "Camera.h"
#include "Logs.h"
#include "utilities.h"
#include "simulation.h"
#include "Train.h"
namespace audio {
@@ -333,6 +335,7 @@ openal_renderer::update( double const Deltatime ) {
::alListenerfv( AL_ORIENTATION, reinterpret_cast<ALfloat const *>( orientation ) );
// velocity
if( Deltatime > 0 ) {
/*
glm::dvec3 const listenerposition { Global.pCamera.Pos };
glm::dvec3 const listenermovement { listenerposition - m_listenerposition };
m_listenerposition = listenerposition;
@@ -340,6 +343,40 @@ openal_renderer::update( double const Deltatime ) {
glm::length( listenermovement ) < 1000.0 ? // large jumps are typically camera changes
limit_velocity( listenermovement / Deltatime ) :
glm::vec3() );
*/
auto cameramove{ glm::dvec3{ Global.pCamera.Pos - m_camerapos} };
// intercept sudden user-induced camera jumps...
// ...from free fly mode change
if( m_freeflymode != FreeFlyModeFlag ) {
m_freeflymode = FreeFlyModeFlag;
if( true == m_freeflymode ) {
// cache last precipitation vector in the cab
m_cabcameramove = m_cameramove;
// don't carry previous precipitation vector to a new unrelated location
m_cameramove = glm::dvec3{ 0.0 };
}
else {
// restore last cached precipitation vector
m_cameramove = m_cabcameramove;
}
cameramove = glm::dvec3{ 0.0 };
}
// ...from jump between cab and window/mirror view
if( m_windowopen != Global.CabWindowOpen ) {
m_windowopen = Global.CabWindowOpen;
cameramove = glm::dvec3{ 0.0 };
}
// ... from cab change
if( ( simulation::Train != nullptr ) && ( simulation::Train->iCabn != m_activecab ) ) {
m_activecab = simulation::Train->iCabn;
cameramove = glm::dvec3{ 0.0 };
}
// ... from camera jump to another location
if( glm::length( cameramove ) > 100.0 ) {
cameramove = glm::dvec3{ 0.0 };
}
m_listenervelocity = limit_velocity( cameramove / Deltatime );
::alListenerfv( AL_VELOCITY, reinterpret_cast<ALfloat const *>( glm::value_ptr( m_listenervelocity ) ) );
}

View File

@@ -147,8 +147,16 @@ private:
ALCdevice * m_device { nullptr };
ALCcontext * m_context { nullptr };
bool m_ready { false }; // renderer is initialized and functional
/*
glm::dvec3 m_listenerposition;
*/
glm::vec3 m_listenervelocity;
glm::dvec3 m_camerapos{ 0.0 };
glm::dvec3 m_cameramove{ 0.0 };
glm::dvec3 m_cabcameramove{ 0.0 };
bool m_freeflymode{ true };
bool m_windowopen{ true };
int m_activecab{ 0 };
buffer_manager m_buffers;
// TBD: list of sources as vector, sorted by distance, for openal implementations with limited number of active sources?

View File

@@ -188,6 +188,14 @@ driver_mode::update() {
if( Global.changeDynObj ) {
// ABu zmiana pojazdu - przejście do innego
ChangeDynamic();
// move inside, but only if the human is in charge (otherwise we'll get pulled in when ai switches cabs)
if( ( simulation::Train != nullptr )
&& ( simulation::Train->Dynamic() != nullptr )
&& ( simulation::Train->Dynamic()->Mechanik != nullptr )
&& ( simulation::Train->Dynamic()->Mechanik->AIControllFlag == false )
&& ( true == FreeFlyModeFlag ) ) {
InOutKey();
}
}
if( simulation::Train != nullptr ) {
@@ -708,7 +716,6 @@ driver_mode::OnKeyDown(int cKey) {
}
break;
}
case GLFW_KEY_F4: {
if( Global.shiftState ) { ExternalView(); } // with Shift, cycle through external views
@@ -722,46 +729,76 @@ driver_mode::OnKeyDown(int cKey) {
break;
}
TDynamicObject *tmp = std::get<TDynamicObject *>( simulation::Region->find_vehicle( Global.pCamera.Pos, 50, true, false ) );
TDynamicObject *targetvehicle = std::get<TDynamicObject *>( simulation::Region->find_vehicle( Global.pCamera.Pos, 50, false, false ) );
if( tmp != nullptr ) {
if( targetvehicle != nullptr ) {
if( ( true == DebugModeFlag )
|| ( tmp->MoverParameters->Vel <= 5.0 ) ) {
|| ( targetvehicle->MoverParameters->Vel <= 5.0 ) ) {
// works always in debug mode, or for stopped/slow moving vehicles otherwise
if( simulation::Train ) { // jeśli mielismy pojazd
if( simulation::Train->Dynamic()->Mechanik ) { // na skutek jakiegoś błędu może czasem zniknąć
if( ( tmp->ctOwner == simulation::Train->Dynamic()->Mechanik )
&& ( true == Global.ctrlState ) ) {
// if the vehicle we left to the ai controlled the vehicle we're about to take over
// put the ai we left in charge of our old vehicle to sleep
// TODO: remove ctrl key mode once manual cab (de)activation is in place
simulation::Train->Dynamic()->Mechanik->primary( false );
simulation::Train->Dynamic()->Mechanik->action() = TAction::actSleep;
simulation::Train->Dynamic()->MoverParameters->CabDeactivisation();
}
simulation::Train->Dynamic()->Mechanik->TakeControl( true ); // oddajemy dotychczasowy AI
}
}
if( simulation::Train == nullptr ) {
simulation::Train = new TTrain(); // jeśli niczym jeszcze nie jeździlismy
}
if( simulation::Train->Init( tmp ) ) {
if( simulation::Train->Dynamic() != nullptr ) {
// jeśli mielismy pojazd
if( simulation::Train->Dynamic()->Mechanik ) { // na skutek jakiegoś błędu może czasem zniknąć
auto const *currentvehicle { simulation::Train->Dynamic() };
auto const sameconsist {
( targetvehicle->ctOwner == currentvehicle->Mechanik )
|| ( targetvehicle->ctOwner == currentvehicle->ctOwner ) };
auto const isincharge { currentvehicle->Mechanik->primary() };
auto const aidriveractive { currentvehicle->Mechanik->AIControllFlag };
if( !sameconsist && isincharge ) {
// oddajemy dotychczasowy AI
simulation::Train->Dynamic()->Mechanik->TakeControl( true );
}
if( ( !sameconsist ) // we leave behind an ai driver which should be preserved
|| ( aidriveractive ) // we want to preserve existing ai driver
|| ( targetvehicle->Mechanik != nullptr ) ) { // .changedynobj swaps drivers but we want a takeover not a swap
if( sameconsist && !aidriveractive ) {
// we will be taking over controller in the target vehicle, so get rid of the old one
// unless it's an active ai in which case leave it running
SafeDelete( simulation::Train->Dynamic()->Mechanik );
}
// HACK: by resetting owned vehicle we can reuse dynamic==nullptr code branch below
// TODO: refactor into utility method
simulation::Train->DynamicSet( nullptr );
}
else {
// we can simply move the 'human' controller to the new vehicle
Global.changeDynObj = targetvehicle;
// TODO: choose active cab based on camera's location relative to vehicle's location
/*
Global.changeDynObj->MoverParameters->ActiveCab = (
Train->DynamicObject->MoverParameters->Neighbours[ exitdirection ].vehicle_end ?
-1 :
1 );
*/
}
}
}
if( simulation::Train->Dynamic() == nullptr ) {
// jeśli niczym jeszcze nie jeździlismy
if( simulation::Train->Init( targetvehicle ) ) {
// przejmujemy sterowanie
if( true == Global.ctrlState ) {
// make sure we can take over the consist
// TODO: remove ctrl key mode once manual cab (de)activation is in place
simulation::Train->Dynamic()->Mechanik->primary( true );
simulation::Train->Dynamic()->MoverParameters->CabActivisation();
}
simulation::Train->Dynamic()->Mechanik->TakeControl( false, true );
if( true == simulation::Train->Dynamic()->Mechanik->primary() ) {
simulation::Train->Dynamic()->MoverParameters->CabDeactivisation( true ); // potentially left active
simulation::Train->Dynamic()->MoverParameters->CabActivisation();
}
InOutKey(); // do kabiny
}
else {
SafeDelete( simulation::Train ); // i nie ma czym sterować
}
if( simulation::Train ) {
InOutKey(); // do kabiny
}
}
}

View File

@@ -708,7 +708,9 @@ void opengl33_renderer::Render_pass(viewport_config &vp, rendermode const Mode)
// with active precipitation draw the opaque cab parts here to mask rain/snow placed 'inside' the cab
setup_drawing(false);
Render_cab(vehicle, vehicle->InteriorLightLevel, false);
Render_interior( false );
setup_drawing(true);
Render_interior( true );
}
Render_cab(vehicle, vehicle->InteriorLightLevel, true);
if( vehicle->InteriorLightLevel > 0.f ) {
@@ -931,6 +933,104 @@ void opengl33_renderer::Render_pass(viewport_config &vp, rendermode const Mode)
}
}
bool opengl33_renderer::Render_interior( bool const Alpha ) {
// TODO: early frustum based cull, camera might be pointing elsewhere
std::vector< std::pair<float, TDynamicObject *> > dynamics;
auto *dynamic { simulation::Train->Dynamic() };
// draw interiors of the occupied vehicle, and all vehicles behind it with permanent coupling, in case they're open-ended
while( dynamic != nullptr ) {
glm::dvec3 const originoffset { dynamic->vPosition - m_renderpass.pass_camera.position() };
float const squaredistance{ glm::length2( glm::vec3{ originoffset } / Global.ZoomFactor ) / Global.fDistanceFactor };
dynamics.emplace_back( squaredistance, dynamic );
dynamic = dynamic->NextC( coupling::permanent );
}
// draw also interiors of permanently coupled vehicles in front, if there's any
dynamic = simulation::Train->Dynamic()->PrevC( coupling::permanent );
while( dynamic != nullptr ) {
glm::dvec3 const originoffset { dynamic->vPosition - m_renderpass.pass_camera.position() };
float const squaredistance{ glm::length2( glm::vec3{ originoffset } / Global.ZoomFactor ) / Global.fDistanceFactor };
dynamics.emplace_back( squaredistance, dynamic );
dynamic = dynamic->PrevC( coupling::permanent );
}
if( Alpha ) {
std::sort(
std::begin( dynamics ), std::end( dynamics ),
[]( std::pair<float, TDynamicObject *> const &Left, std::pair<float, TDynamicObject *> const &Right ) {
return ( Left.first ) > ( Right.first ); } );
}
for( auto &dynamic : dynamics ) {
Render_lowpoly( dynamic.second, dynamic.first, true, Alpha );
}
return true;
}
bool opengl33_renderer::Render_lowpoly( TDynamicObject *Dynamic, float const Squaredistance, bool const Setup, bool const Alpha ) {
if( Dynamic->mdLowPolyInt == nullptr ) { return false; }
// low poly interior
if( Setup ) {
TSubModel::iInstance = reinterpret_cast<std::uintptr_t>( Dynamic ); //żeby nie robić cudzych animacji
glm::dvec3 const originoffset{ Dynamic->vPosition - m_renderpass.pass_camera.position() };
Dynamic->ABuLittleUpdate( Squaredistance ); // ustawianie zmiennych submodeli dla wspólnego modelu
glm::mat4 mv = OpenGLMatrices.data( GL_MODELVIEW );
::glPushMatrix();
::glTranslated( originoffset.x, originoffset.y, originoffset.z );
::glMultMatrixd( Dynamic->mMatrix.readArray() );
}
// HACK: reduce light level for vehicle interior if there's strong global lighting source
if( false == Alpha ) {
auto const luminance{ static_cast<float>( 0.5 * ( std::max( 0.3, Global.fLuminance - Global.Overcast ) ) ) };
setup_sunlight_intensity(
clamp( (
Dynamic->fShade > 0.f ?
Dynamic->fShade :
1.f )
- luminance,
0.f, 1.f ) );
Render( Dynamic->mdLowPolyInt, Dynamic->Material(), Squaredistance );
// HACK: if the model has low poly interior, we presume the load is placed inside and also affected by reduced light level
if( Dynamic->mdLoad ) {
// renderowanie nieprzezroczystego ładunku
Render( Dynamic->mdLoad, Dynamic->Material(), Squaredistance, { 0.f, Dynamic->LoadOffset, 0.f }, {} );
}
setup_sunlight_intensity( Dynamic->fShade > 0.f ? Dynamic->fShade : 1.f );
}
else {
// Render_Alpha( Dynamic->mdLowPolyInt, Dynamic->Material(), Squaredistance );
// HACK: some models have windows included as part of the main model instead of lowpoly
if( Dynamic->mdModel ) {
// main model
Render_Alpha( Dynamic->mdModel, Dynamic->Material(), Squaredistance );
}
}
if( Setup ) {
if( Dynamic->fShade > 0.0f ) {
// restore regular light level
setup_sunlight_intensity();
}
::glPopMatrix();
// TODO: check if this reset is needed. In theory each object should render all parts based on its own instance data anyway?
if( Dynamic->btnOn ) {
Dynamic->TurnOff(); // przywrócenie domyślnych pozycji submodeli
}
}
return true;
}
// creates dynamic environment cubemap
bool opengl33_renderer::Render_reflections(viewport_config &vp)
{
@@ -2301,23 +2401,7 @@ bool opengl33_renderer::Render(TDynamicObject *Dynamic)
// render
if( Dynamic->mdLowPolyInt ) {
// low poly interior
// HACK: reduce light level for vehicle interior if there's strong global lighting source
auto const luminance { static_cast<float>( 0.5 * ( std::max( 0.3, Global.fLuminance - Global.Overcast ) ) ) };
setup_sunlight_intensity(
clamp( (
Dynamic->fShade > 0.f ?
Dynamic->fShade :
1.f )
- luminance,
0.f, 1.f ) );
Render( Dynamic->mdLowPolyInt, Dynamic->Material(), squaredistance );
// HACK: if the model has low poly interior, we presume the load is placed inside and also affected by reduced light level
if( Dynamic->mdLoad ) {
// renderowanie nieprzezroczystego ładunku
Render( Dynamic->mdLoad, Dynamic->Material(), squaredistance, { 0.f, Dynamic->LoadOffset, 0.f }, {} );
}
setup_sunlight_intensity( Dynamic->fShade > 0.f ? Dynamic->fShade : 1.f );
Render_lowpoly( Dynamic, squaredistance, false );
}
else {
// HACK: if the model lacks low poly interior, we presume the load is placed outside
@@ -4069,10 +4153,12 @@ bool opengl33_renderer::Init_caps()
GLint texturesize;
::glGetIntegerv(GL_MAX_TEXTURE_SIZE, &texturesize);
Global.iMaxTextureSize = std::min(Global.iMaxTextureSize, texturesize);
WriteLog("texture sizes capped at " + std::to_string(Global.iMaxTextureSize) + "px");
Global.iMaxCabTextureSize = std::min( Global.iMaxCabTextureSize, texturesize );
WriteLog( "texture sizes capped at " + std::to_string(Global.iMaxTextureSize) + "p (" + std::to_string( Global.iMaxCabTextureSize ) + "p for cab textures)" );
Global.CurrentMaxTextureSize = Global.iMaxTextureSize;
m_shadowbuffersize = Global.shadowtune.map_size;
m_shadowbuffersize = std::min(m_shadowbuffersize, texturesize);
WriteLog("shadows map size capped at " + std::to_string(m_shadowbuffersize) + "px");
WriteLog("shadows map size capped at " + std::to_string(m_shadowbuffersize) + "p");
}
Global.DynamicLightCount = std::min(Global.DynamicLightCount, 8);

View File

@@ -225,6 +225,8 @@ class opengl33_renderer : public gfx_renderer {
void Render(TTrack *Track);
void Render(scene::basic_cell::path_sequence::const_iterator First, scene::basic_cell::path_sequence::const_iterator Last);
bool Render_cab(TDynamicObject const *Dynamic, float const Lightlevel, bool const Alpha = false);
bool Render_interior( bool const Alpha = false );
bool Render_lowpoly( TDynamicObject *Dynamic, float const Squaredistance, bool const Setup, bool const Alpha = false );
void Render(TMemCell *Memcell);
void Render_particles();
void Render_precipitation();

View File

@@ -525,7 +525,9 @@ opengl_renderer::Render_pass( rendermode const Mode ) {
// with active precipitation draw the opaque cab parts here to mask rain/snow placed 'inside' the cab
setup_drawing( false );
Render_cab( vehicle, vehicle->InteriorLightLevel, false );
Render_interior( false);
setup_drawing( true );
Render_interior( true );
}
Render_cab( vehicle, vehicle->InteriorLightLevel, true );
if( vehicle->InteriorLightLevel > 0.f ) {
@@ -723,6 +725,107 @@ opengl_renderer::Render_pass( rendermode const Mode ) {
}
}
bool opengl_renderer::Render_interior( bool const Alpha ) {
// NOTE: legacy renderer doesn't need to repaint translucent parts
// TODO: investigate reasons (depth writing?) and duplicate in opengl33 branch
if( Alpha ) { return false; }
// TODO: early frustum based cull, camera might be pointing elsewhere
std::vector< std::pair<float, TDynamicObject *> > dynamics;
auto *dynamic { simulation::Train->Dynamic() };
// draw interiors of the occupied vehicle, and all vehicles behind it with permanent coupling, in case they're open-ended
while( dynamic != nullptr ) {
glm::dvec3 const originoffset { dynamic->vPosition - m_renderpass.camera.position() };
float const squaredistance{ glm::length2( glm::vec3{ originoffset } / Global.ZoomFactor ) / Global.fDistanceFactor };
dynamics.emplace_back( squaredistance, dynamic );
dynamic = dynamic->NextC( coupling::permanent );
}
// draw also interiors of permanently coupled vehicles in front, if there's any
dynamic = simulation::Train->Dynamic()->PrevC( coupling::permanent );
while( dynamic != nullptr ) {
glm::dvec3 const originoffset { dynamic->vPosition - m_renderpass.camera.position() };
float const squaredistance{ glm::length2( glm::vec3{ originoffset } / Global.ZoomFactor ) / Global.fDistanceFactor };
dynamics.emplace_back( squaredistance, dynamic );
dynamic = dynamic->PrevC( coupling::permanent );
}
if( Alpha ) {
std::sort(
std::begin( dynamics ), std::end( dynamics ),
[]( std::pair<float, TDynamicObject *> const &Left, std::pair<float, TDynamicObject *> const &Right ) {
return ( Left.first ) > ( Right.first ); } );
}
for( auto &dynamic : dynamics ) {
Render_lowpoly( dynamic.second, dynamic.first, true, Alpha );
}
return true;
}
bool opengl_renderer::Render_lowpoly( TDynamicObject *Dynamic, float const Squaredistance, bool const Setup, bool const Alpha ) {
if( Dynamic->mdLowPolyInt == nullptr ) { return false; }
// low poly interior
glm::dvec3 const originoffset { Dynamic->vPosition - m_renderpass.camera.position() };
if( Setup ) {
TSubModel::iInstance = reinterpret_cast<std::uintptr_t>( Dynamic ); //żeby nie robić cudzych animacji
Dynamic->ABuLittleUpdate( Squaredistance ); // ustawianie zmiennych submodeli dla wspólnego modelu
::glPushMatrix();
::glTranslated( originoffset.x, originoffset.y, originoffset.z );
::glMultMatrixd( Dynamic->mMatrix.getArray() );
m_renderspecular = true; // vehicles are rendered with specular component. static models without, at least for the time being
}
// HACK: reduce light level for vehicle interior if there's strong global lighting source
if( false == Alpha ) {
auto const luminance{ static_cast<float>( 0.5 * ( std::max( 0.3, Global.fLuminance - Global.Overcast ) ) ) };
m_sunlight.apply_intensity(
clamp( (
Dynamic->fShade > 0.f ?
Dynamic->fShade :
1.f )
- luminance,
0.f, 1.f ) );
Render( Dynamic->mdLowPolyInt, Dynamic->Material(), Squaredistance );
// HACK: if the model has low poly interior, we presume the load is placed inside and also affected by reduced light level
if( Dynamic->mdLoad ) {
// renderowanie nieprzezroczystego ładunku
Render( Dynamic->mdLoad, Dynamic->Material(), Squaredistance, { 0.f, Dynamic->LoadOffset, 0.f }, {} );
}
m_sunlight.apply_intensity( Dynamic->fShade > 0.f ? Dynamic->fShade : 1.f );
}
else {
// Render_Alpha( Dynamic->mdLowPolyInt, Dynamic->Material(), Squaredistance );
// HACK: some models have windows included as part of the main model instead of lowpoly
if( Dynamic->mdModel ) {
// main model
Render_Alpha( Dynamic->mdModel, Dynamic->Material(), Squaredistance );
}
}
if( Setup ) {
m_renderspecular = false;
if( Dynamic->fShade > 0.0f ) {
// restore regular light level
m_sunlight.apply_intensity();
}
::glPopMatrix();
// TODO: check if this reset is needed. In theory each object should render all parts based on its own instance data anyway?
if( Dynamic->btnOn ) {
Dynamic->TurnOff(); // przywrócenie domyślnych pozycji submodeli
}
}
return true;
}
// creates dynamic environment cubemap
bool
opengl_renderer::Render_reflections() {
@@ -2182,25 +2285,7 @@ opengl_renderer::Render( TDynamicObject *Dynamic ) {
m_renderspecular = true; // vehicles are rendered with specular component. static models without, at least for the time being
// render
if( Dynamic->mdLowPolyInt ) {
// HACK: reduce light level for vehicle interior if there's strong global lighting source
auto const luminance { static_cast<float>( 0.5 * ( std::max( 0.3, Global.fLuminance - Global.Overcast ) ) ) };
m_sunlight.apply_intensity(
clamp( (
Dynamic->fShade > 0.f ?
Dynamic->fShade :
1.f )
- luminance,
0.f, 1.f ) );
// low poly interior
Render( Dynamic->mdLowPolyInt, Dynamic->Material(), squaredistance );
// HACK: if the model has low poly interior, we presume the load is placed inside and also affected by reduced light level
if( Dynamic->mdLoad ) {
// renderowanie nieprzezroczystego ładunku
Render( Dynamic->mdLoad, Dynamic->Material(), squaredistance, { 0.f, Dynamic->LoadOffset, 0.f }, {} );
}
m_sunlight.apply_intensity( Dynamic->fShade > 0.f ? Dynamic->fShade : 1.f );
Render_lowpoly( Dynamic, squaredistance, false );
}
else {
// HACK: if the model lacks low poly interior, we presume the load is placed outside
@@ -4078,11 +4163,13 @@ opengl_renderer::Init_caps() {
{
GLint texturesize;
::glGetIntegerv( GL_MAX_TEXTURE_SIZE, &texturesize );
Global.iMaxTextureSize = std::min( Global.iMaxTextureSize, texturesize );
WriteLog( "Texture sizes capped at " + std::to_string( Global.iMaxTextureSize ) + " pixels" );
Global.iMaxTextureSize = std::min(Global.iMaxTextureSize, texturesize);
Global.iMaxCabTextureSize = std::min( Global.iMaxCabTextureSize, texturesize );
WriteLog( "texture sizes capped at " + std::to_string(Global.iMaxTextureSize) + "p (" + std::to_string( Global.iMaxCabTextureSize ) + "p for cab textures)" );
Global.CurrentMaxTextureSize = Global.iMaxTextureSize;
m_shadowbuffersize = Global.shadowtune.map_size;
m_shadowbuffersize = std::min( m_shadowbuffersize, texturesize );
WriteLog( "Shadows map size capped at " + std::to_string( m_shadowbuffersize ) + " pixels" );
WriteLog( "Shadows map size capped at " + std::to_string( m_shadowbuffersize ) + "p" );
}
// cap the number of supported lights based on hardware
{

View File

@@ -218,6 +218,10 @@ private:
Render( scene::basic_cell::path_sequence::const_iterator First, scene::basic_cell::path_sequence::const_iterator Last );
bool
Render_cab( TDynamicObject const *Dynamic, float const Lightlevel, bool const Alpha = false );
bool
Render_interior( bool const Alpha = false );
bool
Render_lowpoly( TDynamicObject *Dynamic, float const Squaredistance, bool const Setup, bool const Alpha = false );
void
Render( TMemCell *Memcell );
void

View File

@@ -333,7 +333,7 @@ sound_source::play( int const Flags ) {
// initialize emitter-specific pitch variation if it wasn't yet set
if( m_pitchvariation == 0.f ) {
m_pitchvariation = 0.01f * static_cast<float>( Random( 97.5, 102.5 ) );
m_pitchvariation = 1.f; // 0.01f * static_cast<float>( Random( 97.5, 102.5 ) );
}
/*
if( ( ( m_flags & sound_flags::exclusive ) != 0 )