Add a way to precise mark border color for scatter plots
[scilab.git] / scilab / modules / scirenderer / src / org / scilab / forge / scirenderer / implementation / g2d / motor / Motor3D.java
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2012-2013 - Scilab Enterprises - Calixte Denizet
4  *
5  * This file must be used under the terms of the CeCILL.
6  * This source file is licensed as described in the file COPYING, which
7  * you should have received as part of this distribution.  The terms
8  * are also available at
9  * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
10  */
11
12 package org.scilab.forge.scirenderer.implementation.g2d.motor;
13
14 import java.awt.Color;
15 import java.awt.Dimension;
16 import java.awt.Graphics2D;
17 import java.awt.RenderingHints;
18 import java.awt.Stroke;
19 import java.awt.image.BufferedImage;
20 import java.nio.FloatBuffer;
21 import java.nio.IntBuffer;
22 import java.util.Arrays;
23 import java.util.List;
24
25 import org.scilab.forge.scirenderer.DrawingTools;
26 import org.scilab.forge.scirenderer.buffers.ElementsBuffer;
27 import org.scilab.forge.scirenderer.clipping.ClippingPlane;
28 import org.scilab.forge.scirenderer.implementation.g2d.G2DCanvas;
29 import org.scilab.forge.scirenderer.implementation.g2d.buffers.G2DElementsBuffer;
30 import org.scilab.forge.scirenderer.implementation.g2d.texture.G2DTextureDrawingTools;
31 import org.scilab.forge.scirenderer.implementation.g2d.texture.G2DTextureManager;
32 import org.scilab.forge.scirenderer.shapes.appearance.Appearance;
33 import org.scilab.forge.scirenderer.shapes.geometry.Geometry;
34 import org.scilab.forge.scirenderer.shapes.geometry.Geometry.FaceCullingMode;
35 import org.scilab.forge.scirenderer.texture.AnchorPosition;
36 import org.scilab.forge.scirenderer.texture.Texture;
37 import org.scilab.forge.scirenderer.tranformations.Transformation;
38 import org.scilab.forge.scirenderer.tranformations.Vector3d;
39 import org.scilab.forge.scirenderer.tranformations.Vector3f;
40
41 import org.scilab.forge.scirenderer.lightning.Light;
42 import org.scilab.forge.scirenderer.lightning.LightManager;
43 import org.scilab.forge.scirenderer.implementation.g2d.lighting.G2DLight;
44 import org.scilab.forge.scirenderer.implementation.g2d.lighting.G2DLightManager;
45 import org.scilab.forge.scirenderer.shapes.appearance.Material;
46
47 /**
48  * @author Calixte DENIZET
49  */
50 public class Motor3D {
51
52     private Transformation transf;
53     private Transformation singleTransf;
54     private FaceCullingMode mode = FaceCullingMode.BOTH;
55     private Graphics2D g2d;
56     private Dimension dim;
57     private G2DTextureDrawingTools textureDrawingTools;
58     private G2DCanvas canvas;
59
60     /**
61      * Default constructor
62      * @param g2d a Graphics2D object where to draw
63      * @param dim the graphic dimensions
64      */
65     public Motor3D(G2DCanvas canvas, Graphics2D g2d, Dimension dim) {
66         this.canvas = canvas;
67         this.g2d = g2d;
68         this.dim = dim;
69         this.textureDrawingTools = new G2DTextureDrawingTools(g2d);
70         AbstractDrawable3DObject.resetDefaultPrecedence();
71     }
72
73     public void setGraphics(Graphics2D g2d) {
74         this.g2d = g2d;
75         this.textureDrawingTools.setGraphics(g2d);
76     }
77
78     public void setAntialiased(boolean aa) {
79         if (aa) {
80             g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
81         } else {
82             g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);
83         }
84     }
85
86     public boolean is2DView() {
87         return canvas.getMainDrawer().is2DView();
88     }
89
90     public void setClippingPlanes(List<ClippingPlane> clippingPlanes) {
91         Scene.setClippingPlanes(clippingPlanes);
92     }
93
94     /**
95      * Set the face culling mode
96      * @param mode the mode to set
97      */
98     public void setFaceCullingMode(FaceCullingMode mode) {
99         this.mode = mode;
100     }
101
102     /**
103      * Set the current transformation
104      * @param transf the transformation to set
105      */
106     public void setTransformation(Transformation transf, Transformation single) {
107         this.transf = transf;
108         this.singleTransf = single;
109     }
110
111     public Transformation getCurrentTransformation() {
112         return transf;
113     }
114
115     public Transformation getCurrentSingleTransformation() {
116         return singleTransf;
117     }
118
119     /**
120      * Reset this motor
121      * @param color the filling color
122      */
123     public void reset(Color color) {
124         transf = null;
125         mode = FaceCullingMode.BOTH;
126         g2d.setColor(color);
127         g2d.fillRect(0, 0, (int) dim.getWidth(), (int) dim.getHeight());
128         Scene.clear();
129     }
130
131     /**
132      * Clear the depth buffer
133      */
134     public void clearDepth() {
135         Scene.clearDepth();
136     }
137
138     /**
139      * Draw the scene in the Graphics2D
140      */
141     public void draw() {
142         Scene.drawRoot(g2d);
143         clean();
144     }
145
146     public void clean() {
147         Scene.clearAll();
148         G2DTextureManager.clear();
149     }
150
151     public void drawTexture(DrawingTools drawingTools, BufferedImage image, Texture texture) {
152         try {
153             SpritedRectangle o = new SpritedRectangle(new Vector3d(0, 0, 0), transf, image, texture.getMagnificationFilter());
154             add(o);
155         } catch (InvalidPolygonException e) { }
156     }
157
158     /**
159      * Add the geometry to the scene
160      * @param drawingTools the DrawingTools
161      * @param geometry the geometry to draw
162      * @param appearance the appearance to use
163      */
164     public void draw(DrawingTools drawingTools, Geometry geometry, Appearance appearance) {
165         setFaceCullingMode(geometry.getFaceCullingMode());
166         FloatBuffer vertexBuffer = geometry.getVertices().getData();
167
168         IntBuffer indicesBuffer = null;;
169         if (geometry.getIndices() != null) {
170             indicesBuffer = geometry.getIndices().getData();
171         }
172
173         IntBuffer wireIndicesBuffer = null;
174         if (geometry.getWireIndices() != null) {
175             wireIndicesBuffer = geometry.getWireIndices().getData();
176         }
177
178         FloatBuffer colorBuffer = null;
179         if (geometry.getColors() != null) {
180             colorBuffer = geometry.getColors().getData();
181         }
182
183         FloatBuffer normalBuffer = null;
184         if (geometry.getNormals() != null) {
185             normalBuffer = geometry.getNormals().getData();
186         }
187
188         Texture texture = appearance.getTexture();
189         FloatBuffer textureCoordinatesBuffer = null;
190         BufferedImage image = null;
191         if (texture != null && geometry.getTextureCoordinates() != null) {
192             textureCoordinatesBuffer = geometry.getTextureCoordinates().getData();
193             image = ((G2DTextureManager.G2DTexture) texture).getImage();
194         }
195
196         G2DLightManager lm = (G2DLightManager)drawingTools.getLightManager();
197         lm.setMaterial(appearance.getMaterial());
198
199         if (geometry.getFillDrawingMode() != Geometry.FillDrawingMode.NONE) {
200             addTriangles(vertexBuffer, normalBuffer, colorBuffer, appearance.getFillColor(), indicesBuffer, textureCoordinatesBuffer, image, texture, geometry.getFillDrawingMode(), lm);
201         }
202
203         if (geometry.getLineDrawingMode() != Geometry.LineDrawingMode.NONE) {
204             if (appearance.getLineColor() == null) {
205                 addSegments(vertexBuffer, colorBuffer, null, wireIndicesBuffer, geometry.getLineDrawingMode(), appearance);
206             } else {
207                 addSegments(vertexBuffer, null, appearance.getLineColor(), wireIndicesBuffer, geometry.getLineDrawingMode(), appearance);
208             }
209         }
210     }
211
212     public void draw(DrawingTools drawingTools, Texture texture, AnchorPosition anchor, ElementsBuffer positions, int offset, int stride, double rotationAngle, org.scilab.forge.scirenderer.shapes.appearance.Color auxColor, ElementsBuffer colors) {
213         FloatBuffer positionsBuffer = positions.getData();
214         float[] buffer;
215         offset = offset < 0 ? 0 : offset;
216         stride = stride < 1 ? 1 : stride;
217         Color[] colorsArray = null;
218
219         positionsBuffer.rewind();
220         if (positionsBuffer.hasArray()) {
221             buffer = positionsBuffer.array();
222         } else {
223             buffer = new float[positionsBuffer.limit()];
224             positionsBuffer.get(buffer);
225         }
226         Vector3d[] verticesArray = getMultiVectors(buffer, transf, false);
227
228         if (colors != null) {
229             FloatBuffer colorsBuffer = colors.getData();
230             colorsBuffer.rewind();
231             if (colorsBuffer.hasArray()) {
232                 buffer = colorsBuffer.array();
233             } else {
234                 buffer = new float[colorsBuffer.limit()];
235                 colorsBuffer.get(buffer);
236             }
237             colorsArray = getMultiColors(buffer);
238         }
239
240         for (int i = offset; i < verticesArray.length; i += stride) {
241             try {
242                 Vector3d v = verticesArray[i];
243                 SpritedRectangle o;
244                 if (colorsArray == null) {
245                     o = new SpritedRectangle(v, texture, anchor, textureDrawingTools, rotationAngle, null, null);
246                 } else {
247                     o = new SpritedRectangle(v, texture, anchor, textureDrawingTools, rotationAngle, (Color) auxColor, colorsArray[i]);
248                 }
249                 add(o);
250             } catch (InvalidPolygonException e) { }
251         }
252     }
253
254     public void draw(DrawingTools drawingTools, Texture texture, AnchorPosition anchor, Vector3d position, double rotationAngle) {
255         try {
256             add(new SpritedRectangle(transf.project(position), texture, anchor, textureDrawingTools, rotationAngle, null, null));
257         } catch (InvalidPolygonException e) { }
258     }
259
260     /**
261      * Add a Triangle to the scene
262      * @param tri the triangle to add
263      */
264     private void add(Triangle tri) {
265         final boolean is2d = is2DView();
266         if (is2d) {
267             Scene.addToRoot(is2d, tri);
268         } else {
269             Vector3d normal = tri.getNormal();
270             if (normal != null) {
271                 //normal = transf.projectDirection(normal);
272                 if ((mode == FaceCullingMode.CW && normal.getZ() > 0) || (mode == FaceCullingMode.CCW && normal.getZ() < 0) || mode == FaceCullingMode.BOTH) {
273                     Scene.addToRoot(is2d, tri);
274                 }
275             } else {
276                 Scene.addToRoot(is2d, tri);
277             }
278         }
279     }
280
281     /**
282      * Add a segment to the scene
283      * @param s the segment to add
284      */
285     private void add(Segment s) {
286         Scene.addToRoot(is2DView(), s);
287     }
288
289     private void add(SpritedRectangle sprite) {
290         Scene.addToRoot(is2DView(), sprite);
291     }
292
293     private void add(PolyLine p) {
294         Scene.addToRoot(is2DView(), p);
295     }
296
297     /**
298      * Get arrays from Buffer
299      * @param vertices a buffer containing vertices
300      * @param colors a buffer containing the colors
301      * @param defaultColor the color to use when colors is null
302      * @param indices a buffer containg the index of the vertices to retrieve
303      * @return an array of length 2 containing the vertices array and the colors array
304      */
305     private Object[] getArrays(FloatBuffer vertices, FloatBuffer colors, Color defaultColor, FloatBuffer textureCoords, IntBuffer indices) {
306         float[] buffer;
307         Vector3d[] verticesArray;
308         Vector3d[] textureCoordsArray = null;
309         Color[] colorsArray;
310
311         vertices.rewind();
312         if (vertices.hasArray()) {
313             buffer = vertices.array();
314         } else {
315             buffer = new float[vertices.limit()];
316             vertices.get(buffer);
317         }
318         verticesArray = getMultiVectors(buffer, transf, false);
319
320         if (colors != null) {
321             colors.rewind();
322             if (colors.hasArray()) {
323                 buffer = colors.array();
324             } else {
325                 buffer = new float[colors.limit()];
326                 colors.get(buffer);
327             }
328             colorsArray = getMultiColors(buffer);
329         } else {
330             colorsArray = new Color[vertices.limit() / G2DElementsBuffer.ELEMENT_SIZE];
331             Arrays.fill(colorsArray, defaultColor);
332         }
333
334         if (textureCoords != null) {
335             textureCoords.rewind();
336             if (textureCoords.hasArray()) {
337                 buffer = textureCoords.array();
338             } else {
339                 buffer = new float[textureCoords.limit()];
340                 textureCoords.get(buffer);
341             }
342             textureCoordsArray = getMultiVectors(buffer);
343         }
344
345         if (indices != null) {
346             indices.rewind();
347             int[] ind;
348             if (indices.hasArray()) {
349                 ind = indices.array();
350             } else {
351                 ind = new int[indices.limit()];
352                 indices.get(ind);
353             }
354             Vector3d[] va = new Vector3d[ind.length];
355             Color[] ca = new Color[ind.length];
356             Vector3d[] ta = null;
357             if (textureCoords != null) {
358                 ta = new Vector3d[ind.length];
359             }
360
361             for (int i = 0; i < ind.length; i++) {
362                 va[i] = verticesArray[ind[i]];
363                 ca[i] = colorsArray[ind[i]];
364                 if (ta != null) {
365                     ta[i] = textureCoordsArray[ind[i]];
366                 }
367             }
368             verticesArray = va;
369             colorsArray = ca;
370             textureCoordsArray = ta;
371         }
372
373         return new Object[] {verticesArray, colorsArray, textureCoordsArray};
374     }
375
376     /**
377      * Convert the buffer vertices into vertices array and put the segments in the scene
378      * @param vertices a buffer containing vertices
379      * @param colors a buffer containing the colors
380      * @param defaultColor the color to use when colors is null
381      * @param indices a buffer containg the index of the vertices to retrieve
382      * @param drawingMode the drawing mode
383      * @param stroke the Stroke to use to draw a segment
384      */
385     private void addSegments(FloatBuffer vertices, FloatBuffer colors, Color defaultColor, IntBuffer indices, Geometry.LineDrawingMode drawingMode, Appearance appearance) {
386         Object[] arrays = getArrays(vertices, colors, defaultColor, null, indices);
387         Vector3d[] verticesArray = (Vector3d[]) arrays[0];
388         Color[] colorsArray = (Color[]) arrays[1];
389         Vector3d[] v;
390         Color[] c;
391         double cumLength = 0;
392
393         if (verticesArray.length <= 1) {
394             return;
395         }
396
397         switch (drawingMode) {
398             case SEGMENTS_STRIP :
399                 if (is2DView()) {
400                     List<PolyLine> list = PolyLine.getPolyLines(verticesArray, colorsArray, G2DStroke.getStroke(appearance, 0), false);
401                     for (PolyLine p : list) {
402                         add(p);
403                     }
404                 } else {
405                     for (int i = 0; i < verticesArray.length - 1; i++) {
406                         v = new Vector3d[] {verticesArray[i], verticesArray[i + 1]};
407                         c = new Color[] {colorsArray[i], colorsArray[i + 1]};
408                         try {
409                             add(new Segment(v, c, G2DStroke.getStroke(appearance, cumLength), false));
410                             cumLength += Segment.getLength(v);
411                         } catch (InvalidPolygonException e) {
412                             cumLength = 0;
413                         }
414                     }
415                 }
416                 break;
417             case SEGMENTS_LOOP :
418                 if (is2DView()) {
419                     List<PolyLine> list = PolyLine.getPolyLines(verticesArray, colorsArray, G2DStroke.getStroke(appearance, 0), true);
420                     for (PolyLine p : list) {
421                         add(p);
422                     }
423                 } else {
424                     for (int i = 0; i < verticesArray.length - 1; i++) {
425                         v = new Vector3d[] {verticesArray[i], verticesArray[i + 1]};
426                         c = new Color[] {colorsArray[i], colorsArray[i + 1]};
427                         try {
428                             add(new Segment(v, c, G2DStroke.getStroke(appearance, cumLength), false));
429                             cumLength += Segment.getLength(v);
430                         } catch (InvalidPolygonException e) {
431                             cumLength = 0;
432                         }
433                     }
434                     int n = verticesArray.length - 1;
435                     v = new Vector3d[] {verticesArray[n], verticesArray[0]};
436                     c = new Color[] {colorsArray[n], colorsArray[0]};
437                     try {
438                         add(new Segment(v, c, G2DStroke.getStroke(appearance, cumLength), false));
439                     } catch (InvalidPolygonException e) { }
440                 }
441                 break;
442             case SEGMENTS :
443             default :
444                 for (int i = 0; i < verticesArray.length - 1; i += 2) {
445                     v = new Vector3d[] {verticesArray[i], verticesArray[i + 1]};
446                     c = new Color[] {colorsArray[i], colorsArray[i + 1]};
447                     try {
448                         add(new Segment(v, c, G2DStroke.getStroke(appearance, 0), is2DView()));
449                     } catch (InvalidPolygonException e) { }
450                 }
451                 break;
452         }
453     }
454
455     /**
456      * Convert the buffer vertices into vertices array and put the triangles in the scene
457      * @param vertices a buffer containing vertices
458      * @param normals a buffer containing the normals (not used)
459      * @param colors a buffer containing the colors
460      * @param defaultColor the color to use when colors is null
461      * @param indices a buffer containg the index of the vertices to retrieve
462      * @param drawingMode the drawing mode
463      */
464     private void addTriangles(FloatBuffer vertices, FloatBuffer normals, FloatBuffer colors, Color defaultColor, IntBuffer indices, FloatBuffer textureCoords, final BufferedImage image, Texture texture, Geometry.FillDrawingMode drawingMode, G2DLightManager lightManager) {
465         Object[] arrays = getArrays(vertices, colors, defaultColor, textureCoords, indices);
466         Vector3d[] verticesArray = (Vector3d[]) arrays[0];
467         Color[] colorsArray = (Color[]) arrays[1];
468         Vector3d[] textureCoordsArray = (Vector3d[]) arrays[2];
469         Vector3d[] v;
470         Color[] c;
471         Texture.Filter filter = Texture.Filter.NEAREST;
472
473         if (texture != null) {
474             filter = texture.getMagnificationFilter();
475         }
476
477         colorsArray = applyLighting(vertices, normals, indices, colorsArray, lightManager);
478
479         switch (drawingMode) {
480             case TRIANGLE_FAN :
481                 for (int i = 1; i < verticesArray.length - 1; i++) {
482                     v = new Vector3d[] {verticesArray[0], verticesArray[i], verticesArray[i + 1]};
483                     try {
484                         if (image == null) {
485                             c = new Color[] {colorsArray[0], colorsArray[i], colorsArray[i + 1]};
486                             add(new Triangle(v, c, null));
487                         } else {
488                             add(new Triangle(v, new Vector3d[] {textureCoordsArray[0], textureCoordsArray[i], textureCoordsArray[i + 1]}, image, filter));
489                         }
490                     } catch (InvalidPolygonException e) { }
491                 }
492                 int n = verticesArray.length - 1;
493                 v = new Vector3d[] {verticesArray[0], verticesArray[n], verticesArray[1]};
494                 try {
495                     if (image == null) {
496                         c = new Color[] {colorsArray[0], colorsArray[n], colorsArray[1]};
497                         add(new Triangle(v, c, null));
498                     } else {
499                         add(new Triangle(v, new Vector3d[] {textureCoordsArray[0], textureCoordsArray[n], textureCoordsArray[1]}, image, filter));
500                     }
501                 } catch (InvalidPolygonException e) { }
502                 break;
503             case TRIANGLE_STRIP :
504                 for (int i = 0; i < verticesArray.length - 2; i++) {
505                     v = new Vector3d[] {verticesArray[i], verticesArray[i + 1], verticesArray[i + 2]};
506                     try {
507                         if (image == null) {
508                             c = new Color[] {colorsArray[i], colorsArray[i + 1], colorsArray[i + 2]};
509                             add(new Triangle(v, c, null));
510                         } else {
511                             add(new Triangle(v, new Vector3d[] {textureCoordsArray[i], textureCoordsArray[i + 1], textureCoordsArray[i + 2]}, image, filter));
512                         }
513                     } catch (InvalidPolygonException e) { }
514                 }
515                 break;
516             case TRIANGLES :
517             default :
518                 for (int i = 0; i < verticesArray.length - 2; i += 3) {
519                     v = new Vector3d[] {verticesArray[i], verticesArray[i + 1], verticesArray[i + 2]};
520                     try {
521                         if (image == null) {
522                             c = new Color[] {colorsArray[i], colorsArray[i + 1], colorsArray[i + 2]};
523                             add(new Triangle(v, c, null));
524                         } else {
525                             add(new Triangle(v, new Vector3d[] {textureCoordsArray[i], textureCoordsArray[i + 1], textureCoordsArray[i + 2]}, image, filter));
526                         }
527                     } catch (InvalidPolygonException e) { }
528                 }
529                 break;
530         }
531     }
532
533     /**
534      * Convert an array of float into an array of Vector3d objects
535      * @param vertices an array of float containing (vertices.length / G2DElementsBuffer.ELEMENT_SIZE) vectors coordinates
536      * @param t the transformation to use for the projection
537      * @param dir if true t.projectDirection() is used rather than t.project()
538      * @return an array of Vector3d containg the vertices
539      */
540     private static final Vector3d[] getMultiVectors(final float[] vertices, final Transformation t, final boolean dir) {
541         Vector3d[] v = new Vector3d[vertices.length / G2DElementsBuffer.ELEMENT_SIZE];
542         if (dir) {
543             int j = 0;
544             for (int i = 0; i < v.length; i++) {
545                 v[i] = t.projectDirection(new Vector3d(vertices[j], vertices[j + 1], vertices[j + 2]));
546                 j += G2DElementsBuffer.ELEMENT_SIZE;
547             }
548         } else {
549             int j = 0;
550             for (int i = 0; i < v.length; i++) {
551                 v[i] = t.project(new Vector3d(vertices[j], vertices[j + 1], vertices[j + 2]));
552                 j += G2DElementsBuffer.ELEMENT_SIZE;
553             }
554         }
555
556         return v;
557     }
558
559     /**
560      * Convert an array of float into an array of Vector3d objects
561      * @param vertices an array of float containing (vertices.length / G2DElementsBuffer.ELEMENT_SIZE) vectors coordinates
562      * @return an array of Vector3d containg the vertices
563      */
564     private static final Vector3d[] getMultiVectors(final float[] vertices) {
565         Vector3d[] v = new Vector3d[vertices.length / G2DElementsBuffer.ELEMENT_SIZE];
566         int j = 0;
567         for (int i = 0; i < v.length; i++) {
568             v[i] = new Vector3d(vertices[j], vertices[j + 1], vertices[j + 2]);
569             j += G2DElementsBuffer.ELEMENT_SIZE;
570         }
571
572         return v;
573     }
574
575     /**
576      * Convert a float array into a Color array
577      * @param colors a float array
578      * @return an array of Color
579      */
580     private static final Color[] getMultiColors(final float[] colors) {
581         Color[] c = new Color[colors.length / G2DElementsBuffer.ELEMENT_SIZE];
582         int j = 0;
583         Color prev = Color.BLACK;
584         for (int i = 0; i < c.length; i++) {
585             c[i] = new Color(colors[j], colors[j + 1], colors[j + 2], colors[j + 3]);
586             if (prev.equals(c[i])) {
587                 c[i] = prev;
588             }
589             prev = c[i];
590             j += G2DElementsBuffer.ELEMENT_SIZE;
591         }
592
593         return c;
594     }
595
596     /**
597      * Perform per-vertex lighting
598      */
599     private Color[] applyLighting(FloatBuffer vertices, FloatBuffer normals, IntBuffer index, Color[] colors, G2DLightManager lightManager) {
600
601         if (!lightManager.isLightningEnable() || vertices == null || normals == null
602                 || index == null || colors == null) {
603             return colors;
604         }
605
606         Material mat = lightManager.getMaterial();
607         if (mat == null) {
608             return colors;
609         }
610
611         float[] vertexTransf = lightManager.getVertexTransform();
612         float[] normalTransf = lightManager.getNormalTransform();
613         //for transformed vertices camera is at origin.
614         Vector3f camera = new Vector3f(0.f, 0.f , 0.f);
615         Vector3f[] vertexArray = LightHelper.getIndexedVector3f(vertices, index, G2DElementsBuffer.ELEMENT_SIZE, vertexTransf);
616         Vector3f[] normalArray = LightHelper.getIndexedVector3f(normals, index, G2DElementsBuffer.ELEMENT_SIZE, normalTransf);
617
618         for (int i = 0; i < normalArray.length; ++i) {
619             normalArray[i] = normalArray[i].getNormalized();
620         }
621
622
623         Color[] outColors = new Color[colors.length];
624         boolean first = true;
625         for (int i = 0; i < lightManager.getLightNumber(); ++i) {
626             G2DLight l = (G2DLight)lightManager.getLight(i);
627
628             if (l == null || !l.isEnable()) {
629                 continue;
630             }
631
632             outColors = LightHelper.applyLight(l, mat, camera, vertexArray, normalArray, colors, outColors, vertexTransf, !first);
633             first = false;
634         }
635         return outColors;
636     }
637 }