summaryrefslogtreecommitdiffstats
path: root/chalk/colorspaces/wet/kis_wetop.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'chalk/colorspaces/wet/kis_wetop.cpp')
-rw-r--r--chalk/colorspaces/wet/kis_wetop.cpp230
1 files changed, 230 insertions, 0 deletions
diff --git a/chalk/colorspaces/wet/kis_wetop.cpp b/chalk/colorspaces/wet/kis_wetop.cpp
new file mode 100644
index 000000000..15625e5d3
--- /dev/null
+++ b/chalk/colorspaces/wet/kis_wetop.cpp
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2005 Boudewijn Rempt <boud@valdyas.org>
+ *
+ * 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 <tqrect.h>
+#include <tqcheckbox.h>
+
+#include <kdebug.h>
+
+#include <kis_brush.h>
+#include <kis_debug_areas.h>
+#include <kis_paint_device.h>
+#include <kis_painter.h>
+#include <kis_types.h>
+#include <kis_paintop.h>
+#include <kis_iterators_pixel.h>
+#include <kis_layer.h>
+#include <kis_meta_registry.h>
+#include <kis_colorspace_factory_registry.h>
+#include "kis_input_device.h"
+
+#include "kis_wetop.h"
+#include "kis_wet_colorspace.h"
+
+KisWetOpSettings::KisWetOpSettings(TQWidget *parent)
+ : super(parent)
+{
+ m_options = new WetPaintOptions(parent, "wet option widget");
+}
+
+bool KisWetOpSettings::varySize() const
+{
+ return m_options->checkSize->isChecked();
+}
+
+bool KisWetOpSettings::varyWetness() const
+{
+ return m_options->checkWetness->isChecked();
+}
+
+bool KisWetOpSettings::varyStrength() const
+{
+ return m_options->checkStrength->isChecked();
+}
+
+KisPaintOp * KisWetOpFactory::createOp(const KisPaintOpSettings *settings, KisPainter * painter)
+{
+ const KisWetOpSettings *wetopSettings = dynamic_cast<const KisWetOpSettings *>(settings);
+ Q_ASSERT(settings == 0 || wetopSettings != 0);
+
+ KisPaintOp * op = new KisWetOp(wetopSettings, painter);
+ TQ_CHECK_PTR(op);
+ return op;
+}
+
+KisPaintOpSettings* KisWetOpFactory::settings(TQWidget * parent, const KisInputDevice& inputDevice)
+{
+ if (inputDevice == KisInputDevice::mouse()) {
+ // No options for mouse, only tablet devices
+ return 0;
+ } else {
+ return new KisWetOpSettings(parent);
+ }
+}
+
+KisWetOp::KisWetOp(const KisWetOpSettings * settings, KisPainter * painter)
+ : super(painter)
+{
+ if (settings) {
+ m_size = settings->varySize();
+ m_wetness = settings->varyWetness();
+ m_strength = settings->varyStrength();
+ } else {
+ m_size = false;
+ m_wetness = false;
+ m_strength = false;
+ }
+}
+
+KisWetOp::~KisWetOp()
+{
+}
+
+void KisWetOp::paintAt(const KisPoint &pos, const KisPaintInformation& info)
+{
+ if (!m_painter) return;
+
+ if (!m_painter->device()) return;
+ KisPaintDeviceSP device = m_painter->device();
+ if (!m_painter->device()) return;
+
+ KisBrush *brush = m_painter->brush();
+ Q_ASSERT(brush);
+
+ if (! brush->canPaintFor(info) )
+ return;
+
+ KisPaintInformation inf(info);
+
+ if (!m_size)
+ inf.pressure = PRESSURE_DEFAULT;
+
+ KisPaintDeviceSP dab = 0;
+
+ if (brush->brushType() == IMAGE || brush->brushType() == PIPE_IMAGE) {
+ dab = brush->image(KisMetaRegistry::instance()->csRegistry()->getAlpha8(), inf);
+ }
+ else {
+ KisAlphaMaskSP mask = brush->mask(inf);
+ dab = computeDab(mask, KisMetaRegistry::instance()->csRegistry()->getAlpha8());
+ }
+
+ KisColorSpace * cs = device->colorSpace();
+
+ if (cs->id() != KisID("WET","")) {
+ kdDebug(DBG_AREA_CMS) << "You cannot paint wet paint on dry pixels.\n";
+ return;
+ }
+
+ KisColor paintColor = m_painter->paintColor();
+ paintColor.convertTo(cs);
+ // hopefully this does
+ // nothing, conversions are bad ( wet->rgb->wet gives horrible mismatches, due to
+ // the conversion to rgb actually rendering the paint above white
+
+ WetPack* paintPack = reinterpret_cast<WetPack*>(paintColor.data());
+ WetPix paint = paintPack->paint;
+
+ // Get the paint info (we store the strength in the otherwise unused (?) height field of
+ // the paint
+ // double wetness = paint.w; // XXX: Was unused
+ // strength is a double in the 0 - 2 range, but upscaled to TQ_UINT16:
+ //kdDebug() << "Original strength as in paint.h: " << paint.h << endl;
+
+ double strength = 2.0 * static_cast<double>(paint.h) / (double)(0xffff);
+
+ //kdDebug() << "Before strength: " << strength << endl;
+
+ if (m_strength)
+ strength = strength * (strength + info.pressure) * 0.5;
+ else
+ strength = strength * (strength + PRESSURE_DEFAULT) * 0.5;
+
+ double pressure = 0.75 + 0.25 * info.pressure;
+
+ //kdDebug() << "info.pressure " << info.pressure << ", local pressure: " << pressure << ", strength: " << strength << endl;
+
+ WetPack currentPack;
+ WetPix currentPix;
+ double eff_height;
+ double press, contact;
+
+ int maskW = brush->maskWidth(inf);
+ int maskH = brush->maskHeight(inf);
+ KoPoint dest = (pos - (brush->hotSpot(inf)));
+ int xStart = (int)dest.x();
+ int yStart = (int)dest.y();
+
+ for (int y = 0; y < maskH; y++) {
+ KisHLineIteratorPixel dabIt = dab->createHLineIterator(0, y, maskW, false);
+ KisHLineIteratorPixel it = device->createHLineIterator(xStart, yStart+y, maskW, true);
+
+ while (!dabIt.isDone()) {
+ // This only does something with .paint, and not with adsorb.
+ currentPack = *(reinterpret_cast<WetPack*>(it.rawData()));
+ WetPix currentData = currentPack.adsorb;
+ currentPix = currentPack.paint;
+
+ // Hardcoded threshold for the dab 'strength': above it, it will get painted
+ if (*dabIt.rawData() > 125)
+ press = pressure * 0.25;
+ else
+ press = -1;
+ //kdDebug() << "After mysterious line, press becomes: " << press << ", this is the same as in the orignal. Good" << endl;
+ // XXX - 192 is probably only useful for paper with a texture...
+ eff_height = (currentData.h + currentData.w - 192.0) * (1.0 / 255.0);
+ contact = (press + eff_height) * 0.2;
+ double old_contact = contact;
+ if (contact > 0.5)
+ contact = 1.0 - 0.5 * exp(-2.0 * contact - 1.0);
+
+ //kdDebug() << "Contact was " << old_contact << " and has become: " << contact << endl;
+ if (contact > 0.0001) {
+ int v;
+ double rnd = rand() * (1.0 / RAND_MAX);
+
+ v = currentPix.rd;
+ currentPix.rd = floor(v + (paint.rd * strength - v) * contact + rnd);
+ //kdDebug() << "Rd was " << v << " and has become " << currentPix.rd << endl;
+ v = currentPix.rw;
+ currentPix.rw = floor(v + (paint.rw * strength - v) * contact + rnd);
+ v = currentPix.gd;
+ currentPix.gd = floor(v + (paint.gd * strength - v) * contact + rnd);
+ v = currentPix.gw;
+ currentPix.gw = floor(v + (paint.gw * strength - v) * contact + rnd);
+ v = currentPix.bd;
+ currentPix.bd = floor(v + (paint.bd * strength - v) * contact + rnd);
+ v = currentPix.bw;
+ currentPix.bw = floor(v + (paint.bw * strength - v) * contact + rnd);
+ v = currentPix.w;
+ if (m_wetness)
+ currentPix.w = (CLAMP(floor(
+ v + (paint.w * (0.5 + pressure) - v) * contact + rnd), 0, 512));
+ else
+ currentPix.w = floor(v + (paint.w - v) * contact + rnd);
+
+ currentPack.paint = currentPix;
+ *(reinterpret_cast<WetPack*>(it.rawData())) = currentPack;
+ }
+ ++dabIt;
+ ++it;
+ }
+ }
+
+ m_painter->addDirtyRect(TQRect(xStart, yStart, maskW, maskH));
+}