Permalink
Browse files

Add initial animation support to libmythui.

The bulk of this code is from Jonatan <mythtv@comhem.se> (many thanks!),
with the major changes being:-

- sundry formatting/style changes.
- added OpenGL 2.0/ES support by way of full stackable transformation
support (emulates the deprecated OpenGL push/pop matrix functionality).
- removed the 'size' effect as this doesn't appear to work at the moment
(easy enough to add back).
- moved the Effects struct to a UIEffects class for additional
functionality.
- converted the xml 'zoom' scale to 0-100 (and beyond) rather then
0.0-1.0 (still uses a float internally).
- added separate verticalzoom and horizontalzoom effects. You can use
one in isolation or both together for separate effects and there is
technically nothing stopping you from using them together with normal
'zoom' - though the results will be undefined.
- added a 'centre' attribute that dictates the centre used for both
rotation and zooming. Available centres topleft, top, topright, left,
middle, right, bottomleft, bottom and right. You cannot set a different
centre for rotation and zoom.
- reworked the xml structure in line with Stuart Morgan's suggested
schema (see below).

This currently only works with an OpenGL painter in the main interface
(so no OSD yet) and is currently only triggered on 'AboutToShow' and
'AboutToHide' for windows (ie. no lower level widgets yet). Extending
this should just be a matter of adding additional triggers in the
correct slots. I'll add direct3d support to my long list of direct3d
ToDo's.

There are some obvious issues around deactivating looped animations and
some animation effects based on pre-existing code (e.g. position?
alpha?) appear to interfere with window behaviour (e.g. actions aren't
processed until the animation is complete).

The xml looks something like this:-

<animation trigger="AboutToShow">
    <section duration="500" centre="middle">
        <alpha start="120" end="255" easingcurve="Linear"
reversible="true" looped="true" />
        <zoom start="0" end="100" easingcurve="OutCurve" duration="200"
/>
    </section>
</animation>

This should allow for future improvements such as adding additonal
sections for animations processed in sequence, paths and onCompletion
style triggers.

Attributes will use default values if missing:-
trigger="AboutToShow"
duration="500"
centre="middle"
start="0" (or equivalent)
end="0" (or equivalent)
easingcurve="Linear"
reversible="false"
looped="false"
  • Loading branch information...
Mark Kendall
Mark Kendall committed Jan 17, 2012
1 parent c29b91c commit f39fa3b626d98c0629571ecd4676e704747d3ca6
@@ -31,6 +31,7 @@ HEADERS += mythvirtualkeyboard.h mythuishape.h mythuiguidegrid.h
HEADERS += mythrender_base.h mythfontmanager.h mythuieditbar.h
HEADERS += mythdisplay.h mythuivideo.h mythudplistener.h
HEADERS += mythuiexp.h mythuisimpletext.h mythuistatetracker.h
+HEADERS += mythuianimation.h
SOURCES = mythmainwindow.cpp mythpainter.cpp mythimage.cpp mythrect.cpp
SOURCES += myththemebase.cpp mythpainter_qimage.cpp mythpainter_yuva.cpp
@@ -49,6 +50,7 @@ SOURCES += mythvirtualkeyboard.cpp mythuishape.cpp mythuiguidegrid.cpp
SOURCES += mythfontmanager.cpp mythuieditbar.cpp
SOURCES += mythdisplay.cpp mythuivideo.cpp mythudplistener.cpp
SOURCES += mythuisimpletext.cpp mythuistatetracker.cpp
+SOURCES += mythuianimation.cpp
inc.path = $${PREFIX}/include/mythtv/libmythui/
@@ -67,6 +69,7 @@ inc.files += mythvirtualkeyboard.h mythuishape.h mythuiguidegrid.h
inc.files += mythuieditbar.h mythuifilebrowser.h mythuivideo.h
inc.files += mythuiexp.h mythuisimpletext.h mythuiactions.h
inc.files += mythuistatetracker.h
+inc.files += mythuianimation.h
INSTALLS += inc
@@ -158,6 +158,7 @@ class MythMainWindowPrivate
sysEventHandler(NULL),
+ drawInterval(1000 / 70),
drawTimer(NULL),
mainStack(NULL),
@@ -235,6 +236,7 @@ class MythMainWindowPrivate
QObject *sysEventHandler;
+ int drawInterval;
MythSignalingTimer *drawTimer;
QVector<MythScreenStack *> stackList;
MythScreenStack *mainStack;
@@ -479,7 +481,7 @@ MythMainWindow::MythMainWindow(const bool useDB)
connect(d->hideMouseTimer, SIGNAL(timeout()), SLOT(HideMouseTimeout()));
d->drawTimer = new MythSignalingTimer(this, SLOT(animate()));
- d->drawTimer->start(1000 / 70);
+ d->drawTimer->start(d->drawInterval);
d->AllowInput = true;
@@ -2456,6 +2458,11 @@ void MythMainWindow::SetUIScreenRect(QRect &rect)
d->uiScreenRect = rect;
}
+int MythMainWindow::GetDrawInterval() const
+{
+ return d->drawInterval;
+}
+
void MythMainWindow::StartLIRC(void)
{
#ifdef USE_LIRC
@@ -105,6 +105,7 @@ class MUI_PUBLIC MythMainWindow : public QWidget
QRect GetUIScreenRect();
void SetUIScreenRect(QRect &rect);
+ int GetDrawInterval() const;
int NormalizeFontSize(int pointSize);
MythRect NormRect(const MythRect &rect);
QPoint NormPoint(const QPoint &point);
@@ -21,6 +21,7 @@ class QColor;
class MythFontProperties;
class MythImage;
+class UIEffects;
typedef QVector<QTextLayout *> LayoutVector;
typedef QVector<QTextLayout::FormatRange> FormatVector;
@@ -67,6 +68,9 @@ class MUI_PUBLIC MythPainter
virtual void DrawEllipse(const QRect &area, const QBrush &fillBrush,
const QPen &linePen, int alpha);
+ virtual void PushTransformation(const UIEffects &zoom, QPointF center = QPointF()) { }
+ virtual void PopTransformation(void) { }
+
MythImage *GetFormatImage();
void DeleteFormatImage(MythImage *im);
@@ -227,3 +227,15 @@ void MythOpenGLPainter::DeleteFormatImagePriv(MythImage *im)
m_ImageExpireList.remove(im);
}
}
+
+void MythOpenGLPainter::PushTransformation(const UIEffects &fx, QPointF center)
+{
+ if (realRender)
+ realRender->PushTransformation(fx, center);
+}
+
+void MythOpenGLPainter::PopTransformation(void)
+{
+ if (realRender)
+ realRender->PopTransformation();
+}
@@ -34,6 +34,9 @@ class MUI_PUBLIC MythOpenGLPainter : public MythPainter
const QBrush &fillBrush, const QPen &linePen,
int alpha);
+ virtual void PushTransformation(const UIEffects &fx, QPointF center = QPointF());
+ virtual void PopTransformation(void);
+
protected:
virtual MythImage* GetFormatImagePriv(void) { return new MythImage(this); }
virtual void DeleteFormatImagePriv(MythImage *im);
@@ -33,6 +33,8 @@
#include "mythrender_base.h"
#include "mythrender_opengl_defs.h"
+#include "mythuianimation.h"
+
typedef enum
{
kGLFeatNone = 0x0000,
@@ -122,6 +124,8 @@ class MUI_PUBLIC MythRenderOpenGL : public QGLContext, public MythRender
void MoveResizeWindow(const QRect &rect);
void SetViewPort(const QRect &rect, bool viewportonly = false);
QRect GetViewPort(void) { return m_viewport; }
+ virtual void PushTransformation(const UIEffects &fx, QPointF &center) = 0;
+ virtual void PopTransformation(void) = 0;
void Flush(bool use_fence);
void SetBlend(bool enable);
virtual void SetColor(int r, int g, int b, int a) { }
@@ -292,6 +292,24 @@ void MythRenderOpenGL1::SetMatrixView(void)
glLoadIdentity();
}
+void MythRenderOpenGL1::PushTransformation(const UIEffects &fx, QPointF &center)
+{
+ makeCurrent();
+ glPushMatrix();
+ glTranslatef(center.x(), center.y(), 0.0);
+ glScalef(fx.hzoom, fx.vzoom, 1.0);
+ glRotatef(fx.angle, 0, 0, 1);
+ glTranslatef(-center.x(), -center.y(), 0.0);
+ doneCurrent();
+}
+
+void MythRenderOpenGL1::PopTransformation(void)
+{
+ makeCurrent();
+ glPopMatrix();
+ doneCurrent();
+}
+
void MythRenderOpenGL1::DeleteShaders(void)
{
QVector<GLuint>::iterator it;
@@ -19,6 +19,10 @@ class MUI_PUBLIC MythRenderOpenGL1 : public MythRenderOpenGL
virtual uint CreateHelperTexture(void);
+ virtual void PushTransformation(const UIEffects &fx, QPointF &center);
+ virtual void PopTransformation(void);
+
+
protected:
virtual ~MythRenderOpenGL1();
virtual void DrawBitmapPriv(uint tex, const QRect *src, const QRect *dst,
@@ -3,6 +3,67 @@
#define LOC QString("OpenGL2: ")
+class GLMatrix
+{
+ public:
+ GLMatrix()
+ {
+ setToIdentity();
+ }
+
+ void setToIdentity(void)
+ {
+ for (int i = 0; i < 4; i++)
+ for (int j = 0; j < 4; j++)
+ m[i][j] = (i == j) ? 1.0f : 0.0f;
+ }
+
+ void rotate(int degrees)
+ {
+ float rotation = degrees * (M_PI / 180.0);
+ GLMatrix rotate;
+ rotate.m[0][0] = rotate.m[1][1] = cos(rotation);
+ rotate.m[0][1] = sin(rotation);
+ rotate.m[1][0] = -rotate.m[0][1];
+ this->operator *=(rotate);
+ }
+
+ void scale(float horizontal, float vertical)
+ {
+ GLMatrix scale;
+ scale.m[0][0] = horizontal;
+ scale.m[1][1] = vertical;
+ this->operator *=(scale);
+ }
+
+ void translate(float x, float y)
+ {
+ GLMatrix translate;
+ translate.m[3][0] = x;
+ translate.m[3][1] = y;
+ this->operator *=(translate);
+ }
+
+ GLMatrix & operator*=(const GLMatrix &r)
+ {
+ for (int i = 0; i < 4; i++)
+ product(i, r);
+ return *this;
+ }
+
+ void product(int row, const GLMatrix &r)
+ {
+ float t0, t1, t2, t3;
+ t0 = m[row][0] * r.m[0][0] + m[row][1] * r.m[1][0] + m[row][2] * r.m[2][0] + m[row][3] * r.m[3][0];
+ t1 = m[row][0] * r.m[0][1] + m[row][1] * r.m[1][1] + m[row][2] * r.m[2][1] + m[row][3] * r.m[3][1];
+ t2 = m[row][0] * r.m[0][2] + m[row][1] * r.m[1][2] + m[row][2] * r.m[2][2] + m[row][3] * r.m[3][2];
+ t3 = m[row][0] * r.m[0][3] + m[row][1] * r.m[1][3] + m[row][2] * r.m[2][3] + m[row][3] * r.m[3][3];
+ m[row][0] = t0; m[row][1] = t1; m[row][2] = t2; m[row][3] = t3;
+ }
+
+ float m[4][4];
+};
+
#define VERTEX_INDEX 0
#define COLOR_INDEX 1
#define TEXTURE_INDEX 2
@@ -21,8 +82,9 @@ static const QString kDefaultVertexShader =
"varying vec4 v_color;\n"
"varying vec2 v_texcoord0;\n"
"uniform mat4 u_projection;\n"
+"uniform mat4 u_transform;\n"
"void main() {\n"
-" gl_Position = u_projection * vec4(a_position, 0.0, 1.0);\n"
+" gl_Position = u_projection * u_transform * vec4(a_position, 0.0, 1.0);\n"
" v_texcoord0 = a_texcoord0;\n"
" v_color = a_color;\n"
"}\n";
@@ -43,8 +105,9 @@ static const QString kSimpleVertexShader =
"attribute vec4 a_color;\n"
"varying vec4 v_color;\n"
"uniform mat4 u_projection;\n"
+"uniform mat4 u_transform;\n"
"void main() {\n"
-" gl_Position = u_projection * vec4(a_position, 0.0, 1.0);\n"
+" gl_Position = u_projection * u_transform * vec4(a_position, 0.0, 1.0);\n"
" v_color = a_color;\n"
"}\n";
@@ -63,8 +126,9 @@ static const QString kDrawVertexShader =
"varying vec4 v_color;\n"
"varying vec2 v_position;\n"
"uniform mat4 u_projection;\n"
+"uniform mat4 u_transform;\n"
"void main() {\n"
-" gl_Position = u_projection * vec4(a_position, 0.0, 1.0);\n"
+" gl_Position = u_projection * u_transform * vec4(a_position, 0.0, 1.0);\n"
" v_color = a_color;\n"
" v_position = a_position;\n"
"}\n";
@@ -167,11 +231,11 @@ void MythRenderOpenGL2::ResetVars(void)
{
MythRenderOpenGL::ResetVars();
memset(m_projection, 0, sizeof(m_projection));
- memset(m_scale, 0, sizeof(m_scale));
- memset(m_rotate, 0, sizeof(m_rotate));
memset(m_parameters, 0, sizeof(m_parameters));
memset(m_shaders, 0, sizeof(m_shaders));
m_active_obj = 0;
+ m_transforms.clear();
+ m_transforms.push(GLMatrix());
}
void MythRenderOpenGL2::ResetProcs(void)
@@ -402,6 +466,7 @@ void MythRenderOpenGL2::DrawBitmapPriv(uint tex, const QRect *src,
EnableShaderObject(prog);
SetShaderParams(prog, &m_projection[0][0], "u_projection");
+ SetShaderParams(prog, &m_transforms.top().m[0][0], "u_transform");
SetBlend(true);
EnableTextures(tex);
@@ -448,6 +513,7 @@ void MythRenderOpenGL2::DrawBitmapPriv(uint *textures, uint texture_count,
EnableShaderObject(prog);
SetShaderParams(prog, &m_projection[0][0], "u_projection");
+ SetShaderParams(prog, &m_transforms.top().m[0][0], "u_transform");
SetBlend(false);
EnableTextures(first);
@@ -541,6 +607,7 @@ void MythRenderOpenGL2::DrawRoundRectPriv(const QRect &area, int cornerRadius,
// Enable the Circle shader
SetShaderParams(elip, &m_projection[0][0], "u_projection");
+ SetShaderParams(elip, &m_transforms.top().m[0][0], "u_transform");
// Draw the top left segment
m_parameters[0][0] = tl.left() + rad;
@@ -589,6 +656,7 @@ void MythRenderOpenGL2::DrawRoundRectPriv(const QRect &area, int cornerRadius,
EnableShaderObject(fill);
SetShaderParams(fill, &m_projection[0][0], "u_projection");
+ SetShaderParams(fill, &m_transforms.top().m[0][0], "u_transform");
GetCachedVBO(GL_TRIANGLE_STRIP, main);
m_glVertexAttribPointer(VERTEX_INDEX, VERTEX_SIZE, GL_FLOAT, GL_FALSE,
@@ -628,6 +696,7 @@ void MythRenderOpenGL2::DrawRoundRectPriv(const QRect &area, int cornerRadius,
// Enable the edge shader
SetShaderParams(edge, &m_projection[0][0], "u_projection");
+ SetShaderParams(edge, &m_transforms.top().m[0][0], "u_transform");
// Draw the top left edge segment
m_parameters[0][0] = tl.left() + rad;
@@ -671,6 +740,8 @@ void MythRenderOpenGL2::DrawRoundRectPriv(const QRect &area, int cornerRadius,
// Vertical lines
SetShaderParams(vline, &m_projection[0][0], "u_projection");
+ SetShaderParams(vline, &m_transforms.top().m[0][0], "u_transform");
+
m_parameters[0][1] = lineWidth / 2.0;
QRect vl(r.left(), r.top() + rad,
lineWidth, r.height() - dia);
@@ -696,6 +767,7 @@ void MythRenderOpenGL2::DrawRoundRectPriv(const QRect &area, int cornerRadius,
// Horizontal lines
SetShaderParams(hline, &m_projection[0][0], "u_projection");
+ SetShaderParams(hline, &m_transforms.top().m[0][0], "u_transform");
QRect hl(r.left() + rad, r.top(),
r.width() - dia, lineWidth);
@@ -861,20 +933,22 @@ void MythRenderOpenGL2::SetMatrixView(void)
m_projection[3][3] = 1.0;
}
-void MythRenderOpenGL2::SetRotation(int degrees)
+void MythRenderOpenGL2::PushTransformation(const UIEffects &fx, QPointF &center)
{
- float rotation = degrees * (M_PI / 180.0);
- m_rotate[0][0] = m_rotate[1][1] = cos(rotation);
- m_rotate[1][0] = sin(rotation);
- m_rotate[0][1] = -m_rotate[1][0];
- m_rotate[2][2] = m_rotate[3][3] = 1.0;
+ GLMatrix newtop = m_transforms.top();
+ if (fx.hzoom != 1.0 || fx.vzoom != 1.0 || fx.angle != 0.0)
+ {
+ newtop.translate(-center.x(), -center.y());
+ newtop.scale(fx.hzoom, fx.vzoom);
+ newtop.rotate(fx.angle);
+ newtop.translate(center.x(), center.y());
+ }
+ m_transforms.push(newtop);
}
-void MythRenderOpenGL2::SetScaling(int horizontal, int vertical)
+void MythRenderOpenGL2::PopTransformation(void)
{
- m_scale[0][0] = horizontal / 100.0;
- m_scale[1][1] = vertical / 100.0;
- m_scale[2][2] = m_scale[3][3] = 1.0;
+ m_transforms.pop();
}
void MythRenderOpenGL2::DeleteShaders(void)
Oops, something went wrong.

0 comments on commit f39fa3b

Please sign in to comment.