KOffice – TDE office suite
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

151 lines
5.1KB

  1. /*
  2. * Copyright (c) 2002 Patrick Julien <freak@codepimps.org>
  3. * Copyright (c) 2004 Boudewijn Rempt <boud@valdyas.org>
  4. * Copyright (c) 2004 Clarence Dang <dang@kde.org>
  5. * Copyright (c) 2004 Adrian Page <adrian@pagenet.plus.com>
  6. * Copyright (c) 2004 Cyrille Berger <cberger@cberger.net>
  7. *
  8. * This program is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation; either version 2 of the License, or
  11. * (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, write to the Free Software
  20. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  21. */
  22. #include <tqrect.h>
  23. #include <kdebug.h>
  24. #include "kis_vec.h"
  25. #include "kis_brush.h"
  26. #include "kis_global.h"
  27. #include "kis_paint_device.h"
  28. #include "kis_painter.h"
  29. #include "kis_types.h"
  30. #include "kis_paintop.h"
  31. #include "kis_layer.h"
  32. #include "kis_selection.h"
  33. #include "kis_airbrushop.h"
  34. KisPaintOp * KisAirbrushOpFactory::createOp(const KisPaintOpSettings */*settings*/, KisPainter * painter)
  35. {
  36. KisPaintOp * op = new KisAirbrushOp(painter);
  37. Q_CHECK_PTR(op);
  38. return op;
  39. }
  40. KisAirbrushOp::KisAirbrushOp(KisPainter * painter)
  41. : super(painter)
  42. {
  43. }
  44. KisAirbrushOp::~KisAirbrushOp()
  45. {
  46. }
  47. void KisAirbrushOp::paintAt(const KisPoint &pos, const KisPaintInformation& info)
  48. {
  49. // See: http://www.sysf.physto.se/~klere/airbrush/ for information
  50. // about _real_ airbrushes.
  51. //
  52. // Most graphics apps -- especially the simple ones like Kolourpaint
  53. // and the previous version of this routine in Chalk took a brush
  54. // shape -- often a simple ellipse -- and filled that shape with a
  55. // random 'spray' of single pixels.
  56. //
  57. // Other, more advanced graphics apps, like the Gimp or Photoshop,
  58. // take the brush shape and paint just as with the brush paint op,
  59. // only making the initial dab more transparent, and perhaps adding
  60. // extra transparence near the edges. Then, using a timer, when the
  61. // cursor stays in place, dab upon dab is positioned in the same
  62. // place, which makes the result less and less transparent.
  63. //
  64. // What I want to do here is create an airbrush that approaches a real
  65. // one. It won't use brush shapes, instead going for the old-fashioned
  66. // circle. Depending upon pressure, both the size of the dab and the
  67. // rate of paint deposition is determined. The edges of the dab are
  68. // more transparent than the center, with perhaps even some fully
  69. // transparent pixels between the near-transparent pixels.
  70. //
  71. // By pressing some to-be-determined key at the same time as pressing
  72. // mouse-down, one edge of the dab is made straight, to simulate
  73. // working with a shield.
  74. //
  75. // Tilt may be used to make the gradients more realistic, but I don't
  76. // have a tablet that supports tilt.
  77. //
  78. // Anyway, it's exactly twenty years ago that I have held a real
  79. // airbrush, for the first and up to now the last time...
  80. //
  81. if (!m_painter) return;
  82. KisPaintDeviceSP device = m_painter->device();
  83. // For now: use the current brush shape -- it beats calculating
  84. // ellipes and cones, and it shows the working of the timer.
  85. if (!device) return;
  86. KisBrush * brush = m_painter->brush();
  87. if (! brush->canPaintFor(info) )
  88. return;
  89. KisPaintDeviceSP dab = m_painter->dab();
  90. KisPoint hotSpot = brush->hotSpot(info);
  91. KisPoint pt = pos - hotSpot;
  92. TQ_INT32 x;
  93. double xFraction;
  94. TQ_INT32 y;
  95. double yFraction;
  96. splitCoordinate(pt.x(), &x, &xFraction);
  97. splitCoordinate(pt.y(), &y, &yFraction);
  98. if (brush->brushType() == IMAGE || brush->brushType() == PIPE_IMAGE) {
  99. dab = brush->image(device->colorSpace(), info, xFraction, yFraction);
  100. }
  101. else {
  102. KisAlphaMaskSP mask = brush->mask(info, xFraction, yFraction);
  103. dab = computeDab(mask);
  104. }
  105. m_painter->setDab(dab); // Cache dab for future paints in the painter.
  106. m_painter->setPressure(info.pressure); // Cache pressure in the current painter.
  107. TQRect dabRect = TQRect(0, 0, brush->maskWidth(info), brush->maskHeight(info));
  108. TQRect dstRect = TQRect(x, y, dabRect.width(), dabRect.height());
  109. KisImage * image = device->image();
  110. if (image != 0) {
  111. dstRect &= image->bounds();
  112. }
  113. if (dstRect.isNull() || dstRect.isEmpty() || !dstRect.isValid()) return;
  114. TQ_INT32 sx = dstRect.x() - x;
  115. TQ_INT32 sy = dstRect.y() - y;
  116. TQ_INT32 sw = dstRect.width();
  117. TQ_INT32 sh = dstRect.height();
  118. if (m_source->hasSelection()) {
  119. m_painter->bltSelection(dstRect.x(), dstRect.y(), m_painter->compositeOp(), dab.data(),
  120. m_source->selection(), m_painter->opacity(), sx, sy, sw, sh);
  121. }
  122. else {
  123. m_painter->bitBlt(dstRect.x(), dstRect.y(), m_painter->compositeOp(), dab.data(), m_painter->opacity(), sx, sy, sw, sh);
  124. }
  125. m_painter->addDirtyRect(dstRect);
  126. }