]> git.tdb.fi Git - libs/gl.git/commitdiff
Support linear to sRGB conversion when loading materials and textures
authorMikko Rasa <tdb@tdb.fi>
Tue, 29 Apr 2014 05:28:27 +0000 (08:28 +0300)
committerMikko Rasa <tdb@tdb.fi>
Tue, 29 Apr 2014 05:28:27 +0000 (08:28 +0300)
13 files changed:
source/material.cpp
source/material.h
source/pixelformat.cpp
source/pixelformat.h
source/renderpass.cpp
source/resources.cpp
source/resources.h
source/texture.cpp
source/texture.h
source/texture2d.cpp
source/texture2d.h
source/texturecube.cpp
source/texturecube.h

index 7d90dd5a5878f51fb7de27fddef0b89b28ffbf6e..13f2d1d9d9f785ddefa152a22ad3f4dd0fed3a01 100644 (file)
@@ -1,5 +1,6 @@
 #include "gl.h"
 #include "material.h"
+#include "resources.h"
 
 namespace Msp {
 namespace GL {
@@ -73,8 +74,24 @@ void Material::bind() const
 
 
 Material::Loader::Loader(Material &m):
-       DataFile::ObjectLoader<Material>(m)
+       DataFile::CollectionObjectLoader<Material>(m, 0)
 {
+       init();
+}
+
+Material::Loader::Loader(Material &m, Collection &c):
+       DataFile::CollectionObjectLoader<Material>(m, &c)
+{
+       init();
+}
+
+void Material::Loader::init()
+{
+       if(Resources *res = dynamic_cast<Resources *>(coll))
+               srgb = res->get_srgb_conversion();
+       else
+               srgb = false;
+
        add("ambient",   &Loader::ambient);
        add("diffuse",   &Loader::diffuse);
        add("specular",  &Loader::specular);
@@ -82,24 +99,32 @@ Material::Loader::Loader(Material &m):
        add("shininess", &Loader::shininess);
 }
 
+Color Material::Loader::make_color(float r, float g, float b, float a)
+{
+       Color c(r, g, b, a);
+       if(srgb)
+               c = c.to_linear();
+       return c;
+}
+
 void Material::Loader::ambient(float r, float g, float b, float a)
 {
-       obj.set_ambient(GL::Color(r, g, b, a));
+       obj.set_ambient(make_color(r, g, b, a));
 }
 
 void Material::Loader::diffuse(float r, float g, float b, float a)
 {
-       obj.set_diffuse(GL::Color(r, g, b, a));
+       obj.set_diffuse(make_color(r, g, b, a));
 }
 
 void Material::Loader::specular(float r, float g, float b, float a)
 {
-       obj.set_specular(GL::Color(r, g, b, a));
+       obj.set_specular(make_color(r, g, b, a));
 }
 
 void Material::Loader::emission(float r, float g, float b, float a)
 {
-       obj.set_emission(GL::Color(r, g, b, a));
+       obj.set_emission(make_color(r, g, b, a));
 }
 
 void Material::Loader::shininess(float s)
index 5a71aa34bae2be1470016f1c9ef7a3848447503a..a38dddd6a8d5efe097882e44623a3f1f7474a118 100644 (file)
@@ -16,12 +16,18 @@ objects, application of material is done with several calls to glMaterial.
 class Material: public BindableWithDefault<Material>
 {
 public:
-       class Loader: public DataFile::ObjectLoader<Material>
+       class Loader: public DataFile::CollectionObjectLoader<Material>
        {
+       private:
+               bool srgb;
+
        public:
                Loader(Material &);
-
+               Loader(Material &, Collection &);
        private:
+               void init();
+
+               Color make_color(float, float, float, float);
                void ambient(float, float, float, float);
                void diffuse(float, float, float, float);
                void specular(float, float, float, float);
index 027ae88c7fe1bb7c5e11290ef5133e3c143b8d05..b8180b2fb75e559477c0388eddc53509f35263ba 100644 (file)
@@ -105,6 +105,22 @@ PixelFormat get_base_pixelformat(PixelFormat pf)
        }
 }
 
+PixelFormat get_srgb_pixelformat(PixelFormat pf)
+{
+       switch(pf)
+       {
+       case RGB: return SRGB;
+       case RGBA: return SRGB_ALPHA;
+       case RGB8: return SRGB8;
+       case RGBA8: return SRGB8_ALPHA8;
+       case LUMINANCE: return SLUMINANCE;
+       case LUMINANCE8: return SLUMINANCE8;
+       case LUMINANCE_ALPHA: return SLUMINANCE_ALPHA;
+       case LUMINANCE_ALPHA8: return SLUMINANCE8_ALPHA8;
+       default: return pf;
+       }
+}
+
 unsigned get_component_count(PixelFormat pf)
 {
        switch(get_base_pixelformat(pf))
index 01f626c43882bc192b00e83051b9c7c723fcf07c..590ab97eb62cd1e48821e27b9ddda71352149d48 100644 (file)
@@ -54,6 +54,7 @@ PixelFormat pixelformat_from_graphics(Graphics::PixelFormat);
 PixelFormat storage_pixelformat_from_graphics(Graphics::PixelFormat);
 
 PixelFormat get_base_pixelformat(PixelFormat);
+PixelFormat get_srgb_pixelformat(PixelFormat);
 unsigned get_component_count(PixelFormat);
 
 void require_pixelformat(PixelFormat);
index 158e9fc8390206aea6025f7fae37ab844048068c..448db60a91f967cca6362a2ad9e5c41ff5afdc68 100644 (file)
@@ -102,7 +102,10 @@ void RenderPass::Loader::init()
 void RenderPass::Loader::material_inline()
 {
        RefPtr<Material> mat = new Material;
-       load_sub(*mat);
+       if(coll)
+               load_sub(*mat, get_collection());
+       else
+               load_sub(*mat);
        obj.material = mat;
 }
 
@@ -173,7 +176,10 @@ void RenderPass::TextureLoader::texture(const string &name)
 void RenderPass::TextureLoader::texture2d()
 {
        tex = new Texture2D;
-       load_sub(static_cast<Texture2D &>(*tex));
+       if(coll)
+               load_sub(static_cast<Texture2D &>(*tex), get_collection());
+       else
+               load_sub(static_cast<Texture2D &>(*tex));
 }
 
 } // namespace GL
index 8e872d5defbc7a703aec6b9ee56d3218fd393289..10d76148860c0e43d3464429e534502b08a966f3 100644 (file)
@@ -19,7 +19,8 @@ namespace Msp {
 namespace GL {
 
 Resources::Resources():
-       default_tex_filter(LINEAR_MIPMAP_LINEAR)
+       default_tex_filter(LINEAR_MIPMAP_LINEAR),
+       srgb_conversion(false)
 {
        add_type<Animation>().suffix(".anim").keyword("animation");
        add_type<Armature>().suffix(".arma").keyword("armature");
@@ -40,6 +41,11 @@ void Resources::set_default_texture_filter(TextureFilter tf)
        default_tex_filter = tf;
 }
 
+void Resources::set_srgb_conversion(bool c)
+{
+       srgb_conversion = c;
+}
+
 Texture2D *Resources::create_texture2d(const string &name)
 {
        string ext = FS::extpart(name);
index 8871c16e0b2648767bc3586727982d8c0bcfa296..0390d85936902d4b7e75b4c2d569ec8548e61353 100644 (file)
@@ -13,12 +13,19 @@ class Resources: virtual public DataFile::Collection
 {
 private:
        TextureFilter default_tex_filter;
+       bool srgb_conversion;
 
 public:
        Resources();
 
        void set_default_texture_filter(TextureFilter);
 
+       /** Enables or disables sRGB conversion.  If enabled, textures and material
+       colors are converted from sRGB to linear color space when loaded. */
+       void set_srgb_conversion(bool);
+
+       bool get_srgb_conversion() const { return srgb_conversion; }
+
 protected:
        Texture2D *create_texture2d(const std::string &);
 };
index fe8b7be9a3e4fbb56dda02464bfb0541d8e131ce..d738bb36e9a63c2df69ef97a205e292b59aa5b49 100644 (file)
@@ -2,6 +2,7 @@
 #include <msp/gl/extensions/sgis_generate_mipmap.h>
 #include <msp/strings/format.h>
 #include "error.h"
+#include "resources.h"
 #include "texture.h"
 #include "texunit.h"
 
@@ -209,8 +210,24 @@ void Texture::unbind_from(unsigned i)
 
 
 Texture::Loader::Loader(Texture &t):
-       DataFile::ObjectLoader<Texture>(t)
+       DataFile::CollectionObjectLoader<Texture>(t, 0)
 {
+       init();
+}
+
+Texture::Loader::Loader(Texture &t, Collection &c):
+       DataFile::CollectionObjectLoader<Texture>(t, &c)
+{
+       init();
+}
+
+void Texture::Loader::init()
+{
+       if(Resources *res = dynamic_cast<Resources *>(coll))
+               srgb = res->get_srgb_conversion();
+       else
+               srgb = false;
+
        add("filter", &Loader::filter);
        add("max_anisotropy", &Loader::max_anisotropy);
        add("generate_mipmap", &Loader::generate_mipmap);
index c091c884cacfd592833120b785c7f83ff2fe303e..477eaca382fa55dbe6ab1925fb62677db1ed72c1 100644 (file)
@@ -8,6 +8,8 @@
 namespace Msp {
 namespace GL {
 
+class Resources;
+
 enum TextureFilter
 {
        /// No filtering
@@ -66,11 +68,17 @@ wrapping is applied.  The default for all directions is REPEAT.
 class Texture
 {
 protected:
-       class Loader: public DataFile::ObjectLoader<Texture>
+       class Loader: public DataFile::CollectionObjectLoader<Texture>
        {
+       protected:
+               bool srgb;
+
        public:
                Loader(Texture &);
+               Loader(Texture &, Collection &);
        private:
+               void init();
+
                void filter(TextureFilter);
                void generate_mipmap(bool);
                void mag_filter(TextureFilter);
index f4af7e7259bef9ccaf3319be8c56df51cd9881a0..96da77d1b9aba0400805461f0706c84d017ab60e 100644 (file)
@@ -2,6 +2,7 @@
 #include "bindable.h"
 #include "error.h"
 #include "pixelstore.h"
+#include "resources.h"
 #include "texture2d.h"
 
 using namespace std;
@@ -68,21 +69,26 @@ void Texture2D::sub_image(unsigned level, int x, int y, unsigned wd, unsigned ht
        glTexSubImage2D(target, level, x, y, wd, ht, fmt, type, data);
 }
 
-void Texture2D::load_image(const string &fn)
+void Texture2D::load_image(const string &fn, bool srgb)
 {
        Graphics::Image img;
        img.load_file(fn);
 
-       image(img);
+       image(img, srgb);
 }
 
-void Texture2D::image(const Graphics::Image &img)
+void Texture2D::image(const Graphics::Image &img, bool srgb)
 {
        unsigned w = img.get_width();
        unsigned h = img.get_height();
        PixelFormat fmt = pixelformat_from_graphics(img.get_format());
        if(width==0)
-               storage(storage_pixelformat_from_graphics(img.get_format()), w, h);
+       {
+               PixelFormat f = storage_pixelformat_from_graphics(img.get_format());
+               if(srgb)
+                       f = get_srgb_pixelformat(f);
+               storage(f, w, h);
+       }
        else if(w!=width || h!=height)
                throw incompatible_data("Texture2D::image");
 
@@ -106,6 +112,17 @@ void Texture2D::get_level_size(unsigned level, unsigned &w, unsigned &h)
 
 Texture2D::Loader::Loader(Texture2D &t):
        DataFile::DerivedObjectLoader<Texture2D, Texture::Loader>(t)
+{
+       init();
+}
+
+Texture2D::Loader::Loader(Texture2D &t, Collection &c):
+       DataFile::DerivedObjectLoader<Texture2D, Texture::Loader>(t, c)
+{
+       init();
+}
+
+void Texture2D::Loader::init()
 {
        add("image_data", &Loader::image_data);
        add("raw_data", &Loader::raw_data);
@@ -119,7 +136,7 @@ void Texture2D::Loader::image_data(const string &data)
        IO::Memory mem(data.data(), data.size());
        img.load_io(mem);
 
-       obj.image(img);
+       obj.image(img, srgb);
 }
 
 void Texture2D::Loader::raw_data(const string &data)
@@ -129,6 +146,8 @@ void Texture2D::Loader::raw_data(const string &data)
 
 void Texture2D::Loader::storage(PixelFormat fmt, unsigned w, unsigned h)
 {
+       if(srgb)
+               fmt = get_srgb_pixelformat(fmt);
        obj.storage(fmt, w, h);
 }
 
index 6c089ed2fc675c27ed40edf9d07f85cffe1dd019..dce58a7873213e772381582e490c11363f8557b6 100644 (file)
@@ -22,7 +22,10 @@ public:
        {
        public:
                Loader(Texture2D &);
+               Loader(Texture2D &, Collection &);
        private:
+               void init();
+
                void image_data(const std::string &);
                void raw_data(const std::string &);
                void storage(PixelFormat, unsigned, unsigned);
@@ -60,12 +63,12 @@ public:
        /** Loads an image from a file and uploads it to the texture.  If storage
        has not been defined, it will be set to match the loaded image.  Otherwise
        the image must be compatible with the defined storage. */
-       void load_image(const std::string &fn);
+       void load_image(const std::string &fn, bool srgb = false);
 
        /** Uploads an image to the texture.  If storage has not been defined, it
        will be set to match the image.  Otherwise the image must be compatible with
        the defined storage. */
-       void image(const Graphics::Image &);
+       void image(const Graphics::Image &, bool srgb = false);
 
        unsigned get_width() const { return width; }
        unsigned get_height() const { return height; }
index d5453c182e128b13e201cb87d7b738e38caefd00..b071e8545df50ce665b1476b0683058a00af0590 100644 (file)
@@ -71,17 +71,20 @@ void TextureCube::image(TextureCubeFace face, unsigned level, PixelFormat fmt, D
        }
 }
 
-void TextureCube::image(TextureCubeFace face, const Graphics::Image &img)
+void TextureCube::image(TextureCubeFace face, const Graphics::Image &img, bool srgb)
 {
        unsigned w = img.get_width();
        unsigned h = img.get_height();
        PixelFormat fmt = pixelformat_from_graphics(img.get_format());
        if(size==0)
        {
-               if(w==h)
-                       storage(storage_pixelformat_from_graphics(img.get_format()), w);
-               else
+               if(w!=h)
                        throw incompatible_data("TextureCube::image");
+
+               PixelFormat f = storage_pixelformat_from_graphics(img.get_format());
+               if(srgb)
+                       f = get_srgb_pixelformat(f);
+               storage(f, w);
        }
        else if(w!=size || h!=size)
                throw incompatible_data("TextureCube::image");
@@ -166,6 +169,17 @@ Vector3 TextureCube::get_texel_direction(TextureCubeFace face, unsigned u, unsig
 
 TextureCube::Loader::Loader(TextureCube &t):
        DataFile::DerivedObjectLoader<TextureCube, Texture::Loader>(t)
+{
+       init();
+}
+
+TextureCube::Loader::Loader(TextureCube &t, Collection &c):
+       DataFile::DerivedObjectLoader<TextureCube, Texture::Loader>(t, c)
+{
+       init();
+}
+
+void TextureCube::Loader::init()
 {
        add("image_data", &Loader::image_data);
        add("raw_data", &Loader::raw_data);
@@ -178,7 +192,7 @@ void TextureCube::Loader::image_data(TextureCubeFace face, const string &data)
        IO::Memory mem(data.data(), data.size());
        img.load_io(mem);
 
-       obj.image(face, img);
+       obj.image(face, img, srgb);
 }
 
 void TextureCube::Loader::raw_data(TextureCubeFace face, const string &data)
@@ -188,6 +202,8 @@ void TextureCube::Loader::raw_data(TextureCubeFace face, const string &data)
 
 void TextureCube::Loader::storage(PixelFormat fmt, unsigned s)
 {
+       if(srgb)
+               fmt = get_srgb_pixelformat(fmt);
        obj.storage(fmt, s);
 }
 
index e775be1d31ec0ceb26d2fd47ee75597803caf969..077b58ac59f48d6e1bc688564b9787a5086d5b28 100644 (file)
@@ -40,7 +40,10 @@ public:
        {
        public:
                Loader(TextureCube &);
+               Loader(TextureCube &, Collection &);
        private:
+               void init();
+
                void image_data(TextureCubeFace, const std::string &);
                void raw_data(TextureCubeFace, const std::string &);
                void storage(PixelFormat, unsigned);
@@ -77,7 +80,7 @@ public:
                int x, int y, unsigned w, unsigned h,
                PixelFormat fmt, DataType type, const void *data);
 
-       void image(TextureCubeFace, const Graphics::Image &);
+       void image(TextureCubeFace, const Graphics::Image &, bool = false);
 
        unsigned get_size() const { return size; }
 private: