1 package com.jme3.scene.plugins.blender.textures.blending;
2 
3 import java.nio.ByteBuffer;
4 import java.util.ArrayList;
5 import java.util.logging.Level;
6 import java.util.logging.Logger;
7 
8 import com.jme3.math.FastMath;
9 import com.jme3.scene.plugins.blender.BlenderContext;
10 import com.jme3.texture.Image;
11 import com.jme3.texture.Texture;
12 import com.jme3.texture.Texture2D;
13 import com.jme3.texture.Texture3D;
14 import com.jme3.texture.Image.Format;
15 import com.jme3.util.BufferUtils;
16 
17 /**
18  * The class that is responsible for blending the following texture types:
19  * <li> Luminance8
20  * <li> Luminance8Alpha8
21  * Not yet supported (but will be):
22  * <li> Luminance16:
23  * <li> Luminance16Alpha16:
24  * <li> Luminance16F:
25  * <li> Luminance16FAlpha16F:
26  * <li> Luminance32F:
27  * @author Marcin Roguski (Kaelthas)
28  */
29 public class TextureBlenderLuminance extends AbstractTextureBlender {
30 	private static final Logger	LOGGER	= Logger.getLogger(TextureBlenderLuminance.class.getName());
31 
32 	@Override
blend(float[] materialColor, Texture texture, float[] color, float affectFactor, int blendType, boolean neg, BlenderContext blenderContext)33 	public Texture blend(float[] materialColor, Texture texture, float[] color, float affectFactor, int blendType, boolean neg, BlenderContext blenderContext) {
34 		Format format = texture.getImage().getFormat();
35 		ByteBuffer data = texture.getImage().getData(0);
36 		data.rewind();
37 
38 		int width = texture.getImage().getWidth();
39 		int height = texture.getImage().getHeight();
40 		int depth = texture.getImage().getDepth();
41 		if (depth == 0) {
42 			depth = 1;
43 		}
44 		ByteBuffer newData = BufferUtils.createByteBuffer(width * height * depth * 4);
45 
46 		float[] resultPixel = new float[4];
47 		float[] tinAndAlpha = new float[2];
48 		int dataIndex = 0;
49 		while (data.hasRemaining()) {
50 			this.getTinAndAlpha(data, format, neg, tinAndAlpha);
51 			this.blendPixel(resultPixel, materialColor, color, tinAndAlpha[0], affectFactor, blendType, blenderContext);
52 			newData.put(dataIndex++, (byte) (resultPixel[0] * 255.0f));
53 			newData.put(dataIndex++, (byte) (resultPixel[1] * 255.0f));
54 			newData.put(dataIndex++, (byte) (resultPixel[2] * 255.0f));
55 			newData.put(dataIndex++, (byte) (tinAndAlpha[1] * 255.0f));
56 		}
57 		if (texture.getType() == Texture.Type.TwoDimensional) {
58 			return new Texture2D(new Image(Format.RGBA8, width, height, newData));
59 		} else {
60 			ArrayList<ByteBuffer> dataArray = new ArrayList<ByteBuffer>(1);
61 			dataArray.add(newData);
62 			return new Texture3D(new Image(Format.RGBA8, width, height, depth, dataArray));
63 		}
64 	}
65 
66 	/**
67 	 * This method return texture intensity and alpha value.
68 	 *
69 	 * @param data
70 	 *            the texture data
71 	 * @param imageFormat
72 	 *            the image format
73 	 * @param neg
74 	 *            indicates if the texture is negated
75 	 * @param result
76 	 *            the table (2 elements) where the result is being stored
77 	 */
getTinAndAlpha(ByteBuffer data, Format imageFormat, boolean neg, float[] result)78 	protected void getTinAndAlpha(ByteBuffer data, Format imageFormat, boolean neg, float[] result) {
79 		byte pixelValue = data.get();// at least one byte is always taken
80 		float firstPixelValue = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
81 		switch (imageFormat) {
82 			case Luminance8:
83 				result[0] = neg ? 1.0f - firstPixelValue : firstPixelValue;
84 				result[1] = 1.0f;
85 				break;
86 			case Luminance8Alpha8:
87 				result[0] = neg ? 1.0f - firstPixelValue : firstPixelValue;
88 				pixelValue = data.get();
89 				result[1] = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
90 				break;
91 			case Luminance16:
92 			case Luminance16Alpha16:
93 			case Luminance16F:
94 			case Luminance16FAlpha16F:
95 			case Luminance32F:
96 				LOGGER.log(Level.WARNING, "Image type not yet supported for blending: {0}", imageFormat);
97 				break;
98 			default:
99 				throw new IllegalStateException("Invalid image format type for DDS texture blender: " + imageFormat);
100 		}
101 	}
102 
103 	/**
104 	 * This method blends the texture with an appropriate color.
105 	 *
106 	 * @param result
107 	 *            the result color (variable 'in' in blender source code)
108 	 * @param materialColor
109 	 *            the texture color (variable 'out' in blender source coude)
110 	 * @param color
111 	 *            the previous color (variable 'tex' in blender source code)
112 	 * @param textureIntensity
113 	 *            texture intensity (variable 'fact' in blender source code)
114 	 * @param textureFactor
115 	 *            texture affection factor (variable 'facg' in blender source
116 	 *            code)
117 	 * @param blendtype
118 	 *            the blend type
119 	 * @param blenderContext
120 	 *            the blender context
121 	 */
blendPixel(float[] result, float[] materialColor, float[] color, float textureIntensity, float textureFactor, int blendtype, BlenderContext blenderContext)122 	protected void blendPixel(float[] result, float[] materialColor, float[] color, float textureIntensity, float textureFactor, int blendtype, BlenderContext blenderContext) {
123 		float oneMinusFactor, col;
124 		textureIntensity *= textureFactor;
125 
126 		switch (blendtype) {
127 			case MTEX_BLEND:
128 				oneMinusFactor = 1.0f - textureIntensity;
129 				result[0] = textureIntensity * color[0] + oneMinusFactor * materialColor[0];
130 				result[1] = textureIntensity * color[1] + oneMinusFactor * materialColor[1];
131 				result[2] = textureIntensity * color[2] + oneMinusFactor * materialColor[2];
132 				break;
133 			case MTEX_MUL:
134 				oneMinusFactor = 1.0f - textureFactor;
135 				result[0] = (oneMinusFactor + textureIntensity * materialColor[0]) * color[0];
136 				result[1] = (oneMinusFactor + textureIntensity * materialColor[1]) * color[1];
137 				result[2] = (oneMinusFactor + textureIntensity * materialColor[2]) * color[2];
138 				break;
139 			case MTEX_DIV:
140 				oneMinusFactor = 1.0f - textureIntensity;
141 				if (color[0] != 0.0) {
142 					result[0] = (oneMinusFactor * materialColor[0] + textureIntensity * materialColor[0] / color[0]) * 0.5f;
143 				}
144 				if (color[1] != 0.0) {
145 					result[1] = (oneMinusFactor * materialColor[1] + textureIntensity * materialColor[1] / color[1]) * 0.5f;
146 				}
147 				if (color[2] != 0.0) {
148 					result[2] = (oneMinusFactor * materialColor[2] + textureIntensity * materialColor[2] / color[2]) * 0.5f;
149 				}
150 				break;
151 			case MTEX_SCREEN:
152 				oneMinusFactor = 1.0f - textureFactor;
153 				result[0] = 1.0f - (oneMinusFactor + textureIntensity * (1.0f - materialColor[0])) * (1.0f - color[0]);
154 				result[1] = 1.0f - (oneMinusFactor + textureIntensity * (1.0f - materialColor[1])) * (1.0f - color[1]);
155 				result[2] = 1.0f - (oneMinusFactor + textureIntensity * (1.0f - materialColor[2])) * (1.0f - color[2]);
156 				break;
157 			case MTEX_OVERLAY:
158 				oneMinusFactor = 1.0f - textureFactor;
159 				if (materialColor[0] < 0.5f) {
160 					result[0] = color[0] * (oneMinusFactor + 2.0f * textureIntensity * materialColor[0]);
161 				} else {
162 					result[0] = 1.0f - (oneMinusFactor + 2.0f * textureIntensity * (1.0f - materialColor[0])) * (1.0f - color[0]);
163 				}
164 				if (materialColor[1] < 0.5f) {
165 					result[1] = color[1] * (oneMinusFactor + 2.0f * textureIntensity * materialColor[1]);
166 				} else {
167 					result[1] = 1.0f - (oneMinusFactor + 2.0f * textureIntensity * (1.0f - materialColor[1])) * (1.0f - color[1]);
168 				}
169 				if (materialColor[2] < 0.5f) {
170 					result[2] = color[2] * (oneMinusFactor + 2.0f * textureIntensity * materialColor[2]);
171 				} else {
172 					result[2] = 1.0f - (oneMinusFactor + 2.0f * textureIntensity * (1.0f - materialColor[2])) * (1.0f - color[2]);
173 				}
174 				break;
175 			case MTEX_SUB:
176 				result[0] = materialColor[0] - textureIntensity * color[0];
177 				result[1] = materialColor[1] - textureIntensity * color[1];
178 				result[2] = materialColor[2] - textureIntensity * color[2];
179 				result[0] = FastMath.clamp(result[0], 0.0f, 1.0f);
180 				result[1] = FastMath.clamp(result[1], 0.0f, 1.0f);
181 				result[2] = FastMath.clamp(result[2], 0.0f, 1.0f);
182 				break;
183 			case MTEX_ADD:
184 				result[0] = (textureIntensity * color[0] + materialColor[0]) * 0.5f;
185 				result[1] = (textureIntensity * color[1] + materialColor[1]) * 0.5f;
186 				result[2] = (textureIntensity * color[2] + materialColor[2]) * 0.5f;
187 				break;
188 			case MTEX_DIFF:
189 				oneMinusFactor = 1.0f - textureIntensity;
190 				result[0] = oneMinusFactor * materialColor[0] + textureIntensity * Math.abs(materialColor[0] - color[0]);
191 				result[1] = oneMinusFactor * materialColor[1] + textureIntensity * Math.abs(materialColor[1] - color[1]);
192 				result[2] = oneMinusFactor * materialColor[2] + textureIntensity * Math.abs(materialColor[2] - color[2]);
193 				break;
194 			case MTEX_DARK:
195 				col = textureIntensity * color[0];
196 				result[0] = col < materialColor[0] ? col : materialColor[0];
197 				col = textureIntensity * color[1];
198 				result[1] = col < materialColor[1] ? col : materialColor[1];
199 				col = textureIntensity * color[2];
200 				result[2] = col < materialColor[2] ? col : materialColor[2];
201 				break;
202 			case MTEX_LIGHT:
203 				col = textureIntensity * color[0];
204 				result[0] = col > materialColor[0] ? col : materialColor[0];
205 				col = textureIntensity * color[1];
206 				result[1] = col > materialColor[1] ? col : materialColor[1];
207 				col = textureIntensity * color[2];
208 				result[2] = col > materialColor[2] ? col : materialColor[2];
209 				break;
210 			case MTEX_BLEND_HUE:
211 			case MTEX_BLEND_SAT:
212 			case MTEX_BLEND_VAL:
213 			case MTEX_BLEND_COLOR:
214 				System.arraycopy(materialColor, 0, result, 0, 3);
215 				this.blendHSV(blendtype, result, textureIntensity, color, blenderContext);
216 				break;
217 			default:
218 				throw new IllegalStateException("Unknown blend type: " + blendtype);
219 		}
220 	}
221 }
222