diff options
Diffstat (limited to 'kjsembed/plugins/imagefx_plugin.cpp')
-rw-r--r-- | kjsembed/plugins/imagefx_plugin.cpp | 858 |
1 files changed, 858 insertions, 0 deletions
diff --git a/kjsembed/plugins/imagefx_plugin.cpp b/kjsembed/plugins/imagefx_plugin.cpp new file mode 100644 index 00000000..903c7655 --- /dev/null +++ b/kjsembed/plugins/imagefx_plugin.cpp @@ -0,0 +1,858 @@ +// -*- c++ -*- + +/* + * Copyright (C) 2003, Ian Reinhart Geiser <geiseri@kde.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include <kdebug.h> +#include <kglobal.h> +#include <kjsembed/jsopaqueproxy.h> +#include <kjsembed/jsbinding.h> +#include <kjsembed/jsfactory.h> +#include <kjsembed/jsfactory_imp.h> +#include <kjsembed/kjsembedpart.h> +#include <kjsembed/customobject_imp.h> +#include <qvariant.h> +#include <qbrush.h> + +#include "imagefx_plugin.h" + +namespace KJSEmbed { +namespace Bindings { + + +ImageFXLoader::ImageFXLoader( QObject *parent, const char *name, const QStringList &args ) : + JSBindingPlugin(parent, name, args) +{ +} + +KJS::Object ImageFXLoader::createBinding(KJSEmbedPart */*jspart*/, KJS::ExecState *exec, const KJS::List &/*args*/) const +{ + kdDebug() << "Loading a ImageFX object" << endl; + JSOpaqueProxy *prx = new JSOpaqueProxy( (int*)0, "ImageFX" ); + + KJS::Object proxyObj(prx); + ImageFX::addBindings( exec, proxyObj ); + return proxyObj; +} + +ImageFX::ImageFX( KJS::ExecState *exec, int id ) + : JSProxyImp(exec), mid(id) +{ +} + +ImageFX::~ImageFX() +{ +} + +void ImageFX::addBindings( KJS::ExecState *exec, KJS::Object &object ) { + + kdDebug() << "ImageFX::addBindings()" << endl; + JSOpaqueProxy *op = JSProxy::toOpaqueProxy( object.imp() ); + if ( !op ) { + kdWarning() << "ImageFX::addBindings() failed, not a JSOpaqueProxy" << endl; + return; + } + + if ( op->typeName() != "ImageFX" ) { + kdWarning() << "ImageFX::addBindings() failed, type is " << op->typeName() << endl; + return; + } + + JSProxy::MethodTable methods[] = { + { Methodgradient, "gradient" }, + { MethodunbalancedGradient, "unbalancedGradient" }, + { MethodblendColor, "blendColor" }, + { MethodblendImage, "blendImage" }, + { MethodcomputeDestinationRect, "computeDestinationRect" }, + { MethodchannelIntensity, "channelIntensity" }, + { Methodfade, "fade" }, + { Methodflatten, "flatten" }, + { Methodhash, "hash" }, + { Methodintensity, "intensity" }, + { Methodmodulate, "modulate" }, + { MethodtoGray, "toGray" }, + { Methoddesaturate, "desaturate" }, + { Methoddither, "dither" }, + { MethodselectedImage, "selectedImage" }, + { MethodcontrastHSV, "contrastHSV" }, + { Methodnormalize, "normalize" }, + { Methodequalize, "equalize" }, + { Methodthreshold, "threshold" }, + { Methodsolarize, "solarize" }, + { Methodemboss, "emboss" }, + { Methoddespeckle, "despeckle" }, + { Methodcharcoal, "charcoal" }, + { Methodcharcoal2, "charcoal2" }, + { Methodrotate, "rotate" }, + { Methodsample, "sample" }, + { MethodaddNoise, "addNoise" }, + { Methodblur, "blur" }, + { Methodedge, "edge" }, + { Methodimplode, "implode" }, + { MethodoilPaintConvolve, "oilPaintConvolve" }, + { MethodoilPaint, "MethodoilPaint" }, + { Methodsharpen, "sharpen" }, + { Methodsharpen2, "sharpen2" }, + { Methodspread, "spread" }, + { Methodshade, "shade" }, + { Methodswirl, "swirl" }, + { Methodwave, "wave" }, + { Methodcontrast, "contrast" }, + { MethodbumpMap, "bumpmap" }, + { 0, 0 } + }; + + int idx = 0; + do { + ImageFX *meth = new ImageFX( exec, methods[idx].id ); + object.put( exec , methods[idx].name, KJS::Object(meth) ); + ++idx; + } while( methods[idx].id ); + + // + // Define the enum constants + // + struct EnumValue { + const char *id; + int val; + }; + + EnumValue enums[] = { + // GradiantType + { "VerticalGradient", 0 }, + { "HorizontalGradient", 1 }, + { "DiagonalGradient", 2 }, + { "CrossDiagonalGradient", 3 }, + { "PyramidGradient", 4 }, + { "RectangleGradient", 5 }, + { "PipeCrossGradient", 6 }, + { "EllipticGradient", 7 }, + // RGBComponent + { "Red", 0 }, + { "Green", 1 }, + { "Blue", 2 }, + { "Gray", 3 }, + { "All", 4 }, + // Lighting + { "NorthLite", 0 }, + { "NWLite", 1 }, + { "WestLite", 2 }, + { "SWLite", 3 }, + { "SouthLite", 4 }, + { "SELite", 5 }, + { "EastLite", 6 }, + { "NELite", 7 }, + // ModulationType + { "Intensity", 0 }, + { "Saturation", 1 }, + { "HueShift", 2 }, + { "Contrast", 3 }, + // NoiseType + { "UniformNoise", 0 }, + { "GaussianNoise", 1 }, + { "MultiplicativeGaussianNoise", 2 }, + { "ImpulseNoise", 3 }, + { "LaplacianNoise", 4 }, + { "PoissonNoise", 5 }, + // RotateDirection + { "Rotate90", 0 }, + { "Rotate180", 1 }, + { "Rotate270", 2 }, + // BumpmapType + { "Linear", 0}, + { "Spherical", 1}, + { "Sinuosidal", 2}, + { 0, 0 } + }; + + int enumidx = 0; + do { + object.put( exec, enums[enumidx].id, KJS::Number(enums[enumidx].val), KJS::ReadOnly ); + ++enumidx; + } while( enums[enumidx].id ); +} + +KJS::Value ImageFX::call( KJS::ExecState *exec, KJS::Object &self, const KJS::List &args ) { + + kdDebug() << "ImageFX::call() " << mid << endl; + JSOpaqueProxy *op = JSProxy::toOpaqueProxy( self.imp() ); + if ( !op ) { + kdWarning() << "ImageFX::call() failed, not a JSOpaqueProxy" << endl; + return KJS::Value(); + } + + if ( op->typeName() != "ImageFX" ) { + kdWarning() << "ImageFX::call() failed, type is " << op->typeName() << endl; + return KJS::Value(); + } + + + KJS::Value retValue = KJS::Value(); + switch ( mid ) { + case Methodgradient: { + QSize size = extractQSize(exec, args, 0); + QColor ca = extractQColor(exec, args, 1); + QColor cb = extractQColor(exec, args, 2); + int type = extractInt( exec, args, 3); + int ncols = extractInt( exec, args, 4); + QImage img = KImageEffect::gradient(size, ca, cb, (KImageEffect::GradientType)type, ncols); + retValue = convertToValue(exec, img); + break; + } + case MethodunbalancedGradient: { + QSize size = extractQSize(exec, args, 0); + QColor ca = extractQColor(exec, args, 1); + QColor cb = extractQColor(exec, args, 2); + int type = extractInt( exec, args, 3); + int xfactor = extractInt( exec, args, 4); + int yfactor = extractInt( exec, args, 5); + int ncols = extractInt( exec, args, 6); + QImage img = KImageEffect::unbalancedGradient(size, ca, cb, (KImageEffect::GradientType)type, xfactor, yfactor, ncols); + retValue = convertToValue(exec, img); + break; + } + case MethodblendColor: { + QColor clr = extractQColor(exec, args, 0); + QImage dst = extractQImage(exec, args, 1); + float opacity = (float)extractDouble(exec, args, 2); + QImage img = KImageEffect::blend(clr, dst, opacity); + retValue = convertToValue(exec, img); + break; + } + case MethodblendImage: { + QImage src = extractQImage(exec, args, 0); + QImage dst = extractQImage(exec, args, 1); + float opacity = (float)extractDouble(exec, args, 2); + QImage img = KImageEffect::blend(src, dst, opacity); + retValue = convertToValue(exec, img); + break; + } + case MethodcomputeDestinationRect: { + QSize lowerSize = extractQSize(exec, args, 0); + int disposition = extractInt(exec, args, 1); + QImage upper = extractQImage(exec, args, 2); + QRect rect = KImageEffect::computeDestinationRect(lowerSize, (KImageEffect::Disposition) disposition, upper); + retValue = convertToValue(exec, rect); + break; + } + case MethodchannelIntensity: { + QImage image = extractQImage(exec, args, 0); + float percent = (float)extractDouble(exec, args, 1); + int channel = extractInt(exec, args, 2); + QImage img = KImageEffect::channelIntensity(image, percent, (KImageEffect::RGBComponent)channel); + retValue = convertToValue(exec, img); + break; + } + case Methodfade: { + QImage image = extractQImage(exec, args, 0); + float val = (float)extractDouble(exec, args, 1); + QColor color = extractQColor(exec, args, 2); + QImage img = KImageEffect::fade(image, val, color); + retValue = convertToValue(exec, img); + break; + } + case Methodflatten: { + QImage image = extractQImage(exec, args, 0); + QColor ca = extractQColor(exec, args, 1); + QColor cb = extractQColor(exec, args, 2); + int ncols = extractInt(exec, args, 3); + QImage img = KImageEffect::flatten(image, ca, cb, ncols); + retValue = convertToValue(exec, img); + break; + } + case Methodhash: { + + QImage image = extractQImage(exec, args, 0); + int lite = extractInt(exec, args, 1); + int spacing = extractInt(exec, args, 2); + QImage img = KImageEffect::hash(image, (KImageEffect::Lighting)lite, spacing); + retValue = convertToValue(exec, img); + break; + } + case Methodintensity: { + + QImage image = extractQImage(exec, args, 0); + float percent = (float)extractDouble(exec, args, 1); + QImage img = KImageEffect::intensity(image, percent); + retValue = convertToValue(exec, img); + break; + } + case Methodmodulate: { + QImage image = extractQImage(exec, args, 0); + QImage modImage = extractQImage(exec, args, 0); + bool reverse = extractBool(exec, args, 1); + int type = extractInt(exec, args, 2); + int factor = extractInt(exec, args, 3); + int channel = extractInt(exec, args, 4); + QImage img = KImageEffect::modulate(image, modImage, reverse, (KImageEffect::ModulationType)type, factor, (KImageEffect::RGBComponent)channel); + retValue = convertToValue(exec, img); + break; + } + + case MethodtoGray: { + QImage image = extractQImage(exec, args, 0); + bool fast = extractBool(exec, args, 1); + QImage img = KImageEffect::toGray(image, fast); + retValue = convertToValue(exec, img); + break; + } + case Methoddesaturate: { + QImage image = extractQImage(exec, args, 0); + float desat = (float)extractDouble(exec, args, 1); + QImage img = KImageEffect::desaturate(image, desat); + retValue = convertToValue(exec, img); + break; + } + case Methoddither: { + + //dither( palette, size) + break; + } + case MethodselectedImage: { + + QImage image = extractQImage(exec, args, 0); + QColor col = extractQColor(exec, args, 1); + QImage img = KImageEffect::selectedImage(image, col); + retValue = convertToValue(exec, img); + break; + } + case MethodcontrastHSV: { + QImage image = extractQImage(exec, args, 0); + bool sharpen = extractBool(exec, args, 1); + KImageEffect::contrastHSV(image, sharpen); + retValue = convertToValue(exec, image); + break; + } + case Methodnormalize: { + QImage image = extractQImage(exec, args, 0); + KImageEffect::normalize(image); + retValue = convertToValue(exec, image); + break; + } + case Methodequalize: { + QImage image = extractQImage(exec, args, 0); + KImageEffect::equalize(image); + retValue = convertToValue(exec, image); + break; + } + case Methodthreshold: { + QImage image = extractQImage(exec, args, 0); + uint value = extractUInt(exec, args, 1); + KImageEffect::threshold(image, value); + retValue = convertToValue(exec, image); + break; + } + case Methodsolarize: { + QImage image = extractQImage(exec, args, 0); + double factor = extractDouble(exec, args, 1); + KImageEffect::solarize(image, factor); + retValue = convertToValue(exec, image); + break; + } + case Methodemboss: { + QImage image = extractQImage(exec, args, 0); + double radius = extractDouble(exec, args, 1); + double sigma = extractDouble(exec, args, 2); + QImage img = KImageEffect::emboss(image, radius, sigma); + retValue = convertToValue(exec, img); + break; + } + case Methoddespeckle: { + QImage image = extractQImage(exec, args, 0); + QImage img = KImageEffect::despeckle(image); + retValue = convertToValue(exec, img); + break; + } + case Methodcharcoal: { + QImage image = extractQImage(exec, args, 0); + double factor = extractDouble(exec, args, 1); + QImage img = KImageEffect::charcoal( image, factor); + retValue = convertToValue(exec, img); + break; + } + case Methodcharcoal2: { + QImage image = extractQImage(exec, args, 0); + double radius = extractDouble(exec, args, 1); + double sigma = extractDouble(exec, args, 2); + QImage img = KImageEffect::charcoal(image, radius, sigma); + retValue = convertToValue(exec, img); + break; + } + case Methodrotate: { + QImage image = extractQImage(exec, args, 0); + int r = extractInt(exec, args, 1); + QImage img = KImageEffect::rotate(image, (KImageEffect::RotateDirection) r); + retValue = convertToValue(exec, img); + break; + } + case Methodsample: { + QImage image = extractQImage(exec, args, 0); + int width = extractInt(exec, args, 1); + int height = extractInt(exec, args, 2); + QImage img = KImageEffect::sample(image, width, height); + retValue = convertToValue(exec, img); + break; + } + case MethodaddNoise: { + QImage image = extractQImage(exec, args, 0); + int type = extractInt(exec, args, 1); + QImage img = KImageEffect::addNoise(image, (KImageEffect::NoiseType) type); + retValue = convertToValue(exec, img); + break; + } + case Methodblur: { + QImage image = extractQImage(exec, args, 0); + double radius = extractDouble(exec, args, 1); + double sigma = extractDouble(exec, args, 2); + QImage img = KImageEffect::blur(image, radius, sigma); + retValue = convertToValue(exec, img); + break; + } + case Methodedge: { + QImage image = extractQImage(exec, args, 0); + double radius = extractDouble(exec, args, 1); + QImage img = KImageEffect::edge(image, radius); + retValue = convertToValue(exec, img); + break; + } + case Methodimplode: { + QImage image = extractQImage(exec, args, 0); + double factor = extractDouble(exec, args, 1); + uint background = extractUInt(exec, args, 2); + QImage img = KImageEffect::implode(image, factor, background); + retValue = convertToValue(exec, img); + break; + } + case MethodoilPaintConvolve: { + QImage image = extractQImage(exec, args, 0); + double radius = extractDouble(exec, args, 1); + QImage img = KImageEffect::oilPaintConvolve(image, radius); + retValue = convertToValue(exec, img); + break; + } + case MethodoilPaint: { + QImage image = extractQImage(exec, args, 0); + int radius = extractInt(exec, args, 1); + QImage img = KImageEffect::oilPaint(image, radius); + retValue = convertToValue(exec, img); + break; + } + + + case Methodsharpen: { + QImage image = extractQImage(exec, args, 0); + double factor = extractDouble(exec, args, 1); + QImage img = KImageEffect::sharpen(image, factor); + retValue = convertToValue(exec, img); + break; + } + case Methodsharpen2: { + QImage image = extractQImage(exec, args, 0); + double radius = extractDouble(exec, args, 1); + double sigma = extractDouble(exec, args, 2); + QImage img = KImageEffect::sharpen(image, radius, sigma); + retValue = convertToValue(exec, img); + break; + } + case Methodspread: { + QImage image = extractQImage(exec, args, 0); + uint amount = extractUInt(exec, args, 1); + QImage img = KImageEffect::spread(image, amount); + retValue = convertToValue(exec, img); + break; + } + case Methodshade: { + QImage image = extractQImage(exec, args, 0); + bool color_shading = extractBool(exec, args, 1); + double azimuth = extractDouble(exec, args, 2); + double elevation = extractDouble(exec, args, 3); + QImage img = KImageEffect::shade(image, color_shading, azimuth, elevation); + retValue = convertToValue(exec, img); + break; + } + case Methodswirl: { + QImage image = extractQImage(exec, args, 0); + double degrees = extractDouble(exec, args, 1); + uint background = extractUInt(exec, args, 2); + QImage img = KImageEffect::swirl(image, degrees, background); + retValue = convertToValue(exec, img); + break; + } + case Methodwave: { + QImage image = extractQImage(exec, args, 0); + double amplitude = extractDouble(exec, args, 1); + double frequency = extractDouble(exec, args, 2); + uint background = extractUInt(exec, args, 3); + QImage img = KImageEffect::wave(image, amplitude, frequency, background); + retValue = convertToValue(exec, img); + break; + } + case Methodcontrast: { + QImage image = extractQImage(exec, args, 0); + int c = extractInt(exec, args, 1); + QImage img = KImageEffect::contrast(image, c); + retValue = convertToValue(exec, img); + break; + } + case MethodbumpMap: { + QImage mask = extractQImage(exec, args, 0); + QImage img = bumpmap(img, + mask, + extractDouble(exec, args, 1), + extractDouble(exec, args, 2), + extractInt(exec, args, 3), + extractInt(exec, args, 4), + extractInt(exec, args, 5), + extractInt(exec, args, 6), + extractInt(exec, args, 7), + extractBool(exec, args, 8), + extractBool(exec, args, 9), + (BumpmapType) extractInt(exec, args, 10), + extractBool(exec, args, 11)); + + retValue = convertToValue(exec, img); + break; + } + default: + kdWarning() << "ImageFX has no method " << mid << endl; + break; + } + + return retValue; +} + +/*********************************************************************** + * Here's a pretty fast bumpmap implementation. + * NOTE: remind me to move it to KImageEffects after 3.2. + */ +#define DegreesToRadians(x) ((x)*M_PI/180.0) +#define MOD(x, y) ((x) < 0 ? ((y) - 1 - ((y) - 1 - (x)) % (y)) : (x) % (y)) + +/** + * NOTE: kclamp needs to be moved to kglobals.h along kmin and kmax + */ +#define KCLAMP(x,low,high) kClamp(x,low,high) +template<class T> +inline const T& kClamp( const T& x, const T& low, const T& high ) +{ + if ( x < low ) + return low; + else if ( x > high ) + return high; + else + return x; +} + +static inline unsigned int intensityValue( unsigned int color ) { + return (unsigned int)( (0.299*qRed( color ) + + 0.587*qGreen( color ) + + 0.1140000000000001*qBlue( color ) ) ); +} + +struct BumpmapParams { + BumpmapParams( double bm_azimuth, double bm_elevation, + int bm_depth, BumpmapType bm_type, + bool invert ) { + /* Convert to radians */ + double azimuth = DegreesToRadians( bm_azimuth ); + double elevation = DegreesToRadians( bm_elevation ); + + /* Calculate the light vector */ + lx = (int)( cos(azimuth) * cos(elevation) * 255.0 ); + ly = (int)( sin(azimuth) * cos(elevation) * 255.0 ); + int lz = (int)( sin(elevation) * 255.0 ); + + /* Calculate constant Z component of surface normal */ + int nz = (6 * 255) / bm_depth; + nz2 = nz * nz; + nzlz = nz * lz; + + /* Optimize for vertical normals */ + background = lz; + + /* Calculate darkness compensation factor */ + compensation = sin(elevation); + + /* Create look-up table for map type */ + for (int i = 0; i < 256; i++) + { + double n = 0; + switch (bm_type) + { + case Spherical: + n = i / 255.0 - 1.0; + lut[i] = (int) (255.0 * sqrt(1.0 - n * n) + 0.5); + break; + + case Sinuosidal: + n = i / 255.0; + lut[i] = (int) (255.0 * (sin((-M_PI / 2.0) + M_PI * n) + 1.0) / + 2.0 + 0.5); + break; + + case Linear: + default: + lut[i] = i; + } + + if (invert) + lut[i] = 255 - lut[i]; + } + } + int lx, ly; + int nz2, nzlz; + int background; + double compensation; + uchar lut[256]; +}; + + +static void bumpmap_convert_row( uint *row, + int width, + int bpp, + int has_alpha, + uchar *lut, + int waterlevel ) +{ + uint *p; + + p = row; + + has_alpha = has_alpha ? 1 : 0; + + if (bpp >= 3) + for (; width; width--) + { + if (has_alpha) { + unsigned int idx = (unsigned int)(intensityValue( *row ) + 0.5); + *p++ = lut[(unsigned int) ( waterlevel + + ( ( idx - + waterlevel) * qBlue( *row )) / 255.0 )]; + } else { + unsigned int idx = (unsigned int)(intensityValue( *row ) + 0.5); + *p++ = lut[idx]; + } + + ++row; + } +} + +static void bumpmap_row( uint *src, + uint *dest, + int width, + int bpp, + int has_alpha, + uint *bm_row1, + uint *bm_row2, + uint *bm_row3, + int bm_width, + int bm_xofs, + bool tiled, + bool row_in_bumpmap, + int ambient, + bool compensate, + BumpmapParams *params ) +{ + int xofs1, xofs2, xofs3; + int shade; + int ndotl; + int nx, ny; + int x; + int pbpp; + int tmp; + + if (has_alpha) + pbpp = bpp - 1; + else + pbpp = bpp; + + tmp = bm_xofs; + xofs2 = MOD(tmp, bm_width); + + for (x = 0; x < width; x++) + { + /* Calculate surface normal from bump map */ + + if (tiled || (row_in_bumpmap && + x >= - tmp && x < - tmp + bm_width)) { + if (tiled) { + xofs1 = MOD(xofs2 - 1, bm_width); + xofs3 = MOD(xofs2 + 1, bm_width); + } else { + xofs1 = KCLAMP(xofs2 - 1, 0, bm_width - 1); + xofs3 = KCLAMP(xofs2 + 1, 0, bm_width - 1); + } + nx = (bm_row1[xofs1] + bm_row2[xofs1] + bm_row3[xofs1] - + bm_row1[xofs3] - bm_row2[xofs3] - bm_row3[xofs3]); + ny = (bm_row3[xofs1] + bm_row3[xofs2] + bm_row3[xofs3] - + bm_row1[xofs1] - bm_row1[xofs2] - bm_row1[xofs3]); + } else { + nx = ny = 0; + } + + /* Shade */ + + if ((nx == 0) && (ny == 0)) + shade = params->background; + else { + ndotl = nx * params->lx + ny * params->ly + params->nzlz; + + if (ndotl < 0) + shade = (int)( params->compensation * ambient ); + else { + shade = (int)( ndotl / sqrt(nx * nx + ny * ny + params->nz2) ); + + shade = (int)( shade + KMAX(0.0, (255 * params->compensation - shade)) * + ambient / 255 ); + } + } + + /* Paint */ + + /** + * NOTE: if we want to work with non-32bit images the alpha handling would + * also change + */ + if (compensate) { + int red = (int)((qRed( *src ) * shade) / (params->compensation * 255)); + int green = (int)((qGreen( *src ) * shade) / (params->compensation * 255)); + int blue = (int)((qBlue( *src ) * shade) / (params->compensation * 255)); + int alpha = (int)((qAlpha( *src ) * shade) / (params->compensation * 255)); + ++src; + *dest++ = qRgba( red, green, blue, alpha ); + } else { + int red = qRed( *src ) * shade / 255; + int green = qGreen( *src ) * shade / 255; + int blue = qBlue( *src ) * shade / 255; + int alpha = qAlpha( *src ) * shade / 255; + ++src; + *dest++ = qRgba( red, green, blue, alpha ); + } + + /* Next pixel */ + + if (++xofs2 == bm_width) + xofs2 = 0; + } +} + +/** + * A bumpmapping algorithm. + * + * @param img the image you want bumpmap + * @param map the map used + * @param azimuth azimuth + * @param elevation elevation + * @param depth depth (not the depth of the image, but of the map) + * @param xofs X offset + * @param yofs Y offset + * @param waterlevel level that full transparency should represent + * @param ambient ambient lighting factor + * @param compensate compensate for darkening + * @param invert invert bumpmap + * @param type type of the bumpmap + * + * @return The destination image (dst) containing the result. + * @author Zack Rusin <zack@kde.org> + */ +QImage ImageFX::bumpmap(QImage &img, QImage &map, double azimuth, double elevation, + int depth, int xofs, int yofs, int waterlevel, + int ambient, bool compensate, bool invert, + BumpmapType type, bool tiled) +{ + QImage dst; + + if ( img.depth() != 32 || img.depth() != 32 ) { + qWarning( "Bump-mapping effect works only with 32 bit images"); + return dst; + } + + dst.create( img.width(), img.height(), img.depth() ); + int bm_width = map.width(); + int bm_height = map.height(); + int bm_bpp = map.depth(); + int bm_has_alpha = map.hasAlphaBuffer(); + + int yofs1, yofs2, yofs3; + + if ( tiled ) { + yofs2 = MOD( yofs, bm_height ); + yofs1 = MOD( yofs2 - 1, bm_height); + yofs3 = MOD( yofs2 + 1, bm_height); + } else { + yofs1 = 0; + yofs2 = 0; + yofs3 = KCLAMP( yofs2+1, 0, bm_height - 1 ); + } + + BumpmapParams params( azimuth, elevation, depth, type, invert ); + + uint* bm_row1 = (unsigned int*)map.scanLine( yofs1 ); + uint* bm_row2 = (unsigned int*)map.scanLine( yofs2 ); + uint* bm_row3 = (unsigned int*)map.scanLine( yofs3 ); + + bumpmap_convert_row( bm_row1, bm_width, bm_bpp, bm_has_alpha, params.lut, waterlevel ); + bumpmap_convert_row( bm_row2, bm_width, bm_bpp, bm_has_alpha, params.lut, waterlevel ); + bumpmap_convert_row( bm_row3, bm_width, bm_bpp, bm_has_alpha, params.lut, waterlevel ); + + for (int y = 0; y < img.height(); ++y) + { + int row_in_bumpmap = (y >= - yofs && y < - yofs + bm_height); + + uint* src_row = (unsigned int*)img.scanLine( y ); + uint* dest_row = (unsigned int*)dst.scanLine( y ); + + bumpmap_row( src_row, dest_row, img.width(), img.depth(), img.hasAlphaBuffer(), + bm_row1, bm_row2, bm_row3, bm_width, xofs, + tiled, + row_in_bumpmap, ambient, compensate, + ¶ms ); + + /* Next line */ + + if (tiled || row_in_bumpmap) + { + uint* bm_tmprow = bm_row1; + bm_row1 = bm_row2; + bm_row2 = bm_row3; + bm_row3 = bm_tmprow; + + if (++yofs2 == bm_height) + yofs2 = 0; + + if (tiled) + yofs3 = MOD(yofs2 + 1, bm_height); + else + yofs3 = KCLAMP(yofs2 + 1, 0, bm_height - 1); + + bm_row3 = (unsigned int*)map.scanLine( yofs3 ); + bumpmap_convert_row( bm_row3, bm_width, bm_bpp, bm_has_alpha, + params.lut, waterlevel ); + } + } + return dst; +} + + +} // namespace KJSEmbed::Bindings +} // namespace KJSEmbed + +#include <kgenericfactory.h> +typedef KGenericFactory<KJSEmbed::Bindings::ImageFXLoader> ImageFXLoaderFactory; +K_EXPORT_COMPONENT_FACTORY( libimagefxplugin, ImageFXLoaderFactory( "ImageFXLoader" ) ) |