2 * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3 * Copyright (C) 2012 - Scilab Enterprises - Calixte Denizet
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
12 package org.scilab.forge.scirenderer.implementation.g2d.motor;
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;
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;
41 * @author Calixte DENIZET
43 public class Motor3D {
45 private Transformation transf;
46 private Transformation singleTransf;
47 private FaceCullingMode mode = FaceCullingMode.BOTH;
48 private Graphics2D g2d;
49 private Dimension dim;
50 private G2DTextureDrawingTools textureDrawingTools;
51 private G2DCanvas canvas;
55 * @param g2d a Graphics2D object where to draw
56 * @param dim the graphic dimensions
58 public Motor3D(G2DCanvas canvas, Graphics2D g2d, Dimension dim) {
62 this.textureDrawingTools = new G2DTextureDrawingTools(g2d);
63 AbstractDrawable3DObject.resetDefaultPrecedence();
66 public void setGraphics(Graphics2D g2d) {
68 this.textureDrawingTools.setGraphics(g2d);
71 public void setAntialiased(boolean aa) {
73 g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
75 g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);
79 public boolean is2DView() {
80 return canvas.getMainDrawer().is2DView();
83 public void setClippingPlanes(List<ClippingPlane> clippingPlanes) {
84 Scene.setClippingPlanes(clippingPlanes);
88 * Set the face culling mode
89 * @param mode the mode to set
91 public void setFaceCullingMode(FaceCullingMode mode) {
96 * Set the current transformation
97 * @param transf the transformation to set
99 public void setTransformation(Transformation transf, Transformation single) {
100 this.transf = transf;
101 this.singleTransf = single;
104 public Transformation getCurrentTransformation() {
108 public Transformation getCurrentSingleTransformation() {
114 * @param color the filling color
116 public void reset(Color color) {
118 mode = FaceCullingMode.BOTH;
120 g2d.fillRect(0, 0, (int) dim.getWidth(), (int) dim.getHeight());
125 * Clear the depth buffer
127 public void clearDepth() {
132 * Draw the scene in the Graphics2D
137 G2DTextureManager.clear();
140 public void drawTexture(DrawingTools drawingTools, BufferedImage image, Texture texture) {
142 SpritedRectangle o = new SpritedRectangle(new Vector3d(0, 0, 0), transf, image, texture.getMagnificationFilter());
144 } catch (InvalidPolygonException e) { }
148 * Add the geometry to the scene
149 * @param drawingTools the DrawingTools
150 * @param geometry the geometry to draw
151 * @param appearance the appearance to use
153 public void draw(DrawingTools drawingTools, Geometry geometry, Appearance appearance) {
154 setFaceCullingMode(geometry.getFaceCullingMode());
155 FloatBuffer vertexBuffer = geometry.getVertices().getData();
157 IntBuffer indicesBuffer = null;;
158 if (geometry.getIndices() != null) {
159 indicesBuffer = geometry.getIndices().getData();
162 IntBuffer wireIndicesBuffer = null;
163 if (geometry.getWireIndices() != null) {
164 wireIndicesBuffer = geometry.getWireIndices().getData();
167 FloatBuffer colorBuffer = null;
168 if (geometry.getColors() != null) {
169 colorBuffer = geometry.getColors().getData();
172 FloatBuffer normalBuffer = null;
173 if (geometry.getNormals() != null) {
174 normalBuffer = geometry.getNormals().getData();
177 Texture texture = appearance.getTexture();
178 FloatBuffer textureCoordinatesBuffer = null;
179 BufferedImage image = null;
180 if (texture != null && geometry.getTextureCoordinates() != null) {
181 textureCoordinatesBuffer = geometry.getTextureCoordinates().getData();
182 image = ((G2DTextureManager.G2DTexture) texture).getImage();
185 if (geometry.getFillDrawingMode() != Geometry.FillDrawingMode.NONE) {
186 addTriangles(vertexBuffer, normalBuffer, colorBuffer, appearance.getFillColor(), indicesBuffer, textureCoordinatesBuffer, image, texture, geometry.getFillDrawingMode());
189 if (geometry.getLineDrawingMode() != Geometry.LineDrawingMode.NONE) {
190 if (appearance.getLineColor() == null) {
191 addSegments(vertexBuffer, colorBuffer, null, wireIndicesBuffer, geometry.getLineDrawingMode(), appearance);
193 addSegments(vertexBuffer, null, appearance.getLineColor(), wireIndicesBuffer, geometry.getLineDrawingMode(), appearance);
198 public void draw(DrawingTools drawingTools, Texture texture, AnchorPosition anchor, ElementsBuffer positions, double rotationAngle) {
199 FloatBuffer positionsBuffer = positions.getData();
202 positionsBuffer.rewind();
203 if (positionsBuffer.hasArray()) {
204 buffer = positionsBuffer.array();
206 buffer = new float[positionsBuffer.limit()];
207 positionsBuffer.get(buffer);
209 Vector3d[] verticesArray = getMultiVectors(buffer, transf, false);
211 for (Vector3d v : verticesArray) {
213 SpritedRectangle o = new SpritedRectangle(v, texture, anchor, textureDrawingTools, rotationAngle);
215 } catch (InvalidPolygonException e) { }
219 public void draw(DrawingTools drawingTools, Texture texture, AnchorPosition anchor, Vector3d position, double rotationAngle) {
221 add(new SpritedRectangle(transf.project(position), texture, anchor, textureDrawingTools, rotationAngle));
222 } catch (InvalidPolygonException e) { }
226 * Add a Triangle to the scene
227 * @param tri the triangle to add
229 private void add(Triangle tri) {
230 Vector3d normal = tri.getNormal();
231 if (normal != null) {
232 //normal = transf.projectDirection(normal);
233 if ((mode == FaceCullingMode.CW && normal.getZ() > 0) || (mode == FaceCullingMode.CCW && normal.getZ() < 0) || mode == FaceCullingMode.BOTH) {
234 Scene.addToRoot(is2DView(), tri);
237 Scene.addToRoot(is2DView(), tri);
242 * Add a segment to the scene
243 * @param s the segment to add
245 private void add(Segment s) {
246 Scene.addToRoot(is2DView(), s);
249 private void add(SpritedRectangle sprite) {
250 Scene.addToRoot(is2DView(), sprite);
254 * Get arrays from Buffer
255 * @param vertices a buffer containing vertices
256 * @param colors a buffer containing the colors
257 * @param defaultColor the color to use when colors is null
258 * @param indices a buffer containg the index of the vertices to retrieve
259 * @return an array of length 2 containing the vertices array and the colors array
261 private Object[] getArrays(FloatBuffer vertices, FloatBuffer colors, Color defaultColor, FloatBuffer textureCoords, IntBuffer indices) {
263 Vector3d[] verticesArray;
264 Vector3d[] textureCoordsArray = null;
268 if (vertices.hasArray()) {
269 buffer = vertices.array();
271 buffer = new float[vertices.limit()];
272 vertices.get(buffer);
274 verticesArray = getMultiVectors(buffer, transf, false);
276 if (colors != null) {
278 if (colors.hasArray()) {
279 buffer = colors.array();
281 buffer = new float[colors.limit()];
284 colorsArray = getMultiColors(buffer);
286 colorsArray = new Color[vertices.limit()];
287 Arrays.fill(colorsArray, defaultColor);
290 if (textureCoords != null) {
291 textureCoords.rewind();
292 if (textureCoords.hasArray()) {
293 buffer = textureCoords.array();
295 buffer = new float[textureCoords.limit()];
296 textureCoords.get(buffer);
298 textureCoordsArray = getMultiVectors(buffer);
301 if (indices != null) {
304 if (indices.hasArray()) {
305 ind = indices.array();
307 ind = new int[indices.limit()];
310 Vector3d[] va = new Vector3d[ind.length];
311 Color[] ca = new Color[ind.length];
312 Vector3d[] ta = null;
313 if (textureCoords != null) {
314 ta = new Vector3d[ind.length];
316 for (int i = 0; i < ind.length; i++) {
317 va[i] = verticesArray[ind[i]];
318 ca[i] = colorsArray[ind[i]];
320 ta[i] = textureCoordsArray[ind[i]];
325 textureCoordsArray = ta;
328 return new Object[] {verticesArray, colorsArray, textureCoordsArray};
332 * Convert the buffer vertices into vertices array and put the segments in the scene
333 * @param vertices a buffer containing vertices
334 * @param colors a buffer containing the colors
335 * @param defaultColor the color to use when colors is null
336 * @param indices a buffer containg the index of the vertices to retrieve
337 * @param drawingMode the drawing mode
338 * @param stroke the Stroke to use to draw a segment
340 private void addSegments(FloatBuffer vertices, FloatBuffer colors, Color defaultColor, IntBuffer indices, Geometry.LineDrawingMode drawingMode, Appearance appearance) {
341 Object[] arrays = getArrays(vertices, colors, defaultColor, null, indices);
342 Vector3d[] verticesArray = (Vector3d[]) arrays[0];
343 Color[] colorsArray = (Color[]) arrays[1];
346 double cumLength = 0;
348 if (verticesArray.length <= 1) {
352 switch (drawingMode) {
353 case SEGMENTS_STRIP :
354 for (int i = 0; i < verticesArray.length - 1; i++) {
355 v = new Vector3d[] {verticesArray[i], verticesArray[i + 1]};
356 c = new Color[] {colorsArray[i], colorsArray[i + 1]};
358 add(new Segment(v, c, G2DStroke.getStroke(appearance, cumLength)));
359 cumLength += Segment.getLength(v);
360 } catch (InvalidPolygonException e) {
366 for (int i = 0; i < verticesArray.length - 1; i++) {
367 v = new Vector3d[] {verticesArray[i], verticesArray[i + 1]};
368 c = new Color[] {colorsArray[i], colorsArray[i + 1]};
370 add(new Segment(v, c, G2DStroke.getStroke(appearance, cumLength)));
371 cumLength += Segment.getLength(v);
372 } catch (InvalidPolygonException e) {
376 int n = verticesArray.length - 1;
377 v = new Vector3d[] {verticesArray[n], verticesArray[0]};
378 c = new Color[] {colorsArray[n], colorsArray[0]};
380 add(new Segment(v, c, G2DStroke.getStroke(appearance, cumLength)));
381 } catch (InvalidPolygonException e) { }
385 for (int i = 0; i < verticesArray.length - 1; i += 2) {
386 v = new Vector3d[] {verticesArray[i], verticesArray[i + 1]};
387 c = new Color[] {colorsArray[i], colorsArray[i + 1]};
389 add(new Segment(v, c, G2DStroke.getStroke(appearance, 0)));
390 } catch (InvalidPolygonException e) { }
397 * Convert the buffer vertices into vertices array and put the triangles in the scene
398 * @param vertices a buffer containing vertices
399 * @param normals a buffer containing the normals (not used)
400 * @param colors a buffer containing the colors
401 * @param defaultColor the color to use when colors is null
402 * @param indices a buffer containg the index of the vertices to retrieve
403 * @param drawingMode the drawing mode
405 private void addTriangles(FloatBuffer vertices, FloatBuffer normals, FloatBuffer colors, Color defaultColor, IntBuffer indices, FloatBuffer textureCoords, final BufferedImage image, Texture texture, Geometry.FillDrawingMode drawingMode) {
406 Object[] arrays = getArrays(vertices, colors, defaultColor, textureCoords, indices);
407 Vector3d[] verticesArray = (Vector3d[]) arrays[0];
408 Color[] colorsArray = (Color[]) arrays[1];
409 Vector3d[] textureCoordsArray = (Vector3d[]) arrays[2];
412 Texture.Filter filter = Texture.Filter.NEAREST;
414 if (texture != null) {
415 filter = texture.getMagnificationFilter();
418 switch (drawingMode) {
420 for (int i = 1; i < verticesArray.length - 1; i++) {
421 v = new Vector3d[] {verticesArray[0], verticesArray[i], verticesArray[i + 1]};
424 c = new Color[] {colorsArray[0], colorsArray[i], colorsArray[i + 1]};
425 add(new Triangle(v, c, null));
427 add(new Triangle(v, new Vector3d[] {textureCoordsArray[0], textureCoordsArray[i], textureCoordsArray[i + 1]}, image, filter));
429 } catch (InvalidPolygonException e) { }
431 int n = verticesArray.length - 1;
432 v = new Vector3d[] {verticesArray[0], verticesArray[n], verticesArray[1]};
435 c = new Color[] {colorsArray[0], colorsArray[n], colorsArray[1]};
436 add(new Triangle(v, c, null));
438 add(new Triangle(v, new Vector3d[] {textureCoordsArray[0], textureCoordsArray[n], textureCoordsArray[1]}, image, filter));
440 } catch (InvalidPolygonException e) { }
442 case TRIANGLE_STRIP :
443 for (int i = 0; i < verticesArray.length - 2; i++) {
444 v = new Vector3d[] {verticesArray[i], verticesArray[i + 1], verticesArray[i + 2]};
447 c = new Color[] {colorsArray[i], colorsArray[i + 1], colorsArray[i + 2]};
448 add(new Triangle(v, c, null));
450 add(new Triangle(v, new Vector3d[] {textureCoordsArray[i], textureCoordsArray[i + 1], textureCoordsArray[i + 2]}, image, filter));
452 } catch (InvalidPolygonException e) { }
457 for (int i = 0; i < verticesArray.length - 2; i += 3) {
458 v = new Vector3d[] {verticesArray[i], verticesArray[i + 1], verticesArray[i + 2]};
461 c = new Color[] {colorsArray[i], colorsArray[i + 1], colorsArray[i + 2]};
462 add(new Triangle(v, c, null));
464 add(new Triangle(v, new Vector3d[] {textureCoordsArray[i], textureCoordsArray[i + 1], textureCoordsArray[i + 2]}, image, filter));
466 } catch (InvalidPolygonException e) { }
473 * Convert an array of float into an array of Vector3d objects
474 * @param vertices an array of float containing (vertices.length / G2DElementsBuffer.ELEMENT_SIZE) vectors coordinates
475 * @param t the transformation to use for the projection
476 * @param dir if true t.projectDirection() is used rather than t.project()
477 * @return an array of Vector3d containg the vertices
479 private static final Vector3d[] getMultiVectors(final float[] vertices, final Transformation t, final boolean dir) {
480 Vector3d[] v = new Vector3d[vertices.length / G2DElementsBuffer.ELEMENT_SIZE];
483 for (int i = 0; i < v.length; i++) {
484 v[i] = t.projectDirection(new Vector3d(vertices[j], vertices[j + 1], vertices[j + 2]));
485 j += G2DElementsBuffer.ELEMENT_SIZE;
489 for (int i = 0; i < v.length; i++) {
490 v[i] = t.project(new Vector3d(vertices[j], vertices[j + 1], vertices[j + 2]));
491 j += G2DElementsBuffer.ELEMENT_SIZE;
499 * Convert an array of float into an array of Vector3d objects
500 * @param vertices an array of float containing (vertices.length / G2DElementsBuffer.ELEMENT_SIZE) vectors coordinates
501 * @return an array of Vector3d containg the vertices
503 private static final Vector3d[] getMultiVectors(final float[] vertices) {
504 Vector3d[] v = new Vector3d[vertices.length / G2DElementsBuffer.ELEMENT_SIZE];
506 for (int i = 0; i < v.length; i++) {
507 v[i] = new Vector3d(vertices[j], vertices[j + 1], vertices[j + 2]);
508 j += G2DElementsBuffer.ELEMENT_SIZE;
515 * Convert a float array into a Color array
516 * @param colors a float array
517 * @return an array of Color
519 private static final Color[] getMultiColors(final float[] colors) {
520 Color[] c = new Color[colors.length / G2DElementsBuffer.ELEMENT_SIZE];
522 Color prev = Color.BLACK;
523 for (int i = 0; i < c.length; i++) {
524 c[i] = new Color(colors[j], colors[j + 1], colors[j + 2], colors[j + 3]);
525 if (prev.equals(c[i])) {
529 j += G2DElementsBuffer.ELEMENT_SIZE;