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