ganeswidgets/src/hgvgquadrenderer.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Tue, 06 Jul 2010 15:29:26 +0300
changeset 9 dde80bf4a8c7
parent 5 4fa04caf0f43
permissions -rw-r--r--
Revision: 201025 Kit: 2010127

/*
* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:    
*
*/

#include "hgvgquadrenderer.h"
#include "hgtransformedquad.h"
#include "hgquad.h"
#include "hgvgimage.h"
#include "trace.h"
#include "hgimagefader.h"

#include <VG/openvg.h>
#include <VG/vgu.h>
#include <QVector2D>
#include <QPolygon>
#include <QMatrix4x4>
#include <QPainter>

static void matrixFromTransform(VGfloat* matrix, const QTransform& tm)
{
    matrix[0] = tm.m11();
    matrix[1] = tm.m12();
    matrix[2] = tm.m13();

    matrix[3] = tm.m21();
    matrix[4] = tm.m22();
    matrix[5] = tm.m23();

    matrix[6] = tm.m31();
    matrix[7] = tm.m32();
    matrix[8] = tm.m33();
}

class HgVgQuad : public HgTransformedQuad
{
public:
    
    HgVgQuad(HgVgQuadRenderer* renderer) : HgTransformedQuad(-1), mRenderer(renderer)
    {
        
    }

    ~HgVgQuad()
    {
        
    }

    void draw(QPainter* painter, const QRectF& rect)    
    {
        Q_UNUSED(painter)
        Q_UNUSED(rect)
        
        if (!mQuad->visible())
            return;
                
        HgVgImage* image = (HgVgImage*)mQuad->image();
                
        if (image == NULL  || image->alpha() == 0)
        {
            if (mRenderer->defaultImage()) {
                drawImage(mRenderer->defaultImage(), 1.0f);
            }
        }
        else
        {
            image->upload(mQuad->mirrorImageEnabled());
            
            if (image->image() == VG_INVALID_HANDLE)
            {
                if (mRenderer->defaultImage()) {
                    drawImage(mRenderer->defaultImage(), 1.0f);
                }
            }
            else
            {

                if ( mQuad->alpha() < 1.0f )
                {
                    if (mRenderer->defaultImage()) {
                        drawImage(mRenderer->defaultImage(), 1.0f - mQuad->alpha());            
                    }
                }
                
                drawImage(image, mQuad->alpha());
            }
        }
        
        
    }

    void drawImage(HgVgImage* image, qreal alpha)
    {
        Q_UNUSED(alpha)
            
        VGImage vgImage = image->image();
        
        vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);

        VGfloat m[9];
        vgGetMatrix(m);
        
        computeWarpMatrix(mMatrix, image->width(), image->height(), mTransformedPoints, QVector2D());

        vgMultMatrix(mMatrix);
        vgDrawImage(vgImage);    
        
        vgLoadMatrix(m);

        if (mQuad->mirrorImageEnabled())
        {
            VGImage mirrorImage = image->mirrorImage();
            if (mirrorImage == VG_INVALID_HANDLE)
                return;
            
            computeWarpMatrix(mMirrorMatrix, image->mirrorImageWidth(), image->mirrorImageHeight(), mMirroredPoints, QVector2D());
            vgMultMatrix(mMirrorMatrix);
                
            vgDrawImage(mirrorImage);    
            vgLoadMatrix(m);    
        }
        
    }
    
private:

    void computeWarpMatrix(VGfloat* matrix, int pxWidth, int pxHeight, const QVector2D* points, 
        const QVector2D& translate)
    {        
        Q_UNUSED(translate)

        vguComputeWarpQuadToQuad(
            points[0].x(), points[0].y(), 
            points[1].x(), points[1].y(),
            points[2].x(), points[2].y(),
            points[3].x(), points[3].y(),
            0, pxHeight,
            pxWidth, pxHeight,
            pxWidth, 0,
            0, 0,
            matrix);
    
    }

    HgVgQuadRenderer* mRenderer;
    VGfloat mMatrix[9];
    VGfloat mMirrorMatrix[9];
};


HgVgQuadRenderer::HgVgQuadRenderer(int maxQuads) : 
    HgTransformedQuadRenderer(maxQuads),
    mDefaultVgImage(NULL)
{
    init(maxQuads);
}

HgVgQuadRenderer::~HgVgQuadRenderer()
{
    delete mDefaultVgImage;
}

void HgVgQuadRenderer::drawQuads(QPainter* painter, const QRectF& rect, 
    const QMatrix4x4& viewMatrix, const QMatrix4x4& projectionMatrix,
    Qt::Orientation orientation, 
    const QTransform& sceneTransform)
{
    // start direct vg
    painter->beginNativePainting();

    // setup default vg states
    vgSeti(VG_COLOR_TRANSFORM, VG_FALSE);
    vgSeti(VG_BLEND_MODE, VG_BLEND_SRC_OVER);
    vgSeti(VG_IMAGE_MODE, VG_DRAW_IMAGE_NORMAL);

    // setup root transform
    vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);
    VGfloat toVgMatrix[9];
    matrixFromTransform(toVgMatrix, qtToVgTransform(painter, sceneTransform, rect, orientation));
    vgLoadMatrix(toVgMatrix);   

    // transform quads to screen
    transformQuads(viewMatrix, projectionMatrix, QPointF(rect.width()/2, rect.height()/2), 
        QSizeF(rect.width(), rect.height()));

    drawTransformedQuads(painter, rect);

    // end directt vg
    painter->endNativePainting();
    
}

HgImage* HgVgQuadRenderer::createNativeImage()
{    
    return new HgVgImage(this);   
}

HgTransformedQuad* HgVgQuadRenderer::createNativeQuad()
{
    return new HgVgQuad(this);
}

HgVgImage* HgVgQuadRenderer::defaultImage()
{
    if (mDefaultVgImage && mDefaultVgImage->image() == VG_INVALID_HANDLE) {
        mDefaultVgImage->upload(true);
    }

    return mDefaultVgImage;
}

void HgVgQuadRenderer::setDefaultImage(QImage defaultImage)
{
    HgQuadRenderer::setDefaultImage(defaultImage);
    delete mDefaultVgImage;
    mDefaultVgImage = 0;
    mDefaultVgImage = static_cast<HgVgImage*>(createNativeImage());
    mDefaultVgImage->setImage(mDefaultImage);
    mDefaultVgImage->upload(true);    
}

QTransform HgVgQuadRenderer::qtToVgTransform(QPainter* painter, const QTransform& sceneTransform, 
    const QRectF& rect, Qt::Orientation orientation) const
{
    QTransform t;
    if (orientation == Qt::Vertical)
    {
        t.translate(sceneTransform.dx(), painter->viewport().height() - sceneTransform.dy());
        t.scale(1, -1);    
    }
    else
    {
        // TODO: this will need reviewing later :)
        t.translate(rect.bottom(), 0);
        t.scale(-1, 1);
        t.translate(0, rect.right());
        t.rotate(-90, Qt::ZAxis);        
    }

    return t;
}