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