diff --git a/Docs/Reference.dox b/Docs/Reference.dox index 5eb442c41..bab5f2e0f 100644 --- a/Docs/Reference.dox +++ b/Docs/Reference.dox @@ -663,6 +663,19 @@ Make sure the normal map is oriented correctly: an even surface should have the Specular maps encode the specular surface color as RGB. Note that deferred rendering is only able to use monochromatic specular intensity from the G channel, while forward and light pre-pass rendering use fully colored specular. DXT1 format should suit these textures well. +Textures can have an accompanying XML file which specifies load-time parameters, such as addressing, mipmapping, and number of mip levels to skip on each quality level: + +\code + +
+ + + + + + +\endcode + \section Materials_Techniques Techniques and passes A technique definition looks like this: @@ -811,7 +824,7 @@ The render path XML definition looks like this: \code + format="rgb|rgba|r32f|rgba16|rgba16f|rgba32f|rg16|rg16f|rg32f|lineardepth" filter="true|false" srgb="true|false" /> diff --git a/Engine/Engine/APITemplates.h b/Engine/Engine/APITemplates.h index eee09636b..dc6d87309 100644 --- a/Engine/Engine/APITemplates.h +++ b/Engine/Engine/APITemplates.h @@ -720,6 +720,8 @@ template void RegisterTexture(asIScriptEngine* engine, const char* cla engine->RegisterObjectMethod(className, "TextureAddressMode get_addressMode(TextureCoordinate) const", asMETHOD(T, GetAddressMode), asCALL_THISCALL); engine->RegisterObjectMethod(className, "void set_borderColor(const Color&in)", asMETHOD(T, SetBorderColor), asCALL_THISCALL); engine->RegisterObjectMethod(className, "const Color& get_borderColor() const", asMETHOD(T, GetBorderColor), asCALL_THISCALL); + engine->RegisterObjectMethod(className, "void set_sRGB(bool)", asMETHOD(T, SetSRGB), asCALL_THISCALL); + engine->RegisterObjectMethod(className, "bool get_sRGB() const", asMETHOD(T, GetSRGB), asCALL_THISCALL); engine->RegisterObjectMethod(className, "void set_backupTexture(Texture@+)", asMETHOD(T, SetBackupTexture), asCALL_THISCALL); engine->RegisterObjectMethod(className, "Texture@+ get_backupTexture() const", asMETHOD(T, GetBackupTexture), asCALL_THISCALL); engine->RegisterObjectMethod(className, "bool get_dataLost() const", asMETHODPR(T, IsDataLost, () const, bool), asCALL_THISCALL); diff --git a/Engine/Engine/GraphicsAPI.cpp b/Engine/Engine/GraphicsAPI.cpp index 7dac1ca1a..ec5c6fe6a 100644 --- a/Engine/Engine/GraphicsAPI.cpp +++ b/Engine/Engine/GraphicsAPI.cpp @@ -174,7 +174,6 @@ static bool TextureCubeLoad(CubeMapFace face, Image* image, bool useAlpha, Textu static void ConstructRenderTargetInfo(RenderTargetInfo* ptr) { - // Init to zero because performance is not critical new(ptr) RenderTargetInfo(); } @@ -190,7 +189,6 @@ static void DestructRenderTargetInfo(RenderTargetInfo* ptr) static void ConstructRenderPathCommand(RenderPathCommand* ptr) { - // Init to zero because performance is not critical new(ptr) RenderPathCommand(); } @@ -293,6 +291,7 @@ static void RegisterRenderPath(asIScriptEngine* engine) engine->RegisterObjectProperty("RenderTargetInfo", "RenderTargetSizeMode sizeMode", offsetof(RenderTargetInfo, sizeMode_)); engine->RegisterObjectProperty("RenderTargetInfo", "bool active", offsetof(RenderTargetInfo, active_)); engine->RegisterObjectProperty("RenderTargetInfo", "bool filtered", offsetof(RenderTargetInfo, filtered_)); + engine->RegisterObjectProperty("RenderTargetInfo", "bool sRGB", offsetof(RenderTargetInfo, sRGB_)); engine->RegisterObjectType("RenderPathCommand", sizeof(RenderPathCommand), asOBJ_VALUE | asOBJ_APP_CLASS_C); engine->RegisterObjectBehaviour("RenderPathCommand", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(ConstructRenderPathCommand), asCALL_CDECL_OBJLAST); @@ -996,6 +995,8 @@ static void RegisterGraphics(asIScriptEngine* engine) engine->RegisterObjectMethod("Graphics", "bool TakeScreenShot(Image@+)", asMETHOD(Graphics, TakeScreenShot), asCALL_THISCALL); engine->RegisterObjectMethod("Graphics", "void set_windowTitle(const String&in)", asMETHOD(Graphics, SetWindowTitle), asCALL_THISCALL); engine->RegisterObjectMethod("Graphics", "const String& get_windowTitle() const", asMETHOD(Graphics, GetWindowTitle), asCALL_THISCALL); + engine->RegisterObjectMethod("Graphics", "void set_sRGB(bool)", asMETHOD(Graphics, SetSRGB), asCALL_THISCALL); + engine->RegisterObjectMethod("Graphics", "bool get_sRGB() const", asMETHOD(Graphics, GetSRGB), asCALL_THISCALL); engine->RegisterObjectMethod("Graphics", "int get_width() const", asMETHOD(Graphics, GetWidth), asCALL_THISCALL); engine->RegisterObjectMethod("Graphics", "int get_height() const", asMETHOD(Graphics, GetHeight), asCALL_THISCALL); engine->RegisterObjectMethod("Graphics", "int get_multiSample() const", asMETHOD(Graphics, GetMultiSample), asCALL_THISCALL); @@ -1011,6 +1012,7 @@ static void RegisterGraphics(asIScriptEngine* engine) engine->RegisterObjectMethod("Graphics", "bool get_lightPrepassSupport() const", asMETHOD(Graphics, GetLightPrepassSupport), asCALL_THISCALL); engine->RegisterObjectMethod("Graphics", "bool get_deferredSupport() const", asMETHOD(Graphics, GetDeferredSupport), asCALL_THISCALL); engine->RegisterObjectMethod("Graphics", "bool get_hardwareShadowSupport() const", asMETHOD(Graphics, GetHardwareShadowSupport), asCALL_THISCALL); + engine->RegisterObjectMethod("Graphics", "bool get_sRGBSupport() const", asMETHOD(Graphics, GetSRGBSupport), asCALL_THISCALL); engine->RegisterObjectMethod("Graphics", "void set_forceSM2(bool)", asMETHOD(Graphics, SetForceSM2), asCALL_THISCALL); engine->RegisterObjectMethod("Graphics", "bool get_forceSM2() const", asMETHOD(Graphics, GetForceSM2), asCALL_THISCALL); engine->RegisterObjectMethod("Graphics", "Array@ get_resolutions() const", asFUNCTION(GraphicsGetResolutions), asCALL_CDECL_OBJLAST); diff --git a/Engine/Graphics/Direct3D9/D3D9Graphics.cpp b/Engine/Graphics/Direct3D9/D3D9Graphics.cpp index d9a9925d9..e835ff8f6 100644 --- a/Engine/Graphics/Direct3D9/D3D9Graphics.cpp +++ b/Engine/Graphics/Direct3D9/D3D9Graphics.cpp @@ -182,11 +182,13 @@ Graphics::Graphics(Context* context) : resizable_(false), vsync_(false), tripleBuffer_(false), + sRGB_(false), deviceLost_(false), lightPrepassSupport_(false), deferredSupport_(false), hardwareShadowSupport_(false), streamOffsetSupport_(false), + sRGBSupport_(true), hasSM3_(false), forceSM2_(false), numPrimitives_(0), @@ -370,7 +372,7 @@ bool Graphics::SetMode(int width, int height, bool fullscreen, bool resizable, b impl_->presentParams_.hDeviceWindow = WIN_GetWindowHandle(impl_->window_); impl_->presentParams_.EnableAutoDepthStencil = TRUE; impl_->presentParams_.AutoDepthStencilFormat = D3DFMT_D24S8; - impl_->presentParams_.Flags = 0; + impl_->presentParams_.Flags = D3DPRESENT_LINEAR_CONTENT; impl_->presentParams_.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT; if (vsync) @@ -443,6 +445,11 @@ bool Graphics::SetMode(int width, int height) return SetMode(width, height, fullscreen_, resizable_, vsync_, tripleBuffer_, multiSample_); } +void Graphics::SetSRGB(bool enabled) +{ + sRGB_ = enabled; +} + bool Graphics::ToggleFullscreen() { return SetMode(width_, height_, !fullscreen_, resizable_, vsync_, tripleBuffer_, multiSample_); @@ -1274,6 +1281,12 @@ void Graphics::SetTexture(unsigned index, Texture* texture) impl_->borderColors_[index] = borderColor; } } + bool sRGB = texture->GetSRGB(); + if (sRGB != impl_->sRGBModes_[index]) + { + impl_->device_->SetSamplerState(index, D3DSAMP_SRGBTEXTURE, sRGB ? TRUE : FALSE); + impl_->sRGBModes_[index] = sRGB; + } } } @@ -1344,6 +1357,17 @@ void Graphics::SetRenderTarget(unsigned index, RenderSurface* renderTarget) SetTexture(i, textures_[i]->GetBackupTexture()); } } + + // First rendertarget controls sRGB write mode + if (!index) + { + bool sRGBWrite = renderTarget ? renderTarget->GetParentTexture()->GetSRGB() : sRGB_; + if (sRGBWrite != impl_->sRGBWrite_) + { + impl_->device_->SetRenderState(D3DRS_SRGBWRITEENABLE, sRGBWrite ? TRUE : FALSE); + impl_->sRGBWrite_ = sRGBWrite; + } + } } void Graphics::SetRenderTarget(unsigned index, Texture2D* texture) @@ -2286,6 +2310,7 @@ void Graphics::ResetCachedState() impl_->vAddressModes_[i] = D3DTADDRESS_WRAP; impl_->wAddressModes_[i] = D3DTADDRESS_WRAP; impl_->borderColors_[i] = Color(0.0f, 0.0f, 0.0f, 0.0f); + impl_->sRGBModes_[i] = false; } for (unsigned i = 0; i < MAX_RENDERTARGETS; ++i) @@ -2298,6 +2323,7 @@ void Graphics::ResetCachedState() impl_->depthStencilSurface_ = 0; viewTexture_ = 0; viewport_ = IntRect(0, 0, width_, height_); + impl_->sRGBWrite_ = false; for (unsigned i = 0; i < MAX_VERTEX_STREAMS; ++i) streamFrequencies_[i] = 1; diff --git a/Engine/Graphics/Direct3D9/D3D9Graphics.h b/Engine/Graphics/Direct3D9/D3D9Graphics.h index 8c40e3a84..eda5e2421 100644 --- a/Engine/Graphics/Direct3D9/D3D9Graphics.h +++ b/Engine/Graphics/Direct3D9/D3D9Graphics.h @@ -87,6 +87,8 @@ public: bool SetMode(int width, int height, bool fullscreen, bool resizable, bool vsync, bool tripleBuffer, int multiSample); /// Set screen resolution only. Return true if successful. bool SetMode(int width, int height); + /// Set whether the main window uses sRGB writing. + void SetSRGB(bool enable); /// Toggle between full screen and windowed mode. Return true if successful. bool ToggleFullscreen(); /// Close the window. @@ -220,6 +222,8 @@ public: bool GetVSync() const { return vsync_; } /// Return whether triple buffering is enabled. bool GetTripleBuffer() const { return tripleBuffer_; } + /// Return whether the main window is using SRGB writing. + bool IsSRGB() const { return sRGB_; } /// Return whether Direct3D device is lost, and can not yet render. This happens during fullscreen resolution switching. bool IsDeviceLost() const { return deviceLost_; } /// Return number of primitives drawn this frame. @@ -242,6 +246,8 @@ public: bool GetHardwareShadowSupport() const { return hardwareShadowSupport_; } /// Return whether stream offset is supported. bool GetStreamOffsetSupport() const { return streamOffsetSupport_; } + /// Return whether sRGB textures are supported. + bool GetSRGBSupport() const { return sRGBSupport_; } /// Return supported fullscreen resolutions. PODVector GetResolutions() const; /// Return supported multisampling levels. @@ -407,6 +413,8 @@ private: bool vsync_; /// Triple buffering flag. bool tripleBuffer_; + /// sRGB writing flag for the main window. + bool sRGB_; /// Direct3D device lost flag. bool deviceLost_; /// Light pre-pass rendering support flag. @@ -417,6 +425,8 @@ private: bool hardwareShadowSupport_; /// Stream offset support flag. bool streamOffsetSupport_; + /// sRGB texture support flag. + bool sRGBSupport_; /// Shader Model 3 flag. bool hasSM3_; /// Force Shader Model 2 flag. diff --git a/Engine/Graphics/Direct3D9/D3D9GraphicsImpl.h b/Engine/Graphics/Direct3D9/D3D9GraphicsImpl.h index 2092b017c..1df198326 100644 --- a/Engine/Graphics/Direct3D9/D3D9GraphicsImpl.h +++ b/Engine/Graphics/Direct3D9/D3D9GraphicsImpl.h @@ -83,6 +83,10 @@ private: D3DTEXTUREADDRESS wAddressModes_[MAX_TEXTURE_UNITS]; /// Texture border colors in use. Color borderColors_[MAX_TEXTURE_UNITS]; + /// sRGB mode in use. + bool sRGBModes_[MAX_TEXTURE_UNITS]; + /// sRGB write flag. + bool sRGBWrite_; /// Color surfaces in use. IDirect3DSurface9* colorSurfaces_[MAX_RENDERTARGETS]; /// Depth-stencil surface in use. diff --git a/Engine/Graphics/Direct3D9/D3D9Texture.cpp b/Engine/Graphics/Direct3D9/D3D9Texture.cpp index 2efd93762..8f02df6a4 100644 --- a/Engine/Graphics/Direct3D9/D3D9Texture.cpp +++ b/Engine/Graphics/Direct3D9/D3D9Texture.cpp @@ -65,7 +65,8 @@ Texture::Texture(Context* context) : requestedLevels_(0), width_(0), height_(0), - filterMode_(FILTER_DEFAULT) + filterMode_(FILTER_DEFAULT), + sRGB_(false) { for (int i = 0; i < MAX_COORDS; ++i) addressMode_[i] = ADDRESS_WRAP; @@ -100,6 +101,11 @@ void Texture::SetBorderColor(const Color& color) borderColor_ = color; } +void Texture::SetSRGB(bool enable) +{ + sRGB_ = enable; +} + void Texture::SetBackupTexture(Texture* texture) { backupTexture_ = texture; @@ -261,6 +267,9 @@ void Texture::LoadParameters(const XMLElement& element) mipsToSkip_[i] = mipsToSkip_[i - 1]; } } + + if (name == "srgb") + SetSRGB(paramElem.GetBool("enable")); paramElem = paramElem.GetNext(); } diff --git a/Engine/Graphics/Direct3D9/D3D9Texture.h b/Engine/Graphics/Direct3D9/D3D9Texture.h index 1c75ab49e..0f824fff0 100644 --- a/Engine/Graphics/Direct3D9/D3D9Texture.h +++ b/Engine/Graphics/Direct3D9/D3D9Texture.h @@ -53,6 +53,8 @@ public: void SetAddressMode(TextureCoordinate coord, TextureAddressMode address); /// Set border color for border addressing mode. void SetBorderColor(const Color& color); + /// Set sRGB sampling and writing mode. + void SetSRGB(bool enable); /// Set backup texture to use when rendering to this texture. void SetBackupTexture(Texture* texture); @@ -72,6 +74,8 @@ public: TextureAddressMode GetAddressMode(TextureCoordinate coord) const { return addressMode_[coord]; } /// Return border color. const Color& GetBorderColor() const { return borderColor_; } + /// Return whether is using sRGB sampling and writing. + bool GetSRGB() const { return sRGB_; } /// Return backup texture. Texture* GetBackupTexture() const { return backupTexture_; } /// Return mip level width, or 0 if level does not exist. @@ -118,6 +122,8 @@ protected: unsigned mipsToSkip_[MAX_TEXTURE_QUALITY_LEVELS]; /// Border color. Color borderColor_; + /// sRGB sampling and writing mode flag. + bool sRGB_; /// Backup texture. SharedPtr backupTexture_; }; diff --git a/Engine/Graphics/OpenGL/OGLGraphics.cpp b/Engine/Graphics/OpenGL/OGLGraphics.cpp index 3e4d5b4e3..56be65b78 100644 --- a/Engine/Graphics/OpenGL/OGLGraphics.cpp +++ b/Engine/Graphics/OpenGL/OGLGraphics.cpp @@ -167,6 +167,7 @@ Graphics::Graphics(Context* context_) : dxtTextureSupport_(false), etcTextureSupport_(false), pvrtcTextureSupport_(false), + sRGBSupport_(false), numPrimitives_(0), numBatches_(0), maxScratchBufferRequest_(0), @@ -379,6 +380,7 @@ bool Graphics::SetMode(int width, int height, bool fullscreen, bool resizable, b dxtTextureSupport_ = GLEW_EXT_texture_compression_s3tc != 0; anisotropySupport_ = GLEW_EXT_texture_filter_anisotropic != 0; + sRGBSupport_ = GLEW_EXT_texture_sRGB != 0; #else dxtTextureSupport_ = CheckExtension(extensions, "EXT_texture_compression_dxt1"); etcTextureSupport_ = CheckExtension(extensions, "OES_compressed_ETC1_RGB8_texture"); @@ -439,6 +441,11 @@ bool Graphics::SetMode(int width, int height) return SetMode(width, height, fullscreen_, resizable_, vsync_, tripleBuffer_, multiSample_); } +void Graphics::SetSRGB(bool enabled) +{ + sRGB_ = enabled && sRGBSupport_; +} + bool Graphics::ToggleFullscreen() { return SetMode(width_, height_, !fullscreen_, resizable_, vsync_, tripleBuffer_, multiSample_); diff --git a/Engine/Graphics/OpenGL/OGLGraphics.h b/Engine/Graphics/OpenGL/OGLGraphics.h index 6c8567c36..20ec85b72 100644 --- a/Engine/Graphics/OpenGL/OGLGraphics.h +++ b/Engine/Graphics/OpenGL/OGLGraphics.h @@ -92,6 +92,8 @@ public: bool SetMode(int width, int height, bool fullscreen, bool resizable, bool vsync, bool tripleBuffer, int multiSample); /// Set screen resolution only. Return true if successful. bool SetMode(int width, int height); + /// Set whether the main window uses sRGB writing. + void SetSRGB(bool enable); /// Toggle between full screen and windowed mode. bool ToggleFullscreen(); /// Close the window. @@ -229,6 +231,8 @@ public: bool GetVSync() const { return vsync_; } /// Return whether triple buffering is enabled. bool GetTripleBuffer() const { return tripleBuffer_; } + /// Return whether the main window is using SRGB writing. + bool GetSRGB() const { return sRGB_; } /// Return whether device is lost, and can not yet render. bool IsDeviceLost() const; /// Return number of primitives drawn this frame. @@ -253,6 +257,8 @@ public: bool GetHardwareShadowSupport() const { return true; } /// Return whether stream offset is supported. Always false on OpenGL. bool GetStreamOffsetSupport() const { return false; } + /// Return whether sRGB textures are supported. + bool GetSRGBSupport() const { return sRGBSupport_; } /// Return supported fullscreen resolutions. PODVector GetResolutions() const; /// Return supported multisampling levels. @@ -416,6 +422,8 @@ private: bool vsync_; /// Triple buffering flag. bool tripleBuffer_; + /// sRGB writing flag for the main window. + bool sRGB_; /// Light prepass support flag. bool lightPrepassSupport_; /// Deferred rendering support flag. @@ -428,6 +436,8 @@ private: bool etcTextureSupport_; /// PVRTC formats support flag. bool pvrtcTextureSupport_; + /// sRGB texture support flag. + bool sRGBSupport_; /// Number of primitives this frame. unsigned numPrimitives_; /// Number of batches this frame. diff --git a/Engine/Graphics/OpenGL/OGLGraphicsImpl.h b/Engine/Graphics/OpenGL/OGLGraphicsImpl.h index e55fa1f50..c03c009d0 100644 --- a/Engine/Graphics/OpenGL/OGLGraphicsImpl.h +++ b/Engine/Graphics/OpenGL/OGLGraphicsImpl.h @@ -30,13 +30,13 @@ #include #include #elif defined(IOS) -#include -#include -#else -#include -#endif - -#ifndef GL_COMPRESSED_RGBA_S3TC_DXT1_EXT +#include +#include +#else +#include +#endif + +#ifndef GL_COMPRESSED_RGBA_S3TC_DXT1_EXT #define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83f1 #endif #ifndef GL_ETC1_RGB8_OES diff --git a/Engine/Graphics/OpenGL/OGLTexture.cpp b/Engine/Graphics/OpenGL/OGLTexture.cpp index 8e6c9b62b..2bf77b6d3 100644 --- a/Engine/Graphics/OpenGL/OGLTexture.cpp +++ b/Engine/Graphics/OpenGL/OGLTexture.cpp @@ -78,7 +78,8 @@ Texture::Texture(Context* context) : height_(0), shadowCompare_(false), parametersDirty_(true), - filterMode_(FILTER_DEFAULT) + filterMode_(FILTER_DEFAULT), + sRGB_(false) { for (int i = 0; i < MAX_COORDS; ++i) addressMode_[i] = ADDRESS_WRAP; @@ -119,6 +120,11 @@ void Texture::SetBorderColor(const Color& color) parametersDirty_ = true; } +void Texture::SetSRGB(bool enable) +{ + sRGB_ = enable; +} + void Texture::SetBackupTexture(Texture* texture) { backupTexture_ = texture; @@ -298,17 +304,20 @@ unsigned Texture::GetRowDataSize(int width) const unsigned Texture::GetExternalFormat(unsigned format) { #ifndef GL_ES_VERSION_2_0 - // For DEPTH_COMPONENTxx textures DEPTH_COMPONENT needs to be returned if (format == GL_DEPTH_COMPONENT16 || format == GL_DEPTH_COMPONENT24 || format == GL_DEPTH_COMPONENT32) return GL_DEPTH_COMPONENT; else if (format == GL_DEPTH24_STENCIL8_EXT) return GL_DEPTH_STENCIL_EXT; - else if (format == GL_LUMINANCE16F_ARB || format == GL_LUMINANCE32F_ARB) + else if (format == GL_LUMINANCE16F_ARB || format == GL_LUMINANCE32F_ARB || format == GL_SLUMINANCE_EXT) return GL_LUMINANCE; + else if (format == GL_SLUMINANCE_ALPHA_EXT) + return GL_LUMINANCE_ALPHA; else if (format == GL_RG16 || format == GL_RG16F || format == GL_RG32F) return GL_RG; - else if (format == GL_RGBA16 || format == GL_RGBA16F_ARB || format == GL_RGBA32F_ARB) + else if (format == GL_RGBA16 || format == GL_RGBA16F_ARB || format == GL_RGBA32F_ARB || format == GL_SRGB_ALPHA_EXT) return GL_RGBA; + else if (format == GL_SRGB_EXT) + return GL_RGB; else return format; #else @@ -408,10 +417,43 @@ void Texture::LoadParameters(const XMLElement& elem) } } + if (name == "srgb") + SetSRGB(paramElem.GetBool("enable")); + paramElem = paramElem.GetNext(); } } +unsigned Texture::GetSRGBFormat(unsigned format) +{ + #ifndef GL_ES_VERSION_2_0 + if (!graphics_ || !graphics_->GetSRGBSupport()) + return format; + + switch (format) + { + case GL_RGB: + return GL_SRGB_EXT; + case GL_RGBA: + return GL_SRGB_ALPHA_EXT; + case GL_LUMINANCE: + return GL_SLUMINANCE_EXT; + case GL_LUMINANCE_ALPHA: + return GL_SLUMINANCE_ALPHA_EXT; + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT; + case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: + return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT; + case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: + return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT; + default: + return format; + } + #else + return format; + #endif +} + void Texture::CheckTextureBudget(ShortStringHash type) { ResourceCache* cache = GetSubsystem(); diff --git a/Engine/Graphics/OpenGL/OGLTexture.h b/Engine/Graphics/OpenGL/OGLTexture.h index 9b7c34db8..40f81b0bf 100644 --- a/Engine/Graphics/OpenGL/OGLTexture.h +++ b/Engine/Graphics/OpenGL/OGLTexture.h @@ -55,6 +55,8 @@ public: void SetShadowCompare(bool enable); /// Set border color for border addressing mode. void SetBorderColor(const Color& color); + /// Set sRGB sampling and writing mode. + void SetSRGB(bool enable); /// Set backup texture to use when rendering to this texture. void SetBackupTexture(Texture* texture); /// Dirty the parameters. @@ -84,6 +86,8 @@ public: bool GetShadowCompare() const { return shadowCompare_; } /// Return border color. const Color& GetBorderColor() const { return borderColor_; } + /// Return whether is using sRGB sampling and writing. + bool GetSRGB() const { return sRGB_; } /// Return backup texture. Texture* GetBackupTexture() const { return backupTexture_; } /// Return mip level width, or 0 if level does not exist. @@ -107,6 +111,8 @@ public: void LoadParameters(XMLFile* xml); /// Load parameters from an XML element. void LoadParameters(const XMLElement& elem); + /// Return the corresponding SRGB texture format if supported. If not supported, return format unchanged. + unsigned GetSRGBFormat(unsigned format); protected: /// Check whether texture memory budget has been exceeded. Free unused materials in that case to release the texture references. @@ -138,6 +144,8 @@ protected: unsigned mipsToSkip_[MAX_TEXTURE_QUALITY_LEVELS]; /// Border color. Color borderColor_; + /// sRGB sampling and writing mode flag. + bool sRGB_; /// Backup texture. SharedPtr backupTexture_; }; diff --git a/Engine/Graphics/OpenGL/OGLTexture2D.cpp b/Engine/Graphics/OpenGL/OGLTexture2D.cpp index a02a771a0..f4aac6beb 100644 --- a/Engine/Graphics/OpenGL/OGLTexture2D.cpp +++ b/Engine/Graphics/OpenGL/OGLTexture2D.cpp @@ -219,19 +219,21 @@ bool Texture2D::SetData(unsigned level, int x, int y, int width, int height, con graphics_->SetTextureForUpdate(this); + unsigned format = GetSRGB() ? GetSRGBFormat(format_) : format_; + if (!IsCompressed()) { if (wholeLevel) - glTexImage2D(target_, level, format_, width, height, 0, GetExternalFormat(format_), GetDataType(format_), data); + glTexImage2D(target_, level, format, width, height, 0, GetExternalFormat(format_), GetDataType(format_), data); else glTexSubImage2D(target_, level, x, y, width, height, GetExternalFormat(format_), GetDataType(format_), data); } else { if (wholeLevel) - glCompressedTexImage2D(target_, level, format_, width, height, 0, GetDataSize(width, height), data); + glCompressedTexImage2D(target_, level, format, width, height, 0, GetDataSize(width, height), data); else - glCompressedTexSubImage2D(target_, level, x, y, width, height, format_, GetDataSize(width, height), data); + glCompressedTexSubImage2D(target_, level, x, y, width, height, format, GetDataSize(width, height), data); } graphics_->SetTexture(0, 0); @@ -410,20 +412,21 @@ bool Texture2D::Create() return true; } + unsigned format = GetSRGB() ? GetSRGBFormat(format_) : format_; unsigned externalFormat = GetExternalFormat(format_); unsigned dataType = GetDataType(format_); // Create a renderbuffer instead of a texture if depth texture is not properly supported, or if this will be a packed // depth stencil texture #ifndef GL_ES_VERSION_2_0 - if (format_ == Graphics::GetDepthStencilFormat()) + if (format == Graphics::GetDepthStencilFormat()) #else if (!graphics_->GetShadowMapFormat() && externalFormat == GL_DEPTH_COMPONENT) #endif { if (renderSurface_) { - renderSurface_->CreateRenderBuffer(width_, height_, format_); + renderSurface_->CreateRenderBuffer(width_, height_, format); return true; } else @@ -437,10 +440,11 @@ bool Texture2D::Create() // If not compressed, create the initial level 0 texture with null data bool success = true; + if (!IsCompressed()) { glGetError(); - glTexImage2D(target_, 0, format_, width_, height_, 0, externalFormat, dataType, 0); + glTexImage2D(target_, 0, format, width_, height_, 0, externalFormat, dataType, 0); if (glGetError()) { LOGERROR("Failed to create texture"); diff --git a/Engine/Graphics/OpenGL/OGLTextureCube.cpp b/Engine/Graphics/OpenGL/OGLTextureCube.cpp index b7cdbd1ce..e2c5b0670 100644 --- a/Engine/Graphics/OpenGL/OGLTextureCube.cpp +++ b/Engine/Graphics/OpenGL/OGLTextureCube.cpp @@ -216,10 +216,12 @@ bool TextureCube::SetData(CubeMapFace face, unsigned level, int x, int y, int wi graphics_->SetTextureForUpdate(this); + unsigned format = GetSRGB() ? GetSRGBFormat(format_) : format_; + if (!IsCompressed()) { if (wholeLevel) - glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level, format_, width, height, 0, GetExternalFormat(format_), + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level, format, width, height, 0, GetExternalFormat(format_), GetDataType(format_), data); else glTexSubImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level, x, y, width, height, GetExternalFormat(format_), @@ -228,10 +230,10 @@ bool TextureCube::SetData(CubeMapFace face, unsigned level, int x, int y, int wi else { if (wholeLevel) - glCompressedTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level, format_, width, height, 0, + glCompressedTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level, format, width, height, 0, GetDataSize(width, height), data); else - glCompressedTexSubImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level, x, y, width, height, format_, + glCompressedTexSubImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level, x, y, width, height, format, GetDataSize(width, height), data); } @@ -528,6 +530,7 @@ bool TextureCube::Create() graphics_->SetTextureForUpdate(this); // If not compressed, create the initial level 0 texture with null data + unsigned format = GetSRGB() ? GetSRGBFormat(format_) : format_; unsigned externalFormat = GetExternalFormat(format_); unsigned dataType = GetDataType(format_); @@ -537,7 +540,7 @@ bool TextureCube::Create() glGetError(); for (unsigned i = 0; i < MAX_CUBEMAP_FACES; ++i) { - glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, format_, width_, height_, 0, externalFormat, dataType, 0); + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, format, width_, height_, 0, externalFormat, dataType, 0); if (glGetError()) success = false; } diff --git a/Engine/Graphics/RenderPath.cpp b/Engine/Graphics/RenderPath.cpp index c1b01cc51..6f499d3bf 100644 --- a/Engine/Graphics/RenderPath.cpp +++ b/Engine/Graphics/RenderPath.cpp @@ -63,7 +63,10 @@ void RenderTargetInfo::LoadParameters(const XMLElement& element) if (element.HasAttribute("filter")) filtered_ = element.GetBool("filter"); - + + if (element.HasAttribute("srgb")) + sRGB_ = element.GetBool("srgb"); + if (element.HasAttribute("size")) size_ = element.GetIntVector2("size"); if (element.HasAttribute("sizedivisor")) diff --git a/Engine/Graphics/RenderPath.h b/Engine/Graphics/RenderPath.h index d6955bd86..2c8bde457 100644 --- a/Engine/Graphics/RenderPath.h +++ b/Engine/Graphics/RenderPath.h @@ -65,7 +65,8 @@ struct RenderTargetInfo size_(IntVector2::ZERO), sizeMode_(SIZE_ABSOLUTE), active_(true), - filtered_(false) + filtered_(false), + sRGB_(false) { } @@ -86,6 +87,8 @@ struct RenderTargetInfo bool active_; /// Filtering flag. bool filtered_; + /// sRGB sampling/writing mode flag. + bool sRGB_; }; /// Rendering path command. diff --git a/Engine/Graphics/Renderer.cpp b/Engine/Graphics/Renderer.cpp index 67ffc0603..58b67e20e 100644 --- a/Engine/Graphics/Renderer.cpp +++ b/Engine/Graphics/Renderer.cpp @@ -927,15 +927,20 @@ Texture2D* Renderer::GetShadowMap(Light* light, Camera* camera, unsigned viewWid return newShadowMap; } -Texture2D* Renderer::GetScreenBuffer(int width, int height, unsigned format, bool filtered) +Texture2D* Renderer::GetScreenBuffer(int width, int height, unsigned format, bool filtered, bool srgb) { bool depthStencil = (format == Graphics::GetDepthStencilFormat()); if (depthStencil) + { filtered = false; + srgb = false; + } long long searchKey = ((long long)format << 32) | (width << 16) | height; if (filtered) searchKey |= 0x8000000000000000LL; + if (srgb) + searchKey |= 0x4000000000000000LL; // If new size or format, initialize the allocation stats if (screenBuffers_.Find(searchKey) == screenBuffers_.End()) @@ -949,6 +954,7 @@ Texture2D* Renderer::GetScreenBuffer(int width, int height, unsigned format, boo if (allocations >= screenBuffers_[searchKey].Size()) { SharedPtr newBuffer(new Texture2D(context_)); + newBuffer->SetSRGB(srgb); newBuffer->SetSize(width, height, format, depthStencil ? TEXTURE_DEPTHSTENCIL : TEXTURE_RENDERTARGET); newBuffer->SetFilterMode(filtered ? FILTER_BILINEAR : FILTER_NEAREST); newBuffer->ResetUseTimer(); diff --git a/Engine/Graphics/Renderer.h b/Engine/Graphics/Renderer.h index 47d080901..51f9b5158 100644 --- a/Engine/Graphics/Renderer.h +++ b/Engine/Graphics/Renderer.h @@ -307,7 +307,7 @@ public: /// Allocate a shadow map. If shadow map reuse is disabled, a different map is returned each time. Texture2D* GetShadowMap(Light* light, Camera* camera, unsigned viewWidth, unsigned viewHeight); /// Allocate a rendertarget or depth-stencil texture for deferred rendering or postprocessing. Should only be called during actual rendering, not before. - Texture2D* GetScreenBuffer(int width, int height, unsigned format, bool filtered = false); + Texture2D* GetScreenBuffer(int width, int height, unsigned format, bool filtered = false, bool srgb = false); /// Allocate a depth-stencil surface that does not need to be readable. Should only be called during actual rendering, not before. RenderSurface* GetDepthStencil(int width, int height); /// Allocate an occlusion buffer. diff --git a/Engine/UI/UI.cpp b/Engine/UI/UI.cpp index 571aa4922..2c6974896 100644 --- a/Engine/UI/UI.cpp +++ b/Engine/UI/UI.cpp @@ -265,7 +265,7 @@ void UI::Render() return; // Update quad geometry into the vertex buffer - unsigned numVertices = vertexData_.Size() / 6; + unsigned numVertices = vertexData_.Size() / UI_VERTEX_SIZE; // Resize the vertex buffer if too small or much too large if (vertexBuffer_->GetVertexCount() < numVertices || vertexBuffer_->GetVertexCount() > numVertices * 2) vertexBuffer_->SetSize(numVertices, MASK_POSITION | MASK_COLOR | MASK_TEXCOORD1, true); @@ -333,7 +333,8 @@ void UI::Render() graphics_->SetScissorTest(true, batch.scissor_); graphics_->SetTexture(0, batch.texture_); graphics_->SetVertexBuffer(vertexBuffer_); - graphics_->Draw(TRIANGLE_LIST, batch.vertexStart_ / 6, (batch.vertexEnd_ - batch.vertexStart_) / 6); + graphics_->Draw(TRIANGLE_LIST, batch.vertexStart_ / UI_VERTEX_SIZE, (batch.vertexEnd_ - batch.vertexStart_) / + UI_VERTEX_SIZE); } } diff --git a/Engine/UI/UIBatch.cpp b/Engine/UI/UIBatch.cpp index bd54c5673..d337ae9dd 100644 --- a/Engine/UI/UIBatch.cpp +++ b/Engine/UI/UIBatch.cpp @@ -104,7 +104,7 @@ void UIBatch::AddQuad(int x, int y, int width, int height, int texOffsetX, int t float bottomUV = (texOffsetY + (texHeight ? texHeight : height)) * invTextureSize_.y_; unsigned begin = vertexData_->Size(); - vertexData_->Resize(begin + 6 * 6); + vertexData_->Resize(begin + 6 * UI_VERTEX_SIZE); float* dest = &(vertexData_->At(begin)); vertexEnd_ = vertexData_->Size(); @@ -170,7 +170,7 @@ void UIBatch::AddQuad(const Matrix3x4& transform, int x, int y, int width, int h float bottomUV = ((float)(texOffsetY + (texHeight ? texHeight : height))) * invTextureSize_.y_; unsigned begin = vertexData_->Size(); - vertexData_->Resize(begin + 6 * 6); + vertexData_->Resize(begin + 6 * UI_VERTEX_SIZE); float* dest = &(vertexData_->At(begin)); vertexEnd_ = vertexData_->Size(); diff --git a/Engine/UI/UIBatch.h b/Engine/UI/UIBatch.h index a0def9e9b..636f17a9e 100644 --- a/Engine/UI/UIBatch.h +++ b/Engine/UI/UIBatch.h @@ -36,6 +36,8 @@ class ShaderVariation; class Texture; class UIElement; +static const unsigned UI_VERTEX_SIZE = 6; + /// %UI rendering draw call. class UIBatch {