00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <stdlib.h>
00023 #include <string.h>
00024 #include <cfloat>
00025 #include <cmath>
00026 #include <climits>
00027 #include <strings.h>
00028
00029 #include "qbrush.h"
00030 #include "qfontinfo.h"
00031 #include "qfontmetrics.h"
00032 #include "qpen.h"
00033 #include "qregion.h"
00034 #include "qwmatrix.h"
00035 #include <qimage.h>
00036 #include <qmap.h>
00037 #include <qpainter.h>
00038 #include <qpixmap.h>
00039 #include <qpointarray.h>
00040 #include <qrect.h>
00041 #include <qstring.h>
00042
00043 #include <kdebug.h>
00044 #include <kcommand.h>
00045 #include <klocale.h>
00046
00047 #include "kis_brush.h"
00048 #include "kis_debug_areas.h"
00049 #include "kis_image.h"
00050 #include "kis_layer.h"
00051 #include "kis_paint_device.h"
00052 #include "kis_painter.h"
00053 #include "kis_pattern.h"
00054 #include "kis_rect.h"
00055 #include "kis_colorspace.h"
00056 #include "kis_transaction.h"
00057 #include "kis_types.h"
00058 #include "kis_vec.h"
00059 #include "kis_iterators_pixel.h"
00060 #include "kis_paintop.h"
00061 #include "kis_selection.h"
00062 #include "kis_fill_painter.h"
00063 #include "kis_color.h"
00064
00065
00066
00067 #define BEZIER_FLATNESS_THRESHOLD 0.5
00068
00069 KisPainter::KisPainter()
00070 {
00071 init();
00072 }
00073
00074 KisPainter::KisPainter(KisPaintDeviceSP device)
00075 {
00076 init();
00077 Q_ASSERT(device);
00078 begin(device);
00079 }
00080
00081 void KisPainter::init()
00082 {
00083 m_transaction = 0;
00084 m_paintOp = 0;
00085 m_filter = 0;
00086 m_brush = 0;
00087 m_pattern= 0;
00088 m_opacity = OPACITY_OPAQUE;
00089 m_compositeOp = COMPOSITE_OVER;
00090 m_dab = 0;
00091 m_fillStyle = FillStyleNone;
00092 m_strokeStyle = StrokeStyleBrush;
00093 m_pressure = PRESSURE_MIN;
00094 m_duplicateHealing = false;
00095 m_duplicateHealingRadius = 10;
00096 m_duplicatePerspectiveCorrection = false;
00097 }
00098
00099 KisPainter::~KisPainter()
00100 {
00101 m_brush = 0;
00102 delete m_paintOp;
00103 end();
00104 }
00105
00106 void KisPainter::begin(KisPaintDeviceSP device)
00107 {
00108 if (!device) return;
00109
00110 if (m_transaction)
00111 delete m_transaction;
00112
00113 m_device = device;
00114 m_colorSpace = device->colorSpace();
00115 m_pixelSize = device->pixelSize();
00116 }
00117
00118 KCommand *KisPainter::end()
00119 {
00120 return endTransaction();
00121 }
00122
00123 void KisPainter::beginTransaction(const QString& customName)
00124 {
00125 if (m_transaction)
00126 delete m_transaction;
00127 m_transaction = new KisTransaction(customName, m_device);
00128 Q_CHECK_PTR(m_transaction);
00129 }
00130
00131 void KisPainter::beginTransaction( KisTransaction* command)
00132 {
00133 if (m_transaction)
00134 delete m_transaction;
00135 m_transaction = command;
00136 }
00137
00138
00139 KCommand *KisPainter::endTransaction()
00140 {
00141 KCommand *command = m_transaction;
00142 m_transaction = 0;
00143 return command;
00144 }
00145
00146
00147 QRect KisPainter::dirtyRect() {
00148 QRect r = m_dirtyRect;
00149 m_dirtyRect = QRect();
00150 return r;
00151 }
00152
00153 void KisPainter::bitBlt(Q_INT32 dx, Q_INT32 dy,
00154 const KisCompositeOp& op,
00155 KisPaintDeviceSP srcdev,
00156 Q_UINT8 opacity,
00157 Q_INT32 sx, Q_INT32 sy,
00158 Q_INT32 sw, Q_INT32 sh)
00159 {
00160 if (srcdev == 0) {
00161 return;
00162 }
00163
00164 QRect srcRect = QRect(sx, sy, sw, sh);
00165
00166 if (srcdev->extentIsValid() && op != COMPOSITE_COPY) {
00167 srcRect &= srcdev->extent();
00168 }
00169
00170 if (srcRect.isEmpty()) {
00171 return;
00172 }
00173
00174 dx += srcRect.x() - sx;
00175 dy += srcRect.y() - sy;
00176
00177 sx = srcRect.x();
00178 sy = srcRect.y();
00179 sw = srcRect.width();
00180 sh = srcRect.height();
00181
00182 addDirtyRect(QRect(dx, dy, sw, sh));
00183
00184 KisColorSpace * srcCs = srcdev->colorSpace();
00185
00186 Q_INT32 dstY = dy;
00187 Q_INT32 srcY = sy;
00188 Q_INT32 rowsRemaining = sh;
00189
00190 while (rowsRemaining > 0) {
00191
00192 Q_INT32 dstX = dx;
00193 Q_INT32 srcX = sx;
00194 Q_INT32 columnsRemaining = sw;
00195 Q_INT32 numContiguousDstRows = m_device->numContiguousRows(dstY, dstX, dstX + sw - 1);
00196 Q_INT32 numContiguousSrcRows = srcdev->numContiguousRows(srcY, srcX, srcX + sw - 1);
00197
00198 Q_INT32 rows = QMIN(numContiguousDstRows, numContiguousSrcRows);
00199 rows = QMIN(rows, rowsRemaining);
00200
00201 while (columnsRemaining > 0) {
00202
00203 Q_INT32 numContiguousDstColumns = m_device->numContiguousColumns(dstX, dstY, dstY + rows - 1);
00204 Q_INT32 numContiguousSrcColumns = srcdev->numContiguousColumns(srcX, srcY, srcY + rows - 1);
00205
00206 Q_INT32 columns = QMIN(numContiguousDstColumns, numContiguousSrcColumns);
00207 columns = QMIN(columns, columnsRemaining);
00208
00209 Q_INT32 srcRowStride = srcdev->rowStride(srcX, srcY);
00210
00211 KisHLineIteratorPixel srcIt = srcdev->createHLineIterator(srcX, srcY, columns, false);
00212 const Q_UINT8 *srcData = srcIt.rawData();
00213
00214
00215 Q_INT32 dstRowStride = m_device->rowStride(dstX, dstY);
00216 KisHLineIteratorPixel dstIt = m_device->createHLineIterator(dstX, dstY, columns, true);
00217 Q_UINT8 *dstData = dstIt.rawData();
00218
00219
00220 m_colorSpace->bitBlt(dstData,
00221 dstRowStride,
00222 srcCs,
00223 srcData,
00224 srcRowStride,
00225 0,
00226 0,
00227 opacity,
00228 rows,
00229 columns,
00230 op);
00231
00232 srcX += columns;
00233 dstX += columns;
00234 columnsRemaining -= columns;
00235 }
00236
00237 srcY += rows;
00238 dstY += rows;
00239 rowsRemaining -= rows;
00240 }
00241 }
00242
00243 void KisPainter::bltSelection(Q_INT32 dx, Q_INT32 dy,
00244 const KisCompositeOp &op,
00245 KisPaintDeviceSP srcdev,
00246 KisSelectionSP seldev,
00247 Q_UINT8 opacity,
00248 Q_INT32 sx, Q_INT32 sy,
00249 Q_INT32 sw, Q_INT32 sh)
00250 {
00251
00252 if (seldev->isProbablyTotallyUnselected(QRect(dx, dy, sw, sh))) {
00253
00254
00255
00256
00257
00258
00259
00260
00261 return;
00262 }
00263 bltMask(dx,dy,op,srcdev,seldev.data(),opacity,sx,sy,sw,sh);
00264 }
00265
00266 void KisPainter::bltMask(Q_INT32 dx, Q_INT32 dy,
00267 const KisCompositeOp &op,
00268 KisPaintDeviceSP srcdev,
00269 KisPaintDeviceSP seldev,
00270 Q_UINT8 opacity,
00271 Q_INT32 sx, Q_INT32 sy,
00272 Q_INT32 sw, Q_INT32 sh)
00273
00274 {
00275 if (srcdev == 0) return;
00276
00277 if (seldev == 0) return;
00278
00279 if (m_device == 0) return;
00280
00281
00282 QRect srcRect = QRect(sx, sy, sw, sh);
00283
00284 if (srcdev->extentIsValid() && op != COMPOSITE_COPY) {
00285 srcRect &= srcdev->extent();
00286 }
00287
00288 if (srcRect.isEmpty()) {
00289 return;
00290 }
00291
00292 dx += srcRect.x() - sx;
00293 dy += srcRect.y() - sy;
00294
00295 sx = srcRect.x();
00296 sy = srcRect.y();
00297 sw = srcRect.width();
00298 sh = srcRect.height();
00299
00300 addDirtyRect(QRect(dx, dy, sw, sh));
00301
00302 KisColorSpace * srcCs = srcdev->colorSpace();
00303
00304 Q_INT32 dstY = dy;
00305 Q_INT32 srcY = sy;
00306 Q_INT32 rowsRemaining = sh;
00307
00308 while (rowsRemaining > 0) {
00309
00310 Q_INT32 dstX = dx;
00311 Q_INT32 srcX = sx;
00312 Q_INT32 columnsRemaining = sw;
00313 Q_INT32 numContiguousDstRows = m_device->numContiguousRows(dstY, dstX, dstX + sw - 1);
00314 Q_INT32 numContiguousSrcRows = srcdev->numContiguousRows(srcY, srcX, srcX + sw - 1);
00315 Q_INT32 numContiguousSelRows = seldev->numContiguousRows(dstY, dstX, dstX + sw - 1);
00316
00317 Q_INT32 rows = QMIN(numContiguousDstRows, numContiguousSrcRows);
00318 rows = QMIN(numContiguousSelRows, rows);
00319 rows = QMIN(rows, rowsRemaining);
00320
00321 while (columnsRemaining > 0) {
00322
00323 Q_INT32 numContiguousDstColumns = m_device->numContiguousColumns(dstX, dstY, dstY + rows - 1);
00324 Q_INT32 numContiguousSrcColumns = srcdev->numContiguousColumns(srcX, srcY, srcY + rows - 1);
00325 Q_INT32 numContiguousSelColumns = seldev->numContiguousColumns(dstX, dstY, dstY + rows - 1);
00326
00327 Q_INT32 columns = QMIN(numContiguousDstColumns, numContiguousSrcColumns);
00328 columns = QMIN(numContiguousSelColumns, columns);
00329 columns = QMIN(columns, columnsRemaining);
00330
00331
00332 Q_INT32 dstRowStride = m_device->rowStride(dstX, dstY);
00333 KisHLineIteratorPixel dstIt = m_device->createHLineIterator(dstX, dstY, columns, true);
00334 Q_UINT8 *dstData = dstIt.rawData();
00335
00336
00337 Q_INT32 srcRowStride = srcdev->rowStride(srcX, srcY);
00338 KisHLineIteratorPixel srcIt = srcdev->createHLineIterator(srcX, srcY, columns, false);
00339 const Q_UINT8 *srcData = srcIt.rawData();
00340
00341
00342 Q_INT32 selRowStride = seldev->rowStride(dstX, dstY);
00343 KisHLineIteratorPixel selIt = seldev->createHLineIterator(dstX, dstY, columns, false);
00344 const Q_UINT8 *selData = selIt.rawData();
00345
00346 m_colorSpace->bitBlt(dstData,
00347 dstRowStride,
00348 srcCs,
00349 srcData,
00350 srcRowStride,
00351 selData,
00352 selRowStride,
00353 opacity,
00354 rows,
00355 columns,
00356 op);
00357
00358 srcX += columns;
00359 dstX += columns;
00360 columnsRemaining -= columns;
00361 }
00362
00363 srcY += rows;
00364 dstY += rows;
00365 rowsRemaining -= rows;
00366 }
00367 }
00368
00369
00370 void KisPainter::bltSelection(Q_INT32 dx, Q_INT32 dy,
00371 const KisCompositeOp& op,
00372 KisPaintDeviceSP srcdev,
00373 Q_UINT8 opacity,
00374 Q_INT32 sx, Q_INT32 sy,
00375 Q_INT32 sw, Q_INT32 sh)
00376 {
00377 if (m_device == 0) return;
00378 if (!m_device->hasSelection()) {
00379 bitBlt(dx, dy, op, srcdev, opacity, sx, sy, sw, sh);
00380 }
00381 else
00382 bltSelection(dx,dy,op,srcdev, m_device->selection(),opacity,sx,sy,sw,sh);
00383 }
00384
00385 double KisPainter::paintLine(const KisPoint & pos1,
00386 const double pressure1,
00387 const double xTilt1,
00388 const double yTilt1,
00389 const KisPoint & pos2,
00390 const double pressure2,
00391 const double xTilt2,
00392 const double yTilt2,
00393 const double inSavedDist)
00394 {
00395 if (!m_device) return 0;
00396 if (!m_paintOp) return 0;
00397 if (!m_brush) return 0;
00398
00399 double savedDist = inSavedDist;
00400 KisVector2D end(pos2);
00401 KisVector2D start(pos1);
00402
00403 KisVector2D dragVec = end - start;
00404 KisVector2D movement = dragVec;
00405
00406 if (savedDist < 0) {
00407 m_paintOp->paintAt(pos1, KisPaintInformation(pressure1, xTilt1, yTilt1, movement));
00408 savedDist = 0;
00409 }
00410
00411
00412
00413 double xSpacing = m_brush->xSpacing((pressure1 + pressure2) / 2);
00414 double ySpacing = m_brush->ySpacing((pressure1 + pressure2) / 2);
00415
00416 if (xSpacing < 0.5) {
00417 xSpacing = 0.5;
00418 }
00419 if (ySpacing < 0.5) {
00420 ySpacing = 0.5;
00421 }
00422
00423 double xScale = 1;
00424 double yScale = 1;
00425 double spacing;
00426
00427
00428
00429
00430 if (xSpacing > ySpacing) {
00431 yScale = xSpacing / ySpacing;
00432 spacing = xSpacing;
00433 }
00434 else {
00435 xScale = ySpacing / xSpacing;
00436 spacing = ySpacing;
00437 }
00438
00439 dragVec.setX(dragVec.x() * xScale);
00440 dragVec.setY(dragVec.y() * yScale);
00441
00442 double newDist = dragVec.length();
00443 double dist = savedDist + newDist;
00444 double l_savedDist = savedDist;
00445
00446 if (dist < spacing) {
00447 return dist;
00448 }
00449
00450 dragVec.normalize();
00451 KisVector2D step(0, 0);
00452
00453 while (dist >= spacing) {
00454 if (l_savedDist > 0) {
00455 step += dragVec * (spacing - l_savedDist);
00456 l_savedDist -= spacing;
00457 }
00458 else {
00459 step += dragVec * spacing;
00460 }
00461
00462 KisPoint p(start.x() + (step.x() / xScale), start.y() + (step.y() / yScale));
00463
00464 double distanceMoved = step.length();
00465 double t = 0;
00466
00467 if (newDist > DBL_EPSILON) {
00468 t = distanceMoved / newDist;
00469 }
00470
00471 double pressure = (1 - t) * pressure1 + t * pressure2;
00472 double xTilt = (1 - t) * xTilt1 + t * xTilt2;
00473 double yTilt = (1 - t) * yTilt1 + t * yTilt2;
00474
00475 m_paintOp->paintAt(p, KisPaintInformation(pressure, xTilt, yTilt, movement));
00476 dist -= spacing;
00477 }
00478
00479 if (dist > 0)
00480 return dist;
00481 else
00482 return 0;
00483 }
00484
00485 void KisPainter::paintPolyline (const vKisPoint &points,
00486 int index, int numPoints)
00487 {
00488 if (index >= (int) points.count ())
00489 return;
00490
00491 if (numPoints < 0)
00492 numPoints = points.count ();
00493
00494 if (index + numPoints > (int) points.count ())
00495 numPoints = points.count () - index;
00496
00497
00498 for (int i = index; i < index + numPoints - 1; i++)
00499 {
00500 paintLine (points [index], 0, 0, 0, points [index + 1],
00501 0, 0, 0);
00502 }
00503 }
00504
00505 void KisPainter::getBezierCurvePoints(const KisPoint &pos1,
00506 const KisPoint &control1,
00507 const KisPoint &control2,
00508 const KisPoint &pos2,
00509 vKisPoint& points)
00510 {
00511 double d1 = pointToLineDistance(control1, pos1, pos2);
00512 double d2 = pointToLineDistance(control2, pos1, pos2);
00513
00514 if (d1 < BEZIER_FLATNESS_THRESHOLD && d2 < BEZIER_FLATNESS_THRESHOLD) {
00515 points.push_back(pos1);
00516 } else {
00517
00518 KisVector2D p1 = pos1;
00519 KisVector2D p2 = control1;
00520 KisVector2D p3 = control2;
00521 KisVector2D p4 = pos2;
00522
00523 KisVector2D l2 = (p1 + p2) / 2;
00524 KisVector2D h = (p2 + p3) / 2;
00525 KisVector2D l3 = (l2 + h) / 2;
00526 KisVector2D r3 = (p3 + p4) / 2;
00527 KisVector2D r2 = (h + r3) / 2;
00528 KisVector2D l4 = (l3 + r2) / 2;
00529 KisVector2D r1 = l4;
00530 KisVector2D l1 = p1;
00531 KisVector2D r4 = p4;
00532
00533 getBezierCurvePoints(l1.toKisPoint(), l2.toKisPoint(), l3.toKisPoint(), l4.toKisPoint(), points);
00534 getBezierCurvePoints(r1.toKisPoint(), r2.toKisPoint(), r3.toKisPoint(), r4.toKisPoint(), points);
00535 }
00536 }
00537
00538 double KisPainter::paintBezierCurve(const KisPoint &pos1,
00539 const double pressure1,
00540 const double xTilt1,
00541 const double yTilt1,
00542 const KisPoint &control1,
00543 const KisPoint &control2,
00544 const KisPoint &pos2,
00545 const double pressure2,
00546 const double xTilt2,
00547 const double yTilt2,
00548 const double savedDist)
00549 {
00550 double newDistance;
00551 double d1 = pointToLineDistance(control1, pos1, pos2);
00552 double d2 = pointToLineDistance(control2, pos1, pos2);
00553
00554 if (d1 < BEZIER_FLATNESS_THRESHOLD && d2 < BEZIER_FLATNESS_THRESHOLD) {
00555 newDistance = paintLine(pos1, pressure1, xTilt1, yTilt1, pos2, pressure2, xTilt2, yTilt2, savedDist);
00556 } else {
00557
00558 KisVector2D p1 = pos1;
00559 KisVector2D p2 = control1;
00560 KisVector2D p3 = control2;
00561 KisVector2D p4 = pos2;
00562
00563 KisVector2D l2 = (p1 + p2) / 2;
00564 KisVector2D h = (p2 + p3) / 2;
00565 KisVector2D l3 = (l2 + h) / 2;
00566 KisVector2D r3 = (p3 + p4) / 2;
00567 KisVector2D r2 = (h + r3) / 2;
00568 KisVector2D l4 = (l3 + r2) / 2;
00569 KisVector2D r1 = l4;
00570 KisVector2D l1 = p1;
00571 KisVector2D r4 = p4;
00572
00573 double midPressure = (pressure1 + pressure2) / 2;
00574 double midXTilt = (xTilt1 + xTilt2) / 2;
00575 double midYTilt = (yTilt1 + yTilt2) / 2;
00576
00577 newDistance = paintBezierCurve(l1.toKisPoint(), pressure1, xTilt1, yTilt1,
00578 l2.toKisPoint(), l3.toKisPoint(),
00579 l4.toKisPoint(), midPressure, midXTilt, midYTilt,
00580 savedDist);
00581 newDistance = paintBezierCurve(r1.toKisPoint(), midPressure, midXTilt, midYTilt,
00582 r2.toKisPoint(),
00583 r3.toKisPoint(),
00584 r4.toKisPoint(), pressure2, xTilt2, yTilt2, newDistance);
00585 }
00586
00587 return newDistance;
00588 }
00589
00590 void KisPainter::paintRect (const KisPoint &startPoint,
00591 const KisPoint &endPoint,
00592 const double ,
00593 const double ,
00594 const double )
00595 {
00596 KoRect normalizedRect = KisRect (startPoint, endPoint).normalize ();
00597
00598 vKisPoint points;
00599
00600 points.push_back(normalizedRect.topLeft());
00601 points.push_back(normalizedRect.bottomLeft());
00602 points.push_back(normalizedRect.bottomRight());
00603 points.push_back(normalizedRect.topRight());
00604
00605 paintPolygon(points);
00606 }
00607
00608 void KisPainter::paintEllipse (const KisPoint &startPoint,
00609 const KisPoint &endPoint,
00610 const double ,
00611 const double ,
00612 const double )
00613 {
00614 KisRect r = KisRect(startPoint, endPoint).normalize();
00615
00616
00617
00618 const double kappa = 0.5522847498;
00619 const double lx = (r.width() / 2) * kappa;
00620 const double ly = (r.height() / 2) * kappa;
00621
00622 KisPoint center = r.center();
00623
00624 KisPoint p0(r.left(), center.y());
00625 KisPoint p1(r.left(), center.y() - ly);
00626 KisPoint p2(center.x() - lx, r.top());
00627 KisPoint p3(center.x(), r.top());
00628
00629 vKisPoint points;
00630
00631 getBezierCurvePoints(p0, p1, p2, p3, points);
00632
00633 KisPoint p4(center.x() + lx, r.top());
00634 KisPoint p5(r.right(), center.y() - ly);
00635 KisPoint p6(r.right(), center.y());
00636
00637 getBezierCurvePoints(p3, p4, p5, p6, points);
00638
00639 KisPoint p7(r.right(), center.y() + ly);
00640 KisPoint p8(center.x() + lx, r.bottom());
00641 KisPoint p9(center.x(), r.bottom());
00642
00643 getBezierCurvePoints(p6, p7, p8, p9, points);
00644
00645 KisPoint p10(center.x() - lx, r.bottom());
00646 KisPoint p11(r.left(), center.y() + ly);
00647
00648 getBezierCurvePoints(p9, p10, p11, p0, points);
00649
00650 paintPolygon(points);
00651 }
00652
00653 void KisPainter::paintAt(const KisPoint & pos,
00654 const double pressure,
00655 const double xTilt,
00656 const double yTilt)
00657 {
00658 if (!m_paintOp) return;
00659 m_paintOp->paintAt(pos, KisPaintInformation(pressure, xTilt, yTilt, KisVector2D()));
00660 }
00661
00662 double KisPainter::pointToLineDistance(const KisPoint& p, const KisPoint& l0, const KisPoint& l1)
00663 {
00664 double lineLength = sqrt((l1.x() - l0.x()) * (l1.x() - l0.x()) + (l1.y() - l0.y()) * (l1.y() - l0.y()));
00665 double distance = 0;
00666
00667 if (lineLength > DBL_EPSILON) {
00668 distance = ((l0.y() - l1.y()) * p.x() + (l1.x() - l0.x()) * p.y() + l0.x() * l1.y() - l1.x() * l0.y()) / lineLength;
00669 distance = fabs(distance);
00670 }
00671
00672 return distance;
00673 }
00674
00675
00676
00677
00678
00679
00680
00681
00682
00683
00684
00685
00686
00687
00688
00689
00690
00691
00692
00693
00694
00695
00696
00697
00698
00699
00700
00701
00702 typedef struct {
00703 double x;
00704 double dx;
00705 int i;
00706 } Edge;
00707
00708 static int n;
00709 static const KisPoint *pt;
00710
00711 static int nact;
00712 static Edge *active;
00713
00714
00715 static int compare_ind(const void *pu, const void *pv)
00716 {
00717 const int *u = static_cast<const int *>(pu);
00718 const int *v = static_cast<const int *>(pv);
00719
00720 return pt[*u].y() <= pt[*v].y() ? -1 : 1;
00721 }
00722
00723 static int compare_active(const void *pu, const void *pv)
00724 {
00725 const Edge *u = static_cast<const Edge *>(pu);
00726 const Edge *v = static_cast<const Edge *>(pv);
00727
00728 return u->x <= v->x ? -1 : 1;
00729 }
00730
00731 static void cdelete(int i)
00732 {
00733 int j;
00734
00735 for (j=0; j<nact && active[j].i!=i; j++);
00736 if (j>=nact) return;
00737 nact--;
00738 bcopy(&active[j+1], &active[j], (nact-j)*sizeof active[0]);
00739 }
00740
00741 static void cinsert(int i, int y)
00742 {
00743 int j;
00744 double dx;
00745 const KisPoint *p, *q;
00746
00747 j = i<n-1 ? i+1 : 0;
00748 if (pt[i].y() < pt[j].y()) {
00749 p = &pt[i]; q = &pt[j];
00750 } else {
00751 p = &pt[j]; q = &pt[i];
00752 }
00753
00754 active[nact].dx = dx = (q->x()-p->x())/(q->y()-p->y());
00755 active[nact].x = dx*(y+.5-p->y())+p->x();
00756 active[nact].i = i;
00757 nact++;
00758 }
00759
00760 void KisPainter::fillPolygon(const vKisPoint& points, FillStyle fillStyle)
00761 {
00762 int nvert = points.count();
00763 int k, y0, y1, y, i, j, xl, xr;
00764 int *ind;
00765
00766 n = nvert;
00767 pt = &(points[0]);
00768 if (n<3) return;
00769 if (fillStyle == FillStyleNone) {
00770 return;
00771 }
00772
00773 ind = new int[n];
00774 Q_CHECK_PTR(ind);
00775 active = new Edge[n];
00776 Q_CHECK_PTR(active);
00777
00778
00779 for (k=0; k<n; k++)
00780 ind[k] = k;
00781 qsort(ind, n, sizeof ind[0], compare_ind);
00782
00783 nact = 0;
00784 k = 0;
00785 y0 = static_cast<int>(ceil(pt[ind[0]].y()-.5));
00786 y1 = static_cast<int>(floor(pt[ind[n-1]].y()-.5));
00787
00788 int x0 = INT_MAX;
00789 int x1 = INT_MIN;
00790
00791 for (int i = 0; i < nvert; i++) {
00792 int pointHighX = static_cast<int>(ceil(points[i].x() - 0.5));
00793 int pointLowX = static_cast<int>(floor(points[i].x() - 0.5));
00794
00795 if (pointLowX < x0) {
00796 x0 = pointLowX;
00797 }
00798 if (pointHighX > x1) {
00799 x1 = pointHighX;
00800 }
00801 }
00802
00803
00804
00805
00806 KisPaintDeviceSP polygon = new KisPaintDevice(m_device->colorSpace(), "polygon");
00807 Q_CHECK_PTR(polygon);
00808
00809 KisFillPainter fillPainter(polygon);
00810 QRect boundingRectangle(x0, y0, x1 - x0 + 1, y1 - y0 + 1);
00811
00812
00813 if (m_device->image()) {
00814 boundingRectangle &= m_device->image()->bounds();
00815 }
00816
00817 switch (fillStyle) {
00818 default:
00819
00820 case FillStyleGradient:
00821
00822 case FillStyleStrokes:
00823
00824 kdWarning(DBG_AREA_CORE) << "Unknown or unsupported fill style in fillPolygon\n";
00825 case FillStyleForegroundColor:
00826 fillPainter.fillRect(boundingRectangle, paintColor(), OPACITY_OPAQUE);
00827 break;
00828 case FillStyleBackgroundColor:
00829 fillPainter.fillRect(boundingRectangle, backgroundColor(), OPACITY_OPAQUE);
00830 break;
00831 case FillStylePattern:
00832 Q_ASSERT(m_pattern != 0);
00833 fillPainter.fillRect(boundingRectangle, m_pattern);
00834 break;
00835 }
00836
00837 KisSelectionSP polygonMask = new KisSelection(polygon);
00838
00839 for (y=y0; y<=y1; y++) {
00840
00841
00842
00843 for (; k<n && pt[ind[k]].y()<=y+.5; k++) {
00844
00845
00846 i = ind[k];
00847
00848
00849
00850
00851 j = i>0 ? i-1 : n-1;
00852 if (pt[j].y() <= y-.5)
00853 cdelete(j);
00854 else if (pt[j].y() > y+.5)
00855 cinsert(j, y);
00856 j = i<n-1 ? i+1 : 0;
00857 if (pt[j].y() <= y-.5)
00858 cdelete(i);
00859 else if (pt[j].y() > y+.5)
00860 cinsert(i, y);
00861 }
00862
00863
00864 qsort(active, nact, sizeof active[0], compare_active);
00865
00866
00867 for (j=0; j<nact; j+=2) {
00868
00869 xl = static_cast<int>(ceil(active[j].x-.5));
00870 xr = static_cast<int>(floor(active[j+1].x-.5));
00871
00872 if (xl<=xr) {
00873 KisHLineIterator it = polygonMask->createHLineIterator(xl, y, xr - xl + 1, true);
00874
00875 while (!it.isDone()) {
00876
00877 it.rawData()[0] = MAX_SELECTED;
00878 ++it;
00879 }
00880 }
00881
00882 active[j].x += active[j].dx;
00883 active[j+1].x += active[j+1].dx;
00884 }
00885 }
00886 delete [] ind;
00887 delete [] active;
00888
00889 polygon->applySelectionMask(polygonMask);
00890
00891 QRect r = polygon->extent();
00892
00893
00894
00895
00896
00897 bltSelection(r.x(), r.y(), compositeOp(), polygon, opacity(), r.x(), r.y(), r.width(), r.height());
00898 }
00899
00900 void KisPainter::paintPolygon(const vKisPoint& points)
00901 {
00902 if (m_fillStyle != FillStyleNone) {
00903 fillPolygon(points, m_fillStyle);
00904 }
00905
00906 if (m_strokeStyle != StrokeStyleNone) {
00907 if (points.count() > 1) {
00908 double distance = -1;
00909
00910 for (uint i = 0; i < points.count() - 1; i++) {
00911 distance = paintLine(points[i], PRESSURE_DEFAULT, 0, 0, points[i + 1], PRESSURE_DEFAULT, 0, 0, distance);
00912 }
00913 paintLine(points[points.count() - 1], PRESSURE_DEFAULT, 0, 0, points[0], PRESSURE_DEFAULT, 0, 0, distance);
00914 }
00915 }
00916 }
00917