Home | History | Annotate | Download | only in blending
      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.scene.plugins.blender.BlenderContext;
      9 import com.jme3.texture.Image;
     10 import com.jme3.texture.Texture;
     11 import com.jme3.texture.Texture2D;
     12 import com.jme3.texture.Texture3D;
     13 import com.jme3.texture.Image.Format;
     14 import 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  */
     38 public 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