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