Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : */
9 :
10 : #include <vcl/opengl/GLMHelper.hxx>
11 : #include <vcl/opengl/OpenGLHelper.hxx>
12 :
13 : #include <osl/file.hxx>
14 : #include <rtl/bootstrap.hxx>
15 : #include <config_folders.h>
16 : #include <vcl/salbtype.hxx>
17 : #include <vcl/bmpacc.hxx>
18 : #include <boost/scoped_array.hpp>
19 : #include <vcl/pngwrite.hxx>
20 : #include <vcl/graph.hxx>
21 :
22 : #include <vector>
23 :
24 : namespace {
25 :
26 0 : OUString getShaderFolder()
27 : {
28 0 : OUString aUrl("$BRAND_BASE_DIR/" LIBO_ETC_FOLDER);
29 0 : rtl::Bootstrap::expandMacros(aUrl);
30 :
31 0 : return aUrl + "/opengl/";
32 : }
33 :
34 0 : OString loadShader(const OUString& rFilename)
35 : {
36 0 : OUString aFileURL = getShaderFolder() + rFilename +".glsl";
37 0 : osl::File aFile(aFileURL);
38 0 : if(aFile.open(osl_File_OpenFlag_Read) == osl::FileBase::E_None)
39 : {
40 0 : sal_uInt64 nSize = 0;
41 0 : aFile.getSize(nSize);
42 0 : boost::scoped_array<char> content(new char[nSize+1]);
43 0 : sal_uInt64 nBytesRead = 0;
44 0 : aFile.read(content.get(), nSize, nBytesRead);
45 0 : if(nSize != nBytesRead)
46 : assert(false);
47 :
48 0 : content[nSize] = 0;
49 0 : return OString(content.get());
50 : }
51 : else
52 : {
53 : SAL_WARN("vcl.opengl", "could not load the file: " << aFileURL);
54 : }
55 :
56 0 : return OString();
57 : }
58 :
59 : }
60 :
61 0 : GLint OpenGLHelper::LoadShaders(const OUString& rVertexShaderName,const OUString& rFragmentShaderName)
62 : {
63 : // Create the shaders
64 0 : GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER);
65 0 : GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);
66 :
67 0 : GLint Result = GL_FALSE;
68 : int InfoLogLength;
69 :
70 : // Compile Vertex Shader
71 0 : OString aVertexShaderSource = loadShader(rVertexShaderName);
72 0 : char const * VertexSourcePointer = aVertexShaderSource.getStr();
73 0 : glShaderSource(VertexShaderID, 1, &VertexSourcePointer , NULL);
74 0 : glCompileShader(VertexShaderID);
75 :
76 : // Check Vertex Shader
77 0 : glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &Result);
78 0 : if ( !Result )
79 : {
80 0 : glGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
81 0 : if ( InfoLogLength > 0 )
82 : {
83 0 : std::vector<char> VertexShaderErrorMessage(InfoLogLength+1);
84 0 : glGetShaderInfoLog(VertexShaderID, InfoLogLength, NULL, &VertexShaderErrorMessage[0]);
85 0 : VertexShaderErrorMessage.push_back('\0');
86 0 : SAL_WARN("vcl.opengl", "vertex shader compile for " << rVertexShaderName << " failed : " << &VertexShaderErrorMessage[0]);
87 : }
88 : else
89 : SAL_WARN("vcl.opengl", "vertex shader compile failed without error log");
90 :
91 0 : return 0;
92 : }
93 :
94 : // Compile Fragment Shader
95 0 : OString aFragmentShaderSource = loadShader(rFragmentShaderName);
96 0 : char const * FragmentSourcePointer = aFragmentShaderSource.getStr();
97 0 : glShaderSource(FragmentShaderID, 1, &FragmentSourcePointer , NULL);
98 0 : glCompileShader(FragmentShaderID);
99 :
100 : // Check Fragment Shader
101 0 : glGetShaderiv(FragmentShaderID, GL_COMPILE_STATUS, &Result);
102 0 : if ( !Result )
103 : {
104 0 : glGetShaderiv(FragmentShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
105 0 : if ( InfoLogLength > 0 )
106 : {
107 0 : std::vector<char> FragmentShaderErrorMessage(InfoLogLength+1);
108 0 : glGetShaderInfoLog(FragmentShaderID, InfoLogLength, NULL, &FragmentShaderErrorMessage[0]);
109 0 : FragmentShaderErrorMessage.push_back('\0');
110 0 : SAL_WARN("vcl.opengl", "fragment shader compile for " << rFragmentShaderName << " failed : " << &FragmentShaderErrorMessage[0]);
111 : }
112 : else
113 : SAL_WARN("vcl.opengl", "fragment shader compile failed without error log");
114 :
115 :
116 0 : return 0;
117 : }
118 :
119 : // Link the program
120 0 : GLint ProgramID = glCreateProgram();
121 0 : glAttachShader(ProgramID, VertexShaderID);
122 0 : glAttachShader(ProgramID, FragmentShaderID);
123 0 : glLinkProgram(ProgramID);
124 :
125 0 : glDeleteShader(VertexShaderID);
126 0 : glDeleteShader(FragmentShaderID);
127 :
128 : // Check the program
129 0 : glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result);
130 0 : if ( !Result )
131 : {
132 0 : glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength);
133 0 : if ( InfoLogLength > 0 )
134 : {
135 0 : std::vector<char> ProgramErrorMessage(InfoLogLength+1);
136 0 : glGetProgramInfoLog(ProgramID, InfoLogLength, NULL, &ProgramErrorMessage[0]);
137 0 : ProgramErrorMessage.push_back('\0');
138 0 : SAL_WARN("vcl.opengl", "Shader Program failed : " << &ProgramErrorMessage[0]);
139 : }
140 : else
141 : SAL_WARN("vcl.opengl", "shader program link failed without error log");
142 :
143 0 : return 0;
144 : }
145 :
146 0 : return ProgramID;
147 : }
148 :
149 0 : void OpenGLHelper::ConvertBitmapExToRGBATextureBuffer(const BitmapEx& rBitmapEx, sal_uInt8* o_pRGBABuffer, const bool bFlip)
150 : {
151 0 : long nBmpWidth = rBitmapEx.GetSizePixel().Width();
152 0 : long nBmpHeight = rBitmapEx.GetSizePixel().Height();
153 :
154 0 : Bitmap aBitmap (rBitmapEx.GetBitmap());
155 0 : AlphaMask aAlpha (rBitmapEx.GetAlpha());
156 0 : Bitmap::ScopedReadAccess pReadAccces( aBitmap );
157 0 : AlphaMask::ScopedReadAccess pAlphaReadAccess( aAlpha );
158 0 : size_t i = 0;
159 0 : for (long ny = (bFlip ? nBmpHeight - 1 : 0); (bFlip ? ny >= 0 : ny < nBmpHeight); (bFlip ? ny-- : ny++))
160 : {
161 0 : Scanline pAScan = pAlphaReadAccess ? pAlphaReadAccess->GetScanline(ny) : 0;
162 0 : for(long nx = 0; nx < nBmpWidth; nx++)
163 : {
164 0 : BitmapColor aCol = pReadAccces->GetColor( ny, nx );
165 0 : o_pRGBABuffer[i++] = aCol.GetRed();
166 0 : o_pRGBABuffer[i++] = aCol.GetGreen();
167 0 : o_pRGBABuffer[i++] = aCol.GetBlue();
168 0 : o_pRGBABuffer[i++] = pAScan ? 255 - *pAScan++ : 255;
169 0 : }
170 0 : }
171 0 : }
172 :
173 0 : void OpenGLHelper::renderToFile(long nWidth, long nHeight, const OUString& rFileName)
174 : {
175 0 : boost::scoped_array<sal_uInt8> pBuffer(new sal_uInt8[nWidth*nHeight*4]);
176 0 : glReadPixels(0, 0, nWidth, nHeight, GL_BGRA, GL_UNSIGNED_BYTE, pBuffer.get());
177 0 : BitmapEx aBitmap = ConvertBGRABufferToBitmapEx(pBuffer.get(), nWidth, nHeight);
178 : try {
179 0 : vcl::PNGWriter aWriter( aBitmap );
180 0 : SvFileStream sOutput( rFileName, STREAM_WRITE );
181 0 : aWriter.Write( sOutput );
182 0 : sOutput.Close();
183 0 : } catch (...) {
184 : SAL_WARN("vcl.opengl", "Error writing png to " << rFileName);
185 0 : }
186 0 : }
187 :
188 0 : BitmapEx OpenGLHelper::ConvertBGRABufferToBitmapEx(const sal_uInt8* const pBuffer, long nWidth, long nHeight)
189 : {
190 : assert(pBuffer);
191 0 : Bitmap aBitmap( Size(nWidth, nHeight), 24 );
192 0 : AlphaMask aAlpha( Size(nWidth, nHeight) );
193 :
194 : {
195 0 : Bitmap::ScopedWriteAccess pWriteAccess( aBitmap );
196 0 : AlphaMask::ScopedWriteAccess pAlphaWriteAccess( aAlpha );
197 :
198 0 : size_t nCurPos = 0;
199 0 : for( int y = 0; y < nHeight; ++y)
200 : {
201 0 : Scanline pScan = pWriteAccess->GetScanline(y);
202 0 : Scanline pAlphaScan = pAlphaWriteAccess->GetScanline(y);
203 0 : for( int x = 0; x < nWidth; ++x )
204 : {
205 0 : *pScan++ = pBuffer[nCurPos];
206 0 : *pScan++ = pBuffer[nCurPos+1];
207 0 : *pScan++ = pBuffer[nCurPos+2];
208 :
209 0 : nCurPos += 3;
210 0 : *pAlphaScan++ = static_cast<sal_uInt8>( 255 - pBuffer[nCurPos++] );
211 : }
212 0 : }
213 : }
214 0 : return BitmapEx(aBitmap, aAlpha);
215 : }
216 :
217 0 : const char* OpenGLHelper::GLErrorString(GLenum errorCode)
218 : {
219 : static const struct {
220 : GLenum code;
221 : const char *string;
222 : } errors[]=
223 : {
224 : /* GL */
225 : {GL_NO_ERROR, "no error"},
226 : {GL_INVALID_ENUM, "invalid enumerant"},
227 : {GL_INVALID_VALUE, "invalid value"},
228 : {GL_INVALID_OPERATION, "invalid operation"},
229 : {GL_STACK_OVERFLOW, "stack overflow"},
230 : {GL_STACK_UNDERFLOW, "stack underflow"},
231 : {GL_OUT_OF_MEMORY, "out of memory"},
232 : {GL_INVALID_FRAMEBUFFER_OPERATION, "invalid framebuffer operation"},
233 :
234 : {0, NULL }
235 : };
236 :
237 : int i;
238 :
239 0 : for (i=0; errors[i].string; i++)
240 : {
241 0 : if (errors[i].code == errorCode)
242 : {
243 0 : return errors[i].string;
244 : }
245 : }
246 :
247 0 : return NULL;
248 : }
249 :
250 0 : std::ostream& operator<<(std::ostream& rStrm, const glm::vec4& rPos)
251 : {
252 0 : rStrm << "( " << rPos[0] << ", " << rPos[1] << ", " << rPos[2] << ", " << rPos[3] << ")";
253 0 : return rStrm;
254 : }
255 :
256 0 : std::ostream& operator<<(std::ostream& rStrm, const glm::vec3& rPos)
257 : {
258 0 : rStrm << "( " << rPos[0] << ", " << rPos[1] << ", " << rPos[2] << ")";
259 0 : return rStrm;
260 : }
261 :
262 0 : std::ostream& operator<<(std::ostream& rStrm, const glm::mat4& rMatrix)
263 : {
264 0 : for(int i = 0; i < 4; ++i)
265 : {
266 0 : rStrm << "\n( ";
267 0 : for(int j = 0; j < 4; ++j)
268 : {
269 0 : rStrm << rMatrix[j][i];
270 0 : rStrm << " ";
271 : }
272 0 : rStrm << ")\n";
273 : }
274 0 : return rStrm;
275 : }
276 :
277 0 : void OpenGLHelper::createFramebuffer(long nWidth, long nHeight, GLuint& nFramebufferId,
278 : GLuint& nRenderbufferDepthId, GLuint& nRenderbufferColorId, bool bRenderbuffer)
279 : {
280 : // create a renderbuffer for depth attachment
281 0 : glGenRenderbuffers(1, &nRenderbufferDepthId);
282 0 : glBindRenderbuffer(GL_RENDERBUFFER, nRenderbufferDepthId);
283 0 : glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, nWidth, nHeight);
284 0 : glBindRenderbuffer(GL_RENDERBUFFER, 0);
285 :
286 0 : if(bRenderbuffer)
287 : {
288 : // create a renderbuffer for color attachment
289 0 : glGenRenderbuffers(1, &nRenderbufferColorId);
290 0 : glBindRenderbuffer(GL_RENDERBUFFER, nRenderbufferColorId);
291 0 : glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, nWidth, nHeight);
292 0 : glBindRenderbuffer(GL_RENDERBUFFER, 0);
293 : }
294 : else
295 : {
296 0 : glGenTextures(1, &nRenderbufferColorId);
297 0 : glBindTexture(GL_TEXTURE_2D, nRenderbufferColorId);
298 0 : glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
299 0 : glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
300 0 : glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
301 0 : glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
302 : glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, nWidth, nHeight, 0,
303 0 : GL_RGBA, GL_UNSIGNED_BYTE, 0);
304 0 : glBindTexture(GL_TEXTURE_2D, 0);
305 :
306 : glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
307 0 : GL_TEXTURE_2D, nRenderbufferColorId, 0);
308 : }
309 :
310 : // create a framebuffer object and attach renderbuffer
311 0 : glGenFramebuffers(1, &nFramebufferId);
312 0 : glCheckFramebufferStatus(GL_FRAMEBUFFER);
313 0 : glBindFramebuffer(GL_FRAMEBUFFER, nFramebufferId);
314 : // attach a renderbuffer to FBO color attachement point
315 0 : glBindRenderbuffer(GL_RENDERBUFFER, nRenderbufferColorId);
316 0 : glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, nRenderbufferColorId);
317 0 : glCheckFramebufferStatus(GL_FRAMEBUFFER);
318 : // attach a renderbuffer to depth attachment point
319 0 : glBindRenderbuffer(GL_RENDERBUFFER, nRenderbufferDepthId);
320 0 : glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, nRenderbufferDepthId);
321 0 : GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
322 0 : if (status != GL_FRAMEBUFFER_COMPLETE)
323 : {
324 : SAL_WARN("vcl.opengl", "invalid framebuffer status");
325 : }
326 0 : glBindRenderbuffer(GL_RENDERBUFFER, 0);
327 0 : glBindFramebuffer(GL_FRAMEBUFFER, 0);
328 0 : }
329 :
330 0 : float OpenGLHelper::getGLVersion()
331 : {
332 0 : float fVersion = 1.0;
333 0 : const GLubyte* aVersion = glGetString( GL_VERSION );
334 0 : if( aVersion && aVersion[0] )
335 : {
336 0 : fVersion = aVersion[0] - '0';
337 0 : if( aVersion[1] == '.' && aVersion[2] )
338 : {
339 0 : fVersion += (aVersion[2] - '0')/10.0;
340 : }
341 : }
342 0 : return fVersion;
343 : }
344 :
345 0 : void OpenGLHelper::checkGLError(const char* pFile, size_t nLine)
346 : {
347 0 : GLenum glErr = glGetError();
348 0 : while (glErr != GL_NO_ERROR)
349 : {
350 0 : const char* sError = OpenGLHelper::GLErrorString(glErr);
351 :
352 0 : if (sError)
353 : SAL_WARN("vcl.opengl", "GL Error #" << glErr << "(" << sError << ") in File " << pFile << " at line: " << nLine);
354 : else
355 : SAL_WARN("vcl.opengl", "GL Error #" << glErr << " (no message available) in File " << pFile << " at line: " << nLine);
356 :
357 0 : glErr = glGetError();
358 : }
359 651 : }
360 :
361 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|