X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2Fmaterial.h;h=5515f29eee539a211059fb15f6869332659c1224;hb=15effbd5a8b135d2b38db5f4651824b9b5cd7300;hp=e1bfec4caa0707419941b88476394955ab651244;hpb=c51030d1cb2308d30db80303a561de1774dfdb76;p=libs%2Fgl.git diff --git a/source/material.h b/source/material.h index e1bfec4c..5515f29e 100644 --- a/source/material.h +++ b/source/material.h @@ -1,108 +1,192 @@ #ifndef MSP_GL_MATERIAL_H_ #define MSP_GL_MATERIAL_H_ +#include +#include #include -#include "bindable.h" #include "color.h" #include "programdata.h" +#include "texture.h" namespace Msp { namespace GL { -/** -Stores basic material properties. This includes color and reflection -parameters, but does not include texturing. Materials interact with light -soucres and ambient lighting to produce the base color of a surface. Textures -can be used to add detail. +class Texturing; -Material provides a set of uniform variables for use with shaders. Standard -shaders generated by ProgramBuilder only use it when legacy mode is disabled. - -In legacy mode, materials are applied with several calls to glMaterial. -*/ -class Material: public BindableWithDefault +class Material { +protected: + template + struct Property + { + T value; + const Texture *texture; + + Property(): value(T()), texture(0) { } + }; + + template + class LoaderBase: public DataFile::CollectionObjectLoader + { + protected: + LoaderBase(C &m): CollectionObjectLoader(m, 0) { } + LoaderBase(C &m, Collection &c): CollectionObjectLoader(m, &c) { } + + void add_property(const std::string &, void (C::*)(float), void (C::*)(const Texture *)); + void add_property(const std::string &, void (C::*)(const Color &), void (C::*)(const Texture *), bool); + void add_property(const std::string &, void (C::*)(const Texture *)); + + void property_value_scalar(void (C::*)(float), float); + void property_value_rgb(void (C::*)(const Color &), float, float, float); + void property_value_rgba(void (C::*)(const Color &), float, float, float, float); + void property_value_srgb(void (C::*)(const Color &), float, float, float); + void property_value_srgb_alpha(void (C::*)(const Color &), float, float, float, float); + void property_texture(void (C::*)(const Texture *), const std::string &); + }; + public: - class Loader: public DataFile::CollectionObjectLoader + class GenericLoader: public DataFile::Loader { private: - bool srgb; + template + struct AddType + { + static void add(GenericLoader &ldr, const std::string &kw) { ldr.add(kw, &GenericLoader::typed_material); } + }; + + DataFile::Collection *coll; + RefPtr material; + + static ActionMap shared_actions; public: - Loader(Material &); - Loader(Material &, Collection &); + GenericLoader(DataFile::Collection * = 0); + + Material *get_material() { return material.release(); } 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); - void emission(float, float, float, float); - void shininess(float); - void reflectivity(float); + virtual void init_actions(); + + template + void typed_material(); + + friend class Material; }; private: - enum ParameterMask - { - AMBIENT = 1, - DIFFUSE = 2, - SPECULAR = 4, - EMISSION = 8, - SHININESS = 16 - }; + typedef DataFile::LoadableTypeRegistry MaterialRegistry; - Color ambient; - Color diffuse; - Color specular; - Color emission; - float shininess; - float reflectivity; +protected: ProgramData shdata; + Material() { } public: - Material(); + virtual ~Material() { } -private: - void update_parameter(int) const; + virtual Program *create_compatible_shader() const; + virtual const Program *create_compatible_shader(DataFile::Collection &) const; +protected: + virtual std::string create_program_source() const = 0; public: - /** Sets the ambient color of the material. Provided to shaders with the - name material.ambient. */ - void set_ambient(const Color &); - - /** Sets the diffuse (direction-independent) color of the material. - Provided to shaders with the name material.diffuse. */ - void set_diffuse(const Color &); - - /** Sets the specular (direction-dependent) color of the material. Provided - to shaders with the name material.specular. */ - void set_specular(const Color &); - void set_emission(const Color &); - - /** Sets the specular exponent of the material. Provided to shaders with - the name material.shininess. */ - void set_shininess(float); - - /** Sets the reflectivity of the material. Provided to shaders with the - name reflectivity. Has no effect when shaders are not used. */ - void set_reflectivity(float); - - const Color &get_ambient() const { return ambient; } - const Color &get_diffuse() const { return diffuse; } - const Color &get_specular() const { return specular; } - const Color &get_emission() const { return emission; } - float get_shininess() const { return shininess; } - float get_reflectivity() const { return reflectivity; } - - /** Returns the uniforms for the material. Not needed for shaders that use - the legacy built-in uniform gl_FrontMaterial and have no reflections. */ + /** Returns the uniforms for the material. */ const ProgramData &get_shader_data() const { return shdata; } - void bind() const; +protected: + void attach_texture_to(const Texture *, Texturing &, ProgramData &, const std::string &) const; +public: + virtual void attach_textures_to(Texturing &, ProgramData &) const = 0; + + template + static void register_type(const std::string &); +private: + static MaterialRegistry &get_material_registry(); }; +template +void Material::register_type(const std::string &kw) +{ + get_material_registry().register_type(kw); +} + + +template +void Material::LoaderBase::add_property(const std::string &kw, void (C::*set_value)(float), void (C::*set_texture)(const Texture *)) +{ + add(kw, &LoaderBase::property_value_scalar, set_value); + add(kw+"_map", &LoaderBase::property_texture, set_texture); +} + +template +void Material::LoaderBase::add_property(const std::string &kw, void (C::*set_value)(const Color &), void (C::*set_texture)(const Texture *), bool allow_alpha) +{ + add(kw, &LoaderBase::property_value_rgb, set_value); + add(kw+"_srgb", &LoaderBase::property_value_srgb, set_value); + if(allow_alpha) + { + add(kw, &LoaderBase::property_value_rgba, set_value); + add(kw+"_srgb", &LoaderBase::property_value_srgb_alpha, set_value); + } + add(kw+"_map", &LoaderBase::property_texture, set_texture); +} + +template +void Material::LoaderBase::add_property(const std::string &kw, void (C::*set_texture)(const Texture *)) +{ + add(kw+"_map", &LoaderBase::property_texture, set_texture); +} + +template +void Material::LoaderBase::property_value_scalar(void (C::*set_value)(float), float value) +{ + (static_cast(obj).*set_value)(value); +} + +template +void Material::LoaderBase::property_value_rgb(void (C::*set_value)(const Color &), float r, float g, float b) +{ + (static_cast(obj).*set_value)(Color(r, g, b)); +} + +template +void Material::LoaderBase::property_value_rgba(void (C::*set_value)(const Color &), float r, float g, float b, float a) +{ + (static_cast(obj).*set_value)(Color(r, g, b, a)); +} + +template +void Material::LoaderBase::property_value_srgb(void (C::*set_value)(const Color &), float r, float g, float b) +{ + (static_cast(obj).*set_value)(Color(r, g, b).to_linear()); +} + +template +void Material::LoaderBase::property_value_srgb_alpha(void (C::*set_value)(const Color &), float r, float g, float b, float a) +{ + (static_cast(obj).*set_value)(Color(r, g, b, a).to_linear()); +} + +template +void Material::LoaderBase::property_texture(void (C::*set_texture)(const Texture *), const std::string &name) +{ + /* The static_cast around get_collection is needed because otherwise Android + SDK's g++ 4.9 fails to parse get as a template function call */ + (static_cast(obj).*set_texture)(&static_cast(get_collection()).get(name)); +} + + +template +void Material::GenericLoader::typed_material() +{ + if(material) + throw std::logic_error("Material was already loaded"); + RefPtr mat = new T; + if(coll) + load_sub(*mat, *coll); + else + load_sub(*mat); + material = mat; +} + } // namespace GL } // namespace Msp