]> git.tdb.fi Git - libs/gl.git/blob - source/program.cpp
Rework Bind and enable it to restore the old binding
[libs/gl.git] / source / program.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 <algorithm>
9 #include "arb_shader_objects.h"
10 #include "arb_vertex_shader.h"
11 #include "except.h"
12 #include "extension.h"
13 #include "program.h"
14 #include "shader.h"
15
16 using namespace std;
17
18 namespace Msp {
19 namespace GL {
20
21 Program::Program():
22         del_shaders(false)
23 {
24         init();
25 }
26
27 Program::Program(const string &vert, const string &frag):
28         del_shaders(true)
29 {
30         init();
31
32         attach_shader(*new Shader(VERTEX_SHADER, vert));
33         attach_shader(*new Shader(FRAGMENT_SHADER, frag));
34         link();
35 }
36
37 void Program::init()
38 {
39         static RequireExtension _ext("GL_ARB_shader_objects");
40
41         linked = false;
42         id = glCreateProgramObjectARB();
43 }
44
45 Program::~Program()
46 {
47         if(del_shaders)
48         {
49                 for(list<Shader *>::iterator i=shaders.begin(); i!=shaders.end(); ++i)
50                         delete *i;
51         }
52         glDeleteObjectARB(id);
53 }
54
55 void Program::attach_shader(Shader &shader)
56 {
57         if(find(shaders.begin(), shaders.end(), &shader)==shaders.end())
58         {
59                 glAttachObjectARB(id, shader.get_id());
60                 shaders.push_back(&shader);
61         }
62 }
63
64 void Program::detach_shader(Shader &shader)
65 {
66         list<Shader *>::iterator i = remove(shaders.begin(), shaders.end(), &shader);
67         if(i!=shaders.end())
68         {
69                 shaders.erase(i, shaders.end());
70                 glDetachObjectARB(id, shader.get_id());
71         }
72 }
73
74 void Program::set_del_shaders(bool ds)
75 {
76         del_shaders = ds;
77 }
78
79 void Program::bind_attribute(unsigned index, const string &name)
80 {
81         static RequireExtension _ext("GL_ARB_vertex_shader");
82         glBindAttribLocationARB(id, index, name.c_str());
83 }
84
85 void Program::link()
86 {
87         for(list<Shader *>::iterator i=shaders.begin(); i!=shaders.end(); ++i)
88                 if(!(*i)->get_compiled())
89                         (*i)->compile();
90
91         glLinkProgramARB(id);
92         if(!(linked = get_param(GL_LINK_STATUS)))
93                 throw CompileError(get_info_log());
94 }
95
96 int Program::get_param(GLenum param) const
97 {
98         int value;
99         glGetObjectParameterivARB(id, param, &value);
100         return value;
101 }
102
103 string Program::get_info_log() const
104 {
105         GLsizei len = get_param(GL_INFO_LOG_LENGTH);
106         char log[len+1];
107         glGetInfoLogARB(id, len+1, &len, log);
108         return string(log, len);
109 }
110
111 void Program::bind() const
112 {
113         if(!linked)
114                 throw InvalidState("Program is not linked");
115
116         if(!set_current(this))
117                 return;
118
119         glUseProgramObjectARB(id);
120 }
121
122 int Program::get_uniform_location(const string &n) const
123 {
124         return glGetUniformLocationARB(id, n.c_str());
125 }
126
127 void Program::unbind()
128 {
129         if(!set_current(0))
130                 return;
131
132         glUseProgramObjectARB(0);
133 }
134
135
136 Program::Loader::Loader(Program &p):
137         DataFile::ObjectLoader<Program>(p)
138 {
139         obj.set_del_shaders(true);
140
141         add("vertex_shader",   &Loader::vertex_shader);
142         add("fragment_shader", &Loader::fragment_shader);
143         add("attribute",       &Loader::attribute);
144 }
145
146 void Program::Loader::vertex_shader(const string &src)
147 {
148         obj.attach_shader(*new Shader(VERTEX_SHADER, src));
149 }
150
151 void Program::Loader::fragment_shader(const string &src)
152 {
153         obj.attach_shader(*new Shader(FRAGMENT_SHADER, src));
154 }
155
156 void Program::Loader::attribute(unsigned i, const string &n)
157 {
158         obj.bind_attribute(i, n);
159 }
160
161 void Program::Loader::finish()
162 {
163         obj.link();
164 }
165
166 } // namespace GL
167 } // namespace Msp