1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
|
#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 createCubef Creates a cube and apends it for drawing.
* @param lbb The left bottom back cube vector.
* @param rtf The right top front cube vector.
*/
virtual void createCube(const QVector3D &lbb, const QVector3D &rtf);
/**
* @brief createF Creates an 'F' with cubes.
* @param height The height of the 'F'.
*/
virtual void createF(double height);
/**
* @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
|