aboutsummaryrefslogtreecommitdiff
path: root/engine/src/blender/com/jme3/scene/plugins/blender/textures/blending/TextureBlenderAWT.java
blob: 918072e41227858c1cd57e65a4b48289f6c94cde (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
package com.jme3.scene.plugins.blender.textures.blending;

import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.jme3.scene.plugins.blender.BlenderContext;
import com.jme3.texture.Image;
import com.jme3.texture.Texture;
import com.jme3.texture.Texture2D;
import com.jme3.texture.Texture3D;
import com.jme3.texture.Image.Format;
import com.jme3.util.BufferUtils;

/**
 * The class that is responsible for blending the following texture types:
 * <li> RGBA8
 * <li> ABGR8
 * <li> BGR8
 * <li> RGB8
 * Not yet supported (but will be):
 * <li> ARGB4444:
 * <li> RGB10:
 * <li> RGB111110F:
 * <li> RGB16:
 * <li> RGB16F:
 * <li> RGB16F_to_RGB111110F:
 * <li> RGB16F_to_RGB9E5:
 * <li> RGB32F:
 * <li> RGB565:
 * <li> RGB5A1:
 * <li> RGB9E5:
 * <li> RGBA16:
 * <li> RGBA16F
 * @author Marcin Roguski (Kaelthas)
 */
public class TextureBlenderAWT extends AbstractTextureBlender {
	private static final Logger	LOGGER	= Logger.getLogger(TextureBlenderAWT.class.getName());

	@Override
	public Texture blend(float[] materialColor, Texture texture, float[] color, float affectFactor, int blendType, boolean neg, BlenderContext blenderContext) {
		float[] pixelColor = new float[] { color[0], color[1], color[2], 1.0f };
		Format format = texture.getImage().getFormat();
		ByteBuffer data = texture.getImage().getData(0);
		data.rewind();

		int width = texture.getImage().getWidth();
		int height = texture.getImage().getHeight();
		int depth = texture.getImage().getDepth();
		if (depth == 0) {
			depth = 1;
		}
		ByteBuffer newData = BufferUtils.createByteBuffer(width * height * depth * 4);

		float[] resultPixel = new float[4];
		int dataIndex = 0;
		while (data.hasRemaining()) {
			this.setupMaterialColor(data, format, neg, pixelColor);
			this.blendPixel(resultPixel, materialColor, pixelColor, affectFactor, blendType, blenderContext);
			newData.put(dataIndex++, (byte) (resultPixel[0] * 255.0f));
			newData.put(dataIndex++, (byte) (resultPixel[1] * 255.0f));
			newData.put(dataIndex++, (byte) (resultPixel[2] * 255.0f));
			newData.put(dataIndex++, (byte) (pixelColor[3] * 255.0f));
		}
		if (texture.getType() == Texture.Type.TwoDimensional) {
			return new Texture2D(new Image(Format.RGBA8, width, height, newData));
		} else {
			ArrayList<ByteBuffer> dataArray = new ArrayList<ByteBuffer>(1);
			dataArray.add(newData);
			return new Texture3D(new Image(Format.RGBA8, width, height, depth, dataArray));
		}
	}

	/**
	 * This method alters the material color in a way dependent on the type of
	 * the image. For example the color remains untouched if the texture is of
	 * Luminance type. The luminance defines the interaction between the
	 * material color and color defined for texture blending. If the type has 3
	 * or more color channels then the material color is replaced with the
	 * texture's color and later blended with the defined blend color. All alpha
	 * values (if present) are ignored and not used during blending.
	 * 
	 * @param data
	 *            the image data
	 * @param imageFormat
	 *            the format of the image
	 * @param neg
	 *            defines it the result color should be nagated
	 * @param materialColor
	 *            the material's color (value may be changed)
	 * @return texture intensity for the current pixel
	 */
	protected float setupMaterialColor(ByteBuffer data, Format imageFormat, boolean neg, float[] materialColor) {
		float tin = 0.0f;
		byte pixelValue = data.get();// at least one byte is always taken :)
		float firstPixelValue = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
		switch (imageFormat) {
			case RGBA8:
				materialColor[0] = firstPixelValue;
				pixelValue = data.get();
				materialColor[1] = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
				pixelValue = data.get();
				materialColor[2] = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
				pixelValue = data.get();
				materialColor[3] = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
				break;
			case ABGR8:
				materialColor[3] = firstPixelValue;
				pixelValue = data.get();
				materialColor[2] = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
				pixelValue = data.get();
				materialColor[1] = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
				pixelValue = data.get();
				materialColor[0] = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
				break;
			case BGR8:
				materialColor[2] = firstPixelValue;
				pixelValue = data.get();
				materialColor[1] = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
				pixelValue = data.get();
				materialColor[0] = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
				materialColor[3] = 1.0f;
				break;
			case RGB8:
				materialColor[0] = firstPixelValue;
				pixelValue = data.get();
				materialColor[1] = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
				pixelValue = data.get();
				materialColor[2] = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
				materialColor[3] = 1.0f;
				break;
			case ARGB4444:
			case RGB10:
			case RGB111110F:
			case RGB16:
			case RGB16F:
			case RGB16F_to_RGB111110F:
			case RGB16F_to_RGB9E5:
			case RGB32F:
			case RGB565:
			case RGB5A1:
			case RGB9E5:
			case RGBA16:
			case RGBA16F:
			case RGBA32F:// TODO: implement these textures
				LOGGER.log(Level.WARNING, "Image type not yet supported for blending: {0}", imageFormat);
				break;
			default:
				throw new IllegalStateException("Invalid image format type for AWT texture blender: " + imageFormat);
		}
		if (neg) {
			materialColor[0] = 1.0f - materialColor[0];
			materialColor[1] = 1.0f - materialColor[1];
			materialColor[2] = 1.0f - materialColor[2];
		}
		// Blender formula for texture intensity calculation:
		// 0.35*texres.tr+0.45*texres.tg+0.2*texres.tb
		tin = 0.35f * materialColor[0] + 0.45f * materialColor[1] + 0.2f * materialColor[2];
		return tin;
	}
}