Version 6.1.4.1, tag libreoffice-6.1.4.1
[LibreOffice.git] / chart2 / source / view / main / OpenGLRender.cxx
blob35fbbac1d76fe5f8baad690e4cd25b478297f1b4
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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 */
10 #include <epoxy/gl.h>
11 #include <cmath>
12 #include <vector>
13 #include "OpenGLRender.hxx"
14 #include <vcl/graph.hxx>
15 #include <com/sun/star/awt/XBitmap.hpp>
16 #include <com/sun/star/beans/XPropertySet.hpp>
17 #include <com/sun/star/graphic/XGraphic.hpp>
18 #include <com/sun/star/drawing/CircleKind.hpp>
19 #include <com/sun/star/drawing/DoubleSequence.hpp>
20 #include <com/sun/star/drawing/FlagSequence.hpp>
21 #include <com/sun/star/drawing/FillStyle.hpp>
22 #include <com/sun/star/drawing/LineStyle.hpp>
23 #include <com/sun/star/drawing/NormalsKind.hpp>
24 #include <com/sun/star/drawing/PointSequence.hpp>
25 #include <com/sun/star/drawing/PolygonKind.hpp>
26 #include <com/sun/star/drawing/PolyPolygonBezierCoords.hpp>
27 #include <com/sun/star/drawing/ProjectionMode.hpp>
28 #include <com/sun/star/drawing/ShadeMode.hpp>
29 #include <com/sun/star/drawing/TextFitToSizeType.hpp>
30 #include <com/sun/star/drawing/TextureProjectionMode.hpp>
31 #include <com/sun/star/text/XText.hpp>
32 #include <editeng/unoprnms.hxx>
33 #include <vcl/virdev.hxx>
34 #include <vcl/dibtools.hxx>
35 #include <vcl/svapp.hxx>
37 #include <vcl/opengl/OpenGLHelper.hxx>
39 #include <CommonConverters.hxx>
41 using namespace com::sun::star;
43 #define DEBUG_PNG 0
45 #if DEBUG_PNG
46 #include <vcl/pngwrite.hxx>
47 #endif
49 #define GL_PI 3.14159f
51 #define Z_STEP 0.001f
53 static GLfloat squareVertices[] = {
54 -1.0f, -1.0f, -1.0,
55 1.0f, -1.0f, -1.0,
56 1.0f, 1.0f, -1.0,
57 -1.0f, 1.0f, -1.0
60 static GLfloat coordReverseVertices[] = {
61 0.0f, 1.0f,
62 1.0f, 1.0f,
63 1.0f, 0.0f,
64 0.0f, 0.0f,
67 #define CHECK_GL_FRAME_BUFFER_STATUS() \
68 GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);\
69 if( status != GL_FRAMEBUFFER_COMPLETE ) {\
70 SAL_WARN("chart2.opengl", "OpenGL error: " << status );\
71 return -1;\
74 namespace {
76 GLfloat texCoords[] = {
77 0.0f, 0.0f,
78 1.0f, 0.0f,
79 1.0f, 1.0f,
80 0.0f, 1.0f
85 int OpenGLRender::InitOpenGL()
87 glEnable(GL_TEXTURE_2D);
88 glDisable(GL_CULL_FACE);
89 glCullFace(GL_BACK);
90 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
91 // Enable depth test
92 glEnable(GL_DEPTH_TEST);
93 // Accept fragment if it closer to the camera than the former one
94 glDepthFunc(GL_LESS);
95 glEnable(GL_POINT_SMOOTH);
96 glEnable(GL_LINE_SMOOTH);
97 glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
98 glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
99 glEnable(GL_BLEND);
100 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
102 glClearColor (1.0, 1.0, 1.0, 1.0);
103 glClear(GL_COLOR_BUFFER_BIT);
104 glClearDepth(1.0f);
105 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
107 glGenBuffers(1, &m_VertexBuffer);
108 glGenBuffers(1, &m_ColorBuffer);
110 CHECK_GL_ERROR();
112 m_CommonProID = OpenGLHelper::LoadShaders("commonVertexShader", "commonFragmentShader");
113 m_MatrixID = glGetUniformLocation(m_CommonProID, "MVP");
114 m_2DVertexID = glGetAttribLocation(m_CommonProID, "vPosition");
115 m_2DColorID = glGetUniformLocation(m_CommonProID, "vColor");
116 CHECK_GL_ERROR();
118 #if DEBUG_POSITIONING
119 m_DebugProID = OpenGLHelper::LoadShaders("debugVertexShader", "debugFragmentShader");
120 m_DebugVertexID = glGetAttribLocation(m_DebugProID, "vPosition");
121 CHECK_GL_ERROR();
122 #endif
124 m_BackgroundProID = OpenGLHelper::LoadShaders("backgroundVertexShader", "backgroundFragmentShader");
125 m_BackgroundMatrixID = glGetUniformLocation(m_BackgroundProID, "MVP");
126 m_BackgroundVertexID = glGetAttribLocation(m_BackgroundProID, "vPosition");
127 m_BackgroundColorID = glGetAttribLocation(m_BackgroundProID, "vColor");
129 CHECK_GL_ERROR();
131 m_SymbolProID = OpenGLHelper::LoadShaders("symbolVertexShader", "symbolFragmentShader");
132 m_SymbolVertexID = glGetAttribLocation(m_SymbolProID, "vPosition");
133 m_SymbolMatrixID = glGetUniformLocation(m_SymbolProID, "MVP");
134 m_SymbolColorID = glGetUniformLocation(m_SymbolProID, "vColor");
135 m_SymbolShapeID = glGetUniformLocation(m_SymbolProID, "shape");
137 CHECK_GL_ERROR();
139 m_TextProID = OpenGLHelper::LoadShaders("textVertexShader", "textFragmentShader");
140 m_TextMatrixID = glGetUniformLocation(m_TextProID, "MVP");
141 m_TextVertexID = glGetAttribLocation(m_TextProID, "vPosition");
142 m_TextTexCoordID = glGetAttribLocation(m_TextProID, "texCoord");
143 m_TextTexID = glGetUniformLocation(m_TextProID, "TextTex");
144 CHECK_GL_ERROR();
146 glGenBuffers(1, &m_RenderVertexBuf);
147 glBindBuffer(GL_ARRAY_BUFFER, m_RenderVertexBuf);
148 glBufferData(GL_ARRAY_BUFFER, sizeof(squareVertices), squareVertices, GL_STATIC_DRAW);
149 glBindBuffer(GL_ARRAY_BUFFER, 0);
151 glGenBuffers(1, &m_RenderTexCoordBuf);
152 glBindBuffer(GL_ARRAY_BUFFER, m_RenderTexCoordBuf);
153 glBufferData(GL_ARRAY_BUFFER, sizeof(coordReverseVertices), coordReverseVertices, GL_STATIC_DRAW);
154 glBindBuffer(GL_ARRAY_BUFFER, 0);
156 glGenBuffers(1, &m_TextTexCoordBuf);
157 glBindBuffer(GL_ARRAY_BUFFER, m_TextTexCoordBuf);
158 glBufferData(GL_ARRAY_BUFFER, sizeof(texCoords), texCoords, GL_STATIC_DRAW);
159 glBindBuffer(GL_ARRAY_BUFFER, 0);
161 glEnable(GL_LIGHTING);
162 GLfloat const light_direction[] = { 0.0 , 0.0 , 1.0 };
163 GLfloat const materialDiffuse[] = { 1.0 , 1.0 , 1.0 , 1.0};
164 glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, light_direction);
165 glMaterialfv(GL_FRONT,GL_DIFFUSE,materialDiffuse);
166 glEnable(GL_LIGHT0);
167 glEnable(GL_NORMALIZE);
169 return 0;
172 int OpenGLRender::SetLine2DShapePoint(float x, float y, int listLength)
174 if (m_Line2DPointList.empty())
176 m_Line2DPointList.reserve(listLength*3);
178 m_Line2DPointList.push_back(x);
179 m_Line2DPointList.push_back(y);
180 m_Line2DPointList.push_back(m_fZStep);
182 if (m_Line2DPointList.size() == size_t(listLength * 3))
184 m_Line2DShapePointList.push_back(m_Line2DPointList);
185 m_Line2DPointList.clear();
187 return 0;
190 int OpenGLRender::RenderLine2FBO()
192 CHECK_GL_ERROR();
193 glLineWidth(m_fLineWidth);
194 PosVecf3 const trans = {0.0f, 0.0f, 0.0f};
195 PosVecf3 const angle = {0.0f, 0.0f, 0.0f};
196 PosVecf3 const scale = {1.0f, 1.0f, 1.0f};
197 MoveModelf(trans, angle, scale);
198 m_MVP = m_Projection * m_View * m_Model;
199 for (auto const& pointList : m_Line2DShapePointList)
201 //fill vertex buffer
202 glBindBuffer(GL_ARRAY_BUFFER, m_VertexBuffer);
203 CHECK_GL_ERROR();
204 glBufferData(GL_ARRAY_BUFFER, pointList.size() * sizeof(float), &pointList[0], GL_STATIC_DRAW);
205 CHECK_GL_ERROR();
206 // Use our shader
207 glUseProgram(m_CommonProID);
208 CHECK_GL_ERROR();
210 glUniform4fv(m_2DColorID, 1, &m_2DColor[0]);
211 CHECK_GL_ERROR();
212 glUniformMatrix4fv(m_MatrixID, 1, GL_FALSE, &m_MVP[0][0]);
213 //CHECK_GL_ERROR();
215 // 1rst attribute buffer : vertices
216 CHECK_GL_ERROR();
217 glVertexAttribPointer(
218 m_2DVertexID,
219 3, // size
220 GL_FLOAT, // type
221 GL_FALSE, // normalized?
222 0, // stride
223 nullptr // array buffer offset
225 glEnableVertexAttribArray(m_2DVertexID);
226 glDrawArrays(GL_LINE_STRIP, 0, pointList.size()/3); // 12*3 indices starting at 0 -> 12 triangles
227 CHECK_GL_ERROR();
228 glUseProgram(0);
229 glDisableVertexAttribArray(m_2DVertexID);
230 CHECK_GL_ERROR();
232 m_Line2DShapePointList.clear();
233 CHECK_GL_ERROR();
234 CHECK_GL_FRAME_BUFFER_STATUS();
235 m_fZStep += Z_STEP;
236 return 0;
239 #if DEBUG_POSITIONING
240 void OpenGLRender::renderDebug()
242 CHECK_GL_ERROR();
244 GLfloat vertices[4][3] = {
245 {-0.9, -0.9, 0 },
246 {-0.6, -0.2, 0 },
247 {0.3, 0.3, 0 },
248 {0.9, 0.9, 0 } };
250 glBindBuffer(GL_ARRAY_BUFFER, m_VertexBuffer);
251 CHECK_GL_ERROR();
252 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
253 CHECK_GL_ERROR();
254 glUseProgram(m_DebugProID);
255 CHECK_GL_ERROR();
256 glVertexAttribPointer(m_DebugVertexID, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
257 CHECK_GL_ERROR();
258 glEnableVertexAttribArray(m_DebugVertexID);
260 glDrawArrays(GL_LINE_STRIP, 0, 3);
261 CHECK_GL_ERROR();
262 glDisableVertexAttribArray(m_DebugVertexID);
264 CHECK_GL_ERROR();
266 #endif
268 void OpenGLRender::prepareToRender()
270 glViewport(0, 0, m_iWidth, m_iHeight);
272 // Clear the screen
273 glClearDepth(1.0f);
274 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
275 m_fZStep = 0;
278 int OpenGLRender::MoveModelf(const PosVecf3& trans, const PosVecf3& angle, const PosVecf3& scale)
280 glm::mat4 aTranslationMatrix = glm::translate(glm::vec3(trans.x, trans.y, trans.z));
281 glm::mat4 aScaleMatrix = glm::scale(glm::vec3(scale.x, scale.y, scale.z));
282 glm::mat4 aRotationMatrix = glm::eulerAngleYXZ(angle.y, angle.x, angle.z);
283 m_Model = aTranslationMatrix * aRotationMatrix * aScaleMatrix;
284 return 0;
287 void OpenGLRender::Release()
289 glDeleteBuffers(1, &m_VertexBuffer);
290 glDeleteBuffers(1, &m_ColorBuffer);
291 glDeleteBuffers(1, &m_TextTexCoordBuf);
292 glDeleteProgram(m_CommonProID);
293 glDeleteProgram(m_TextProID);
294 glDeleteProgram(m_BackgroundProID);
295 glDeleteProgram(m_SymbolProID);
298 OpenGLRender::OpenGLRender()
299 : m_iWidth(1600)
300 , m_iHeight(900)
301 , m_Model(glm::mat4(1.0f))
302 , m_VertexBuffer(0)
303 , m_ColorBuffer(0)
304 , m_MatrixID(0)
305 , m_RenderVertexBuf(0)
306 , m_RenderTexCoordBuf(0)
307 , m_fLineWidth(0.001f)
308 , m_2DColor(glm::vec4(1.0, 0.0, 0.0, 1.0))
309 , m_CommonProID(0)
310 , m_2DVertexID(0)
311 , m_2DColorID(0)
312 , m_fZStep(0)
313 , m_TextProID(0)
314 , m_TextMatrixID(0)
315 , m_TextVertexID(0)
316 , m_TextTexCoordID(0)
317 , m_TextTexCoordBuf(0)
318 , m_TextTexID(0)
319 , m_BackgroundProID(0)
320 , m_BackgroundMatrixID(0)
321 , m_BackgroundVertexID(0)
322 , m_BackgroundColorID(0)
323 , m_SymbolProID(0)
324 , m_SymbolVertexID(0)
325 , m_SymbolMatrixID(0)
326 , m_SymbolColorID(0)
327 , m_SymbolShapeID(0)
329 //TODO: moggi: use STL
330 for (float & i : m_BackgroundColor)
332 i = 1.0;
336 OpenGLRender::~OpenGLRender()
338 Release();
341 // TODO: moggi: that screws up FBO if called after buffers have been created!!!!
342 void OpenGLRender::SetSize(int width, int height)
344 m_iWidth = width;
345 m_iHeight = height;
348 void OpenGLRender::SetSizePixel(int width, int height)
350 m_Projection = glm::ortho(0.f, float(m_iWidth), 0.f, float(m_iHeight), -4.f, 3.f);
351 m_Projection = m_Projection * glm::scale(glm::vec3(static_cast<float>(width) / m_iWidth, -static_cast<float>(height) / m_iHeight, 1.0f));
353 m_View = glm::lookAt(glm::vec3(0,m_iHeight,1),
354 glm::vec3(0,m_iHeight,0),
355 glm::vec3(0,1,0) );
358 void OpenGLRender::SetLine2DColor(sal_uInt8 r, sal_uInt8 g, sal_uInt8 b, sal_uInt8 nAlpha)
360 m_2DColor = glm::vec4(static_cast<float>(r) / 255.0f, static_cast<float>(g) / 255.0f, static_cast<float>(b) / 255.0f, nAlpha/255.f);
363 void OpenGLRender::SetLine2DWidth(int width)
365 m_fLineWidth = std::max(static_cast<float>(width), 0.001f);
368 void OpenGLRender::SetColor(sal_uInt32 color, sal_uInt8 nAlpha)
370 sal_uInt8 r = (color & 0x00FF0000) >> 16;
371 sal_uInt8 g = (color & 0x0000FF00) >> 8;
372 sal_uInt8 b = (color & 0x000000FF);
373 m_2DColor = glm::vec4(static_cast<float>(r) / 255.0f, static_cast<float>(g) / 255.0f, static_cast<float>(b) / 255.0f, nAlpha/ 255.f);
376 int OpenGLRender::Create2DCircle(int detail)
378 float angle;
379 if (detail <= 0)
381 return -1;
383 m_Bubble2DCircle.clear();
384 m_Bubble2DCircle.reserve(2 * (detail + 3));
385 m_Bubble2DCircle.push_back(0);
386 m_Bubble2DCircle.push_back(0);
387 for(angle = 2.0f * GL_PI; angle > -(2.0f * GL_PI / detail); angle -= (2.0f * GL_PI / detail))
389 m_Bubble2DCircle.push_back(std::sin(angle));
390 m_Bubble2DCircle.push_back(std::cos(angle));
392 return 0;
395 int OpenGLRender::Bubble2DShapePoint(float x, float y, float directionX, float directionY)
397 //check whether to create the circle data
398 if (m_Bubble2DCircle.empty())
400 Create2DCircle(100);
403 Bubble2DPointList aBubble2DPointList;
404 aBubble2DPointList.xScale = directionX;
405 aBubble2DPointList.yScale = directionY;
406 aBubble2DPointList.x = x + aBubble2DPointList.xScale / 2;
407 aBubble2DPointList.y = y + aBubble2DPointList.yScale / 2;
409 m_Bubble2DShapePointList.push_back(aBubble2DPointList);
410 return 0;
413 int OpenGLRender::RenderBubble2FBO()
415 CHECK_GL_ERROR();
416 glm::vec4 edgeColor = glm::vec4(0.0, 0.0, 0.0, 1.0);
417 for (auto const& pointList : m_Bubble2DShapePointList)
419 //move the circle to the pos, and scale using the xScale and Y scale
420 PosVecf3 const trans = {pointList.x, pointList.y, m_fZStep};
421 PosVecf3 const angle = {0.0f, 0.0f, 0.0f};
422 PosVecf3 const scale = {pointList.xScale / 2, pointList.yScale / 2 , 1.0f};
423 MoveModelf(trans, angle, scale);
424 m_MVP = m_Projection * m_View * m_Model;
425 //render to fbo
426 //fill vertex buffer
427 glBindBuffer(GL_ARRAY_BUFFER, m_VertexBuffer);
428 if (m_Bubble2DCircle.empty())
430 Create2DCircle(100);
432 glBufferData(GL_ARRAY_BUFFER, m_Bubble2DCircle.size() * sizeof(GLfloat), &m_Bubble2DCircle[0], GL_STATIC_DRAW);
434 glUseProgram(m_CommonProID);
436 glUniform4fv(m_2DColorID, 1, &m_2DColor[0]);
438 glUniformMatrix4fv(m_MatrixID, 1, GL_FALSE, &m_MVP[0][0]);
439 // 1rst attribute buffer : vertices
440 glEnableVertexAttribArray(m_2DVertexID);
441 glBindBuffer(GL_ARRAY_BUFFER, m_VertexBuffer);
442 glVertexAttribPointer(
443 m_2DVertexID, // attribute. No particular reason for 0, but must match the layout in the shader.
444 2, // size
445 GL_FLOAT, // type
446 GL_FALSE, // normalized?
447 0, // stride
448 nullptr // array buffer offset
450 glDrawArrays(GL_TRIANGLE_FAN, 0, m_Bubble2DCircle.size() / 2);
451 glDisableVertexAttribArray(m_2DVertexID);
452 glUseProgram(0);
453 glBindBuffer(GL_ARRAY_BUFFER, 0);
454 //add black edge
455 glLineWidth(3.0);
456 glBindBuffer(GL_ARRAY_BUFFER, m_VertexBuffer);
457 glBufferData(GL_ARRAY_BUFFER, m_Bubble2DCircle.size() * sizeof(GLfloat) -2 , &m_Bubble2DCircle[2], GL_STATIC_DRAW);
458 glUseProgram(m_CommonProID);
459 glUniform4fv(m_2DColorID, 1, &edgeColor[0]);
460 glUniformMatrix4fv(m_MatrixID, 1, GL_FALSE, &m_MVP[0][0]);
461 glEnableVertexAttribArray(m_2DVertexID);
462 glBindBuffer(GL_ARRAY_BUFFER, m_VertexBuffer);
463 glVertexAttribPointer(
464 m_2DVertexID, // attribute. No particular reason for 0, but must match the layout in the shader.
465 2, // size
466 GL_FLOAT, // type
467 GL_FALSE, // normalized?
468 0, // stride
469 nullptr // array buffer offset
471 glDrawArrays(GL_LINE_STRIP, 0, (m_Bubble2DCircle.size() * sizeof(GLfloat) -2) / sizeof(float) / 2);
472 glDisableVertexAttribArray(m_2DVertexID);
473 glUseProgram(0);
474 glBindBuffer(GL_ARRAY_BUFFER, 0);
475 glLineWidth(m_fLineWidth);
477 m_Bubble2DShapePointList.clear();
478 //if use MSAA, we should copy the data to the FBO texture
479 GLenum fbResult = glCheckFramebufferStatus(GL_FRAMEBUFFER);
480 if( fbResult != GL_FRAMEBUFFER_COMPLETE )
482 SAL_WARN("chart2.opengl", "error");
483 return -1;
485 CHECK_GL_ERROR();
486 m_fZStep += Z_STEP;
487 return 0;
490 int OpenGLRender::RectangleShapePoint(float x, float y, float directionX, float directionY)
492 RectanglePointList aRectangle;
494 aRectangle.points[0] = x;
495 aRectangle.points[1] = y;
496 aRectangle.points[2] = m_fZStep;
497 aRectangle.points[3] = x + directionX;
498 aRectangle.points[4] = y;
499 aRectangle.points[5] = m_fZStep;
500 aRectangle.points[6] = x + directionX;
501 aRectangle.points[7] = y + directionY;
502 aRectangle.points[8] = m_fZStep;
503 aRectangle.points[9] = x;
504 aRectangle.points[10] = y + directionY;
505 aRectangle.points[11] = m_fZStep;
507 m_RectangleShapePointList.push_back(aRectangle);
508 return 0;
511 int OpenGLRender::RenderRectangleShape(bool bBorder, bool bFill)
513 for (auto const& pointList : m_RectangleShapePointList)
515 //move the circle to the pos, and scale using the xScale and Y scale
517 PosVecf3 const trans = {0, 0, 0};
518 PosVecf3 const angle = {0.0f, 0.0f, 0.0f};
519 PosVecf3 const scale = {1, 1, 1.0f};
520 MoveModelf(trans, angle, scale);
521 m_MVP = m_Projection * m_View * m_Model;
524 //render to fbo
525 //fill vertex buffer
526 glBindBuffer(GL_ARRAY_BUFFER, m_VertexBuffer);
527 glBufferData(GL_ARRAY_BUFFER, sizeof(pointList.points), pointList.points, GL_STATIC_DRAW);
529 glBindBuffer(GL_ARRAY_BUFFER, m_ColorBuffer);
530 glBufferData(GL_ARRAY_BUFFER, sizeof(m_BackgroundColor), m_BackgroundColor, GL_STATIC_DRAW);
531 glUseProgram(m_BackgroundProID);
533 glUniformMatrix4fv(m_BackgroundMatrixID, 1, GL_FALSE, &m_MVP[0][0]);
534 if(bFill)
536 glEnableVertexAttribArray(m_BackgroundVertexID);
537 glBindBuffer(GL_ARRAY_BUFFER, m_VertexBuffer);
538 glVertexAttribPointer(
539 m_BackgroundVertexID, // attribute. No particular reason for 0, but must match the layout in the shader.
540 3, // size
541 GL_FLOAT, // type
542 GL_FALSE, // normalized?
543 0, // stride
544 nullptr // array buffer offset
547 // 2nd attribute buffer : color
548 glEnableVertexAttribArray(m_BackgroundColorID);
549 glBindBuffer(GL_ARRAY_BUFFER, m_ColorBuffer);
550 glVertexAttribPointer(
551 m_BackgroundColorID, // attribute. No particular reason for 0, but must match the layout in the shader.
552 4, // size
553 GL_FLOAT, // type
554 GL_FALSE, // normalized?
555 0, // stride
556 nullptr // array buffer offset
558 //TODO: moggi: get rid of GL_QUADS
559 glDrawArrays(GL_QUADS, 0, 4);
560 glDisableVertexAttribArray(m_BackgroundVertexID);
561 glDisableVertexAttribArray(m_BackgroundColorID);
563 if(bBorder)
565 if(bFill)
567 PosVecf3 const trans = {0.0, 0.0, Z_STEP };
568 PosVecf3 const angle = {0.0f, 0.0f, 0.0f};
569 PosVecf3 const scale = {1, 1, 1.0f};
570 MoveModelf(trans, angle, scale);
571 m_MVP = m_Projection * m_View * m_Model;
573 m_fZStep += Z_STEP;
574 glUniformMatrix4fv(m_BackgroundMatrixID, 1, GL_FALSE, &m_MVP[0][0]);
576 SetBackGroundColor(COL_BLACK, COL_BLACK, css::drawing::FillStyle_SOLID);
578 glBindBuffer(GL_ARRAY_BUFFER, m_ColorBuffer);
579 glBufferData(GL_ARRAY_BUFFER, sizeof(m_BackgroundColor), m_BackgroundColor, GL_STATIC_DRAW);
580 // 1rst attribute buffer : vertices
581 glEnableVertexAttribArray(m_BackgroundVertexID);
582 glBindBuffer(GL_ARRAY_BUFFER, m_VertexBuffer);
583 glVertexAttribPointer(
584 m_BackgroundVertexID, // attribute. No particular reason for 0, but must match the layout in the shader.
585 3, // size
586 GL_FLOAT, // type
587 GL_FALSE, // normalized?
588 0, // stride
589 nullptr // array buffer offset
592 // 2nd attribute buffer : color
593 glEnableVertexAttribArray(m_BackgroundColorID);
594 glBindBuffer(GL_ARRAY_BUFFER, m_ColorBuffer);
595 glVertexAttribPointer(
596 m_BackgroundColorID, // attribute. No particular reason for 0, but must match the layout in the shader.
597 4, // size
598 GL_FLOAT, // type
599 GL_FALSE, // normalized?
600 0, // stride
601 nullptr // array buffer offset
603 glDrawArrays(GL_LINE_LOOP, 0, 4);
604 glDisableVertexAttribArray(m_BackgroundVertexID);
605 glDisableVertexAttribArray(m_BackgroundColorID);
607 glDisableVertexAttribArray(m_BackgroundVertexID);
608 glDisableVertexAttribArray(m_BackgroundColorID);
609 glUseProgram(0);
610 glBindBuffer(GL_ARRAY_BUFFER, 0);
612 m_RectangleShapePointList.clear();
613 CHECK_GL_ERROR();
615 m_fZStep += Z_STEP;
616 return 0;
620 int OpenGLRender::CreateTextTexture(const BitmapEx& rBitmapEx, const awt::Size& aSize, long rotation,
621 const drawing::HomogenMatrix3& rTrans)
623 #if DEBUG_PNG // debug PNG writing
624 static int nIdx = 0;
625 OUString aName = OUString( "file:///home/moggi/Documents/work/text" ) + OUString::number( nIdx++ ) + ".png";
626 try {
627 vcl::PNGWriter aWriter( rBitmapEx );
628 SvFileStream sOutput( aName, StreamMode::WRITE );
629 aWriter.Write( sOutput );
630 sOutput.Close();
631 } catch (...) {
632 SAL_WARN("chart2.opengl", "Error writing png to " << aName);
634 #endif
636 boost::shared_array<sal_uInt8> bitmapBuf(new sal_uInt8[4 * rBitmapEx.GetSizePixel().Width() * rBitmapEx.GetSizePixel().Height()]);
638 OpenGLHelper::ConvertBitmapExToRGBATextureBuffer(rBitmapEx, bitmapBuf.get());
640 return CreateTextTexture(bitmapBuf, rBitmapEx.GetSizePixel(),
641 aSize, rotation, rTrans);
644 int OpenGLRender::CreateTextTexture(const boost::shared_array<sal_uInt8> &rPixels,
645 const ::Size &aPixelSize,
646 const awt::Size& aSize,
647 long rotation,
648 const drawing::HomogenMatrix3& rTrans)
650 long bmpWidth = aPixelSize.Width();
651 long bmpHeight = aPixelSize.Height();
653 TextInfo aTextInfo;
654 aTextInfo.rotation = -static_cast<double>(rotation) / 360.0 * 2* GL_PI;
655 aTextInfo.vertex[0] = -aSize.Width / 2;
656 aTextInfo.vertex[1] = -aSize.Height / 2;
657 aTextInfo.vertex[2] = m_fZStep;
659 aTextInfo.vertex[3] = aSize.Width / 2;
660 aTextInfo.vertex[4] = -aSize.Height / 2;
661 aTextInfo.vertex[5] = m_fZStep;
663 aTextInfo.vertex[6] = aSize.Width / 2;
664 aTextInfo.vertex[7] = aSize.Height / 2;
665 aTextInfo.vertex[8] = m_fZStep;
667 aTextInfo.vertex[9] = -aSize.Width / 2;
668 aTextInfo.vertex[10] = aSize.Height / 2;
669 aTextInfo.vertex[11] = m_fZStep;
670 aTextInfo.nDx = (rTrans.Line1.Column3 + aSize.Width / 2 ) - bmpWidth/2;
671 aTextInfo.nDy = (rTrans.Line2.Column3 + aSize.Height / 2 ) - bmpHeight/2;
673 CHECK_GL_ERROR();
674 glGenTextures(1, &aTextInfo.texture);
675 CHECK_GL_ERROR();
676 glBindTexture(GL_TEXTURE_2D, aTextInfo.texture);
677 CHECK_GL_ERROR();
678 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
679 CHECK_GL_ERROR();
680 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
681 CHECK_GL_ERROR();
682 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
683 CHECK_GL_ERROR();
684 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
685 CHECK_GL_ERROR();
686 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bmpWidth, bmpHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, rPixels.get());
687 CHECK_GL_ERROR();
688 glBindTexture(GL_TEXTURE_2D, 0);
689 CHECK_GL_ERROR();
690 m_TextInfoVector.push_back(aTextInfo);
691 return 0;
694 int OpenGLRender::RenderTextShape()
696 CHECK_GL_ERROR();
697 for (auto const& textInfo : m_TextInfoVector)
699 PosVecf3 const trans = { textInfo.nDx, textInfo.nDy, 0};
700 PosVecf3 const angle = {0.0f, 0.0f, float(textInfo.rotation)};
701 PosVecf3 const scale = {1.0, 1.0, 1.0f};
702 MoveModelf(trans, angle, scale);
703 m_MVP = m_Projection * m_View * m_Model;
704 glBindBuffer(GL_ARRAY_BUFFER, m_VertexBuffer);
705 CHECK_GL_ERROR();
706 glBufferData(GL_ARRAY_BUFFER, sizeof(textInfo.vertex), textInfo.vertex, GL_STATIC_DRAW);
707 CHECK_GL_ERROR();
708 glUseProgram(m_TextProID);
710 CHECK_GL_ERROR();
711 glUniformMatrix4fv(m_TextMatrixID, 1, GL_FALSE, &m_MVP[0][0]);
712 // 1rst attribute buffer : vertices
713 glEnableVertexAttribArray(m_TextVertexID);
714 glBindBuffer(GL_ARRAY_BUFFER, m_VertexBuffer);
715 glVertexAttribPointer(
716 m_TextVertexID,
717 3, // size
718 GL_FLOAT, // type
719 GL_FALSE, // normalized?
720 0, // stride
721 nullptr // array buffer offset
723 //tex coord
724 CHECK_GL_ERROR();
725 glEnableVertexAttribArray(m_TextTexCoordID);
726 glBindBuffer(GL_ARRAY_BUFFER, m_TextTexCoordBuf);
727 glVertexAttribPointer(
728 m_TextTexCoordID,
729 2, // size
730 GL_FLOAT, // type
731 GL_FALSE, // normalized?
732 0, // stride
733 nullptr // array buffer offset
735 //texture
736 CHECK_GL_ERROR();
737 glBindTexture(GL_TEXTURE_2D, textInfo.texture);
738 CHECK_GL_ERROR();
739 glUniform1i(m_TextTexID, 0);
740 CHECK_GL_ERROR();
741 //TODO: moggi: get rid fo GL_QUADS
742 glDrawArrays(GL_QUADS, 0, 4);
743 CHECK_GL_ERROR();
744 glDisableVertexAttribArray(m_TextTexCoordID);
745 CHECK_GL_ERROR();
746 glDisableVertexAttribArray(m_TextVertexID);
747 CHECK_GL_ERROR();
748 glBindTexture(GL_TEXTURE_2D, 0);
749 glUseProgram(0);
750 glDeleteTextures(1, &textInfo.texture);
751 CHECK_GL_ERROR();
753 m_TextInfoVector.clear();
754 CHECK_GL_ERROR();
755 m_fZStep += Z_STEP;
756 return 0;
759 int OpenGLRender::SetArea2DShapePoint(float x, float y, int listLength)
761 if (m_Area2DPointList.empty())
763 m_Area2DPointList.reserve(listLength);
765 m_Area2DPointList.push_back(x);
766 m_Area2DPointList.push_back(y);
767 m_Area2DPointList.push_back(m_fZStep);
769 if (m_Area2DPointList.size() == size_t(listLength * 3))
771 m_Area2DShapePointList.push_back(m_Area2DPointList);
772 m_Area2DPointList.clear();
774 return 0;
777 namespace {
779 // only 2D
780 bool checkCCW(const PointList& rPoints)
782 if(rPoints.size() < 3)
783 return true;
785 GLfloat sum = 0;
786 for(size_t i = 1; i < rPoints.size()/3; i += 3)
788 GLfloat x1 = rPoints[(i-1)*3];
789 GLfloat x2 = rPoints[i*3];
790 GLfloat y1 = rPoints[(i-1)*3 + 1];
791 GLfloat y2 = rPoints[i*3 + 1];
792 GLfloat prod = (x2-x1)*(y2+y1);
794 sum += prod;
797 return (sum <= 0);
802 int OpenGLRender::RenderArea2DShape()
804 CHECK_GL_ERROR();
806 glDisable(GL_MULTISAMPLE);
807 PosVecf3 const trans = {0.0f, 0.0f, 0.0f};
808 PosVecf3 const angle = {0.0f, 0.0f, 0.0f};
809 PosVecf3 const scale = {1.0f, 1.0f, 1.0f};
810 MoveModelf(trans, angle, scale);
811 m_MVP = m_Projection * m_View * m_Model;
812 for (auto const& pointList : m_Area2DShapePointList)
814 bool bIsCCW = checkCCW(pointList); // is it counter clockwise (CCW) or clockwise (CW)
815 if(!bIsCCW)
816 glFrontFace(GL_CW);
817 //fill vertex buffer
818 glBindBuffer(GL_ARRAY_BUFFER, m_VertexBuffer);
819 glBufferData(GL_ARRAY_BUFFER, pointList.size() * sizeof(float), &pointList[0], GL_STATIC_DRAW);
820 // Use our shader
821 glUseProgram(m_CommonProID);
823 glUniform4fv(m_2DColorID, 1, &m_2DColor[0]);
825 glUniformMatrix4fv(m_MatrixID, 1, GL_FALSE, &m_MVP[0][0]);
827 // 1rst attribute buffer : vertices
828 glEnableVertexAttribArray(m_2DVertexID);
829 glBindBuffer(GL_ARRAY_BUFFER, m_VertexBuffer);
830 glVertexAttribPointer(
831 m_2DVertexID, // attribute. No particular reason for 0, but must match the layout in the shader.
832 3, // size
833 GL_FLOAT, // type
834 GL_FALSE, // normalized?
835 0, // stride
836 nullptr // array buffer offset
838 // TODO: moggi: remove deprecated GL_POLYGON
839 glDrawArrays(GL_POLYGON, 0, pointList.size() / 3); // 12*3 indices starting at 0 -> 12 triangles
840 glDisableVertexAttribArray(m_2DVertexID);
841 glUseProgram(0);
842 if(!bIsCCW)
843 glFrontFace(GL_CCW);
845 m_Area2DShapePointList.clear();
846 glEnable(GL_MULTISAMPLE);
847 m_fZStep += Z_STEP;
849 CHECK_GL_ERROR();
851 return 0;
854 void OpenGLRender::SetBackGroundColor(::Color color1, ::Color color2, css::drawing::FillStyle fillStyle)
856 sal_uInt8 r = color1.GetRed();
857 sal_uInt8 g = color1.GetGreen();
858 sal_uInt8 b = color1.GetBlue();
860 m_BackgroundColor[0] = static_cast<float>(r) / 255.0f;
861 m_BackgroundColor[1] = static_cast<float>(g) / 255.0f;
862 m_BackgroundColor[2] = static_cast<float>(b) / 255.0f;
863 m_BackgroundColor[3] = fillStyle != css::drawing::FillStyle_NONE ? 1.0 : 0.0;
865 m_BackgroundColor[4] = static_cast<float>(r) / 255.0f;
866 m_BackgroundColor[5] = static_cast<float>(g) / 255.0f;
867 m_BackgroundColor[6] = static_cast<float>(b) / 255.0f;
868 m_BackgroundColor[7] = fillStyle != css::drawing::FillStyle_NONE ? 1.0 : 0.0;
870 r = color2.GetRed();
871 g = color2.GetGreen();
872 b = color2.GetBlue();
874 m_BackgroundColor[8] = static_cast<float>(r) / 255.0f;
875 m_BackgroundColor[9] = static_cast<float>(g) / 255.0f;
876 m_BackgroundColor[10] = static_cast<float>(b) / 255.0f;
877 m_BackgroundColor[11] = fillStyle != css::drawing::FillStyle_NONE ? 1.0 : 0.0;
879 m_BackgroundColor[12] = static_cast<float>(r) / 255.0f;
880 m_BackgroundColor[13] = static_cast<float>(g) / 255.0f;
881 m_BackgroundColor[14] = static_cast<float>(b) / 255.0f;
882 m_BackgroundColor[15] = fillStyle != css::drawing::FillStyle_NONE ? 1.0 : 0.0;
883 SAL_INFO("chart2.opengl", "color1 = " << sal_uInt32(color1) << ", color2 = " << sal_uInt32(color2));
887 void OpenGLRender::SetChartTransparencyGradient(long transparencyGradient)
889 if (transparencyGradient == 1)
891 m_BackgroundColor[11] = 0.0;
892 m_BackgroundColor[15] = 0.0;
896 void OpenGLRender::GeneratePieSegment2D(double fInnerRadius, double fOutterRadius, double nAngleStart, double nAngleWidth)
898 double nAngleStep = 1;
899 PointList aPointList;
900 // TODO: moggi: GL_TRIANGLE_FAN seems not to work
901 const bool bInnerRadiusNotZero = true; //!rtl::math::approxEqual(0.0, fInnerRadius);
902 size_t nVectorSize = 3*(nAngleWidth/nAngleStep);
903 if(bInnerRadiusNotZero)
904 nVectorSize *= 2;
906 nAngleStart += 90;
907 aPointList.reserve(nVectorSize);
908 // if inner radius = 0 generate a normal pie segment (triangle fan)
909 // if inner radius != 0 generate a pie segment - inner pie (triangle strip)
910 if(!bInnerRadiusNotZero)
912 aPointList.push_back(0);
913 aPointList.push_back(0);
914 aPointList.push_back(m_fZStep);
916 for(double nAngle = nAngleStart; nAngle <= nAngleStart + nAngleWidth; nAngle += nAngleStep)
918 float xVal = sin(nAngle/360*2*GL_PI);
919 float yVal = cos(nAngle/360*2*GL_PI);
920 aPointList.push_back(fOutterRadius * xVal);
921 aPointList.push_back(fOutterRadius * yVal);
922 aPointList.push_back(m_fZStep);
924 if(bInnerRadiusNotZero)
926 aPointList.push_back(fInnerRadius * xVal);
927 aPointList.push_back(fInnerRadius * yVal);
928 aPointList.push_back(m_fZStep);
932 m_PieSegment2DShapePointList.push_back(aPointList);
935 int OpenGLRender::RenderPieSegment2DShape(float fSize, float fPosX, float fPosY)
937 int listNum = m_PieSegment2DShapePointList.size();
938 PosVecf3 const trans = {fPosX, fPosY, 0.0f};
939 PosVecf3 const angle = {0.0f, 0.0f, 0.0f};
940 PosVecf3 const scale = {fSize, fSize, 1.0f};
941 MoveModelf(trans, angle, scale);
942 m_MVP = m_Projection * m_View * m_Model;
944 for (int i = 0; i < listNum; i++)
946 PointList &pointList = m_PieSegment2DShapePointList.back();
947 //fill vertex buffer
948 glBindBuffer(GL_ARRAY_BUFFER, m_VertexBuffer);
949 glBufferData(GL_ARRAY_BUFFER, pointList.size() * sizeof(float), &pointList[0] , GL_STATIC_DRAW);
950 // Use our shader
951 glUseProgram(m_CommonProID);
953 glUniform4fv(m_2DColorID, 1, &m_2DColor[0]);
955 glUniformMatrix4fv(m_MatrixID, 1, GL_FALSE, &m_MVP[0][0]);
957 // 1rst attribute buffer : vertices
958 glEnableVertexAttribArray(m_2DVertexID);
959 glBindBuffer(GL_ARRAY_BUFFER, m_VertexBuffer);
960 glVertexAttribPointer(
961 m_2DVertexID, // attribute. No particular reason for 0, but must match the layout in the shader.
962 3, // size
963 GL_FLOAT, // type
964 GL_FALSE, // normalized?
965 0, // stride
966 nullptr // array buffer offset
968 glDrawArrays(GL_TRIANGLE_STRIP, 0, pointList.size() / 3); // 12*3 indices starting at 0 -> 12 triangles
969 glDisableVertexAttribArray(m_2DVertexID);
970 glUseProgram(0);
971 m_PieSegment2DShapePointList.pop_back();
972 CHECK_GL_ERROR();
975 m_fZStep += Z_STEP;
977 CHECK_GL_ERROR();
978 return 0;
981 int OpenGLRender::RenderSymbol2DShape(float x, float y, sal_Int32 nSymbol)
983 CHECK_GL_ERROR();
985 glPointSize(20.f);
986 CHECK_GL_ERROR();
987 PosVecf3 const trans = {0.0, 0.0, 0.0};
988 PosVecf3 const angle = {0.0f, 0.0f, 0.0f};
989 PosVecf3 const scale = {1.0, 1.0, 1.0f};
990 MoveModelf(trans, angle, scale);
991 m_MVP = m_Projection * m_View * m_Model;
993 float aPos[3] = { x, y, m_fZStep };
994 //fill vertex buffer
995 glBindBuffer(GL_ARRAY_BUFFER, m_VertexBuffer);
996 CHECK_GL_ERROR();
997 glBufferData(GL_ARRAY_BUFFER, 3 * sizeof(float), aPos, GL_STATIC_DRAW);
998 CHECK_GL_ERROR();
1000 // Use our shader
1001 glUseProgram(m_SymbolProID);
1002 CHECK_GL_ERROR();
1004 glUniform4fv(m_SymbolColorID, 1, &m_2DColor[0]);
1005 glUniform1i(m_SymbolShapeID, nSymbol);
1006 CHECK_GL_ERROR();
1008 glUniformMatrix4fv(m_SymbolMatrixID, 1, GL_FALSE, &m_MVP[0][0]);
1010 CHECK_GL_ERROR();
1011 // 1rst attribute buffer : vertices
1012 glEnableVertexAttribArray(m_SymbolVertexID);
1013 glBindBuffer(GL_ARRAY_BUFFER, m_VertexBuffer);
1014 glVertexAttribPointer(
1015 m_SymbolVertexID, // attribute. No particular reason for 0, but must match the layout in the shader.
1016 3, // size
1017 GL_FLOAT, // type
1018 GL_FALSE, // normalized?
1019 0, // stride
1020 nullptr // array buffer offset
1023 glDrawArrays(GL_POINTS, 0, 1);
1025 glDisableVertexAttribArray(m_SymbolVertexID);
1026 CHECK_GL_ERROR();
1027 glUseProgram(0);
1028 m_fZStep += Z_STEP;
1030 CHECK_GL_ERROR();
1031 return 0;
1034 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */