summaryrefslogtreecommitdiffstats
path: root/chalk/core/kis_painter.cc
diff options
context:
space:
mode:
authorMichele Calgaro <michele.calgaro@yahoo.it>2021-05-23 20:48:35 +0900
committerMichele Calgaro <michele.calgaro@yahoo.it>2021-05-29 15:16:28 +0900
commit8b78a8791bc539bcffe7159f9d9714d577cb3d7d (patch)
tree1328291f966f19a22d7b13657d3f01a588eb1083 /chalk/core/kis_painter.cc
parent95834e2bdc5e01ae1bd21ac0dfa4fa1d2417fae9 (diff)
downloadkoffice-8b78a8791bc539bcffe7159f9d9714d577cb3d7d.tar.gz
koffice-8b78a8791bc539bcffe7159f9d9714d577cb3d7d.zip
Renaming of files in preparation for code style tools.
Signed-off-by: Michele Calgaro <michele.calgaro@yahoo.it>
Diffstat (limited to 'chalk/core/kis_painter.cc')
-rw-r--r--chalk/core/kis_painter.cc928
1 files changed, 0 insertions, 928 deletions
diff --git a/chalk/core/kis_painter.cc b/chalk/core/kis_painter.cc
deleted file mode 100644
index f3f5c928..00000000
--- a/chalk/core/kis_painter.cc
+++ /dev/null
@@ -1,928 +0,0 @@
-/*
- * Copyright (c) 2002 Patrick Julien <freak@codepimps.org>
- * Copyright (c) 2004 Boudewijn Rempt <boud@valdyas.org>
- * Copyright (c) 2004 Clarence Dang <dang@kde.org>
- * Copyright (c) 2004 Adrian Page <adrian@pagenet.plus.com>
- * Copyright (c) 2004 Cyrille Berger <cberger@cberger.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-#include <stdlib.h>
-#include <string.h>
-#include <cfloat>
-#include <cmath>
-#include <climits>
-#include <strings.h>
-
-#include "tqbrush.h"
-#include "tqfontinfo.h"
-#include "tqfontmetrics.h"
-#include "tqpen.h"
-#include "tqregion.h"
-#include "tqwmatrix.h"
-#include <tqimage.h>
-#include <tqmap.h>
-#include <tqpainter.h>
-#include <tqpixmap.h>
-#include <tqpointarray.h>
-#include <tqrect.h>
-#include <tqstring.h>
-
-#include <kdebug.h>
-#include <kcommand.h>
-#include <tdelocale.h>
-
-#include "kis_brush.h"
-#include "kis_debug_areas.h"
-#include "kis_image.h"
-#include "kis_layer.h"
-#include "kis_paint_device.h"
-#include "kis_painter.h"
-#include "kis_pattern.h"
-#include "kis_rect.h"
-#include "kis_colorspace.h"
-#include "kis_transaction.h"
-#include "kis_types.h"
-#include "kis_vec.h"
-#include "kis_iterators_pixel.h"
-#include "kis_paintop.h"
-#include "kis_selection.h"
-#include "kis_fill_painter.h"
-#include "kis_color.h"
-
-// Maximum distance from a Bezier control point to the line through the start
-// and end points for the curve to be considered flat.
-#define BEZIER_FLATNESS_THRESHOLD 0.5
-
-KisPainter::KisPainter()
-{
- init();
-}
-
-KisPainter::KisPainter(KisPaintDeviceSP device)
-{
- init();
- Q_ASSERT(device);
- begin(device);
-}
-
-void KisPainter::init()
-{
- m_transaction = 0;
- m_paintOp = 0;
- m_filter = 0;
- m_brush = 0;
- m_pattern= 0;
- m_opacity = OPACITY_OPAQUE;
- m_compositeOp = COMPOSITE_OVER;
- m_dab = 0;
- m_fillStyle = FillStyleNone;
- m_strokeStyle = StrokeStyleBrush;
- m_pressure = PRESSURE_MIN;
- m_duplicateHealing = false;
- m_duplicateHealingRadius = 10;
- m_duplicatePerspectiveCorrection = false;
- m_varyBrushSpacingWithPressureWhenDrawingALine = true;
-}
-
-KisPainter::~KisPainter()
-{
- m_brush = 0;
- delete m_paintOp;
- end();
-}
-
-void KisPainter::begin(KisPaintDeviceSP device)
-{
- if (!device) return;
-
- if (m_transaction)
- delete m_transaction;
-
- m_device = device;
- m_colorSpace = device->colorSpace();
- m_pixelSize = device->pixelSize();
-}
-
-KCommand *KisPainter::end()
-{
- return endTransaction();
-}
-
-void KisPainter::beginTransaction(const TQString& customName)
-{
- if (m_transaction)
- delete m_transaction;
- m_transaction = new KisTransaction(customName, m_device);
- TQ_CHECK_PTR(m_transaction);
-}
-
-void KisPainter::beginTransaction( KisTransaction* command)
-{
- if (m_transaction)
- delete m_transaction;
- m_transaction = command;
-}
-
-
-KCommand *KisPainter::endTransaction()
-{
- KCommand *command = m_transaction;
- m_transaction = 0;
- return command;
-}
-
-
-TQRect KisPainter::dirtyRect() {
- TQRect r = m_dirtyRect;
- m_dirtyRect = TQRect();
- return r;
-}
-
-void KisPainter::bitBlt(TQ_INT32 dx, TQ_INT32 dy,
- const KisCompositeOp& op,
- KisPaintDeviceSP srcdev,
- TQ_UINT8 opacity,
- TQ_INT32 sx, TQ_INT32 sy,
- TQ_INT32 sw, TQ_INT32 sh)
-{
- if (srcdev == 0) {
- return;
- }
-
- TQRect srcRect = TQRect(sx, sy, sw, sh);
-
- if (srcdev->extentIsValid() && op != COMPOSITE_COPY) {
- srcRect &= srcdev->extent();
- }
-
- if (srcRect.isEmpty()) {
- return;
- }
-
- dx += srcRect.x() - sx;
- dy += srcRect.y() - sy;
-
- sx = srcRect.x();
- sy = srcRect.y();
- sw = srcRect.width();
- sh = srcRect.height();
-
- addDirtyRect(TQRect(dx, dy, sw, sh));
-
- KisColorSpace * srcCs = srcdev->colorSpace();
-
- TQ_INT32 dstY = dy;
- TQ_INT32 srcY = sy;
- TQ_INT32 rowsRemaining = sh;
-
- while (rowsRemaining > 0) {
-
- TQ_INT32 dstX = dx;
- TQ_INT32 srcX = sx;
- TQ_INT32 columnsRemaining = sw;
- TQ_INT32 numContiguousDstRows = m_device->numContiguousRows(dstY, dstX, dstX + sw - 1);
- TQ_INT32 numContiguousSrcRows = srcdev->numContiguousRows(srcY, srcX, srcX + sw - 1);
-
- TQ_INT32 rows = TQMIN(numContiguousDstRows, numContiguousSrcRows);
- rows = TQMIN(rows, rowsRemaining);
-
- while (columnsRemaining > 0) {
-
- TQ_INT32 numContiguousDstColumns = m_device->numContiguousColumns(dstX, dstY, dstY + rows - 1);
- TQ_INT32 numContiguousSrcColumns = srcdev->numContiguousColumns(srcX, srcY, srcY + rows - 1);
-
- TQ_INT32 columns = TQMIN(numContiguousDstColumns, numContiguousSrcColumns);
- columns = TQMIN(columns, columnsRemaining);
-
- TQ_INT32 srcRowStride = srcdev->rowStride(srcX, srcY);
- //const TQ_UINT8 *srcData = srcdev->pixel(srcX, srcY);
- KisHLineIteratorPixel srcIt = srcdev->createHLineIterator(srcX, srcY, columns, false);
- const TQ_UINT8 *srcData = srcIt.rawData();
-
- //TQ_UINT8 *dstData = m_device->writablePixel(dstX, dstY);
- TQ_INT32 dstRowStride = m_device->rowStride(dstX, dstY);
- KisHLineIteratorPixel dstIt = m_device->createHLineIterator(dstX, dstY, columns, true);
- TQ_UINT8 *dstData = dstIt.rawData();
-
-
- m_colorSpace->bitBlt(dstData,
- dstRowStride,
- srcCs,
- srcData,
- srcRowStride,
- 0,
- 0,
- opacity,
- rows,
- columns,
- op);
-
- srcX += columns;
- dstX += columns;
- columnsRemaining -= columns;
- }
-
- srcY += rows;
- dstY += rows;
- rowsRemaining -= rows;
- }
-}
-
-void KisPainter::bltSelection(TQ_INT32 dx, TQ_INT32 dy,
- const KisCompositeOp &op,
- KisPaintDeviceSP srcdev,
- KisSelectionSP seldev,
- TQ_UINT8 opacity,
- TQ_INT32 sx, TQ_INT32 sy,
- TQ_INT32 sw, TQ_INT32 sh)
-{
- // Better use a probablistic method than a too slow one
- if (seldev->isProbablyTotallyUnselected(TQRect(dx, dy, sw, sh))) {
-/*
- kdDebug() << "Blitting outside selection rect\n";
-
- kdDebug() << "srcdev: " << srcdev << " (" << srcdev->name() << ")"
- << ", seldev: " << seldev << " (" << seldev->name() << ")"
- << ". dx, dy " << dx << "," << dy
- << ". sx, sy : sw, sy " << sx << "," << sy << " : " << sw << "," << sh << endl;
-*/
- return;
- }
- bltMask(dx,dy,op,srcdev,seldev.data(),opacity,sx,sy,sw,sh);
-}
-
-void KisPainter::bltMask(TQ_INT32 dx, TQ_INT32 dy,
- const KisCompositeOp &op,
- KisPaintDeviceSP srcdev,
- KisPaintDeviceSP seldev,
- TQ_UINT8 opacity,
- TQ_INT32 sx, TQ_INT32 sy,
- TQ_INT32 sw, TQ_INT32 sh)
-
-{
- if (srcdev == 0) return;
-
- if (seldev == 0) return;
-
- if (m_device == 0) return;
-
-
- TQRect srcRect = TQRect(sx, sy, sw, sh);
-
- if (srcdev->extentIsValid() && op != COMPOSITE_COPY) {
- srcRect &= srcdev->extent();
- }
-
- if (srcRect.isEmpty()) {
- return;
- }
-
- dx += srcRect.x() - sx;
- dy += srcRect.y() - sy;
-
- sx = srcRect.x();
- sy = srcRect.y();
- sw = srcRect.width();
- sh = srcRect.height();
-
- addDirtyRect(TQRect(dx, dy, sw, sh));
-
- KisColorSpace * srcCs = srcdev->colorSpace();
-
- TQ_INT32 dstY = dy;
- TQ_INT32 srcY = sy;
- TQ_INT32 rowsRemaining = sh;
-
- while (rowsRemaining > 0) {
-
- TQ_INT32 dstX = dx;
- TQ_INT32 srcX = sx;
- TQ_INT32 columnsRemaining = sw;
- TQ_INT32 numContiguousDstRows = m_device->numContiguousRows(dstY, dstX, dstX + sw - 1);
- TQ_INT32 numContiguousSrcRows = srcdev->numContiguousRows(srcY, srcX, srcX + sw - 1);
- TQ_INT32 numContiguousSelRows = seldev->numContiguousRows(dstY, dstX, dstX + sw - 1);
-
- TQ_INT32 rows = TQMIN(numContiguousDstRows, numContiguousSrcRows);
- rows = TQMIN(numContiguousSelRows, rows);
- rows = TQMIN(rows, rowsRemaining);
-
- while (columnsRemaining > 0) {
-
- TQ_INT32 numContiguousDstColumns = m_device->numContiguousColumns(dstX, dstY, dstY + rows - 1);
- TQ_INT32 numContiguousSrcColumns = srcdev->numContiguousColumns(srcX, srcY, srcY + rows - 1);
- TQ_INT32 numContiguousSelColumns = seldev->numContiguousColumns(dstX, dstY, dstY + rows - 1);
-
- TQ_INT32 columns = TQMIN(numContiguousDstColumns, numContiguousSrcColumns);
- columns = TQMIN(numContiguousSelColumns, columns);
- columns = TQMIN(columns, columnsRemaining);
-
- //TQ_UINT8 *dstData = m_device->writablePixel(dstX, dstY);
- TQ_INT32 dstRowStride = m_device->rowStride(dstX, dstY);
- KisHLineIteratorPixel dstIt = m_device->createHLineIterator(dstX, dstY, columns, true);
- TQ_UINT8 *dstData = dstIt.rawData();
-
- //const TQ_UINT8 *srcData = srcdev->pixel(srcX, srcY);
- TQ_INT32 srcRowStride = srcdev->rowStride(srcX, srcY);
- KisHLineIteratorPixel srcIt = srcdev->createHLineIterator(srcX, srcY, columns, false);
- const TQ_UINT8 *srcData = srcIt.rawData();
-
- //const TQ_UINT8 *selData = seldev->pixel(dstX, dstY);
- TQ_INT32 selRowStride = seldev->rowStride(dstX, dstY);
- KisHLineIteratorPixel selIt = seldev->createHLineIterator(dstX, dstY, columns, false);
- const TQ_UINT8 *selData = selIt.rawData();
-
- m_colorSpace->bitBlt(dstData,
- dstRowStride,
- srcCs,
- srcData,
- srcRowStride,
- selData,
- selRowStride,
- opacity,
- rows,
- columns,
- op);
-
- srcX += columns;
- dstX += columns;
- columnsRemaining -= columns;
- }
-
- srcY += rows;
- dstY += rows;
- rowsRemaining -= rows;
- }
-}
-
-
-void KisPainter::bltSelection(TQ_INT32 dx, TQ_INT32 dy,
- const KisCompositeOp& op,
- KisPaintDeviceSP srcdev,
- TQ_UINT8 opacity,
- TQ_INT32 sx, TQ_INT32 sy,
- TQ_INT32 sw, TQ_INT32 sh)
-{
- if (m_device == 0) return;
- if (!m_device->hasSelection()) {
- bitBlt(dx, dy, op, srcdev, opacity, sx, sy, sw, sh);
- }
- else
- bltSelection(dx,dy,op,srcdev, m_device->selection(),opacity,sx,sy,sw,sh);
-}
-
-double KisPainter::paintLine(const KisPoint & pos1,
- const double pressure1,
- const double xTilt1,
- const double yTilt1,
- const KisPoint & pos2,
- const double pressure2,
- const double xTilt2,
- const double yTilt2,
- const double inSavedDist)
-{
- if (!m_device) return 0;
- if (!m_paintOp) return 0;
- if (!m_brush) return 0;
-
- double savedDist = inSavedDist;
- KisVector2D end(pos2);
- KisVector2D start(pos1);
-
- KisVector2D dragVec = end - start;
- KisVector2D movement = dragVec;
-
- if (savedDist < 0) {
- m_paintOp->paintAt(pos1, KisPaintInformation(pressure1, xTilt1, yTilt1, movement));
- savedDist = 0;
- }
-
- double xSpacing = 0;
- double ySpacing = 0;
-
- if ( m_varyBrushSpacingWithPressureWhenDrawingALine ) {
- // XXX: The spacing should vary as the pressure changes along the
- // line.
- // This is a quick simplification.
- xSpacing = m_brush->xSpacing((pressure1 + pressure2) / 2);
- ySpacing = m_brush->ySpacing((pressure1 + pressure2) / 2);
- }
- else {
- xSpacing = m_brush->xSpacing( PRESSURE_DEFAULT );
- ySpacing = m_brush->ySpacing( PRESSURE_DEFAULT );
- }
-
- if (xSpacing < 0.5) {
- xSpacing = 0.5;
- }
- if (ySpacing < 0.5) {
- ySpacing = 0.5;
- }
-
- double xScale = 1;
- double yScale = 1;
- double spacing;
- // Scale x or y so that we effectively have a square brush
- // and calculate distance in that coordinate space. We reverse this scaling
- // before drawing the brush. This produces the correct spacing in both
- // x and y directions, even if the brush's aspect ratio is not 1:1.
- if (xSpacing > ySpacing) {
- yScale = xSpacing / ySpacing;
- spacing = xSpacing;
- }
- else {
- xScale = ySpacing / xSpacing;
- spacing = ySpacing;
- }
-
- dragVec.setX(dragVec.x() * xScale);
- dragVec.setY(dragVec.y() * yScale);
-
- double newDist = dragVec.length();
- double dist = savedDist + newDist;
- double l_savedDist = savedDist;
-
- if (dist < spacing) {
- return dist;
- }
-
- dragVec.normalize();
- KisVector2D step(0, 0);
-
- while (dist >= spacing) {
- if (l_savedDist > 0) {
- step += dragVec * (spacing - l_savedDist);
- l_savedDist -= spacing;
- }
- else {
- step += dragVec * spacing;
- }
-
- KisPoint p(start.x() + (step.x() / xScale), start.y() + (step.y() / yScale));
-
- double distanceMoved = step.length();
- double t = 0;
-
- if (newDist > DBL_EPSILON) {
- t = distanceMoved / newDist;
- }
-
- double pressure = (1 - t) * pressure1 + t * pressure2;
- double xTilt = (1 - t) * xTilt1 + t * xTilt2;
- double yTilt = (1 - t) * yTilt1 + t * yTilt2;
-
- m_paintOp->paintAt(p, KisPaintInformation(pressure, xTilt, yTilt, movement));
- dist -= spacing;
- }
-
- if (dist > 0)
- return dist;
- else
- return 0;
-}
-
-void KisPainter::paintPolyline (const vKisPoint &points,
- int index, int numPoints)
-{
- if (index >= (int) points.count ())
- return;
-
- if (numPoints < 0)
- numPoints = points.count ();
-
- if (index + numPoints > (int) points.count ())
- numPoints = points.count () - index;
-
-
- for (int i = index; i < index + numPoints - 1; i++)
- {
- paintLine (points [index], 0/*pressure*/, 0, 0, points [index + 1],
- 0/*pressure*/, 0, 0);
- }
-}
-
-void KisPainter::getBezierCurvePoints(const KisPoint &pos1,
- const KisPoint &control1,
- const KisPoint &control2,
- const KisPoint &pos2,
- vKisPoint& points)
-{
- double d1 = pointToLineDistance(control1, pos1, pos2);
- double d2 = pointToLineDistance(control2, pos1, pos2);
-
- if (d1 < BEZIER_FLATNESS_THRESHOLD && d2 < BEZIER_FLATNESS_THRESHOLD) {
- points.push_back(pos1);
- } else {
- // Midpoint subdivision. See Foley & Van Dam Computer Graphics P.508
- KisVector2D p1 = pos1;
- KisVector2D p2 = control1;
- KisVector2D p3 = control2;
- KisVector2D p4 = pos2;
-
- KisVector2D l2 = (p1 + p2) / 2;
- KisVector2D h = (p2 + p3) / 2;
- KisVector2D l3 = (l2 + h) / 2;
- KisVector2D r3 = (p3 + p4) / 2;
- KisVector2D r2 = (h + r3) / 2;
- KisVector2D l4 = (l3 + r2) / 2;
- KisVector2D r1 = l4;
- KisVector2D l1 = p1;
- KisVector2D r4 = p4;
-
- getBezierCurvePoints(l1.toKisPoint(), l2.toKisPoint(), l3.toKisPoint(), l4.toKisPoint(), points);
- getBezierCurvePoints(r1.toKisPoint(), r2.toKisPoint(), r3.toKisPoint(), r4.toKisPoint(), points);
- }
-}
-
-double KisPainter::paintBezierCurve(const KisPoint &pos1,
- const double pressure1,
- const double xTilt1,
- const double yTilt1,
- const KisPoint &control1,
- const KisPoint &control2,
- const KisPoint &pos2,
- const double pressure2,
- const double xTilt2,
- const double yTilt2,
- const double savedDist)
-{
- double newDistance;
- double d1 = pointToLineDistance(control1, pos1, pos2);
- double d2 = pointToLineDistance(control2, pos1, pos2);
-
- if (d1 < BEZIER_FLATNESS_THRESHOLD && d2 < BEZIER_FLATNESS_THRESHOLD) {
- newDistance = paintLine(pos1, pressure1, xTilt1, yTilt1, pos2, pressure2, xTilt2, yTilt2, savedDist);
- } else {
- // Midpoint subdivision. See Foley & Van Dam Computer Graphics P.508
- KisVector2D p1 = pos1;
- KisVector2D p2 = control1;
- KisVector2D p3 = control2;
- KisVector2D p4 = pos2;
-
- KisVector2D l2 = (p1 + p2) / 2;
- KisVector2D h = (p2 + p3) / 2;
- KisVector2D l3 = (l2 + h) / 2;
- KisVector2D r3 = (p3 + p4) / 2;
- KisVector2D r2 = (h + r3) / 2;
- KisVector2D l4 = (l3 + r2) / 2;
- KisVector2D r1 = l4;
- KisVector2D l1 = p1;
- KisVector2D r4 = p4;
-
- double midPressure = (pressure1 + pressure2) / 2;
- double midXTilt = (xTilt1 + xTilt2) / 2;
- double midYTilt = (yTilt1 + yTilt2) / 2;
-
- newDistance = paintBezierCurve(l1.toKisPoint(), pressure1, xTilt1, yTilt1,
- l2.toKisPoint(), l3.toKisPoint(),
- l4.toKisPoint(), midPressure, midXTilt, midYTilt,
- savedDist);
- newDistance = paintBezierCurve(r1.toKisPoint(), midPressure, midXTilt, midYTilt,
- r2.toKisPoint(),
- r3.toKisPoint(),
- r4.toKisPoint(), pressure2, xTilt2, yTilt2, newDistance);
- }
-
- return newDistance;
-}
-
-void KisPainter::paintRect (const KisPoint &startPoint,
- const KisPoint &endPoint,
- const double /*pressure*/,
- const double /*xTilt*/,
- const double /*yTilt*/)
-{
- KoRect normalizedRect = KisRect (startPoint, endPoint).normalize ();
-
- vKisPoint points;
-
- points.push_back(normalizedRect.topLeft());
- points.push_back(normalizedRect.bottomLeft());
- points.push_back(normalizedRect.bottomRight());
- points.push_back(normalizedRect.topRight());
-
- paintPolygon(points);
-}
-
-void KisPainter::paintEllipse (const KisPoint &startPoint,
- const KisPoint &endPoint,
- const double /*pressure*/,
- const double /*xTilt*/,
- const double /*yTilt*/)
-{
- KisRect r = KisRect(startPoint, endPoint).normalize();
-
- // See http://www.whizkidtech.redprince.net/bezier/circle/ for explanation.
- // kappa = (4/3*(sqrt(2)-1))
- const double kappa = 0.5522847498;
- const double lx = (r.width() / 2) * kappa;
- const double ly = (r.height() / 2) * kappa;
-
- KisPoint center = r.center();
-
- KisPoint p0(r.left(), center.y());
- KisPoint p1(r.left(), center.y() - ly);
- KisPoint p2(center.x() - lx, r.top());
- KisPoint p3(center.x(), r.top());
-
- vKisPoint points;
-
- getBezierCurvePoints(p0, p1, p2, p3, points);
-
- KisPoint p4(center.x() + lx, r.top());
- KisPoint p5(r.right(), center.y() - ly);
- KisPoint p6(r.right(), center.y());
-
- getBezierCurvePoints(p3, p4, p5, p6, points);
-
- KisPoint p7(r.right(), center.y() + ly);
- KisPoint p8(center.x() + lx, r.bottom());
- KisPoint p9(center.x(), r.bottom());
-
- getBezierCurvePoints(p6, p7, p8, p9, points);
-
- KisPoint p10(center.x() - lx, r.bottom());
- KisPoint p11(r.left(), center.y() + ly);
-
- getBezierCurvePoints(p9, p10, p11, p0, points);
-
- paintPolygon(points);
-}
-
-void KisPainter::paintAt(const KisPoint & pos,
- const double pressure,
- const double xTilt,
- const double yTilt)
-{
- if (!m_paintOp) return;
- m_paintOp->paintAt(pos, KisPaintInformation(pressure, xTilt, yTilt, KisVector2D()));
-}
-
-double KisPainter::pointToLineDistance(const KisPoint& p, const KisPoint& l0, const KisPoint& l1)
-{
- double lineLength = sqrt((l1.x() - l0.x()) * (l1.x() - l0.x()) + (l1.y() - l0.y()) * (l1.y() - l0.y()));
- double distance = 0;
-
- if (lineLength > DBL_EPSILON) {
- distance = ((l0.y() - l1.y()) * p.x() + (l1.x() - l0.x()) * p.y() + l0.x() * l1.y() - l1.x() * l0.y()) / lineLength;
- distance = fabs(distance);
- }
-
- return distance;
-}
-
-/*
- * Concave Polygon Scan Conversion
- * by Paul Heckbert
- * from "Graphics Gems", Academic Press, 1990
- */
-
-/*
- * concave: scan convert nvert-sided concave non-simple polygon with vertices at
- * (point[i].x, point[i].y) for i in [0..nvert-1] within the window win by
- * calling spanproc for each visible span of pixels.
- * Polygon can be clockwise or counterclockwise.
- * Algorithm does uniform point sampling at pixel centers.
- * Inside-outside test done by Jordan's rule: a point is considered inside if
- * an emanating ray intersects the polygon an odd number of times.
- * drawproc should fill in pixels from xl to xr inclusive on scanline y,
- * e.g:
- * drawproc(y, xl, xr)
- * int y, xl, xr;
- * {
- * int x;
- * for (x=xl; x<=xr; x++)
- * pixel_write(x, y, pixelvalue);
- * }
- *
- * Paul Heckbert 30 June 81, 18 Dec 89
- */
-
-typedef struct { /* a polygon edge */
- double x; /* x coordinate of edge's intersection with current scanline */
- double dx; /* change in x with respect to y */
- int i; /* edge number: edge i goes from pt[i] to pt[i+1] */
-} Edge;
-
-static int n; /* number of vertices */
-static const KisPoint *pt; /* vertices */
-
-static int nact; /* number of active edges */
-static Edge *active; /* active edge list:edges crossing scanline y */
-
-/* comparison routines for qsort */
-static int compare_ind(const void *pu, const void *pv)
-{
- const int *u = static_cast<const int *>(pu);
- const int *v = static_cast<const int *>(pv);
-
- return pt[*u].y() <= pt[*v].y() ? -1 : 1;
-}
-
-static int compare_active(const void *pu, const void *pv)
-{
- const Edge *u = static_cast<const Edge *>(pu);
- const Edge *v = static_cast<const Edge *>(pv);
-
- return u->x <= v->x ? -1 : 1;
-}
-
-static void cdelete(int i) /* remove edge i from active list */
-{
- int j;
-
- for (j=0; j<nact && active[j].i!=i; j++);
- if (j>=nact) return; /* edge not in active list; happens at win->y0*/
- nact--;
- bcopy(&active[j+1], &active[j], (nact-j)*sizeof active[0]);
-}
-
-static void cinsert(int i, int y) /* append edge i to end of active list */
-{
- int j;
- double dx;
- const KisPoint *p, *q;
-
- j = i<n-1 ? i+1 : 0;
- if (pt[i].y() < pt[j].y()) {
- p = &pt[i]; q = &pt[j];
- } else {
- p = &pt[j]; q = &pt[i];
- }
- /* initialize x position at intersection of edge with scanline y */
- active[nact].dx = dx = (q->x()-p->x())/(q->y()-p->y());
- active[nact].x = dx*(y+.5-p->y())+p->x();
- active[nact].i = i;
- nact++;
-}
-
-void KisPainter::fillPolygon(const vKisPoint& points, FillStyle fillStyle)
-{
- int nvert = points.count();
- int k, y0, y1, y, i, j, xl, xr;
- int *ind; /* list of vertex indices, sorted by pt[ind[j]].y */
-
- n = nvert;
- pt = &(points[0]);
- if (n<3) return;
- if (fillStyle == FillStyleNone) {
- return;
- }
-
- ind = new int[n];
- TQ_CHECK_PTR(ind);
- active = new Edge[n];
- TQ_CHECK_PTR(active);
-
- /* create y-sorted array of indices ind[k] into vertex list */
- for (k=0; k<n; k++)
- ind[k] = k;
- qsort(ind, n, sizeof ind[0], compare_ind); /* sort ind by pt[ind[k]].y */
-
- nact = 0; /* start with empty active list */
- k = 0; /* ind[k] is next vertex to process */
- y0 = static_cast<int>(ceil(pt[ind[0]].y()-.5)); /* ymin of polygon */
- y1 = static_cast<int>(floor(pt[ind[n-1]].y()-.5)); /* ymax of polygon */
-
- int x0 = INT_MAX;
- int x1 = INT_MIN;
-
- for (int i = 0; i < nvert; i++) {
- int pointHighX = static_cast<int>(ceil(points[i].x() - 0.5));
- int pointLowX = static_cast<int>(floor(points[i].x() - 0.5));
-
- if (pointLowX < x0) {
- x0 = pointLowX;
- }
- if (pointHighX > x1) {
- x1 = pointHighX;
- }
- }
-
- // Fill the polygon bounding rectangle with the required contents then we'll
- // create a mask for the actual polygon coverage.
-
- KisPaintDeviceSP polygon = new KisPaintDevice(m_device->colorSpace(), "polygon");
- TQ_CHECK_PTR(polygon);
-
- KisFillPainter fillPainter(polygon);
- TQRect boundingRectangle(x0, y0, x1 - x0 + 1, y1 - y0 + 1);
-
- // Clip to the image bounds.
- if (m_device->image()) {
- boundingRectangle &= m_device->image()->bounds();
- }
-
- switch (fillStyle) {
- default:
- // Fall through
- case FillStyleGradient:
- // Currently unsupported, fall through
- case FillStyleStrokes:
- // Currently unsupported, fall through
- kdWarning(DBG_AREA_CORE) << "Unknown or unsupported fill style in fillPolygon\n";
- case FillStyleForegroundColor:
- fillPainter.fillRect(boundingRectangle, paintColor(), OPACITY_OPAQUE);
- break;
- case FillStyleBackgroundColor:
- fillPainter.fillRect(boundingRectangle, backgroundColor(), OPACITY_OPAQUE);
- break;
- case FillStylePattern:
- Q_ASSERT(m_pattern != 0);
- fillPainter.fillRect(boundingRectangle, m_pattern);
- break;
- }
-
- KisSelectionSP polygonMask = new KisSelection(polygon);
-
- for (y=y0; y<=y1; y++) { /* step through scanlines */
- /* scanline y is at y+.5 in continuous coordinates */
-
- /* check vertices between previous scanline and current one, if any */
- for (; k<n && pt[ind[k]].y()<=y+.5; k++) {
- /* to simplify, if pt.y=y+.5, pretend it's above */
- /* invariant: y-.5 < pt[i].y <= y+.5 */
- i = ind[k];
- /*
- * insert or delete edges before and after vertex i (i-1 to i,
- * and i to i+1) from active list if they cross scanline y
- */
- j = i>0 ? i-1 : n-1; /* vertex previous to i */
- if (pt[j].y() <= y-.5) /* old edge, remove from active list */
- cdelete(j);
- else if (pt[j].y() > y+.5) /* new edge, add to active list */
- cinsert(j, y);
- j = i<n-1 ? i+1 : 0; /* vertex next after i */
- if (pt[j].y() <= y-.5) /* old edge, remove from active list */
- cdelete(i);
- else if (pt[j].y() > y+.5) /* new edge, add to active list */
- cinsert(i, y);
- }
-
- /* sort active edge list by active[j].x */
- qsort(active, nact, sizeof active[0], compare_active);
-
- /* draw horizontal segments for scanline y */
- for (j=0; j<nact; j+=2) { /* draw horizontal segments */
- /* span 'tween j & j+1 is inside, span tween j+1 & j+2 is outside */
- xl = static_cast<int>(ceil(active[j].x-.5)); /* left end of span */
- xr = static_cast<int>(floor(active[j+1].x-.5)); /* right end of span */
-
- if (xl<=xr) {
- KisHLineIterator it = polygonMask->createHLineIterator(xl, y, xr - xl + 1, true);
-
- while (!it.isDone()) {
- // We're using a selection here, that means alpha colorspace, that means one byte.
- it.rawData()[0] = MAX_SELECTED;
- ++it;
- }
- }
-
- active[j].x += active[j].dx; /* increment edge coords */
- active[j+1].x += active[j+1].dx;
- }
- }
- delete [] ind;
- delete [] active;
-
- polygon->applySelectionMask(polygonMask);
-
- TQRect r = polygon->extent();
-
- // The strokes for the outline may have already added updated the dirtyrect, but it can't hurt,
- // and if we're painting without outlines, then there will be no dirty rect. Let's do it ourselves...
- // addDirtyRect( r ); // XXX the bltSelection will add to the dirtyrect
-
- bltSelection(r.x(), r.y(), compositeOp(), polygon, opacity(), r.x(), r.y(), r.width(), r.height());
-}
-
-void KisPainter::paintPolygon(const vKisPoint& points)
-{
- if (m_fillStyle != FillStyleNone) {
- fillPolygon(points, m_fillStyle);
- }
-
- if (m_strokeStyle != StrokeStyleNone) {
- if (points.count() > 1) {
- double distance = -1;
-
- for (uint i = 0; i < points.count() - 1; i++) {
- distance = paintLine(points[i], PRESSURE_DEFAULT, 0, 0, points[i + 1], PRESSURE_DEFAULT, 0, 0, distance);
- }
- paintLine(points[points.count() - 1], PRESSURE_DEFAULT, 0, 0, points[0], PRESSURE_DEFAULT, 0, 0, distance);
- }
- }
-}
-