|
- /*
- * 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 <limits.h>
- #include <stdlib.h>
-
- #include <config.h>
- #include LCMS_HEADER
-
- #include <tqimage.h>
-
- #include <tdelocale.h>
- #include <kdebug.h>
-
- #include "kis_color_conversions.h"
- #include "kis_abstract_colorspace.h"
- #include "kis_colorspace_registry.h"
- #include "kis_image.h"
- #include "kis_wet_sticky_colorspace.h"
- #include "kis_integer_maths.h"
- #include "kis_types.h"
- #include "kis_channelinfo.h"
-
- #define NOWSDEBUG
-
- using namespace WetAndSticky;
-
- enum WetStickyChannelIndex {
- BLUE_CHANNEL_INDEX,
- GREEN_CHANNEL_INDEX,
- RED_CHANNEL_INDEX,
- ALPHA_CHANNEL_INDEX,
- HUE_CHANNEL_INDEX,
- SATURATION_CHANNEL_INDEX,
- LIGHTNESS_CHANNEL_INDEX,
- LIQUID_CONTENT_CHANNEL_INDEX,
- DRYING_RATE_CHANNEL_INDEX,
- MISCIBILITY_CHANNEL_INDEX,
- GRAVITATIONAL_DIRECTION_INDEX,
- GRAVITATIONAL_STRENGTH_CHANNEL_INDEX,
- ABSORBANCY_CHANNEL_INDEX,
- PAINT_VOLUME_CHANNEL_INDEX
- };
-
- KisWetStickyColorSpace::KisWetStickyColorSpace() :
- KisAbstractColorSpace(KisID("W&S", i18n("Wet & Sticky")), 0, icMaxEnumData)
- {
- TQ_INT32 pos = 0;
-
- // Basic representational definition
- m_channels.push_back(new KisChannelInfo(i18n("Blue"), "B", pos, COLOR, 1));
- m_channels.push_back(new KisChannelInfo(i18n("Green"), "G", ++pos, COLOR, 1));
- m_channels.push_back(new KisChannelInfo(i18n("Red"), "R", ++pos, COLOR, 1));
- m_channels.push_back(new KisChannelInfo(i18n("Alpha"), "A", ++pos, ALPHA, 1));
-
- // Paint definition
- m_channels.push_back(new KisChannelInfo(i18n("Hue"), "H", ++pos, COLOR, sizeof(float)));
- m_channels.push_back(new KisChannelInfo(i18n("Saturation"), "S", pos+=sizeof(float) , COLOR, sizeof(float)));
- m_channels.push_back(new KisChannelInfo(i18n("Lightness"), "L", pos+=sizeof(float), COLOR, sizeof(float)));
-
- m_channels.push_back(new KisChannelInfo(i18n("Liquid Content"), "Q", pos+=sizeof(float), SUBSTANCE, 1));
- m_channels.push_back(new KisChannelInfo(i18n("Drying Rate"), "D", ++pos, SUBSTANCE, 1));
- m_channels.push_back(new KisChannelInfo(i18n("Miscibility"), "M", ++pos, SUBSTANCE, 1));
-
- // Substrate definition
- m_channels.push_back(new KisChannelInfo(i18n("Gravitational Direction"), "Gd", ++pos, SUBSTRATE, sizeof(enumDirection)));
- m_channels.push_back(new KisChannelInfo(i18n("Gravitational Strength"), "Gs", pos+=sizeof(enumDirection), SUBSTRATE, 1));
-
- m_channels.push_back(new KisChannelInfo(i18n("Absorbency"), "Ad", ++pos, SUBSTRATE, 1));
- m_channels.push_back(new KisChannelInfo(i18n("Paint Volume"), "V", ++pos, SUBSTANCE, 1));
-
- m_alphaPos = 3;
- m_alphaSize = 1;
- setDefaultProfile( 0 );
-
- #ifdef WSDEBUG
- TQValueVector<KisChannelInfo *>_it it;
- int i = 0;
- for (it = m_channels.begin(); it != m_channels.end(); ++it)
- {
- KisChannelInfo * ch = (*it);
- kdDebug(DBG_AREA_CMS) << "Channel: " << ch->name() << ", " << ch->pos() << ", " << i << "\n";
- ++i;
- }
-
- kdDebug(DBG_AREA_CMS) << "Size of cell: " << sizeof(CELL) << "\n";
- #endif
- }
-
-
- KisWetStickyColorSpace::~KisWetStickyColorSpace()
- {
- }
-
- void KisWetStickyColorSpace::fromTQColor(const TQColor& c, TQ_UINT8 *dst, KisProfile * profile)
- {
- CELL_PTR p = (CELL_PTR) dst;
- TQ_UINT8 r, g, b;
-
- r = c.red();
- g = c.green();
- b = c.blue();
-
- p -> red = r;
- p -> green = g;
- p -> blue = b;
- p -> alpha = OPACITY_OPAQUE;
-
- rgb_to_hls(r, g, b, &p->hue, &p->lightness, &p->saturation);
-
- p -> liquid_content = 0;
- p -> drying_rate = 0;
- p -> miscibility = 0;
-
- p -> direction = DOWN;
- p -> strength = 10;
-
- p -> absorbancy = 10;
- p -> volume = 0;
-
- #ifdef WSDEBUG
- kdDebug(DBG_AREA_CMS) << "qcolor: "
- << " r: " << c.red() << " b: " << c.blue() << " g: " << c.red()
- << " native color: (" << TQString().setNum(p->red) << ", "
- << TQString().setNum(p->green) << ", "
- << TQString().setNum(p->blue) << ", "
- << TQString().setNum(p->alpha) << ") "
- << ", hls: (" << p->hue << ", "
- << p->lightness << ", "
- << p->saturation << ")\n";
- #endif
- }
-
- void KisWetStickyColorSpace::fromTQColor(const TQColor& c, TQ_UINT8 opacity, TQ_UINT8 *dst, KisProfile * profile)
- {
- CELL_PTR p = (CELL_PTR) dst;
- TQ_UINT8 r, g, b;
-
- r = c.red();
- g = c.green();
- b = c.blue();
-
- p -> red = r;
- p -> green = g;
- p -> blue = b;
- p -> alpha = opacity;
- rgb_to_hls(r, g, b, &p -> hue, &p -> lightness, &p -> saturation);
-
- p ->liquid_content = 0;
- p ->drying_rate = 0;
- p ->miscibility = 0;
-
- p -> direction = DOWN;
- p -> strength = 10;
-
- p -> absorbancy = 10;
- p -> volume = 0;
-
- #ifdef WSDEBUG
- kdDebug(DBG_AREA_CMS) << "qcolor: "
- << " r: " << c.red() << " b: " << c.blue() << " g: " << c.red() << " opacity: " << opacity
- << " native color: (" << TQString().setNum(p->red) << ", "
- << TQString().setNum(p->green) << ", "
- << TQString().setNum(p->blue) << ", "
- << TQString().setNum(p->alpha) << ") "
- << ", hls: (" << p->hue << ", "
- << p->lightness << ", "
- << p->saturation << ")\n";
- #endif
- }
-
- void KisWetStickyColorSpace::toTQColor(const TQ_UINT8 *src, TQColor *c, KisProfile * profile)
- {
- CELL_PTR p = (CELL_PTR) src;
-
- c -> setRgb(p -> red,
- p -> green,
- p -> blue);
- #ifdef WSDEBUG
- kdDebug(DBG_AREA_CMS) << "Created qcolor from wet & sticky: " << " r: " << c->red() << " b: " << c->blue() << " g: " << c->red() << "\n";
- #endif
- }
-
- void KisWetStickyColorSpace::toTQColor(const TQ_UINT8 *src, TQColor *c, TQ_UINT8 *opacity, KisProfile * profile)
- {
-
- CELL_PTR p = (CELL_PTR) src;
-
- c -> setRgb(p -> red,
- p -> green,
- p -> blue);
-
- *opacity = p -> alpha;
- #ifdef WSDEBUG
- kdDebug(DBG_AREA_CMS) << "Created qcolor from wet & sticky: " << " r: " << c->red() << " b: " << c->blue() << " g: " << c->red() << "\n";
- #endif
- }
-
-
-
- KisPixelRO KisWetStickyColorSpace::toKisPixelRO(const TQ_UINT8 *src, KisProfile * profile)
- {
- return KisPixelRO (src, src, this, profile);
- }
-
- KisPixel KisWetStickyColorSpace::toKisPixel(TQ_UINT8 *src, KisProfile * profile)
- {
- return KisPixel (src, src, this, profile);
- }
-
- void KisWetStickyColorSpace::mixColors(const TQ_UINT8 **colors, const TQ_UINT8 *weights, TQ_UINT32 nColors, TQ_UINT8 *dst) const
- {
- }
-
- TQ_UINT8 KisWetStickyColorSpace::getAlpha(const TQ_UINT8 *pixel) const
- {
- return ((CELL_PTR)pixel)->alpha;
- }
-
- void KisWetStickyColorSpace::setAlpha(TQ_UINT8 * pixels, TQ_UINT8 alpha, TQ_INT32 nPixels) const
- {
- while (nPixels > 0) {
- ((CELL_PTR)pixels)->alpha = alpha;
- --nPixels;
- pixels+=pixelSize();
- }
- }
-
- void KisWetStickyColorSpace::applyAlphaU8Mask(TQ_UINT8 * pixels, TQ_UINT8 * alpha, TQ_INT32 nPixels)
- {
- }
-
- void KisWetStickyColorSpace::applyInverseAlphaU8Mask(TQ_UINT8 * pixels, TQ_UINT8 * alpha, TQ_INT32 nPixels)
- {
- }
-
- TQ_UINT8 KisWetStickyColorSpace::scaleToU8(const TQ_UINT8 * srcPixel, TQ_INT32 channelPos)
- {
- return 0;
- }
-
- TQ_UINT16 KisWetStickyColorSpace::scaleToU16(const TQ_UINT8 * srcPixel, TQ_INT32 channelPos)
- {
- return 0;
- }
-
-
- TQValueVector<KisChannelInfo *> KisWetStickyColorSpace::channels() const
- {
- return m_channels;
- }
-
- bool KisWetStickyColorSpace::hasAlpha() const
- {
- return true;
- }
-
- TQ_INT32 KisWetStickyColorSpace::nChannels() const
- {
- return 14;
- }
-
- TQ_INT32 KisWetStickyColorSpace::nColorChannels() const
- {
- return 3;
- }
-
- TQ_INT32 KisWetStickyColorSpace::nSubstanceChannels() const
- {
- return 4;
-
- }
-
- TQ_INT32 KisWetStickyColorSpace::pixelSize() const
- {
- return sizeof(CELL);
- }
-
-
- TQImage KisWetStickyColorSpace::convertToTQImage(const TQ_UINT8 *data, TQ_INT32 width, TQ_INT32 height,
- KisProfile * /*srcProfile*/, KisProfile * /*dstProfile*/,
- TQ_INT32 /*renderingIntent*/, float /*exposure*/)
- {
-
- TQImage img(width, height, 32, 0, TQImage::LittleEndian);
-
- TQ_INT32 i = 0;
- uchar *j = img.bits();
-
- CELL_PTR p = (CELL_PTR) data;
-
- while ( i < width * height) {
-
- const TQ_UINT8 PIXEL_BLUE = 0;
- const TQ_UINT8 PIXEL_GREEN = 1;
- const TQ_UINT8 PIXEL_RED = 2;
- const TQ_UINT8 PIXEL_ALPHA = 3;
-
- *( j + PIXEL_ALPHA ) = p -> alpha;
- *( j + PIXEL_RED ) = p -> red;
- *( j + PIXEL_GREEN ) = p -> green;
- *( j + PIXEL_BLUE ) = p -> blue;
-
- p++;
- i++;
- j += 4; // Because we're hard-coded 32 bits deep, 4 bytes
- }
- return img;
- }
-
- bool KisWetStickyColorSpace::convertPixelsTo(const TQ_UINT8 * src, KisProfile * /*srcProfile*/,
- TQ_UINT8 * dst, KisAbstractColorSpace * dstColorSpace, KisProfile * dstProfile,
- TQ_UINT32 numPixels,
- TQ_INT32 /*renderingIntent*/)
- {
- TQ_INT32 dSize = dstColorSpace -> pixelSize();
- TQ_INT32 sSize = pixelSize();
-
- TQ_UINT32 j = 0;
- TQ_UINT32 i = 0;
- TQColor c;
- CELL_PTR cp;
- while ( i < numPixels ) {
- cp = (CELL_PTR) (src + i);
-
- c.setRgb(cp -> red,
- cp -> green,
- cp -> blue);
-
- dstColorSpace -> fromTQColor(c, cp -> alpha, (dst + j), dstProfile);
-
- i += sSize;
- j += dSize;
-
- }
- return true;
-
- }
-
- void KisWetStickyColorSpace::bitBlt(TQ_UINT8 *dst,
- TQ_INT32 dstRowStride,
- const TQ_UINT8 *src,
- TQ_INT32 srcRowStride,
- const TQ_UINT8 *mask,
- TQ_INT32 maskRowStride,
- TQ_UINT8 opacity,
- TQ_INT32 rows,
- TQ_INT32 cols,
- const KisCompositeOp& op)
- {
- switch (op.op()) {
- case COMPOSITE_UNDEF:
- // Undefined == no composition
- break;
- case COMPOSITE_OVER:
- compositeOver(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
- break;
- case COMPOSITE_COPY:
- default:
- compositeCopy(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
- break;
- }
-
- }
-
-
- void KisWetStickyColorSpace::compositeOver(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *maskRowStart, TQ_INT32 maskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT8 opacity)
- {
- // XXX: This is basically the same as with rgb and used to composite layers for Composition for
- // painting works differently
-
-
- while (rows > 0) {
-
- const TQ_UINT8 *src = srcRowStart;
- TQ_UINT8 *dst = dstRowStart;
- const TQ_UINT8 *mask = maskRowStart;
-
- TQ_INT32 columns = numColumns;
-
- while (columns > 0) {
-
- CELL_PTR dstCell = (CELL_PTR) dst;
- CELL_PTR srcCell = (CELL_PTR) src;
-
- #ifdef WSDEBUG
- kdDebug(DBG_AREA_CMS) << "Source: " << rows << ", " << columns << " color: " <<
- srcCell->red << ", " << srcCell->blue << ", " << srcCell->green << ", " << srcCell->alpha << ", " << srcCell->volume << "\n";
-
-
- kdDebug(DBG_AREA_CMS) << "Destination: " << rows << ", " << columns << " color: " <<
- dstCell->red << ", " << dstCell->blue << ", " << dstCell->green << ", " << dstCell->alpha << ", " << dstCell->volume << "\n";
-
- #endif
-
- TQ_UINT8 srcAlpha = srcCell->alpha;
-
- // apply the alphamask
- if(mask != 0)
- {
- if(*mask != OPACITY_OPAQUE)
- srcAlpha = UINT8_MULT(srcAlpha, *mask);
- mask++;
- }
-
- if (srcAlpha != OPACITY_TRANSPARENT) {
-
- if (opacity != OPACITY_OPAQUE) {
- srcAlpha = UINT8_MULT(srcCell->alpha, opacity);
- }
-
- if (srcAlpha == OPACITY_OPAQUE) {
- memcpy(dst, src, 3); // XXX: First three bytes for rgb?
- } else {
- TQ_UINT8 dstAlpha = dstCell->alpha;
-
- TQ_UINT8 srcBlend;
-
- if (dstAlpha == OPACITY_OPAQUE) {
- srcBlend = srcAlpha;
- } else {
- TQ_UINT8 newAlpha = dstAlpha + UINT8_MULT(OPACITY_OPAQUE - dstAlpha, srcAlpha);
- dstCell->alpha = newAlpha;
-
- if (newAlpha != 0) {
- srcBlend = UINT8_DIVIDE(srcAlpha, newAlpha);
- } else {
- srcBlend = srcAlpha;
- }
- }
-
- if (srcBlend == OPACITY_OPAQUE) {
- memcpy(dst, src, 3); //XXX: First three bytes for rgb?
- } else {
- dstCell->red = UINT8_BLEND(srcCell->red, dstCell->red, srcBlend);
- dstCell->green = UINT8_BLEND(srcCell->green, dstCell->green, srcBlend);
- dstCell->blue = UINT8_BLEND(srcCell->blue, dstCell->blue, srcBlend);
- }
- }
- }
- columns--;
- src += sizeof(CELL);
- dst += sizeof(CELL);
- }
- rows--;
- srcRowStart += srcRowStride;
- dstRowStart += dstRowStride;
-
- if(maskRowStart)
- maskRowStart += maskRowStride;
- }
-
- }
-
- void KisWetStickyColorSpace::compositeCopy(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *mask, TQ_INT32 maskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT8 opacity)
- {
- TQ_INT32 linesize = sizeof(CELL) * columns;
- TQ_UINT8 *d;
- const TQ_UINT8 *s;
- d = dst;
- s = src;
-
- while (rows-- > 0) {
- memcpy(d, s, linesize);
- d += dstRowStride;
- s += srcRowStride;
- }
-
- }
-
-
- KisCompositeOpList KisWetStickyColorSpace::userVisiblecompositeOps() const
- {
- KisCompositeOpList list;
-
- list.append(KisCompositeOp(COMPOSITE_OVER));
-
- return list;
- }
-
- TQString KisWetStickyColorSpace::channelValueText(const TQ_UINT8 *U8_pixel, TQ_UINT32 channelIndex) const
- {
- Q_ASSERT(channelIndex < nChannels());
- const CELL *pixel = reinterpret_cast<const CELL *>(U8_pixel);
-
- switch (channelIndex) {
- case BLUE_CHANNEL_INDEX:
- return TQString().setNum(pixel -> blue);
- case GREEN_CHANNEL_INDEX:
- return TQString().setNum(pixel -> green);
- case RED_CHANNEL_INDEX:
- return TQString().setNum(pixel -> red);
- case ALPHA_CHANNEL_INDEX:
- return TQString().setNum(pixel -> alpha);
- case HUE_CHANNEL_INDEX:
- return TQString().setNum(pixel -> hue);
- case SATURATION_CHANNEL_INDEX:
- return TQString().setNum(pixel -> saturation);
- case LIGHTNESS_CHANNEL_INDEX:
- return TQString().setNum(pixel -> lightness);
- case LIQUID_CONTENT_CHANNEL_INDEX:
- return TQString().setNum(pixel -> liquid_content);
- case DRYING_RATE_CHANNEL_INDEX:
- return TQString().setNum(pixel -> drying_rate);
- case MISCIBILITY_CHANNEL_INDEX:
- return TQString().setNum(pixel -> miscibility);
- case GRAVITATIONAL_DIRECTION_INDEX:
- {
- switch (pixel -> direction) {
- case UP:
- return i18n("Up");
- case DOWN:
- return i18n("Down");
- case LEFT:
- return i18n("Left");
- case RIGHT:
- return i18n("Right");
- default:
- Q_ASSERT(false);
- return TQString();
- }
- }
- case GRAVITATIONAL_STRENGTH_CHANNEL_INDEX:
- return TQString().setNum(pixel -> strength);
- case ABSORBANCY_CHANNEL_INDEX:
- return TQString().setNum(pixel -> absorbancy);
- case PAINT_VOLUME_CHANNEL_INDEX:
- return TQString().setNum(pixel -> volume);
- default:
- Q_ASSERT(false);
- return TQString();
- }
- }
-
- TQString KisWetStickyColorSpace::normalisedChannelValueText(const TQ_UINT8 *U8_pixel, TQ_UINT32 channelIndex) const
- {
- Q_ASSERT(channelIndex < nChannels());
- const CELL *pixel = reinterpret_cast<const CELL *>(U8_pixel);
-
- //XXX: Are these right?
-
- switch (channelIndex) {
- case BLUE_CHANNEL_INDEX:
- return TQString().setNum(static_cast<float>(pixel -> blue) / UINT8_MAX);
- case GREEN_CHANNEL_INDEX:
- return TQString().setNum(static_cast<float>(pixel -> green) / UINT8_MAX);
- case RED_CHANNEL_INDEX:
- return TQString().setNum(static_cast<float>(pixel -> red) / UINT8_MAX);
- case ALPHA_CHANNEL_INDEX:
- return TQString().setNum(static_cast<float>(pixel -> alpha) / UINT8_MAX);
- case HUE_CHANNEL_INDEX:
- return TQString().setNum(pixel -> hue);
- case SATURATION_CHANNEL_INDEX:
- return TQString().setNum(pixel -> saturation);
- case LIGHTNESS_CHANNEL_INDEX:
- return TQString().setNum(pixel -> lightness);
- case LIQUID_CONTENT_CHANNEL_INDEX:
- return TQString().setNum(static_cast<float>(pixel -> liquid_content) / UINT8_MAX);
- case DRYING_RATE_CHANNEL_INDEX:
- return TQString().setNum(static_cast<float>(pixel -> drying_rate) / UINT8_MAX);
- case MISCIBILITY_CHANNEL_INDEX:
- return TQString().setNum(static_cast<float>(pixel -> miscibility) / UINT8_MAX);
- case GRAVITATIONAL_DIRECTION_INDEX:
- {
- switch (pixel -> direction) {
- case UP:
- return i18n("Up");
- case DOWN:
- return i18n("Down");
- case LEFT:
- return i18n("Left");
- case RIGHT:
- return i18n("Right");
- default:
- Q_ASSERT(false);
- return TQString();
- }
- }
- case GRAVITATIONAL_STRENGTH_CHANNEL_INDEX:
- return TQString().setNum(static_cast<float>(pixel -> strength) / UINT8_MAX);
- case ABSORBANCY_CHANNEL_INDEX:
- return TQString().setNum(static_cast<float>(pixel -> absorbancy) / UINT8_MAX);
- case PAINT_VOLUME_CHANNEL_INDEX:
- return TQString().setNum(static_cast<float>(pixel -> volume) / UINT8_MAX);
- default:
- Q_ASSERT(false);
- return TQString();
- }
- }
|