]> git.tdb.fi Git - libs/gl.git/blob - source/renderpass.cpp
Use texture unit numbers instead of slot names in RenderPass
[libs/gl.git] / source / renderpass.cpp
1 /* $Id$
2
3 This file is part of libmspgl
4 Copyright © 2007  Mikko Rasa, Mikkosoft Productions
5 Distributed under the LGPL
6 */
7
8 #include <msp/core/refptr.h>
9 #include <msp/datafile/collection.h>
10 #include <msp/strings/formatter.h>
11 #include "material.h"
12 #include "renderpass.h"
13 #include "program.h"
14 #include "programdata.h"
15 #include "texture.h"
16 #include "texture2d.h"
17
18 using namespace std;
19
20 namespace Msp {
21 namespace GL {
22
23 RenderPass::RenderPass():
24         shprog(0),
25         shdata(0),
26         material(0)
27 { }
28
29 RenderPass::RenderPass(const RenderPass &other):
30         shprog(other.shprog),
31         shdata(other.shdata ? new ProgramData(*other.shdata) : 0),
32         material(other.material),
33         textures(other.textures)
34 { }
35
36 RenderPass::~RenderPass()
37 {
38         delete shdata;
39 }
40
41 void RenderPass::set_material(const Material *mat)
42 {
43         material = mat;
44 }
45
46 void RenderPass::set_texture(unsigned index, const Texture *tex)
47 {
48         for(vector<TextureSlot>::iterator i=textures.begin(); i!=textures.end(); ++i)
49                 if(i->index==index)
50                 {
51                         i->texture = tex;
52                         i->texture.keep();
53                         return;
54                 }
55
56         throw KeyError("No texture slot for that unit", lexical_cast(index));
57 }
58
59 void RenderPass::bind() const
60 {
61         const RenderPass *old = current();
62         if(!set_current(this))
63                 return;
64
65         if(shprog)
66         {
67                 shprog->bind();
68                 shdata->apply();
69         }
70         else if(old && old->shprog)
71                 GL::Program::unbind();
72
73         if(material)
74                 material->bind();
75         else if(old && old->material)
76                 GL::Material::unbind();
77
78         unsigned used_tex_units = 0;
79         for(vector<TextureSlot>::const_iterator i=textures.begin(); i!=textures.end(); ++i)
80         {
81                 i->texture->bind_to(i->index);
82                 used_tex_units |= 1<<i->index;
83         }
84         if(old)
85         {
86                 for(vector<TextureSlot>::const_iterator i=old->textures.begin(); i!=old->textures.end(); ++i)
87                         if(!used_tex_units&(1<<i->index))
88                                 Texture::unbind_from(i->index);
89         }
90 }
91
92 void RenderPass::unbind()
93 {
94         const RenderPass *old = current();
95         if(!set_current(0))
96                 return;
97
98         if(old->shprog)
99                 GL::Program::unbind();
100
101         if(old->material)
102                 GL::Material::unbind();
103
104         for(unsigned i=old->textures.size(); i--; )
105                 GL::Texture::unbind_from(i);
106 }
107
108
109 RenderPass::TextureSlot::TextureSlot(unsigned i):
110         index(i),
111         texture(0)
112 { }
113
114
115 RenderPass::Loader::Loader(RenderPass &p):
116         DataFile::CollectionObjectLoader<RenderPass>(p, 0)
117 {
118         init();
119 }
120
121 RenderPass::Loader::Loader(RenderPass &p, Collection &c):
122         DataFile::CollectionObjectLoader<RenderPass>(p, &c)
123 {
124         init();
125 }
126
127 void RenderPass::Loader::init()
128 {
129         allow_pointer_reload = false;
130
131         add("shader",   &RenderPass::shprog);
132         add("material", static_cast<void (Loader::*)()>(&Loader::material));
133         add("material", static_cast<void (Loader::*)(const string &)>(&Loader::material));
134         add("texunit",  &Loader::texunit);
135         add("uniforms", &Loader::uniforms);
136 }
137
138 void RenderPass::Loader::finish()
139 {
140         // XXX Make shdata optional
141         if(obj.shprog && !obj.shdata)
142                 obj.shdata = new ProgramData;
143 }
144
145 void RenderPass::Loader::material()
146 {
147         RefPtr<Material> mat = new Material;
148         load_sub(*mat);
149         obj.material = mat;
150 }
151
152 void RenderPass::Loader::material(const string &name)
153 {
154         obj.material = get_collection().get<Material>(name);
155         obj.material.keep();
156 }
157
158 void RenderPass::Loader::texunit(unsigned i)
159 {
160         TextureSlot slot(i);
161         load_sub(slot);
162         obj.textures.push_back(slot);
163 }
164
165 void RenderPass::Loader::uniforms()
166 {
167         if(!obj.shprog)
168                 throw InvalidState("Can't load uniforms without a shader program");
169         if(!obj.shdata)
170                 obj.shdata = new ProgramData;
171         load_sub(*obj.shdata, *obj.shprog);
172 }
173
174
175 RenderPass::TextureSlot::Loader::Loader(TextureSlot &s):
176         DataFile::CollectionObjectLoader<TextureSlot>(s, 0)
177 {
178         init();
179 }
180
181 RenderPass::TextureSlot::Loader::Loader(TextureSlot &s, Collection &c):
182         DataFile::CollectionObjectLoader<TextureSlot>(s, &c)
183 {
184         init();
185 }
186
187 void RenderPass::TextureSlot::Loader::init()
188 {
189         add("texture",   &Loader::texture);
190         add("texture2d", &Loader::texture2d);
191 }
192
193 void RenderPass::TextureSlot::Loader::texture(const string &name)
194 {
195         obj.texture = get_collection().get<Texture>(name);
196         obj.texture.keep();
197 }
198
199 void RenderPass::TextureSlot::Loader::texture2d()
200 {
201         RefPtr<Texture2D> tex = new Texture2D;
202         load_sub(*tex);
203         obj.texture = tex;
204 }
205
206 } // namespace GL
207 } // namespace Msp