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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 286 public Object clone() throws CloneNotSupportedException { 287 return super.clone(); 288 } 289 290 @Override 291 public String toString() { 292 return "[" + red + ", " + green + ", " + blue + ", " + alpha + " {" + intensity + "}]"; 293 } 294 } 295