现在的位置: 首页 > 综合 > 正文

Qt OpenglES 2.0 — 绘制Gif等动态图片以实现简易的帧动画效果

2013年08月31日 ⁄ 综合 ⁄ 共 5574字 ⁄ 字号 评论关闭

       使用Qt opengles 2.0模块绘制Gif等动态图片以实现简易的帧动画效果,这里程序使用的测试平台是Nokia N9,在其他的能够使用Qt OpenglES 2.0模块的移动终端上用法也是一样的。在这里主要分享一下绘制Gif的绘制思路。

       在Qt中有一个QMovie的类,它可以解析动态图片,能够得到动态图片中的对应的每一帧的图片,以及能够获取每帧图片切换到下一帧的时间。这样就对绘制这个gif图片来说就已经够用了。首先用QMovie读取一个gif的图片,然后将获得的每一帧的图片绑定纹理得到一组纹理数组供绘制使用;最后根据帧图片切换的时间间隔来顺序这些图片即可。

       在QMovie中,我们这里用到了3个主要的方法:

       int QMovie::frameCount();--用来获取gif中图片的总数。

       int QMovie::jumpToFrame(int frameNumber);--跳转到指定的帧数索引的那张图片(即是设定当前帧的索引)。

       QImage QMovie::currentImage();--获得当前帧的图片,返回值是QImage。

      程序见源代码, 部分代码如下所示:

qgifframeanimation.h:

#ifndef QGIFFRAMEANIMATION_H
#define QGIFFRAMEANIMATION_H

#include <QObject>
#include <QMovie>
#include <QImage>
#include <QGLShaderProgram>
#include <QTime>

#include <qshapes.h>
#include <QtOpenGL>

class QGifFrameAnimation : public QObject
{
    Q_OBJECT
public:
    explicit QGifFrameAnimation(QObject *parent = 0);
    virtual ~QGifFrameAnimation();

    void init(GLuint* tex, int frameCount, int frameInterval);
    void startAnima();
    void drawAnimation(QGLShaderProgram& program, float depth);
    bool isCompleted();

private:
    bool    m_isDraw;
    int     m_curFrameIndex;
    int     m_frameCount;
    int     m_frameInterval;
    GLuint* m_tex;
    QTime   m_frameTime;
};

#endif // QGIFFRAMEANIMATION_H

qgifframeanimation.cpp:

#include "qgifframeanimation.h"

QGifFrameAnimation::QGifFrameAnimation(QObject *parent) :
    QObject(parent)
{
    m_curFrameIndex = 0;
    m_isDraw = false;
}

QGifFrameAnimation::~QGifFrameAnimation()
{
}

void QGifFrameAnimation::init(GLuint *tex, int frameCount, int frameInterval)
{
    m_tex = tex;
    m_frameCount = frameCount;
    m_frameInterval = frameInterval;
}

void QGifFrameAnimation::startAnima()
{
    m_curFrameIndex = 0;
    m_isDraw = true;
    m_frameTime.start();
}

void QGifFrameAnimation::drawAnimation(QGLShaderProgram &program, float depth)
{
    if(!m_isDraw)   return;

    if(m_frameTime.elapsed() > m_frameInterval)
    {
        if(m_curFrameIndex > m_frameCount)
        {
            m_isDraw = false;
            return;
        }
        m_curFrameIndex++;
        m_frameTime.start();
    }
    QShapes::drawRect(m_tex[m_curFrameIndex], depth, program, 0, 0, 854, 480);
}

bool QGifFrameAnimation::isCompleted()
{
    return (m_isDraw && m_curFrameIndex > m_frameCount);
}

QGLWidget窗口类:

#ifndef QGLTESTWIDGET_H
#define QGLTESTWIDGET_H

#include <QGLWidget>
#include <QGLShaderProgram>
#include <QBasicTimer>
#include <QMovie>
#include <QTime>

#include "qshapes.h"
#include "qebtimewheel.h"
#include "qgifframeanimation.h"

class QGLTestWidget : public QGLWidget
{
    Q_OBJECT
public:
    explicit QGLTestWidget(const QGLFormat& format, QWidget *parent = 0);
    virtual ~QGLTestWidget();

private:
    void initializeGL();
    void paintGL();
    void resizeGL(int w, int h);
    void timerEvent(QTimerEvent *e);
    void mouseReleaseEvent(QMouseEvent *e);

    void initShaders(QGLShaderProgram *program, QString vshader, QString fshader);
    void initTextures();

    void loadTextures(QString texPath, GLuint &tex);
    void loadStartScreenAnimaTextures();

    void renderScore(int score, float depth);
    void drawStartScreenAnimation();

private:
    QGLShaderProgram *m_program;

    QMatrix4x4 m_projection;

    QBasicTimer  m_timer;

    QMovie*                 m_startScreenMovie;
    GLuint*                 m_gifTex;
    QGifFrameAnimation*     m_startScreenAnima;
};

#endif // QGLTESTWIDGET_H

cpp:

#include "qgltestwidget.h"

#include <QDebug>

const QString ImagesForTest[] = {
    ":/images/animation_test_1.gif",
};

enum EIMAGEINDEX
{
    animationTest1Index,
};

QGLTestWidget::QGLTestWidget(const QGLFormat &format, QWidget *parent) :
    QGLWidget(format, parent)
{
    startTimer(1000.0f / 12);
    m_program = new QGLShaderProgram(context());

    m_timer.start(1000.0f / 100, this);
    m_startScreenMovie = new QMovie(ImagesForTest[animationTest1Index]);
    m_startScreenAnima = new QGifFrameAnimation();
}

QGLTestWidget::~QGLTestWidget()
{
    m_program->deleteLater();
}

void QGLTestWidget::initializeGL()
{
    initShaders(m_program, ":/shaders/v_shader.vsh", ":/shaders/f_shader.fsh");
    initTextures();

    m_program->bind();

    m_startScreenAnima->init(m_gifTex, m_startScreenMovie->frameCount(),
                             m_startScreenMovie->nextFrameDelay());
    glEnable(GL_TEXTURE_2D);
    glEnable(GL_CULL_FACE);

    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glBlendEquation(GL_FUNC_ADD);
}

void QGLTestWidget::paintGL()
{
    glClear(GL_COLOR_BUFFER_BIT);

    m_program->setUniformValue("u_mvpMatrix", m_projection);
    m_startScreenAnima->drawAnimation(*m_program, 0.0f);
}

void QGLTestWidget::resizeGL(int w, int h)
{
    glViewport(0, 0, w, h);

    m_projection.setToIdentity();
    m_projection.ortho(0, w, h, 0, -100, 100);

    m_program->setUniformValue("u_mvpMatrix", m_projection);
}

void QGLTestWidget::timerEvent(QTimerEvent *e)
{
    Q_UNUSED(e);
    updateGL();
}

void QGLTestWidget::mouseReleaseEvent(QMouseEvent *e)
{
    Q_UNUSED(e);
    m_startScreenAnima->startAnima();
}

void QGLTestWidget::initShaders(QGLShaderProgram *program, QString vshader, QString fshader)
{
    setlocale(LC_NUMERIC, "C");

    program->addShaderFromSourceFile(QGLShader::Vertex, vshader);
    program->addShaderFromSourceFile(QGLShader::Fragment, fshader);
    program->link();
    program->bind();

    setlocale(LC_ALL, "");
}

void QGLTestWidget::loadTextures(QString texPath, GLuint &tex)
{
    glActiveTexture(GL_TEXTURE0);
    glEnable(GL_TEXTURE_2D);

    tex = bindTexture(QImage(texPath));

    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
}

void QGLTestWidget::loadStartScreenAnimaTextures()
{
    m_gifTex = new GLuint[m_startScreenMovie->frameCount()];

    for(int i = 0; i < m_startScreenMovie->frameCount(); i++)
    {
        m_startScreenMovie->jumpToFrame(i);
        glActiveTexture(GL_TEXTURE0);
        glEnable(GL_TEXTURE_2D);

        m_gifTex[i] = bindTexture(m_startScreenMovie->currentImage());

        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    }
}

void QGLTestWidget::initTextures()
{
    loadStartScreenAnimaTextures();
}

抱歉!评论已关闭.