]> git.tdb.fi Git - libs/gl.git/blob - source/renderpass.cpp
Improve allocation handling in cube map textures
[libs/gl.git] / source / renderpass.cpp
1 #include <msp/datafile/collection.h>
2 #include <msp/strings/format.h>
3 #include "error.h"
4 #include "material.h"
5 #include "renderpass.h"
6 #include "program.h"
7 #include "programdata.h"
8 #include "renderer.h"
9 #include "texture.h"
10 #include "texture2d.h"
11 #include "texturing.h"
12
13 using namespace std;
14
15 namespace Msp {
16 namespace GL {
17
18 RenderPass::RenderPass():
19         shprog(0),
20         shprog_from_material(false),
21         shdata(0),
22         material(0),
23         texturing(0),
24         back_faces(false)
25 { }
26
27 RenderPass::RenderPass(const RenderPass &other):
28         shprog(other.shprog),
29         shprog_from_material(other.shprog_from_material),
30         shdata(other.shdata),
31         uniform_slots(other.uniform_slots),
32         material(other.material),
33         material_slot(other.material_slot),
34         texturing(other.texturing ? new Texturing(*other.texturing) : 0),
35         tex_names(other.tex_names),
36         back_faces(other.back_faces)
37 { }
38
39 RenderPass &RenderPass::operator=(const RenderPass &other)
40 {
41         shprog = other.shprog;
42         shprog_from_material = other.shprog_from_material;
43         shdata = other.shdata;
44         uniform_slots = other.uniform_slots;
45         material = other.material;
46         material_slot = other.material_slot;
47         texturing = other.texturing ? new Texturing(*other.texturing) : 0;
48         tex_names = other.tex_names;
49         back_faces = other.back_faces;
50         return *this;
51 }
52
53 RenderPass::~RenderPass()
54 {
55         delete texturing;
56 }
57
58 void RenderPass::finalize_material(DataFile::Collection *coll)
59 {
60         maybe_create_material_shader(coll);
61         ensure_private_shader_data();
62
63         if(!texturing)
64                 texturing = new Texturing;
65         material->attach_textures_to(*texturing, *shdata);
66 }
67
68 void RenderPass::maybe_create_material_shader(DataFile::Collection *coll)
69 {
70         if(shprog && !shprog_from_material)
71                 return;
72
73         if(coll)
74         {
75                 shprog = material->create_compatible_shader(*coll);
76                 shprog.keep();
77         }
78         else
79                 shprog = material->create_compatible_shader();
80
81         if(shdata)
82                 shdata = new ProgramData(*shdata, shprog.get());
83
84         shprog_from_material = true;
85 }
86
87 void RenderPass::ensure_private_shader_data()
88 {
89         if(!shprog)
90                 throw invalid_operation("RenderPass::ensure_private_shader_data");
91
92         if(!shdata)
93                 shdata = new ProgramData(shprog.get());
94         else if(shdata.refcount()>1)
95                 shdata = new ProgramData(*shdata);
96 }
97
98 void RenderPass::set_shader_program(const Program *prog, const ProgramData *data)
99 {
100         shprog = prog;
101         shprog.keep();
102         shprog_from_material = false;
103         shdata = (data ? new ProgramData(*data) : 0);
104         if(material)
105                 finalize_material(0);
106 }
107
108 const string &RenderPass::get_slotted_uniform_name(const string &slot) const
109 {
110         map<string, string>::const_iterator i = uniform_slots.find(slot);
111         if(i==uniform_slots.end())
112         {
113                 static string empty;
114                 return empty;
115         }
116         return i->second;
117 }
118
119 void RenderPass::set_material(const Material *mat)
120 {
121         material = mat;
122         material.keep();
123         finalize_material(0);
124 }
125
126 void RenderPass::set_texture(unsigned index, const Texture *tex)
127 {
128         if(!texturing)
129                 texturing = new Texturing;
130
131         texturing->attach(index, *tex);
132 }
133
134 int RenderPass::get_texture_index(const string &n) const
135 {
136         map<string, unsigned>::const_iterator i = tex_names.find(n);
137         if(i==tex_names.end())
138                 return -1;
139         return i->second;
140 }
141
142 void RenderPass::apply(Renderer &renderer) const
143 {
144         renderer.set_texturing(texturing);
145         renderer.set_material(material.get());
146         renderer.set_shader_program(shprog.get(), shdata.get());
147         renderer.set_reverse_winding(back_faces);
148 }
149
150
151 RenderPass::Loader::Loader(RenderPass &p):
152         DataFile::CollectionObjectLoader<RenderPass>(p, 0)
153 {
154         init();
155 }
156
157 RenderPass::Loader::Loader(RenderPass &p, Collection &c):
158         DataFile::CollectionObjectLoader<RenderPass>(p, &c)
159 {
160         init();
161 }
162
163 void RenderPass::Loader::init()
164 {
165         add("shader",   &Loader::shader);
166         add("material", &Loader::material_inline);
167         add("material", &Loader::material);
168         add("material_slot", &RenderPass::material_slot);
169         add("back_faces",&RenderPass::back_faces);
170         add("texunit",  &Loader::texunit);
171         add("texunit",  &Loader::texunit_auto);
172         add("texunit",  &Loader::texunit_named);
173         add("uniforms", &Loader::uniforms);
174         add("uniform_slot", &Loader::uniform_slot);
175         add("uniform_slot", &Loader::uniform_slot2);
176 }
177
178 void RenderPass::Loader::material_inline()
179 {
180         Material::GenericLoader ldr(coll);
181         load_sub_with(ldr);
182         obj.material = ldr.get_material();
183         obj.finalize_material(coll);
184 }
185
186 void RenderPass::Loader::material(const string &name)
187 {
188         obj.material = &get_collection().get<Material>(name);
189         obj.material.keep();
190         obj.finalize_material(coll);
191 }
192
193 void RenderPass::Loader::shader(const string &n)
194 {
195         obj.shprog = &get_collection().get<Program>(n);
196         obj.shprog.keep();
197         obj.shprog_from_material = false;
198         if(obj.shdata)
199                 obj.shdata = new ProgramData(*obj.shdata, obj.shprog.get());
200         if(obj.material)
201                 obj.finalize_material(coll);
202 }
203
204 void RenderPass::Loader::texunit(unsigned i)
205 {
206         if(!obj.texturing)
207                 obj.texturing = new Texturing;
208         TextureLoader ldr(*obj.texturing, i, coll);
209         load_sub_with(ldr);
210 }
211
212 void RenderPass::Loader::texunit_auto(const string &n)
213 {
214         if(!obj.texturing)
215                 obj.texturing = new Texturing;
216         int i = obj.texturing->find_free_unit(n);
217         if(i<0)
218                 throw runtime_error("no free texunit");
219         texunit_named(i, n);
220 }
221
222 void RenderPass::Loader::texunit_named(unsigned i, const string &n)
223 {
224         texunit(i);
225         obj.tex_names[n] = i;
226         obj.ensure_private_shader_data();
227         obj.shdata->uniform(n, static_cast<int>(i));
228 }
229
230 void RenderPass::Loader::uniforms()
231 {
232         obj.ensure_private_shader_data();
233         load_sub(*obj.shdata);
234 }
235
236 void RenderPass::Loader::uniform_slot(const string &name)
237 {
238         uniform_slot2(name, name);
239 }
240
241 void RenderPass::Loader::uniform_slot2(const string &name, const string &slot)
242 {
243         obj.uniform_slots[slot] = name;
244 }
245
246
247 RenderPass::TextureLoader::TextureLoader(Texturing &t, unsigned i, Collection *c):
248         DataFile::CollectionObjectLoader<Texturing>(t, c),
249         index(i)
250 {
251         add("texture",   &TextureLoader::texture);
252 }
253
254 void RenderPass::TextureLoader::texture(const string &name)
255 {
256         obj.attach(index, get_collection().get<Texture>(name));
257 }
258
259 } // namespace GL
260 } // namespace Msp