1 package com.jme3.scene.plugins.blender.textures;
2 
3 import com.jme3.math.ColorRGBA;
4 import com.jme3.math.FastMath;
5 import com.jme3.texture.Image.Format;
6 import java.nio.ByteBuffer;
7 import java.util.logging.Level;
8 import java.util.logging.Logger;
9 
10 /**
11  * The class that stores the pixel values of a texture.
12  *
13  * @author Marcin Roguski (Kaelthas)
14  */
15 public class TexturePixel implements Cloneable {
16 	private static final Logger	LOGGER	= Logger.getLogger(TexturePixel.class.getName());
17 
18 	/** The pixel data. */
19 	public float				intensity, red, green, blue, alpha;
20 
21 	/**
22 	 * Copies the values from the given pixel.
23 	 *
24 	 * @param pixel
25 	 *            the pixel that we read from
26 	 */
fromPixel(TexturePixel pixel)27 	public void fromPixel(TexturePixel pixel) {
28 		this.intensity = pixel.intensity;
29 		this.red = pixel.red;
30 		this.green = pixel.green;
31 		this.blue = pixel.blue;
32 		this.alpha = pixel.alpha;
33 	}
34 
35 	/**
36 	 * Copies the values from the given color.
37 	 *
38 	 * @param colorRGBA
39 	 *            the color that we read from
40 	 */
fromColor(ColorRGBA colorRGBA)41 	public void fromColor(ColorRGBA colorRGBA) {
42 		this.red = colorRGBA.r;
43 		this.green = colorRGBA.g;
44 		this.blue = colorRGBA.b;
45 		this.alpha = colorRGBA.a;
46 	}
47 
48 	/**
49 	 * Copies the values from the given values.
50 	 *
51 	 * @param a
52 	 *            the alpha value
53 	 * @param r
54 	 *            the red value
55 	 * @param g
56 	 *            the green value
57 	 * @param b
58 	 *            the blue value
59 	 */
fromARGB8(float a, float r, float g, float b)60 	public void fromARGB8(float a, float r, float g, float b) {
61 		this.alpha = a;
62 		this.red = r;
63 		this.green = g;
64 		this.blue = b;
65 	}
66 
67 	/**
68 	 * Copies the values from the given integer that stores the ARGB8 data.
69 	 *
70 	 * @param argb8
71 	 *            the data stored in an integer
72 	 */
fromARGB8(int argb8)73 	public void fromARGB8(int argb8) {
74 		byte pixelValue = (byte) ((argb8 & 0xFF000000) >> 24);
75 		this.alpha = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
76 		pixelValue = (byte) ((argb8 & 0xFF0000) >> 16);
77 		this.red = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
78 		pixelValue = (byte) ((argb8 & 0xFF00) >> 8);
79 		this.green = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
80 		pixelValue = (byte) (argb8 & 0xFF);
81 		this.blue = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
82 	}
83 
84 	/**
85 	 * Copies the data from the given image.
86 	 *
87 	 * @param imageFormat
88 	 *            the image format
89 	 * @param data
90 	 *            the image data
91 	 * @param pixelIndex
92 	 *            the index of the required pixel
93 	 */
fromImage(Format imageFormat, ByteBuffer data, int pixelIndex)94 	public void fromImage(Format imageFormat, ByteBuffer data, int pixelIndex) {
95 		int firstByteIndex;
96 		byte pixelValue;
97 		switch (imageFormat) {
98 			case ABGR8:
99 				firstByteIndex = pixelIndex << 2;
100 				pixelValue = data.get(firstByteIndex);
101 				this.alpha = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
102 				pixelValue = data.get(firstByteIndex + 1);
103 				this.blue = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
104 				pixelValue = data.get(firstByteIndex + 2);
105 				this.green = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
106 				pixelValue = data.get(firstByteIndex + 3);
107 				this.red = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
108 				break;
109 			case RGBA8:
110 				firstByteIndex = pixelIndex << 2;
111 				pixelValue = data.get(firstByteIndex);
112 				this.red = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
113 				pixelValue = data.get(firstByteIndex + 1);
114 				this.green = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
115 				pixelValue = data.get(firstByteIndex + 2);
116 				this.blue = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
117 				pixelValue = data.get(firstByteIndex + 3);
118 				this.alpha = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
119 				break;
120 			case BGR8:
121 				firstByteIndex = pixelIndex * 3;
122 				pixelValue = data.get(firstByteIndex);
123 				this.blue = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
124 				pixelValue = data.get(firstByteIndex + 1);
125 				this.green = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
126 				pixelValue = data.get(firstByteIndex + 2);
127 				this.red = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
128 				this.alpha = 1.0f;
129 				break;
130 			case RGB8:
131 				firstByteIndex = pixelIndex * 3;
132 				pixelValue = data.get(firstByteIndex);
133 				this.red = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
134 				pixelValue = data.get(firstByteIndex + 1);
135 				this.green = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
136 				pixelValue = data.get(firstByteIndex + 2);
137 				this.blue = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
138 				this.alpha = 1.0f;
139 				break;
140 			case Luminance8:
141 				pixelValue = data.get(pixelIndex);
142 				this.intensity = pixelValue >= 0 ? pixelValue / 255.0f : 1.0f - (~pixelValue) / 255.0f;
143 				break;
144 			default:
145 				LOGGER.log(Level.FINEST, "Unknown type of texture: {0}. Black pixel used!", imageFormat);
146 				this.intensity = this.blue = this.red = this.green = this.alpha = 0.0f;
147 		}
148 	}
149 
150 	/**
151 	 * Stores RGBA values in the given array.
152 	 *
153 	 * @param result
154 	 *            the array to store values
155 	 */
toRGBA(float[] result)156 	public void toRGBA(float[] result) {
157 		result[0] = this.red;
158 		result[1] = this.green;
159 		result[2] = this.blue;
160 		result[3] = this.alpha;
161 	}
162 
163 	/**
164 	 * Stores the data in the given table.
165 	 *
166 	 * @param result
167 	 *            the result table
168 	 */
toRGBA8(byte[] result)169 	public void toRGBA8(byte[] result) {
170 		result[0] = (byte) (this.red * 255.0f);
171 		result[1] = (byte) (this.green * 255.0f);
172 		result[2] = (byte) (this.blue * 255.0f);
173 		result[3] = (byte) (this.alpha * 255.0f);
174 	}
175 
176 	/**
177 	 * Stores the pixel values in the integer.
178 	 *
179 	 * @return the integer that stores the pixel values
180 	 */
toARGB8()181 	public int toARGB8() {
182 		int result = 0;
183 		int b = (int) (this.alpha * 255.0f);
184 		result |= b << 24;
185 		b = (int) (this.red * 255.0f);
186 		result |= b << 16;
187 		b = (int) (this.green * 255.0f);
188 		result |= b << 8;
189 		b = (int) (this.blue * 255.0f);
190 		result |= b;
191 		return result;
192 	}
193 
194 	/**
195 	 * Merges two pixels (adds the values of each color).
196 	 *
197 	 * @param pixel
198 	 *            the pixel we merge with
199 	 */
merge(TexturePixel pixel)200 	public void merge(TexturePixel pixel) {
201 		float oneMinusAlpha = 1 - pixel.alpha;
202 		this.red = oneMinusAlpha * this.red + pixel.alpha * pixel.red;
203 		this.green = oneMinusAlpha * this.green + pixel.alpha * pixel.green;
204 		this.blue = oneMinusAlpha * this.blue + pixel.alpha * pixel.blue;
205 		// alpha should be always 1.0f as a result
206 	}
207 
208 	/**
209 	 * This method negates the colors.
210 	 */
negate()211 	public void negate() {
212 		this.red = 1.0f - this.red;
213 		this.green = 1.0f - this.green;
214 		this.blue = 1.0f - this.blue;
215 		this.alpha = 1.0f - this.alpha;
216 	}
217 
218 	/**
219 	 * This method clears the pixel values.
220 	 */
clear()221 	public void clear() {
222 		this.intensity = this.blue = this.red = this.green = this.alpha = 0.0f;
223 	}
224 
225 	/**
226 	 * This method adds the calues of the given pixel to the current pixel.
227 	 *
228 	 * @param pixel
229 	 *            the pixel we add
230 	 */
add(TexturePixel pixel)231 	public void add(TexturePixel pixel) {
232 		this.red += pixel.red;
233 		this.green += pixel.green;
234 		this.blue += pixel.blue;
235 		this.alpha += pixel.alpha;
236 		this.intensity += pixel.intensity;
237 	}
238 
239 	/**
240 	 * This method multiplies the values of the given pixel by the given value.
241 	 *
242 	 * @param value
243 	 *            multiplication factor
244 	 */
mult(float value)245 	public void mult(float value) {
246 		this.red *= value;
247 		this.green *= value;
248 		this.blue *= value;
249 		this.alpha *= value;
250 		this.intensity *= value;
251 	}
252 
253 	/**
254 	 * This method divides the values of the given pixel by the given value.
255 	 * ATTENTION! Beware of the zero value. This will cause you NaN's in the
256 	 * pixel values.
257 	 *
258 	 * @param value
259 	 *            division factor
260 	 */
divide(float value)261 	public void divide(float value) {
262 		this.red /= value;
263 		this.green /= value;
264 		this.blue /= value;
265 		this.alpha /= value;
266 		this.intensity /= value;
267 	}
268 
269 	/**
270 	 * This method clamps the pixel values to the given borders.
271 	 *
272 	 * @param min
273 	 *            the minimum value
274 	 * @param max
275 	 *            the maximum value
276 	 */
clamp(float min, float max)277 	public void clamp(float min, float max) {
278 		this.red = FastMath.clamp(this.red, min, max);
279 		this.green = FastMath.clamp(this.green, min, max);
280 		this.blue = FastMath.clamp(this.blue, min, max);
281 		this.alpha = FastMath.clamp(this.alpha, min, max);
282 		this.intensity = FastMath.clamp(this.intensity, min, max);
283 	}
284 
285 	@Override
clone()286 	public Object clone() throws CloneNotSupportedException {
287 		return super.clone();
288 	}
289 
290 	@Override
toString()291 	public String toString() {
292 		return "[" + red + ", " + green + ", " + blue + ", " + alpha + " {" + intensity + "}]";
293 	}
294 }
295