]> git.tdb.fi Git - libs/gl.git/blob - source/materials/technique.cpp
Some more cleanup of includes and forward declarations
[libs/gl.git] / source / materials / technique.cpp
1 #include <msp/core/refptr.h>
2 #include <msp/datafile/collection.h>
3 #include <msp/fs/utils.h>
4 #include <msp/strings/format.h>
5 #include "material.h"
6 #include "programdata.h"
7 #include "technique.h"
8 #include "texture.h"
9
10 using namespace std;
11
12 namespace Msp {
13 namespace GL {
14
15 RenderPass &Technique::add_pass(Tag tag)
16 {
17         return insert_unique(passes, tag, RenderPass())->second;
18 }
19
20 bool Technique::has_pass(Tag tag) const
21 {
22         return passes.count(tag);
23 }
24
25 const RenderPass &Technique::get_pass(Tag tag) const
26 {
27         return get_item(passes, tag);
28 }
29
30 const RenderPass *Technique::find_pass(Tag tag) const
31 {
32         auto i = passes.find(tag);
33         return (i!=passes.end() ? &i->second : 0);
34 }
35
36 bool Technique::replace_texture(const string &slot, const Texture &tex)
37 {
38         bool replaced = false;
39         for(auto &kvp: passes)
40         {
41                 Tag tag = kvp.second.get_texture_tag(slot);
42                 if(tag.id)
43                 {
44                         kvp.second.set_texture(tag, &tex);
45                         replaced = true;
46                 }
47         }
48
49         return replaced;
50 }
51
52 bool Technique::replace_material(const string &slot, const Material &mat)
53 {
54         bool replaced = false;
55         for(auto &kvp: passes)
56         {
57                 const string &pass_slot = kvp.second.get_material_slot_name();
58                 if(!pass_slot.empty() && pass_slot==slot)
59                 {
60                         kvp.second.set_material(&mat);
61                         replaced = true;
62                 }
63         }
64
65         return replaced;
66 }
67
68 bool Technique::replace_uniforms(const ProgramData &shdata)
69 {
70         bool replaced = false;
71         const vector<Tag> &uniform_tags = shdata.get_uniform_tags();
72         for(auto &kvp: passes)
73         {
74                 RefPtr<ProgramData> new_shdata;
75                 for(Tag t: uniform_tags)
76                 {
77                         Tag tag = kvp.second.get_slotted_uniform_tag(t);
78                         if(!tag.id)
79                                 continue;
80
81                         if(!new_shdata)
82                                 new_shdata = new ProgramData(*kvp.second.get_shader_data());
83
84                         new_shdata->copy_uniform(shdata, tag);
85                         replaced = true;
86                 }
87
88                 if(new_shdata)
89                         kvp.second.set_shader_program(kvp.second.get_shader_program(), new_shdata.get());
90         }
91
92         return replaced;
93 }
94
95 bool Technique::has_shaders() const
96 {
97         for(const auto &kvp: passes)
98                 if(kvp.second.get_shader_program())
99                         return true;
100         return false;
101 }
102
103 void Technique::set_debug_name(const string &name)
104 {
105 #ifdef DEBUG
106         for(auto &kvp: passes)
107                 kvp.second.set_debug_name(format("%s [pass:%s]", name, kvp.first.str()));
108 #else
109         (void)name;
110 #endif
111 }
112
113
114 DataFile::Loader::ActionMap Technique::Loader::shared_actions;
115
116 Technique::Loader::Loader(Technique &t):
117         DataFile::CollectionObjectLoader<Technique>(t, 0)
118 {
119         set_actions(shared_actions);
120 }
121
122 Technique::Loader::Loader(Technique &t, Collection &c):
123         DataFile::CollectionObjectLoader<Technique>(t, &c)
124 {
125         set_actions(shared_actions);
126 }
127
128 void Technique::Loader::init_actions()
129 {
130         add("inherit", &Loader::inherit);
131         add("pass", &Loader::pass);
132 }
133
134 void Technique::Loader::set_inline_base_name(const string &n)
135 {
136         inline_base_name = n;
137 }
138
139 void Technique::Loader::inherit(const string &n)
140 {
141         obj.passes = get_collection().get<Technique>(n).get_passes();
142         InheritLoader ldr(obj, get_collection());
143         load_sub_with(ldr);
144 }
145
146 void Technique::Loader::pass(const string &n)
147 {
148         RenderPass p;
149         if(coll)
150         {
151                 RenderPass::Loader ldr(p, get_collection());
152                 ldr.set_inline_base_name(format("%s/%s.pass", (inline_base_name.empty() ? FS::basename(get_source()) : inline_base_name), n));
153                 load_sub_with(ldr);
154         }
155         else
156                 load_sub(p);
157
158         if(!p.get_shader_program())
159                 throw logic_error("no shader program in pass");
160
161         insert_unique(obj.passes, n, p);
162 }
163
164
165 Technique::InheritLoader::InheritLoader(Technique &t, Collection &c):
166         DataFile::CollectionObjectLoader<Technique>(t, &c)
167 {
168         add("material", &InheritLoader::material);
169         add("texture", &InheritLoader::texture);
170         add("uniforms", &InheritLoader::uniforms);
171 }
172
173 void Technique::InheritLoader::material(const string &slot, const string &name)
174 {
175         const Material &mat = get_collection().get<Material>(name);
176         if(obj.replace_material(slot, mat))
177                 return;
178
179         // For backwards compatibility
180         RenderPass &pass = get_item(obj.passes, slot);
181         if(const Material *base_mat = pass.get_material())
182         {
183                 for(auto &kvp: obj.passes)
184                         if(kvp.second.get_material()==base_mat)
185                                 kvp.second.set_material(&mat);
186         }
187         else
188                 pass.set_material(&mat);
189 }
190
191 void Technique::InheritLoader::texture(const string &slot, const string &name)
192 {
193         if(!obj.replace_texture(slot, get_collection().get<Texture>(name)))
194                 throw key_error(slot);
195 }
196
197 void Technique::InheritLoader::uniforms()
198 {
199         ProgramData shdata;
200         load_sub(shdata);
201         obj.replace_uniforms(shdata);
202 }
203
204 } // namespace GL
205 } // namespace Msp