1package com.jme3.scene.plugins.blender.textures.blending;
2
3import java.nio.ByteBuffer;
4import java.util.ArrayList;
5import java.util.logging.Level;
6import java.util.logging.Logger;
7
8import com.jme3.scene.plugins.blender.BlenderContext;
9import com.jme3.texture.Image;
10import com.jme3.texture.Texture;
11import com.jme3.texture.Texture2D;
12import com.jme3.texture.Texture3D;
13import com.jme3.texture.Image.Format;
14import com.jme3.util.BufferUtils;
15
16/**
17 * The class that is responsible for blending the following texture types:
18 * <li> RGBA8
19 * <li> ABGR8
20 * <li> BGR8
21 * <li> RGB8
22 * Not yet supported (but will be):
23 * <li> ARGB4444:
24 * <li> RGB10:
25 * <li> RGB111110F:
26 * <li> RGB16:
27 * <li> RGB16F:
28 * <li> RGB16F_to_RGB111110F:
29 * <li> RGB16F_to_RGB9E5:
30 * <li> RGB32F:
31 * <li> RGB565:
32 * <li> RGB5A1:
33 * <li> RGB9E5:
34 * <li> RGBA16:
35 * <li> RGBA16F
36 * @author Marcin Roguski (Kaelthas)
37 */
38public class TextureBlenderAWT extends AbstractTextureBlender {
39	private static final Logger	LOGGER	= Logger.getLogger(TextureBlenderAWT.class.getName());
40
41	@Override
42	public Texture blend(float[] materialColor, Texture texture, float[] color, float affectFactor, int blendType, boolean neg, BlenderContext blenderContext) {
43		float[] pixelColor = new float[] { color[0], color[1], color[2], 1.0f };
44		Format format = texture.getImage().getFormat();
45		ByteBuffer data = texture.getImage().getData(0);
46		data.rewind();
47
48		int width = texture.getImage().getWidth();
49		int height = texture.getImage().getHeight();
50		int depth = texture.getImage().getDepth();
51		if (depth == 0) {
52			depth = 1;
53		}
54		ByteBuffer newData = BufferUtils.createByteBuffer(width * height * depth * 4);
55
56		float[] resultPixel = new float[4];
57		int dataIndex = 0;
58		while (data.hasRemaining()) {
59			this.setupMaterialColor(data, format, neg, pixelColor);
60			this.blendPixel(resultPixel, materialColor, pixelColor, affectFactor, blendType, blenderContext);
61			newData.put(dataIndex++, (byte) (resultPixel[0] * 255.0f));
62			newData.put(dataIndex++, (byte) (resultPixel[1] * 255.0f));
63			newData.put(dataIndex++, (byte) (resultPixel[2] * 255.0f));
64			newData.put(dataIndex++, (byte) (pixelColor[3] * 255.0f));
65		}
66		if (texture.getType() == Texture.Type.TwoDimensional) {
67			return new Texture2D(new Image(Format.RGBA8, width, height, newData));
68		} else {
69			ArrayList<ByteBuffer> dataArray = new ArrayList<ByteBuffer>(1);
70			dataArray.add(newData);
71			return new Texture3D(new Image(Format.RGBA8, width, height, depth, dataArray));
72		}
73	}
74
75	/**
76	 * This method alters the material color in a way dependent on the type of
77	 * the image. For example the color remains untouched if the texture is of
78	 * Luminance type. The luminance defines the interaction between the
79	 * material color and color defined for texture blending. If the type has 3
80	 * or more color channels then the material color is replaced with the
81	 * texture's color and later blended with the defined blend color. All alpha
82	 * values (if present) are ignored and not used during blending.
83	 *
84	 * @param data
85	 *            the image data
86	 * @param imageFormat
87	 *            the format of the image
88	 * @param neg
89	 *            defines it the result color should be nagated
90	 * @param materialColor
91	 *            the material's color (value may be changed)
92	 * @return texture intensity for the current pixel
93	 */
94	protected float setupMaterialColor(ByteBuffer data, Format imageFormat, boolean neg, float[] materialColor) {
95		float tin = 0.0f;
96		byte pixelValue = data.get();// at least one byte is always taken :)
97		float firstPixelValue = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
98		switch (imageFormat) {
99			case RGBA8:
100				materialColor[0] = firstPixelValue;
101				pixelValue = data.get();
102				materialColor[1] = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
103				pixelValue = data.get();
104				materialColor[2] = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
105				pixelValue = data.get();
106				materialColor[3] = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
107				break;
108			case ABGR8:
109				materialColor[3] = firstPixelValue;
110				pixelValue = data.get();
111				materialColor[2] = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
112				pixelValue = data.get();
113				materialColor[1] = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
114				pixelValue = data.get();
115				materialColor[0] = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
116				break;
117			case BGR8:
118				materialColor[2] = firstPixelValue;
119				pixelValue = data.get();
120				materialColor[1] = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
121				pixelValue = data.get();
122				materialColor[0] = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
123				materialColor[3] = 1.0f;
124				break;
125			case RGB8:
126				materialColor[0] = firstPixelValue;
127				pixelValue = data.get();
128				materialColor[1] = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
129				pixelValue = data.get();
130				materialColor[2] = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
131				materialColor[3] = 1.0f;
132				break;
133			case ARGB4444:
134			case RGB10:
135			case RGB111110F:
136			case RGB16:
137			case RGB16F:
138			case RGB16F_to_RGB111110F:
139			case RGB16F_to_RGB9E5:
140			case RGB32F:
141			case RGB565:
142			case RGB5A1:
143			case RGB9E5:
144			case RGBA16:
145			case RGBA16F:
146			case RGBA32F:// TODO: implement these textures
147				LOGGER.log(Level.WARNING, "Image type not yet supported for blending: {0}", imageFormat);
148				break;
149			default:
150				throw new IllegalStateException("Invalid image format type for AWT texture blender: " + imageFormat);
151		}
152		if (neg) {
153			materialColor[0] = 1.0f - materialColor[0];
154			materialColor[1] = 1.0f - materialColor[1];
155			materialColor[2] = 1.0f - materialColor[2];
156		}
157		// Blender formula for texture intensity calculation:
158		// 0.35*texres.tr+0.45*texres.tg+0.2*texres.tb
159		tin = 0.35f * materialColor[0] + 0.45f * materialColor[1] + 0.2f * materialColor[2];
160		return tin;
161	}
162}
163