159b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartapackage com.jme3.scene.plugins.blender.textures.blending;
259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
359b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.nio.ByteBuffer;
459b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.util.ArrayList;
559b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.util.logging.Level;
659b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.util.logging.Logger;
759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
859b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.plugins.blender.BlenderContext;
959b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.texture.Image;
1059b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.texture.Texture;
1159b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.texture.Texture2D;
1259b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.texture.Texture3D;
1359b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.texture.Image.Format;
1459b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.util.BufferUtils;
1559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
1659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta/**
1759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * The class that is responsible for blending the following texture types:
1859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * <li> RGBA8
1959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * <li> ABGR8
2059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * <li> BGR8
2159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * <li> RGB8
2259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Not yet supported (but will be):
2359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * <li> ARGB4444:
2459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * <li> RGB10:
2559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * <li> RGB111110F:
2659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * <li> RGB16:
2759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * <li> RGB16F:
2859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * <li> RGB16F_to_RGB111110F:
2959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * <li> RGB16F_to_RGB9E5:
3059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * <li> RGB32F:
3159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * <li> RGB565:
3259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * <li> RGB5A1:
3359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * <li> RGB9E5:
3459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * <li> RGBA16:
3559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * <li> RGBA16F
3659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @author Marcin Roguski (Kaelthas)
3759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */
3859b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartapublic class TextureBlenderAWT extends AbstractTextureBlender {
3959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	private static final Logger	LOGGER	= Logger.getLogger(TextureBlenderAWT.class.getName());
4059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
4159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	@Override
4259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public Texture blend(float[] materialColor, Texture texture, float[] color, float affectFactor, int blendType, boolean neg, BlenderContext blenderContext) {
4359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		float[] pixelColor = new float[] { color[0], color[1], color[2], 1.0f };
4459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		Format format = texture.getImage().getFormat();
4559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		ByteBuffer data = texture.getImage().getData(0);
4659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		data.rewind();
4759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
4859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		int width = texture.getImage().getWidth();
4959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		int height = texture.getImage().getHeight();
5059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		int depth = texture.getImage().getDepth();
5159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		if (depth == 0) {
5259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			depth = 1;
5359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		}
5459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		ByteBuffer newData = BufferUtils.createByteBuffer(width * height * depth * 4);
5559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
5659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		float[] resultPixel = new float[4];
5759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		int dataIndex = 0;
5859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		while (data.hasRemaining()) {
59a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta			this.setupMaterialColor(data, format, neg, pixelColor);
60a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta			this.blendPixel(resultPixel, materialColor, pixelColor, affectFactor, blendType, blenderContext);
6159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			newData.put(dataIndex++, (byte) (resultPixel[0] * 255.0f));
6259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			newData.put(dataIndex++, (byte) (resultPixel[1] * 255.0f));
6359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			newData.put(dataIndex++, (byte) (resultPixel[2] * 255.0f));
6459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			newData.put(dataIndex++, (byte) (pixelColor[3] * 255.0f));
6559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		}
6659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		if (texture.getType() == Texture.Type.TwoDimensional) {
6759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			return new Texture2D(new Image(Format.RGBA8, width, height, newData));
6859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		} else {
6959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			ArrayList<ByteBuffer> dataArray = new ArrayList<ByteBuffer>(1);
7059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			dataArray.add(newData);
7159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			return new Texture3D(new Image(Format.RGBA8, width, height, depth, dataArray));
7259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		}
7359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	}
7459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
7559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	/**
7659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * This method alters the material color in a way dependent on the type of
7759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * the image. For example the color remains untouched if the texture is of
7859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * Luminance type. The luminance defines the interaction between the
7959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * material color and color defined for texture blending. If the type has 3
8059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * or more color channels then the material color is replaced with the
8159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * texture's color and later blended with the defined blend color. All alpha
8259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * values (if present) are ignored and not used during blending.
8359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 *
8459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * @param data
8559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 *            the image data
8659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * @param imageFormat
8759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 *            the format of the image
8859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * @param neg
8959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 *            defines it the result color should be nagated
9059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * @param materialColor
9159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 *            the material's color (value may be changed)
9259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * @return texture intensity for the current pixel
9359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 */
9459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	protected float setupMaterialColor(ByteBuffer data, Format imageFormat, boolean neg, float[] materialColor) {
9559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		float tin = 0.0f;
9659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		byte pixelValue = data.get();// at least one byte is always taken :)
9759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		float firstPixelValue = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
9859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		switch (imageFormat) {
9959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			case RGBA8:
10059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				materialColor[0] = firstPixelValue;
10159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				pixelValue = data.get();
10259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				materialColor[1] = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
10359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				pixelValue = data.get();
10459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				materialColor[2] = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
10559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				pixelValue = data.get();
10659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				materialColor[3] = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
10759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				break;
10859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			case ABGR8:
10959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				materialColor[3] = firstPixelValue;
11059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				pixelValue = data.get();
11159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				materialColor[2] = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
11259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				pixelValue = data.get();
11359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				materialColor[1] = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
11459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				pixelValue = data.get();
11559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				materialColor[0] = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
11659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				break;
11759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			case BGR8:
11859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				materialColor[2] = firstPixelValue;
11959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				pixelValue = data.get();
12059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				materialColor[1] = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
12159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				pixelValue = data.get();
12259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				materialColor[0] = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
12359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				materialColor[3] = 1.0f;
12459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				break;
12559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			case RGB8:
12659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				materialColor[0] = firstPixelValue;
12759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				pixelValue = data.get();
12859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				materialColor[1] = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
12959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				pixelValue = data.get();
13059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				materialColor[2] = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
13159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				materialColor[3] = 1.0f;
13259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				break;
13359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			case ARGB4444:
13459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			case RGB10:
13559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			case RGB111110F:
13659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			case RGB16:
13759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			case RGB16F:
13859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			case RGB16F_to_RGB111110F:
13959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			case RGB16F_to_RGB9E5:
14059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			case RGB32F:
14159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			case RGB565:
14259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			case RGB5A1:
14359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			case RGB9E5:
14459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			case RGBA16:
14559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			case RGBA16F:
14659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			case RGBA32F:// TODO: implement these textures
14759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				LOGGER.log(Level.WARNING, "Image type not yet supported for blending: {0}", imageFormat);
14859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				break;
14959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			default:
15059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				throw new IllegalStateException("Invalid image format type for AWT texture blender: " + imageFormat);
15159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		}
15259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		if (neg) {
15359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			materialColor[0] = 1.0f - materialColor[0];
15459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			materialColor[1] = 1.0f - materialColor[1];
15559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			materialColor[2] = 1.0f - materialColor[2];
15659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		}
15759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		// Blender formula for texture intensity calculation:
15859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		// 0.35*texres.tr+0.45*texres.tg+0.2*texres.tb
15959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		tin = 0.35f * materialColor[0] + 0.45f * materialColor[1] + 0.2f * materialColor[2];
16059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		return tin;
16159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	}
16259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta}
163