1 /***********************************************************************
2 created: Wed, 8th Feb 2012
3 author: Lukas E Meindl
4 *************************************************************************/
5 /***************************************************************************
6 * Copyright (C) 2004 - 2012 Paul D Turner & The CEGUI Development Team
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining
9 * a copy of this software and associated documentation files (the
10 * "Software"), to deal in the Software without restriction, including
11 * without limitation the rights to use, copy, modify, merge, publish,
12 * distribute, sublicense, and/or sell copies of the Software, and to
13 * permit persons to whom the Software is furnished to do so, subject to
14 * the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be
17 * included in all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
23 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
24 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 * OTHER DEALINGS IN THE SOFTWARE.
26 ***************************************************************************/
27 #include "CEGUI/RendererModules/OpenGL/GL.h"
28 #include "CEGUI/RendererModules/OpenGL/Shader.h"
29 #include "CEGUI/Logger.h"
30 #include "CEGUI/Exceptions.h"
31
32 #include <sstream>
33 #include <iostream>
34
35 namespace CEGUI
36 {
37 //----------------------------------------------------------------------------//
38 static const size_t LOG_BUFFER_SIZE = 8096;
39
40 //----------------------------------------------------------------------------//
OpenGL3Shader(const std::string & vertex_shader_source,const std::string & fragment_shader_source)41 OpenGL3Shader::OpenGL3Shader(const std::string& vertex_shader_source,
42 const std::string& fragment_shader_source) :
43 d_createdSucessfully(false),
44 d_vertexShader(0),
45 d_fragmentShader(0),
46 d_geometryShader(0),
47 d_program(0)
48 {
49 // Compile the shaders
50
51 d_vertexShader = compile(GL_VERTEX_SHADER, vertex_shader_source);
52 if (d_vertexShader == 0)
53 return;
54
55 checkGLErrors();
56
57 if(fragment_shader_source.length() > 0)
58 {
59 d_fragmentShader = compile(GL_FRAGMENT_SHADER, fragment_shader_source);
60
61 if (d_fragmentShader == 0)
62 return;
63 }
64
65 checkGLErrors();
66
67 d_program = glCreateProgram();
68 }
69
70 //----------------------------------------------------------------------------//
~OpenGL3Shader()71 OpenGL3Shader::~OpenGL3Shader()
72 {
73 if(d_program != 0)
74 glDeleteProgram(d_program);
75 if(d_vertexShader != 0)
76 glDeleteShader(d_vertexShader);
77 if(d_fragmentShader != 0)
78 glDeleteShader(d_fragmentShader);
79 if(d_geometryShader != 0)
80 glDeleteShader(d_geometryShader);
81 }
82
83 //----------------------------------------------------------------------------//
bind() const84 void OpenGL3Shader::bind() const
85 {
86 glUseProgram(d_program);
87 }
88
89 //----------------------------------------------------------------------------//
unbind() const90 void OpenGL3Shader::unbind() const
91 {
92 glUseProgram(0);
93 }
94
95 //----------------------------------------------------------------------------//
getAttribLocation(const std::string & name) const96 GLuint OpenGL3Shader::getAttribLocation(const std::string &name) const
97 {
98 return glGetAttribLocation(d_program, name.c_str());
99 }
100
101 //----------------------------------------------------------------------------//
getUniformLocation(const std::string & name) const102 GLuint OpenGL3Shader::getUniformLocation(const std::string &name) const
103 {
104 return glGetUniformLocation(d_program, name.c_str());
105 }
106
107 //----------------------------------------------------------------------------//
bindFragDataLocation(const std::string & name)108 void OpenGL3Shader::bindFragDataLocation(const std::string &name)
109 {
110 if(d_program > 0)
111 {
112 glBindFragDataLocation(d_program, 0, name.c_str());
113 link();
114 }
115 }
116
117 //----------------------------------------------------------------------------//
isCreatedSuccessfully()118 bool OpenGL3Shader::isCreatedSuccessfully()
119 {
120 return d_createdSucessfully;
121 }
122
123 //----------------------------------------------------------------------------//
compile(GLuint type,const std::string & source)124 GLuint OpenGL3Shader::compile(GLuint type, const std::string &source)
125 {
126 // Create shader object
127 checkGLErrors();
128 GLuint shader = glCreateShader(type);
129
130 if (shader == 0)
131 {
132 std::stringstream stringStream;
133 stringStream << "Critical Error - Could not create shader object of type:" << type << ".";
134 CEGUI_THROW(RendererException(stringStream.str().c_str()));
135 return 0;
136 }
137
138 checkGLErrors();
139
140 // Define shader source and compile
141
142 const char* src = source.data();
143 int len = source.size();
144
145 glShaderSource(shader, 1, &src, &len);
146
147 glCompileShader(shader);
148
149 // Check for errors
150 GLint status;
151 glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
152
153 if (status != GL_TRUE)
154 {
155 outputShaderLog(shader);
156 return 0;
157 }
158
159 checkGLErrors();
160
161 return shader;
162 }
163
164 //----------------------------------------------------------------------------//
link()165 void OpenGL3Shader::link()
166 {
167
168 // Attach shaders and link
169 glAttachShader(d_program, d_vertexShader);
170
171 if(d_geometryShader != 0)
172 glAttachShader(d_program, d_geometryShader);
173
174 if(d_fragmentShader !=0)
175 glAttachShader(d_program, d_fragmentShader);
176
177 glLinkProgram(d_program);
178
179 // Check for problems
180
181 GLint status;
182 glGetProgramiv(d_program, GL_LINK_STATUS, &status);
183
184 if (status != GL_TRUE)
185 {
186 outputProgramLog(d_program);
187
188 glDeleteProgram(d_program);
189 d_program = 0;
190 }
191
192 checkGLErrors();
193
194 if (d_program == 0)
195 return;
196
197 d_createdSucessfully = true;
198 checkGLErrors();
199
200 if (OpenGLInfo::getSingleton().isUsingDesktopOpengl())
201 {
202 glBindFragDataLocation(d_program, 0, "out0"); // GL_COLOR_ATTACHMENT0
203 glBindFragDataLocation(d_program, 1, "out1"); // GL_COLOR_ATTACHMENT1
204 glBindFragDataLocation(d_program, 2, "out2"); // ...
205 glBindFragDataLocation(d_program, 3, "out3");
206 glBindFragDataLocation(d_program, 4, "out4");
207 glBindFragDataLocation(d_program, 5, "out5");
208 glBindFragDataLocation(d_program, 6, "out6");
209 glBindFragDataLocation(d_program, 7, "out7");
210 }
211 checkGLErrors();
212 }
213
214 //----------------------------------------------------------------------------//
outputProgramLog(GLuint program)215 void OpenGL3Shader::outputProgramLog(GLuint program)
216 {
217 char logBuffer[LOG_BUFFER_SIZE];
218 GLsizei length;
219
220 logBuffer[0] = '\0';
221 glGetProgramInfoLog(program, LOG_BUFFER_SIZE, &length, logBuffer);
222
223 if (length > 0)
224 {
225 std::stringstream sstream;
226 sstream << "OpenGL3Shader linking has failed.\n" << logBuffer;
227 CEGUI_THROW(RendererException(sstream.str().c_str()));
228 }
229 }
230
231 //----------------------------------------------------------------------------//
outputShaderLog(GLuint shader)232 void OpenGL3Shader::outputShaderLog(GLuint shader)
233 {
234 char logBuffer[LOG_BUFFER_SIZE];
235 GLsizei length;
236
237 logBuffer[0] = '\0';
238 glGetShaderInfoLog(shader, LOG_BUFFER_SIZE, &length, logBuffer);
239
240 if (length > 0)
241 {
242 std::stringstream ss;
243 ss << "OpenGL3Shader compilation has failed.\n" << logBuffer;
244 CEGUI_THROW(RendererException(ss.str().c_str()));
245 }
246 }
247
248 //----------------------------------------------------------------------------//
getGLErrors(const char * location)249 void getGLErrors(const char *location)
250 {
251 GLenum error = glGetError();
252
253 if (error != GL_NO_ERROR)
254 {
255 std::stringstream stringStream;
256 stringStream << "OpenGL3Renderer: Notification - OpenGL error at " << location << ": " << std::endl;
257
258 switch (error)
259 {
260 case GL_INVALID_ENUM:
261 stringStream << "GL_INVALID_ENUM: enum argument out of range." << std::endl;
262 break;
263 case GL_INVALID_VALUE:
264 stringStream << "GL_INVALID_VALUE: Numeric argument out of range." << std::endl;
265 break;
266 case GL_INVALID_OPERATION:
267 stringStream << "GL_INVALID_OPERATION: Operation illegal in current state." << std::endl;
268 break;
269 case GL_INVALID_FRAMEBUFFER_OPERATION:
270 stringStream << "GL_INVALID_FRAMEBUFFER_OPERATION: Framebuffer object is not complete." << std::endl;
271 break;
272 case GL_OUT_OF_MEMORY:
273 stringStream << "GL_OUT_OF_MEMORY: Not enough memory left to execute command." << std::endl;
274 break;
275 default:
276 stringStream << "GL_ERROR: Unknown error." << std::endl;
277 }
278
279 if (CEGUI::Logger* logger = CEGUI::Logger::getSingletonPtr())
280 logger->logEvent(stringStream.str().c_str());
281 else
282 std::cerr << stringStream.str() << std::endl;
283 }
284 }
285
286 //----------------------------------------------------------------------------//
287
288 }
289