Files
loongoffice/chart2/source/view/main/OpenGLRender.cxx
Markus Mohrhard 0c3a8965b5 simplify code
Change-Id: If0b1c47a1e0f6084795fb5ca4a2acced736d4523
2014-09-02 01:08:49 +02:00

1083 lines
38 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#include <GL/glew.h>
#include <vector>
#include "OpenGLRender.hxx"
#include <vcl/graph.hxx>
#include <com/sun/star/awt/XBitmap.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/graphic/XGraphic.hpp>
#include <comphelper/InlineContainer.hxx>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/drawing/CircleKind.hpp>
#include <com/sun/star/drawing/DoubleSequence.hpp>
#include <com/sun/star/drawing/FlagSequence.hpp>
#include <com/sun/star/drawing/FillStyle.hpp>
#include <com/sun/star/drawing/LineStyle.hpp>
#include <com/sun/star/drawing/NormalsKind.hpp>
#include <com/sun/star/drawing/PointSequence.hpp>
#include <com/sun/star/drawing/PolygonKind.hpp>
#include <com/sun/star/drawing/PolyPolygonBezierCoords.hpp>
#include <com/sun/star/drawing/ProjectionMode.hpp>
#include <com/sun/star/drawing/ShadeMode.hpp>
#include <com/sun/star/drawing/TextFitToSizeType.hpp>
#include <com/sun/star/drawing/TextureProjectionMode.hpp>
#include <com/sun/star/text/XText.hpp>
#include <com/sun/star/uno/Any.hxx>
#include <editeng/unoprnms.hxx>
#include <vcl/virdev.hxx>
#include <vcl/dibtools.hxx>
#include <vcl/svapp.hxx>
#include <vcl/opengl/OpenGLHelper.hxx>
#include "CommonConverters.hxx"
using namespace com::sun::star;
#define DEBUG_PNG 0
#if DEBUG_PNG
#include <vcl/pngwrite.hxx>
#endif
#define GL_PI 3.14159f
#define Z_STEP 0.001f
static GLfloat squareVertices[] = {
-1.0f, -1.0f, -1.0,
1.0f, -1.0f, -1.0,
1.0f, 1.0f, -1.0,
-1.0f, 1.0f, -1.0
};
static GLfloat coordReverseVertices[] = {
0.0f, 1.0f,
1.0f, 1.0f,
1.0f, 0.0f,
0.0f, 0.0f,
};
#define CHECK_GL_FRAME_BUFFER_STATUS() \
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);\
if( status != GL_FRAMEBUFFER_COMPLETE ) {\
SAL_WARN("chart2.opengl", "OpenGL error: " << status );\
return -1;\
}
namespace {
GLfloat texCoords[] = {
0.0f, 0.0f,
1.0f, 0.0f,
1.0f, 1.0f,
0.0f, 1.0f
};
}
int OpenGLRender::InitOpenGL()
{
glEnable(GL_TEXTURE_2D);
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
// Enable depth test
glEnable(GL_DEPTH_TEST);
// Accept fragment if it closer to the camera than the former one
glDepthFunc(GL_LESS);
glEnable(GL_POINT_SMOOTH);
glEnable(GL_LINE_SMOOTH);
glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glClearColor (1.0, 1.0, 1.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
glClearDepth(1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//Init the Projection matrix
m_Projection = glm::ortho(0.f, float(m_iWidth), 0.f, float(m_iHeight), -1.f, 1.f);
m_View = glm::lookAt(glm::vec3(0,0,1), // Camera is at (4,3,-3), in World Space
glm::vec3(0,0,0), // and looks at the origin
glm::vec3(0,1,0) // Head is up (set to 0,-1,0 to look upside-down)
);
m_MVP = m_Projection * m_View * m_Model;
glGenBuffers(1, &m_VertexBuffer);
glGenBuffers(1, &m_ColorBuffer);
CHECK_GL_ERROR();
m_CommonProID = OpenGLHelper::LoadShaders("commonVertexShader", "commonFragmentShader");
m_MatrixID = glGetUniformLocation(m_CommonProID, "MVP");
m_2DVertexID = glGetAttribLocation(m_CommonProID, "vPosition");
m_2DColorID = glGetUniformLocation(m_CommonProID, "vColor");
CHECK_GL_ERROR();
#if DEBUG_POSITIONING
m_DebugProID = OpenGLHelper::LoadShaders("debugVertexShader", "debugFragmentShader");
m_DebugVertexID = glGetAttribLocation(m_DebugProID, "vPosition");
CHECK_GL_ERROR();
#endif
m_BackgroundProID = OpenGLHelper::LoadShaders("backgroundVertexShader", "backgroundFragmentShader");
m_BackgroundMatrixID = glGetUniformLocation(m_BackgroundProID, "MVP");
m_BackgroundVertexID = glGetAttribLocation(m_BackgroundProID, "vPosition");
m_BackgroundColorID = glGetAttribLocation(m_BackgroundProID, "vColor");
CHECK_GL_ERROR();
m_SymbolProID = OpenGLHelper::LoadShaders("symbolVertexShader", "symbolFragmentShader");
m_SymbolVertexID = glGetAttribLocation(m_SymbolProID, "vPosition");
m_SymbolMatrixID = glGetUniformLocation(m_SymbolProID, "MVP");
m_SymbolColorID = glGetUniformLocation(m_SymbolProID, "vColor");
m_SymbolShapeID = glGetUniformLocation(m_SymbolProID, "shape");
CHECK_GL_ERROR();
m_TextProID = OpenGLHelper::LoadShaders("textVertexShader", "textFragmentShader");
m_TextMatrixID = glGetUniformLocation(m_TextProID, "MVP");
m_TextVertexID = glGetAttribLocation(m_TextProID, "vPosition");
m_TextTexCoordID = glGetAttribLocation(m_TextProID, "texCoord");
m_TextTexID = glGetUniformLocation(m_TextProID, "TextTex");
CHECK_GL_ERROR();
glGenBuffers(1, &m_RenderVertexBuf);
glBindBuffer(GL_ARRAY_BUFFER, m_RenderVertexBuf);
glBufferData(GL_ARRAY_BUFFER, sizeof(squareVertices), squareVertices, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glGenBuffers(1, &m_RenderTexCoordBuf);
glBindBuffer(GL_ARRAY_BUFFER, m_RenderTexCoordBuf);
glBufferData(GL_ARRAY_BUFFER, sizeof(coordReverseVertices), coordReverseVertices, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glGenBuffers(1, &m_TextTexCoordBuf);
glBindBuffer(GL_ARRAY_BUFFER, m_TextTexCoordBuf);
glBufferData(GL_ARRAY_BUFFER, sizeof(texCoords), texCoords, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glEnable(GL_LIGHTING);
GLfloat light_direction[] = { 0.0 , 0.0 , 1.0 };
GLfloat materialDiffuse[] = { 1.0 , 1.0 , 1.0 , 1.0};
glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, light_direction);
glMaterialfv(GL_FRONT,GL_DIFFUSE,materialDiffuse);
glEnable(GL_LIGHT0);
glEnable(GL_NORMALIZE);
return 0;
}
int OpenGLRender::SetLine2DShapePoint(float x, float y, int listLength)
{
if (m_Line2DPointList.empty())
{
m_Line2DPointList.reserve(listLength*3);
}
float actualX = (x / OPENGL_SCALE_VALUE);
float actualY = (y / OPENGL_SCALE_VALUE);
m_Line2DPointList.push_back(actualX);
m_Line2DPointList.push_back(actualY);
m_Line2DPointList.push_back(m_fZStep);
if (m_Line2DPointList.size() == size_t(listLength * 3))
{
m_Line2DShapePointList.push_back(m_Line2DPointList);
m_Line2DPointList.clear();
}
return 0;
}
int OpenGLRender::RenderLine2FBO(int)
{
CHECK_GL_ERROR();
glLineWidth(m_fLineWidth);
size_t listNum = m_Line2DShapePointList.size();
PosVecf3 trans = {0.0f, 0.0f, 0.0f};
PosVecf3 angle = {0.0f, 0.0f, 0.0f};
PosVecf3 scale = {1.0f, 1.0f, 1.0f};
MoveModelf(trans, angle, scale);
m_MVP = m_Projection * m_View * m_Model;
for (size_t i = 0; i < listNum; i++)
{
PointList &pointList = m_Line2DShapePointList.front();
//fill vertex buffer
glBindBuffer(GL_ARRAY_BUFFER, m_VertexBuffer);
CHECK_GL_ERROR();
glBufferData(GL_ARRAY_BUFFER, pointList.size() * sizeof(float), &pointList[0], GL_STATIC_DRAW);
CHECK_GL_ERROR();
// Use our shader
glUseProgram(m_CommonProID);
CHECK_GL_ERROR();
glUniform4fv(m_2DColorID, 1, &m_2DColor[0]);
CHECK_GL_ERROR();
glUniformMatrix4fv(m_MatrixID, 1, GL_FALSE, &m_MVP[0][0]);
//CHECK_GL_ERROR();
// 1rst attribute buffer : vertices
CHECK_GL_ERROR();
glVertexAttribPointer(
m_2DVertexID,
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
glEnableVertexAttribArray(m_2DVertexID);
glDrawArrays(GL_LINE_STRIP, 0, pointList.size()/3); // 12*3 indices starting at 0 -> 12 triangles
CHECK_GL_ERROR();
glUseProgram(0);
glDisableVertexAttribArray(m_2DVertexID);
CHECK_GL_ERROR();
m_Line2DShapePointList.pop_front();
}
CHECK_GL_ERROR();
CHECK_GL_FRAME_BUFFER_STATUS();
m_fZStep += Z_STEP;
return 0;
}
#if DEBUG_POSITIONING
void OpenGLRender::renderDebug()
{
CHECK_GL_ERROR();
GLfloat vertices[4][3] = {
{-0.9, -0.9, 0 },
{-0.6, -0.2, 0 },
{0.3, 0.3, 0 },
{0.9, 0.9, 0 } };
glBindBuffer(GL_ARRAY_BUFFER, m_VertexBuffer);
CHECK_GL_ERROR();
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
CHECK_GL_ERROR();
glUseProgram(m_DebugProID);
CHECK_GL_ERROR();
glVertexAttribPointer(m_DebugVertexID, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
CHECK_GL_ERROR();
glEnableVertexAttribArray(m_DebugVertexID);
glDrawArrays(GL_LINE_STRIP, 0, 3);
CHECK_GL_ERROR();
glDisableVertexAttribArray(m_DebugVertexID);
CHECK_GL_ERROR();
}
#endif
void OpenGLRender::prepareToRender()
{
glViewport(0, 0, m_iWidth, m_iHeight);
// Clear the screen
glClearDepth(1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
m_fZStep = 0;
}
int OpenGLRender::MoveModelf(PosVecf3 trans, PosVecf3 angle, PosVecf3 scale)
{
glm::mat4 aTranslationMatrix = glm::translate(glm::vec3(trans.x, trans.y, trans.z));
glm::mat4 aScaleMatrix = glm::scale(glm::vec3(scale.x, scale.y, scale.z));
glm::mat4 aRotationMatrix = glm::eulerAngleYXZ(angle.y, angle.x, angle.z);
m_Model = aTranslationMatrix * aRotationMatrix * aScaleMatrix;
return 0;
}
void OpenGLRender::Release()
{
glDeleteBuffers(1, &m_VertexBuffer);
glDeleteBuffers(1, &m_ColorBuffer);
glDeleteBuffers(1, &m_TextTexCoordBuf);
glDeleteProgram(m_CommonProID);
glDeleteProgram(m_TextProID);
glDeleteProgram(m_BackgroundProID);
glDeleteProgram(m_SymbolProID);
}
OpenGLRender::OpenGLRender()
: m_iWidth(1600)
, m_iHeight(900)
, m_Model(glm::mat4(1.0f))
, m_VertexBuffer(0)
, m_ColorBuffer(0)
, m_MatrixID(0)
, m_RenderVertexBuf(0)
, m_RenderTexCoordBuf(0)
, m_fLineWidth(0.001f)
, m_2DColor(glm::vec4(1.0, 0.0, 0.0, 1.0))
, m_CommonProID(0)
, m_2DVertexID(0)
, m_2DColorID(0)
, m_fZStep(0)
, m_TextProID(0)
, m_TextMatrixID(0)
, m_TextVertexID(0)
, m_TextTexCoordID(0)
, m_TextTexCoordBuf(0)
, m_TextTexID(0)
, m_BackgroundProID(0)
, m_BackgroundMatrixID(0)
, m_BackgroundVertexID(0)
, m_BackgroundColorID(0)
, m_SymbolProID(0)
, m_SymbolVertexID(0)
, m_SymbolMatrixID(0)
, m_SymbolColorID(0)
, m_SymbolShapeID(0)
{
//TODO: moggi: use STL
for (size_t i = 0; i < sizeof(m_BackgroundColor) / sizeof(float); i++)
{
m_BackgroundColor[i] = 1.0;
}
}
OpenGLRender::~OpenGLRender()
{
Release();
}
// TODO: moggi: that screws up FBO if called after buffers have been created!!!!
void OpenGLRender::SetSize(int width, int height)
{
m_iWidth = width;
m_iHeight = height;
m_Projection = glm::ortho(0.f, float(m_iWidth), 0.f, float(m_iHeight), -4.f, 3.f);
}
void OpenGLRender::SetLine2DColor(sal_uInt8 r, sal_uInt8 g, sal_uInt8 b, sal_uInt8 nAlpha)
{
m_2DColor = glm::vec4((float)r / 255.0f, (float)g / 255.0f, (float)b / 255.0f, nAlpha/255.f);
}
void OpenGLRender::SetLine2DWidth(int width)
{
m_fLineWidth = std::max((float)width / OPENGL_SCALE_VALUE, 0.001f);
}
void OpenGLRender::SetColor(sal_uInt32 color, sal_uInt8 nAlpha)
{
sal_uInt8 r = (color & 0x00FF0000) >> 16;
sal_uInt8 g = (color & 0x0000FF00) >> 8;
sal_uInt8 b = (color & 0x000000FF);
m_2DColor = glm::vec4((float)r / 255.0f, (float)g / 255.0f, (float)b / 255.0f, nAlpha/ 255.f);
}
int OpenGLRender::Create2DCircle(int detail)
{
float angle;
if (detail <= 0)
{
return -1;
}
m_Bubble2DCircle.clear();
m_Bubble2DCircle.reserve(2 * (detail + 3));
m_Bubble2DCircle.push_back(0);
m_Bubble2DCircle.push_back(0);
for(angle = 2.0f * GL_PI; angle > -(2.0f * GL_PI / detail); angle -= (2.0f * GL_PI / detail))
{
m_Bubble2DCircle.push_back(sin(angle));
m_Bubble2DCircle.push_back(cos(angle));
}
return 0;
}
int OpenGLRender::Bubble2DShapePoint(float x, float y, float directionX, float directionY)
{
//check whether to create the circle data
if (m_Bubble2DCircle.empty())
{
Create2DCircle(100);
}
float actualX = (x / OPENGL_SCALE_VALUE);
float actualY = (y / OPENGL_SCALE_VALUE);
Bubble2DPointList aBubble2DPointList;
aBubble2DPointList.xScale = directionX / OPENGL_SCALE_VALUE;
aBubble2DPointList.yScale = directionY / OPENGL_SCALE_VALUE;
aBubble2DPointList.x = actualX + aBubble2DPointList.xScale / 2;
aBubble2DPointList.y = actualY + aBubble2DPointList.yScale / 2;
m_Bubble2DShapePointList.push_back(aBubble2DPointList);
return 0;
}
int OpenGLRender::RenderBubble2FBO(int)
{
CHECK_GL_ERROR();
glm::vec4 edgeColor = glm::vec4(0.0, 0.0, 0.0, 1.0);
size_t listNum = m_Bubble2DShapePointList.size();
for (size_t i = 0; i < listNum; i++)
{
//move the circle to the pos, and scale using the xScale and Y scale
Bubble2DPointList &pointList = m_Bubble2DShapePointList.front();
PosVecf3 trans = {pointList.x, pointList.y, m_fZStep};
PosVecf3 angle = {0.0f, 0.0f, 0.0f};
PosVecf3 scale = {pointList.xScale / 2, pointList.yScale / 2 , 1.0f};
MoveModelf(trans, angle, scale);
m_MVP = m_Projection * m_View * m_Model;
//render to fbo
//fill vertex buffer
glBindBuffer(GL_ARRAY_BUFFER, m_VertexBuffer);
if (m_Bubble2DCircle.empty())
{
Create2DCircle(100);
}
glBufferData(GL_ARRAY_BUFFER, m_Bubble2DCircle.size() * sizeof(GLfloat), &m_Bubble2DCircle[0], GL_STATIC_DRAW);
glUseProgram(m_CommonProID);
glUniform4fv(m_2DColorID, 1, &m_2DColor[0]);
glUniformMatrix4fv(m_MatrixID, 1, GL_FALSE, &m_MVP[0][0]);
// 1rst attribute buffer : vertices
glEnableVertexAttribArray(m_2DVertexID);
glBindBuffer(GL_ARRAY_BUFFER, m_VertexBuffer);
glVertexAttribPointer(
m_2DVertexID, // attribute. No particular reason for 0, but must match the layout in the shader.
2, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
glDrawArrays(GL_TRIANGLE_FAN, 0, m_Bubble2DCircle.size() / 2);
glDisableVertexAttribArray(m_2DVertexID);
glUseProgram(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
//add black edge
glLineWidth(3.0);
glBindBuffer(GL_ARRAY_BUFFER, m_VertexBuffer);
glBufferData(GL_ARRAY_BUFFER, m_Bubble2DCircle.size() * sizeof(GLfloat) -2 , &m_Bubble2DCircle[2], GL_STATIC_DRAW);
glUseProgram(m_CommonProID);
glUniform4fv(m_2DColorID, 1, &edgeColor[0]);
glUniformMatrix4fv(m_MatrixID, 1, GL_FALSE, &m_MVP[0][0]);
glEnableVertexAttribArray(m_2DVertexID);
glBindBuffer(GL_ARRAY_BUFFER, m_VertexBuffer);
glVertexAttribPointer(
m_2DVertexID, // attribute. No particular reason for 0, but must match the layout in the shader.
2, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
glDrawArrays(GL_LINE_STRIP, 0, (m_Bubble2DCircle.size() * sizeof(GLfloat) -2) / sizeof(float) / 2);
glDisableVertexAttribArray(m_2DVertexID);
glUseProgram(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
m_Bubble2DShapePointList.pop_front();
glLineWidth(m_fLineWidth);
}
//if use MSAA, we should copy the data to the FBO texture
GLenum fbResult = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if( fbResult != GL_FRAMEBUFFER_COMPLETE )
{
SAL_WARN("chart2.opengl", "error");
return -1;
}
CHECK_GL_ERROR();
m_fZStep += Z_STEP;
return 0;
}
int OpenGLRender::RectangleShapePoint(float x, float y, float directionX, float directionY)
{
//check whether to create the circle data
float actualX = x / OPENGL_SCALE_VALUE;
float actualY = y / OPENGL_SCALE_VALUE;
float actualSizeX = directionX / OPENGL_SCALE_VALUE;
float actualSizeY = directionY / OPENGL_SCALE_VALUE;
RectanglePointList aRectangle;
aRectangle.points[0] = actualX;
aRectangle.points[1] = actualY;
aRectangle.points[2] = m_fZStep;
aRectangle.points[3] = actualX + actualSizeX;
aRectangle.points[4] = actualY;
aRectangle.points[5] = m_fZStep;
aRectangle.points[6] = actualX + actualSizeX;
aRectangle.points[7] = actualY + actualSizeY;
aRectangle.points[8] = m_fZStep;
aRectangle.points[9] = actualX;
aRectangle.points[10] = actualY + actualSizeY;
aRectangle.points[11] = m_fZStep;
m_RectangleShapePointList.push_back(aRectangle);
return 0;
}
int OpenGLRender::RenderRectangleShape(bool bBorder, bool bFill)
{
size_t listNum = m_RectangleShapePointList.size();
for (size_t i = 0; i < listNum; i++)
{
//move the circle to the pos, and scale using the xScale and Y scale
RectanglePointList &pointList = m_RectangleShapePointList.front();
{
PosVecf3 trans = {0, 0, 0};
PosVecf3 angle = {0.0f, 0.0f, 0.0f};
PosVecf3 scale = {1, 1, 1.0f};
MoveModelf(trans, angle, scale);
m_MVP = m_Projection * m_View * m_Model;
}
//render to fbo
//fill vertex buffer
glBindBuffer(GL_ARRAY_BUFFER, m_VertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(pointList.points), pointList.points, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, m_ColorBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(m_BackgroundColor), m_BackgroundColor, GL_STATIC_DRAW);
glUseProgram(m_BackgroundProID);
glUniformMatrix4fv(m_BackgroundMatrixID, 1, GL_FALSE, &m_MVP[0][0]);
if(bFill)
{
glEnableVertexAttribArray(m_BackgroundVertexID);
glBindBuffer(GL_ARRAY_BUFFER, m_VertexBuffer);
glVertexAttribPointer(
m_BackgroundVertexID, // attribute. No particular reason for 0, but must match the layout in the shader.
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
// 2nd attribute buffer : color
glEnableVertexAttribArray(m_BackgroundColorID);
glBindBuffer(GL_ARRAY_BUFFER, m_ColorBuffer);
glVertexAttribPointer(
m_BackgroundColorID, // attribute. No particular reason for 0, but must match the layout in the shader.
4, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
//TODO: moggi: get rid of GL_QUADS
glDrawArrays(GL_QUADS, 0, 4);
glDisableVertexAttribArray(m_BackgroundVertexID);
glDisableVertexAttribArray(m_BackgroundColorID);
}
if(bBorder)
{
if(bFill)
{
PosVecf3 trans = {0.0, 0.0, Z_STEP };
PosVecf3 angle = {0.0f, 0.0f, 0.0f};
PosVecf3 scale = {1, 1, 1.0f};
MoveModelf(trans, angle, scale);
m_MVP = m_Projection * m_View * m_Model;
m_fZStep += Z_STEP;
glUniformMatrix4fv(m_BackgroundMatrixID, 1, GL_FALSE, &m_MVP[0][0]);
}
SetBackGroundColor(COL_BLACK, COL_BLACK, 255);
glBindBuffer(GL_ARRAY_BUFFER, m_ColorBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(m_BackgroundColor), m_BackgroundColor, GL_STATIC_DRAW);
// 1rst attribute buffer : vertices
glEnableVertexAttribArray(m_BackgroundVertexID);
glBindBuffer(GL_ARRAY_BUFFER, m_VertexBuffer);
glVertexAttribPointer(
m_BackgroundVertexID, // attribute. No particular reason for 0, but must match the layout in the shader.
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
// 2nd attribute buffer : color
glEnableVertexAttribArray(m_BackgroundColorID);
glBindBuffer(GL_ARRAY_BUFFER, m_ColorBuffer);
glVertexAttribPointer(
m_BackgroundColorID, // attribute. No particular reason for 0, but must match the layout in the shader.
4, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
glDrawArrays(GL_LINE_LOOP, 0, 4);
glDisableVertexAttribArray(m_BackgroundVertexID);
glDisableVertexAttribArray(m_BackgroundColorID);
}
glDisableVertexAttribArray(m_BackgroundVertexID);
glDisableVertexAttribArray(m_BackgroundColorID);
glUseProgram(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
m_RectangleShapePointList.pop_front();
}
CHECK_GL_ERROR();
m_fZStep += Z_STEP;
return 0;
}
int OpenGLRender::CreateTextTexture(::rtl::OUString const &textValue, Font aFont, long , awt::Point aPos, awt::Size aSize, long rotation)
{
VirtualDevice aDevice(*Application::GetDefaultDevice(), 0, 0);
aDevice.Erase();
Rectangle aRect;
aDevice.SetFont(aFont);
aDevice.GetTextBoundRect(aRect, textValue);
int screenWidth = (aRect.BottomRight().X() + 3) & ~3;
int screenHeight = (aRect.BottomRight().Y() + 3) & ~3;
aDevice.SetOutputSizePixel(Size(screenWidth * 3, screenHeight));
aDevice.SetBackground(Wallpaper(COL_TRANSPARENT));
aDevice.DrawText(Point(0, 0), textValue);
int bmpWidth = (aRect.Right() - aRect.Left() + 3) & ~3;
int bmpHeight = (aRect.Bottom() - aRect.Top() + 3) & ~3;
BitmapEx aBitmap = BitmapEx(aDevice.GetBitmapEx(aRect.TopLeft(), Size(bmpWidth, bmpHeight)));
sal_Int32 nXPos = aPos.X;
sal_Int32 nYPos = aPos.Y;
::basegfx::B2DHomMatrix aM;
aM.rotate( -rotation*F_PI/180.0 );//#i78696#->#i80521#
aM.translate( nXPos, nYPos );
drawing::HomogenMatrix3 aTrans = chart::B2DHomMatrixToHomogenMatrix3(aM);
aTrans.Line1.Column1 = 20 * bmpWidth;
aTrans.Line2.Column2 = 20 * bmpHeight;
return CreateTextTexture(aBitmap,aPos,aSize,rotation,aTrans);
}
int OpenGLRender::CreateTextTexture(const BitmapEx& rBitmapEx, const awt::Point&, const awt::Size& aSize, long rotation,
const drawing::HomogenMatrix3& rTrans)
{
#if DEBUG_PNG // debug PNG writing
static int nIdx = 0;
OUString aName = OUString( "file:///home/moggi/Documents/work/text" ) + OUString::number( nIdx++ ) + ".png";
try {
vcl::PNGWriter aWriter( rBitmapEx );
SvFileStream sOutput( aName, STREAM_WRITE );
aWriter.Write( sOutput );
sOutput.Close();
} catch (...) {
SAL_WARN("chart2.opengl", "Error writing png to " << aName);
}
#endif
boost::shared_array<sal_uInt8> bitmapBuf(new sal_uInt8[4 * rBitmapEx.GetSizePixel().Width() * rBitmapEx.GetSizePixel().Height()]);
OpenGLHelper::ConvertBitmapExToRGBATextureBuffer(rBitmapEx, bitmapBuf.get());
return CreateTextTexture(bitmapBuf, rBitmapEx.GetSizePixel(),
awt::Point(), aSize, rotation, rTrans);
}
int OpenGLRender::CreateTextTexture(const boost::shared_array<sal_uInt8> &rPixels,
const ::Size &aPixelSize,
const awt::Point&,
const awt::Size& aSize,
long rotation,
const drawing::HomogenMatrix3& rTrans)
{
long bmpWidth = aPixelSize.Width();
long bmpHeight = aPixelSize.Height();
TextInfo aTextInfo;
aTextInfo.rotation = -(double)rotation / 360.0 * 2* GL_PI;
aTextInfo.vertex[0] = -aSize.Width / 2 / OPENGL_SCALE_VALUE;
aTextInfo.vertex[1] = -aSize.Height / 2 / OPENGL_SCALE_VALUE;
aTextInfo.vertex[2] = m_fZStep;
aTextInfo.vertex[3] = aSize.Width / 2 / OPENGL_SCALE_VALUE ;
aTextInfo.vertex[4] = -aSize.Height / 2 / OPENGL_SCALE_VALUE;
aTextInfo.vertex[5] = m_fZStep;
aTextInfo.vertex[6] = aSize.Width / 2 / OPENGL_SCALE_VALUE;
aTextInfo.vertex[7] = aSize.Height / 2 / OPENGL_SCALE_VALUE;
aTextInfo.vertex[8] = m_fZStep;
aTextInfo.vertex[9] = -aSize.Width / 2 / OPENGL_SCALE_VALUE;
aTextInfo.vertex[10] = aSize.Height / 2 / OPENGL_SCALE_VALUE;
aTextInfo.vertex[11] = m_fZStep;
aTextInfo.nDx = (rTrans.Line1.Column3 + aSize.Width / 2 ) / OPENGL_SCALE_VALUE - bmpWidth/2;
aTextInfo.nDy = (rTrans.Line2.Column3 + aSize.Height / 2 ) / OPENGL_SCALE_VALUE - bmpHeight/2;
CHECK_GL_ERROR();
glGenTextures(1, &aTextInfo.texture);
CHECK_GL_ERROR();
glBindTexture(GL_TEXTURE_2D, aTextInfo.texture);
CHECK_GL_ERROR();
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
CHECK_GL_ERROR();
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
CHECK_GL_ERROR();
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
CHECK_GL_ERROR();
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
CHECK_GL_ERROR();
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bmpWidth, bmpHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, rPixels.get());
CHECK_GL_ERROR();
glBindTexture(GL_TEXTURE_2D, 0);
CHECK_GL_ERROR();
m_TextInfoList.push_back(aTextInfo);
return 0;
}
int OpenGLRender::RenderTextShape()
{
CHECK_GL_ERROR();
size_t listNum = m_TextInfoList.size();
for (size_t i = 0; i < listNum; i++)
{
TextInfo &textInfo = m_TextInfoList.front();
PosVecf3 trans = { textInfo.nDx, textInfo.nDy, 0};
PosVecf3 angle = {0.0f, 0.0f, float(textInfo.rotation)};
PosVecf3 scale = {1.0, 1.0, 1.0f};
MoveModelf(trans, angle, scale);
m_MVP = m_Projection * m_View * m_Model;
glBindBuffer(GL_ARRAY_BUFFER, m_VertexBuffer);
CHECK_GL_ERROR();
glBufferData(GL_ARRAY_BUFFER, sizeof(textInfo.vertex), textInfo.vertex, GL_STATIC_DRAW);
CHECK_GL_ERROR();
glUseProgram(m_TextProID);
CHECK_GL_ERROR();
glUniformMatrix4fv(m_TextMatrixID, 1, GL_FALSE, &m_MVP[0][0]);
// 1rst attribute buffer : vertices
glEnableVertexAttribArray(m_TextVertexID);
glBindBuffer(GL_ARRAY_BUFFER, m_VertexBuffer);
glVertexAttribPointer(
m_TextVertexID,
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
//tex coord
CHECK_GL_ERROR();
glEnableVertexAttribArray(m_TextTexCoordID);
glBindBuffer(GL_ARRAY_BUFFER, m_TextTexCoordBuf);
glVertexAttribPointer(
m_TextTexCoordID,
2, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
//texture
CHECK_GL_ERROR();
glBindTexture(GL_TEXTURE_2D, textInfo.texture);
CHECK_GL_ERROR();
glUniform1i(m_TextTexID, 0);
CHECK_GL_ERROR();
//TODO: moggi: get rid fo GL_QUADS
glDrawArrays(GL_QUADS, 0, 4);
CHECK_GL_ERROR();
glDisableVertexAttribArray(m_TextTexCoordID);
CHECK_GL_ERROR();
glDisableVertexAttribArray(m_TextVertexID);
CHECK_GL_ERROR();
glBindTexture(GL_TEXTURE_2D, 0);
glUseProgram(0);
glDeleteTextures(1, &textInfo.texture);
CHECK_GL_ERROR();
m_TextInfoList.pop_front();
}
CHECK_GL_ERROR();
m_fZStep += Z_STEP;
return 0;
}
int OpenGLRender::SetArea2DShapePoint(float x, float y, int listLength)
{
if (m_Area2DPointList.empty())
{
m_Area2DPointList.reserve(listLength);
}
float actualX = (x / OPENGL_SCALE_VALUE);
float actualY = (y / OPENGL_SCALE_VALUE);
m_Area2DPointList.push_back(actualX);
m_Area2DPointList.push_back(actualY);
m_Area2DPointList.push_back(m_fZStep);
if (m_Area2DPointList.size() == size_t(listLength * 3))
{
m_Area2DShapePointList.push_back(m_Area2DPointList);
m_Area2DPointList.clear();
}
return 0;
}
namespace {
// only 2D
bool checkCCW(const PointList& rPoints)
{
if(rPoints.size() < 3)
return true;
GLfloat sum = 0;
for(size_t i = 1; i < rPoints.size()/3; i += 3)
{
GLfloat x1 = rPoints[(i-1)*3];
GLfloat x2 = rPoints[i*3];
GLfloat y1 = rPoints[(i-1)*3 + 1];
GLfloat y2 = rPoints[i*3 + 1];
GLfloat prod = (x2-x1)*(y2+y1);
sum += prod;
}
return (sum <= 0);
}
}
int OpenGLRender::RenderArea2DShape()
{
CHECK_GL_ERROR();
glDisable(GL_MULTISAMPLE);
size_t listNum = m_Area2DShapePointList.size();
PosVecf3 trans = {0.0f, 0.0f, 0.0f};
PosVecf3 angle = {0.0f, 0.0f, 0.0f};
PosVecf3 scale = {1.0f, 1.0f, 1.0f};
MoveModelf(trans, angle, scale);
m_MVP = m_Projection * m_View * m_Model;
for (size_t i = 0; i < listNum; ++i)
{
PointList &pointList = m_Area2DShapePointList.front();
bool bIsCCW = checkCCW(pointList); // is it counter clockwise (CCW) or clockwise (CW)
if(!bIsCCW)
glFrontFace(GL_CW);
//fill vertex buffer
glBindBuffer(GL_ARRAY_BUFFER, m_VertexBuffer);
glBufferData(GL_ARRAY_BUFFER, pointList.size() * sizeof(float), &pointList[0], GL_STATIC_DRAW);
// Use our shader
glUseProgram(m_CommonProID);
glUniform4fv(m_2DColorID, 1, &m_2DColor[0]);
glUniformMatrix4fv(m_MatrixID, 1, GL_FALSE, &m_MVP[0][0]);
// 1rst attribute buffer : vertices
glEnableVertexAttribArray(m_2DVertexID);
glBindBuffer(GL_ARRAY_BUFFER, m_VertexBuffer);
glVertexAttribPointer(
m_2DVertexID, // attribute. No particular reason for 0, but must match the layout in the shader.
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
// TODO: moggi: remove deprecated GL_POLYGON
glDrawArrays(GL_POLYGON, 0, pointList.size() / 3); // 12*3 indices starting at 0 -> 12 triangles
glDisableVertexAttribArray(m_2DVertexID);
glUseProgram(0);
if(!bIsCCW)
glFrontFace(GL_CCW);
m_Area2DShapePointList.pop_front();
}
glEnable(GL_MULTISAMPLE);
m_fZStep += Z_STEP;
CHECK_GL_ERROR();
return 0;
}
void OpenGLRender::SetBackGroundColor(sal_uInt32 color1, sal_uInt32 color2, sal_uInt8 fillStyle)
{
sal_uInt8 r = (color1 & 0x00FF0000) >> 16;
sal_uInt8 g = (color1 & 0x0000FF00) >> 8;
sal_uInt8 b = (color1 & 0x000000FF);
m_BackgroundColor[0] = (float)r / 255.0f;
m_BackgroundColor[1] = (float)g / 255.0f;
m_BackgroundColor[2] = (float)b / 255.0f;
m_BackgroundColor[3] = fillStyle ? 1.0 : 0.0;
m_BackgroundColor[4] = (float)r / 255.0f;
m_BackgroundColor[5] = (float)g / 255.0f;
m_BackgroundColor[6] = (float)b / 255.0f;
m_BackgroundColor[7] = fillStyle ? 1.0 : 0.0;
r = (color2 & 0x00FF0000) >> 16;
g = (color2 & 0x0000FF00) >> 8;
b = (color2 & 0x000000FF);
m_BackgroundColor[8] = (float)r / 255.0f;
m_BackgroundColor[9] = (float)g / 255.0f;
m_BackgroundColor[10] = (float)b / 255.0f;
m_BackgroundColor[11] = fillStyle ? 1.0 : 0.0;
m_BackgroundColor[12] = (float)r / 255.0f;
m_BackgroundColor[13] = (float)g / 255.0f;
m_BackgroundColor[14] = (float)b / 255.0f;
m_BackgroundColor[15] = fillStyle ? 1.0 : 0.0;
SAL_INFO("chart2.opengl", "color1 = " << color1 << ", color2 = " << color2);
}
void OpenGLRender::SetChartTransparencyGradient(long transparencyGradient)
{
if (transparencyGradient == 1)
{
m_BackgroundColor[11] = 0.0;
m_BackgroundColor[15] = 0.0;
}
}
void OpenGLRender::GeneratePieSegment2D(double fInnerRadius, double fOutterRadius, double nAngleStart, double nAngleWidth)
{
double nAngleStep = 1;
PointList aPointList;
// TODO: moggi: GL_TRIANGLE_FAN seems not to work
bool bInnerRadiusNotZero = true; //!rtl::math::approxEqual(0.0, fInnerRadius);
size_t nVectorSize = 3*(nAngleWidth/nAngleStep);
if(bInnerRadiusNotZero)
nVectorSize *= 2;
nAngleStart += 90;
aPointList.reserve(nVectorSize);
// if inner radius = 0 generate a normal pie segment (triangle fan)
// if inner radius != 0 generate a pie segment - inner pie (triangle strip)
if(!bInnerRadiusNotZero)
{
aPointList.push_back(0);
aPointList.push_back(0);
aPointList.push_back(m_fZStep);
}
for(double nAngle = nAngleStart; nAngle <= nAngleStart + nAngleWidth; nAngle += nAngleStep)
{
float xVal = sin(nAngle/360*2*GL_PI);
float yVal = cos(nAngle/360*2*GL_PI);
aPointList.push_back(fOutterRadius * xVal);
aPointList.push_back(fOutterRadius * yVal);
aPointList.push_back(m_fZStep);
if(bInnerRadiusNotZero)
{
aPointList.push_back(fInnerRadius * xVal);
aPointList.push_back(fInnerRadius * yVal);
aPointList.push_back(m_fZStep);
}
}
m_PieSegment2DShapePointList.push_back(aPointList);
}
int OpenGLRender::RenderPieSegment2DShape(float fSize, float fPosX, float fPosY)
{
int listNum = m_PieSegment2DShapePointList.size();
PosVecf3 trans = {fPosX/OPENGL_SCALE_VALUE, fPosY/OPENGL_SCALE_VALUE, 0.0f};
PosVecf3 angle = {0.0f, 0.0f, 0.0f};
PosVecf3 scale = {fSize/OPENGL_SCALE_VALUE, fSize/OPENGL_SCALE_VALUE, 1.0f};
MoveModelf(trans, angle, scale);
m_MVP = m_Projection * m_View * m_Model;
for (int i = 0; i < listNum; i++)
{
PointList &pointList = m_PieSegment2DShapePointList.back();
//fill vertex buffer
glBindBuffer(GL_ARRAY_BUFFER, m_VertexBuffer);
glBufferData(GL_ARRAY_BUFFER, pointList.size() * sizeof(float), &pointList[0] , GL_STATIC_DRAW);
// Use our shader
glUseProgram(m_CommonProID);
glUniform4fv(m_2DColorID, 1, &m_2DColor[0]);
glUniformMatrix4fv(m_MatrixID, 1, GL_FALSE, &m_MVP[0][0]);
// 1rst attribute buffer : vertices
glEnableVertexAttribArray(m_2DVertexID);
glBindBuffer(GL_ARRAY_BUFFER, m_VertexBuffer);
glVertexAttribPointer(
m_2DVertexID, // attribute. No particular reason for 0, but must match the layout in the shader.
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
glDrawArrays(GL_TRIANGLE_STRIP, 0, pointList.size() / 3); // 12*3 indices starting at 0 -> 12 triangles
glDisableVertexAttribArray(m_2DVertexID);
glUseProgram(0);
m_PieSegment2DShapePointList.pop_back();
CHECK_GL_ERROR();
}
m_fZStep += Z_STEP;
CHECK_GL_ERROR();
return 0;
}
int OpenGLRender::RenderSymbol2DShape(float x, float y, float , float , sal_Int32 nSymbol)
{
CHECK_GL_ERROR();
glPointSize(20.f);
CHECK_GL_ERROR();
PosVecf3 trans = {0.0, 0.0, 0.0};
PosVecf3 angle = {0.0f, 0.0f, 0.0f};
PosVecf3 scale = {1.0, 1.0, 1.0f};
MoveModelf(trans, angle, scale);
m_MVP = m_Projection * m_View * m_Model;
float aPos[3] = { x/OPENGL_SCALE_VALUE, y/OPENGL_SCALE_VALUE, m_fZStep };
//fill vertex buffer
glBindBuffer(GL_ARRAY_BUFFER, m_VertexBuffer);
CHECK_GL_ERROR();
glBufferData(GL_ARRAY_BUFFER, 3 * sizeof(float), aPos, GL_STATIC_DRAW);
CHECK_GL_ERROR();
// Use our shader
glUseProgram(m_SymbolProID);
CHECK_GL_ERROR();
glUniform4fv(m_SymbolColorID, 1, &m_2DColor[0]);
glUniform1i(m_SymbolShapeID, nSymbol);
CHECK_GL_ERROR();
glUniformMatrix4fv(m_SymbolMatrixID, 1, GL_FALSE, &m_MVP[0][0]);
CHECK_GL_ERROR();
// 1rst attribute buffer : vertices
glEnableVertexAttribArray(m_SymbolVertexID);
glBindBuffer(GL_ARRAY_BUFFER, m_VertexBuffer);
glVertexAttribPointer(
m_SymbolVertexID, // attribute. No particular reason for 0, but must match the layout in the shader.
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
glDrawArrays(GL_POINTS, 0, 1);
glDisableVertexAttribArray(m_SymbolVertexID);
CHECK_GL_ERROR();
glUseProgram(0);
m_fZStep += Z_STEP;
CHECK_GL_ERROR();
return 0;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */