1
/***************************************************************************
2
* Copyright (C) 2009-2013 by Savoir-Faire Linux *
3
* Author : Emmanuel Lepage Valle <emmanuel.lepage@savoirfairelinux.com >*
6
* This program is free software; you can redistribute it and/or modify *
7
* it under the terms of the GNU General Public License as published by *
8
* the Free Software Foundation; either version 3 of the License, or *
9
* (at your option) any later version. *
11
* This program is distributed in the hope that it will be useful, *
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14
* GNU General Public License for more details. *
16
* You should have received a copy of the GNU General Public License *
17
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
18
**************************************************************************/
19
#include "acceleratedvideowidget.h"
22
#include "../lib/videomodel.h"
23
#include "../lib/videorenderer.h"
27
#include <QtGui/QImage>
28
#include <QtCore/QPropertyAnimation>
30
static const qreal FACE_SIZE = 0.4;
32
static const qreal speeds[] = { 1.8f, 2.4f, 3.6f };
33
static const qreal amplitudes[] = { 2.0f, 2.5f, 3.0f };
35
static inline void qSetColor(float colorVec[], QColor c)
37
colorVec[0] = c.redF();
38
colorVec[1] = c.greenF();
39
colorVec[2] = c.blueF();
40
colorVec[3] = c.alphaF();
43
int Geometry::append(const QVector3D &a, const QVector3D &n, const QVector2D &t)
45
int v = vertices.count();
50
colors.append(QVector4D(0.6f, 0.6f, 0.6f, 1.0f));
54
void Geometry::addQuad(const QVector3D &a, const QVector3D &b,
55
const QVector3D &c, const QVector3D &d,
56
const QVector<QVector2D> &tex)
58
QVector3D norm = QVector3D::normal(a, b, c);
59
// append first triangle
60
int aref = append(a, norm, tex[0]);
61
append(b, norm, tex[1]);
62
int cref = append(c, norm, tex[2]);
63
// append second triangle
66
append(d, norm, tex[3]);
69
void Geometry::loadArrays() const
71
glEnableClientState(GL_VERTEX_ARRAY);
72
glEnableClientState(GL_NORMAL_ARRAY);
73
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
74
glEnableClientState(GL_COLOR_ARRAY);
75
glVertexPointer(3, GL_FLOAT, 0, vertices.constData());
76
glNormalPointer(GL_FLOAT, 0, normals.constData());
77
glTexCoordPointer(2, GL_FLOAT, 0, texCoords.constData());
78
glColorPointer(4, GL_FLOAT, 0, colors.constData());
81
void Geometry::setColors(int start, GLfloat colorArray[4][4])
83
int off = faces[start];
84
for (int i = 0; i < 4; ++i)
85
colors[i + off] = QVector4D(colorArray[i][0],
91
Tile::Tile(const QVector3D &loc)
98
qSetColor(faceColor, QColor(Qt::darkGray));
101
void Tile::setColors(GLfloat colorArray[4][4])
104
geom->setColors(start, colorArray);
107
static inline void qMultMatrix(const QMatrix4x4 &mat)
109
if (sizeof(qreal) == sizeof(GLfloat))
110
glMultMatrixf((GLfloat*)mat.constData());
112
else if (sizeof(qreal) == sizeof(GLdouble))
113
glMultMatrixd((GLdouble*)mat.constData());
118
qreal const *r = mat.constData();
119
for (int i = 0; i < 16; ++i)
125
void Tile::draw() const
128
mat.translate(location);
129
mat.rotate(orientation);
130
glMatrixMode(GL_MODELVIEW);
133
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, faceColor);
134
glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_SHORT, geom->indices() + start);
138
TileBuilder::TileBuilder(Geometry *g, qreal depth, qreal size)
145
// front face - make a square with bottom-left at origin
146
verts[br].setX(size);
147
verts[tr].setX(size);
148
verts[tr].setY(size);
149
verts[tl].setY(size);
151
// these vert numbers are good for the tex-coords
152
for (int i = 0; i < 4; ++i)
153
tex[i] = verts[i].toVector2D();
155
// now move verts half cube width across so cube is centered on origin
156
for (int i = 0; i < 4; ++i)
157
verts[i] -= QVector3D(size / 2.0f, size / 2.0f, -depth);
159
// add the front face
160
g->addQuad(verts[bl], verts[br], verts[tr], verts[tl], tex);
162
count = g->count() - start;
165
void TileBuilder::initialize(Tile *tile) const
170
qSetColor(tile->faceColor, color);
173
Tile *TileBuilder::newTile(const QVector3D &loc) const
175
Tile *tile = new Tile(loc);
180
Cube::Cube(const QVector3D &loc)
191
void Cube::setAltitude(qreal a)
193
if (location.y() != a)
200
void Cube::setRange(qreal r)
202
if (location.x() != r)
209
void Cube::setRotation(qreal r)
213
orientation = QQuaternion::fromAxisAndAngle(QVector3D(1.0f, 1.0f, 1.0f), r);
218
void Cube::removeBounce()
226
void Cube::startAnimation()
231
r->setCurrentTime(startx);
239
void Cube::setAnimationPaused(bool paused)
261
CubeBuilder::CubeBuilder(Geometry *g, qreal depth, qreal size)
262
: TileBuilder(g, depth)
265
for (int i = 0; i < 4; ++i)
266
verts[i].setZ(size / 2.0f);
267
// back face - "extrude" verts down
268
QVector<QVector3D> back(verts);
269
for (int i = 0; i < 4; ++i)
270
back[i].setZ(-size / 2.0f);
273
g->addQuad(back[br], back[bl], back[tl], back[tr], tex);
276
g->addQuad(back[bl], back[br], verts[br], verts[bl], tex);
277
g->addQuad(back[br], back[tr], verts[tr], verts[br], tex);
278
g->addQuad(back[tr], back[tl], verts[tl], verts[tr], tex);
279
g->addQuad(back[tl], back[bl], verts[bl], verts[tl], tex);
281
count = g->count() - start;
284
Cube *CubeBuilder::newCube(const QVector3D &loc) const
286
Cube *c = new Cube(loc);
290
// Animate movement from left to right
291
c->r = new QPropertyAnimation(c, "range");
292
c->r->setStartValue(-1.3f);
293
c->r->setEndValue(1.3f);
294
c->startx = ix * d3 * 3.0f;
295
c->r->setDuration(d * 4.0f);
296
c->r->setLoopCount(-1);
297
c->r->setEasingCurve(QEasingCurve(QEasingCurve::CosineCurve));
298
// Animate movement from bottom to top
299
c->a = new QPropertyAnimation(c, "altitude");
300
c->a->setEndValue(loc.y());
301
c->a->setStartValue(loc.y() + amplitudes[ix]);
302
c->a->setDuration(d / speeds[ix]);
303
c->a->setLoopCount(-1);
304
c->a->setEasingCurve(QEasingCurve(QEasingCurve::CosineCurve));
306
c->rtn = new QPropertyAnimation(c, "rotation");
307
c->rtn->setStartValue(c->rot);
308
c->rtn->setEndValue(359.0f);
309
c->rtn->setDuration(d * 2.0f);
310
c->rtn->setLoopCount(-1);
311
c->rtn->setDuration(d / 2);
317
void AcceleratedVideoWidget::newFrameEvent()
319
qDebug() << "New frame event";
320
QSize size(VideoModel::getInstance()->getRenderer()->getActiveResolution().width, VideoModel::getInstance()->getRenderer()->getActiveResolution().height);
321
m_Image = QImage((uchar*)VideoModel::getInstance()->getRenderer()->rawData() , size.width(), size.height(), QImage::Format_ARGB32 );
325
static GLfloat colorArray[][4] = {
326
{0.243f , 0.423f , 0.125f , 1.0f},
327
{0.176f , 0.31f , 0.09f , 1.0f},
328
{0.4f , 0.69f , 0.212f , 1.0f},
329
{0.317f , 0.553f , 0.161f , 1.0f}
332
AcceleratedVideoWidget::AcceleratedVideoWidget(QWidget *parent)
333
: QGLWidget(QGLFormat(QGL::SampleBuffers), parent)
337
// create the pbuffer
338
QGLFormat pbufferFormat = format();
339
pbufferFormat.setSampleBuffers(false);
340
pbuffer = new QGLPixelBuffer(QSize(512, 512), pbufferFormat, this);
341
setWindowTitle(tr("OpenGL pbuffers"));
342
initializeGeometry();
343
connect(VideoModel::getInstance(),SIGNAL(frameUpdated()),this,SLOT(newFrameEvent()));
346
AcceleratedVideoWidget::~AcceleratedVideoWidget()
348
pbuffer->releaseFromDynamicTexture();
349
glDeleteTextures(1, &dynamicTexture);
357
void AcceleratedVideoWidget::initializeGL()
360
glShadeModel(GL_SMOOTH);
361
glEnable(GL_LIGHTING);
363
static GLfloat lightPosition[4] = { 0.5, 5.0, 7.0, 1.0 };
364
glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);
366
cube->startAnimation();
367
connect(cube, SIGNAL(changed()), this, SLOT(update()));
368
for (int i = 0; i < 3; ++i)
370
cubes[i]->startAnimation();
371
connect(cubes[i], SIGNAL(changed()), this, SLOT(update()));
375
void AcceleratedVideoWidget::paintGL()
377
QSize size(VideoModel::getInstance()->getRenderer()->getActiveResolution().width, VideoModel::getInstance()->getRenderer()->getActiveResolution().height);
378
if (size != minimumSize())
379
setMinimumSize(size);
381
pbuffer->makeCurrent();
383
// On direct render platforms, drawing onto the pbuffer context above
384
// automatically updates the dynamic texture. For cases where rendering
385
// directly to a texture is not supported, explicitly copy.
386
if (!hasDynamicTextureUpdate)
387
pbuffer->updateDynamicTexture(dynamicTexture);
390
// Use the pbuffer as a texture to render the scene
391
glBindTexture(GL_TEXTURE_2D, dynamicTexture);
393
// set up to render the scene
394
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
396
glTranslatef(0.0f, 0.0f, -10.0f);
398
// draw the background
400
glScalef(aspect, 1.0f, 1.0f);
401
for (int i = 0; i < tiles.count(); ++i)
405
// draw the bouncing cubes
406
for (int i = 0; i < cubes.count(); ++i)
410
void AcceleratedVideoWidget::initializeGeometry()
412
geom = new Geometry();
413
CubeBuilder cBuilder(geom, 0.5);
414
cBuilder.setColor(QColor(255, 255, 255, 212));
415
// build the 3 bouncing, spinning cubes
416
for (int i = 0; i < 3; ++i)
417
cubes.append(cBuilder.newCube(QVector3D((float)(i-1), -1.5f, 5 - i)));
419
// build the spinning cube which goes in the dynamic texture
420
cube = cBuilder.newCube();
421
cube->removeBounce();
423
// build the background tiles
424
TileBuilder tBuilder(geom);
425
tBuilder.setColor(QColor(Qt::white));
426
for (int c = -2; c <= +2; ++c)
427
for (int r = -2; r <= +2; ++r)
428
tiles.append(tBuilder.newTile(QVector3D(c, r, 0)));
430
// graded backdrop for the pbuffer scene
431
TileBuilder bBuilder(geom, 0.0f, 2.0f);
432
bBuilder.setColor(QColor(102, 176, 54, 210));
433
backdrop = bBuilder.newTile(QVector3D(0.0f, 0.0f, -1.5f));
434
backdrop->setColors(colorArray);
437
void AcceleratedVideoWidget::initCommon()
439
qglClearColor(QColor(Qt::darkGray));
441
glEnable(GL_DEPTH_TEST);
442
glEnable(GL_CULL_FACE);
443
glEnable(GL_MULTISAMPLE);
445
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
448
glEnable(GL_TEXTURE_2D);
453
void AcceleratedVideoWidget::perspectiveProjection()
455
glMatrixMode(GL_PROJECTION);
458
glFrustumf(-aspect, +aspect, -1.0, +1.0, 4.0, 15.0);
460
glFrustum(-aspect, +aspect, -1.0, +1.0, 4.0, 15.0);
462
glMatrixMode(GL_MODELVIEW);
465
void AcceleratedVideoWidget::orthographicProjection()
467
glMatrixMode(GL_PROJECTION);
470
glOrthof(-1.0, +1.0, -1.0, +1.0, -90.0, +90.0);
472
glOrtho(-1.0, +1.0, -1.0, +1.0, -90.0, +90.0);
474
glMatrixMode(GL_MODELVIEW);
477
void AcceleratedVideoWidget::resizeGL(int width, int height)
479
glViewport(0, 0, width, height);
480
aspect = (qreal)width / (qreal)(height ? height : 1);
481
perspectiveProjection();
484
void AcceleratedVideoWidget::drawPbuffer()
486
cubeTexture = bindTexture(m_Image);
489
orthographicProjection();
491
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
492
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
494
glDisable(GL_TEXTURE_2D);
496
glEnable(GL_TEXTURE_2D);
498
glBindTexture(GL_TEXTURE_2D, cubeTexture);
499
glDisable(GL_CULL_FACE);
501
glEnable(GL_CULL_FACE);
506
void AcceleratedVideoWidget::initPbuffer()
508
pbuffer->makeCurrent();
510
// cubeTexture = bindTexture(QImage("/home/lepagee/ccu_12.png"));
511
cubeTexture = bindTexture(m_Image);
515
// generate a texture that has the same size/format as the pbuffer
516
dynamicTexture = pbuffer->generateDynamicTexture();
518
// bind the dynamic texture to the pbuffer - this is a no-op under X11
519
hasDynamicTextureUpdate = pbuffer->bindToDynamicTexture(dynamicTexture);
523
void AcceleratedVideoWidget::setAnimationPaused(bool enable)
525
cube->setAnimationPaused(enable);
526
for (int i = 0; i < 3; ++i)
527
cubes[i]->setAnimationPaused(enable);