/* * Copyright (c) 2005 Boudewijn Rempt * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #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(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(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(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(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(it.rawData())) = currentPack; } ++dabIt; ++it; } } m_painter->addDirtyRect(TQRect(xStart, yStart, maskW, maskH)); }