ganeswidgets/src/hgvgquadrenderer.cpp
changeset 0 89c329efa980
child 1 e48454f237ca
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ganeswidgets/src/hgvgquadrenderer.cpp	Mon Apr 19 14:40:06 2010 +0300
@@ -0,0 +1,471 @@
+/*
+* 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 "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>
+
+
+class HgVgQuad
+{
+public:
+    HgVgQuad(HgVgQuadRenderer* renderer);
+    ~HgVgQuad();
+    
+    int index() const;
+    bool isPointInside(const QPointF& point) const;
+    void transformQuad(int index, const QMatrix4x4& matrix, HgQuad* quad, 
+        const QRectF& rect, qreal mirroringPlaneY);
+    void draw();
+
+    void getTransformedPoints(QPolygonF& polygon) const;
+        
+    void computeMirrorMatrix(const QMatrix4x4& tm, const QMatrix4x4& projView, 
+        const QRectF& rect, qreal mirroringPlaneY);
+    
+    bool perspectiveTransformPoints(QVector2D* points, const QMatrix4x4& matrix, 
+        const QRectF& rect);
+    
+    void computeWarpMatrix(VGfloat* matrix, int pxWidth, int pxHeight, const QVector2D* points);
+    
+    void drawImage(HgVgImage* image, qreal alpha);
+    
+    int mIndex;
+    HgQuad* mQuad;
+    QVector2D mTransformedPoints[4];
+    VGfloat mMatrix[9];
+    VGfloat mMirrorMatrix[9];
+    HgVgQuadRenderer* mRenderer;
+    bool mDegenerate;
+private:
+    HgVgQuad(const HgVgQuad&);
+    HgVgQuad& operator=(const HgVgQuad&);
+};
+
+static bool quadSorter(HgVgQuad* a, HgVgQuad* b)
+{
+    return a->mQuad->position().z() < b->mQuad->position().z();
+}
+
+HgVgQuad::HgVgQuad(HgVgQuadRenderer* renderer) : mRenderer(renderer)
+{
+    
+}
+
+HgVgQuad::~HgVgQuad()
+{
+    
+}
+
+int HgVgQuad::index() const
+    {
+    return mIndex;
+    }
+
+bool HgVgQuad::isPointInside(const QPointF& point) const
+{    
+    QPolygonF poly;
+    getTransformedPoints(poly);
+    QRectF rect = poly.boundingRect();
+    if (rect.contains(point))
+    {
+        return true;
+    }
+    return false;
+}
+
+
+void HgVgQuad::computeMirrorMatrix(const QMatrix4x4& trans, const QMatrix4x4& projView, 
+    const QRectF& rect, qreal mirroringPlaneY)
+{
+    HgQuad* quad = mQuad;
+
+    QMatrix4x4 mirror = trans;
+
+    qreal distToPlane = qAbs(quad->position().y() - mirroringPlaneY);
+    
+    mirror.translate(quad->position().x(), mirroringPlaneY - distToPlane/2, quad->position().z());
+    mirror.scale(quad->scale().x(), -quad->scale().y()/2);
+    mirror.rotate(quad->rotation());
+        
+    QMatrix4x4 modelViewProjMatrix = projView * mirror;
+    
+    QVector2D temp[4];
+    
+    perspectiveTransformPoints(temp, modelViewProjMatrix, rect);
+    
+    HgVgImage* image = (HgVgImage*)mQuad->image();
+    
+    if (image == NULL)
+    {
+        image = mRenderer->defaultImage();
+    }
+    
+    int pxWidth = image->mirrorImageWidth();
+    int pxHeight = image->mirrorImageHeight();
+
+    computeWarpMatrix(mMirrorMatrix, pxWidth, pxHeight, temp);
+}
+
+void HgVgQuad::transformQuad(int index, const QMatrix4x4& projView, HgQuad* quad, 
+    const QRectF& rect, qreal mirroringPlaneY)
+{
+    mIndex = index;
+    mQuad = quad;
+        
+    QMatrix4x4 tm;
+    tm.setToIdentity();
+    tm.rotate(quad->outerRotation());
+
+    if (mQuad->mirrorImageEnabled())
+    {
+        computeMirrorMatrix(tm, projView, rect, mirroringPlaneY);
+    }
+    
+    tm.translate(quad->position());    
+    tm.rotate(quad->rotation());    
+    tm.scale(quad->scale().x(), quad->scale().y());
+
+    tm = projView * tm;         
+    //QMatrix4x4 tmt = tm.transposed();
+    
+    mDegenerate = false;
+    if (!perspectiveTransformPoints(mTransformedPoints, tm, rect))
+    {
+        mDegenerate = true;
+    }
+
+    HgVgImage* image = (HgVgImage*)mQuad->image();
+    
+    if (image == NULL)
+    {
+        image = mRenderer->defaultImage();
+    }
+    
+    int pxWidth = image->width();
+    int pxHeight = image->height();
+    
+    computeWarpMatrix(mMatrix, pxWidth, pxHeight, mTransformedPoints);
+    
+}
+
+bool HgVgQuad::perspectiveTransformPoints(QVector2D* outPoints, const QMatrix4x4& matrix, 
+    const QRectF& rect)
+{
+    const QVector4D points[] = 
+    {
+        QVector4D(-0.5f, -0.5f, 0.0f, 1.0f),
+        QVector4D( 0.5f, -0.5f, 0.0f, 1.0f),
+        QVector4D( 0.5f,  0.5f, 0.0f, 1.0f),
+        QVector4D(-0.5f,  0.5f, 0.0f, 1.0f)
+    };
+
+    qreal hw = rect.width() * 0.5f;
+    qreal hh = rect.height() * 0.5f;
+
+    for (int i = 0; i < 4; i++)
+    {
+        QVector4D temp = matrix * points[i];
+                            
+        outPoints[i] = QVector2D(
+            hw + temp.x() / temp.w() * hw, 
+            hh + temp.y() / temp.w() * hh);
+
+    }
+    
+    return true;
+}
+
+void HgVgQuad::computeWarpMatrix(VGfloat* matrix, int pxWidth, int pxHeight, const QVector2D* points)
+{        
+    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);
+/*    
+    INFO("P0 x:" << points[0].x() << " y:" << points[0].y());
+    INFO("P1 x:" << points[1].x() << " y:" << points[1].y());
+    INFO("P2 x:" << points[2].x() << " y:" << points[2].y());
+    INFO("P3 x:" << points[3].x() << " y:" << points[3].y());*/
+}
+
+
+void HgVgQuad::draw()
+{
+    if (!mQuad->visible())
+        return;
+    
+    if (mDegenerate)
+        return;
+    
+    HgVgImage* image = (HgVgImage*)mQuad->image();
+    
+    
+    if (image == NULL  || image->alpha() == 0)
+    {
+        return;
+        //drawImage(mRenderer->defaultImage(), 1.0f);
+    }
+    else
+    {
+        image->upload(mQuad->mirrorImageEnabled());
+        
+        if (image->image() == VG_INVALID_HANDLE)
+        {
+            drawImage(mRenderer->defaultImage(), 1.0f);
+        }
+        else
+        {
+
+            if ( mQuad->alpha() < 1.0f )
+            {
+                drawImage(mRenderer->defaultImage(), 1.0f - mQuad->alpha());            
+            }
+            
+            drawImage(image, mQuad->alpha());
+        }
+    }
+    
+    
+}
+
+void HgVgQuad::drawImage(HgVgImage* image, qreal alpha)
+{
+    Q_UNUSED(alpha)
+
+    //VGfloat values[] = { 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0 };
+    //values[3] = alpha;
+    
+    //vgSetfv(VG_COLOR_TRANSFORM_VALUES, 8, values);
+        
+    VGImage vgImage = image->image();
+    
+    vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);
+
+    VGfloat m[9];
+    vgGetMatrix(m);
+    
+    vgMultMatrix(mMatrix);
+    vgDrawImage(vgImage);    
+    
+    vgLoadMatrix(m);
+
+    if (mQuad->mirrorImageEnabled())
+    {
+        VGImage mirrorImage = image->mirrorImage();
+        if (mirrorImage == VG_INVALID_HANDLE)
+            return;
+        
+        vgMultMatrix(mMirrorMatrix);
+            
+        vgDrawImage(mirrorImage);    
+        vgLoadMatrix(m);    
+    }
+    
+}
+
+
+void HgVgQuad::getTransformedPoints(QPolygonF& poly) const
+{
+    poly.append(mTransformedPoints[0].toPointF());
+    poly.append(mTransformedPoints[1].toPointF());
+    poly.append(mTransformedPoints[2].toPointF());
+    poly.append(mTransformedPoints[3].toPointF());    
+}
+
+
+HgVgQuadRenderer::HgVgQuadRenderer(int maxQuads) : 
+    HgQuadRenderer(maxQuads),
+    mDefaultVgImage(NULL)
+{
+    for (int i = 0; i < maxQuads; i++)
+    {
+        mTransformedQuads.append(new HgVgQuad(this));
+    }
+    mImageFader = new HgImageFader();
+}
+
+HgVgQuadRenderer::~HgVgQuadRenderer()
+{
+    delete mDefaultVgImage;
+}
+
+HgQuad* HgVgQuadRenderer::getQuadAt(const QPointF& point) const
+{
+    FUNC_LOG
+        
+    // TODO: need to use sorted quads here, in reversed order.
+    QList<HgVgQuad*>::const_iterator i = mSortedQuads.begin();
+    while(i != mSortedQuads.end())
+    {
+        HgVgQuad* q = (*i);
+        if (q->isPointInside(point))
+        {
+            return q->mQuad;
+        }
+        i++;
+    }
+    
+    return NULL;
+}
+
+
+void HgVgQuadRenderer::transformQuads(const QMatrix4x4& view, const QMatrix4x4& proj, 
+    const QRectF& rect)
+{
+    QMatrix4x4 pv = proj * view;
+    
+    mSortedQuads.clear();
+    
+    for (int i = 0; i < mQuads.size(); i++)
+    {
+        HgQuad* q = mQuads[i];
+            
+        HgVgQuad* tq = mTransformedQuads[i];
+        
+        if (q->visible())
+        {
+            tq->transformQuad(i, pv, q, rect, mMirroringPlaneY);   
+            mSortedQuads.append(tq);
+        }
+    }
+        
+    qSort(mSortedQuads.begin(), mSortedQuads.end(), quadSorter);
+}
+
+void HgVgQuadRenderer::drawQuads(const QRectF& rect, QPainter* painter)
+{
+    Q_UNUSED(rect)
+            
+    
+    painter->beginNativePainting();
+
+    // need to save old scissoring rects, otherwise hb
+    // screws up with rendering
+/*    VGint oldScissoring = vgGeti(VG_SCISSORING);
+    VGint numRects = 32;//vgGeti(VG_MAX_SCISSOR_RECTS);
+    VGint oldRects[32*4];
+    vgGetiv(VG_SCISSOR_RECTS, numRects, oldRects);
+
+    // setup our new scissoring rects
+    VGint sRect[4];
+    sRect[0] = rect.left();
+    sRect[1] = rect.top();
+    sRect[2] = rect.width();
+    sRect[3] = rect.height();
+    vgSeti(VG_SCISSORING, VG_TRUE);
+    vgSetiv(VG_SCISSOR_RECTS, 4, sRect);
+ */
+    // setup root transform
+    vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);
+    vgLoadIdentity();    
+    vgTranslate(rect.left(), rect.top());
+    
+    vgSeti(VG_COLOR_TRANSFORM, VG_FALSE);
+    vgSeti(VG_BLEND_MODE, VG_BLEND_SRC_OVER);
+    vgSeti(VG_IMAGE_MODE, VG_DRAW_IMAGE_NORMAL);
+    
+    // draw quads
+    for (int i = 0; i < mSortedQuads.size(); i++)
+    {
+        mSortedQuads[i]->draw();
+    }
+    
+    // set back old scissor rects
+  //  vgSeti(VG_SCISSORING, oldScissoring);
+  //  vgSetiv(VG_SCISSOR_RECTS, numRects, oldRects);
+
+    painter->endNativePainting();
+    
+}
+
+bool HgVgQuadRenderer::getQuadTranformedPoints(QPolygonF& points, int index) const
+{
+    for (int i = 0; i < mSortedQuads.count(); i++)
+    {
+        HgVgQuad* quad = mSortedQuads[i];
+        if (quad->mQuad)
+        {
+            bool bOk;
+            if (quad->mQuad->userData().toInt(&bOk) == index)
+            {
+                quad->getTransformedPoints(points);
+                return true;
+            }
+        }
+    }
+    
+    return false;
+}
+
+HgImage* HgVgQuadRenderer::createNativeImage()
+{    
+    return new HgVgImage(this);   
+}
+
+HgVgImage* HgVgQuadRenderer::defaultImage()
+{
+    if (mDefaultVgImage == NULL)
+    {
+        QImage defaultImage(64,64,QImage::Format_RGB16);
+        defaultImage.fill(qRgb(255,0,0));
+        mDefaultVgImage = static_cast<HgVgImage*>(createNativeImage());
+        mDefaultVgImage->setImage(defaultImage);
+        mDefaultVgImage->upload(true);        
+    }
+    return mDefaultVgImage;
+}
+
+HgImageFader* HgVgQuadRenderer::imageFader()
+{
+    return mImageFader;
+}
+
+QList<HgQuad*> HgVgQuadRenderer::getVisibleQuads(const QRectF& rect) const
+{
+    FUNC_LOG;
+    
+    // this implementation isn't 100% precise
+    QList<HgQuad*> result;
+    for (int i = 0; i < mSortedQuads.count(); i++) {
+       QPolygonF poly;
+       mSortedQuads[i]->getTransformedPoints(poly);
+       QRectF bounds = poly.boundingRect();       
+       if (bounds.intersects(rect) || rect.contains(bounds)) {
+           result.append(mSortedQuads[i]->mQuad);
+       }           
+    }
+    
+    return result;    
+}
+
+