vec4 specular;
};
-struct MaterialParameters
+struct BasicMaterialParameters
{
- vec4 ambient;
vec4 diffuse;
vec4 specular;
+ vec4 emission;
float shininess;
+ float reflectivity;
};
struct ClipPlane
mat4 projection_matrix;
};
-uniform Material
+uniform BasicMaterial
{
- MaterialParameters material;
- float reflectivity;
+ BasicMaterialParameters basic_material;
};
uniform Lighting
};
uniform sampler2D diffuse_map;
+uniform sampler2D specular_map;
+uniform sampler2D shininess_map;
+uniform sampler2D emission_map;
uniform sampler2D normal_map;
uniform sampler2DShadow shadow;
vec3 diffuse_light = diffuse_intensity*light_sources[0].diffuse.rgb;
vec3 half_vec = normalize(light_dir-incident_dir);
- float specular_intensity = pow(max(dot(half_vec, normal), 0.0), material.shininess);
+ float specular_intensity = pow(max(dot(half_vec, normal), 0.0), basic_material.shininess);
if(use_shadow_map)
specular_intensity *= shadow_intensity;
vec3 specular_light = specular_intensity*light_sources[0].specular.rgb;
- vec3 result = material.ambient.rgb*ambient_light+material.diffuse.rgb*diffuse_light;
+ vec3 result = basic_material.diffuse.rgb*ambient_light+basic_material.diffuse.rgb*diffuse_light;
if(use_diffuse_map)
result *= diffuse_sample.rgb;
if(use_specular)
- result += material.specular.rgb*specular_light;
+ result += basic_material.specular.rgb*specular_light;
return result;
}
float singlepass_transparency()
{
- float alpha = material.diffuse.a;
+ float alpha = basic_material.diffuse.a;
if(use_diffuse_map)
alpha *= diffuse_sample.a;
return alpha;
--- /dev/null
+#include "basicmaterial.h"
+
+using namespace std;
+
+namespace Msp {
+namespace GL {
+
+BasicMaterial::BasicMaterial()
+{
+ set_diffuse(Color(1.0f));
+ set_specular(Color(0.0f));
+ set_emission(Color(0.0f));
+ set_shininess(50.0f);
+ set_reflectivity(0.0f);
+}
+
+void BasicMaterial::attach_textures_to(Texturing &texturing, ProgramData &tex_shdata) const
+{
+ attach_texture_to(diffuse.texture, texturing, tex_shdata, "diffuse_map");
+ attach_texture_to(specular.texture, texturing, tex_shdata, "specular_map");
+ attach_texture_to(normal.texture, texturing, tex_shdata, "normal_map");
+ attach_texture_to(emission.texture, texturing, tex_shdata, "emission_map");
+ attach_texture_to(shininess.texture, texturing, tex_shdata, "shininess_map");
+ attach_texture_to(reflectivity.texture, texturing, tex_shdata, "reflectivity_map");
+}
+
+void BasicMaterial::set_diffuse(const Color &color)
+{
+ diffuse.value = color;
+ shdata.uniform("basic_material.diffuse", color);
+}
+
+void BasicMaterial::set_diffuse_map(const Texture *tex)
+{
+ diffuse.texture = tex;
+}
+
+void BasicMaterial::set_specular(const Color &color)
+{
+ specular.value = color;
+ shdata.uniform("basic_material.specular", color);
+}
+
+void BasicMaterial::set_specular_map(const Texture *tex)
+{
+ specular.texture = tex;
+}
+
+void BasicMaterial::set_normal_map(const Texture *tex)
+{
+ normal.texture = tex;
+}
+
+void BasicMaterial::set_emission(const Color &color)
+{
+ emission.value = color;
+ shdata.uniform("basic_material.emission", color);
+}
+
+void BasicMaterial::set_emission_map(const Texture *tex)
+{
+ emission.texture = tex;
+}
+
+void BasicMaterial::set_shininess(float value)
+{
+ shininess.value = value;
+ shdata.uniform("basic_material.shininess", value);
+}
+
+void BasicMaterial::set_shininess_map(const Texture *tex)
+{
+ shininess.texture = tex;
+}
+
+void BasicMaterial::set_reflectivity(float value)
+{
+ reflectivity.value = value;
+ shdata.uniform("basic_material.reflectivity", value);
+}
+
+void BasicMaterial::set_reflectivity_map(const Texture *tex)
+{
+ reflectivity.texture = tex;
+}
+
+
+DataFile::Loader::ActionMap BasicMaterial::Loader::shared_actions;
+
+BasicMaterial::Loader::Loader(BasicMaterial &m):
+ DerivedObjectLoader<BasicMaterial, Material::LoaderBase<BasicMaterial> >(m)
+{
+ set_actions(shared_actions);
+}
+
+BasicMaterial::Loader::Loader(BasicMaterial &m, Collection &c):
+ DerivedObjectLoader<BasicMaterial, Material::LoaderBase<BasicMaterial> >(m, c)
+{
+ set_actions(shared_actions);
+}
+
+void BasicMaterial::Loader::init_actions()
+{
+ add_property("diffuse", &BasicMaterial::set_diffuse, &BasicMaterial::set_diffuse_map, true);
+ add_property("specular", &BasicMaterial::set_specular, &BasicMaterial::set_specular_map, false);
+ add_property("normal", &BasicMaterial::set_normal_map);
+ add_property("emission", &BasicMaterial::set_emission, &BasicMaterial::set_emission_map, false);
+ add_property("shininess", &BasicMaterial::set_shininess, &BasicMaterial::set_shininess_map);
+ add_property("reflectivity", &BasicMaterial::set_reflectivity, &BasicMaterial::set_reflectivity_map);
+}
+
+} // namespace GL
+} // namespace Msp
--- /dev/null
+#ifndef MSP_GL_BASICMATERIAL_H_
+#define MSP_GL_BASICMATERIAL_H_
+
+#include "material.h"
+
+namespace Msp {
+namespace GL {
+
+class BasicMaterial: public Material
+{
+public:
+ class Loader: public DataFile::DerivedObjectLoader<BasicMaterial, Material::LoaderBase<BasicMaterial> >
+ {
+ private:
+ static ActionMap shared_actions;
+
+ public:
+ Loader(BasicMaterial &);
+ Loader(BasicMaterial &, Collection &);
+
+ private:
+ virtual void init_actions();
+ };
+
+private:
+ Property<Color> diffuse;
+ Property<Color> specular;
+ Property<float> shininess;
+ Property<Vector3> normal;
+ Property<Color> emission;
+ Property<float> reflectivity;
+
+public:
+ BasicMaterial();
+
+ void attach_textures_to(Texturing &, ProgramData &) const;
+
+ void set_diffuse(const Color &);
+ void set_diffuse_map(const Texture *);
+ void set_specular(const Color &);
+ void set_specular_map(const Texture *);
+ void set_normal_map(const Texture *);
+ void set_emission(const Color &);
+ void set_emission_map(const Texture *);
+ void set_shininess(float);
+ void set_shininess_map(const Texture *);
+ void set_reflectivity(float);
+ void set_reflectivity_map(const Texture *);
+};
+
+} // namespace GL
+} // namespace Msp
+
+#endif
+#include "basicmaterial.h"
#include "gl.h"
-#include "material.h"
#include "resources.h"
+#include "texturing.h"
+
+using namespace std;
namespace Msp {
namespace GL {
-Material::Material()
-{
- set_ambient(0.2);
- set_diffuse(0.8);
- set_specular(0);
- set_emission(0);
- set_shininess(0);
- set_reflectivity(0);
-}
-
-void Material::set_ambient(const Color &a)
-{
- ambient = a;
- shdata.uniform("material.ambient", ambient);
-}
-
-void Material::set_diffuse(const Color &d)
-{
- diffuse = d;
- shdata.uniform("material.diffuse", diffuse);
-}
-
-void Material::set_specular(const Color &s)
+void Material::attach_texture_to(const Texture *tex, Texturing &texturing, ProgramData &tex_shdata, const string &name) const
{
- specular = s;
- shdata.uniform("material.specular", specular);
-}
+ if(!tex)
+ return;
-void Material::set_emission(const Color &e)
-{
- emission = e;
- shdata.uniform("material.emission", emission);
-}
-
-void Material::set_shininess(float s)
-{
- shininess = s;
- shdata.uniform("material.shininess", shininess);
+ int unit = texturing.find_free_unit(name);
+ if(unit<0)
+ throw runtime_error("no free texunit");
+ texturing.attach(unit, *tex);
+ tex_shdata.uniform(name, unit);
}
-void Material::set_reflectivity(float r)
+Material::MaterialRegistry &Material::get_material_registry()
{
- reflectivity = r;
- shdata.uniform("reflectivity", reflectivity);
+ static MaterialRegistry registry;
+ static bool initialized = false;
+ if(!initialized)
+ {
+ registry.register_type<BasicMaterial>("basic");
+ }
+ return registry;
}
-Material::Loader::Loader(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);
- add("emission", &Loader::emission);
- add("shininess", &Loader::shininess);
- add("reflectivity", &Loader::reflectivity);
-}
-
-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(make_color(r, g, b, a));
-}
-
-void Material::Loader::diffuse(float r, float g, float b, float 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(make_color(r, g, b, a));
-}
-
-void Material::Loader::emission(float r, float g, float b, float a)
-{
- obj.set_emission(make_color(r, g, b, a));
-}
+DataFile::Loader::ActionMap Material::GenericLoader::shared_actions;
-void Material::Loader::shininess(float s)
+Material::GenericLoader::GenericLoader(DataFile::Collection *c):
+ coll(c)
{
- obj.set_shininess(s);
+ set_actions(shared_actions);
}
-void Material::Loader::reflectivity(float r)
+void Material::GenericLoader::init_actions()
{
- obj.set_reflectivity(r);
+ get_material_registry().add_all(*this);
}
} // namespace GL
#ifndef MSP_GL_MATERIAL_H_
#define MSP_GL_MATERIAL_H_
+#include <msp/datafile/collection.h>
+#include <msp/datafile/loadabletyperegistry.h>
#include <msp/datafile/objectloader.h>
#include "color.h"
#include "programdata.h"
namespace Msp {
namespace GL {
-/**
-Stores basic material properties. This includes color and reflection
-parameters, but does not include texturing. Materials interact with light
-sources and ambient lighting to produce the base color of a surface. Textures
-can be used to add detail.
+class Texture;
+class Texturing;
-Material provides a set of uniform variables for use with shaders.
-*/
class Material
{
+protected:
+ template<typename T>
+ struct Property
+ {
+ T value;
+ const Texture *texture;
+
+ Property(): value(T()), texture(0) { }
+ };
+
+ template<typename C>
+ class LoaderBase: public DataFile::CollectionObjectLoader<Material>
+ {
+ protected:
+ LoaderBase(C &m): CollectionObjectLoader<Material>(m, 0) { }
+ LoaderBase(C &m, Collection &c): CollectionObjectLoader<Material>(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<Material>
+ class GenericLoader: public DataFile::Loader
{
private:
- bool srgb;
+ template<typename T>
+ struct AddType
+ {
+ static void add(GenericLoader &ldr, const std::string &kw) { ldr.add(kw, &GenericLoader::typed_material<T>); }
+ };
+
+ DataFile::Collection *coll;
+ RefPtr<Material> 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<typename T>
+ void typed_material();
+
+ friend class Material;
};
private:
- Color ambient;
- Color diffuse;
- Color specular;
- Color emission;
- float shininess;
- float reflectivity;
+ typedef DataFile::LoadableTypeRegistry<GenericLoader, GenericLoader::AddType> MaterialRegistry;
+
+protected:
ProgramData shdata;
+ Material() { }
+public:
+ virtual ~Material() { }
+
+public:
+ /** Returns the uniforms for the material. */
+ const ProgramData &get_shader_data() const { return shdata; }
+
+protected:
+ void attach_texture_to(const Texture *, Texturing &, ProgramData &, const std::string &) const;
public:
- Material();
+ virtual void attach_textures_to(Texturing &, ProgramData &) const = 0;
+
+ template<typename T>
+ static void register_type(const std::string &);
+private:
+ static MaterialRegistry &get_material_registry();
+};
- /** Sets the ambient color of the material. Provided to shaders with the
- name material.ambient. */
- void set_ambient(const Color &);
+template<typename T>
+void Material::register_type(const std::string &kw)
+{
+ get_material_registry().register_type<T>(kw);
+}
- /** 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 &);
+template<typename C>
+void Material::LoaderBase<C>::add_property(const std::string &kw, void (C::*set_value)(float), void (C::*set_texture)(const Texture *))
+{
+ add(kw, &LoaderBase<C>::property_value_scalar, set_value);
+ add(kw+"_map", &LoaderBase<C>::property_texture, set_texture);
+}
- /** Sets the specular exponent of the material. Provided to shaders with
- the name material.shininess. */
- void set_shininess(float);
+template<typename C>
+void Material::LoaderBase<C>::add_property(const std::string &kw, void (C::*set_value)(const Color &), void (C::*set_texture)(const Texture *), bool allow_alpha)
+{
+ add(kw, &LoaderBase<C>::property_value_rgb, set_value);
+ add(kw+"_srgb", &LoaderBase<C>::property_value_srgb, set_value);
+ if(allow_alpha)
+ {
+ add(kw, &LoaderBase<C>::property_value_rgba, set_value);
+ add(kw+"_srgb", &LoaderBase<C>::property_value_srgb_alpha, set_value);
+ }
+ add(kw+"_map", &LoaderBase<C>::property_texture, set_texture);
+}
+
+template<typename C>
+void Material::LoaderBase<C>::add_property(const std::string &kw, void (C::*set_texture)(const Texture *))
+{
+ add(kw+"_map", &LoaderBase<C>::property_texture, set_texture);
+}
- /** 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);
+template<typename C>
+void Material::LoaderBase<C>::property_value_scalar(void (C::*set_value)(float), float value)
+{
+ (static_cast<C &>(obj).*set_value)(value);
+}
- 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; }
+template<typename C>
+void Material::LoaderBase<C>::property_value_rgb(void (C::*set_value)(const Color &), float r, float g, float b)
+{
+ (static_cast<C &>(obj).*set_value)(Color(r, g, b));
+}
- /** Returns the uniforms for the material. */
- const ProgramData &get_shader_data() const { return shdata; }
-};
+template<typename C>
+void Material::LoaderBase<C>::property_value_rgba(void (C::*set_value)(const Color &), float r, float g, float b, float a)
+{
+ (static_cast<C &>(obj).*set_value)(Color(r, g, b, a));
+}
+
+template<typename C>
+void Material::LoaderBase<C>::property_value_srgb(void (C::*set_value)(const Color &), float r, float g, float b)
+{
+ (static_cast<C &>(obj).*set_value)(Color(r, g, b).to_linear());
+}
+
+template<typename C>
+void Material::LoaderBase<C>::property_value_srgb_alpha(void (C::*set_value)(const Color &), float r, float g, float b, float a)
+{
+ (static_cast<C &>(obj).*set_value)(Color(r, g, b, a).to_linear());
+}
+
+template<typename C>
+void Material::LoaderBase<C>::property_texture(void (C::*set_texture)(const Texture *), const std::string &name)
+{
+ (static_cast<C &>(obj).*set_texture)(&get_collection().get<GL::Texture>(name));
+}
+
+
+template<typename T>
+void Material::GenericLoader::typed_material()
+{
+ if(material)
+ throw std::logic_error("Material was already loaded");
+ RefPtr<T> mat = new T;
+ if(coll)
+ load_sub(*mat, *coll);
+ else
+ load_sub(*mat);
+ material = mat;
+}
} // namespace GL
} // namespace Msp
delete texturing;
}
+void RenderPass::finalize_material()
+{
+ ensure_private_shader_data();
+
+ if(!texturing)
+ texturing = new Texturing;
+ material->attach_textures_to(*texturing, *shdata);
+}
+
void RenderPass::ensure_private_shader_data()
{
if(!shprog)
{
material = mat;
material.keep();
+ finalize_material();
}
void RenderPass::set_texture(unsigned index, const Texture *tex)
void RenderPass::Loader::material_inline()
{
- RefPtr<Material> mat = new Material;
- if(coll)
- load_sub(*mat, get_collection());
- else
- load_sub(*mat);
- obj.material = mat;
+ Material::GenericLoader ldr(coll);
+ load_sub_with(ldr);
+ obj.material = ldr.get_material();
+ obj.finalize_material();
}
void RenderPass::Loader::material(const string &name)
{
obj.material = &get_collection().get<Material>(name);
obj.material.keep();
+ obj.finalize_material();
}
void RenderPass::Loader::texunit(unsigned i)
~RenderPass();
private:
+ void finalize_material();
void ensure_private_shader_data();
public:
add_type<Font>().keyword("font");
add_type<KeyFrame>().suffix(".kframe").keyword("keyframe");
add_type<Lighting>().suffix(".lightn").keyword("lighting");
- add_type<Material>().suffix(".mat").keyword("material");
+ add_type<Material>().suffix(".mat").creator(&Resources::create_material);
add_type<Mesh>().keyword("mesh").creator(&Resources::create_mesh);
add_type<Object>().keyword("object");
add_type<PipelineTemplate>().suffix(".pipe").keyword("pipeline");
resource_manager = m;
}
+Material *Resources::create_material(const string &name)
+{
+ if(RefPtr<IO::Seekable> io = open_raw(name))
+ {
+ DataFile::Parser parser(*io, name);
+ Material::GenericLoader ldr(this);
+ ldr.load(parser);
+ return ldr.get_material();
+ }
+
+ return 0;
+}
+
Mesh *Resources::create_mesh(const string &name)
{
if(!resource_manager)
namespace Msp {
namespace GL {
+class Material;
class Mesh;
class Program;
class ResourceManager;
void set_resource_manager(ResourceManager *);
protected:
+ Material *create_material(const std::string &);
Mesh *create_mesh(const std::string &);
Texture2D *create_texture2d(const std::string &);
Program *create_program(const std::string &);