1 ////////////////////////////////////////////////////////////////////////////////
2 // Scorched3D (c) 2000-2011
3 //
4 // This file is part of Scorched3D.
5 //
6 // Scorched3D is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 2 of the License, or
9 // (at your option) any later version.
10 //
11 // Scorched3D is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
15 //
16 // You should have received a copy of the GNU General Public License along
17 // with this program; if not, write to the Free Software Foundation, Inc.,
18 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 ////////////////////////////////////////////////////////////////////////////////
20
21 #include <GLSL/GLSLProgram.h>
22 #include <GLEXT/GLStateExtension.h>
23 #include <common/Logger.h>
24 #include <common/Defines.h>
25
26 const GLSLProgram* GLSLProgram::used_program_(0);
27
GLSLProgram()28 GLSLProgram::GLSLProgram() :
29 id_(0), linked_(false)
30 {
31 DIALOG_ASSERT(GLStateExtension::hasShaders());
32
33 id_ = glCreateProgramObjectARB();
34
35 DIALOG_ASSERT(id_);// ("can't create glsl program");
36 }
37
~GLSLProgram()38 GLSLProgram::~GLSLProgram()
39 {
40 if (used_program_ == this)
41 {
42 // rather use some kind of "bug!"-exception here
43 Logger::log("warning: deleting bound glsl program!");
44 use_fixed();
45 }
46 // if shaders are still attached, it is rather a bug...
47 std::list<GLSLShader*>::iterator it;
48 for (it = attached_shaders_.begin();
49 it != attached_shaders_.end();
50 ++it)
51 {
52 glDetachObjectARB(id_, (*it)->getId());
53 }
54
55 glDeleteObjectARB(id_);
56 }
57
attach(GLSLShader & s)58 void GLSLProgram::attach(GLSLShader &s)
59 {
60 glAttachObjectARB(id_, s.getId());
61 attached_shaders_.push_front(&s);
62 linked_ = false;
63 }
64
detach(GLSLShader & s)65 void GLSLProgram::detach(GLSLShader &s)
66 {
67 glDetachObjectARB(id_, s.getId());
68
69 std::list<GLSLShader*>::iterator it;
70 for (it = attached_shaders_.begin();
71 it != attached_shaders_.end(); )
72 {
73 if (*it == &s)
74 {
75 glDetachObjectARB(id_, (*it)->getId());
76 it = attached_shaders_.erase(it);
77 } else
78 {
79 ++it;
80 }
81 }
82 linked_ = false;
83 }
84
link()85 void GLSLProgram::link()
86 {
87 glLinkProgramARB(id_);
88
89 GLint waslinked = GL_FALSE;
90 glGetObjectParameterivARB(id_, GL_OBJECT_LINK_STATUS_ARB, &waslinked);
91 if (waslinked == GL_FALSE)
92 {
93 // get link log
94 GLint maxlength = 0;
95 glGetObjectParameterivARB(id_, GL_OBJECT_INFO_LOG_LENGTH_ARB, &maxlength);
96 std::string logText(maxlength+1, ' ');
97 GLsizei length = 0;
98 glGetInfoLogARB(id_, maxlength, &length, &logText[0]);
99
100 S3D::dialogExit("GLSLProgram",
101 S3D::formatStringBuffer("linking of program failed : %s", logText.c_str()));
102 }
103
104 linked_ = true;
105 }
106
use() const107 void GLSLProgram::use() const
108 {
109 DIALOG_ASSERT(linked_);
110 glUseProgramObjectARB(id_);
111 used_program_ = this;
112 }
113
set_gl_texture(GLTexture & tex,const char * texname,unsigned texunit) const114 void GLSLProgram::set_gl_texture(GLTexture &tex, const char *texname, unsigned texunit) const
115 {
116 DIALOG_ASSERT(used_program_ == this);
117
118 GLint uniloc = glGetUniformLocationARB(id_, texname);
119 glActiveTextureARB(GL_TEXTURE0 + texunit);
120 tex.draw(true);
121 glUniform1iARB(uniloc, texunit);
122 }
123
set_gl_texture(GLShadowFrameBuffer & tex,const char * texname,unsigned texunit) const124 void GLSLProgram::set_gl_texture(GLShadowFrameBuffer &tex, const char *texname, unsigned texunit) const
125 {
126 DIALOG_ASSERT(used_program_ == this);
127
128 GLint uniloc = glGetUniformLocationARB(id_, texname);
129 glActiveTextureARB(GL_TEXTURE0 + texunit);
130 tex.bindDepthTexture();
131 glUniform1iARB(uniloc, texunit);
132 }
133
set_gl_texture_unit(const char * texname,unsigned texunit) const134 void GLSLProgram::set_gl_texture_unit(const char *texname, unsigned texunit) const
135 {
136 DIALOG_ASSERT(used_program_ == this);
137
138 GLint uniloc = glGetUniformLocationARB(id_, texname);
139 glActiveTextureARB(GL_TEXTURE0 + texunit);
140 glUniform1iARB(uniloc, texunit);
141 }
142
set_uniform(const char * name,const Vector & value) const143 void GLSLProgram::set_uniform(const char *name, const Vector& value) const
144 {
145 DIALOG_ASSERT(used_program_ == this);
146
147 GLint loc = glGetUniformLocationARB(id_, name);
148 glUniform3fARB(loc, value[0], value[1], value[2]);
149 }
150
set_uniform(const char * name,const float value) const151 void GLSLProgram::set_uniform(const char *name, const float value) const
152 {
153 DIALOG_ASSERT(used_program_ == this);
154
155 GLint loc = glGetUniformLocationARB(id_, name);
156 glUniform1fARB(loc, value);
157 }
158
get_vertex_attrib_index(const char * name) const159 unsigned GLSLProgram::get_vertex_attrib_index(const char *name) const
160 {
161 DIALOG_ASSERT(used_program_ == this);
162
163 return glGetAttribLocationARB(id_, name);
164 }
165
use_fixed()166 void GLSLProgram::use_fixed()
167 {
168 glUseProgramObjectARB(0);
169 used_program_ = 0;
170 }
171