playn.java.BlendComposite Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of playn-java-base Show documentation
Show all versions of playn-java-base Show documentation
Code shared by all PlayN Java (JVM) backends
/**
* Copyright 2012 The PlayN Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package playn.java;
import java.awt.Composite;
import java.awt.CompositeContext;
import java.awt.RenderingHints;
import java.awt.image.ColorModel;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;
/**
* Handles non-Porter-Duff image composition.
*/
public class BlendComposite implements Composite {
/** A blend composite that yields [ Sa * Da, Sc * Dc]. */
public static final BlendComposite Multiply = new BlendComposite(new Blender() {
@Override
protected int blend (int srcA, int srcR, int srcG, int srcB,
int dstA, int dstR, int dstG, int dstB, float alpha) {
return compose(srcA + dstA - (srcA*dstA)/255,
(srcR * dstR) >> 8,
(srcG * dstG) >> 8,
(srcB * dstB) >> 8,
dstA, dstR, dstG, dstB, alpha);
}
});
private final Blender blender;
private final float alpha;
private final CompositeContext context = new CompositeContext() {
@Override
public void compose(Raster src, Raster dstIn, WritableRaster dstOut) {
int width = Math.min(src.getWidth(), dstIn.getWidth());
int height = Math.min(src.getHeight(), dstIn.getHeight());
int[] srcPixels = new int[width], dstPixels = new int[width];
for (int yy = 0; yy < height; yy++) {
src.getDataElements(0, yy, width, 1, srcPixels);
dstIn.getDataElements(0, yy, width, 1, dstPixels);
blender.blend(srcPixels, dstPixels, width, alpha);
dstOut.setDataElements(0, yy, width, 1, dstPixels);
}
}
@Override
public void dispose() {
// nada
}
};
/** Returns a derived composite with the specified alpha. */
public BlendComposite derive(float alpha) {
return (alpha == this.alpha) ? this : new BlendComposite(blender, alpha);
}
@Override
public CompositeContext createContext(ColorModel srcColorModel, ColorModel dstColorModel,
RenderingHints hints) {
return context; // our context maintains no state
}
protected BlendComposite(Blender blender) {
this(blender, 1f);
}
protected BlendComposite(Blender blender, float alpha) {
this.blender = blender;
this.alpha = alpha;
}
protected static abstract class Blender {
public void blend (int[] srcPixels, int[] dstPixels, int width, float alpha) {
for (int xx = 0; xx < width; xx++) {
// pixels are stored as INT_ARGB
int srcARGB = srcPixels[xx], dstARGB = dstPixels[xx];
int srcA = (srcARGB >> 24) & 0xFF, dstA = (dstARGB >> 24) & 0xFF;
int srcR = (srcARGB >> 16) & 0xFF, dstR = (dstARGB >> 16) & 0xFF;
int srcG = (srcARGB >> 8) & 0xFF, dstG = (dstARGB >> 8) & 0xFF;
int srcB = (srcARGB ) & 0xFF, dstB = (dstARGB ) & 0xFF;
dstPixels[xx] = blend(srcA, srcR, srcG, srcB, dstA, dstR, dstG, dstB, alpha);
}
}
protected abstract int blend (int srcA, int srcR, int srcG, int srcB,
int dstA, int dstR, int dstG, int dstB, float alpha);
protected int compose (int a, int r, int g, int b, int dstA, int dstR, int dstG, int dstB,
float alpha) {
return ((0xFF & (int) (dstA + (a - dstA) * alpha)) << 24 |
(0xFF & (int) (dstR + (r - dstR) * alpha)) << 16 |
(0xFF & (int) (dstG + (g - dstG) * alpha)) << 8 |
(0xFF & (int) (dstB + (b - dstB) * alpha)));
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy