You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdebindings/kjsembed/plugins/imagefx_plugin.cpp

859 lines
28 KiB

// -*- 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 <tqvariant.h>
#include <tqbrush.h>
#include "imagefx_plugin.h"
namespace KJSEmbed {
namespace Bindings {
ImageFXLoader::ImageFXLoader( TTQObject *parent, const char *name, const TTQStringList &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: {
TTQSize size = extractTQSize(exec, args, 0);
TTQColor ca = extractTQColor(exec, args, 1);
TTQColor cb = extractTQColor(exec, args, 2);
int type = extractInt( exec, args, 3);
int ncols = extractInt( exec, args, 4);
TTQImage img = KImageEffect::gradient(size, ca, cb, (KImageEffect::GradientType)type, ncols);
retValue = convertToValue(exec, img);
break;
}
case MethodunbalancedGradient: {
TTQSize size = extractTQSize(exec, args, 0);
TTQColor ca = extractTQColor(exec, args, 1);
TTQColor cb = extractTQColor(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);
TTQImage img = KImageEffect::unbalancedGradient(size, ca, cb, (KImageEffect::GradientType)type, xfactor, yfactor, ncols);
retValue = convertToValue(exec, img);
break;
}
case MethodblendColor: {
TTQColor clr = extractTQColor(exec, args, 0);
TTQImage dst = extractTQImage(exec, args, 1);
float opacity = (float)extractDouble(exec, args, 2);
TTQImage img = KImageEffect::blend(clr, dst, opacity);
retValue = convertToValue(exec, img);
break;
}
case MethodblendImage: {
TTQImage src = extractTQImage(exec, args, 0);
TTQImage dst = extractTQImage(exec, args, 1);
float opacity = (float)extractDouble(exec, args, 2);
TTQImage img = KImageEffect::blend(src, dst, opacity);
retValue = convertToValue(exec, img);
break;
}
case MethodcomputeDestinationRect: {
TTQSize lowerSize = extractTQSize(exec, args, 0);
int disposition = extractInt(exec, args, 1);
TTQImage upper = extractTQImage(exec, args, 2);
TTQRect rect = KImageEffect::computeDestinationRect(lowerSize, (KImageEffect::Disposition) disposition, upper);
retValue = convertToValue(exec, rect);
break;
}
case MethodchannelIntensity: {
TTQImage image = extractTQImage(exec, args, 0);
float percent = (float)extractDouble(exec, args, 1);
int channel = extractInt(exec, args, 2);
TTQImage img = KImageEffect::channelIntensity(image, percent, (KImageEffect::RGBComponent)channel);
retValue = convertToValue(exec, img);
break;
}
case Methodfade: {
TTQImage image = extractTQImage(exec, args, 0);
float val = (float)extractDouble(exec, args, 1);
TTQColor color = extractTQColor(exec, args, 2);
TTQImage img = KImageEffect::fade(image, val, color);
retValue = convertToValue(exec, img);
break;
}
case Methodflatten: {
TTQImage image = extractTQImage(exec, args, 0);
TTQColor ca = extractTQColor(exec, args, 1);
TTQColor cb = extractTQColor(exec, args, 2);
int ncols = extractInt(exec, args, 3);
TTQImage img = KImageEffect::flatten(image, ca, cb, ncols);
retValue = convertToValue(exec, img);
break;
}
case Methodhash: {
TTQImage image = extractTQImage(exec, args, 0);
int lite = extractInt(exec, args, 1);
int spacing = extractInt(exec, args, 2);
TTQImage img = KImageEffect::hash(image, (KImageEffect::Lighting)lite, spacing);
retValue = convertToValue(exec, img);
break;
}
case Methodintensity: {
TTQImage image = extractTQImage(exec, args, 0);
float percent = (float)extractDouble(exec, args, 1);
TTQImage img = KImageEffect::intensity(image, percent);
retValue = convertToValue(exec, img);
break;
}
case Methodmodulate: {
TTQImage image = extractTQImage(exec, args, 0);
TTQImage modImage = extractTQImage(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);
TTQImage img = KImageEffect::modulate(image, modImage, reverse, (KImageEffect::ModulationType)type, factor, (KImageEffect::RGBComponent)channel);
retValue = convertToValue(exec, img);
break;
}
case MethodtoGray: {
TTQImage image = extractTQImage(exec, args, 0);
bool fast = extractBool(exec, args, 1);
TTQImage img = KImageEffect::toGray(image, fast);
retValue = convertToValue(exec, img);
break;
}
case Methoddesaturate: {
TTQImage image = extractTQImage(exec, args, 0);
float desat = (float)extractDouble(exec, args, 1);
TTQImage img = KImageEffect::desaturate(image, desat);
retValue = convertToValue(exec, img);
break;
}
case Methoddither: {
//dither( palette, size)
break;
}
case MethodselectedImage: {
TTQImage image = extractTQImage(exec, args, 0);
TTQColor col = extractTQColor(exec, args, 1);
TTQImage img = KImageEffect::selectedImage(image, col);
retValue = convertToValue(exec, img);
break;
}
case MethodcontrastHSV: {
TTQImage image = extractTQImage(exec, args, 0);
bool sharpen = extractBool(exec, args, 1);
KImageEffect::contrastHSV(image, sharpen);
retValue = convertToValue(exec, image);
break;
}
case Methodnormalize: {
TTQImage image = extractTQImage(exec, args, 0);
KImageEffect::normalize(image);
retValue = convertToValue(exec, image);
break;
}
case Methodequalize: {
TTQImage image = extractTQImage(exec, args, 0);
KImageEffect::equalize(image);
retValue = convertToValue(exec, image);
break;
}
case Methodthreshold: {
TTQImage image = extractTQImage(exec, args, 0);
uint value = extractUInt(exec, args, 1);
KImageEffect::threshold(image, value);
retValue = convertToValue(exec, image);
break;
}
case Methodsolarize: {
TTQImage image = extractTQImage(exec, args, 0);
double factor = extractDouble(exec, args, 1);
KImageEffect::solarize(image, factor);
retValue = convertToValue(exec, image);
break;
}
case Methodemboss: {
TTQImage image = extractTQImage(exec, args, 0);
double radius = extractDouble(exec, args, 1);
double sigma = extractDouble(exec, args, 2);
TTQImage img = KImageEffect::emboss(image, radius, sigma);
retValue = convertToValue(exec, img);
break;
}
case Methoddespeckle: {
TTQImage image = extractTQImage(exec, args, 0);
TTQImage img = KImageEffect::despeckle(image);
retValue = convertToValue(exec, img);
break;
}
case Methodcharcoal: {
TTQImage image = extractTQImage(exec, args, 0);
double factor = extractDouble(exec, args, 1);
TTQImage img = KImageEffect::charcoal( image, factor);
retValue = convertToValue(exec, img);
break;
}
case Methodcharcoal2: {
TTQImage image = extractTQImage(exec, args, 0);
double radius = extractDouble(exec, args, 1);
double sigma = extractDouble(exec, args, 2);
TTQImage img = KImageEffect::charcoal(image, radius, sigma);
retValue = convertToValue(exec, img);
break;
}
case Methodrotate: {
TTQImage image = extractTQImage(exec, args, 0);
int r = extractInt(exec, args, 1);
TTQImage img = KImageEffect::rotate(image, (KImageEffect::RotateDirection) r);
retValue = convertToValue(exec, img);
break;
}
case Methodsample: {
TTQImage image = extractTQImage(exec, args, 0);
int width = extractInt(exec, args, 1);
int height = extractInt(exec, args, 2);
TTQImage img = KImageEffect::sample(image, width, height);
retValue = convertToValue(exec, img);
break;
}
case MethodaddNoise: {
TTQImage image = extractTQImage(exec, args, 0);
int type = extractInt(exec, args, 1);
TTQImage img = KImageEffect::addNoise(image, (KImageEffect::NoiseType) type);
retValue = convertToValue(exec, img);
break;
}
case Methodblur: {
TTQImage image = extractTQImage(exec, args, 0);
double radius = extractDouble(exec, args, 1);
double sigma = extractDouble(exec, args, 2);
TTQImage img = KImageEffect::blur(image, radius, sigma);
retValue = convertToValue(exec, img);
break;
}
case Methodedge: {
TTQImage image = extractTQImage(exec, args, 0);
double radius = extractDouble(exec, args, 1);
TTQImage img = KImageEffect::edge(image, radius);
retValue = convertToValue(exec, img);
break;
}
case Methodimplode: {
TTQImage image = extractTQImage(exec, args, 0);
double factor = extractDouble(exec, args, 1);
uint background = extractUInt(exec, args, 2);
TTQImage img = KImageEffect::implode(image, factor, background);
retValue = convertToValue(exec, img);
break;
}
case MethodoilPaintConvolve: {
TTQImage image = extractTQImage(exec, args, 0);
double radius = extractDouble(exec, args, 1);
TTQImage img = KImageEffect::oilPaintConvolve(image, radius);
retValue = convertToValue(exec, img);
break;
}
case MethodoilPaint: {
TTQImage image = extractTQImage(exec, args, 0);
int radius = extractInt(exec, args, 1);
TTQImage img = KImageEffect::oilPaint(image, radius);
retValue = convertToValue(exec, img);
break;
}
case Methodsharpen: {
TTQImage image = extractTQImage(exec, args, 0);
double factor = extractDouble(exec, args, 1);
TTQImage img = KImageEffect::sharpen(image, factor);
retValue = convertToValue(exec, img);
break;
}
case Methodsharpen2: {
TTQImage image = extractTQImage(exec, args, 0);
double radius = extractDouble(exec, args, 1);
double sigma = extractDouble(exec, args, 2);
TTQImage img = KImageEffect::sharpen(image, radius, sigma);
retValue = convertToValue(exec, img);
break;
}
case Methodspread: {
TTQImage image = extractTQImage(exec, args, 0);
uint amount = extractUInt(exec, args, 1);
TTQImage img = KImageEffect::spread(image, amount);
retValue = convertToValue(exec, img);
break;
}
case Methodshade: {
TTQImage image = extractTQImage(exec, args, 0);
bool color_shading = extractBool(exec, args, 1);
double azimuth = extractDouble(exec, args, 2);
double elevation = extractDouble(exec, args, 3);
TTQImage img = KImageEffect::shade(image, color_shading, azimuth, elevation);
retValue = convertToValue(exec, img);
break;
}
case Methodswirl: {
TTQImage image = extractTQImage(exec, args, 0);
double degrees = extractDouble(exec, args, 1);
uint background = extractUInt(exec, args, 2);
TTQImage img = KImageEffect::swirl(image, degrees, background);
retValue = convertToValue(exec, img);
break;
}
case Methodwave: {
TTQImage image = extractTQImage(exec, args, 0);
double amplitude = extractDouble(exec, args, 1);
double frequency = extractDouble(exec, args, 2);
uint background = extractUInt(exec, args, 3);
TTQImage img = KImageEffect::wave(image, amplitude, frequency, background);
retValue = convertToValue(exec, img);
break;
}
case Methodcontrast: {
TTQImage image = extractTQImage(exec, args, 0);
int c = extractInt(exec, args, 1);
TTQImage img = KImageEffect::contrast(image, c);
retValue = convertToValue(exec, img);
break;
}
case MethodbumpMap: {
TTQImage mask = extractTQImage(exec, args, 0);
TTQImage 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>
*/
TTQImage ImageFX::bumpmap(TTQImage &img, TTQImage &map, double azimuth, double elevation,
int depth, int xofs, int yofs, int waterlevel,
int ambient, bool compensate, bool invert,
BumpmapType type, bool tiled)
{
TTQImage 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,
&params );
/* 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" ) )