environment-centric light level, groundwork for delayed texture upload, minor bug fixes

This commit is contained in:
tmj-fstate
2017-03-18 01:37:00 +01:00
parent 441b39ce5f
commit 775e959bc9
10 changed files with 277 additions and 95 deletions

View File

@@ -2340,8 +2340,7 @@ void TDynamicObject::Move(double fDistance)
{ // przeliczenie cienia
TTrack *t0 = Axle0.GetTrack(); // już po przesunięciu
TTrack *t1 = Axle1.GetTrack();
if ((t0->eEnvironment == e_flat) && (t1->eEnvironment == e_flat)) // może być
// e_bridge...
if ((t0->eEnvironment == e_flat) && (t1->eEnvironment == e_flat)) // może być e_bridge...
fShade = 0.0; // standardowe oświetlenie
else
{ // jeżeli te tory mają niestandardowy stopień zacienienia
@@ -2364,6 +2363,21 @@ void TDynamicObject::Move(double fDistance)
if (Axle0.GetDirection() < 0)
d = t0->fTrackLength - d; // od drugiej strony liczona długość
d /= fAxleDist; // rozsataw osi procentowe znajdowanie się na torze
float shadefrom = 1.0f, shadeto = 1.0f;
// NOTE, TODO: calculating brightness level is used enough times to warrant encapsulation into a function
switch( t0->eEnvironment ) {
case e_canyon: { shadeto = 0.65f; break; }
case e_tunnel: { shadeto = 0.2f; break; }
default: {break; }
}
switch( t1->eEnvironment ) {
case e_canyon: { shadefrom = 0.65f; break; }
case e_tunnel: { shadefrom = 0.2f; break; }
default: {break; }
}
fShade = interpolate( shadefrom, shadeto, static_cast<float>( d ) );
/*
switch (t0->eEnvironment)
{ // typ zmiany oświetlenia - zakładam, że
// drugi tor ma e_flat
@@ -2384,6 +2398,7 @@ void TDynamicObject::Move(double fDistance)
fShade = d + (1.0 - d) * 0.20;
break; // zacienienie w tunelu
}
*/
}
}
}
@@ -3748,7 +3763,6 @@ void TDynamicObject::Render()
vPosition.z); // standardowe przesunięcie względem początku scenerii
glMultMatrixd(mMatrix.getArray());
#ifdef EU07_USE_OLD_LIGHTING_MODEL
// TODO: re-implement this
if (fShade > 0.0)
{ // Ra: zmiana oswietlenia w tunelu, wykopie
GLfloat ambientLight[4] = {0.5f, 0.5f, 0.5f, 1.0f};
@@ -3765,6 +3779,11 @@ void TDynamicObject::Render()
glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseLight);
glLightfv(GL_LIGHT0, GL_SPECULAR, specularLight);
}
#else
if( fShade > 0.0f ) {
// change light level based on light level of the occupied track
Global::DayLight.apply_intensity( fShade );
}
#endif
if (Global::bUseVBO)
{ // wersja VBO
@@ -3866,6 +3885,11 @@ void TDynamicObject::Render()
glLightfv(GL_LIGHT0, GL_DIFFUSE, Global::diffuseDayLight);
glLightfv(GL_LIGHT0, GL_SPECULAR, Global::specularDayLight);
}
#else
if( fShade > 0.0f ) {
// restore regular light level
Global::DayLight.apply_intensity();
}
#endif
glPopMatrix();
if (btnOn)

View File

@@ -94,8 +94,10 @@ void make_screenshot()
void window_resize_callback(GLFWwindow *window, int w, int h)
{
Global::ScreenWidth = w;
Global::ScreenHeight = h;
// NOTE: we have two variables which basically do the same thing as we don't have dynamic fullscreen toggle
// TBD, TODO: merge them?
Global::ScreenWidth = Global::iWindowWidth = w;
Global::ScreenHeight = Global::iWindowHeight = h;
Global::fDistanceFactor = std::max( 0.5f, h / 768.0f ); // not sure if this is really something we want to use
glViewport(0, 0, w, h);
}

View File

@@ -2582,7 +2582,6 @@ bool TGround::Init(std::string File)
// TFileStream *fs;
// int size;
std::string subpath = Global::asCurrentSceneryPath; // "scenery/";
auto const tokencount = cParser::countTokens( File, subpath );
cParser parser(File, cParser::buffer_FILE, subpath, Global::bLoadTraction);
std::string token;
@@ -2623,7 +2622,7 @@ bool TGround::Init(std::string File)
while (token != "") //(!Parser->EndOfFile)
{
++processed;
if( processed % 25 == 0 )
if( processed % 1000 == 0 )
{
UILayer.set_progress( parser.getProgress(), parser.getFullProgress() );
GfxRenderer.Render();

View File

@@ -53,6 +53,13 @@ opengl_texture::load() {
// data state will be set by called loader, so we're all done here
if( data_state == resource_state::good ) {
has_alpha = (
data_components == GL_RGBA ?
true :
false );
size = data.size() / 1024;
return;
}
@@ -487,82 +494,101 @@ opengl_texture::load_TGA() {
return;
}
void
resource_state
opengl_texture::bind() {
if( false == is_ready ) {
create();
if( data_state != resource_state::good ) {
return data_state;
}
}
::glBindTexture( GL_TEXTURE_2D, id );
return data_state;
}
resource_state
opengl_texture::create() {
if( data_state != resource_state::good ) {
// don't bother until we have useful texture data
return;
return data_state;
}
::glGenTextures( 1, &id );
::glBindTexture( GL_TEXTURE_2D, id );
// TODO: consider creating and storing low-res version of the texture if it's ever unloaded from the gfx card,
// as a placeholder until it can be loaded again
if( id == -1 ) {
// analyze specified texture traits
bool wraps{ true };
bool wrapt{ true };
for( auto const &trait : traits ) {
::glGenTextures( 1, &id );
::glBindTexture( GL_TEXTURE_2D, id );
switch( trait ) {
// analyze specified texture traits
bool wraps{ true };
bool wrapt{ true };
for( auto const &trait : traits ) {
case 's': { wraps = false; break; }
case 't': { wrapt = false; break; }
switch( trait ) {
case 's': { wraps = false; break; }
case 't': { wrapt = false; break; }
}
}
}
::glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, ( wraps == true ? GL_REPEAT : GL_CLAMP_TO_EDGE ) );
::glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, ( wrapt == true ? GL_REPEAT : GL_CLAMP_TO_EDGE ) );
::glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, ( wraps == true ? GL_REPEAT : GL_CLAMP_TO_EDGE ) );
::glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, ( wrapt == true ? GL_REPEAT : GL_CLAMP_TO_EDGE ) );
set_filtering();
set_filtering();
if( data_mapcount == 1 ) {
// fill missing mipmaps if needed
::glTexParameteri( GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE );
}
// upload texture data
int dataoffset = 0,
datasize = 0,
datawidth = data_width,
dataheight = data_height;
for( int maplevel = 0; maplevel < data_mapcount; ++maplevel ) {
if( data_mapcount == 1 ) {
// fill missing mipmaps if needed
::glTexParameteri( GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE );
}
// upload texture data
int dataoffset = 0,
datasize = 0,
datawidth = data_width,
dataheight = data_height;
for( int maplevel = 0; maplevel < data_mapcount; ++maplevel ) {
if( ( data_format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT )
|| ( data_format == GL_COMPRESSED_RGBA_S3TC_DXT3_EXT )
|| ( data_format == GL_COMPRESSED_RGBA_S3TC_DXT5_EXT ) ) {
// compressed dds formats
int const datablocksize =
( data_format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT ?
if( ( data_format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT )
|| ( data_format == GL_COMPRESSED_RGBA_S3TC_DXT3_EXT )
|| ( data_format == GL_COMPRESSED_RGBA_S3TC_DXT5_EXT ) ) {
// compressed dds formats
int const datablocksize =
( data_format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT ?
8 :
16 );
datasize = ( ( std::max(datawidth, 4) + 3 ) / 4 ) * ( ( std::max(dataheight, 4) + 3 ) / 4 ) * datablocksize;
datasize = ( ( std::max( datawidth, 4 ) + 3 ) / 4 ) * ( ( std::max( dataheight, 4 ) + 3 ) / 4 ) * datablocksize;
::glCompressedTexImage2D(
GL_TEXTURE_2D, maplevel, data_format,
datawidth, dataheight, 0,
datasize, (GLubyte *)&data[dataoffset] );
::glCompressedTexImage2D(
GL_TEXTURE_2D, maplevel, data_format,
datawidth, dataheight, 0,
datasize, (GLubyte *)&data[ dataoffset ] );
dataoffset += datasize;
datawidth = std::max( datawidth / 2, 1 );
dataheight = std::max( dataheight / 2, 1 );
}
else{
// uncompressed texture data
::glTexImage2D(
GL_TEXTURE_2D, 0, GL_RGBA8,
data_width, data_height, 0,
data_format, GL_UNSIGNED_BYTE, (GLubyte *)&data[0] );
dataoffset += datasize;
datawidth = std::max( datawidth / 2, 1 );
dataheight = std::max( dataheight / 2, 1 );
}
else {
// uncompressed texture data
::glTexImage2D(
GL_TEXTURE_2D, 0, GL_RGBA8,
data_width, data_height, 0,
data_format, GL_UNSIGNED_BYTE, (GLubyte *)&data[ 0 ] );
}
}
data.resize( 0 ); // TBD, TODO: keep the texture data if we start doing some gpu data cleaning down the road
/*
data_state = resource_state::none;
*/
data_state = resource_state::good;
is_ready = true;
}
is_ready = true;
has_alpha = (
data_components == GL_RGBA ?
true :
false );
data.resize( 0 ); // TBD, TODO: keep the texture data if we start doing some gpu data cleaning down the road
data_state = resource_state::none;
return data_state;
}
void
@@ -735,7 +761,9 @@ texture_manager::GetTextureId( std::string Filename, std::string const &Dir, int
if( true == Loadnow ) {
Texture( textureindex ).load();
#ifndef EU07_DEFERRED_TEXTURE_UPLOAD
Texture( textureindex ).create();
#endif
}
return textureindex;
@@ -755,20 +783,77 @@ texture_manager::Bind( texture_manager::size_type const Id ) {
*/
// TODO: do binding in texture object, add support for other types
if( Id != 0 ) {
auto const &texture = Texture( Id );
if( true == texture.is_ready ) {
::glBindTexture( GL_TEXTURE_2D, texture.id );
#ifndef EU07_DEFERRED_TEXTURE_UPLOAD
::glBindTexture( GL_TEXTURE_2D, Id );
m_activetexture = 0;
#else
if( Texture( Id ).bind() == resource_state::good ) {
m_activetexture = Id;
return;
}
else {
// TODO: bind a special 'error' texture on failure
}
#endif
}
else {
::glBindTexture( GL_TEXTURE_2D, 0 );
m_activetexture = 0;
::glBindTexture( GL_TEXTURE_2D, 0 );
m_activetexture = 0;
}
// all done
return;
}
void
texture_manager::Free() {
for( auto const &texture : m_textures ) {
// usunięcie wszyskich tekstur (bez usuwania struktury)
if( ( texture.id > 0 )
&& ( texture.id != -1 ) ) {
::glDeleteTextures( 1, &texture.id );
}
}
}
// debug performance string
std::string
texture_manager::Info() const {
// TODO: cache this data and update only during resource sweep
std::size_t totaltexturecount{ m_textures.size() - 1 };
std::size_t totaltexturesize{ 0 };
#ifdef EU07_DEFERRED_TEXTURE_UPLOAD
std::size_t readytexturecount{ 0 };
std::size_t readytexturesize{ 0 };
#endif
for( auto const& texture : m_textures ) {
totaltexturesize += texture.size;
#ifdef EU07_DEFERRED_TEXTURE_UPLOAD
if( texture.is_ready ) {
++readytexturecount;
readytexturesize += texture.size;
}
#endif
}
return
"Textures: "
#ifdef EU07_DEFERRED_TEXTURE_UPLOAD
+ std::to_string( readytexturecount )
+ " ("
+ to_string( readytexturesize / 1024.0f, 2 ) + " mb)"
+ " in vram, ";
#endif
+ std::to_string( totaltexturecount )
+ " ("
+ to_string( totaltexturesize / 1024.0f, 2 ) + " mb)"
+ " total";
}
// checks whether specified texture is in the texture bank. returns texture id, or npos.
texture_manager::size_type
texture_manager::find_in_databank( std::string const &Texturename ) {
@@ -808,12 +893,3 @@ texture_manager::find_on_disk( std::string const &Texturename ) {
// no results either way, report failure
return "";
}
void
texture_manager::Free()
{
for( auto const &texture : m_textures ) {
// usunięcie wszyskich tekstur (bez usuwania struktury)
::glDeleteTextures( 1, &texture.id );
}
}

View File

@@ -29,13 +29,15 @@ struct opengl_texture {
// methods
void load();
void create();
resource_state bind();
resource_state create();
// members
GLuint id{ (GLuint)-1 }; // associated GL resource
bool has_alpha{ false }; // indicates the texture has alpha channel
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 name; // name of the texture source file
std::size_t size{ 0 }; // size of the texture data, in kb
private:
// methods
@@ -71,11 +73,19 @@ public:
texture_manager();
~texture_manager() { Free(); }
size_type GetTextureId( std::string Filename, std::string const &Dir, int const Filter = -1, bool const Loadnow = true );
void Bind( size_type const Id );
opengl_texture &Texture( size_type const Id ) { return m_textures.at( Id ); }
void Init();
void Free();
size_type
GetTextureId( std::string Filename, std::string const &Dir, int const Filter = -1, bool const Loadnow = true );
void
Bind( size_type const Id );
opengl_texture &
Texture( size_type const Id ) { return m_textures[ Id ]; }
void
Init();
void
Free();
// debug performance string
std::string
Info() const;
private:
typedef std::unordered_map<std::string, size_type> index_map;

View File

@@ -2615,6 +2615,20 @@ void TTrack::EnvironmentSet()
break;
}
}
#else
switch( eEnvironment ) {
case e_canyon: {
Global::DayLight.apply_intensity( 0.5f );
break;
}
case e_tunnel: {
Global::DayLight.apply_intensity( 0.2f );
break;
}
default: {
break;
}
}
#endif
};
@@ -2630,6 +2644,17 @@ void TTrack::EnvironmentReset()
glLightfv(GL_LIGHT0, GL_DIFFUSE, Global::diffuseDayLight);
glLightfv(GL_LIGHT0, GL_SPECULAR, Global::specularDayLight);
}
#else
switch( eEnvironment ) {
case e_canyon:
case e_tunnel: {
Global::DayLight.apply_intensity();
break;
}
default: {
break;
}
}
#endif
};

View File

@@ -1285,7 +1285,6 @@ TWorld::Render_Cab() {
if( dynamic->mdKabina ) // bo mogła zniknąć przy przechodzeniu do innego pojazdu
{
#ifdef EU07_USE_OLD_LIGHTING_MODEL
// TODO: re-implement this
// oswietlenie kabiny
GLfloat ambientCabLight[ 4 ] = { 0.5f, 0.5f, 0.5f, 1.0f };
GLfloat diffuseCabLight[ 4 ] = { 0.5f, 0.5f, 0.5f, 1.0f };
@@ -1367,6 +1366,10 @@ TWorld::Render_Cab() {
glLightfv( GL_LIGHT0, GL_DIFFUSE, diffuseCabLight );
glLightfv( GL_LIGHT0, GL_SPECULAR, specularCabLight );
#else
if( dynamic->fShade > 0.0f ) {
// change light level based on light level of the occupied track
Global::DayLight.apply_intensity( dynamic->fShade );
}
if( dynamic->InteriorLightLevel > 0.0f ) {
// crude way to light the cabin, until we have something more complete in place
@@ -1393,12 +1396,15 @@ TWorld::Render_Cab() {
}
*/
#ifdef EU07_USE_OLD_LIGHTING_MODEL
// TODO: re-implement this
// przywrócenie standardowych, bo zawsze są zmieniane
glLightfv( GL_LIGHT0, GL_AMBIENT, Global::ambientDayLight );
glLightfv( GL_LIGHT0, GL_DIFFUSE, Global::diffuseDayLight );
glLightfv( GL_LIGHT0, GL_SPECULAR, Global::specularDayLight );
#else
if( dynamic->fShade > 0.0f ) {
// change light level based on light level of the occupied track
Global::DayLight.apply_intensity();
}
if( dynamic->InteriorLightLevel > 0.0f ) {
// reset the overall ambient
GLfloat ambient[] = { 0.0f, 0.0f, 0.0f, 1.0f };
@@ -1429,7 +1435,7 @@ TWorld::Update_UI() {
}
if( Controlled
&& Controlled->Mechanik ) {
OutText2 = Controlled->Mechanik->Relation();
OutText2 = Global::Bezogonkow( Controlled->Mechanik->Relation(), true );
if( !OutText2.empty() ) {
// jeśli jest podana relacja, to dodajemy punkt następnego zatrzymania
OutText3 = " -> " + Global::Bezogonkow( Controlled->Mechanik->NextStop(), true );
@@ -1700,7 +1706,9 @@ TWorld::Update_UI() {
std::string("Rendering mode: ")
+ ( Global::bUseVBO ?
"VBO" :
"Display Lists" );
"Display Lists" )
+ ". "
+ GfxRenderer.Info();
// dump last opengl error, if any
GLenum glerror = glGetError();

View File

@@ -67,7 +67,7 @@ light_array::update() {
if( light.count > 0 ) {
// TODO: intensity can be affected further by dim switch or other factors
light.intensity = std::max( 0.0f, std::log1p( (float)light.count ) );
light.intensity = std::max( 0.0f, std::log( (float)light.count + 1.0f ) );
light.intensity *= ( light.owner->DimHeadlights ? 0.6f : 1.0f );
}
else {

View File

@@ -465,8 +465,17 @@ opengl_renderer::Update ( double const Deltatime ) {
}
// TODO: add garbage collection and other less frequent works here
if( DebugModeFlag )
m_debuginfo = m_textures.Info();
};
// debug performance string
std::string const &
opengl_renderer::Info() const {
return m_debuginfo;
}
void
opengl_renderer::Update_Lights( light_array const &Lights ) {
@@ -494,14 +503,27 @@ opengl_renderer::Update_Lights( light_array const &Lights ) {
renderlight->set_position( scenelight.position );
renderlight->direction = scenelight.direction;
auto const luminance = Global::fLuminance; // TODO: adjust this based on location, e.g. for tunnels
auto luminance = Global::fLuminance; // TODO: adjust this based on location, e.g. for tunnels
auto const environment = scenelight.owner->fShade;
if( environment > 0.0f ) {
luminance *= environment;
}
renderlight->diffuse[ 0 ] = std::max( 0.0, scenelight.color.x - luminance );
renderlight->diffuse[ 1 ] = std::max( 0.0, scenelight.color.y - luminance );
renderlight->diffuse[ 2 ] = std::max( 0.0, scenelight.color.z - luminance );
renderlight->ambient[ 0 ] = std::max( 0.0, scenelight.color.x * scenelight.intensity - luminance);
renderlight->ambient[ 1 ] = std::max( 0.0, scenelight.color.y * scenelight.intensity - luminance );
renderlight->ambient[ 2 ] = std::max( 0.0, scenelight.color.z * scenelight.intensity - luminance );
/*
// NOTE: we have no simple way to determine whether the lights are falling on objects located in darker environment
// until this issue is resolved we're disabling reduction of light strenght based on the global luminance
renderlight->diffuse[ 0 ] = std::max( 0.0f, scenelight.color.x );
renderlight->diffuse[ 1 ] = std::max( 0.0f, scenelight.color.y );
renderlight->diffuse[ 2 ] = std::max( 0.0f, scenelight.color.z );
renderlight->ambient[ 0 ] = std::max( 0.0f, scenelight.color.x * scenelight.intensity );
renderlight->ambient[ 1 ] = std::max( 0.0f, scenelight.color.y * scenelight.intensity );
renderlight->ambient[ 2 ] = std::max( 0.0f, scenelight.color.z * scenelight.intensity );
*/
::glLightf( renderlight->id, GL_LINEAR_ATTENUATION, (0.25f * scenelight.count) / std::pow( scenelight.count, 2 ) * (scenelight.owner->DimHeadlights ? 1.25f : 1.0f) );
::glEnable( renderlight->id );

View File

@@ -33,11 +33,23 @@ struct opengl_light {
}
inline
void apply_intensity() {
void apply_intensity( float const Factor = 1.0f ) {
glLightfv( id, GL_AMBIENT, ambient );
glLightfv( id, GL_DIFFUSE, diffuse );
glLightfv( id, GL_SPECULAR, specular );
if( Factor == 1.0 ) {
glLightfv( id, GL_AMBIENT, ambient );
glLightfv( id, GL_DIFFUSE, diffuse );
glLightfv( id, GL_SPECULAR, specular );
}
else {
// temporary light scaling mechanics (ultimately this work will be left to the shaders
float4 scaledambient( ambient[ 0 ] * Factor, ambient[ 1 ] * Factor, ambient[ 2 ] * Factor, ambient[ 3 ] );
float4 scaleddiffuse( diffuse[ 0 ] * Factor, diffuse[ 1 ] * Factor, diffuse[ 2 ] * Factor, diffuse[ 3 ] );
float4 scaledspecular( specular[ 0 ] * Factor, specular[ 1 ] * Factor, specular[ 2 ] * Factor, specular[ 3 ] );
glLightfv( id, GL_AMBIENT, &scaledambient.x );
glLightfv( id, GL_DIFFUSE, &scaleddiffuse.x );
glLightfv( id, GL_SPECULAR, &scaledspecular.x );
}
}
inline
void apply_angle() {
@@ -127,6 +139,9 @@ public:
inline
bool
Visible( TDynamicObject const *Dynamic ) const { return m_camera.visible( Dynamic ); }
// debug performance string
std::string const &
Info() const;
texture_manager::size_type
GetTextureId( std::string Filename, std::string const &Dir, int const Filter = -1, bool const Loadnow = true ) {
@@ -168,6 +183,7 @@ private:
float m_drawrange{ 2500.0f }; // current drawing range
float m_drawtime{ 1000.0f / 30.0f * 20.0f }; // start with presumed 'neutral' average of 30 fps
double m_updateaccumulator{ 0.0 };
std::string m_debuginfo;
GLFWwindow *m_window{ nullptr };
};