set_reflectivity(0.0f);
}
+string BasicMaterial::create_program_source() const
+{
+ string source = "import phong;\n";
+ if(diffuse.texture)
+ source += "const bool use_diffuse_map = true;\n";
+ if(specular.texture || specular.value.r || specular.value.g || specular.value.b)
+ {
+ source += "const bool use_specular = true;\n";
+ if(specular.texture)
+ source += "const bool use_specular_map = true;\n";
+ if(shininess.texture)
+ source += "const bool use_shininess_map = true;\n";
+ }
+ if(normal.texture)
+ source += "const bool use_normal_map = true;\n";
+ if(emission.texture || emission.value.r || emission.value.g || emission.value.b)
+ {
+ source += "const bool use_emission = true;\n";
+ if(emission.texture)
+ source += "const bool use_emission_map = true;\n";
+ }
+ if(reflectivity.value || reflectivity.texture)
+ {
+ source += "const bool use_reflectivity = true;\n";
+ if (reflectivity.texture)
+ source += "const bool use_reflectivity_map = true;\n";
+ }
+ return source;
+}
+
void BasicMaterial::attach_textures_to(Texturing &texturing, ProgramData &tex_shdata) const
{
attach_texture_to(diffuse.texture, texturing, tex_shdata, "diffuse_map");
+#include <msp/core/hash.h>
+#include <msp/strings/format.h>
#include "basicmaterial.h"
#include "gl.h"
#include "resources.h"
namespace Msp {
namespace GL {
+Program *Material::create_compatible_shader() const
+{
+ return new Program(create_program_source());
+}
+
+const Program *Material::create_compatible_shader(DataFile::Collection &coll) const
+{
+ string source = create_program_source();
+ string name = format("_material_%016x.glsl", hash64(source));
+ Program *shprog = coll.find<Program>(name);
+ if(shprog)
+ return shprog;
+
+ shprog = new Program(create_program_source());
+ try
+ {
+ coll.add(name, shprog);
+ }
+ catch(...)
+ {
+ delete shprog;
+ throw;
+ }
+
+ return shprog;
+}
+
void Material::attach_texture_to(const Texture *tex, Texturing &texturing, ProgramData &tex_shdata, const string &name) const
{
if(!tex)
RenderPass::RenderPass():
shprog(0),
+ shprog_from_material(false),
shdata(0),
material(0),
texturing(0),
RenderPass::RenderPass(const RenderPass &other):
shprog(other.shprog),
+ shprog_from_material(other.shprog_from_material),
shdata(other.shdata),
uniform_slots(other.uniform_slots),
material(other.material),
RenderPass &RenderPass::operator=(const RenderPass &other)
{
shprog = other.shprog;
+ shprog_from_material = other.shprog_from_material;
shdata = other.shdata;
uniform_slots = other.uniform_slots;
material = other.material;
delete texturing;
}
-void RenderPass::finalize_material()
+void RenderPass::finalize_material(DataFile::Collection *coll)
{
+ maybe_create_material_shader(coll);
ensure_private_shader_data();
if(!texturing)
material->attach_textures_to(*texturing, *shdata);
}
+void RenderPass::maybe_create_material_shader(DataFile::Collection *coll)
+{
+ if(shprog && !shprog_from_material)
+ return;
+
+ if(coll)
+ {
+ shprog = material->create_compatible_shader(*coll);
+ shprog.keep();
+ }
+ else
+ shprog = material->create_compatible_shader();
+
+ if(shdata)
+ shdata = new ProgramData(*shdata, shprog.get());
+
+ shprog_from_material = true;
+}
+
void RenderPass::ensure_private_shader_data()
{
if(!shprog)
throw invalid_operation("RenderPass::ensure_private_shader_data");
if(!shdata)
- shdata = new ProgramData(shprog);
- else if(shdata.refcount() > 1)
+ shdata = new ProgramData(shprog.get());
+ else if(shdata.refcount()>1)
shdata = new ProgramData(*shdata);
}
void RenderPass::set_shader_program(const Program *prog, const ProgramData *data)
{
shprog = prog;
+ shprog.keep();
+ shprog_from_material = false;
shdata = (data ? new ProgramData(*data) : 0);
+ if(material)
+ finalize_material(0);
}
const string &RenderPass::get_slotted_uniform_name(const string &slot) const
{
material = mat;
material.keep();
- finalize_material();
+ finalize_material(0);
}
void RenderPass::set_texture(unsigned index, const Texture *tex)
{
renderer.set_texturing(texturing);
renderer.set_material(material.get());
- renderer.set_shader_program(shprog, shdata.get());
+ renderer.set_shader_program(shprog.get(), shdata.get());
renderer.set_reverse_winding(back_faces);
}
Material::GenericLoader ldr(coll);
load_sub_with(ldr);
obj.material = ldr.get_material();
- obj.finalize_material();
+ obj.finalize_material(coll);
}
void RenderPass::Loader::material(const string &name)
{
obj.material = &get_collection().get<Material>(name);
obj.material.keep();
- obj.finalize_material();
+ obj.finalize_material(coll);
}
void RenderPass::Loader::shader(const string &n)
{
obj.shprog = &get_collection().get<Program>(n);
+ obj.shprog.keep();
+ obj.shprog_from_material = false;
if(obj.shdata)
- obj.shdata = new ProgramData(*obj.shdata, obj.shprog);
+ obj.shdata = new ProgramData(*obj.shdata, obj.shprog.get());
if(obj.material)
- obj.finalize_material();
+ obj.finalize_material(coll);
}
void RenderPass::Loader::texunit(unsigned i)
void texture2d();
};
- const Program *shprog;
+ RefPtr<const Program> shprog;
+ bool shprog_from_material;
RefPtr<ProgramData> shdata;
std::map<std::string, std::string> uniform_slots;
RefPtr<const Material> material;
~RenderPass();
private:
- void finalize_material();
+ void finalize_material(DataFile::Collection *);
+ void maybe_create_material_shader(DataFile::Collection *);
void ensure_private_shader_data();
public:
void set_shader_program(const Program *, const ProgramData *);
- const Program *get_shader_program() const { return shprog; }
+ const Program *get_shader_program() const { return shprog.get(); }
const ProgramData *get_shader_data() const { return shdata.get(); }
const std::string &get_slotted_uniform_name(const std::string &) const;
void set_material(const Material *);