ganeswidgets/src/hgqtquadrenderer.cpp
author hgs
Wed, 06 Oct 2010 14:53:41 +0300
changeset 20 a60f8b6b1d32
parent 17 a10844a9914d
permissions -rw-r--r--
201039

/*
* 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 "hgqtquadrenderer.h"
#include "hgquad.h"
#include "hgtransformedquad.h"
#include "trace.h"
#include "hgimage.h"

#include <QVector2D>
#include <QPolygon>
#include <QMatrix4x4>
#include <QPainter>
#include <QPixmapCache>


class HgQtImage : public HgImage
{
public:    
    HgQtImage(HgQtQuadRenderer* renderer)
    {
    Q_UNUSED(renderer)
    }

    ~HgQtImage()
    {
    }

    int width() const {
        return mPixmap.width();
    }

    int height() const {
        return mPixmap.height();
    }

    int mirrorPixmapWidth() const {
        return mMirrorPixmap.width();
    }

    int mirrorPixmapHeight() const {
        return mMirrorPixmap.height();
    }
    
    void setPixmap(const QPixmap& pixmap, bool createMirror) {
        mPixmap = pixmap;        
        if (createMirror) {
            createMirrorPixmap(mPixmap);
        } else {
            mMirrorPixmap = QPixmap();
        }
    }
    
    void releaseImages() {
        mPixmap = QPixmap();
        mMirrorPixmap = QPixmap();
    }
            
    QPixmap pixmap() const {
        return mPixmap;
    }
    
    QPixmap mirrorPixmap() {
        return mMirrorPixmap;
    }

    void setMirrorPixmap(const QPixmap& mirrorPixmap) {
        mMirrorPixmap = mirrorPixmap;
    }
    
    void createMirrorPixmap(const QPixmap& source) {
        if (!source.isNull()) {
            mMirrorPixmap = source.copy(QRect(0,source.height()*ReflectionHeight,source.width(),source.height()));
            QPainter painter(&mMirrorPixmap);
            painter.setCompositionMode(QPainter::CompositionMode_DestinationIn);
            QLinearGradient gradient(0.5,0.0,0.5,1);
            gradient.setCoordinateMode(QGradient::ObjectBoundingMode);
            gradient.setColorAt(1, QColor::fromRgb(0,0,0,128));
            gradient.setColorAt(0, QColor::fromRgb(0,0,0,0));
            QBrush brush(gradient);
            painter.setBrush(brush);
            painter.setPen(Qt::NoPen);
            painter.drawRect(mMirrorPixmap.rect());
        }    
    }
    
    void updateMirror(bool enabled) {
        if (enabled && !mPixmap.isNull() && mMirrorPixmap.isNull()) {
            createMirrorPixmap(mPixmap);
        } else if(!enabled) {
            mMirrorPixmap = QPixmap();
        }
    }
    
    QPixmap mPixmap;
    QPixmap mMirrorPixmap;
};

class HgQtQuad : public HgTransformedQuad
{
public:
    
    HgQtQuad(HgQtQuadRenderer* renderer) : HgTransformedQuad(-1), mRenderer(renderer)
    {
        
    }

    ~HgQtQuad()
    {
        
    }

    void draw(QPainter* painter, const QRectF& rect, const QTransform& transform)    
    {
        if (!quad()->visible())
            return;
                
        HgQtImage* image = (HgQtImage*)quad()->image();        
        if (image == NULL)
            image = mRenderer->defaultImage();
        
        if (image == NULL)
            return;
        
        if (image->pixmap().isNull())
            image = mRenderer->defaultImage();
        
        drawImage(painter, image, rect, transform);                      
    }

    
private:

    void computeWarpMatrix(QTransform& tm, int pxWidth, int pxHeight, const QVector2D* points)
    {
        QPolygonF poly;

        poly << points[0].toPointF();
        poly << points[1].toPointF();
        poly << points[2].toPointF();
        poly << points[3].toPointF();

        QPolygonF img;

        img.append(QPointF(0,pxHeight));
        img.append(QPointF(pxWidth,pxHeight));
        img.append(QPointF(pxWidth,0));
        img.append(QPointF(0,0));

        QTransform::quadToQuad(img, poly, tm);
    }
    
    void drawImage(QPainter* painter, HgQtImage* image, const QRectF& rect, const QTransform& transform)
    {
        QPixmap pixmap = image->pixmap();
        
        if (pixmap.isNull())            
            return;
        
                
        const QVector2D* points = mTransformedPoints;
        if (mRenderer->isReflection() && quad()->mirrorImageEnabled()) {
            points = mMirroredPoints;
            pixmap = image->mirrorPixmap();            
        }
        
        QPolygonF poly;
        poly << points[0].toPointF();
        poly << points[1].toPointF();
        poly << points[2].toPointF();
        poly << points[3].toPointF();        
        QRectF bounds = poly.boundingRect();
        if (!(bounds.intersects(rect) || rect.contains(bounds))) {
            return;
        }
        
        computeWarpMatrix(mTransform, pixmap.width(), pixmap.height(), points);
        
        painter->setTransform(mTransform * transform);    

        painter->drawPixmap(QPointF(0,0), pixmap);
    }

    HgQtQuadRenderer* mRenderer;
    QTransform mTransform;
    QTransform mMirrorTransform;
};


HgQtQuadRenderer::HgQtQuadRenderer(int maxQuads) : 
    HgTransformedQuadRenderer(maxQuads),
    mDefaultQtImage(NULL)
{
    // initialize base class to the end.
    init(maxQuads);
    QImage image(QSize(250,250), QImage::QImage::Format_ARGB32_Premultiplied);
    image.fill(0xFFFFFFFF);
    setDefaultImage(QPixmap::fromImage(image));
    
    QPixmapCache::setCacheLimit(2048);
}

HgQtQuadRenderer::~HgQtQuadRenderer()
{
    delete mDefaultQtImage;
}

void HgQtQuadRenderer::drawQuads(QPainter* painter, const QRectF& rect, 
    const QMatrix4x4& viewMatrix, const QMatrix4x4& projectionMatrix,
    Qt::Orientation orientation, 
    const QTransform& sceneTransform)
{
    Q_UNUSED(orientation)
    Q_UNUSED(sceneTransform)

    transformQuads(viewMatrix, projectionMatrix, 
        QPointF(rect.width()/2, rect.height()/2), QSizeF(rect.width(), rect.height()));
    
    // save old transform
    QTransform temp = painter->transform();

    if (mReflectionsEnabled) 
    {
        mIsReflection = true;

        drawTransformedQuads(painter, rect, temp);    

        painter->setTransform(temp);        
        drawFloor(painter, rect);
    }
    
    mIsReflection = false;
    
    drawTransformedQuads(painter, rect, temp);
        
    painter->setTransform(temp);
    
}

HgImage* HgQtQuadRenderer::createNativeImage()
{    
    return new HgQtImage(this);   
}

HgQtImage* HgQtQuadRenderer::defaultImage()
{
    return mDefaultQtImage;
}

void HgQtQuadRenderer::setDefaultImage(QPixmap defaultImage)
{
    HgQuadRenderer::setDefaultImage(defaultImage);
    
    delete mDefaultQtImage;
    mDefaultQtImage = 0;
    
    mDefaultQtImage = static_cast<HgQtImage*>(createNativeImage());
    mDefaultQtImage->setPixmap(mDefaultImage, true);
}

HgTransformedQuad* HgQtQuadRenderer::createNativeQuad()
{
    return new HgQtQuad(this);
}

bool HgQtQuadRenderer::isReflection() const
{
    return mIsReflection;
}

void HgQtQuadRenderer::drawFloor(QPainter* painter, const QRectF& rect)
{
    Q_UNUSED(painter);
    Q_UNUSED(rect);
}