ganeswidgets/src/hgvgquadrenderer.cpp
changeset 0 89c329efa980
child 1 e48454f237ca
equal deleted inserted replaced
-1:000000000000 0:89c329efa980
       
     1 /*
       
     2 * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:    
       
    15 *
       
    16 */
       
    17 
       
    18 #include "hgvgquadrenderer.h"
       
    19 #include "hgquad.h"
       
    20 #include "hgvgimage.h"
       
    21 #include "trace.h"
       
    22 #include "HgImageFader.h"
       
    23 
       
    24 #include <VG/openvg.h>
       
    25 #include <VG/vgu.h>
       
    26 #include <qvector2d>
       
    27 #include <qpolygon>
       
    28 #include <qmatrix4x4>
       
    29 #include <qpainter>
       
    30 
       
    31 
       
    32 class HgVgQuad
       
    33 {
       
    34 public:
       
    35     HgVgQuad(HgVgQuadRenderer* renderer);
       
    36     ~HgVgQuad();
       
    37     
       
    38     int index() const;
       
    39     bool isPointInside(const QPointF& point) const;
       
    40     void transformQuad(int index, const QMatrix4x4& matrix, HgQuad* quad, 
       
    41         const QRectF& rect, qreal mirroringPlaneY);
       
    42     void draw();
       
    43 
       
    44     void getTransformedPoints(QPolygonF& polygon) const;
       
    45         
       
    46     void computeMirrorMatrix(const QMatrix4x4& tm, const QMatrix4x4& projView, 
       
    47         const QRectF& rect, qreal mirroringPlaneY);
       
    48     
       
    49     bool perspectiveTransformPoints(QVector2D* points, const QMatrix4x4& matrix, 
       
    50         const QRectF& rect);
       
    51     
       
    52     void computeWarpMatrix(VGfloat* matrix, int pxWidth, int pxHeight, const QVector2D* points);
       
    53     
       
    54     void drawImage(HgVgImage* image, qreal alpha);
       
    55     
       
    56     int mIndex;
       
    57     HgQuad* mQuad;
       
    58     QVector2D mTransformedPoints[4];
       
    59     VGfloat mMatrix[9];
       
    60     VGfloat mMirrorMatrix[9];
       
    61     HgVgQuadRenderer* mRenderer;
       
    62     bool mDegenerate;
       
    63 private:
       
    64     HgVgQuad(const HgVgQuad&);
       
    65     HgVgQuad& operator=(const HgVgQuad&);
       
    66 };
       
    67 
       
    68 static bool quadSorter(HgVgQuad* a, HgVgQuad* b)
       
    69 {
       
    70     return a->mQuad->position().z() < b->mQuad->position().z();
       
    71 }
       
    72 
       
    73 HgVgQuad::HgVgQuad(HgVgQuadRenderer* renderer) : mRenderer(renderer)
       
    74 {
       
    75     
       
    76 }
       
    77 
       
    78 HgVgQuad::~HgVgQuad()
       
    79 {
       
    80     
       
    81 }
       
    82 
       
    83 int HgVgQuad::index() const
       
    84     {
       
    85     return mIndex;
       
    86     }
       
    87 
       
    88 bool HgVgQuad::isPointInside(const QPointF& point) const
       
    89 {    
       
    90     QPolygonF poly;
       
    91     getTransformedPoints(poly);
       
    92     QRectF rect = poly.boundingRect();
       
    93     if (rect.contains(point))
       
    94     {
       
    95         return true;
       
    96     }
       
    97     return false;
       
    98 }
       
    99 
       
   100 
       
   101 void HgVgQuad::computeMirrorMatrix(const QMatrix4x4& trans, const QMatrix4x4& projView, 
       
   102     const QRectF& rect, qreal mirroringPlaneY)
       
   103 {
       
   104     HgQuad* quad = mQuad;
       
   105 
       
   106     QMatrix4x4 mirror = trans;
       
   107 
       
   108     qreal distToPlane = qAbs(quad->position().y() - mirroringPlaneY);
       
   109     
       
   110     mirror.translate(quad->position().x(), mirroringPlaneY - distToPlane/2, quad->position().z());
       
   111     mirror.scale(quad->scale().x(), -quad->scale().y()/2);
       
   112     mirror.rotate(quad->rotation());
       
   113         
       
   114     QMatrix4x4 modelViewProjMatrix = projView * mirror;
       
   115     
       
   116     QVector2D temp[4];
       
   117     
       
   118     perspectiveTransformPoints(temp, modelViewProjMatrix, rect);
       
   119     
       
   120     HgVgImage* image = (HgVgImage*)mQuad->image();
       
   121     
       
   122     if (image == NULL)
       
   123     {
       
   124         image = mRenderer->defaultImage();
       
   125     }
       
   126     
       
   127     int pxWidth = image->mirrorImageWidth();
       
   128     int pxHeight = image->mirrorImageHeight();
       
   129 
       
   130     computeWarpMatrix(mMirrorMatrix, pxWidth, pxHeight, temp);
       
   131 }
       
   132 
       
   133 void HgVgQuad::transformQuad(int index, const QMatrix4x4& projView, HgQuad* quad, 
       
   134     const QRectF& rect, qreal mirroringPlaneY)
       
   135 {
       
   136     mIndex = index;
       
   137     mQuad = quad;
       
   138         
       
   139     QMatrix4x4 tm;
       
   140     tm.setToIdentity();
       
   141     tm.rotate(quad->outerRotation());
       
   142 
       
   143     if (mQuad->mirrorImageEnabled())
       
   144     {
       
   145         computeMirrorMatrix(tm, projView, rect, mirroringPlaneY);
       
   146     }
       
   147     
       
   148     tm.translate(quad->position());    
       
   149     tm.rotate(quad->rotation());    
       
   150     tm.scale(quad->scale().x(), quad->scale().y());
       
   151 
       
   152     tm = projView * tm;         
       
   153     //QMatrix4x4 tmt = tm.transposed();
       
   154     
       
   155     mDegenerate = false;
       
   156     if (!perspectiveTransformPoints(mTransformedPoints, tm, rect))
       
   157     {
       
   158         mDegenerate = true;
       
   159     }
       
   160 
       
   161     HgVgImage* image = (HgVgImage*)mQuad->image();
       
   162     
       
   163     if (image == NULL)
       
   164     {
       
   165         image = mRenderer->defaultImage();
       
   166     }
       
   167     
       
   168     int pxWidth = image->width();
       
   169     int pxHeight = image->height();
       
   170     
       
   171     computeWarpMatrix(mMatrix, pxWidth, pxHeight, mTransformedPoints);
       
   172     
       
   173 }
       
   174 
       
   175 bool HgVgQuad::perspectiveTransformPoints(QVector2D* outPoints, const QMatrix4x4& matrix, 
       
   176     const QRectF& rect)
       
   177 {
       
   178     const QVector4D points[] = 
       
   179     {
       
   180         QVector4D(-0.5f, -0.5f, 0.0f, 1.0f),
       
   181         QVector4D( 0.5f, -0.5f, 0.0f, 1.0f),
       
   182         QVector4D( 0.5f,  0.5f, 0.0f, 1.0f),
       
   183         QVector4D(-0.5f,  0.5f, 0.0f, 1.0f)
       
   184     };
       
   185 
       
   186     qreal hw = rect.width() * 0.5f;
       
   187     qreal hh = rect.height() * 0.5f;
       
   188 
       
   189     for (int i = 0; i < 4; i++)
       
   190     {
       
   191         QVector4D temp = matrix * points[i];
       
   192                             
       
   193         outPoints[i] = QVector2D(
       
   194             hw + temp.x() / temp.w() * hw, 
       
   195             hh + temp.y() / temp.w() * hh);
       
   196 
       
   197     }
       
   198     
       
   199     return true;
       
   200 }
       
   201 
       
   202 void HgVgQuad::computeWarpMatrix(VGfloat* matrix, int pxWidth, int pxHeight, const QVector2D* points)
       
   203 {        
       
   204     vguComputeWarpQuadToQuad(
       
   205         points[0].x(), points[0].y(), 
       
   206         points[1].x(), points[1].y(),
       
   207         points[2].x(), points[2].y(),
       
   208         points[3].x(), points[3].y(),
       
   209         0, pxHeight,
       
   210         pxWidth, pxHeight,
       
   211         pxWidth, 0,
       
   212         0, 0,
       
   213         matrix);
       
   214 /*    
       
   215     INFO("P0 x:" << points[0].x() << " y:" << points[0].y());
       
   216     INFO("P1 x:" << points[1].x() << " y:" << points[1].y());
       
   217     INFO("P2 x:" << points[2].x() << " y:" << points[2].y());
       
   218     INFO("P3 x:" << points[3].x() << " y:" << points[3].y());*/
       
   219 }
       
   220 
       
   221 
       
   222 void HgVgQuad::draw()
       
   223 {
       
   224     if (!mQuad->visible())
       
   225         return;
       
   226     
       
   227     if (mDegenerate)
       
   228         return;
       
   229     
       
   230     HgVgImage* image = (HgVgImage*)mQuad->image();
       
   231     
       
   232     
       
   233     if (image == NULL  || image->alpha() == 0)
       
   234     {
       
   235         return;
       
   236         //drawImage(mRenderer->defaultImage(), 1.0f);
       
   237     }
       
   238     else
       
   239     {
       
   240         image->upload(mQuad->mirrorImageEnabled());
       
   241         
       
   242         if (image->image() == VG_INVALID_HANDLE)
       
   243         {
       
   244             drawImage(mRenderer->defaultImage(), 1.0f);
       
   245         }
       
   246         else
       
   247         {
       
   248 
       
   249             if ( mQuad->alpha() < 1.0f )
       
   250             {
       
   251                 drawImage(mRenderer->defaultImage(), 1.0f - mQuad->alpha());            
       
   252             }
       
   253             
       
   254             drawImage(image, mQuad->alpha());
       
   255         }
       
   256     }
       
   257     
       
   258     
       
   259 }
       
   260 
       
   261 void HgVgQuad::drawImage(HgVgImage* image, qreal alpha)
       
   262 {
       
   263     Q_UNUSED(alpha)
       
   264 
       
   265     //VGfloat values[] = { 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0 };
       
   266     //values[3] = alpha;
       
   267     
       
   268     //vgSetfv(VG_COLOR_TRANSFORM_VALUES, 8, values);
       
   269         
       
   270     VGImage vgImage = image->image();
       
   271     
       
   272     vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);
       
   273 
       
   274     VGfloat m[9];
       
   275     vgGetMatrix(m);
       
   276     
       
   277     vgMultMatrix(mMatrix);
       
   278     vgDrawImage(vgImage);    
       
   279     
       
   280     vgLoadMatrix(m);
       
   281 
       
   282     if (mQuad->mirrorImageEnabled())
       
   283     {
       
   284         VGImage mirrorImage = image->mirrorImage();
       
   285         if (mirrorImage == VG_INVALID_HANDLE)
       
   286             return;
       
   287         
       
   288         vgMultMatrix(mMirrorMatrix);
       
   289             
       
   290         vgDrawImage(mirrorImage);    
       
   291         vgLoadMatrix(m);    
       
   292     }
       
   293     
       
   294 }
       
   295 
       
   296 
       
   297 void HgVgQuad::getTransformedPoints(QPolygonF& poly) const
       
   298 {
       
   299     poly.append(mTransformedPoints[0].toPointF());
       
   300     poly.append(mTransformedPoints[1].toPointF());
       
   301     poly.append(mTransformedPoints[2].toPointF());
       
   302     poly.append(mTransformedPoints[3].toPointF());    
       
   303 }
       
   304 
       
   305 
       
   306 HgVgQuadRenderer::HgVgQuadRenderer(int maxQuads) : 
       
   307     HgQuadRenderer(maxQuads),
       
   308     mDefaultVgImage(NULL)
       
   309 {
       
   310     for (int i = 0; i < maxQuads; i++)
       
   311     {
       
   312         mTransformedQuads.append(new HgVgQuad(this));
       
   313     }
       
   314     mImageFader = new HgImageFader();
       
   315 }
       
   316 
       
   317 HgVgQuadRenderer::~HgVgQuadRenderer()
       
   318 {
       
   319     delete mDefaultVgImage;
       
   320 }
       
   321 
       
   322 HgQuad* HgVgQuadRenderer::getQuadAt(const QPointF& point) const
       
   323 {
       
   324     FUNC_LOG
       
   325         
       
   326     // TODO: need to use sorted quads here, in reversed order.
       
   327     QList<HgVgQuad*>::const_iterator i = mSortedQuads.begin();
       
   328     while(i != mSortedQuads.end())
       
   329     {
       
   330         HgVgQuad* q = (*i);
       
   331         if (q->isPointInside(point))
       
   332         {
       
   333             return q->mQuad;
       
   334         }
       
   335         i++;
       
   336     }
       
   337     
       
   338     return NULL;
       
   339 }
       
   340 
       
   341 
       
   342 void HgVgQuadRenderer::transformQuads(const QMatrix4x4& view, const QMatrix4x4& proj, 
       
   343     const QRectF& rect)
       
   344 {
       
   345     QMatrix4x4 pv = proj * view;
       
   346     
       
   347     mSortedQuads.clear();
       
   348     
       
   349     for (int i = 0; i < mQuads.size(); i++)
       
   350     {
       
   351         HgQuad* q = mQuads[i];
       
   352             
       
   353         HgVgQuad* tq = mTransformedQuads[i];
       
   354         
       
   355         if (q->visible())
       
   356         {
       
   357             tq->transformQuad(i, pv, q, rect, mMirroringPlaneY);   
       
   358             mSortedQuads.append(tq);
       
   359         }
       
   360     }
       
   361         
       
   362     qSort(mSortedQuads.begin(), mSortedQuads.end(), quadSorter);
       
   363 }
       
   364 
       
   365 void HgVgQuadRenderer::drawQuads(const QRectF& rect, QPainter* painter)
       
   366 {
       
   367     Q_UNUSED(rect)
       
   368             
       
   369     
       
   370     painter->beginNativePainting();
       
   371 
       
   372     // need to save old scissoring rects, otherwise hb
       
   373     // screws up with rendering
       
   374 /*    VGint oldScissoring = vgGeti(VG_SCISSORING);
       
   375     VGint numRects = 32;//vgGeti(VG_MAX_SCISSOR_RECTS);
       
   376     VGint oldRects[32*4];
       
   377     vgGetiv(VG_SCISSOR_RECTS, numRects, oldRects);
       
   378 
       
   379     // setup our new scissoring rects
       
   380     VGint sRect[4];
       
   381     sRect[0] = rect.left();
       
   382     sRect[1] = rect.top();
       
   383     sRect[2] = rect.width();
       
   384     sRect[3] = rect.height();
       
   385     vgSeti(VG_SCISSORING, VG_TRUE);
       
   386     vgSetiv(VG_SCISSOR_RECTS, 4, sRect);
       
   387  */
       
   388     // setup root transform
       
   389     vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);
       
   390     vgLoadIdentity();    
       
   391     vgTranslate(rect.left(), rect.top());
       
   392     
       
   393     vgSeti(VG_COLOR_TRANSFORM, VG_FALSE);
       
   394     vgSeti(VG_BLEND_MODE, VG_BLEND_SRC_OVER);
       
   395     vgSeti(VG_IMAGE_MODE, VG_DRAW_IMAGE_NORMAL);
       
   396     
       
   397     // draw quads
       
   398     for (int i = 0; i < mSortedQuads.size(); i++)
       
   399     {
       
   400         mSortedQuads[i]->draw();
       
   401     }
       
   402     
       
   403     // set back old scissor rects
       
   404   //  vgSeti(VG_SCISSORING, oldScissoring);
       
   405   //  vgSetiv(VG_SCISSOR_RECTS, numRects, oldRects);
       
   406 
       
   407     painter->endNativePainting();
       
   408     
       
   409 }
       
   410 
       
   411 bool HgVgQuadRenderer::getQuadTranformedPoints(QPolygonF& points, int index) const
       
   412 {
       
   413     for (int i = 0; i < mSortedQuads.count(); i++)
       
   414     {
       
   415         HgVgQuad* quad = mSortedQuads[i];
       
   416         if (quad->mQuad)
       
   417         {
       
   418             bool bOk;
       
   419             if (quad->mQuad->userData().toInt(&bOk) == index)
       
   420             {
       
   421                 quad->getTransformedPoints(points);
       
   422                 return true;
       
   423             }
       
   424         }
       
   425     }
       
   426     
       
   427     return false;
       
   428 }
       
   429 
       
   430 HgImage* HgVgQuadRenderer::createNativeImage()
       
   431 {    
       
   432     return new HgVgImage(this);   
       
   433 }
       
   434 
       
   435 HgVgImage* HgVgQuadRenderer::defaultImage()
       
   436 {
       
   437     if (mDefaultVgImage == NULL)
       
   438     {
       
   439         QImage defaultImage(64,64,QImage::Format_RGB16);
       
   440         defaultImage.fill(qRgb(255,0,0));
       
   441         mDefaultVgImage = static_cast<HgVgImage*>(createNativeImage());
       
   442         mDefaultVgImage->setImage(defaultImage);
       
   443         mDefaultVgImage->upload(true);        
       
   444     }
       
   445     return mDefaultVgImage;
       
   446 }
       
   447 
       
   448 HgImageFader* HgVgQuadRenderer::imageFader()
       
   449 {
       
   450     return mImageFader;
       
   451 }
       
   452 
       
   453 QList<HgQuad*> HgVgQuadRenderer::getVisibleQuads(const QRectF& rect) const
       
   454 {
       
   455     FUNC_LOG;
       
   456     
       
   457     // this implementation isn't 100% precise
       
   458     QList<HgQuad*> result;
       
   459     for (int i = 0; i < mSortedQuads.count(); i++) {
       
   460        QPolygonF poly;
       
   461        mSortedQuads[i]->getTransformedPoints(poly);
       
   462        QRectF bounds = poly.boundingRect();       
       
   463        if (bounds.intersects(rect) || rect.contains(bounds)) {
       
   464            result.append(mSortedQuads[i]->mQuad);
       
   465        }           
       
   466     }
       
   467     
       
   468     return result;    
       
   469 }
       
   470 
       
   471