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
{