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 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 */ 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 */ 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