diff --git a/AnimModel.cpp b/AnimModel.cpp index 684ebb26..615b65ba 100644 --- a/AnimModel.cpp +++ b/AnimModel.cpp @@ -434,7 +434,7 @@ bool TAnimModel::Init(std::string const &asName, std::string const &asReplacable m_materialdata.replacable_skins[ 1 ] = GfxRenderer.Fetch_Material( asReplacableTexture ); } if( ( m_materialdata.replacable_skins[ 1 ] != null_handle ) - && ( GfxRenderer.Material( m_materialdata.replacable_skins[ 1 ] ).opacity < 1.0f ) ) { + && ( GfxRenderer.Material( m_materialdata.replacable_skins[ 1 ] ).opacity == 0.0f ) ) { // tekstura z kanałem alfa - nie renderować w cyklu nieprzezroczystych m_materialdata.textures_alpha = 0x31310031; } diff --git a/CMakeLists.txt b/CMakeLists.txt index 5fbb1841..71897631 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -86,6 +86,7 @@ set(SOURCES "gl/framebuffer.cpp" "gl/renderbuffer.cpp" "gl/postfx.cpp" +"gl/cubemap.cpp" "imgui/imgui.cpp" "imgui/imgui_demo.cpp" diff --git a/DynObj.cpp b/DynObj.cpp index 4e2296f5..3715bf9a 100644 --- a/DynObj.cpp +++ b/DynObj.cpp @@ -4587,7 +4587,7 @@ void TDynamicObject::LoadMMediaFile( std::string BaseDir, std::string TypeName, else { m_materialdata.replacable_skins[ 1 ] = GfxRenderer.Fetch_Material( ReplacableSkin ); } - if( GfxRenderer.Material( m_materialdata.replacable_skins[ 1 ] ).opacity < 1.0f ) { + if( GfxRenderer.Material( m_materialdata.replacable_skins[ 1 ] ).opacity == 0.0f ) { // tekstura -1 z kanałem alfa - nie renderować w cyklu nieprzezroczystych m_materialdata.textures_alpha = 0x31310031; } @@ -4597,17 +4597,17 @@ void TDynamicObject::LoadMMediaFile( std::string BaseDir, std::string TypeName, } if( ( m_materialdata.replacable_skins[ 2 ] ) - && ( GfxRenderer.Material( m_materialdata.replacable_skins[ 2 ] ).opacity < 1.0f ) ) { + && ( GfxRenderer.Material( m_materialdata.replacable_skins[ 2 ] ).opacity == 0.0f ) ) { // tekstura -2 z kanałem alfa - nie renderować w cyklu nieprzezroczystych m_materialdata.textures_alpha |= 0x02020002; } if( ( m_materialdata.replacable_skins[ 3 ] ) - && ( GfxRenderer.Material( m_materialdata.replacable_skins[ 3 ] ).opacity < 1.0f ) ) { + && ( GfxRenderer.Material( m_materialdata.replacable_skins[ 3 ] ).opacity == 0.0f ) ) { // tekstura -3 z kanałem alfa - nie renderować w cyklu nieprzezroczystych m_materialdata.textures_alpha |= 0x04040004; } if( ( m_materialdata.replacable_skins[ 4 ] ) - && ( GfxRenderer.Material( m_materialdata.replacable_skins[ 4 ] ).opacity < 1.0f ) ) { + && ( GfxRenderer.Material( m_materialdata.replacable_skins[ 4 ] ).opacity == 0.0f ) ) { // tekstura -4 z kanałem alfa - nie renderować w cyklu nieprzezroczystych m_materialdata.textures_alpha |= 0x08080008; } diff --git a/Model3d.cpp b/Model3d.cpp index d64d8b2d..9d0ae230 100644 --- a/Model3d.cpp +++ b/Model3d.cpp @@ -309,27 +309,27 @@ int TSubModel::Load( cParser &parser, TModel3d *Model, /*int Pos,*/ bool dynamic else if (material.find("replacableskin") != material.npos) { // McZapkie-060702: zmienialne skory modelu m_material = -1; - iFlags |= (Opacity < 1.0) ? 1 : 0x10; // zmienna tekstura 1 + iFlags |= (Opacity == 1.0f) ? 1 : 0x10; // zmienna tekstura 1 } else if (material == "-1") { m_material = -1; - iFlags |= (Opacity < 1.0) ? 1 : 0x10; // zmienna tekstura 1 + iFlags |= (Opacity == 1.0f) ? 1 : 0x10; // zmienna tekstura 1 } else if (material == "-2") { m_material = -2; - iFlags |= (Opacity < 1.0) ? 2 : 0x10; // zmienna tekstura 2 + iFlags |= (Opacity == 1.0f) ? 2 : 0x10; // zmienna tekstura 2 } else if (material == "-3") { m_material = -3; - iFlags |= (Opacity < 1.0) ? 4 : 0x10; // zmienna tekstura 3 + iFlags |= (Opacity == 1.0f) ? 4 : 0x10; // zmienna tekstura 3 } else if (material == "-4") { m_material = -4; - iFlags |= (Opacity < 1.0) ? 8 : 0x10; // zmienna tekstura 4 + iFlags |= (Opacity == 1.0f) ? 8 : 0x10; // zmienna tekstura 4 } else { Name_Material(material); @@ -344,13 +344,18 @@ int TSubModel::Load( cParser &parser, TModel3d *Model, /*int Pos,*/ bool dynamic // 1. Opacity=0 (przejściowo <1, czy tam <100) oraz // 2. tekstura ma przezroczystość iFlags |= - ( ( ( Opacity < 1.0 ) + ( ( ( Opacity == 0.0f ) && ( ( m_material != null_handle ) - && ( GfxRenderer.Material( m_material ).opacity < 1.0f ) ) ) ? + && ( GfxRenderer.Material( m_material ).opacity == 0.0f ) ) ) ? 0x20 : 0x10 ); // 0x10-nieprzezroczysta, 0x20-przezroczysta }; } + else if (eType == TP_STARS) + { + m_material = GfxRenderer.Fetch_Material( "stars" ); + iFlags |= 0x10; + } else iFlags |= 0x10; @@ -1682,7 +1687,7 @@ void TSubModel::BinInit(TSubModel *s, float4x4 *m, std::vector *t, // texture-alpha based fallback if for some reason we don't have opacity flag set yet iFlags |= ( ( ( m_material != null_handle ) - && ( GfxRenderer.Material( m_material ).opacity < 1.0f ) ) ? + && ( GfxRenderer.Material( m_material ).opacity == 0.0f ) ) ? 0x20 : 0x10 ); // 0x10-nieprzezroczysta, 0x20-przezroczysta } diff --git a/Texture.cpp b/Texture.cpp index 048bd50f..69b02dac 100644 --- a/Texture.cpp +++ b/Texture.cpp @@ -49,7 +49,7 @@ opengl_texture::load() { if( extension == "dds" ) { load_DDS(); } else if( extension == "tga" ) { load_TGA(); } - else if( extension == "png" ) { load_PNG(); } + else if( extension == "png" ) { load_PNG(); } else if( extension == "bmp" ) { load_BMP(); } else if( extension == "tex" ) { load_TEX(); } else { goto fail; } @@ -107,8 +107,8 @@ void opengl_texture::load_PNG() data.resize(PNG_IMAGE_SIZE(png)); - png_image_finish_read(&png, nullptr, - (void*)&data[0], -data_width * PNG_IMAGE_PIXEL_SIZE(png.format), nullptr); + png_image_finish_read(&png, nullptr, + (void*)&data[0], -data_width * PNG_IMAGE_PIXEL_SIZE(png.format), nullptr); // we're storing texture data internally with bottom-left origin // so use negative stride @@ -277,17 +277,17 @@ opengl_texture::load_DDS() { { case FOURCC_DXT1: // DXT1's compression ratio is 8:1 - data_format = GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT; + data_format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; break; case FOURCC_DXT3: // DXT3's compression ratio is 4:1 - data_format = GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT; + data_format = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; break; case FOURCC_DXT5: // DXT5's compression ratio is 4:1 - data_format = GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT; + data_format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; break; default: @@ -299,7 +299,7 @@ opengl_texture::load_DDS() { data_height = ddsd.dwHeight; data_mapcount = ddsd.dwMipMapCount; - int blockSize = ( data_format == GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT ? 8 : 16 ); + int blockSize = ( data_format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT ? 8 : 16 ); int offset = 0; while( ( data_width > Global.iMaxTextureSize ) || ( data_height > Global.iMaxTextureSize ) ) { @@ -341,11 +341,11 @@ opengl_texture::load_DDS() { // while DDS stores it with top-left origin. we need to flip it. if (Global.dds_upper_origin) { - char *mipmap = (char*)&data[0]; - int mapcount = data_mapcount, - width = data_width, - height = data_height; - while (mapcount) + char *mipmap = (char*)&data[0]; + int mapcount = data_mapcount, + width = data_width, + height = data_height; + while (mapcount) { if (ddsd.ddpfPixelFormat.dwFourCC == FOURCC_DXT1) flip_s3tc::flip_dxt1_image(mipmap, width, height); @@ -354,11 +354,11 @@ opengl_texture::load_DDS() { else if (ddsd.ddpfPixelFormat.dwFourCC == FOURCC_DXT5) flip_s3tc::flip_dxt45_image(mipmap, width, height); - mipmap += ( ( width + 3 ) / 4 ) * ( ( height + 3 ) / 4 ) * blockSize; - width = std::max( width / 2, 4 ); - height = std::max( height / 2, 4 ); - --mapcount; - } + mipmap += ( ( width + 3 ) / 4 ) * ( ( height + 3 ) / 4 ) * blockSize; + width = std::max( width / 2, 4 ); + height = std::max( height / 2, 4 ); + --mapcount; + } } data_components = @@ -525,7 +525,7 @@ opengl_texture::load_TGA() { buffer[ 1 ] = buffer[ 0 ]; buffer[ 2 ] = buffer[ 0 ]; } - // copy the color into the image data as many times as dictated + // copy the color into the image data as many times as dictated for( int i = 0; i <= chunkheader; ++i ) { ( *datapointer ) = ( *bufferpointer ); @@ -581,6 +581,78 @@ opengl_texture::bind() { return true; } +std::unordered_map opengl_texture::precompressed_formats = +{ + { GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, 8 }, + { GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, 16 }, + { GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, 16 }, + { GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, 8 }, + { GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, 16 }, + { GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, 16 }, +}; + +std::unordered_map opengl_texture::drivercompressed_formats = +{ + { GL_SRGB_ALPHA, GL_COMPRESSED_SRGB_ALPHA }, + { GL_SRGB, GL_COMPRESSED_SRGB }, + { GL_RGBA, GL_COMPRESSED_RGBA }, + { GL_RGB, GL_COMPRESSED_RGB }, + { GL_RG, GL_COMPRESSED_RG }, + { GL_RED, GL_COMPRESSED_RED }, +}; + +std::unordered_map> opengl_texture::mapping = +{ + // image have, material wants, gl internalformat + { GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, { { GL_SRGB_ALPHA, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT }, + { GL_SRGB, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT }, + { GL_RGBA, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT }, + { GL_RGB, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT }, + { GL_RG, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT }, + { GL_RED, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT } } }, + { GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, { { GL_SRGB_ALPHA, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT }, + { GL_SRGB, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT }, + { GL_RGBA, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT }, + { GL_RGB, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT }, + { GL_RG, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT }, + { GL_RED, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT } } }, + { GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, { { GL_SRGB_ALPHA, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT }, + { GL_SRGB, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT }, + { GL_RGBA, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT }, + { GL_RGB, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT }, + { GL_RG, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT }, + { GL_RED, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT } } }, + { GL_RGBA, { { GL_SRGB_ALPHA, GL_SRGB_ALPHA }, + { GL_SRGB, GL_SRGB }, + { GL_RGBA, GL_RGBA }, + { GL_RGB, GL_RGB }, + { GL_RG, GL_RG }, + { GL_RED, GL_RED } } }, + { GL_RGB, { { GL_SRGB_ALPHA, GL_SRGB }, // bad + { GL_SRGB, GL_SRGB }, + { GL_RGBA, GL_RGB }, // bad + { GL_RGB, GL_RGB }, + { GL_RG, GL_RG }, + { GL_RED, GL_RED } } }, + { GL_RG, { { GL_SRGB_ALPHA, GL_SRGB }, // bad + { GL_SRGB, GL_SRGB }, // bad + { GL_RGBA, GL_RG }, // bad + { GL_RGB, GL_RG }, // bad + { GL_RG, GL_RG }, + { GL_RED, GL_RED } } }, + { GL_RED, { { GL_SRGB_ALPHA, GL_SRGB }, // bad + { GL_SRGB, GL_SRGB }, // bad + { GL_RGBA, GL_RED }, // bad + { GL_RGB, GL_RED }, // bad + { GL_RG, GL_RED }, // bad + { GL_RED, GL_RED } } }, +}; + +void opengl_texture::set_components_hint(GLint hint) +{ + components_hint = hint; +} + bool opengl_texture::create() { @@ -618,12 +690,12 @@ opengl_texture::create() { { glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); - glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); + glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); if (data_components == GL_DEPTH_COMPONENT) - { + { glTexParameteri(target, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); - float borderColor[] = { 1.0f, 1.0f, 1.0f, 1.0f }; + float borderColor[] = { 1.0f, 1.0f, 1.0f, 1.0f }; glTexParameterfv(target, GL_TEXTURE_BORDER_COLOR, borderColor); } if (target == GL_TEXTURE_2D) @@ -637,21 +709,32 @@ opengl_texture::create() { ::glTexParameteri(target, GL_TEXTURE_WRAP_T, (wrapt == true ? GL_REPEAT : GL_CLAMP_TO_EDGE)); set_filtering(); + // data_format and data_type specifies how image is laid out in memory + // data_components specifies what useful channels image contains + // components_hint specifies what format we want to load + + // now map that mess into opengl internal format + + GLint components = data_components; + auto f_it = precompressed_formats.find(data_format); + if (f_it != precompressed_formats.end()) + components = data_format; + + GLint internal_format = mapping[components][components_hint]; + + auto blocksize_it = precompressed_formats.find(internal_format); + for( int maplevel = 0; maplevel < data_mapcount; ++maplevel ) { - if( ( data_format == GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT ) - || ( data_format == GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT ) - || ( data_format == GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT ) ) { + if (blocksize_it != precompressed_formats.end()) + { // compressed dds formats - int const datablocksize = - ( data_format == GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT ? - 8 : - 16 ); + const int datablocksize = blocksize_it->second; datasize = ( ( std::max( datawidth, 4 ) + 3 ) / 4 ) * ( ( std::max( dataheight, 4 ) + 3 ) / 4 ) * datablocksize; ::glCompressedTexImage2D( - target, maplevel, data_format, + target, maplevel, internal_format, datawidth, dataheight, 0, datasize, (GLubyte *)&data[ dataoffset ] ); @@ -660,10 +743,12 @@ opengl_texture::create() { dataheight = std::max( dataheight / 2, 1 ); } else { + GLint compressed_format = drivercompressed_formats[internal_format]; + // uncompressed texture data. have the gfx card do the compression as it sees fit ::glTexImage2D( - target, 0, - Global.compress_tex ? GL_COMPRESSED_SRGB_ALPHA : GL_SRGB_ALPHA, + target, 0, + Global.compress_tex ? compressed_format : internal_format, data_width, data_height, 0, data_format, data_type, (GLubyte *)&data[ 0 ] ); } @@ -752,11 +837,7 @@ opengl_texture::set_filtering() const { // default texture mode ::glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); ::glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR ); - - if( GLEW_EXT_texture_filter_anisotropic ) { - // anisotropic filtering - ::glTexParameterf(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, Global.AnisotropicFiltering ); - } + ::glTexParameterf(target, GL_TEXTURE_MAX_ANISOTROPY, Global.AnisotropicFiltering ); bool sharpen{ false }; for( auto const &trait : traits ) { @@ -821,7 +902,7 @@ texture_manager::unit( GLint const Textureunit ) { // ustalenie numeru tekstury, wczytanie jeśli jeszcze takiej nie było texture_handle -texture_manager::create( std::string Filename, bool const Loadnow ) { +texture_manager::create(std::string Filename, bool const Loadnow , GLint fh) { if( Filename.find( '|' ) != std::string::npos ) Filename.erase( Filename.find( '|' ) ); // po | może być nazwa kolejnej tekstury @@ -863,6 +944,7 @@ texture_manager::create( std::string Filename, bool const Loadnow ) { traits += '#'; } texture->traits = traits; + texture->components_hint = fh; auto const textureindex = (texture_handle)m_textures.size(); m_textures.emplace_back( texture, std::chrono::steady_clock::time_point() ); m_texturemappings.emplace( disklookup.first, textureindex ); diff --git a/Texture.h b/Texture.h index 6f527425..d3fac126 100644 --- a/Texture.h +++ b/Texture.h @@ -42,6 +42,7 @@ struct opengl_texture { return data_height; } void alloc_rendertarget(GLint format, GLint components, GLint type, int width, int height, int samples = 1); + void set_components_hint(GLint hint); // members GLuint id{ (GLuint)-1 }; // associated GL resource @@ -50,6 +51,7 @@ struct opengl_texture { 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 + GLint components_hint; // components that material wants GLenum target = GL_TEXTURE_2D; @@ -81,6 +83,10 @@ private: std::atomic is_loaded{ false }; // indicates the texture data was loaded and can be processed std::atomic is_good{ false }; // indicates the texture data was retrieved without errors */ + + static std::unordered_map precompressed_formats; + static std::unordered_map drivercompressed_formats; + static std::unordered_map> mapping; }; typedef int texture_handle; @@ -96,7 +102,7 @@ public: unit( GLint const Textureunit ); // creates texture object out of data stored in specified file texture_handle - create( std::string Filename, bool const Loadnow = true ); + create( std::string Filename, bool const Loadnow = true, GLint format_hint = GL_SRGB_ALPHA ); // binds specified texture to specified texture unit void bind( std::size_t const Unit, texture_handle const Texture ); diff --git a/TextureDDS.cpp b/TextureDDS.cpp index ca61748e..1d218422 100644 --- a/TextureDDS.cpp +++ b/TextureDDS.cpp @@ -325,15 +325,15 @@ void DecompressDXT(DDS_IMAGE_DATA lImage, const GLubyte *lCompData, GLubyte *Dat { switch (lImage.format) { - case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: DecompressDXT1(lImage, lCompData, Data); break; - case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: DecompressDXT3(lImage, lCompData, Data); break; - case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: DecompressDXT5(lImage, lCompData, Data); break; }; diff --git a/gl/cubemap.cpp b/gl/cubemap.cpp new file mode 100644 index 00000000..3bc686d2 --- /dev/null +++ b/gl/cubemap.cpp @@ -0,0 +1,37 @@ +#include "cubemap.h" + +gl::cubemap::cubemap() +{ + glGenTextures(1, *this); + + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); +} + +gl::cubemap::~cubemap() +{ + glDeleteTextures(1, *this); +} + +void gl::cubemap::alloc(GLint format, int width, int height, GLenum components, GLenum type) +{ + glBindTexture(GL_TEXTURE_CUBE_MAP, *this); + for (GLuint tgt = GL_TEXTURE_CUBE_MAP_POSITIVE_X; tgt <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z; tgt++) + glTexImage2D(tgt, 0, format, width, height, 0, components, type, nullptr); + + glBindTexture(GL_TEXTURE_CUBE_MAP, 0); +} + +void gl::cubemap::bind(int unit) +{ + glActiveTexture(unit); + glBindTexture(GL_TEXTURE_CUBE_MAP, *this); +} + +void gl::cubemap::generate_mipmaps() +{ + glBindTexture(GL_TEXTURE_CUBE_MAP, *this); + glGenerateMipmap(GL_TEXTURE_CUBE_MAP); + glBindTexture(GL_TEXTURE_CUBE_MAP, 0); +} diff --git a/gl/cubemap.h b/gl/cubemap.h new file mode 100644 index 00000000..e874c221 --- /dev/null +++ b/gl/cubemap.h @@ -0,0 +1,19 @@ +#pragma once + +#include "object.h" + +namespace gl +{ + // cubemap texture rendertarget + // todo: integrate with texture system + class cubemap : public object + { + public: + cubemap(); + ~cubemap(); + + void alloc(GLint format, int width, int height, GLenum components, GLenum type); + void bind(int unit); + void generate_mipmaps(); + }; +} diff --git a/gl/framebuffer.cpp b/gl/framebuffer.cpp index eda58b1a..91958932 100644 --- a/gl/framebuffer.cpp +++ b/gl/framebuffer.cpp @@ -22,12 +22,24 @@ void gl::framebuffer::attach(const opengl_texture &tex, GLenum location) glFramebufferTexture2D(GL_FRAMEBUFFER, location, tex.target, tex.id, 0); } +void gl::framebuffer::attach(const cubemap &tex, int face, GLenum location) +{ + bind(); + glFramebufferTexture2D(GL_FRAMEBUFFER, location, GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, *tex, 0); +} + void gl::framebuffer::attach(const renderbuffer &rb, GLenum location) { bind(); glFramebufferRenderbuffer(GL_FRAMEBUFFER, location, GL_RENDERBUFFER, *rb); } +void gl::framebuffer::detach(GLenum location) +{ + bind(); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, location, GL_RENDERBUFFER, 0); +} + bool gl::framebuffer::is_complete() { bind(); diff --git a/gl/framebuffer.h b/gl/framebuffer.h index 7a65e678..a0ecb8fe 100644 --- a/gl/framebuffer.h +++ b/gl/framebuffer.h @@ -4,6 +4,7 @@ #include "bindable.h" #include "renderbuffer.h" #include "Texture.h" +#include "cubemap.h" namespace gl { @@ -14,7 +15,9 @@ namespace gl ~framebuffer(); void attach(const opengl_texture &tex, GLenum location); + void attach(const cubemap &tex, int face, GLenum location); void attach(const renderbuffer &rb, GLenum location); + void detach(GLenum location); void clear(GLbitfield mask); bool is_complete(); diff --git a/gl/shader.cpp b/gl/shader.cpp index 80c53b2d..dde3fc45 100644 --- a/gl/shader.cpp +++ b/gl/shader.cpp @@ -50,10 +50,62 @@ void gl::shader::expand_includes(std::string &str) } } +std::unordered_map gl::shader::components_mapping = +{ + { "R", components_e::R }, + { "RG", components_e::RG }, + { "RGB", components_e::RGB }, + { "RGBA", components_e::RGBA }, + { "sRGB", components_e::sRGB }, + { "sRGB_A", components_e::sRGB_A } +}; + +void gl::shader::parse_config(std::string &str) +{ + size_t start_pos = 0; + + std::string magic = "#texture"; + while ((start_pos = str.find(magic, start_pos)) != str.npos) + { + size_t fp = str.find('(', start_pos); + size_t fe = str.find(')', start_pos); + if (fp == str.npos || fe == str.npos) + return; + + std::istringstream ss(str.substr(fp + 1, fe - fp - 1)); + std::string token; + + texture_entry conf; + + size_t arg = 0; + while (std::getline(ss, token, ',')) + { + std::istringstream token_ss(token); + if (arg == 0) + token_ss >> conf.name; + else if (arg == 1) + token_ss >> conf.id; + else if (arg == 2) + { + std::string comp; + token_ss >> comp; + conf.components = components_mapping[comp]; + } + arg++; + } + + if (arg == 3) + texture_conf.push_back(conf); + + str.erase(start_pos, fe - start_pos + 1); + } +} + gl::shader::shader(const std::string &filename) { std::string str = read_file(filename); expand_includes(str); + parse_config(str); const GLchar *cstr = str.c_str(); @@ -92,21 +144,12 @@ void gl::program::init() { bind(); - int i = 0; - GLuint loc; - while (true) + for (shader::texture_entry &e : texture_conf) { - std::string name = "tex" + std::to_string(i + 1); - loc = glGetUniformLocation(*this, name.c_str()); - if (loc != -1) - glUniform1i(loc, i); - else - break; - i++; + GLuint loc = glGetUniformLocation(*this, e.name.c_str()); + glUniform1i(loc, e.id); } - //tbd: do something better - glUniform1i(glGetUniformLocation(*this, "shadowmap"), MAX_TEXTURES + 0); glUniform1i(glGetUniformLocation(*this, "envmap"), MAX_TEXTURES + 1); @@ -136,6 +179,7 @@ gl::program::program(std::vector> shade void gl::program::attach(const gl::shader &s) { + std::copy(s.texture_conf.begin(), s.texture_conf.end(), std::back_inserter(texture_conf)); glAttachShader(*this, *s); } diff --git a/gl/shader.h b/gl/shader.h index 97ae7e08..a3074d53 100644 --- a/gl/shader.h +++ b/gl/shader.h @@ -15,9 +15,31 @@ namespace gl shader(const std::string &filename); ~shader(); + enum class components_e + { + R, + RG, + RGB, + RGBA, + sRGB, + sRGB_A + }; + + struct texture_entry + { + std::string name; + size_t id; + components_e components; + }; + + std::vector texture_conf; + private: void expand_includes(std::string &str); + void parse_config(std::string &str); std::string read_file(const std::string &filename); + + static std::unordered_map components_mapping; }; class program : public object, public bindable @@ -33,6 +55,8 @@ namespace gl void attach(const shader &); void link(); + std::vector texture_conf; + private: void init(); }; diff --git a/material.cpp b/material.cpp index facb3b11..19fbc0b7 100644 --- a/material.cpp +++ b/material.cpp @@ -117,6 +117,15 @@ opengl_material::deserialize_mapping( cParser &Input, int const Priority, bool c return true; // return value marks a key: value pair was extracted, nothing about whether it's recognized } +std::unordered_map material_manager::components_mapping = +{ + { gl::shader::components_e::R, GL_RED }, + { gl::shader::components_e::RG, GL_RG }, + { gl::shader::components_e::RGB, GL_RGB }, + { gl::shader::components_e::RGBA, GL_RGBA }, + { gl::shader::components_e::sRGB, GL_SRGB }, + { gl::shader::components_e::sRGB_A, GL_SRGB_ALPHA } +}; // create material object from data stored in specified file. // NOTE: the deferred load parameter is passed to textures defined by material, the material itself is always loaded immediately @@ -167,12 +176,18 @@ material_manager::create( std::string const &Filename, bool const Loadnow ) { if (!material.shader) material.shader = GfxRenderer.Fetch_Shader("default"); + for (gl::shader::texture_entry &entry : material.shader->texture_conf) + { + material_handle handle = material.textures[entry.id]; + if (handle) + GfxRenderer.Texture(handle).set_components_hint(components_mapping[entry.components]); + } + if (std::isnan(material.opacity)) { + material.opacity = 1.0f; if (material.textures[0] != null_handle) material.opacity = GfxRenderer.Texture( material.textures[0] ).has_alpha ? 0.0f : 1.0f; - else - material.opacity = 1.0f; } material_handle handle = m_materials.size(); diff --git a/material.h b/material.h index 40fc9eaf..58e335c4 100644 --- a/material.h +++ b/material.h @@ -61,6 +61,8 @@ public: create( std::string const &Filename, bool const Loadnow ); opengl_material const & material( material_handle const Material ) const { return m_materials[ Material ]; } + opengl_material & + material( material_handle const Material ) { return m_materials[ Material ]; } private: // types @@ -77,6 +79,7 @@ private: material_sequence m_materials; index_map m_materialmappings; + static std::unordered_map components_mapping; }; //--------------------------------------------------------------------------- diff --git a/renderer.cpp b/renderer.cpp index 4777295e..50b0fbfa 100644 --- a/renderer.cpp +++ b/renderer.cpp @@ -212,6 +212,25 @@ bool opengl_renderer::Init(GLFWwindow *Window) if (!m_pick_fb->is_complete()) return false; + m_env_rb = std::make_unique(); + m_env_rb->alloc(GL_DEPTH_COMPONENT24, EU07_ENVIRONMENTBUFFERSIZE, EU07_ENVIRONMENTBUFFERSIZE); + m_env_tex = std::make_unique(); + m_env_tex->alloc(GL_RGB16F, EU07_ENVIRONMENTBUFFERSIZE, EU07_ENVIRONMENTBUFFERSIZE, GL_RGB, GL_FLOAT); + m_empty_cubemap = std::make_unique(); + m_empty_cubemap->alloc(GL_RGB16F, 16, 16, GL_RGB, GL_FLOAT); + + m_env_fb = std::make_unique(); + + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + for (int i = 0; i < 6; i++) + { + m_env_fb->attach(*m_empty_cubemap, i, GL_COLOR_ATTACHMENT0); + m_env_fb->clear(GL_COLOR_BUFFER_BIT); + } + + m_env_fb->detach(GL_COLOR_ATTACHMENT0); + m_env_fb->attach(*m_env_rb, GL_DEPTH_ATTACHMENT); + return true; } @@ -332,17 +351,12 @@ void opengl_renderer::Render_pass(rendermode const Mode) glDebug("render shadowmap end"); } - m_msaa_fb->bind(); + // potentially update environmental cube map + if (Render_reflections()) + setup_pass(m_renderpass, Mode); // restore color pass settings + setup_env_map(m_env_tex.get()); - /* - if( ( true == m_environmentcubetexturesupport ) - && ( true == World.InitPerformed() ) ) { - // potentially update environmental cube map - if( true == Render_reflections() ) { - setup_pass( m_renderpass, Mode ); // restore draw mode. TBD, TODO: render mode stack - } - } - */ + m_msaa_fb->bind(); glViewport(0, 0, Global.render_width, Global.render_height); glEnable(GL_DEPTH_TEST); @@ -394,18 +408,8 @@ void opengl_renderer::Render_pass(rendermode const Mode) Render_cab(vehicle, true); } - /* - if( m_environmentcubetexturesupport ) { - // restore default texture matrix for reflections cube map - select_unit( m_helpertextureunit ); - ::glMatrixMode( GL_TEXTURE ); - ::glPopMatrix(); - select_unit( m_diffusetextureunit ); - ::glMatrixMode( GL_MODELVIEW ); - } - */ - setup_shadow_map(nullptr, m_renderpass); + setup_env_map(nullptr); m_main_fb->clear(GL_COLOR_BUFFER_BIT); m_msaa_fb->blit_to(*m_main_fb.get(), Global.render_width, Global.render_height, GL_COLOR_BUFFER_BIT); @@ -479,8 +483,8 @@ void opengl_renderer::Render_pass(rendermode const Mode) scene_ubs.projection = OpenGLMatrices.data(GL_PROJECTION); scene_ubo->update(scene_ubs); - Render_cab( World.Train->Dynamic(), false ); - Render_cab( World.Train->Dynamic(), true ); + Render_cab(World.Train->Dynamic(), false); + Render_cab(World.Train->Dynamic(), true); m_cabshadowpass = m_renderpass; // glDisable(GL_POLYGON_OFFSET_FILL); @@ -494,6 +498,42 @@ void opengl_renderer::Render_pass(rendermode const Mode) case rendermode::reflections: { + if (!World.InitPerformed()) + break; + + glDebug("rendermode::reflections"); + + // NOTE: buffer attachment and viewport setup in this mode is handled by the wrapper method + glEnable(GL_DEPTH_TEST); + glDepthMask(GL_TRUE); + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + m_env_fb->clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + m_env_fb->bind(); + + setup_env_map(m_empty_cubemap.get()); + + setup_matrices(); + setup_shadow_map(nullptr, m_renderpass); + + // render + setup_drawing(true); + + scene_ubs.projection = OpenGLMatrices.data(GL_PROJECTION); + scene_ubo->update(scene_ubs); + Render(&World.Environment); + + // opaque parts... + setup_drawing(false); + setup_shadow_map(m_shadow_tex.get(), m_shadowpass); + + scene_ubs.projection = OpenGLMatrices.data(GL_PROJECTION); + scene_ubo->update(scene_ubs); + Render(simulation::Region); + + m_env_fb->unbind(); + + glDebug("rendermode::reflections end"); + break; } @@ -556,6 +596,25 @@ void opengl_renderer::Render_pass(rendermode const Mode) // creates dynamic environment cubemap bool opengl_renderer::Render_reflections() { + auto const &time = simulation::Time.data(); + auto const timestamp = time.wDay * 24 * 60 + time.wHour * 60 + time.wMinute; + if ((timestamp - m_environmentupdatetime < 1) && (glm::length(m_renderpass.camera.position() - m_environmentupdatelocation) < 1000.0)) + { + // run update every 5+ mins of simulation time, or at least 1km from the last location + return false; + } + m_environmentupdatetime = timestamp; + m_environmentupdatelocation = m_renderpass.camera.position(); + + glViewport(0, 0, EU07_ENVIRONMENTBUFFERSIZE, EU07_ENVIRONMENTBUFFERSIZE); + for (m_environmentcubetextureface = 0; m_environmentcubetextureface < 6; ++m_environmentcubetextureface) + { + m_env_fb->attach(*m_env_tex, m_environmentcubetextureface, GL_COLOR_ATTACHMENT0); + if (m_env_fb->is_complete()) + Render_pass(rendermode::reflections); + } + m_env_tex->generate_mipmaps(); + m_env_fb->detach(GL_COLOR_ATTACHMENT0); return true; } @@ -702,36 +761,26 @@ void opengl_renderer::setup_pass(renderpass_config &Config, rendermode const Mod break; } - case rendermode::cabshadows: { + case rendermode::cabshadows: + { // fixed size cube large enough to enclose a vehicle compartment // modelview - auto const lightvector = - glm::normalize( glm::vec3{ - m_sunlight.direction.x, - std::min( m_sunlight.direction.y, -0.2f ), - m_sunlight.direction.z } ); - camera.position() = Global.pCameraPosition - glm::dvec3 { lightvector }; - viewmatrix *= glm::lookAt( - camera.position(), - glm::dvec3 { Global.pCameraPosition }, - glm::dvec3 { 0.f, 1.f, 0.f } ); + auto const lightvector = glm::normalize(glm::vec3{m_sunlight.direction.x, std::min(m_sunlight.direction.y, -0.2f), m_sunlight.direction.z}); + camera.position() = Global.pCameraPosition - glm::dvec3{lightvector}; + viewmatrix *= glm::lookAt(camera.position(), glm::dvec3{Global.pCameraPosition}, glm::dvec3{0.f, 1.f, 0.f}); // projection - auto const maphalfsize { Config.draw_range * 0.5f }; - camera.projection() *= - glm::ortho( - -maphalfsize, maphalfsize, - -maphalfsize, maphalfsize, - -Config.draw_range, Config.draw_range ); -/* - // adjust the projection to sample complete shadow map texels - auto shadowmaptexel = glm::vec2 { camera.projection() * glm::mat4{ viewmatrix } * glm::vec4{ 0.f, 0.f, 0.f, 1.f } }; - shadowmaptexel *= ( m_shadowbuffersize / 2 ) * 0.5f; - auto shadowmapadjustment = glm::round( shadowmaptexel ) - shadowmaptexel; - shadowmapadjustment /= ( m_shadowbuffersize / 2 ) * 0.5f; - camera.projection() = glm::translate( glm::mat4{ 1.f }, glm::vec3{ shadowmapadjustment, 0.f } ) * camera.projection(); -*/ + auto const maphalfsize{Config.draw_range * 0.5f}; + camera.projection() *= glm::ortho(-maphalfsize, maphalfsize, -maphalfsize, maphalfsize, -Config.draw_range, Config.draw_range); + /* + // adjust the projection to sample complete shadow map texels + auto shadowmaptexel = glm::vec2 { camera.projection() * glm::mat4{ viewmatrix } * glm::vec4{ 0.f, 0.f, 0.f, 1.f } }; + shadowmaptexel *= ( m_shadowbuffersize / 2 ) * 0.5f; + auto shadowmapadjustment = glm::round( shadowmaptexel ) - shadowmaptexel; + shadowmapadjustment /= ( m_shadowbuffersize / 2 ) * 0.5f; + camera.projection() = glm::translate( glm::mat4{ 1.f }, glm::vec3{ shadowmapadjustment, 0.f } ) * camera.projection(); + */ break; -} + } case rendermode::pickcontrols: case rendermode::pickscenery: { @@ -743,6 +792,18 @@ void opengl_renderer::setup_pass(renderpass_config &Config, rendermode const Mod 0.1f * Global.ZoomFactor, Config.draw_range * Global.fDistanceFactor); break; } + case rendermode::reflections: + { + // modelview + camera.position() = (((true == DebugCameraFlag) && (false == Ignoredebug)) ? Global.DebugCameraPosition : Global.pCameraPosition); + glm::dvec3 const cubefacetargetvectors[6] = {{1.0, 0.0, 0.0}, {-1.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {0.0, -1.0, 0.0}, {0.0, 0.0, 1.0}, {0.0, 0.0, -1.0}}; + glm::dvec3 const cubefaceupvectors[6] = {{0.0, -1.0, 0.0}, {0.0, -1.0, 0.0}, {0.0, 0.0, 1.0}, {0.0, 0.0, -1.0}, {0.0, -1.0, 0.0}, {0.0, -1.0, 0.0}}; + auto const cubefaceindex = m_environmentcubetextureface; + viewmatrix *= glm::lookAt(camera.position(), camera.position() + cubefacetargetvectors[cubefaceindex], cubefaceupvectors[cubefaceindex]); + // projection + camera.projection() *= glm::perspective(glm::radians(90.f), 1.f, 0.1f * Global.ZoomFactor, Config.draw_range * Global.fDistanceFactor); + break; + } default: { break; @@ -754,22 +815,9 @@ void opengl_renderer::setup_pass(renderpass_config &Config, rendermode const Mod void opengl_renderer::setup_matrices() { - ::glMatrixMode(GL_PROJECTION); OpenGLMatrices.load_matrix(m_renderpass.camera.projection()); - /* - if( ( m_renderpass.draw_mode == rendermode::color ) - && ( m_environmentcubetexturesupport ) ) { - // special case, for colour render pass setup texture matrix for reflections cube map - select_unit( m_helpertextureunit ); - ::glMatrixMode( GL_TEXTURE ); - ::glPushMatrix(); - ::glMultMatrixf( glm::value_ptr( glm::inverse( glm::mat4{ glm::mat3{ m_renderpass.camera.modelview() } } ) ) ); - select_unit( m_diffusetextureunit ); - } - */ - // trim modelview matrix just to rotation, since rendering is done in camera-centric world space ::glMatrixMode(GL_MODELVIEW); OpenGLMatrices.load_matrix(glm::mat4(glm::mat3(m_renderpass.camera.modelview()))); @@ -777,11 +825,16 @@ void opengl_renderer::setup_matrices() void opengl_renderer::setup_drawing(bool const Alpha) { - if (true == Alpha) + { ::glEnable(GL_BLEND); - else - ::glDisable(GL_BLEND); + m_blendphase = true; + } + else + { + ::glDisable(GL_BLEND); + m_blendphase = false; + } switch (m_renderpass.draw_mode) { @@ -832,6 +885,19 @@ void opengl_renderer::setup_shadow_map(opengl_texture *tex, renderpass_config co } } +void opengl_renderer::setup_env_map(gl::cubemap *tex) +{ + if (tex) + tex->bind(GL_TEXTURE0 + gl::MAX_TEXTURES + 1); + else + { + glActiveTexture(GL_TEXTURE0 + gl::MAX_TEXTURES + 1); + glBindTexture(GL_TEXTURE_2D, 0); + } + glActiveTexture(GL_TEXTURE0); + m_textures.reset_unit_cache(); +} + void opengl_renderer::setup_environment_light(TEnvironmentType const Environment) { @@ -895,20 +961,39 @@ bool opengl_renderer::Render(world_environment *Environment) gfx::opengl_vbogeometrybank::reset(); // celestial bodies - float const duskfactor = 1.0f - clamp( std::abs( Environment->m_sun.getAngle() ), 0.0f, 12.0f ) / 12.0f; - glm::vec3 suncolor = interpolate( - glm::vec3( 255.0f / 255.0f, 242.0f / 255.0f, 231.0f / 255.0f ), - glm::vec3( 235.0f / 255.0f, 140.0f / 255.0f, 36.0f / 255.0f ), - duskfactor ); + float const duskfactor = 1.0f - clamp(std::abs(Environment->m_sun.getAngle()), 0.0f, 12.0f) / 12.0f; + glm::vec3 suncolor = interpolate(glm::vec3(255.0f / 255.0f, 242.0f / 255.0f, 231.0f / 255.0f), glm::vec3(235.0f / 255.0f, 140.0f / 255.0f, 36.0f / 255.0f), duskfactor); m_textures.reset_unit_cache(); // m7t: restore celestial bodies + // stars + if (Environment->m_stars.m_stars != nullptr) + { + // setup + ::glPushMatrix(); + ::glRotatef(Environment->m_stars.m_latitude, 1.f, 0.f, 0.f); // ustawienie osi OY na północ + ::glRotatef(-std::fmod((float)Global.fTimeAngleDeg, 360.f), 0.f, 1.f, 0.f); // obrót dobowy osi OX + + // render + GfxRenderer.Render(Environment->m_stars.m_stars, nullptr, 1.0); + + // post-render cleanup + ::glPopMatrix(); + } + // clouds if (Environment->m_clouds.mdCloud) { // setup - // m7t set cloud color + glm::vec3 color = interpolate(Environment->m_skydome.GetAverageColor(), suncolor, duskfactor * 0.25f) * interpolate(1.f, 0.35f, Global.Overcast / 2.f) // overcast darkens the clouds + * 2.5f; + + // write cloud color into material + TSubModel *mdl = Environment->m_clouds.mdCloud->Root; + if (mdl->m_material != null_handle) + m_materials.material(mdl->m_material).params[0] = glm::vec4(color, 1.0f); + // render Render(Environment->m_clouds.mdCloud, nullptr, 100.0); Render_Alpha(Environment->m_clouds.mdCloud, nullptr, 100.0); @@ -986,13 +1071,17 @@ std::shared_ptr opengl_renderer::Fetch_Shader(const std::string &na void opengl_renderer::Bind_Material(material_handle const Material) { - if (Material != null_handle) { auto &material = m_materials.material(Material); for (size_t i = 0; i < gl::MAX_PARAMS; i++) model_ubs.param[i] = material.params[i]; - model_ubs.opacity = material.opacity; + + if (m_blendphase) + model_ubs.opacity = 0.0f; + else + model_ubs.opacity = 1.0f; + material.shader->bind(); size_t unit = 0; @@ -1028,14 +1117,12 @@ void opengl_renderer::Bind_Material_Shadow(material_handle const Material) opengl_material const &opengl_renderer::Material(material_handle const Material) const { - return m_materials.material(Material); } -texture_handle opengl_renderer::Fetch_Texture(std::string const &Filename, bool const Loadnow) +texture_handle opengl_renderer::Fetch_Texture(std::string const &Filename, bool const Loadnow, GLint format_hint) { - - return m_textures.create(Filename, Loadnow); + return m_textures.create(Filename, Loadnow, format_hint); } void opengl_renderer::Bind_Texture(size_t Unit, texture_handle const Texture) @@ -1111,6 +1198,11 @@ void opengl_renderer::Render(scene::basic_region *Region) break; } case rendermode::reflections: + { + // for the time being reflections render only terrain geometry + Render(std::begin(m_sectionqueue), std::end(m_sectionqueue)); + break; + } case rendermode::pickcontrols: default: { @@ -1127,14 +1219,8 @@ void opengl_renderer::Render(section_sequence::iterator First, section_sequence: { case rendermode::color: case rendermode::reflections: - { - - break; - } case rendermode::shadows: - { break; - } case rendermode::pickscenery: { // non-interactive scenery elements get neutral colour @@ -1142,10 +1228,8 @@ void opengl_renderer::Render(section_sequence::iterator First, section_sequence: break; } default: - { break; } - } while (First != Last) { @@ -1393,10 +1477,9 @@ void opengl_renderer::Render(scene::shape_node const &Shape, bool const Ignorera switch (m_renderpass.draw_mode) { case rendermode::color: + case rendermode::reflections: Bind_Material(data.material); break; - case rendermode::reflections: - break; case rendermode::shadows: Bind_Material_Shadow(data.material); break; @@ -1655,12 +1738,12 @@ bool opengl_renderer::Render_cab(TDynamicObject const *Dynamic, bool const Alpha break; } case rendermode::cabshadows: - if( true == Alpha ) + if (true == Alpha) // translucent parts - Render_Alpha( Dynamic->mdKabina, Dynamic->Material(), 0.0 ); + Render_Alpha(Dynamic->mdKabina, Dynamic->Material(), 0.0); else // opaque parts - Render( Dynamic->mdKabina, Dynamic->Material(), 0.0 ); + Render(Dynamic->mdKabina, Dynamic->Material(), 0.0); break; case rendermode::pickcontrols: { @@ -1932,6 +2015,8 @@ void opengl_renderer::Render(TSubModel *Submodel) setup_shadow_color( m_shadowcolor ); */ + glDisable(GL_BLEND); + ::glPopMatrix(); } } @@ -1954,14 +2039,14 @@ void opengl_renderer::Render(TSubModel *Submodel) { if (Global.fLuminance < Submodel->fLight) { - - Bind_Material(null_handle); + Bind_Material(Submodel->m_material); // main draw call model_ubs.set_modelview(OpenGLMatrices.data(GL_MODELVIEW)); model_ubo->update(model_ubs); + glPointSize(2.0f * 2.0f); - // m_geometry.draw( Submodel->m_geometry, gfx::color_streams ); + m_geometry.draw(Submodel->m_geometry); } break; } @@ -2434,9 +2519,7 @@ void opengl_renderer::Render_Alpha(scene::lines_node const &Lines) } // setup auto const distance{static_cast(std::sqrt(distancesquared))}; - auto const linealpha = (data.line_width > 0.f ? glm::clamp(10.f * data.line_width / - std::max(0.5f * data.area.radius + 1.f, - distance - (0.5f * data.area.radius)), 0.0f, 1.0f) : + auto const linealpha = (data.line_width > 0.f ? glm::clamp(10.f * data.line_width / std::max(0.5f * data.area.radius + 1.f, distance - (0.5f * data.area.radius)), 0.0f, 1.0f) : 1.f); // negative width means the lines are always opague if (m_widelines_supported) glLineWidth(clamp(0.5f * linealpha + data.line_width * data.area.radius / 1000.f, 1.f, 8.f)); @@ -2720,29 +2803,30 @@ void opengl_renderer::Render_Alpha(TSubModel *Submodel) // reduce the glare in bright daylight glarelevel = clamp(glarelevel - static_cast(Global.fLuminance), 0.f, 1.f); - if( glarelevel > 0.0f ) { - glDepthMask( GL_FALSE ); - glBlendFunc( GL_SRC_ALPHA, GL_ONE ); + if (glarelevel > 0.0f) + { + glDepthMask(GL_FALSE); + glBlendFunc(GL_SRC_ALPHA, GL_ONE); - ::glPushMatrix(); - ::glLoadIdentity(); // macierz jedynkowa - ::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 + ::glPushMatrix(); + ::glLoadIdentity(); // macierz jedynkowa + ::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 m_billboard_shader->bind(); - Bind_Texture( 0, m_glaretexture ); + Bind_Texture(0, m_glaretexture); m_textures.reset_unit_cache(); model_ubs.param[0] = glm::vec4(glm::vec3(Submodel->f4Diffuse), glarelevel); - // main draw call + // main draw call model_ubs.set_modelview(OpenGLMatrices.data(GL_MODELVIEW)); - model_ubo->update(model_ubs); - m_geometry.draw( m_billboardgeometry ); + model_ubo->update(model_ubs); + m_geometry.draw(m_billboardgeometry); glDepthMask(GL_TRUE); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - ::glPopMatrix(); + ::glPopMatrix(); } } } @@ -2825,6 +2909,8 @@ TSubModel const *opengl_renderer::Update_Pick_Control() scene::basic_node const *opengl_renderer::Update_Pick_Node() { + //m7t: restore picking + /* Render_pass(rendermode::pickscenery); // determine point to examine @@ -2852,6 +2938,8 @@ scene::basic_node const *opengl_renderer::Update_Pick_Node() m_picksceneryitem = node; return node; + */ + return nullptr; } void opengl_renderer::Update(double const Deltatime) @@ -3040,7 +3128,7 @@ void opengl_renderer::Update_Lights(light_array &Lights) light_ubs.lights_count = light_i; light_ubs.fog_color = Global.FogColor; - if( Global.fFogEnd > 0 ) + if (Global.fFogEnd > 0) light_ubs.fog_density = 1.0f / Global.fFogEnd; else light_ubs.fog_density = 0.0f; diff --git a/renderer.h b/renderer.h index 54f55121..0290032d 100644 --- a/renderer.h +++ b/renderer.h @@ -24,6 +24,7 @@ http://mozilla.org/MPL/2.0/. #include "gl/renderbuffer.h" #include "gl/postfx.h" #include "gl/shader.h" +#include "gl/cubemap.h" #define EU07_USE_PICKING_FRAMEBUFFER //#define EU07_USE_DEBUG_SHADOWMAP @@ -157,7 +158,7 @@ class opengl_renderer opengl_material const &Material(material_handle const Material) const; // texture methods - texture_handle Fetch_Texture(std::string const &Filename, bool const Loadnow = true); + texture_handle Fetch_Texture(std::string const &Filename, bool const Loadnow = true, GLint format_hint = GL_SRGB_ALPHA); void Bind_Texture(size_t Unit, texture_handle const Texture); opengl_texture &Texture(texture_handle const Texture) const; // utility methods @@ -227,6 +228,7 @@ class opengl_renderer void setup_matrices(); void setup_drawing(bool const Alpha = false); void setup_shadow_map(opengl_texture *tex, renderpass_config conf); + void setup_env_map(gl::cubemap *tex); void setup_environment_light(TEnvironmentType const Environment = e_flat); // runs jobs needed to generate graphics for specified render pass void Render_pass(rendermode const Mode); @@ -371,8 +373,16 @@ class opengl_renderer std::unique_ptr m_cabshadows_fb; std::unique_ptr m_cabshadows_tex; + std::unique_ptr m_env_fb; + std::unique_ptr m_env_rb; + std::unique_ptr m_env_tex; + + std::unique_ptr m_empty_cubemap; + material_handle m_invalid_material; + bool m_blendphase; // m7t: todo: remove kludge! + bool m_widelines_supported; }; diff --git a/scenenode.cpp b/scenenode.cpp index 13cb7298..9a0a7de2 100644 --- a/scenenode.cpp +++ b/scenenode.cpp @@ -340,7 +340,7 @@ shape_node::convert( TSubModel const *Submodel ) { m_data.lighting.diffuse = Submodel->f4Diffuse; m_data.lighting.specular = Submodel->f4Specular; m_data.material = Submodel->m_material; - m_data.translucent = ( true == GfxRenderer.Material( m_data.material ).opacity < 1.0f ); + m_data.translucent = ( GfxRenderer.Material( m_data.material ).opacity == 0.0f ); // NOTE: we set unlimited view range typical for terrain, because we don't expect to convert any other 3d models m_data.rangesquared_max = std::numeric_limits::max(); diff --git a/shaders/alphashadowmap.frag b/shaders/alphashadowmap.frag index 750b0464..2e2c571d 100644 --- a/shaders/alphashadowmap.frag +++ b/shaders/alphashadowmap.frag @@ -2,6 +2,7 @@ in vec2 f_coord; +#texture (tex1, 0, sRGB_A) uniform sampler2D tex1; void main() diff --git a/shaders/billboard.frag b/shaders/billboard.frag index 8ad34d64..03c51083 100644 --- a/shaders/billboard.frag +++ b/shaders/billboard.frag @@ -3,6 +3,7 @@ in vec3 f_normal; in vec2 f_coord; +#texture (tex1, 0, sRGB_A) uniform sampler2D tex1; #include diff --git a/shaders/mat_default.frag b/shaders/mat_default.frag index 5992b6da..8892619c 100644 --- a/shaders/mat_default.frag +++ b/shaders/mat_default.frag @@ -7,8 +7,11 @@ in vec4 f_light_pos; #include +#texture (tex1, 0, sRGB_A) uniform sampler2D tex1; + uniform sampler2DShadow shadowmap; +uniform samplerCube envmap; float calc_shadow() { @@ -89,8 +92,16 @@ void main() { vec4 tex_color = texture(tex1, f_coord); - if (opacity == 0.0f && tex_color.a < 0.9f) - discard; + if (opacity == 0.0f) + { + //blending + } + else + { + //test + if (tex_color.a < 0.5f) + discard; + } float shadow = calc_shadow(); vec3 result = ambient * 0.3 + vec3(1.0) * emission; diff --git a/shaders/mat_mir.frag b/shaders/mat_mir.frag new file mode 100644 index 00000000..a88dc286 --- /dev/null +++ b/shaders/mat_mir.frag @@ -0,0 +1,123 @@ +#version 330 + +in vec3 f_normal; +in vec2 f_coord; +in vec3 f_pos; +in vec4 f_light_pos; + +#include + +#texture (tex1, 0, sRGB_A) +uniform sampler2D tex1; + +uniform sampler2DShadow shadowmap; +uniform samplerCube envmap; + +float calc_shadow() +{ + vec3 coords = f_light_pos.xyz / f_light_pos.w; + + // do something better + float bias = 0.0001f; + + //sampler PCF + //float shadow = texture(shadowmap, vec3(coords.xy, coords.z - bias)); + + //sampler PCF + PCF + float shadow = 0.0; + vec2 texel = 1.0 / textureSize(shadowmap, 0); + for (float y = -1.5; y <= 1.5; y += 1.0) + for (float x = -1.5; x <= 1.5; x += 1.0) + shadow += texture(shadowmap, coords.xyz + vec3(vec2(x, y) * texel, -bias)); + shadow /= 16.0; + + if (coords.z > 1.0f) + shadow = 1.0f; + + return shadow; +} + +vec3 apply_fog(vec3 color) +{ + float sun_amount = 0.0; + if (lights_count >= 1U && lights[0].type == LIGHT_DIR) + sun_amount = max(dot(normalize(f_pos), normalize(-lights[0].dir)), 0.0); + vec3 fog_color_v = mix(fog_color, lights[0].color, pow(sun_amount, 30.0)); + float fog_amount_v = 1.0 - min(1.0, exp(-length(f_pos) * fog_density)); + return mix(color, fog_color_v, fog_amount_v); +} + +float calc_light(vec3 light_dir) +{ + vec3 normal = normalize(f_normal); + vec3 view_dir = normalize(vec3(0.0f, 0.0f, 0.0f) - f_pos); + vec3 halfway_dir = normalize(light_dir + view_dir); + + float diffuse_v = max(dot(normal, light_dir), 0.0); + float specular_v = pow(max(dot(normal, halfway_dir), 0.0), 15.0); + + return specular_v + diffuse_v; +} + +float calc_point_light(light_s light) +{ + vec3 light_dir = normalize(light.pos - f_pos); + float val = calc_light(light_dir); + + float distance = length(light.pos - f_pos); + float atten = 1.0f / (1.0f + light.linear * distance + light.quadratic * (distance * distance)); + + return val * atten; +} + +float calc_spot_light(light_s light) +{ + vec3 light_dir = normalize(light.pos - f_pos); + + float theta = dot(light_dir, normalize(-light.dir)); + float epsilon = light.in_cutoff - light.out_cutoff; + float intensity = clamp((theta - light.out_cutoff) / epsilon, 0.0, 1.0); + + float point = calc_point_light(light); + return point * intensity; +} + +float calc_dir_light(light_s light) +{ + vec3 light_dir = normalize(-light.dir); + return calc_light(light_dir); +} + +void main() +{ + vec4 tex_color = texture(tex1, f_coord); + + if (opacity == 0.0f && tex_color.a < 0.9f) + discard; + + float shadow = calc_shadow(); + vec3 result = ambient * 0.3 + vec3(1.0) * emission; + for (uint i = 0U; i < lights_count; i++) + { + light_s light = lights[i]; + float part = 0.0; + + if (light.type == LIGHT_SPOT) + part = calc_spot_light(light); + else if (light.type == LIGHT_POINT) + part = calc_point_light(light); + else if (light.type == LIGHT_DIR) + part = calc_dir_light(light); + + if (i == 0U) + part *= shadow; + result += light.color * part; + } + + vec3 R = reflect(f_pos, normalize(f_normal)); + vec3 r = texture(envmap, R).rgb; + r *= vec3(1.0, 0.84, 0.2); + + vec3 c = apply_fog(result * tex_color.xyz); + gl_FragColor = vec4(c * 0.05 + r * 0.95, tex_color.w); +} diff --git a/shaders/mat_nolight.frag b/shaders/mat_nolight.frag index 290ec0b2..235586fd 100644 --- a/shaders/mat_nolight.frag +++ b/shaders/mat_nolight.frag @@ -4,6 +4,7 @@ in vec3 f_normal; in vec2 f_coord; in vec3 f_pos; +#texture (tex1, 0, sRGB_A) uniform sampler2D tex1; #include @@ -11,5 +12,5 @@ uniform sampler2D tex1; void main() { vec4 tex_color = texture(tex1, f_coord); - gl_FragColor = vec4(tex_color.xyz * ambient, tex_color.a); + gl_FragColor = tex_color * param[0]; } diff --git a/shaders/mat_normal.frag b/shaders/mat_normal.frag index 83780453..920d48eb 100644 --- a/shaders/mat_normal.frag +++ b/shaders/mat_normal.frag @@ -6,7 +6,10 @@ in vec3 f_pos; in mat3 f_tbn; in vec4 f_tangent; +#texture (tex1, 0, sRGB_A) uniform sampler2D tex1; + +#texture (tex2, 1, RGB) uniform sampler2D tex2; #include diff --git a/shaders/mat_stars.frag b/shaders/mat_stars.frag new file mode 100644 index 00000000..1f16228d --- /dev/null +++ b/shaders/mat_stars.frag @@ -0,0 +1,17 @@ +#version 330 + +#include + +in vec3 f_normal; + +void main() +{ + float x = (gl_PointCoord.x - 0.5f) * 2.0f; + float y = (gl_PointCoord.y - 0.5f) * 2.0f; + float dist2 = abs(x * x + y * y); + if (dist2 > 0.5f * 0.5f) + discard; + + // color data is shared with normals, ugh + gl_FragColor = vec4(f_normal, 1.0f); +} diff --git a/shaders/postfx_tonemapping.frag b/shaders/postfx_tonemapping.frag index 3bca6a76..696ebb11 100644 --- a/shaders/postfx_tonemapping.frag +++ b/shaders/postfx_tonemapping.frag @@ -3,6 +3,7 @@ out vec4 FragColor; in vec2 f_coords; +#texture (tex1, 0, RGB) uniform sampler2D tex1; vec3 reinhard(vec3 x)