1 /* 2 * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab 3 * Copyright (C) 2013 - Pedro SOUZA 4 * 5 * Copyright (C) 2012 - 2016 - Scilab Enterprises 6 * 7 * This file is hereby licensed under the terms of the GNU GPL v2.0, 8 * pursuant to article 5.3.4 of the CeCILL v.2.1. 9 * This file was originally licensed under the terms of the CeCILL v2.1, 10 * and continues to be available under such terms. 11 * For more information, see the COPYING file which you should have received 12 * along with this program. 13 */ 14 15 package org.scilab.forge.scirenderer.implementation.g2d.motor; 16 17 import java.awt.Color; 18 import java.nio.FloatBuffer; 19 import java.nio.IntBuffer; 20 21 22 import org.scilab.forge.scirenderer.tranformations.Vector3f; 23 import org.scilab.forge.scirenderer.implementation.g2d.lighting.G2DLight; 24 import org.scilab.forge.scirenderer.shapes.appearance.Material; 25 26 /** 27 * @author Pedro SOUZA 28 */ 29 public class LightHelper { 30 31 /** 32 * @param buffer the float buffer. 33 * @param stride the stride between elements. 34 * @return an array of Vector3f from the given float buffer. 35 */ getVector3f(FloatBuffer buffer, int stride)36 public static Vector3f[] getVector3f(FloatBuffer buffer, int stride) { 37 if (buffer == null) { 38 return null; 39 } 40 if (stride < 3) { 41 return null; 42 } 43 44 float[] floats; 45 buffer.rewind(); 46 if (buffer.hasArray()) { 47 floats = buffer.array(); 48 } else { 49 floats = new float[buffer.limit()]; 50 buffer.get(floats); 51 } 52 53 Vector3f[] ret = new Vector3f[floats.length / stride]; 54 for (int i = 0; i < floats.length; i += stride) { 55 ret[i] = new Vector3f(floats[i], floats[i + 1], floats[i + 2]); 56 } 57 return ret; 58 } 59 60 /** 61 * @param buffer the float buffer. 62 * @param index the indices buffer. 63 * @param stride the stride between elements. 64 * @param transf matrix to transform the vector, if null no transformation is applied. 65 * @return an array of Vector3f from the given float buffer. 66 */ getIndexedVector3f(FloatBuffer buffer, IntBuffer index, int stride, float[] transf)67 public static Vector3f[] getIndexedVector3f(FloatBuffer buffer, IntBuffer index, int stride, float[] transf) { 68 if (buffer == null || index == null) { 69 return null; 70 } 71 if (stride < 3) { 72 return null; 73 } 74 75 float[] floats; 76 buffer.rewind(); 77 if (buffer.hasArray()) { 78 floats = buffer.array(); 79 } else { 80 floats = new float[buffer.limit()]; 81 buffer.get(floats); 82 } 83 84 int[] idx; 85 index.rewind(); 86 if (index.hasArray()) { 87 idx = index.array(); 88 } else { 89 idx = new int[index.limit()]; 90 index.get(idx); 91 } 92 93 Vector3f[] ret = new Vector3f[idx.length]; 94 float x, y, z; 95 if (transf != null && transf.length == 16) { 96 for (int i = 0; i < idx.length; ++i) { 97 ret[i] = transform(floats[stride * idx[i]], floats[stride * idx[i] + 1], floats[stride * idx[i] + 2], transf); 98 } 99 } else { 100 for (int i = 0; i < idx.length; ++i) { 101 ret[i] = new Vector3f(floats[stride * idx[i]], floats[stride * idx[i] + 1], floats[stride * idx[i] + 2]); 102 } 103 } 104 return ret; 105 } 106 transform(float x, float y, float z, float[] transf)107 static Vector3f transform(float x, float y, float z, float[] transf) { 108 float xx = transf[0] * x + transf[4] * y + transf[8] * z + transf[12]; 109 float yy = transf[1] * x + transf[5] * y + transf[9] * z + transf[13]; 110 float zz = transf[2] * x + transf[6] * y + transf[10] * z + transf[14]; 111 return new Vector3f(xx, yy, zz); 112 } 113 transformDirection(float x, float y, float z, float[] transf)114 static Vector3f transformDirection(float x, float y, float z, float[] transf) { 115 float xx = transf[0] * x + transf[4] * y + transf[8] * z; 116 float yy = transf[1] * x + transf[5] * y + transf[9] * z; 117 float zz = transf[2] * x + transf[6] * y + transf[10] * z; 118 return new Vector3f(xx, yy, zz); 119 } 120 121 /** 122 * Apply the given ambient color to the output. 123 * @param ambient the ambient color. 124 * @param output the color vector to apply the ambient color. 125 * @param additive if true the ambient color is added to output. 126 * @return the resulting color vector. 127 */ applyAmbient(Color ambient, Color[] output, boolean additive)128 public static Color[] applyAmbient(Color ambient, Color[] output, boolean additive) { 129 for (int i = 0; i < output.length; ++i) { 130 if (additive) { 131 output[i] = getColorSum(ambient, output[i]); 132 } else { 133 output[i] = ambient; 134 } 135 } 136 return output; 137 } 138 139 /** 140 * Apply the given ambient color to the output. 141 * @param ambient the ambient color. 142 * @param input the input color. 143 * @param output the color vector to apply the ambient color. 144 * @param additive if true the ambient color is added to output. 145 * @return the resulting color vector. 146 */ applyAmbient(Color ambient, Color[] input, Color[] output, boolean additive)147 public static Color[] applyAmbient(Color ambient, Color[] input, Color[] output, boolean additive) { 148 for (int i = 0; i < output.length; ++i) { 149 if (additive) { 150 output[i] = getColorSum(getColorProduct(ambient, input[i]), output[i]); 151 } else { 152 output[i] = getColorProduct(ambient, input[i]); 153 } 154 } 155 return output; 156 } 157 158 /** 159 * Apply diffuse light to the output colors 160 * @param light the light position or direction. 161 * @param directional if true the vector light is considered a direction otherwise a position. 162 * @param vertices the surface vertices. 163 * @param normals the surface normals. 164 * @param colors the surface per-vertex colors. 165 * @param dffuse the light diffuse color. 166 * @param output the output color vector. 167 * @param additive if true the calculated diffuse color is added to the output. 168 * @return the resulting color vector. 169 */ applyDiffuse(Vector3f light, boolean directional, Vector3f[] vertices, Vector3f[] normals, Color[] colors, Color diffuse, Color[] output, boolean additive)170 public static Color[] applyDiffuse(Vector3f light, boolean directional, Vector3f[] vertices, Vector3f[] normals, Color[] colors, Color diffuse, Color[] output, boolean additive) { 171 float ndotl; 172 for (int i = 0; i < colors.length; ++i) { 173 174 if (directional) { 175 ndotl = normals[i].scalar(light); 176 } else { 177 Vector3f ray = light.minus(vertices[i]).getNormalized(); 178 ndotl = normals[i].scalar(ray); 179 } 180 ndotl = clamp(ndotl); 181 Color c = getColorProduct(colors[i], diffuse); 182 if (additive) { 183 output[i] = getColorSum(getColorProduct(c, ndotl), output[i]); 184 } else { 185 output[i] = getColorProduct(c, ndotl); 186 } 187 } 188 return output; 189 } 190 191 /** 192 * Apply diffuse light to the output colors 193 * @param light the light position or direction. 194 * @param directional if true the vector light is considered a direction otherwise a position. 195 * @param vertices the surface vertices. 196 * @param normals the surface normals. 197 * @param color the surface color. 198 * @param output the output color vector. 199 * @param additive if true the calculated diffuse color is added to the output. 200 * @return the resulting color vector. 201 */ applyDiffuse(Vector3f light, boolean directional, Vector3f[] vertices, Vector3f[] normals, Color color, Color[] output, boolean additive)202 public static Color[] applyDiffuse(Vector3f light, boolean directional, Vector3f[] vertices, Vector3f[] normals, Color color, Color[] output, boolean additive) { 203 float ndotl; 204 for (int i = 0; i < output.length; ++i) { 205 206 if (directional) { 207 ndotl = normals[i].scalar(light); 208 } else { 209 Vector3f ray = light.minus(vertices[i]).getNormalized(); 210 ndotl = normals[i].scalar(ray); 211 } 212 ndotl = clamp(ndotl); 213 if (additive) { 214 output[i] = getColorSum(getColorProduct(color, ndotl), output[i]); 215 } else { 216 output[i] = getColorProduct(color, ndotl); 217 } 218 } 219 return output; 220 } 221 applySpecular(Vector3f camera, Vector3f light, float shininess, boolean directional, Vector3f[] vertices, Vector3f[] normals, Color specular, Color[] output, boolean additive)222 public static Color[] applySpecular(Vector3f camera, Vector3f light, float shininess, boolean directional, Vector3f[] vertices, Vector3f[] normals, Color specular, Color[] output, boolean additive) { 223 224 for (int i = 0; i < output.length; ++i) { 225 226 Vector3f view = camera.minus(vertices[i]).getNormalized(); 227 Vector3f half; 228 float ndotl; 229 if (directional) { 230 half = view.plus(light); 231 ndotl = normals[i].scalar(light); 232 } else { 233 Vector3f ray = light.minus(vertices[i]).getNormalized(); 234 half = view.plus(ray); 235 ndotl = normals[i].scalar(ray); 236 } 237 half = half.getNormalized(); 238 239 float s = 0.0f; 240 if (ndotl > 0.0f) { 241 s = normals[i].scalar(half); 242 s = clamp(s); 243 s = (float)Math.pow((double)s, (double)shininess); 244 } 245 246 if (additive) { 247 output[i] = getColorSum(getColorProduct(specular, s), output[i]); 248 } else { 249 output[i] = getColorProduct(specular, s); 250 } 251 } 252 return output; 253 } 254 255 /** 256 * Apply a per-vertex lighting to the given colors 257 * @param light the light. 258 * @param mat the material properties. 259 * @param camera the camera position. 260 * @param vertices the surface vertices. 261 * @param normals the surface normals. 262 * @param colors the surface per-vertex colors. 263 * @param output the output color vector. 264 * @param transf the light transformation matrix. If null no transformation is applyed. 265 * @param additive if true the calculated color is added to the output. 266 * @return the resulting color vector. 267 */ applyLight(G2DLight light, Material mat, Vector3f camera, Vector3f[] vertices, Vector3f[] normals, Color[] colors, Color[] output, float[] transf, boolean additive)268 public static Color[] applyLight(G2DLight light, Material mat, Vector3f camera, Vector3f[] vertices, Vector3f[] normals, Color[] colors, Color[] output, float[] transf, boolean additive) { 269 Color ambient = getColorProduct(mat.getAmbientColor(), light.getAmbientColor()); 270 Color diffuse = getColorProduct(mat.getDiffuseColor(), light.getDiffuseColor()); 271 Color specular = getColorProduct(mat.getSpecularColor(), light.getSpecularColor()); 272 273 Color[] finalColor; 274 if (mat.isColorMaterialEnable()) { 275 finalColor = applyAmbient(light.getAmbientColor(), colors, output, additive); 276 } else { 277 finalColor = applyAmbient(ambient, output, additive); 278 } 279 280 float[] v; 281 if (light.isPoint()) { 282 v = light.getPosition().getDataAsFloatArray(); 283 } else { 284 v = light.getDirection().getDataAsFloatArray(); 285 } 286 287 Vector3f vec; 288 if (transf != null && transf.length == 16) { 289 if (light.isPoint()) { 290 vec = transform(v[0], v[1], v[2], transf); 291 } else { 292 vec = transformDirection(v[0], v[1], v[2], transf).getNormalized(); 293 } 294 } else { 295 vec = new Vector3f(v[0], v[1], v[2]); 296 } 297 298 if (mat.isColorMaterialEnable()) { 299 finalColor = applyDiffuse(vec, !light.isPoint(), vertices, normals, colors, light.getDiffuseColor(), finalColor, true); 300 } else { 301 finalColor = applyDiffuse(vec, !light.isPoint(), vertices, normals, diffuse, finalColor, true); 302 } 303 304 finalColor = applySpecular(camera, vec, mat.getShininess(), !light.isPoint(), vertices, normals, specular, finalColor, true); 305 306 return finalColor; 307 } 308 309 /** 310 * return the product of the given colors 311 */ getColorProduct(Color a, Color b)312 private static Color getColorProduct(Color a, Color b) { 313 float[] ca = a.getComponents(null); 314 float[] cb = b.getComponents(null); 315 return new Color(ca[0] * cb[0], ca[1] * cb[1], ca[2] * cb[2]); 316 } 317 318 /** 319 * return the clamped product of the color 320 */ getColorProduct(Color a, float f)321 private static Color getColorProduct(Color a, float f) { 322 float[] ca = a.getComponents(null); 323 return new Color(clamp(ca[0] * f), clamp(ca[1] * f), clamp(ca[2] * f)); 324 } 325 326 /** 327 * return the clamped sum of the given colors 328 */ getColorSum(Color a, Color b)329 private static Color getColorSum(Color a, Color b) { 330 float[] ca = a.getComponents(null); 331 float[] cb = b.getComponents(null); 332 return new Color(clamp(ca[0] + cb[0]), clamp(ca[1] + cb[1]), clamp(ca[2] + cb[2])); 333 } 334 335 /** 336 * Clamp the given value to [0, 1] 337 */ clamp(float f)338 private static float clamp(float f) { 339 f = f < 0.0f ? 0.0f : f; 340 f = f > 1.0f ? 1.0f : f; 341 return f; 342 } 343 reflect(Vector3f I, Vector3f N)344 static Vector3f reflect(Vector3f I, Vector3f N) { 345 return I.minus(N.times(2 * I.scalar(N))); 346 } 347 } 348