]> git.tdb.fi Git - libs/gl.git/blob - source/program.cpp
Add support for detecting extensions
[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 "arb_shader_objects.h"
9 #include "arb_vertex_shader.h"
10 #include "except.h"
11 #include "extension.h"
12 #include "program.h"
13 #include "shader.h"
14
15 using namespace std;
16
17 namespace Msp {
18 namespace GL {
19
20 Program::Program():
21         del_shaders(false),
22         linked(false)
23 {
24         require_extension("GL_ARB_shader_objects");
25         require_extension("GL_ARB_vertex_shader");
26
27         id=glCreateProgramObjectARB();
28 }
29
30 Program::Program(const string &vert, const string &frag):
31         del_shaders(true),
32         linked(false)
33 {
34         require_extension("GL_ARB_shader_objects");
35         require_extension("GL_ARB_vertex_shader");
36
37         id=glCreateProgramObjectARB();
38         attach_shader(*new Shader(VERTEX_SHADER, vert));
39         attach_shader(*new Shader(FRAGMENT_SHADER, frag));
40         link();
41 }
42
43 Program::~Program()
44 {
45         if(del_shaders)
46         {
47                 for(list<Shader *>::iterator i=shaders.begin(); i!=shaders.end(); ++i)
48                         delete *i;
49         }
50         glDeleteObjectARB(id);
51 }
52
53 void Program::attach_shader(Shader &shader)
54 {
55         if(find(shaders.begin(), shaders.end(), &shader)==shaders.end())
56         {
57                 glAttachObjectARB(id, shader.get_id());
58                 shaders.push_back(&shader);
59         }
60 }
61
62 void Program::detach_shader(Shader &shader)
63 {
64         list<Shader *>::iterator i=remove(shaders.begin(), shaders.end(), &shader);
65         if(i!=shaders.end())
66         {
67                 shaders.erase(i, shaders.end());
68                 glDetachObjectARB(id, shader.get_id());
69         }
70 }
71
72 void Program::set_del_shaders(bool ds)
73 {
74         del_shaders=ds;
75 }
76
77 void Program::bind_attribute(int index, const string &name)
78 {
79         glBindAttribLocationARB(id, index, name.c_str());
80 }
81
82 bool Program::link()
83 {
84         for(list<Shader *>::iterator i=shaders.begin(); i!=shaders.end(); ++i)
85                 if(!(*i)->get_compiled() && !(*i)->compile())
86                         return false;
87
88         glLinkProgramARB(id);
89         linked=get_param(GL_LINK_STATUS);
90         return linked;
91 }
92
93 int Program::get_param(GLenum param) const
94 {
95         int value;
96         glGetObjectParameterivARB(id, param, &value);
97         return value;
98 }
99
100 string Program::get_info_log() const
101 {
102         sizei len=get_param(GL_INFO_LOG_LENGTH);
103         char log[len+1];
104         glGetInfoLogARB(id, len+1, reinterpret_cast<GLsizei *>(&len), log);
105         return string(log, len);
106 }
107
108 void Program::bind()
109 {
110         if(!linked)
111                 throw InvalidState("Program is not linked");
112
113         glUseProgramObjectARB(id);
114         cur_prog=this;
115 }
116
117 int Program::get_uniform_location(const string &n) const
118 {
119         return glGetUniformLocationARB(id, n.c_str());
120 }
121
122 void Program::uniform(int i, int v)
123 {
124         glUniform1iARB(i, v);
125 }
126
127 void Program::uniform(int i, float x)
128 {
129         glUniform1fARB(i, x);
130 }
131
132 void Program::uniform(int i, float x, float y)
133 {
134         glUniform2fARB(i, x, y);
135 }
136
137 void Program::uniform(int i, float x, float y, float z)
138 {
139         glUniform3fARB(i, x, y, z);
140 }
141
142 void Program::uniform(int i, float x, float y, float z, float w)
143 {
144         glUniform4fARB(i, x, y, z, w);
145 }
146
147 void Program::uniform_matrix4(int i, const float *v)
148 {
149         glUniformMatrix4fvARB(i, 1, false, v);
150 }
151
152 void Program::unbind()
153 {
154         if(cur_prog)
155         {
156                 glUseProgramObjectARB(0);
157                 cur_prog=0;
158         }
159 }
160
161 void Program::maybe_bind()
162 {
163         if(cur_prog!=this)
164                 bind();
165 }
166
167 Program *Program::cur_prog=0;
168
169
170 Program::Loader::Loader(Program &p):
171         prog(p)
172 {
173         prog.set_del_shaders(true);
174
175         add("vertex_shader",   &Loader::vertex_shader);
176         add("fragment_shader", &Loader::fragment_shader);
177 }
178
179 Program::Loader::~Loader()
180 {
181         prog.link();
182 }
183
184 void Program::Loader::vertex_shader(const string &src)
185 {
186         prog.attach_shader(*new Shader(VERTEX_SHADER, src));
187 }
188
189 void Program::Loader::fragment_shader(const string &src)
190 {
191         prog.attach_shader(*new Shader(FRAGMENT_SHADER, src));
192 }
193
194 } // namespace GL
195 } // namespace Msp