00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050 #include "qxtflowview_p.h"
00051
00052
00053
00054
00055
00056
00057 QxtFlowViewState::QxtFlowViewState():
00058 backgroundColor(0), slideWidth(150), slideHeight(200),
00059 reflectionEffect(QxtFlowView::BlurredReflection), centerIndex(0)
00060 {
00061 }
00062
00063 QxtFlowViewState::~QxtFlowViewState()
00064 {
00065 for (int i = 0; i < (int)slideImages.count(); i++)
00066 delete slideImages[i];
00067 }
00068
00069
00070 void QxtFlowViewState::reposition()
00071 {
00072 angle = 70 * IANGLE_MAX / 360;
00073
00074 offsetX = slideWidth / 2 * (PFREAL_ONE - fcos(angle));
00075 offsetY = slideWidth / 2 * fsin(angle);
00076 offsetX += slideWidth * PFREAL_ONE;
00077 offsetY += slideWidth * PFREAL_ONE / 4;
00078 spacing = 40;
00079 }
00080
00081
00082 void QxtFlowViewState::reset()
00083 {
00084 centerSlide.angle = 0;
00085 centerSlide.cx = 0;
00086 centerSlide.cy = 0;
00087 centerSlide.slideIndex = centerIndex;
00088 centerSlide.blend = 256;
00089
00090 leftSlides.resize(6);
00091 for (int i = 0; i < (int)leftSlides.count(); i++)
00092 {
00093 SlideInfo& si = leftSlides[i];
00094 si.angle = angle;
00095 si.cx = -(offsetX + spacing * i * PFREAL_ONE);
00096 si.cy = offsetY;
00097 si.slideIndex = centerIndex - 1 - i;
00098 si.blend = 256;
00099 if (i == (int)leftSlides.count() - 2)
00100 si.blend = 128;
00101 if (i == (int)leftSlides.count() - 1)
00102 si.blend = 0;
00103 }
00104
00105 rightSlides.resize(6);
00106 for (int i = 0; i < (int)rightSlides.count(); i++)
00107 {
00108 SlideInfo& si = rightSlides[i];
00109 si.angle = -angle;
00110 si.cx = offsetX + spacing * i * PFREAL_ONE;
00111 si.cy = offsetY;
00112 si.slideIndex = centerIndex + 1 + i;
00113 si.blend = 256;
00114 if (i == (int)rightSlides.count() - 2)
00115 si.blend = 128;
00116 if (i == (int)rightSlides.count() - 1)
00117 si.blend = 0;
00118 }
00119 }
00120
00121
00122
00123 QxtFlowViewAnimator::QxtFlowViewAnimator():
00124 state(0), target(0), step(0), frame(0)
00125 {
00126 }
00127
00128 void QxtFlowViewAnimator::start(int slide)
00129 {
00130 target = slide;
00131 if (!animateTimer.isActive() && state)
00132 {
00133 step = (target < state->centerSlide.slideIndex) ? -1 : 1;
00134 animateTimer.start(30);
00135 }
00136 }
00137
00138 void QxtFlowViewAnimator::stop(int slide)
00139 {
00140 step = 0;
00141 target = slide;
00142 frame = slide << 16;
00143 animateTimer.stop();
00144 }
00145
00146 void QxtFlowViewAnimator::update()
00147 {
00148 if (!animateTimer.isActive())
00149 return;
00150 if (step == 0)
00151 return;
00152 if (!state)
00153 return;
00154
00155 int speed = 16384 / 4;
00156
00157 #if 1
00158
00159 const int max = 2 * 65536;
00160
00161 int fi = frame;
00162 fi -= (target << 16);
00163 if (fi < 0)
00164 fi = -fi;
00165 fi = qMin(fi, max);
00166
00167 int ia = IANGLE_MAX * (fi - max / 2) / (max * 2);
00168 speed = 512 + 16384 * (PFREAL_ONE + fsin(ia)) / PFREAL_ONE;
00169 #endif
00170
00171 frame += speed * step;
00172
00173 int index = frame >> 16;
00174 int pos = frame & 0xffff;
00175 int neg = 65536 - pos;
00176 int tick = (step < 0) ? neg : pos;
00177 PFreal ftick = (tick * PFREAL_ONE) >> 16;
00178
00179 if (step < 0)
00180 index++;
00181
00182 if (state->centerIndex != index)
00183 {
00184 state->centerIndex = index;
00185 frame = index << 16;
00186 state->centerSlide.slideIndex = state->centerIndex;
00187 for (int i = 0; i < (int)state->leftSlides.count(); i++)
00188 state->leftSlides[i].slideIndex = state->centerIndex - 1 - i;
00189 for (int i = 0; i < (int)state->rightSlides.count(); i++)
00190 state->rightSlides[i].slideIndex = state->centerIndex + 1 + i;
00191 }
00192
00193 state->centerSlide.angle = (step * tick * state->angle) >> 16;
00194 state->centerSlide.cx = -step * fmul(state->offsetX, ftick);
00195 state->centerSlide.cy = fmul(state->offsetY, ftick);
00196
00197 if (state->centerIndex == target)
00198 {
00199 stop(target);
00200 state->reset();
00201 return;
00202 }
00203
00204 for (int i = 0; i < (int)state->leftSlides.count(); i++)
00205 {
00206 SlideInfo& si = state->leftSlides[i];
00207 si.angle = state->angle;
00208 si.cx = -(state->offsetX + state->spacing * i * PFREAL_ONE + step * state->spacing * ftick);
00209 si.cy = state->offsetY;
00210 }
00211
00212 for (int i = 0; i < (int)state->rightSlides.count(); i++)
00213 {
00214 SlideInfo& si = state->rightSlides[i];
00215 si.angle = -state->angle;
00216 si.cx = state->offsetX + state->spacing * i * PFREAL_ONE - step * state->spacing * ftick;
00217 si.cy = state->offsetY;
00218 }
00219
00220 if (step > 0)
00221 {
00222 PFreal ftick = (neg * PFREAL_ONE) >> 16;
00223 state->rightSlides[0].angle = -(neg * state->angle) >> 16;
00224 state->rightSlides[0].cx = fmul(state->offsetX, ftick);
00225 state->rightSlides[0].cy = fmul(state->offsetY, ftick);
00226 }
00227 else
00228 {
00229 PFreal ftick = (pos * PFREAL_ONE) >> 16;
00230 state->leftSlides[0].angle = (pos * state->angle) >> 16;
00231 state->leftSlides[0].cx = -fmul(state->offsetX, ftick);
00232 state->leftSlides[0].cy = fmul(state->offsetY, ftick);
00233 }
00234
00235
00236 if (target < index) if (step > 0)
00237 step = -1;
00238 if (target > index) if (step < 0)
00239 step = 1;
00240
00241
00242 int nleft = state->leftSlides.count();
00243 int nright = state->rightSlides.count();
00244 int fade = pos / 256;
00245
00246 for (int index = 0; index < nleft; index++)
00247 {
00248 int blend = 256;
00249 if (index == nleft - 1)
00250 blend = (step > 0) ? 0 : 128 - fade / 2;
00251 if (index == nleft - 2)
00252 blend = (step > 0) ? 128 - fade / 2 : 256 - fade / 2;
00253 if (index == nleft - 3)
00254 blend = (step > 0) ? 256 - fade / 2 : 256;
00255 state->leftSlides[index].blend = blend;
00256 }
00257 for (int index = 0; index < nright; index++)
00258 {
00259 int blend = (index < nright - 2) ? 256 : 128;
00260 if (index == nright - 1)
00261 blend = (step > 0) ? fade / 2 : 0;
00262 if (index == nright - 2)
00263 blend = (step > 0) ? 128 + fade / 2 : fade / 2;
00264 if (index == nright - 3)
00265 blend = (step > 0) ? 256 : 128 + fade / 2;
00266 state->rightSlides[index].blend = blend;
00267 }
00268
00269 }
00270
00271
00272
00273 QxtFlowViewSoftwareRenderer::QxtFlowViewSoftwareRenderer():
00274 QxtFlowViewAbstractRenderer(), size(0, 0), bgcolor(0), effect(-1), blankSurface(0)
00275 {
00276 }
00277
00278 QxtFlowViewSoftwareRenderer::~QxtFlowViewSoftwareRenderer()
00279 {
00280 surfaceCache.clear();
00281 buffer = QImage();
00282 delete blankSurface;
00283 }
00284
00285 void QxtFlowViewSoftwareRenderer::paint()
00286 {
00287 if (!widget)
00288 return;
00289
00290 if (widget->size() != size)
00291 init();
00292
00293 if (state->backgroundColor != bgcolor)
00294 {
00295 bgcolor = state->backgroundColor;
00296 surfaceCache.clear();
00297 }
00298
00299 if ((int)(state->reflectionEffect) != effect)
00300 {
00301 effect = (int)state->reflectionEffect;
00302 surfaceCache.clear();
00303 }
00304
00305 if (dirty)
00306 render();
00307
00308 QPainter painter(widget);
00309 painter.drawImage(QPoint(0, 0), buffer);
00310 }
00311
00312 void QxtFlowViewSoftwareRenderer::init()
00313 {
00314 if (!widget)
00315 return;
00316
00317 surfaceCache.clear();
00318 blankSurface = 0;
00319
00320 size = widget->size();
00321 int ww = size.width();
00322 int wh = size.height();
00323 int w = (ww + 1) / 2;
00324 int h = (wh + 1) / 2;
00325
00326 #ifdef PICTUREFLOW_QT4
00327 buffer = QImage(ww, wh, QImage::Format_RGB32);
00328 #endif
00329 #if defined(PICTUREFLOW_QT3) || defined(PICTUREFLOW_QT2)
00330 buffer.create(ww, wh, 32);
00331 #endif
00332 buffer.fill(bgcolor);
00333
00334 rays.resize(w*2);
00335 for (int i = 0; i < w; i++)
00336 {
00337 PFreal gg = ((PFREAL_ONE >> 1) + i * PFREAL_ONE) / (2 * h);
00338 rays[w-i-1] = -gg;
00339 rays[w+i] = gg;
00340 }
00341
00342 dirty = true;
00343 }
00344
00345
00346 static QRgb blendColor(QRgb c1, QRgb c2, int blend)
00347 {
00348 int r = qRed(c1) * blend / 256 + qRed(c2) * (256 - blend) / 256;
00349 int g = qGreen(c1) * blend / 256 + qGreen(c2) * (256 - blend) / 256;
00350 int b = qBlue(c1) * blend / 256 + qBlue(c2) * (256 - blend) / 256;
00351 return qRgb(r, g, b);
00352 }
00353
00354
00355 static QImage* prepareSurface(const QImage* slideImage, int w, int h, QRgb bgcolor,
00356 QxtFlowView::ReflectionEffect reflectionEffect)
00357 {
00358 #ifdef PICTUREFLOW_QT4
00359 Qt::TransformationMode mode = Qt::SmoothTransformation;
00360 QImage img = slideImage->scaled(w, h, Qt::IgnoreAspectRatio, mode);
00361 #endif
00362 #if defined(PICTUREFLOW_QT3) || defined(PICTUREFLOW_QT2)
00363 QImage img = slideImage->smoothScale(w, h);
00364 #endif
00365
00366
00367 int hs = h * 2;
00368 int hofs = h / 3;
00369
00370
00371 #ifdef PICTUREFLOW_QT4
00372 QImage* result = new QImage(hs, w, QImage::Format_RGB32);
00373 #endif
00374 #if defined(PICTUREFLOW_QT3) || defined(PICTUREFLOW_QT2)
00375 QImage* result = new QImage;
00376 result->create(hs, w, 32);
00377 #endif
00378 result->fill(bgcolor);
00379
00380
00381
00382
00383 for (int x = 0; x < w; x++)
00384 for (int y = 0; y < h; y++)
00385 result->setPixel(hofs + y, x, img.pixel(x, y));
00386
00387 if (reflectionEffect != QxtFlowView::NoReflection)
00388 {
00389
00390 int ht = hs - h - hofs;
00391 int hte = ht;
00392 for (int x = 0; x < w; x++)
00393 for (int y = 0; y < ht; y++)
00394 {
00395 QRgb color = img.pixel(x, img.height() - y - 1);
00396 result->setPixel(h + hofs + y, x, blendColor(color, bgcolor, 128*(hte - y) / hte));
00397 }
00398
00399 if (reflectionEffect == QxtFlowView::BlurredReflection)
00400 {
00401
00402
00403 QRect rect(hs / 2, 0, hs / 2, w);
00404 rect &= result->rect();
00405
00406 int r1 = rect.top();
00407 int r2 = rect.bottom();
00408 int c1 = rect.left();
00409 int c2 = rect.right();
00410
00411 int bpl = result->bytesPerLine();
00412 int rgba[4];
00413 unsigned char* p;
00414
00415
00416
00417 for (int loop = 0; loop < 2; loop++)
00418 {
00419 for (int col = c1; col <= c2; col++)
00420 {
00421 p = result->scanLine(r1) + col * 4;
00422 for (int i = 0; i < 3; i++)
00423 rgba[i] = p[i] << 4;
00424
00425 p += bpl;
00426 for (int j = r1; j < r2; j++, p += bpl)
00427 for (int i = 0; i < 3; i++)
00428 p[i] = (rgba[i] += (((p[i] << 4) - rgba[i])) >> 1) >> 4;
00429 }
00430
00431 for (int row = r1; row <= r2; row++)
00432 {
00433 p = result->scanLine(row) + c1 * 4;
00434 for (int i = 0; i < 3; i++)
00435 rgba[i] = p[i] << 4;
00436
00437 p += 4;
00438 for (int j = c1; j < c2; j++, p += 4)
00439 for (int i = 0; i < 3; i++)
00440 p[i] = (rgba[i] += (((p[i] << 4) - rgba[i])) >> 1) >> 4;
00441 }
00442
00443 for (int col = c1; col <= c2; col++)
00444 {
00445 p = result->scanLine(r2) + col * 4;
00446 for (int i = 0; i < 3; i++)
00447 rgba[i] = p[i] << 4;
00448
00449 p -= bpl;
00450 for (int j = r1; j < r2; j++, p -= bpl)
00451 for (int i = 0; i < 3; i++)
00452 p[i] = (rgba[i] += (((p[i] << 4) - rgba[i])) >> 1) >> 4;
00453 }
00454
00455 for (int row = r1; row <= r2; row++)
00456 {
00457 p = result->scanLine(row) + c2 * 4;
00458 for (int i = 0; i < 3; i++)
00459 rgba[i] = p[i] << 4;
00460
00461 p -= 4;
00462 for (int j = c1; j < c2; j++, p -= 4)
00463 for (int i = 0; i < 3; i++)
00464 p[i] = (rgba[i] += (((p[i] << 4) - rgba[i])) >> 1) >> 4;
00465 }
00466 }
00467
00468
00469 for (int x = 0; x < w; x++)
00470 for (int y = 0; y < h; y++)
00471 result->setPixel(hofs + y, x, img.pixel(x, y));
00472 }
00473 }
00474
00475 return result;
00476 }
00477
00478 QImage* QxtFlowViewSoftwareRenderer::surface(int slideIndex)
00479 {
00480 if (!state)
00481 return 0;
00482 if (slideIndex < 0)
00483 return 0;
00484 if (slideIndex >= (int)state->slideImages.count())
00485 return 0;
00486
00487 #ifdef PICTUREFLOW_QT4
00488 int key = slideIndex;
00489 #endif
00490 #if defined(PICTUREFLOW_QT3) || defined(PICTUREFLOW_QT2)
00491 QString key = QString::number(slideIndex);
00492 #endif
00493
00494 QImage* img = state->slideImages.at(slideIndex);
00495 bool empty = img ? img->isNull() : true;
00496 if (empty)
00497 {
00498 surfaceCache.remove(key);
00499 imageHash.remove(slideIndex);
00500 if (!blankSurface)
00501 {
00502 int sw = state->slideWidth;
00503 int sh = state->slideHeight;
00504
00505 #ifdef PICTUREFLOW_QT4
00506 QImage img = QImage(sw, sh, QImage::Format_RGB32);
00507
00508 QPainter painter(&img);
00509 QPoint p1(sw*4 / 10, 0);
00510 QPoint p2(sw*6 / 10, sh);
00511 QLinearGradient linearGrad(p1, p2);
00512 linearGrad.setColorAt(0, Qt::black);
00513 linearGrad.setColorAt(1, Qt::white);
00514 painter.setBrush(linearGrad);
00515 painter.fillRect(0, 0, sw, sh, QBrush(linearGrad));
00516
00517 painter.setPen(QPen(QColor(64, 64, 64), 4));
00518 painter.setBrush(QBrush());
00519 painter.drawRect(2, 2, sw - 3, sh - 3);
00520 painter.end();
00521 #endif
00522 #if defined(PICTUREFLOW_QT3) || defined(PICTUREFLOW_QT2)
00523 QPixmap pixmap(sw, sh, 32);
00524 QPainter painter(&pixmap);
00525 painter.fillRect(pixmap.rect(), QColor(192, 192, 192));
00526 painter.fillRect(5, 5, sw - 10, sh - 10, QColor(64, 64, 64));
00527 painter.end();
00528 QImage img = pixmap.convertToImage();
00529 #endif
00530
00531 blankSurface = prepareSurface(&img, sw, sh, bgcolor, state->reflectionEffect);
00532 }
00533 return blankSurface;
00534 }
00535
00536 #ifdef PICTUREFLOW_QT4
00537 bool exist = imageHash.contains(slideIndex);
00538 if (exist)
00539 if (img == imageHash.find(slideIndex).value())
00540 #endif
00541 #ifdef PICTUREFLOW_QT3
00542 bool exist = imageHash.find(slideIndex) != imageHash.end();
00543 if (exist)
00544 if (img == imageHash.find(slideIndex).data())
00545 #endif
00546 #ifdef PICTUREFLOW_QT2
00547 if (img == imageHash[slideIndex])
00548 #endif
00549 if (surfaceCache.contains(key))
00550 return surfaceCache[key];
00551
00552 QImage* sr = prepareSurface(img, state->slideWidth, state->slideHeight, bgcolor, state->reflectionEffect);
00553 surfaceCache.insert(key, sr);
00554 imageHash.insert(slideIndex, img);
00555
00556 return sr;
00557 }
00558
00559
00560
00561 QRect QxtFlowViewSoftwareRenderer::renderSlide(const SlideInfo &slide, int col1, int col2)
00562 {
00563 int blend = slide.blend;
00564 if (!blend)
00565 return QRect();
00566
00567 QImage* src = surface(slide.slideIndex);
00568 if (!src)
00569 return QRect();
00570
00571 QRect rect(0, 0, 0, 0);
00572
00573 int sw = src->height();
00574 int sh = src->width();
00575 int h = buffer.height();
00576 int w = buffer.width();
00577
00578 if (col1 > col2)
00579 {
00580 int c = col2;
00581 col2 = col1;
00582 col1 = c;
00583 }
00584
00585 col1 = (col1 >= 0) ? col1 : 0;
00586 col2 = (col2 >= 0) ? col2 : w - 1;
00587 col1 = qMin(col1, w - 1);
00588 col2 = qMin(col2, w - 1);
00589
00590 int zoom = 100;
00591 int distance = h * 100 / zoom;
00592 PFreal sdx = fcos(slide.angle);
00593 PFreal sdy = fsin(slide.angle);
00594 PFreal xs = slide.cx - state->slideWidth * sdx / 2;
00595 PFreal ys = slide.cy - state->slideWidth * sdy / 2;
00596 PFreal dist = distance * PFREAL_ONE;
00597
00598 int xi = qMax((PFreal)0, ((w * PFREAL_ONE / 2) + fdiv(xs * h, dist + ys)) >> PFREAL_SHIFT);
00599 if (xi >= w)
00600 return rect;
00601
00602 bool flag = false;
00603 rect.setLeft(xi);
00604 for (int x = qMax(xi, col1); x <= col2; x++)
00605 {
00606 PFreal hity = 0;
00607 PFreal fk = rays[x];
00608 if (sdy)
00609 {
00610 fk = fk - fdiv(sdx, sdy);
00611 hity = -fdiv((rays[x] * distance - slide.cx + slide.cy * sdx / sdy), fk);
00612 }
00613
00614 dist = distance * PFREAL_ONE + hity;
00615 if (dist < 0)
00616 continue;
00617
00618 PFreal hitx = fmul(dist, rays[x]);
00619 PFreal hitdist = fdiv(hitx - slide.cx, sdx);
00620
00621 int column = sw / 2 + (hitdist >> PFREAL_SHIFT);
00622 if (column >= sw)
00623 break;
00624 if (column < 0)
00625 continue;
00626
00627 rect.setRight(x);
00628 if (!flag)
00629 rect.setLeft(x);
00630 flag = true;
00631
00632 int y1 = h / 2;
00633 int y2 = y1 + 1;
00634 QRgb* pixel1 = (QRgb*)(buffer.scanLine(y1)) + x;
00635 QRgb* pixel2 = (QRgb*)(buffer.scanLine(y2)) + x;
00636 QRgb pixelstep = pixel2 - pixel1;
00637
00638 int center = (sh / 2);
00639 int dy = dist / h;
00640 int p1 = center * PFREAL_ONE - dy / 2;
00641 int p2 = center * PFREAL_ONE + dy / 2;
00642
00643 const QRgb *ptr = (const QRgb*)(src->scanLine(column));
00644 if (blend == 256)
00645 while ((y1 >= 0) && (y2 < h) && (p1 >= 0))
00646 {
00647 *pixel1 = ptr[p1 >> PFREAL_SHIFT];
00648 *pixel2 = ptr[p2 >> PFREAL_SHIFT];
00649 p1 -= dy;
00650 p2 += dy;
00651 y1--;
00652 y2++;
00653 pixel1 -= pixelstep;
00654 pixel2 += pixelstep;
00655 }
00656 else
00657 while ((y1 >= 0) && (y2 < h) && (p1 >= 0))
00658 {
00659 QRgb c1 = ptr[p1 >> PFREAL_SHIFT];
00660 QRgb c2 = ptr[p2 >> PFREAL_SHIFT];
00661 *pixel1 = blendColor(c1, bgcolor, blend);
00662 *pixel2 = blendColor(c2, bgcolor, blend);
00663 p1 -= dy;
00664 p2 += dy;
00665 y1--;
00666 y2++;
00667 pixel1 -= pixelstep;
00668 pixel2 += pixelstep;
00669 }
00670 }
00671
00672 rect.setTop(0);
00673 rect.setBottom(h - 1);
00674 return rect;
00675 }
00676
00677 void QxtFlowViewSoftwareRenderer::renderSlides()
00678 {
00679 int nleft = state->leftSlides.count();
00680 int nright = state->rightSlides.count();
00681
00682 QRect r = renderSlide(state->centerSlide);
00683 int c1 = r.left();
00684 int c2 = r.right();
00685
00686 for (int index = 0; index < nleft; index++)
00687 {
00688 QRect rs = renderSlide(state->leftSlides[index], 0, c1 - 1);
00689 if (!rs.isEmpty())
00690 c1 = rs.left();
00691 }
00692 for (int index = 0; index < nright; index++)
00693 {
00694 QRect rs = renderSlide(state->rightSlides[index], c2 + 1, buffer.width());
00695 if (!rs.isEmpty())
00696 c2 = rs.right();
00697 }
00698 }
00699
00700
00701 void QxtFlowViewSoftwareRenderer::render()
00702 {
00703 buffer.fill(state->backgroundColor);
00704 renderSlides();
00705 dirty = false;
00706 }
00707
00708
00709
00710
00711
00712
00713
00714