diff options
Diffstat (limited to 'chalk/colorspaces/wet/kis_wetop.cpp')
-rw-r--r-- | chalk/colorspaces/wet/kis_wetop.cpp | 230 |
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)); +} |