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