/*
JWildfire - an image and animation processor written in Java
Copyright (C) 1995-2011 Andreas Maschke
This is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser
General Public License as published by the Free Software Foundation; either version 2.1 of the
License, or (at your option) any later version.
This software 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along with this software;
if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jwildfire.transform;
import java.awt.Color;
import java.awt.image.BufferedImage;
import org.jwildfire.base.Property;
import org.jwildfire.base.PropertyCategory;
import org.jwildfire.base.PropertyMax;
import org.jwildfire.base.PropertyMin;
import org.jwildfire.base.mathlib.MathLib;
import org.jwildfire.image.Pixel;
import org.jwildfire.image.SimpleImage;
import org.jwildfire.image.WFImage;
import org.jwildfire.swing.Buffer.BufferType;
import com.l2fprod.common.beans.editor.ComboBoxPropertyEditor;
public abstract class Mesh3DTransformer extends Transformer {
public enum Rotate {
XY, YZ, XZ, NONE
}
public enum Light {
NORMAL, PHONG, OFF
};
public enum Faces {
NORMAL, DOUBLE, MIRRORED
};
@Property(category = PropertyCategory.RENDERING, description = "Type of shading", editorClass = LightEditor.class)
protected Light light = Light.NORMAL;
@Property(category = PropertyCategory.RENDERING, description = "Treat faces as single or double sided", editorClass = FacesEditor.class)
protected Faces faces = Faces.NORMAL;
@Property(category = PropertyCategory.RENDERING, description = "Rotation mode", editorClass = RotateEditor.class)
protected Rotate doRotate = Rotate.XY;
@Property(category = PropertyCategory.RENDERING, description = "Rotation angle alpha")
@PropertyMin(-360)
@PropertyMax(360)
protected double alpha = 30.0;
@Property(category = PropertyCategory.RENDERING, description = "Rotation angle beta")
@PropertyMin(-360)
@PropertyMax(360)
protected double beta = 60.0;
@Property(category = PropertyCategory.RENDERING, description = "Object zoom factor")
@PropertyMin(0.01)
@PropertyMax(10.0)
protected double zoom = 1.40;
@Property(category = PropertyCategory.RENDERING, description = "Detail of the generated 3d-object (higher value -> less detail <-> better performance)")
@PropertyMin(0.01)
@PropertyMax(10.0)
protected double quant3D = 1.0;
@Property(category = PropertyCategory.RENDERING, description = "X-coordinate of the object centre")
protected double centreX = 350.0;
@Property(category = PropertyCategory.RENDERING, description = "Y-coordinate of the object centre")
protected double centreY = 400.0;
@Property(category = PropertyCategory.RENDERING, description = "Simulate camera view (perspective)")
protected boolean doCam = true;
@Property(category = PropertyCategory.RENDERING, description = "X-coordinate of the camera position")
protected double camX = 0.0;
@Property(category = PropertyCategory.RENDERING, description = "Y-coordinate of the camera position")
protected double camY = 0.0;
@Property(category = PropertyCategory.RENDERING, description = "Z-coordinate of the camera position")
protected double camZ = -1000.0;
@Property(category = PropertyCategory.RENDERING, description = "X-coordinate of the 1st light source")
protected double light1X = -200.0;
@Property(category = PropertyCategory.RENDERING, description = "Y-coordinate of the 1st light source")
protected double light1Y = 100.0;
@Property(category = PropertyCategory.RENDERING, description = "Z-coordinate of the 1st light source")
protected double light1Z = -600.0;
@Property(category = PropertyCategory.RENDERING, description = "Color of the 1st light source")
protected Color light1Color = new Color(255, 255, 255);
@Property(category = PropertyCategory.RENDERING, description = "X-coordinate of the 2nd light source")
protected double light2X = 200.0;
@Property(category = PropertyCategory.RENDERING, description = "Y-coordinate of the 2nd light source")
protected double light2Y = 100.0;
@Property(category = PropertyCategory.RENDERING, description = "Z-coordinate of the 2nd light source")
protected double light2Z = -600.0;
@Property(category = PropertyCategory.RENDERING, description = "Color of the 2nd light source")
protected Color light2Color = new Color(0, 0, 0);
@Property(category = PropertyCategory.RENDERING, description = "X-coordinate of the 3rd light source")
protected double light3X = -200.0;
@Property(category = PropertyCategory.RENDERING, description = "Y-coordinate of the 3rd light source")
protected double light3Y = -100.0;
@Property(category = PropertyCategory.RENDERING, description = "Z-coordinate of the 3rd light source")
protected double light3Z = -600.0;
@Property(category = PropertyCategory.RENDERING, description = "Color of the 3rd light source")
protected Color light3Color = new Color(0, 0, 0);
@Property(category = PropertyCategory.RENDERING, description = "X-coordinate of the 4th light source")
protected double light4X = 200.0;
@Property(category = PropertyCategory.RENDERING, description = "Y-coordinate of the 4th light source")
protected double light4Y = -100.0;
@Property(category = PropertyCategory.RENDERING, description = "Z-coordinate of the 4th light source")
protected double light4Z = -600.0;
@Property(category = PropertyCategory.RENDERING, description = "Color of the 4th light source")
protected Color light4Color = new Color(0, 0, 0);
@Property(category = PropertyCategory.RENDERING, description = "Ambient light intensity")
@PropertyMin(0.0)
@PropertyMax(1.0)
protected double ambient = 0.06;
@Property(category = PropertyCategory.RENDERING, description = "Diffuse light intensity")
@PropertyMin(0.0)
@PropertyMax(1.0)
protected double diffuse = 0.94;
@Property(category = PropertyCategory.RENDERING, description = "Phong light intensity")
@PropertyMin(0.0)
@PropertyMax(1.0)
protected double phong = 0.900;
@Property(category = PropertyCategory.RENDERING, description = "Sharpness of the phong spot size (the higher the value the more the sharpness)")
@PropertyMin(0.0)
protected double phongSize = 30.00;
@Property(category = PropertyCategory.RENDERING, description = "Phong angle")
@PropertyMin(-360.0)
@PropertyMax(360.0)
protected double phongAngle = 60.00;
@Property(description = "Smoothing amount", category = PropertyCategory.SECONDARY)
private int smoothing = 1;
@Property(description = "Image scale", category = PropertyCategory.SECONDARY)
private double imgScale = 1.0;
protected abstract void transformMesh(Mesh3D pMesh3D, int pImageWidth, int pImageHeight);
private Mesh3D inputMesh3D;
private Mesh3D outputMesh3D;
@Override
public void setInputMesh3D(Mesh3D pInputMesh3D) {
inputMesh3D = pInputMesh3D;
}
@Override
public Mesh3D getOutputMesh3D(boolean pRemoveOwnReference) {
Mesh3D res = outputMesh3D;
if (pRemoveOwnReference)
outputMesh3D = null;
return res;
}
protected void createMeshFromImage(Mesh3D pMesh3D, SimpleImage pImg, double pQuant3D) {
pMesh3D.readPixels(pImg, pQuant3D);
}
@Override
protected void performImageTransformation(WFImage pImg) {
Mesh3D lInputMesh3D;
SimpleImage img = (SimpleImage) pImg;
if (inputMesh3D == null) {
lInputMesh3D = new Mesh3D();
createMeshFromImage(lInputMesh3D, img, quant3D);
}
else {
lInputMesh3D = inputMesh3D.clone();
}
int width = pImg.getImageWidth();
int height = pImg.getImageHeight();
transformMesh(lInputMesh3D, width, height);
if (storeMesh3D) {
this.outputMesh3D = lInputMesh3D.clone();
this.outputMesh3D.setLastTransformation(this);
}
transform3D(lInputMesh3D, width, height);
img.fillBackground(0, 0, 0);
render3D(lInputMesh3D, img);
applySmoothing(img, smoothing);
lInputMesh3D = null;
inputMesh3D = null;
}
private void transform3D(Mesh3D pMesh3D, int pWidth, int pHeight) {
/* check the parameters */
int width = pWidth;
int height = pHeight;
int pCount = pMesh3D.getPCount();
double zeroX = (double) centreX - (double) width / 2.0;
double zeroY = (double) centreY - (double) height / 2.0;
if ((Math.abs(alpha) <= MathLib.EPSILON) && (Math.abs(beta) <= MathLib.EPSILON))
doRotate = Rotate.NONE;
boolean doZoom = Math.abs(zoom - 1.0) > MathLib.EPSILON;
double x[] = pMesh3D.getX();
double y[] = pMesh3D.getY();
double z[] = pMesh3D.getZ();
/* rotate it */
if (doRotate != Rotate.NONE) {
double alpha = this.alpha * Math.PI / 180.0;
double beta = this.beta * Math.PI / 180.0;
double sinA = Math.sin(alpha);
double cosA = Math.cos(alpha);
double sinB = Math.sin(beta);
double cosB = Math.cos(beta);
if (doRotate == Rotate.XY) {
double sinBsinA = sinB * sinA;
double cosBsinA = cosB * sinA;
double sinBcosA = sinB * cosA;
double cosBcosA = cosB * cosA;
for (int i = 0; i < pCount; i++) {
double dx = x[i] - zeroX;
double dy = y[i] - zeroY;
double dz = z[i];
x[i] = cosA * dx - sinBsinA * dy + cosBsinA * dz + zeroX;
y[i] = cosB * dy + sinB * dz + zeroY;
z[i] = -sinA * dx - sinBcosA * dy + cosBcosA * dz;
}
}
else if (doRotate == Rotate.YZ) {
double cosAcosB = cosA * cosB;
double sinAcosB = sinA * cosB;
double cosAsinB = cosA * sinB;
double sinAsinB = sinA * sinB;
for (int i = 0; i < pCount; i++) {
double dx = x[i] - zeroX;
double dy = y[i] - zeroY;
double dz = z[i];
x[i] = cosAcosB * dx + sinAcosB * dy + sinB * dz + zeroX;
y[i] = -sinA * dx + cosA * dy + zeroY;
z[i] = -cosAsinB * dx - sinAsinB * dy + cosB * dz;
}
}
else if (doRotate == Rotate.XZ) {
double cosBsinA = cosB * sinA;
double sinBsinA = sinB * sinA;
double cosBcosA = cosB * cosA;
double sinBcosA = sinB * cosA;
for (int i = 0; i < pCount; i++) {
double dx = x[i] - zeroX;
double dy = y[i] - zeroY;
double dz = z[i];
x[i] = cosA * dx + cosBsinA * dy + sinBsinA * dz + zeroX;
y[i] = -sinA * dx + cosBcosA * dy + sinBcosA * dz + zeroY;
z[i] = -sinB * dy + cosB * dz;
}
}
}
/* zoom it */
if (doZoom) {
double zoom = this.zoom;
for (int i = 0; i < pCount; i++) {
double dx = x[i] - zeroX;
double dy = y[i] - zeroY;
x[i] = dx * zoom + zeroX;
y[i] = dy * zoom + zeroY;
z[i] *= zoom;
}
}
/* add camera */
if (doCam) {
double camX = this.camX;
double camY = this.camY;
double camZ = this.camZ;
if (camZ > (-50.0))
camZ = -50.0;
for (int i = 0; i < pCount; i++) {
double dx = x[i];
double dy = y[i];
double dz = z[i];
dx -= camX;
dy += camY;
double ttf = camZ / ((double) camZ - dz);
dx *= ttf;
dy *= ttf;
dz *= ttf;
x[i] = dx;
y[i] = dy;
z[i] = dz;
}
}
}
private void render3D(Mesh3D pMesh3D, SimpleImage pImg) {
Mesh3DRenderer renderer;
if (light != Light.PHONG)
renderer = new Simple3DRenderer();
else
renderer = new Phong3DRenderer();
if (Math.abs(imgScale - 1.0) > MathLib.EPSILON) {
// scaled image
int width = (int) ((double) pImg.getImageWidth() * imgScale + 0.5);
int height = (int) ((double) pImg.getImageHeight() * imgScale + 0.5);
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
pImg.setBufferedImage(img, width, height);
// scaled mesh
Mesh3D mesh3D = pMesh3D.clone(imgScale);
// scaled params
double oCentreX = centreX;
double oCentreY = centreY;
double oCamX = camX;
double oCamY = camY;
double oCamZ = camZ;
double oLight1X = light1X;
double oLight1Y = light1Y;
double oLight1Z = light1Z;
double oLight2X = light2X;
double oLight2Y = light2Y;
double oLight2Z = light2Z;
double oLight3X = light3X;
double oLight3Y = light3Y;
double oLight3Z = light3Z;
double oLight4X = light4X;
double oLight4Y = light4Y;
double oLight4Z = light4Z;
double oPhongSize = phongSize;
try {
oCentreX *= imgScale;
oCentreY *= imgScale;
oCamX *= imgScale;
oCamY *= imgScale;
oCamZ *= imgScale;
oLight1X *= imgScale;
oLight1Y *= imgScale;
oLight1Z *= imgScale;
oLight2X *= imgScale;
oLight2Y *= imgScale;
oLight2Z *= imgScale;
oLight3X *= imgScale;
oLight3Y *= imgScale;
oLight3Z *= imgScale;
oLight4X *= imgScale;
oLight4Y *= imgScale;
oLight4Z *= imgScale;
oPhongSize *= imgScale;
// render
renderer.renderImage(mesh3D, this, pImg);
}
finally {
// reset params
centreX = oCentreX;
centreY = oCentreY;
camX = oCamX;
camY = oCamY;
camZ = oCamZ;
light1X = oLight1X;
light1Y = oLight1Y;
light1Z = oLight1Z;
light2X = oLight2X;
light2Y = oLight2Y;
light2Z = oLight2Z;
light3X = oLight3X;
light3Y = oLight3Y;
light3Z = oLight3Z;
light4X = oLight4X;
light4Y = oLight4Y;
light4Z = oLight4Z;
phongSize = oPhongSize;
}
}
else {
renderer.renderImage(pMesh3D, this, pImg);
}
/*
{*/
/* antialiasing */
/*
if(r3dSmoothing!=0) {
UBYTE r1,r2,r3,g1,g2,g3,b1,b2,b3,r,g,b,*dred,*dgreen,*dblue;
WORD av1,av2,av3,av,d1,d2,d3,rw1,k;
ULONG rv,gv,bv;
#ifdef SDEBUG
ULONG pixels;
#endif
rw1=width16-width+1;
for(k=0;k<r3dSmoothing;k++) {
dred=red;
dgreen=green;
dblue=blue;
#ifdef SDEBUG
pixels=0;
#endif
// copy 1st line
dred+=width16;dgreen+=width16;dblue+=width16;
for(i=1;i<(height-1);i++) {
// copy last pixel
dred++;dgreen++;dblue++;
// process pixels 2..width-1
for(j=1;j<(width-1);j++) {
r1=*(dred-width16);g1=*(dgreen-width16);b1=*(dblue-width16);
r2=*(dred+1);g2=*(dgreen+1);b2=*(dblue+1);
r3=*(dred+width16);g3=*(dgreen+width16);b3=*(dblue+width16);
r=*(dred);g=*(dgreen);b=*(dblue);
av1=((WORD)r1+(WORD)g1+(WORD)b1);av2=((WORD)r2+(WORD)g2+(WORD)b2);
av3=((WORD)r3+(WORD)g3+(WORD)b3);av=((WORD)r+(WORD)g+(WORD)b);
d1=av1-av;if(d1<0) d1=0-d1;d2=av2-av;if(d2<0) d2=0-d2;d3=av3-av;if(d3<0) d3=0-d3;
if((d1>64) && (d2>64)) {
rv=(LONG)r1*(LONG)d1+(LONG)r2*(LONG)d2;
rv/=(LONG)(d1+d2);rv+=(WORD)r;rv/=2;
gv=(LONG)g1*(LONG)d1+(LONG)g2*(LONG)d2;
gv/=(LONG)(d1+d2);gv+=(WORD)g;gv/=2;
bv=(LONG)b1*(LONG)d1+(LONG)b2*(LONG)d2;
bv/=(LONG)(d1+d2);bv+=(WORD)b;bv/=2;
*dred++=(UBYTE)rv;*dgreen++=(UBYTE)gv;*dblue++=(UBYTE)bv;
#ifdef SDEBUG
pixels++;
#endif
}
else if((d2>64) && (d3>64)) {
rv=(LONG)r2*(LONG)d2+(LONG)r3*(LONG)d3;
rv/=(LONG)(d2+d3);rv+=(WORD)r;rv/=2;
gv=(LONG)g2*(LONG)d2+(LONG)g3*(LONG)d3;
gv/=(LONG)(d2+d3);gv+=(WORD)g;gv/=2;
bv=(LONG)b2*(LONG)d2+(LONG)b3*(LONG)d3;
bv/=(LONG)(d2+d3);bv+=(WORD)b;bv/=2;
*dred++=(UBYTE)rv;*dgreen++=(UBYTE)gv;*dblue++=(UBYTE)bv;
#ifdef SDEBUG
pixels++;
#endif
}
else {
*dred++;*dgreen++;*dblue++;
}
}
// copy last pixel
dred+=rw1;dgreen+=rw1;dblue+=rw1;
}
#ifdef SDEBUG
printf("pixels: %ld\n",pixels);
#endif
}
}
}
*/
}
@Override
public void initDefaultParams(WFImage pImg) {
int width = pImg.getImageWidth();
int height = pImg.getImageHeight();
double rr = Math.sqrt(width * width + height * height);
light = Light.NORMAL;
faces = Faces.NORMAL;
doRotate = Rotate.XY;
alpha = 30.0;
beta = 40.0;
zoom = 1.40;
quant3D = 1.0;
centreX = Math.round((double) width / 2.05);
centreY = Math.round((double) height / 1.95);
doCam = true;
camX = Math.round(0.005 * rr);
camY = Math.round(-0.01 * rr);
camZ = Math.round(-4.0 * rr);
light1X = -200.0;
light1Y = 100.0;
light1Z = -600.0;
light1Color = new Color(255, 255, 255);
light2X = 200.0;
light2Y = 100.0;
light2Z = -600.0;
light2Color = new Color(0, 0, 0);
light3X = -200.0;
light3Y = -100.0;
light3Z = -600.0;
light3Color = new Color(0, 0, 0);
light4X = 200.0;
light4Y = -100.0;
light4Z = -600.0;
light4Color = new Color(0, 0, 0);
ambient = 0.06;
diffuse = 0.94;
phong = 0.900;
phongSize = Math.round(rr / 20.0);
phongAngle = 60.00;
smoothing = 1;
imgScale = 1.0;
}
@Override
public boolean acceptsInputBufferType(BufferType pBufferType) {
return (pBufferType == BufferType.IMAGE) || (pBufferType == BufferType.MESH3D);
}
public Light getLight() {
return light;
}
public void setLight(Light light) {
this.light = light;
}
public Faces getFaces() {
return faces;
}
public void setFaces(Faces faces) {
this.faces = faces;
}
public Rotate getDoRotate() {
return doRotate;
}
public void setDoRotate(Rotate doRotate) {
this.doRotate = doRotate;
}
public double getAlpha() {
return alpha;
}
public void setAlpha(double alpha) {
this.alpha = alpha;
}
public double getBeta() {
return beta;
}
public void setBeta(double beta) {
this.beta = beta;
}
public double getZoom() {
return zoom;
}
public void setZoom(double zoom) {
this.zoom = zoom;
}
public double getQuant3D() {
return quant3D;
}
public void setQuant3D(double quant3d) {
quant3D = quant3d;
}
public double getCentreX() {
return centreX;
}
public void setCentreX(double centreX) {
this.centreX = centreX;
}
public double getCentreY() {
return centreY;
}
public void setCentreY(double centreY) {
this.centreY = centreY;
}
public boolean isDoCam() {
return doCam;
}
public void setDoCam(boolean doCam) {
this.doCam = doCam;
}
public double getCamX() {
return camX;
}
public void setCamX(double camX) {
this.camX = camX;
}
public double getCamY() {
return camY;
}
public void setCamY(double camY) {
this.camY = camY;
}
public double getCamZ() {
return camZ;
}
public void setCamZ(double camZ) {
this.camZ = camZ;
}
public double getLight1X() {
return light1X;
}
public void setLight1X(double light1x) {
light1X = light1x;
}
public double getLight1Y() {
return light1Y;
}
public void setLight1Y(double light1y) {
light1Y = light1y;
}
public double getLight1Z() {
return light1Z;
}
public void setLight1Z(double light1z) {
light1Z = light1z;
}
public Color getLight1Color() {
return light1Color;
}
public void setLight1Color(Color light1Color) {
this.light1Color = light1Color;
}
public double getLight2X() {
return light2X;
}
public void setLight2X(double light2x) {
light2X = light2x;
}
public double getLight2Y() {
return light2Y;
}
public void setLight2Y(double light2y) {
light2Y = light2y;
}
public double getLight2Z() {
return light2Z;
}
public void setLight2Z(double light2z) {
light2Z = light2z;
}
public Color getLight2Color() {
return light2Color;
}
public void setLight2Color(Color light2Color) {
this.light2Color = light2Color;
}
public double getLight3X() {
return light3X;
}
public void setLight3X(double light3x) {
light3X = light3x;
}
public double getLight3Y() {
return light3Y;
}
public void setLight3Y(double light3y) {
light3Y = light3y;
}
public double getLight3Z() {
return light3Z;
}
public void setLight3Z(double light3z) {
light3Z = light3z;
}
public Color getLight3Color() {
return light3Color;
}
public void setLight3Color(Color light3Color) {
this.light3Color = light3Color;
}
public double getLight4X() {
return light4X;
}
public void setLight4X(double light4x) {
light4X = light4x;
}
public double getLight4Y() {
return light4Y;
}
public void setLight4Y(double light4y) {
light4Y = light4y;
}
public double getLight4Z() {
return light4Z;
}
public void setLight4Z(double light4z) {
light4Z = light4z;
}
public Color getLight4Color() {
return light4Color;
}
public void setLight4Color(Color light4Color) {
this.light4Color = light4Color;
}
public double getAmbient() {
return ambient;
}
public void setAmbient(double ambient) {
this.ambient = ambient;
}
public double getDiffuse() {
return diffuse;
}
public void setDiffuse(double diffuse) {
this.diffuse = diffuse;
}
public double getPhong() {
return phong;
}
public void setPhong(double phong) {
this.phong = phong;
}
public double getPhongSize() {
return phongSize;
}
public void setPhongSize(double phongSize) {
this.phongSize = phongSize;
}
public double getPhongAngle() {
return phongAngle;
}
public void setPhongAngle(double phongAngle) {
this.phongAngle = phongAngle;
}
public static class RotateEditor extends ComboBoxPropertyEditor {
public RotateEditor() {
super();
setAvailableValues(new Rotate[] { Rotate.XY, Rotate.YZ, Rotate.XZ, Rotate.NONE });
}
}
public static class LightEditor extends ComboBoxPropertyEditor {
public LightEditor() {
super();
setAvailableValues(new Light[] { Light.NORMAL, Light.PHONG, Light.OFF });
}
}
public static class FacesEditor extends ComboBoxPropertyEditor {
public FacesEditor() {
super();
setAvailableValues(new Faces[] { Faces.NORMAL, Faces.DOUBLE, Faces.MIRRORED });
}
}
@Override
public boolean supports3DOutput() {
return true;
}
protected void applySmoothing(SimpleImage pImg, int pSmoothingAmount) {
int width = pImg.getImageWidth();
int height = pImg.getImageHeight();
Pixel pixel = new Pixel();
for (int k = 0; k < pSmoothingAmount; k++) {
for (int i = 1; i < (height - 1); i++) {
/* process pixels 2..width-1 */
for (int j = 1; j < (width - 1); j++) {
pixel.setARGBValue(pImg.getARGBValue(j, i - 1));
int r1 = pixel.r;
int g1 = pixel.g;
int b1 = pixel.b;
pixel.setARGBValue(pImg.getARGBValue(j + 1, i));
int r2 = pixel.r;
int g2 = pixel.g;
int b2 = pixel.b;
pixel.setARGBValue(pImg.getARGBValue(j, i + 1));
int r3 = pixel.r;
int g3 = pixel.g;
int b3 = pixel.b;
pixel.setARGBValue(pImg.getARGBValue(j, i));
int r = pixel.r;
int g = pixel.g;
int b = pixel.b;
int av1 = (r1 + g1 + b1);
int av2 = (r2 + g2 + b2);
int av3 = (r3 + g3 + b3);
int av = (r + g + b);
int d1 = av1 - av;
if (d1 < 0)
d1 = 0 - d1;
int d2 = av2 - av;
if (d2 < 0)
d2 = 0 - d2;
int d3 = av3 - av;
if (d3 < 0)
d3 = 0 - d3;
if ((d1 > 64) && (d2 > 64)) {
int rv = r1 * d1 + r2 * d2;
rv /= (d1 + d2);
rv += r;
rv /= 2;
int gv = g1 * d1 + g2 * d2;
gv /= (d1 + d2);
gv += g;
gv /= 2;
int bv = b1 * d1 + b2 * d2;
bv /= (d1 + d2);
bv += b;
bv /= 2;
pImg.setRGB(j, i, rv, gv, bv);
}
else if ((d2 > 64) && (d3 > 64)) {
int rv = r2 * d2 + r3 * d3;
rv /= (d2 + d3);
rv += r;
rv /= 2;
int gv = g2 * d2 + g3 * d3;
gv /= (d2 + d3);
gv += g;
gv /= 2;
int bv = b2 * d2 + b3 * d3;
bv /= (d2 + d3);
bv += b;
bv /= 2;
pImg.setRGB(j, i, rv, gv, bv);
}
}
}
}
}
public int getSmoothing() {
return smoothing;
}
public void setSmoothing(int smoothing) {
this.smoothing = smoothing;
}
public double getImgScale() {
return imgScale;
}
public void setImgScale(double imgScale) {
this.imgScale = imgScale;
}
}