From: Mikko Rasa Date: Sun, 11 Apr 2021 20:25:18 +0000 (+0300) Subject: Overhaul texture management in rendering classes X-Git-Url: http://git.tdb.fi/?a=commitdiff_plain;h=6f39983060a27634c012f66c82fea0d09fea9774;p=libs%2Fgl.git Overhaul texture management in rendering classes Textures are now set based on the uniform name (tag) rather than texture unit. The Texturing class has been deprecated because it was making things difficult when textures come from multiple sources, such as with effects or decals. RenderPass and Renderer now handle multiple textures directly. There's some compatibility code but things are likely to break. --- diff --git a/source/core/datatype.h b/source/core/datatype.h index c7ee2841..ccd288c9 100644 --- a/source/core/datatype.h +++ b/source/core/datatype.h @@ -93,6 +93,7 @@ enum DataType inline unsigned get_type_size(DataType t) { return t&0xFF; } inline bool is_matrix(DataType t) { return t&0xC000; } inline bool is_vector(DataType t) { return !is_matrix(t) && (t&0x3000); } +inline bool is_image(DataType t) { return t&0x70000; } GLenum get_gl_type(DataType); DataType from_gl_type(GLenum); diff --git a/source/core/program.cpp b/source/core/program.cpp index 0d8e6bd1..22626c65 100644 --- a/source/core/program.cpp +++ b/source/core/program.cpp @@ -400,6 +400,9 @@ void Program::query_uniforms() i->location = glGetUniformLocation(id, i->name.c_str()); i->block = &default_block; default_block.uniforms.push_back(&*i); + + if(is_image(i->type) && i->location>=0) + glGetUniformiv(id, i->location, &i->binding); } default_block.layout_hash = compute_layout_hash(default_block.uniforms); @@ -681,6 +684,12 @@ int Program::get_uniform_location(Tag tag) const return i!=uniforms.end() && i->tag==tag && i->block->bind_point<0 ? i->location : -1; } +int Program::get_uniform_binding(Tag tag) const +{ + vector::const_iterator i = lower_bound_member(uniforms, tag, &UniformInfo::tag); + return i!=uniforms.end() && i->tag==tag ? i->binding : -1; +} + const Program::AttributeInfo &Program::get_attribute_info(const string &name) const { vector::const_iterator i = lower_bound_member(attributes, name, &AttributeInfo::name); @@ -724,7 +733,8 @@ Program::UniformInfo::UniformInfo(): array_size(0), array_stride(0), matrix_stride(0), - type(VOID) + type(VOID), + binding(-1) { } diff --git a/source/core/program.h b/source/core/program.h index 377c3eee..666cfd3e 100644 --- a/source/core/program.h +++ b/source/core/program.h @@ -74,6 +74,7 @@ public: unsigned matrix_stride; DataType type; Tag tag; + int binding; UniformInfo(); }; @@ -174,6 +175,7 @@ public: const UniformInfo &get_uniform_info(Tag) const; int get_uniform_location(const std::string &) const; int get_uniform_location(Tag) const; + int get_uniform_binding(Tag) const; const std::vector &get_attributes() const { return attributes; } const AttributeInfo &get_attribute_info(const std::string &) const; int get_attribute_location(const std::string &) const; diff --git a/source/effects/ambientocclusion.cpp b/source/effects/ambientocclusion.cpp index bae5e780..d47d18aa 100644 --- a/source/effects/ambientocclusion.cpp +++ b/source/effects/ambientocclusion.cpp @@ -20,8 +20,6 @@ AmbientOcclusion::AmbientOcclusion(Resources &resources, unsigned w, unsigned h, linear_sampler(resources.get("_linear_clamp.samp")), nearest_sampler(resources.get("_nearest_clamp.samp")) { - texturing.attach(2, occlude_target.get_target_texture(RENDER_COLOR), &linear_sampler); - unsigned seed = 1; rotate_lookup.storage(RGBA8, 4, 4, 1); unsigned char data[64]; @@ -37,12 +35,6 @@ AmbientOcclusion::AmbientOcclusion(Resources &resources, unsigned w, unsigned h, } rotate_lookup.image(0, data); - texturing.attach(3, rotate_lookup, &nearest_sampler); - - shdata.uniform("source", 0); - shdata.uniform("depth", 1); - shdata.uniform("occlusion", 2); - shdata.uniform("rotate", 3); shdata.uniform("inverse_projection", Matrix()); set_n_samples(16); @@ -92,14 +84,14 @@ void AmbientOcclusion::set_edge_depth_threshold(float edt) void AmbientOcclusion::render(Renderer &renderer, const Texture2D &color, const Texture2D &depth) { - texturing.attach(0, color, &nearest_sampler); - texturing.attach(1, depth, &nearest_sampler); - if(renderer.get_camera()) shdata.uniform("inverse_projection", invert(renderer.get_camera()->get_projection_matrix())); Renderer::Push push(renderer); - renderer.set_texturing(&texturing); + renderer.set_texture("source", &color, &nearest_sampler); + renderer.set_texture("depth", &depth, &nearest_sampler); + renderer.set_texture("occlusion", &occlude_target.get_target_texture(RENDER_COLOR), &linear_sampler); + renderer.set_texture("rotate", &rotate_lookup, &nearest_sampler); renderer.set_shader_program(&occlude_shader, &shdata); { diff --git a/source/effects/ambientocclusion.h b/source/effects/ambientocclusion.h index 25fab5c9..2497d5b7 100644 --- a/source/effects/ambientocclusion.h +++ b/source/effects/ambientocclusion.h @@ -8,7 +8,6 @@ #include "programdata.h" #include "rendertarget.h" #include "texture2d.h" -#include "texturing.h" namespace Msp { namespace GL { @@ -42,7 +41,6 @@ public: private: Texture2D rotate_lookup; RenderTarget occlude_target; - Texturing texturing; const Program &occlude_shader; const Program &combine_shader; mutable ProgramData shdata; diff --git a/source/effects/bloom.cpp b/source/effects/bloom.cpp index 1e39c686..98afedfc 100644 --- a/source/effects/bloom.cpp +++ b/source/effects/bloom.cpp @@ -27,11 +27,6 @@ Bloom::Bloom(Resources &resources, unsigned w, unsigned h): for(unsigned i=0; i<2; ++i) target[i] = new RenderTarget(w, h, (RENDER_COLOR,RGB16F)); - common_shdata.uniform("source", 0); - common_shdata.uniform("blurred", 1); - - combine_texturing.attach(1, target[1]->get_target_texture(RENDER_COLOR), &linear_sampler); - set_radius(2.0f); set_strength(0.2f); } @@ -76,13 +71,13 @@ void Bloom::render(Renderer &renderer, const Texture2D &src, const Texture2D &) { BindRestore bind_fbo(target[i]->get_framebuffer()); Renderer::Push push2(renderer); - renderer.set_texture(i ? &target[0]->get_target_texture(RENDER_COLOR) : &src, &nearest_sampler); + renderer.set_texture("source", (i ? &target[0]->get_target_texture(RENDER_COLOR) : &src), &nearest_sampler); renderer.add_shader_data(blur_shdata[i]); quad.draw(renderer); } - combine_texturing.attach(0, src, &nearest_sampler); - renderer.set_texturing(&combine_texturing); + renderer.set_texture("source", &src, &nearest_sampler); + renderer.set_texture("blurred", &target[1]->get_target_texture(RENDER_COLOR), &linear_sampler); renderer.set_shader_program(&combine_shader); quad.draw(renderer); } diff --git a/source/effects/bloom.h b/source/effects/bloom.h index 27584886..f2d9db7f 100644 --- a/source/effects/bloom.h +++ b/source/effects/bloom.h @@ -5,7 +5,6 @@ #include "mesh.h" #include "postprocessor.h" #include "texture2d.h" -#include "texturing.h" #include "program.h" #include "programdata.h" #include "rendertarget.h" @@ -49,7 +48,6 @@ private: const Mesh &quad; const Sampler &nearest_sampler; const Sampler &linear_sampler; - Texturing combine_texturing; public: Bloom(Resources &, unsigned, unsigned); diff --git a/source/effects/colorcurve.cpp b/source/effects/colorcurve.cpp index 7b8c63b0..130fa8df 100644 --- a/source/effects/colorcurve.cpp +++ b/source/effects/colorcurve.cpp @@ -18,11 +18,7 @@ ColorCurve::ColorCurve(Resources &resources): linear_sampler(resources.get("_linear_clamp.samp")), nearest_sampler(resources.get("_nearest_clamp.samp")) { - shdata.uniform("source", 0); - shdata.uniform("curve", 1); - curve.storage(LUMINANCE8, 256, 1); - texturing.attach(1, curve, &linear_sampler); set_exposure_adjust(0.0f); set_brightness_response(0.4f); @@ -72,11 +68,10 @@ void ColorCurve::set_linear() void ColorCurve::render(Renderer &renderer, const Texture2D &color_buf, const Texture2D &) { - texturing.attach(0, color_buf, &nearest_sampler); - Renderer::Push push(renderer); renderer.set_shader_program(&shprog, &shdata); - renderer.set_texturing(&texturing); + renderer.set_texture("source", &color_buf, &nearest_sampler); + renderer.set_texture("curve", &curve, &linear_sampler); quad.draw(renderer); } diff --git a/source/effects/colorcurve.h b/source/effects/colorcurve.h index b99bb14e..e34834aa 100644 --- a/source/effects/colorcurve.h +++ b/source/effects/colorcurve.h @@ -5,7 +5,6 @@ #include "program.h" #include "programdata.h" #include "texture1d.h" -#include "texturing.h" namespace Msp { namespace GL { @@ -48,7 +47,6 @@ private: const Program &shprog; ProgramData shdata; Texture1D curve; - Texturing texturing; const Mesh &quad; const Sampler &linear_sampler; const Sampler &nearest_sampler; diff --git a/source/effects/environmentmap.cpp b/source/effects/environmentmap.cpp index 977822ac..1448c49c 100644 --- a/source/effects/environmentmap.cpp +++ b/source/effects/environmentmap.cpp @@ -106,14 +106,10 @@ void EnvironmentMap::render(Renderer &renderer, Tag tag) const Renderer::Push _push_rend(renderer); - unsigned unit = renderer.allocate_effect_texunit(); - shdata.uniform("environment_map", static_cast(unit)); - Bind _bind_sampler(sampler, unit); - Bind _bind_env(env_tex, unit); - const Matrix &camera_matrix = renderer.get_camera()->get_object_matrix(); shdata.uniform("env_eye_matrix", camera_matrix.block<3, 3>(0, 0)); + renderer.set_texture("environment_map", &env_tex, &sampler); renderer.add_shader_data(shdata); renderer.render(renderable, tag); } diff --git a/source/effects/shadowmap.cpp b/source/effects/shadowmap.cpp index e43e9bde..41a97f80 100644 --- a/source/effects/shadowmap.cpp +++ b/source/effects/shadowmap.cpp @@ -93,15 +93,6 @@ void ShadowMap::render(Renderer &renderer, Tag tag) const if(!enabled_passes.count(tag)) return renderer.render(renderable, tag); - Renderer::Push _push_rend(renderer); - - unsigned unit = renderer.allocate_effect_texunit(); - int iunit = unit; - shdata.uniform("shadow_map", iunit); - - Bind _bind_sampler(sampler, unit); - Bind _bind_depth(depth_buf, unit); - if(const Camera *camera = renderer.get_camera()) /* Multiply by camera's object matrix to form a matrix that transforms from eye space to shadow space. */ @@ -109,6 +100,9 @@ void ShadowMap::render(Renderer &renderer, Tag tag) const else shdata.uniform("shd_eye_matrix", shadow_matrix); + Renderer::Push _push_rend(renderer); + + renderer.set_texture("shadow_map", &depth_buf, &sampler); renderer.add_shader_data(shdata); renderer.render(renderable, tag); } diff --git a/source/materials/basicmaterial.cpp b/source/materials/basicmaterial.cpp index 33dced53..5ad694b6 100644 --- a/source/materials/basicmaterial.cpp +++ b/source/materials/basicmaterial.cpp @@ -5,6 +5,17 @@ using namespace std; namespace Msp { namespace GL { +const Tag BasicMaterial::texture_tags[] = +{ + Tag("diffuse_map"), + Tag("specular_map"), + Tag("shininess_map"), + Tag("normal_map"), + Tag("emission_map"), + Tag("reflectivity_map"), + Tag() +}; + BasicMaterial::BasicMaterial(): receive_shadows(false) { @@ -32,6 +43,8 @@ void BasicMaterial::fill_program_info(string &module_name, map &spe spec_values["use_shadow_map"] = receive_shadows; } +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" void BasicMaterial::attach_textures_to(Texturing &texturing, ProgramData &tex_shdata) const { attach_texture_to(diffuse.texture, texturing, tex_shdata, "diffuse_map"); @@ -41,6 +54,25 @@ void BasicMaterial::attach_textures_to(Texturing &texturing, ProgramData &tex_sh attach_texture_to(shininess.texture, texturing, tex_shdata, "shininess_map"); attach_texture_to(reflectivity.texture, texturing, tex_shdata, "reflectivity_map"); } +#pragma GCC diagnostic pop + +const Texture *BasicMaterial::get_texture(Tag tag) const +{ + if(tag==texture_tags[0]) + return diffuse.texture; + else if(tag==texture_tags[1]) + return specular.texture; + else if(tag==texture_tags[2]) + return shininess.texture; + else if(tag==texture_tags[3]) + return normal.texture; + else if(tag==texture_tags[4]) + return emission.texture; + else if(tag==texture_tags[5]) + return reflectivity.texture; + else + return 0; +} void BasicMaterial::set_diffuse(const Color &color) { diff --git a/source/materials/basicmaterial.h b/source/materials/basicmaterial.h index ef7d1526..2b27b212 100644 --- a/source/materials/basicmaterial.h +++ b/source/materials/basicmaterial.h @@ -31,6 +31,8 @@ private: Property reflectivity; bool receive_shadows; + static const Tag texture_tags[]; + public: BasicMaterial(); @@ -38,7 +40,10 @@ protected: virtual void fill_program_info(std::string &, std::map &) const; public: - virtual void attach_textures_to(Texturing &, ProgramData &) const; + DEPRECATED virtual void attach_textures_to(Texturing &, ProgramData &) const; + + virtual const Tag *get_texture_tags() const { return texture_tags; } + virtual const Texture *get_texture(Tag) const; void set_diffuse(const Color &); void set_diffuse_map(const Texture *); diff --git a/source/materials/material.cpp b/source/materials/material.cpp index eaabad15..3eaf83ab 100644 --- a/source/materials/material.cpp +++ b/source/materials/material.cpp @@ -43,6 +43,8 @@ const Program *Material::create_compatible_shader(DataFile::Collection &coll) co return shprog; } +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" void Material::attach_texture_to(const Texture *tex, Texturing &texturing, ProgramData &tex_shdata, const string &name) const { if(!tex) @@ -62,6 +64,7 @@ void Material::attach_texture_to(const Texture *tex, Texturing &texturing, Progr texturing.attach(unit, *tex, sampler); tex_shdata.uniform(name, unit); } +#pragma GCC diagnostic pop Material::MaterialRegistry &Material::get_material_registry() { diff --git a/source/materials/material.h b/source/materials/material.h index 727c61b7..a04e7458 100644 --- a/source/materials/material.h +++ b/source/materials/material.h @@ -105,9 +105,13 @@ public: const ProgramData &get_shader_data() const { return shdata; } protected: - void attach_texture_to(const Texture *, Texturing &, ProgramData &, const std::string &) const; + DEPRECATED void attach_texture_to(const Texture *, Texturing &, ProgramData &, const std::string &) const; public: - virtual void attach_textures_to(Texturing &, ProgramData &) const = 0; + DEPRECATED virtual void attach_textures_to(Texturing &, ProgramData &) const = 0; + + virtual const Tag *get_texture_tags() const = 0; + virtual const Texture *get_texture(Tag) const = 0; + const Sampler *get_sampler() const { return sampler; } template static void register_type(const std::string &); diff --git a/source/materials/pbrmaterial.cpp b/source/materials/pbrmaterial.cpp index 16c287b4..92801204 100644 --- a/source/materials/pbrmaterial.cpp +++ b/source/materials/pbrmaterial.cpp @@ -5,6 +5,17 @@ using namespace std; namespace Msp { namespace GL { +const Tag PbrMaterial::texture_tags[] = +{ + Tag("base_color_map"), + Tag("normal_map"), + Tag("metalness_map"), + Tag("roughness_map"), + Tag("occlusion_map"), + Tag("emission_map"), + Tag() +}; + PbrMaterial::PbrMaterial(): receive_shadows(false) { @@ -28,6 +39,8 @@ void PbrMaterial::fill_program_info(string &module_name, map &spec_ spec_values["use_shadow_map"] = receive_shadows; } +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" void PbrMaterial::attach_textures_to(Texturing &texturing, ProgramData &tex_shdata) const { attach_texture_to(base_color.texture, texturing, tex_shdata, "base_color_map"); @@ -37,6 +50,25 @@ void PbrMaterial::attach_textures_to(Texturing &texturing, ProgramData &tex_shda attach_texture_to(occlusion.texture, texturing, tex_shdata, "occlusion_map"); attach_texture_to(emission.texture, texturing, tex_shdata, "emission_map"); } +#pragma GCC diagnostic pop + +const Texture *PbrMaterial::get_texture(Tag tag) const +{ + if(tag==texture_tags[0]) + return base_color.texture; + else if(tag==texture_tags[1]) + return normal.texture; + else if(tag==texture_tags[2]) + return metalness.texture; + else if(tag==texture_tags[3]) + return roughness.texture; + else if(tag==texture_tags[4]) + return occlusion.texture; + else if(tag==texture_tags[5]) + return emission.texture; + else + return 0; +} void PbrMaterial::set_base_color(const Color &color) { diff --git a/source/materials/pbrmaterial.h b/source/materials/pbrmaterial.h index a1f736f4..00e5e1ba 100644 --- a/source/materials/pbrmaterial.h +++ b/source/materials/pbrmaterial.h @@ -31,6 +31,8 @@ private: Property emission; bool receive_shadows; + static const Tag texture_tags[]; + public: PbrMaterial(); @@ -38,7 +40,10 @@ protected: virtual void fill_program_info(std::string &, std::map &) const; public: - virtual void attach_textures_to(Texturing &, ProgramData &) const; + DEPRECATED virtual void attach_textures_to(Texturing &, ProgramData &) const; + + virtual const Tag *get_texture_tags() const { return texture_tags; } + virtual const Texture *get_texture(Tag) const; void set_base_color(const Color &); void set_base_color_map(const Texture *); diff --git a/source/materials/renderpass.cpp b/source/materials/renderpass.cpp index 7431a446..702bddea 100644 --- a/source/materials/renderpass.cpp +++ b/source/materials/renderpass.cpp @@ -1,8 +1,8 @@ +#include #include #include #include #include "error.h" -#include "material.h" #include "renderpass.h" #include "program.h" #include "programdata.h" @@ -10,6 +10,7 @@ #include "texture.h" #include "texture2d.h" #include "texturing.h" +#include "uniform.h" using namespace std; @@ -21,49 +22,17 @@ RenderPass::RenderPass(): shprog_from_material(false), shdata(0), material(0), - texturing(0), back_faces(false) { } -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), - material_slot(other.material_slot), - texturing(other.texturing ? new Texturing(*other.texturing) : 0), - tex_names(other.tex_names), - back_faces(other.back_faces) -{ } - -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; - material_slot = other.material_slot; - texturing = other.texturing ? new Texturing(*other.texturing) : 0; - tex_names = other.tex_names; - back_faces = other.back_faces; - return *this; -} - -RenderPass::~RenderPass() -{ - delete texturing; -} - void RenderPass::finalize_material(DataFile::Collection *coll) { maybe_create_material_shader(coll); ensure_private_shader_data(); - if(!texturing) - texturing = new Texturing; - material->attach_textures_to(*texturing, *shdata); + const Tag *material_texture_tags = material->get_texture_tags(); + for(const Tag *tag=material_texture_tags; tag->id; ++tag) + set_texture(*tag, material->get_texture(*tag), material->get_sampler()); } void RenderPass::maybe_create_material_shader(DataFile::Collection *coll) @@ -121,25 +90,60 @@ void RenderPass::set_material(const Material *mat, DataFile::Collection *coll) finalize_material(coll); } +void RenderPass::set_texture(Tag tag, const Texture *tex, const Sampler *samp) +{ + vector::iterator i = find_member(textures, tag, &TextureSlot::tag); + if(i==textures.end()) + { + textures.push_back(TextureSlot(tag)); + i = textures.end()-1; + } + i->texture = tex; + if(samp) + i->sampler = samp; +} + +Tag RenderPass::get_texture_tag(const string &slot) const +{ + vector::const_iterator i = find_member(textures, slot, &TextureSlot::slot_name); + return (i!=textures.end() ? i->tag : Tag()); +} + void RenderPass::set_texture(unsigned index, const Texture *tex, const Sampler *samp) { - if(!texturing) - texturing = new Texturing; + if(!shprog) + throw invalid_operation("RenderPass::set_texture"); + + const vector &uniforms = shprog->get_uniforms(); + for(vector::const_iterator i=uniforms.begin(); i!=uniforms.end(); ++i) + if(is_image(i->type) && i->binding==static_cast(index)) + return set_texture(i->tag, tex, samp); - texturing->attach(index, *tex, (samp ? samp : texturing->get_attached_sampler(index))); + if(shdata) + { + const vector &tags = shdata->get_uniform_tags(); + for(vector::const_iterator i=tags.begin(); i!=tags.end(); ++i) + { + vector::const_iterator j = find_member(uniforms, *i, &Program::UniformInfo::tag); + if(j==uniforms.end() || !is_image(j->type)) + continue; + if(const Uniform1i *uni1i = dynamic_cast(shdata->find_uniform(*i))) + if(uni1i->get()==static_cast(index)) + return set_texture(*i, tex, samp); + } + } } int RenderPass::get_texture_index(const string &n) const { - map::const_iterator i = tex_names.find(n); - if(i==tex_names.end()) - return -1; - return i->second; + vector::const_iterator i = find_member(textures, n, &TextureSlot::slot_name); + return (shprog && i!=textures.end() ? shprog->get_uniform_binding(i->tag) : -1); } void RenderPass::apply(Renderer &renderer) const { - renderer.set_texturing(texturing); + for(vector::const_iterator i=textures.begin(); i!=textures.end(); ++i) + renderer.set_texture(i->tag, i->texture, i->sampler); renderer.set_material(material.get()); renderer.set_shader_program(shprog.get(), shdata.get()); renderer.set_reverse_winding(back_faces); @@ -165,12 +169,15 @@ void RenderPass::Loader::init() add("material", &Loader::material); add("material_slot", &RenderPass::material_slot); add("back_faces",&RenderPass::back_faces); - add("texunit", &Loader::texunit); - add("texunit", &Loader::texunit_auto); - add("texunit", &Loader::texunit_named); + add("texture", &Loader::texture); add("uniforms", &Loader::uniforms); add("uniform_slot", &Loader::uniform_slot); add("uniform_slot", &Loader::uniform_slot2); + + // Deprecated + add("texunit", &Loader::texunit); + add("texunit", &Loader::texture); + add("texunit", &Loader::texunit_named); } // Temporary compatibility feature @@ -210,30 +217,46 @@ void RenderPass::Loader::shader(const string &n) obj.finalize_material(coll); } -void RenderPass::Loader::texunit(unsigned i) +void RenderPass::Loader::texture(const string &n) { - if(!obj.texturing) - obj.texturing = new Texturing; - TextureLoader ldr(*obj.texturing, i, coll); + vector::iterator i = find_member(obj.textures, Tag(n), &TextureSlot::tag); + if(i==obj.textures.end()) + { + obj.textures.push_back(TextureSlot(n)); + i = obj.textures.end()-1; + } + TextureSlot::Loader ldr(*i, n, coll); load_sub_with(ldr); } -void RenderPass::Loader::texunit_auto(const string &n) +void RenderPass::Loader::texunit(unsigned) { - if(!obj.texturing) - obj.texturing = new Texturing; - int i = obj.texturing->find_free_unit(n); - if(i<0) - throw runtime_error("no free texunit"); - texunit_named(i, n); + IO::print(IO::cerr, "Warning: specifying textures by unit number is deprecated and may not produce expected results"); + string name; + if(obj.shprog) + { + const vector &uniforms = obj.shprog->get_uniforms(); + for(vector::const_iterator i=uniforms.begin(); i!=uniforms.end(); ++i) + if(is_image(i->type) && i->binding>=0) + { + if(!name.empty()) + { + name.clear(); + break; + } + name = i->name; + } + } + + if(name.empty()) + throw runtime_error("Could not determine name for texture"); + + texture(name); } -void RenderPass::Loader::texunit_named(unsigned i, const string &n) +void RenderPass::Loader::texunit_named(unsigned, const string &n) { - texunit(i); - obj.tex_names[n] = i; - obj.ensure_private_shader_data(); - obj.shdata->uniform(n, static_cast(i)); + texture(n); } void RenderPass::Loader::uniforms() @@ -253,32 +276,19 @@ void RenderPass::Loader::uniform_slot2(const string &name, const string &slot) } -RenderPass::TextureLoader::TextureLoader(Texturing &t, unsigned i, Collection *c): - DataFile::CollectionObjectLoader(t, c), - index(i), - tex(0), - samp(0) -{ - add("sampler", &TextureLoader::sampler); - add("texture", &TextureLoader::texture); -} - -void RenderPass::TextureLoader::finish() -{ - if(tex) - obj.attach(index, *tex, samp); - else if(samp) - obj.attach(index, *samp); -} - -void RenderPass::TextureLoader::sampler(const string &name) +RenderPass::TextureSlot::Loader::Loader(TextureSlot &ts, const string &an, Collection *c): + CollectionObjectLoader(ts, c), + auto_slot_name(an) { - samp = &get_collection().get(name); + add("sampler", &TextureSlot::sampler); + add("slot", &Loader::slot_auto); + add("slot", &TextureSlot::slot_name); + add("texture", &TextureSlot::texture); } -void RenderPass::TextureLoader::texture(const string &name) +void RenderPass::TextureSlot::Loader::slot_auto() { - tex = &get_collection().get(name); + obj.slot_name = auto_slot_name; } } // namespace GL diff --git a/source/materials/renderpass.h b/source/materials/renderpass.h index 0e8ccdf2..8a69ad12 100644 --- a/source/materials/renderpass.h +++ b/source/materials/renderpass.h @@ -3,11 +3,11 @@ #include #include +#include "material.h" namespace Msp { namespace GL { -class Material; class Program; class ProgramData; class Renderer; @@ -36,8 +36,8 @@ public: void material_inline(); void material(const std::string &); void shader(const std::string &); + void texture(const std::string &); void texunit(unsigned); - void texunit_auto(const std::string &); void texunit_named(unsigned, const std::string &); void uniforms(); void uniform_slot(const std::string &); @@ -45,20 +45,26 @@ public: }; private: - struct TextureLoader: public DataFile::CollectionObjectLoader + struct TextureSlot { - private: - unsigned index; - const Texture *tex; - const Sampler *samp; + class Loader: public DataFile::CollectionObjectLoader + { + private: + std::string auto_slot_name; - public: - TextureLoader(Texturing &, unsigned, Collection *); - private: - virtual void finish(); + public: + Loader(TextureSlot &, const std::string &, Collection *); - void sampler(const std::string &); - void texture(const std::string &); + private: + void slot_auto(); + }; + + Tag tag; + std::string slot_name; + const Texture *texture; + const Sampler *sampler; + + TextureSlot(Tag t): tag(t), texture(0), sampler(0) { } }; RefPtr shprog; @@ -67,15 +73,11 @@ private: std::map uniform_slots; RefPtr material; std::string material_slot; - Texturing *texturing; - std::map tex_names; + std::vector textures; bool back_faces; public: RenderPass(); - RenderPass(const RenderPass &); - RenderPass &operator=(const RenderPass &); - ~RenderPass(); private: void finalize_material(DataFile::Collection *); @@ -90,9 +92,11 @@ public: void set_material(const Material *, DataFile::Collection * = 0); const Material *get_material() const { return material.get(); } const std::string &get_material_slot_name() const { return material_slot; } - void set_texture(unsigned, const Texture *, const Sampler * = 0); - const Texturing *get_texturing() const { return texturing; } - int get_texture_index(const std::string &) const; + void set_texture(Tag, const Texture *, const Sampler * = 0); + Tag get_texture_tag(const std::string &) const; + DEPRECATED void set_texture(unsigned, const Texture *, const Sampler * = 0); + DEPRECATED const Texturing *get_texturing() const { return 0; } + DEPRECATED int get_texture_index(const std::string &) const; void set_back_faces(bool); bool get_back_faces() const { return back_faces; } diff --git a/source/materials/technique.cpp b/source/materials/technique.cpp index a382376e..12111e5e 100644 --- a/source/materials/technique.cpp +++ b/source/materials/technique.cpp @@ -39,10 +39,10 @@ bool Technique::replace_texture(const string &slot, const Texture &tex) bool replaced = false; for(PassMap::iterator i=passes.begin(); i!=passes.end(); ++i) { - int index = i->second.get_texture_index(slot); - if(index>=0) + Tag tag = i->second.get_texture_tag(slot); + if(tag.id) { - i->second.set_texture(index, &tex); + i->second.set_texture(tag, &tex); replaced = true; } } diff --git a/source/materials/unlitmaterial.cpp b/source/materials/unlitmaterial.cpp index e81be8ae..38dbd3a3 100644 --- a/source/materials/unlitmaterial.cpp +++ b/source/materials/unlitmaterial.cpp @@ -5,6 +5,12 @@ using namespace std; namespace Msp { namespace GL { +const Tag UnlitMaterial::texture_tags[] = +{ + Tag("color_tex"), + Tag() +}; + UnlitMaterial::UnlitMaterial(): texture(0), vertex_color(false) @@ -19,10 +25,21 @@ void UnlitMaterial::fill_program_info(string &module_name, map &spe spec_values["use_vertex_color"] = vertex_color; } +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" void UnlitMaterial::attach_textures_to(Texturing &texturing, ProgramData &tex_shdata) const { attach_texture_to(texture, texturing, tex_shdata, "color_tex"); } +#pragma GCC diagnostic pop + +const Texture *UnlitMaterial::get_texture(Tag tag) const +{ + if(tag==texture_tags[0]) + return texture; + else + return 0; +} void UnlitMaterial::set_texture(const Texture *tex) { diff --git a/source/materials/unlitmaterial.h b/source/materials/unlitmaterial.h index a98b1284..442348da 100644 --- a/source/materials/unlitmaterial.h +++ b/source/materials/unlitmaterial.h @@ -29,6 +29,8 @@ private: Color color; bool vertex_color; + static const Tag texture_tags[]; + public: UnlitMaterial(); @@ -36,7 +38,13 @@ protected: virtual void fill_program_info(std::string &, std::map &) const; public: - virtual void attach_textures_to(Texturing &, ProgramData &) const; +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + DEPRECATED virtual void attach_textures_to(Texturing &, ProgramData &) const; +#pragma GCC diagnostic pop + + virtual const Tag *get_texture_tags() const { return texture_tags; } + virtual const Texture *get_texture(Tag) const; void set_texture(const Texture *); void set_color(const Color &); diff --git a/source/render/programdata.cpp b/source/render/programdata.cpp index ec273c22..0f641a4a 100644 --- a/source/render/programdata.cpp +++ b/source/render/programdata.cpp @@ -154,7 +154,11 @@ bool ProgramData::validate_tag(Tag tag) const #endif { if(tied_program) - tied_program->get_uniform_info(tag); + { + const Program::UniformInfo &info = tied_program->get_uniform_info(tag); + if(is_image(info.type)) + throw invalid_operation("ProgramData::uniform"); + } return true; } #ifdef DEBUG @@ -608,8 +612,12 @@ void ProgramData::update_block(SharedBlock &block, const Program::UniformBlockIn { const UInt8 *indices = block.get_uniform_indices(); for(unsigned i=0; itype)) + ; // Temporarily ignore deprecated use of sampler uniforms in ProgramData + else if(indices[i]!=0xFF) block.block->attach(*info.uniforms[i], *uniforms[indices[i]].value); + } } void ProgramData::apply() const diff --git a/source/render/renderer.cpp b/source/render/renderer.cpp index ad7ba5a7..03653edc 100644 --- a/source/render/renderer.cpp +++ b/source/render/renderer.cpp @@ -74,19 +74,76 @@ void Renderer::transform(const Matrix &matrix) changed |= MATRIX; } +void Renderer::set_texture(Tag tag, const Texture *tex, const Sampler *samp) +{ + set_texture(tag, -1, tex, samp); +} + +void Renderer::set_texture(Tag tag, int unit, const Texture *tex, const Sampler *samp) +{ + if(texture_stack.size()>state->texture_count) + { + BoundTexture &bt = texture_stack[state->texture_count]; + if((!tag.id || bt.tag==tag) && (unit<0 || bt.unit==unit) && bt.texture==tex && bt.sampler==samp) + { + ++state->texture_count; + return; + } + else + flush_textures(); + } + + for(vector::iterator i=texture_stack.end(); i!=texture_stack.begin(); ) + if((--i)->tag==tag && i->unit==unit) + { + i->replaced = texture_stack.size(); + break; + } + + texture_stack.push_back(BoundTexture()); + BoundTexture &bound_tex = texture_stack.back(); + bound_tex.tag = tag; + bound_tex.unit = unit; + bound_tex.texture = tex; + bound_tex.sampler = samp; + state->texture_count = texture_stack.size(); +} + void Renderer::set_texture(const Texture *t, const Sampler *s) { - state->texture = t; - state->sampler = s; - state->texturing = 0; + set_texture(Tag(), 0, t, s); } +void Renderer::flush_textures() +{ + for(unsigned i=0; i=state->texture_count && bt.unit>=0) + { + Texture::unbind_from(bt.unit); + Sampler::unbind_from(bt.unit); + } + else if(bt.replaced>=static_cast(state->texture_count)) + bt.replaced = -1; + } + + texture_stack.erase(texture_stack.begin()+state->texture_count, texture_stack.end()); +} + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" void Renderer::set_texturing(const Texturing *t) { - state->texturing = t; - state->texture = 0; - state->sampler = 0; + if(t) + { + unsigned n_units = TexUnit::get_n_units(); + for(unsigned i=0; iget_attached_texture(i)) + set_texture(Tag(), i, tex, t->get_attached_sampler(i)); + } } +#pragma GCC diagnostic pop unsigned Renderer::allocate_effect_texunit() { @@ -233,8 +290,12 @@ void Renderer::end() shdata_stack.clear(); excluded.clear(); - Texturing::unbind(); - Texture::unbind_from(0); + for(vector::iterator i=texture_stack.begin(); i!=texture_stack.end(); ++i) + if(i->unit>=0) + { + Texture::unbind_from(i->unit); + Sampler::unbind_from(i->unit); + } Clipping::unbind(); Program::unbind(); VertexSetup::unbind(); @@ -280,21 +341,20 @@ void Renderer::apply_state() /* We (mostly) let the objects themselves figure out if the binding has changed */ - if(state->texturing) - state->texturing->bind(); - else + if(state->texture_count::const_iterator i=texture_stack.begin(); i!=texture_stack.end(); ++i) { - Texturing::unbind(); - if(state->texture) + int unit = (i->tag.id ? state->shprog->get_uniform_binding(i->tag) : i->unit); + if(unit>=0) { - if(state->sampler) - state->sampler->bind_to(0); - else - Sampler::unbind_from(0); - state->texture->bind_to(0); + if(i->texture) + i->texture->bind_to(unit); + if(i->sampler) + i->sampler->bind_to(unit); + i->unit = unit; } - else - Texture::unbind_from(0); } if(state->clipping) @@ -354,10 +414,17 @@ void Renderer::apply_state() } +Renderer::BoundTexture::BoundTexture(): + unit(-1), + texture(0), + sampler(0), + replaced(-1) +{ } + + Renderer::State::State(): camera(0), - texture(0), - texturing(0), + texture_count(0), lowest_effect_texunit(TexUnit::get_n_units()), material(0), lighting(0), diff --git a/source/render/renderer.h b/source/render/renderer.h index f8d29728..60386607 100644 --- a/source/render/renderer.h +++ b/source/render/renderer.h @@ -64,13 +64,22 @@ public: }; private: + struct BoundTexture + { + Tag tag; + mutable int unit; + const Texture *texture; + const Sampler *sampler; + int replaced; + + BoundTexture(); + }; + struct State { const Camera *camera; Matrix modelview_matrix; - const Texture *texture; - const Sampler *sampler; - const Texturing *texturing; + unsigned texture_count; unsigned lowest_effect_texunit; const Material *material; const Lighting *lighting; @@ -99,6 +108,7 @@ private: unsigned char changed; std::vector state_stack; State *state; + std::vector texture_stack; ProgramData standard_shdata; std::vector shdata_stack; std::set excluded; @@ -126,9 +136,17 @@ public: /** Returns the current modelview matrix. */ const Matrix &get_matrix() const { return state->modelview_matrix; } - void set_texture(const Texture *, const Sampler * = 0); - void set_texturing(const Texturing *); - unsigned allocate_effect_texunit(); + void set_texture(Tag, const Texture *, const Sampler * = 0); +private: + void set_texture(Tag, int, const Texture *, const Sampler *); + void flush_textures(); +public: +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + DEPRECATED void set_texture(const Texture *, const Sampler * = 0); + DEPRECATED void set_texturing(const Texturing *); + DEPRECATED unsigned allocate_effect_texunit(); +#pragma GCC diagnostic pop void set_material(const Material *); void set_lighting(const Lighting *); diff --git a/source/render/texturing.cpp b/source/render/texturing.cpp index be24d5d7..341cdb79 100644 --- a/source/render/texturing.cpp +++ b/source/render/texturing.cpp @@ -5,6 +5,8 @@ using namespace std; +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + namespace Msp { namespace GL { diff --git a/source/render/texturing.h b/source/render/texturing.h index 0da3eae4..44189c90 100644 --- a/source/render/texturing.h +++ b/source/render/texturing.h @@ -9,7 +9,7 @@ namespace GL { class Texture; -class Texturing: public Bindable +class DEPRECATED Texturing: public Bindable { private: struct Attachment