summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/glcolorrgba.cpp43
-rw-r--r--src/glcolorrgba.h38
-rw-r--r--src/gldefines.h49
-rw-r--r--src/glesrenderer.cpp776
-rw-r--r--src/glesrenderer.h472
-rw-r--r--src/glitem.cpp408
-rw-r--r--src/glitem.h290
-rw-r--r--src/glpoint.cpp13
-rw-r--r--src/glpoint.h45
-rw-r--r--src/main.cpp15
-rw-r--r--src/mmscene.cpp89
-rw-r--r--src/mmscene.h43
-rw-r--r--src/shaderdebugger.cpp103
-rw-r--r--src/shaderdebugger.h68
14 files changed, 2452 insertions, 0 deletions
diff --git a/src/glcolorrgba.cpp b/src/glcolorrgba.cpp
new file mode 100644
index 0000000..28d1008
--- /dev/null
+++ b/src/glcolorrgba.cpp
@@ -0,0 +1,43 @@
+#include "glcolorrgba.h"
+
+GLColorRgba GLColorRgba::clBlack = GLColorRgba(0.0,0.0,0.0,1.0);
+GLColorRgba GLColorRgba::clRed = GLColorRgba(1.0,0.0,0.0,1.0);
+GLColorRgba GLColorRgba::clYellow = GLColorRgba(1.0,1.0,0.0,1.0);
+GLColorRgba GLColorRgba::clGreen = GLColorRgba(0.0,1.0,0.0,1.0);
+GLColorRgba GLColorRgba::clCyan = GLColorRgba(0.0,1.0,1.0,1.0);
+GLColorRgba GLColorRgba::clBlue = GLColorRgba(0.0,0.0,1.0,1.0);
+GLColorRgba GLColorRgba::clMagenta = GLColorRgba(1.0,0.0,1.0,1.0);
+GLColorRgba GLColorRgba::clGray = GLColorRgba(0.5,0.5,0.5,1.0);
+GLColorRgba GLColorRgba::clWhite = GLColorRgba(1.0,1.0,1.0,1.0);
+
+GLColorRgba::GLColorRgba(float r, float g, float b, float a)
+ :QVector4D(r,g,b,a)
+{
+ //nothing else to do
+}
+
+GLColorRgba::GLColorRgba(const GLColorRgba &other)
+ :QVector4D(other.red(),other.green(),other.blue(),other.alpha())
+{
+}
+
+GLColorRgba::GLColorRgba(const QVector4D &other)
+ :QVector4D(other.x(),other.y(),other.z(),other.w())
+{
+}
+
+/**
+ * Returns the inverted color with a= 1.0
+ */
+GLColorRgba GLColorRgba::inverted()
+{
+ return GLColorRgba(1.0 - x(), 1.0 - y(), 1.0 - z(), 1.0);
+}
+
+GLColorRgba GLColorRgba::operator *(float factor)
+{
+ return GLColorRgba(red()*factor,
+ green() *factor,
+ blue() * factor,
+ alpha());
+}
diff --git a/src/glcolorrgba.h b/src/glcolorrgba.h
new file mode 100644
index 0000000..53efcc2
--- /dev/null
+++ b/src/glcolorrgba.h
@@ -0,0 +1,38 @@
+#ifndef GLCOLORRGBA_H
+#define GLCOLORRGBA_H
+
+#include <QVector4D>
+/**
+ * @brief The GlColorRgba class is a convenience class to replace QVector4D for color variables.
+ */
+class GLColorRgba: public QVector4D{
+public:
+ GLColorRgba(float r = 0.0, float g= 0.0, float b = 0.0, float a = 1.0);
+ GLColorRgba(const GLColorRgba & other);
+ GLColorRgba(const QVector4D & other);
+ /**
+ * Returns the inverted color with a= 1.0
+ */
+ GLColorRgba inverted();
+
+ GLColorRgba operator * (float factor);
+ //convenience getters
+ float red()const{return x();}
+ float green()const{return y();}
+ float blue()const{return z();}
+ float alpha()const{return w();}
+
+//predefined colors
+ static GLColorRgba clBlack;
+ static GLColorRgba clRed;
+ static GLColorRgba clYellow;
+ static GLColorRgba clGreen;
+ static GLColorRgba clCyan;
+ static GLColorRgba clBlue;
+ static GLColorRgba clMagenta;
+ static GLColorRgba clGray;
+ static GLColorRgba clWhite;
+};
+
+
+#endif // GLCOLORRGBA_H
diff --git a/src/gldefines.h b/src/gldefines.h
new file mode 100644
index 0000000..3425b43
--- /dev/null
+++ b/src/gldefines.h
@@ -0,0 +1,49 @@
+/********************************************************
+ * Convenience objects for building OpenGL surfaces.
+ *
+ * Created on: 24.04.2012
+ * Author: Walter Roth
+ * Copyright by Walter Roth 2012, Licence: GPL
+ *
+ *******************************************************/
+
+/** \file
+ * \brief Convenience objects for building OpenGL surfaces.
+ *
+ * Predefined 3D-vectors and colors that are frequently used.
+ */
+
+#ifndef GLDEFINES_H
+#define GLDEFINES_H
+
+#include <QVector3D>
+#include "glcolorrgba.h"
+
+//Predefined vectors
+
+const static QVector3D v_Zero = QVector3D(0.0, 0.0, 0.0);
+const static QVector3D v_X = QVector3D(1.0, 0.0, 0.0);
+const static QVector3D v_Y = QVector3D(0.0, 1.0, 0.0);
+const static QVector3D v_Z = QVector3D(0.0, 0.0, 1.0);
+const static QVector3D v_XY = QVector3D(1.0, 1.0, 0.0);
+const static QVector3D v_XZ = QVector3D(1.0, 0.0, 1.0);
+const static QVector3D v_YZ = QVector3D(0.0, 1.0, 1.0);
+const static QVector3D v_XYZ = QVector3D(1.0, 1.0, 1.0);
+
+
+/** Predefined global colors for convenience.
+ */
+const static GLColorRgba cl_White = GLColorRgba(1.0,1.0,1.0);
+const static GLColorRgba cl_Black = GLColorRgba(0.0,0.0,0.0);
+const static GLColorRgba cl_Red = GLColorRgba(1.0,0.0,0.0);
+const static GLColorRgba cl_Green = GLColorRgba(0.0,1.0,0.0);
+const static GLColorRgba cl_Blue = GLColorRgba(0.0,0.0,1.0);
+const static GLColorRgba cl_LightBlue = GLColorRgba(0.5,0.5,1.0);
+const static GLColorRgba cl_Gray = GLColorRgba(0.5,0.5,0.5);
+const static GLColorRgba cl_Yellow = GLColorRgba(1.0,1.0,0.0);
+const static GLColorRgba cl_Magenta = GLColorRgba(1.0,0.0,1.0);
+const static GLColorRgba cl_Cyan = GLColorRgba(0.0,1.0,1.0);
+
+
+
+#endif // GLDEFINES_H
diff --git a/src/glesrenderer.cpp b/src/glesrenderer.cpp
new file mode 100644
index 0000000..7d7339d
--- /dev/null
+++ b/src/glesrenderer.cpp
@@ -0,0 +1,776 @@
+/***************************************************************************
+ * Copyright (C) 2008, 2012 by Walter Roth *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "glesrenderer.h"
+
+#include <math.h>
+
+//#define DEBUG_GLESRENDERER
+
+//#ifdef DEBUG_GLESRENDERER
+#include "shaderdebugger.h"
+//#endif
+
+#ifdef Q_OS_ANDROID
+#ifndef GLES
+ #define GLES //Android uses GLES 2.0
+#endif
+#endif
+
+
+GLESRenderer::GLESRenderer(QObject *parent,
+ const QString & vShaderFilename,
+ const QString & fShaderFilename )
+ :QObject(parent)
+{
+ this->m_vShaderFileName = vShaderFilename;
+ this->m_fShaderFileName = fShaderFilename;
+
+ //flags
+ m_initialized = false;
+ m_bound = false;
+ m_lightingEnabled = false; // flag for lighting
+ m_colorArrayEnabled = false;
+ m_invertedMvpMatrixValid = false; //delay matrix inversion until it is really neccessary
+ m_textureEnabled = false;
+
+ m_lightDirection = QVector3D(1.0,1.0,1.0); //position of directional light
+ m_pointSize = 4.0;
+ m_shininess = 200.0;
+ m_ambientAndDiffuseColor = cl_White;
+ m_ambientLightBrightness = 0.2;
+ m_specularColor = cl_White;
+
+ m_vShader = NULL; //vertex shader, render thread
+ m_fShader = NULL; // fragment shader, render thread
+ m_renderProgram = NULL;// GUI-Thread
+
+ // Locations of shader variables
+ //attributes
+ m_location_aVertex = -1;
+ m_location_aColor = -1;
+ m_location_aNormal = -1;
+ m_location_aTexCoord = -1;
+ //uniforms
+ //flags
+ m_location_uColorArrayEnabled = -1;
+ m_location_uTextureEnabled = -1;
+ m_location_uLightingEnabled = -1;
+ //matrices
+ m_location_uNormalMatrix = -1;
+ m_location_uMvpMatrix = -1;
+ //lighting
+ m_location_uAmbientAndDiffuseColor = -1;
+ m_location_uAmbientLightBrightness = -1;
+ m_location_uSpecularColor = -1;
+ m_location_uLightDirection = -1;
+ m_location_uHalfPlaneVector = -1;
+ //texture
+ m_location_uTextureSampler = -1;
+
+ //viewport
+ m_viewportX = 0;
+ m_viewportY = 0;
+ m_viewportW = 100;
+ m_viewportH = 100;
+
+ //clippings
+ m_fovy = 45.0;
+ m_aspect = 1.0;
+ m_nearClip = 1.0;
+ m_farClip = 10.0;
+
+}
+/**
+ * @brief GLESRenderer::~GLESRenderer
+ * We need to delete the shaders here. They can not be added to the child list, because they live in render thread.
+ */
+GLESRenderer::~GLESRenderer()
+{
+ if(m_vShader)
+ delete m_vShader;
+ if(m_fShader)
+ delete m_fShader;
+}
+
+/**
+ * Set modelview matrix. Updates mvpMatrix and normalMatrix too.
+ * Call setPMatrix first.
+ */
+void GLESRenderer::setMvMatrix(const QMatrix4x4 newVal)
+{
+ m_mvMatrix = newVal;
+ m_normalMatrix = m_mvMatrix.normalMatrix(); //invert and transpose mvMatrix
+ m_invertedMvpMatrixValid = false; //delay matrix inversion until it is really neccessary
+
+ if(m_bound && (m_location_uNormalMatrix != -1))
+ m_renderProgram->setUniformValue(m_location_uNormalMatrix, m_normalMatrix);
+
+ m_mvpMatrix = m_pMatrix * m_mvMatrix;
+ if(m_bound && (m_location_uMvpMatrix != -1))
+ m_renderProgram->setUniformValue(m_location_uMvpMatrix, m_mvpMatrix);
+#ifdef DEBUG_GLESRENDERER
+ ShaderDebugger::debugMatrix4x4(m_mvMatrix, "GLESRenderer uses modelview matrix:");
+ ShaderDebugger::debugMatrix3x3(m_normalMatrix, "GLESRenderer uses normal matrix:");
+ ShaderDebugger::debugMatrix4x4(m_mvpMatrix, "GLESRenderer uses MVP matrix:");
+#endif
+}
+
+/**
+ * Sets mvMatrix to a lookAt transformation.
+ * Call setPMatrix or setPerspective first.
+ */
+void GLESRenderer::setLookAt(const QVector3D & eye,const QVector3D & center,const QVector3D & up )
+{
+ QMatrix4x4 m;
+ m.setToIdentity();
+ m.lookAt(eye, center, up);
+ setMvMatrix(m);
+}
+
+/**
+ * Set projection matrix. Call setMvMatrix after this.
+ */
+void GLESRenderer::setPMatrix(const QMatrix4x4 newVal)
+{
+ m_pMatrix = newVal;
+ m_mvpMatrix = m_pMatrix * m_mvMatrix;
+ if(m_bound && (m_location_uMvpMatrix != -1))
+ m_renderProgram->setUniformValue(m_location_uMvpMatrix, m_mvpMatrix);
+}
+
+/**
+ * Setup projection matrix. Call setMvMatrix after this.
+ */
+void GLESRenderer::setPerspective(GLfloat fovy, GLfloat aspect, GLfloat nearClip, GLfloat farClip)
+{
+ m_fovy = fovy;
+ m_aspect = aspect;
+ m_nearClip = nearClip;
+ m_farClip = farClip;
+ m_pMatrix.setToIdentity();
+ m_pMatrix.perspective(m_fovy, m_aspect, m_nearClip, m_farClip);
+ m_mvpMatrix = m_pMatrix * m_mvMatrix;
+ if(m_bound && (m_location_uMvpMatrix != -1))
+ m_renderProgram->setUniformValue(m_location_uMvpMatrix, m_mvpMatrix);
+#ifdef DEBUG_GLESRENDERER
+ ShaderDebugger::debugMatrix4x4(m_pMatrix, "GLESRenderer uses projection matrix:");
+#endif
+}
+
+void GLESRenderer::setOrtho(float left, float right, float bottom, float top, float nearPlane, float farPlane)
+{
+ m_fovy = 0.0;
+ m_aspect = (left - right) / (top - bottom);
+ m_nearClip = nearPlane;
+ m_farClip = farPlane;
+ m_pMatrix.setToIdentity();
+ m_pMatrix.ortho(left, right, bottom, top, nearPlane, farPlane);
+ m_mvpMatrix = m_pMatrix * m_mvMatrix;
+ if(m_bound && (m_location_uMvpMatrix != -1))
+ m_renderProgram->setUniformValue(m_location_uMvpMatrix, m_mvpMatrix);
+#ifdef DEBUG_GLESRENDERER
+ ShaderDebugger::debugMatrix4x4(m_pMatrix, "GLESRenderer uses projection matrix:");
+#endif
+}
+
+/**
+ * Set viewport
+ */
+void GLESRenderer::setViewport(int x, int y, int w, int h)
+{
+ m_viewportX = x;
+ m_viewportY = y;
+ m_viewportW = w;
+ m_viewportH = h;
+ //qDebug() << "GLESRenderer::setViewport x:" << x << " y: " << y << " w: " << w << " h: " << h;
+}
+
+/**
+ * Uses viewport and matrix settings to reverse the vertex transformation chain.
+ * WinX, winY, winZ are the coordinates in window coordinates. Lower left of viewport
+ * is winX = 0, winY = 0. Use winZ = 0.0 for a point on near clipping plane
+ * and winZ = 1.0 for a point on far clipping plane.
+ * This function assumes, that the vertex shader computes gl_positon as v * mvpMatrix.
+ * Use a custom shader reverse function, if this is not true.
+ * Returns coordinate in object space.
+ */
+QVector3D GLESRenderer::unProjectViewportPoint(const QVector3D & vWin)
+{
+ QVector3D vClip = viewportToClip(vWin);
+ if(!m_invertedMvpMatrixValid)
+ {
+ m_invertedMvpMatrix = m_mvpMatrix.inverted();
+ m_invertedMvpMatrixValid = true;
+ }
+ ShaderDebugger::debugMatrix4x4(m_mvpMatrix, "MVP Matrix:");
+ ShaderDebugger::debugMatrix4x4(m_invertedMvpMatrix, "Inverted MVP Matrix:");
+ QVector3D result = m_invertedMvpMatrix * vClip;
+ ShaderDebugger::debugVector3D(result, "Vector in model space:");
+ return result;
+}
+
+/**
+ * Performs inverse viewport transform.
+ */
+QVector3D GLESRenderer::viewportToClip(const QVector3D & vWin)
+{
+ //reverse viewport transformation, for original code see below
+ float xClip = (vWin.x() - (float)m_viewportX) / (float)m_viewportW * 2.0 - 1.0;
+ float yClip = (vWin.y() - (float)m_viewportY) / (float)m_viewportH * 2.0 - 1.0;
+ float zClip = 2.0 * vWin.z() - 1.0;
+
+ // original code from gluUnproject
+ //Transformation of normalized coordinates between -1 and 1
+ // in[0]=(winx-(float)viewport[0])/(float)viewport[2]*2.0-1.0;
+ // in[1]=(winy-(float)viewport[1])/(float)viewport[3]*2.0-1.0;
+ // in[2]=2.0*winz-1.0;
+ // in[3]=1.0;
+
+ QVector3D result = QVector3D(xClip, yClip, zClip);
+ ShaderDebugger::debugVector3D(result, "Vector in clip space:");
+ return result;
+}
+
+/**
+ * Returns the points on near and far clipping plane, that correspond to the
+ * mouseX and mouseY coordinates of a mouse click.
+ * mouseX and mouseY are coordinates as delivered by QMouseEvent or QDeclarativeMouseEvent.
+ */
+void GLESRenderer::calculateMousePoints(QVector3D * nearPoint, QVector3D * farPoint, const QPoint & mousePos)
+{
+ float winX = m_viewportX + mousePos.x();
+ float winY = m_viewportY + (m_viewportH - mousePos.y());
+ * nearPoint = unProjectViewportPoint(QVector3D(winX, winY, 0.0));
+ * farPoint = unProjectViewportPoint(QVector3D(winX, winY, 1.0));
+}
+
+/**
+ * Calculate the distance of the "mouse ray line" to point p in model space.
+ * mouseX, mouseY are the coordinates of the mouse click as delivered by QMouseEvent.
+ * Returns distance.
+ */
+float GLESRenderer::distanceToMouseClick(QVector3D p, const QPoint & mousePos)
+{
+ QVector3D nearPoint, farPoint;
+ calculateMousePoints(&nearPoint, &farPoint, mousePos);
+
+ QVector3D lineVector = nearPoint - farPoint;
+ float area = QVector3D::crossProduct(p - nearPoint, lineVector).length();
+ float distance = area / lineVector.length();
+
+ return distance;
+}
+
+/**
+ * Calculates intersection of "mouse ray line" with the plane defined by normal and d.
+ * mouseX, mouseY are the coordinates of the mouse click as delivered by QMouseEvent.
+ * Returns true, if intersection is in the visible frustum, else returns false.
+ * If return value is true, *intersection is the intersection of the mouse ray line with
+ * the plane normal*(x,y,z) + d = 0.
+ * If return value is false, *intersection is not modified.
+ */
+bool GLESRenderer::mouseIntersection(QVector3D * intersection, QVector3D normal, float d, const QPoint & mousePos)
+{
+ float m0, m15;
+ QVector3D pNear, pFar; //mouse intersections on near and far clipping plane
+ calculateMousePoints(&pNear, &pFar, mousePos);
+ QVector3D v = pFar - pNear; //vector from near to far clipping plane
+ m15 = d + QVector3D::dotProduct(normal, pNear);
+ m0 = QVector3D::dotProduct( normal, v);
+ if(fabs(m0) < fabs(m15)) //we have no intersection in frustum (lambda will be > 1.0)
+ {
+ return false;
+ }
+ float lambda = -m15 / m0;
+ * intersection = pNear + lambda * v;
+ return true;
+}
+
+/**
+ * Set the color for ambient and diffuse lighting (or no lighting).
+ * Alternatively use a color array and color attribute.
+ */
+void GLESRenderer::setAmbientAndDiffuseColor(const GLColorRgba newVal)
+{
+ m_ambientAndDiffuseColor = newVal;
+ if(m_bound && m_location_uAmbientAndDiffuseColor != -1)
+ m_renderProgram->setUniformValue(m_location_uAmbientAndDiffuseColor, m_ambientAndDiffuseColor);
+}
+
+/**
+ * Set the dimming factor for ambient light.
+ * Defaults to 0.2.
+ */
+void GLESRenderer::setAmbientLightBrightness(float newVal)
+{
+ m_ambientLightBrightness = newVal;
+ if(m_bound && m_location_uAmbientLightBrightness != -1)
+ m_renderProgram->setUniformValue(m_location_uAmbientLightBrightness, m_ambientLightBrightness);
+}
+
+/**
+ * Set the color for specular lighting.
+ */
+void GLESRenderer::setSpecularColor(const GLColorRgba newVal)
+{
+ m_specularColor = newVal;
+ if(m_bound && (m_location_uSpecularColor != -1))
+ m_renderProgram->setUniformValue(m_location_uSpecularColor,
+ m_specularColor.red(), m_specularColor.green(),
+ m_specularColor.blue(), m_specularColor.alpha());
+}
+
+/**
+ * Set the shininess for specular lighting.
+ */
+void GLESRenderer::setShininess(float newVal)
+{
+ m_shininess = newVal;
+ if(m_bound && (m_location_uShininess != -1))
+ m_renderProgram->setUniformValue(m_location_uShininess, m_shininess);
+}
+
+/**
+ * Enable / disable lighting.
+ */
+void GLESRenderer::setLightingEnabled(bool newVal)
+{
+ m_lightingEnabled = newVal;
+ if(m_bound && (m_location_uLightingEnabled != -1))
+ m_renderProgram->setUniformValue(m_location_uLightingEnabled, m_lightingEnabled);
+}
+
+/**
+ * Enable / disable color array.
+ */
+void GLESRenderer::setColorArrayEnabled(bool newVal)
+{
+ m_colorArrayEnabled = newVal;
+ if(m_bound && (m_location_uColorArrayEnabled != -1))
+ m_renderProgram->setUniformValue(m_location_uColorArrayEnabled, m_colorArrayEnabled);
+}
+
+/**
+ * Set the texture flag.
+ */
+void GLESRenderer::setTextureEnabled(bool newVal)
+{
+ m_textureEnabled = newVal;
+ if(m_bound && (m_location_uTextureEnabled != -1))
+ m_renderProgram->setUniformValue(m_location_uTextureEnabled, m_textureEnabled);
+}
+
+/**
+ * Set light direction.
+ */
+void GLESRenderer::setLightDirection(const QVector3D & newVal)
+{
+ m_lightDirection = newVal;
+#ifdef DEBUG_GLESRENDERER
+ ShaderDebugger::debugVector3D(m_lightDirection, "GLESRenderer uses lightDirection in object space:");
+#endif
+ QMatrix4x4 nMatrix = QMatrix4x4(m_normalMatrix);
+ m_lightDirection = (nMatrix * m_lightDirection).normalized();//transform to eye space
+ m_halfPlaneVector = (m_lightDirection + QVector3D(0.0,0.0,1.0)).normalized();//eye direction is 0,0,1 in eye space
+#ifdef DEBUG_GLESRENDERER
+ ShaderDebugger::debugVector3D(m_lightDirection, "GLESRenderer uses lightDirection in eye space:");
+ ShaderDebugger::debugVector3D(m_lightDirection, "GLESRenderer uses halfplane vector in eye space:");
+#endif
+ if(m_bound && (m_location_uLightDirection != -1))
+ m_renderProgram->setUniformValue(m_location_uLightDirection, m_lightDirection);
+ if(m_location_uHalfPlaneVector != -1)
+ m_renderProgram->setUniformValue(m_location_uHalfPlaneVector, m_halfPlaneVector);
+}
+
+/**
+ * Set size of points drawn with GL_POINTS.
+ */
+void GLESRenderer::setPointSize(int newVal)
+{
+ m_pointSize = newVal;
+ if(m_bound && (m_location_uPointSize != -1))
+ m_renderProgram->setUniformValue(m_location_uPointSize, m_pointSize);
+#ifndef GLES
+ glPointSize(m_pointSize); //set point size independent of vertex shader
+#endif
+}
+
+/**
+ * Pops mvMatrix from stack and updates normalMatrix and mvpMatrix.
+ */
+void GLESRenderer::popMvMatrix()
+{
+ setMvMatrix(m_mvMatrixStack.pop());
+}
+
+/**
+ * Translates mvMatrix by v
+ */
+void GLESRenderer::translate(const QVector3D & v)
+{
+ m_mvMatrix.translate(v);
+ setMvMatrix(m_mvMatrix); //update normalMatrix and mvpMatrix and copy to shader
+}
+
+/**
+ * Rotates mvMatrix by angle around axis
+ */
+void GLESRenderer::rotate(GLfloat angle, const QVector3D & axis)
+{
+ m_mvMatrix.rotate(angle, axis);
+ setMvMatrix(m_mvMatrix); //update normalMatrix and mvpMatrix and copy to shader
+}
+
+void GLESRenderer::addTransformation(const QMatrix4x4 additionalTransformation)
+{
+ setMvMatrix(m_mvMatrix * additionalTransformation); //update normalMatrix and mvpMatrix and copy to shader
+}
+
+/**
+ * Scales mvMatrix.
+ */
+void GLESRenderer::scale(const QVector3D & v )
+{
+ m_mvMatrix.scale(v);
+ setMvMatrix(m_mvMatrix);//update normalMatrix and mvpMatrix and copy to shader
+}
+
+void GLESRenderer::rotate( float angle, float x, float y, float z ) {
+ m_mvMatrix.rotate ( angle, x, y, z );
+ setMvMatrix( m_mvMatrix );
+} /* ----- end of method mvRotate ----- */
+
+void GLESRenderer::zoom( float zoomFactor ) {
+ // Es muss vor dem Zoom die Einheitsmatrix generiert werden. Ansonsten wird das vorherige Zoomen dazu addiert
+ m_pMatrix.setToIdentity();
+ m_pMatrix.perspective ( m_fovy * zoomFactor, m_aspect, m_nearClip, m_farClip );
+ // Auch hier muss die ProjectionModelView Matrix neu berechnet werden
+ m_mvpMatrix = m_pMatrix * m_mvMatrix;
+}
+
+
+void GLESRenderer::translate( float x, float y, float z ) {
+ m_mvMatrix.translate( x, y, z );
+ setMvMatrix( m_mvMatrix);
+} /* ----- end of method translate ----- */
+
+
+/**
+ * Compile shaders, get attribute and uniform locations.
+ * This function needs an active OpenGL context.
+ */
+bool GLESRenderer::initialize()
+{
+ if(m_initialized)
+ return true;
+ //Setup shaders and program
+ m_vShader = new QOpenGLShader(QOpenGLShader::Vertex,this); //vertex shader
+ m_vShader->compileSourceFile(m_vShaderFileName);
+ if(!m_vShader->isCompiled())
+ {
+ qDebug("GLESRenderer::initialize: Compiling vertex shader failed. Log follows:\n%s",
+ qPrintable(m_vShader->log()));
+ return false;
+ }
+ m_fShader = new QOpenGLShader(QOpenGLShader::Fragment,this); // fragment shader
+ m_fShader->compileSourceFile(m_fShaderFileName);
+ if(!m_fShader->isCompiled())
+ {
+ qDebug("GLESRenderer::initialize: Compiling fragment shader failed. Log follows:\n%s",
+ qPrintable(m_fShader->log()));
+ return false;
+ }
+
+ m_renderProgram = new QOpenGLShaderProgram(this);
+ m_renderProgram->addShader(m_vShader);
+ m_renderProgram->addShader(m_fShader);
+ m_renderProgram->link();
+ if(!m_renderProgram->isLinked())
+ {
+ qDebug("GLESRenderer::initialize: Linking program failed. Log follows:\n%s",
+ qPrintable(m_renderProgram->log()));
+ return false;
+ }
+
+ // Get all locations of shader variables
+ //Get locations of attributes and uniforms
+ //Non existing attributes and uniforms will return -1
+ //Attributes
+ m_location_aVertex = m_renderProgram->attributeLocation("a_Vertex");
+ m_location_aColor = m_renderProgram->attributeLocation("a_Color");
+ m_location_aNormal = m_renderProgram->attributeLocation("a_Normal");
+ m_location_aTexCoord = m_renderProgram->attributeLocation("a_TexCoord");
+ //Uniforms
+ //flags
+ m_location_uLightingEnabled = m_renderProgram->uniformLocation("u_LightingEnabled");
+ m_location_uColorArrayEnabled = m_renderProgram->uniformLocation("u_ColorArrayEnabled");
+ m_location_uTextureEnabled = m_renderProgram->uniformLocation("u_TextureEnabled");
+ //matrices
+ m_location_uNormalMatrix = m_renderProgram->uniformLocation("u_NormalMatrix");
+ m_location_uMvpMatrix = m_renderProgram->uniformLocation("u_MvpMatrix");
+ //lighting
+ m_location_uAmbientAndDiffuseColor = m_renderProgram->uniformLocation("u_AmbientAndDiffuseColor");
+ m_location_uAmbientLightBrightness = m_renderProgram->uniformLocation("u_AmbientLightBrightness");
+ m_location_uLightDirection = m_renderProgram->uniformLocation("u_LightDirection");
+ m_location_uSpecularColor = m_renderProgram->uniformLocation("u_SpecularColor");
+ m_location_uShininess = m_renderProgram->uniformLocation("u_Shininess");
+ m_location_uHalfPlaneVector = m_renderProgram->uniformLocation("u_HalfPlaneVector");
+ //texture
+ m_location_uTextureSampler = m_renderProgram->uniformLocation("s_Texture");
+ //point size
+ m_location_uPointSize = m_renderProgram->uniformLocation("u_PointSize");
+
+#ifdef DEBUG_GLESRENDERER
+ ShaderDebugger::setEnabled(true);
+ ShaderDebugger::debugUniforms(m_renderProgram->programId());
+ ShaderDebugger::setEnabled(false);
+#endif
+
+ //get present viewport settings
+ readGLViewportSettings();
+ m_initialized = true;
+ return true;
+}
+
+/**
+ * Bind program and transfer attribute and uniform data to the shaders.
+ * Calls initialize, if not already initialized.
+ */
+bool GLESRenderer::bind()
+{
+ bool ok = true;
+ if(!m_initialized)
+ ok = initialize();
+ if(!ok)
+ return false;
+ m_renderProgram->bind();
+ //Activate uniforms
+ //flags
+ if(m_location_uColorArrayEnabled != -1)
+ m_renderProgram->setUniformValue(m_location_uColorArrayEnabled, m_colorArrayEnabled);
+ if(m_location_uLightingEnabled != -1)
+ m_renderProgram->setUniformValue(m_location_uLightingEnabled, m_lightingEnabled);
+ if(m_location_uTextureEnabled != -1)
+ m_renderProgram->setUniformValue(m_location_uTextureEnabled, m_textureEnabled);
+ //matrices
+ if( m_location_uNormalMatrix != -1)
+ m_renderProgram->setUniformValue(m_location_uNormalMatrix, m_normalMatrix);
+ if(m_location_uMvpMatrix != -1)
+ m_renderProgram->setUniformValue(m_location_uMvpMatrix, m_mvpMatrix);
+ //lighting
+ if(m_location_uAmbientAndDiffuseColor != -1)
+ m_renderProgram->setUniformValue(m_location_uAmbientAndDiffuseColor,
+ m_ambientAndDiffuseColor.red(), m_ambientAndDiffuseColor.green(),
+ m_ambientAndDiffuseColor.blue(), m_ambientAndDiffuseColor.alpha());
+ if(m_location_uAmbientLightBrightness != -1)
+ m_renderProgram->setUniformValue(m_location_uAmbientLightBrightness, m_ambientLightBrightness);
+ if(m_location_uLightDirection != -1)
+ m_renderProgram->setUniformValue(m_location_uLightDirection, m_lightDirection);
+ if(m_location_uSpecularColor != -1)
+ m_renderProgram->setUniformValue(m_location_uSpecularColor,
+ m_specularColor.red(), m_specularColor.green(),
+ m_specularColor.blue(), m_specularColor.alpha());
+ if(m_location_uShininess != -1)
+ m_renderProgram->setUniformValue(m_location_uShininess, m_shininess);
+ if(m_location_uHalfPlaneVector != -1)
+ m_renderProgram->setUniformValue(m_location_uHalfPlaneVector, m_halfPlaneVector);
+ //texture
+ if(m_location_uTextureSampler != -1)
+ m_renderProgram->setUniformValue(m_location_uTextureSampler, 0); //set sampler to use texture unit 0
+ //point size
+ if(m_location_uPointSize != -1)
+ m_renderProgram->setUniformValue(m_location_uPointSize, m_pointSize);
+#ifndef GLES
+ glPointSize(m_pointSize); //set point size independent of vertex shader
+#endif
+
+ m_renderProgram->setUniformValue("u_viewPortCenter",
+ QVector2D(m_viewportW / 2, m_viewportH /2));
+ GLfloat diameterSquare = 200.0 * 200.0;
+ m_renderProgram->setUniformValue("u_diameterSquare", diameterSquare);
+
+
+ m_bound = true;
+ return m_bound;
+}
+
+/**
+ * Enables Vertex, normal, color or texCoord arrays and sets start adresses of arrays
+ * arrayLocation may be: VERTEX_LOCATION, NORMAL_LOCATION, COLOR_LOCATION, TEXCOORD_LOCATION
+ */
+bool GLESRenderer::activateAttributeArray (AttributeLocation arrayLocation, const QVector2D *values, int stride )
+{
+ return activateAttributeArray(arrayLocation, (float*)values, 2, stride);
+}
+/**
+ * Enables Vertex, normal, color or texCoord arrays and sets start adresses of arrays
+ * arrayLocation may be: VERTEX_LOCATION, NORMAL_LOCATION, COLOR_LOCATION, TEXCOORD_LOCATION
+ */
+bool GLESRenderer::activateAttributeArray (AttributeLocation arrayLocation, const QVector3D *values, int stride )
+{
+ return activateAttributeArray(arrayLocation, (float*)values, 3, stride);
+}
+/**
+ * Enables Vertex, normal, color or texCoord arrays and sets start adresses of arrays
+ * arrayLocation may be: VERTEX_LOCATION, NORMAL_LOCATION, COLOR_LOCATION, TEXCOORD_LOCATION
+ */
+bool GLESRenderer::activateAttributeArray (AttributeLocation arrayLocation, const QVector4D *values, int stride )
+{
+ return activateAttributeArray(arrayLocation, (float*)values, 4, stride);
+}
+
+/**
+ * Enables Vertex, normal, color or texCoord arrays and sets start adresses of arrays
+ * arrayLocation may be: VERTEX_LOCATION, NORMAL_LOCATION, COLOR_LOCATION, TEXCOORD_LOCATION
+ */
+bool GLESRenderer::activateAttributeArray (AttributeLocation arrayLocation, const float * values, int tupleSize, int stride )
+{
+ int location = -1;
+ switch(arrayLocation){
+ case VERTEX_LOCATION: location = m_location_aVertex; break;
+ case NORMAL_LOCATION: location = m_location_aNormal; break;
+ case COLOR_LOCATION : location = m_location_aColor; break;
+ case TEXCOORD_LOCATION : location = m_location_aTexCoord; break;
+ default: return false;
+ }
+
+ if(values && (location != -1))
+ {
+ m_renderProgram->enableAttributeArray(location);
+ m_renderProgram->setAttributeArray(location, values, tupleSize, stride);
+ m_activeAttributeLocations.append(location);
+ return true;
+ }
+ else return false;
+}
+
+///**
+// * Enables Vertex, normal, color or texCoord arrays and sets start adresses of arrays
+// * Type may be: VERTEX_LOCATION, COLOR_LOCATION
+// */
+//bool GLESRenderer::activateAttributeArray (AttributeLocation arrayLocation, const QVector4D * values, int stride )
+//{
+// if(!m_initialized)
+// return false;
+// int location = -1;
+// switch(arrayLocation){
+// case VERTEX_LOCATION: location = m_location_aVertex; break;
+// case COLOR_LOCATION : location = m_location_aColor; break;
+// default: return false;
+// }
+
+// if(values && (location != -1))
+// {
+// m_renderProgram->enableAttributeArray(location);
+// m_renderProgram->setAttributeArray(location, GL_FLOAT, values, 4, stride);
+// m_activeAttributeLocations.append(location);
+// return true;
+// }
+// else return false;
+//}
+
+bool GLESRenderer::activateAttributeBuffer(GLESRenderer::AttributeLocation bufferLocation, int bufferId, int stride)
+{
+ int location = -1;
+ int elements = 3;
+ int offset = 0;
+ switch(bufferLocation){
+ case VERTEX_LOCATION: location = m_location_aVertex; break;
+ case NORMAL_LOCATION: location = m_location_aNormal; break;
+ case COLOR_LOCATION : {
+ location = m_location_aColor;
+ elements = 4; //RGBA colors
+ }break;
+ case TEXCOORD_LOCATION : location = m_location_aTexCoord; break;
+ default: return false;
+ }
+ if( bufferId != 0 ) {
+ m_renderProgram->setAttributeBuffer(location, GL_FLOAT, offset, elements, stride);
+ m_renderProgram->enableAttributeArray( location );
+ return true;
+ }
+ else {
+ qDebug() << "GLESRenderer::activateAttributeBuffer: Error, invalid buffer id";
+ return false;
+ }
+}
+
+/**
+ * Disables all enabled attribute arrays.
+ */
+void GLESRenderer::disableAttributeArrays()
+{
+ for(int i = 0; i < m_activeAttributeLocations.size(); i++)
+ m_renderProgram->disableAttributeArray(m_activeAttributeLocations[i]);
+ m_activeAttributeLocations.clear();
+}
+
+/**
+ * Releases program. To be called, when all rendering is finished.
+ */
+void GLESRenderer::release()
+{
+ disableAttributeArrays();
+ if(m_renderProgram)
+ m_renderProgram->release();
+ else qDebug() << "GLESRenderer::release() called without valid render program.";
+ m_bound = false;
+}
+
+/**
+ * get the present settings from GL engine
+ */
+void GLESRenderer::readGLViewportSettings()
+{
+ GLint vp[4];
+ glGetIntegerv(GL_VIEWPORT, vp);
+ m_viewportX = vp[0];
+ m_viewportY = vp[1];
+ m_viewportW = vp[2];
+ m_viewportH = vp[3];
+}
+
+/**
+ * Multiplies current mvp matrix with v. Mainly for debugging.
+ */
+QVector3D GLESRenderer::modelToClip(const QVector3D & v)
+{
+ ShaderDebugger::debugVector3D(v, "Vector in model space:");
+ QVector3D result = m_mvpMatrix * v;
+ ShaderDebugger::debugVector3D(result, "Vector in clip space:");
+ return result;
+}
+
+/**
+ * Performs viewport transform. Mainly for debugging.
+ */
+QVector3D GLESRenderer::clipToViewport(const QVector3D & v)
+{
+ float ox = (m_viewportX + m_viewportW) / 2.0;
+ float oy = (m_viewportY + m_viewportH) / 2.0;
+ ShaderDebugger::debugVector3D(v, "Vector in clip space:");
+ float xw = (m_viewportW / 2.0) * v.x() + ox;
+ float yw = (m_viewportH / 2.0) * v.y() + oy;
+ float zw = ((m_farClip - m_nearClip) / 2.0) * v.z() + (m_nearClip + m_farClip) / 2.0;
+ QVector3D result = QVector3D(xw, yw, zw);
+ ShaderDebugger::debugVector3D(result, "Vector in viewport space:");
+ return result;
+}
+
+
diff --git a/src/glesrenderer.h b/src/glesrenderer.h
new file mode 100644
index 0000000..e5cc723
--- /dev/null
+++ b/src/glesrenderer.h
@@ -0,0 +1,472 @@
+/***************************************************************************
+ * Copyright (C) 2012 by Walter Roth *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef GLESRENDERER_H
+#define GLESRENDERER_H
+
+#include <QOpenGLShaderProgram>
+#include <QList>
+#include <QStack>
+
+#include "glcolorrgba.h"
+#include "gldefines.h"
+
+/** \brief A render program that can be used as a simple replacement for the OpenGL fixed
+ * function pipeline.
+ * \author Walter Roth, 2014
+ *
+ * GLESRenderer supports vertex, colors, normals, texCoords, textures and matrix manipulation.
+ * It owns a modelview and a projection matrix which can be used like in the old days of OpenGL 1.
+ * The vertex shader program needs to stick to the following variable names:
+ * attribute highp vec4 a_Vertex;
+ * attribute highp vec4 a_Color;
+ * attribute highp vec3 a_Normal;
+ * attribute highp vec2 a_TexCoord;
+ *
+ * uniform bool u_ColorArrayEnabled
+ * uniform bool u_LightingEnabled;
+ * uniform highp mat4 u_MvpMatrix;
+ * uniform highp mat3 u_NormalMatrix;
+ * uniform highp vec3 u_LightDirection;
+ * uniform highp vec4 u_AmbientAndDiffuseColor;
+ * uniform highp vec4 u_SpecularColor;
+ * uniform highp float u_Shininess;
+ * uniform mediump float int u_PointSize;
+ *
+ * The fragment shader texture variable must have the following name:
+ * uniform sampler2d s_Texture;
+ *
+ * These names are used to determine the locations of the varables in the shaders.
+ * If you need more variables, subclass GLESRenderer and add new variable(s) to
+ * location_XXX variables. Extend virtual intialize(), bind() and disableAttributeArrays() functions
+ * to support the new variable(s).
+ *
+ * The shader source should be in a separate file (e.g. added to the resources).
+ * Example shaders vshader1 and fshader1 emulate a simple fixed-function lighted OpenGL 1 scene.
+ *
+ * Call initialize, after a valid OpenGL context has been made current.
+ * Setup viewing with setViewport, setLookAt and setPerspective.
+ * Viewport coordinates must be given as
+ * GL-viewport coordinates, where lower left is (0,0).
+ * Call bind to bind the program and set the uniform values you need.
+ * After this, call activateAttributeLocation to enable the attribute arrays.
+ * To change attribute arrays, call disableAttributeArrays and then again activateAttributeLocations.
+ * Finally call release.
+ *
+ * GLESRenderer contains functions for projecting points from modelspace to screen and unprojecting points
+ * from screen to model space. These functions use the current matrix settings. Therefore, you have to
+ * (re)set the matrices to the values that are used to paint the model, before you call the project and
+ * unproject functions.
+ *
+ * For convenient mouse interaction, GLESRenderer supplies the calculateMousePoints(), distanceToMouseClick()
+ * and mouseIntersection() functions. These functions use the unproject functions and therefore do also need
+ * valid model painting matrix settings.
+ */
+class GLESRenderer : public QObject
+{
+ Q_OBJECT
+public:
+ typedef enum{
+ VERTEX_LOCATION,
+ NORMAL_LOCATION,
+ COLOR_LOCATION,
+ TEXCOORD_LOCATION
+ }AttributeLocation;
+
+ explicit GLESRenderer(QObject *parent,
+ const QString & vShaderFilename = ":/src/vshader.vsh",
+ const QString & fShaderFilename = ":/src/fshader.fsh");
+
+ virtual ~GLESRenderer();
+
+ //=========================================================================
+ /**
+ * \name Initialization, binding and releasing
+ */
+ ///@{
+ /**
+ * Compile shaders, get attribute and uniform locations of shaders.
+ * This function needs an active OpenGL context.
+ * Returns false, if initialization failed.
+ */
+ virtual bool initialize();
+
+ /**
+ * Bind program and transfer attribute and uniform data to the shaders.
+ * Calls initialize, if not alraedy initialized.
+ * Returns false, if binding failed.
+ */
+ virtual bool bind();
+
+ /**
+ * Releases program. To be called, when all rendering is finished.
+ * Calls disableAttributeArrays and releases program.
+ */
+ void release();
+ ///@}
+
+ //=================================================================
+ /**
+ * \name Unproject, project and mouse interaction functions
+ */
+ ///@{
+ /**
+ * Uses viewport and matrix settings to reverse the vertex transformation chain.
+ * vWin x,y and z are the coordinates in window coordinates. Lower left of viewport
+ * is winX = 0, winY = 0. Use winZ = 0.0 for a point on near clipping plane
+ * and winZ = 1.0 for a point on far clipping plane.
+ * This function assumes, that the vertex shader computes gl_positon as v * mvpMatrix.
+ * Use a custom shader reverse function, if this is not true.
+ * Returns coordinate in object space.
+ */
+ QVector3D unProjectViewportPoint(const QVector3D & vWin);
+
+ /**
+ * Performs inverse viewport transform.
+ */
+ QVector3D viewportToClip(const QVector3D & v);
+
+ /**
+ * Returns the points on near and far clipping plane, that correspond to the
+ * mouseX and mouseY coordinates of a mouse click.
+ * mouseX and mouseY are coordinates as delivered by QMouseEvent or QDeclarativeMouseEvent.
+ */
+ void calculateMousePoints(QVector3D * nearPoint, QVector3D * farPoint, const QPoint &mousePos );
+
+ /**
+ * Calculate the distance of the "mouse ray line" to point p in model space.
+ * mouseX, mouseY are the coordinates of the mouse click as delivered by QMouseEvent.
+ * Returns distance.
+ */
+ float distanceToMouseClick(QVector3D p, const QPoint &mousePos);
+
+ /**
+ * Calculates intersection of "mouse ray line" with the plane defined by normal and d.
+ * mouseX, mouseY are the coordinates of the mouse click as delivered by QMouseEvent.
+ * Returns true, if intersection is in the visible frustum, else returns false.
+ * If return value is true, *intersection is the intersection of the mouse ray line with
+ * the plane normal*(x,y,z) + d = 0.
+ * If return value is false, *intersection is not modified.
+ */
+ bool mouseIntersection(QVector3D * intersection, QVector3D normal, float d, const QPoint &mousePos);
+ ///@}
+
+
+ //======================================================================================
+ ///@{
+
+ /** Getters and setters for uniforms
+ */
+ /**
+ * Set modelview matrix. Updates mvpMatrix and normalMatrix too.
+ * Call setPMatrix or setPerspective first.
+ */
+ void setMvMatrix(const QMatrix4x4 newVal);
+ /**
+ * Getter for debugging.
+ */
+ const QMatrix4x4 & getMvMatrix(){return m_mvMatrix;}
+ /**
+ * Getter for debugging.
+ */
+ const QMatrix3x3 & getNormalMatrix(){return m_normalMatrix;}
+
+ /**
+ * Sets mvMatrix to a lookAt transformation.
+ * Call setPMatrix or setPerspective first.
+ */
+ void setLookAt(const QVector3D & eye,const QVector3D & center,const QVector3D & up );
+
+ /**
+ * Set projection matrix. Call setMvMatrix after this.
+ */
+ void setPMatrix(const QMatrix4x4 newVal);
+ /**
+ * Getter for debugging.
+ */
+ const QMatrix4x4 & getPMatrix(){return m_pMatrix;}
+ /**
+ * Setup projection matrix. Call setMvMatrix after this.
+ */
+ void setPerspective(GLfloat fovy, GLfloat aspect, GLfloat nearClip, GLfloat farClip);
+ /**
+ * @brief setOrtho Set pMatrix to an orthogonal projection.
+ * @param left
+ * @param right
+ * @param bottom
+ * @param top
+ * @param nearPlane
+ * @param farPlane
+ */
+ void setOrtho(float left, float right, float bottom, float top, float nearPlane, float farPlane);
+ /**
+ * Set viewport
+ * Viewport coordinates must be given as
+ * GL-viewport coordinates, where lower left is (0,0).
+ */
+ void setViewport(int x, int y, int w, int h);
+ /**
+ * Get the present viewport settings from GL engine
+ */
+ void readGLViewportSettings();
+
+ /**
+ * Set the color for ambient and diffuse lighting (or no lighting).
+ * Alternatively use a color array and color attribute.
+ * Defaults to white.
+ */
+ void setAmbientAndDiffuseColor(const GLColorRgba newVal);
+ /**
+ * Set the dimming factor for ambient light.
+ * Defaults to 0.2.
+ */
+ void setAmbientLightBrightness(float newVal);
+
+ /**
+ * Set the color for specular lighting.
+ * Defaults to white.
+ */
+ void setSpecularColor(const GLColorRgba newVal);
+ /**
+ * Set the shininess (exponent) for specular lighting.
+ * Defaults to 200.
+ */
+ void setShininess(float newVal);
+
+ /**
+ * Enable / disable lighting.
+ * Defaults to false.
+ */
+ void setLightingEnabled(bool newVal);
+ /**
+ * Returns lighting flag.
+ */
+ bool isLightingEnabled(){return m_lightingEnabled;}
+ /**
+ * Enable / disable color array.
+ * Defaults to false.
+ */
+ void setColorArrayEnabled(bool newVal);
+ /**
+ * Returns lighting flag.
+ */
+ bool isColorArrayEnabled(){return m_colorArrayEnabled;}
+ /**
+ * Set the texture flag.
+ * Defaults to false.
+ */
+ void setTextureEnabled(bool newVal);
+ /**
+ * Returns texture flag;
+ */
+ bool isTextureEnabled(){return m_textureEnabled;}
+ /**
+ * Set light direction.
+ * Defaults to (1.0, 1.0, 1.0)
+ */
+ void setLightDirection(const QVector3D & newVal);
+ /**
+ * Getter.
+ */
+ const QVector3D getLightDirection(){return m_lightDirection;}
+
+ /**
+ * Set size of points drawn with GL_POINTS.
+ * Defaults to 2.0.
+ */
+ void setPointSize(int newVal);
+
+ /**
+ * Returns pointSize;
+ */
+ int getPointSize(){return m_pointSize;}
+
+ /**
+ * Pushes mvMatrix.
+ */
+ void pushMvMatrix(){m_mvMatrixStack.push(m_mvMatrix);}
+
+ /**
+ * Pops mvMatrix from stack and updates normalMatrix and mvpMatrix.
+ */
+ void popMvMatrix();
+
+ /**
+ * Translates mvMatrix by v
+ */
+ void translate(const QVector3D & v);
+ void translate(float x, float y, float z);
+ /**
+ * Rotates mvMatrix by angle around axis
+ */
+ void rotate(GLfloat angle, const QVector3D & axis);
+ /**
+ * Rotates mvMatrix by angle around axis (x,y,z)
+ */
+ void rotate(float angle, float x, float y, float z);
+ void zoom(float zoomFactor);
+
+ /**
+ * @brief addTransformation
+ * Multiplies additionalTransformation to mvMatrix.
+ * @param additionalTransformation
+ */
+ void addTransformation(const QMatrix4x4 additionalTransformation);
+
+ /**
+ * Scales mvMatrix.
+ */
+ void scale(const QVector3D & v );
+
+ ///@}
+
+ //======================================================================================
+
+ ///@{
+ /**
+ * \name Attribute setters
+ */
+
+ /**
+ * Enables 2D Vertex, normal, color or texCoord arrays and sets start adresses of arrays
+ * Type may be: VERTEX_LOCATION, NORMAL_LOCATION, COLOR_LOCATION, TEXCOORD_LOCATION
+ */
+ bool activateAttributeArray (AttributeLocation location, const QVector2D * values, int stride = 0 );
+ /**
+ * Enables 3D Vertex, normal, color or texCoord arrays and sets start adresses of arrays
+ * Type may be: VERTEX_LOCATION, NORMAL_LOCATION, COLOR_LOCATION, TEXCOORD_LOCATION
+ */
+ bool activateAttributeArray (AttributeLocation location, const QVector3D * values, int stride = 0 );
+ /**
+ * Enables 4D Vertex or color arrays and sets start adresses of arrays
+ * Type may be: VERTEX_LOCATION, COLOR_LOCATION
+ */
+ bool activateAttributeArray (AttributeLocation location, const QVector4D * values, int stride = 0 );
+ /**
+ * Enables 3D Vertex, normal, color or texCoord buffer
+ * location may be: VERTEX_LOCATION, NORMAL_LOCATION, COLOR_LOCATION, TEXCOORD_LOCATION
+ * numbersPerElement: 3 for vertex, 2 or 3 for texture, 3 or 4 for color
+ */
+ bool activateAttributeBuffer (AttributeLocation location, int numbersPerElement, int bufferId);
+ /**
+ * Disables all enabled attribute arrays.
+ * To be called after rendering an object.
+ */
+ virtual void disableAttributeArrays();
+ ///@}
+
+ //==============================================================
+ ///@{
+
+ /**
+ * \name Debugging
+ */
+
+ /**
+ * Multiplies current mvp matrix with v. Mainly for debugging.
+ */
+ QVector3D modelToClip(const QVector3D & v);
+ /**
+ * Performs viewport transform. Mainly for debugging.
+ */
+ QVector3D clipToViewport(const QVector3D & v);
+ ///@}
+
+protected:
+
+ /**
+ * @brief activateAttributeArray
+ * Enables Vertex, normal, color or texCoord arrays and sets start adresses of arrays
+ * location may be: VERTEX_LOCATION, NORMAL_LOCATION, COLOR_LOCATION, TEXCOORD_LOCATION
+ * @param location
+ * @param values Address of first number
+ * @param tupleSize Numbers per vertex
+ * @param stride Distance to next tuple
+ * @return
+ */
+ bool activateAttributeArray (AttributeLocation location, const float * values, int tupleSize, int stride = 0 );
+
+ bool m_initialized;
+ bool m_bound;
+
+ //Uniforms to be passed to the shader
+ //flags
+ bool m_lightingEnabled; // flag for lighting
+ bool m_colorArrayEnabled; //flag for a valid color array
+ bool m_textureEnabled; //flag for active texturing
+ bool m_invertedMvpMatrixValid; //flag for a valid inverted ModelViewProjection matrix
+ //matrices
+ QMatrix4x4 m_mvpMatrix; //combined modelview and projection matrix
+ //The inverted mvp matrix for unproject purposes
+ //Use the invertedMvpMatrixValid flag for calculating it when required.
+ QMatrix4x4 m_invertedMvpMatrix;
+ QStack <QMatrix4x4>m_mvMatrixStack;
+ QMatrix4x4 m_mvMatrix; //modelview matrix
+ QMatrix4x4 m_pMatrix; //projection matrix
+ float m_fovy;
+ float m_aspect;
+ float m_nearClip; //near clipping plane
+ float m_farClip; //far clipping plane
+ bool m_OrthoMode;
+ QMatrix3x3 m_normalMatrix; //matrix for normal transformation
+ //lighting
+ QVector3D m_lightDirection; //direction of directional light
+ QVector3D m_halfPlaneVector; //half plane vector for specular light calculation
+ GLColorRgba m_ambientAndDiffuseColor;
+ float m_ambientLightBrightness;
+ GLColorRgba m_specularColor;
+ float m_shininess;
+ //texturing
+ int m_pointSize;
+
+ //Shaders and program
+ QString m_vShaderFileName; //vertex shader
+ QString m_fShaderFileName; //fragment shader
+ QOpenGLShader * m_vShader; //vertex shader
+ QOpenGLShader * m_fShader; // fragment shader
+ QOpenGLShaderProgram * m_renderProgram;
+
+ // Locations of shader variables
+ int m_location_aVertex;
+ int m_location_aColor;
+ int m_location_aNormal;
+ int m_location_aTexCoord;
+ int m_location_uColorArrayEnabled;
+ int m_location_uLightingEnabled;
+ int m_location_uNormalMatrix;
+ int m_location_uMvpMatrix;
+ int m_location_uAmbientAndDiffuseColor;
+ int m_location_uAmbientLightBrightness;
+ int m_location_uSpecularColor;
+ int m_location_uShininess;
+ int m_location_uLightDirection;
+ int m_location_uHalfPlaneVector;
+ int m_location_uPointSize;
+ int m_location_uTextureSampler;
+ int m_location_uTextureEnabled;
+
+ //The list of enabled attribute locations
+ QList<int>m_activeAttributeLocations;
+ //viewport
+ int m_viewportX;
+ int m_viewportY;
+ int m_viewportW;
+ int m_viewportH;
+};
+
+#endif // GLESRENDERER_H
diff --git a/src/glitem.cpp b/src/glitem.cpp
new file mode 100644
index 0000000..6e3984c
--- /dev/null
+++ b/src/glitem.cpp
@@ -0,0 +1,408 @@
+#include "glitem.h"
+#include "glesrenderer.h"
+#include "gldefines.h"
+#include "glcolorrgba.h"
+
+#include <QDebug>
+#include <QString>
+#include <QQuickWindow>
+#include <QtQuick/QQuickItem>
+#include <QtGui/QOpenGLShaderProgram>
+#include <QtGui/QOpenGLContext>
+
+#include <QSGSimpleRectNode>
+
+#include <math.h>
+
+#ifdef Q_OS_ANDROID
+#ifndef GLES
+ #define GLES //Android uses GLES 2.0
+#endif
+#endif
+
+
+GLItem::GLItem(QQuickItem *parent,
+ const QString &vertexShaderFilename,
+ const QString &fragmentShaderFilename) :
+ QQuickItem(parent)
+{
+ m_fragmentShaderFilename = fragmentShaderFilename;
+ m_vertexShaderFilename = vertexShaderFilename;
+ setFlag(ItemHasContents);
+ m_geometryIsValid = false;
+ m_colorArrayEnabled = false;
+ m_texturesEnabled = false;
+ m_lightingEnabled = true;
+ m_activatePaintBeforeQml = false;
+ m_activatePaintAfterQml = true;
+
+ m_lightDirection = v_XYZ;
+ m_backgroundColor = GLColorRgba::clBlue;
+
+ m_eye = 1.5 * v_XYZ;
+ m_center = v_Zero;
+ m_up = v_Y;
+ //pespective
+ m_fovy = 45.0;
+ m_aspect = 1.0;
+ m_near = 1.0;
+ m_far = 100.0;
+ m_orthoMode = false;
+
+ //The windowChanged signal is emitted by QQuickItem when it is added to the scenegraph.
+ //This is the first time when a valid window exists.
+ connect(this, SIGNAL(windowChanged(QQuickWindow*)),
+ this, SLOT(handleWindowChanged(QQuickWindow*)));
+ m_geometryIsValid = false; //invalidate geometry, we may need to set it up for the new window
+ m_timer = new QTimer(this);
+ m_timer->setInterval(20);
+ connect(m_timer, SIGNAL(timeout()),
+ this, SLOT(onTimerTimeout()), Qt::DirectConnection);
+ m_timer->start(50);
+ m_guiThreadRotation = 0.0;
+ m_renderThreadRotation = 0.0;
+ m_renderer = NULL;
+ m_firstAxesPoint = 0;
+ m_lastAxesPoint = 0;
+ m_viewportX = 0;
+ m_viewportY = 0;
+ setFlags(flags() | QQuickItem::ItemHasContents);
+}
+
+GLItem::~GLItem()
+{
+ deleteRenderer();
+}
+
+/**
+ * @brief GlItem::updatePaintNode
+ * @param node Returns the root of the subtree to be rendered ON TOP of scene rendered
+ * in paint().
+ * @return
+ */
+
+QSGNode * GLItem::updatePaintNode(QSGNode *node, UpdatePaintNodeData *updatePaintNodeData)
+{
+ //qDebug() << "GlItem::updatePaintNode called";
+ return QQuickItem::updatePaintNode(node, updatePaintNodeData);
+
+ //remove the above line and uncomment the rest of this function to draw a blue rectangle
+ //Example code for a blue rectangle
+ /* QSGSimpleRectNode *rect = static_cast<QSGSimpleRectNode *>(node);
+ if (!rect) {
+ rect = new QSGSimpleRectNode();
+ }
+ double w = 100;
+ if(window())
+ w = window()->width();
+ rect->setRect(0, 0, w, 100);
+ rect->setColor(Qt::blue);
+ return rect;
+ */
+}
+
+bool GLItem::movementActivated()
+{
+ return (m_timer && m_timer->isActive());
+}
+
+
+void GLItem::paintBefore()
+{
+ // qDebug() << "GlItem::paintBefore() called";
+ if(!m_renderer)
+ initializeRenderer();
+ if(!m_geometryIsValid)
+ setupGeometry();
+ if(!isVisible())
+ return;
+ setupView(true, true);
+ m_renderer->bind();
+ paintUnderQmlScene();
+ m_renderer->release();
+ window()->resetOpenGLState();
+}
+
+void GLItem::paintAfter()
+{
+ // qDebug() << "GlItem::paintBefore() called";
+
+ if(!m_renderer)
+ initializeRenderer();
+ if(!m_geometryIsValid)
+ setupGeometry();
+ if(!isVisible())
+ return;
+ setupView(false, true); // enables scissor test
+ m_renderer->bind();
+ paintOnTopOfQmlScene();
+ m_renderer->release();
+ glDisable(GL_SCISSOR_TEST);
+ window()->resetOpenGLState();
+}
+
+void GLItem::initializeRenderer()
+{
+ qDebug() <<"GlItem::initializeRenderer called.";
+ if(!m_renderer)
+ m_renderer = new GLESRenderer(NULL, m_vertexShaderFilename, m_fragmentShaderFilename);
+
+}
+
+void GLItem::deleteRenderer()
+{
+ qDebug() <<"GlItem::deleteRenderer() called.";
+ if(m_renderer)
+ {
+ delete m_renderer;
+ m_renderer = NULL;
+ }
+}
+
+void GLItem::synchronizeThreads()
+{
+// qDebug() << "GLItem::synchronizeThreads";
+ m_renderThreadRotation = m_guiThreadRotation;
+}
+
+void GLItem::timeOut()
+{
+ m_guiThreadRotation += 2.0;
+}
+
+void GLItem::toggleMove()
+{
+ qDebug() << "GlItem::move() called";
+ if(m_timer->isActive())
+ m_timer->stop();
+ else m_timer->start();
+ emit movementActivatedChanged();
+}
+
+void GLItem::mousePressed(int x, int y)
+{
+ qDebug() << "GlItem::mousePressed at x:" << x << " y: " << y;
+}
+
+void GLItem::mousePositionChanged(int x, int y)
+{
+ qDebug() << "GlItem::mouse position changed to x:" << x << " y: " << y;
+}
+
+void GLItem::mouseReleased(int x, int y)
+{
+ qDebug() << "GlItem::mouse released at x:" << x << " y: " << y;
+}
+
+void GLItem::setViewportX(int arg)
+{
+ if (m_viewportX == arg)
+ return;
+
+ m_viewportX = arg;
+ emit viewportXChanged(arg);
+}
+
+void GLItem::setViewportY(int arg)
+{
+ if (m_viewportY == arg)
+ return;
+
+ m_viewportY = arg;
+ emit viewportYChanged(arg);
+}
+
+void GLItem::setupView(bool clearColor, bool clearDepth)
+{
+ if(!m_renderer)
+ return;
+
+ qreal ratio = window()->devicePixelRatio();
+ int vx = int(ratio * m_viewportX);
+ int vy = int(ratio * m_viewportY); // y from bottom upwards!
+ int vw = int(ratio * width());
+ int vh = int(ratio * height());
+ glViewport(vx, vy, vw, vh);
+ //qDebug() << "GLItem::setupView viewport x: " << vx << " y: " << vy << " w: " << vw << " h: " << vh;
+ m_renderer->setViewport(vx, vy, vw, vh);
+ glEnable(GL_SCISSOR_TEST);
+ glScissor(vx,vy,vw,vh);
+
+ m_aspect = (double)vw / (double)vh;
+ if(! m_orthoMode ){
+ m_renderer->setPerspective(m_fovy,
+ m_aspect,
+ m_near,
+ m_far);
+ }
+ else m_renderer->setOrtho(-2.0, 2.0, -2.0, 2.0, 0.1, 100.0); // for debugging
+ m_renderer->setLookAt(m_eye, //eye
+ m_center, //center
+ m_up);//up
+ //setup light before turning
+ m_renderer->setLightDirection(m_lightDirection);
+ m_renderer->setLightingEnabled(true);
+ //now turn
+ m_renderer->addTransformation(m_cameraTransform);
+
+ m_renderer->rotate(m_renderThreadRotation, QVector3D(0.0,0.0,1.0));
+
+ glEnable(GL_DEPTH_TEST);
+ glDepthFunc(GL_LESS);
+ glDepthMask(true);
+
+ //Clear buffers as required
+#ifndef GLES
+ glClearDepth(1.0);
+#endif
+ glClearColor(m_backgroundColor.red(), m_backgroundColor.green(),
+ m_backgroundColor.blue(), m_backgroundColor.alpha());
+ GLuint clearMode = 0;
+ if(clearColor)
+ clearMode |= GL_COLOR_BUFFER_BIT;
+ if(clearDepth)
+ clearMode |= GL_DEPTH_BUFFER_BIT;
+ glClear(clearMode);
+
+
+ glEnable(GL_BLEND);
+ glBlendFunc(1.0, 0.0);
+ // glPolygonMode(GL_FRONT, GL_FILL);
+ // glPolygonMode(GL_BACK, GL_LINES);
+}
+
+/**
+ * @brief GlItem::handleWindowChanged
+ *
+ * Connect to the window's signals. This can not be done in the constructor, because at that time
+ * there is no valid window yet.
+ * @param win The window in which this QQuickItem will be painted.
+ */
+void GLItem::handleWindowChanged(QQuickWindow *win)
+{
+ qDebug() << "GlItem::handleWindowChanged() called.";
+ if (win) {
+ // Connect the beforeRendering signal to our paint function.
+ // Since this call is executed on the rendering thread it must be
+ // a Qt::DirectConnection
+ if(m_activatePaintBeforeQml)
+ connect(win, SIGNAL(beforeRendering()),
+ this, SLOT(paintBefore()), Qt::DirectConnection);
+ if(m_activatePaintAfterQml)
+ connect(win, SIGNAL(afterRendering()),
+ this, SLOT(paintAfter()), Qt::DirectConnection);
+ connect(win, SIGNAL(beforeSynchronizing()),
+ this, SLOT(slotSynchronizeThreads()), Qt::DirectConnection);
+ if(win->openglContext())
+ connect(win->openglContext(), SIGNAL(aboutToBeDestroyed()), //cleanup context before destroying window
+ this, SLOT(deleteRenderer()), Qt::DirectConnection);
+ // If we allow QML to do the clearing, they would clear what we paint
+ // and nothing would show.
+ win->setClearBeforeRendering(false);
+ }
+}
+
+void GLItem::onTimerTimeout()
+{
+ //qDebug() << "GlItem::onTimerTimeout() called";
+ timeOut();
+ if (window())
+ window()->update();
+}
+
+void GLItem::slotSynchronizeThreads()
+{
+ synchronizeThreads();
+}
+
+void GLItem::setupGeometry()
+{
+ m_geometryIsValid = true;
+}
+
+
+void GLItem::paintUnderQmlScene()
+{
+ qDebug() << "GlItem::paintUnderQmlScene() was called. Overwrite this function to paint your scene!";
+}
+
+void GLItem::paintOnTopOfQmlScene()
+{
+ qDebug() << "GlItem::paintOnTopOfQmlScene() was called. Overwrite this function to paint your scene!";
+}
+
+void GLItem::drawAxes(double length)
+{
+ if(m_lastAxesPoint == 0)
+ createAxes(length);
+ GLfloat lineWidth[4]; //4 floats, just for safety
+ glGetFloatv(GL_LINE_WIDTH, lineWidth);
+ glLineWidth(3.0);
+ m_renderer->setColorArrayEnabled(true);
+
+ m_renderer->setLightingEnabled(false);
+ int stride = sizeof(GLPoint);
+ m_renderer->activateAttributeArray(GLESRenderer::VERTEX_LOCATION,
+ m_points[0].vertexPointer(), stride);
+ m_renderer->activateAttributeArray(GLESRenderer::COLOR_LOCATION,
+ m_points[0].colorPointer(), stride);
+ glDrawArrays(GL_LINES, m_firstAxesPoint, m_lastAxesPoint - m_firstAxesPoint); //Coordinate Axes
+ m_renderer->disableAttributeArrays();
+ //restore old settings
+ m_renderer->setColorArrayEnabled(false);
+ m_renderer->setLightingEnabled(true);
+ glLineWidth(lineWidth[0]);
+}
+
+void GLItem::createAxis(double length, const QVector3D & origin, const QVector3D & axis,
+ const QVector3D & normal, const QVector3D & texCoord,
+ const GLColorRgba& color)
+{
+ int ticks = floor(length);
+ double tickLength = 0.1;
+ double tickLongLength = tickLength * 2;
+ m_points.append(GLPoint(origin, normal, texCoord,color));
+ m_points.append(GLPoint(axis * length, normal, texCoord,color));
+ for(int tick = 1; tick <= ticks; tick++)
+ {
+ if(tick % 5 == 0)
+ {
+ m_points.append(GLPoint(origin + axis * tick, normal, texCoord, color));
+ m_points.append(GLPoint(origin + axis * tick + normal * tickLongLength, normal, texCoord, color));
+ }
+ else
+ {
+ m_points.append(GLPoint(origin + axis * tick, normal, texCoord, color));
+ m_points.append(GLPoint(origin + axis * tick + normal * tickLength, normal, texCoord, color));
+ }
+ }
+}
+
+void GLItem::createAxes(double length)
+{
+
+ m_firstAxesPoint = m_points.size();
+
+ //X-axis
+ QVector3D origin = v_Zero;
+ QVector3D axis = v_X;
+ QVector3D normal = v_Y;
+ QVector3D texCoord = v_Zero;
+ GLColorRgba color = cl_Red;
+
+ createAxis(length, origin, axis, normal, texCoord, color);
+ //Y-Axis
+ axis = v_Y;
+ normal = v_Z;
+ color= cl_Green;
+ createAxis(length, origin, axis, normal, texCoord, color);
+
+ //Z-Axis
+ axis = v_Z;
+ normal = v_X;
+ color= cl_Blue;
+ createAxis(length, origin, axis, normal, texCoord, color);
+
+ m_lastAxesPoint = m_points.size();
+}
+
diff --git a/src/glitem.h b/src/glitem.h
new file mode 100644
index 0000000..268dbeb
--- /dev/null
+++ b/src/glitem.h
@@ -0,0 +1,290 @@
+#ifndef GLITEM_H
+#define GLITEM_H
+
+#include <QQuickItem>
+#include <QOpenGLShaderProgram>
+#include <QMatrix4x4>
+#include <QVector>
+#include <QTimer>
+
+#include "glpoint.h"
+#include "glesrenderer.h"
+
+/**
+ * @brief The GlItem class is a 3D-scene item designed for use in QML SceneGraphs.
+ * It should be subclassed according to your requirements, registered with qmlRegisterType
+ * and used as a component in QML files.
+ * The default constructor will use src/vshader.vsh and src/fshader.fsh as shaders.
+ * Fell free to use shaders of your own. Refer to the GLESRenderer class for shader requirements.
+ * Geometry data should be put into m_points and m_vertices containers for maximum performance.
+ * Use paintUnderQml or paintOnTopOfQml to paint a 3D scene under or on top of the QML elements of the QML SceneGraph.
+ * For debugging geometries, call toggleMove to let the scene rotate around m_rotationAxis.
+ * Warning:
+ * Updating geometry data must be carried out in synchronizeThreads, because drawing will be performed
+ * on the rendering thread. The rendering thread is waiting when synchronizeThreads is called.
+ *
+ */
+class GLItem : public QQuickItem
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QString vertexShaderFilename READ vertexShaderFilename WRITE setVertexShaderFilename NOTIFY vertexShaderFilenameChanged)
+ Q_PROPERTY(QString fragmentShaderFilename READ fragmentShaderFilename WRITE setFragmentShaderFilename NOTIFY fragmentShaderFilenameChanged)
+ Q_PROPERTY(bool movementActivated READ movementActivated NOTIFY movementActivatedChanged)
+ Q_PROPERTY(int viewportX READ viewportX WRITE setViewportX NOTIFY viewportXChanged)
+ Q_PROPERTY(int viewportY READ viewportY WRITE setViewportY NOTIFY viewportYChanged)
+
+ typedef enum{
+ VERTEX_LOCATION,
+ NORMAL_LOCATION,
+ COLOR_LOCATION,
+ TEXCOORD_LOCATION
+ }AttributeLocation;
+
+ /**
+ * @brief m_viewportX The viewport position in window() coordinates to be used
+ * for OpenGL rendering. width and height are taken from QQuickItem.
+ */
+ int m_viewportX;
+
+ /**
+ * @brief m_viewportX The viewport position in window() coordinates to be used
+ * for OpenGL rendering. width and height are taken from QQuickItem.
+ * ! Positive y axis is upwards!
+ */
+ int m_viewportY;
+ /**
+ * @brief createAxis creates a coordinate axis
+ * @param length Total length of axis, starting from origin
+ * @param origin Start coordinate of axis
+ * @param axis Direction of axis
+ * @param normal Direction of ticks and dummy normal.
+ * @param texCoord Dummy texture coordinate
+ * @param color Color of axis
+ */
+ void createAxis(double length, const QVector3D &origin, const QVector3D &axis,
+ const QVector3D &normal, const QVector3D &texCoord,
+ const GLColorRgba &color);
+
+public:
+ explicit GLItem(QQuickItem *parent = 0,
+ const QString &vertexShaderFilename = ":/shaders/vshader.vsh",
+ const QString &fragmentShaderFilename = ":/shaders/fshader.fsh");
+ virtual ~GLItem();
+
+ /**
+ * @brief updatePaintNode Overwrite this function, if you want to add items to the scenegraph.
+ * Do not call this function. It will be called automatically.
+ * @param node
+ * @return
+ */
+ QSGNode * updatePaintNode(QSGNode *node, UpdatePaintNodeData *updatePaintNodeData);
+
+ //simple getters
+ QString fragmentShaderFilename() const{return m_fragmentShaderFilename;}
+ QString vertexShaderFilename() const{return m_vertexShaderFilename;}
+
+ bool movementActivated();
+
+ void setEye (const QVector3D & newVal)
+ {
+ m_eye = newVal;
+ }
+
+ int viewportX() const
+ {
+ return m_viewportX;
+ }
+
+ int viewportY() const
+ {
+ return m_viewportY;
+ }
+
+protected:
+ /**
+ * @brief paintUnderQmlScene
+ * Virtual function for painting under a QML scene. This function is called by paintBefore after
+ * calling createGeometries and initializing and binding the renderer.
+ * Overwrite in subclasses for painting geometries in m_points with the renderer.
+ */
+ virtual void paintUnderQmlScene();
+ /**
+ * @brief paintUnderQmlScene
+ * Virtual function for painting on top of a QML scene. This function is called by paintAfter after
+ * calling createGeometries and initializing and binding the renderer.
+ * Overwrite in subclasses for painting geometries in m_points with the renderer.
+ */
+ virtual void paintOnTopOfQmlScene();
+
+ /**
+ * @brief drawAxes Draw the axes in GL_LINES mode without lighting.
+ * If axes points do not exist, call createAxes with length parameter
+ * @param length Axes length
+ */
+ virtual void drawAxes(double length);
+
+ /**
+ * @brief createAxes Creates x, y and z axis with specified length starting for (0,0,0)
+ * @param length Axes length.
+ */
+ virtual void createAxes(double length);
+
+signals:
+
+ //NOTIFY signals
+ void vertexShaderFilenameChanged(QString arg);
+ void fragmentShaderFilenameChanged(QString arg);
+ void movementActivatedChanged();
+ void viewportXChanged(int arg);
+ void viewportYChanged(int arg);
+
+public slots:
+ /**
+ * @brief paintBefore
+ * Activates renderer, clear color and depth buffers and calls paintUnderQmlScene.
+ * This function should not be overwritten
+ */
+ void paintBefore();
+ /**
+ * @brief paintAfter
+ * Activates renderer, clear color and depth buffers and calls paintOnTopOfQmlScene.
+ * This function should not be overwritten
+ */
+ void paintAfter();
+
+ /**
+ * @brief toggleMove
+ * Start or stop movement by starting or stopping the redraw timer.
+ */
+ void toggleMove();
+
+ /** Mouse event handler to be called from QML
+ **/
+ void mousePressed(int x, int y);
+ void mousePositionChanged(int x, int y);
+ void mouseReleased(int x, int y);
+
+ // Simple setters
+ void setVertexShaderFilename(QString arg)
+ {
+ if (m_vertexShaderFilename != arg) {
+ m_vertexShaderFilename = arg;
+ emit vertexShaderFilenameChanged(arg);
+ }
+ }
+ void setFragmentShaderFilename(QString arg)
+ {
+ if (m_fragmentShaderFilename != arg) {
+ m_fragmentShaderFilename = arg;
+ emit fragmentShaderFilenameChanged(arg);
+ }
+ }
+
+
+ void setViewportX(int arg);
+
+ void setViewportY(int arg);
+
+protected slots:
+ /**
+ * @brief handleWindowChanged
+ * @param win This function is called when the parent Window changes.
+ * This is also the case, when a parent window is set for the first time.
+ */
+ void handleWindowChanged(QQuickWindow *win);
+ /**
+ * @brief onTimerTimeout Overwrite for moving the scene.
+ */
+ void onTimerTimeout();
+
+ /**
+ * @brief slotSynchronizeThreads This slot is connected to the beforeSysnchronizing signal.
+ * Calls virtual synchronizeThreads() function.
+ */
+ void slotSynchronizeThreads();
+
+ /**
+ * @brief deleteRenderer
+ * Delete renderer unloads shader program and deletes renderer.
+ */
+ void deleteRenderer();
+
+protected:
+
+ /**
+ * @brief synchronizeThreads
+ * Render thread is sleeping when this function is called.
+ * Copy geometry modifications from GuiThread owned variables here.
+ */
+ virtual void synchronizeThreads();
+ /**
+ * @brief timeOut Virtual function, called in slot onTimerTimeout
+ * To be overwritten in subclasses.
+ */
+ virtual void timeOut();
+ QVector<GLPoint> * points(){return &m_points;}
+ QVector<GLshort> * indices(){return &m_indices;}
+ GLESRenderer * renderer() {return m_renderer;}
+
+
+ /**
+ * @brief setupGeometry Put the geometric data into the points array and set m_geometryIsValid flag.
+ * MUST be overridden in subclasses. GlItem::setupGeometry() does nothing.
+ */
+ virtual void setupGeometry();
+ /**
+ * @brief setupView Setup matrices, lighting and basic GL rendering settings
+ * GlItem::setupView sets up a basic view with (0,0,0) in the center of the screen.
+ * You may override this function to fit your requirements.
+ */
+ virtual void setupView(bool clearColor, bool clearDepth);
+
+protected:
+ //flags
+ bool m_geometryIsValid;
+ bool m_colorArrayEnabled;
+ bool m_texturesEnabled;
+ bool m_lightingEnabled;
+ bool m_activatePaintBeforeQml;
+ bool m_activatePaintAfterQml;
+ bool m_orthoMode;//orthogonal projection for debugging
+
+ //lighting and colors
+ QVector3D m_lightDirection;
+ GLfloat m_ambientLightBrightness;
+ GLColorRgba m_backgroundColor;
+ //vectors for lookAt
+ QVector3D m_eye;
+ QVector3D m_center;
+ QVector3D m_up;
+ //pespective
+ double m_fovy;
+ double m_aspect;
+ double m_near;
+ double m_far;
+ //rotation
+ QTimer * m_timer;
+ double m_guiThreadRotation;
+ double m_renderThreadRotation;
+ //shaders
+ QString m_vertexShaderFilename;
+ QString m_fragmentShaderFilename;
+ //Camera transformation matrix
+ QMatrix4x4 m_cameraTransform;
+
+ /**
+ * @brief createShaderProgram
+ * creates and links the shader program using vshader.
+ */
+ virtual void initializeRenderer();
+ //containers for geometry
+ QVector <GLPoint> m_points;
+ QVector <GLshort> m_indices;
+ int m_firstAxesPoint;
+ int m_lastAxesPoint;
+ //renderer
+ GLESRenderer * m_renderer;
+};
+
+#endif // GLITEM_H
diff --git a/src/glpoint.cpp b/src/glpoint.cpp
new file mode 100644
index 0000000..a8a1a8d
--- /dev/null
+++ b/src/glpoint.cpp
@@ -0,0 +1,13 @@
+#include "glpoint.h"
+
+GLPoint::GLPoint(const QVector3D & vertex, const QVector3D & normal, const QVector3D & texCoord,
+ const GLColorRgba & color ) {
+ this->vertex = vertex;
+ this->normal = normal;
+ this->texCoord = texCoord;
+ this->color = color ;
+} /* ----- end of constructor ----- */
+
+GLPoint::~GLPoint() {
+ // Es gibt momentan keinen Speicherplatz der freigegebene werden muss
+} /* ----- end of destructor ----- */
diff --git a/src/glpoint.h b/src/glpoint.h
new file mode 100644
index 0000000..317cc95
--- /dev/null
+++ b/src/glpoint.h
@@ -0,0 +1,45 @@
+#ifndef GLPOINT_H
+#define GLPOINT_H
+#include <QVector3D>
+#include "glcolorrgba.h"
+// ----------------------------------------------------------------------------
+class GLPoint {
+ public : GLPoint( const QVector3D & vertex = QVector3D (0.0, 0.0, 0.0),
+ const QVector3D & normal = QVector3D (0.0, 1.0, 0.0),
+ const QVector3D & texCoord = QVector3D (0.0, 0.0, 0.0),
+ const GLColorRgba & color = GLColorRgba(1.0, 1.0, 1.0, 1.0) );
+ ~GLPoint();
+
+ QVector3D * vertexPointer (); // Returns address of vertex coordinate
+ QVector3D * normalPointer (); // Returns address of normal coordinate
+ QVector3D * texCoordPointer(); // Returns address of texture coordinate
+ QVector4D * colorPointer (); // Returns address of color
+
+ void move( QVector3D vMove );
+
+ private: QVector3D vertex;
+ QVector3D normal;
+ QVector3D texCoord;
+ GLColorRgba color ;
+}; /* ----- end of class GLPoint ----- */
+
+inline QVector3D * GLPoint::vertexPointer() {
+ return & vertex;
+} /* ----- end of method vertexPointer ----- */
+
+inline QVector3D * GLPoint::normalPointer() {
+ return & normal;
+} /* ----- end of method normalPointer ----- */
+
+inline QVector3D * GLPoint::texCoordPointer() {
+ return & texCoord;
+} /* ----- end of method texCoordPointer ----- */
+
+inline QVector4D * GLPoint::colorPointer() {
+ return (QVector4D *) & color;
+} /* ----- end of method colorPointer ----- */
+
+inline void GLPoint::move( QVector3D vMove ) {
+ vertex = vertex + vMove;
+} /* ----- end of method move ----- */
+#endif // GLPOINT_H
diff --git a/src/main.cpp b/src/main.cpp
new file mode 100644
index 0000000..cbdc925
--- /dev/null
+++ b/src/main.cpp
@@ -0,0 +1,15 @@
+#include <QApplication>
+#include <QQmlApplicationEngine>
+#include <qqml.h>
+#include "mmscene.h"
+
+int main(int argc, char *argv[])
+{
+ QApplication app(argc, argv);
+
+ QQmlApplicationEngine engine;
+ qmlRegisterType<MMScene>("MultiMediaProgrammierung", 1, 0, "MMScene");
+ engine.load(QUrl(QStringLiteral("qrc:/qml/main.qml")));
+
+ return app.exec();
+}
diff --git a/src/mmscene.cpp b/src/mmscene.cpp
new file mode 100644
index 0000000..1aca89f
--- /dev/null
+++ b/src/mmscene.cpp
@@ -0,0 +1,89 @@
+#include "mmscene.h"
+#include "glpoint.h"
+#include "glcolorrgba.h"
+
+MMScene::MMScene(QQuickItem *parent)
+ :GLItem(parent)
+{
+ m_vertexShaderFilename = ":/shaders/vshader.vsh";
+ m_eye = 2.5 * v_XYZ;
+
+}
+
+MMScene::~MMScene()
+{
+
+}
+
+void MMScene::paintUnderQmlScene()
+{
+ m_renderer->pushMvMatrix();
+ // drawAxes(2.5);
+ drawTriangles();
+ m_renderer->popMvMatrix();
+}
+
+void MMScene::paintOnTopOfQmlScene()
+{
+ m_renderer->pushMvMatrix();
+ drawAxes(2.5);
+ drawTriangles();
+ m_renderer->popMvMatrix();
+}
+
+void MMScene::setupGeometry()
+{
+ //Now we create the geometry. Every corner needs a vertex, a normal, a color and a texture,
+ //although normal and texture are not used for basic rendering.
+ QVector3D v00 = QVector3D(0.0, 0.0, 0.0);
+ QVector3D v01 = QVector3D(1.0, 0.0, 0.0);
+ QVector3D v02 = QVector3D(0.0, 1.0, 0.0);
+ QVector3D n0 = QVector3D(0.0, 0.0, 1.0); //dummy normal
+ QVector3D t0 = QVector3D(0.0,0.0,0.0); //dummy texture
+
+ //append the vertices for the triangle
+ m_points.append(GLPoint(v00, n0, t0, GLColorRgba::clRed));
+ m_points.append(GLPoint(v01, n0, t0, GLColorRgba::clGreen));
+ m_points.append(GLPoint(v02, n0, t0, GLColorRgba::clBlue));
+
+ QVector3D v10 = QVector3D(1.0, 1.0, 0.0);
+ QVector3D v11 = QVector3D(1.0, 0.0, 0.0);
+ QVector3D v12 = QVector3D(0.0, 1.0, 0.0);
+
+ //append the vertices for the triangle
+ m_points.append(GLPoint(v10, n0, t0, GLColorRgba::clRed));
+ m_points.append(GLPoint(v11, n0, t0, GLColorRgba::clGreen));
+ m_points.append(GLPoint(v12, n0, t0, GLColorRgba::clBlue));
+
+ m_colorArrayEnabled = true;
+
+ m_geometryIsValid = true;
+}
+
+void MMScene::drawTriangles()
+{
+ renderer()->setLightingEnabled(m_lightingEnabled);
+ renderer()->setColorArrayEnabled(m_colorArrayEnabled);
+ renderer()->setTextureEnabled(false);
+
+ //enable required arrays
+ int stride = sizeof(GLPoint);
+ for(int i = 0; i < m_points.length(); i += 3)
+ {
+ if(i > m_lastAxesPoint || i < m_firstAxesPoint)
+ {
+ renderer()->activateAttributeArray(GLESRenderer::VERTEX_LOCATION,
+ m_points[i].vertexPointer(), stride);
+ renderer()->activateAttributeArray(GLESRenderer::NORMAL_LOCATION,
+ m_points[i].normalPointer(), stride);
+ renderer()->activateAttributeArray(GLESRenderer::TEXCOORD_LOCATION,
+ m_points[i].texCoordPointer(), stride);
+ renderer()->activateAttributeArray(GLESRenderer::COLOR_LOCATION,
+ m_points[i].colorPointer(), stride);
+
+ glDrawArrays(GL_TRIANGLES, 0, 3);
+ }
+ }
+ renderer()->disableAttributeArrays();
+}
+
diff --git a/src/mmscene.h b/src/mmscene.h
new file mode 100644
index 0000000..8bfa74e
--- /dev/null
+++ b/src/mmscene.h
@@ -0,0 +1,43 @@
+#ifndef MMSCENE_H
+#define MMSCENE_H
+
+#include "glitem.h"
+
+class MMScene : public GLItem
+{
+ Q_OBJECT
+
+public:
+ MMScene(QQuickItem *parent = 0);
+ ~MMScene();
+
+protected:
+ /**
+ * @brief paintUnderQmlScene
+ * Virtual function for painting under a QML scene. This function is called by paintBefore after
+ * calling createGeometries and initializing and binding the renderer.
+ * Overwrite in subclasses for painting geometries in m_points with the renderer.
+ */
+ virtual void paintUnderQmlScene();
+ /**
+ * @brief paintUnderQmlScene
+ * Virtual function for painting on top of a QML scene. This function is called by paintAfter after
+ * calling createGeometries and initializing and binding the renderer.
+ * Overwrite in subclasses for painting geometries in m_points with the renderer.
+ */
+ virtual void paintOnTopOfQmlScene();
+ /**
+ * @brief setupGeometry puts the geometric data into the arrays (m_Vertices etc.) and sets geometryIsValid flag.
+ */
+ void setupGeometry();
+
+ /**
+ * @brief drawTriangles
+ * Draws two triangles.
+ */
+ void drawTriangles();
+
+
+};
+
+#endif // MMSCENE_H
diff --git a/src/shaderdebugger.cpp b/src/shaderdebugger.cpp
new file mode 100644
index 0000000..8132654
--- /dev/null
+++ b/src/shaderdebugger.cpp
@@ -0,0 +1,103 @@
+#include "shaderdebugger.h"
+
+bool ShaderDebugger::enabled = false;
+
+ShaderDebugger::ShaderDebugger()
+{
+}
+
+void ShaderDebugger::debugUniforms(int programId)
+{
+ if(!enabled)
+ return;
+#ifdef GLES
+ char name[256];
+ int length;
+ int size;
+ GLenum type;
+ int nUniforms;
+ glGetProgramiv(programId, GL_ACTIVE_UNIFORMS, &nUniforms);
+ for (int i = 0; i < nUniforms; i++)
+ {
+ glGetActiveUniform(programId,
+ i,
+ sizeof(name),
+ &length,
+ &size,
+ &type,
+ name );
+ qDebug("Properties of uniform at index %i : %s", i, name);
+ switch (type)
+ {
+ case GL_FLOAT_MAT3: qDebug("Type : GL_FLOAT_MAT3");break;
+ case GL_FLOAT_MAT4: qDebug("Type : GL_FLOAT_MAT4");break;
+ case GL_FLOAT_VEC2: qDebug("Type : GL_FLOAT_VEC2");break;
+ case GL_FLOAT_VEC3: qDebug("Type : GL_FLOAT_VEC3");break;
+ case GL_FLOAT_VEC4: qDebug("Type : GL_FLOAT_VEC4");break;
+ case GL_FLOAT: qDebug("Type : GL_FLOAT");break;
+ case GL_BOOL: qDebug("Type : GL_BOOL");break;
+ default: qDebug("Type: %i", type);
+ }
+ qDebug("Array size: %i", size);
+ int location = glGetUniformLocation(programId, name);
+ qDebug("Location: %i", location);
+ }
+#else
+ qDebug("ShaderDebugger::debugUniforms works on GLES platforms only.");
+ Q_UNUSED(programId);
+#endif
+}
+
+
+void ShaderDebugger::debugMatrix4x4(const QMatrix4x4 & m, const QString & caption)
+{
+ if(!enabled)
+ return;
+
+ qDebug("%s",qPrintable(caption));
+ for(int row = 0; row < 4; row ++)
+ {
+ QVector4D vRow = m.row(row);
+ QString sRow = QString(" Row %1: %2\t %3\t%4\t%5")\
+ .arg(row).arg(vRow.x(),4,'g',4).arg(vRow.y(),4,'g',4).arg(vRow.z(),4,'g',4).arg(vRow.w(),4,'g',4);
+ qDebug("%s",qPrintable(sRow));
+ }
+}
+
+void ShaderDebugger::debugMatrix3x3(const QMatrix3x3 & m, const QString & caption)
+{
+ if(!enabled)
+ return;
+
+ QMatrix4x4 m4x4 = QMatrix4x4(m);
+ qDebug("%s",qPrintable(caption));
+ for(int row = 0; row < 3; row ++)
+ {
+ QVector4D vRow = m4x4.row(row);
+ QString sRow = QString(" Row %1: %2\t %3\t%4")\
+ .arg(row).arg(vRow.x(),4,'g',4).arg(vRow.y(),4,'g',4).arg(vRow.z(),4,'g',4);
+ qDebug("%s",qPrintable(sRow));
+ }
+}
+
+void ShaderDebugger::debugVector4D(const QVector4D & v, const QString & caption)
+{
+ if(!enabled)
+ return;
+
+ QVector4D vRow = v;
+ QString sRow = QString(" %1\t%2\t%3\t%4")\
+ .arg(vRow.x(),4,'g',4).arg(vRow.y(),4,'g',4).arg(vRow.z(),4,'g',4).arg(vRow.w(),4,'g',4);
+ qDebug("%s",qPrintable(caption + sRow));
+}
+
+void ShaderDebugger::debugVector3D(const QVector3D & v, const QString & caption)
+{
+ if(!enabled)
+ return;
+
+ QVector3D vRow = v;
+ QString sRow = QString(" %1\t%2\t%3")\
+ .arg(vRow.x(),4,'g',4).arg(vRow.y(),4,'g',4).arg(vRow.z(),4,'g',4);
+ qDebug("%s",qPrintable(caption + sRow));
+}
diff --git a/src/shaderdebugger.h b/src/shaderdebugger.h
new file mode 100644
index 0000000..db6f9e3
--- /dev/null
+++ b/src/shaderdebugger.h
@@ -0,0 +1,68 @@
+/***************************************************************************
+ * Copyright (C) 2012 by Walter Roth *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef SHADERDEBUGGER_H
+#define SHADERDEBUGGER_H
+
+#include <QtOpenGL/QGLWidget>
+#include <QMatrix3x3>
+#include <QMatrix4x4>
+
+/** \brief A simple debugging tool for uniforms passed to a shader.
+ *
+ * There is no way to get the values of variables inside a shader, therefore you have to look
+ * at the variables, before they are passed to the shader.
+ */
+class ShaderDebugger
+{
+public:
+ ShaderDebugger();
+ static void setEnabled(bool newVal){enabled = newVal;}
+ /**
+ * Works on GLES platforms only.
+ */
+ static void debugUniforms(int programId);
+ /**
+ * @brief debugMatrix4x4 Send debug output to stderr.
+ * @param m The matrix
+ * @param caption
+ */
+ static void debugMatrix4x4(const QMatrix4x4 & m, const QString & caption = "QMatrix4x4");
+ /**
+ * @brief debugMatrix3x3 Send debug output to stderr.
+ * @param m The matrix
+ * @param caption
+ */
+ static void debugMatrix3x3(const QMatrix3x3 & m, const QString & caption = "QMatrix3x3");
+ /**
+ * @brief debugVector4D Send debug output to stderr.
+ * @param m The vector
+ * @param caption
+ */
+ static void debugVector4D(const QVector4D & v, const QString & caption = "QVector4D");
+ /**
+ * @brief debugVector4D Send debug output to stderr.
+ * @param m The vector
+ * @param caption
+ */
+ static void debugVector3D(const QVector3D & v, const QString & caption = "QVector3D");
+private:
+ static bool enabled;
+};
+
+#endif // SHADERDEBUGGER_H