1 package com.jme3.scene.plugins.blender.textures.blending;
2 
3 import com.jme3.math.FastMath;
4 import com.jme3.scene.plugins.blender.BlenderContext;
5 import com.jme3.scene.plugins.blender.materials.MaterialHelper;
6 
7 /**
8  * An abstract class that contains the basic methods used by the classes that
9  * will derive from it.
10  *
11  * @author Marcin Roguski (Kaelthas)
12  */
13 /* package */abstract class AbstractTextureBlender implements TextureBlender {
14 	/**
15 	 * This method blends the single pixel depending on the blending type.
16 	 *
17 	 * @param result
18 	 *            the result pixel
19 	 * @param materialColor
20 	 *            the material color
21 	 * @param pixelColor
22 	 *            the pixel color
23 	 * @param blendFactor
24 	 *            the blending factor
25 	 * @param blendtype
26 	 *            the blending type
27 	 * @param blenderContext
28 	 *            the blender context
29 	 */
blendPixel(float[] result, float[] materialColor, float[] pixelColor, float blendFactor, int blendtype, BlenderContext blenderContext)30 	protected void blendPixel(float[] result, float[] materialColor, float[] pixelColor, float blendFactor, int blendtype, BlenderContext blenderContext) {
31 		float oneMinusFactor = 1.0f - blendFactor, col;
32 
33 		switch (blendtype) {
34 			case MTEX_BLEND:
35 				result[0] = blendFactor * pixelColor[0] + oneMinusFactor * materialColor[0];
36 				result[1] = blendFactor * pixelColor[1] + oneMinusFactor * materialColor[1];
37 				result[2] = blendFactor * pixelColor[2] + oneMinusFactor * materialColor[2];
38 				break;
39 			case MTEX_MUL:
40 				result[0] = (oneMinusFactor + blendFactor * materialColor[0]) * pixelColor[0];
41 				result[1] = (oneMinusFactor + blendFactor * materialColor[1]) * pixelColor[1];
42 				result[2] = (oneMinusFactor + blendFactor * materialColor[2]) * pixelColor[2];
43 				break;
44 			case MTEX_DIV:
45 				if (pixelColor[0] != 0.0) {
46 					result[0] = (oneMinusFactor * materialColor[0] + blendFactor * materialColor[0] / pixelColor[0]) * 0.5f;
47 				}
48 				if (pixelColor[1] != 0.0) {
49 					result[1] = (oneMinusFactor * materialColor[1] + blendFactor * materialColor[1] / pixelColor[1]) * 0.5f;
50 				}
51 				if (pixelColor[2] != 0.0) {
52 					result[2] = (oneMinusFactor * materialColor[2] + blendFactor * materialColor[2] / pixelColor[2]) * 0.5f;
53 				}
54 				break;
55 			case MTEX_SCREEN:
56 				result[0] = 1.0f - (oneMinusFactor + blendFactor * (1.0f - materialColor[0])) * (1.0f - pixelColor[0]);
57 				result[1] = 1.0f - (oneMinusFactor + blendFactor * (1.0f - materialColor[1])) * (1.0f - pixelColor[1]);
58 				result[2] = 1.0f - (oneMinusFactor + blendFactor * (1.0f - materialColor[2])) * (1.0f - pixelColor[2]);
59 				break;
60 			case MTEX_OVERLAY:
61 				if (materialColor[0] < 0.5f) {
62 					result[0] = pixelColor[0] * (oneMinusFactor + 2.0f * blendFactor * materialColor[0]);
63 				} else {
64 					result[0] = 1.0f - (oneMinusFactor + 2.0f * blendFactor * (1.0f - materialColor[0])) * (1.0f - pixelColor[0]);
65 				}
66 				if (materialColor[1] < 0.5f) {
67 					result[1] = pixelColor[1] * (oneMinusFactor + 2.0f * blendFactor * materialColor[1]);
68 				} else {
69 					result[1] = 1.0f - (oneMinusFactor + 2.0f * blendFactor * (1.0f - materialColor[1])) * (1.0f - pixelColor[1]);
70 				}
71 				if (materialColor[2] < 0.5f) {
72 					result[2] = pixelColor[2] * (oneMinusFactor + 2.0f * blendFactor * materialColor[2]);
73 				} else {
74 					result[2] = 1.0f - (oneMinusFactor + 2.0f * blendFactor * (1.0f - materialColor[2])) * (1.0f - pixelColor[2]);
75 				}
76 				break;
77 			case MTEX_SUB:
78 				result[0] = materialColor[0] - blendFactor * pixelColor[0];
79 				result[1] = materialColor[1] - blendFactor * pixelColor[1];
80 				result[2] = materialColor[2] - blendFactor * pixelColor[2];
81 				result[0] = FastMath.clamp(result[0], 0.0f, 1.0f);
82 				result[1] = FastMath.clamp(result[1], 0.0f, 1.0f);
83 				result[2] = FastMath.clamp(result[2], 0.0f, 1.0f);
84 				break;
85 			case MTEX_ADD:
86 				result[0] = (blendFactor * pixelColor[0] + materialColor[0]) * 0.5f;
87 				result[1] = (blendFactor * pixelColor[1] + materialColor[1]) * 0.5f;
88 				result[2] = (blendFactor * pixelColor[2] + materialColor[2]) * 0.5f;
89 				break;
90 			case MTEX_DIFF:
91 				result[0] = oneMinusFactor * materialColor[0] + blendFactor * Math.abs(materialColor[0] - pixelColor[0]);
92 				result[1] = oneMinusFactor * materialColor[1] + blendFactor * Math.abs(materialColor[1] - pixelColor[1]);
93 				result[2] = oneMinusFactor * materialColor[2] + blendFactor * Math.abs(materialColor[2] - pixelColor[2]);
94 				break;
95 			case MTEX_DARK:
96 				col = blendFactor * pixelColor[0];
97 				result[0] = col < materialColor[0] ? col : materialColor[0];
98 				col = blendFactor * pixelColor[1];
99 				result[1] = col < materialColor[1] ? col : materialColor[1];
100 				col = blendFactor * pixelColor[2];
101 				result[2] = col < materialColor[2] ? col : materialColor[2];
102 				break;
103 			case MTEX_LIGHT:
104 				col = blendFactor * pixelColor[0];
105 				result[0] = col > materialColor[0] ? col : materialColor[0];
106 				col = blendFactor * pixelColor[1];
107 				result[1] = col > materialColor[1] ? col : materialColor[1];
108 				col = blendFactor * pixelColor[2];
109 				result[2] = col > materialColor[2] ? col : materialColor[2];
110 				break;
111 			case MTEX_BLEND_HUE:
112 			case MTEX_BLEND_SAT:
113 			case MTEX_BLEND_VAL:
114 			case MTEX_BLEND_COLOR:
115 				System.arraycopy(materialColor, 0, result, 0, 3);
116 				this.blendHSV(blendtype, result, blendFactor, pixelColor, blenderContext);
117 				break;
118 			default:
119 				throw new IllegalStateException("Unknown blend type: " + blendtype);
120 		}
121 	}
122 
123 	/**
124 	 * The method that performs the ramp blending.
125 	 *
126 	 * @param type
127 	 *            the blend type
128 	 * @param materialRGB
129 	 *            the rgb value of the material, here the result is stored too
130 	 * @param fac
131 	 *            color affection factor
132 	 * @param pixelColor
133 	 *            the texture color
134 	 * @param blenderContext
135 	 *            the blender context
136 	 */
blendHSV(int type, float[] materialRGB, float fac, float[] pixelColor, BlenderContext blenderContext)137 	protected void blendHSV(int type, float[] materialRGB, float fac, float[] pixelColor, BlenderContext blenderContext) {
138 		float oneMinusFactor = 1.0f - fac;
139 		MaterialHelper materialHelper = blenderContext.getHelper(MaterialHelper.class);
140 
141 		switch (type) {
142 			case MTEX_BLEND_HUE: {// FIXME: not working well for image textures
143 									// (works fine for generated textures)
144 				float[] colorTransformResult = new float[3];
145 				materialHelper.rgbToHsv(pixelColor[0], pixelColor[1], pixelColor[2], colorTransformResult);
146 				if (colorTransformResult[0] != 0.0f) {
147 					float colH = colorTransformResult[0];
148 					materialHelper.rgbToHsv(materialRGB[0], materialRGB[1], materialRGB[2], colorTransformResult);
149 					materialHelper.hsvToRgb(colH, colorTransformResult[1], colorTransformResult[2], colorTransformResult);
150 					materialRGB[0] = oneMinusFactor * materialRGB[0] + fac * colorTransformResult[0];
151 					materialRGB[1] = oneMinusFactor * materialRGB[1] + fac * colorTransformResult[1];
152 					materialRGB[2] = oneMinusFactor * materialRGB[2] + fac * colorTransformResult[2];
153 				}
154 				break;
155 			}
156 			case MTEX_BLEND_SAT: {
157 				float[] colorTransformResult = new float[3];
158 				materialHelper.rgbToHsv(materialRGB[0], materialRGB[1], materialRGB[2], colorTransformResult);
159 				float h = colorTransformResult[0];
160 				float s = colorTransformResult[1];
161 				float v = colorTransformResult[2];
162 				if (s != 0.0f) {
163 					materialHelper.rgbToHsv(pixelColor[0], pixelColor[1], pixelColor[2], colorTransformResult);
164 					materialHelper.hsvToRgb(h, (oneMinusFactor * s + fac * colorTransformResult[1]), v, materialRGB);
165 				}
166 				break;
167 			}
168 			case MTEX_BLEND_VAL: {
169 				float[] rgbToHsv = new float[3];
170 				float[] colToHsv = new float[3];
171 				materialHelper.rgbToHsv(materialRGB[0], materialRGB[1], materialRGB[2], rgbToHsv);
172 				materialHelper.rgbToHsv(pixelColor[0], pixelColor[1], pixelColor[2], colToHsv);
173 				materialHelper.hsvToRgb(rgbToHsv[0], rgbToHsv[1], (oneMinusFactor * rgbToHsv[2] + fac * colToHsv[2]), materialRGB);
174 				break;
175 			}
176 			case MTEX_BLEND_COLOR: {// FIXME: not working well for image
177 									// textures (works fine for generated
178 									// textures)
179 				float[] rgbToHsv = new float[3];
180 				float[] colToHsv = new float[3];
181 				materialHelper.rgbToHsv(pixelColor[0], pixelColor[1], pixelColor[2], colToHsv);
182 				if (colToHsv[2] != 0) {
183 					materialHelper.rgbToHsv(materialRGB[0], materialRGB[1], materialRGB[2], rgbToHsv);
184 					materialHelper.hsvToRgb(colToHsv[0], colToHsv[1], rgbToHsv[2], rgbToHsv);
185 					materialRGB[0] = oneMinusFactor * materialRGB[0] + fac * rgbToHsv[0];
186 					materialRGB[1] = oneMinusFactor * materialRGB[1] + fac * rgbToHsv[1];
187 					materialRGB[2] = oneMinusFactor * materialRGB[2] + fac * rgbToHsv[2];
188 				}
189 				break;
190 			}
191 			default:
192 				throw new IllegalStateException("Unknown ramp type: " + type);
193 		}
194 	}
195 }
196